fileManager.lib.php 79 KB

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