我正在使用 PHP zip 流处理直接从 zip 存档中读取的 XML 文件。有时,这些文件包含与我无关的大型 CDATA 块,但会使 SimpleXml 处理耗尽内存。
我认为在将数据传递给之前实现一个流过滤器来删除这些块simple_xml_load_string
可以解决问题。但是 PHP 在有和没有过滤器的情况下使用完全相同的内存量。
我的流过滤器如下所示:
class JunkContentsNodesStreamFilter extends \php_user_filter
{
const START_MARKER = '<Contents><!\\[CDATA\\[';
const END_MARKER = '\\]\\]></Contents>';
private $skipping = false;
public function filter($in, $out, &$consumed, $closing)
{
while ($bucket = stream_bucket_make_writeable($in)) {
// Always consume all input.
$consumed = $bucket->datalen;
// Entire match in the same bucket. Just remove it.
$bucket->data = preg_replace('^' . self::START_MARKER . '.*?' . self::END_MARKER . '^ms', '', $bucket->data);
if ($this->skipping) {
$pos = strpos($bucket->data, self::END_MARKER);
if ($pos === false) {
// Skip entire block
$bucket->data = '';
} else {
// Found an end marker. Remove and stop skipping
$bucket->data = substr($bucket->data, $pos + strlen(self::END_MARKER));
$this->skipping = false;
}
} else {
$pos = strpos($bucket->data, self::START_MARKER);
if ($pos !== false) {
// Found a start marker. Remove and start skipping
$bucket->data = substr($bucket->data, 0, $pos);
$this->skipping = true;
}
}
$bucket->datalen = strlen($bucket->data);
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
我像这样使用它:
stream_filter_register('junk_contents_nodes', 'JunkContentsNodesStreamFilter');
$data = file_get_contents('php://filter/read=junk_contents_nodes/resource=zip://pathtozip.zip#fileinzip.xml');
它确实返回了剥离的内容,但内存使用量根本没有下降。原始数据约为 50 Mb,剥离后的数据约为 150 Kb,因此我预计会看到一些差异。