PHP test for corrupt (but apparently fine) images - php

I have a simple image upload script that uses SimpleImage.php
(http://www.white-hat-web-design.co.uk/blog/resizing-images-with-php/)
to resize and save 2 copies of an uploaded image.
There isn't a massive amount of validation, just checking that it exists and that the file extension is fine, and also an exif_imagetype(); call.
This has worked with no problems so far until I tried to upload a seemingly normal jpeg which turned out to be invisibly (and untestably?) corrupt. There was something not right about it, but I know very little about image corruption - it looked fine and opened no problem on anything, but when I tried to save a scaled copy in my script I got a white page.
The problem is definitely that specific image, I've tested exhastively with other images both from my local stock and from stock image sites, and only that one image breaks it.
I resized a copy using Photoshop (the predicted file size thingy gave me some wierd numbers - 45meg for top quality jpeg) and that uploaded with no issues.
So my question is, how do I test for this?
The image in question is here: http://chinawin.co.uk/broken.jpg //beware, 700k
notes: I've tested with similar resolutions, image sizes and names, everything else worked apart from this image.
UPDATE:
Through trial and error I've narrowed down where the script breaks to the line where I load the image into a var for SimpleImage. Strangely this is the second line that does so (the first being to create the large copy, this one to create a thumbnail).
Commenting it out means the rest works ok... perhaps some refactoring will avoid this problem.
2nd Update:
Here's a snippet of code and some context from the line that fails:
//check if our image is OK
if ($image && $imageThumb)
{
//check if image is a jpeg
if (exif_imagetype($_FILES[$k]['tmp_name']) == IMAGETYPE_JPEG)
{
list($width, $height, $type, $attr) = getimagesize($_FILES[$k]['tmp_name']);
//echo 1;
$image = new SimpleImage();
//echo 2;
$image->load($_FILES[$k]['tmp_name']);
//echo 3;
$imageThumb = new SimpleImage();
//echo 4;
//this next line topples my script, but only for that one image - why?:
$imageThumb->load($_FILES[$k]['tmp_name']);
//echo '5<br/><br/>-------<br/>';
//do stuff, save & update db, etc
}
}
Final edit:
Turns out my script was running out of memory, and with good reason - 4900x3900 image with 240 ppi turns out to be around 48 meg when loaded into memory, twice - so I was using probably > 90meg of ram, per image.
Hats off to #Pekka for spotting this.
Refactoring the script to only have the image loaded once, and then this variable used instead of it's sibling, fixed my script. Still having (different) issues with upoading larger (2.5meg) images but this is for another question.

This is most likely a memory issue: Your JPG is very large (more than 4000 x 4000 pixels) and, uncompressed, will indeed eat up around 48 Megabytes of RAM.
Activate error reporting to make sure. If it's the reason, see e.g. here on what to do: Uploading images with PHP and hitting the script memory limit

Related

PHP memory leak when working with image

I'm having a bad time trying to work with an image with PHP.
The image is well ... big. It is a high definition picture (36MP resolution) for a total size of 23Mo.
I'm doing certain things on this picture, like resizing it or transforming it to greyscale.
The problem is, when I'm looking the memory usage using htop on a terminal, I can see that apache is using memory (a little more than 140Mb) but is not releasing it when image processing is over.
I deleted each image processing functions one by one and now have only those 3 simple lines, but the leak is still there :
$image = imagecreatefromstring( file_get_contents($imageFullPath) );
imagedestroy($image);
unset($image);
Does someone have any idea why ?
Thanks !
Jim
it is a common memory problem in php . unset($image) is not deleting image from memory it only deletes link of data. try empty image like this .
$image = NULL;

Why would a PHP image copy and resize script cause a browser to return "Content Encoding Error"?

I have a PHP script that takes an images, checks type and filesize, then creates 2 resized copies of the master image, all 3 images are saved to the server. I was under the impression everything worked fine. I was testing out script and on one jpg image I got thrown the error "Content Encoding Error" by firefox. Doing some reading suggested this was a Firefox issue but testing in IE and Chrome resulted in similar errors.
The odd thing is that some .jpg files work, others don't. For those that don't work the error is occurring when the script comes to encode the second resized copy as the master, and first copy are outputted to specified folder. I have checked to see that the image itself isn't corrupt after doing some more reading. The only difference I could note between a .jpg that would allow the script to complete fully and one that wouldn't was that, when viewing the properties of the failing one within Windows it appeared to carry more data, such as camera used to, model number, etc.
Does anyone know what might be causing this error to be thrown?
EDIT
Here's the code I'm using.
$imgsrc = imagecreatefromjpeg($file);
imagecopyresampled($thbout,$imgsrc,0,0,0,0,$thbwid,$thbhei,$width,$height);
imagejpeg($thbout,$thbpath,80);
imagedestroy($thbout);
imagecopyresampled($optout,$imgsrc,0,0,0,0,$optwid,$opthei,$width,$height);
imagejpeg($optout,$optpath,80);
imagedestroy($optout);
Having played about a bit tonight I got it working, by switching the code to this. (Switch to create larger file first)
$imgsrc = imagecreatefromjpeg($file);
imagecopyresampled($optout,$imgsrc,0,0,0,0,$optwid,$opthei,$width,$height);
imagejpeg($optout,$optpath,80);
imagedestroy($optout);
imagecopyresampled($thbout,$imgsrc,0,0,0,0,$thbwid,$thbhei,$width,$height);
imagejpeg($thbout,$thbpath,80);
imagedestroy($thbout);
So I guess my new question becomes, why does it behave like this?

Image SRC From PHP Script on IIS - Not Displaying Consistently

Last week I converted my page img src values from pointing at image files to using a PHP script to serve up the images. The primary reason was to accommodate both files and database BLOBs as the actual source.
Now when a user goes to a page, sometimes images show and sometimes not. If not, and the page is refreshed\reloaded, then the image appears. When images do not appear, sometimes it is an image the user has already accessed previously today.
I am stumped.
Here is the img tag:
<img src="../somedir/image_script.php?i=1234">
The image_script.php file figures out where to get the image from, then finishes up with:
header("Content-type: image/jpeg");
if($from_db){
print $image_blob;
} else {
$im = imagecreatefromjpeg($image_file);
imagejpeg($im,null,100);
imagedestroy($im)
}
I am using PHP 5.2.8 on IIS 6 using FastCGI. There are no cache headers on the image_script.php file nor on the directory it is in. Currently 99.9% of the images are file based, so I do not know if there is a difference in result between db-based and file-based images. When I go directly to image_script.php in my browser it returns the requested image (i=????) 100% of the time.
a> Any clue as to why the hit and miss with images being displayed? and,
b> what would be a proper way to actually cache the images served up by the PHP script? (they are very static)
Scott
Hmm. Can't tell for sure, but maybe your imagecreatefromjpeg is occasionally running out of memory? In that case, you'd serve an error message out as JPEG data and never see it, right?
Incidentally, wouldn't just grabbing the image file in as a string and shovelling it out without going through imagecreatefromjpeg/imagejpeg/imagedestroy be more efficient? It looks like you're reading a JPEG file, creating an internal PHP memory image from it, then reconverting it to a JPEG (at hefty 100% quality) then serving that data out, when you could simply read the JPEG file data in and print it, like you do from the database.
What happens if you do, say...
...
} else {
header ('Content-length: ' .filesize($image_file));
readfile ($image_file);
}

How to compress images in CodeIgniter, yet do not change their dimensions?

I have a site where users can upload images. I process these images directly and resize them into 5 additional formats using the CodeIgniter Image Manipulation class. I do this quite efficiently as follow:
I always resize from the previous format, instead of from the original
I resize using an image quality of 90% which about halves the file size of jpegs
The above way of doing things I implemented after advise I got from another question I asked. My test case is a 1.6MB JPEG in RGB mode with a high resolution of 3872 x 2592. For that image, which is kind of borderline case, the resize process in total takes about 2 secs, which is acceptable to me.
Now, only one challenge remains. I want the original file to be compressed using that 90% quality but without resizing it. The idea being that that file too will take half the file size. I figured I could simply resize it to its' current dimensions, but that doesn't seem to do anything to the file or its size. Here's my code, somewhat simplified:
$sourceimage = "test.jpg";
$resize_settings['image_library'] = 'gd2';
$resize_settings['source_image'] = $sourceimage;
$resize_settings['maintain_ratio'] = false;
$resize_settings['quality'] = '90%';
$this->load->library('image_lib', $resize_settings);
$resize_settings['width'] = $imagefile['width'];
$resize_settings['height'] = $imagefile['height'];
$resize_settings['new_image'] = $filename;
$this->image_lib->initialize($resize_settings);
$this->image_lib->resize();
The above code works fine for all formats except the original. I tried debugging into the CI class to see why nothing happens and I noticed that the script detects that the dimensions did not change. Next, it simply makes a copy of that file without processing it at all. I commented that piece of code to force it to resize but now still nothing happens.
Does anybody know how to compress an image (any image, not just jpegs) to 90% using the CI class without changing the dimensions?
I guess you could do something like this:
$original_size = getimagesize('/path/to/original.jpg');
And then set the following options like this:
$resize_settings['width'] = $original_size[0];
$resize_settings['height'] = $original_size[1];
Ok, so that doesn't work due to CI trying to be smart, the way I see it you've three possible options:
Rotate the Image by 360º
Watermark the Image (with a 1x1 Transparent Image)
Do It Yourself
The DIY approach is really simple, I know you don't want to use "custom" functions but take a look:
ImageJPEG(ImageCreateFromString(file_get_contents('/path/to/original.jpg')), '/where/to/save/optimized.jpg', 90);
As you can see, it's even more simpler than using CI.
PS: The snippet above can open any type of image (GIF, PNG and JPEG) and it always saves the image as JPEG with 90% of quality, I believe this is what you're trying to archive.

imagecreatefromjpeg is silently terminating scripts

Like so many before me, I'm writing a PHP script to do some image thumbnailing. The script has earned WOMM (works on my machine) certification, but when I move it to my host (1&1 Basic), there's an issue: images above a certain filesize cannot be processed. I've moved all operations to the filesystem, to be certain it's not some latent POST issue. Here's the relevant code:
function cropAndResizeImage( $imageLocation )
{
//
// Just to be certain
//
ini_set('display_errors','on');
error_reporting(E_ALL);
ini_set('memory_limit','128M');
ini_set('max_execution_time','300');
$image_info = getimagesize($imageLocation);
$image_width = $image_info[0];
$image_height = $image_info[1];
$image_type = $image_info[2];
switch ( $image_type )
{
// snip...
case IMAGETYPE_JPEG:
$image = imagecreatefromjpeg($imageLocation);
break;
default:
break;
}
// snip...
}
Using my mystical powers of println debugging, I've been able to determine that imagecreatefromjpeg is not returning; in fact, the script halts completely when it gets to it. Some facts:
This is correlated to filesize. Images under 1MB appear to be fine (spot-checked), but images around 3MB barf. No clue what the precise cutoff is, though.
This is not due to server timeouts; wget returns in <1s on 3MB images, significantly longer on "appropriately small" images (indicating no processing of large images).
Prefixing the function call with # to suppress errors has no effect. This matches well with the fact that the script is not throwing an error, it's simply silently terminating upon this function call.
If I had to guess, there may be some GD parameter that I don't know about (or have access to) that limits input file sizes on 1&1's servers — the config variable guess is due to the fact that it barfs immediately, and doesn't appear (heuristically) to do any actual loading of or computations on the image.
Any suggestions? Thanks for the help.
Update (courtesy #Darryl's comments): calls to phpinfo indicate that PHP is updating the max_execution_time and memory_limit variables correctly. This doesn't necessarily mean that these resources are being allocated, simply that they appear to be functioning as expected.
Update 2: following some references from The Google, I tried optimizing the JPEG (reduced in quality from 3MB to 200KB) with no luck, so it's not an image filesize issue. I then tried reducing the number of pixels of the original 3888x2592 image, and the first successful size is 1400x2592 (1401x and 1402x both result in half-parses and errors indicating "malformed JPEG", which doesn't make much sense unless the entire image isn't being loaded). By reducing further to 1300x2592, I can instantiate the 400x300 thumbnail image that I'm actually looking for; at 1400x2592, the imagecreatetruecolor call I'm using to take care of that task fails silently in the same manner as imagecreatefromjpeg.
As to why this is, I'm a little uncertain. 1400 * 2592 == 3.5MB gives nothing particularly meaningful, but I have to imagine this is a limit on the number of pixels GD + PHP will process.
Please see this note regarding memory usage on the php website.
*"The memory required to load an image using imagecreatefromjpeg() is a function of the image's dimensions and the images's bit depth, multipled by an overhead.
It can calculated from this formula:
Num bytes = Width * Height * Bytes per pixel * Overhead fudge factor"*
I'm guessing 1&1 doesn't allow you to change scripts memory_limit or max_execution_time, so it's probably running out of memory. Have you tried running phpinfo() to see what the limits are?

Categories