views:

3941

answers:

11

The best I could find, an if fclose fopen type thing, makes the page load really slowly.

Basically what I'm trying to do is the following: I have a list of websites, and I want to display their favicons next to them. However, if a site doesn't have one, I'd like to replace it with another image rather than display a broken image.

Any ideas? Thanks!

+2  A: 

I think you can use CURL and check its return codes. But if it's the speed that is a problem, just do it offline and cache.

Pies
Caching them locally might just be the best solution, because it'll save on a lot of TCP connections. Favicons very rarely change, right?
Yes, but I would still recommend using an offline script (run from cron) that parses the list of websites, checks if they've got favicons and cache that data for the frontend. If you don't/can't use cron, at least cache the results for every new URL you check.
Pies
+1  A: 
if (false === file_get_contents("http://example.com/path/to/image")) {
    $image = $default_image;
}

Should work ;)

CoolGoose
+7  A: 

You can instruct curl to use the HTTP HEAD method via CURLOPT_NOBODY.

More or less

$ch = curl_init("http://www.example.com/favicon.ico");

curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// $retcode > 400 -> not found, $retcode = 200, found.
curl_close($ch);

Anyway, you only save the cost of the HTTP transfer, not the TCP connection establishment and closing. And being favicons small, you might not see much improvement.

Caching the result locally seems a good idea if it turns out to be too slow. HEAD checks the time of the file, and returns it in the headers. You can do like browsers and get the CURLINFO_FILETIME of the icon. In your cache you can store the URL => [ favicon, timestamp ]. You can then compare the timestamp and reload the favicon.

Ramon Poca
ah, you beat me to it.
Tom Haigh
A: 

Don't know if this one is any faster when the file does not exist remotely, is_file(), but you could give it a shot.

$favIcon = 'default FavIcon';
if(is_file($remotePath)) {
   $favIcon = file_get_contents($remotePath);
}
PatrikAkerstrand
A: 

You should issue HEAD requests, not GET one, because you don't need the URI contents at all. As Pies said above, you should check for status code (in 200-299 ranges, and you may optionally follow 3xx redirects).

The answers question contain a lot of code examples which may be helpful: http://stackoverflow.com/questions/770179/php-curl-head-request-takes-a-long-time-on-some-sites

drdaeman
+3  A: 
Tom Haigh
+3  A: 

A radical solution would be to display the favicons as background images in a div above your default icon. That way, all overhead would be placed on the client while still not displaying broken images (missing background images are ignored in all browsers AFAIK).

truppo
+1 if you're not checking multiple locations for their favicon (favicon.ico, favicon.gif, favicon.png) this seems to be the best solution
Galen
+1  A: 

There's an even more sophisticated alternative. You can do the checking all client-side using a JQuery trick.

$('a[href^="http://"]').filter(function(){
     return this.hostname && this.hostname !== location.hostname;
}).each(function() {
    var link = jQuery(this);
    var faviconURL =
      link.attr('href').replace(/^(http:\/\/[^\/]+).*$/, '$1')+'/favicon.ico';
    var faviconIMG = jQuery('<img src="favicon.png" alt="" />')['appendTo'](link);
    var extImg = new Image();
    extImg.src = faviconURL;
    if (extImg.complete)
      faviconIMG.attr('src', faviconURL);
    else
      extImg.onload = function() { faviconIMG.attr('src', faviconURL); };
});

From http://snipplr.com/view/18782/add-a-favicon-near-external-links-with-jquery/ (the original blog is presently down)

S Pangborn
+2  A: 

CoolGoose's solution is good but this is faster for large files (as it only tries to read 1 byte):

if (false === file_get_contents("http://example.com/path/to/image",0,null,0,1)) {
    $image = $default_image;
}
luBar
+1. Is there what are the drawbacks for this solution against the CURL one?
Adriano Varoli Piazza
A: 

@ luBar

Cool and ultra-short trick, works like a charm. Thanks.

Bee
+1  A: 

This is not an answer to your original question, but a better way of doing what you're trying to do:

Instead of actually trying to get the site's favicon directly (which is a royal pain given it could be /favicon.png, /favicon.ico, /favicon.gif, or even /path/to/favicon.png), use google:

<img src="http://www.google.com/s2/favicons?domain=[domain]"&gt;

Done.

Mala