web-dev-qa-db-ja.com

作成方法PHP Chunked応答を生成する

私はこの問題をググったが、それに対する答えはない。

PHPスクリプトでHTTP応答をチャンクで生成する( http://en.wikipedia.org/wiki/Chunked_transfer_encoding ))方法は?

更新:わかりました。 Transfer-encodingヘッダーを指定してフラッシュする必要があります。

header("Transfer-encoding: chunked");
flush(); 

フラッシュが必要です。それ以外の場合、Content-Lengthヘッダーが生成されます。

そして、私は自分でチャンクを作らなければなりません。ヘルパー機能があれば難しくありません。

function dump_chunk($chunk)
{
    echo sprintf("%x\r\n", strlen($chunk));
    echo $chunk;
    echo "\r\n";
}
31
Morgan Cheng

これは少し価値があります...大きな断定されたチャンク(0x1000オクテット程度)を気にしない場合は、はい、PHPで作成されます。

<?php

while (true) {
    # output data
    flush()
    usleep(pow(2,18));
}
?>

PHPは番号付きセクションなどを生成します。

AJAXクライアントと同じように、小さなチャンクを送信したい場合は、まあ、私はOPsの質問とPHP.NETに関するいくつかの調査を組み合わせました。彼は良いことに夢中になっているように見えます。

$ echo -en "GET/chunked/HTTP/1.1\r\nホスト:ec\r\n\r\n" | nc localhost 80

HTTP/1.1 200 OK
Date: Wed, 23 May 2012 13:03:01 GMT
Server: Apache/2.2.9 (Debian) PHP/5.3.5-1 with Suhosin-Patch mod_ssl/2.2.9 OpenSSL/0.9.8o
X-Powered-By: PHP/5.3.5-1
Transfer-encoding: chunked
Content-Type: text/html

14
Teachers have class.
50
We secure our friends not by accepting favors but by doing them.
            -- Thucydides
48
Vulcans never bluff.
            -- Spock, "The Doomsday Machine", stardate 4202.1
31
All kings is mostly rapscallions.
            -- Mark Twain
41
Reappraisal, n.:
    An abrupt change of mind after being found out.
49
He who knows, does not speak.  He who speaks, does not know.
            -- Lao Tsu

それが最終的にそれ自体の(誤った)チャンク数を絞り出すかどうかはまだわかりません...しかし、その兆候は見られませんでした。

<?php
header("Transfer-encoding: chunked");
@Apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++)  ob_end_flush();
ob_implicit_flush(1); flush();

function dump_chunk($chunk)
{
  printf("%x\r\n%s\r\n", strlen($chunk), $chunk);
  flush();
}

for (;;) {
  $output = array();
  exec("/usr/games/fortune", $output);
  dump_chunk(implode("\n", $output));
  usleep(pow(2,18));
}
?>
6
Orwellophile

PHP応答は、content-lengthヘッダーを指定しない場合、常にチャンクされ、フラッシュが発生します。(これは、xバイトの後に自動的に発生しますが、正確な量がわからないだけです。 )。

これは奇妙なことです。これはある種の学問的/学習的な演習ですか、それとも解決しようとしている現実の問題がありますか?

5
Evert

2013年2月16日の作業サンプル

<?php

function dump_chunk($chunk) {
    //echo sprintf("%x\r\n", strlen($chunk));
    echo sprintf("\r\n");
    echo $chunk;
    echo "\r\n";
}

ob_start();
?>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Title</title>
    </head>
    <body>
        <?php
        ob_end_flush();
        flush();
        ob_flush();
        for ($i = 0; $i < 5; $i++) {
            sleep(1);
            dump_chunk('Sending data chunk ' . ($i + 1) . ' of 1000 <br />');
            flush();
            ob_flush();
        }
        sleep(1); // needed for last animation
        ?>
    </body>
</html>
5
Andriy F.

(独自のデータチャンクを作成せずに)より簡単な方法は、flush()のみを使用することです。

<?php 
$fp = fopen('data.bin', "rb");
flush();
fpassthru($fp);
?>

これは、次のHTTP要求と応答に示すように私にとってはうまくいきました。

リクエスト:

00000000  47 45 54 20 2f 67 65 74  2d 63 68 75 6e 6b 2e 70 GET /get -chunk.p
00000010  68 70 20 48 54 54 50 2f  31 2e 31 0d 0a 55 73 65 hp HTTP/ 1.1..Use
00000020  72 2d 41 67 65 6e 74 3a  20 63 75 72 6c 2f 37 2e r-Agent:  curl/7.
00000030  32 31 2e 37 20 28 69 36  38 36 2d 70 63 2d 6c 69 21.7 (i6 86-pc-li
00000040  6e 75 78 2d 67 6e 75 29  20 6c 69 62 63 75 72 6c nux-gnu)  libcurl
00000050  2f 37 2e 32 31 2e 37 20  4f 70 65 6e 53 53 4c 2f /7.21.7  OpenSSL/
00000060  31 2e 30 2e 30 64 20 7a  6c 69 62 2f 31 2e 32 2e 1.0.0d z lib/1.2.
00000070  35 20 6c 69 62 73 73 68  32 2f 31 2e 32 2e 37 0d 5 libssh 2/1.2.7.
00000080  0a 48 6f 73 74 3a 20 67  61 69 61 0d 0a 41 63 63 .Host: g aia..Acc
00000090  65 70 74 3a 20 2a 2f 2a  0d 0a 0d 0a             ept: */* ....

応答:

00000000  48 54 54 50 2f 31 2e 31  20 32 30 30 20 4f 4b 0d HTTP/1.1  200 OK.
00000010  0a 44 61 74 65 3a 20 54  68 75 2c 20 32 32 20 53 .Date: T hu, 22 S
00000020  65 70 20 32 30 31 31 20  32 33 3a 35 33 3a 30 32 ep 2011  23:53:02
00000030  20 47 4d 54 0d 0a 53 65  72 76 65 72 3a 20 41 70  GMT..Se rver: Ap
00000040  61 63 68 65 2f 32 2e 32  2e 38 20 28 46 65 64 6f ache/2.2 .8 (Fedo
00000050  72 61 29 0d 0a 58 2d 50  6f 77 65 72 65 64 2d 42 ra)..X-P owered-B
00000060  79 3a 20 50 48 50 2f 35  2e 32 2e 36 0d 0a 54 72 y: PHP/5 .2.6..Tr
00000070  61 6e 73 66 65 72 2d 45  6e 63 6f 64 69 6e 67 3a ansfer-E ncoding:
00000080  20 63 68 75 6e 6b 65 64  0d 0a 43 6f 6e 74 65 6e  chunked ..Conten
00000090  74 2d 54 79 70 65 3a 20  74 65 78 74 2f 68 74 6d t-Type:  text/htm
000000A0  6c 3b 20 63 68 61 72 73  65 74 3d 55 54 46 2d 38 l; chars et=UTF-8
000000B0  0d 0a 0d 0a                                      ....
000000B4  61 0d 0a 54 45 53 54 20  44 41 54 41 0a 0d 0a 30 a..TEST  DATA...0
000000C4  0d 0a 0d 0a                                      ....
2
Wade

あなたは使用できるはずです:

<?php header("Transfer-Encoding: chunked");

ただし、出力が仕様に従っていることを確認する必要があります。

2
Andre

出力バッファは、いっぱいになるまでブラウザに送信されません。デフォルトのサイズは_4096_バイトです。したがって、バッファサイズを変更するか、チャンクを埋め込む必要があります。また、ブラウザには、ページが表示される前に独自の最小バッファがある場合があります。チャンクエンコーディングについて Wikipedia Article によると、_0\r\n\r\n_チャンクを送信すると応答が終了することに注意してください。

出力バッファリングサイズの設定を変更する場合は、ini_set('output_buffering', $value)を使用できないことを確認しました。代わりに、php.iniファイルに以下を追加して、出力バッファリング設定を変更します。

_php_value output_buffering 1024
_

これがチャンクのパディングの例です

_header("Transfer-Encoding: chunked");
header("Content-Encoding: none");

// Send chunk to browser
function send_chunk($chunk)
{
    // The chunk must fill the output buffer or php won't send it
    $chunk = str_pad($chunk, 4096);

    printf("%x\r\n%s\r\n", strlen($chunk), $chunk);
    flush();
}

// Send your content in chunks
for($i=0; $i<10; $i++)
{
    send_chunk("This is Chunk #$i.<br>\r\n");
    usleep(500000);
}

// note that if you send an empty chunk
// the browser won't display additional output
echo "0\r\n\r\n";
flush();
_

次に、出力を終了する_0\r\n\r\n\_を示す短いバージョンを示します。

_$output = "hello world";
header("Transfer-Encoding: chunked");
header('Content-Encoding: none');
printf("%x\r\n%s\r\n", strlen($output), $output);
ob_flush();
print("0\r\n\r\n");
ob_flush();
flush();
sleep(10);
print('POST PROCESSING');
_
2
skibulk

サイズが十分に大きければ、Apacheが代わりに行います。 ob_gzhandlerを使用している場合、それは意味がないと思います。できるだけ早くバッファを解放する方が良いでしょう。 PHPが実際にcontent-lengthヘッダーを自動的に送信しないか、content-lengthが非圧縮コンテンツからのものである場合:

ob_start();
ob_start("ob_gzhandler");
...
ob_end_flush();  
header('Content-Length: '.ob_get_length()); 
ob_end_flush();

Apache のmod_buffer(PHPのini_setを使用する場合があります)を使用して、バッファーサイズを減らすことができます。

PS:サイズが十分に大きく、content-lengthが不明な場合、コンテンツは一時的な変更としてチャンクで送信されます。

0
B.F.

Andriy F.のソリューション は私のために働きました。これは彼の答えの簡略版です:

_function dump_chunk($chunk)
{
    echo $chunk;
    flush();
    ob_flush();
}

header('Content-Type: text/html; charset=UTF-8');

flush();

for ($i = 0; $i < 3; $i++) {
    dump_chunk('Sending data chunk ' . ($i + 1) . ' of 1000 <br />');
    sleep(1);
}
_

ob_flush()呼び出しが必要な理由はわかりませんが。誰かが知っている場合は、コメントしてください。

0
Ohas