php没有数据传出,如果没有数据传输,PHP流超时

我目前正在实现一个PHP类,它获取图像文件并在本地缓存它们.这些图像可能来自其他本地来源,通过HTTP或使用Guzzle客户端通过HTTP.使用PHP流包装器,我应该能够以相同的方式处理所有源.

如果没有数据通过流传输,我现在要做的就是实现超时.这应该处理以下情况:

>首先无法建立流.这可能应该在fopen调用时处理,而不是超时.

>已建立流但未传输任何数据.

>流已建立,数据已传输但在传输过程中会停止一段时间.

我想我可以用stream_set_timeout做到这一切,但我不太清楚这实际上是做什么的.如果流上的任何操作花费的时间超过允许的时间,那么超时是否适用,即我可以做一些需要0.5秒并且超时为0.75秒的事情?或者仅在没有数据通过流传输的时间超过允许时间时才适用?

我尝试使用这个简短的脚本测试行为:

$in = fopen('https://reqres.in/api/users?delay=5', 'r');

$out = fopen('out', 'w');

stream_set_timeout($in, 1);

stream_copy_to_stream($in, $out);

var_dump(stream_get_meta_data($in)['timed_out']);

虽然来自reqres.in的响应延迟了5秒,但我总是在1秒的超时时间内得到假.请有人解释一下吗?

解决方法:

我建议您使用file_get_contents和file_put_contents而不是流,它们支持所有包装器,您可以将上下文传递给它们,就像您可以fopen一样.它们通常更容易使用,因为它们返回并接受字符串而不是流.话虽这么说,我不知道你的缓存机制的性质,如果流更适合你的用例,更多的权力给你:)

问题

这里的问题似乎是误解了fopen如何在阻塞模式下使用http流包装器(在我试用之前我还没有完全理解).对于GET(the default),fopen似乎在调用时执行HTTP请求,而不是在读取流时.这可以解释为什么stream_set_timeout不能按预期运行,因为它在调用fopen后修改了流上下文.

解决方案

值得庆幸的是,有一种方法可以在调用fopen之前修改超时,而不是;你可以用上下文调用fopen.将从stream_context_create(作为Sammitch链接)返回的上下文传递给所有三种情况的fopen超时.作为参考,这是您的脚本将被修改的方式:

$ctx = stream_context_create(['http' => [

'timeout' => 1.0,

]]);

$in = fopen('https://reqres.in/api/users?delay=5', 'r', false, $ctx);

$out = STDOUT;

stream_copy_to_stream($in, $out);

var_dump(stream_get_meta_data($in)['timed_out']);

fclose($in);

注意:我假设您打算将流复制到stdout而不是“out”,这不是我平台上的有效流(Darwin).我还在脚本结尾处输入了流,这总是很好的做法.

这将创建一个超时为1的流,从调用fopen时开始.现在来测试你的三个条件.

验证行为

The stream cannot be established in the first place. This should probably be handled at the fopen call and not with a timeout.

这样可以正常工作 – 如果无法建立连接(服务器脱机等),fopen调用会立即触发警告.只需将脚本指向localhost上的任意端口,即没有任何内容正在侦听.请注意,如果未成功建立连接,则fopen返回false.您必须在代码中检查它,以避免将false用作流.

The stream is established but no data is transferred.

此方案也可以,只需使用普通URL运行脚本即可.这也使fopen返回false并触发警告(另一个).

The stream is established, data is transferred but it stops some time during transfer.

这是一个有趣的案例.要测试这个,你可以编写一个脚本,发送Content-Length和其他一些标题以及一些部分数据,然后等到超时,即:

header('Content-Type: text/plain');

header('Content-Length: 10');

echo "hi";

ob_flush();

sleep(10);

ob_flush是使PHP在睡眠和脚本退出之前写入输出(不关闭连接)所必需的.您可以使用php -S localhost:port来提供此服务,然后将其他脚本指向localhost:port.在这种情况下,客户端脚本不会发出警告,并且fopen实际上将元数据集中的timed_out返回为true.

结论

stream_set_timeout不能与HTTP GET请求一起使用,并且在阻塞模式下fopen,因为fopen在调用时执行请求而不是等待读取操作.您可以通过超时将上下文传递给fopen以解决此问题.

标签:php,php-stream-wrappers

来源: https://codeday.me/bug/20190611/1216276.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值