1

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

4

0 回答 0