【问题标题】:Catch 404 error on DOMDocument->load()在 DOMDocument->load() 上捕获 404 错误
【发布时间】:2012-05-10 20:49:33
【问题描述】:

我正在使用 DOM 加载一堆 rss 提要,有时会出现 404 而不是生成文件。问题是网络服务器发送了一个 html 404 页面来代替预期的 xml 文件,因此使用以下代码:

$rssDom = new DOMDocument();
$rssDom->load($url);
$channel = $rssDom->getElementsByTagName('channel');
$channel = $channel->item(0);
$items = $channel->getElementsByTagName('item');

我收到此警告:

Warning: DOMDocument::load() [domdocument.load]: Entity 'nbsp' not defined

随后出现此错误:

Fatal error: Call to a member function getElementsByTagName() on a non-object

通常,此代码可以正常工作,但在我收到 404 的情况下,它无法执行任何操作。我在 load 语句周围尝试了一个标准的 try-catch,但它似乎没有捕捉到它。

【问题讨论】:

  • 如果“实体 nbsp; 未定义”,也许 404 返回了 XML(不是 HTML)源? (  未在 XML 中定义。)

标签: php xml dom rss


【解决方案1】:

您可以suppress the output of parsing errors

libxml_use_internal_errors(true);

要检查返回的响应是否为 404,您可以在调用 DOMDocument::load() 后检查 $http_response_header

例子:

libxml_use_internal_errors(true);
$rssDom = new DOMDocument();
$rssDom->load($url);
if (strpos($http_response_header[0], '404')) {
    die('file not found. exiting.');
}

替代方法是使用file_get_contents,然后检查响应标头,如果不是404,则使用DOMDocument::loadXml 加载标记。这将阻止 DOMDocument 解析无效的 XML。

请注意,所有这些都假定服务器在响应中正确返回了 404 标头。

【讨论】:

  • +1,虽然我认为我更喜欢它,因为我根本不知道 $http_response_headers。 PHP,你能走多低?
  • @Jon 是的,我更喜欢get_last_response_headers() 之类的函数,而不是$http_response_headers 在http 调用后神奇地填充。这太不明显了。
  • 错字? $http_response_headers 未定义,而 $http_response_header 已定义。文档页面 $http_response_header 也链接到单数 header
【解决方案2】:

使用file_get_contentscurl 手动加载HTML(允许您自己进行错误检查),如果一切顺利,则将结果提供给DOMDocument::loadHTML

这里有很多curl 的例子(例如,看看this one,虽然它肯定不是最好的);要获取 HTTP 状态代码,您将使用 curl_getinfo

【讨论】:

【解决方案3】:

为避免警告,您可以使用LIBXML_NOWARNING(注意:通常禁止显示警告并不是一件好事)。

这里更重要的问题是致命错误:为避免这种情况,您应该检查文档是否已正确加载。为此,只需保存load()s return-value 并使用它:

$loaded = $rssDom->load($url, LIBXML_NOWARNING);
if($loaded){
    $channel = $rssDom->getElementsByTagName('channel');
    $channel = $channel->item(0);
    $items = $channel->getElementsByTagName('item');
}else{
    // show error-message or something like that
}

【讨论】:

  • 问题是load认为成功了,所以不会一直为假。
【解决方案4】:

像这样:

$rssDom = new DOMDocument();
if($rssDom->load($url)) {
   $channel = $rssDom->getElementsByTagName('channel');
   $channel = $channel->item(0);
   $items = $channel->getElementsByTagName('item');
}

【讨论】:

  • 我上面说了,问题是load认为成功了,所以不会一直为假。
【解决方案5】:

如果有人需要解决方案,这就像魅力一样:

$objDOM = new DOMDocument();
$loaded=@$objDOM->load(url);

if (!$loaded){
    //something went terribly wrong
} else {
    //this is going ok!!
}

当我们通过 '@' 抑制警告并在发生错误时加载返回 true 或 false 时,这会起作用。

【讨论】:

    猜你喜欢
    • 2013-02-18
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 2013-12-04
    • 2010-11-21
    • 2018-01-16
    • 2017-04-17
    相关资源
    最近更新 更多