fileUpload.lib.php 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * FILE UPLOAD LIBRARY
  5. *
  6. * This is the file upload library for Chamilo.
  7. * Include/require it in your code to use its functionality.
  8. *
  9. * @package chamilo.library
  10. * @todo test and reorganise
  11. */
  12. /**
  13. * This function executes our safety precautions
  14. * more functions can be added
  15. *
  16. * @param string $filename
  17. * @return string
  18. * @see php2phps()
  19. * @see htaccess2txt()
  20. */
  21. function disable_dangerous_file($filename) {
  22. return htaccess2txt(php2phps($filename));
  23. }
  24. /**
  25. * Returns the name without extension, used for the title
  26. *
  27. * @param string $name
  28. * @return name without the extension
  29. */
  30. function get_document_title($name) {
  31. // If they upload .htaccess...
  32. $name = disable_dangerous_file($name);
  33. $ext = substr(strrchr($name, '.'), 0);
  34. return substr($name, 0, strlen($name) - strlen(strstr($name, $ext)));
  35. }
  36. /**
  37. * This function checks if the upload succeeded
  38. *
  39. * @param array $uploaded_file ($_FILES)
  40. * @return true if upload succeeded
  41. */
  42. function process_uploaded_file($uploaded_file, $show_output = true)
  43. {
  44. // Checking the error code sent with the file upload.
  45. if (isset($uploaded_file['error'])) {
  46. switch ($uploaded_file['error']) {
  47. case 1:
  48. // The uploaded file exceeds the upload_max_filesize directive in php.ini.
  49. if ($show_output) {
  50. Display::display_error_message(get_lang('UplExceedMaxServerUpload').ini_get('upload_max_filesize'));
  51. }
  52. return false;
  53. case 2:
  54. // The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.
  55. // 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).
  56. $max_file_size = intval($_POST['MAX_FILE_SIZE']);
  57. if ($show_output) {
  58. Display::display_error_message(get_lang('UplExceedMaxPostSize'). format_file_size($max_file_size));
  59. }
  60. return false;
  61. case 3:
  62. // The uploaded file was only partially uploaded.
  63. if ($show_output) {
  64. Display::display_error_message(get_lang('UplPartialUpload').' '.get_lang('PleaseTryAgain'));
  65. }
  66. return false;
  67. case 4:
  68. // No file was uploaded.
  69. if ($show_output) {
  70. Display::display_error_message(get_lang('UplNoFileUploaded').' '. get_lang('UplSelectFileFirst'));
  71. }
  72. return false;
  73. }
  74. }
  75. if (!file_exists($uploaded_file['tmp_name'])) {
  76. // No file was uploaded.
  77. if ($show_output) {
  78. Display::display_error_message(get_lang('UplUploadFailed'));
  79. }
  80. return false;
  81. }
  82. if (file_exists($uploaded_file['tmp_name'])) {
  83. $filesize = filesize($uploaded_file['tmp_name']);
  84. if (empty($filesize)) {
  85. // No file was uploaded.
  86. if ($show_output) {
  87. Display::display_error_message(get_lang('UplUploadFailedSizeIsZero'));
  88. }
  89. return false;
  90. }
  91. }
  92. $course_id = api_get_course_id();
  93. //Checking course quota if we are in a course
  94. if (!empty($course_id)) {
  95. $max_filled_space = DocumentManager::get_course_quota();
  96. // Check if there is enough space to save the file
  97. if (!DocumentManager::enough_space($uploaded_file['size'], $max_filled_space)) {
  98. if ($show_output) {
  99. Display::display_error_message(get_lang('UplNotEnoughSpace'));
  100. }
  101. return false;
  102. }
  103. }
  104. // case 0: default: We assume there is no error, the file uploaded with success.
  105. return true;
  106. }
  107. /**
  108. * This function does the save-work for the documents.
  109. * It handles the uploaded file and adds the properties to the database
  110. * If unzip=1 and the file is a zipfile, it is extracted
  111. * If we decide to save ALL kinds of documents in one database,
  112. * we could extend this with a $type='document', 'scormdocument',...
  113. *
  114. * @param array $courseInfo
  115. * @param array $uploadedFile ($_FILES)
  116. * array(
  117. * 'name' => 'picture.jpg',
  118. * 'tmp_name' => '...', // absolute path
  119. * );
  120. * @param string $documentDir Example: /var/www/chamilo/courses/ABC/document
  121. * @param string $uploadPath Example: /folder1/folder2/
  122. * @param int $userId
  123. * @param int $groupId, 0 for everybody
  124. * @param int $toUserId, NULL for everybody
  125. * @param int $unzip 1/0
  126. * @param string $whatIfFileExists overwrite, rename or warn if exists (default)
  127. * @param boolean $output Optional output parameter.
  128. * @param bool $onlyUploadFile
  129. * @param string $comment
  130. * @param int $sessionId
  131. *
  132. * So far only use for unzip_uploaded_document function.
  133. * If no output wanted on success, set to false.
  134. * @param string $comment
  135. * @return string path of the saved file
  136. */
  137. function handle_uploaded_document(
  138. $courseInfo,
  139. $uploadedFile,
  140. $documentDir,
  141. $uploadPath,
  142. $userId,
  143. $groupId = 0,
  144. $toUserId = null,
  145. $unzip = 0,
  146. $whatIfFileExists = '',
  147. $output = true,
  148. $onlyUploadFile = false,
  149. $comment = null,
  150. $sessionId = null
  151. ) {
  152. if (!$userId) {
  153. return false;
  154. }
  155. $userInfo = api_get_user_info();
  156. $uploadedFile['name'] = stripslashes($uploadedFile['name']);
  157. // Add extension to files without one (if possible)
  158. $uploadedFile['name'] = add_ext_on_mime($uploadedFile['name'], $uploadedFile['type']);
  159. if (empty($sessionId)) {
  160. $sessionId = api_get_session_id();
  161. } else {
  162. $sessionId = intval($sessionId);
  163. }
  164. // Just in case process_uploaded_file is not called
  165. $maxSpace = DocumentManager::get_course_quota();
  166. // Check if there is enough space to save the file
  167. if (!DocumentManager::enough_space($uploadedFile['size'], $maxSpace)) {
  168. if ($output) {
  169. Display::display_error_message(get_lang('UplNotEnoughSpace'));
  170. }
  171. return false;
  172. }
  173. // If the want to unzip, check if the file has a .zip (or ZIP,Zip,ZiP,...) extension
  174. if ($unzip == 1 && preg_match('/.zip$/', strtolower($uploadedFile['name']))) {
  175. return unzip_uploaded_document(
  176. $courseInfo,
  177. $userInfo,
  178. $uploadedFile,
  179. $uploadPath,
  180. $documentDir,
  181. $maxSpace,
  182. $sessionId,
  183. $groupId,
  184. $output
  185. );
  186. } elseif ($unzip == 1 && !preg_match('/.zip$/', strtolower($uploadedFile['name']))) {
  187. // We can only unzip ZIP files (no gz, tar,...)
  188. if ($output) {
  189. Display::display_error_message(
  190. get_lang('UplNotAZip')." ".get_lang('PleaseTryAgain')
  191. );
  192. }
  193. return false;
  194. } else {
  195. // Clean up the name, only ASCII characters should stay. (and strict)
  196. $cleanName = api_replace_dangerous_char($uploadedFile['name'], 'strict');
  197. // No "dangerous" files
  198. $cleanName = disable_dangerous_file($cleanName);
  199. // Checking file extension
  200. if (!filter_extension($cleanName)) {
  201. if ($output) {
  202. Display::display_error_message(
  203. get_lang('UplUnableToSaveFileFilteredExtension')
  204. );
  205. }
  206. return false;
  207. } else {
  208. // If the upload path differs from / (= root) it will need a slash at the end
  209. if ($uploadPath != '/') {
  210. $uploadPath = $uploadPath.'/';
  211. }
  212. // Full path to where we want to store the file with trailing slash
  213. $whereToSave = $documentDir.$uploadPath;
  214. // At least if the directory doesn't exist, tell so
  215. if (!is_dir($whereToSave)) {
  216. if (!mkdir($whereToSave, api_get_permissions_for_new_directories())) {
  217. if ($output) {
  218. Display::display_error_message(
  219. get_lang('DestDirectoryDoesntExist').' ('.$uploadPath.')'
  220. );
  221. }
  222. return false;
  223. }
  224. }
  225. // Just upload the file "as is"
  226. if ($onlyUploadFile) {
  227. $errorResult = moveUploadedFile($uploadedFile, $whereToSave.$cleanName);
  228. if ($errorResult) {
  229. return $whereToSave.$cleanName;
  230. } else {
  231. return $errorResult;
  232. }
  233. }
  234. /*
  235. Based in the clean name we generate a new filesystem name
  236. Using the session_id and group_id if values are not empty
  237. */
  238. /*$fileExists = DocumentManager::documentExists(
  239. $uploadPath.$cleanName,
  240. $courseInfo,
  241. $sessionId,
  242. $groupId
  243. );*/
  244. $fileSystemName = DocumentManager::fixDocumentName(
  245. $cleanName,
  246. 'file',
  247. $courseInfo,
  248. $sessionId,
  249. $groupId
  250. );
  251. // Name of the document without the extension (for the title)
  252. $documentTitle = get_document_title($uploadedFile['name']);
  253. // Size of the uploaded file (in bytes)
  254. $fileSize = $uploadedFile['size'];
  255. // File permissions
  256. $filePermissions = api_get_permissions_for_new_files();
  257. // Example: /var/www/chamilo/courses/xxx/document/folder/picture.jpg
  258. $fullPath = $whereToSave.$fileSystemName;
  259. // Example: /folder/picture.jpg
  260. $filePath = $uploadPath.$fileSystemName;
  261. $docId = DocumentManager::get_document_id(
  262. $courseInfo,
  263. $filePath,
  264. $sessionId
  265. );
  266. $documentList = DocumentManager::getDocumentByPathInCourse(
  267. $courseInfo,
  268. $filePath //$filePath
  269. );
  270. // This means that the path already exists in this course.
  271. if (!empty($documentList) && $whatIfFileExists != 'overwrite') {
  272. //$found = false;
  273. // Checking if we are talking about the same course + session
  274. /*foreach ($documentList as $document) {
  275. if ($document['session_id'] == $sessionId) {
  276. $found = true;
  277. break;
  278. }
  279. }*/
  280. //if ($found == false) {
  281. $whatIfFileExists = 'rename';
  282. //}
  283. }
  284. // What to do if the target file exists
  285. switch ($whatIfFileExists) {
  286. // Overwrite the file if it exists
  287. case 'overwrite':
  288. // Check if the target file exists, so we can give another message
  289. $fileExists = file_exists($fullPath);
  290. if (moveUploadedFile($uploadedFile, $fullPath)) {
  291. chmod($fullPath, $filePermissions);
  292. if ($fileExists && $docId) {
  293. // UPDATE DATABASE
  294. $documentId = DocumentManager::get_document_id(
  295. $courseInfo,
  296. $filePath
  297. );
  298. if (is_numeric($documentId)) {
  299. // Update file size
  300. update_existing_document(
  301. $courseInfo,
  302. $documentId,
  303. $uploadedFile['size']
  304. );
  305. // Update document item_property
  306. api_item_property_update(
  307. $courseInfo,
  308. TOOL_DOCUMENT,
  309. $documentId,
  310. 'DocumentUpdated',
  311. $userId,
  312. $groupId,
  313. $toUserId,
  314. null,
  315. null,
  316. $sessionId
  317. );
  318. // Redo visibility
  319. api_set_default_visibility(
  320. $documentId,
  321. TOOL_DOCUMENT,
  322. null,
  323. $courseInfo
  324. );
  325. } else {
  326. // There might be cases where the file exists on disk but there is no registration of that in the database
  327. // In this case, and if we are in overwrite mode, overwrite and create the db record
  328. $documentId = add_document(
  329. $courseInfo,
  330. $filePath,
  331. 'file',
  332. $fileSize,
  333. $documentTitle,
  334. $comment,
  335. 0,
  336. true,
  337. $groupId,
  338. $sessionId
  339. );
  340. if ($documentId) {
  341. // Put the document in item_property update
  342. api_item_property_update(
  343. $courseInfo,
  344. TOOL_DOCUMENT,
  345. $documentId,
  346. 'DocumentAdded',
  347. $userId,
  348. $groupId,
  349. $toUserId,
  350. null,
  351. null,
  352. $sessionId
  353. );
  354. // Redo visibility
  355. api_set_default_visibility($documentId, TOOL_DOCUMENT, null, $courseInfo);
  356. }
  357. }
  358. // If the file is in a folder, we need to update all parent folders
  359. item_property_update_on_folder($courseInfo, $uploadPath, $userId);
  360. // Display success message with extra info to user
  361. if ($output) {
  362. Display::display_confirmation_message(
  363. get_lang('UplUploadSucceeded') . '<br /> ' . $documentTitle . ' ' . get_lang('UplFileOverwritten'),
  364. false
  365. );
  366. }
  367. return $filePath;
  368. } else {
  369. // Put the document data in the database
  370. $documentId = add_document(
  371. $courseInfo,
  372. $filePath,
  373. 'file',
  374. $fileSize,
  375. $documentTitle,
  376. $comment,
  377. 0,
  378. true,
  379. $groupId,
  380. $sessionId
  381. );
  382. if ($documentId) {
  383. // Put the document in item_property update
  384. api_item_property_update(
  385. $courseInfo,
  386. TOOL_DOCUMENT,
  387. $documentId,
  388. 'DocumentAdded',
  389. $userId,
  390. $groupId,
  391. $toUserId,
  392. null,
  393. null,
  394. $sessionId
  395. );
  396. // Redo visibility
  397. api_set_default_visibility($documentId, TOOL_DOCUMENT, null, $courseInfo);
  398. }
  399. // If the file is in a folder, we need to update all parent folders
  400. item_property_update_on_folder($courseInfo, $uploadPath, $userId);
  401. // Display success message to user
  402. if ($output) {
  403. Display::display_confirmation_message(get_lang('UplUploadSucceeded').'<br /> '.$documentTitle, false);
  404. }
  405. return $filePath;
  406. }
  407. } else {
  408. if ($output) {
  409. Display::display_error_message(get_lang('UplUnableToSaveFile'));
  410. }
  411. return false;
  412. }
  413. break;
  414. // Rename the file if it exists
  415. case 'rename':
  416. // Always rename.
  417. $cleanName = DocumentManager::getUniqueFileName(
  418. $uploadPath,
  419. $cleanName,
  420. $courseInfo,
  421. $sessionId,
  422. $groupId
  423. );
  424. $fileSystemName = DocumentManager::fixDocumentName(
  425. $cleanName,
  426. 'file',
  427. $courseInfo,
  428. $sessionId,
  429. $groupId
  430. );
  431. $documentTitle = get_document_title($cleanName);
  432. $fullPath = $whereToSave.$fileSystemName;
  433. $filePath = $uploadPath.$fileSystemName;
  434. if (moveUploadedFile($uploadedFile, $fullPath)) {
  435. chmod($fullPath, $filePermissions);
  436. // Put the document data in the database
  437. $documentId = add_document(
  438. $courseInfo,
  439. $filePath,
  440. 'file',
  441. $fileSize,
  442. $documentTitle,
  443. $comment, // comment
  444. 0, // read only
  445. true, // save visibility
  446. $groupId,
  447. $sessionId
  448. );
  449. if ($documentId) {
  450. // Update document item_property
  451. api_item_property_update(
  452. $courseInfo,
  453. TOOL_DOCUMENT,
  454. $documentId,
  455. 'DocumentAdded',
  456. $userId,
  457. $groupId,
  458. $toUserId,
  459. null,
  460. null,
  461. $sessionId
  462. );
  463. // Redo visibility
  464. api_set_default_visibility($documentId, TOOL_DOCUMENT, null, $courseInfo);
  465. }
  466. // If the file is in a folder, we need to update all parent folders
  467. item_property_update_on_folder($courseInfo, $uploadPath, $userId);
  468. // Display success message to user
  469. if ($output) {
  470. Display::display_confirmation_message(
  471. get_lang('UplUploadSucceeded') . '<br />' . get_lang('UplFileSavedAs') .' '.$documentTitle,
  472. false
  473. );
  474. }
  475. return $filePath;
  476. } else {
  477. if ($output) {
  478. Display::display_error_message(get_lang('UplUnableToSaveFile'));
  479. }
  480. return false;
  481. }
  482. break;
  483. default:
  484. // Only save the file if it doesn't exist or warn user if it does exist
  485. if (file_exists($fullPath) && $docId) {
  486. if ($output) {
  487. Display::display_error_message($cleanName.' '.get_lang('UplAlreadyExists'));
  488. }
  489. } else {
  490. if (moveUploadedFile($uploadedFile, $fullPath)) {
  491. chmod($fullPath, $filePermissions);
  492. // Put the document data in the database
  493. $documentId = add_document(
  494. $courseInfo,
  495. $filePath,
  496. 'file',
  497. $fileSize,
  498. $documentTitle,
  499. $comment,
  500. 0,
  501. true,
  502. $groupId,
  503. $sessionId
  504. );
  505. if ($documentId) {
  506. // Update document item_property
  507. api_item_property_update(
  508. $courseInfo,
  509. TOOL_DOCUMENT,
  510. $documentId,
  511. 'DocumentAdded',
  512. $userId,
  513. $groupId,
  514. $toUserId,
  515. null,
  516. null,
  517. $sessionId
  518. );
  519. // Redo visibility
  520. api_set_default_visibility($documentId, TOOL_DOCUMENT, null, $courseInfo);
  521. }
  522. // If the file is in a folder, we need to update all parent folders
  523. item_property_update_on_folder(
  524. $courseInfo,
  525. $uploadPath,
  526. $userId
  527. );
  528. // Display success message to user
  529. if ($output) {
  530. Display::display_confirmation_message(
  531. get_lang('UplUploadSucceeded').'<br /> '.$documentTitle,
  532. false
  533. );
  534. }
  535. return $filePath;
  536. } else {
  537. if ($output) {
  538. Display::display_error_message(get_lang('UplUnableToSaveFile'));
  539. }
  540. return false;
  541. }
  542. }
  543. break;
  544. }
  545. }
  546. }
  547. }
  548. /**
  549. * @param string $file
  550. * @param string $storePath
  551. *
  552. * @return bool
  553. */
  554. function moveUploadedFile($file, $storePath)
  555. {
  556. $handleFromFile = isset($file['from_file']) && $file['from_file'] ? true : false;
  557. $moveFile = isset($file['move_file']) && $file['move_file'] ? true : false;
  558. if ($moveFile) {
  559. copy($file['tmp_name'], $storePath);
  560. }
  561. if ($handleFromFile) {
  562. return file_exists($file['tmp_name']);
  563. } else {
  564. return move_uploaded_file($file['tmp_name'], $storePath);
  565. }
  566. }
  567. /**
  568. * Checks if there is enough place to add a file on a directory
  569. * on the base of a maximum directory size allowed
  570. * deprecated: use enough_space instead!
  571. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  572. * @param - file_size (int) - size of the file in byte
  573. * @param - dir (string) - Path of the directory
  574. * whe the file should be added
  575. * @param - max_dir_space (int) - maximum size of the diretory in byte
  576. * @return - boolean true if there is enough space,
  577. * boolean false otherwise
  578. *
  579. * @see - enough_size() uses dir_total_space() function
  580. */
  581. function enough_size($file_size, $dir, $max_dir_space)
  582. {
  583. // If the directory is the archive directory, safely ignore the size limit
  584. if (api_get_path(SYS_ARCHIVE_PATH) == $dir) {
  585. return true;
  586. }
  587. if ($max_dir_space) {
  588. $already_filled_space = dir_total_space($dir);
  589. if (($file_size + $already_filled_space) > $max_dir_space) {
  590. return false;
  591. }
  592. }
  593. return true;
  594. }
  595. /**
  596. * Computes the size already occupied by a directory and is subdirectories
  597. *
  598. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  599. * @param - dir_path (string) - size of the file in byte
  600. * @return - int - return the directory size in bytes
  601. */
  602. function dir_total_space($dir_path)
  603. {
  604. $save_dir = getcwd();
  605. chdir($dir_path) ;
  606. $handle = opendir($dir_path);
  607. $sumSize = 0;
  608. $dirList = array();
  609. while ($element = readdir($handle)) {
  610. if ( $element == '.' || $element == '..') {
  611. continue; // Skip the current and parent directories
  612. }
  613. if (is_file($element)) {
  614. $sumSize += filesize($element);
  615. }
  616. if (is_dir($element)) {
  617. $dirList[] = $dir_path.'/'.$element;
  618. }
  619. }
  620. closedir($handle) ;
  621. if (sizeof($dirList) > 0) {
  622. foreach ($dirList as $j) {
  623. $sizeDir = dir_total_space($j); // Recursivity
  624. $sumSize += $sizeDir;
  625. }
  626. }
  627. chdir($save_dir); // Return to initial position
  628. return $sumSize;
  629. }
  630. /**
  631. * Tries to add an extension to files without extension
  632. * Some applications on Macintosh computers don't add an extension to the files.
  633. * This subroutine try to fix this on the basis of the MIME type sent
  634. * by the browser.
  635. *
  636. * Note : some browsers don't send the MIME Type (e.g. Netscape 4).
  637. * We don't have solution for this kind of situation
  638. *
  639. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  640. * @author - Bert Vanderkimpen
  641. * @param - file_name (string) - Name of the file
  642. * @param - file_type (string) - Type of the file
  643. * @return - file_name (string)
  644. */
  645. function add_ext_on_mime($file_name, $file_type)
  646. {
  647. // Check whether the file has an extension AND whether the browser has sent a MIME Type
  648. if (!preg_match('/^.*\.[a-zA-Z_0-9]+$/', $file_name) && $file_type) {
  649. // Build a "MIME-types / extensions" connection table
  650. static $mime_type = array();
  651. $mime_type[] = 'application/msword'; $extension[] = '.doc';
  652. $mime_type[] = 'application/rtf'; $extension[] = '.rtf';
  653. $mime_type[] = 'application/vnd.ms-powerpoint'; $extension[] = '.ppt';
  654. $mime_type[] = 'application/vnd.ms-excel'; $extension[] = '.xls';
  655. $mime_type[] = 'application/pdf'; $extension[] = '.pdf';
  656. $mime_type[] = 'application/postscript'; $extension[] = '.ps';
  657. $mime_type[] = 'application/mac-binhex40'; $extension[] = '.hqx';
  658. $mime_type[] = 'application/x-gzip'; $extension[] = 'tar.gz';
  659. $mime_type[] = 'application/x-shockwave-flash'; $extension[] = '.swf';
  660. $mime_type[] = 'application/x-stuffit'; $extension[] = '.sit';
  661. $mime_type[] = 'application/x-tar'; $extension[] = '.tar';
  662. $mime_type[] = 'application/zip'; $extension[] = '.zip';
  663. $mime_type[] = 'application/x-tar'; $extension[] = '.tar';
  664. $mime_type[] = 'text/html'; $extension[] = '.html';
  665. $mime_type[] = 'text/plain'; $extension[] = '.txt';
  666. $mime_type[] = 'text/rtf'; $extension[] = '.rtf';
  667. $mime_type[] = 'img/gif'; $extension[] = '.gif';
  668. $mime_type[] = 'img/jpeg'; $extension[] = '.jpg';
  669. $mime_type[] = 'img/png'; $extension[] = '.png';
  670. $mime_type[] = 'audio/midi'; $extension[] = '.mid';
  671. $mime_type[] = 'audio/mpeg'; $extension[] = '.mp3';
  672. $mime_type[] = 'audio/x-aiff'; $extension[] = '.aif';
  673. $mime_type[] = 'audio/x-pn-realaudio'; $extension[] = '.rm';
  674. $mime_type[] = 'audio/x-pn-realaudio-plugin'; $extension[] = '.rpm';
  675. $mime_type[] = 'audio/x-wav'; $extension[] = '.wav';
  676. $mime_type[] = 'video/mpeg'; $extension[] = '.mpg';
  677. $mime_type[] = 'video/mpeg4-generic'; $extension[] = '.mp4';
  678. $mime_type[] = 'video/quicktime'; $extension[] = '.mov';
  679. $mime_type[] = 'video/x-msvideo'; $extension[] = '.avi';
  680. $mime_type[] = 'video/x-ms-wmv'; $extension[] = '.wmv';
  681. $mime_type[] = 'video/x-flv'; $extension[] = '.flv';
  682. $mime_type[] = 'image/svg+xml'; $extension[] = '.svg';
  683. $mime_type[] = 'image/svg+xml'; $extension[] = '.svgz';
  684. $mime_type[] = 'video/ogg'; $extension[] = '.ogv';
  685. $mime_type[] = 'audio/ogg'; $extension[] = '.oga';
  686. $mime_type[] = 'application/ogg'; $extension[] = '.ogg';
  687. $mime_type[] = 'application/ogg'; $extension[] = '.ogx';
  688. $mime_type[] = 'application/x-freemind'; $extension[] = '.mm';
  689. $mime_type[] = 'application/vnd.ms-word.document.macroEnabled.12'; $extension[] = '.docm';
  690. $mime_type[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; $extension[] = '.docx';
  691. $mime_type[] = 'application/vnd.ms-word.template.macroEnabled.12'; $extension[] = '.dotm';
  692. $mime_type[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.template'; $extension[] = '.dotx';
  693. $mime_type[] = 'application/vnd.ms-powerpoint.template.macroEnabled.12'; $extension[] = '.potm';
  694. $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.template'; $extension[] = '.potx';
  695. $mime_type[] = 'application/vnd.ms-powerpoint.addin.macroEnabled.12'; $extension[] = '.ppam';
  696. $mime_type[] = 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12'; $extension[] = '.ppsm';
  697. $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.slideshow'; $extension[] = '.ppsx';
  698. $mime_type[] = 'application/vnd.ms-powerpoint.presentation.macroEnabled.12'; $extension[] = '.pptm';
  699. $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'; $extension[] = '.pptx';
  700. $mime_type[] = 'application/vnd.ms-excel.addin.macroEnabled.12'; $extension[] = '.xlam';
  701. $mime_type[] = 'application/vnd.ms-excel.sheet.binary.macroEnabled.12'; $extension[] = '.xlsb';
  702. $mime_type[] = 'application/vnd.ms-excel.sheet.macroEnabled.12'; $extension[] = '.xlsm';
  703. $mime_type[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; $extension[] = '.xlsx';
  704. $mime_type[] = 'application/vnd.ms-excel.template.macroEnabled.12'; $extension[] = '.xltm';
  705. $mime_type[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.template'; $extension[] = '.xltx';
  706. // Test on PC (files with no extension get application/octet-stream)
  707. //$mime_type[] = 'application/octet-stream'; $extension[] = '.ext';
  708. // Check whether the MIME type sent by the browser is within the table
  709. foreach ($mime_type as $key => & $type) {
  710. if ($type == $file_type) {
  711. $file_name .= $extension[$key];
  712. break;
  713. }
  714. }
  715. unset($mime_type, $extension, $type, $key); // Delete to eschew possible collisions
  716. }
  717. return $file_name;
  718. }
  719. /**
  720. * Manages all the unzipping process of an uploaded file
  721. *
  722. * @author Hugues Peeters <hugues.peeters@claroline.net>
  723. *
  724. * @param array $uploaded_file - follows the $_FILES Structure
  725. * @param string $upload_path - destination of the upload.
  726. * This path is to append to $base_work_dir
  727. * @param string $base_work_dir - base working directory of the module
  728. * @param int $max_filled_space - amount of bytes to not exceed in the base
  729. * working directory
  730. *
  731. * @return boolean true if it succeeds false otherwise
  732. */
  733. function unzip_uploaded_file($uploaded_file, $upload_path, $base_work_dir, $max_filled_space)
  734. {
  735. $zip_file = new PclZip($uploaded_file['tmp_name']);
  736. // Check the zip content (real size and file extension)
  737. if (file_exists($uploaded_file['tmp_name'])) {
  738. $zip_content_array = $zip_file->listContent();
  739. $ok_scorm = false;
  740. $realFileSize = 0;
  741. foreach ($zip_content_array as & $this_content) {
  742. if (preg_match('~.(php.*|phtml)$~i', $this_content['filename'])) {
  743. throw new \Exception('php_file_in_zip_file');
  744. } elseif (stristr($this_content['filename'], 'imsmanifest.xml')) {
  745. $ok_scorm = true;
  746. } elseif (stristr($this_content['filename'], 'LMS')) {
  747. $ok_plantyn_scorm1 = true;
  748. } elseif (stristr($this_content['filename'], 'REF')) {
  749. $ok_plantyn_scorm2 = true;
  750. } elseif (stristr($this_content['filename'], 'SCO')) {
  751. $ok_plantyn_scorm3 = true;
  752. } elseif (stristr($this_content['filename'], 'AICC')) {
  753. $ok_aicc_scorm = true;
  754. }
  755. $realFileSize += $this_content['size'];
  756. }
  757. if (($ok_plantyn_scorm1 && $ok_plantyn_scorm2 && $ok_plantyn_scorm3) || $ok_aicc_scorm) {
  758. $ok_scorm = true;
  759. }
  760. if (!$ok_scorm && defined('CHECK_FOR_SCORM') && CHECK_FOR_SCORM) {
  761. throw new \Exception(get_lang('ScormPackageFormatNotScorm'));
  762. }
  763. if (!enough_size($realFileSize, $base_work_dir, $max_filled_space)) {
  764. throw new \Exception(get_lang('ScormNotEnoughSpaceInCourseToInstallPackage'));
  765. }
  766. // It happens on Linux that $upload_path sometimes doesn't start with '/'
  767. if ($upload_path[0] != '/' && substr($base_work_dir,-1,1) != '/') {
  768. $upload_path = '/'.$upload_path;
  769. }
  770. if ($upload_path[strlen($upload_path) - 1] == '/') {
  771. $upload_path=substr($upload_path, 0, -1);
  772. }
  773. /* Uncompressing phase */
  774. /*
  775. The first version, using OS unzip, is not used anymore
  776. because it does not return enough information.
  777. We need to process each individual file in the zip archive to
  778. - add it to the database
  779. - parse & change relative html links
  780. */
  781. if (PHP_OS == 'Linux' && ! get_cfg_var('safe_mode') && false) { // *** UGent, changed by OC ***
  782. // Shell Method - if this is possible, it gains some speed
  783. exec("unzip -d \"".$base_work_dir.$upload_path."/\"".$uploaded_file['name']." " .$uploaded_file['tmp_name']);
  784. } else {
  785. // PHP method - slower...
  786. $save_dir = getcwd();
  787. chdir($base_work_dir.$upload_path);
  788. $unzippingState = $zip_file->extract();
  789. for ($j=0; $j < count($unzippingState); $j++) {
  790. $state = $unzippingState[$j];
  791. // Fix relative links in html files
  792. $extension = strrchr($state['stored_filename'], '.');
  793. }
  794. if ($dir = @opendir($base_work_dir.$upload_path)) {
  795. while ($file = readdir($dir)) {
  796. if ($file != '.' && $file != '..') {
  797. $filetype = 'file';
  798. if (is_dir($base_work_dir.$upload_path.'/'.$file)) $filetype = 'folder';
  799. $safe_file = api_replace_dangerous_char($file, 'strict');
  800. @rename($base_work_dir.$upload_path.'/'.$file,$base_work_dir.$upload_path.'/'.$safe_file);
  801. set_default_settings($upload_path, $safe_file,$filetype);
  802. }
  803. }
  804. closedir($dir);
  805. } else {
  806. error_log('Could not create directory '.$base_work_dir.$upload_path.' to unzip files');
  807. }
  808. chdir($save_dir); // Back to previous dir position
  809. }
  810. }
  811. return true;
  812. }
  813. /**
  814. * Manages all the unzipping process of an uploaded document
  815. * This uses the item_property table for properties of documents
  816. *
  817. * @author Hugues Peeters <hugues.peeters@claroline.net>
  818. * @author Bert Vanderkimpen
  819. *
  820. * @param array $courseInfo
  821. * @param array $userInfo
  822. * @param array $uploaded_file - follows the $_FILES Structure
  823. * @param string $upload_path - destination of the upload.
  824. * This path is to append to $base_work_dir
  825. * @param string $base_work_dir - base working directory of the module
  826. * @param int $maxFilledSpace - amount of bytes to not exceed in the base
  827. * working directory
  828. * @param int $sessionId
  829. * @param int $groupId
  830. * @param boolean $output Optional. If no output not wanted on success, set to false.
  831. *
  832. * @return boolean true if it succeeds false otherwise
  833. */
  834. function unzip_uploaded_document(
  835. $courseInfo,
  836. $userInfo,
  837. $uploaded_file,
  838. $uploadPath,
  839. $base_work_dir,
  840. $maxFilledSpace,
  841. $sessionId = 0,
  842. $groupId = 0,
  843. $output = true
  844. ) {
  845. $zip = new PclZip($uploaded_file['tmp_name']);
  846. // Check the zip content (real size and file extension)
  847. $zip_content_array = (array)$zip->listContent();
  848. $realSize = 0;
  849. foreach ($zip_content_array as & $this_content) {
  850. $realSize += $this_content['size'];
  851. }
  852. if (!DocumentManager::enough_space($realSize, $maxFilledSpace)) {
  853. Display::display_error_message(get_lang('UplNotEnoughSpace'));
  854. return false;
  855. }
  856. $folder = api_get_unique_id();
  857. $destinationDir = api_get_path(SYS_ARCHIVE_PATH).$folder;
  858. mkdir($destinationDir, api_get_permissions_for_new_directories(), true);
  859. /* Uncompress zip file*/
  860. // We extract using a callback function that "cleans" the path
  861. $zip->extract(
  862. PCLZIP_OPT_PATH,
  863. $destinationDir,
  864. PCLZIP_CB_PRE_EXTRACT,
  865. 'clean_up_files_in_zip',
  866. PCLZIP_OPT_REPLACE_NEWER
  867. );
  868. // Add all documents in the unzipped folder to the database
  869. add_all_documents_in_folder_to_database(
  870. $courseInfo,
  871. $userInfo,
  872. $base_work_dir,
  873. $destinationDir,
  874. $sessionId,
  875. $groupId,
  876. $output,
  877. array('path' => $uploadPath)
  878. );
  879. if (is_dir($destinationDir)) {
  880. rmdirr($destinationDir);
  881. }
  882. return true;
  883. }
  884. /**
  885. * This function is a callback function that is used while extracting a zipfile
  886. * http://www.phpconcept.net/pclzip/man/en/index.php?options-pclzip_cb_pre_extract
  887. *
  888. * @param $p_event
  889. * @param $p_header
  890. * @return 1 (If the function returns 1, then the extraction is resumed)
  891. */
  892. function clean_up_files_in_zip($p_event, &$p_header)
  893. {
  894. $res = clean_up_path($p_header['filename']);
  895. return $res;
  896. }
  897. /**
  898. * This function cleans up a given path
  899. * by eliminating dangerous file names and cleaning them
  900. *
  901. * @param string $path
  902. * @return $path
  903. * @see disable_dangerous_file()
  904. * @see api_replace_dangerous_char()
  905. */
  906. function clean_up_path(&$path)
  907. {
  908. // Split the path in folders and files
  909. $path_array = explode('/', $path);
  910. // Clean up every foler and filename in the path
  911. foreach ($path_array as $key => & $val) {
  912. // We don't want to lose the dots in ././folder/file (cfr. zipfile)
  913. if ($val != '.') {
  914. $val = disable_dangerous_file(api_replace_dangerous_char($val));
  915. }
  916. }
  917. // Join the "cleaned" path (modified in-place as passed by reference)
  918. $path = implode('/', $path_array);
  919. $res = filter_extension($path);
  920. return $res;
  921. }
  922. /**
  923. * Checks if the file is dangerous, based on extension and/or mimetype.
  924. * The list of extensions accepted/rejected can be found from
  925. * api_get_setting('upload_extensions_exclude') and api_get_setting('upload_extensions_include')
  926. * @param string filename passed by reference. The filename will be modified
  927. * if filter rules say so! (you can include path but the filename should look like 'abc.html')
  928. * @return int 0 to skip file, 1 to keep file
  929. */
  930. function filter_extension(&$filename)
  931. {
  932. if (substr($filename, -1) == '/') {
  933. return 1; // Authorize directories
  934. }
  935. $blacklist = api_get_setting('document.upload_extensions_list_type');
  936. if ($blacklist != 'whitelist') { // if = blacklist
  937. $extensions = explode(
  938. ';',
  939. strtolower(api_get_setting('document.upload_extensions_blacklist'))
  940. );
  941. $skip = api_get_setting('document.upload_extensions_skip');
  942. $ext = strrchr($filename, '.');
  943. $ext = substr($ext, 1);
  944. if (empty($ext)) {
  945. return 1; // We're in blacklist mode, so accept empty extensions
  946. }
  947. if (in_array(strtolower($ext), $extensions)) {
  948. if ($skip == 'true') {
  949. return 0;
  950. } else {
  951. $new_ext = api_get_setting(
  952. 'document.upload_extensions_replace_by'
  953. );
  954. $filename = str_replace('.'.$ext, '.'.$new_ext, $filename);
  955. return 1;
  956. }
  957. } else {
  958. return 1;
  959. }
  960. } else {
  961. $extensions = explode(
  962. ';',
  963. strtolower(api_get_setting('document.upload_extensions_whitelist'))
  964. );
  965. $skip = api_get_setting('document.upload_extensions_skip');
  966. $ext = strrchr($filename, '.');
  967. $ext = substr($ext, 1);
  968. if (empty($ext)) {
  969. return 1; // Accept empty extensions
  970. }
  971. if (!in_array(strtolower($ext), $extensions)) {
  972. if ($skip == 'true') {
  973. return 0;
  974. } else {
  975. $new_ext = api_get_setting(
  976. 'document.upload_extensions_replace_by'
  977. );
  978. $filename = str_replace('.'.$ext, '.'.$new_ext, $filename);
  979. return 1;
  980. }
  981. } else {
  982. return 1;
  983. }
  984. }
  985. }
  986. /**
  987. * Adds a new document to the database
  988. *
  989. * @param array $_course
  990. * @param string $path
  991. * @param string $filetype
  992. * @param int $filesize
  993. * @param string $title
  994. * @param string $comment
  995. * @param int $readonly
  996. * @param bool $save_visibility
  997. * @param int $group_id
  998. * @param int $session_id Session ID, if any
  999. * @param int $userId creator id
  1000. *
  1001. * @return int id if inserted document
  1002. */
  1003. function add_document(
  1004. $_course,
  1005. $path,
  1006. $filetype,
  1007. $filesize,
  1008. $title,
  1009. $comment = null,
  1010. $readonly = 0,
  1011. $save_visibility = true,
  1012. $group_id = null,
  1013. $session_id = 0,
  1014. $userId = 0
  1015. ) {
  1016. $session_id = empty($session_id) ? api_get_session_id() : $session_id;
  1017. $userId = empty($userId) ? api_get_user_id() : $userId;
  1018. $readonly = intval($readonly);
  1019. $c_id = $_course['real_id'];
  1020. $table_document = Database::get_course_table(TABLE_DOCUMENT);
  1021. $params = [
  1022. 'c_id' => $c_id,
  1023. 'path' => $path,
  1024. 'filetype' => $filetype,
  1025. 'size' => $filesize,
  1026. 'title' => $title,
  1027. 'comment' => $comment,
  1028. 'readonly' => $readonly,
  1029. 'session_id' => $session_id,
  1030. ];
  1031. $documentId = Database::insert($table_document, $params);
  1032. if ($documentId) {
  1033. $sql = "UPDATE $table_document SET id = iid WHERE iid = $documentId";
  1034. Database::query($sql);
  1035. if ($save_visibility) {
  1036. api_set_default_visibility($documentId, TOOL_DOCUMENT, $group_id, $_course, $session_id, $userId);
  1037. }
  1038. return $documentId;
  1039. } else {
  1040. return false;
  1041. }
  1042. }
  1043. /**
  1044. * Updates an existing document in the database
  1045. * as the file exists, we only need to change the size
  1046. *
  1047. * @param array $_course
  1048. * @param int $documentId
  1049. * @param int $filesize
  1050. * @param int $readonly
  1051. * @return boolean true /false
  1052. */
  1053. function update_existing_document($_course, $documentId, $filesize, $readonly = 0)
  1054. {
  1055. $document_table = Database::get_course_table(TABLE_DOCUMENT);
  1056. $documentId = intval($documentId);
  1057. $filesize = intval($filesize);
  1058. $readonly = intval($readonly);
  1059. $course_id = $_course['real_id'];
  1060. $sql = "UPDATE $document_table SET
  1061. size = '$filesize',
  1062. readonly = '$readonly'
  1063. WHERE c_id = $course_id AND id = $documentId";
  1064. if (Database::query($sql)) {
  1065. return true;
  1066. } else {
  1067. return false;
  1068. }
  1069. }
  1070. /**
  1071. * This function updates the last_edit_date, last edit user id on all folders in a given path
  1072. *
  1073. * @param array $_course
  1074. * @param string $path
  1075. * @param int $user_id
  1076. */
  1077. function item_property_update_on_folder($_course, $path, $user_id)
  1078. {
  1079. // If we are in the root, just return... no need to update anything
  1080. if ($path == '/') {
  1081. return;
  1082. }
  1083. $user_id = intval($user_id);
  1084. // If the given path ends with a / we remove it
  1085. $endchar = substr($path, strlen($path) - 1, 1);
  1086. if ($endchar == '/') {
  1087. $path = substr($path, 0, strlen($path) - 1);
  1088. }
  1089. $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
  1090. // Get the time
  1091. $time = date('Y-m-d H:i:s', time());
  1092. // Det all paths in the given path
  1093. // /folder/subfolder/subsubfolder/file
  1094. // if file is updated, subsubfolder, subfolder and folder are updated
  1095. $exploded_path = explode('/', $path);
  1096. $course_id = api_get_course_int_id();
  1097. $newpath = '';
  1098. foreach ($exploded_path as $key => & $value) {
  1099. // We don't want a slash before our first slash
  1100. if ($key != 0) {
  1101. $newpath .= '/'.$value;
  1102. //echo 'path= '.$newpath.'<br />';
  1103. // Select ID of given folder
  1104. $folder_id = DocumentManager::get_document_id($_course, $newpath);
  1105. if ($folder_id) {
  1106. $sql = "UPDATE $table SET
  1107. lastedit_date='$time',lastedit_type='DocumentInFolderUpdated', lastedit_user_id='$user_id'
  1108. WHERE c_id = $course_id AND tool='".TOOL_DOCUMENT."' AND ref='$folder_id'";
  1109. Database::query($sql);
  1110. }
  1111. }
  1112. }
  1113. }
  1114. /**
  1115. * Returns the directory depth of the file.
  1116. *
  1117. * @author Olivier Cauberghe <olivier.cauberghe@ugent.be>
  1118. * @param path+filename eg: /main/document/document.php
  1119. * @return The directory depth
  1120. */
  1121. function get_levels($filename) {
  1122. $levels = explode('/', $filename);
  1123. if (empty($levels[count($levels) - 1])) {
  1124. unset($levels[count($levels) - 1]);
  1125. }
  1126. return count($levels);
  1127. }
  1128. /**
  1129. * Adds file to document table in database
  1130. * deprecated: use file_set_default_settings instead
  1131. *
  1132. * @author Olivier Cauberghe <olivier.cauberghe@ugent.be>
  1133. * @param path,filename
  1134. * action: Adds an entry to the document table with the default settings.
  1135. */
  1136. function set_default_settings($upload_path, $filename, $filetype = 'file')
  1137. {
  1138. $dbTable = Database::get_course_table(TABLE_DOCUMENT);
  1139. global $default_visibility;
  1140. if (!$default_visibility) {
  1141. $default_visibility = 'v';
  1142. }
  1143. $filetype = Database::escape_string($filetype);
  1144. $upload_path = str_replace('\\', '/', $upload_path);
  1145. $upload_path = str_replace('//', '/', $upload_path);
  1146. if ($upload_path == '/') {
  1147. $upload_path='';
  1148. } elseif (!empty($upload_path) && $upload_path[0] != '/') {
  1149. $upload_path="/$upload_path";
  1150. }
  1151. $endchar = substr($filename, strlen($filename) - 1, 1);
  1152. if ($endchar == '/') {
  1153. $filename = substr($filename, 0, -1);
  1154. }
  1155. $filename = Database::escape_string($filename);
  1156. $query = "SELECT count(*) as bestaat FROM $dbTable
  1157. WHERE path='$upload_path/$filename'";
  1158. $result = Database::query($query);
  1159. $row = Database::fetch_array($result);
  1160. if ($row['bestaat'] > 0) {
  1161. $query = "UPDATE $dbTable SET
  1162. path='$upload_path/$filename',
  1163. visibility='$default_visibility',
  1164. filetype='$filetype'
  1165. WHERE path='$upload_path/$filename'";
  1166. } else {
  1167. $query = "INSERT INTO $dbTable (path,visibility,filetype)
  1168. VALUES('$upload_path/$filename','$default_visibility','$filetype')";
  1169. }
  1170. Database::query($query);
  1171. }
  1172. /**
  1173. * Retrieves the image path list in a html file
  1174. *
  1175. * @author Hugues Peeters <hugues.peeters@claroline.net>
  1176. * @param string $html_file
  1177. * @return array - images path list
  1178. */
  1179. function search_img_from_html($html_file) {
  1180. $img_path_list = array();
  1181. if (!$fp = fopen($html_file, 'r')) {
  1182. return ;
  1183. }
  1184. // Aearch and store occurences of the <img> tag in an array
  1185. $size_file = (filesize($html_file) === 0) ? 1 : filesize($html_file);
  1186. if (isset($fp) && $fp !== false) {
  1187. $buffer = fread($fp, $size_file);
  1188. if (strlen($buffer) >= 0 && $buffer !== false) {
  1189. //
  1190. } else {
  1191. die('<center>Can not read file.</center>');
  1192. }
  1193. } else {
  1194. die('<center>Can not read file.</center>');
  1195. }
  1196. $matches = array();
  1197. if (preg_match_all('~<[[:space:]]*img[^>]*>~i', $buffer, $matches)) {
  1198. $img_tag_list = $matches[0];
  1199. }
  1200. fclose ($fp);
  1201. unset($buffer);
  1202. // Search the image file path from all the <IMG> tag detected
  1203. if (sizeof($img_tag_list) > 0) {
  1204. foreach ($img_tag_list as & $this_img_tag) {
  1205. if (preg_match('~src[[:space:]]*=[[:space:]]*[\"]{1}([^\"]+)[\"]{1}~i', $this_img_tag, $matches)) {
  1206. $img_path_list[] = $matches[1];
  1207. }
  1208. }
  1209. $img_path_list = array_unique($img_path_list); // Remove duplicate entries
  1210. }
  1211. return $img_path_list;
  1212. }
  1213. /**
  1214. * Creates a new directory trying to find a directory name
  1215. * that doesn't already exist
  1216. * (we could use unique_name() here...)
  1217. *
  1218. * @author Hugues Peeters <hugues.peeters@claroline.net>
  1219. * @author Bert Vanderkimpen
  1220. * @param array $_course current course information
  1221. * @param int $user_id current user id
  1222. * @param int $session_id
  1223. * @param int $to_group_id
  1224. * @param int $to_user_id
  1225. * @param string $base_work_dir /var/www/chamilo/courses/ABC/document
  1226. * @param string $desired_dir_name complete path of the desired name
  1227. * Example: /folder1/folder2
  1228. * @param string $title "folder2"
  1229. * @param int $visibility (0 for invisible, 1 for visible, 2 for deleted)
  1230. * @param bool $generateNewNameIfExists
  1231. * @return string actual directory name if it succeeds,
  1232. * boolean false otherwise
  1233. */
  1234. function create_unexisting_directory(
  1235. $_course,
  1236. $user_id,
  1237. $session_id,
  1238. $to_group_id,
  1239. $to_user_id,
  1240. $base_work_dir,
  1241. $desired_dir_name,
  1242. $title = null,
  1243. $visibility = null,
  1244. $generateNewNameIfExists = false
  1245. ) {
  1246. $course_id = $_course['real_id'];
  1247. $session_id = intval($session_id);
  1248. $folderExists = DocumentManager::folderExists(
  1249. $desired_dir_name,
  1250. $_course,
  1251. $session_id,
  1252. $to_group_id
  1253. );
  1254. if ($folderExists === true) {
  1255. if ($generateNewNameIfExists) {
  1256. $counter = 1;
  1257. while (1) {
  1258. $folderExists = DocumentManager::folderExists(
  1259. $desired_dir_name.'_'.$counter,
  1260. $_course,
  1261. $session_id,
  1262. $to_group_id
  1263. );
  1264. if ($folderExists === false) {
  1265. break;
  1266. }
  1267. $counter++;
  1268. }
  1269. $desired_dir_name = $desired_dir_name.'_'.$counter;
  1270. } else {
  1271. return false;
  1272. }
  1273. }
  1274. $systemFolderName = $desired_dir_name;
  1275. // Adding suffix
  1276. $suffix = DocumentManager::getDocumentSuffix(
  1277. $_course,
  1278. $session_id,
  1279. $to_group_id
  1280. );
  1281. $systemFolderName .= $suffix;
  1282. if ($title == null) {
  1283. $title = basename($desired_dir_name);
  1284. }
  1285. if (!is_dir($base_work_dir.$systemFolderName)) {
  1286. $result = mkdir(
  1287. $base_work_dir . $systemFolderName,
  1288. api_get_permissions_for_new_directories(),
  1289. true
  1290. );
  1291. if ($result) {
  1292. // Check if pathname already exists inside document table
  1293. $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
  1294. $sql = "SELECT id, path FROM $tbl_document
  1295. WHERE
  1296. c_id = $course_id AND
  1297. (
  1298. path = '" . $systemFolderName . "'
  1299. )
  1300. ";
  1301. $rs = Database::query($sql);
  1302. if (Database::num_rows($rs) == 0) {
  1303. $document_id = add_document(
  1304. $_course,
  1305. $systemFolderName,
  1306. 'folder',
  1307. 0,
  1308. $title,
  1309. null,
  1310. 0,
  1311. true,
  1312. $to_group_id,
  1313. $session_id,
  1314. $user_id
  1315. );
  1316. if ($document_id) {
  1317. // Update document item_property
  1318. if (!empty($visibility)) {
  1319. $visibilities = array(
  1320. 0 => 'invisible',
  1321. 1 => 'visible',
  1322. 2 => 'delete'
  1323. );
  1324. api_item_property_update(
  1325. $_course,
  1326. TOOL_DOCUMENT,
  1327. $document_id,
  1328. $visibilities[$visibility],
  1329. $user_id,
  1330. $to_group_id,
  1331. $to_user_id,
  1332. null,
  1333. null,
  1334. $session_id
  1335. );
  1336. } else {
  1337. api_item_property_update(
  1338. $_course,
  1339. TOOL_DOCUMENT,
  1340. $document_id,
  1341. 'FolderCreated',
  1342. $user_id,
  1343. $to_group_id,
  1344. $to_user_id,
  1345. null,
  1346. null,
  1347. $session_id
  1348. );
  1349. }
  1350. $documentData = DocumentManager::get_document_data_by_id(
  1351. $document_id,
  1352. $_course['code'],
  1353. false,
  1354. $session_id
  1355. );
  1356. return $documentData;
  1357. }
  1358. } else {
  1359. $document = Database::fetch_array($rs);
  1360. $documentData = DocumentManager::get_document_data_by_id(
  1361. $document['id'],
  1362. $_course['code'],
  1363. false,
  1364. $session_id
  1365. );
  1366. /* This means the folder NOT exist in the filesystem
  1367. (now this was created) but there is a record in the Database*/
  1368. return $documentData;
  1369. }
  1370. }
  1371. }
  1372. return false;
  1373. }
  1374. /**
  1375. * Handles uploaded missing images
  1376. *
  1377. * @author Hugues Peeters <hugues.peeters@claroline.net>
  1378. * @author Bert Vanderkimpen
  1379. * @param array $_course
  1380. * @param array $uploaded_file_collection - follows the $_FILES Structure
  1381. * @param string $base_work_dir
  1382. * @param string $missing_files_dir
  1383. * @param int $user_id
  1384. * @param int $max_filled_space
  1385. */
  1386. function move_uploaded_file_collection_into_directory(
  1387. $_course,
  1388. $uploaded_file_collection,
  1389. $base_work_dir,
  1390. $missing_files_dir,
  1391. $user_id,
  1392. $to_group_id,
  1393. $to_user_id,
  1394. $max_filled_space
  1395. ) {
  1396. $number_of_uploaded_images = count($uploaded_file_collection['name']);
  1397. $new_file_list = array();
  1398. for ($i = 0; $i < $number_of_uploaded_images; $i++) {
  1399. $missing_file['name'] = $uploaded_file_collection['name'][$i];
  1400. $missing_file['type'] = $uploaded_file_collection['type'][$i];
  1401. $missing_file['tmp_name'] = $uploaded_file_collection['tmp_name'][$i];
  1402. $missing_file['error'] = $uploaded_file_collection['error'][$i];
  1403. $missing_file['size'] = $uploaded_file_collection['size'][$i];
  1404. $upload_ok = process_uploaded_file($missing_file);
  1405. if ($upload_ok) {
  1406. $new_file_list[] = handle_uploaded_document(
  1407. $_course,
  1408. $missing_file,
  1409. $base_work_dir,
  1410. $missing_files_dir,
  1411. $user_id,
  1412. $to_group_id,
  1413. $to_user_id,
  1414. $max_filled_space,
  1415. 0,
  1416. 'overwrite'
  1417. );
  1418. }
  1419. unset($missing_file);
  1420. }
  1421. return $new_file_list;
  1422. }
  1423. /**
  1424. * Opens the old html file and replace the src path into the img tag
  1425. * This also works for files in subdirectories.
  1426. * @param $original_img_path is an array
  1427. * @param $new_img_path is an array
  1428. */
  1429. function replace_img_path_in_html_file($original_img_path, $new_img_path, $html_file)
  1430. {
  1431. // Open the file
  1432. $fp = fopen($html_file, 'r');
  1433. $buffer = fread($fp, filesize($html_file));
  1434. $new_html_content = '';
  1435. // Fix the image tags
  1436. for ($i = 0, $fileNb = count($original_img_path); $i < $fileNb ; $i++) {
  1437. $replace_what = $original_img_path[$i];
  1438. // We only need the directory and the filename /path/to/file_html_files/missing_file.gif -> file_html_files/missing_file.gif
  1439. $exploded_file_path = explode('/', $new_img_path[$i]);
  1440. $replace_by = $exploded_file_path[count($exploded_file_path) - 2].'/'.$exploded_file_path[count($exploded_file_path) - 1];
  1441. $buffer = str_replace($replace_what, $replace_by, $buffer);
  1442. }
  1443. $new_html_content .= $buffer;
  1444. @fclose($fp);
  1445. // Write the resulted new file
  1446. if (!$fp = fopen($html_file, 'w')) {
  1447. return;
  1448. }
  1449. if (!fwrite($fp, $new_html_content)) {
  1450. return;
  1451. }
  1452. }
  1453. /**
  1454. * Creates a file containing an html redirection to a given url
  1455. *
  1456. * @author Hugues Peeters <hugues.peeters@claroline.net>
  1457. * @param string $file_path
  1458. * @param string $url
  1459. * @return void
  1460. */
  1461. function create_link_file($file_path, $url)
  1462. {
  1463. $file_content = '<html>'
  1464. .'<head>'
  1465. .'<meta http-equiv="refresh" content="1;url='.$url.'">'
  1466. .'</head>'
  1467. .'<body>'
  1468. .'</body>'
  1469. .'</html>';
  1470. if (file_exists($file_path)) {
  1471. if (!($fp = fopen ($file_path, 'w'))) {
  1472. return false;
  1473. }
  1474. return fwrite($fp, $file_content);
  1475. }
  1476. }
  1477. /**
  1478. * Opens html file $full_file_name;
  1479. * Parses the hyperlinks; and
  1480. * Writes the result back in the html file.
  1481. *
  1482. * @author Roan Embrechts
  1483. * @version 0.1
  1484. */
  1485. function api_replace_links_in_html($upload_path, $full_file_name)
  1486. {
  1487. // Open the file
  1488. if (file_exists($full_file_name)) {
  1489. $fp = fopen($full_file_name, 'r');
  1490. $buffer = fread ($fp, filesize ($full_file_name));
  1491. // Parse the contents
  1492. $new_html_content = api_replace_links_in_string($upload_path, $buffer);
  1493. // Write the result
  1494. $fp = fopen($full_file_name, 'w');
  1495. fwrite($fp, $new_html_content);
  1496. }
  1497. }
  1498. /**
  1499. deprecated: use api_replace_parameter instead
  1500. Parse the buffer string provided as parameter
  1501. Replace the a href tags so they are displayed correctly.
  1502. - works for files in root and subdirectories
  1503. - replace relative hyperlinks to use showinframes.php?file= ...
  1504. - add target="_self" to all absolute hyperlinks
  1505. - leave local anchors untouched (e.g. #CHAPTER1)
  1506. - leave links with download.php and showinframes.php untouched
  1507. @author Roan Embrechts
  1508. @version 0.6
  1509. */
  1510. function api_replace_links_in_string($upload_path, $buffer) {
  1511. // Search for hyperlinks
  1512. $matches = array();
  1513. if (preg_match_all('/<a[\s]*href[^<]*>/i', $buffer, $matches)) {
  1514. $tag_list = $matches[0];
  1515. }
  1516. // Search the filepath of all detected <a href> tags
  1517. if (sizeof($tag_list) > 0) {
  1518. $file_path_list = array();
  1519. $href_list = array();
  1520. foreach ($tag_list as & $this_tag) {
  1521. /* Match case insensitive, the stuff between the two ~ :
  1522. a href = <exactly one quote><one or more non-quotes><exactly one ">
  1523. e.g. a href="www.google.be", A HREF = "info.html"
  1524. to match ["] escape the " or else PHP interprets it
  1525. [\"]{1} --> matches exactly one "
  1526. + 1 or more (like * is 0 or more)
  1527. [\s]* matches whitespace
  1528. $matches contains captured subpatterns
  1529. the only one here is ([^\"]+) --> matches[1]
  1530. */
  1531. if (preg_match("~a href[\s]*=[\s]*[\"]{1}([^\"]+)[\"]{1}~i", $this_tag, $matches)) {
  1532. $file_path_list[] = $matches[1]; // older
  1533. $href_list[] = $matches[0]; // to also add target="_self"
  1534. }
  1535. }
  1536. }
  1537. // Replace the original hyperlinks by the correct ones
  1538. for ($count = 0; $count < sizeof($href_list); $count++) {
  1539. $replace_what[$count] = $href_list[$count];
  1540. $is_absolute_hyperlink = strpos($replace_what[$count], 'http');
  1541. $is_local_anchor = strpos($replace_what[$count], "#");
  1542. if (!$is_absolute_hyperlink && !$is_local_anchor) {
  1543. // This is a relative hyperlink
  1544. if ((strpos($replace_what[$count], 'showinframes.php') === false) &&
  1545. (strpos($replace_what[$count], 'download.php') === false)
  1546. ) {
  1547. // Fix the link to use showinframes.php
  1548. $replace_by[$count] = 'a href = "showinframes.php?file='.$upload_path.'/'.$file_path_list[$count].'" target="_self"';
  1549. } else {
  1550. // URL has been already fixed, leave it as is
  1551. $replace_by[$count] = $replace_what[$count];
  1552. }
  1553. } elseif ($is_absolute_hyperlink) {
  1554. $replace_by[$count] = 'a href="'.$file_path_list[$count].'" target ="_self"';
  1555. } else {
  1556. // Don't change anything
  1557. $replace_by[$count] = $replace_what[$count];
  1558. }
  1559. //Display::display_normal_message('Link replaced by ' . $replace_by[$count]); // debug
  1560. }
  1561. $buffer = str_replace($replace_what, $replace_by, $buffer);
  1562. return $buffer;
  1563. }
  1564. /**
  1565. EXPERIMENTAL - function seems to work, needs more testing
  1566. @param $upload_path is the path where the document is stored, like "/archive/"
  1567. if it is the root level, the function expects "/"
  1568. otherwise "/path/"
  1569. This function parses all tags with $param_name parameters.
  1570. so the tags are displayed correctly.
  1571. --------------
  1572. Algorithm v1.0
  1573. --------------
  1574. given a string and a parameter,
  1575. * OK find all tags in that string with the specified parameter (like href or src)
  1576. * OK for every one of these tags, find the src|href|... part to edit it
  1577. * OK change the src|href|... part to use download.php (or showinframes.php)
  1578. * OK do some special stuff for hyperlinks
  1579. Exceptions
  1580. * OK if download.php or showinframes.php is already in the tag, leave it alone
  1581. * OK if mailto is in the tag, leave it alone
  1582. * OK if the src|href param contains http://, it's absolute --> leave it alone
  1583. Special for hyperlinks (a href...)
  1584. * OK add target="_self"
  1585. * OK use showinframes.php instead of download.php
  1586. @author Roan Embrechts
  1587. @version 1.1
  1588. */
  1589. function api_replace_parameter($upload_path, $buffer, $param_name = 'src')
  1590. {
  1591. // Search for tags with $param_name as a parameter
  1592. /*
  1593. // [\s]* matches whitespace
  1594. // [\"=a-z] matches ", = and a-z
  1595. // ([\s]*[a-z]*)* matches all whitespace and normal alphabet
  1596. // characters a-z combinations but seems too slow
  1597. // perhaps ([\s]*[a-z]*) a maximum number of times ?
  1598. // [\s]*[a-z]*[\s]* matches many tags
  1599. // the ending "i" means to match case insensitive (a matches a and A)
  1600. */
  1601. $matches = array();
  1602. if (preg_match_all('/<[a-z]+[^<]*'.$param_name.'[^<]*>/i', $buffer, $matches)) {
  1603. $tag_list = $matches[0];
  1604. }
  1605. // Search the filepath of parameter $param_name in all detected tags
  1606. if (sizeof($tag_list) > 0) {
  1607. $file_path_list = array();
  1608. $href_list = array();
  1609. foreach ($tag_list as & $this_tag) {
  1610. //Display::display_normal_message(htmlentities($this_tag)); //debug
  1611. if ( preg_match("~".$param_name."[\s]*=[\s]*[\"]{1}([^\"]+)[\"]{1}~i", $this_tag, $matches)) {
  1612. $file_path_list[] = $matches[1]; // older
  1613. $href_list[] = $matches[0]; // to also add target="_self"
  1614. }
  1615. }
  1616. }
  1617. // Replace the original tags by the correct ones
  1618. for ($count = 0; $count < sizeof($href_list); $count++) {
  1619. $replace_what[$count] = $href_list[$count];
  1620. $is_absolute_hyperlink = strpos($replace_what[$count], 'http');
  1621. $is_local_anchor = strpos($replace_what[$count], '#');
  1622. if (!$is_absolute_hyperlink && !$is_local_anchor) {
  1623. if ((strpos($replace_what[$count], 'showinframes.php') === false)
  1624. && (strpos($replace_what[$count], 'download.php') === false)
  1625. && (strpos($replace_what[$count], 'mailto') === false)) {
  1626. // Fix the link to use download.php or showinframes.php
  1627. if (preg_match("/<a([\s]*[\"\/:'=a-z0-9]*){5}href[^<]*>/i", $tag_list[$count])) {
  1628. $replace_by[$count] = " $param_name =\"showinframes.php?file=" . $upload_path.$file_path_list[$count]."\" target=\"_self\" ";
  1629. } else {
  1630. $replace_by[$count] = " $param_name =\"download.php?doc_url=" . $upload_path.$file_path_list[$count]."\" ";
  1631. }
  1632. } else {
  1633. // "mailto" or url already fixed, leave as is
  1634. //$message .= "Already fixed or contains mailto: ";
  1635. $replace_by[$count] = $replace_what[$count];
  1636. }
  1637. } elseif ($is_absolute_hyperlink) {
  1638. //$message .= "Absolute hyperlink, don't change, add target=_self: ";
  1639. $replace_by[$count] = " $param_name=\"" . $file_path_list[$count] . "\" target =\"_self\"";
  1640. } else {
  1641. // Don't change anything
  1642. //$message .= "Local anchor, don't change: ";
  1643. $replace_by[$count] = $replace_what[$count];
  1644. }
  1645. //$message .= "In tag $count, <b>" . htmlentities($tag_list[$count])
  1646. // . "</b>, parameter <b>" . $replace_what[$count] . "</b> replaced by <b>" . $replace_by[$count] . "</b><br>"; //debug
  1647. }
  1648. //if ($message) api_display_debug_info($message); //debug
  1649. $buffer = str_replace($replace_what, $replace_by, $buffer);
  1650. return $buffer;
  1651. }
  1652. /**
  1653. * Checks the extension of a file, if it's .htm or .html
  1654. * we use search_img_from_html to get all image paths in the file
  1655. *
  1656. * @param string $file
  1657. * @return array paths
  1658. * @see check_for_missing_files() uses search_img_from_html()
  1659. */
  1660. function check_for_missing_files($file)
  1661. {
  1662. if (strrchr($file, '.') == '.htm' || strrchr($file, '.') == '.html') {
  1663. $img_file_path = search_img_from_html($file);
  1664. return $img_file_path;
  1665. }
  1666. return false;
  1667. }
  1668. /**
  1669. * This function builds a form that asks for the missing images in a html file
  1670. * maybe we should do this another way?
  1671. *
  1672. * @param array $missing_files
  1673. * @param string $upload_path
  1674. * @param string $file_name
  1675. * @return string the form
  1676. */
  1677. function build_missing_files_form($missing_files, $upload_path, $file_name)
  1678. {
  1679. // Do we need a / or not?
  1680. $added_slash = ($upload_path == '/') ? '' : '/';
  1681. $folder_id = DocumentManager::get_document_id(api_get_course_info(), $upload_path);
  1682. // Build the form
  1683. $form = "<p><strong>".get_lang('MissingImagesDetected')."</strong></p>"
  1684. ."<form method=\"post\" action=\"".api_get_self()."\" enctype=\"multipart/form-data\">"
  1685. // Related_file is the path to the file that has missing images
  1686. ."<input type=\"hidden\" name=\"related_file\" value=\"".$upload_path.$added_slash.$file_name."\" />"
  1687. ."<input type=\"hidden\" name=\"upload_path\" value=\"".$upload_path."\" />"
  1688. ."<input type=\"hidden\" name=\"id\" value=\"".$folder_id."\" />"
  1689. ."<table border=\"0\">";
  1690. foreach ($missing_files as & $this_img_file_path) {
  1691. $form .= "<tr>"
  1692. ."<td>".basename($this_img_file_path)." : </td>"
  1693. ."<td>"
  1694. ."<input type=\"file\" name=\"img_file[]\"/>"
  1695. ."<input type=\"hidden\" name=\"img_file_path[]\" value=\"".$this_img_file_path."\" />"
  1696. ."</td>"
  1697. ."</tr>";
  1698. }
  1699. $form .= "</table>"
  1700. ."<button type='submit' name=\"cancel_submit_image\" value=\"".get_lang('Cancel')."\" class=\"cancel\">".get_lang('Cancel')."</button>"
  1701. ."<button type='submit' name=\"submit_image\" value=\"".get_lang('Ok')."\" class=\"save\">".get_lang('Ok')."</button>"
  1702. ."</form>";
  1703. return $form;
  1704. }
  1705. /**
  1706. * This recursive function can be used during the upgrade process form older
  1707. * versions of Chamilo
  1708. * It crawls the given directory, checks if the file is in the DB and adds
  1709. * it if it's not
  1710. *
  1711. * @param array $courseInfo
  1712. * @param array $userInfo
  1713. * @param string $base_work_dir
  1714. * @param string $folderPath
  1715. * @param int $sessionId
  1716. * @param int $groupId
  1717. * @param bool $output
  1718. * @param array $parent
  1719. * @param string $uploadPath
  1720. *
  1721. */
  1722. function add_all_documents_in_folder_to_database(
  1723. $courseInfo,
  1724. $userInfo,
  1725. $base_work_dir,
  1726. $folderPath,
  1727. $sessionId = 0,
  1728. $groupId = 0,
  1729. $output = false,
  1730. $parent = array()
  1731. ) {
  1732. if (empty($userInfo) || empty($courseInfo)) {
  1733. return false;
  1734. }
  1735. $userId = $userInfo['user_id'];
  1736. // Open dir
  1737. $handle = opendir($folderPath);
  1738. $files = array();
  1739. if (is_dir($folderPath)) {
  1740. // Run trough
  1741. while ($file = readdir($handle)) {
  1742. if ($file == '.' || $file == '..') {
  1743. continue;
  1744. }
  1745. $parentPath = null;
  1746. if (!empty($parent) && isset($parent['path'])) {
  1747. $parentPath = $parent['path'];
  1748. if ($parentPath == '/') {
  1749. $parentPath = null;
  1750. }
  1751. }
  1752. $completePath = $parentPath.'/'.$file;
  1753. $sysFolderPath = $folderPath.'/'.$file;
  1754. // Is directory?
  1755. if (is_dir($sysFolderPath)) {
  1756. $newFolderData = create_unexisting_directory(
  1757. $courseInfo,
  1758. $userId,
  1759. $sessionId,
  1760. $groupId,
  1761. null,
  1762. $base_work_dir,
  1763. $completePath,
  1764. null,
  1765. null,
  1766. true
  1767. );
  1768. $files[$file] = $newFolderData;
  1769. // Recursive
  1770. add_all_documents_in_folder_to_database(
  1771. $courseInfo,
  1772. $userInfo,
  1773. $base_work_dir,
  1774. $sysFolderPath,
  1775. $sessionId,
  1776. $groupId,
  1777. $output,
  1778. $newFolderData
  1779. );
  1780. } else {
  1781. // Rename
  1782. $uploadedFile = array(
  1783. 'name' => $file,
  1784. 'tmp_name' => $sysFolderPath,
  1785. 'size' => filesize($sysFolderPath),
  1786. 'type' => null,
  1787. 'from_file' => true,
  1788. 'move_file' => true
  1789. );
  1790. handle_uploaded_document(
  1791. $courseInfo,
  1792. $uploadedFile,
  1793. $base_work_dir,
  1794. $parentPath,
  1795. $userId,
  1796. $groupId,
  1797. null,
  1798. 0,
  1799. 'overwrite',
  1800. $output,
  1801. false,
  1802. null,
  1803. $sessionId
  1804. );
  1805. }
  1806. }
  1807. }
  1808. }