These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * BULLETPROOF |
||
4 | * |
||
5 | * Bulletproof is a single-class library to upload images in PHP with security. |
||
6 | * |
||
7 | * PHP support 5.3+ |
||
8 | * |
||
9 | * @package bulletproof |
||
10 | * @version 3.1.0 |
||
11 | * @author https://twitter.com/_samayo |
||
12 | * @link https://github.com/samayo/bulletproof |
||
13 | * @license MIT |
||
14 | */ |
||
15 | namespace BulletProof; |
||
16 | |||
17 | class Image implements \ArrayAccess |
||
18 | { |
||
19 | /** |
||
20 | * @var string The new image name, to be provided or will be generated. |
||
21 | */ |
||
22 | protected $name; |
||
23 | |||
24 | /** |
||
25 | * @var int The image width in pixels |
||
26 | */ |
||
27 | protected $width; |
||
28 | |||
29 | /** |
||
30 | * @var int The image height in pixels |
||
31 | */ |
||
32 | protected $height; |
||
33 | |||
34 | /** |
||
35 | * @var string The image mime type (extension) |
||
36 | */ |
||
37 | protected $mime; |
||
38 | |||
39 | /** |
||
40 | * @var string The full image path (dir + image + mime) |
||
41 | */ |
||
42 | protected $fullPath; |
||
43 | |||
44 | /** |
||
45 | * @var string The folder or image storage location |
||
46 | */ |
||
47 | protected $location; |
||
48 | |||
49 | /** |
||
50 | * @var array A json format of all information about an image |
||
51 | */ |
||
52 | protected $serialize = array(); |
||
53 | |||
54 | /** |
||
55 | * @var array The min and max image size allowed for upload (in bytes) |
||
56 | */ |
||
57 | protected $size = array(100, 500000); |
||
58 | |||
59 | /** |
||
60 | * @var array The max height and width image allowed |
||
61 | */ |
||
62 | protected $dimensions = array(5000, 5000); |
||
63 | |||
64 | /** |
||
65 | * @var array The mime types allowed for upload |
||
66 | */ |
||
67 | protected $mimeTypes = array('jpeg', 'png', 'gif'); |
||
68 | |||
69 | /** |
||
70 | * @var array list of known image types |
||
71 | */ |
||
72 | protected $imageMimes = array( |
||
73 | 1 => 'gif', 'jpeg', 'png', 'swf', 'psd', |
||
74 | 'bmp', 'tiff', 'tiff', 'jpc', 'jp2', 'jpx', |
||
75 | 'jb2', 'swc', 'iff', 'wbmp', 'xbm', 'ico' |
||
76 | ); |
||
77 | |||
78 | /** |
||
79 | * @var array storage for the $_FILES global array |
||
80 | */ |
||
81 | private $_files = array(); |
||
82 | |||
83 | /** |
||
84 | * @var string storage for any errors |
||
85 | */ |
||
86 | private $error = ''; |
||
87 | |||
88 | /** |
||
89 | * @var array error messages strings |
||
90 | */ |
||
91 | protected $common_upload_errors = array( |
||
92 | UPLOAD_ERR_OK => '', |
||
93 | UPLOAD_ERR_INI_SIZE => 'Image is larger than the specified amount set by the server', |
||
94 | UPLOAD_ERR_FORM_SIZE => 'Image is larger than the specified amount specified by browser', |
||
95 | UPLOAD_ERR_PARTIAL => 'Image could not be fully uploaded. Please try again later', |
||
96 | UPLOAD_ERR_NO_FILE => 'Image is not found', |
||
97 | UPLOAD_ERR_NO_TMP_DIR => 'Can\'t write to disk, due to server configuration ( No tmp dir found )', |
||
98 | UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk. Please check you file permissions', |
||
99 | UPLOAD_ERR_EXTENSION => 'A PHP extension has halted this file upload process' |
||
100 | ); |
||
101 | |||
102 | /** |
||
103 | * @param array $_files represents the $_FILES array passed as dependency |
||
104 | */ |
||
105 | public function __construct(array $_files = array()) |
||
106 | { |
||
107 | /* check if php_exif is enabled */ |
||
108 | if (!function_exists('exif_imagetype')) { |
||
109 | $this->error = 'Function \'exif_imagetype\' Not found. Please enable \'php_exif\' in your PHP.ini'; |
||
110 | return null; |
||
111 | } |
||
112 | |||
113 | $this->_files = $_files; |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * Gets the real image mime type |
||
118 | * |
||
119 | * @param $tmp_name string The upload tmp directory |
||
120 | * |
||
121 | * @return null|string |
||
122 | */ |
||
123 | protected function getImageMime($tmp_name) |
||
124 | { |
||
125 | $mime = @$this->imageMimes[exif_imagetype($tmp_name)]; |
||
126 | |||
127 | if (!$mime) { |
||
128 | return null; |
||
129 | } |
||
130 | |||
131 | return $mime; |
||
132 | } |
||
133 | |||
134 | /** |
||
135 | * @param mixed $offset |
||
136 | * @param mixed $value |
||
137 | */ |
||
138 | public function offsetSet($offset, $value) |
||
139 | { |
||
140 | } |
||
141 | |||
142 | /** |
||
143 | * @param mixed $offset |
||
144 | * @return null |
||
145 | */ |
||
146 | public function offsetExists($offset) |
||
147 | { |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * @param mixed $offset |
||
152 | */ |
||
153 | public function offsetUnset($offset) |
||
154 | { |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Gets array value \ArrayAccess |
||
159 | * |
||
160 | * @param mixed $offset |
||
161 | * |
||
162 | * @return bool |
||
0 ignored issues
–
show
|
|||
163 | */ |
||
164 | public function offsetGet($offset) |
||
165 | { |
||
166 | if ($offset == 'error') { |
||
167 | return $this->error; |
||
168 | } |
||
169 | |||
170 | if(!isset($this->_files[$offset])){ |
||
171 | return ; |
||
172 | } |
||
173 | |||
174 | /* check for common upload errors */ |
||
175 | if ($this->_files[$offset]['error'] == 2) { |
||
176 | $this->error = "Image is larger than specified by the browser"; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
Image is larger than specified by the browser does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation.
Loading history...
|
|||
177 | return ; |
||
178 | } |
||
179 | |||
180 | if ($this->error || $this->error = $this->commonUploadErrors($this->_files[$offset]['error'])) { |
||
181 | return false; |
||
182 | } |
||
183 | |||
184 | if (isset($this->_files[$offset]) && file_exists($this->_files[$offset]['tmp_name'])) { |
||
185 | $this->_files = $this->_files[$offset]; |
||
186 | return true; |
||
187 | } |
||
188 | |||
189 | return false; |
||
190 | } |
||
191 | |||
192 | |||
193 | /** |
||
194 | * Provide image name if not provided |
||
195 | * |
||
196 | * @param null $isNameProvided |
||
197 | * @return $this |
||
198 | */ |
||
199 | public function setName($isNameProvided = null) |
||
200 | { |
||
201 | if ($isNameProvided) { |
||
202 | $this->name = filter_var($isNameProvided, FILTER_SANITIZE_STRING); |
||
203 | } |
||
204 | |||
205 | return $this; |
||
206 | } |
||
207 | |||
208 | /** |
||
209 | * Define a mime type for uploading |
||
210 | * |
||
211 | * @param array $fileTypes |
||
212 | * |
||
213 | * @return $this |
||
214 | */ |
||
215 | public function setMime(array $fileTypes) |
||
216 | { |
||
217 | $this->mimeTypes = $fileTypes; |
||
218 | return $this; |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * Define a min and max image size for uploading |
||
223 | * |
||
224 | * @param $min int minimum value in bytes |
||
225 | * @param $max int maximum value in bytes |
||
226 | * |
||
227 | * @return $this |
||
228 | */ |
||
229 | public function setSize($min, $max) |
||
230 | { |
||
231 | $this->size = array($min, $max); |
||
232 | return $this; |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * Creates a location for upload storage |
||
237 | * |
||
238 | * @param $dir string the folder name to create |
||
239 | * @param int $permission chmod permission |
||
240 | * |
||
241 | * @return $this |
||
242 | */ |
||
243 | public function setLocation($dir = 'bulletproof', $permission = 0666) |
||
244 | { |
||
245 | |||
246 | if (!file_exists($dir) && !is_dir($dir) && !$this->location) { |
||
247 | $createFolder = @mkdir('' . $dir, (int)$permission, true); |
||
248 | if (!$createFolder) { |
||
249 | $this->error = 'Error! Folder ' . $dir . ' could not be created'; |
||
250 | return false; |
||
251 | } |
||
252 | } |
||
253 | |||
254 | /* check if we can create a file in the directory */ |
||
255 | if (!is_writable($dir)) { |
||
256 | $this->error = "The images directory \"" . $dir . "\" is not writable!"; |
||
257 | return false; |
||
258 | } |
||
259 | |||
260 | $this->location = $dir; |
||
261 | return $this; |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * Sets acceptable max image height and width |
||
266 | * |
||
267 | * @param $maxWidth int max width value |
||
268 | * @param $maxHeight int max height value |
||
269 | * |
||
270 | * @return $this |
||
271 | */ |
||
272 | public function setDimension($maxWidth, $maxHeight) |
||
273 | { |
||
274 | $this->dimensions = array($maxWidth, $maxHeight); |
||
275 | return $this; |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * Returns the image name |
||
280 | * |
||
281 | * @return string |
||
282 | */ |
||
283 | public function getName() |
||
284 | { |
||
285 | if (!$this->name) { |
||
286 | return uniqid('', true) . '_' . str_shuffle(implode(range('e', 'q'))); |
||
287 | } |
||
288 | |||
289 | return $this->name; |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * Returns the full path of the image ex 'location/image.mime' |
||
294 | * |
||
295 | * @return string |
||
296 | */ |
||
297 | public function getFullPath() |
||
298 | { |
||
299 | $this->fullPath = $this->location . '/' . $this->name . '.' . $this->mime; |
||
300 | return $this->fullPath; |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * Returns the image size in bytes |
||
305 | * |
||
306 | * @return int |
||
307 | */ |
||
308 | public function getSize() |
||
309 | { |
||
310 | return (int)$this->_files['size']; |
||
311 | } |
||
312 | |||
313 | /** |
||
314 | * Returns the image height in pixels |
||
315 | * |
||
316 | * @return int |
||
317 | */ |
||
318 | public function getHeight() |
||
319 | { |
||
320 | if ($this->height != null) { |
||
321 | return $this->height; |
||
322 | } |
||
323 | |||
324 | list(, $height) = getImageSize($this->_files['tmp_name']); |
||
325 | return $height; |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * Returns the image width |
||
330 | * |
||
331 | * @return int |
||
332 | */ |
||
333 | public function getWidth() |
||
334 | { |
||
335 | if ($this->width != null) { |
||
336 | return $this->width; |
||
337 | } |
||
338 | |||
339 | list($width) = getImageSize($this->_files['tmp_name']); |
||
340 | return $width; |
||
341 | } |
||
342 | |||
343 | /** |
||
344 | * Returns the storage / folder name |
||
345 | * |
||
346 | * @return string |
||
347 | */ |
||
348 | public function getLocation() |
||
349 | { |
||
350 | if (!$this->location) { |
||
351 | $this->setLocation(); |
||
352 | } |
||
353 | |||
354 | return $this->location; |
||
355 | } |
||
356 | |||
357 | /** |
||
358 | * Returns a JSON format of the image width, height, name, mime ... |
||
359 | * |
||
360 | * @return string |
||
361 | */ |
||
362 | public function getJson() |
||
363 | { |
||
364 | return json_encode($this->serialize); |
||
365 | } |
||
366 | |||
367 | /** |
||
368 | * Returns the image mime type |
||
369 | * |
||
370 | * @return string |
||
371 | */ |
||
372 | public function getMime() |
||
373 | { |
||
374 | if (!$this->mime) { |
||
375 | return $this->getImageMime($this->_files['tmp_name']); |
||
376 | } |
||
377 | return $this->mime; |
||
378 | } |
||
379 | |||
380 | /** |
||
381 | * Returns error string or false if no errors occurred |
||
382 | * |
||
383 | * @return string|bool |
||
384 | */ |
||
385 | public function getError() |
||
386 | { |
||
387 | return $this->error != '' ? $this->error : false; |
||
388 | } |
||
389 | |||
390 | /** |
||
391 | * Checks for the common upload errors |
||
392 | * |
||
393 | * @param $errors int error constant |
||
394 | * |
||
395 | * @return string |
||
396 | */ |
||
397 | protected function commonUploadErrors($errors) |
||
398 | { |
||
399 | return $this->common_upload_errors[$errors]; |
||
400 | } |
||
401 | |||
402 | /** |
||
403 | * This methods validates and uploads the image |
||
404 | * @return false|Image |
||
405 | */ |
||
406 | public function upload() |
||
407 | { |
||
408 | /* modify variable names for convenience */ |
||
409 | $image = $this; |
||
410 | $files = $this->_files; |
||
411 | |||
412 | /* check image for valid mime types and return mime */ |
||
413 | $image->mime = $image->getImageMime($files['tmp_name']); |
||
414 | |||
415 | /* validate image mime type */ |
||
416 | if (!in_array($image->mime, $image->mimeTypes)) { |
||
417 | $ext = implode(', ', $image->mimeTypes); |
||
418 | $image->error = sprintf('Invalid File! Only (%s) image types are allowed', $ext); |
||
419 | return false; |
||
420 | } |
||
421 | |||
422 | |||
423 | /* initialize image properties */ |
||
424 | $image->name = $image->getName(); |
||
425 | $image->width = $image->getWidth(); |
||
426 | $image->height = $image->getHeight(); |
||
427 | $image->location = $image->getLocation(); |
||
428 | |||
429 | /* get image sizes */ |
||
430 | list($minSize, $maxSize) = $image->size; |
||
431 | |||
432 | /* check image size based on the settings */ |
||
433 | if ($files['size'] < $minSize || $files['size'] > $maxSize) { |
||
434 | $min = intval($minSize / 1000) ?: 1; |
||
435 | $max = intval($maxSize / 1000) ?: 1; |
||
436 | $image->error = "Image size should be at least " . $min . " KB, and no more than " . $max . " KB"; |
||
437 | return null; |
||
438 | } |
||
439 | |||
440 | /* check image dimension */ |
||
441 | list($allowedWidth, $allowedHeight) = $image->dimensions; |
||
442 | |||
443 | if ($image->height > $allowedHeight || $image->width > $allowedWidth) { |
||
444 | $image->error = 'Image height/width should be less than ' . $allowedHeight . '/' . $allowedWidth . ' pixels'; |
||
445 | return false; |
||
446 | } |
||
447 | |||
448 | if ($image->height < 2 || $image->width < 2) { |
||
449 | $image->error = 'Image height/width too small or corrupted.'; |
||
450 | return false; |
||
451 | } |
||
452 | |||
453 | /* set and get folder name */ |
||
454 | $image->fullPath = $image->location . '/' . $image->name . '.' . $image->mime; |
||
455 | |||
456 | /* gather image info for json storage */ |
||
457 | $image->serialize = array( |
||
458 | 'name' => $image->name, |
||
459 | 'mime' => $image->mime, |
||
460 | 'height' => $image->height, |
||
461 | 'width' => $image->width, |
||
462 | 'size' => $files['size'], |
||
463 | 'location' => $image->location, |
||
464 | 'fullpath' => $image->fullPath |
||
465 | ); |
||
466 | |||
467 | if ($image->error === '') { |
||
468 | $moveUpload = $image->moveUploadedFile($files['tmp_name'], $image->fullPath); |
||
469 | if (false !== $moveUpload) { |
||
470 | return $image; |
||
471 | } |
||
472 | } |
||
473 | |||
474 | $image->error = 'Upload failed, Unknown error occured'; |
||
475 | return false; |
||
476 | } |
||
477 | |||
478 | /** |
||
479 | * Final upload method to be called, isolated for testing purposes |
||
480 | * |
||
481 | * @param $tmp_name int the temporary location of the image file |
||
482 | * @param $destination int upload destination |
||
483 | * |
||
484 | * @return bool |
||
485 | */ |
||
486 | public function moveUploadedFile($tmp_name, $destination) |
||
487 | { |
||
488 | return move_uploaded_file($tmp_name, $destination); |
||
489 | } |
||
490 | } |
||
491 |
This check compares the return type specified in the
@return
annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.