162 votes

Un moyen simple de tester une URL pour 404 en PHP ?

Je suis en train de m'initier au scraping et j'ai constaté que parfois les URL que j'introduis dans mon code renvoient 404, ce qui gomme tout le reste de mon code.

J'ai donc besoin d'un test en haut du code pour vérifier si l'URL renvoie 404 ou non.

Cela semble être une tâche assez simple, mais Google ne me donne aucune réponse. J'ai peur de chercher les mauvaises choses.

Un blog m'a recommandé d'utiliser ceci :

$valid = @fsockopen($url, 80, $errno, $errstr, 30);

et ensuite tester pour voir si $valid est vide ou non.

Mais je pense que l'URL qui me pose problème a une redirection, donc $valid est vide pour toutes les valeurs. Ou peut-être que je fais quelque chose d'autre de mal.

J'ai également cherché une "demande principale", mais je n'ai pas encore trouvé d'exemples concrets de code avec lesquels je puisse jouer ou que je puisse essayer.

Des suggestions ? Et c'est quoi cette histoire de boucles ?

295voto

strager Points 41713

Si vous utilisez la fonction curl fixations vous pouvez vérifier le code d'erreur en utilisant curl_getinfo comme tel :

$handle = curl_init($url);
curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);

/* Get the HTML or whatever is linked in $url. */
$response = curl_exec($handle);

/* Check for 404 (file not found). */
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
    /* Handle 404 here. */
}

curl_close($handle);

/* Handle $response here. */

110voto

Asciant Points 1049

Si vous utilisez php5, vous pouvez utiliser :

$url = 'http://www.example.com';
print_r(get_headers($url, 1));

Alternativement avec php4 un utilisateur a contribué ce qui suit :

/**
This is a modified version of code from "stuart at sixletterwords dot com", at 14-Sep-2005 04:52. This version tries to emulate get_headers() function at PHP4. I think it works fairly well, and is simple. It is not the best emulation available, but it works.

Features:
- supports (and requires) full URLs.
- supports changing of default port in URL.
- stops downloading from socket as soon as end-of-headers is detected.

Limitations:
- only gets the root URL (see line with "GET / HTTP/1.1").
- don't support HTTPS (nor the default HTTPS port).
*/

if(!function_exists('get_headers'))
{
    function get_headers($url,$format=0)
    {
        $url=parse_url($url);
        $end = "\r\n\r\n";
        $fp = fsockopen($url['host'], (empty($url['port'])?80:$url['port']), $errno, $errstr, 30);
        if ($fp)
        {
            $out  = "GET / HTTP/1.1\r\n";
            $out .= "Host: ".$url['host']."\r\n";
            $out .= "Connection: Close\r\n\r\n";
            $var  = '';
            fwrite($fp, $out);
            while (!feof($fp))
            {
                $var.=fgets($fp, 1280);
                if(strpos($var,$end))
                    break;
            }
            fclose($fp);

            $var=preg_replace("/\r\n\r\n.*\$/",'',$var);
            $var=explode("\r\n",$var);
            if($format)
            {
                foreach($var as $i)
                {
                    if(preg_match('/^([a-zA-Z -]+): +(.*)$/',$i,$parts))
                        $v[$parts[1]]=$parts[2];
                }
                return $v;
            }
            else
                return $var;
        }
    }
}

Les deux auraient un résultat similaire à :

Array
(
    [0] => HTTP/1.1 200 OK
    [Date] => Sat, 29 May 2004 12:28:14 GMT
    [Server] => Apache/1.3.27 (Unix)  (Red-Hat/Linux)
    [Last-Modified] => Wed, 08 Jan 2003 23:11:55 GMT
    [ETag] => "3f80f-1b6-3e1cb03b"
    [Accept-Ranges] => bytes
    [Content-Length] => 438
    [Connection] => close
    [Content-Type] => text/html
)

Par conséquent, vous pouvez simplement vérifier que l'en-tête de réponse est OK, par exemple :

$headers = get_headers($url, 1);
if ($headers[0] == 'HTTP/1.1 200 OK') {
//valid 
}

if ($headers[0] == 'HTTP/1.1 301 Moved Permanently') {
//moved or redirect page
}

Codes et définitions du W3C

39voto

Aram Kocharyan Points 8530

Avec le code de Strager, vous pouvez également vérifier le CURLINFO_HTTP_CODE pour d'autres codes. Certains sites Web ne signalent pas un 404, mais redirigent simplement vers une page 404 personnalisée et renvoient 302 (redirection) ou quelque chose de similaire. J'ai utilisé ceci pour vérifier si un fichier réel (par exemple, robots.txt) existait ou non sur le serveur. Il est clair que ce type de fichier ne provoquerait pas de redirection s'il existait, mais s'il n'existait pas, il redirigerait vers une page 404, qui, comme je l'ai dit précédemment, peut ne pas avoir de code 404.

function is_404($url) {
    $handle = curl_init($url);
    curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);

    /* Get the HTML or whatever is linked in $url. */
    $response = curl_exec($handle);

    /* Check for 404 (file not found). */
    $httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
    curl_close($handle);

    /* If the document has loaded successfully without any redirection or error */
    if ($httpCode >= 200 && $httpCode < 300) {
        return false;
    } else {
        return true;
    }
}

24voto

Beau Simensen Points 2409

Comme le suggère Strager, envisagez d'utiliser cURL. Vous pouvez également être intéressé par le paramétrage de CURLOPT_NOBODY avec curl_setopt pour ne pas télécharger la page entière (vous ne voulez que les en-têtes).

16voto

Nasaralla Points 1292

Si vous cherchez la solution la plus simple et celle que vous pouvez essayer en une seule fois sur php5, faites ce qui suit

file_get_contents('www.yoursite.com');
//and check by echoing
echo $http_response_header[0];

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X