Простой способ проверить URL для 404 в PHP? - PullRequest
143 голосов
/ 03 января 2009

Я учу себя некоторому основному анализу, и я обнаружил, что иногда URL-адреса, которые я передаю в мой код, возвращают 404, что объединяет весь остальной код.

Так что мне нужен тест вверху кода, чтобы проверить, возвращает ли URL 404 или нет.

Это может показаться довольно простой задачей, но Google не дает мне никаких ответов. Я волнуюсь, я ищу не те вещи.

Один блог рекомендовал использовать это:

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

, а затем проверьте, действителен ли $, если он пуст или нет.

Но я думаю, что URL, который вызывает у меня проблемы, имеет перенаправление, поэтому $ valid будет пустым для всех значений. Или, возможно, я делаю что-то еще не так.

Я также изучил «главный запрос», но мне еще не удалось найти какие-либо реальные примеры кода, с которыми можно поиграть или попробовать.

Предложения? И что это за скручиваемость?

Ответы [ 14 ]

258 голосов
/ 03 января 2009

Если вы используете PHP curl привязок , вы можете проверить код ошибки, используя curl_getinfo как таковой:

$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. */
98 голосов
/ 03 января 2009

Если у вас работает php5, вы можете использовать:

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

В качестве альтернативы с php4 пользователь добавил следующее:

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

Оба результата будут похожи на:

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
)

Поэтому вы можете просто проверить, что ответ заголовка в порядке, например:

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

Коды и определения W3C

32 голосов
/ 03 января 2011

С помощью кода Стражера вы также можете проверить CURLINFO_HTTP_CODE на наличие других кодов. Некоторые веб-сайты не сообщают 404, скорее они просто перенаправляют на пользовательскую страницу 404 и возвращают 302 (перенаправление) или что-то подобное. Я использовал это, чтобы проверить, существует ли фактический файл (например, robots.txt) на сервере или нет. Очевидно, что этот тип файла не вызовет перенаправления, если он существует, но если он этого не сделает, он перенаправит на страницу 404, которая, как я уже говорил, может не иметь кода 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;
    }
}
21 голосов
/ 03 января 2009

Как подсказывает Страгер, рассмотрите использование cURL. Вам также может быть интересно установить CURLOPT_NOBODY с curl_setopt , чтобы пропустить загрузку всей страницы (вам просто нужны заголовки).

15 голосов
/ 12 мая 2011

Если вы ищете простейшее решение, которое вы можете попробовать за один раз, зайдите на php5 и сделайте

file_get_contents('www.yoursite.com');
//and check by echoing
echo $http_response_header[0];
6 голосов
/ 03 января 2009

Я нашел этот ответ здесь :

if(($twitter_XML_raw=file_get_contents($timeline))==false){
    // Retrieve HTTP status code
    list($version,$status_code,$msg) = explode(' ',$http_response_header[0], 3);

    // Check the HTTP Status code
    switch($status_code) {
        case 200:
                $error_status="200: Success";
                break;
        case 401:
                $error_status="401: Login failure.  Try logging out and back in.  Password are ONLY used when posting.";
                break;
        case 400:
                $error_status="400: Invalid request.  You may have exceeded your rate limit.";
                break;
        case 404:
                $error_status="404: Not found.  This shouldn't happen.  Please let me know what happened using the feedback link above.";
                break;
        case 500:
                $error_status="500: Twitter servers replied with an error. Hopefully they'll be OK soon!";
                break;
        case 502:
                $error_status="502: Twitter servers may be down or being upgraded. Hopefully they'll be OK soon!";
                break;
        case 503:
                $error_status="503: Twitter service unavailable. Hopefully they'll be OK soon!";
                break;
        default:
                $error_status="Undocumented error: " . $status_code;
                break;
    }

По сути, вы используете метод «file get content» для извлечения URL, который автоматически заполняет переменную заголовка ответа http кодом состояния.

3 голосов
/ 22 января 2014

приложение, протестированы эти 3 метода с учетом производительности.

Результат, по крайней мере, в моей тестовой среде:

Завиток побед

Этот тест проводится с учетом того, что нужны только заголовки (noBody). Проверь себя:

$url = "http://de.wikipedia.org/wiki/Pinocchio";

$start_time = microtime(TRUE);
$headers = get_headers($url);
echo $headers[0]."<br>";
$end_time = microtime(TRUE);
echo $end_time - $start_time."<br>";


$start_time = microtime(TRUE);
$response = file_get_contents($url);
echo $http_response_header[0]."<br>";
$end_time = microtime(TRUE);
echo $end_time - $start_time."<br>";

$start_time = microtime(TRUE);
$handle = curl_init($url);
curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($handle, CURLOPT_NOBODY, 1); // and *only* get the header 
/* 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. */
// }
echo $httpCode."<br>";
curl_close($handle);
$end_time = microtime(TRUE);
echo $end_time - $start_time."<br>";
2 голосов
/ 23 марта 2018

Это даст вам истину, если URL не вернет 200 OK

function check_404($url) {
   $headers=get_headers($url, 1);
   if ($headers[0]!='HTTP/1.1 200 OK') return true; else return false;
}
2 голосов
/ 14 августа 2011

В качестве дополнительной подсказки к большому принятому ответу:

При использовании варианта предложенного решения я получал ошибки из-за установки php 'max_execution_time'. Итак, я сделал следующее:

set_time_limit(120);
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_NOBODY, true);
$result = curl_exec($curl);
set_time_limit(ini_get('max_execution_time'));
curl_close($curl);

Сначала я установил ограничение по времени на большее количество секунд, в конце я установил его обратно на значение, определенное в настройках php.

1 голос
/ 24 июня 2014
<?php

$url= 'www.something.com';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, true);   
curl_setopt($ch, CURLOPT_NOBODY, true);    
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.4");
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_TIMEOUT,10);
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$output = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);


echo $httpcode;
?>
...