php
64 lines · 10 steps
How HTTP range requests stream files in PHP
A PHP file streamer that honors the Range header to serve partial content for resumable and seekable downloads.
Explained by
highlit
1<?php
2
3function streamFileWithRanges(string $path, ?string $rangeHeader): void
4{
5 if (!is_file($path)) {
6 http_response_code(404);
7 return;
8 }
9
10 $size = filesize($path);
11 $mime = mime_content_type($path) ?: 'application/octet-stream';
12 $handle = fopen($path, 'rb');
13
14 header('Content-Type: ' . $mime);
15 header('Accept-Ranges: bytes');
16 header('Content-Disposition: attachment; filename="' . basename($path) . '"');
17
18 $start = 0;
19 $end = $size - 1;
20
21 if ($rangeHeader !== null && preg_match('/^bytes=(\d*)-(\d*)$/', trim($rangeHeader), $m)) {
22 if ($m[1] === '' && $m[2] === '') {
23 http_response_code(416);
24 header('Content-Range: bytes */' . $size);
25 fclose($handle);
26 return;
27 }
28
29 if ($m[1] === '') {
30 $start = max(0, $size - (int) $m[2]);
31 } else {
32 $start = (int) $m[1];
33 if ($m[2] !== '') {
34 $end = min((int) $m[2], $size - 1);
35 }
36 }
37
38 if ($start > $end || $start >= $size) {
39 http_response_code(416);
40 header('Content-Range: bytes */' . $size);
41 fclose($handle);
42 return;
43 }
44
45 http_response_code(206);
46 header("Content-Range: bytes {$start}-{$end}/{$size}");
47 } else {
48 http_response_code(200);
49 }
50
51 $length = $end - $start + 1;
52 header('Content-Length: ' . $length);
53
54 fseek($handle, $start);
55 $chunkSize = 8192;
56 while ($length > 0 && !feof($handle)) {
57 $read = min($chunkSize, $length);
58 echo fread($handle, $read);
59 flush();
60 $length -= $read;
61 }
62
63 fclose($handle);
64}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1The Range header lets clients request byte slices, enabling resumable downloads and media seeking.
- 2Invalid or unsatisfiable ranges must return 416 with a Content-Range that reports the full size.
- 3Streaming in fixed chunks with flush() keeps memory flat regardless of file size.
Related explainers
php
<?php class NameParser {
Parsing a full name into components in PHP
string-parsing
arrays
normalization
Intermediate
8 steps
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
python
import random from typing import Iterator, List
How reservoir sampling picks k items
reservoir-sampling
streaming
randomness
Intermediate
5 steps
php
<?php namespace App\Services;
Building a cached daily leaderboard in Laravel
caching
aggregation
eager-loading
Intermediate
9 steps
php
<?php final class RotatingFileLogger {
How a rotating file logger works in PHP
logging
file-rotation
io
Intermediate
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-http-range-requests-stream-files-in-php-explained-php-7b19/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.