SimpleXMLElementのファイル限界値があったのでPEAR::XMLRPC2を書き換えてみた話
php - How can I handle a huge XML file using SimpleXML but to prevent memory and performance problems? - Stack Overflow
で大きいファイルダメっすよって言われてるのだけど、PEARのXMLRPC2がSimploeXMLElement使ってて、ぐぬぬって思ったので調査
すると、どうも
10000064
で頭打ちみたい。なので、だいたい10,000,000文字、10Mバイト超えたらダメですよってことで。
ところで、DOMDocumentなら100Mくらいは実績値でやってるので行けます。*1
書き換えるかな。・・・ということで、
<?php class Junoe_XMLRPC_Decorder { /** * @brief * @param * @retval */ public function decode($xml) { $r = ""; $dom = new DOMDocument('1.0'); $dom->loadXML($xml, LIBXML_PARSEHUGE); $xpath = new DOMXpath($dom); // fault $result = $xpath->query('/methodResponse/fault'); if ($result->length > 0){ $r = array(); foreach ($xpath->query('//struct/member', $result->item(0)) as $member){ $name = $xpath->query('name', $member)->item(0)->textContent; $value = $xpath->query('value', $member)->item(0)->textContent; $r[$name] = $value; } throw XML_RPC2_FaultException::createFromDecode($r); } else { $v_ele = $xpath->query('/methodResponse/params/param/value/*'); if ($v_ele->length >= 1){ $r = self::getvalue($xpath, $v_ele->item(0)); } } return $r; } /** * @brief * @param * @retval */ private function getvalue($xpath, $ele) { $value = ""; switch (strtolower($ele->tagName)) { case 'array': $value = array(); foreach ($xpath->query('data/value/*', $ele) as $vele){ $value[] = self::getvalue($xpath, $vele); } break; case 'struct': $value = array(); foreach ($xpath->query('member', $ele) as $member){ $name = $xpath->query('name', $member)->item(0)->textContent; $val = self::getvalue($xpath, $xpath->query('value/*', $member)->item(0)); $value[$name] = $val; } break; case 'datetime.iso8601': throw new Exception('not implemented yet.'); break; case 'boolean': $text = $ele->textContent; if (strcasecmp($text, "true") === 0 || strcasecmp($text, "1") === 0){ $value = true; } if (strcasecmp($text, "false") === 0 || strcasecmp($text, "0") === 0){ $value = false; } break; case 'double': $text = $ele->textContent; $value = doubleval($text); break; case 'i4': case 'int': $text = $ele->textContent; $value = intval($text); break; case 'string': $value = $ele->textContent; break; case 'nil': $value = null; break; case 'base64': $value = new stdClass(); $text = $ele->textContent; $value->scalar = base64_decode($text); $value->xmlrpc_type = "base64"; break; } return $value; } }
ってClassを1つ作って、./Backend/Xmlrpcext/Client.php のxmlrpc_decode()が使われているところでフック。
<?php $result = xmlrpc_decode($body, $this->encoding); if (is_null($result)){ $result = Junoe_XMLRPC_Decorder::decode($body); // in case of $body is larger than 10M byte xmlrpc_decode fail. }
*1:ただし、loadXMLの第二引数に LIBXML_PARSEHUGE を付けること。