在PHP中测试404 URL的简单方法?


152

我正在自学一些基本的抓取方法,并且发现有时输入到代码中的URL返回404,这将困扰我所有的代码。

因此,我需要在代码顶部进行测试,以检查URL是否返回404。

这似乎是一个非常直截了当的任务,但是Google并没有给我任何答案。我担心我在寻找错误的东西。

一个博客建议我使用这个:

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

然后测试以查看$ valid是否为空。

但是我认为给我带来问题的URL上有一个重定向,因此$ valid对于所有值都为空。也许我在做其他错误。

我还研究了“ head请求”,但还没有找到可以使用或尝试的任何实际代码示例。

有什么建议吗?那卷曲呢?

Answers:


276

如果您使用的是PHP的curlbindings,则可以这样检查错误代码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,我在代码中犯了一个错误。(稍后将修复。)您可以在PHP的站点上查看curl_exec的文档。
斯特拉格

4
@bflora $ response将包含$ url的内容,因此您可以执行其他操作,例如检查内容中的特定字符串或其他内容。在您的情况下,您只关心404状态,因此您可能不必担心$ response。
Beau Simensen

5
如果您只想加载标题而不是下载整个文件怎么办?
帕特里克2014年

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方法要快吗?
FLY 2013年

4
当目标URL重定向到404时,此解决方案无效。在这种情况下,$ headers [0]将是重定向代码,而最终的404代码将在以后的返回数组中附加到某个地方。
roomcays 13-10-17

1
当试图简单地处理脚本中的状态码而不是回显结果以进行读取时,这比在php中从结果字符串中过滤出实际代码要麻烦得多。
卡扎伊

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

但是如果存在合法的302重定向,这还会返回404 = true?
罗伯特·辛克莱

22

正如strager建议的那样,请研究使用cURL。您可能还对将curl_setopt设置为CURLOPT_NOBODY 以跳过下载整个页面感兴趣(您只需要标题)。


1
+1表示我^ W ^在仅需要检查标头的情况下提供了更有效的替代方法。=]
斯特拉格

16

如果您正在寻找一种最简单的解决方案,并且可以一次尝试使用php5,

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

3
顺便说一句,如果这样做和URL 404一样,则会引发警告,并导致输出。
克里斯·K

更容易做到$ isExists = @file_get_contents('www.yoursite.com'); if($ isExists!== true){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,该URL将自动使用状态代码填充http响应标头变量。


2
有趣-我以前从未听说过这种魔术。 php.net/manual/en/reserved.variables.httpresponseheader.php
Frank Farmer 2009年

2
具有讽刺意味的-链接是404
Hamzah Malik

6

如果url不返回200,则将为您提供true

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

如果要对URL进行简单的布尔检查,这比使用cURL快得多。谢谢。
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 2012年

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

此函数返回PHP 7中URL的状态码:

/**
 * @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 Exists!”。如果没有,它将输出“ URL不存在!”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.