Question

The following PHP "failed to load external entity", even though it is trying to load a local XML file:

<?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";
?>

The basic question is how can this be fixed?

Log file:

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"

Uncommenting the libxml_disable_entity_loader line works, but this is not an acceptable solution for a few reasons, e.g. it is systemwide for php-fpm.

Running the PHP from shell returns "status = success". Doing a file_get_contents and then $dom->loadXML($string) also works (i.e. file exists and not a permissions issue). This might be an acceptable workaround, but shouldn't be necessary and doesn't explain why the error is occurring.

The XML file itself is the Horde config, but the problem does not seem to be the contents of the file, since it also occurs with this XML content:

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

Environment is php and php-fpm 5.3.3, nginx 1.4.6, libxml2 2.7.6. My first guess is something to do with php-fpm, but I can't find any config setting that affects this. Any pearls of wisdom appreciated!

EDIT TO ADD

Restarting php-fpm causes it to work briefly. Disabling APC did not seem to help. Seems like something with php-fpm - but what?

FURTHER TESTING

Some additional info:

  1. I tried hitting the server repeatedly, and get an error about 80% of the time. The pattern isn't random - a few seconds of successes followed by a series of errors;
  2. I added a phpinfo() to the end of the above php and doing a diff on the success and failure runs - there is no difference;
  3. If I put libxml_disable_entity_loader(true), I seem to always get an error, which suggests that bug #64938 is at work.

It seems that I need to find why the XML is considered to have external entities.

Was it helpful?

Solution

I think that, if the external entity loader is disabled, it should be obvious that external entities can't be loaded. The only solution is to enable loading of external entities with libxml_disable_entity_loader(false). Since this setting is not thread-safe, I can see two approaches:

  • Enable it globally and use some other feature to prevent loading of unwanted entities (typically from a network):
    • Register your own entity loader with libxml_set_external_entity_loader. I think that's the safest solution.
    • Use the parse option LIBXML_NONET. This should be enough if you simply want to disable network access of libxml2. But you have to make sure to always pass it to calls like DOMDocument::load.
  • Use locks to protect calls to libxml_disable_entity_loader. This is probably impractical and potentially unsafe.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top