Skip to content

Commit 489c2bf

Browse files
authored
Merge pull request #2573 from MGatner/image-withfile
Image verification
2 parents 6b93add + 7f347e0 commit 489c2bf

7 files changed

Lines changed: 127 additions & 43 deletions

File tree

system/Images/Exceptions/ImageException.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@
55

66
class ImageException extends FrameworkException implements ExceptionInterface
77
{
8+
public static function forMissingImage()
9+
{
10+
return new static(lang('Images.sourceImageRequired'));
11+
}
12+
13+
public static function forFileNotSupported()
14+
{
15+
return new static(lang('Images.fileNotSupported'));
16+
}
17+
818
public static function forMissingAngle()
919
{
1020
return new static(lang('Images.rotationAngleRequired'));
@@ -15,6 +25,11 @@ public static function forInvalidDirection(string $dir = null)
1525
return new static(lang('Images.invalidDirection', [$dir]));
1626
}
1727

28+
public static function forInvalidPath()
29+
{
30+
return new static(lang('Images.invalidPath'));
31+
}
32+
1833
public static function forEXIFUnsupported()
1934
{
2035
return new static(lang('Images.exifNotSupported'));

system/Images/Handlers/BaseHandler.php

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ abstract class BaseHandler implements ImageHandlerInterface
6262
*/
6363
protected $image = null;
6464

65+
/**
66+
* Whether the image file has been confirmed.
67+
*
68+
* @var bool
69+
*/
70+
protected $verified = false;
71+
6572
/**
6673
* Image width.
6774
*
@@ -158,6 +165,7 @@ public function withFile(string $path)
158165
// Clear out the old resource so that
159166
// it doesn't try to use a previous image
160167
$this->resource = null;
168+
$this->verified = false;
161169

162170
$this->image = new Image($path, true);
163171

@@ -177,9 +185,9 @@ protected function ensureResource()
177185
{
178186
if ($this->resource === null)
179187
{
180-
$path = $this->image->getPathname();
188+
$path = $this->image()->getPathname();
181189
// if valid image type, make corresponding image resource
182-
switch ($this->image->imageType)
190+
switch ($this->image()->imageType)
183191
{
184192
case IMAGETYPE_GIF:
185193
$this->resource = imagecreatefromgif($path);
@@ -206,6 +214,43 @@ public function getFile()
206214
return $this->image;
207215
}
208216

217+
/**
218+
* Verifies that a file has been supplied and it is an image.
219+
*
220+
* @return Image The image instance
221+
* @throws type ImageException
222+
*/
223+
protected function image(): ?Image
224+
{
225+
if ($this->verified)
226+
{
227+
return $this->image;
228+
}
229+
230+
// Verify withFile has been called
231+
if (empty($this->image))
232+
{
233+
throw ImageException::forMissingImage();
234+
}
235+
236+
// Verify the loaded image is an Image instance
237+
if (! $this->image instanceof Image)
238+
{
239+
throw ImageException::forInvalidPath();
240+
}
241+
242+
// File::__construct has verified the file exists - make sure it is an image
243+
if (! is_int($this->image->imageType))
244+
{
245+
throw ImageException::forFileNotSupported();
246+
}
247+
248+
// Note that the image has been verified
249+
$this->verified = true;
250+
251+
return $this->image;
252+
}
253+
209254
//--------------------------------------------------------------------
210255

211256
/**
@@ -236,7 +281,7 @@ public function getResource()
236281
public function resize(int $width, int $height, bool $maintainRatio = false, string $masterDim = 'auto')
237282
{
238283
// If the target width/height match the source, then we have nothing to do here.
239-
if ($this->image->origWidth === $width && $this->image->origHeight === $height)
284+
if ($this->image()->origWidth === $width && $this->image()->origHeight === $height)
240285
{
241286
return $this;
242287
}
@@ -302,7 +347,7 @@ public function crop(int $width = null, int $height = null, int $x = null, int $
302347
*/
303348
public function convert(int $imageType)
304349
{
305-
$this->image->imageType = $imageType;
350+
$this->image()->imageType = $imageType;
306351
return $this;
307352
}
308353

@@ -359,8 +404,8 @@ public function rotate(float $angle)
359404
*/
360405
public function flatten(int $red = 255, int $green = 255, int $blue = 255)
361406
{
362-
$this->width = $this->image->origWidth;
363-
$this->height = $this->image->origHeight;
407+
$this->width = $this->image()->origWidth;
408+
$this->height = $this->image()->origHeight;
364409

365410
return $this->_flatten();
366411
}
@@ -538,11 +583,11 @@ public function getEXIF(string $key = null, bool $silent = false)
538583
}
539584

540585
$exif = null; // default
541-
switch ($this->image->imageType)
586+
switch ($this->image()->imageType)
542587
{
543588
case IMAGETYPE_JPEG:
544589
case IMAGETYPE_TIFF_II:
545-
$exif = exif_read_data($this->image->getPathname());
590+
$exif = exif_read_data($this->image()->getPathname());
546591
if (! is_null($key) && is_array($exif))
547592
{
548593
$exif = $exif[$key] ?? false;
@@ -576,8 +621,8 @@ public function getEXIF(string $key = null, bool $silent = false)
576621
*/
577622
public function fit(int $width, int $height = null, string $position = 'center')
578623
{
579-
$origWidth = $this->image->origWidth;
580-
$origHeight = $this->image->origHeight;
624+
$origWidth = $this->image()->origWidth;
625+
$origHeight = $this->image()->origHeight;
581626

582627
list($cropWidth, $cropHeight) = $this->calcAspectRatio($width, $height, $origWidth, $origHeight);
583628

@@ -749,9 +794,9 @@ protected abstract function process(string $action);
749794
*/
750795
public function __call(string $name, array $args = [])
751796
{
752-
if (method_exists($this->image, $name))
797+
if (method_exists($this->image(), $name))
753798
{
754-
return $this->image->$name(...$args);
799+
return $this->image()->$name(...$args);
755800
}
756801
}
757802

@@ -772,11 +817,11 @@ public function __call(string $name, array $args = [])
772817
protected function reproportion()
773818
{
774819
if (($this->width === 0 && $this->height === 0) ||
775-
$this->image->origWidth === 0 ||
776-
$this->image->origHeight === 0 ||
820+
$this->image()->origWidth === 0 ||
821+
$this->image()->origHeight === 0 ||
777822
( ! ctype_digit((string) $this->width) && ! ctype_digit((string) $this->height)) ||
778-
! ctype_digit((string) $this->image->origWidth) ||
779-
! ctype_digit((string) $this->image->origHeight)
823+
! ctype_digit((string) $this->image()->origWidth) ||
824+
! ctype_digit((string) $this->image()->origHeight)
780825
)
781826
{
782827
return;
@@ -790,7 +835,7 @@ protected function reproportion()
790835
{
791836
if ($this->width > 0 && $this->height > 0)
792837
{
793-
$this->masterDim = ((($this->image->origHeight / $this->image->origWidth) - ($this->height / $this->width)) < 0) ? 'width' : 'height';
838+
$this->masterDim = ((($this->image()->origHeight / $this->image()->origWidth) - ($this->height / $this->width)) < 0) ? 'width' : 'height';
794839
}
795840
else
796841
{
@@ -805,11 +850,11 @@ protected function reproportion()
805850

806851
if ($this->masterDim === 'width')
807852
{
808-
$this->height = (int) ceil($this->width * $this->image->origHeight / $this->image->origWidth);
853+
$this->height = (int) ceil($this->width * $this->image()->origHeight / $this->image()->origWidth);
809854
}
810855
else
811856
{
812-
$this->width = (int) ceil($this->image->origWidth * $this->height / $this->image->origHeight);
857+
$this->width = (int) ceil($this->image()->origWidth * $this->height / $this->image()->origHeight);
813858
}
814859
}
815860

system/Images/Handlers/GDHandler.php

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,8 @@ public function _flip(string $direction)
151151
{
152152
$srcImg = $this->createImage();
153153

154-
$width = $this->image->origWidth;
155-
$height = $this->image->origHeight;
154+
$width = $this->image()->origWidth;
155+
$height = $this->image()->origHeight;
156156

157157
if ($direction === 'horizontal')
158158
{
@@ -254,8 +254,8 @@ public function _crop()
254254
*/
255255
protected function process(string $action)
256256
{
257-
$origWidth = $this->image->origWidth;
258-
$origHeight = $this->image->origHeight;
257+
$origWidth = $this->image()->origWidth;
258+
$origHeight = $this->image()->origHeight;
259259

260260
if ($action === 'crop')
261261
{
@@ -266,8 +266,8 @@ protected function process(string $action)
266266
// Modify the "original" width/height to the new
267267
// values so that methods that come after have the
268268
// correct size to work with.
269-
$this->image->origHeight = $this->height;
270-
$this->image->origWidth = $this->width;
269+
$this->image()->origHeight = $this->height;
270+
$this->image()->origWidth = $this->width;
271271
}
272272

273273
// Create the image handle
@@ -286,7 +286,7 @@ protected function process(string $action)
286286

287287
$dest = $create($this->width, $this->height);
288288

289-
if ($this->image->imageType === IMAGETYPE_PNG) // png we can actually preserve transparency
289+
if ($this->image()->imageType === IMAGETYPE_PNG) // png we can actually preserve transparency
290290
{
291291
imagealphablending($dest, false);
292292
imagesavealpha($dest, true);
@@ -318,9 +318,9 @@ protected function process(string $action)
318318
*/
319319
public function save(string $target = null, int $quality = 90): bool
320320
{
321-
$target = empty($target) ? $this->image->getPathname() : $target;
321+
$target = empty($target) ? $this->image()->getPathname() : $target;
322322

323-
switch ($this->image->imageType)
323+
switch ($this->image()->imageType)
324324
{
325325
case IMAGETYPE_GIF:
326326
if (! function_exists('imagegif'))
@@ -389,12 +389,12 @@ protected function createImage(string $path = '', string $imageType = '')
389389

390390
if ($path === '')
391391
{
392-
$path = $this->image->getPathname();
392+
$path = $this->image()->getPathname();
393393
}
394394

395395
if ($imageType === '')
396396
{
397-
$imageType = $this->image->imageType;
397+
$imageType = $this->image()->imageType;
398398
}
399399

400400
switch ($imageType)
@@ -490,21 +490,21 @@ protected function _text(string $text, array $options = [])
490490
if ($options['vAlign'] === 'middle')
491491
{
492492
// Don't apply padding when you're in the middle of the image.
493-
$yAxis += ($this->image->origHeight / 2) + ($fontheight / 2) - $options['padding'];
493+
$yAxis += ($this->image()->origHeight / 2) + ($fontheight / 2) - $options['padding'];
494494
}
495495
elseif ($options['vAlign'] === 'bottom')
496496
{
497-
$yAxis = ($this->image->origHeight - $fontheight - $options['shadowOffset'] - ($fontheight / 2)) - $yAxis;
497+
$yAxis = ($this->image()->origHeight - $fontheight - $options['shadowOffset'] - ($fontheight / 2)) - $yAxis;
498498
}
499499

500500
// Set horizontal alignment
501501
if ($options['hAlign'] === 'right')
502502
{
503-
$xAxis += ($this->image->origWidth - ($fontwidth * strlen($text)) - $options['shadowOffset']) - (2 * $options['padding']);
503+
$xAxis += ($this->image()->origWidth - ($fontwidth * strlen($text)) - $options['shadowOffset']) - (2 * $options['padding']);
504504
}
505505
elseif ($options['hAlign'] === 'center')
506506
{
507-
$xAxis += floor(($this->image->origWidth - ($fontwidth * strlen($text))) / 2);
507+
$xAxis += floor(($this->image()->origWidth - ($fontwidth * strlen($text))) / 2);
508508
}
509509

510510
$options['xAxis'] = $xAxis;

system/Images/Handlers/ImageMagickHandler.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public function __construct($config = null)
9797
*/
9898
public function _resize(bool $maintainRatio = false)
9999
{
100-
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
100+
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
101101
$destination = $this->getResourcePath();
102102

103103
$escape = '\\';
@@ -123,7 +123,7 @@ public function _resize(bool $maintainRatio = false)
123123
*/
124124
public function _crop()
125125
{
126-
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
126+
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
127127
$destination = $this->getResourcePath();
128128

129129
$action = ' -crop ' . $this->width . 'x' . $this->height . '+' . $this->xAxis . '+' . $this->yAxis . ' "' . $source . '" "' . $destination . '"';
@@ -148,7 +148,7 @@ protected function _rotate(int $angle)
148148
{
149149
$angle = '-rotate ' . $angle;
150150

151-
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
151+
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
152152
$destination = $this->getResourcePath();
153153

154154
$action = ' ' . $angle . ' "' . $source . '" "' . $destination . '"';
@@ -174,7 +174,7 @@ public function _flatten(int $red = 255, int $green = 255, int $blue = 255)
174174
{
175175
$flatten = "-background RGB({$red},{$green},{$blue}) -flatten";
176176

177-
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
177+
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
178178
$destination = $this->getResourcePath();
179179

180180
$action = ' ' . $flatten . ' "' . $source . '" "' . $destination . '"';
@@ -198,7 +198,7 @@ public function _flip(string $direction)
198198
{
199199
$angle = $direction === 'horizontal' ? '-flop' : '-flip';
200200

201-
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
201+
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
202202
$destination = $this->getResourcePath();
203203

204204
$action = ' ' . $angle . ' "' . $source . '" "' . $destination . '"';
@@ -286,7 +286,7 @@ protected function process(string $action, int $quality = 100): array
286286
*/
287287
public function save(string $target = null, int $quality = 90): bool
288288
{
289-
$target = empty($target) ? $this->image : $target;
289+
$target = empty($target) ? $this->image() : $target;
290290

291291
// If no new resource has been created, then we're
292292
// simply copy the existing one.
@@ -295,7 +295,7 @@ public function save(string $target = null, int $quality = 90): bool
295295
$name = basename($target);
296296
$path = pathinfo($target, PATHINFO_DIRNAME);
297297

298-
return $this->image->copy($path, $name);
298+
return $this->image()->copy($path, $name);
299299
}
300300

301301
// Copy the file through ImageMagick so that it has
@@ -433,7 +433,7 @@ protected function _text(string $text, array $options = [])
433433
// Text
434434
$cmd .= " -annotate 0 '{$text}'";
435435

436-
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
436+
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
437437
$destination = $this->getResourcePath();
438438

439439
$cmd = " '{$source}' {$cmd} '{$destination}'";

system/Images/Image.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ public function getProperties(bool $return = false)
137137
{
138138
$path = $this->getPathname();
139139

140-
$vals = getimagesize($path);
140+
if (! $vals = getimagesize($path))
141+
{
142+
throw ImageException::forFileNotSupported();
143+
}
144+
141145
$types = [
142146
1 => 'gif',
143147
2 => 'jpeg',

system/Language/en/Images.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
'gifNotSupported' => 'GIF images are often not supported due to licensing restrictions. You may have to use JPG or PNG images instead.',
2222
'jpgNotSupported' => 'JPG images are not supported.',
2323
'pngNotSupported' => 'PNG images are not supported.',
24+
'fileNotSupported' => 'The supplied file is not a supported image type.',
2425
'unsupportedImageCreate' => 'Your server does not support the GD function required to process this type of image.',
2526
'jpgOrPngRequired' => 'The image resize protocol specified in your preferences only works with JPEG or PNG image types.',
2627
'rotateUnsupported' => 'Image rotation does not appear to be supported by your server.',

0 commit comments

Comments
 (0)