fileUpload.lib.php 73 KB

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