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

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

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

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

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

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

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

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

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

Предложения? А что насчет завитка?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
157
0
243 572
15
Перейти к ответу Данный вопрос помечен как решенный

Ответы 15

Нашел такой ответ здесь:

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 contents» для получения URL-адреса, который автоматически заполняет переменную заголовка HTTP-ответа кодом состояния.

Интересно - я никогда раньше не слышал об этом волшебном глобале. php.net/manual/en/reserved.variables.httpresponseheader.php

Frank Farmer 30.09.2009 03:06

ирония - ссылка 404

Hamzah Malik 27.08.2017 01:12
Ответ принят как подходящий

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

Я еще не знаком с cURL, поэтому мне не хватает нескольких концепций. Что мне делать с переменной $ response внизу? Что в нем содержится?

bflora 03.01.2009 04:09

@bflora, я ошибся в коде. (Исправлю через секунду.) Вы можете увидеть документацию для curl_exec на сайте PHP.

strager 03.01.2009 04:24

@bflora $ response будет содержать содержимое $ url, чтобы вы могли делать дополнительные вещи, например проверять содержимое на наличие определенных строк или что-то еще. В вашем случае вы просто заботитесь о состоянии 404, поэтому вам, вероятно, не нужно беспокоиться о $ response.

Beau Simensen 03.01.2009 04:42

Интересно. Сейчас я использую $ html = new DOMDocument (); @ $ html-> loadHTMLFile ($ url); $ xml = simplexml_import_dom ($ html); Чтобы получить содержимое URL-адресов и пройти по ним, чтобы получить элементы, которые мне нужно вставить. Было бы лучше curl?

bflora 03.01.2009 05:17

@bflora, Если вы отправите запрос на сервер, он обработает ваш запрос и вернет HTTP-код вместе с данными. Если вы запросите дважды, ваш скрипт будет примерно в два раза медленнее (обычно ввод-вывод - самая медленная часть). Если вы воспользуетесь данными, полученными при первом запросе, это будет быстрее.

strager 03.01.2009 05:24

@bflora, Кроме того, в PHP есть опция, которая запрещает использовать fopen () URL (и DOMDocument, вероятно, использует fopen () в loadHTMLFile ()). curl лучше, и он обеспечивает гораздо больше возможностей настройки (например, вы можете запросить сжатие ответа или на другом языке).

strager 03.01.2009 05:25

Что делать, если вы хотите загружать только заголовки, а не загружать файл целиком?

patrick 12.03.2014 02:28

@patrick, тогда вам нужно указать curl_setopt($handle, CURLOPT_NOBODY, true); перед запуском curl_exec

user 28.11.2014 06:39

могу я получить пример в реальном времени?

Gem 10.03.2018 15:01

А как насчет перенаправления, кода 302, на 404? Где CURLOPT_FOLLOWLOCATION?

dima.rus 28.07.2019 10:56

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

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

strager 03.01.2009 04:04

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

            $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'];

Если у вас запущен 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

Я сделал несколько улучшений форматирования вашего ответа, я также добавил возможность для https: get_headers($https_url,1,443);. Я уверен, что он будет работать, хотя его нет в стандартной функции get_headers() .. Не стесняйтесь протестировать его и сообщить статус для него.

JamesM-SiteGen 06.02.2011 08:07

хороший обходной путь для php4, но для таких случаев у нас есть HTTP-метод HEAD.

vidstige 17.01.2013 01:16

Значит, это будет быстрее, чем метод curl?

FLY 15.02.2013 12:37

Это решение недействительно, если целевой URL-адрес перенаправляет на 404. В этом случае $ headers [0] будет кодом перенаправления, а окончательный код 404 будет добавлен где-то позже в возвращаемом массиве.

roomcays 17.10.2013 20:33

В конечном итоге это создает больше проблем, чем это того стоит в php, чтобы отфильтровать фактический код из результирующей строки при попытке просто обработать код состояния в сценарии, в отличие от вывода результата для чтения.

Kzqai 10.06.2016 21:51

Kzqai, в этом нет никаких проблем, вызывать целое приложение для выполнения этой работы просто глупо, если у вас нет других применений для curl.

Garet Claborn 01.05.2018 23:11
get_headers($url, 1)[0] === "HTTP/1.1 200 OK" был именно тем, что я хотел! Большое спасибо!
RedGuy11 21.02.2021 00:33

С помощью кода незнакомца вы также можете проверить 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;
    }
}

+1 за использование "успешных" HTTP-кодов вместо 404 ... Пользователь может получить 408 Request Timeout, а не 404

guillaume 05.05.2013 16:20

Работал как шарм. Я использую это, чтобы проверить, есть ли еще статья на ebay.

Nerdkowski 26.01.2016 16:36

Для тех, кто ожидает, что приведенный выше код будет работать с https, попробуйте добавить следующее: curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, FALSE);

Kirk Hammett 19.10.2017 21:52

но это также вернет 404 = true, если есть законное перенаправление 302?

Robert Sinclair 31.10.2018 18:20

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

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

кстати, если это сделать и URL-адрес 404, возникает предупреждение, вызывающее вывод.

Chris K 10.01.2015 13:39

проще сделать $ isExists = @file_get_contents ('www.yoursite.com'); if ($ isExists! == true) {echo "возвращает 404"}

Tebe 17.12.2017 01:03

поставить пробный улов, затем обработать 404 с уловом

Garet Claborn 01.05.2018 23:12

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

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

хххмммм ... кроме того ... ваш код потребляет меньше ресурсов, потому что вы не возвращаете контент ... тем не менее, если вы можете добавить обратную передачу в false, тогда вы можете сэкономить много ресурсов, когда люди используют несколько вызовов ... новички не думают много и поэтому это причина для 40 голосов за ... это нормально ...

Jayapal Chandran 07.03.2012 18:26

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

<?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');
?>

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

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

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

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

Curl побеждает

Этот тест проводится с учетом того, что нужны только заголовки (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>";
<?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;
?>

Это даст вам истину, если 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 06.05.2019 15:41

Вот способ!

<?php

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

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

?>

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

Эта функция возвращает код состояния 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

Другие вопросы по теме