介绍/免责声明
其中相当一部分是可以在很大程度上被忽略的输出。它仍然是一个读者,但我试图在我的分析和提问中做到彻底。如果你熟悉stream_get_meta_data
,你可以跳到最后的“问题”。
除了在文档中,我很难找到很多关于 PHP 的stream_get_meta_data
. 整体功能与 PHP 的功能并没有太大的不同get_headers
,但我终其一生都找不到两者之间的任何比较,或者前者的优缺点。
设置
到目前为止,我一直使用 PHPget_headers
来验证 URL 的有效性。缺点get_headers
是速度慢是出了名的。可以理解,大部分延迟直接归因于托管感兴趣站点的服务器,但可能该方法过于稳健,或者其他原因使其变慢。
有很多链接建议使用CURL
,声称它更快,但我已经同时运行了两者的定时测试,并且get_headers
总是名列前茅,通常是 1.5 或 2 倍。
我还没有看到任何使用 的解决方案stream_get_meta_data
,今天才第一次偶然发现它。我已经用尽了我的 Google 技能,但运气不佳。但是,为了优化我的方案,我进行了一些测试。
测试
使用 106 个当前(即 live、valid、status=200)URL 的列表运行get_headers
和之间的比较:stream_get_meta_data
Code Block #1
// All URLs in format "http://www.domain.com"
$urls = array('...', '...', '...'); // *106 URLs
// get_headers
$start = microtime(true);
foreach($urls as $url) {
try{
// Unfortunately, get_headers does not offer a context argument
stream_context_set_default(array('http' => array('method' => "HEAD")));
$headers[] = @get_headers($url, 1);
stream_context_set_default(array('http' => array('method' => "GET")));
}catch(Exception $e){
continue;
}
}
$end1 = microtime(true) - $start;
// stream_get_meta_data
$cont = stream_context_create(array('http' => array('method' => "HEAD")));
$start = microtime(true);
foreach($urls as $url) {
try{
$fp = fopen($url, 'rb', false, $cont);
if(!$fp) {
continue;
}
$streams[] = stream_get_meta_data($fp);
}catch(Exception $e){
continue;
}
}
$end2 = microtime(true) - $start;
而且我得到的结果在90% 或更多的情况下stream_get_meta_data
都名列前茅。有时时间几乎相同,但通常运行时间更短stream_get_meta_data
Run Times #1
"get_headers": 112.23 // seconds
"stream_get": 42.61 // seconds
两者的 [stringified] 输出类似于:
Excerpt of Comparison #1
url .. "http://www.wired.com/"
get_headers
| 0 ............................ "HTTP/1.1 200 OK"
| Access-Control-Allow-Origin .. "*"
| Cache-Control ................ "stale-while-revalidate=86400, stale-while-error=86400"
| Content-Type ................. "text/html; charset=UTF-8"
| Link ......................... "; rel=\"https://api.w.org/\""
| Server ....................... "Apache"
| Via
| | "1.1 varnish"
| | "1.1 varnish"
|
| Fastly-Debug-State ........... "HIT"
| Fastly-Debug-Digest .......... "c245efbf14778c681ce317da114c1a762199e1326323d07b531d765e97fc8695"
| Content-Length ............... "135495"
| Accept-Ranges ................ "bytes"
| Date ......................... "Tue, 23 Aug 2016 22:32:26 GMT"
| Age .......................... "701"
| Connection ................... "close"
| X-Served-By .................. "cache-jfk8149-JFK, cache-den6024-DEN"
| X-Cache ...................... "HIT, HIT"
| X-Cache-Hits ................. "51, 1"
| X-Timer ...................... "S1471991546.459931,VS0,VE0"
| Vary ......................... "Accept-Encoding"
stream_get
| wrapper_data
| | "HTTP/1.1 200 OK"
| | "Access-Control-Allow-Origin: *"
| | "Cache-Control: stale-while-revalidate=86400, stale-while-error=86400"
| | "Content-Type: text/html; charset=UTF-8"
| | "Link: ; rel=\"https://api.w.org/\""
| | "Server: Apache"
| | "Via: 1.1 varnish"
| | "Fastly-Debug-State: HIT"
| | "Fastly-Debug-Digest: c245efbf14778c681ce317da114c1a762199e1326323d07b531d765e97fc8695"
| | "Content-Length: 135495"
| | "Accept-Ranges: bytes"
| | "Date: Tue, 23 Aug 2016 22:32:26 GMT"
| | "Via: 1.1 varnish"
| | "Age: 701"
| | "Connection: close"
| | "X-Served-By: cache-jfk8149-JFK, cache-den6020-DEN"
| | "X-Cache: HIT, HIT"
| | "X-Cache-Hits: 51, 1"
| | "X-Timer: S1471991546.614958,VS0,VE0"
| | "Vary: Accept-Encoding"
|
| wrapper_type ................. "http"
| stream_type .................. "tcp_socket/ssl"
| mode ......................... "rb"
| unread_bytes ................. 0
| seekable ..................... false
| uri .......................... "http://www.wired.com/"
| timed_out .................... false
| blocked ...................... true
| eof .......................... false
在大多数情况下,所有相同的数据,除了stream_get_meta_data
不提供任何包含键的方法之外wrapper_data
,无需手动解析。
够简单...
Code Block #2.1/2.2
$wd = $meta[$url]['wrapper_data'];
$wArr = wrapperToKeys($wd);
在哪里...
function wrapperToKeys($wd) {
$wArr = array();
foreach($wd as $row) {
$pos = strpos($row, ': '); // *Assuming* that all separated by ": " (Might be colon, without the space?)
if($pos === false) {
$wArr[] = $row;
}else {
// $pos, $key and $value can probably be done with one good preg_match
$key = substr($row, 0, $pos);
$value = substr($row, ($pos + 2));
// If key doesn't exist, assign value
if(empty($wArr[$key])) {
$wArr[$key] = $value;
}
// If key already points to an array, add value to array
else if(is_array($wArr[$key])) {
$wArr[$key][] = $value;
}
// If key currently points to string, swap value into an array
else {
$wArr[$key] = array($wArr[$key], $value);
}
}
}
return $wArr;
}
并且输出与以下内容相同get_headers($url, 1)
:
Excerpt of Comparison #2
url .. "http://www.wired.com/"
headers
| 0 ............................ "HTTP/1.1 200 OK"
| Access-Control-Allow-Origin .. "*"
| Cache-Control ................ "stale-while-revalidate=86400, stale-while-error=86400"
| Content-Type ................. "text/html; charset=UTF-8"
| Link ......................... "; rel=\"https://api.w.org/\""
| Server ....................... "Apache"
| Via
| | "1.1 varnish"
| | "1.1 varnish"
|
| Fastly-Debug-State ........... "HIT"
| Fastly-Debug-Digest .......... "c245efbf14778c681ce317da114c1a762199e1326323d07b531d765e97fc8695"
| Content-Length ............... "135495"
| Accept-Ranges ................ "bytes"
| Date ......................... "Tue, 23 Aug 2016 22:35:29 GMT"
| Age .......................... "883"
| Connection ................... "close"
| X-Served-By .................. "cache-jfk8149-JFK, cache-den6027-DEN"
| X-Cache ...................... "HIT, HIT"
| X-Cache-Hits ................. "51, 1"
| X-Timer ...................... "S1471991729.021214,VS0,VE0"
| Vary ......................... "Accept-Encoding"
w-arr
| 0 ............................ "HTTP/1.1 200 OK"
| Access-Control-Allow-Origin .. "*"
| Cache-Control ................ "stale-while-revalidate=86400, stale-while-error=86400"
| Content-Type ................. "text/html; charset=UTF-8"
| Link ......................... "; rel=\"https://api.w.org/\""
| Server ....................... "Apache"
| Via
| | "1.1 varnish"
| | "1.1 varnish"
|
| Fastly-Debug-State ........... "HIT"
| Fastly-Debug-Digest .......... "c245efbf14778c681ce317da114c1a762199e1326323d07b531d765e97fc8695"
| Content-Length ............... "135495"
| Accept-Ranges ................ "bytes"
| Date ......................... "Tue, 23 Aug 2016 22:35:29 GMT"
| Age .......................... "884"
| Connection ................... "close"
| X-Served-By .................. "cache-jfk8149-JFK, cache-den6021-DEN"
| X-Cache ...................... "HIT, HIT"
| X-Cache-Hits ................. "51, 1"
| X-Timer ...................... "S1471991729.173641,VS0,VE0"
| Vary ......................... "Accept-Encoding"
即使整理出钥匙,stream_get_meta_data
也是冠军:
Sample Run Times #2
"get_headers": 99.51 // seconds
"stream_get": 43.79 // seconds
注意:这些测试在廉价的共享服务器上运行 - 因此测试时间差异很大。话虽如此,两种方法之间的差距在测试之间是高度一致的。
额外的
对于那些了解 PHP 的 c 代码并觉得他们可以从中获得一些见解的人,可以在以下位置找到函数定义:
和
'stream_get_meta_data' (PHP Git)
问题
stream_get_meta_data
与 相比,为什么代表性不足(在搜索和可用代码片段中)get_headers
?我的措辞导致了意见,但我的意图更接近于:“是否有一些如此知名和可怕的东西
stream_get_meta_data
会阻止人们使用它?”与前面类似,两者之间是否存在众所周知的、业界公认的优缺点?对 CS 有更全面的理解会暗示的事情。也许
get_headers
更安全/更健壮,更不容易受到 ne'erdowells 和服务器输出不一致的影响?或者可能get_headers
已知在产生和错误的情况下工作?stream_get_meta_data
据我所知,
stream_get_meta_data
确实有一些注释和警告(... for fopen),但没有什么可怕到无法解决的。
只要它是安全且一致的,我想将它合并到我的项目中,因为这个操作经常执行,并且将运行时间减少一半会产生很大的不同。
编辑#1
从那以后,我发现了一些成功的 URL,get_headers
但会发出警告stream_get_meta_data
PHP Warning: fopen(http://www.alealimay.com/): failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request
PHP Warning: fopen(http://www.thelovelist.net/): failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request
PHP Warning: fopen(http://www.bleedingcool.com/): failed to open stream: HTTP request failed! HTTP/1.1 403 Forbidden
get_headers
仅返回403 Forbidden
状态,即使您可以将 URL 粘贴到浏览器中并查看它们是工作站点。
对此不确定: 的分解stream_get_meta_data
和不完整的标头get_headers
(应包括所有重定向和最终status_code = 200
功能站点)。
非常感谢,如果你做到了这一步。
另外,如果您投反对票,请发表评论,以便我可以改进问题,我们都可以为将来的案例学习。