We have a web app using Andrew Valums ajax file uploader, if we kick off 5 - 10 image uploads at once, more often then not at least 2 or 3 will result in the same gd error "Corrupt JPEG data"
Warning: imagecreatefromjpeg() [function.imagecreatefromjpeg]:
gd-jpeg, libjpeg: recoverable error: Corrupt JPEG data:
47 extraneous bytes before marker 0xd9 in ....
However this did not happen on our old test server, or local development box's, only on our new production server.
The file size on the server is the same as the original on my local machine, so it completes the upload but I think the data is being corrupted by the server.
I can "fix" the broken files by deleting them and uploading again, or manually uploading via FTP
We had a shared host on Godaddy and just have started to have this issue on a new box (that I set up, so probably explains a lot :) CentOS 5.5+, Apache 2.2.3, PHP 5.2.10
You can see some example good and bad picture here. http://174.127.115.220/temp/pics.zip
When I BinDiffed them I see a consistent pattern the corruption is always 64 byte blocks, and while the distance between corrupted blocks is not constant the number 4356 comes up a lot.
I really think we can rule out the Internet as error checking and retransmission with TCP is pretty reliable, further there seems to be no difference between browser versions, or if I turn anti-virus and firewalls off.
So I'm picking configuration of Apache / PHP?
Some cameras will append some data inside the file that will get interpreted incorrectly (most likely do to character encoding with in the headers).
A solution I found was to read the file in binary mode like so
$fh = fopen('test.jpg', 'rb');
$str = '';
while($fh !== false && !feof($fh)){
$str .= fread($fh, 1024);
}
$test = #imagecreatefromstring($str);
imagepng($test,'save.png');
Well, i think the problem is jpeg-header data, and as far as i know there is nothing to do with it by PHP, i think the problem is your fileuploader, maybe there are some configuration for it that you are missing.
Hmm - a 64 byte corruption?...or did you mean 64 bit?
I'm going to suggest that the issue is in fact as a result of the PHP script. the problem that regularly comes up here is that the script inserts CRLFs into the data stream being uploaded, and is caused by differences between the Window/*nix standards.
Solution is to force the php script to upload in binary mode (use the +b switch for ALL fopen() commands in the php upload). It is safe to upload a text file in binary mode as at least you can still see the data.
Read here for more information on this issue:
http://us2.php.net/manual/en/function.fopen.php
This can be solved with:
ini_set ('gd.jpeg_ignore_warning', 1);
I had this problem with GoDaddy hosting.
I had created the database on GoDaddy using their cPanel interface. It was created as "latin collation" (or something like that). The database on the development server was UTF8. I've tried all solutions on this page, to no avail. Then I converted the database to UTF8, and it worked.
Database encoding shouldn't affect BLOB data (or so I would think). BLOB stands for BINARY Large Object (something...), to my knowledge!
Also, strangely, the data was copied from the dev to production server while the database was still "latin", and it was not corrupted at all. It's only when inserting new images that the problem appeared. So I guess the image data was being fed to MySQL as text data, and I think there is a way (when using SQL) of inserting binary data, and I did not follow it.
Edit: just took a look at the MySQL export script, here it is:
INSERT INTO ... VALUES (..., _binary 0xFFD8FF ...
Anyway, hope this will help someone. The OP did not indicate what solved his problem...
Related
We are using ImageMagick for resizing/thumbnailing JPGs to a specific size. The source file is loaded via HTTP. It's working as expected, but from time to time some images are partially broken.
We already tried different software like GraphicsMagick or VIPS, but the problem is still there. It also only seems to happen if there are parallel processes. So the whole script is locked via sempahores, but it also does not help
We found multiple similar problems, but all without any solution: https://legacy.imagemagick.org/discourse-server/viewtopic.php?t=22506
We also wonder, why it is the same behaviour in all these softwares. We also tried different PHP versions. It seems to happen more often on source images with a huge dimension/filesize.
Any idea what to do here?
Example 1 Example 2 Example 3
I would guess the source image has been truncated for some reason. Perhaps something timed out during the download?
libvips is normally permissive, meaning that it'll try to give you something, even if the input is damaged. You can make it strict with the fail flag (ie. fail on the first warning).
For example:
$ head -c 10000 shark.jpg > truncated.jpg
$ vipsthumbnail truncated.jpg
(vipsthumbnail:9391): VIPS-WARNING **: 11:24:50.439: read gave 2 warnings
(vipsthumbnail:9391): VIPS-WARNING **: 11:24:50.439: VipsJpeg: Premature end of JPEG file
$ echo $?
0
I made a truncated jpg file, then ran thumbnail. It gave a warning, but did not fail. If I run:
$ vipsthumbnail truncated.jpg[fail]
VipsJpeg: Premature end of input file
$ echo $?
1
Or in php:
$thumb = Vips\Image::thumbnail('truncated.jpg[fail]', 128);
Now there's no output, and there's an error code. I'm sure there's an imagemagick equivalent, though I don't know it.
There's a downside: thumbnailing will now fail if there's anything wrong with the image, and it might be something you don't care about, like invalid resolution.
After some additional investigation we discovered that indeed the sourceimage was already damaged. It was downloaded via a vpn connection which was not stable enough. Sometimes the download stopped, so the JPG was only half written.
Having trouble capturing the following dynamic image on disk, all I get is a 1K size file
http://water.weather.gov/precip/save.php?timetype=RECENT&loctype=NWS&units=engl&timeframe=current&product=observed&loc=regionER
I have setup PHP cURL feature to work just fine on static imagery, but does not work for the above link. Similarly, also copy function, file_put_contents (file_get_contents)...they all work fine for static image. Plenty of references in SO for usage of these PHP functions, so I will not get into details here. Just the copy command:
copy('http://water.weather.gov/precip/save.php?timetype=RECENT&loctype=NWS&units=engl&timeframe=current&product=observed&loc=regionER', 'precip5.png');
Behavior is same, getting precip5.png size 760 bytes, on my windows development box and linux staging box, so can rule OS issues out. Again, all PHP functions do exactly the same thing - generate a file - but empty. Command line curl program is also generating that same junk 1K file.
So, the issue seems to be source and the best I can tell is that it is a dynamic (streaming?) image.
Ideally, I would like this be done in PHP or some command line utility like curl. I am trying to avoid adding java (imageio) dependency just for this...until I absolutely have have to go there...
I am trying to understand the nature of the beast (the image) first ;-)...
The URL you are saving produces HTML output, not the image. You are missing the parameter &print=1
http://water.weather.gov/precip/save.php?timetype=RECENT&loctype=NWS&units=engl&timeframe=current&product=observed&loc=regionER&print=1
I have recently bought a new MacBook Pro. Before I had my MacBook Pro I was working on a website on my desktop computer. And now I want to transfer this code to my new MacBook Pro.
The problem is that when I transfered the code (I put it on Dropbox and simply downloaded it on my MacBook Pro) I started to see lots of error messages in my PHP code.
The error message I”m receiving is:
Warning: Cannot modify header information - headers already sent by (output started at /some/file.php:1) in /some/file.php on line 23
I have done some research on this and it seems that this error is most frequently caused by a new line, simple whitespace or any output before the <?php sign. I have looked through all the places where I have cookies that are being sent in the HTTP request and also where I'm using the header() function. I haven’t detected any output or whitespace that possibly could interfere and cause this problem.
Noteworthy is that the error always says that the output is started at line 1. Which got me thinking if there is some kind of coding differences in the way that the Mac OS X and Windows operating systems handle new lines or white spaces? Or could the Dropbox transfer messed something up?
The code on one of the sites(login.php) which produces the error:
<?php
include "mysql_database.php";
login();
$id = $_SESSION['Loggedin'];
setcookie("login", $id, (time()+60*60*24*30));
header('Location: ' . $_SERVER['HTTP_REFERER']);
?>
login function:
function login() {
$connection = connecttodatabase();
$pass = "";
$user = "";
$query = "";
if (isset($_POST['user']) && $_POST['user'] != null) {
$user = $_POST['user'];
if (isset($_POST['pass']) && $_POST['pass'] != null) {
$pass = md5($_POST['pass']);
$query = "SELECT ID FROM Anvandare WHERE Nickname='$user' AND Password ='$pass'";
}
}
if ($query != "") {
$id = $connection->query($query);
$id = mysqli_fetch_assoc($id);
$id = $id['ID'];
$_SESSION['Loggedin'] = $id;
}
closeconnection($connection);
}
Complete error:
Warning: Cannot modify header information - headers already sent by (output started at /Users/name/GitHub/website/login.php:1) in /Users/namn/GitHub/website/login.php on line 9
Check if there are spaces in front of your php opening tag. Also try resaving the file from notepad++ using the windows (crlr) line endings. (Edit > EOL Conversion > Windows format)
Noteworthy is that the error always says that the output is started at
line 1. Which got me thinking if there is some kind of coding
differences in the way that the Mac OS X and Windows operating systems
handle new lines or white spaces? Or could the Dropbox transfer messed
something up?
Don’t redo your code or worry about the header() calls or even the cookie stuff. That is not the issue.
The issue is that Windows line endings are different from Mac line endings. More details here.
Different operating systems use different characters to mark the end
of line:
Unix / Linux / OS X uses LF (line feed, '\n', 0x0A)
Macs prior to OS X use CR (carriage return, '\r', 0x0D)
Windows / DOS uses CR+LF (carriage return followed by line feed, '\r\n', 0x0D0A)
And what happens in cases like this is the formatting of the page causes the PHP parser in Apache to choke on the files. Possibly sending content to the browser before you intend to when making header() calls or setting cookies. Meaning technically the screwed up line endings force a “header” to be sent because the file itself is outputting data to the browser inadvertently.
The solution might be to avoid using Dropbox & just copy the files onto a flash drive & transfer it that way. That’s an idea but I am not convinced that Dropbox was the culprit in this. Meaning the issue might still exist even if you copy the files to a flash drive.
Or if that does not work, do as the linked to article suggests & download a good text editing tool like TextWrangler. Just load the files into TextWrangler & then manually change the line endings so they are Mac (CR) and resave the files.
Another long-term solution to this issue might be to use a version control system like git coupled with an account on GitHub to manage your code. The benefit is by pushing code to GitHub & pulling code from GitHub, the process itself will deal with cross-platform line ending headaches. And you don’t need to worry about inadvertent oddities caused by a straight copy of files to a service like DropBox.
But again, pretty convinced this has nothing to do with Dropbox. It’s all about Windows line endings being different from Mac OS X line endings.
EDIT: There are some interesting ideas on how to handle the bulk conversion of Windows line endings to Mac OS X line endings on Mac OS X Hints. The most intrguing one is the use of zip and unzip to facilitate the process. I have not tried this, so caveat emptor! But it does sound like something worth testing since the last line states, BTW, it's the "-a" flag to unzip, that is causing the ascii files to have their lines endings converted.:
I've always used the following (in a file named fixascii):
#!/bin/sh
zip -qr foo.zip "$#" && unzip -aqo foo.zip && rm foo.zip
And then execute it as:
fixascii [files or directories to convert]
Which has the benefit over most of these other commands in that you
can point it with impunity at an entire directory tree and it will
process all the files in it and not corrupt any binaries that may
happen to have a string of bits in them that look like a line-ending.
I've seen too many times where someone corrupted a ton of images and
other binaries, when trying to fix line-endings on text files using
dos2unix or tr in combination with find but failed to ensure that only
text files were processed. Unzip figure out which files are ascii,
converts them, and leaves the binaries alone.
BTW, it's the "-a" flag to unzip, that is causing the ascii files to
have their lines endings converted.
And then looking in the official man page for unzip under the -a (convert text files) option; emphasis is mine:
Ordinarily all files are extracted exactly as
they are stored (as ''binary'' files). The -a option causes files
identified by zip as text files (those with the 't' label in zipinfo
listings, rather than 'b') to be automatically extracted as
such, converting line endings, end-of-file characters and the
character set itself as necessary. (For example, Unix files use
line feeds (LFs) for end-of-line (EOL) and have no end-of-file (EOF)
marker; Macintoshes use carriage returns (CRs) for EOLs; and most
PC operating systems use CR+LF for EOLs and control-Z for EOF. In
addition, IBM mainframes and the Michigan Terminal System use
EBCDIC rather than the more common ASCII character set, and NT
supports Unicode.) Note that zip's identification of text files
is by no means perfect; some ''text'' files may actually be binary
and vice versa. unzip therefore prints ''[text]'' or
''[binary]'' as a visual check for each file it extracts when using
the -a option. The -aa option forces all files to be extracted
as text, regardless of the supposed file type.
EDIT: Also, if you have access to a Linux machine, you might want to checkout dos2unix. More details here as well. And found another Stack Overflow question here.
Finally found an easy way to fix this! I was looking through the php.ini file when i came across an option which is named: auto_detect_line_endings, and has its default value set to: Off.
The description to this option is:
; If your scripts have to deal with files from Macintosh systems,
; or you are running on a Mac and need to deal with files from
; unix or win32 systems, setting this flag will cause PHP to
; automatically detect the EOL character in those files so that
; fgets() and file() will work regardless of the source of the file.
; http://php.net/auto-detect-line-endings
Which is exactly what i was looking for!
I simply used the ini_set() function at the beginning of my database file(which i load on every php page) and it seems to have solved the problem for me! The ini_set() function also returns the option changed in the php.ini file to normal when script is completed.
Full line of the ini_set() function that i used:
ini_set("auto_detect_line_endings", true);
Thanks for all your help guys!
More info on ini_set() function here: ini_set() function
More info on the auto_detect_line_endings option here: Auto detect line endings option
I have a php script running, which loops through all files in a specified directory. It returns name, filesize, modified_date etc. for each file it finds. The script returns the info for most of the files correctly, except for the ones that have Chinese or other symbols in it. Then I get the famous filesize stat failed error (warning). How would I solve this, without changing the filenames?
I will provide code if needed.
I've encountered this before; file system encoding is difficult and hard to predict, but this usually works for me:
stat(iconv('UTF-8', 'ISO-8859-1', $filename));
It just converts the filename from utf8 to iso8859-1 and tries.
This is tricky though, just look at this page for a juicy dialog in the post comments: http://www.rooftopsolutions.nl/blog/filesystem-encoding-and-php
I am having trouble uploading files to S3 from on one of our servers. We use S3 to store our backups and all of our servers are running Ubuntu 8.04 with PHP 5.2.4 and libcurl 7.18.0. Whenever I try to upload a file Amazon returns a RequestTimeout error. I know there is a bug in our current version of libcurl preventing uploads of over 200MB. For that reason we split our backups into smaller files.
We have servers hosted on Amazon's EC2 and servers hosted on customer's "private clouds" (a VMWare ESX box behind their company firewall). The specific server that I am having trouble with is hosted on a customer's private cloud.
We use the Amazon S3 PHP Class from http://undesigned.org.za/2007/10/22/amazon-s3-php-class. I have tried 200MB, 100MB and 50MB files, all with the same results. We use the following to upload the files:
$s3 = new S3($access_key, $secret_key, false);
$success = $s3->putObjectFile($local_path, $bucket_name,
$remote_name, S3::ACL_PRIVATE);
I have tried setting curl_setopt($curl, CURLOPT_NOPROGRESS, false); to view the progress bar while it uploads the file. The first time I ran it with this option set it worked. However, every subsequent time it has failed. It seems to upload the file at around 3Mb/s for 5-10 seconds then drops to 0. After 20 seconds sitting at 0, Amazon returns the "RequestTimeout - Your socket connection to the server was not read from or written to within the timeout period. Idle connections will be closed." error.
I have tried updating the S3 class to the latest version from GitHub but it made no difference. I also found the Amazon S3 Stream Wrapper class and gave that a try using the following code:
include 'gs3.php';
define('S3_KEY', 'ACCESSKEYGOESHERE');
define('S3_PRIVATE','SECRETKEYGOESHERE');
$local = fopen('/path/to/backup_id.tar.gz.0000', 'r');
$remote = fopen('s3://bucket-name/customer/backup_id.tar.gz.0000', 'w+r');
$count = 0;
while (!feof($local))
{
$result = fwrite($remote, fread($local, (1024 * 1024)));
if ($result === false)
{
fwrite(STDOUT, $count++.': Unable to write!'."\n");
}
else
{
fwrite(STDOUT, $count++.': Wrote '.$result.' bytes'."\n");
}
}
fclose($local);
fclose($remote);
This code reads the file one MB at a time in order to stream it to S3. For a 50MB file, I get "1: Wrote 1048576 bytes" 49 times (the first number changes each time of course) but on the last iteration of the loop I get an error that says "Notice: fputs(): send of 8192 bytes failed with errno=11 Resource temporarily unavailable in /path/to/http.php on line 230".
My first thought was that this is a networking issue. We called up the customer and explained the issue and asked them to take a look at their firewall to see if they were dropping anything. According to their network administrator the traffic is flowing just fine.
I am at a loss as to what I can do next. I have been running the backups manually and using SCP to transfer them to another machine and upload them. This is obviously not ideal and any help would be greatly appreciated.
Update - 06/23/2011
I have tried many of the options below but they all provided the same result. I have found that even trying to scp a file from the server in question to another server stalls immediately and eventually times out. However, I can use scp to download that same file from another machine. This makes me even more convinced that this is a networking issue on the clients end, any further suggestions would be greatly appreciated.
This problem exists because you are trying to upload the same file again. Example:
$s3 = new S3('XXX','YYYY', false);
$s3->putObjectFile('file.jpg','bucket-name','file.jpg');
$s3->putObjectFile('file.jpg','bucket-name','newname-file.jpg');
To fix it, just copy the file and give it new name then upload it normally.
Example:
$s3 = new S3('XXX','YYYY', false);
$s3->putObjectFile('file.jpg','bucket-name','file.jpg');
now rename file.jpg to newname-file.jpg
$s3->putObjectFile('newname-file.jpg','bucket-name','newname-file.jpg');
I solved this problem in another way. My bug was, that filesize() function returns invalid cached size value. So just use clearstatcache()
I have experienced this exact same issue several times.
I have many scripts right now which are uploading files to S3 constantly.
The best solution that I can offer is to use the Zend libraries (either the stream wrapper or direct S3 API).
http://framework.zend.com/manual/en/zend.service.amazon.s3.html
Since the latest release of Zend framework, I haven't seen any issues with timeouts. But, if you find that you are still having problems, a simple tweak will do the trick.
Simply open the file Zend/Http/Client.php and modify the 'timeout' value in the $config array. At the time of writing this it existed on line 114. Before the latest release I was running at 120 seconds, but now things are running smooth with a 10 second timeout.
Hope this helps!
There are quite a bit of solutions available. I had this exact problem but I don't wanted to write a code and figure out the problem.
Initially I was searching for a possibility to mount S3 bucket in the Linux machine, found something interesting:
s3fs - http://code.google.com/p/s3fs/wiki/InstallationNotes
- this did work for me. It uses FUSE file-system + rsync to sync the files in S3. It kepes a copy of all filenames in the local system & make it look like a FILE/FOLDER.
This saves BUNCH of our time + no headache of writing a code for transferring the files.
Now, when I was trying to see if there is other options, I found a ruby script which works in CLI, can help you manage S3 account.
s3cmd - http://s3tools.org/s3cmd - this looks pretty clear.
[UPDATE]
Found one more CLI tool - s3sync
s3sync - https://forums.aws.amazon.com/thread.jspa?threadID=11975&start=0&tstart=0 - found in the Amazon AWS community.
I don't see both of them different, if you are not worried about the disk-space then I would choose a s3fs than a s3cmd. A disk makes you feel more comfortable + you can see the files in the disk.
Hope it helps.
You should take a look at the AWS PHP SDK. This is the AWS PHP library formerly known as tarzan and cloudfusion.
http://aws.amazon.com/sdkforphp/
The S3 class included with this is rock solid. We use it to upload multi GB files all of the time.