Hal pertama yang perlu Anda lakukan adalah mengirim Accept-Ranges: bytes
header di semua tanggapan, untuk memberi tahu klien bahwa Anda mendukung konten parsial. Kemudian, jika permintaan dengan Range: bytes=x-y
header diterima (dengan x
dan y
menjadi nomor) Anda mengurai berbagai klien meminta, buka file seperti biasa, seek x
byte depan dan mengirim berikutnya y
- x
byte. Juga setel tanggapannya ke HTTP/1.0 206 Partial Content
.
Tanpa menguji apa pun, ini bisa berhasil, kurang lebih:
$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);
Saya mungkin telah melewatkan sesuatu yang jelas, dan saya pasti telah mengabaikan beberapa potensi sumber kesalahan, tetapi ini seharusnya menjadi permulaan.
Ada deskripsi konten parsial di sini dan saya menemukan beberapa info tentang konten parsial di halaman dokumentasi untuk fread .
$length
akan menjadi negatif.$length = (($matches[2]) ? intval($matches[2]) : $filesize) - $offset;
memperbaikinya. 2.Content-Range
memperlakukan byte pertama sebagai byte0
, jadi byte terakhir adalah$filesize - 1
. Oleh karena itu, harus demikian($offset + $length - 1)
.EDIT 2017/01 - Saya menulis perpustakaan untuk melakukan ini di PHP> = 7.0 https://github.com/DaveRandom/Resume
EDIT 2016/02 - Kode sepenuhnya ditulis ulang ke satu set alat modular, sebuah contoh penggunaan, bukan fungsi monolitik. Koreksi yang disebutkan dalam komentar di bawah telah dimasukkan.
Solusi yang teruji dan berfungsi (berdasarkan jawaban Theo di atas) yang berhubungan dengan unduhan yang dapat dilanjutkan, dalam satu set beberapa alat mandiri. Kode ini membutuhkan PHP 5.4 atau yang lebih baru.
Solusi ini masih hanya dapat menangani satu rentang per permintaan, tetapi dalam keadaan apa pun dengan browser standar yang dapat saya pikirkan, ini seharusnya tidak menimbulkan masalah.
Contoh penggunaan:
sumber
$start = $end - intval($range[0]);
harusrange[1]
Ini berfungsi 100% super, periksa Saya menggunakannya dan tidak ada masalah lagi.
sumber
Iya. Mendukung byteranges. Lihat RFC 2616 bagian 14.35 .
Ini pada dasarnya berarti bahwa Anda harus membaca
Range
header, dan mulai menyajikan file dari offset yang ditentukan.Ini berarti Anda tidak dapat menggunakan readfile (), karena itu melayani seluruh file. Sebagai gantinya, gunakan fopen () terlebih dahulu, lalu fseek () ke posisi yang benar, lalu gunakan fpassthru () untuk menyajikan file.
sumber
echo file_get_contents(...)
tidak bekerja (OOM). Jadi menurut saya itu bukan masalah. PHP 5.3.fpassthru
akan gagal bahkan pada file 50 MB. Anda sebaiknya tidak menggunakannya, jika Anda menyajikan file besar pada konfigurasi server yang lemah. Seperti yang @Wimmer tunjukkan dengan benar,fread
+print
adalah segalanya, yang Anda butuhkan dalam kasus ini.Cara yang sangat bagus untuk mengatasi ini tanpa harus "menggulung kode PHP Anda sendiri" adalah dengan menggunakan modul Apache mod_xsendfile. Kemudian di PHP, Anda tinggal mengatur header yang sesuai. Apache bisa melakukan tugasnya.
sumber
XSendFilePath <absolute path> [AllowFileDelete]
( tn123.org/mod_xsendfile/beta ).Jika Anda ingin memasang modul PECL baru, cara termudah untuk mendukung unduhan yang dapat dilanjutkan dengan PHP adalah melalui
http_send_file()
, seperti inisumber: http://www.php.net/manual/en/function.http-send-file.php
Kami menggunakannya untuk menyajikan konten yang disimpan database dan berfungsi dengan sangat baik!
sumber
Jawaban teratas memiliki berbagai bug.
bytes a-b
seharusnya berarti[a, b]
bukan[a, b)
, danbytes a-
tidak ditangani.Ini kode saya yang dimodifikasi:
sumber
ini_set('memory_limit', '-1');
?if(!isset($matches[2])) { $end=$fs-1; } else { $end = intval($matches[2]); }
Ya, Anda dapat menggunakan header Range untuk itu. Anda perlu memberikan 3 tajuk lagi kepada klien untuk unduhan lengkap:
Dari pada unduhan yang terputus, Anda perlu memeriksa header permintaan Range dengan:
Dan dalam hal ini jangan lupa untuk menyajikan konten dengan 206 kode status:
Anda akan mendapatkan $ start dan $ to variabel dari header permintaan, dan menggunakan fseek () untuk mencari posisi yang benar dalam file.
sumber
Ini bekerja dengan sangat baik untuk saya: https://github.com/pomle/php-serveFileP Partial
sumber
Kelas berkemampuan komposer kecil yang bekerja dengan cara yang sama seperti pecl http_send_file. Ini berarti dukungan untuk unduhan dan throttle yang dapat dilanjutkan. https://github.com/diversen/http-send-file
sumber
Melanjutkan unduhan dalam HTTP dilakukan melalui
Range
header. Jika permintaan berisiRange
header, dan jika indikator lain (misalnyaIf-Match
,If-Unmodified-Since
) menunjukkan bahwa konten belum berubah sejak pengunduhan dimulai, Anda memberikan 206 kode tanggapan (bukan 200), tunjukkan rentang byte yang Anda kembalikan dalamContent-Range
header, lalu berikan rentang tersebut di isi respons.Saya tidak tahu bagaimana melakukan itu di PHP.
sumber
Terima kasih Theo! metode Anda tidak langsung berfungsi untuk streaming divx karena saya menemukan pemutar divx mengirim rentang seperti byte = 9932800-
tapi itu menunjukkan kepada saya bagaimana melakukannya jadi terima kasih: D
sumber
Anda dapat menggunakan kode di bawah ini untuk dukungan permintaan rentang byte di semua browser
sumber