<?php
class StreamResponse {
/**
* @var string|null
*/
private $path;
/**
* @var resource|null
*/
private $stream;
/**
* @var int
*/
private $buffer = 102400;
/**
* @var int
*/
private $start = -1;
/**
* @var int
*/
private $end = -1;
/**
* @var int
*/
private $size = 0;
/**
* @var array<string, array<int, string>>
*/
private $headers;
/**
* @var int
*/
private $status;
public function __construct(string $filePath, array $headers = [], int $status = 200)
{
$this->path = $filePath;
$this->headers = $headers;
$this->status = $status;
}
/**
* Start streaming video content.
*/
public function send(): void
{
$this->open();
$this->setHeader();
$this->stream();
fclose($this->stream);
}
/**
* Open stream.
*
*
* @throws RuntimeException
*/
private function open(): void
{
if (!($this->stream = fopen($this->path, 'rb'))) {
throw new RuntimeException('Could not open stream for reading');
}
}
/**
* Set proper header to serve the video content.
*/
private function setHeader(): void
{
ob_get_clean();
http_response_code($this->status);
foreach ($this->headers as $header => $values) {
$values = (array) $values;
header($header . ': ' . implode(',', $values));
}
header('Content-Type: ' . mime_content_type($this->path), false);
header('Cache-Control: max-age=2592000, public', false);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 2592000) . ' GMT', false);
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', @filemtime($this->path)) . ' GMT', false);
$this->start = 0;
$this->size = filesize($this->path);
$this->end = $this->size - 1;
header('Accept-Ranges: 0-' . $this->end);
if (isset($_SERVER['HTTP_RANGE'])) {
$c_end = $this->end;
[, $range] = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (false !== strpos($range, ',')) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $this->start-$this->end/$this->size");
return;
}
if ('-' === $range) {
$c_start = $this->size - substr($range, 1);
} else {
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $c_end;
}
$c_end = ($c_end > $this->end) ? $this->end : $c_end;
if ($c_start > $c_end || $c_start > $this->size - 1 || $c_end >= $this->size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header('Content-Range: bytes ' . $this->start - $this->end . '/' . $this->size);
return;
}
$this->start = $c_start;
$this->end = $c_end;
$length = $this->end - $this->start + 1;
fseek($this->stream, $this->start);
header('HTTP/1.1 206 Partial Content');
header('Content-Length: ' . $length);
header('Content-Range: bytes ' . $this->start - $this->end . '/' . $this->size);
} else {
header('Content-Length: ' . $this->size);
}
}
/**
* perform the streaming of calculated range.
*/
private function stream(): void
{
$i = $this->start;
set_time_limit(0);
while (!feof($this->stream) && $i <= $this->end) {
$bytesToRead = $this->buffer;
if (($i + $bytesToRead) > $this->end) {
$bytesToRead = $this->end - $i + 1;
}
$data = fread($this->stream, $bytesToRead);
echo $data;
flush();
$i += $bytesToRead;
}
}
}
- Output for 7.1.0 - 7.1.33, 7.2.0 - 7.2.34, 7.3.0 - 7.3.31, 7.4.0 - 7.4.25, 8.0.0 - 8.0.12
- Output for 7.0.0 - 7.0.33
- Parse error: syntax error, unexpected ',', expecting ']' in /in/KeUdg on line 99
Process exited with code 255. - Output for 5.6.0 - 5.6.40
- Fatal error: Default value for parameters with a class type hint can only be NULL in /in/KeUdg on line 44
Process exited with code 255.
preferences:
148.75 ms | 401 KiB | 218 Q