Cara mudah untuk menguji URL untuk 404 di PHP?

152

Saya mengajar diri sendiri beberapa goresan dasar dan saya menemukan bahwa kadang-kadang URL yang saya masukkan ke kode saya kembali 404, yang merupakan gusi semua sisa kode saya.

Jadi saya perlu tes di bagian atas kode untuk memeriksa apakah URL mengembalikan 404 atau tidak.

Ini akan tampak seperti tugas langsung, tetapi Google tidak memberi saya jawaban. Saya khawatir saya mencari hal yang salah.

Satu blog merekomendasikan saya menggunakan ini:

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

dan kemudian tes untuk melihat apakah $ valid jika kosong atau tidak.

Tapi saya pikir URL yang memberi saya masalah memiliki arahan ulang, jadi $ valid akan kosong untuk semua nilai. Atau mungkin saya melakukan sesuatu yang salah.

Saya juga telah melihat ke dalam "permintaan kepala" tetapi saya belum menemukan contoh kode aktual yang bisa saya mainkan atau coba.

Saran? Dan apa ini tentang ikal?

hidung besar
sumber

Jawaban:

276

Jika Anda menggunakan curlbinding PHP , Anda dapat memeriksa kode kesalahan menggunakan curl_getinfoseperti:

$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
sumber
1
Saya belum terbiasa dengan CURL, jadi saya kehilangan beberapa konsep. Apa yang harus saya lakukan dengan variabel $ response di bawah? Apa isinya?
1
@ Blora, saya membuat kesalahan dalam kode. (Akan diperbaiki dalam sedetik.) Anda dapat melihat dokumentasi untuk curl_exec di situs PHP.
strager
4
@ bflora $ response akan berisi konten $ url sehingga Anda dapat melakukan hal-hal tambahan seperti memeriksa konten untuk string tertentu atau apa pun. Dalam kasus Anda, Anda hanya peduli pada kondisi 404, jadi Anda mungkin tidak perlu khawatir tentang $ response.
Beau Simensen
5
Bagaimana jika Anda hanya ingin memuat header daripada mengunduh seluruh file?
patrick
13
@patrick maka Anda perlu menentukan curl_setopt($handle, CURLOPT_NOBODY, true);sebelum menjalankancurl_exec
pengguna
101

Jika Anda menjalankan php5 Anda dapat menggunakan:

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

Atau dengan php4 pengguna berkontribusi sebagai berikut:

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

Keduanya akan memiliki hasil yang mirip dengan:

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
)

Karenanya, Anda bisa memeriksa untuk melihat bahwa respons tajuk OK, misalnya:

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

Kode dan Definisi W3C

Asciant
sumber
Saya membuat beberapa perbaikan format jawaban Anda, saya juga menambahkan kemampuan untuk https: get_headers($https_url,1,443);Saya yakin itu akan berfungsi meskipun tidak dalam get_headers()fungsi standar .. Jangan ragu untuk mengujinya dan merespons dengan status untuk itu.
JamesM-SiteGen
1
solusi yang bagus untuk php4, tetapi untuk kasus seperti ini kami memiliki metode HEAD http.
vidstige
Jadi ini sebenarnya akan lebih cepat daripada metode curl?
FLY
4
Solusi ini tidak valid ketika URL target dialihkan ke 404. Dalam hal ini $ header [0] akan menjadi kode pengalihan, dan kode 404 akhir akan ditambahkan di suatu tempat nanti dalam mengembalikan array.
roomcays
1
Ini berakhir menjadi lebih banyak masalah daripada nilainya di php untuk menyaring kode aktual dari string yang dihasilkan, ketika mencoba untuk hanya berurusan dengan kode status dalam sebuah skrip, yang bertentangan dengan menggemakan hasil untuk dibaca.
Kzqai
37

Dengan kode strager, Anda juga dapat memeriksa CURLINFO_HTTP_CODE untuk kode lain. Beberapa situs web tidak melaporkan 404, melainkan hanya mengarahkan ulang ke halaman 404 khusus dan mengembalikan 302 (redirect) atau yang serupa. Saya menggunakan ini untuk memeriksa apakah file aktual (mis. Robots.txt) ada di server atau tidak. Jelas jenis file ini tidak akan menyebabkan pengalihan jika ada, tetapi jika tidak maka akan diarahkan ke halaman 404, yang seperti saya katakan sebelumnya mungkin tidak memiliki kode 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;
    }
}
Aram Kocharyan
sumber
5
+1 untuk penggunaan kode HTTP "sukses" alih-alih 404 ... Pengguna dapat memperoleh 408 Request Timeout, bukan a404
guillaume
Bekerja lika pesona. Saya menggunakan ini untuk memeriksa apakah artikel di ebay masih online.
Nerdkowski
Bagi mereka yang mengharapkan kode di atas untuk bekerja dengan https, coba tambahkan yang berikut:curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, FALSE);
Kirk Hammett
tetapi ini juga akan mengembalikan 404 = benar jika ada 302 redirect yang sah?
Robert Sinclair
22

Seperti yang disarankan strager, lihatlah menggunakan CURL. Anda juga mungkin tertarik untuk menyetel CURLOPT_NOBODY dengan curl_setopt untuk melewati pengunduhan seluruh halaman (Anda hanya ingin tajuknya ).

Beau Simensen
sumber
1
+1 untuk menyebut saya ^ W ^ Menyediakan alternatif yang lebih efisien, dalam hal hanya header yang perlu diperiksa. =]
strager
16

Jika Anda mencari solusi termudah dan yang dapat Anda coba sekaligus, lakukanlah php5

file_get_contents('www.yoursite.com');
//and check by echoing
echo $http_response_header[0];
Nasaralla
sumber
3
btw, jika melakukan ini dan url 404, peringatan dinaikkan, menyebabkan output.
Chris K
lebih mudah untuk melakukan $ isExists = @file_get_contents ('www.yoursite.com'); if ($ isExists! == true) {echo "yield 404"}
Tebe
masukkan mencoba menangkap, kemudian menangani 404 dengan menangkap
Garet Claborn
7

Saya menemukan jawaban ini di sini :

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

Pada dasarnya, Anda menggunakan metode "file mendapatkan konten" untuk mengambil URL, yang secara otomatis mengisi variabel header respons http dengan kode status.

Ross
sumber
2
Menarik - Saya belum pernah mendengar sihir global itu sebelumnya. php.net/manual/en/reserved.variables.httpresponseheader.php
Frank Farmer
2
ironi - tautannya adalah 404
Hamzah Malik
6

Ini akan memberi Anda benar jika url tidak mengembalikan 200 OK

function check_404($url) {
   $headers=get_headers($url, 1);
   if ($headers[0]!='HTTP/1.1 200 OK') return true; else return false;
}
Juergen
sumber
Ini jauh lebih cepat daripada menggunakan CURL, jika Anda ingin melakukan pemeriksaan bool sederhana pada url. Terima kasih.
Drmzindec
5

tambahan, menguji 3 metode yang mempertimbangkan kinerja.

Hasilnya, setidaknya di lingkungan pengujian saya:

Curl menang

Tes ini dilakukan dengan pertimbangan bahwa hanya header (noBody) yang diperlukan. Uji dirimu:

$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>";
Surel
sumber
3

Sebagai petunjuk tambahan untuk jawaban yang diterima:

Ketika menggunakan variasi dari solusi yang diusulkan, saya mendapat kesalahan karena pengaturan php 'max_execution_time'. Jadi yang saya lakukan adalah sebagai berikut:

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

Pertama saya mengatur batas waktu ke jumlah detik yang lebih tinggi, pada akhirnya saya mengaturnya kembali ke nilai yang ditentukan dalam pengaturan php.

markus
sumber
hhhmmmm ... selain itu ... kode Anda menghabiskan lebih sedikit sumber daya karena Anda tidak mengembalikan konten ... masih jika Anda dapat menambahkan transfer balik ke false maka dapat menghemat banyak sumber daya ketika orang-orang menggunakan beberapa panggilan ... pemula tidak berpikir banyak dan jadi alasan untuk 40 suara ... itu baik-baik saja ...
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;
?>
Melbin Mathew Antony
sumber
3

Ini solusi singkatnya.

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

Dalam kasus Anda, Anda dapat mengubah application/rdf+xmlapa pun yang Anda gunakan.

Andreas
sumber
2

Fungsi ini mengembalikan kode status URL di PHP 7:

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

Contoh:

echo getHttpResponseCode('https://www.google.com');
//displays: 200
Sebastian Viereck
sumber
1

Anda dapat menggunakan kode ini juga, untuk melihat status tautan apa pun:

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

ini adil dan sepotong kode, harapan berhasil untuk Anda

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

sumber
0

Ini caranya!

<?php

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

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

?>

Skrip sederhana ini hanya membuat permintaan ke URL untuk kode sumbernya. Jika permintaan berhasil diselesaikan, itu akan menampilkan "URL Ada!". Jika tidak, itu akan menampilkan "URL Tidak Ada!".

Hayden Frobenius
sumber