Простий спосіб перевірити URL-адресу на 404 в PHP?


152

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

Тому мені потрібен тест у верхній частині коду, щоб перевірити, повертає URL-адресу 404 чи ні.

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

Один блог рекомендував використовувати цей:

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

а потім перевірити, чи $ дійсний, якщо порожній чи ні.

Але я думаю, що 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. */

1
З CURL я ще не знайомий, тому мені не вистачає кількох понять. Що мені робити зі змінною $ response внизу? Що він містить?

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

4
@bflora $ відповідь буде містити вміст $ url, тому ви можете робити додаткові речі, такі як перевірка вмісту для певних рядків або будь-якого іншого. У вашому випадку ви просто дбаєте про стан 404, тому вам, мабуть, не потрібно турбуватися про $ response.
Beau Simensen

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


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

1
добре вирішити php4, але для таких випадків у нас є метод HEAD http.
vidstige

Так це насправді було б швидше, ніж метод curl?
ЛЕТ

4
Це рішення недійсне, коли цільова URL-адреса переспрямовує на 404. У цьому випадку $ headers [0] буде кодом переадресації, а остаточний код 404 буде доданий десь пізніше у масиві, що повертається.
roomcays

1
Це, в кінцевому підсумку, становить більше проблем, ніж варто в php, щоб відфільтрувати фактичний код із результуючого рядка, намагаючись просто мати справу з кодом статусу в сценарії, на відміну від повторення результату для читання.
Kzqai

37

За допомогою коду strager ви також можете перевірити 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
guillaume

Працювала лайка чарівністю. Я використовую це, щоб перевірити, чи є стаття на ebay ще в Інтернеті.
Nerdkowski

Для тих, хто очікує, що вищевказаний код працюватиме з https, спробуйте додати наступне:curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, FALSE);
Кірк Хамметт

але це також поверне 404 = true, якщо є законне перенаправлення 302?
Роберт Сінклер

22

Як пропонує Strager, погляньте на використання CURL. Можливо, вам також буде цікаво встановити CURLOPT_NOBODY за допомогою curl_setopt, щоб пропустити завантаження всієї сторінки (ви просто хочете заголовки).


1
+1 для згадки про мене ^ W ^ Надання більш ефективної альтернативи, якщо потрібно перевірити лише заголовок. =]
страгер

16

Якщо ви шукаєте найпростіше рішення і те, що ви можете спробувати за один раз на php5 do

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

3
btw, якщо це робиться і URL-адреса 404, піднімається попередження, викликаючи вихід.
Кріс К

простіше зробити $ isExists = @file_get_contents ('www.yoursite.com'); if ($ isExists! == true) {echo "приносить 404"}
Тебе

поставити спробу лову, а потім обробити 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;
    }

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


2
Цікаво - я ніколи раніше не чув про цю магічну глобальну. php.net/manual/en/reserved.variables.httpresponseheader.php
Френк Фермер

2
іронія - посилання 404
Hamzah Malik

6

Це дасть вам істину, якщо URL не поверне 200 ОК

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

Додано; випробували ці 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.


hhhmmmm ... до того ж ... ваш код споживає менше ресурсів, тому що ви не повертаєте вміст ... все-таки, якщо ви можете додати зворотну передачу до false, тоді ви можете зекономити багато ресурсів, коли люди, що використовують декілька дзвінків ... новачки не думають багато і тому це причина 40 голосів "за" ... це добре ...
Jayapal Chandran

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те, що використовуєте.


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

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 існує!". Якщо ні, то він виведе "URL не існує!".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.