为何php_user_filter::filter()仅执行一次?如何为每行添加'Test,'前缀
解决PHP自定义流过滤器仅处理第一行的问题
我明白你的问题了——你写的自定义流过滤器只在读取的第一行前加上了Test,,后面的行都没生效,对吧?这是因为流过滤器处理的是底层的流数据块(bucket),而不是逐行处理的,你的当前代码只是在整个数据块的开头加了前缀,而不是每行开头。
问题根源
当你用fgets()读取时,PHP的流可能会一次性读取多个行到一个bucket里,你的过滤器只在这个bucket的最前面加了Test,,自然只有第一行受影响。要实现每行都添加前缀,你需要在过滤器内部把bucket中的内容按行拆分,给每行都加上前缀,再重新组合起来。
修改后的过滤器代码
class custom_filter extends php_user_filter { function filter($in, $out, &$consumed, $closing) { while ($bucket = stream_bucket_make_writeable($in)) { // 给每行开头添加Test,,兼容空行和不同换行符的情况 $bucket->data = preg_replace('/^/m', 'Test,', $bucket->data); $consumed += $bucket->datalen; stream_bucket_append($out, $bucket); } return PSFS_PASS_ON; } }
代码解释
这里用了正则表达式的多行模式(/m修饰符),^在多行模式下会匹配每行的开头(包括换行符之后的位置),这样不管bucket里包含多少行,每行的开头都会被替换成Test,,完美解决你的问题。
验证使用
你原来的调用代码不需要改动,直接用即可:
$source = fopen($file, 'rb'); stream_filter_register("custom_filter", "custom_filter"); stream_filter_append($source, "custom_filter", STREAM_FILTER_READ); while (!feof($source)) { $line = fgets($source); // 现在每行都会输出带Test,前缀的内容了 echo $line; } fclose($source);
另外,这个写法也能兼容不同操作系统的换行符(比如Windows的\r\n),多行模式的^会自动识别换行后的起始位置。
内容的提问来源于stack exchange,提问作者Artem Chernov
相关产品推荐
相关产品推荐

