Premature end of JPEG file - php

I am getting this Premature end of JPEG file error while resizing some of the images. Interesting and strange part is that i am getting this error only when i upload any camera taken images, like from mobile, other than those every thing works great. I thought this could be because of the chunk size used in plupload. So, i uploaded with larger sized image to somewhat like 3mb to test. Works fine with images other than camera taken images. So, whenever i upload camera pics i get this error.
Further elaborations on the error: php function imagecreatefromjpeg is throwing an error "imgname.jpg is not a valid JPEG file".
To resize images i am using Codeigniter's image Manipulation Class.

Based on what you have provided, I can only give you my deductions.
Camera images are usually very big. I suggest that you try to resize the camera images and see if it works.
What is your PHP version? There is a bug related to this: https://bugs.php.net/bug.php?id=29878
Please also check if your JPEG files are in RGB format. Somewhere in the manual mentioned that it could not properly load CMYK for certain versions of the GD library.
Are you open to using another class? I use this class to resize images and have not encountered any problems with it for years.
Resizing images is as easy as:
<?php
include('SimpleImage.php');
$image = new SimpleImage();
$image->load('picture.jpg');
$image->resizeToHeight(500);
$image->save('picture2.jpg');
$image->resizeToHeight(200);
$image->save('picture3.jpg');
?>
If all the suggestions did not work out, you can try using ImageMagick.

Also "Premature end of JPEG file" it's a general software error if image content is not complete. Software determines it by color of last pixel.
I've get 'Premature end of JPEG file' from tesseract(Open Source OCR Engine) because file was not copied properly through network.

did you found that sometimes it hang the php when imagecreatefromjpeg() run on bad JPEG. I found that this is cause by the JPEG file U used dont have EOI (end of image)
the FF D9 at the end of your JPEG
JPEG image should start with 0xFFD8 and end with 0xFFD9
// this may help to fix the error
function check_jpeg($f, $fix=false )
{
# check for jpeg file header and footer - also try to fix it
if ( false !== (#$fd = fopen($f, 'r+b' )) ){
if ( fread($fd,2)==chr(255).chr(216) ){
fseek ( $fd, -2, SEEK_END );
if ( fread($fd,2)==chr(255).chr(217) ){
fclose($fd);
return true;
}else{
if ( $fix && fwrite($fd,chr(255).chr(217)) ){return true;}
fclose($fd);
return false;
}
}else{fclose($fd); return false;}
}else{
return false;
}
}

You can set default value of gd.jpeg_ignore_warning=1 in php.ini
OR
You can set it like this ini_set('gd.jpeg_ignore_warning', true); in your PHP script before calling imagecreatefromjpeg()
After implementing any of the above, GD Library will ignore the error where it use to fail and imagecreatefromjpeg() will return an image resource identifier.
Note: In PHP 7.1.0 the default value of gd.jpeg_ignore_warning has been changed from 0 to 1.
Reference

Related

Partial image download using cURL. How to detect?

We use PHP-cURL to download images from the web for one of our apps and sometimes the image downloads partially due to a timeout. Here is what a partially downloaded image looks like
I am wondering if there is any way to detect this using PHP? We don't see any errors as far as cURL is concerned.
Any imagick commands for example that can be used?
I realise this is an old post, but I stumbled upon it when I had the same issue.
I wrote this php code to check if the image file is valid:
function imageIsValid($local_path)
{
$im = imagecreatefromjpeg($local_path);
$valid = !!$im;
imagedestroy($im);
return $valid;
}
This works because imagecreatefromjpeg will return nothing if the image stream is corrupted.

imagecopy fails when source image is corrupt

I wrote a simple PHP script to add additional information to a webcam JPG file. It adds header and footer with some text. To do so I create a new image with this information and then copy the original JPG inside using imagecopy. And it all works fine.
The webcam has a poor wifi connection to the internet, so it seldom happens that the JPG file uploaded via FTP is partial or corrupt: I can open it using GIMP or other image software, and I see it has some missing information to the bottom. When this happens the above imagecopy seems to fail in copying image data, and the destination image remains blank (for the image area).
I tried everything I found to check the original JPG is valid:
// Check image
if (exif_imagetype($last) != IMAGETYPE_JPEG) // Not a valid jpeg
continue;
$details = getimagesize($last);
if ($details === FALSE) // Not a valid mage
continue;
$im = imagecreatefromjpeg($last);
but all tests pass. I also added:
if (imagecopy($dest_image, $im, 0, $top_banner_height+1, 0, 0, $img_width, $img_heigth) === FALSE) {
imagedestroy($im);
imagedestroy($dest_image);
continue;
}
but I still cannot catch an unterminated upload. How can I check if the image is valid for GD processing?
edit: this is how the source image appears in GIMP:
This is a portion of the original uploaded file.
As requested I added how I open the file, using imagecreatefromjpeg. It cannot be a permission problem because the script works fine 90% of the times, it's just when it encounters such images which fails.
edit2: I originally thought it could be a concurrency problem, being that I run the script via cron every minute, but the FTP upload is out of server control, so they run asynchronously. So perhaps the script was accessing the file exactly while being uploaded, but I checked and it's not the case, as I wrote above the uploaded file is corrupt in the beginning.
edit3: the suggested imagecolorat is not a solution (at least not at for all cases): I just found a messed up picture that would pass that test. jpeginfo says: Corrupt JPEG data: 10839 extraneous bytes before marker 0xd9
Thanks for all the suggestions, but in the end I found another possible way.
As said above and in other answers the command line tool jpeginfo -c filename checks if the image is a valid jpeg, printing a warning or and error (and a return code != 0). So it's the most precise solution so far, but involves an external command.
On the PHP side there doesn't seem to be a perfect check, as also the counterpart Imagick::valid doesn't perform a validity check on the full image.
At that very same page there's another proposed solution:
// check for the existence of the EOI segment header at the end of the file
$file = fopen($image_file, "r");
if (0 !== fseek($file, -2, SEEK_END) || "\xFF\xD9" !== fread($file, 2)) {
// jpeg is not valid
fclose($file);
return FALSE;
}
This works great, but only for unfinished images (first case). The example posted in edit 3 still passes this test.

Is ImageMagick identify enough to verify that the image is indeed an image

I use the code below to test whether an uploaded file is indeed an image. (The code below is not the same OOP style found in the php website when using ImageMagick because I am on a shared server and that is the instructions my hosting provided when using ImageMagick AND Actual script will involve rerouting users, unlinking or deleting the file uploaded and more so please do not criticize the code below, I just want to dwell in the concept of using IMAGICK IDENTIFY as an image verification tool.)
<?php
if(!exec('/usr/bin/identify /home/user/public_html/joteco_test_folder/thisisanimage.jpg'))
{
echo "NOT AN IMAGE";
}
else
{
echo exec('/path/here/identify /path/here/thisisanimage.jpg');
}
?>
I tried the following on the code above:
A .jpg made with photoshop cs6.
(It passed and echoed the following details "810x203 810x203+0+0 8-bit DirectClass 32.4KB 0.000u 0:00.000")
A .txt file. (It failed and echoed "NOT AN IMAGE")
A .jpg file made with notepad that has text characters written that says "I AM AN IMAGE". (It failed and echoed "NOT AN IMAGE")
(In my point of view I think it was a success, but I know that hackers do more than what I did in test #3.)
SO! Do you think that would be enough as a security check to verify if an uploaded file is indeed an image? Or are there other tools in ImageMagick that I can use for this purpose? Your thoughts?
(Pls. do not suggest or mention ( MIME | EXTENSION | GETIMAGESIZE ) as it has been repeatedly mentioned in stackoverflow as useless methods in verifying uploaded files. Thank you)
This should help you out.
$im = #imagecreatefromjpeg($imgname);
if(!$im)
{
return false;
}
else
{
imagedestroy($im);
return true;
}
In addition to checking if its an image it also returns false for incomplete (partaily uploaded) images

Image upload security - reprocess with GD

I've heard that the best way to handle uploaded images is to "re-process" them using the GD library and save the processed image. see: PHP image upload security check list
My question is how do this "re-processing" in GD? What this means exactly? I don't know the GD library very well and I'm afraid I will mess it up...
So if anyone who did this before could you give me an example for this?
(I know, another other option is to use ImageMagick. For ImageMagick I found an answer here: Remove EXIF data from JPG using PHP, but I can't use ImgMagick now. By the way.. removing EXIF data means completely recreate the image in this case?)
(I'm using Zend Framework if someone interested.)
If the user uploads a JPEG file, you could do something like this to reprocess it:
$newIm = #imagecreatefromjpeg($_FILES['file']['tmp_name']);
if (!$newIm) {
// gd could not create an image from the source
// most likely, the file was not a valid jpeg image
}
You could then discard the $newIm image using imagedestroy() and use the uploaded file from the user, or save out the image from GD and use that. There could be some issues with saving the GD image as it is not the original image.
Another simple method would be to check the header (first several bytes) of the image file to make sure it is correct; for example all JPEG files begin with 0xff 0xd8.
See also imagecreatefromstring(), and you can also use getimagesize() to run similar checks on the uploaded image.
function isvalidjpeg($file)
{
$finfo = finfo_open(FILEINFO_MIME_TYPE);
return is_resource($finfo) &&
(finfo_file($finfo, $file) === 'image/jpeg') &&
finfo_close($finfo);
}
if(isvalidjpeg($_FILES['file']['tmp_name'])) {
$newIm = #imagecreatefromjpeg($_FILES['file']['tmp_name']); .....

Rotating a picture in PHP once it's saved

I have this PHP script that saves a picture on my website. I would like to, once the picture is saved, rotate the picture by 90 degrees if it's not landscape. This a piece of my script:
$uploadfile = 'path/where/to/save/picture.jpg';
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
//The code under here is not working
if($_GET['landscape'] == false || $_GET['landscape'] == 'false'){
$img = imagecreatefromjpeg($uploadfile);
$newimg = imagerotate($img, 90.0, 0);
imagejpeg($newimg, $uploadfile);
}
//this is code under here is working
$prev = create_preview($filename, $uploadfile, $ext, true);
}
As you can see I move_uploaded_file() and then I have an if statement that if the picture is not landscape (so landscape == false) I rotate it. Then I create a preview of the picture.
If I comment out the if statement that checks the landscape the code WORKS, so it uploads the picture but it's NOT ROTATED as I want and creates a preview. If I let the if uncommented (like in this case) it seems like it's not saved anymore because when I try to visualize it I see nothing. This means that the code flow goes into the if, then something happens and the picture is not visualized anymore. The problem is in the if statement that rotates the picture.
So there is definitely something wrong in the procedure to rotate the picture, but I don't understand exactly what's wrong, I create the image from the location it has been uploaded to, I rotate it using the PHP function and then recreate the image in the same exact location.
Can anyone of you see where I'm getting this wrong?
Thanks,
Masiar
It's a shame you can't see the error messages. I suggest writing a small test page that will "fake" the iPhone side of things and allow you to test by submitting images without using the phone. Or simply write a short script that will open an image, imagerotate() it and save it, and use that for testing.
Also, as gnud points out, the PHP errors may even already be being written out to a server logfile. (Typically, they'll be somewhere like /var/log/apache/..., but figuring out where they are on your box will be more of a question for SuperUser, I guess...)
Having said that, given all you've said, I suspect that the PHP package for the distribution of Linux you're using does not support the (fairly-heavily-edited) PHP "packaged" version of the GD library. See this enhancement request for Ubuntu for some details.
This means that the imagerotate() function that you're using simply doesn't exist. You'd verify this easily if you enabled error reporting and used a test script.
As a workaround, your options are either to find a version of the GD library that you can install on your box to replace the standard one, or perhaps use a function written in PHP to do the rotation manually.
Alternatively, as Eamorr suggests, you could shell out to a command-line tool like ImageMagick (or maybe use ImageMagick via the PECL ImageMagick library, but that's probably overkill for one rotate.)
As an aside, I believe the iPhone specifically "rotates" photos that it's taken (e.g. in landscape orientation) by setting a flag in the image metadata, rather than actually rotating the image data, so if you're rotating images taken on an iPhone, make sure that you test with images taken in both portrait and landscape orientations, and check that your image rotation is doing the right thing in each case.
If I recall correctly, the photo data is always in portrait orientation, and just has the "landscapeness" set in the EXIF orientation data if the photo was taken with the phone held in landscape orientation. There are different values for if the phone's held upside-down, too.
To flip 180 degrees:
exec('mogrify -flip /path/to/your/picture');
You need to install imagemagick
I'm sure you can figure out how to flip it 90 degrees very easily.

Categories