chunked編碼問題

來源:互聯網
上載者:User
PHP採集到的資料是chunked傳輸編碼,gzip壓縮格式的
chunk編碼的思路貌似是: 將資料分塊傳輸,每一塊分為頭部和主體欄位,頭部包含主體資訊的長度且以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);        }


基本上每次都會出現這個提示:
Warning: gzinflate(): data error in E:\CodeEdit\php\http\dict.php on line 384
偶爾能正常解析,應該是chunked解碼有問題,查看過一些資料,也變換過集中解碼方式,但還是功虧一簣


回複討論(解決方案)

你可用 gzdecode 解碼

你可用 gzdecode 解碼



奇怪的是有時可以擷取到結果,比如:
int.(打招呼)喂;你好
有時提示錯誤,比如:
Warning: gzinflate(): data error in E:\CodeEdit\php\http\dict.php on line 380

估計錯誤還是出現在chunked解碼這塊,這裡的問題是返回的資料是先經過gzip壓縮,然後通過chunked分塊傳輸的,所以解碼的過程就是反過來的

你可用 gzdecode 解碼



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 "
";// print_r($result); /* foreach($result as $v){echo $v."
";}echo ""; *//* echo hexdec($result[0])."
";echo mb_strlen($result[1])+mb_strlen($result[2])."
"; */$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))一次性讀取所有的資料

然後因為chunk分塊傳輸的頭部和主體之間是用斷行符號換行分隔的,所以直接用正則分割,得到一個數組包含資料長度和資料的數組,第一項表示所有資料的總長度(而不是每一個chunk分塊的長度,這個貌似和chunk編碼有點出入,也難怪按照chunk編碼會失敗,),最後一個數組項為0表示結束.。。。反覆測試,OK了
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.