Простой способ проверить URL на 404 в PHP?


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

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

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

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

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

А затем проверьте, чтобы увидеть, если $допустимо, если пусто или нет.

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

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

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

Author: bignose, 0000-00-00

13 answers

Если вы используете 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. */
 252
Author: strager, 2009-01-03 01:25:59

Если вы используете 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

 96
Author: Asciant, 2013-02-04 09:53:04

С помощью кода Стрейджера вы также можете проверить код 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;
    }
}
 32
Author: Aram Kocharyan, 2011-01-08 02:54:47

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

 20
Author: Beau Simensen, 2009-01-03 00:59:16

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

file_get_contents('www.yoursite.com');
//and check by echoing
echo $http_response_header[0];
 15
Author: Nasaralla, 2011-05-12 14:43:14

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

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

По сути, вы используете метод "получить содержимое файла" для получения URL-адреса, который автоматически заполняет переменную заголовка http-ответа кодом состояния.

 6
Author: Ross, 2009-01-03 00:55:07

Добавление; протестировал эти 3 метода с учетом производительности.

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

Керл выигрывает

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

$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>";
 3
Author: Email, 2014-01-22 16:05:59

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

При использовании варианта предлагаемого решения я получил ошибки из-за настройки 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.

 2
Author: markus, 2011-08-14 14:01:43

Вы также можете использовать этот код, чтобы увидеть статус любой ссылки:

<?php

function get_url_status($url, $timeout = 10) 
{
$ch = curl_init();
// set cURL options
$opts = array(CURLOPT_RETURNTRANSFER => true, // do not output to browser
            CURLOPT_URL => $url,            // set URL
            CURLOPT_NOBODY => true,         // do a HEAD request only
            CURLOPT_TIMEOUT => $timeout);   // set timeout
curl_setopt_array($ch, $opts);
curl_exec($ch); // do it!
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE); // find HTTP status
curl_close($ch); // close handle
echo $status; //or return $status;
    //example checking
    if ($status == '302') { echo 'HEY, redirection';}
}

get_url_status('http://yourpage.comm');
?>
 1
Author: T.Todua, 2013-03-26 14:17:20
<?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;
?>
 1
Author: Melbin Mathew Antony, 2014-06-24 06:48:45

Вот краткое решение.

$handle = curl_init($uri);
curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($handle,CURLOPT_HTTPHEADER,array ("Accept: application/rdf+xml"));
curl_setopt($handle, CURLOPT_NOBODY, true);
curl_exec($handle);
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
if($httpCode == 200||$httpCode == 303) 
{
    echo "you might get a reply";
}
curl_close($handle);

В вашем случае вы можете изменить application/rdf+xml на все, что вы используете.

 1
Author: Andreas, 2016-11-04 16:53:36

Это просто и фрагмент кода, надеюсь, сработает для вас

            $ch = @curl_init();
            @curl_setopt($ch, CURLOPT_URL, 'http://example.com');
            @curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1");
            @curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            @curl_setopt($ch, CURLOPT_TIMEOUT, 10);

            $response       = @curl_exec($ch);
            $errno          = @curl_errno($ch);
            $error          = @curl_error($ch);

                    $response = $response;
                    $info = @curl_getinfo($ch);
return $info['http_code'];
 0
Author: , 2009-01-03 01:01:01

Чтобы поймать все ошибки: 4XX и 5XX, я использую этот небольшой скрипт:

function URLIsValid($URL){
    $headers = @get_headers($URL);
    preg_match("/ [45][0-9]{2} /", (string)$headers[0] , $match);
    return count($match) === 0;
}
 0
Author: wawan, 2014-03-17 09:59:30