我目前正在实现一个 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']);
尽管 reqres.in 的响应延迟了 5 秒,但我总是得到 false,超时时间为 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 超时对于您的所有三种情况都是正确的。作为引用,这是您的脚本的修改方式:
<?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);
注意:我假设您打算将流复制到 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 调用会立即触发警告。只需将脚本指向本地主机上没有任何监听的任意端口。 请注意,如果连接未成功建立,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 以及一些部分数据,然后等到超时,即:
<?php
header('Content-Type: text/plain');
header('Content-Length: 10');
echo "hi";
ob_flush();
sleep(10);
ob_flush 是使 PHP 在 sleep 和脚本退出之前写入输出(不关闭连接)所必需的。您可以使用 php -S localhost:port 提供此服务,然后将另一个脚本指向 localhost:port。在这种情况下,客户端脚本不会抛出警告,fopen 实际上会返回元数据中的 timed_out 设置为 true 的流。
stream_set_timeout 不适用于 HTTP GET 请求和 fopen 阻塞模式 因为 fopen 执行请求时它被调用而不是等待读取来这样做。您可以通过超时将上下文传递给 fopen 来解决此问题。
关于如果没有数据传输,PHP 流超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49054102/
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
我有一个奇怪的问题:我在rvm上安装了rubyonrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
如果我使用ruby版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更