《PHP應(yīng)用:關(guān)于PHP 如何用 curl 讀取 HTTP chunked 數(shù)據(jù)》要點(diǎn):
本文介紹了PHP應(yīng)用:關(guān)于PHP 如何用 curl 讀取 HTTP chunked 數(shù)據(jù),希望對您有用。如果有疑問,可以聯(lián)系我們。
對于 Web 服務(wù)器返回的 HTTP chunked 數(shù)據(jù), 我們可能希望在每一個 chunk 返回時得到回調(diào), 而不是所有的響應(yīng)返回后再回調(diào). 例如, 當(dāng)服務(wù)器是 icomet 的時候.PHP教程
在 PHP 中使用 curl 代碼如下:PHP教程
<?php $url = "http://127.0.0.1:8100/stream"; $ch = curl_init($url); curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'myfunc'); $result = curl_exec($ch); curl_close($ch); function myfunc($ch, $data){ $bytes = strlen($data); // 處理 data return $bytes; }
但是, 這里有一個問題. 對于一個 chunk, 回調(diào)函數(shù)可能會被調(diào)用多次, 每一次大概是 16k 的數(shù)據(jù). 這顯然不是我們希望得到的. 因為 icomet 的一個 chunk 是以 "\n" 結(jié)尾, 所以回調(diào)函數(shù)可以做一下緩沖.PHP教程
function myfunc($ch, $data){ $bytes = strlen($data); static $buf = ''; $buf .= $data; while(1){ $pos = strpos($buf, "\n"); if($pos === false){ break; } $data = substr($buf, 0, $pos+1); $buf = substr($buf, $pos+1); // 處理 data } }
下面給大家介紹下chunked php使用fsockopen讀取分段數(shù)據(jù)(transfer-encoding: chunked) PHP教程
使用fsockopen讀取數(shù)據(jù)時遇到了一個神奇的問題,具體情況如下:
PHP教程
讀取地址:http://blog.maxthon.cn/?feed=rss2
PHP教程
讀取代碼:
PHP教程
<?php $fp = fsockopen("blog.maxthon.cn", 80, $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)<br />\n"; } else { $out = "GET /?feed=rss2 HTTP/1.1\r\n"; $out .= "Host: blog.maxthon.cn\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); while (!feof($fp)) { echo fgets($fp, 128); } fclose($fp); } ?>
返回http內(nèi)容:PHP教程
Date: Mon, 29 Mar 2010 10:16:13 GMT Server: Apache/2.2.8 (Unix) mod_ssl/2.2.8 OpenSSL/0.9.8b PHP/5.2.6 X-Powered-By: PHP/5.2.6 X-Pingback: http://blog.maxthon.cn/xmlrpc.php Last-Modified: Wed, 03 Mar 2010 03:13:41 GMT ETag: "8f16b619f32188bde3bc008a60c2cc11" Keep-Alive: timeout=15, max=120 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/xml; charset=UTF-8 22de <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" <description><![CDATA[2009年12月31日 1711 ....... 1fe8 ]]></description> <content:encoded><![CDATA[<p>2009年12月31日<br /> 1711</p>
請注意上面那些標(biāo)紅的4個字符,它們每隔一段數(shù)據(jù)就會出現(xiàn)一次,但是用其他的辦法如curl,file_get_contents等取回的數(shù)據(jù)則沒有這些玩意.換成其他的網(wǎng)站來抓取,也只是少數(shù)的網(wǎng)站會出現(xiàn)這種情況,多方搜索無解后,我無意中看到了上面返回頭中有這么一個聲明:Transfer-Encoding: chunked,而常見的Content-lenght字段沒有了.這個聲明的大致的意思是傳輸編碼為分段方式.
PHP教程
在Google上搜索該關(guān)鍵詞,在維基百科上找到對這個聲明的解釋(由于沒有中文版,我只能自己依照意思翻譯):
PHP教程
Chunked Transfer Encoding is a mechanism that allows HTTP messages to be split in several parts. This can be applied to both HTTP requests (from client to server) and HTTP responses (from server to client)
分塊傳輸編碼是一種機(jī)制,允許將HTTP消息分成幾個部分傳輸.同時適用于HTTP哀求(從客戶端到服務(wù)器)和 HTTP響應(yīng)(從服務(wù)器到客戶端)
PHP教程
For example, let us consider the way in which an HTTP server may transmit data to a client application (usually a web browser). Normally, data delivered in HTTP responses is sent in one piece, whose length is indicated by the Content-Length header field. The length of the data is important, because the client needs to know where the response ends and any following response starts. With chunked encoding, however, the data is broken up into a series of blocks of data and transmitted in one or more "chunks" so that a server may start sending data before it knows the final size of the content that it's sending. Often, the size of these blocks is the same, but this is not always the case.
PHP教程
例如,讓我們考慮HTTP服務(wù)器可將數(shù)據(jù)傳輸?shù)娇蛻舳藨?yīng)用程序(通常是一個網(wǎng)絡(luò)瀏覽器)使用哪些方式.通常情況下,在HTTP響應(yīng)數(shù)據(jù)是依照一整塊發(fā)送給客戶端的,數(shù)據(jù)的長度是由Content - Length頭域表示.數(shù)據(jù)的長度很重要,因為客戶需要知道在哪里響應(yīng)結(jié)束和后面的響應(yīng)何時啟動.而使用Chunked編碼方式,不管怎樣,數(shù)據(jù)都會分割成一系列的數(shù)據(jù)塊和一個或多個轉(zhuǎn)發(fā)的“塊”,因此服務(wù)器在知道內(nèi)容的長度之前,就可以開始發(fā)送數(shù)據(jù)后.通常情況下,這些數(shù)據(jù)塊的大小是一樣的,但也并不是絕對的.
PHP教程
大概意思了解后,我們來看例子:
PHP教程
Chunked編碼使用若干個Chunk串連而成,由一個標(biāo)明長度為0的chunk標(biāo)示結(jié)束.每個Chunk分為頭部和正文兩部分,頭部內(nèi)容指定下一段正文的字符總數(shù)(十六進(jìn)制的數(shù)字)和數(shù)量單位(一般不寫),正文部分就是指定長度的實際內(nèi)容,兩部分之間用回車換行(CRLF)隔開.在最后一個長度為0的Chunk中的內(nèi)容是稱為footer的內(nèi)容,是一些附加的Header信息(通常可以直接忽略).具體的Chunk編碼格式如下:
PHP教程
編過碼的響應(yīng)內(nèi)容:PHP教程
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunkedPHP教程
25
PHP教程
這是第一段數(shù)據(jù)PHP教程
1A
PHP教程
然后這是第二段數(shù)據(jù)
PHP教程
0PHP教程
解碼的數(shù)據(jù):
PHP教程
這是第一段內(nèi)容,然后這是第二段數(shù)據(jù)
PHP教程
情況搞清楚了,那么我們怎么來解碼這個編碼后的數(shù)據(jù)呢?
PHP教程
在php官方手冊fsockopen函數(shù)下面的評論中,已經(jīng)有很多人提出了解決辦法
PHP教程
辦法1.
PHP教程
<?php function unchunk($result) { return preg_replace_callback( '/(?:(?:\r\n|\n)|^)([0-9A-F]+)(?:\r\n|\n){1,2}(.*?)'. '((?:\r\n|\n)(?:[0-9A-F]+(?:\r\n|\n))|$)/si', create_function( '$matches', 'return hexdec($matches[1]) == strlen($matches[2]) ? $matches[2] : $matches[0];' ), $result ); }
辦法二.
PHP教程
function unchunkHttp11($data) { $fp = 0; $outData = ""; while ($fp < strlen($data)) { $rawnum = substr($data, $fp, strpos(substr($data, $fp), "\r\n") + 2); $num = hexdec(trim($rawnum)); $fp += strlen($rawnum); $chunk = substr($data, $fp, $num); $outData .= $chunk; $fp += strlen($chunk); } return $outData; }
注意:這兩個函數(shù)的參數(shù)都是返回的http原始數(shù)據(jù)(包含頭)PHP教程
維易PHP培訓(xùn)學(xué)院每天發(fā)布《PHP應(yīng)用:關(guān)于PHP 如何用 curl 讀取 HTTP chunked 數(shù)據(jù)》等實戰(zhàn)技能,PHP、MYSQL、LINUX、APP、JS,CSS全面培養(yǎng)人才。
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/7507.html