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

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

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

  • Первое использование $e->nodeValue='' для удаления всех дочерних узлов ( это нормально? );
  • Второй сохраняет один (произвольный) 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>: xxxx@aaa.com</p></fn> <p>Nonnnononn onononono nonono nonono </p> </body> </article> и  <?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>: xxxx@aaa.com</p></fn> <p>Nonnnononn onononono nonono nonono </p> </body> </article> и  <?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>: xxxx@aaa.com</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 «Файл не существует», который находится в sucess 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 – это удалить или записать узлы, которые не существуют).

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

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

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