Das erste, was Sie tun müssen, ist, den Accept-Ranges: bytes
Header in allen Antworten zu senden , um dem Client mitzuteilen, dass Sie Teilinhalte unterstützen. Dann wird , wenn Anfrage mit einem Range: bytes=x-y
Header empfangen wird (mit x
und für y
Zahlen) analysieren Sie den Bereich der Client anfordert, öffnen Sie die Datei wie gewohnt, seek x
Bytes voraus und die nächsten senden y
- x
Bytes. Stellen Sie auch die Antwort auf ein HTTP/1.0 206 Partial Content
.
Ohne etwas getestet zu haben, könnte dies mehr oder weniger funktionieren:
$filesize = filesize($file);
$offset = 0;
$length = $filesize;
if ( isset($_SERVER['HTTP_RANGE']) ) {
// if the HTTP_RANGE header is set we're dealing with partial content
$partialContent = true;
// find the requested range
// this might be too simplistic, apparently the client can request
// multiple ranges, which can become pretty complex, so ignore it for now
preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$offset = intval($matches[1]);
$length = intval($matches[2]) - $offset;
} else {
$partialContent = false;
}
$file = fopen($file, 'r');
// seek to the requested offset, this is 0 if it's not a partial content request
fseek($file, $offset);
$data = fread($file, $length);
fclose($file);
if ( $partialContent ) {
// output the right headers for partial content
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes ' . $offset . '-' . ($offset + $length) . '/' . $filesize);
}
// output the regular HTTP headers
header('Content-Type: ' . $ctype);
header('Content-Length: ' . $filesize);
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Accept-Ranges: bytes');
// don't forget to send the data too
print($data);
Ich habe vielleicht etwas Offensichtliches übersehen und einige potenzielle Fehlerquellen definitiv ignoriert, aber es sollte ein Anfang sein.
Es gibt hier eine Beschreibung des Teilinhalts und ich habe einige Informationen zum Teilinhalt auf der Dokumentationsseite für fread gefunden .
$length
ist er negativ.$length = (($matches[2]) ? intval($matches[2]) : $filesize) - $offset;
behebt das. 2.Content-Range
behandelt das erste Byte als Byte0
, also das letzte Byte$filesize - 1
. Deshalb muss es sein($offset + $length - 1)
.EDIT 2017/01 - Ich habe eine Bibliothek geschrieben, um dies in PHP> = 7.0 https://github.com/DaveRandom/Resume zu tun
EDIT 2016/02 - Code einer Reihe von modularen Werkzeugen ein Beispiel Nutzung, sondern als eine monolithische Funktion komplett neu geschrieben. Die in den Kommentaren unten erwähnten Korrekturen wurden übernommen.
Eine getestete, funktionierende Lösung (die stark auf der obigen Antwort von Theo basiert), die sich mit wiederaufnehmbaren Downloads in einigen eigenständigen Tools befasst. Dieser Code erfordert PHP 5.4 oder höher.
Diese Lösung kann immer noch nur einen Bereich pro Anfrage bewältigen, aber unter allen Umständen mit einem Standardbrowser, den ich mir vorstellen kann, sollte dies kein Problem verursachen.
Anwendungsbeispiel:
quelle
$start = $end - intval($range[0]);
sollte seinrange[1]
Das funktioniert 100% super check it Ich benutze es und keine Probleme mehr.
quelle
Ja. Support byteranges. Siehe RFC 2616, Abschnitt 14.35 .
Dies bedeutet im Grunde, dass Sie den
Range
Header lesen und die Datei ab dem angegebenen Offset bereitstellen sollten.Dies bedeutet, dass Sie readfile () nicht verwenden können, da dies die gesamte Datei bedient. Verwenden Sie stattdessen zuerst fopen () , dann fseek () an der richtigen Position und dann fpassthru () , um die Datei bereitzustellen .
quelle
echo file_get_contents(...)
hat nicht funktioniert (OOM). Ich denke also nicht, dass das ein Problem ist. PHP 5.3.fpassthru
sogar bei 50-MB-Dateien fehl. Sie sollten es definitiv nicht verwenden, wenn Sie große Dateien mit schwacher Serverkonfiguration bereitstellen. Wie @Wimmer richtig hervorhebt, istfread
+print
alles, was Sie in diesem Fall benötigen.Eine wirklich gute Möglichkeit, dies zu lösen, ohne Ihren eigenen PHP-Code "rollen" zu müssen, ist die Verwendung des Apache-Moduls mod_xsendfile. Dann setzen Sie in PHP einfach die entsprechenden Header. Apache darf sein Ding machen.
quelle
XSendFilePath <absolute path> [AllowFileDelete]
( tn123.org/mod_xsendfile/beta )).Wenn Sie bereit sind , ein neues PECL - Modul zu installieren, der einfachste Weg , resumeable Downloads mit PHP zu unterstützen , ist durch
http_send_file()
, wie diesQuelle: http://www.php.net/manual/en/function.http-send-file.php
Wir verwenden es, um in der Datenbank gespeicherte Inhalte bereitzustellen, und es funktioniert wie ein Zauber!
quelle
Die Top-Antwort hat verschiedene Fehler.
bytes a-b
bedeuten sollte[a, b]
statt[a, b)
undbytes a-
wird nicht behandelt.Hier ist mein geänderter Code:
quelle
ini_set('memory_limit', '-1');
?if(!isset($matches[2])) { $end=$fs-1; } else { $end = intval($matches[2]); }
Ja, dafür können Sie den Range-Header verwenden. Sie müssen dem Client 3 weitere Header für einen vollständigen Download geben:
Für einen unterbrochenen Download müssen Sie den Header der Bereichsanforderung überprüfen, indem Sie:
Und vergessen Sie in diesem Fall nicht, den Inhalt mit dem Statuscode 206 bereitzustellen:
Sie erhalten die Variablen $ start und $ to aus dem Anforderungsheader und verwenden fseek (), um nach der richtigen Position in der Datei zu suchen.
quelle
Das hat bei mir sehr gut funktioniert: https://github.com/pomle/php-serveFilePartial
quelle
Kleine Composer-fähige Klasse, die genauso funktioniert wie pecl http_send_file. Dies bedeutet Unterstützung für wiederaufnehmbare Downloads und Drosselung. https://github.com/diversen/http-send-file
quelle
Das Fortsetzen von Downloads in HTTP erfolgt über den
Range
Header. Wenn die Anforderung enthält einenRange
Header, und wenn andere Indikatoren (zBIf-Match
,If-Unmodified-Since
) zeigen an, dass der Inhalt nicht , da der Download geändert hat begonnen, Sie einen 206 - Antwortcode geben (statt 200), geben Sie den Bereich von Bytes Sie RückkehrContent-Range
Geben Sie dann im Header diesen Bereich im Antworttext an.Ich weiß allerdings nicht, wie ich das in PHP machen soll.
quelle
Danke Theo! Ihre Methode funktionierte nicht direkt für das Streaming von DivX, da ich feststellte, dass der DivX-Player Bereiche wie Bytes = 9932800- sendete.
aber es hat mir gezeigt, wie es geht, danke: D.
quelle
Sie können den folgenden Code für die Unterstützung von Bytebereichsanforderungen in jedem Browser verwenden
quelle