Mou*_*gip 4 php php-stream-wrappers
我目前正在实现一个PHP类,它获取图像文件并在本地缓存它们.这些图像可能来自其他本地来源,通过HTTP或使用Guzzle客户端通过HTTP.使用PHP流包装器,我应该能够以相同的方式处理所有源.
如果没有数据通过流传输,我现在要做的就是实现超时.这应该处理以下情况:
fopen通话时处理,而不是超时.我想我可以做到这一切,stream_set_timeout但我不太清楚这实际上是做什么的.如果流上的任何操作花费的时间超过允许的时间,那么超时是否适用,即我可以做一些需要0.5秒并且超时为0.75秒的事情?或者仅在没有数据通过流传输的时间超过允许时间时才适用?
我尝试使用这个简短的脚本测试行为:
<?php
$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']);
Run Code Online (Sandbox Code Playgroud)
虽然响应时间reqres.in延迟了5秒,但总是会false超时1秒.请有人解释一下吗?
我建议您使用file_get_contents而file_put_contents不是流,它们支持所有包装器,您可以像往常一样将上下文传递给它们fopen.它们通常更容易使用,因为它们返回并接受字符串而不是流.话虽这么说,我不知道你的缓存机制的性质,如果流更适合你的用例,更多的权力给你:)
这里的问题似乎是在阻塞模式下对流包装器的fopen工作方式的误解http(在我尝试之前我还没有完全理解).对于GET(默认值),fopen似乎在调用时执行HTTP请求,而不是在读取流时执行.这可以解释为什么stream_set_timeout不能按预期运行,因为它在fopen调用后修改流上下文.
值得庆幸的是,有一种方法可以在fopen调用之前修改超时,而不是; 你可以fopen用上下文调用.将stream_context_create(从Sammitch链接)返回的上下文传递fopen给所有三种情况的正确超时.作为参考,这是您的脚本的修改方式:
<?php
$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);
Run Code Online (Sandbox Code Playgroud)
注意:我假设您打算将流复制到stdout而不是"out",这不是我平台上的有效流(Darwin).我还在脚本结尾处输入了流,这总是很好的做法.
这将创建一个超时为1的流,从fopen调用时开始.现在来测试你的三个条件.
- 首先无法建立流.这可能应该在fopen调用时处理,而不是超时.
这样可以正常工作 - 如果无法建立连接(服务器脱机等),则fopen呼叫会立即触发警告.只需将脚本指向localhost上的任意端口,即没有任何内容正在侦听.请注意,如果未成功建立连接,则fopen返回false.您必须在代码中检查它,以避免将false用作流.
- 流已建立,但未传输任何数据.
此方案也可以,只需使用普通URL运行脚本即可.这也会使fopen返回错误并触发警告(另一个警告).
- 建立流,传输数据但在传输过程中停止一段时间.
这是一个有趣的案例.要测试这个,你可以编写一个脚本来发送Content-Length一些其他标题以及一些部分数据,然后等到超时,即:
<?php
header('Content-Type: text/plain');
header('Content-Length: 10');
echo "hi";
ob_flush();
sleep(10);
Run Code Online (Sandbox Code Playgroud)
在ob_flush有必要使PHP写的输出(而不关闭连接)在睡觉前和脚本退出.您可以使用php -S localhost:port其他脚本指向此服务localhost:port.在这种情况下,客户端脚本不会发出警告,fopen实际上会将timed_out元数据集中的流返回true.
stream_set_timeout不适用于HTTP GET请求和fopen 阻塞模式,因为fopen在调用请求时执行请求而不是等待读取.您可以通过fopen超时传递上下文来解决此问题.
| 归档时间: |
|
| 查看次数: |
722 次 |
| 最近记录: |