วิธีง่ายๆในการทดสอบ 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 $ response จะมีเนื้อหาของ $ url เพื่อให้คุณสามารถทำสิ่งเพิ่มเติมเช่นการตรวจสอบเนื้อหาสำหรับสตริงที่เฉพาะเจาะจงหรืออะไรก็ตาม ในกรณีของคุณคุณเพียงแค่สนใจเกี่ยวกับสถานะ 404 ดังนั้นคุณอาจไม่จำเป็นต้องกังวลเกี่ยวกับการตอบกลับ $
Beau Simensen

5
ถ้าคุณต้องการโหลดส่วนหัวแทนที่จะดาวน์โหลดไฟล์ทั้งหมดล่ะ?
patrick

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

ดังนั้นนี่จะเร็วกว่าวิธีการม้วนงอจริงหรือ
FLY

4
วิธีนี้ไม่ถูกต้องเมื่อ URL เป้าหมายเปลี่ยนเส้นทางไปที่ 404 ในกรณีนี้ $ headers [0] จะเป็นรหัสเปลี่ยนเส้นทางและรหัส 404 สุดท้ายจะถูกต่อท้ายในอาร์เรย์ที่กลับมา
พัก

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 ยังคงออนไลน์อยู่หรือไม่
Nerdkowski

สำหรับผู้ที่คาดหวังว่ารหัสข้างต้นจะทำงานกับ https ลองเพิ่มต่อไปนี้:curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, FALSE);
Kirk Hammett

แต่จะกลับ 404 = จริงหากมีการเปลี่ยนเส้นทาง 302 ถูกต้องหรือไม่
Robert Sinclair

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

3
btw หากทำเช่นนี้กับ url 404 คำเตือนจะถูกยกขึ้นทำให้เกิดเอาต์พุต
Chris K

ง่ายกว่าในการทำ $ isExists = @file_get_contents ('www.yoursite.com'); if ($ isExists! == จริง) {echo "yields 404"}
Tebe

ใส่ลองจับแล้วจัดการ 404 ด้วยการจับ
Garet Claborn

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
Frank Farmer

2
ประชด - ลิงค์คือ 404
Hamzah Malik

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 มากถ้าคุณต้องการตรวจสอบบูลอย่างง่าย ๆ บน url ขอบคุณ.
Drmzindec

5

ภาคผนวก; ทดสอบทั้ง 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>";

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 ... นอกจากนี้ ... รหัสของคุณใช้ทรัพยากรน้อยลงทำให้คุณไม่ได้กลับเนื้อหา ... แต่ถ้าคุณสามารถเพิ่มการส่งคืนเป็นเท็จแล้วสามารถประหยัดทรัพยากรได้มากเมื่อผู้ที่ใช้โทรศัพท์หลายสาย ... ผู้เริ่มต้นไม่คิดมาก และด้วยเหตุผล 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 ไม่มีอยู่!"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.