Cách dễ dàng để kiểm tra URL cho 404 trong PHP?


152

Tôi đang tự dạy mình một số thao tác cơ bản và tôi đã thấy rằng đôi khi các URL mà tôi nạp vào mã của mình trả về 404, điều này tổng hợp tất cả phần còn lại của mã của tôi.

Vì vậy, tôi cần một bài kiểm tra ở đầu mã để kiểm tra xem URL có trả về 404 hay không.

Điều này có vẻ như là một nhiệm vụ khá đơn giản, nhưng Google không cho tôi bất kỳ câu trả lời nào. Tôi lo lắng tôi đang tìm kiếm những thứ sai.

Một blog khuyên tôi nên sử dụng điều này:

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

và sau đó kiểm tra xem $ hợp lệ nếu trống hay không.

Nhưng tôi nghĩ rằng URL gây ra sự cố cho tôi có một chuyển hướng trên đó, vì vậy $ hợp lệ sẽ trở nên trống rỗng cho tất cả các giá trị. Hoặc có lẽ tôi đang làm điều gì đó sai.

Tôi cũng đã xem xét một "yêu cầu đầu" nhưng tôi chưa tìm thấy bất kỳ ví dụ mã thực tế nào tôi có thể chơi hoặc thử.

Gợi ý? Và những gì về curl?

Câu trả lời:


276

Nếu bạn đang sử dụng các curlràng buộc của PHP , bạn có thể kiểm tra mã lỗi bằng cách sử dụng curl_getinfonhư sau:

$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
Tôi chưa quen với cURL, vì vậy tôi thiếu một vài khái niệm. Tôi phải làm gì với biến phản hồi $ bên dưới? Nó chứa cái gì?

1
@bflora, tôi đã mắc lỗi trong mã. (Sẽ sửa trong giây lát.) Bạn có thể xem tài liệu về curl_exec trên trang web của PHP.
strager

4
@bflora $ reply sẽ chứa nội dung của $ url để bạn có thể thực hiện các việc bổ sung như kiểm tra nội dung cho các chuỗi cụ thể hoặc bất cứ điều gì. Trong trường hợp của bạn, bạn chỉ cần quan tâm đến trạng thái 404, vì vậy bạn có thể không cần phải lo lắng về phản hồi $.
Beau Simensen

5
Điều gì sẽ xảy ra nếu bạn chỉ muốn tải tiêu đề thay vì tải xuống toàn bộ tệp?
patrick

13
@patrick sau đó bạn cần chỉ định curl_setopt($handle, CURLOPT_NOBODY, true);trước khi chạycurl_exec
người dùng

101

Nếu php5 đang chạy của bạn, bạn có thể sử dụng:

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

Ngoài ra, với php4, một người dùng đã đóng góp như sau:

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

Cả hai sẽ có kết quả tương tự như:

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
)

Do đó, bạn chỉ có thể kiểm tra xem phản hồi tiêu đề có ổn không, ví dụ:

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

Mã và định nghĩa W3C


Tôi đã thực hiện một vài cải tiến định dạng cho câu trả lời của bạn, tôi cũng đã thêm vào khả năng cho https: get_headers($https_url,1,443);Tôi chắc chắn rằng nó sẽ hoạt động mặc dù nó không có trong get_headers()chức năng tiêu chuẩn .. Hãy kiểm tra và trả lời với trạng thái cho nó.
JamesM-SiteGen

1
cách giải quyết tốt cho php4, nhưng đối với những trường hợp như thế này, chúng ta có phương thức CHÍNH http.
vidstige

Vì vậy, điều này thực sự sẽ nhanh hơn phương pháp curl?
FLY

4
Giải pháp này không hợp lệ khi URL mục tiêu chuyển hướng đến 404. Trong trường hợp này, các tiêu đề $ [0] sẽ là mã chuyển hướng và mã 404 cuối cùng sẽ được thêm vào đâu đó sau đó trong mảng trả về.
phòng vào

1
Điều này kết thúc là rắc rối hơn giá trị của php trong việc lọc mã thực tế khỏi chuỗi kết quả, khi cố gắng xử lý đơn giản mã trạng thái trong tập lệnh, trái ngược với việc lặp lại kết quả để đọc.
Kzqai

37

Với mã của trình phân tích, bạn cũng có thể kiểm tra CURLINEFO_HTTP_CODE để biết các mã khác. Một số trang web không báo cáo 404, thay vào đó họ chỉ chuyển hướng đến trang 404 tùy chỉnh và trả lại 302 (chuyển hướng) hoặc một cái gì đó tương tự. Tôi đã sử dụng điều này để kiểm tra xem một tập tin thực tế (ví dụ: robot.txt) có tồn tại trên máy chủ hay không. Rõ ràng loại tệp này sẽ không gây ra chuyển hướng nếu nó tồn tại, nhưng nếu nó không chuyển hướng đến trang 404, như tôi đã nói trước đây có thể không có mã 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 cho việc sử dụng mã HTTP "thành công" thay vì 404 ... Người dùng có thể nhận được 408 Request Timeout, chứ không phải404
guillaume

Làm việc như một sự quyến rũ. Tôi sử dụng điều này để kiểm tra nếu một bài viết trên ebay vẫn còn trực tuyến.
Nerdkowski

Đối với những người mong đợi mã trên hoạt động với https, hãy thử thêm vào sau:curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, FALSE);
Kirk Hammett

nhưng điều này cũng sẽ trả về 404 = true nếu có chuyển hướng 302 hợp pháp?
Robert Sinclair

22

Như strager gợi ý, hãy xem xét sử dụng cURL. Bạn cũng có thể quan tâm đến việc thiết lập CURLOPT_NOBODY với curl_setopt để bỏ qua việc tải xuống toàn bộ trang (bạn chỉ muốn các tiêu đề).


1
+1 để đề cập đến tôi ^ W ^ Cung cấp một giải pháp thay thế hiệu quả hơn, trong trường hợp chỉ cần kiểm tra tiêu đề. =]
strager

16

Nếu bạn đang tìm kiếm một giải pháp đơn giản nhất và giải pháp bạn có thể thử trong một lần trên php5

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

3
btw, nếu làm điều này và url 404, một cảnh báo được đưa ra, gây ra đầu ra.
Chris K

dễ dàng hơn để làm $ isExists = @file_get_contents ('www.yoursite.com'); if ($ isExists! == true) {echo "mang lại 404"}
Tebe

thử bắt, sau đó xử lý 404 bằng cách bắt
Garet Claborn

7

Tôi tìm thấy câu trả lời ở đây :

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

Về cơ bản, bạn sử dụng phương thức "lấy nội dung tệp" để truy xuất URL, tự động điền biến tiêu đề phản hồi http với mã trạng thái.


2
Thú vị - tôi chưa bao giờ nghe nói về phép thuật toàn cầu đó trước đây. php.net/manual/en/reserved.variabled.httpresponseheader.php
Nông dân Frank

2
trớ trêu - liên kết là một 404
Hamzah Malik

6

Điều này sẽ cung cấp cho bạn đúng nếu url không trả về 200 OK

function check_404($url) {
   $headers=get_headers($url, 1);
   if ($headers[0]!='HTTP/1.1 200 OK') return true; else return false;
}

Điều này nhanh hơn nhiều so với sử dụng cURL, nếu bạn muốn thực hiện kiểm tra bool đơn giản trên một url. Cảm ơn bạn.
Drmzindec

5

phụ lục, đã thử nghiệm 3 phương pháp xem xét hiệu suất.

Kết quả, ít nhất là trong môi trường thử nghiệm của tôi:

Curl thắng

Thử nghiệm này được thực hiện dưới sự xem xét rằng chỉ cần các tiêu đề (noBody). Tự kiểm tra:

$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

Như một gợi ý bổ sung cho câu trả lời tuyệt vời được chấp nhận:

Khi sử dụng một biến thể của giải pháp được đề xuất, tôi đã gặp lỗi do cài đặt php 'max_execut_time'. Vì vậy, những gì tôi đã làm là như sau:

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

Đầu tiên tôi đặt giới hạn thời gian thành số giây cao hơn, cuối cùng tôi đặt lại về giá trị được xác định trong cài đặt php.


hhhmmmm ... bên cạnh đó ... mã của bạn tiêu tốn ít tài nguyên hơn vì bạn không trả lại nội dung ... nếu bạn có thể thêm chuyển trả lại thành false thì có thể tiết kiệm nhiều tài nguyên khi mọi người sử dụng nhiều cuộc gọi ... người mới bắt đầu không nghĩ nhiều và đó là lý do để tăng 40 phiếu bầu ... thật tốt ...
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

Đây là một giải pháp ngắn.

$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);

Trong trường hợp của bạn, bạn có thể thay đổi application/rdf+xmlthành bất cứ điều gì bạn sử dụng.


2

Hàm này trả về mã trạng thái của một URL trong PHP 7:

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

Thí dụ:

echo getHttpResponseCode('https://www.google.com');
//displays: 200

1

Bạn cũng có thể sử dụng mã này để xem trạng thái của bất kỳ liên kết nào:

<?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

đây chỉ là một lát mã, hy vọng có hiệu quả với bạn

            $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

Đây là một cách!

<?php

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

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

?>

Kịch bản đơn giản này chỉ đơn giản là thực hiện một yêu cầu tới URL cho mã nguồn của nó. Nếu yêu cầu được hoàn thành thành công, nó sẽ xuất ra "URL tồn tại!". Nếu không, nó sẽ xuất ra "URL không tồn tại!".

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.