Ошибки simplexml_load_string в больших файлах возникают в одной системе, но не в другой
Я имею дело со сторонней библиотекой PHP, которую я не могу редактировать, и она работает нормально почти год. Оно использует simplexml_load_string
на ответ с удаленного сервера. В последнее время он задыхался от больших откликов. Это фид данных для списков недвижимости, и формат выглядит примерно так:
<?xml version="1.0"?>
<RETS ReplyCode="0" ReplyText="Operation Successful Reference ID: 9bac803e-b507-49b7-ac7c-d8e8e3f3aa89">
<COUNT Records="9506" />
<DELIMITER value="09" />
<COLUMNS> sysid 1 2 3 4 5 6 </COLUMNS>
<DATA> 252370080 Residential 0.160 No ADDR0 06051</DATA>
<DATA> 252370081 Residential 0.440 Yes ADDR0 06043</DATA>
<DATA> 252370082 Residential 1.010 No ADDR0 06023</DATA>
<DATA>More tab delimited text</DATA>
<!-- snip 9000+ lines -->
</RETS>
Я скачал образец файла ответа (около 22 МБ), и здесь я закончил с отладкой и здравомыслием. Оба сервера работают под управлением PHP версии 5.3.8, но обратите внимание на разные результаты. Я уверен в том, что оба файла одинаковы (я полагаю, что разные размеры файлов, strlen и последние 50 символов могут быть объяснены символами перевода строки Windows, имеющими дополнительный символ возврата каретки). Тестовый скрипт:
error_reporting(-1);
ini_set('display_errors', 1);
$file = 'error-example.xml';
$xml = file_get_contents($file);
echo 'filesize: ';
var_dump(filesize($file));
echo 'strlen: ';
var_dump(strlen($xml));
echo 'simplexml object? ';
var_dump(is_object(simplexml_load_string($xml)));
echo 'Last 50 characters: ';
var_dump(substr($xml, -50));
Вывод локально в Windows:
filesize: int(21893604)
strlen: int(21893604)
simplexml object? bool(true)
Last 50 characters: string(50) "RD DR CT Watertown 203-555-5555 </DATA>
</RETS>"
Вывод на удаленный сервер UNIX:
filesize: int(21884093)
strlen: int(21884093)
simplexml object?
Warning: simplexml_load_string(): Entity: line 9511: parser error : internal error in /path/to/test.php on line 19
Warning: simplexml_load_string(): AULTED CEILING IN FOYER, BRICK FP IN FR, NEW FLOORING IN LR DR FR FOYER KITCHEN in /path/to/test.php on line 19
Warning: simplexml_load_string(): ^ in /path/to/test.php on line 19
Warning: simplexml_load_string(): Entity: line 9511: parser error : Extra content at the end of the document in /path/to/test.php on line 19
Warning: simplexml_load_string(): AULTED CEILING IN FOYER, BRICK FP IN FR, NEW FLOORING IN LR DR FR FOYER KITCHEN in /path/to/test.php on line 19
Warning: simplexml_load_string(): ^ in /path/to/test.php on line 19
bool(false)
Last 50 characters: string(50) "ORD DR CT Watertown 203-555-5555 </DATA>
</RETS>"
Некоторые ответы на комментарии и дополнительную информацию:
Насколько я могу судить, сам XML кажется верным (и он работает в моей системе).
magic_quotes_runtime
определенно выключен.Работающий сервер имеет версию 2.7.7 libxml, а другой - 2.7.6. Может ли это действительно иметь значение? Я не смог найти журнал изменений libxml, но это кажется маловероятным.
Похоже, что это происходит только тогда, когда размер ответа / файла превышает определенный размер, и ошибка всегда возникает в следующей за последней строке.
У меня нет проблем с памятью, тестовый скрипт запускается мгновенно.
Существуют различия в конфигурациях PHP, которые я могу опубликовать, если буду знать, какие из них актуальны. Любая идея, в чем может быть проблема, или знаете что-нибудь еще, что я хотел бы проверить?
3 ответа
Изменения в libxml2 содержат "608773 добавить отсутствующую проверку в xmlGROW (Daniel Veillard)", что, похоже, связано с буферизацией ввода. Заметьте, я ничего не знаю о внутренностях libxml2, но вполне возможно, что вы исправили ошибку 2.7.6, исправленную в 2.7.7.
Проверьте, отличается ли поведение при использовании simplexml_load_file()
напрямую, и попробуйте установить параметры, связанные с синтаксическим анализатором libxml, например
simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_COMPACT | LIBXML_PARSEHUGE)
В частности, вы можете попробовать LIBXML_PARSEHUGE
флаг.
http://php.net/manual/en/libxml.constants.php
XML_PARSE_HUGE
флаг ослабляет любой жестко заданный лимит парсера. Это влияет на ограничения, такие как максимальная глубина документа или рекурсия объекта, а также на ограничения размера текстовых узлов.
Ваш XML неверен и должен вызывать проблемы в обоих случаях.
Вы должны иметь только одну корень.
то есть. Все должно быть внутри ваших тегов:
<?xml version="1.0"?>
<RETS>
...
</RETS>
У вас есть несколько корней в вашем XML, что вызовет проблему:-)
Попробуйте обернуть все это в корневой узел и посмотреть, работает ли он.
<?xml version="1.0"?>
<rootNode>
<RETS>
...
</RETS>
<count bla="99" />
</rootNode>
Я не уверен, будет ли это разница в libxml или другой уровень отчетов об ошибках, позволяющий работать на одном, а не на другом, но мне это кажется проблемой.
Мой XMLSpy подтвердил, что ваш XML-файл (который я скачал по предоставленной вами ссылке) не имеет проблем и правильно сформирован.
Однако одной потенциальной проблемой является тот факт, что атрибут "кодировка" отсутствует в преамбуле XML: в зависимости от вашей версии libxml2, я предполагаю, что возможен следующий сценарий: Сервер проверяет наличие атрибута кодировки, при отсутствии которого сервер возвращается к какое-то значение по умолчанию (настройка конфигурации). Возможно, более старые версии библиотеки не проверяют спецификацию.
Также просмотрите эту ссылку, у них была похожая проблема с кодировкой libxml: /questions/31879114/utf-8-problemyi-s-php-dom-na-servere-debian
суть в том, что обновление вашей библиотеки libxml может действительно решить проблему. В качестве альтернативы, возможно, стоит проверить настройку кодировки по умолчанию в конфигурации.
Согласно моему XMLSpy, файл имеет кодировку utf-8 - в качестве теста, возможно, стоит проверить, если указать
<?xml version="1.0" encoding="UTF-8"?>
поскольку преамбула файла останавливает ваш сервер Unix от удушья.