¿Una forma sencilla de probar una URL para 404 en PHP?

Resuelto asked hace 54 años • 15 respuestas

Me estoy enseñando algo de scraping básico y descubrí que a veces las URL que introduzco en mi código devuelven 404, lo que arruina el resto de mi código.

Entonces necesito una prueba en la parte superior del código para verificar si la URL devuelve 404 o no.

Esto parecería una tarea bastante sencilla, pero Google no me da ninguna respuesta. Me preocupa estar buscando cosas equivocadas.

Un blog me recomendó usar esto:

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

y luego pruebe para ver si $valid está vacío o no.

Pero creo que la URL que me está dando problemas tiene una redirección, por lo que $valid aparece vacío para todos los valores. O quizás estoy haciendo algo más mal.

También investigué una "solicitud principal", pero todavía tengo que encontrar ejemplos de código reales con los que pueda jugar o probar.

¿Sugerencias? ¿Y qué es eso del rizo?

 avatar Jan 01 '70 08:01
Aceptado

Si está utilizando curlenlaces de PHP , puede verificar el código de error usando curl_getinfoel siguiente:

$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. */
strager avatar Jan 03 '2009 00:01 strager

Si estás ejecutando php5 puedes usar:

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

Alternativamente con php4 un usuario ha contribuido con lo siguiente:

/**
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;
        }
    }
}

Ambos tendrían un resultado similar a:

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
)

Por lo tanto, podrías simplemente verificar que la respuesta del encabezado fuera correcta, por ejemplo:

$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
}

Códigos y definiciones del W3C

Asciant avatar Jan 03 '2009 01:01 Asciant