Почему эта функция DOM-replaceNode иногда дает сбой?

Первая функция (ниже) работает нормально, в цикле по множеству одинаковых узлов DOMDocumentНо иногда вылетает (нет сообщения об ошибке, но остановка сервера).

Когда мы используем второй (replace_innerXML_secure), в том же цикле узла, он никогда не падает. Зачем? Что не так с первым?

  • Первое использование $e->nodeValue='' удалить все ChildNodes (это нормально?);
  • Второй сохраняет один (произвольный) childNode и использовать RemoveChild удалить … Необычный обходной путь, чтобы избежать полного удаления, когда там был какой-то тег.

«Эквивалентные» функции № 1 и № 2:

// 1. What is wrong with THIS function??
function replace_innerXML(DOMNode $e,$innerXML='') {
if ($e && ($innerXML>'' || $e->nodeValue>'')) {
$e->nodeValue='';
if ($innerXML>'') {
$tmp = $this->dom->createDocumentFragment();
$tmp->appendXML($innerXML);
$e->appendChild( $tmp );
}
return true;
}
return false;
}

// 2. Here a workaround... slower but... NOT crashes (!), WHY??
function replace_innerXML_secure(DOMNode $e,$innerXML='') {
if ($e) {
$tmp = $e->ownerDocument->createDocumentFragment();
$tmp->appendXML($innerXML);
$once=null;
foreach(iterator_to_array($e->childNodes) as $e2)
if (!$once && $e2->nodeType===1) $once=$e2;
else $e->removeChild($e2);
if ($once)
$once->parentNode->replaceChild( $tmp, $once );
else {
$e->nodeValue='';
$e->appendChild( $tmp );
}
return true;
}
return false;
}

EDIT2 для запроса @Prix, некоторые примеры.

Цикл очень сложный, но его можно смоделировать как

   // use this with ANY (and a lot of) BIG HTML files from web...
// I have ~1 error/100 samples
$dom = new DOMDocument();
$dom->load($file); // any XML, or loadHTMLfile()

$plst = array();  // you can take off the rand()
foreach ($dom->getElementsByTagName('*') as $node) if (1 || rand(1,3)==1) {
$plst[] = $node->getNodePath();
}
rsort($plst); // from leaves to root
foreach ($plst as $p) {
$xp = new DOMXpath($dom); // refresh for each $p
$node = $xp->query($p);
if ($node->length && $node=$node->item(0))
// USING HERE the function#1 or #2:
replace_innerXML($node,'<new x="1">text</new>');
}
$dom->normalizeDocument();

Вот пример XML для $ dom, но вы можете использовать любой $dom->loadHTML($file) тестировать (!).

  <?xml version="1.0" encoding="utf-8"?>

<article dtd-version="3.0" article-type="research-article" xml:lang="en">
<front><journal-meta>
<journal-title-group><journal-title>text text text</journal-title>
<abbrev-journal-title abbrev-type="acronym">aaaa</abbrev-journal-title>
<abbrev-journal-title abbrev-type="publisher">aaabbb aaa</abbrev-journal-title>
</journal-title-group>
<etc>....</etc>
<history><date date-type="received"><label>Received</label> 9 July 2014</date>
<date date-type="accepted"><label>Accepted</label> 25 July 2014</date>
</history>
</journal-meta></front>
<body>
<p>Nonnnononn onononono  nonono</p>
<fn><p><label>XXXXX yyyyy</label>: [email protected]</p></fn>

<p>Nonnnononn onononono  nonono nonono </p>
</body>
</article>

EDIT1 для версий и логов

Версии:

  • libxml2: 2.8.0 + dfsg1-7 + wheezy1
  • php5: 5.4.4-14 + deb7u14
  • apache2: 2.2.22-13 + deb7u3

Журналы: где? Я знаю только /var/log/apache2/error.log, но ошибки нет (только обычный png «Файл не существует», который находится в успешном http).

… на этом компьютере, работающем сегодня снова, после сбоя http, не сообщалось ни о какой большой ошибке, только «Файл не существует: /var/www/favicon.ico» до сбоя … Но я был работает также на машине с Ubuntu, где я нахожу (!) отчет о дате и моменте аварии:

 [Wed Oct 15 20:16:16.840578 2014] [core:notice] [pid 1770] AH00051: child pid 14873 exit signal Segmentation fault (11), possible coredump in /etc/apache2
[Wed Oct 15 20:16:16.840684 2014] [core:notice] [pid 1770] AH00051: child pid 14879 exit signal Segmentation fault (11), possible coredump in /etc/apache2
*** Error in `/usr/sbin/apache2': corrupted double-linked list: 0x00007f457b81af70 ***
[Wed Oct 15 20:16:56.886473 2014] [core:notice] [pid 1770] AH00051: child pid 14844 exit signal Aborted (6), possible coredump in /etc/apache2
[Wed Oct 15 20:16:57.887638 2014] [core:notice] [pid 1770] AH00051: child pid 14894 exit signal Segmentation fault (11), possible coredump in /etc/apache2

да, большая авария, понятия не имею, почему. (Я помню, что «стандартная проблема coredump» в LibXML2 удалить или записать узлы, которые не существуют).

1

Решение

Хотя я не нашел ничего странного в коде (проверил его на моей машине с несколькими XML-файлами и не обнаружил проблем), я подозреваю, что что-то использует его таким образом, что приводит к бесконечной рекурсии.

Функции, которые вводят слишком глубокую рекурсию, известны тем, что заставляют PHP SEGFAULTs. [1, 2] Либо это, либо серьезная ошибка PHP / libxml2.

Возможно, проблема кроется в другом месте?

-1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]