使用 PHP 逻辑流式传输文件


Streaming files with PHP logic

在我们的网站上,用户可以上传mp3音频和mp4视频媒体。他们还可以在其上设置私有/公共标志,以拒绝除他们之外的其他用户的访问。

我们想流式传输这些媒体并使用一些 Javascript 播放器显示它们,但由于我们需要执行一些 PHP 逻辑,我们不能让 Web 服务器流式传输它们。

流式传输这些媒体并能够在之前执行一些PHP逻辑(授予或拒绝访问)的有效方法是什么?

我已经编写并测试了这个脚本以供下载。也应该适用于流媒体。

$file_name = $_GET['file'];
/* define UPLOADS_DIR */
$file_path = UPLOADS_DIR . $file_name;
if (!is_file($file_path)) {
    header('HTTP/1.0 404 Not Found');
    exit;
}
/* define has_access */
if (!has_access($file_name)) {
    header('HTTP/1.0 403 Forbidden');
    exit;
}
$file = fopen($file_path, 'rb');
if (!$file) {
    header('HTTP/1.0 500 Internal Server Error');
    exit;
}
$file_size = filesize($file_path);
$start = 0;
$end = $file_size - 1;
$length = $file_size;
if (isset($_SERVER['HTTP_RANGE'])) {
    if (!preg_match('/^bytes=('d*)-('d*)/', $_SERVER['HTTP_RANGE'], $matches) || ($matches[1] === '' && $matches[2] === '')) {
        header('HTTP/1.1 416 Requested Range Not Satisfiable');
        fclose($file);
        exit;
    }
    $start = (int)$matches[1];
    $end = $matches[2] === '' ? $file_size - 1 : (int)$matches[2];
    if ($start >= $end || $end >= $file_size) {
        header('HTTP/1.1 416 Requested Range Not Satisfiable');
        fclose($file);
        exit;
    }
    $length = $end - $start + 1;
}
if ($length != $file_size) {
    header('HTTP/1.1 206 Partial Content');
    header('Content-Range: bytes ' . $start . '-' . $end . '/' . $file_size);
}
else {
    header('HTTP/1.1 200 OK');
}
header('Pragma: public');
header('Expires: -1');
header('Cache-Control: public, must-revalidate, post-check=0, pre-check=0');
header('Accept-Ranges: bytes');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $file_name . '"');
header('Content-Length: ' . $length);
set_time_limit(0);
/* you can modify the chunk size */
$chunk_size = 1024 * 8;
fseek($file, $start);
$left = $length;
while ($left > 0) {
    $size = $chunk_size > $left ? $left : $chunk_size;
    echo fread($file, $size);
    ob_flush();
    flush();
    if (connection_status()) {
        fclose($file);
        exit;
    }
    $left -= $size;
}
fclose($file);