13

I know that there are at least 10 the same questions with answers but none of them seems to work for me flawlessly. I'm trying to check if internal or external image exists (is image URL valid?).

  1. fopen($url, 'r') fails unless I use @fopen():

    Warning: fopen(http://example.com/img.jpg) [function.fopen]: failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in file.php on line 21 
  2. getimagesize($img) fails when image doesn't exist (PHP 5.3.8):

    Warning: getimagesize() [function.getimagesize]: php_network_getaddresses: getaddrinfo failed 
  3. CURL fails because it isn't supported by some servers (although it's present mostly everywhere).
  4. fileExists() fails because it doesn't work with external URLs and can't possibly check if we're dealing with image.

Four methods that are the most common answers to such question are wrong. What would be the correct way to do that?

10
  • 4
    cURL is the right answer. If it isn't supported by your server, configure it. Commented Dec 19, 2012 at 16:40
  • 1
    @Bard I'm developing WP themes - I can't possibly ask people to configure that. It has to work out of the box for everyone. Commented Dec 19, 2012 at 16:41
  • All your other methods will fail if url fopen is disabled so you don't gain anything. Commented Dec 19, 2012 at 16:42
  • @Paul, I have never used a shared hosting provider that didn't have cURL enabled. If you can't expect people to use cURL, you probably can't expect them to use anything. You need a way to get the HTTP status code from the response... cURL is the defacto standard and proper way to do this. Commented Dec 19, 2012 at 16:43
  • I know @ is generally frowned upon, but I believe this is one of its few legitimate use cases. As long as you anticipate and handle the potential error condition, suppressing the error message is acceptable (IMHO). Having said that, you shouldn't worry about the error message in production anyway because display_errors should be off ;-) Commented Dec 19, 2012 at 16:43

9 Answers 9

15

getimagesize($img) fails when image doesn't exist: am not sure you understand what you want .....

FROM PHP DOC

The getimagesize() function will determine the size of any given image file and return the dimensions along with the file type and a height/width text string to be used inside a normal HTML IMG tag and the correspondant HTTP content type.

On failure, FALSE is returned.

Example

$img = array("https://i.sstatic.net/52Ha1.png","http://example.com/img.jpg"); foreach ( $img as $v ) { echo $v, getimagesize($v) ? " = OK \n" : " = Not valid \n"; } 

Output

https://i.sstatic.net/52Ha1.png = OK http://example.com/img.jpg = Not valid 

getimagesize works just fine

Edit

@Paul .but your question is essentially saying "How do I handle this so I won't get an error when there's an error condition". And the answer to that is "you can't". Because all these functions will trigger an error when there is an error condition. So (if you don't want the error) you suppress it. None of this should matter in production because you shouldn't be displaying errors anyway ;-) – DaveRandom

Sign up to request clarification or add additional context in comments.

9 Comments

In my case on PHP 5.3 it returns the above mentioned PHP Warning. Can you take a look at it? It would be excellent if it returned false. I'm on average shared hosting (but good one with a lot of functions enabled).
The issue is that getimagesize() is just using the HTTP fopen wrapper, which is where your warning is happening.
@Bard Is there any way to turn that into something that won't return PHP Warning? It's just weird - it's the first time I see and use this function and it doesn't seems to work on shared hosting.
@Baba With error suppression a lot of things will work but it feels not alright to have warnings, notices and errors.
@Paul ...but your question is essentially saying "How do I handle this so I won't get an error when there's an error condition". And the answer to that is "you can't". Because all these functions will trigger an error when there is an error condition. So (if you don't want the error) you suppress it. None of this should matter in production because you shouldn't be displaying errors anyway ;-)
|
15

This code is actually to check file... But, it does works for images!

$url = "http://www.myfico.com/Images/sample_overlay.gif"; $header_response = get_headers($url, 1); if ( strpos( $header_response[0], "404" ) !== false ) { // FILE DOES NOT EXIST } else { // FILE EXISTS!! } 

2 Comments

if you really want it to check for images us something like: $header_response['Content-Type'] == "image/jpeg"
And what if image is corrupt?
4
function checkExternalFile($url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_NOBODY, true); curl_exec($ch); $retCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return $retCode; } $fileExists = checkExternalFile("http://example.com/your/url/here.jpg"); // $fileExists > 400 = not found // $fileExists = 200 = found. 

Comments

1

If you're using PHP >=5.0.0 you can pass an additional parameter into fopen to specify context options for HTTP, among them whether to ignore failure status codes.

$contextOptions = array( 'http' => array('ignore_errors' => true)); $context = stream_context_create($contextOptions); $handle = fopen($url, 'r', false, $context); 

1 Comment

Seems like a good answer! And can be used in conjunction with getimagesize($img).
0

Use fsockopen, connect to the server, send a HEAD request and see what status you get back.

The only time you need to be aware of problems is if the domain doesn't exist.

Example code:

$file = "http://example.com/img.jpg"; $path = parse_url($file); $fp = @fsockopen($path['host'],$path['port']?:80); if( !$fp) echo "Failed to connect... Either server is down or host doesn't exist."; else { fputs($fp,"HEAD ".$file." HTTP/1.0\r\n" ."Host: ".$path['host']."\r\n\r\n"); $firstline = fgets($fp); list(,$status,$statustext) = explode(" ",$firstline,3); if( $status == 200) echo "OK!"; else "Status ".$status." ".$statustext."..."; } 

1 Comment

There are still plenty of hosts out there that do not support a HEAD request. Unfortunately, a GET is still required, unless you want to try HEAD first and fall back to GET.
0

You can use the PEAR/HTTP_Request2 Package for this. You can find it here

Here comes an example. The Example expects that you have installed or downloaded the HTTP_Request2 package properly. It uses the old style socket adapter, not curl.

<?php require_once 'HTTP/Request2.php'; require_once 'HTTP/Request2/Adapter/Socket.php'; $request = new HTTP_Request2 ( $your_url, HTTP_Request2::METHOD_GET, array('adapter' => new HTTP_Request2_Adapter_Socket()) ); switch($request->send()->getResponseCode()) { case 404 : echo 'not found'; break; case 200 : echo 'found'; break; default : echo 'needs further attention'; } 

2 Comments

If he has problems with having cURL on hand, this will certainly fail unless bundled with the theme.
It supports the old style socket adapter too. this works without curl. preparing an example
0

I found try catch the best solution for this. It is working fine with me.

try{ list($width, $height) = getimagesize($h_image->image_url); } catch (Exception $e) { } 

Comments

0

I know you wrote "without curl" but still, somebody may find this helpfull:

function curl_head($url) { $ch = curl_init($url); //curl_setopt($ch, CURLOPT_USERAGENT, 'Your user agent'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 1); # get headers curl_setopt($ch, CURLOPT_NOBODY, 1); # omit body //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); # do SSL check //curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); # verify domain within cert curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); # follow "Location" redirs //curl_setopt($ch, CURLOPT_TIMEOUT_MS, 700); # dies after 700ms $result = curl_exec($ch); curl_close($ch); return $result; } print_r(curl_head('https://www.example.com/image.jpg')); 

You will see someting like this HTTP/1.1 200 OK or HTTP/1.1 404 Not Found in returned header array. You can do also multiple parallel requests with curl multi.

Comments

-1

There are multiple steps, there is no single solution:

  1. Validate URL
  2. Check whether the file is available (can be done directly with step 3)
  3. Download the image into a tmp file.
  4. Use getimagesize to check the size of the image.

For this kind of work you can catch the exceptions and handle them well to define your answer. In this case you could even suppress errors because it's intended that they trick might fail. So you handle the errors correctly.

Because it's not possible to do a 100% check on it without having the actual image downloaded. So step 1 and 2 are required, 3 and 4 optional for a more definitive answer.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.