diff --git a/bl-kernel/helpers/simple-image.class.php b/bl-kernel/helpers/simple-image.class.php index bfc89455..51e56733 100644 --- a/bl-kernel/helpers/simple-image.class.php +++ b/bl-kernel/helpers/simple-image.class.php @@ -1,6 +1,6 @@ flags = [ + "sslVerify" => true // Skip SSL peer validation + ]; + + // Override default flag values. + foreach($flags as $flag => $value) { + $this->setFlag($flag, $value); + } + // Load an image through the constructor if(preg_match('/^data:(.*?);/', $image)) { $this->fromDataUri($image); @@ -77,6 +89,37 @@ class SimpleImage { } } + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Helper functions + ////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Set flag value. + * + * @param string $flag Name of the flag to set. + * @param boolean $value State of the flag. + * @throws \Exception Thrown if flag does not exist (no default value). + */ + public function setFlag($flag, $value) { + // Throw if flag does not exist + if(!in_array($flag, array_keys($this->flags))) { + throw new \Exception('Invalid flag.', self::ERR_INVALID_FLAG); + } + + // Set flag value by name + $this->flags[$flag] = $value; + } + + /** + * Get flag value. + * + * @param string $flag Name of the flag to get. + * @return boolean|null + */ + public function getFlag($flag) { + return in_array($flag, array_keys($this->flags)) ? $this->flags[$flag] : null; + } + ////////////////////////////////////////////////////////////////////////////////////////////////// // Loaders ////////////////////////////////////////////////////////////////////////////////////////////////// @@ -118,70 +161,66 @@ class SimpleImage { * Loads an image from a file. * * @param string $file The image file to load. + * @param boolean $sslVerify Set to false to skip SSL validation. * @throws \Exception Thrown if file or image data is invalid. * @return \claviska\SimpleImage */ public function fromFile($file) { - // Check if the file exists and is readable. We're using fopen() instead of file_exists() - // because not all URL wrappers support the latter. - $handle = @fopen($file, 'r'); - if($handle === false) { + // Set fopen options. + $sslVerify = $this->getFlag("sslVerify"); // Don't perform peer validation when true + $opts = [ + "ssl" => [ + "verify_peer" => $sslVerify, + "verify_peer_name" => $sslVerify + ] + ]; + + // Check if the file exists and is readable. + $file = @file_get_contents($file, false, stream_context_create($opts)); + if($file === false) { throw new \Exception("File not found: $file", self::ERR_FILE_NOT_FOUND); } - fclose($handle); + + // Create image object from string + $this->image = imagecreatefromstring($file); // Get image info - $info = @getimagesize($file); + $info = @getimagesizefromstring($file); if($info === false) { throw new \Exception("Invalid image file: $file", self::ERR_INVALID_IMAGE); } $this->mimeType = $info['mime']; - // Create image object from file - switch($this->mimeType) { - case 'image/gif': - // Load the gif - $gif = imagecreatefromgif($file); - if($gif) { - // Copy the gif over to a true color image to preserve its transparency. This is a - // workaround to prevent imagepalettetruecolor() from borking transparency. - $width = imagesx($gif); - $height = imagesy($gif); - $this->image = imagecreatetruecolor($width, $height); - $transparentColor = imagecolorallocatealpha($this->image, 0, 0, 0, 127); - imagecolortransparent($this->image, $transparentColor); - imagefill($this->image, 0, 0, $transparentColor); - imagecopy($this->image, $gif, 0, 0, 0, 0, $width, $height); - imagedestroy($gif); - } - break; - case 'image/jpeg': - $this->image = imagecreatefromjpeg($file); - break; - case 'image/png': - $this->image = imagecreatefrompng($file); - break; - case 'image/webp': - $this->image = imagecreatefromwebp($file); - break; - case 'image/bmp': - case 'image/x-ms-bmp': - case 'image/x-windows-bmp': - $this->image = imagecreatefrombmp($file); - break; - } if(!$this->image) { throw new \Exception("Unsupported format: " . $this->mimeType, self::ERR_UNSUPPORTED_FORMAT); } + switch($this->mimeType) { + case 'image/gif': + // Copy the gif over to a true color image to preserve its transparency. This is a + // workaround to prevent imagepalettetotruecolor() from borking transparency. + $width = imagesx($this->image); + $height = imagesx($this->image); + + $gif = imagecreatetruecolor((int) $width, (int) $height); + $alpha = imagecolorallocatealpha($gif, 0, 0, 0, 127); + imagecolortransparent($gif, $alpha); + imagefill($gif, 0, 0, $alpha); + + imagecopy($this->image, $gif, 0, 0, 0, 0, $width, $height); + imagedestroy($gif); + break; + case 'image/jpeg': + // Load exif data from JPEG images + if(function_exists('exif_read_data')) { + $this->exif = @exif_read_data("data://image/jpeg;base64," . base64_encode($file)); + } + break; + } + // Convert pallete images to true color images imagepalettetotruecolor($this->image); - // Load exif data from JPEG images - if($this->mimeType === 'image/jpeg' && function_exists('exif_read_data')) { - $this->exif = @exif_read_data($file); - } - return $this; } @@ -194,7 +233,7 @@ class SimpleImage { * @return \claviska\SimpleImage */ public function fromNew($width, $height, $color = 'transparent') { - $this->image = imagecreatetruecolor($width, $height); + $this->image = imagecreatetruecolor((int) $width, (int) $height); // Use PNG for dynamically created images because it's lossless and supports transparency $this->mimeType = 'image/png'; @@ -490,7 +529,7 @@ class SimpleImage { imagefilter($srcIm, IMG_FILTER_COLORIZE, 0, 0, 0, 127 * ((100 - $pct) / 100)); } - imagecopy($dstIm, $srcIm, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH); + imagecopy($dstIm, $srcIm, (int) $dstX, (int) $dstY, (int) $srcX, (int) $srcY, (int) $srcW, (int) $srcH); return true; } @@ -593,7 +632,7 @@ class SimpleImage { // Avoid using native imagecrop() because of a bug with PNG transparency $dstW = abs($x2 - $x1); $dstH = abs($y2 - $y1); - $newImage = imagecreatetruecolor($dstW, $dstH); + $newImage = imagecreatetruecolor((int) $dstW, (int) $dstH); $transparentColor = imagecolorallocatealpha($newImage, 0, 0, 0, 127); imagecolortransparent($newImage, $transparentColor); imagefill($newImage, 0, 0, $transparentColor); @@ -603,10 +642,10 @@ class SimpleImage { $newImage, $this->image, 0, 0, min($x1, $x2), min($y1, $y2), - $dstW, - $dstH, - $dstW, - $dstH + (int) $dstW, + (int) $dstH, + (int) $dstW, + (int) $dstH ); // Swap out the new image @@ -802,7 +841,7 @@ class SimpleImage { // We can't use imagescale because it doesn't seem to preserve transparency properly. The // workaround is to create a new truecolor image, allocate a transparent color, and copy the // image over to it using imagecopyresampled. - $newImage = imagecreatetruecolor($width, $height); + $newImage = imagecreatetruecolor((int) $width, (int) $height); $transparentColor = imagecolorallocatealpha($newImage, 0, 0, 0, 127); imagecolortransparent($newImage, $transparentColor); imagefill($newImage, 0, 0, $transparentColor); @@ -810,8 +849,8 @@ class SimpleImage { $newImage, $this->image, 0, 0, 0, 0, - $width, - $height, + (int) $width, + (int) $height, $this->getWidth(), $this->getHeight() ); @@ -1885,7 +1924,7 @@ class SimpleImage { $color['red'], $color['green'], $color['blue'], - 127 - ($color['alpha'] * 127) + (int) (127 - ($color['alpha'] * 127)) ); if($index > -1) { // Yes, return this color index