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