A few months ago I wrote a website for a customer using PHP 5.3. It works perfectly on my own LAMP webserver. However, when he tried to install it in his own server (currently an OVH server running DirectAdmin on CentOS 5) he ran into an issue I’m having trouble figuring out.
The website can store images uploaded through forms. Images are watermarked on upload and moved to a directory in the webserver (some metadata is stored in the database, but this isn’t related to this issue).
In order to display these images back to the user, a script is used like so:
header("Content-type: image/jpeg");
ob_start();
echo file_get_contents($path);
$size = ob_get_length();
$img = ob_get_contents();
ob_end_clean();
header ("Content-length: " . $size);
echo $img;
Unfortunately, this always returns a broken image (in Firefox, “The image cannot be displayed because it contains errors”). Now, after careful testing, I know that:
-
Images are correctly uploaded to the server. The image data stored in the webserver is valid and can be obtained via FTP as the regular image.
-
If I store $img to a file immediately before the final line of the previous script, like so:
$fh = fopen("test.jpg", "w"); fwrite($fh, $img); fclose($fh);It will save the correct image data to the file also. So the data is intact immediately before being sent to the user’s web browser.
-
The headers are being sent correctly.
However! If I use a text/plain header rather than image/jpeg, I can see that the gibberish returned is different from the gibberish displayed if I open the file locally with notepad (or send the image directly through apache as a text file). In the original image, I can see some EXIF. In the image generated by PHP and then send to the user’s web browser, I still see the JFIF magic code (for JPEG File Image Format) but the rest looks different.
I’m afraid I have a configuration-related issue on either PHP or Apache related to encoding, buffering, content compression or something like that. Does anyone know anything I can try to solve this issue?
EDIT:
Changed the script to use:
$img = file_get_contents($path);
$size = filesize($path);
The issue remains unchanged, but the content now looks exactly the same comparing the real image to the image sent from PHP. According to the headers, the content encoding is gzip. Any ideas?
Well, after some investigation it turned to be infamous Byte Order Mark signature (in conjunction, of course, with output buffering which suppressed an error) in PHP script.
It seems just re-saving the file without BOM will solve the problem
does it work?
or this?
download this image (using wget or make a link on it and use ‘Save as’) and see the difference. It may shed the light on the cause
And yeah. ob has absolutely nothing to do here. if you want to get a file size – there is a (surprise!) a function for it