fileManage.lib.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * This is the file manage library for Chamilo.
  5. * Include/require it in your code to use its functionality.
  6. *
  7. * @package chamilo.library
  8. */
  9. /**
  10. * Update the file or directory path in the document db document table
  11. *
  12. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  13. * @param - action (string) - action type require : 'delete' or 'update'
  14. * @param - old_path (string) - old path info stored to change
  15. * @param - new_path (string) - new path info to substitute
  16. * @desc Update the file or directory path in the document db document table
  17. *
  18. */
  19. function update_db_info($action, $old_path, $new_path = '') {
  20. global $dbTable; // Table 'document'
  21. /* DELETE */
  22. if ($action == 'delete') {
  23. /* // RH: metadata, update 2004/08/23
  24. these two lines replaced by new code below:
  25. $query = "DELETE FROM `$dbTable`
  26. WHERE path='".$old_path."' OR path LIKE '".$old_path."/%'";
  27. */
  28. $to_delete = "WHERE path LIKE BINARY '".$old_path."' OR path LIKE BINARY '".$old_path."/%'";
  29. $query = "DELETE FROM $dbTable " . $to_delete;
  30. $result = Database::query("SELECT id FROM $dbTable " . $to_delete);
  31. if (Database::num_rows($result)) {
  32. require_once api_get_path(INCLUDE_PATH).'../metadata/md_funcs.php';
  33. $mdStore = new mdstore(TRUE); // create if needed
  34. $md_type = (substr($dbTable, -13) == 'scormdocument') ? 'Scorm' : 'Document';
  35. while ($row = Database::fetch_array($result)) {
  36. $eid = $md_type . '.' . $row['id'];
  37. $mdStore->mds_delete($eid);
  38. $mdStore->mds_delete_offspring($eid);
  39. }
  40. }
  41. }
  42. /* UPDATE */
  43. if ($action == 'update') {
  44. //Display::display_normal_message("new_path = $new_path");
  45. if ($new_path[0] == '.') $new_path = substr($new_path, 1);
  46. $new_path = str_replace('//', '/', $new_path);
  47. //Display::display_normal_message("character 0 = " . $new_path[0] . " 1=" . $new_path[1]);
  48. //Display::display_normal_message("new_path = $new_path");
  49. // Older broken version
  50. //$query = "UPDATE `$dbTable`
  51. //SET path = CONCAT('".$new_path."', SUBSTRING(path, LENGTH('".$old_path."')+1) )
  52. //WHERE path = '".$old_path."' OR path LIKE '".$old_path."/%'";
  53. // Attempt to update - tested & working for root dir
  54. $query = "UPDATE $dbTable
  55. SET path = CONCAT('".$new_path."', SUBSTRING(path, LENGTH('".$old_path."')+1) )
  56. WHERE path LIKE BINARY '".$old_path."' OR path LIKE BINARY '".$old_path."/%'";
  57. }
  58. //echo $query;
  59. //error_log($query,0);
  60. Database::query($query);
  61. //Display::display_normal_message("query = $query");
  62. }
  63. /**
  64. * Cheks a file or a directory actually exist at this location
  65. *
  66. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  67. * @param - file_path (string) - path of the presume existing file or dir
  68. * @return - boolean TRUE if the file or the directory exists
  69. * boolean FALSE otherwise.
  70. */
  71. function check_name_exist($file_path) {
  72. clearstatcache();
  73. $save_dir = getcwd();
  74. if (!is_dir(dirname($file_path))) {
  75. return false;
  76. }
  77. chdir(dirname($file_path));
  78. $file_name = basename($file_path);
  79. if (file_exists($file_name)) {
  80. chdir($save_dir);
  81. return true;
  82. } else {
  83. chdir($save_dir);
  84. return false;
  85. }
  86. }
  87. /**
  88. * Deletes a file or a directory
  89. *
  90. * @author - Hugues Peeters
  91. * @param - $file (String) - the path of file or directory to delete
  92. * @return - bolean - true if the delete succeed
  93. * bolean - false otherwise.
  94. * @see - delete() uses check_name_exist() and removeDir() functions
  95. */
  96. function my_delete($file) {
  97. if (check_name_exist($file)) {
  98. if (is_file($file)) { // FILE CASE
  99. unlink($file);
  100. return true;
  101. } elseif (is_dir($file)) { // DIRECTORY CASE
  102. removeDir($file);
  103. return true;
  104. }
  105. } else {
  106. return false; // no file or directory to delete
  107. }
  108. }
  109. /**
  110. * Removes a directory recursively
  111. *
  112. * @returns true if OK, otherwise false
  113. *
  114. * @author Amary <MasterNES@aol.com> (from Nexen.net)
  115. * @author Olivier Brouckaert <oli.brouckaert@skynet.be>
  116. *
  117. * @param string $dir directory to remove
  118. */
  119. function removeDir($dir) {
  120. if (!@$opendir = opendir($dir)) {
  121. return false;
  122. }
  123. while ($readdir = readdir($opendir)) {
  124. if ($readdir != '..' && $readdir != '.') {
  125. if (is_file($dir.'/'.$readdir)) {
  126. if (!@unlink($dir.'/'.$readdir)) {
  127. return false;
  128. }
  129. } elseif (is_dir($dir.'/'.$readdir)) {
  130. if (!removeDir($dir.'/'.$readdir)) {
  131. return false;
  132. }
  133. }
  134. }
  135. }
  136. closedir($opendir);
  137. if (!@rmdir($dir)) {
  138. return false;
  139. }
  140. return true;
  141. }
  142. /**
  143. * Renames a file or a directory
  144. *
  145. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  146. * @param - $file_path (string) - complete path of the file or the directory
  147. * @param - $new_file_name (string) - new name for the file or the directory
  148. * @return - boolean - true if succeed
  149. * - boolean - false otherwise
  150. * @see - rename() uses the check_name_exist() and php2phps() functions
  151. */
  152. function my_rename($file_path, $new_file_name) {
  153. $save_dir = getcwd();
  154. $path = dirname($file_path);
  155. $old_file_name = basename($file_path);
  156. $new_file_name = replace_dangerous_char($new_file_name);
  157. // If no extension, take the old one
  158. if ((strpos($new_file_name, '.') === false) && ($dotpos = strrpos($old_file_name, '.'))) {
  159. $new_file_name .= substr($old_file_name, $dotpos);
  160. }
  161. // Note: still possible: 'xx.yy' -rename-> '.yy' -rename-> 'zz'
  162. // This is useful for folder names, where otherwise '.' would be sticky
  163. // Extension PHP is not allowed, change to PHPS
  164. $new_file_name = php2phps($new_file_name);
  165. if ($new_file_name == $old_file_name) {
  166. return $old_file_name;
  167. }
  168. if (strtolower($new_file_name) != strtolower($old_file_name) && check_name_exist($path.'/'.$new_file_name)) {
  169. return false;
  170. }
  171. // On a Windows server, it would be better not to do the above check
  172. // because it succeeds for some new names resembling the old name.
  173. // But on Unix/Linux the check must be done because rename overwrites.
  174. chdir($path);
  175. $res = rename($old_file_name, $new_file_name) ? $new_file_name : false;
  176. chdir($save_dir);
  177. return $res;
  178. }
  179. /**
  180. * Moves a file or a directory to an other area
  181. *
  182. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  183. * @param - $source (String) - the path of file or directory to move
  184. * @param - $target (String) - the path of the new area
  185. * @return - bolean - true if the move succeed
  186. * bolean - false otherwise.
  187. * @see - move() uses check_name_exist() and copyDirTo() functions
  188. */
  189. function move($source, $target) {
  190. if (check_name_exist($source)) {
  191. $file_name = basename($source);
  192. if (check_name_exist($target.'/'.$file_name)) {
  193. return false;
  194. } else {
  195. /* File case */
  196. if (is_file($source)) {
  197. copy($source , $target.'/'.$file_name);
  198. unlink($source);
  199. return true;
  200. }
  201. /* Directory case */
  202. elseif (is_dir($source)) {
  203. // Check to not copy the directory inside itself
  204. if (ereg('^'.$source.'/', $target.'/')) { // TODO: ereg() function is deprecated in PHP 5.3
  205. return false;
  206. } else {
  207. copyDirTo($source, $target);
  208. return true;
  209. }
  210. }
  211. }
  212. } else {
  213. return false;
  214. }
  215. }
  216. /**
  217. * Moves a directory and its content to an other area
  218. *
  219. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  220. * @param - $orig_dir_path (string) - the path of the directory to move
  221. * @param - $destination (string) - the path of the new area
  222. * @return - no return
  223. */
  224. function copyDirTo($orig_dir_path, $destination, $move = true) {
  225. $save_dir = getcwd();
  226. // Extract directory name - create it at destination - update destination trail
  227. $dir_name = basename($orig_dir_path);
  228. if (is_dir($dir_name)) {
  229. mkdir($destination.'/'.$dir_name, api_get_permissions_for_new_directories());
  230. $destination_trail = $destination.'/'.$dir_name;
  231. if (is_dir($destination)) {
  232. chdir ($orig_dir_path) ;
  233. $handle = opendir($orig_dir_path);
  234. while ($element = readdir($handle)) {
  235. if ( $element == '.' || $element == '..') {
  236. continue; // Skip the current and parent directories
  237. } elseif (is_file($element)) {
  238. copy($element, $destination_trail.'/'.$element);
  239. if ($move) {
  240. unlink($element) ;
  241. }
  242. } elseif (is_dir($element)) {
  243. $dir_to_copy[] = $orig_dir_path.'/'.$element;
  244. }
  245. }
  246. closedir($handle) ;
  247. if (sizeof($dir_to_copy) > 0) {
  248. foreach ($dir_to_copy as $this_dir) {
  249. copyDirTo($this_dir, $destination_trail, $move); // Recursivity
  250. }
  251. }
  252. if ($move) {
  253. rmdir($orig_dir_path) ;
  254. }
  255. chdir($save_dir);
  256. }
  257. }
  258. }
  259. /* NOTE: These functions batch is used to automatically build HTML forms
  260. * with a list of the directories contained on the course Directory.
  261. *
  262. * From a thechnical point of view, form_dir_lists calls sort_dir wich calls index_dir
  263. */
  264. /**
  265. * Gets all the directories and subdirectories
  266. * contented in a given directory
  267. *
  268. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  269. * @param - path (string) - directory path of the one to index
  270. * @return - an array containing the path of all the subdirectories
  271. */
  272. function index_dir($path) {
  273. $dir_array = array();
  274. $save_dir = getcwd();
  275. if (is_dir($path)){
  276. chdir($path);
  277. $handle = opendir($path);
  278. // Reads directory content end record subdirectoies names in $dir_array
  279. if ($handle !== false) {
  280. while ($element = readdir($handle)) {
  281. if ($element == '.' || $element == '..') continue; // Skip the current and parent directories
  282. if (is_dir($element)) $dir_array[] = $path.'/'.$element;
  283. }
  284. closedir($handle) ;
  285. }
  286. // Recursive operation if subdirectories exist
  287. $dir_number = sizeof($dir_array);
  288. if ($dir_number > 0) {
  289. for ($i = 0 ; $i < $dir_number ; $i++) {
  290. $sub_dir_array = index_dir($dir_array[$i]); // Function recursivity
  291. $dir_array = array_merge((array)$dir_array, (array)$sub_dir_array); // Data merge
  292. }
  293. }
  294. }
  295. chdir($save_dir) ;
  296. return $dir_array ;
  297. }
  298. /**
  299. * Indexes all the directories and subdirectories
  300. * contented in a given directory, and sort them alphabetically
  301. *
  302. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  303. * @param - path (string) - directory path of the one to index
  304. * @return - an array containing the path of all the subdirectories sorted
  305. * false, if there is no directory
  306. * @see - index_and_sort_dir uses the index_dir() function
  307. */
  308. function index_and_sort_dir($path) {
  309. $dir_list = index_dir($path);
  310. if ($dir_list) {
  311. natsort($dir_list);
  312. return $dir_list;
  313. }
  314. return false;
  315. }
  316. /**
  317. * Builds a html form listing all directories of a given directory
  318. *
  319. */
  320. function form_dir_list($source_type, $source_component, $command, $base_work_dir) {
  321. $dir_list = index_and_sort_dir($base_work_dir);
  322. $dialog_box .= "<form action=\"".api_get_self()."\" method=\"post\">\n" ;
  323. $dialog_box .= "<input type=\"hidden\" name=\"".$source_type."\" value=\"".$source_component."\">\n" ;
  324. $dialog_box .= get_lang('Move').' '.$source_component.' '.get_lang('To');
  325. $dialog_box .= "<select name=\"".$command."\">\n" ;
  326. $dialog_box .= "<option value=\"\" style=\"color:#999999\">".get_lang('Root')."\n";
  327. $bwdLen = strlen($base_work_dir) ; // base directories lenght, used under
  328. /* build html form inputs */
  329. if ($dir_list) {
  330. while (list( , $path_value) = each($dir_list) ) {
  331. $path_value = substr ( $path_value , $bwdLen ); // Truncates cunfidential informations confidentielles
  332. $dirname = basename ($path_value); // Extracts $path_value directory name du nom
  333. /* compute de the display tab */
  334. $tab = ""; // $tab reinitialisation
  335. $depth = substr_count($path_value, '/'); // The number of nombre '/' indicates the directory deepness
  336. for ($h = 0; $h < $depth; $h++) {
  337. $tab .= "&nbsp;&nbsp;";
  338. }
  339. $dialog_box .= "<option value=\"$path_value\">$tab>$dirname\n";
  340. }
  341. }
  342. $dialog_box .= "</select>\n";
  343. $dialog_box .= "<input type=\"submit\" value=\"".get_lang('Ok')."\">";
  344. $dialog_box .= "</form>\n";
  345. return $dialog_box;
  346. }
  347. /**
  348. * Extracting extention of a filename
  349. *
  350. * @returns array
  351. * @param string $filename filename
  352. */
  353. function getextension($filename) {
  354. $bouts = explode('.', $filename);
  355. return array(array_pop($bouts), implode('.', $bouts));
  356. }
  357. /**
  358. * Calculation size of a directory
  359. *
  360. * @returns integer size
  361. * @param string $path path to size
  362. * @param boolean $recursive if true , include subdir in total
  363. */
  364. function dirsize($root, $recursive = true) {
  365. $dir = @opendir($root);
  366. $size = 0;
  367. while ($file = @readdir($dir)) {
  368. if (!in_array($file, array('.', '..'))) {
  369. if (is_dir($root.'/'.$file)) {
  370. $size += $recursive ? dirsize($root.'/'.$file) : 0;
  371. } else {
  372. $size += @filesize($root.'/'.$file);
  373. }
  374. }
  375. }
  376. @closedir($dir);
  377. return $size;
  378. }
  379. /* CLASS FileManager */
  380. /**
  381. This class contains functions that you can access statically.
  382. FileManager::list_all_directories($path)
  383. FileManager::list_all_files($dir_array)
  384. FileManager::compat_load_file($file_name)
  385. FileManager::set_default_settings($upload_path, $filename, $filetype="file", $glued_table, $default_visibility='v')
  386. @author Roan Embrechts
  387. @version 1.1, July 2004
  388. */
  389. class FileManager
  390. {
  391. /**
  392. Returns a list of all directories, except the base dir,
  393. of the current course. This function uses recursion.
  394. Convention: the parameter $path does not end with a slash.
  395. @author Roan Embrechts
  396. @version 1.0.1
  397. */
  398. function list_all_directories($path) {
  399. $result_array = array();
  400. if (is_dir($path)) {
  401. $save_dir = getcwd();
  402. chdir($path);
  403. $handle = opendir($path);
  404. while ($element = readdir($handle)) {
  405. if ($element == '.' || $element == '..') continue; // Skip the current and parent directories
  406. if (is_dir($element)) {
  407. $dir_array[] = $path.'/'.$element;
  408. }
  409. }
  410. closedir($handle);
  411. // Recursive operation if subdirectories exist
  412. $dir_number = sizeof($dir_array);
  413. if ($dir_number > 0) {
  414. for ($i = 0 ; $i < $dir_number ; $i++) {
  415. $sub_dir_array = FileManager::list_all_directories($dir_array[$i]); // Function recursivity
  416. if (is_array($dir_array) && is_array($sub_dir_array)) {
  417. $dir_array = array_merge($dir_array, $sub_dir_array); // Data merge
  418. }
  419. }
  420. }
  421. $result_array = $dir_array;
  422. chdir($save_dir) ;
  423. }
  424. return $result_array ;
  425. }
  426. /**
  427. This function receives a list of directories.
  428. It returns a list of all files in these directories
  429. @author Roan Embrechts
  430. @version 1.0
  431. */
  432. function list_all_files($dir_array) {
  433. $element_array = array();
  434. if (is_dir($dir_array)) {
  435. $save_dir = getcwd();
  436. foreach ($dir_array as $directory) {
  437. chdir($directory);
  438. $handle = opendir($directory);
  439. while ($element = readdir($handle)) {
  440. if ($element == '.' || $element == '..' || $element == '.htaccess') continue; // Skip the current and parent directories
  441. if (!is_dir($element)) {
  442. $element_array[] = $directory.'/'.$element;
  443. }
  444. }
  445. closedir($handle);
  446. chdir('..');
  447. chdir($save_dir);
  448. }
  449. }
  450. return $element_array;
  451. }
  452. /**
  453. Loads contents of file $filename into memory and returns them as a string.
  454. Function kept for compatibility with older PHP versions.
  455. Function is binary safe (is needed on Windows)
  456. */
  457. function compat_load_file($file_name) {
  458. $buffer = '';
  459. if (file_exists($file_name)) {
  460. $fp = fopen($file_name, 'rb');
  461. $buffer = fread ($fp, filesize($file_name));
  462. fclose ($fp);
  463. }
  464. return $buffer;
  465. }
  466. /**
  467. * Adds file/folder to document table in database
  468. * improvement from set_default_settings (see below):
  469. * take all info from function parameters
  470. * no global variables needed
  471. *
  472. * NOTE $glued_table should already have backticks around it
  473. * (get it from the database library, and it is done automatically)
  474. *
  475. * @param path, filename, filetype,
  476. $glued_table, default_visibility
  477. * @action Adds an entry to the document table with the default settings.
  478. * @author Olivier Cauberghe <olivier.cauberghe@ugent.be>
  479. * @author Roan Embrechts
  480. * @version 1.2
  481. */
  482. function set_default_settings($upload_path, $filename, $filetype = 'file', $glued_table, $default_visibility = 'v') {
  483. if (!$default_visibility) $default_visibility = 'v';
  484. // Make sure path is not wrongly formed
  485. $upload_path = !empty($upload_path) ? "/$upload_path" : '';
  486. $endchar = substr($filename, strlen($filename) - 1, 1);
  487. if ($endchar == "\\" || $endchar == '/') {
  488. $filename = substr($filename, 0, strlen($filename) - 1);
  489. }
  490. $full_file_name = $upload_path.'/'.$filename;
  491. //$upload_path = str_replace("//", '/', $upload_path);
  492. $full_file_name = str_replace("//", '/', $full_file_name);
  493. $sql_query = "SELECT count(*) as number_existing FROM $glued_table WHERE path='$full_file_name'";
  494. $sql_result = Database::query($sql_query);
  495. $result = Database::fetch_array($sql_result);
  496. // Determine which query to execute
  497. if ($result['number_existing'] > 0) {
  498. // Entry exists, update
  499. $query = "UPDATE $glued_table SET path='$full_file_name',visibility='$default_visibility', filetype='$filetype' WHERE path='$full_file_name'";
  500. } else {
  501. // No entry exists, create new one
  502. $query = "INSERT INTO $glued_table (path,visibility,filetype) VALUES('$full_file_name','$default_visibility','$filetype')";
  503. }
  504. Database::query($query);
  505. }
  506. /**
  507. * Like in Java, creates the directory named by this abstract pathname,
  508. * including any necessary but nonexistent parent directories.
  509. *
  510. * @author Hugues Peeters <peeters@ipm.ucl.ac.be>
  511. * @author Christophe Gesche <gesche@ipm.ucl.ac.be>
  512. *
  513. * @param string $path - path to create
  514. * @param string $mode - directory permission (default is '770')
  515. *
  516. * @return boolean TRUE if succeeds FALSE otherwise
  517. */
  518. function mkdirs($path, $mode = '0770') {
  519. if (file_exists($path)) {
  520. return false;
  521. } else {
  522. FileManager :: mkdirs(dirname($path), $mode);
  523. //mkdir($path, $mode);
  524. return true;
  525. }
  526. }
  527. } //end class FileManager
  528. /* DEPRECATED FUNCTIONS */
  529. /**
  530. * @deprecated 06-FEB-2010. The function mkdir() is able to create directories recursively.
  531. * @link http://php.net/manual/en/function.mkdir.php
  532. *
  533. * to create missing directory in a gived path
  534. *
  535. * @returns a resource identifier or FALSE if the query was not executed correctly.
  536. * @author KilerCris@Mail.com original function from php manual
  537. * @author Christophe Gesch� gesche@ipm.ucl.ac.be Claroline Team
  538. * @since 28-Aug-2001 09:12
  539. * @param sting $path wanted path
  540. * @param boolean $verbose fix if comments must be printed
  541. * @param string $mode fix if chmod is same of parent or default (Note: This misterious parameter is not used).
  542. * @global string $langCreatedIn string to say "create in"
  543. */
  544. function mkpath($path, $verbose = false, $mode = 'herit') {
  545. global $langCreatedIn, $_configuration;
  546. $path = str_replace('/', "\\", $path);
  547. $dirs = explode("\\", $path);
  548. $path = $dirs[0];
  549. if ($verbose) {
  550. echo '<ul>';
  551. }
  552. for ($i = 1; $i < sizeof($dirs); $i++) {
  553. $path .= '/'.$dirs[$i];
  554. if (ereg('^'.$path, $_configuration['root_sys']) && strlen($path) < strlen($_configuration['root_sys'])) {
  555. continue;
  556. }
  557. if (!is_dir($path)) {
  558. $ret = mkdir($path, api_get_permissions_for_new_directories());
  559. if ($ret) {
  560. if ($verbose) {
  561. echo '<li><strong>'.basename($path).'</strong><br />'.$langCreatedIn.'<br /><strong>'.realpath($path.'/..').'</strong></li>';
  562. }
  563. } else {
  564. if ($verbose) {
  565. echo '</ul>error : '.$path.' not created';
  566. }
  567. $ret = false;
  568. break;
  569. }
  570. }
  571. }
  572. if ($verbose) {
  573. echo '</ul>';
  574. }
  575. return $ret;
  576. }