Wie man PHP dazu bringt, eine Chunked-Antwort zu generieren

Lesezeit: 8 Minuten

Wie man PHP dazu bringt eine Chunked Antwort zu generieren
Morgan Cheng

Ich habe nach diesem Problem gegoogelt, aber es gibt keine Antwort darauf.

Ich möchte, dass mein PHP-Skript eine HTTP-Antwort in Chunked generiert ( http://en.wikipedia.org/wiki/Chunked_transfer_encoding). Wie es geht?

Update: Ich habe es herausgefunden. muss ich angeben Transfer-Codierung Header und spülen Sie es.

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

Die Spülung ist notwendig. Andernfalls wird der Content-Length-Header generiert.

Und Brocken muss ich selber machen. Mit einer Hilfsfunktion ist es nicht schwer.

function dump_chunk($chunk)
{
    echo sprintf("%xrn", strlen($chunk));
    echo $chunk;
    echo "rn";
}

  • Sie können nach jedem Chunk spülen.

    – Gumbo

    1. Juli 10 um 6:39 Uhr

  • Würden Sie erklären, wie die Chunks aus der Datei gewonnen werden? Bitte? ^_º

    – José Manuel Abarca Rodríguez

    27. Januar 21 um 22:24 Uhr

  • Achtung: Einstellung header("Transfer-encoding: chunked"); unterbricht explizit die native Chunked-Codierung von PHP und berechnet und sendet die Chunk-Längen nicht mehr!

    – Reinstaat

    25. März 21 um 11:26 Uhr


Eine PHP-Antwort wird immer aufgeteilt, wenn Sie keinen Header mit Inhaltslänge angeben, und es kommt zu einem Flush. (was automatisch nach x Bytes passieren wird, weiß nur nicht genau wie viel).

Das ist eine seltsame Sache, um die man sich kümmern muss. Ist das eine Art akademische/lernende Übung oder gibt es ein reales Problem, das Sie zu lösen versuchen?

  • Ich möchte eine Chunked-Transfer-Codierung erzwingen, weil ich ein Ruby-Skript teste, das es lesen können soll. Also, wenn ich dich richtig verstehe, brauche ich nur etwas Flush(); Zeilen ein, um regelmäßig ausgeführt zu werden, und das zwingt PHP, in Chunked Transfer Encoding zu antworten. Keine Notwendigkeit, Chunk-Größenzahlen explizit auszugeben?

    – Harry Holz

    23. März 2012 um 11:07 Uhr

  • Apache sollte das für Sie selbst erledigen. Wenn Apache die Länge nicht im Voraus kennt, hat es grundsätzlich keine andere Wahl, als „chunked“ zu verwenden.

    – Evert

    23. März 12 um 12:09 Uhr

  • Apache puffert vor dem Senden eine bestimmte Menge an Ausgaben. Wenn Ihre gesamte Ausgabe in den Puffer passt, wird sie nicht aufgeteilt, es sei denn, Sie erzwingen dies.

    – sosiouxme

    9. März 14 um 0:53 Uhr

Wie man PHP dazu bringt eine Chunked Antwort zu generieren
Orwellophil

Das ist ein wenig vauge geworden … wenn Sie nichts gegen große Brocken haben (0x1000 Oktette oder so), dann ja, PHP wird sie machen.

<?php

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

PHP generiert die nummerierten Abschnitte usw.

Wenn Sie winzig kleine Brocken senden möchten, wie Sie es vielleicht mit einem AJAX-Client tun … Nun, ich habe die OPs-Frage mit etwas Recherche zu PHP.NET kombiniert, und es sieht so aus, als wäre er einer guten Sache auf der Spur .

$ echo -en “GET /chunked/HTTP/1.1rnHost: ecrnrn” | nc lokaler Host 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

Ob es schließlich seine eigene (falsche) Chunk-Anzahl herausquetschen wird oder nicht, bleibt abzuwarten … aber ich habe keine Anzeichen dafür gesehen.

<?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("%xrn%srn", strlen($chunk), $chunk);
  flush();
}

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

  • Wenn Sie jeden Ausgabepuffer loswerden möchten, wird auf diese Weise nur die Hälfte davon entfernt (aufgerundet). Benutzen while(ob_get_level()){ob_end_flush();} stattdessen. Wenn Sie vermeiden möchten, dass die Funktion wiederholt aufgerufen wird: for($i=ob_get_level(); $i; --$i){ob_end_flush();} oder $i=ob_get_level()+1;while(--$i){ob_end_flush();} (Verwenden Sie Post-Decrement, wenn +1 ungerade erscheint). Danke für das Netcat-Beispiel, HTTP ist viel einfacher als ich erwartet hatte, was lustig ist, da ich es gesehen habe <method> <path> <HTTP version>, Kopfzeilen und Textkörper, aber sie werden normalerweise separat angezeigt, wenn ich sie ansehe.

    – Chinoto Vokro

    16. Dezember 16 um 23:09 Uhr


Arbeitsprobe vom 16.02.2013

<?php

function dump_chunk($chunk) {
    //echo sprintf("%xrn", strlen($chunk));
    echo sprintf("rn");
    echo $chunk;
    echo "rn";
}

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>

  • Aus irgendeinem Grund wird die Seite nur angezeigt, wenn die gesamte Seite gerendert wird, anstatt zuzunehmen. Wissen Sie, was das Problem gewesen sein könnte?

    – Schrittmacher

    14. Juli 13 um 6:08 Uhr


  • Welche Konfiguration verwendest du? (Apache-Version, Module, PHP-Version)?

    – Andriy F.

    5. August 13 um 11:11 Uhr

  • PHP 5.3.26, Apache 2.2.24 + nginx hosting24.com/blog/… bereitgestellt durch das Silberpaket von hosting24 hosting24.com/features.php

    – Schrittmacher

    5. August 13 um 11:21 Uhr

  • Versuchen Sie es mit Code apachefriends.org/en/xampp.html. Wenn es auf XAMPP funktioniert, liegt Ihr Problem möglicherweise an nginx (siehe stackoverflow.com/questions/3222007/… oder nginx.org/en/docs/faq/chunked_encoding_from_backend.html für Hinweise)

    – Andriy F.

    5. August 13 um 16:34 Uhr

  • Warum verwenden Sie die Ausgabepufferung? Sie scheinen es nicht zu brauchen, es sei denn, Sie ändern Header, nachdem die Ausgabe begonnen hätte, Sie wenden eine Funktion auf die Ausgabe an oder speichern den Puffer über ob_get_clean() in einer Variablen.

    – Chinoto Vokro

    16. Dezember 16 um 23:24 Uhr

Sie sollten in der Lage sein, Folgendes zu verwenden:

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

Sie müssen jedoch selbst sicherstellen, dass die Ausgabe den Spezifikationen entspricht.

1643916848 584 Wie man PHP dazu bringt eine Chunked Antwort zu generieren
skibulk

Der Ausgabepuffer wird erst an den Browser gesendet, wenn er voll ist. Die Standardgröße ist 4096 Bytes. Sie müssen also entweder die Puffergröße ändern oder Ihre Chunks auffüllen. Außerdem kann der Browser einen eigenen minimalen Puffer haben, bevor die Seite angezeigt wird. Beachten Sie, dass gemäß der Wikipedia-Artikel über Chunked Encoding, Senden a 0rnrn chunk beendet die Antwort.

Wenn Sie die Einstellung für die Ausgabepuffergröße ändern möchten, habe ich gelesen, dass Sie sie nicht verwenden können ini_set('output_buffering', $value). Ändern Sie stattdessen die Einstellung für die Ausgabepufferung, indem Sie Folgendes zu Ihrer php.ini-Datei hinzufügen.

php_value output_buffering 1024

Hier ist ein Beispiel für das Auffüllen Ihrer Chunks

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("%xrn%srn", strlen($chunk), $chunk);
    flush();
}

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

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

Hier ist eine kurze Version, die demonstriert 0rnrn Ausgabe beenden:

$output = "hello world";
header("Transfer-Encoding: chunked");
header('Content-Encoding: none');
printf("%xrn%srn", strlen($output), $output);
ob_flush();
print("0rnrn");
ob_flush();
flush();
sleep(10);
print('POST PROCESSING');

1643916848 409 Wie man PHP dazu bringt eine Chunked Antwort zu generieren
Waten

Eine einfachere Möglichkeit (ohne eigene Datenblöcke zu erstellen) besteht darin, nur flush() zu verwenden:

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

Dies hat bei mir funktioniert, wie in der folgenden HTTP-Anforderung und -Antwort gezeigt.

Anfrage:

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: */* ....

Antwort:

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                                      ....

1643916849 849 Wie man PHP dazu bringt eine Chunked Antwort zu generieren
Gemeinschaft

Die Lösung von Andriy F. hat bei mir funktioniert. Hier ist eine vereinfachte Version seiner Antwort:

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);
}

Obwohl ich nicht verstehe, warum die ob_flush() Anruf erforderlich. Wenn es jemand weiß, bitte kommentieren.

.

759300cookie-checkWie man PHP dazu bringt, eine Chunked-Antwort zu generieren

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy