Skip to content

Instantly share code, notes, and snippets.

@MSeven
Created March 12, 2012 10:02
Show Gist options
  • Save MSeven/2021002 to your computer and use it in GitHub Desktop.
Save MSeven/2021002 to your computer and use it in GitHub Desktop.
http byte range file server
<?php
// check if the file actually exists.
if (file_exists($filePath)) {
//everything OK, log the access and start pushing the file.
$info = pathinfo($filePath);
$fileSize = filesize($filePath) - 1;
$fp = fopen($filePath, 'rb');
// push it.
header("Expires: 0");
header('Content-Type: ' . $this->extensionToMime($info['extension']));
header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
header("Pragma: no-cache");
header("Accept-Ranges: 0-$fileSize");
header("Content-Length: " . $fileSize);
if ($this->dispositionHeader) {
header('Content-Disposition: attachment; filename="' . $info['basename'] . '"');
}
$start = 0; // Start byte
$end = $fileSize; // End byte
//get the HTTP_RANGE Header (required for iPad/HTML5 pseudostreaming)
$range = $request->getServer('HTTP_RANGE');
// was the RANGE header actually set?
if ($range != NULL) {
$range = explode('=', $range);
// should be exactly 2 keys, and the request MUST be addressing by bytes.
if (count($range) == 2 && $range[0] == 'bytes') {
// now try to extract the start/end offsets.
$boundaries = explode('-', $range[1]);
// empty start defaults to 0 which is file_start.
$start = intval($boundaries[0]);
$end = intval($boundaries[1]);
// if end is empty, just push until file_end.
if ($end == 0) {
$end = $fileSize;
}
if ($end < $start || $end > $fileSize) {
header("Status: 416 Requested range not satisfiable");
header("Content-Range: */$fileSize");
return;
}
fseek($fp, $start);
header('HTTP/1.1 206 Partial Content');
// Notify the client the byte range we'll be outputting
header("Content-Range: bytes $start-$end/$fileSize");
}
} elseif ($request->getParam('start') != null) {
$start = intval(str_replace('.', '', $request->getParam('start', 0)));
if ($start < $end) {
fseek($fp, $start);
} else {
header("Status: 416 Requested range not satisfiable");
return;
}
}
$currPos = $start;
// now push the requested file section to the client.
while (! feof($fp) && $currPos < $end) {
/**
* Chunks are the sections read from the file at once.
* This significantly reduces memory usage, since only one chunk resides
* in memory at one time. Choosing a small chunk size increases the php overhead though.
*/
$chunk = 16 * 1024;
$currPos = ftell($fp);
// check if we would overshoot the requested byterange of we push the whole chunk.
if (($currPos + $chunk) > $end) {
//adjust the chunk size
$chunk = $end - $currPos;
// umm.. are we in the badlands already?
if ($chunk <= 0) {
break;
}
}
echo (fread($fp, $chunk));
ob_flush();
}
fclose($fp);
return;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment