DOMDocument->使用PHP-FPM为本地文件加载外部实体失败

时间:2014-03-11 01:38:46

标签: nginx libxml2 php

以下PHP“无法加载外部实体”,即使它正在尝试加载本地XML文件:

<?php
  $path = "/usr/share/pear/www/horde/config";
  #libxml_disable_entity_loader(false);
  $dom = new DOMDocument();
  $v = $dom->load($path . '/conf.xml');
  echo "status = ".($v?'success':'error')."\n";
?>

基本问题是如何解决这个问题?

日志文件:

2014/03/10 20:07:10 [error] 26117#0: *24 FastCGI sent in stderr: "PHP message: PHP Warning:  DOMDocument::load(): I/O warning : failed to load external entity "/usr/share/pear/www/horde/config/conf.xml" in /usr/share/nginx/html/test.php on line 5
PHP message: PHP Stack trace:
PHP message: PHP   1. {main}() /usr/share/nginx/html/test.php:0
PHP message: PHP   2. DOMDocument->load() /usr/share/nginx/html/test.php:5" while reading response header from upstream, client: x.x.x.x, server: example.com, request: "GET /test.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php5-fpm.sock:", host: "example.com"

取消对libxml_disable_entity_loader行的注释,但由于某些原因,这不是一个可接受的解决方案,例如它是php-fpm的系统范围。

从shell运行PHP会返回“status = success”。执行file_get_contents然后$dom->loadXML($string)也可以(即文件存在而不是权限问题)。这可能是一种可接受的解决方法,但不一定是必要的,也不能解释错误发生的原因。

XML文件本身是Horde config,但问题似乎不是文件的内容,因为它也出现在这个XML内容中:

<?xml version="1.0"?>
<configuration></configuration>

环境是php和php-fpm 5.3.3,nginx 1.4.6,libxml2 2.7.6。我的第一个猜测是与php-fpm有关,但我找不到任何影响它的配置设置。任何智慧珍珠都会受到赞赏!

编辑添加

重新启动php-fpm会使其短暂工作。禁用APC似乎没有帮助。看起来像php-fpm的东西 - 但是什么?

进一步测试

其他一些信息:

  1. 我尝试重复点击服务器,并在80%的时间内收到错误。模式不是随机的 - 几秒钟的成功,然后是一系列错误;
  2. 我在上面的php的末尾添加了phpinfo()并在成功和失败运行中执行了diff - 没有区别;
  3. 如果我放libxml_disable_entity_loader(true),我似乎总是收到错误,这表明bug #64938正在发挥作用。
  4. 似乎我需要找到为什么 XML被认为有外部实体。

1 个答案:

答案 0 :(得分:0)

我认为,如果外部实体加载器被禁用,那么显而易见external entities can't be loaded。唯一的解决方案是使用libxml_disable_entity_loader(false)启用外部实体的加载。由于此设置不是线程安全的,我可以看到两种方法:

  • 全局启用它并使用其他功能来阻止加载不需要的实体(通常来自网络):
    • 使用libxml_set_external_entity_loader注册您自己的实体加载器。我认为这是最安全的解决方案。
    • 使用解析选项LIBXML_NONET。如果您只想禁用libxml2的网络访问,这应该足够了。但您必须确保始终将其传递给DOMDocument::load
    • 等调用
  • 使用锁定来保护对libxml_disable_entity_loader的通话。这可能是不切实际的,也可能是不安全的。