什么是斗式旅?

Mar*_*sch 24 php php-stream-wrappers

我真的很想实现一个php_user_filter::filter().但是因此我必须知道斗式旅是什么.这似乎是我可以使用这些stream_bucket_*功能操作的资源.但文档并没有真正的帮助.我能找到的最好的是那些例子stream_filter_register().

我特别好奇这些stream_bucket_new()stream_bucket_make_writeable()能做什么.


更新:似乎PHP暴露了Apache内部数据结构.

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是一个stdClassstream_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.该对象还有另外两个属性:datadatalen,包含缓冲区和此存储区的缓冲区大小.

它将返回给你一个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的现有文档),人们应该能够通过将所有这些强大的可能性组合到更强大的代码中来进行各种魔术用户流过滤.

  • 我非常感谢你为这个答案所付出的努力,但对我而言,它仍然无法解释斗式旅的确是什么*以及为什么在处理(过滤)流时需要这种方法.OP关于Apache旅的链接读起来令人信服,但我想知道你是否可以确认**确实是为什么使用这种"桶式旅行"方法的原因. (3认同)
  • @DecentDabbler我想补充一点,内部API看起来很像apache网站上描述的内容.甚至一些功能名称等也非常相似.但是这些函数都只是暴露给扩展,而不是用户PHP.`php_user_filter`非常多是在内部实现之上的内部实现的(_safe_)剽窃.所以,是的,我认为最终可以说它来自阿帕奇旅. (3认同)