fileUpload.lib.php 72 KB

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