fileManager.lib.php 79 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. This class contains functions that you can access statically.
  5. FileManager::list_all_directories($path)
  6. FileManager::list_all_files($dir_array)
  7. FileManager::compat_load_file($file_name)
  8. FileManager::set_default_settings($upload_path, $filename, $filetype="file", $glued_table, $default_visibility='v')
  9. @author Roan Embrechts
  10. @version 1.1, July 2004
  11. * @package chamilo.library
  12. */
  13. use Symfony\Component\Finder\Finder;
  14. use Symfony\Component\Filesystem\Filesystem;
  15. use Chamilo\CoreBundle\Entity\Course;
  16. class FileManager
  17. {
  18. /**
  19. * Update the file or directory path in the document db document table
  20. *
  21. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  22. * @param - action (string) - action type require : 'delete' or 'update'
  23. * @param - old_path (string) - old path info stored to change
  24. * @param - new_path (string) - new path info to substitute
  25. * @desc Update the file or directory path in the document db document table
  26. *
  27. */
  28. static function update_db_info($action, $old_path, $new_path = '')
  29. {
  30. $dbTable = Database::get_course_table(TABLE_DOCUMENT);
  31. $course_id = api_get_course_int_id();
  32. /* DELETE */
  33. if ($action == 'delete') {
  34. $old_path = Database::escape_string($old_path);
  35. $to_delete = "WHERE c_id = $course_id AND path LIKE BINARY '".$old_path."' OR path LIKE BINARY '".$old_path."/%'";
  36. $query = "DELETE FROM $dbTable ".$to_delete;
  37. $result = Database::query("SELECT id FROM $dbTable ".$to_delete);
  38. if (Database::num_rows($result)) {
  39. /*require_once api_get_path(INCLUDE_PATH).'../metadata/md_funcs.php';
  40. $mdStore = new mdstore(true); // create if needed
  41. $md_type = (substr($dbTable, -13) == 'scormdocument') ? 'Scorm' : 'Document';
  42. while ($row = Database::fetch_array($result)) {
  43. $eid = $md_type.'.'.$row['id'];
  44. $mdStore->mds_delete($eid);
  45. $mdStore->mds_delete_offspring($eid);
  46. }*/
  47. }
  48. }
  49. /* UPDATE */
  50. if ($action == 'update') {
  51. if ($new_path[0] == '.') {
  52. $new_path = substr($new_path, 1);
  53. }
  54. $new_path = str_replace('//', '/', $new_path);
  55. // Attempt to update - tested & working for root dir
  56. $new_path = Database::escape_string($new_path);
  57. $query = "UPDATE $dbTable
  58. SET path = CONCAT('".$new_path."', SUBSTRING(path, LENGTH('".$old_path."')+1) )
  59. WHERE c_id = $course_id AND path LIKE BINARY '".$old_path."' OR path LIKE BINARY '".$old_path."/%'";
  60. }
  61. Database::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. static function check_name_exist($file_path)
  72. {
  73. clearstatcache();
  74. $save_dir = getcwd();
  75. if (!is_dir(dirname($file_path))) {
  76. return false;
  77. }
  78. chdir(dirname($file_path));
  79. $file_name = basename($file_path);
  80. if (file_exists($file_name)) {
  81. chdir($save_dir);
  82. return true;
  83. } else {
  84. chdir($save_dir);
  85. return false;
  86. }
  87. }
  88. /**
  89. * Deletes a file or a directory
  90. *
  91. * @author - Hugues Peeters
  92. * @param - $file (String) - the path of file or directory to delete
  93. * @return - bolean - true if the delete succeed
  94. * bolean - false otherwise.
  95. * @see - delete() uses check_name_exist() and removeDir() functions
  96. */
  97. static function my_delete($file)
  98. {
  99. if (self::check_name_exist($file)) {
  100. if (is_file($file)) { // FILE CASE
  101. unlink($file);
  102. return true;
  103. } elseif (is_dir($file)) { // DIRECTORY CASE
  104. self::removeDir($file);
  105. return true;
  106. }
  107. } else {
  108. return false; // no file or directory to delete
  109. }
  110. }
  111. /**
  112. * Removes a directory recursively
  113. *
  114. * @returns true if OK, otherwise false
  115. *
  116. * @author Amary <MasterNES@aol.com> (from Nexen.net)
  117. * @author Olivier Brouckaert <oli.brouckaert@skynet.be>
  118. *
  119. * @param string $dir directory to remove
  120. */
  121. static function removeDir($dir)
  122. {
  123. if (!@$opendir = opendir($dir)) {
  124. return false;
  125. }
  126. while ($readdir = readdir($opendir)) {
  127. if ($readdir != '..' && $readdir != '.') {
  128. if (is_file($dir.'/'.$readdir)) {
  129. if (!@unlink($dir.'/'.$readdir)) {
  130. return false;
  131. }
  132. } elseif (is_dir($dir.'/'.$readdir)) {
  133. if (!self::removeDir($dir.'/'.$readdir)) {
  134. return false;
  135. }
  136. }
  137. }
  138. }
  139. closedir($opendir);
  140. if (!@rmdir($dir)) {
  141. return false;
  142. }
  143. return true;
  144. }
  145. /**
  146. * Return true if folder is empty
  147. * @author : hubert.borderiou@grenet.fr
  148. * @param string $in_folder : folder path on disk
  149. * @return 1 if folder is empty, 0 otherwise
  150. */
  151. static function folder_is_empty($in_folder)
  152. {
  153. $tab_folder_content = scandir($in_folder);
  154. $folder_is_empty = 0;
  155. if ((count($tab_folder_content) == 2 && in_array(".", $tab_folder_content) && in_array(
  156. "..",
  157. $tab_folder_content
  158. )) || (count($tab_folder_content) < 2)
  159. ) {
  160. $folder_is_empty = 1;
  161. }
  162. return $folder_is_empty;
  163. }
  164. /**
  165. * Renames a file or a directory
  166. *
  167. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  168. * @param - $file_path (string) - complete path of the file or the directory
  169. * @param - $new_file_name (string) - new name for the file or the directory
  170. * @return - boolean - true if succeed
  171. * - boolean - false otherwise
  172. * @see - rename() uses the check_name_exist() and php2phps() functions
  173. */
  174. static function my_rename($file_path, $new_file_name)
  175. {
  176. $save_dir = getcwd();
  177. $path = dirname($file_path);
  178. $old_file_name = basename($file_path);
  179. $new_file_name = api_replace_dangerous_char($new_file_name);
  180. // If no extension, take the old one
  181. if ((strpos($new_file_name, '.') === false) && ($dotpos = strrpos($old_file_name, '.'))) {
  182. $new_file_name .= substr($old_file_name, $dotpos);
  183. }
  184. // Note: still possible: 'xx.yy' -rename-> '.yy' -rename-> 'zz'
  185. // This is useful for folder names, where otherwise '.' would be sticky
  186. // Extension PHP is not allowed, change to PHPS
  187. $new_file_name = self::php2phps($new_file_name);
  188. if ($new_file_name == $old_file_name) {
  189. return $old_file_name;
  190. }
  191. if (strtolower($new_file_name) != strtolower($old_file_name) && self::check_name_exist(
  192. $path.'/'.$new_file_name
  193. )
  194. ) {
  195. return false;
  196. }
  197. // On a Windows server, it would be better not to do the above check
  198. // because it succeeds for some new names resembling the old name.
  199. // But on Unix/Linux the check must be done because rename overwrites.
  200. chdir($path);
  201. $res = rename($old_file_name, $new_file_name) ? $new_file_name : false;
  202. chdir($save_dir);
  203. return $res;
  204. }
  205. /**
  206. * Moves a file or a directory to an other area
  207. *
  208. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  209. * @param - $source (String) - the path of file or directory to move
  210. * @param - $target (String) - the path of the new area
  211. * @return - bolean - true if the move succeed
  212. * bolean - false otherwise.
  213. * @see - move() uses check_name_exist() and copyDirTo() functions
  214. */
  215. static function move($source, $target)
  216. {
  217. if (self::check_name_exist($source)) {
  218. $file_name = basename($source);
  219. if (self::check_name_exist($target.'/'.$file_name)) {
  220. return false;
  221. } else {
  222. /* File case */
  223. if (is_file($source)) {
  224. copy($source, $target.'/'.$file_name);
  225. unlink($source);
  226. return true;
  227. } elseif (is_dir($source)) {
  228. /* Directory case */
  229. // Check to not copy the directory inside itself
  230. if (ereg('^'.$source.'/', $target.'/')) { // TODO: ereg() function is deprecated in PHP 5.3
  231. return false;
  232. } else {
  233. self::copyDirTo($source, $target);
  234. return true;
  235. }
  236. }
  237. }
  238. } else {
  239. return false;
  240. }
  241. }
  242. /**
  243. * Moves a directory and its content to an other area
  244. *
  245. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  246. * @param - $orig_dir_path (string) - the path of the directory to move
  247. * @param - $destination (string) - the path of the new area
  248. * @return - no return
  249. */
  250. static function copyDirTo($orig_dir_path, $destination, $move = true)
  251. {
  252. $save_dir = getcwd();
  253. // Extract directory name - create it at destination - update destination trail
  254. $dir_name = basename($orig_dir_path);
  255. if (is_dir($orig_dir_path)) {
  256. mkdir($destination.'/'.$dir_name, api_get_permissions_for_new_directories());
  257. $destination_trail = $destination.'/'.$dir_name;
  258. if (is_dir($destination)) {
  259. chdir($orig_dir_path);
  260. $handle = opendir($orig_dir_path);
  261. while ($element = readdir($handle)) {
  262. if ($element == '.' || $element == '..') {
  263. continue; // Skip the current and parent directories
  264. } elseif (is_file($element)) {
  265. copy($element, $destination_trail.'/'.$element);
  266. if ($move) {
  267. unlink($element);
  268. }
  269. } elseif (is_dir($element)) {
  270. $dir_to_copy[] = $orig_dir_path.'/'.$element;
  271. }
  272. }
  273. closedir($handle);
  274. if (sizeof($dir_to_copy) > 0) {
  275. foreach ($dir_to_copy as $this_dir) {
  276. self::copyDirTo($this_dir, $destination_trail, $move); // Recursivity
  277. }
  278. }
  279. if ($move) {
  280. rmdir($orig_dir_path);
  281. }
  282. chdir($save_dir);
  283. }
  284. }
  285. }
  286. /* NOTE: These functions batch is used to automatically build HTML forms
  287. * with a list of the directories contained on the course Directory.
  288. *
  289. * From a thechnical point of view, form_dir_lists calls sort_dir wich calls index_dir
  290. */
  291. /**
  292. * Gets all the directories and subdirectories
  293. * contented in a given directory
  294. *
  295. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  296. * @param - path (string) - directory path of the one to index
  297. * @return - an array containing the path of all the subdirectories
  298. */
  299. static function index_dir($path)
  300. {
  301. $dir_array = array();
  302. $save_dir = getcwd();
  303. if (is_dir($path)) {
  304. chdir($path);
  305. $handle = opendir($path);
  306. // Reads directory content end record subdirectoies names in $dir_array
  307. if ($handle !== false) {
  308. while ($element = readdir($handle)) {
  309. if ($element == '.' || $element == '..') {
  310. continue;
  311. } // Skip the current and parent directories
  312. if (is_dir($element)) {
  313. $dir_array[] = $path.'/'.$element;
  314. }
  315. }
  316. closedir($handle);
  317. }
  318. // Recursive operation if subdirectories exist
  319. $dir_number = sizeof($dir_array);
  320. if ($dir_number > 0) {
  321. for ($i = 0; $i < $dir_number; $i++) {
  322. $sub_dir_array = self::index_dir($dir_array[$i]); // Function recursivity
  323. $dir_array = array_merge((array)$dir_array, (array)$sub_dir_array); // Data merge
  324. }
  325. }
  326. }
  327. chdir($save_dir);
  328. return $dir_array;
  329. }
  330. /**
  331. * Indexes all the directories and subdirectories
  332. * contented in a given directory, and sort them alphabetically
  333. *
  334. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  335. * @param - path (string) - directory path of the one to index
  336. * @return - an array containing the path of all the subdirectories sorted
  337. * false, if there is no directory
  338. * @see - index_and_sort_dir uses the index_dir() function
  339. */
  340. static function index_and_sort_dir($path)
  341. {
  342. $dir_list = self::index_dir($path);
  343. if ($dir_list) {
  344. natsort($dir_list);
  345. return $dir_list;
  346. }
  347. return false;
  348. }
  349. /**
  350. * Extracting extention of a filename
  351. *
  352. * @returns array
  353. * @param string $filename filename
  354. */
  355. static function getextension($filename)
  356. {
  357. $bouts = explode('.', $filename);
  358. return array(array_pop($bouts), implode('.', $bouts));
  359. }
  360. /**
  361. * Calculation size of a directory
  362. *
  363. * @returns integer size
  364. * @param string $path path to size
  365. * @param boolean $recursive if true , include subdir in total
  366. */
  367. static function dirsize($root, $recursive = true)
  368. {
  369. $dir = @opendir($root);
  370. $size = 0;
  371. while ($file = @readdir($dir)) {
  372. if (!in_array($file, array('.', '..'))) {
  373. if (is_dir($root.'/'.$file)) {
  374. $size += $recursive ? dirsize($root.'/'.$file) : 0;
  375. } else {
  376. $size += @filesize($root.'/'.$file);
  377. }
  378. }
  379. }
  380. @closedir($dir);
  381. return $size;
  382. }
  383. /**
  384. Returns a list of all directories, except the base dir,
  385. of the current course. This function uses recursion.
  386. Convention: the parameter $path does not end with a slash.
  387. @author Roan Embrechts
  388. @version 1.0.1
  389. */
  390. static function list_all_directories($path)
  391. {
  392. $result_array = array();
  393. if (is_dir($path)) {
  394. $save_dir = getcwd();
  395. chdir($path);
  396. $handle = opendir($path);
  397. while ($element = readdir($handle)) {
  398. if ($element == '.' || $element == '..') {
  399. continue;
  400. } // Skip the current and parent directories
  401. if (is_dir($element)) {
  402. $dir_array[] = $path.'/'.$element;
  403. }
  404. }
  405. closedir($handle);
  406. // Recursive operation if subdirectories exist
  407. $dir_number = sizeof($dir_array);
  408. if ($dir_number > 0) {
  409. for ($i = 0; $i < $dir_number; $i++) {
  410. $sub_dir_array = self::list_all_directories($dir_array[$i]); // Function recursivity
  411. if (is_array($dir_array) && is_array($sub_dir_array)) {
  412. $dir_array = array_merge($dir_array, $sub_dir_array); // Data merge
  413. }
  414. }
  415. }
  416. $result_array = $dir_array;
  417. chdir($save_dir);
  418. }
  419. return $result_array;
  420. }
  421. /**
  422. This function receives a list of directories.
  423. It returns a list of all files in these directories
  424. @author Roan Embrechts
  425. @version 1.0
  426. */
  427. function list_all_files($dir_array)
  428. {
  429. $element_array = array();
  430. if (is_dir($dir_array)) {
  431. $save_dir = getcwd();
  432. foreach ($dir_array as $directory) {
  433. chdir($directory);
  434. $handle = opendir($directory);
  435. while ($element = readdir($handle)) {
  436. if ($element == '.' || $element == '..' || $element == '.htaccess') {
  437. continue;
  438. } // Skip the current and parent directories
  439. if (!is_dir($element)) {
  440. $element_array[] = $directory.'/'.$element;
  441. }
  442. }
  443. closedir($handle);
  444. chdir('..');
  445. chdir($save_dir);
  446. }
  447. }
  448. return $element_array;
  449. }
  450. /**
  451. Loads contents of file $filename into memory and returns them as a string.
  452. Function kept for compatibility with older PHP versions.
  453. Function is binary safe (is needed on Windows)
  454. */
  455. static function compat_load_file($file_name)
  456. {
  457. $buffer = '';
  458. if (file_exists($file_name)) {
  459. $fp = fopen($file_name, 'rb');
  460. $buffer = fread($fp, filesize($file_name));
  461. fclose($fp);
  462. }
  463. return $buffer;
  464. }
  465. static function choose_image($file_name)
  466. {
  467. static $type, $image;
  468. /* TABLES INITIALISATION */
  469. if (!$type || !$image) {
  470. $type['word'] = array('doc', 'dot', 'rtf', 'mcw', 'wps', 'psw', 'docm', 'docx', 'dotm', 'dotx');
  471. $type['web'] = array('htm', 'html', 'htx', 'xml', 'xsl', 'php', 'xhtml');
  472. $type['image'] = array('gif', 'jpg', 'png', 'bmp', 'jpeg', 'tif', 'tiff');
  473. $type['image_vect'] = array('svg', 'svgz');
  474. $type['audio'] = array('wav', 'mid', 'mp2', 'mp3', 'midi', 'sib', 'amr', 'kar', 'oga', 'au', 'wma');
  475. $type['video'] = array(
  476. 'mp4',
  477. 'mov',
  478. 'rm',
  479. 'pls',
  480. 'mpg',
  481. 'mpeg',
  482. 'm2v',
  483. 'm4v',
  484. 'flv',
  485. 'f4v',
  486. 'avi',
  487. 'wmv',
  488. 'asf',
  489. '3gp',
  490. 'ogv',
  491. 'ogg',
  492. 'ogx',
  493. 'webm'
  494. );
  495. $type['excel'] = array('xls', 'xlt', 'xls', 'xlt', 'pxl', 'xlsx', 'xlsm', 'xlam', 'xlsb', 'xltm', 'xltx');
  496. $type['compressed'] = array('zip', 'tar', 'rar', 'gz');
  497. $type['code'] = array('js', 'cpp', 'c', 'java', 'phps', 'jsp', 'asp', 'aspx', 'cfm');
  498. $type['acrobat'] = array('pdf');
  499. $type['powerpoint'] = array('ppt', 'pps', 'pptm', 'pptx', 'potm', 'potx', 'ppam', 'ppsm', 'ppsx');
  500. $type['flash'] = array('fla', 'swf');
  501. $type['text'] = array('txt', 'log');
  502. $type['oo_writer'] = array('odt', 'ott', 'sxw', 'stw');
  503. $type['oo_calc'] = array('ods', 'ots', 'sxc', 'stc');
  504. $type['oo_impress'] = array('odp', 'otp', 'sxi', 'sti');
  505. $type['oo_draw'] = array('odg', 'otg', 'sxd', 'std');
  506. $type['epub'] = array('epub');
  507. $type['java'] = array('class', 'jar');
  508. $type['freemind'] = array('mm');
  509. $image['word'] = 'word.gif';
  510. $image['web'] = 'file_html.gif';
  511. $image['image'] = 'file_image.gif';
  512. $image['image_vect'] = 'file_svg.png';
  513. $image['audio'] = 'file_sound.gif';
  514. $image['video'] = 'film.gif';
  515. $image['excel'] = 'excel.gif';
  516. $image['compressed'] = 'file_zip.gif';
  517. $image['code'] = 'icons/22/mime_code.png';
  518. $image['acrobat'] = 'file_pdf.gif';
  519. $image['powerpoint'] = 'powerpoint.gif';
  520. $image['flash'] = 'file_flash.gif';
  521. $image['text'] = 'icons/22/mime_text.png';
  522. $image['oo_writer'] = 'file_oo_writer.gif';
  523. $image['oo_calc'] = 'file_oo_calc.gif';
  524. $image['oo_impress'] = 'file_oo_impress.gif';
  525. $image['oo_draw'] = 'file_oo_draw.gif';
  526. $image['epub'] = 'file_epub.gif';
  527. $image['java'] = 'file_java.png';
  528. $image['freemind'] = 'file_freemind.png';
  529. }
  530. /* FUNCTION CORE */
  531. $extension = array();
  532. if (!is_array($file_name)) {
  533. if (preg_match('/\.([[:alnum:]]+)(\?|$)/', $file_name, $extension)) {
  534. $extension[1] = strtolower($extension[1]);
  535. foreach ($type as $generic_type => $extension_list) {
  536. if (in_array($extension[1], $extension_list)) {
  537. return $image[$generic_type];
  538. }
  539. }
  540. }
  541. }
  542. return 'defaut.gif';
  543. }
  544. /**
  545. * Transform the file path to a URL.
  546. *
  547. * @param - $file_path (string) - Relative local path of the file on the hard disk
  548. * @return - Relative url
  549. */
  550. static function format_url($file_path)
  551. {
  552. $path_component = explode('/', $file_path);
  553. $path_component = array_map('rawurlencode', $path_component);
  554. return implode('/', $path_component);
  555. }
  556. /**
  557. * Calculates the total size of a directory by adding the sizes (that
  558. * are stored in the database) of all files & folders in this directory.
  559. *
  560. * @param string $path
  561. * @param boolean $can_see_invisible
  562. * @return Total size
  563. */
  564. static function get_total_folder_size($path, $can_see_invisible = false)
  565. {
  566. $table_itemproperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
  567. $table_document = Database::get_course_table(TABLE_DOCUMENT);
  568. $tool_document = TOOL_DOCUMENT;
  569. $course_id = api_get_course_int_id();
  570. $session_id = api_get_session_id();
  571. $session_condition = api_get_session_condition($session_id, true, true, 'props.id_session');
  572. $visibility_rule = ' props.visibility '.($can_see_invisible ? '<> 2' : '= 1');
  573. $sql = "SELECT SUM(table1.size) FROM (
  574. SELECT size FROM $table_itemproperty AS props, $table_document AS docs
  575. WHERE docs.c_id = $course_id AND
  576. docs.id = props.ref AND
  577. docs.path LIKE '$path/%' AND
  578. props.c_id = $course_id AND
  579. props.tool = '$tool_document' AND
  580. $visibility_rule
  581. $session_condition
  582. GROUP BY ref
  583. ) as table1";
  584. $result = Database::query($sql);
  585. if ($result && Database::num_rows($result) != 0) {
  586. $row = Database::fetch_row($result);
  587. return $row[0] == null ? 0 : $row[0];
  588. } else {
  589. return 0;
  590. }
  591. }
  592. /**
  593. * Changes the file name extension from .php to .phps
  594. * Useful for securing a site.
  595. *
  596. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  597. * @param - file_name (string) name of a file
  598. *
  599. * @return string the filename phps'ized
  600. */
  601. static function php2phps($file_name)
  602. {
  603. return preg_replace('/\.(php.?|phtml.?)(\.){0,1}.*$/i', '.phps', $file_name);
  604. }
  605. /**
  606. * Renames .htaccess & .HTACCESS to htaccess.txt
  607. *
  608. * @param string $filename
  609. * @return string
  610. */
  611. static function htaccess2txt($filename)
  612. {
  613. return str_replace(array('.htaccess', '.HTACCESS'), array('htaccess.txt', 'htaccess.txt'), $filename);
  614. }
  615. /**
  616. * This function executes our safety precautions
  617. * more functions can be added
  618. *
  619. * @param string $filename
  620. * @return string
  621. * @see FileManager::php2phps()
  622. * @see htaccess2txt()
  623. */
  624. static function disable_dangerous_file($filename)
  625. {
  626. return self::htaccess2txt(self::php2phps($filename));
  627. }
  628. /**
  629. * This function generates a unique name for a file on a given location. Filenames are changed to name_#.ext
  630. *
  631. * @param string $path
  632. * @param string $name
  633. * @return new unique name
  634. */
  635. static function unique_name($path, $name)
  636. {
  637. $ext = substr(strrchr($name, '.'), 0);
  638. $name_no_ext = substr($name, 0, strlen($name) - strlen(strstr($name, $ext)));
  639. $n = 0;
  640. $unique = '';
  641. while (file_exists($path.$name_no_ext.$unique.$ext)) {
  642. $unique = '_'.++$n;
  643. }
  644. return $name_no_ext.$unique.$ext;
  645. }
  646. /**
  647. * Returns the name without extension, used for the title
  648. *
  649. * @param string $name
  650. * @return name without the extension
  651. */
  652. static function get_document_title($name)
  653. {
  654. // If they upload .htaccess...
  655. $name = self::disable_dangerous_file($name);
  656. $ext = substr(strrchr($name, '.'), 0);
  657. return addslashes(substr($name, 0, strlen($name) - strlen(strstr($name, $ext))));
  658. }
  659. /**
  660. * This function checks if the upload succeeded
  661. *
  662. * @param array $uploaded_file ($_FILES)
  663. * @param bool $show_output
  664. *
  665. * @return true if upload succeeded
  666. */
  667. static function process_uploaded_file($uploaded_file, $show_output = true)
  668. {
  669. // Checking the error code sent with the file upload.
  670. switch ($uploaded_file['error']) {
  671. case 1:
  672. // The uploaded file exceeds the upload_max_filesize directive in php.ini.
  673. if ($show_output) {
  674. Display::display_error_message(
  675. get_lang('UplExceedMaxServerUpload').ini_get('upload_max_filesize')
  676. );
  677. }
  678. return false;
  679. case 2:
  680. // The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.
  681. // Not used at the moment, but could be handy if we want to limit the size of an upload (e.g. image upload in html editor).
  682. $max_file_size = intval($_POST['MAX_FILE_SIZE']);
  683. if ($show_output) {
  684. Display::display_error_message(get_lang('UplExceedMaxPostSize').Text::format_file_size($max_file_size));
  685. }
  686. return false;
  687. case 3:
  688. // The uploaded file was only partially uploaded.
  689. if ($show_output) {
  690. Display::display_error_message(get_lang('UplPartialUpload').' '.get_lang('PleaseTryAgain'));
  691. }
  692. return false;
  693. case 4:
  694. // No file was uploaded.
  695. if ($show_output) {
  696. Display::display_error_message(get_lang('UplNoFileUploaded').' '.get_lang('UplSelectFileFirst'));
  697. }
  698. return false;
  699. }
  700. if (!file_exists($uploaded_file['tmp_name'])) {
  701. // No file was uploaded.
  702. if ($show_output) {
  703. Display::display_error_message(get_lang('UplUploadFailed'));
  704. }
  705. return false;
  706. }
  707. if (file_exists($uploaded_file['tmp_name'])) {
  708. $filesize = filesize($uploaded_file['tmp_name']);
  709. if (empty($filesize)) {
  710. // No file was uploaded.
  711. if ($show_output) {
  712. Display::display_error_message(get_lang('UplUploadFailedSizeIsZero'));
  713. }
  714. return false;
  715. }
  716. }
  717. $course_id = api_get_course_id();
  718. //Checking course quota if we are in a course
  719. if (!empty($course_id)) {
  720. $max_filled_space = DocumentManager::get_course_quota();
  721. // Check if there is enough space to save the file
  722. if (!DocumentManager::enough_space($uploaded_file['size'], $max_filled_space)) {
  723. if ($show_output) {
  724. Display::display_error_message(get_lang('UplNotEnoughSpace'));
  725. }
  726. return false;
  727. }
  728. }
  729. // case 0: default: We assume there is no error, the file uploaded with success.
  730. return true;
  731. }
  732. /**
  733. * This function does the save-work for the documents.
  734. * It handles the uploaded file and adds the properties to the database
  735. * If unzip=1 and the file is a zipfile, it is extracted
  736. * If we decide to save ALL kinds of documents in one database,
  737. * we could extend this with a $type='document', 'scormdocument',...
  738. *
  739. * @param array $_course
  740. * @param array $uploaded_file ($_FILES)
  741. * @param string $base_work_dir
  742. * @param string $upload_path
  743. * @param int $user_id
  744. * @param int $to_group_id, 0 for everybody
  745. * @param int $to_user_id, NULL for everybody
  746. * @param int $unzip 1/0
  747. * @param string $what_if_file_exists overwrite, rename or warn if exists (default)
  748. * @param boolean Optional output parameter. So far only use for unzip_uploaded_document function. If no output wanted on success, set to false.
  749. * @return path of the saved file
  750. */
  751. static function handle_uploaded_document(
  752. $_course,
  753. $uploaded_file,
  754. $base_work_dir,
  755. $upload_path,
  756. $user_id,
  757. $to_group_id = 0,
  758. $to_user_id = null,
  759. $unzip = 0,
  760. $what_if_file_exists = '',
  761. $output = true
  762. ) {
  763. if (!$user_id) {
  764. die('Not a valid user.');
  765. }
  766. // Strip slashes
  767. $uploaded_file['name'] = stripslashes($uploaded_file['name']);
  768. // Add extension to files without one (if possible)
  769. $uploaded_file['name'] = self::add_ext_on_mime($uploaded_file['name'], $uploaded_file['type']);
  770. $current_session_id = api_get_session_id();
  771. //Just in case process_uploaded_file is not called
  772. $max_filled_space = DocumentManager::get_course_quota();
  773. // Check if there is enough space to save the file
  774. if (!DocumentManager::enough_space($uploaded_file['size'], $max_filled_space)) {
  775. if ($output) {
  776. Display::display_error_message(get_lang('UplNotEnoughSpace'));
  777. }
  778. return false;
  779. }
  780. // If the want to unzip, check if the file has a .zip (or ZIP,Zip,ZiP,...) extension
  781. if ($unzip == 1 && preg_match('/.zip$/', strtolower($uploaded_file['name']))) {
  782. return self::unzip_uploaded_document(
  783. $uploaded_file,
  784. $upload_path,
  785. $base_work_dir,
  786. $max_filled_space,
  787. $output,
  788. $to_group_id
  789. );
  790. //display_message('Unzipping file');
  791. } elseif ($unzip == 1 && !preg_match(
  792. '/.zip$/',
  793. strtolower($uploaded_file['name'])
  794. )
  795. ) { // We can only unzip ZIP files (no gz, tar,...)
  796. if ($output) {
  797. Display::display_error_message(get_lang('UplNotAZip')." ".get_lang('PleaseTryAgain'));
  798. }
  799. return false;
  800. } else {
  801. // Clean up the name, only ASCII characters should stay. (and strict)
  802. $clean_name = api_replace_dangerous_char($uploaded_file['name'], 'strict');
  803. // No "dangerous" files
  804. $clean_name = self::disable_dangerous_file($clean_name);
  805. if (!self::filter_extension($clean_name)) {
  806. if ($output) {
  807. Display::display_error_message(get_lang('UplUnableToSaveFileFilteredExtension'));
  808. }
  809. return false;
  810. } else {
  811. // Extension is good
  812. //echo '<br />clean name = '.$clean_name;
  813. //echo '<br />upload_path = '.$upload_path;
  814. // If the upload path differs from / (= root) it will need a slash at the end
  815. if ($upload_path != '/') {
  816. $upload_path = $upload_path.'/';
  817. }
  818. //echo '<br />upload_path = '.$upload_path;
  819. $file_path = $upload_path.$clean_name;
  820. //echo '<br />file path = '.$file_path;
  821. // Full path to where we want to store the file with trailing slash
  822. $where_to_save = $base_work_dir.$upload_path;
  823. // At least if the directory doesn't exist, tell so
  824. if (!is_dir($where_to_save)) {
  825. if ($output) {
  826. Display::display_error_message(get_lang('DestDirectoryDoesntExist').' ('.$upload_path.')');
  827. }
  828. return false;
  829. }
  830. //echo '<br />where to save = '.$where_to_save;
  831. // Full path of the destination
  832. $store_path = $where_to_save.$clean_name;
  833. //echo '<br />store path = '.$store_path;
  834. // Name of the document without the extension (for the title)
  835. $document_name = self::get_document_title($uploaded_file['name']);
  836. // Size of the uploaded file (in bytes)
  837. $file_size = $uploaded_file['size'];
  838. $files_perm = api_get_permissions_for_new_files();
  839. // What to do if the target file exists
  840. switch ($what_if_file_exists) {
  841. // Overwrite the file if it exists
  842. case 'overwrite':
  843. // Check if the target file exists, so we can give another message
  844. $file_exists = file_exists($store_path);
  845. if (self::moveUploadedFile($uploaded_file, $store_path)) {
  846. chmod($store_path, $files_perm);
  847. if ($file_exists) {
  848. // UPDATE DATABASE
  849. $document_id = DocumentManager::get_document_id($_course, $file_path);
  850. if (is_numeric($document_id)) {
  851. // Update filesize
  852. self::update_existing_document($_course, $document_id, $uploaded_file['size']);
  853. // Update document item_property
  854. api_item_property_update(
  855. $_course,
  856. TOOL_DOCUMENT,
  857. $document_id,
  858. 'DocumentUpdated',
  859. $user_id,
  860. $to_group_id,
  861. $to_user_id,
  862. null,
  863. null,
  864. $current_session_id
  865. );
  866. //Redo visibility
  867. api_set_default_visibility($_course, TOOL_DOCUMENT, $document_id);
  868. }
  869. // If the file is in a folder, we need to update all parent folders
  870. self::item_property_update_on_folder($_course, $upload_path, $user_id);
  871. // Display success message with extra info to user
  872. if ($output) {
  873. Display::display_confirmation_message(
  874. get_lang('UplUploadSucceeded').'<br />'.$file_path.' '.get_lang(
  875. 'UplFileOverwritten'
  876. ),
  877. false
  878. );
  879. }
  880. return $file_path;
  881. } else {
  882. // Put the document data in the database
  883. $document_id = self::add_document(
  884. $_course,
  885. $file_path,
  886. 'file',
  887. $file_size,
  888. $document_name,
  889. null,
  890. 0,
  891. true
  892. );
  893. if ($document_id) {
  894. // Put the document in item_property update
  895. api_item_property_update(
  896. $_course,
  897. TOOL_DOCUMENT,
  898. $document_id,
  899. 'DocumentAdded',
  900. $user_id,
  901. $to_group_id,
  902. $to_user_id,
  903. null,
  904. null,
  905. $current_session_id
  906. );
  907. }
  908. // If the file is in a folder, we need to update all parent folders
  909. self::item_property_update_on_folder($_course, $upload_path, $user_id);
  910. // Display success message to user
  911. if ($output) {
  912. Display::display_confirmation_message(
  913. get_lang('UplUploadSucceeded').'<br />'.$file_path,
  914. false
  915. );
  916. }
  917. return $file_path;
  918. }
  919. } else {
  920. if ($output) {
  921. Display::display_error_message(get_lang('UplUnableToSaveFile'));
  922. }
  923. return false;
  924. }
  925. break;
  926. // Rename the file if it exists
  927. case 'rename':
  928. $new_name = self::unique_name($where_to_save, $clean_name);
  929. $store_path = $where_to_save.$new_name;
  930. $new_file_path = $upload_path.$new_name;
  931. if (self::moveUploadedFile($uploaded_file, $store_path)) {
  932. chmod($store_path, $files_perm);
  933. // Put the document data in the database
  934. $document_id = self::add_document(
  935. $_course,
  936. $new_file_path,
  937. 'file',
  938. $file_size,
  939. $document_name,
  940. null,
  941. 0,
  942. true
  943. );
  944. if ($document_id) {
  945. // Update document item_property
  946. api_item_property_update(
  947. $_course,
  948. TOOL_DOCUMENT,
  949. $document_id,
  950. 'DocumentAdded',
  951. $user_id,
  952. $to_group_id,
  953. $to_user_id,
  954. null,
  955. null,
  956. $current_session_id
  957. );
  958. }
  959. // If the file is in a folder, we need to update all parent folders
  960. self::item_property_update_on_folder($_course, $upload_path, $user_id);
  961. // Display success message to user
  962. if ($output) {
  963. Display::display_confirmation_message(
  964. get_lang('UplUploadSucceeded').'<br />'.get_lang('UplFileSavedAs').$new_file_path,
  965. false
  966. );
  967. }
  968. return $new_file_path;
  969. } else {
  970. if ($output) {
  971. Display::display_error_message(get_lang('UplUnableToSaveFile'));
  972. }
  973. return false;
  974. }
  975. break;
  976. // Only save the file if it doesn't exist or warn user if it does exist
  977. default:
  978. if (file_exists($store_path)) {
  979. if ($output) {
  980. Display::display_error_message($clean_name.' '.get_lang('UplAlreadyExists'));
  981. }
  982. } else {
  983. if (self::moveUploadedFile($uploaded_file, $store_path)) {
  984. chmod($store_path, $files_perm);
  985. // Put the document data in the database
  986. $document_id = self::add_document(
  987. $_course,
  988. $file_path,
  989. 'file',
  990. $file_size,
  991. $document_name,
  992. null,
  993. 0,
  994. true
  995. );
  996. if ($document_id) {
  997. // Update document item_property
  998. api_item_property_update(
  999. $_course,
  1000. TOOL_DOCUMENT,
  1001. $document_id,
  1002. 'DocumentAdded',
  1003. $user_id,
  1004. $to_group_id,
  1005. $to_user_id,
  1006. null,
  1007. null,
  1008. $current_session_id
  1009. );
  1010. }
  1011. // If the file is in a folder, we need to update all parent folders
  1012. self::item_property_update_on_folder($_course, $upload_path, $user_id);
  1013. // Display success message to user
  1014. if ($output) {
  1015. Display::display_confirmation_message(
  1016. get_lang('UplUploadSucceeded').'<br />'.$file_path,
  1017. false
  1018. );
  1019. }
  1020. return $file_path;
  1021. } else {
  1022. if ($output) {
  1023. Display::display_error_message(get_lang('UplUnableToSaveFile'));
  1024. }
  1025. return false;
  1026. }
  1027. }
  1028. break;
  1029. }
  1030. }
  1031. }
  1032. }
  1033. /**
  1034. * Checks if there is enough place to add a file on a directory
  1035. * on the base of a maximum directory size allowed
  1036. * deprecated: use enough_space instead!
  1037. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  1038. * @param - file_size (int) - size of the file in byte
  1039. * @param - dir (string) - Path of the directory
  1040. * whe the file should be added
  1041. * @param - max_dir_space (int) - maximum size of the diretory in byte
  1042. * @return - boolean true if there is enough space,
  1043. * boolean false otherwise
  1044. *
  1045. * @see - enough_size() uses dir_total_space() function
  1046. */
  1047. static function enough_size($file_size, $dir, $max_dir_space)
  1048. {
  1049. if ($max_dir_space) {
  1050. $already_filled_space = self::dir_total_space($dir);
  1051. if (($file_size + $already_filled_space) > $max_dir_space) {
  1052. return false;
  1053. }
  1054. }
  1055. return true;
  1056. }
  1057. /**
  1058. * Computes the size already occupied by a directory and is subdirectories
  1059. *
  1060. * @param string dir_path (string) - size of the file in byte
  1061. * @return int - return the directory size in bytes
  1062. */
  1063. static function dir_total_space($dir_path)
  1064. {
  1065. $fs = new Filesystem();
  1066. if (!empty($dir_path) && $fs->exists($dir_path)) {
  1067. $finder = new Finder();
  1068. $finder->files()->in($dir_path);
  1069. $sumSize = 0;
  1070. foreach ($finder as $file) {
  1071. // Print the absolute path
  1072. //var_dump($file->getRelativePathname());
  1073. $sumSize += $file->getSize();
  1074. }
  1075. return $sumSize;
  1076. }
  1077. return 0;
  1078. /*
  1079. // author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  1080. $save_dir = getcwd();
  1081. chdir($dir_path);
  1082. $handle = opendir($dir_path);
  1083. $sumSize = 0;
  1084. $dirList = array();
  1085. while ($element = readdir($handle)) {
  1086. if ($element == '.' || $element == '..') {
  1087. continue; // Skip the current and parent directories
  1088. }
  1089. if (is_file($element)) {
  1090. $sumSize += filesize($element);
  1091. }
  1092. if (is_dir($element)) {
  1093. $dirList[] = $dir_path.'/'.$element;
  1094. }
  1095. }
  1096. closedir($handle);
  1097. if (sizeof($dirList) > 0) {
  1098. foreach ($dirList as $j) {
  1099. $sizeDir = self::dir_total_space($j, 0); // Recursivity
  1100. $sumSize += $sizeDir;
  1101. }
  1102. }
  1103. chdir($save_dir); // Return to initial position
  1104. return $sumSize;*/
  1105. }
  1106. /**
  1107. * Tries to add an extension to files without extension
  1108. * Some applications on Macintosh computers don't add an extension to the files.
  1109. * This subroutine try to fix this on the basis of the MIME type sent
  1110. * by the browser.
  1111. *
  1112. * Note : some browsers don't send the MIME Type (e.g. Netscape 4).
  1113. * We don't have solution for this kind of situation
  1114. *
  1115. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  1116. * @author - Bert Vanderkimpen
  1117. * @param - file_name (string) - Name of the file
  1118. * @param - file_type (string) - Type of the file
  1119. * @return - file_name (string)
  1120. */
  1121. static function add_ext_on_mime($file_name, $file_type)
  1122. {
  1123. // Check whether the file has an extension AND whether the browser has sent a MIME Type
  1124. if (!preg_match('/^.*\.[a-zA-Z_0-9]+$/', $file_name) && $file_type) {
  1125. // Build a "MIME-types / extensions" connection table
  1126. static $mime_type = array();
  1127. $mime_type[] = 'application/msword';
  1128. $extension[] = '.doc';
  1129. $mime_type[] = 'application/rtf';
  1130. $extension[] = '.rtf';
  1131. $mime_type[] = 'application/vnd.ms-powerpoint';
  1132. $extension[] = '.ppt';
  1133. $mime_type[] = 'application/vnd.ms-excel';
  1134. $extension[] = '.xls';
  1135. $mime_type[] = 'application/pdf';
  1136. $extension[] = '.pdf';
  1137. $mime_type[] = 'application/postscript';
  1138. $extension[] = '.ps';
  1139. $mime_type[] = 'application/mac-binhex40';
  1140. $extension[] = '.hqx';
  1141. $mime_type[] = 'application/x-gzip';
  1142. $extension[] = 'tar.gz';
  1143. $mime_type[] = 'application/x-shockwave-flash';
  1144. $extension[] = '.swf';
  1145. $mime_type[] = 'application/x-stuffit';
  1146. $extension[] = '.sit';
  1147. $mime_type[] = 'application/x-tar';
  1148. $extension[] = '.tar';
  1149. $mime_type[] = 'application/zip';
  1150. $extension[] = '.zip';
  1151. $mime_type[] = 'application/x-tar';
  1152. $extension[] = '.tar';
  1153. $mime_type[] = 'text/html';
  1154. $extension[] = '.html';
  1155. $mime_type[] = 'text/plain';
  1156. $extension[] = '.txt';
  1157. $mime_type[] = 'text/rtf';
  1158. $extension[] = '.rtf';
  1159. $mime_type[] = 'img/gif';
  1160. $extension[] = '.gif';
  1161. $mime_type[] = 'img/jpeg';
  1162. $extension[] = '.jpg';
  1163. $mime_type[] = 'img/png';
  1164. $extension[] = '.png';
  1165. $mime_type[] = 'audio/midi';
  1166. $extension[] = '.mid';
  1167. $mime_type[] = 'audio/mpeg';
  1168. $extension[] = '.mp3';
  1169. $mime_type[] = 'audio/x-aiff';
  1170. $extension[] = '.aif';
  1171. $mime_type[] = 'audio/x-pn-realaudio';
  1172. $extension[] = '.rm';
  1173. $mime_type[] = 'audio/x-pn-realaudio-plugin';
  1174. $extension[] = '.rpm';
  1175. $mime_type[] = 'audio/x-wav';
  1176. $extension[] = '.wav';
  1177. $mime_type[] = 'video/mpeg';
  1178. $extension[] = '.mpg';
  1179. $mime_type[] = 'video/mpeg4-generic';
  1180. $extension[] = '.mp4';
  1181. $mime_type[] = 'video/quicktime';
  1182. $extension[] = '.mov';
  1183. $mime_type[] = 'video/x-msvideo';
  1184. $extension[] = '.avi';
  1185. $mime_type[] = 'video/x-ms-wmv';
  1186. $extension[] = '.wmv';
  1187. $mime_type[] = 'video/x-flv';
  1188. $extension[] = '.flv';
  1189. $mime_type[] = 'image/svg+xml';
  1190. $extension[] = '.svg';
  1191. $mime_type[] = 'image/svg+xml';
  1192. $extension[] = '.svgz';
  1193. $mime_type[] = 'video/ogg';
  1194. $extension[] = '.ogv';
  1195. $mime_type[] = 'audio/ogg';
  1196. $extension[] = '.oga';
  1197. $mime_type[] = 'application/ogg';
  1198. $extension[] = '.ogg';
  1199. $mime_type[] = 'application/ogg';
  1200. $extension[] = '.ogx';
  1201. $mime_type[] = 'application/x-freemind';
  1202. $extension[] = '.mm';
  1203. $mime_type[] = 'application/vnd.ms-word.document.macroEnabled.12';
  1204. $extension[] = '.docm';
  1205. $mime_type[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
  1206. $extension[] = '.docx';
  1207. $mime_type[] = 'application/vnd.ms-word.template.macroEnabled.12';
  1208. $extension[] = '.dotm';
  1209. $mime_type[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.template';
  1210. $extension[] = '.dotx';
  1211. $mime_type[] = 'application/vnd.ms-powerpoint.template.macroEnabled.12';
  1212. $extension[] = '.potm';
  1213. $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.template';
  1214. $extension[] = '.potx';
  1215. $mime_type[] = 'application/vnd.ms-powerpoint.addin.macroEnabled.12';
  1216. $extension[] = '.ppam';
  1217. $mime_type[] = 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12';
  1218. $extension[] = '.ppsm';
  1219. $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.slideshow';
  1220. $extension[] = '.ppsx';
  1221. $mime_type[] = 'application/vnd.ms-powerpoint.presentation.macroEnabled.12';
  1222. $extension[] = '.pptm';
  1223. $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
  1224. $extension[] = '.pptx';
  1225. $mime_type[] = 'application/vnd.ms-excel.addin.macroEnabled.12';
  1226. $extension[] = '.xlam';
  1227. $mime_type[] = 'application/vnd.ms-excel.sheet.binary.macroEnabled.12';
  1228. $extension[] = '.xlsb';
  1229. $mime_type[] = 'application/vnd.ms-excel.sheet.macroEnabled.12';
  1230. $extension[] = '.xlsm';
  1231. $mime_type[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
  1232. $extension[] = '.xlsx';
  1233. $mime_type[] = 'application/vnd.ms-excel.template.macroEnabled.12';
  1234. $extension[] = '.xltm';
  1235. $mime_type[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.template';
  1236. $extension[] = '.xltx';
  1237. // Test on PC (files with no extension get application/octet-stream)
  1238. //$mime_type[] = 'application/octet-stream'; $extension[] = '.ext';
  1239. // Check whether the MIME type sent by the browser is within the table
  1240. foreach ($mime_type as $key => & $type) {
  1241. if ($type == $file_type) {
  1242. $file_name .= $extension[$key];
  1243. break;
  1244. }
  1245. }
  1246. unset($mime_type, $extension, $type, $key); // Delete to eschew possible collisions
  1247. }
  1248. return $file_name;
  1249. }
  1250. /**
  1251. * Manages all the unzipping process of an uploaded document
  1252. * This uses the item_property table for properties of documents
  1253. *
  1254. * @author Hugues Peeters <hugues.peeters@claroline.net>
  1255. * @author Bert Vanderkimpen
  1256. *
  1257. * @param array $uploaded_file - follows the $_FILES Structure
  1258. * @param string $upload_path - destination of the upload.
  1259. * This path is to append to $base_work_dir
  1260. * @param string $base_work_dir - base working directory of the module
  1261. * @param int $max_filled_space - amount of bytes to not exceed in the base
  1262. * working directory
  1263. * @param boolean Output switch. Optional. If no output not wanted on success, set to false.
  1264. *
  1265. * @return boolean true if it succeeds false otherwise
  1266. */
  1267. static function unzip_uploaded_document(
  1268. $uploaded_file,
  1269. $upload_path,
  1270. $base_work_dir,
  1271. $max_filled_space,
  1272. $output = true,
  1273. $to_group_id = 0
  1274. ) {
  1275. $_course = api_get_course_info();
  1276. global $_user;
  1277. global $to_user_id;
  1278. global $to_group_id;
  1279. $zip_file = new PclZip($uploaded_file['tmp_name']);
  1280. // Check the zip content (real size and file extension)
  1281. $zip_content_array = (array)$zip_file->listContent();
  1282. $real_filesize = 0;
  1283. foreach ($zip_content_array as & $this_content) {
  1284. $real_filesize += $this_content['size'];
  1285. }
  1286. if (!DocumentManager::enough_space($real_filesize, $max_filled_space)) {
  1287. Display::display_error_message(get_lang('UplNotEnoughSpace'));
  1288. return false;
  1289. }
  1290. // It happens on Linux that $upload_path sometimes doesn't start with '/'
  1291. if ($upload_path[0] != '/') {
  1292. $upload_path = '/'.$upload_path;
  1293. }
  1294. /* Uncompressing phase */
  1295. // Get into the right directory
  1296. $save_dir = getcwd();
  1297. chdir($base_work_dir.$upload_path);
  1298. // We extract using a callback function that "cleans" the path
  1299. //@todo check if this works
  1300. $unzipping_state = $zip_file->extract(
  1301. PCLZIP_CB_PRE_EXTRACT,
  1302. 'FileManager::clean_up_files_in_zip',
  1303. PCLZIP_OPT_REPLACE_NEWER
  1304. );
  1305. // Add all documents in the unzipped folder to the database
  1306. self::add_all_documents_in_folder_to_database(
  1307. $_course,
  1308. $_user['user_id'],
  1309. $base_work_dir,
  1310. $upload_path == '/' ? '' : $upload_path,
  1311. $to_group_id
  1312. );
  1313. //Display::display_normal_message(get_lang('UplZipExtractSuccess'));
  1314. return true;
  1315. }
  1316. /**
  1317. * This function is a callback function that is used while extracting a zipfile
  1318. * http://www.phpconcept.net/pclzip/man/en/index.php?options-pclzip_cb_pre_extract
  1319. *
  1320. * @param $p_event
  1321. * @param $p_header
  1322. * @return 1 (If the function returns 1, then the extraction is resumed)
  1323. */
  1324. function clean_up_files_in_zip($p_event, &$p_header)
  1325. {
  1326. $res = self::clean_up_path($p_header['filename']);
  1327. return $res;
  1328. }
  1329. /**
  1330. * This function cleans up a given path
  1331. * by eliminating dangerous file names and cleaning them
  1332. *
  1333. * @param string $path
  1334. * @return $path
  1335. * @see FileManager::disable_dangerous_file()
  1336. * @see replace_dangerous_char()
  1337. */
  1338. static function clean_up_path(&$path)
  1339. {
  1340. // Split the path in folders and files
  1341. $path_array = explode('/', $path);
  1342. // Clean up every foler and filename in the path
  1343. foreach ($path_array as $key => & $val) {
  1344. // We don't want to lose the dots in ././folder/file (cfr. zipfile)
  1345. if ($val != '.') {
  1346. $val = self::disable_dangerous_file(api_replace_dangerous_char($val));
  1347. }
  1348. }
  1349. // Join the "cleaned" path (modified in-place as passed by reference)
  1350. $path = implode('/', $path_array);
  1351. $res = self::filter_extension($path);
  1352. return $res;
  1353. }
  1354. /**
  1355. * Checks if the file is dangerous, based on extension and/or mimetype.
  1356. * The list of extensions accepted/rejected can be found from
  1357. * api_get_setting('upload_extensions_exclude') and api_get_setting('upload_extensions_include')
  1358. * @param string filename passed by reference. The filename will be modified if filter rules say so! (you can include path but the filename should look like 'abc.html')
  1359. * @return int 0 to skip file, 1 to keep file
  1360. */
  1361. static function filter_extension(&$filename)
  1362. {
  1363. if (substr($filename, -1) == '/') {
  1364. return 1; // Authorize directories
  1365. }
  1366. $blacklist = api_get_setting('upload_extensions_list_type');
  1367. if ($blacklist != 'whitelist') { // if = blacklist
  1368. $extensions = explode(';', strtolower(api_get_setting('upload_extensions_blacklist')));
  1369. $skip = api_get_setting('upload_extensions_skip');
  1370. $ext = strrchr($filename, '.');
  1371. $ext = substr($ext, 1);
  1372. if (empty($ext)) {
  1373. return 1; // We're in blacklist mode, so accept empty extensions
  1374. }
  1375. if (in_array(strtolower($ext), $extensions)) {
  1376. if ($skip == 'true') {
  1377. return 0;
  1378. } else {
  1379. $new_ext = api_get_setting('upload_extensions_replace_by');
  1380. $filename = str_replace('.'.$ext, '.'.$new_ext, $filename);
  1381. return 1;
  1382. }
  1383. } else {
  1384. return 1;
  1385. }
  1386. } else {
  1387. $extensions = split(';', strtolower(api_get_setting('upload_extensions_whitelist')));
  1388. $skip = api_get_setting('upload_extensions_skip');
  1389. $ext = strrchr($filename, '.');
  1390. $ext = substr($ext, 1);
  1391. if (empty($ext)) {
  1392. return 1; // Accept empty extensions
  1393. }
  1394. if (!in_array(strtolower($ext), $extensions)) {
  1395. if ($skip == 'true') {
  1396. return 0;
  1397. } else {
  1398. $new_ext = api_get_setting('upload_extensions_replace_by');
  1399. $filename = str_replace('.'.$ext, '.'.$new_ext, $filename);
  1400. return 1;
  1401. }
  1402. } else {
  1403. return 1;
  1404. }
  1405. }
  1406. }
  1407. /**
  1408. * Adds a new document to the database
  1409. * @param string $course
  1410. * @param string $path
  1411. * @param string $filetype
  1412. * @param string $filesize
  1413. * @param $title
  1414. * @param string $comment
  1415. * @param int $readonly
  1416. * @param bool $save_visibility
  1417. * @param int $group_id
  1418. * @param int $session_id Session ID, if any
  1419. * @return bool|int
  1420. */
  1421. public static function add_document(
  1422. $course,
  1423. $path,
  1424. $filetype,
  1425. $filesize,
  1426. $title,
  1427. $comment = null,
  1428. $readonly = 0,
  1429. $save_visibility = true,
  1430. $group_id = null,
  1431. $session_id = 0
  1432. ) {
  1433. $session_id = intval($session_id);
  1434. if (empty($session_id)) {
  1435. $session_id = api_get_session_id();
  1436. }
  1437. $readonly = intval($readonly);
  1438. $comment = Database::escape_string($comment);
  1439. $path = Database::escape_string($path);
  1440. $filetype = Database::escape_string($filetype);
  1441. $filesize = intval($filesize);
  1442. $title = Database::escape_string($title);
  1443. if (is_array($course)) {
  1444. $c_id = $course['real_id'];
  1445. } else {
  1446. if ($course instanceof Course) {
  1447. $c_id = $course->getId();
  1448. }
  1449. }
  1450. $table_document = Database::get_course_table(TABLE_DOCUMENT);
  1451. $sql = "INSERT INTO $table_document (c_id, path, filetype, size, title, comment, readonly, session_id)
  1452. VALUES ($c_id, '$path','$filetype','$filesize','$title', '$comment', $readonly, $session_id)";
  1453. if (Database::query($sql)) {
  1454. $document_id = Database::insert_id();
  1455. if ($document_id) {
  1456. if ($save_visibility) {
  1457. api_set_default_visibility($course, $document_id, TOOL_DOCUMENT, $group_id);
  1458. }
  1459. }
  1460. return $document_id;
  1461. } else {
  1462. return false;
  1463. }
  1464. }
  1465. /**
  1466. * Updates an existing document in the database
  1467. * as the file exists, we only need to change the size
  1468. *
  1469. * @param array $_course
  1470. * @param int $document_id
  1471. * @param int $filesize
  1472. * @param int $readonly
  1473. *
  1474. * @return boolean true /false
  1475. */
  1476. static function update_existing_document($_course, $document_id, $filesize, $readonly = 0)
  1477. {
  1478. $document_table = Database::get_course_table(TABLE_DOCUMENT);
  1479. $document_id = intval($document_id);
  1480. $filesize = intval($filesize);
  1481. $readonly = intval($readonly);
  1482. $course_id = $_course['real_id'];
  1483. $sql = "UPDATE $document_table SET size = '$filesize' , readonly = '$readonly'
  1484. WHERE c_id = $course_id AND id = $document_id";
  1485. if (Database::query($sql)) {
  1486. return true;
  1487. } else {
  1488. return false;
  1489. }
  1490. }
  1491. /**
  1492. * This function updates the last_edit_date, last edit user id on all folders in a given path
  1493. *
  1494. * @param array $_course
  1495. * @param string $path
  1496. * @param int $user_id
  1497. */
  1498. static function item_property_update_on_folder($_course, $path, $user_id)
  1499. {
  1500. //display_message("Start update_lastedit_on_folder");
  1501. // If we are in the root, just return... no need to update anything
  1502. if ($path == '/') {
  1503. return;
  1504. }
  1505. $user_id = intval($user_id);
  1506. // If the given path ends with a / we remove it
  1507. $endchar = substr($path, strlen($path) - 1, 1);
  1508. if ($endchar == '/') {
  1509. $path = substr($path, 0, strlen($path) - 1);
  1510. }
  1511. $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  1512. // Get the time
  1513. $time = date('Y-m-d H:i:s', time());
  1514. // Det all paths in the given path
  1515. // /folder/subfolder/subsubfolder/file
  1516. // if file is updated, subsubfolder, subfolder and folder are updated
  1517. $exploded_path = explode('/', $path);
  1518. $course_id = api_get_course_int_id();
  1519. foreach ($exploded_path as $key => & $value) {
  1520. // We don't want a slash before our first slash
  1521. if ($key != 0) {
  1522. $newpath .= '/'.$value;
  1523. //echo 'path= '.$newpath.'<br />';
  1524. // Select ID of given folder
  1525. $folder_id = DocumentManager::get_document_id($_course, $newpath);
  1526. if ($folder_id) {
  1527. $sql = "UPDATE $TABLE_ITEMPROPERTY SET lastedit_date='$time',lastedit_type='DocumentInFolderUpdated', lastedit_user_id='$user_id'
  1528. WHERE c_id = $course_id AND tool='".TOOL_DOCUMENT."' AND ref='$folder_id'";
  1529. Database::query($sql);
  1530. }
  1531. }
  1532. }
  1533. }
  1534. /**
  1535. * Returns the directory depth of the file.
  1536. *
  1537. * @author Olivier Cauberghe <olivier.cauberghe@ugent.be>
  1538. * @param path+filename eg: /main/document/document.php
  1539. * @return The directory depth
  1540. */
  1541. static function get_levels($filename)
  1542. {
  1543. $levels = explode('/', $filename);
  1544. if (empty($levels[count($levels) - 1])) {
  1545. unset($levels[count($levels) - 1]);
  1546. }
  1547. return count($levels);
  1548. }
  1549. /**
  1550. * Retrieves the image path list in a html file
  1551. *
  1552. * @author Hugues Peeters <hugues.peeters@claroline.net>
  1553. * @param string $html_file
  1554. * @return array - images path list
  1555. */
  1556. static function search_img_from_html($html_file)
  1557. {
  1558. $img_path_list = array();
  1559. if (!$fp = fopen($html_file, 'r')) {
  1560. return;
  1561. }
  1562. // Aearch and store occurences of the <img> tag in an array
  1563. $size_file = (filesize($html_file) === 0) ? 1 : filesize($html_file);
  1564. if (isset($fp) && $fp !== false) {
  1565. $buffer = fread($fp, $size_file);
  1566. if (strlen($buffer) >= 0 && $buffer !== false) {
  1567. //
  1568. } else {
  1569. die('<center>Can not read file.</center>');
  1570. }
  1571. } else {
  1572. die('<center>Can not read file.</center>');
  1573. }
  1574. $matches = array();
  1575. if (preg_match_all('~<[[:space:]]*img[^>]*>~i', $buffer, $matches)) {
  1576. $img_tag_list = $matches[0];
  1577. }
  1578. fclose($fp);
  1579. unset($buffer);
  1580. // Search the image file path from all the <IMG> tag detected
  1581. if (sizeof($img_tag_list) > 0) {
  1582. foreach ($img_tag_list as & $this_img_tag) {
  1583. if (preg_match('~src[[:space:]]*=[[:space:]]*[\"]{1}([^\"]+)[\"]{1}~i', $this_img_tag, $matches)) {
  1584. $img_path_list[] = $matches[1];
  1585. }
  1586. }
  1587. $img_path_list = array_unique($img_path_list); // Remove duplicate entries
  1588. }
  1589. return $img_path_list;
  1590. }
  1591. /**
  1592. * Creates a new directory trying to find a directory name
  1593. * that doesn't already exist
  1594. * (we could use unique_name() here...)
  1595. *
  1596. * @author Hugues Peeters <hugues.peeters@claroline.net>
  1597. * @author Bert Vanderkimpen
  1598. * @param array $_course current course information
  1599. * @param int $user_id current user id
  1600. * @param string $desiredDirName complete path of the desired name
  1601. * @param string The visible name of the directory
  1602. * @param int Visibility (0 for invisible, 1 for visible, 2 for deleted)
  1603. * @return string actual directory name if it succeeds,
  1604. * boolean false otherwise
  1605. */
  1606. static function create_unexisting_directory(
  1607. $_course,
  1608. $user_id,
  1609. $session_id,
  1610. $to_group_id,
  1611. $to_user_id,
  1612. $base_work_dir,
  1613. $desired_dir_name,
  1614. $title = null,
  1615. $visibility = ''
  1616. ) {
  1617. $nb = '';
  1618. // add numerical suffix to directory if another one of the same number already exists
  1619. while (file_exists($base_work_dir.$desired_dir_name.$nb)) {
  1620. $nb += 1;
  1621. }
  1622. if ($title == null) {
  1623. $title = basename($desired_dir_name);
  1624. }
  1625. $course_id = $_course['real_id'];
  1626. if (mkdir($base_work_dir.$desired_dir_name.$nb, api_get_permissions_for_new_directories(), true)) {
  1627. // Check if pathname already exists inside document table
  1628. $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
  1629. $sql = "SELECT path FROM $tbl_document WHERE c_id = $course_id AND path='".$desired_dir_name.$nb."'";
  1630. $rs = Database::query($sql);
  1631. if (Database::num_rows($rs) == 0) {
  1632. $document_id = self::add_document(
  1633. $_course,
  1634. $desired_dir_name.$nb,
  1635. 'folder',
  1636. 0,
  1637. $title,
  1638. null,
  1639. 0,
  1640. true,
  1641. $to_group_id
  1642. );
  1643. if ($document_id) {
  1644. // Update document item_property
  1645. if ($visibility !== '') {
  1646. $visibilities = array(0 => 'invisible', 1 => 'visible', 2 => 'delete');
  1647. api_item_property_update(
  1648. $_course,
  1649. TOOL_DOCUMENT,
  1650. $document_id,
  1651. $visibilities[$visibility],
  1652. $user_id,
  1653. $to_group_id,
  1654. $to_user_id,
  1655. null,
  1656. null,
  1657. $session_id
  1658. );
  1659. } else {
  1660. api_item_property_update(
  1661. $_course,
  1662. TOOL_DOCUMENT,
  1663. $document_id,
  1664. 'FolderCreated',
  1665. $user_id,
  1666. $to_group_id,
  1667. $to_user_id,
  1668. null,
  1669. null,
  1670. $session_id
  1671. );
  1672. }
  1673. return $desired_dir_name.$nb;
  1674. }
  1675. } else {
  1676. //This means the folder NOT exist in the filesystem (now this was created) but there is a record in the Database
  1677. return $desired_dir_name.$nb;
  1678. }
  1679. } else {
  1680. return false;
  1681. }
  1682. }
  1683. /**
  1684. * Handles uploaded missing images
  1685. *
  1686. * @author Hugues Peeters <hugues.peeters@claroline.net>
  1687. * @author Bert Vanderkimpen
  1688. * @param array $_course
  1689. * @param array $uploaded_file_collection - follows the $_FILES Structure
  1690. * @param string $base_work_dir
  1691. * @param string $missing_files_dir
  1692. * @param int $user_id
  1693. * @param int $max_filled_space
  1694. */
  1695. static function move_uploaded_file_collection_into_directory(
  1696. $_course,
  1697. $uploaded_file_collection,
  1698. $base_work_dir,
  1699. $missing_files_dir,
  1700. $user_id,
  1701. $to_group_id,
  1702. $to_user_id,
  1703. $max_filled_space
  1704. ) {
  1705. $number_of_uploaded_images = count($uploaded_file_collection['name']);
  1706. for ($i = 0; $i < $number_of_uploaded_images; $i++) {
  1707. $missing_file['name'] = $uploaded_file_collection['name'][$i];
  1708. $missing_file['type'] = $uploaded_file_collection['type'][$i];
  1709. $missing_file['tmp_name'] = $uploaded_file_collection['tmp_name'][$i];
  1710. $missing_file['error'] = $uploaded_file_collection['error'][$i];
  1711. $missing_file['size'] = $uploaded_file_collection['size'][$i];
  1712. $upload_ok = self::process_uploaded_file($missing_file);
  1713. if ($upload_ok) {
  1714. $new_file_list[] = self::handle_uploaded_document(
  1715. $_course,
  1716. $missing_file,
  1717. $base_work_dir,
  1718. $missing_files_dir,
  1719. $user_id,
  1720. $to_group_id,
  1721. $to_user_id,
  1722. $max_filled_space,
  1723. 0,
  1724. 'overwrite'
  1725. );
  1726. }
  1727. unset($missing_file);
  1728. }
  1729. return $new_file_list;
  1730. }
  1731. /**
  1732. * Opens the old html file and replace the src path into the img tag
  1733. * This also works for files in subdirectories.
  1734. * @param $original_img_path is an array
  1735. * @param $new_img_path is an array
  1736. */
  1737. static function replace_img_path_in_html_file($original_img_path, $new_img_path, $html_file)
  1738. {
  1739. // Open the file
  1740. $fp = fopen($html_file, 'r');
  1741. $buffer = fread($fp, filesize($html_file));
  1742. $new_html_content = null;
  1743. // Fix the image tags
  1744. for ($i = 0, $fileNb = count($original_img_path); $i < $fileNb; $i++) {
  1745. $replace_what = $original_img_path[$i];
  1746. // We only need the directory and the filename /path/to/file_html_files/missing_file.gif -> file_html_files/missing_file.gif
  1747. $exploded_file_path = explode('/', $new_img_path[$i]);
  1748. $replace_by = $exploded_file_path[count($exploded_file_path) - 2].'/'.$exploded_file_path[count(
  1749. $exploded_file_path
  1750. ) - 1];
  1751. $buffer = str_replace($replace_what, $replace_by, $buffer);
  1752. }
  1753. $new_html_content .= $buffer;
  1754. @fclose($fp);
  1755. // Write the resulted new file
  1756. if (!$fp = fopen($html_file, 'w')) {
  1757. return;
  1758. }
  1759. if (!fwrite($fp, $new_html_content)) {
  1760. return;
  1761. }
  1762. }
  1763. /**
  1764. * Checks the extension of a file, if it's .htm or .html
  1765. * we use search_img_from_html to get all image paths in the file
  1766. *
  1767. * @param string $file
  1768. * @return array paths
  1769. * @see check_for_missing_files() uses search_img_from_html()
  1770. */
  1771. static function check_for_missing_files($file)
  1772. {
  1773. if (strrchr($file, '.') == '.htm' || strrchr($file, '.') == '.html') {
  1774. $img_file_path = self::search_img_from_html($file);
  1775. return $img_file_path;
  1776. }
  1777. return false;
  1778. }
  1779. /**
  1780. * This function builds a form that asks for the missing images in a html file
  1781. * maybe we should do this another way?
  1782. *
  1783. * @param array $missing_files
  1784. * @param string $upload_path
  1785. * @param string $file_name
  1786. * @return string the form
  1787. */
  1788. static function build_missing_files_form($missing_files, $upload_path, $file_name)
  1789. {
  1790. // Do we need a / or not?
  1791. $added_slash = ($upload_path == '/') ? '' : '/';
  1792. $folder_id = DocumentManager::get_document_id(api_get_course_info(), $upload_path);
  1793. // Build the form
  1794. $form = "<p><strong>".get_lang('MissingImagesDetected')."</strong></p>"
  1795. ."<form method=\"post\" action=\"".api_get_self()."\" enctype=\"multipart/form-data\">"
  1796. // Related_file is the path to the file that has missing images
  1797. ."<input type=\"hidden\" name=\"related_file\" value=\"".$upload_path.$added_slash.$file_name."\" />"
  1798. ."<input type=\"hidden\" name=\"upload_path\" value=\"".$upload_path."\" />"
  1799. ."<input type=\"hidden\" name=\"id\" value=\"".$folder_id."\" />"
  1800. ."<table border=\"0\">";
  1801. foreach ($missing_files as & $this_img_file_path) {
  1802. $form .= "<tr>"
  1803. ."<td>".basename($this_img_file_path)." : </td>"
  1804. ."<td>"
  1805. ."<input type=\"file\" name=\"img_file[]\"/>"
  1806. ."<input type=\"hidden\" name=\"img_file_path[]\" value=\"".$this_img_file_path."\" />"
  1807. ."</td>"
  1808. ."</tr>";
  1809. }
  1810. $form .= "</table>"
  1811. ."<button type='submit' name=\"cancel_submit_image\" value=\"".get_lang(
  1812. 'Cancel'
  1813. )."\" class=\"cancel\">".get_lang('Cancel')."</button>"
  1814. ."<button type='submit' name=\"submit_image\" value=\"".get_lang('Ok')."\" class=\"save\">".get_lang(
  1815. 'Ok'
  1816. )."</button>"
  1817. ."</form>";
  1818. return $form;
  1819. }
  1820. /**
  1821. * This recursive function can be used during the upgrade process form older versions of Chamilo
  1822. * It crawls the given directory, checks if the file is in the DB and adds it if it's not
  1823. *
  1824. * @param string $base_work_dir
  1825. * @param string $current_path, needed for recursivity
  1826. */
  1827. public static function add_all_documents_in_folder_to_database(
  1828. $_course,
  1829. $user_id,
  1830. $base_work_dir,
  1831. $current_path = '',
  1832. $to_group_id = 0
  1833. ) {
  1834. $current_session_id = api_get_session_id();
  1835. $path = $base_work_dir.$current_path;
  1836. // Open dir
  1837. $handle = opendir($path);
  1838. if (is_dir($path)) {
  1839. // Run trough
  1840. while ($file = readdir($handle)) {
  1841. if ($file == '.' || $file == '..') {
  1842. continue;
  1843. }
  1844. $completepath = "$path/$file";
  1845. // Directory?
  1846. if (is_dir($completepath)) {
  1847. $title = self::get_document_title($file);
  1848. $safe_file = api_replace_dangerous_char($file);
  1849. @rename($path.'/'.$file, $path.'/'.$safe_file);
  1850. // If we can't find the file, add it
  1851. if (!DocumentManager::get_document_id($_course, $current_path.'/'.$safe_file)) {
  1852. $document_id = self::add_document($_course, $current_path.'/'.$safe_file, 'folder', 0, $title);
  1853. api_item_property_update(
  1854. $_course,
  1855. TOOL_DOCUMENT,
  1856. $document_id,
  1857. 'DocumentAdded',
  1858. $user_id,
  1859. $to_group_id,
  1860. null,
  1861. null,
  1862. null,
  1863. $current_session_id
  1864. );
  1865. //echo $current_path.'/'.$safe_file.' added!<br />';
  1866. }
  1867. // Recursive
  1868. self::add_all_documents_in_folder_to_database(
  1869. $_course,
  1870. $user_id,
  1871. $base_work_dir,
  1872. $current_path.'/'.$safe_file,
  1873. $to_group_id
  1874. );
  1875. } else {
  1876. //Rename
  1877. $safe_file = self::disable_dangerous_file(api_replace_dangerous_char($file, 'strict'));
  1878. @rename($base_work_dir.$current_path.'/'.$file, $base_work_dir.$current_path.'/'.$safe_file);
  1879. $document_id = DocumentManager::get_document_id($_course, $current_path.'/'.$safe_file);
  1880. if (!$document_id) {
  1881. $title = self::get_document_title($file);
  1882. $size = filesize($base_work_dir.$current_path.'/'.$safe_file);
  1883. $document_id = self::add_document(
  1884. $_course,
  1885. $current_path.'/'.$safe_file,
  1886. 'file',
  1887. $size,
  1888. $title
  1889. );
  1890. api_item_property_update(
  1891. $_course,
  1892. TOOL_DOCUMENT,
  1893. $document_id,
  1894. 'DocumentAdded',
  1895. $user_id,
  1896. $to_group_id,
  1897. null,
  1898. null,
  1899. null,
  1900. $current_session_id
  1901. );
  1902. //echo $current_path.'/'.$safe_file.' added!<br />';
  1903. } else {
  1904. api_item_property_update(
  1905. $_course,
  1906. TOOL_DOCUMENT,
  1907. $document_id,
  1908. 'DocumentUpdated',
  1909. $user_id,
  1910. $to_group_id,
  1911. null,
  1912. null,
  1913. null,
  1914. $current_session_id
  1915. );
  1916. }
  1917. }
  1918. }
  1919. }
  1920. }
  1921. /**
  1922. * @param array $file
  1923. * @param string $storePath
  1924. * @return bool
  1925. **/
  1926. public static function moveUploadedFile($file, $storePath)
  1927. {
  1928. $handleFromFile = isset($file['from_file']) && $file['from_file'] ? true : false;
  1929. if ($handleFromFile) {
  1930. return file_exists($file['tmp_name']);
  1931. } else {
  1932. return move_uploaded_file($file['tmp_name'], $storePath);
  1933. }
  1934. }
  1935. }