Простой способ проверить URL для 404 в PHP?

152

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

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

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

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

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

а затем проверьте, является ли $ valid пустым или нет.

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

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

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

большой нос
источник

Ответы:

276

Если вы используете curlпривязки PHP , вы можете проверить код ошибки 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. */
strager
источник
1
Я еще не знаком с cURL, поэтому мне не хватает нескольких концепций. Что мне делать с переменной $ response внизу? Что это содержит?
1
@bflora, я допустил ошибку в коде. (Исправится через секунду.) Вы можете увидеть документацию для curl_exec на сайте PHP.
Страгер
4
@bflora $ response будет содержать содержимое $ url, чтобы вы могли выполнять дополнительные действия, такие как проверка содержимого на наличие определенных строк или чего-либо еще. В вашем случае вы просто заботитесь о состоянии 404, поэтому вам, вероятно, не нужно беспокоиться о $ response.
Бо Сименсен
5
Что делать, если вы просто хотите, чтобы заголовки загружались вместо загрузки всего файла?
Патрик
13
@patrick, то вам нужно указать curl_setopt($handle, CURLOPT_NOBODY, true);перед запускомcurl_exec
пользователь
101

Если у вас работает 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 коды и определения

Asciant
источник
Я внес несколько улучшений в форматирование вашего ответа, а также добавил возможность для https: get_headers($https_url,1,443);я уверен, что он будет работать, хотя он не входит в стандартную get_headers()функцию. Не стесняйтесь тестировать его и отвечать на него статусом.
JamesM-SiteGen
1
хороший обходной путь для php4, но для таких случаев у нас есть метод HEAD http.
Виджет
Так что это будет на самом деле быстрее, чем метод curl?
FLY
4
Это решение недопустимо, когда целевой URL перенаправляется на 404. В этом случае $ headers [0] будет кодом перенаправления, а окончательный код 404 будет добавлен где-то позже в возвращаемом массиве.
roomcays
1
Это приводит к большим проблемам, чем в php, чтобы отфильтровать фактический код из результирующей строки при попытке просто обработать код состояния в скрипте, а не выводить результат для чтения.
Kzqai
37

С помощью кода Страгера вы также можете проверить 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;
    }
}
Арам Кочарян
источник
5
+1 за использование «успешных» HTTP-кодов вместо 404 ... Пользователь может получить, а 408 Request Timeoutне404
гийом
Сработала Лика Шарм. Я использую это, чтобы проверить, если статья на Ebay все еще онлайн.
Нердковски
Для тех, кто ожидает, что приведенный выше код будет работать с https, попробуйте добавить следующее:curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, FALSE);
Кирк Хамметт
но это также вернет 404 = true, если существует законный редирект 302?
Роберт Синклер
22

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

Бо Сименсен
источник
1
+1 за упоминание меня ^ W ^ Обеспечение более эффективной альтернативы, в случае, когда нужно проверить только заголовок. =]
Страгер
16

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

file_get_contents('www.yoursite.com');
//and check by echoing
echo $http_response_header[0];
Nasaralla
источник
3
Кстати, если делать это и URL-адреса 404, выдается предупреждение, вызывая вывод.
Крис К
проще сделать $ isExists = @file_get_contents ('www.yoursite.com'); if ($ isExists! == true) {echo "приводит к 404"}
Тебе
вставьте
пробный
7

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

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 кодом состояния.

Росс
источник
2
Интересно - я никогда раньше не слышал об этом волшебном мире. php.net/manual/en/reserved.variables.httpresponseheader.php
Фрэнк Фармер,
2
ирония - ссылка 404
Хамза Малик
6

Это даст вам истину, если 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;
}
Юргена
источник
Это намного быстрее, чем использование cURL, если вы хотите выполнить простую проверку bool для URL. Спасибо.
Drmzindec
5

addendum, протестировал эти 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>";
Эл. адрес
источник
3

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

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

Markus
источник
хххмммм ... кроме того ... твой код потребляет меньше ресурсов, потому что ты не возвращаешь контент ... тем не менее, если бы ты мог добавить возврат передачи к ложному, то мог бы сэкономить большую часть ресурсов, когда люди используют множественные вызовы ... новички не думают много и так это причина для 40 голосов ... это хорошо ...
Джаяпал Чандран
3
<?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;
?>
Мельбин Мэтью Энтони
источник
3

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

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

Andreas
источник
2

Эта функция возвращает код состояния URL в PHP 7:

/**
 * @param string $url
 * @return int
 */
function getHttpResponseCode(string $url): int
{
    $headers = get_headers($url);
    return substr($headers[0], 9, 3);
}

Пример:

echo getHttpResponseCode('https://www.google.com');
//displays: 200
Себастьян Вирек
источник
1

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

<?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');
?>
T.Todua
источник
0

это всего лишь кусок кода, надежда работает на вас

            $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

Вот способ!

<?php

$url = "http://www.google.com";

if(@file_get_contents($url)){
echo "Url Exists!";
} else {
echo "Url Doesn't Exist!";
}

?>

Этот простой скрипт просто делает запрос к URL-адресу его исходного кода. Если запрос выполнен успешно, он выдаст «URL Exists!». Если нет, он выведет «URL не существует!».

Хайден Фробениус
источник