PHP实现仅注册用户访问视频目录的高效方案求助
最优解决方案
方案1:使用Apache/Nginx的X-Sendfile(推荐)
这是性能最优的方案,PHP只负责权限校验,实际文件由Web服务器直接发送,不会占用PHP进程,也支持断点续传、快速跳转。
Apache配置(配合.htaccess)
- 确保Apache启用了
mod_xsendfile模块 - 在项目的.htaccess中添加:
XSendFile On XSendFilePath /path/to/your/protected/video/folder
- PHP校验脚本(比如
serve-media.php):
<?php // 先校验用户是否已登录(替换为你的登录校验逻辑) if (!isset($_SESSION['user_id'])) { header("HTTP/1.1 403 Forbidden"); exit("Access Denied"); } // 获取请求的文件名(安全过滤,防止目录遍历) $filename = basename($_GET['file']); $file_path = '/path/to/your/protected/video/folder/' . $filename; // 校验文件存在 if (!file_exists($file_path)) { header("HTTP/1.1 404 Not Found"); exit("File Not Found"); } // 设置对应MIME类型 $mime_type = mime_content_type($file_path); header("Content-Type: $mime_type"); // 让Apache发送文件 header("X-Sendfile: $file_path"); exit;
- 前端调用:
<!-- 图片 --> <img src="serve-media.php?file=example.png" alt="Protected Image"> <!-- 视频 --> <video controls src="serve-media.php?file=example.mp4"></video>
方案2:Nginx的X-Accel-Redirect
如果使用Nginx,原理和X-Sendfile一致,仅需替换为X-Accel-Redirect头:
- Nginx配置(在server块内):
location /protected-media/ { internal; # 只允许内部请求访问 root /path/to/your/; # 填写保护文件夹的上级目录 }
- PHP校验脚本:
<?php // 登录校验逻辑 if (!isset($_SESSION['user_id'])) { header("HTTP/1.1 403 Forbidden"); exit("Access Denied"); } $filename = basename($_GET['file']); $file_path = '/protected-media/video-folder/' . $filename; // 对应Nginx的location路径 if (!file_exists('/path/to/your/' . $file_path)) { header("HTTP/1.1 404 Not Found"); exit("File Not Found"); } $mime_type = mime_content_type('/path/to/your/' . $file_path); header("Content-Type: $mime_type"); header("X-Accel-Redirect: $file_path"); exit;
- 前端调用和方案1一致
方案3:优化PHP流实现(解决跳转问题)
如果暂时无法使用Web服务器的X-Sendfile/X-Accel-Redirect,可优化PHP流的断点续传支持,实现视频快速跳转:
<?php session_start(); if (!isset($_SESSION['user_id'])) { header("HTTP/1.1 403 Forbidden"); exit; } $file = '/path/to/your/protected/video/folder/' . basename($_GET['file']); if (!file_exists($file)) { header("HTTP/1.1 404 Not Found"); exit; } $mime_type = mime_content_type($file); $file_size = filesize($file); // 处理断点续传 $offset = 0; $length = $file_size; if (isset($_SERVER['HTTP_RANGE'])) { preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches); $offset = intval($matches[1]); $length = isset($matches[2]) ? intval($matches[2]) - $offset + 1 : $file_size - $offset; header("HTTP/1.1 206 Partial Content"); header("Content-Range: bytes $offset-" . ($offset + $length - 1) . "/$file_size"); } header("Content-Type: $mime_type"); header("Content-Length: $length"); header("Accept-Ranges: bytes"); header("Cache-Control: public"); $fp = fopen($file, 'rb'); fseek($fp, $offset); while ($length > 0) { $chunk_size = min(1024 * 1024, $length); // 按1MB分块读取 echo fread($fp, $chunk_size); flush(); $length -= $chunk_size; } fclose($fp); exit;
优化后的脚本支持断点续传,视频跳转流畅度会大幅提升,同时比Base64嵌入节省约30%的带宽。
内容的提问来源于stack exchange,提问作者Leander
相关产品推荐
相关产品推荐

