We are using a PHP scripting for tunnelling file downloads, since we don't want to expose the absolute path of downloadable file:
header("Content-Type: $ctype");
header("Content-Length: " . filesize($file));
header("Content-Disposition: attachment; filename=\"$fileName\"");
readfile($file);
Unfortunately we noticed that downloads passed through this script can't be resumed by the end user.
Is there any way to support resumable downloads with such a PHP-based solution?
Thanks Theo! your method did not directly work for streaming divx because i found the divx player was sending ranges like bytes=9932800-
but it showed me how to do it so thanks :D
The first thing you need to do is to send the
Accept-Ranges: bytes
header in all responses, to tell the client that you support partial content. Then, if request with aRange: bytes=x-y
header is received (withx
andy
being numbers) you parse the range the client is requesting, open the file as usual, seekx
bytes ahead and send the nexty
-x
bytes. Also set the response toHTTP/1.0 206 Partial Content
.Without having tested anything, this could work, more or less:
I may have missed something obvious, and I have most definitely ignored some potential sources of errors, but it should be a start.
There's a description of partial content here and I found some info on partial content on the documentation page for fread.
This works 100% super check it I am using it and no problems any more.
Yes, you can use the Range header for that. You need to give 3 more headers to the client for a full download:
Than for an interrupted download you need to check the Range request header by:
And in this case don't forget to serve the content with 206 status code:
You'll get the $start and $to variables from the request header, and use fseek() to seek to the correct position in the file.
EDIT 2017/01 - I wrote a library to do this in PHP >=7.0 https://github.com/DaveRandom/Resume
EDIT 2016/02 - Code completely rewritten to a set of modular tools an an example usage, rather than a monolithic function. Corrections mentioned in comments below have been incorporated.
A tested, working solution (based heavily on Theo's answer above) which deals with resumable downloads, in a set of a few standalone tools. This code requires PHP 5.4 or later.
This solution can still only cope with one range per request, but under any circumstance with a standard browser that I can think of, this should not cause a problem.
Example usage:
Resuming downloads in HTTP is done through the
Range
header. If the request contains aRange
header, and if other indicators (e.g.If-Match
,If-Unmodified-Since
) indicate that the content hasn't changed since the download was started, you give a 206 response code (rather than 200), indicate the range of bytes you're returning in theContent-Range
header, then provide that range in the response body.I don't know how to do that in PHP, though.