This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Elgg filestore. |
||
4 | * This file contains functions for saving and retrieving data from files. |
||
5 | * |
||
6 | * @package Elgg.Core |
||
7 | * @subpackage DataModel.FileStorage |
||
8 | */ |
||
9 | |||
10 | /** |
||
11 | * Get the size of the specified directory. |
||
12 | * |
||
13 | * @param string $dir The full path of the directory |
||
14 | * @param int $total_size Add to current dir size |
||
15 | * |
||
16 | * @return int The size of the directory in bytes |
||
17 | */ |
||
18 | function get_dir_size($dir, $total_size = 0) { |
||
19 | $handle = @opendir($dir); |
||
20 | while ($file = @readdir($handle)) { |
||
21 | if (in_array($file, array('.', '..'))) { |
||
22 | continue; |
||
23 | } |
||
24 | if (is_dir($dir . $file)) { |
||
25 | $total_size = get_dir_size($dir . $file . "/", $total_size); |
||
26 | } else { |
||
27 | $total_size += filesize($dir . $file); |
||
28 | } |
||
29 | } |
||
30 | @closedir($handle); |
||
0 ignored issues
–
show
|
|||
31 | |||
32 | return($total_size); |
||
33 | } |
||
34 | |||
35 | /** |
||
36 | * Get the contents of an uploaded file. |
||
37 | * (Returns false if there was an issue.) |
||
38 | * |
||
39 | * @param string $input_name The name of the file input field on the submission form |
||
40 | * |
||
41 | * @return mixed|false The contents of the file, or false on failure. |
||
42 | */ |
||
43 | function get_uploaded_file($input_name) { |
||
44 | $files = _elgg_services()->request->files; |
||
45 | if (!$files->has($input_name)) { |
||
46 | return false; |
||
47 | } |
||
48 | |||
49 | $file = $files->get($input_name); |
||
50 | if (empty($file)) { |
||
51 | // a file input was provided but no file uploaded |
||
52 | return false; |
||
53 | } |
||
54 | if ($file->getError() !== 0) { |
||
55 | return false; |
||
56 | } |
||
57 | |||
58 | return file_get_contents($file->getPathname()); |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * Gets the jpeg contents of the resized version of an uploaded image |
||
63 | * (Returns false if the uploaded file was not an image) |
||
64 | * |
||
65 | * @param string $input_name The name of the file input field on the submission form |
||
66 | * @param int $maxwidth The maximum width of the resized image |
||
67 | * @param int $maxheight The maximum height of the resized image |
||
68 | * @param bool $square If set to true, will take the smallest |
||
69 | * of maxwidth and maxheight and use it to set the |
||
70 | * dimensions on all size; the image will be cropped. |
||
71 | * @param bool $upscale Resize images smaller than $maxwidth x $maxheight? |
||
72 | * |
||
73 | * @return false|mixed The contents of the resized image, or false on failure |
||
74 | */ |
||
75 | function get_resized_image_from_uploaded_file($input_name, $maxwidth, $maxheight, |
||
76 | $square = false, $upscale = false) { |
||
77 | $files = _elgg_services()->request->files; |
||
78 | if (!$files->has($input_name)) { |
||
79 | return false; |
||
80 | } |
||
81 | |||
82 | $file = $files->get($input_name); |
||
83 | if (empty($file)) { |
||
84 | // a file input was provided but no file uploaded |
||
85 | return false; |
||
86 | } |
||
87 | if ($file->getError() !== 0) { |
||
88 | return false; |
||
89 | } |
||
90 | |||
91 | return get_resized_image_from_existing_file($file->getPathname(), $maxwidth, |
||
92 | $maxheight, $square, 0, 0, 0, 0, $upscale); |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * Gets the jpeg contents of the resized version of an already uploaded image |
||
97 | * (Returns false if the file was not an image) |
||
98 | * |
||
99 | * @param string $input_name The name of the file on the disk |
||
100 | * @param int $maxwidth The desired width of the resized image |
||
101 | * @param int $maxheight The desired height of the resized image |
||
102 | * @param bool $square If set to true, takes the smallest of maxwidth and |
||
103 | * maxheight and use it to set the dimensions on the new image. |
||
104 | * If no crop parameters are set, the largest square that fits |
||
105 | * in the image centered will be used for the resize. If square, |
||
106 | * the crop must be a square region. |
||
107 | * @param int $x1 x coordinate for top, left corner |
||
108 | * @param int $y1 y coordinate for top, left corner |
||
109 | * @param int $x2 x coordinate for bottom, right corner |
||
110 | * @param int $y2 y coordinate for bottom, right corner |
||
111 | * @param bool $upscale Resize images smaller than $maxwidth x $maxheight? |
||
112 | * |
||
113 | * @return false|mixed The contents of the resized image, or false on failure |
||
114 | */ |
||
115 | function get_resized_image_from_existing_file($input_name, $maxwidth, $maxheight, $square = false, |
||
116 | $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0, $upscale = false) { |
||
117 | |||
118 | // Get the size information from the image |
||
119 | $imgsizearray = getimagesize($input_name); |
||
120 | if ($imgsizearray == false) { |
||
121 | return false; |
||
122 | } |
||
123 | |||
124 | $width = $imgsizearray[0]; |
||
125 | $height = $imgsizearray[1]; |
||
126 | |||
127 | $accepted_formats = array( |
||
128 | 'image/jpeg' => 'jpeg', |
||
129 | 'image/pjpeg' => 'jpeg', |
||
130 | 'image/png' => 'png', |
||
131 | 'image/x-png' => 'png', |
||
132 | 'image/gif' => 'gif' |
||
133 | ); |
||
134 | |||
135 | // make sure the function is available |
||
136 | $load_function = "imagecreatefrom" . $accepted_formats[$imgsizearray['mime']]; |
||
137 | if (!is_callable($load_function)) { |
||
138 | return false; |
||
139 | } |
||
140 | |||
141 | // get the parameters for resizing the image |
||
142 | $options = array( |
||
143 | 'maxwidth' => $maxwidth, |
||
144 | 'maxheight' => $maxheight, |
||
145 | 'square' => $square, |
||
146 | 'upscale' => $upscale, |
||
147 | 'x1' => $x1, |
||
148 | 'y1' => $y1, |
||
149 | 'x2' => $x2, |
||
150 | 'y2' => $y2, |
||
151 | ); |
||
152 | $params = get_image_resize_parameters($width, $height, $options); |
||
153 | if ($params == false) { |
||
154 | return false; |
||
155 | } |
||
156 | |||
157 | // load original image |
||
158 | $original_image = call_user_func($load_function, $input_name); |
||
159 | if (!$original_image) { |
||
160 | return false; |
||
161 | } |
||
162 | |||
163 | // allocate the new image |
||
164 | $new_image = imagecreatetruecolor($params['newwidth'], $params['newheight']); |
||
165 | if (!$new_image) { |
||
166 | return false; |
||
167 | } |
||
168 | |||
169 | // color transparencies white (default is black) |
||
170 | imagefilledrectangle( |
||
171 | $new_image, 0, 0, $params['newwidth'], $params['newheight'], |
||
172 | imagecolorallocate($new_image, 255, 255, 255) |
||
173 | ); |
||
174 | |||
175 | $rtn_code = imagecopyresampled( $new_image, |
||
176 | $original_image, |
||
177 | 0, |
||
178 | 0, |
||
179 | $params['xoffset'], |
||
180 | $params['yoffset'], |
||
181 | $params['newwidth'], |
||
182 | $params['newheight'], |
||
183 | $params['selectionwidth'], |
||
184 | $params['selectionheight']); |
||
185 | if (!$rtn_code) { |
||
186 | return false; |
||
187 | } |
||
188 | |||
189 | // grab a compressed jpeg version of the image |
||
190 | ob_start(); |
||
191 | imagejpeg($new_image, null, 90); |
||
192 | $jpeg = ob_get_clean(); |
||
193 | |||
194 | imagedestroy($new_image); |
||
195 | imagedestroy($original_image); |
||
196 | |||
197 | return $jpeg; |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * Calculate the parameters for resizing an image |
||
202 | * |
||
203 | * @param int $width Width of the original image |
||
204 | * @param int $height Height of the original image |
||
205 | * @param array $options See $defaults for the options |
||
206 | * |
||
207 | * @return array or false |
||
208 | * @since 1.7.2 |
||
209 | */ |
||
210 | function get_image_resize_parameters($width, $height, $options) { |
||
211 | |||
212 | $defaults = array( |
||
213 | 'maxwidth' => 100, |
||
214 | 'maxheight' => 100, |
||
215 | |||
216 | 'square' => false, |
||
217 | 'upscale' => false, |
||
218 | |||
219 | 'x1' => 0, |
||
220 | 'y1' => 0, |
||
221 | 'x2' => 0, |
||
222 | 'y2' => 0, |
||
223 | ); |
||
224 | |||
225 | $options = array_merge($defaults, $options); |
||
226 | |||
227 | // Avoiding extract() because it hurts static analysis |
||
228 | $maxwidth = $options['maxwidth']; |
||
229 | $maxheight = $options['maxheight']; |
||
230 | $square = $options['square']; |
||
231 | $upscale = $options['upscale']; |
||
232 | $x1 = $options['x1']; |
||
233 | $y1 = $options['y1']; |
||
234 | $x2 = $options['x2']; |
||
235 | $y2 = $options['y2']; |
||
236 | |||
237 | // crop image first? |
||
238 | $crop = true; |
||
239 | View Code Duplication | if ($x1 == 0 && $y1 == 0 && $x2 == 0 && $y2 == 0) { |
|
240 | $crop = false; |
||
241 | } |
||
242 | |||
243 | // how large a section of the image has been selected |
||
244 | if ($crop) { |
||
245 | $selection_width = $x2 - $x1; |
||
246 | $selection_height = $y2 - $y1; |
||
247 | } else { |
||
248 | // everything selected if no crop parameters |
||
249 | $selection_width = $width; |
||
250 | $selection_height = $height; |
||
251 | } |
||
252 | |||
253 | // determine cropping offsets |
||
254 | if ($square) { |
||
255 | // asking for a square image back |
||
256 | |||
257 | // detect case where someone is passing crop parameters that are not for a square |
||
258 | if ($crop == true && $selection_width != $selection_height) { |
||
0 ignored issues
–
show
|
|||
259 | return false; |
||
260 | } |
||
261 | |||
262 | // size of the new square image |
||
263 | $new_width = $new_height = min($maxwidth, $maxheight); |
||
264 | |||
265 | // find largest square that fits within the selected region |
||
266 | $selection_width = $selection_height = min($selection_width, $selection_height); |
||
267 | |||
268 | // set offsets for crop |
||
269 | View Code Duplication | if ($crop) { |
|
270 | $widthoffset = $x1; |
||
271 | $heightoffset = $y1; |
||
272 | $width = $x2 - $x1; |
||
273 | $height = $width; |
||
274 | } else { |
||
275 | // place square region in the center |
||
276 | $widthoffset = floor(($width - $selection_width) / 2); |
||
277 | $heightoffset = floor(($height - $selection_height) / 2); |
||
278 | } |
||
279 | } else { |
||
280 | // non-square new image |
||
281 | $new_width = $maxwidth; |
||
282 | $new_height = $maxheight; |
||
283 | |||
284 | // maintain aspect ratio of original image/crop |
||
285 | View Code Duplication | if (($selection_height / (float)$new_height) > ($selection_width / (float)$new_width)) { |
|
286 | $new_width = floor($new_height * $selection_width / (float)$selection_height); |
||
287 | } else { |
||
288 | $new_height = floor($new_width * $selection_height / (float)$selection_width); |
||
289 | } |
||
290 | |||
291 | // by default, use entire image |
||
292 | $widthoffset = 0; |
||
293 | $heightoffset = 0; |
||
294 | |||
295 | if ($crop) { |
||
296 | $widthoffset = $x1; |
||
297 | $heightoffset = $y1; |
||
298 | } |
||
299 | } |
||
300 | |||
301 | if (!$upscale && ($selection_height < $new_height || $selection_width < $new_width)) { |
||
302 | // we cannot upscale and selected area is too small so we decrease size of returned image |
||
303 | if ($square) { |
||
304 | $new_height = $selection_height; |
||
305 | $new_width = $selection_width; |
||
306 | } else { |
||
307 | if ($selection_height < $new_height && $selection_width < $new_width) { |
||
308 | $new_height = $selection_height; |
||
309 | $new_width = $selection_width; |
||
310 | } |
||
311 | } |
||
312 | } |
||
313 | |||
314 | $params = array( |
||
315 | 'newwidth' => $new_width, |
||
316 | 'newheight' => $new_height, |
||
317 | 'selectionwidth' => $selection_width, |
||
318 | 'selectionheight' => $selection_height, |
||
319 | 'xoffset' => $widthoffset, |
||
320 | 'yoffset' => $heightoffset, |
||
321 | ); |
||
322 | |||
323 | return $params; |
||
324 | } |
||
325 | |||
326 | /** |
||
327 | * Delete an \ElggFile file |
||
328 | * |
||
329 | * @param int $guid \ElggFile GUID |
||
330 | * |
||
331 | * @return bool |
||
332 | */ |
||
333 | function file_delete($guid) { |
||
334 | $file = get_entity($guid); |
||
335 | if (!$file || !$file->canEdit()) { |
||
336 | return false; |
||
337 | } |
||
338 | |||
339 | $thumbnail = $file->thumbnail; |
||
340 | $smallthumb = $file->smallthumb; |
||
341 | $largethumb = $file->largethumb; |
||
342 | if ($thumbnail) { |
||
343 | $delfile = new \ElggFile(); |
||
344 | $delfile->owner_guid = $file->owner_guid; |
||
345 | $delfile->setFilename($thumbnail); |
||
346 | $delfile->delete(); |
||
347 | } |
||
348 | View Code Duplication | if ($smallthumb) { |
|
349 | $delfile = new \ElggFile(); |
||
350 | $delfile->owner_guid = $file->owner_guid; |
||
351 | $delfile->setFilename($smallthumb); |
||
352 | $delfile->delete(); |
||
353 | } |
||
354 | if ($largethumb) { |
||
355 | $delfile = new \ElggFile(); |
||
356 | $delfile->owner_guid = $file->owner_guid; |
||
357 | $delfile->setFilename($largethumb); |
||
358 | $delfile->delete(); |
||
359 | } |
||
360 | |||
361 | return $file->delete(); |
||
362 | } |
||
363 | |||
364 | /** |
||
365 | * Delete a directory and all its contents |
||
366 | * |
||
367 | * @param string $directory Directory to delete |
||
368 | * |
||
369 | * @return bool |
||
370 | */ |
||
371 | function delete_directory($directory) { |
||
372 | // sanity check: must be a directory |
||
373 | if (!$handle = opendir($directory)) { |
||
374 | return false; |
||
375 | } |
||
376 | |||
377 | // loop through all files |
||
378 | while (($file = readdir($handle)) !== false) { |
||
379 | if (in_array($file, array('.', '..'))) { |
||
380 | continue; |
||
381 | } |
||
382 | |||
383 | $path = "$directory/$file"; |
||
384 | if (is_dir($path)) { |
||
385 | // recurse down through directory |
||
386 | if (!delete_directory($path)) { |
||
387 | return false; |
||
388 | } |
||
389 | } else { |
||
390 | // delete file |
||
391 | unlink($path); |
||
392 | } |
||
393 | } |
||
394 | |||
395 | // remove empty directory |
||
396 | closedir($handle); |
||
397 | return rmdir($directory); |
||
398 | } |
||
399 | |||
400 | /** |
||
401 | * Removes all entity files |
||
402 | * |
||
403 | * @warning This only deletes the physical files and not their entities. |
||
404 | * This will result in FileExceptions being thrown. Don't use this function. |
||
405 | * |
||
406 | * @warning This must be kept in sync with \ElggDiskFilestore. |
||
407 | * |
||
408 | * @todo Remove this when all files are entities. |
||
409 | * |
||
410 | * @param \ElggEntity $entity An \ElggEntity |
||
411 | * |
||
412 | * @return void |
||
413 | * @access private |
||
414 | */ |
||
415 | function _elgg_clear_entity_files($entity) { |
||
416 | $dir = new \Elgg\EntityDirLocator($entity->guid); |
||
417 | $file_path = elgg_get_config('dataroot') . $dir; |
||
418 | if (file_exists($file_path)) { |
||
419 | delete_directory($file_path); |
||
420 | } |
||
421 | } |
||
422 | |||
423 | |||
424 | /// Variable holding the default datastore |
||
425 | $DEFAULT_FILE_STORE = null; |
||
426 | |||
427 | /** |
||
428 | * Return the default filestore. |
||
429 | * |
||
430 | * @return \ElggFilestore |
||
431 | */ |
||
432 | function get_default_filestore() { |
||
433 | global $DEFAULT_FILE_STORE; |
||
434 | |||
435 | return $DEFAULT_FILE_STORE; |
||
436 | } |
||
437 | |||
438 | /** |
||
439 | * Set the default filestore for the system. |
||
440 | * |
||
441 | * @param \ElggFilestore $filestore An \ElggFilestore object. |
||
442 | * |
||
443 | * @return true |
||
444 | */ |
||
445 | function set_default_filestore(\ElggFilestore $filestore) { |
||
446 | global $DEFAULT_FILE_STORE; |
||
447 | |||
448 | $DEFAULT_FILE_STORE = $filestore; |
||
449 | |||
450 | return true; |
||
451 | } |
||
452 | |||
453 | /** |
||
454 | * Returns the category of a file from its MIME type |
||
455 | * |
||
456 | * @param string $mime_type The MIME type |
||
457 | * |
||
458 | * @return string 'document', 'audio', 'video', or 'general' if the MIME type was unrecognized |
||
459 | * @since 1.10 |
||
460 | */ |
||
461 | function elgg_get_file_simple_type($mime_type) { |
||
462 | $params = array('mime_type' => $mime_type); |
||
463 | return elgg_trigger_plugin_hook('simple_type', 'file', $params, 'general'); |
||
464 | } |
||
465 | |||
466 | /** |
||
467 | * Initialize the file library. |
||
468 | * Listens to system init and configures the default filestore |
||
469 | * |
||
470 | * @return void |
||
471 | * @access private |
||
472 | */ |
||
473 | function _elgg_filestore_init() { |
||
474 | global $CONFIG; |
||
475 | |||
476 | // Now register a default filestore |
||
477 | if (isset($CONFIG->dataroot)) { |
||
478 | set_default_filestore(new \ElggDiskFilestore($CONFIG->dataroot)); |
||
479 | } |
||
480 | |||
481 | // Fix MIME type detection for Microsoft zipped formats |
||
482 | elgg_register_plugin_hook_handler('mime_type', 'file', '_elgg_filestore_detect_mimetype'); |
||
483 | |||
484 | // Parse category of file from MIME type |
||
485 | elgg_register_plugin_hook_handler('simple_type', 'file', '_elgg_filestore_parse_simpletype'); |
||
486 | |||
487 | // Unit testing |
||
488 | elgg_register_plugin_hook_handler('unit_test', 'system', '_elgg_filestore_test'); |
||
489 | } |
||
490 | |||
491 | /** |
||
492 | * Fix MIME type detection for Microsoft zipped formats |
||
493 | * |
||
494 | * @param string $hook "mime_type" |
||
495 | * @param string $type "file" |
||
496 | * @param string $mime_type Detected MIME type |
||
497 | * @param array $params Hook parameters |
||
498 | * |
||
499 | * @return string The MIME type |
||
500 | * @access private |
||
501 | */ |
||
502 | function _elgg_filestore_detect_mimetype($hook, $type, $mime_type, $params) { |
||
503 | |||
504 | $original_filename = elgg_extract('original_filename', $params); |
||
505 | |||
506 | $info = pathinfo($original_filename); |
||
507 | |||
508 | // hack for Microsoft zipped formats |
||
509 | $office_formats = array('docx', 'xlsx', 'pptx'); |
||
510 | View Code Duplication | if ($mime_type == "application/zip" && in_array($info['extension'], $office_formats)) { |
|
511 | switch ($info['extension']) { |
||
512 | case 'docx': |
||
513 | $mime_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; |
||
514 | break; |
||
515 | case 'xlsx': |
||
516 | $mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; |
||
517 | break; |
||
518 | case 'pptx': |
||
519 | $mime_type = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; |
||
520 | break; |
||
521 | } |
||
522 | } |
||
523 | |||
524 | // check for bad ppt detection |
||
525 | if ($mime_type == "application/vnd.ms-office" && $info['extension'] == "ppt") { |
||
526 | $mime_type = "application/vnd.ms-powerpoint"; |
||
527 | } |
||
528 | |||
529 | return $mime_type; |
||
530 | } |
||
531 | |||
532 | /** |
||
533 | * Parse a file category of file from a MIME type |
||
534 | * |
||
535 | * @param string $hook "simple_type" |
||
536 | * @param string $type "file" |
||
537 | * @param string $simple_type The category of file |
||
538 | * @param array $params Hook parameters |
||
539 | * |
||
540 | * @return string 'document', 'audio', 'video', or 'general' if the MIME type is unrecognized |
||
541 | * @access private |
||
542 | */ |
||
543 | function _elgg_filestore_parse_simpletype($hook, $type, $simple_type, $params) { |
||
544 | |||
545 | $mime_type = elgg_extract('mime_type', $params); |
||
546 | |||
547 | switch ($mime_type) { |
||
548 | case "application/msword": |
||
549 | case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": |
||
550 | case "application/pdf": |
||
551 | return "document"; |
||
552 | |||
553 | case "application/ogg": |
||
554 | return "audio"; |
||
555 | } |
||
556 | |||
557 | if (preg_match('~^(audio|image|video)/~', $mime_type, $m)) { |
||
558 | return $m[1]; |
||
559 | } |
||
560 | if (0 === strpos($mime_type, 'text/') || false !== strpos($mime_type, 'opendocument')) { |
||
561 | return "document"; |
||
562 | } |
||
563 | |||
564 | // unrecognized MIME |
||
565 | return $simple_type; |
||
566 | } |
||
567 | |||
568 | /** |
||
569 | * Unit tests for files |
||
570 | * |
||
571 | * @param string $hook unit_test |
||
572 | * @param string $type system |
||
573 | * @param mixed $value Array of tests |
||
574 | * |
||
575 | * @return array |
||
576 | * @access private |
||
577 | */ |
||
578 | function _elgg_filestore_test($hook, $type, $value) { |
||
579 | global $CONFIG; |
||
580 | $value[] = "{$CONFIG->path}engine/tests/ElggCoreFilestoreTest.php"; |
||
581 | return $value; |
||
582 | } |
||
583 | |||
584 | return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) { |
||
585 | $events->registerHandler('init', 'system', '_elgg_filestore_init', 100); |
||
586 | }; |
||
587 |
If you suppress an error, we recommend checking for the error condition explicitly: