Validating Image Uploads in CakePHP
16th June, 2008 – 10:17 pmFollowing on from my article on CakePHP - Uploaded File Validation in Models, today’s snippet will show you how to use Cake’s validation rules to reject invalid images, or images which do not conform to a specified mime-type. This code relies on the fact that you have LibGD installed on your webserver.
Class Image extends AppModel
{
var $name = ‘Image’;
var $validate = array
(
‘uploaded_image’ => array
(
// Ensure file uploaded OK.
‘valid_upload’ => array
(
‘rule’ => array(‘validateUploadedfile’, false),
‘message’ => ‘An error occured whilst uploading your image, please try again’,
),
// Check image is valid / of allowed mime-type
‘valid_image’ => array
(
‘rule’ => array(‘isValidImageFile’),
‘message’ => ‘The file you have uploaded is not a valid or is unsupported, please try again’,
),
),
);
/**
* Custom validation rule for uploaded files.
*
* @param Array $data CakePHP File info.
* @param Boolean $required Is this field required?
* @return Boolean
*/
function validateUploadedFile($data, $required = false)
{
// Remove first level of Array ($data['Image']['size'] becomes $data['size'])
$upload_info = array_shift($data);
// No file uploaded.
if ($required && $upload_info[’size’] == 0) {
return false;
}
// Check for Basic PHP file errors.
if ($upload_info[‘error’] !== 0) {
return false;
}
// Finally, use PHP’s own file validation method.
return is_uploaded_file($upload_info[‘tmp_name’]);
}
/**
* Use LibGD to determine if an uploaded file is a valid Image by
* running it’s mime-type against a list of $valid_mime_types
*
* @param Array $data CakePHP File info
* @return Boolean
*/
function isValidImageFile($data)
{
// Allow these image mime-types, all others will be rejected
$valid_mime_types = array(‘image/jpeg’, ‘image/png’, ‘image/gif’);
$data = array_shift($data);
$filename = $data[‘tmp_name’];
// Catch I/O Errors.
if (!is_readable($filename)) {
debug(__METHOD__." failed to read input file: {$filename}");
return false;
}
// Retrieve the MimeType of Image, if none is returned, it’s invalid
if (!$mime_type = $this->getImageMimeType($filename)) {
debug(__METHOD__." Uploaded file does not have a mime-type");
return false;
}
// Check the MimeType against the array of valid ones specified above
if (!in_array($mime_type, $valid_mime_types)) {
debug(__METHOD__." Uploaded image has rejected Mime Type: {$mime_type}");
return false;
}
if (!$this->__getImageHandleFromFile($filename)) {
return false;
}
return true;
}
/**
* Use LibGD to return an uploaded Image’s MimeType as a String, FALSE
* on errors or if the file is not an image
*
* @param String $filename Absolute path to file on disc
* @return String Image MimeType of $filename, false on failure
*/
function getImageMimeType($filename)
{
// If this error is thrown LibGD is not installed on your server.
if (!function_exists(‘getimagesize’)) {
debug(__METHOD__." LibGD PHP Extension was not found, please refer to http://www.php.net/manual/en/book.image.php");
exit();
}
$result = getimagesize($filename);
if (isset($result[‘mime’])) {
return $result[‘mime’];
}
return false;
}
/**
* Returns a LibGD Image Handle for a file specified by $filename
*
* @param String $filename Absolute path to image on disk
* @return LibGD Image Handle on success, FALSE on failure.
*/
function __getImageHandleFromFile($filename)
{
if (!is_readable($filename)) {
debug(__METHOD__." failed to read input file: {$filename}");
return false;
}
// Retrieve the MimeType of Image, if none is returned, it’s invalid
if (!$mime_type = $this->getImageMimeType($filename)) {
debug(__METHOD__." failed to assertain MimeType of {$filename}");
return false;
}
switch ($mime_type)
{
case ‘image/jpeg’:
$handle = @imagecreatefromjpeg($filename);
break;
case ‘image/gif’:
$handle = @imagecreatefromgif($filename);
break;
case ‘image/png’:
$handle = @imagecreatefrompng($filename);
break;
default:
debug(__METHOD__." Didn’t know how to handle MimeType: {$mime_type}");
$handle = false;
break;
}
return $handle;
}
}
As always, comments are welcome.
One Response to “Validating Image Uploads in CakePHP”
Just a comment after reading Chris Shiflett’s article on file uploads. You probably shouldn’t rely on $upload_info['size'] for the file size as this is transmitted from the client. Checking the file size yourself with the filesize() function is better.
By John on Aug 26, 2008