Hello,
Das ist aber nett geworden im Manual. Unter "Example #1 Forcing a download using readfile()" ist ja auch genau das Beispiel, das pat benötigt und das ich eigentlich unter header() vermutet hatte...
Allerdings habe ich schon die ganze Zeit darüber nachgedacht, welchen praktischen Nutzen das jetzt haben soll, dass dort
ob_clean();
flush();
eingesetzt wird, _nachdem_ die Header gesetzt wurden. Und auch der Einsatz von file_exists() ist nicht ganz sauber.
Das sollte mMn besser so aussehen. Wenn schon ein Output-Buffering durchgeführt wurde, hat der Programmierer sowieso den Plan verloren. Aber so ist es mMn logischer.
#if (ob_get_level() == 0 and !headers_sent()) ## dachte ich erst, aber OB kann
## ja noch geschachtelt werden
ini_set('track_errors', 1);
if (!headers_sent())
{
ob_start();
if (false !== ($len == @readfile($file))) ## File in den neuen OB laden
{
## Nur bei Erfolg Header ausgeben
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $len);
ob_end_clean();
exit; ## alle anderen OBs werden geschlosen
## und weggeschmissen?
}
else
{
## ## Fehlerbehandlung, Ausgabe oder Logging...
## echo $php_errormsg; ## hierfür ist 'track_errors = 1' notwendig
##
}
ob_end_clean();
}
Somit müsste sowohl das TOCTOU-Problem als auch das Senden von falschen Headern für den Fall, dass keine Datei da ist, oder diese nicht lesbar ist, gelöst sein.
Mir ist im Moment die Wirkung von exit auf gestaffelte OBs noch nicht sicher klar...
Werden die offenen OBs bei exit alle weggeschmissen?
Wie ist Eure Meinung dazu?
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg