tablesort.lib.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <?php
  2. /*
  3. ==============================================================================
  4. Dokeos - elearning and course management software
  5. Copyright (c) 2004-2008 Dokeos S.A.
  6. Copyright (c) 2003 Ghent University (UGent)
  7. Copyright (c) 2001 Universite catholique de Louvain (UCL)
  8. Copyright (c) Bart Mollet (bart.mollet@hogent.be)
  9. For a full list of contributors, see "credits.txt".
  10. The full license can be read in "license.txt".
  11. This program is free software; you can redistribute it and/or
  12. modify it under the terms of the GNU General Public License
  13. as published by the Free Software Foundation; either version 2
  14. of the License, or (at your option) any later version.
  15. See the GNU General Public License for more details.
  16. Contact address: Dokeos, 44 rue des palais, B-1030 Brussels, Belgium
  17. Mail: info@dokeos.com
  18. ==============================================================================
  19. */
  20. /**
  21. ==============================================================================
  22. * This is a library with some functions to sort tabular data
  23. *
  24. * @package dokeos.library
  25. ==============================================================================
  26. */
  27. define('SORT_DATE', 3);
  28. define('SORT_IMAGE',4);
  29. class TableSort
  30. {
  31. /**
  32. * String to lowercase (keep accents).
  33. * @param string $txt The string to convert
  34. * @author Ren� Haentjens
  35. * This function is 8859-1 specific and should be adapted when Dokeos is
  36. * used with other charsets.
  37. */
  38. function strtolower_keepaccents($txt)
  39. {
  40. return strtolower(strtr($txt, "������������������������������", "������������������������������"));
  41. }
  42. /**
  43. * String to lowercase.
  44. * @param string $txt The string to convert
  45. * @author Ren� Haentjens
  46. * This function is 8859-1 specific and should be adapted when Dokeos is
  47. * used with other charsets.
  48. */
  49. function strtolower_eorlatin($txt)
  50. {
  51. return str_replace(array ("�", "�"), array ("ae", "ss"), strtr(TableSort::strtolower_keepaccents($txt), "�����������������������������", "aaaaaaceeeeiiiidnoooooouuuuyy"));
  52. // do not replace "�" by "th", leave it at the end of the alphabet...
  53. // do not replace any of "$&��������", though they resemble letters...
  54. }
  55. /**
  56. * Create a string to use in sorting.
  57. * @param string $txt The string to convert
  58. * @author Ren� Haentjens
  59. * This function is 8859-1 specific and should be adapted when Dokeos is
  60. * used with other charsets.
  61. * See http://anubis.dkuug.dk/CEN/TC304/EOR/eorhome.html
  62. * Function 'orderingstring' can be used to implement EOR level 1 ordering,
  63. * for 8859- 1.
  64. */
  65. function orderingstring($txt)
  66. {
  67. return ereg_replace("[^0-9a-z�]", "", TableSort::strtolower_eorlatin($txt));
  68. }
  69. /**
  70. * Sort 2-dimensional table.
  71. * @param array $data The data to be sorted.
  72. * @param int $column The column on which the data should be sorted (default = 0)
  73. * @param string $direction The direction to sort (SORT_ASC (default) or SORT_DESC)
  74. * @param constant $type How should data be sorted (SORT_REGULAR, SORT_NUMERIC,
  75. * SORT_STRING,SORT_DATE,SORT_IMAGE)
  76. * @return array The sorted dataset
  77. * @author bart.mollet@hogent.be
  78. */
  79. function sort_table($data, $column = 0, $direction = SORT_ASC, $type = SORT_REGULAR)
  80. {
  81. if(!is_array($data) or count($data)==0){return array();}
  82. if($column != strval(intval($column))){return $data;} //probably an attack
  83. if(!in_array($direction,array(SORT_ASC,SORT_DESC))){return $data;} // probably an attack
  84. $compare_function = '';
  85. switch ($type)
  86. {
  87. case SORT_REGULAR :
  88. if (TableSort::is_image_column($data, $column))
  89. {
  90. return TableSort::sort_table($data, $column, $direction, SORT_IMAGE);
  91. }
  92. elseif (TableSort::is_date_column($data, $column))
  93. {
  94. return TableSort::sort_table($data, $column, $direction, SORT_DATE);
  95. }
  96. elseif (TableSort::is_numeric_column($data, $column))
  97. {
  98. return TableSort::sort_table($data, $column, $direction, SORT_NUMERIC);
  99. }
  100. return TableSort::sort_table($data, $column, $direction, SORT_STRING);
  101. break;
  102. case SORT_NUMERIC :
  103. $compare_function = 'strip_tags($el1) > strip_tags($el2)';
  104. break;
  105. case SORT_IMAGE :
  106. $compare_function = 'strnatcmp(TableSort::orderingstring(strip_tags($el1,"<img>")),TableSort::orderingstring(strip_tags($el2,"<img>"))) > 0';
  107. break;
  108. case SORT_DATE :
  109. $compare_function = 'strtotime(strip_tags($el1)) > strtotime(strip_tags($el2))';
  110. break;
  111. case SORT_STRING :
  112. default:
  113. $compare_function = 'strnatcmp(TableSort::orderingstring(strip_tags($el1)),TableSort::orderingstring(strip_tags($el2))) > 0';
  114. break;
  115. }
  116. $function_body = '$el1 = $a['.$column.']; $el2 = $b['.$column.']; return ('.$direction.' == SORT_ASC ? ('.$compare_function.') : !('.$compare_function.'));';
  117. // Sort the content
  118. usort($data, create_function('$a,$b', $function_body));
  119. return $data;
  120. }
  121. /**
  122. * Checks if a column of a 2D-array contains only numeric values
  123. * @param array $data The data-array
  124. * @param int $column The index of the column to check
  125. * @return bool true if column contains only dates, false otherwise
  126. * @todo Take locale into account (eg decimal point or comma ?)
  127. * @author bart.mollet@hogent.be
  128. */
  129. function is_numeric_column($data, $column)
  130. {
  131. $is_numeric = true;
  132. foreach ($data as $index => $row)
  133. {
  134. $is_numeric &= is_numeric(strip_tags($row[$column]));
  135. }
  136. return $is_numeric;
  137. }
  138. /**
  139. * Checks if a column of a 2D-array contains only dates (GNU date syntax)
  140. * @param array $data The data-array
  141. * @param int $column The index of the column to check
  142. * @return bool true if column contains only dates, false otherwise
  143. * @author bart.mollet@hogent.be
  144. */
  145. function is_date_column($data, $column)
  146. {
  147. $is_date = true;
  148. foreach ($data as $index => $row)
  149. {
  150. if(strlen(strip_tags($row[$column])) != 0 )
  151. {
  152. $check_date = strtotime(strip_tags($row[$column]));
  153. // strtotime Returns a timestamp on success, FALSE otherwise.
  154. // Previous to PHP 5.1.0, this function would return -1 on failure.
  155. $is_date &= ($check_date != -1 && $check_date != false);
  156. }
  157. else
  158. {
  159. $is_date &= false;
  160. }
  161. }
  162. return $is_date;
  163. }
  164. /**
  165. * Checks if a column of a 2D-array contains only images (<img src="
  166. * path/file.ext" alt=".."/>)
  167. * @param array $data The data-array
  168. * @param int $column The index of the column to check
  169. * @return bool true if column contains only images, false otherwise
  170. * @author bart.mollet@hogent.be
  171. */
  172. function is_image_column($data, $column)
  173. {
  174. $is_image = true;
  175. foreach ($data as $index => $row)
  176. {
  177. $is_image &= strlen(trim(strip_tags($row[$column],'<img>'))) > 0; // at least one img-tag
  178. $is_image &= strlen(trim(strip_tags($row[$column]))) == 0; // and no text outside attribute-values
  179. }
  180. return $is_image;
  181. }
  182. /**
  183. * Sort 2-dimensional table. It is possile of change the columns that will be show and the way that the columns are sorted.
  184. * @param array $data The data to be sorted.
  185. * @param int $column The column on which the data should be sorted (default = 0)
  186. * @param string $direction The direction to sort (SORT_ASC (default) orSORT_DESC)
  187. * @param array $column_show The columns that we will show in the table i.e: $column_show=array('1','0','1') we will show the 1st and the 3th column.
  188. * @param array $column_order Changes how the columns will be sorted ie. $column_order=array('1','4','3','4') The 2nd column will be sorted like the 4 column
  189. * @param constant $type How should data be sorted (SORT_REGULAR, SORT_NUMERIC,SORT_STRING,SORT_DATE,SORT_IMAGE) *
  190. * @return array The sorted dataset
  191. * @author bart.mollet@hogent.be
  192. */
  193. function sort_table_config($data, $column = 0, $direction = SORT_ASC, $column_show=null, $column_order=null,$type = SORT_REGULAR)
  194. {
  195. if(!is_array($data) or count($data)==0){return array();}
  196. if($column != strval(intval($column))){return $data;} //probably an attack
  197. if(!in_array($direction,array(SORT_ASC,SORT_DESC))){return $data;} // probably an attack
  198. $compare_function = '';
  199. // Change columns sort
  200. // Here we say that the real way of how the columns are going to be order is manage by the $column_order array
  201. if(is_array($column_order))
  202. {
  203. for($i=0;$i<count($column_order);$i++)
  204. {
  205. if ($column== $i+1)
  206. {
  207. $column=$column_order[$i];
  208. }
  209. }
  210. }
  211. switch ($type)
  212. {
  213. case SORT_REGULAR :
  214. if (TableSort::is_image_column($data, $column))
  215. {
  216. return TableSort::sort_table_config($data, $column, $direction, $column_show, $column_order,SORT_IMAGE);
  217. }
  218. elseif (TableSort::is_date_column($data, $column))
  219. {
  220. return TableSort::sort_table_config($data, $column, $direction, $column_show, $column_order,SORT_DATE);
  221. }
  222. elseif (TableSort::is_numeric_column($data, $column))
  223. {
  224. return TableSort::sort_table_config($data, $column, $direction, $column_show, $column_order,SORT_NUMERIC);
  225. }
  226. return TableSort::sort_table_config($data, $column, $direction, $column_show, $column_order,SORT_STRING);
  227. break;
  228. case SORT_NUMERIC :
  229. $compare_function = 'strip_tags($el1) > strip_tags($el2)';
  230. break;
  231. case SORT_IMAGE :
  232. $compare_function = 'strnatcmp(TableSort::orderingstring(strip_tags($el1,"<img>")),TableSort::orderingstring(strip_tags($el2,"<img>"))) > 0';
  233. break;
  234. case SORT_DATE :
  235. $compare_function = 'strtotime(strip_tags($el1)) > strtotime(strip_tags($el2))';
  236. break;
  237. case SORT_STRING :
  238. default:
  239. $compare_function = 'strnatcmp(TableSort::orderingstring(strip_tags($el1)),TableSort::orderingstring(strip_tags($el2))) > 0';
  240. break;
  241. }
  242. $function_body = '$el1 = $a['.$column.']; ' .
  243. '$el2 = $b['.$column.']; ' .
  244. 'return ('.$direction.' == SORT_ASC ? ('.$compare_function.') : !('.$compare_function.'));';
  245. // Sort the content
  246. usort($data, create_function('$a,$b', $function_body));
  247. // We show only the columns data that were set up on the $column_show array
  248. $new_order_data=array();
  249. if(is_array($column_show))
  250. {
  251. for ($j=0;$j<count($data);$j++)
  252. {
  253. $k=0;
  254. for ($i=0;$i<count($column_show);$i++)
  255. {
  256. if ($column_show[$i])
  257. {
  258. $new_order_data[$j][$k]=$data[$j][$i];
  259. }
  260. $k++;
  261. }
  262. }
  263. //replace the multi-arrays
  264. $data=$new_order_data;
  265. }
  266. else
  267. {
  268. return $data;
  269. }
  270. return $data;
  271. }
  272. }
  273. ?>