network.http.Http->request バグ(その2)
昨日書いた network.http.Http->request バグ - gounx2の日記 が間違っていたので書き直します。
どんなバグか?
次のスクリプトを実行すると。。。
<?php require_once('./__init__.php'); Rhaco::import('network.http.Browser'); $url = 'http://twitter.1x1.jp/search/?source=&keyword=千葉&lang=&text=1'; $html = Http::get($url); echo $html;
原因がわかった。
調査の為に、Http->request へ echo を追加した。
class Http{ /** * リクエストを発行する * * @param string $url * @param string $method * @param array $headers * @param int $timeout * @param int $blocking * @return array */ function request($url,$method="GET",$headers=array(),$timeout=5,$blocking=1){ : $fp = @fsockopen((($isssl) ? "ssl://" : "").$host,$port,$errorno,$errormsg,$timeout); if($fp == false || false == stream_set_blocking($fp,$blocking) || false == stream_set_timeout($fp,$timeout)){ return ExceptionTrigger::raise(new NotConnectionException(Message::_("URL [{1}] {2} {3}",$url,$errormsg,$errorno))); } : }else if(preg_match("/Transfer\-Encoding:[\s]+chunked/i",$header)){ while(!feof($fp)){ $bytes = fgets($fp,4096); if(preg_match("/^([0-9a-fA-F]+)[\s\r\n]*$/",$bytes,$match)){ $size = hexdec($match[1]); if($size <= 0) break; // $body .= fread($fp,$size); $wk = fread($fp,$size); $body .= $wk; echo "size:". $size . " fread:" . strlen($wk) . "<br/>"; }else if(!preg_match("/^[\r\n]+$/",$bytes)){ echo "...size:" . strlen($bytes) . "<br/>"; $body .= $bytes; } } }else{ :
これを実行すると、次のログが取れた。
size:2593 fread:2491 --- fread($fp,2593) してるのに 実際に受信したのは 2491byte!! ...size:34 ...size:9 ...size:10 ...size:50 size:1448 fread:1448 --- これはOKですね。 size:2896 fread:2678 --- これはNG ...size:19 ...size:38 ...size:8 ...size:7 ...size:21 :
というように、freadで指定したサイズ分を受信できずに、次の処理に行ってしまっている。
まとめると。
- stream_set_blockingでブロッキングモードにしていても、
- Transfer-Encoding: chunked のときは、効いていないように見える。
ブロッキングっていうのはTCPレベルの話なので、そのあたりは詳しくは無いわけですが、まぁ、そういう特殊な送信の仕方するのが chunked の仕様ってことなのだろう。
と無理やり納得するとして、これを正常に動くようにしてみる。
修正してみる。
得たいデータを確実に取得するよう fgets、fread をループするように修正してみた。
class Http{ /** * リクエストを発行する * * @param string $url * @param string $method * @param array $headers * @param int $timeout * @param int $blocking * @return array */ function request($url,$method="GET",$headers=array(),$timeout=5,$blocking=1){ : }else if(preg_match("/Transfer\-Encoding:[\s]+chunked/i",$header)){ while(!feof($fp)){ // $bytes = fgets($fp,4096); // if(preg_match("/^([0-9a-fA-F]+)[\s\r\n]*$/",$bytes,$match)){ $bytes = ""; while(!feof($fp) && substr($bytes, strlen($bytes)-2) !== "\r\n"){ $bytes = fgets($fp,4096); echo "bytes:" . $bytes . "<br/>"; } if(preg_match("/^([0-9a-fA-F]+)[\s]*\r\n$/",$bytes,$match)){ $size = hexdec($match[1]); if($size <= 0) break; // $body .= fread($fp,$size); echo "fread1:" . $size. "<br/>"; while(!feof($fp) && $size !== 0){ $buf = fread($fp,$size); $size -= strlen($buf); echo "fread1:" . strlen($buf) . " " . $size. "<br/>"; $body .= $buf; } $size = 2; echo "fread2:" . $size. "<br/>"; while(!feof($fp) && $size !== 0){ $buf = fread($fp,$size); $size -= strlen($buf); echo "fread2:" . strlen($buf) . " " . $size. "<br/>"; } // }else if(!preg_match("/^[\r\n]+$/",$bytes)){ // $body .= $bytes; } :
echoの出力が、
bytes:a21 fread1:2593 --- 2593byte受信したい。 fread1:2491 102 --- 2491byte受信した。残り102byte fread1:102 0 --- 102byte受信した。残り0byte fread2:2 fread2:2 0 bytes:5a8 fread1:1448 fread1:1448 0 fread2:2 fread2:2 0 bytes:b50 fread1:2896 fread1:2678 218 fread1:218 0 fread2:2 fread2:2 0 bytes:5a8 fread1:1448 fread1:1448 0 fread2:2 fread2:2 0 :
うまくいってるようだ。
-
- -
2008-06-30追記
以下でfix
http://fixdap.com/p/rhaco/14271/