Friday, April 8, 2011

Problem with php function to catch error on saving image

I have a method to save an image, which is meant to deal gracefully with an error, setting $imageSrc to a particular image in the event of failure. My method works fine if the image is present, but no error conditions seems to be handled correctly.

$imageSrc = save_pic($PIC_URL, $pk);

function save_pic($pic_url, $pk) {
    $imageDir = './';
    if (!strlen($pic_url))
            return "removed.jpg";
    if (!is_dir($imageDir) || !is_writable($imageDir)) {
     return "removed.jpg";
    }
    $image = file_get_contents($pic_url);
    if (empty($image)) {
     return "removed.jpg";
    }
    $r = file_put_contents($imageDir.$pk.".jpg", $image);
    if ($r) {
            return "./$pk.jpg"; 
    } else {
            return "removed.jpg";
    }
}

If the image does not exist, I get :

Warning: getimagesize(http://127.0.0.1/555.jpg) [function.getimagesize]: failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
in C:\Program Files\EasyPHP 2.0b1\www\get_auction.php on line 144

Array (
 [type] => 2 [message] => getimagesize(http://127.0.0.1/555.jpg)
 function.getimagesize]: failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
 [file] => C:\Program Files\EasyPHP 2.0b1\www\get_auction.php
 [line] => 144
) 1

returned.jpg is never returned in any event.

edit: added imageResize code:

function imageResize($imageURL, $maxWidth, $maxHeight)

{

global $outputWidth, $outputHeight, $maxWidth, $maxHeight;

$size = getimagesize($imageURL);

if ($size) {

    $imageWidth  = $size[0];

    $imageHeight = $size[1];

    $wRatio = $imageWidth / $maxWidth;

    $hRatio = $imageHeight / $maxHeight;

    $maxRatio = max($wRatio, $hRatio);



    if ($maxRatio > 1) {

        $outputWidth = $imageWidth / $maxRatio;

        $outputHeight = $imageHeight / $maxRatio;

    } else {

        $outputWidth = $imageWidth;

        $outputHeight = $imageHeight;

    }

} else {

    die(print_r(error_get_last()));

}

}
From stackoverflow
  • Are you sure you're writing to the root folder? Because I can't see any problem with your code. file_get_contents and file_put_contents don't seem to be failing, so your image is being written somewhere.

    Joshxtothe4 : but it doesnt deal with the file not existing in order to get
    Can Berk Güder : so file_get_contents *should* return FALSE but doesn't, is that correct?
    Joshxtothe4 : Exactly, The problem is not with the folder being writable, but with the image not existing at the url
  •  $image = file_get_contents("http://example.com/test.png");
     list($ver, $retcode, $message) = explode(' ', $http_response_header[0], 3);
     if ($retcode != 200) {
       return "removed.jpg";
     }
    

    $retcode will contain HTTP response code.

    Please post this $retcode here and what your strlen($image) returns, it might help to resolve your problem.

    Joshxtothe4 : the error code is 404, it states it in the error message
    Quassnoi : Yes, and he can parse it in the code.
    Joshxtothe4 : I put this in my code as you suggest, and only the file_Get_contens error is output, nothing after that.
    Quassnoi : Does it ever get after file_get_contents? Put an echo right after file_get_contents and see if it gets there.
    Dominic Rodger : ah... the wonder that is debugging PHP
  • Try this:

    <?php
    $imageSrc = save_pic($PIC_URL, $pk);
    
    function save_pic($pic_url, $pk) 
    {
        $imageDir = './';
    
        if (!strlen($pic_url))
        {
            return 'removed.jpg';
        }
    
        if(!is_dir($imageDir) || !is_writable($imageDir)) 
        {
            return 'removed.jpg';
        }
    
        if(!file_exists($pic_url))
        {
            return 'removed.jpg';
        }
    
        if (file_put_contents($imageDir . $pk . '.jpg', file_get_contents($pic_url))) 
        {
                return $imageDir . $pk . '.jpg'; 
        } 
        else 
        {
                return 'removed.jpg';
        }
    }
    
    Joshxtothe4 : Hi Bart, this had the same exact behavior.
    Bart S. : Can you post the code from C:\Program Files\EasyPHP 2.0b1\www\get_auction.php around line 144? Because that is what's causing this error: C:\Program Files\EasyPHP 2.0b1\www\get_auction.php on line 144
    Joshxtothe4 : line 144 is just $imageSrc = save_pic($PIC_URL, $pk);
  • Debug?

    Get an IDE that includes a debugger, like Eclipse or Netbeans, rtm for functions to see how the respond, or do bad-old inline debugging to echo the value of code at runtime.

  • It seems to me you're not posting your complete code?

    The warning message says getimagesize(), yet nowhere is getimagsize() used in your example. To receive better help I would include the whole method or an updated error message of your current efforts. Please also include the PHP version you're using.

    file_get_contents() will return false in case of errors and does so on 404 HTTP errors, as demonstrated:

    mfischer@testing01:~$ php -r 'var_dump(file_get_contents("http://stackoverflow.com/i_do_not_exist.jpg"));'
    
    Warning: file_get_contents(http://stackoverflow.com/i_do_not_exist.jpg): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
     in Command line code on line 1
    
    Call Stack:
        0.0002      51884   1. {main}() Command line code:0
        0.0002      51952   2. file_get_contents() Command line code:1
    
    bool(false)
    mfischer@testing01:~$ php -v
    PHP 5.2.6-5 with Suhosin-Patch 0.9.6.2 (cli) (built: Oct  5 2008 13:07:13)
    

    Trying out your code it works perfectly fine for me here:

    $ cat test.php
    <?php
    $PIC_URL="http://stackoverflow.com/i_dont_exist.jpg";
    $pk = "test";
    $imageSrc = save_pic($PIC_URL, $pk);
    var_dump($imageSrc);
    
    function save_pic($pic_url, $pk) {
        $imageDir = './';
        if (!strlen($pic_url))
                return "removed.jpg";
        if (!is_dir($imageDir) || !is_writable($imageDir)) {
            return "removed.jpg";
        }
        $image = file_get_contents($pic_url);
        if (empty($image)) {
            return "removed.jpg";
        }
        $r = file_put_contents($imageDir.$pk.".jpg", $image);
        if ($r) {
                return "./$pk.jpg";
        } else {
                return "removed.jpg";
        }
    }
    $ php test.php
    
    Warning: file_get_contents(http://stackoverflow.com/i_dont_exist.jpg): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
     in /home/mfischer/tmp/532480/test.php on line 14
    
    Call Stack:
        0.0005      59824   1. {main}() /home/mfischer/tmp/532480/test.php:0
        0.0005      60176   2. save_pic() /home/mfischer/tmp/532480/test.php:4
        0.0006      60444   3. file_get_contents() /home/mfischer/tmp/532480/test.php:14
    
    string(11) "removed.jpg"
    

    PHP functions have the bad habit of just spilling out warning messages right in your code, if you don't like this you can silence them with the '@' operate as suggested before or you can alternatively use a HTTP Client library as provided by PEAR_HTTP or Zend_HTTP_Client to have better control of error handling. Rolling your own thing with sockets, fsockopen, etc. would also be possible.

    But back to the point: if it's still not working, I think there's some information missing.

    Joshxtothe4 : I have updated my question to show the ImageResize function. The problem seems to be with the 404 error however.
  • Should you not be testing for file_get_contents errors? I mean with something like

    if( false == ($image = file_get_contents($pic_url))){
            return "removed.jpg";
        }
    
    • Send HTTP HEAD to given URL
    • Check returncode == 200 (file is there) else it's removed
    • Check that Content-Type header is image/* (for example image/png) else it's removed
    • If server sent Content-Length header, read that to variable
    • file_get_contents(URL)
    • If server sent that Content-Length see if size matches else it's removed
    • Save image
    • Try getimagesize(), if it gives errors remove it via unlink() and it's removed else keep it
    • Success!
  • You are having path issues. You should store the full path to the pic in a define.

    Make sure this file is sourced from the save_pic function.

    DEFINE("RemovedPicUrl", "http://" . $_SERVER['SERVER_NAME'] . "/path/to/removed/image/removed.jpg")
    

    then change all occurances of

    "Removed.jpg"
    

    to

    RemovedPicUrl
    

    And I'll bet you a dollar that fixes your issue.

  • The problem was not a code issue, but was caused by file corruption. This was determined while testing on other machines.

0 comments:

Post a Comment