如何实现PHP流包装器来修改另一个包装器的输出



我使用PHPzip://流包装器逐行解析大型XML文件。例如:

$stream_uri = 'zip://' . __DIR__ . '/archive.zip#foo.xml';
$reader     = new XMLReader();
$reader->open( $stream_uri, null );
$reader->read();
while ( true ) {
echo( $reader->readInnerXml() . PHP_EOL );
if ( ! $reader->next() ) {
break;
}
}

XML文件通常会包含XMLReader不喜欢的不可靠的UTF控制字符。因此,我想实现一个自定义流包装器,我可以将zip://流的输出传递给它,它将在每行上运行一个preg_replace来删除这些字符。

我的梦想是能够做到这一点:

stream_wrapper_register( 'xmlchars', 'XML_Chars' );
$stream_uri = 'xmlchars://zip://' . __DIR__ . '/archive.zip#foo.xml';

并让CCD_ 5愉快地读取整理后的节点。我已经找到了一种基于传递给我的包装器的路径来重构zip流URI的方法:

class XML_Chars {
protected $stream_uri = '';
protected $handle;
function stream_open( $path, $mode, $options, &$opened_path ) {
$parsed_url     = parse_url( $path );
$this->stream_uri = 'zip:' . $parsed_url['path'] . '#' . $parsed_url['fragment'];
return true;
}
}

但我对打开zip://流的最佳方式感到困惑,这样我就可以修改其输出并将结果传递给XMLReader。有人能给我一些关于如何实现这一点的建议吗?

如果对其他人有用,我找到了一种不同的方法来解决这个问题:流过滤器。你这样定义它:

class UTF_Character_Filter extends php_user_filter {
public function filter( $in, $out, &$consumed, $closing ) {
while ( $bucket = stream_bucket_make_writeable( $in ) ) {
$consumed += $bucket->datalen;
// Remove characters in the hex range 0 - 8, B and C, E to 1F
// i.e. all control characters except newline, tab and return
$bucket->data = preg_replace( '|[x0-x8xB-xCxE-x1F]|ms', '', $bucket->data );
stream_bucket_append( $out, $bucket );
}
return PSFS_PASS_ON;
}
}
stream_filter_register( 'utf_character_filter', 'UTF_Character_Filter' );

并像这样使用:

php://filter/read=utf_character_filter/resource=zip://archive.zip#import.xml

我仍然很想知道是否有人知道如何制作一个可以接受另一个流包装器输入的流包装器,因为它可能是一个方便的工具。

最新更新