web-dev-qa-db-fra.com

Comment vérifier si un fichier distant existe en PHP?

Le meilleur que j'ai pu trouver, un objet de type iffclosefopen, accélère le chargement de la page.

Ce que j'essaie de faire est essentiellement le suivant: j'ai une liste de sites Web et je veux afficher leurs favicons à côté d'eux. Cependant, si un site n'en a pas, j'aimerais le remplacer par une autre image plutôt que d'afficher une image endommagée.

83
Oliver

Vous pouvez indiquer à curl d'utiliser la méthode HTTP HEAD via CURLOPT_NOBODY.

Plus ou moins

$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);

Quoi qu’il en soit, vous ne faites qu’économiser le coût du transfert HTTP, pas l’établissement et la fermeture de la connexion TCP. Et, étant donné que les favicons sont petits, vous ne constaterez peut-être pas beaucoup d’améliorations.

Mettre en cache le résultat localement semble une bonne idée s’il s’avère trop lent. HEAD vérifie l'heure du fichier et le renvoie dans les en-têtes. Vous pouvez faire comme des navigateurs et obtenir le CURLINFO_FILETIME de l'icône. Dans votre cache, vous pouvez stocker l'URL => [favicon, timestamp]. Vous pouvez ensuite comparer l’horodatage et recharger le favicon.

131
Ramon Poca

Comme Pies dit, vous pouvez utiliser cURL. Vous pouvez obtenir que cURL ne vous donne que les en-têtes, et non le corps, ce qui pourrait le rendre plus rapide. Un mauvais domaine peut toujours prendre un certain temps car vous attendez l'expiration de la demande; vous pouvez probablement changer la durée de timeout en utilisant cURL.

Voici un exemple:

function remoteFileExists($url) {
    $curl = curl_init($url);

    //don't fetch the actual page, you only want to check the connection is ok
    curl_setopt($curl, CURLOPT_NOBODY, true);

    //do request
    $result = curl_exec($curl);

    $ret = false;

    //if request did not fail
    if ($result !== false) {
        //if request was ok, check response code
        $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);  

        if ($statusCode == 200) {
            $ret = true;   
        }
    }

    curl_close($curl);

    return $ret;
}

$exists = remoteFileExists('http://stackoverflow.com/favicon.ico');
if ($exists) {
    echo 'file exists';
} else {
    echo 'file does not exist';   
}
60
Tom Haigh

La solution de CoolGoose est bonne, mais elle est plus rapide pour les fichiers volumineux (car elle ne tente que de lire 1 octet):

if (false === file_get_contents("http://example.com/path/to/image",0,null,0,1)) {
    $image = $default_image;
}
34
luBar

Ce n'est pas une réponse à votre question initiale, mais une meilleure façon de faire ce que vous essayez de faire:

Au lieu d'essayer d'obtenir le favicon du site directement (ce qui est une douleur royale étant donné qu'il pourrait s'agir de /favicon.png, /favicon.ico, /favicon.gif ou même de /path/to/favicon.png), utilisez google:

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

Terminé.

27
Mala

Si vous utilisez des images, utilisez getimagesize. Contrairement à file_exists, cette fonction intégrée prend en charge les fichiers distants. Il retournera un tableau contenant les informations sur l'image (largeur, hauteur, type ... etc). Tout ce que vous avez à faire est de vérifier le premier élément du tableau (la largeur). utiliser print_r pour afficher le contenu du tableau

$imageArray = getimagesize("http://www.example.com/image.jpg");
if($imageArray[0])
{
    echo "it's an image and here is the image's info<br>";
    print_r($imageArray);
}
else
{
    echo "invalid image";
}

Une fonction complète de la réponse la plus votée:

function remote_file_exists($url)
{
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_NOBODY, true);
    curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if( $httpCode == 200 ){return true;}
}

Vous pouvez l'utiliser comme ceci:

if(remote_file_exists($url))
{
    //file exists, do something
}
15
Pedro Lobito

Cela peut être fait en obtenant le code HTTP Status (404 = introuvable) qui est possible avec file_get_contents Docs en utilisant les options de contexte. Le code suivant prend en compte les redirections et renvoie le code de statut de la destination finale ( Demo ):

$url = 'http://example.com/';
$code = FALSE;

$options['http'] = array(
    'method' => "HEAD",
    'ignore_errors' => 1
);

$body = file_get_contents($url, NULL, stream_context_create($options));

foreach($http_response_header as $header)
    sscanf($header, 'HTTP/%*d.%*d %d', $code);

echo "Status code: $code";

Si vous ne souhaitez pas suivre les redirections, vous pouvez le faire de manière similaire ( Demo ):

$url = 'http://example.com/';
$code = FALSE;

$options['http'] = array(
    'method' => "HEAD",
    'ignore_errors' => 1,
    'max_redirects' => 0
);

$body = file_get_contents($url, NULL, stream_context_create($options));

sscanf($http_response_header[0], 'HTTP/%*d.%*d %d', $code);

echo "Status code: $code";

Certaines des fonctions, options et variables utilisées sont expliquées plus en détail dans un article de blog que j'ai écrit: HEAD en premier avec PHP Streams .

7
hakre

Les fonctions incorporées de PHP peuvent ne pas fonctionner pour vérifier l'URL si le paramètre de allow_url_fopen est désactivé pour des raisons de sécurité. Curl est une meilleure option. comme nous n’aurions pas besoin de changer notre code à un stade ultérieur. Voici le code que j'ai utilisé pour vérifier une URL valide:

$url = str_replace(' ', '%20', $url);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);  
curl_close($ch);
if($httpcode>=200 && $httpcode<300){  return true; } else { return false; } 

Veuillez noter l'option CURLOPT_SSL_VERIFYPEER qui vérifie également l'adresse URL commençant par HTTPS.

6
Krishan Gopal
if (false === file_get_contents("http://example.com/path/to/image")) {
    $image = $default_image;
}

Devrait marcher ;)

6
CoolGoose

Une solution radicale serait d’afficher les favicons en tant qu’images d’arrière-plan dans un div au-dessus de votre icône par défaut. De cette façon, tout le temps système serait placé sur le client sans afficher les images endommagées (les images d’arrière-plan manquantes sont ignorées dans tous les navigateurs, autant que je sache).

4
truppo

Pour vérifier l’existence d’images, exif_imagetype devrait être préféré à getimagesize , car il est beaucoup plus rapide.

Pour supprimer le E_NOTICE, ajoutez simplement l'opérateur de contrôle d'erreur (@).

if (@exif_imagetype($filename)) {
  // Image exist
}

En prime, avec la valeur retournée (IMAGETYPE_XXX) de exif_imagetype nous pourrions aussi obtenir le type mime ou l'extension de fichier avec image_type_to_mime_type/image_type_to_extension.

3
yckart

Vous pouvez utiliser les éléments suivants:

$file = 'http://mysite.co.za/images/favicon.ico';
$file_exists = (@fopen($file, "r")) ? true : false;

Travaillé pour moi en essayant de vérifier si une image existe sur l'URL

3
Rickus Harmse
function remote_file_exists($url){
   return(bool)preg_match('~HTTP/1\.\d\s+200\s+OK~', @current(get_headers($url)));
}  
$ff = "http://www.emeditor.com/pub/emed32_11.0.5.exe";
    if(remote_file_exists($ff)){
        echo "file exist!";
    }
    else{
        echo "file not exist!!!";
    }
3
dr.linux

Vous pouvez utiliser :

$url=getimagesize(“http://www.flickr.com/photos/27505599@N07/2564389539/”);

if(!is_array($url))
{
   $default_image =”…/directoryFolder/junal.jpg”;
}
2
CP Soni

Vous devez émettre des requêtes HEAD, pas une requête GET, car vous n'avez pas du tout besoin du contenu de l'URI. Comme Pies l'a dit plus haut, vous devez vérifier le code d'état (dans les plages 200-299, et vous pouvez éventuellement suivre les redirections 3xx).

La question réponses contient de nombreux exemples de code qui peuvent être utiles: PHP/Curl: HEAD La requête prend beaucoup de temps sur certains sites

1
drdaeman

Cela me permet de vérifier si un fichier distant existe en PHP:

$url = 'https://cdn.sstatic.net/Sites/stackoverflow/img/favicon.ico';
    $header_response = get_headers($url, 1);

    if ( strpos( $header_response[0], "404" ) !== false ) {
        echo 'File does NOT exist';
        } else {
        echo 'File exists';
        }
1
user7018984

toutes les réponses ici qui utilisent get_headers () font une requête GET. Il est beaucoup plus rapide et moins coûteux de simplement faire une demande HEAD.

Pour vous assurer que get_headers () effectue une demande HEAD au lieu d'un GET, vous devez ajouter ceci:

stream_context_set_default(
    array(
        'http' => array(
            'method' => 'HEAD'
        )
    )
);

donc pour vérifier si un fichier existe, votre code devrait ressembler à ceci:

stream_context_set_default(
    array(
        'http' => array(
            'method' => 'HEAD'
        )
    )
);
$headers = get_headers('http://website.com/dir/file.jpg', 1);
$file_found = stristr($headers[0], '200');

$ file_found retournera soit faux soit vrai, évidemment.

1
Ludo - Off the record

Il existe une alternative encore plus sophistiquée. Vous pouvez vérifier tout le côté client en utilisant une astuce JQuery.

$('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); };
});

De http://snipplr.com/view/18782/add-a-favicon-near-external-links-with-jquery/ (le blog original est actuellement en panne)

1
S Pangborn

Si le fichier n'est pas hébergé externe, vous pouvez traduire l'URL distante en un chemin absolu sur votre serveur Web. De cette façon, vous n'avez pas besoin d'appeler CURL ou file_get_contents, etc.

function remoteFileExists($url) {

    $root = realpath($_SERVER["DOCUMENT_ROOT"]);
    $urlParts = parse_url( $url );

    if ( !isset( $urlParts['path'] ) )
        return false;

    if ( is_file( $root . $urlParts['path'] ) )
        return true;
    else
        return false;

}

remoteFileExists( 'https://www.yourdomain.com/path/to/remote/image.png' );

Remarque: votre serveur Web doit renseigner DOCUMENT_ROOT pour utiliser cette fonction.

0
Bastian Fießinger

Je ne sais pas si celui-ci est plus rapide lorsque le fichier n'existe pas à distance, is_file () , mais vous pouvez l'essayer.

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