Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image verification #2573

Merged
merged 4 commits into from
Feb 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions system/Images/Exceptions/ImageException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@

class ImageException extends FrameworkException implements ExceptionInterface
{
public static function forMissingImage()
{
return new static(lang('Images.sourceImageRequired'));
}

public static function forFileNotSupported()
{
return new static(lang('Images.fileNotSupported'));
}

public static function forMissingAngle()
{
return new static(lang('Images.rotationAngleRequired'));
Expand All @@ -15,6 +25,11 @@ public static function forInvalidDirection(string $dir = null)
return new static(lang('Images.invalidDirection', [$dir]));
}

public static function forInvalidPath()
{
return new static(lang('Images.invalidPath'));
}

public static function forEXIFUnsupported()
{
return new static(lang('Images.exifNotSupported'));
Expand Down
83 changes: 64 additions & 19 deletions system/Images/Handlers/BaseHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ abstract class BaseHandler implements ImageHandlerInterface
*/
protected $image = null;

/**
* Whether the image file has been confirmed.
*
* @var bool
*/
protected $verified = false;

/**
* Image width.
*
Expand Down Expand Up @@ -158,6 +165,7 @@ public function withFile(string $path)
// Clear out the old resource so that
// it doesn't try to use a previous image
$this->resource = null;
$this->verified = false;

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

Expand All @@ -177,9 +185,9 @@ protected function ensureResource()
{
if ($this->resource === null)
{
$path = $this->image->getPathname();
$path = $this->image()->getPathname();
// if valid image type, make corresponding image resource
switch ($this->image->imageType)
switch ($this->image()->imageType)
{
case IMAGETYPE_GIF:
$this->resource = imagecreatefromgif($path);
Expand All @@ -206,6 +214,43 @@ public function getFile()
return $this->image;
}

/**
* Verifies that a file has been supplied and it is an image.
*
* @return Image The image instance
* @throws type ImageException
*/
protected function image(): ?Image
{
if ($this->verified)
{
return $this->image;
}

// Verify withFile has been called
if (empty($this->image))
{
throw ImageException::forMissingImage();
}

// Verify the loaded image is an Image instance
if (! $this->image instanceof Image)
{
throw ImageException::forInvalidPath();
}

// File::__construct has verified the file exists - make sure it is an image
if (! is_int($this->image->imageType))
{
throw ImageException::forFileNotSupported();
}

// Note that the image has been verified
$this->verified = true;

return $this->image;
}

//--------------------------------------------------------------------

/**
Expand Down Expand Up @@ -236,7 +281,7 @@ public function getResource()
public function resize(int $width, int $height, bool $maintainRatio = false, string $masterDim = 'auto')
{
// If the target width/height match the source, then we have nothing to do here.
if ($this->image->origWidth === $width && $this->image->origHeight === $height)
if ($this->image()->origWidth === $width && $this->image()->origHeight === $height)
{
return $this;
}
Expand Down Expand Up @@ -302,7 +347,7 @@ public function crop(int $width = null, int $height = null, int $x = null, int $
*/
public function convert(int $imageType)
{
$this->image->imageType = $imageType;
$this->image()->imageType = $imageType;
return $this;
}

Expand Down Expand Up @@ -359,8 +404,8 @@ public function rotate(float $angle)
*/
public function flatten(int $red = 255, int $green = 255, int $blue = 255)
{
$this->width = $this->image->origWidth;
$this->height = $this->image->origHeight;
$this->width = $this->image()->origWidth;
$this->height = $this->image()->origHeight;

return $this->_flatten();
}
Expand Down Expand Up @@ -538,11 +583,11 @@ public function getEXIF(string $key = null, bool $silent = false)
}

$exif = null; // default
switch ($this->image->imageType)
switch ($this->image()->imageType)
{
case IMAGETYPE_JPEG:
case IMAGETYPE_TIFF_II:
$exif = exif_read_data($this->image->getPathname());
$exif = exif_read_data($this->image()->getPathname());
if (! is_null($key) && is_array($exif))
{
$exif = $exif[$key] ?? false;
Expand Down Expand Up @@ -576,8 +621,8 @@ public function getEXIF(string $key = null, bool $silent = false)
*/
public function fit(int $width, int $height = null, string $position = 'center')
{
$origWidth = $this->image->origWidth;
$origHeight = $this->image->origHeight;
$origWidth = $this->image()->origWidth;
$origHeight = $this->image()->origHeight;

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

Expand Down Expand Up @@ -749,9 +794,9 @@ protected abstract function process(string $action);
*/
public function __call(string $name, array $args = [])
{
if (method_exists($this->image, $name))
if (method_exists($this->image(), $name))
{
return $this->image->$name(...$args);
return $this->image()->$name(...$args);
}
}

Expand All @@ -772,11 +817,11 @@ public function __call(string $name, array $args = [])
protected function reproportion()
{
if (($this->width === 0 && $this->height === 0) ||
$this->image->origWidth === 0 ||
$this->image->origHeight === 0 ||
$this->image()->origWidth === 0 ||
$this->image()->origHeight === 0 ||
( ! ctype_digit((string) $this->width) && ! ctype_digit((string) $this->height)) ||
! ctype_digit((string) $this->image->origWidth) ||
! ctype_digit((string) $this->image->origHeight)
! ctype_digit((string) $this->image()->origWidth) ||
! ctype_digit((string) $this->image()->origHeight)
)
{
return;
Expand All @@ -790,7 +835,7 @@ protected function reproportion()
{
if ($this->width > 0 && $this->height > 0)
{
$this->masterDim = ((($this->image->origHeight / $this->image->origWidth) - ($this->height / $this->width)) < 0) ? 'width' : 'height';
$this->masterDim = ((($this->image()->origHeight / $this->image()->origWidth) - ($this->height / $this->width)) < 0) ? 'width' : 'height';
}
else
{
Expand All @@ -805,11 +850,11 @@ protected function reproportion()

if ($this->masterDim === 'width')
{
$this->height = (int) ceil($this->width * $this->image->origHeight / $this->image->origWidth);
$this->height = (int) ceil($this->width * $this->image()->origHeight / $this->image()->origWidth);
}
else
{
$this->width = (int) ceil($this->image->origWidth * $this->height / $this->image->origHeight);
$this->width = (int) ceil($this->image()->origWidth * $this->height / $this->image()->origHeight);
}
}

Expand Down
30 changes: 15 additions & 15 deletions system/Images/Handlers/GDHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ public function _flip(string $direction)
{
$srcImg = $this->createImage();

$width = $this->image->origWidth;
$height = $this->image->origHeight;
$width = $this->image()->origWidth;
$height = $this->image()->origHeight;

if ($direction === 'horizontal')
{
Expand Down Expand Up @@ -254,8 +254,8 @@ public function _crop()
*/
protected function process(string $action)
{
$origWidth = $this->image->origWidth;
$origHeight = $this->image->origHeight;
$origWidth = $this->image()->origWidth;
$origHeight = $this->image()->origHeight;

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

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

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

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

switch ($this->image->imageType)
switch ($this->image()->imageType)
{
case IMAGETYPE_GIF:
if (! function_exists('imagegif'))
Expand Down Expand Up @@ -389,12 +389,12 @@ protected function createImage(string $path = '', string $imageType = '')

if ($path === '')
{
$path = $this->image->getPathname();
$path = $this->image()->getPathname();
}

if ($imageType === '')
{
$imageType = $this->image->imageType;
$imageType = $this->image()->imageType;
}

switch ($imageType)
Expand Down Expand Up @@ -490,21 +490,21 @@ protected function _text(string $text, array $options = [])
if ($options['vAlign'] === 'middle')
{
// Don't apply padding when you're in the middle of the image.
$yAxis += ($this->image->origHeight / 2) + ($fontheight / 2) - $options['padding'];
$yAxis += ($this->image()->origHeight / 2) + ($fontheight / 2) - $options['padding'];
}
elseif ($options['vAlign'] === 'bottom')
{
$yAxis = ($this->image->origHeight - $fontheight - $options['shadowOffset'] - ($fontheight / 2)) - $yAxis;
$yAxis = ($this->image()->origHeight - $fontheight - $options['shadowOffset'] - ($fontheight / 2)) - $yAxis;
}

// Set horizontal alignment
if ($options['hAlign'] === 'right')
{
$xAxis += ($this->image->origWidth - ($fontwidth * strlen($text)) - $options['shadowOffset']) - (2 * $options['padding']);
$xAxis += ($this->image()->origWidth - ($fontwidth * strlen($text)) - $options['shadowOffset']) - (2 * $options['padding']);
}
elseif ($options['hAlign'] === 'center')
{
$xAxis += floor(($this->image->origWidth - ($fontwidth * strlen($text))) / 2);
$xAxis += floor(($this->image()->origWidth - ($fontwidth * strlen($text))) / 2);
}

$options['xAxis'] = $xAxis;
Expand Down
16 changes: 8 additions & 8 deletions system/Images/Handlers/ImageMagickHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public function __construct($config = null)
*/
public function _resize(bool $maintainRatio = false)
{
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
$destination = $this->getResourcePath();

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

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

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

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

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

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

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

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

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

return $this->image->copy($path, $name);
return $this->image()->copy($path, $name);
}

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

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

$cmd = " '{$source}' {$cmd} '{$destination}'";
Expand Down
6 changes: 5 additions & 1 deletion system/Images/Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ public function getProperties(bool $return = false)
{
$path = $this->getPathname();

$vals = getimagesize($path);
if (! $vals = getimagesize($path))
{
throw ImageException::forFileNotSupported();
}

$types = [
1 => 'gif',
2 => 'jpeg',
Expand Down
1 change: 1 addition & 0 deletions system/Language/en/Images.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
'gifNotSupported' => 'GIF images are often not supported due to licensing restrictions. You may have to use JPG or PNG images instead.',
'jpgNotSupported' => 'JPG images are not supported.',
'pngNotSupported' => 'PNG images are not supported.',
'fileNotSupported' => 'The supplied file is not a supported image type.',
'unsupportedImageCreate' => 'Your server does not support the GD function required to process this type of image.',
'jpgOrPngRequired' => 'The image resize protocol specified in your preferences only works with JPEG or PNG image types.',
'rotateUnsupported' => 'Image rotation does not appear to be supported by your server.',
Expand Down
Loading