我正在处理使用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,因此我预计会看到一些差异。