Joachim: moodle: ob_end_flush - ob_end_clean probleme bei bildausgabe

Hi,

ich musste grade einen Fehler in einer mir bis dahin völlig unbekannten Software "moodles" (php) beheben. Konkret ging es um eine Datei, die files (unter bestimmten Voraussetzungen) ausliefert, also auch Bilder. Anstelle der Bilder wurden jedoch der Dateiname, also ...file.php?file=/2/image.jpg mit einem header image/jpeg ausgegeben, und zwar als Grafik.

Die dazugehörige lib nutzt diesen Code zum Ausliefern, in mimetype steht "image/jpeg", path ist der korrekte Bildpfad, und es wird der else-Pfad durchlaufen, also  readfile_chunked() ausgeführt:

@header('Content-Type: '.$mimetype);
        @header('Content-Length: '.$filesize);
        while (@ob_end_flush());
        if ($pathisstring) {
            echo $path;
        } else {
            readfile_chunked($path);
        }

Ich habe in der Doku zu fpassthrough() gelesen, dass ob_end_clean in Fällen automatischer gz-Komprimierung hilft, und habe ob_end_flush damit ersetzt: nun funktioniert es, das Bild wird mit korrektem Header ausgegeben. Ich begreife zwar den Unterschied (Pufferleeren _ohne_ Ausgabe), kann mir aber den Effekt nicht erklären. Kann mir jemand Näheres hierzu sagen?

Gruesse, Joachim

--
Am Ende wird alles gut.
  1. echo $begrüßung;

    Wenn ein Bild ausgegeben werden soll, und dessen Daten allein mit der Funktion readfile_chunked($path) zur Ausgabe gelangen, darf vorher und hinterher keine andere Ausgabe stattfinden, weil diese vom Browser als Bilddaten zu interpretieren versucht werden würde.

    @header('Content-Type: '.$mimetype);
            @header('Content-Length: '.$filesize);
            while (@ob_end_flush());
            if ($pathisstring) {
                echo $path;
            } else {
                readfile_chunked($path);
            }

    Insofern ist es kontraproduktiv, alle Ausgabepuffer in Richtung Client zu entleeren. Möglicherweise gibt es in deinem Fall eine Fehlermeldung, die du

    [...] habe ob_end_flush [mit ob_end_clean()] ersetzt: nun funktioniert es [...]

    durch ob_end_clean() in die ewigen Bytegründe beförderst, so dass der Client nicht mehr darüber stolpert. Du könntest ja mal die Änderung rückgängig machen, im Browser die Bild-URL direkt aufrufen und in der Quelltextansicht nach Fehlermeldungen Ausschau halten.

    echo "$verabschiedung $name";

    1. Hi,

      Wenn ein Bild ausgegeben werden soll, und dessen Daten allein mit der Funktion readfile_chunked($path) zur Ausgabe gelangen, darf vorher und hinterher keine andere Ausgabe stattfinden, weil diese vom Browser als Bilddaten zu interpretieren versucht werden würde.

      Habe ich auch erst gedacht, aber ein Auskommentieren der Zeile (sollte ja auch die Ausgabe verhindern) hat nix geändert.

      Du könntest ja mal die Änderung rückgängig machen, im Browser die Bild-URL direkt aufrufen und in der Quelltextansicht nach Fehlermeldungen Ausschau halten.

      Gab keine. Allerdings habe ich es versäumt, das Ganze mal mit zwangsweise mit einem header text/html zu versehen... muss ich nächste Woche mal machen.

      Ich verstehe eh nicht ganz, was 'while (ob_end_flush())' hier ausgegeben werden sollte, und warum es dazu überhaupt eine while Schleife braucht. Manchmal ist fremde Software wirklich mühsam...

      Sagt Dir denn die Problematik mit der gz-Komprimierung etwas?
      Jedenfalls danke fürs Mitdenken...

      Gruesse, Joachim

      --
      Am Ende wird alles gut.
      1. echo $begrüßung;

        Wenn ein Bild ausgegeben werden soll, [...] darf vorher und hinterher keine andere Ausgabe stattfinden, weil diese vom Browser als Bilddaten zu interpretieren versucht werden würde.
        Habe ich auch erst gedacht, aber ein Auskommentieren der Zeile (sollte ja auch die Ausgabe verhindern) hat nix geändert.

        Vielleicht ist das auszugebende unsichtbar, beispielsweise Whitespace-Zeichen außerhalb von <?php ?>. Wenn in einer Datei nur PHP-Code steht, ist am Anfang zwar immer brav ein <?php, aber am Ende schmuggeln sich gern Whitespaces hinter das ?>. Wenn man das ?> am Ende weglässt, kann das nicht passieren. Ebenso stört eine UTF-8-BOM, die ein Editor beim Dateispeichern eingefügt hat.

        Ich verstehe eh nicht ganz, was 'while (ob_end_flush())' hier ausgegeben werden sollte, und warum es dazu überhaupt eine while Schleife braucht. Manchmal ist fremde Software wirklich mühsam...

        Das ist ein schönes Beispiel, warum es wichtig ist, die Gedanken, die zu einem Stück Code geführt haben, als Kommentar zu notieren. Auf der von dir erwähnten Handbuchseite zu fpassthrough() steht in einem User-Kommentar dieses Konstrukt aber mit …clean nebst Erklärung. Es dient dazu, alle Ausgabepuffer (davon können ja mehrere nacheinander geöffnet werden) zu schließen und deren Inhalt zu entsorgen (zumindest beim …clean, das …flush ergibt für mich auch keinen Sinn).

        Sagt Dir denn die Problematik mit der gz-Komprimierung etwas?

        Nein, aber wenn du die nicht verwendest, dann hast du die ja nicht. Wenn doch, dann schalte sie zumindest mal zum Testen ab.

        echo "$verabschiedung $name";

        1. Hi,

          Es dient dazu, alle Ausgabepuffer (davon können ja mehrere nacheinander geöffnet werden) zu schließen und deren Inhalt zu entsorgen

          ja, aber diese Datei dient nur zum Durchschleusen von irgendwelchen Dateien, auf die nicht direkt zugegriffen werden soll. Und in der Verbindung mit ob_end_flush kapiere ich das wirklich nicht - was ich zwar zuerst immer als Wissenslücke meinerseits interpretieren würde, aber wenn Dir auch nix dazu einfällt... ;-)

          Das ist ein schönes Beispiel, warum es wichtig ist, die Gedanken, die zu einem Stück Code geführt haben, als Kommentar zu notieren

          In der Tat!

          Nein, aber wenn du die nicht verwendest, dann hast du die ja nicht. Wenn doch, dann schalte sie zumindest mal zum Testen ab.

          in diesem Falle ist es leider ein fremder Server und ich spiele nur Feuerwehr... da das ganze aber nur intern genutzt wird denke ich, die ob_end_clean-Lösung sollte erst mal passen.

          Gruesse, Joachim

          --
          Am Ende wird alles gut.