为何PHP VideoStream类无法加载外部视频URL?
问题原因及解决方案
核心问题
你遇到的问题主要来自两方面:PHP配置限制和原VideoStream类本身不支持远程视频资源,具体如下:
- 默认PHP可能未开启
allow_url_fopen,导致fopen()无法打开远程HTTP URL - 原类中
filesize()、filemtime()、fseek()这些函数仅支持本地文件,对远程HTTP流完全无效 - 类里硬编码了
Content-Type: video/mp4,但你传入的是OGG格式视频,响应头类型不匹配 - 远程HTTP流是顺序读取的,原类依赖的本地文件随机定位逻辑无法适配
解决步骤
1. 检查并开启PHP远程访问配置
打开XAMPP的php.ini文件(路径一般是xampp/php/php.ini),找到allow_url_fopen项,设置为:
allow_url_fopen = On
保存后重启XAMPP的Apache服务。
2. 修改VideoStream类以支持远程资源
替换原类为以下适配远程资源的版本:
<?php class VideoStream { private $url = ""; private $ch = null; private $buffer = 102400; private $start = 0; private $end = 0; private $size = 0; private $contentType = "video/mp4"; function __construct($videoUrl) { $this->url = $videoUrl; $this->initCurl(); $this->getRemoteFileInfo(); } private function initCurl() { $this->ch = curl_init($this->url); curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, false); curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false); // 仅测试用,生产环境建议开启SSL验证 } private function getRemoteFileInfo() { $tempCh = curl_init($this->url); curl_setopt($tempCh, CURLOPT_RETURNTRANSFER, true); curl_setopt($tempCh, CURLOPT_HEADER, true); curl_setopt($tempCh, CURLOPT_NOBODY, true); curl_setopt($tempCh, CURLOPT_FOLLOWLOCATION, true); curl_exec($tempCh); // 获取文件大小 $this->size = curl_getinfo($tempCh, CURLINFO_CONTENT_LENGTH_DOWNLOAD); $this->end = $this->size - 1; // 获取Content-Type $contentType = curl_getinfo($tempCh, CURLINFO_CONTENT_TYPE); if ($contentType) { $this->contentType = $contentType; } curl_close($tempCh); } private function setHeader() { ob_get_clean(); header("Content-Type: {$this->contentType}"); header("Cache-Control: max-age=2592000, public"); header("Expires: " . gmdate('D, d M Y H:i:s', time() + 2592000) . ' GMT'); header("Accept-Ranges: 0-" . $this->end); if (isset($_SERVER['HTTP_RANGE'])) { list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); if (strpos($range, ',') !== false) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); header("Content-Range: bytes {$this->start}-{$this->end}/{$this->size}"); exit; } $rangeParts = explode('-', $range); $c_start = isset($rangeParts[0]) && is_numeric($rangeParts[0]) ? intval($rangeParts[0]) : 0; $c_end = isset($rangeParts[1]) && is_numeric($rangeParts[1]) ? intval($rangeParts[1]) : $this->end; $c_end = min($c_end, $this->end); $c_start = max($c_start, 0); if ($c_start > $c_end || $c_start >= $this->size) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); header("Content-Range: bytes {$this->start}-{$this->end}/{$this->size}"); exit; } $this->start = $c_start; $this->end = $c_end; $length = $this->end - $this->start + 1; // 设置cURL的Range参数 curl_setopt($this->ch, CURLOPT_RANGE, "{$this->start}-{$this->end}"); 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}"); } } private function stream() { set_time_limit(0); curl_exec($this->ch); } private function end() { curl_close($this->ch); exit; } function start() { $this->setHeader(); $this->stream(); $this->end(); } }
3. 调用修改后的类
include_once 'videostream.php'; $stream = new VideoStream("https://www.w3schools.com/html/mov_bbb.ogg"); $stream->start();
关键修改说明
- 用cURL替代原生fopen,支持远程URL的流读取和Range请求
- 通过HEAD请求获取远程文件的大小和Content-Type,避免使用不支持远程的
filesize()/filemtime() - 移除
fseek()调用,改用cURL的CURLOPT_RANGE参数处理分段读取 - 动态设置Content-Type,适配不同格式的视频资源
内容的提问来源于stack exchange,提问作者Sudo Sur
相关产品推荐
相关产品推荐

