Skip to content

Instantly share code, notes, and snippets.

@basz
Created August 21, 2017 22:19
Show Gist options
  • Select an option

  • Save basz/df36c32e0a79aef1fe6f58bae0ce07b0 to your computer and use it in GitHub Desktop.

Select an option

Save basz/df36c32e0a79aef1fe6f58bae0ce07b0 to your computer and use it in GitHub Desktop.
protected function downloadFile(ServerRequestInterface $request, string $filePath)
{
$fileName = basename($filePath);
$contentType = (new \finfo(FILEINFO_MIME))->file($filePath);
if (! file_exists($filePath)) {
throw new \Exception("File not found: $filePath");
}
if (! is_readable($filePath)) {
throw new \Exception("File not readable: $filePath");
}
// remove headers that might unnecessarily clutter up the output
$response = (new Response())
->withoutHeader('Cache-Control')
->withoutHeader('Pragma');
// default action is to send the entire file
$byteOffset = 0;
$byteLength = $fileSize = filesize($filePath);
$response = $response
->withHeader('Accept-Ranges', 'bytes')
->withHeader('Content-Disposition', "attachment; filename=$fileName");
$server = $request->getServerParams();
if (isset($server['HTTP_RANGE']) && preg_match('%bytes=(\d+)-(\d+)?%i', $server['HTTP_RANGE'], $match)) {
$byteOffset = (int) $match[1];
if (isset($match[2])) {
$finishBytes = (int) $match[2];
$byteLength = $finishBytes + 1;
} else {
$finishBytes = $fileSize - 1;
}
$response = $response
->withStatus(206, 'Partial Content')
->withHeader('Content-Range', "bytes {$byteOffset}-{$finishBytes}/{$fileSize}");
}
$byteRange = $byteLength - $byteOffset;
$response = $response
->withHeader('Content-Type', $contentType)
->withHeader('Content-Length', $byteRange)
->withHeader('Content-Description', 'Panoramic download')
->withHeader('Pragma', 'public')
->withHeader('Expires', '0')
->withHeader('Cache-Control', 'must-revalidate');
$bufferSize = 512 * 16;
$bytePool = $byteRange;
if (! $fh = fopen($filePath, 'r')) {
throw new \Exception("Could not get filehandler for reading: $filePath");
}
$buffer = new RelativeStream(new Stream($filePath, 'r'), $byteOffset);
// if (fseek($fh, $byteOffset, SEEK_SET) == -1) {
// throw new \Exception("Could not seek to offset $byteOffset in file: $filePath");
// }
$buffer->seek($byteOffset);
while ($bytePool > 0) {
$chunkSizeRequested = min($bufferSize, $bytePool);
//$buffer->attach(fread($fh, $chunkSizeRequested));
$buffer->seek($chunkSizeRequested, SEEK_CUR);
// $buffer->seek($byteOffset, SEEK_SET);
$chunkSizeActual = strlen($buffer);
if ($chunkSizeActual == 0) {
throw new \Exception("Chunksize became 0");
}
$bytePool -= $chunkSizeActual;
}
return $response->withBody($buffer);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment