如何处理 PHP 中 file_get_contents() 函数的警告?

369

我写了一个像这样的 PHP 代码

$site="http://www.google.com";
$content = file_get_content($site);
echo $content;

但是当我从$site中删除"http://"时,我会收到以下警告:

警告:file_get_contents(www.google.com)[function.file-get-contents]:无法打开流:

我尝试了trycatch,但没有起作用。


2
还有一种有趣的方法: https://dev59.com/O2w15IYBdhLWcg3wSJo3 - Hugo Stieglitz
相关链接:https://dev59.com/7nI-5IYBdhLWcg3wI0p9 - Fr0zenFyr
在此处使用try-catch与set_error_handler函数,如此所述:https://dev59.com/mXVC5IYBdhLWcg3whBWj#3406181 - MingalevME
3
如果您从网址中删除"http://",那么您就是在本地磁盘上寻找一个名为"www.google.com"的文件。 - Rauli Rajande
1
这怎么会引起这么多关注和点赞呢?为什么要删除协议信息呢?即使在2008年,你也有FTP和HTTPS。 - Daniel W.
17个回答

591

步骤1:检查返回代码:if($content === FALSE) { // 在此处理错误... }

步骤2:通过在调用file_get_contents()之前放置错误控制运算符(即@)来抑制警告: $content = @file_get_contents($site);


103
记得使用严格比较:if ($content === FALSE)。如果文件包含“0”,则会触发错误的负面结果。 - Aram Kocharyan
8
您好,这对我没有起作用。添加@符号仍然会导致某个全局(而非我的)错误处理程序捕获E_WARNING,我的脚本在处理返回值之前就会终止。有什么建议吗?谢谢。 - Sagi Mann
2
检测到副作用:如果文件不存在,则脚本将停止在@file_get_contents行。 - Dax
5
虽然这个答案很旧,但我仍建议在你的答案中添加一条注释,说明使用@符号可能会对性能产生负面影响。可以参考一个相关帖子上的答案,解释得相当清楚:https://dev59.com/7nI-5IYBdhLWcg3wI0p9#2002789。 - Fr0zenFyr
5
不要这样做。你只是抑制了错误警告,这并不是错误处理!这会在调试时产生问题。 - helle
显示剩余5条评论

179
你还可以将设置错误处理程序作为一个匿名函数,该函数调用一个异常,并在该异常上使用try / catch。
set_error_handler(
    function ($severity, $message, $file, $line) {
        throw new ErrorException($message, $severity, $severity, $file, $line);
    }
);

try {
    file_get_contents('www.google.com');
}
catch (Exception $e) {
    echo $e->getMessage();
}

restore_error_handler();

看起来为了捕捉一个小错误而写了很多代码,但是如果你在整个应用程序中都使用异常处理,你只需要在顶部(比如在一个包含的配置文件中)做一次,它就会将所有错误转换为异常。

考虑到 PHP5,我认为这可能是更有效的答案。 - James P.
有人能解释一下,为什么一个简单的try-catch不足以解决它吗? - vaso123
2
@lolka_bolka 因为 file_get_contents 不会抛出异常,而是抛出 PHP 错误。所以这个例子设置了一个“错误处理程序”,捕获大多数 PHP 错误实例,并将这些错误转换为异常。这里有一个更现代的示例来自文档:http://php.net/manual/en/class.errorexception.php#errorexception.examples - enobrev
2
@enobrev 在抛出异常之前,请记得在匿名函数内恢复错误处理程序。异常可以被处理,如果处理了该异常,则处理程序仍然设置为抛出此特定异常,这可能会导致意外的行为,并且在异常处理中出现另一个错误时难以调试。 - Josef Sábl
2
我建议在finally块中包含restore_error_handler()调用。 - peschanko
显示剩余5条评论

115

我最喜欢的方法相当简单:

if (($data = @file_get_contents("http://www.google.com")) === false) {
      $error = error_get_last();
      echo "HTTP request failed. Error was: " . $error['message'];
} else {
      echo "Everything went better than expected";
}

在尝试使用@enobrev上面提到的try/catch后,我发现了这个方法,但它可以让代码变得更简洁(并且在我看来更易读)。我们只需要使用error_get_last获取最后一个错误的文本,而file_get_contents在失败时返回false,因此一个简单的“if”语句就可以捕获这个错误。


2
这是解决这个问题最简单、最好的方法!也许可以使用@file_get_contents来抑制向浏览器报告错误。 - EDP
1
我承认,在所有答案中,这是唯一明智的答案——如果我们使用@file_get_contents来抑制警告并使用=== FALSE测试结果值,那就更好了。 - kostix
13
如果成功的请求没有返回正文,或者返回一个被解释为 false 的正文,这将会触发错误。建议使用 if (false !== ($data = file_get_contents ())) 的方式进行判断。 - GordonM
文档并没有明确说明,但是根据我的经验,使用@符号可能会导致error_get_last函数返回空值。 - Glenn Schmidt
3
第一个条件是反向的。如果假不等于file_get_contents调用的结果,则它获取了一些内容,我们不应该寻找错误。我感到困惑的是,在先前的测试中看到错误或看到$error为空时,实际上已经找到了Google! - Robert
我已经更新了答案,以包括之前评论中的反馈。 - Garland Pope

42

您可以在前面添加 @:

$content = @file_get_contents($site);

这将抑制任何警告 - 请谨慎使用! 详情请见错误控制运算符

编辑:当您删除“http://”时,您不再寻找网页,而是寻找名为“www.google.....”的磁盘文件。


这是唯一真正有效的方法 - 我无法通过其他方式抑制“无法打开流”消息。 - Olaf

26

一种替代方案是抑制错误并同时抛出异常,这样您可以稍后捕获它。如果您的代码中有多个对file_get_contents()的调用,这尤其有用,因为您不需要手动抑制和处理所有这些调用。相反,可以在单个try / catch块中对此函数进行多次调用。

// Returns the contents of a file
function file_contents($path) {
    $str = @file_get_contents($path);
    if ($str === FALSE) {
        throw new Exception("Cannot access '$path' to read contents.");
    } else {
        return $str;
    }
}

// Example
try {
    file_contents("a");
    file_contents("b");
    file_contents("c");
} catch (Exception $e) {
    // Deal with it.
    echo "Error: " , $e->getMessage();
}

19
function custom_file_get_contents($url) {
    
    return file_get_contents(
        $url,
        false,
        stream_context_create(
            array(
                'http' => array(
                    'ignore_errors' => true
                )
            )
        )
    );
}


if( $content = custom_file_get_contents($url) ) {

    //play with the result

} 
else {

    //handle the error
}

这个不起作用。如果$url是404未找到,警告仍然会出现。 - Raptor
正确的Raptor,我已经使用stream_context_create()改进了答案;没有比这更好的了...不建议使用"@"。 - RafaSashi
1
ignore_errors仅指示HTTP上下文不将状态码大于等于400的HTTP响应解释为错误。虽然有些相关,但这并不能回答关于PHP错误处理的问题。 - sun
1
感谢ignore_errors选项!这正是我所需要的! - Modder

16

这是我是如何做到的... 不需要try-catch块... 最好的解决方案总是最简单的... 享受吧!

$content = @file_get_contents("http://www.google.com");
if (strpos($http_response_header[0], "200")) { 
   echo "SUCCESS";
} else { 
   echo "FAILED";
} 

5
如果你无法连接服务器(例如域名错误)而不是收到404错误等,这种方法就无法起作用。我认为在这种情况下$http_response_header没有被更新,因为没有收到HTTP响应。 - Nathan Reed
1
正如@NathanReed所说,您应该检查$content不是false(使用===),因为如果请求根本无法连接,就会返回它。 - Seb

6
这是我处理此事的方法:
$this->response_body = @file_get_contents($this->url, false, $context);
if ($this->response_body === false) {
    $error = error_get_last();
    $error = explode(': ', $error['message']);
    $error = trim($error[2]) . PHP_EOL;
    fprintf(STDERR, 'Error: '. $error);
    die();
}

5

0

自 PHP 4 开始使用 error_reporting()

$site="http://www.google.com";
$old_error_reporting = error_reporting(E_ALL ^ E_WARNING);
$content = file_get_content($site);
error_reporting($old_error_reporting);
if ($content === FALSE) {
    echo "Error getting '$site'";
} else {
    echo $content;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接