Skip to main content

best way to determine if a URL is an image in PHP



Using PHP, given a URL, how can I determine whether it is an image?





There is no context for the URL - it is just in the middle of a plain text file, or maybe just a string on its own.





I don't want high overhead (e.g. reading the content of the URL) as this could be called for many URLs on a page. Given this restriction, it isn't essential that all images are identified, but I would like a fairly good guess.





At the moment I am just looking at the file extension, but it feels like there should be a better way than this.





Here is what I currently have:







function isImage( $url )

{

$pos = strrpos( $url, ".");

if ($pos === false)

return false;

$ext = strtolower(trim(substr( $url, $pos)));

$imgExts = array(".gif", ".jpg", ".jpeg", ".png", ".tiff", ".tif"); // this is far from complete but that's always going to be the case...

if ( in_array($ext, $imgExts) )

return true;

return false;

}







Edit: In case it's useful to anybody else here is the final function using the technique from Emil H's answer:







function isImage($url)

{

$params = array('http' => array(

'method' => 'HEAD'

));

$ctx = stream_context_create($params);

$fp = @fopen($url, 'rb', false, $ctx);

if (!$fp)

return false; // Problem with url



$meta = stream_get_meta_data($fp);

if ($meta === false)

{

fclose($fp);

return false; // Problem reading data from url

}



$wrapper_data = $meta["wrapper_data"];

if(is_array($wrapper_data)){

foreach(array_keys($wrapper_data) as $hh){

if (substr($wrapper_data[$hh], 0, 19) == "Content-Type: image") // strlen("Content-Type: image") == 19

{

fclose($fp);

return true;

}

}

}



fclose($fp);

return false;

}





Source: Tips4all

Comments

  1. You could use an HTTP HEAD request and check the content-type. This might be a good compromise. It can be done using PHP Streams. Wez Furlong has an article that shows how to use this approach to send post requests, but it can be easily adapted to send HEAD requests instead. You can retrieve the headers from an http response using stream_get_meta_data().

    Of course this isn't really 100%. Some servers send incorrect headers. It will however handle cases where images are delivered through a script and the correct file extension isn't available. The only way to be really certain is to actually retrieve the image - either all of it, or the first few bytes, as suggested by thomasrutter.

    ReplyDelete
  2. There are a few different approaches.


    Sniff the content by looking for a magic number at the start of the file. For example, GIF uses GIF87 or GIF89 as the first five bytes of the file (in ascii). Unfortunately this can't tell you if there's an error in the image or if the image contains malicious content. Here are some magic numbers for various types of image files (feel free to use these):


    "\xff\xd8\xff" => 'image/jpeg',
    "\x89PNG\x0d\x0a\x1a\x0a" => 'image/png',
    "II*\x00" => 'image/tiff',
    "MM\x00*" => 'image/tiff',
    "\x00\x00\x01\x00" => 'image/ico',
    "\x00\x00\x02\x00" => 'image/ico',
    "GIF89a" => 'image/gif',
    "GIF87a" => 'image/gif',
    "BM" => 'image/bmp',


    Sniffing the content like this is probably going to fit your requirements best; you'll only have to read and therefore download the first few bytes of the file (past the header).
    Load the image using the GD library to see if it loads without error. This can tell you if the image is valid, without error or not. Unfortunately this probably doesn't fit your requirements because it requires downloading the complete image.
    If you really don't want to make an HTTP request for the image at all, then this rules out both sniffing and getting HTTP headers. You can, however, try to determine whether something is an image by the context in which it is linked. Something linked using a src attribute in an <img element is almost certainly an image (or an attempt at XSS, but that's another story). This will tell you if something is intended as an image. It won't tell you whether the image is actually available, or valid; you'll have to fetch at least the first small part (header or magic number) of the image URL to find that.


    Unfortunately, it is possible for a file to be both a valid image as well as a ZIP file containing harmful content which could be executed as Java by a harmful site - see the GIFAR exploit. You can almost certainly prevent this vulnerability by loading the image in a library like GD and performing some non-trivial filter on it, like softening or sharpening it a tiny amount (ie using a convolution filter) and saving it to a fresh file without transferring any metadata across.

    Trying to determine if something is an image by its content-type alone is quite unreliable, almost as unreliable as checking the file extension. When loading an image using an <img element, browsers sniff for a magic string.

    ReplyDelete
  3. if(is_array(getimagesize($urlImg)))
    echo 'Yes it's an image!';

    ReplyDelete

Post a Comment

Popular posts from this blog

[韓日関係] 首相含む大幅な内閣改造の可能性…早ければ来月10日ごろ=韓国

div not scrolling properly with slimScroll plugin

I am using the slimScroll plugin for jQuery by Piotr Rochala Which is a great plugin for nice scrollbars on most browsers but I am stuck because I am using it for a chat box and whenever the user appends new text to the boxit does scroll using the .scrollTop() method however the plugin's scrollbar doesnt scroll with it and when the user wants to look though the chat history it will start scrolling from near the top. I have made a quick demo of my situation http://jsfiddle.net/DY9CT/2/ Does anyone know how to solve this problem?

Why does this javascript based printing cause Safari to refresh the page?

The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex