tags:

views:

425

answers:

4

First quesiton on Stack Overflow, so please be gentle.

What I'm trying to do is simple and should be very straightforward in my mind. The results have been less than encouraging. What I'm trying to do: I have a web page that receives base64-encoded PNG image data. I can and have successfully taken that data through the proper steps to create an image on the filesystem. Call this "Script A":

$imageData = $_POST['png'];
$imageStr = base64_decode($imageData);
$image = imagecreatefromstring($imageStr);
imagepng($image, $somePath);

This works fine. But I now have a new requirement, which is to later read this image, base64-encode it, and post it to Script A which will in turn write it back to the filesystem, exactly as above. Call this second script, the one that reads the data and posts it back to Script A, "Script B". It's when Script A attempts to call imagepng on the data received from Script B that I'm getting my error:

imagepng(): supplied argument is not a valid Image resource

Still with me? Impressive. So what this all means to me is that there is something wrong with the way Script B is reading the .png data from the filesystem, encoding it, and posting it to Script A. It does so as follows (w/o error handling here in the interest of brevity, but no errors are occuring) --

// Read in image file, base64-encode
$fd = fopen($somePath, 'rb');
$size = filesize($somePath);
$data = fread($fd, $size);
fclose($fd);
$encoded = base64_encode($data);

It then posts to Script A using cURL, w/ "$encoded" as a param.

Now, I've found countless examples of this methodology on the 'Net. I'm pretty sure it should work. It doesn't. I've also tried using file_get_contents. Also tried using 'imagecreatefrompng' to read the image, then using output buffer control to capture the image as a stream and base64-encoding that...no luck. In the end I think the approach above is the simplest and most common.

Apologies if this post is too long and/or too hard to follow. Lots of moving parts is all. Any feedback would be greatly appreciated.

Cheers


UPDATE: per Jon Skeet's excellent suggestion to examine the image string as I step through the code using MD5, I've narrowed down the problem - once I write the image to the filesystem in Script B, then read it back in, it has changed. So:

$imageStr = base64_decode($imageData);
$image = imagecreatefromstring($imageStr);
imagepng($image, $somePath);

...seems to manipulate the data, because when I read it back in w/ plain old fread(), the MD5 signature has changed. I think it's the imagepng function, perhaps it adds metadata? The php docs aren't clear about this. If this is the case, I think instead of reading the image back in w/ fread(), I would need to do the opposite of what I'm doing when I write it, something like:

$image = imagecreatefrompng($somePath);

...then figure out a way to get the image's content directly. I can't figure out how to do so though: it seems to require a function like "imagepng($image)", w/o a path, to output the image's content...and that's what I don't want to do.

At this point I think the question is either:

  1. how can i undo (or reverse) what imagepng seems to do, or
  2. how can i output an image resource's contents directly

I hope that updating my original post is kosher, I wasn't sure the best way to add further information gleaned.

Thanks

+2  A: 

I suggest you experiment by taking the MD5 hash of the data on the file system that Script B is reading from, again after reading it, and again in Script A after decoding it. That should show you which point is changing the data.

Just as a thought - is the data definitely valid on the file system that Script B is reading from?

EDIT: Okay, so as per your edit it looks like using imagepng is changing the contents. Do you actually need to use imagepng at all? Are you really doing anything with the image? It sounds like you're basically just trying to send a file from script B to script A... so I would do that without ever treating the file as anything other than opaque binary data.

Jon Skeet
MD5 - Excellent suggestion, I'll do some tests and update my original post. As far as the data on the filesytem that Script B is reading, I think so because the image is there and looks fine. Likewise, I have successfully read the file in using imagecreatefrompng, if there'd been corruption I think that function would have complained.
Madbreaks
Please see update to original post.
Madbreaks
A: 

You may want to double-check that GD's PNG support is actually enabled on the system Script B is running from.

It should be in this day and age, but...

if (imagetypes() & IMG_PNG) {
    echo "PNG Support is enabled";
}

P.S. I'm surprised you didn't just use HTML/PHP's built-in file upload mechanism.

cURL can upload files via:

$ch = curl_init();

// file is the field name, file names are prefixed with @
// In this example, $_FILES['file'] on the remote script would have this
// file's metadata
$data = array('file' => '@/home/user/test.png');

curl_setopt($ch, CURLOPT_URL, 'http://localhost/upload.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

curl_exec($ch);
R. Bemrose
Thanks for the reply. The png image is getting created ok on the filesystem, I can view in my browser, and have read it from the filesystem w/ imagecreatefrompng.Thanks for the cURL tip. There are business logic requirements which dictate I do it as I'm currently doing it. :)
Madbreaks
Please see update to original post.
Madbreaks
A: 

Zero experience with PHP and cURL, but are you possibly (accidentally) passing the image data as a GET parameter instead of a POST (this is the first mistake I would make, at any rate)?

I think the easiest way to track down the error is to ensure that the correct base64 encoding is being a) generated by Script B and b) received by Script A, by printing these values out and comparing them. This should tell you where your issue is.

Sumudu Fernando
Thanks for the reply - Script A is receiving the data as sent by Script B, I've confirmed that much. I have also confirmed that the data generated by Script B is exactly what Script A is receiving.
Madbreaks
Please see update to original post.
Madbreaks
A: 

One thing i can see that could be causing the issue is the fact that you are posting the image data and not using urlencode/urldecode.

Some of your image data might be getting mangled by PHP's post handling, or left out entirely if there is a newline anywhere in the data.

TJMonk15