【问题标题】:Why this DOM-replaceNode function sometimes crashes?为什么这个 DOM-replaceNode 函数有时会崩溃?
【发布时间】:2014-09-25 03:12:43
【问题描述】:

第一个函数(如下)工作正常,在同一 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();

这里是 $dom 的一些示例 XML,但您可以使用任何 $dom-&gt;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>

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

是的,一次大崩溃,不知道为什么。 (我记得LibXML2中的“标准coredump问题”是删除或写入不存在的节点)。

【问题讨论】:

  • 为什么要使用大于运算符来比较变量和空字符串?
  • 嗯...是的,在 PHP 中 $a!=''$a&gt;'' 是相同的。 PS:有人投反对票,这是解释吗?我编辑了,现在更好了吗?
  • 哦,好吧,不知道。我不是那个投反对票的人。
  • 我敢打赌 Apache 日志中没有消息?
  • @rr- 我编辑了...没有好的日志...

标签: php domdocument


【解决方案1】:

虽然我没有发现代码有什么奇怪的地方(在我的机器上用几个 XML 对其进行了测试,但没有发现任何问题),但我怀疑某些东西以某种方式使用它,导致无限递归。

众所周知,进入太深递归的函数会导致 PHP 出现SEGFAULTs。 [1, 2] 要么是那个,要么是一个严重的 PHP/libxml2 错误。

也许问题出在其他地方?

【讨论】:

  • 查看注释/edit2:PHP 代码中没有无限递归(也许 libxml2 丢失了一些指针并执行了循环...?)。
  • 好的,我的答案的哪一部分需要反对?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-26
  • 2022-01-13
  • 2020-10-30
  • 2017-04-01
相关资源
最近更新 更多