PHP によって収集されたデータは、チャンク転送エンコーディングです。gzip 圧縮形式でのチャンク エンコーディングの考え方は、次のとおりです。各ブロックはヘッダーとボディ フィールドに分割されます。本文情報は 16 進数のシステム表現であり、ヘッダーと本文は復帰文字と改行文字で区切られ、最後のブロックはブロックが切れていることを示す単一行の 0 で終わります。 。
応答ヘッダー情報:
Array( [0] => HTTP/1.1 200 OK [1] => Server: Dict/34002 [2] => Date: Wed, 17 Dec 2014 06:49:22 GMT [3] => Content-Type: text/html; charset=utf-8 [4] => Transfer-Encoding: chunked [5] => Connection: keep-alive [6] => Keep-Alive: timeout=60 [7] => Cache-Control: private [8] => Last-Modified: Wed, 17 Dec 2014 04:57:49 GMT [9] => Expires: Wed, 17 Dec 2014 06:49:22 GMT [10] => Set-Cookie: uvid=VJEncoTSVYJC; expires=Thu, 31-Dec-37 23:55:55 GMT; domain=.dict.cn; path=/ [11] => Content-Encoding: gzip)
if($this->response_num==200) { if($this->is_chunked) { //读取chunk头部信息,获取chunk主体信息的长度 $chunk_size = (int)hexdec(fgets($this->conn)); // while(!feof($this->conn) && $chunk_size > 0) { //读取chunk头部指定长度的信息 $this->response_body .= fread( $this->conn, $chunk_size ); fseek($this->conn, 2, SEEK_CUR); $chunk_size = (int)hexdec(fgets( $this->conn,4096)); } } else { $len=0; //读取请求返回的主体信息 while($items = fread($this->conn, $this->response_body_length)) { $len = $len+strlen($items); $this->response_body = $items; //当读取完请求的主体信息后跳出循环,不这样做,貌似会被阻塞!!! if($len >= $this->response_body_length) { break; } } } if($this->is_gzip) { $this->response_body = gzinflate(substr($this->response_body,10)); } $this->getTrans($this->response_body); }
奇妙なことに、次のような結果が得られることがあります:
int (挨拶) こんにちは; こんにちは
警告: gzinflate(): data のようなエラーが表示されることがあります。 E:CodeEditphphttpdict.php の 380 行目でエラーが発生しましたif($this->is_chunked) { /* //读取chunk头部信息,获取chunk主体信息的长度 $chunk_size = (int)hexdec(trim(fgets($this->conn))); while(!feof($this->conn) && $chunk_size > 0) { //读取chunk头部指定长度的信息 $this->response_body .= fread( $this->conn, $chunk_size ); fseek($this->conn, 2, SEEK_CUR); $next_line = trim(fgets($this->conn)); if($next_line === '0') { echo $next_line;exit(); } else { $chunk_size = (int)hexdec($next_line); } } */ while(!feof($this->conn)) { $this->response_body .= fread($this->conn, 1024); } if(preg_match_all("#\r\n#i", $this->response_body, $match)) { $result=preg_split("#\r\n#i", $this->response_body, -1, PREG_SPLIT_NO_EMPTY ); // echo "<pre class="brush:php;toolbar:false">"; // print_r($result); /* foreach($result as $v) { echo $v."<br /><hr />"; } echo "<hr />"; */ /* echo hexdec($result[0])."<br />"; echo mb_strlen($result[1])+mb_strlen($result[2])."<br />"; */ $len = count($result); $this->response_body=''; for($i=1; $i<$len-1; $i++) { $this->response_body .= $result[$i]; } //echo strlen($this->response_body); exit(); } else { die("匹配结束符失败"); } }
基本的な考え方は、まず、ヘッダーを connection:close に変更して、while(!feof($this) を通じてすべてのデータを一度に読み取ることができるようにすることです。 ->conn))
次に、チャンク送信ヘッダーとボディは改行で区切られているため、通常の分割を直接使用して、データ長とデータを含む配列を取得します。最初の項目は、すべてのデータの合計長を表します。 (各チャンクの長さではなく)、これはチャンクのエンコーディングとは少し異なるようです。チャンクに応じたエンコーディングが失敗するのも不思議ではありません。)、配列の最後の項目は終了を示す 0 です。 。 。繰り返しテストしました、OK