fileManage.lib.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  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. * @package chamilo.library
  7. */
  8. /**
  9. * Update the file or directory path in the document db document table
  10. *
  11. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  12. * @param - action (string) - action type require : 'delete' or 'update'
  13. * @param - old_path (string) - old path info stored to change
  14. * @param - new_path (string) - new path info to substitute
  15. * @desc Update the file or directory path in the document db document table
  16. *
  17. */
  18. function update_db_info($action, $old_path, $new_path = '')
  19. {
  20. $dbTable = Database::get_course_table(TABLE_DOCUMENT);
  21. $course_id = api_get_course_int_id();
  22. switch ($action) {
  23. case 'delete':
  24. $old_path = Database::escape_string($old_path);
  25. $query = "DELETE FROM $dbTable
  26. WHERE
  27. c_id = $course_id AND
  28. (
  29. path LIKE BINARY '".$old_path."' OR
  30. path LIKE BINARY '".$old_path."/%'
  31. )";
  32. Database::query($query);
  33. break;
  34. case 'update':
  35. if ($new_path[0] == '.') $new_path = substr($new_path, 1);
  36. $new_path = str_replace('//', '/', $new_path);
  37. // Attempt to update - tested & working for root dir
  38. $new_path = Database::escape_string($new_path);
  39. $query = "UPDATE $dbTable SET
  40. path = CONCAT('".$new_path."', SUBSTRING(path, LENGTH('".$old_path."')+1) )
  41. WHERE c_id = $course_id AND (path LIKE BINARY '".$old_path."' OR path LIKE BINARY '".$old_path."/%')";
  42. Database::query($query);
  43. break;
  44. }
  45. }
  46. /**
  47. * Cheks a file or a directory actually exist at this location
  48. *
  49. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  50. * @param - file_path (string) - path of the presume existing file or dir
  51. * @return - boolean TRUE if the file or the directory exists
  52. * boolean FALSE otherwise.
  53. */
  54. function check_name_exist($file_path) {
  55. clearstatcache();
  56. $save_dir = getcwd();
  57. if (!is_dir(dirname($file_path))) {
  58. return false;
  59. }
  60. chdir(dirname($file_path));
  61. $file_name = basename($file_path);
  62. if (file_exists($file_name)) {
  63. chdir($save_dir);
  64. return true;
  65. } else {
  66. chdir($save_dir);
  67. return false;
  68. }
  69. }
  70. /**
  71. * Deletes a file or a directory
  72. *
  73. * @author - Hugues Peeters
  74. * @param $file (String) - the path of file or directory to delete
  75. * @return boolean - true if the delete succeed, false otherwise.
  76. * @see - delete() uses check_name_exist() and removeDir() functions
  77. */
  78. function my_delete($file)
  79. {
  80. if (check_name_exist($file)) {
  81. if (is_file($file)) { // FILE CASE
  82. unlink($file);
  83. return true;
  84. } elseif (is_dir($file)) { // DIRECTORY CASE
  85. removeDir($file);
  86. return true;
  87. }
  88. } else {
  89. return false; // no file or directory to delete
  90. }
  91. }
  92. /**
  93. * Removes a directory recursively
  94. *
  95. * @returns true if OK, otherwise false
  96. *
  97. * @author Amary <MasterNES@aol.com> (from Nexen.net)
  98. * @author Olivier Brouckaert <oli.brouckaert@skynet.be>
  99. *
  100. * @param string $dir directory to remove
  101. */
  102. function removeDir($dir)
  103. {
  104. if (!@$opendir = opendir($dir)) {
  105. return false;
  106. }
  107. while ($readdir = readdir($opendir)) {
  108. if ($readdir != '..' && $readdir != '.') {
  109. if (is_file($dir.'/'.$readdir)) {
  110. if (!@unlink($dir.'/'.$readdir)) {
  111. return false;
  112. }
  113. } elseif (is_dir($dir.'/'.$readdir)) {
  114. if (!removeDir($dir.'/'.$readdir)) {
  115. return false;
  116. }
  117. }
  118. }
  119. }
  120. closedir($opendir);
  121. if (!@rmdir($dir)) {
  122. return false;
  123. }
  124. return true;
  125. }
  126. /**
  127. * Return true if folder is empty
  128. * @author : hubert.borderiou@grenet.fr
  129. * @param string $in_folder : folder path on disk
  130. * @return 1 if folder is empty, 0 otherwise
  131. */
  132. function folder_is_empty($in_folder)
  133. {
  134. $folder_is_empty = 0;
  135. if (is_dir($in_folder)) {
  136. $tab_folder_content = scandir($in_folder);
  137. if ((count($tab_folder_content) == 2 &&
  138. in_array(".", $tab_folder_content) &&
  139. in_array("..", $tab_folder_content)
  140. ) ||
  141. (count($tab_folder_content) < 2)
  142. ) {
  143. $folder_is_empty = 1;
  144. }
  145. }
  146. return $folder_is_empty;
  147. }
  148. /**
  149. * Renames a file or a directory
  150. *
  151. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  152. * @param - $file_path (string) - complete path of the file or the directory
  153. * @param - $new_file_name (string) - new name for the file or the directory
  154. * @return - boolean - true if succeed
  155. * - boolean - false otherwise
  156. * @see - rename() uses the check_name_exist() and php2phps() functions
  157. */
  158. function my_rename($file_path, $new_file_name) {
  159. $save_dir = getcwd();
  160. $path = dirname($file_path);
  161. $old_file_name = basename($file_path);
  162. $new_file_name = api_replace_dangerous_char($new_file_name);
  163. // If no extension, take the old one
  164. if ((strpos($new_file_name, '.') === false) && ($dotpos = strrpos($old_file_name, '.'))) {
  165. $new_file_name .= substr($old_file_name, $dotpos);
  166. }
  167. // Note: still possible: 'xx.yy' -rename-> '.yy' -rename-> 'zz'
  168. // This is useful for folder names, where otherwise '.' would be sticky
  169. // Extension PHP is not allowed, change to PHPS
  170. $new_file_name = php2phps($new_file_name);
  171. if ($new_file_name == $old_file_name) {
  172. return $old_file_name;
  173. }
  174. if (strtolower($new_file_name) != strtolower($old_file_name) && check_name_exist($path.'/'.$new_file_name)) {
  175. return false;
  176. }
  177. // On a Windows server, it would be better not to do the above check
  178. // because it succeeds for some new names resembling the old name.
  179. // But on Unix/Linux the check must be done because rename overwrites.
  180. chdir($path);
  181. $res = rename($old_file_name, $new_file_name) ? $new_file_name : false;
  182. chdir($save_dir);
  183. return $res;
  184. }
  185. /**
  186. * Moves a file or a directory to an other area
  187. *
  188. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  189. * @param - $source (String) - the path of file or directory to move
  190. * @param - $target (String) - the path of the new area
  191. * @return - bolean - true if the move succeed
  192. * bolean - false otherwise.
  193. * @see - move() uses check_name_exist() and copyDirTo() functions
  194. */
  195. function move($source, $target)
  196. {
  197. if (check_name_exist($source)) {
  198. $file_name = basename($source);
  199. /* File case */
  200. if (is_file($source)) {
  201. copy($source , $target.'/'.$file_name);
  202. unlink($source);
  203. return true;
  204. } elseif (is_dir($source)) {
  205. /* Directory */
  206. copyDirTo($source, $target);
  207. return true;
  208. }
  209. } else {
  210. return false;
  211. }
  212. }
  213. /**
  214. * Moves a directory and its content to an other area
  215. *
  216. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  217. * @param - $orig_dir_path (string) - the path of the directory to move
  218. * @param - $destination (string) - the path of the new area
  219. * @return - no return
  220. */
  221. function copyDirTo($orig_dir_path, $destination, $move = true)
  222. {
  223. if ($orig_dir_path == $destination) {
  224. return false;
  225. }
  226. $save_dir = getcwd();
  227. // Extract directory name - create it at destination - update destination trail
  228. $dir_name = basename($orig_dir_path);
  229. $dir_to_copy = array();
  230. if (is_dir($orig_dir_path)) {
  231. if (!is_dir($destination.'/'.$dir_name)) {
  232. mkdir(
  233. $destination.'/'.$dir_name,
  234. api_get_permissions_for_new_directories()
  235. );
  236. }
  237. $destination_trail = $destination.'/'.$dir_name;
  238. if (is_dir($destination)) {
  239. chdir($orig_dir_path) ;
  240. $handle = opendir($orig_dir_path);
  241. while ($element = readdir($handle)) {
  242. if ($element == '.' || $element == '..') {
  243. continue; // Skip the current and parent directories
  244. } elseif (is_file($element)) {
  245. copy($element, $destination_trail.'/'.$element);
  246. if ($move) {
  247. unlink($element) ;
  248. }
  249. } elseif (is_dir($element)) {
  250. $dir_to_copy[] = $orig_dir_path.'/'.$element;
  251. }
  252. }
  253. closedir($handle) ;
  254. if (sizeof($dir_to_copy) > 0) {
  255. foreach ($dir_to_copy as $this_dir) {
  256. copyDirTo($this_dir, $destination_trail, $move); // Recursivity
  257. }
  258. }
  259. if ($move) {
  260. rmdir($orig_dir_path) ;
  261. }
  262. chdir($save_dir);
  263. }
  264. }
  265. }
  266. /**
  267. * Extracting extention of a filename
  268. *
  269. * @returns array
  270. * @param string $filename filename
  271. */
  272. function getextension($filename) {
  273. $bouts = explode('.', $filename);
  274. return array(array_pop($bouts), implode('.', $bouts));
  275. }
  276. /**
  277. * Calculation size of a directory
  278. *
  279. * @returns integer size
  280. * @param string $path path to size
  281. * @param boolean $recursive if true , include subdir in total
  282. */
  283. function dirsize($root, $recursive = true) {
  284. $dir = @opendir($root);
  285. $size = 0;
  286. while ($file = @readdir($dir)) {
  287. if (!in_array($file, array('.', '..'))) {
  288. if (is_dir($root.'/'.$file)) {
  289. $size += $recursive ? dirsize($root.'/'.$file) : 0;
  290. } else {
  291. $size += @filesize($root.'/'.$file);
  292. }
  293. }
  294. }
  295. @closedir($dir);
  296. return $size;
  297. }
  298. /* CLASS FileManager */
  299. /**
  300. This class contains functions that you can access statically.
  301. FileManager::list_all_directories($path)
  302. FileManager::list_all_files($dir_array)
  303. FileManager::compat_load_file($file_name)
  304. FileManager::set_default_settings($upload_path, $filename, $filetype="file", $glued_table, $default_visibility='v')
  305. @author Roan Embrechts
  306. @version 1.1, July 2004
  307. * @package chamilo.library
  308. */
  309. class FileManager
  310. {
  311. /**
  312. Returns a list of all directories, except the base dir,
  313. of the current course. This function uses recursion.
  314. Convention: the parameter $path does not end with a slash.
  315. @author Roan Embrechts
  316. @version 1.0.1
  317. */
  318. function list_all_directories($path) {
  319. $result_array = array();
  320. if (is_dir($path)) {
  321. $save_dir = getcwd();
  322. chdir($path);
  323. $handle = opendir($path);
  324. while ($element = readdir($handle)) {
  325. if ($element == '.' || $element == '..') continue;
  326. // Skip the current and parent directories
  327. if (is_dir($element)) {
  328. $dir_array[] = $path.'/'.$element;
  329. }
  330. }
  331. closedir($handle);
  332. // Recursive operation if subdirectories exist
  333. $dir_number = sizeof($dir_array);
  334. if ($dir_number > 0) {
  335. for ($i = 0 ; $i < $dir_number ; $i++) {
  336. $sub_dir_array = FileManager::list_all_directories($dir_array[$i]); // Function recursivity
  337. if (is_array($dir_array) && is_array($sub_dir_array)) {
  338. $dir_array = array_merge($dir_array, $sub_dir_array); // Data merge
  339. }
  340. }
  341. }
  342. $result_array = $dir_array;
  343. chdir($save_dir) ;
  344. }
  345. return $result_array ;
  346. }
  347. /**
  348. This function receives a list of directories.
  349. It returns a list of all files in these directories
  350. @author Roan Embrechts
  351. @version 1.0
  352. */
  353. function list_all_files($dir_array) {
  354. $element_array = array();
  355. if (is_dir($dir_array)) {
  356. $save_dir = getcwd();
  357. foreach ($dir_array as $directory) {
  358. chdir($directory);
  359. $handle = opendir($directory);
  360. while ($element = readdir($handle)) {
  361. if ($element == '.' || $element == '..' || $element == '.htaccess') continue; // Skip the current and parent directories
  362. if (!is_dir($element)) {
  363. $element_array[] = $directory.'/'.$element;
  364. }
  365. }
  366. closedir($handle);
  367. chdir('..');
  368. chdir($save_dir);
  369. }
  370. }
  371. return $element_array;
  372. }
  373. /**
  374. Loads contents of file $filename into memory and returns them as a string.
  375. Function kept for compatibility with older PHP versions.
  376. Function is binary safe (is needed on Windows)
  377. */
  378. function compat_load_file($file_name) {
  379. $buffer = '';
  380. if (file_exists($file_name)) {
  381. $fp = fopen($file_name, 'rb');
  382. $buffer = fread ($fp, filesize($file_name));
  383. fclose ($fp);
  384. }
  385. return $buffer;
  386. }
  387. /**
  388. * Adds file/folder to document table in database
  389. * improvement from set_default_settings (see below):
  390. * take all info from function parameters
  391. * no global variables needed
  392. *
  393. * NOTE $glued_table should already have backticks around it
  394. * (get it from the database library, and it is done automatically)
  395. *
  396. * @param path, filename, filetype,
  397. $glued_table, default_visibility
  398. * action: Adds an entry to the document table with the default settings.
  399. * @author Olivier Cauberghe <olivier.cauberghe@ugent.be>
  400. * @author Roan Embrechts
  401. * @version 1.2
  402. */
  403. function set_default_settings($upload_path, $filename, $filetype = 'file', $glued_table, $default_visibility = 'v')
  404. {
  405. if (!$default_visibility) $default_visibility = 'v';
  406. // Make sure path is not wrongly formed
  407. $upload_path = !empty($upload_path) ? "/$upload_path" : '';
  408. $endchar = substr($filename, strlen($filename) - 1, 1);
  409. if ($endchar == "\\" || $endchar == '/') {
  410. $filename = substr($filename, 0, strlen($filename) - 1);
  411. }
  412. $full_file_name = $upload_path.'/'.$filename;
  413. //$upload_path = str_replace("//", '/', $upload_path);
  414. $full_file_name = str_replace("//", '/', $full_file_name);
  415. $sql_query = "SELECT count(*) as number_existing FROM $glued_table WHERE path='$full_file_name'";
  416. $sql_result = Database::query($sql_query);
  417. $result = Database::fetch_array($sql_result);
  418. // Determine which query to execute
  419. if ($result['number_existing'] > 0) {
  420. // Entry exists, update
  421. $query = "UPDATE $glued_table SET path='$full_file_name',visibility='$default_visibility', filetype='$filetype'
  422. WHERE path='$full_file_name'";
  423. } else {
  424. // No entry exists, create new one
  425. $query = "INSERT INTO $glued_table (path,visibility,filetype)
  426. VALUES ('$full_file_name','$default_visibility','$filetype')";
  427. }
  428. Database::query($query);
  429. }
  430. } //end class FileManager
  431. /* DEPRECATED FUNCTIONS */
  432. /**
  433. * Like in Java, creates the directory named by this abstract pathname,
  434. * including any necessary but nonexistent parent directories.
  435. *
  436. * @author Hugues Peeters <peeters@ipm.ucl.ac.be>
  437. * @author Christophe Gesche <gesche@ipm.ucl.ac.be>
  438. *
  439. * @param string $path - path to create
  440. * @param string $mode - directory permission (default is '770')
  441. *
  442. * @return boolean TRUE if succeeds FALSE otherwise
  443. */
  444. function mkdirs($path, $mode = '0770') {
  445. if (file_exists($path)) {
  446. return false;
  447. } else {
  448. FileManager :: mkdirs(dirname($path), $mode);
  449. //mkdir($path, $mode);
  450. return true;
  451. }
  452. }