【问题标题】:Good error handling with file_get_contents使用 file_get_contents 进行良好的错误处理
【发布时间】:2010-08-07 16:29:55
【问题描述】:

我正在使用具有此功能的simplehtmldom

// get html dom form file
function file_get_html() {
    $dom = new simple_html_dom;
    $args = func_get_args();
    $dom->load(call_user_func_array('file_get_contents', $args), true);
    return $dom;
}

我是这样使用的:

$html3 = file_get_html(urlencode(trim("$link")));

有时,URL 可能无效,我想处理这个问题。我以为我可以使用 try and catch 但这没有用,因为它不会引发异常,它只是给出这样的 php 警告:

[06-Aug-2010 19:59:42] PHP Warning:  file_get_contents(http://new.mysite.com/ghs 1/) [<a href='function.file-get-contents'>function.file-get-contents</a>]: failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found  in /home/example/public_html/other/simple_html_dom.php on line 39

第 39 行在上面的代码中。

我怎样才能正确处理这个错误,我可以只使用一个普通的ifcondition,它看起来不像返回一个布尔值。

感谢大家的帮助

更新

这是一个好的解决方案吗?

if(fopen(urlencode(trim("$next_url")), 'r')){

    $html3 = file_get_html(urlencode(trim("$next_url")));

}else{
    //do other stuff, error_logging
    return false;

}

【问题讨论】:

  • 为什么是通过url而不是文件名调用的?
  • 这是个好问题,所以 +1
  • @Abs 这可能是因为您无缘无故地对所有答案投了反对票。
  • @Abs(和 Col):如何使用 @ 和返回代码比捕获异常更不合法的“错误处理”,或者您目前在“这是一个好的解决方案吗? '。就因为@?
  • 实际使用 DOM 而不是字符串解析的建议第三方替代方案:phpQueryZend_DomQueryPathFluentDom

标签: php error-handling


【解决方案1】:

这是一个想法:

function fget_contents() {
    $args = func_get_args();
    // the @ can be removed if you lower error_reporting level
    $contents = @call_user_func_array('file_get_contents', $args);

    if ($contents === false) {
        throw new Exception('Failed to open ' . $file);
    } else {
        return $contents;
    }
}

基本上是file_get_contents 的包装器。失败时会抛出异常。 为避免必须覆盖 file_get_contents 本身,您可以

// change this
$dom->load(call_user_func_array('file_get_contents', $args), true); 
// to
$dom->load(call_user_func_array('fget_contents', $args), true); 

现在你可以:

try {
    $html3 = file_get_html(trim("$link")); 
} catch (Exception $e) {
    // handle error here
}

错误抑制(通过使用@ 或通过降低error_reporting 级别是一种有效 解决方案。这可能会引发异常,您可以使用它来处理错误。@ 的原因有很多987654328@ 可能会产生警告,PHP 的手册本身建议降低 error_reporting:See manual

【讨论】:

  • 您可以捕获@file_get_contents 的输出...如果它是=== FALSE,那么您可以抛出自己的异常、设置返回码或其他任何方式。
  • @quantumSoup:请注意,如果成功读取空文件,您的第一个示例 if(file_get... 将给出错误,而第二个示例 if($contents === false) 只有在确实有错误时才会返回错误.
  • @gross 是的,我忘了检查第一个是否与 false 相同。虽然摆脱了整个第一部分。
  • 奇怪,似乎 file_get_contents 不喜欢编码的网址。我已经删除了它,它似乎执行得很好。
  • @Abs 实际上,您不应该将编码的 URL 传递给 PHP 的任何文件函数
【解决方案2】:

使用CURL 获取 URL 并以这种方式处理错误响应。

来自curl_init()的简单示例:

<?php
// create a new cURL resource
$ch = curl_init();

// set URL and other appropriate options
curl_setopt($ch, CURLOPT_URL, "http://www.example.com/");
curl_setopt($ch, CURLOPT_HEADER, 0);

// grab URL and pass it to the browser
curl_exec($ch);

// close cURL resource, and free up system resources
curl_close($ch);
?>

【讨论】:

  • 所以想法是在将 URL 传递给 file_get_contents 之前先检查 URL,我认为这是个好主意。我认为使用 fopen 更好。看到我的更新,你怎么看?
  • 不,CURL 会为您返回内容,因此不需要后续的 file_get_contents。
  • 你会对 curl_setopt() 中的 CURLOPT_RETURNTRANSFER 感兴趣:uk3.php.net/manual/en/function.curl-setopt.php
  • 我无法使用 CURL 或 fopen 来获取内容。我仍然需要使用 API 提供的 file_get_contents,我只需要检查 file_get_contents 是否没有返回错误,如果有则执行一些操作。同样,我不能直接摆弄 file_get_contents,因为它位于 simplehtmldom 的 API 中,就像我在问题中提到的那样。
  • +1 在可用于所有 HTTP 请求的情况下使用 CURL...专为它设计...file_get_contents 可以工作(在大多数情况下),但它不是为 HTTP 设计的,所以它会很难检测到某些类型的错误等......
【解决方案3】:

从我的观点来看,良好的错误处理是 PHP 的一大挑战。幸运的是,您可以注册自己的错误处理程序并自己决定要做什么。

您可以像这样定义一个相当简单的错误处理程序:

function throwExceptionOnError(int $errorCode , string $errorMessage) {
    // Usually you would check if the error code is serious
    // enough (like E_WARNING or E_ERROR) to throw an exception
    throw new Exception($errorMessage);
}

并像这样在你的函数中注册它:

function file_get_html() {
    $dom = new simple_html_dom;
    $args = func_get_args();
    set_error_handler("throwExceptionOnError");
    $dom->load(call_user_func_array('file_get_contents', $args), true);
    restore_error_handler();
    return $dom;
}

【讨论】:

    【解决方案4】:

    要查看 file_get_contents 调用可能失败的原因,您可以使用 php 的 error_get_last 函数:

    if ($contents = file_get_contents($url)) {
        // it worked
    }
    else {
       die("Failed to fetch ".$url.", error: ".error_get_last()['message']);
    }
    

    【讨论】:

      【解决方案5】:

      如果您从外部 URL 获取,最好的处理将来自于引入 HTTP 库,如 Zend_Http。这与使用 CURL 或 fopen 没有太大区别,只是它将这些“驱动程序”的详细信息提取到通用 API 中,然后您可以选择要使用的。它还会有一些内置的错误捕获功能,让您更轻松。

      如果您不想要另一个库的开销,那么您显然可以自己编写代码 - 在这种情况下,我总是更喜欢 CURL。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-14
        • 2012-01-15
        • 2019-02-01
        • 2015-07-05
        • 2021-08-08
        • 1970-01-01
        • 2018-10-10
        相关资源
        最近更新 更多