Mar*_*sch 24 php php-stream-wrappers
我真的很想实现一个php_user_filter::filter()
.但是因此我必须知道斗式旅是什么.这似乎是我可以使用这些stream_bucket_*
功能操作的资源.但文档并没有真正的帮助.我能找到的最好的是那些例子stream_filter_register()
.
我特别好奇这些stream_bucket_new()
和stream_bucket_make_writeable()
能做什么.
bwo*_*ebi 35
啊,欢迎使用PHP手册中记录最少的部分![我打开了关于它的错误报告; 也许这个答案将有助于记录它:https://bugs.php.net/bug.php?id = 69966 ]
从您的初始问题开始,bucket brigade只是名为资源的名称userfilter.bucket brigade
.
你作为第一和第二参数通过了两个不同的旅php_user_filter::filter()
.第一旅是你读取的输入桶,第二旅最初是空的; 你写信给它.
关于数据结构的更新......它实际上只是一个带有字符串的双向链表.但很可能这个名字是从那里偷来的;-)
stream_bucket_prepend()
/stream_bucket_append()
stream_bucket_prepend(resource $brigade, stdClass $bucket): null
stream_bucket_append(resource $brigade, stdClass $bucket): null
Run Code Online (Sandbox Code Playgroud)
预期$brigade
的输出旅也是第二个参数php_user_filter::filter()
.
这$bucket
是一个stdClass
像stream_bucket_make_writable()
或由它返回的对象stream_bucket_new()
.
这两个函数只是将传递的存储桶前置或附加到该旅.
stream_bucket_new()
要揭开这个功能的神秘面纱,首先分析它的功能签名是什么:
stream_bucket_new(resource $stream, string $buffer): stdClass
Run Code Online (Sandbox Code Playgroud)
第一个参数是$stream
你正在写这个桶.其次是$buffer
这个新桶将包含.
[我想在这里指出,$stream
参数实际上并不是非常重要; 它只是用来检查我们是否需要持久地分配内存,以便它能够通过请求存活下来.我只是假设在非持久性过滤器上运行时,通过在此处传递持久流可以使PHP很好地进行段错误...]
现在userfilter.bucket
创建了一个资源,该资源被分配给stdClass
名为的()对象的属性bucket
.该对象还有另外两个属性:data
和datalen
,包含缓冲区和此存储区的缓冲区大小.
它将返回给你一个stdClass
你可以传递到stream_bucket_prepend()
和stream_bucket_append()
.
stream_bucket_make_writable()
stream_bucket_make_writeable(resource $brigade): stdClass|null
Run Code Online (Sandbox Code Playgroud)
它将第一个桶从中移出$brigade
并返回它.如果$brigade
被清空,它会返回null
.
当php_user_filter::filter()
被调用时,$stream
对象上的属性filter()
上调用将被设置为我们目前的工作流.这也是stream_bucket_new()
调用它时需要传递的流.(调用后将再次取消该$stream
属性.例如,您不能重复使用它).php_user_filter::onClose()
另请注意,即使您返回了一个$datalen
属性,也不需要设置该属性,以防在将$data
属性传递给stream_bucket_prepend()
或之前更改属性stream_bucket_append()
.
实现需要您(好吧,它希望或将发出警告)您$in
在返回之前读取存储桶中的所有数据.
还有另一个案例告诉我们:in php_user_filter::onCreate()
,$stream
属性没有设置.它只会在filter()
方法调用期间设置.
通常,不要使用具有非阻塞流的过滤器.我尝试了一次,它发生了可怕的错误...... 并且它不太可能会被修复......
让我们从最简单的案例开始:回写我们得到的东西.
class simple_filter extends php_user_filter {
function filter($in, $out, &$consumed, $closing) {
while ($bucket = stream_bucket_make_writeable($in)) {
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
stream_filter_register("simple", "simple_filter")
Run Code Online (Sandbox Code Playgroud)
这里发生的一切都是从$in
斗式旅中获取铲斗并将其放回$out
斗式旅.
好的,现在尝试操纵我们的输入.
class reverse_filter extends php_user_filter {
function filter($in, $out, &$consumed, $closing) {
while ($bucket = stream_bucket_make_writeable($in)) {
$consumed += $bucket->datalen;
$bucket->data = strrev($bucket->data);
stream_bucket_prepend($out, $bucket);
}
return PSFS_PASS_ON;
}
}
stream_filter_register("reverse", "reverse_filter")
Run Code Online (Sandbox Code Playgroud)
现在我们注册了reverse://
协议,它会反转你的字符串(每次写入都在它自己的反转;写入顺序仍然保留).因此,我们现在显然需要操作存储桶数据并在此处添加前置数据.
现在,用例是stream_bucket_new()
什么?通常你可以追加$bucket->data
; 是的,您甚至可以将所有数据连接到第一个存储桶中,但是当flush()
它可能在存储桶旅中没有任何内容并且您想要发送最后一个存储桶时,则需要它.
class append_filter extends php_user_filter {
public $stream;
function filter($in, $out, &$consumed, $closing) {
while ($bucket = stream_bucket_make_writeable($in)) {
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
// always append a terminating \n
if ($closing) {
$bucket = stream_bucket_new($this->stream, "\n");
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
stream_filter_register("append", "append_filter")
Run Code Online (Sandbox Code Playgroud)
有了它(以及关于php_user_filter
类的现有文档),人们应该能够通过将所有这些强大的可能性组合到更强大的代码中来进行各种魔术用户流过滤.