How to detect spoiled or crashed images after upload - php

How i can detect spoiled images after upload?
Im using some code like this:
$imageSize = getimagesize($tmp_name);
if(!$imageSize || !in_array($imageSize['mime'], $allowMimeType)){
$this->error = 'Bad Image';
#unlink($tmp_name);
return false;
}
$tn = imagecreatetruecolor(80, 80);
switch ($imageSize['mime']){
case 'image/jpeg':
$userphoto = imagecreatefromjpeg($tmp_name);// Error 1
break;
case 'image/png':
$userphoto = imagecreatefrompng($tmp_name);// Error 1
break;
case 'image/gif':
$userphoto = imagecreatefromgif($tmp_name);// Error 1
break;
case 'image/bmp':
$userphoto = imagecreatefromwbmp($tmp_name);// Error 1
break;
default:
$this->error = 'unknown image';
#unlink($tmp_name);
return false;
break;
}
imagecopyresampled($tn, $userphoto, 0, 0, 0, 0, 80, 80, $width, $height);// Error 2
imagejpeg($tn,'images/userphoto/'.$this->username.'.jpg',100);
chmod('images/userphoto/'.$this->username.'.jpg', 0777);
#unlink($tmp_name);
USERPROFILE::updatePhotoByUsersId($this->username.'.jpg', $this->users_id);
But some time i give 2 error tandem,
at lines that have comment // Error 1
imagecreatefromwbmp() [href='function.imagecreatefromwbmp'>function.imagecreatefromwbmp]: >'images/userphoto/4ff7db9800871.bmp' is not a valid WBMP file
imagecreatefromgif() [href='function.imagecreatefromgif'>function.imagecreatefromgif]: >'images/usersphoto/4fe70bb390758' is not a valid GIF file
at line of comment // Error 2
imagecopyresampled(): supplied argument is not a valid Image resource
I think its occurs because the file has damaged during uploading. If i'm right, how i can solve this problem? If not, What is the reason?

Before you do any further processing, you should check the return value of getimagesize() .
If getimagesize() returns a FALSE, that means it has failed and something is wrong with the file, so you should terminate. Once the image passes this check, you can continue with your processing.
As for why you are getting supplied argument is not a valid Image resource, the explaination is simple: Most likely, the image stored in $userphoto is actually FALSE because imagecreatefrompng() and other imagecreatefrom functions have failed, returning a FALSE.
Solution: Check that the uploaded image is valid with getimagesize() before continuing.
Some possible reasons as to why the uploads are failing:
Something is corrupting the images when they are written to the temp directory.
User is uploading corrupted files.
Regarding imagecreatefromwbmp() failing, it is because gd does not support BMP files. You need to convert the BMP into a format gd can work with. For example, you can use bmp2png.

Related

Recreating uploads/linked images with imagecreatefrom* php

User uploaded images account for a large portion of the content on the site I'm working on. I tried storing them outside of the webroot and fetching them with readfile() for security reasons, but it was just too slow so I had to go back to the old method.
Now I'm looking to make sure all uploads are 100% sanitized since they'll be stored inside the webroot. My question is, if a user were to rename a harmful script to a .jpg, .gif, .png, or .bmp and uploaded it, would it still be harmful when executed or fetched if the image was recreated with a function like this:
function imageCreateFromAny($filepath) {
$type = exif_imagetype($filepath); // [] if you don't have exif you could use getImageSize()
$allowedTypes = array(
1, // [] gif
2, // [] jpg
3, // [] png
6 // [] bmp
);
if (!in_array($type, $allowedTypes)) {
return false;
}
switch ($type) {
case 1 :
$im = imageCreateFromGif($filepath);
break;
case 2 :
$im = imageCreateFromJpeg($filepath);
break;
case 3 :
$im = imageCreateFromPng($filepath);
break;
case 6 :
$im = imageCreateFromBmp($filepath);
break;
}
return $im;
}
In other words, is there anyway to trick one of the imagecreatefrom* functions into executing content as a script instead of an image or would even a harmful script that's been run through this be reduced to a broken image?

Possible Xamp or script error?

First time uploading image and getting this error. Image is .jpg. Script seems to be OK for me. So I think problem is with xamp server?
Warning: imagecreatefrompng(): 'C:\xampp\tmp\phpB42E.tmp' is not a
valid PNG file in C:\xampp\htdocs\phphph\check_image.php on line 66
The file you uploaded was not a supported filetype
I was searching on google and didnt find something usefull. So here is part of the script.
switch ($type){
case IMAGETYPE_GIF:
$image = imagecreatefromgif($_FILES['uploadfile']['tmp_name']) or
die ('The file you uploaded was not a supported filetype');
$ext = ' .gif';
break;
case IMAGETYPE_JPEG:
$image = imagecreatefromjpeg($_FILES['uploadfile']['tmp_name']) or
die ('The file you uploaded was not a supported filetype');
$ext = ' .jpeg';
case IMAGETYPE_PNG:
$image = imagecreatefrompng($_FILES['uploadfile']['tmp_name']) or
die ('The file you uploaded was not a supported filetype');
$ext = ' .png';
break;
default:
die('The file you uploaded was not a supported filetype.');
}
Missing break:
$ext = ' .jpeg';
/// missing break here
case IMAGETYPE_PNG:
So you upload a jpg, and the code continues on into the PNG section, hence your error.
And so, no, it's not a problem with Xamp server... It's a PEBKAC error.

imagecreatefromjpeg() returns a black image when resized

I have following code
// load image and get image size
$img = imagecreatefrompng( "{$pathToImages}{$fname}" );
$width = imagesx( $img );
$height = imagesy( $img );
// calculate thumbnail size
$new_width = $imageWidth;
$new_height = 500;
// create a new temporary image
$tmp_img = imagecreatetruecolor( $new_width, $new_height );
// copy and resize old image into new image
imagecopyresized( $tmp_img, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height );
It works fine with some images..but with certain images it shows an error like
Warning: imagecreatefromjpeg() [function.imagecreatefromjpeg]: gd-jpeg: JPEG library reports unrecoverable error:
Warning: imagesx() expects parameter 1 to be resource, boolean given
Warning: imagesy() expects parameter 1 to be resource, boolean given
I have also enabled
gd.jpeg_ignore_warning = 1
in php.ini
Any help appreciated.
According to a blog post from (Feb 2010) its a bug in the implementation of imagecreatefromjpeg which should return false but throws an error instead.
The solution is to check for the filetype of your image (I removed the duplicate call to imagecreatefromjpeg because its totally superfluous; we already check for right file type before and if an error occurs due to some other reason, imagecreatefromjpeg will return false correctly):
function imagecreatefromjpeg_if_correct($file_tempname) {
$file_dimensions = getimagesize($file_tempname);
$file_type = strtolower($file_dimensions['mime']);
if ($file_type == 'image/jpeg' || $file_type == 'image/pjpeg'){
$im = imagecreatefromjpeg($file_tempname);
return $im;
}
return false;
}
Then you can write your code like this:
$img = imagecreatefrompng_if_correct("{$pathToImages}{$fname}");
if ($img == false) {
// report some error
} else {
// enter all your other functions here, because everything is ok
}
Of course you can do the same for png, if you want to open a png file (like your code suggests). Actually, usually you will check which filetype your file really has and then call the correct function between the three (jpeg, png, gif).
Please see PHP Bug #39918 imagecreatefromjpeg doesn't work. The suggestion is to change the GD setting for jpeg image loading:
ini_set("gd.jpeg_ignore_warning", 1);
You then additionally need to check the return value from the imagecreatefromjpegDocs call:
$img = imagecreatefromjpeg($file);
if (!$img) {
printf("Failed to load jpeg image \"%s\".\n", $file);
die();
}
Also please see the potentially duplicate question:
the dreaded “Warning: imagecreatefromjpeg() : '/tmp/filename' is not a valid JPEG file in /phpfile.php on line xxx”
It has nearly the same error description like yours.
My solution for this issue: detect if imagecreatefromjpeg returns 'false' and in that case use imagecreatefromstring on file_get_contents instead.
Worked for me.
See code sample below:
$ind=0;
do{
if($mime == 'image/jpeg'){
$img = imagecreatefromjpeg($image_url_to_upload);
}elseif ($mime == 'image/png') {
$img = imagecreatefrompng($image_url_to_upload);
}
if ($img===false){
echo "imagecreatefromjpeg error!\n";
}
if ($img===false){
$img = imagecreatefromstring(file_get_contents($image_url_to_upload));
}
if ($img===false){
echo "imagecreatefromstring error!\n";
}
$ind++;
}while($img===false&&$ind<5);
Could you give any example of files that do / don't work?
According to http://www.php.net/manual/en/function.imagecreatefromjpeg.php#100338 blanks in remote filenamnes might cause issues.
In case you're using an URL as the source of the image, you will need to make sure the php setting allow_url_fopen is enabled.

Imagecreatefromjpeg returns a black image after resize

I have a script to resize an uploaded image, but when I use it, it just returns a black square. All error messages are pointing at this function:
function resizeImage($image,$width,$height,$scale) {
$newImageWidth = ceil($width * $scale);
$newImageHeight = ceil($height * $scale);
$newImage = imagecreatetruecolor($newImageWidth,$newImageHeight);
$source = imagecreatefromjpeg($image);
imagecopyresampled($newImage,$source,0,0,0,0,$newImageWidth,$newImageHeight,$width,$height);
imagejpeg($newImage,$image,90);
chmod($image, 0777);
return $image;
}
My error logs:
PHP Warning: imagecreatefromjpeg() [<a href='function.imagecreatefromjpeg'>function.imagecreatefromjpeg</a>]: gd-jpeg: JPEG library reports unrecoverable error
PHP Warning: imagecreatefromjpeg() [<a href='function.imagecreatefromjpeg'>function.imagecreatefromjpeg</a>]: 'img/[hidden].jpg' is not a valid JPEG file
PHP Warning: imagecopyresampled(): supplied argument is not a valid Image resource
According to Marc B's answer you could probably make a check if the file is a JPG file. (JPEG, JPG, jpg, jpeg extensions).
it could be something like:
$file = explode(".", $_POST['file']);
$file_ext = $file[count($file)]; // Get the last thing in the array - in this way the filename can containg dots (.)
$allowed_ext = array('jpg', 'JPG', 'jpeg', 'jpg');
if( in_array($file_ext, $allowed_ext )
{
// The code for creating the image here.
}
Check if the imagecreatetruecolor succeeded. If the new image is "large" it could exceed the PHP memory_limit. This function returns FALSE if it failed for any reason.
Ditto with imagecreatefromjpeg(). The two individual images may fit within the memory limit but together could be too large. The source image may also not exist. This function returns FALSE if it failed for any reason
Check if the imagecopyresampled() failed - it also returns FALSE on failure.
Check if imagejpeg() failed - maybe you don't have write permissions on whatever file you're specifying in $image. And again, this function returns FALSE on failure.

How can I only allow certain filetypes on upload in php?

I'm making a page where the user upload a file. I want an if statement to create an $error variable if the file type is anything other jpg, gif, and pdf.
Here's my code:
$file_type = $_FILES['foreign_character_upload']['type']; //returns the mimetype
if(/*$file_type is anything other than jpg, gif, or pdf*/) {
$error_message = 'Only jpg, gif, and pdf files are allowed.';
$error = 'yes';
}
I'm having difficulty structuring the if statement. How would I say that?
Put the allowed types in an array and use in_array().
$file_type = $_FILES['foreign_character_upload']['type']; //returns the mimetype
$allowed = array("image/jpeg", "image/gif", "application/pdf");
if(!in_array($file_type, $allowed)) {
$error_message = 'Only jpg, gif, and pdf files are allowed.';
$error = 'yes';
}
edit
I just realized that you want to allow PDF files as well. In that case check out PHP's Fileinfo class and functions. But as far as security goes, you still shouldn't rely on $_FILES[]['type'] :)
I'll leave the rest here in case it helps someone else who finds this question
For checking the mime type of the image, $_FILES[]['type'] could be unsafe. This data is sent by the browser and could be easily spoofed.
You should use the getimagesize() function if you only want to allow images to be uploaded (despite its maybe misleading name). This function won't just give you the size but all the data you will probably need about the image.
I used the following script in an image handling class:
private function load_image_data($image_file) {
// Firstly, to disambiguate a loading error with a nonexistant file error,
// check to see if the file actually exists.
if( ! file_exists($image_file) ) {
throw new Nonexistent_Image_Exception("The file '{$image_file}' does not exist");
}
// We're going to check the return value of getimagesize, so we don't
// need any pesky warnings or notices popping up, since we're going to
// stop execution of this function if something goes wrong.
$image_data = #getimagesize($image_file);
if( $image_data === false ) {
throw new Load_Image_Exception("Could not get image data from '{$image_file}'");
}
$this->size = new Dimensions($image_data[0], $image_data[1]);
$this->mime = $image_data['mime'];
}
Notice that getimagesize() returns an associative array containing a 'mime' index. The data here is reliable.
In another function I checked the mime type of the image and converted it to PNG with the appropriate GD function:
private function load_image($image_file) {
// Suppress warning messages because we're going to throw an
// exception if it didn't work instead.
switch( $this->mime ) {
case 'image/jpeg':
case 'image/pjpeg':
$this->image = #imagecreatefromjpeg($image_file);
break;
case 'image/gif':
$this->image = #imagecreatefromgif($image_file);
break;
case 'image/png':
$this->image = #imagecreatefrompng($image_file);
break;
default:
throw new Invalid_Image_Exception("The image was of an invalid type");
}
if( $this->image === false ) {
throw new Load_Image_Exception("Loading of image '{$image_file}' failed");
}
}
You probably won't need to do all of this, but you can see what mime types appear for the filetypes you have specified. Notice that a jpeg could have two different mime types.
Hope this helps.
See also Zend Framework's Zend_File_Transfer_Adapter_Http and
Zend_Form_Element_File. You can add multiple different validators like minimum image resolution, MIME type, minimum file size, allowed file extensions, etc.
Use this simple code...
<?
$path = $_FILES['file']['name']; // file means your input type file name
$ext = pathinfo($path, PATHINFO_EXTENSION);
if ($ext=="jpg" OR $ext=="jpeg" OR $ext=="gif" OR $ext=="png") {
// your code here like...
echo "Upload successful";
}else{
// your invalid code here like...
echo "Invalid image format. Only upload JPG or JPEG or GIF or PNG";
}
?>
You can also try this in the frontend to filter or allow file types you want to accept.
<input type="file" name="file" accept="image/jpeg, image/gif, image/png" />

Categories