为什么我不能在文档根目录之外投射由PHP提供的MP4文件? [英] Why can't I cast an MP4 file served by PHP from outside of the document root?
问题描述
好吧,我放弃...发生了非常奇怪的事情,经过数天的混乱,我不得不寻求帮助。我有一个PHP脚本,可从文档根目录外部提供MP4文件。该脚本非常有用,除了一个非常重要的细节(至少对我而言):它不会给我选择投射内容的选项。在同一台服务器上,当我访问位于文档根目录中的MP4文件时,将加载页面,然后单击Chrome视频播放器右下角的三个点,即可选择下载或投射到我的Chromecast。使用我的脚本,我只能选择下载,而我真的需要CAST!我已经做了很多调整,以至于任何一个方法的标题输出都几乎是相同的。这是我的代码...
Ok, I give up... Something very strange is going on and, after days of messing with this, I have to ask for help. I have a PHP script that serves an MP4 file from outside of the document root. This script works great, except for one very important (to me at least) detail: it will not give me the option to cast the content. On the same server, when I access an MP4 file that IS inside the document root, I load the page and when I click the three dots in the bottom right corner of the Chrome video player, I have the option to Download or Cast to my Chromecast. Using my script, I only have the option to Download, and I REALLLLY need to CAST! I have tweaked this so much that the headers output from either method are all but identical. Here is my code...
<?php
$file=$_GET['file'];
//validate
if($file=="." || $file==".."){$file="";}
$mediaRoot="../../../hostMedia";
$file=$mediaRoot . DIRECTORY_SEPARATOR . $file;
$file=str_replace('\\',"/",$file);
$filesize = filesize($file);
$offset = 0;
$length = $filesize;
// find the requested range
preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$offset = intval($matches[1]);
$length = (($matches[2]) ? intval($matches[2]) : $filesize) - $offset;
// output the right headers for partial content
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes ' . $offset . '-' . ($offset + $length-1) . '/' . $filesize);
header('Content-Type: video/mp4');
header('Content-Length: ' . $filesize);
header('Accept-Ranges: bytes');
header('Cache-Control: max-age=0');
// open file for reading
$file = fopen($file, 'r');
// seek to the requested offset, this is 0 if it's not a partial content request
fseek($file, $offset);
// populate $data with all except the last byte of the file
$numBytes=($filesize-1);
$dataLen=0;
while($dataLen<$numBytes){
$lenGrab=($numBytes-$dataLen);
if($lenGrab>(1024*2700)){$lenGrab=(1024*2700);}
$data=fread($file, $lenGrab);
print($data);
$dataLen+=strlen($data);
}
// close file
fclose($file);
?>
一千个谢谢给解决这个问题的人!
A thousand "thank-you"s to whoever solves this one!
更新
好吧,我接受@Brian Heward的建议,花了无数小时来确保标题是绝对相同!!!我非常确定它会起作用,但是,遗憾的是,它仍然无法让我选择投射。这是我更新的PHP ...
Ok, taking @Brian Heward's advice, I have spent countless hours making sure that the headers are ABSOLUTELY IDENTICAL!!! I was so sure it would work, but alas, it still fails to give me the option to cast. Here is my updated PHP...
<?php
session_start();
$accessCode=$_SESSION['accessCode'];
$file=$_GET['file'];
//handle injection
if($file=="." || $file==".."){$file="";}
if($accessCode=="blahblahblah8"){
$mediaRoot="../../../hostMedia";
$file=$mediaRoot . DIRECTORY_SEPARATOR . $file;
$file=str_replace('\\',"/",$file);
$filesize = filesize($file);
$offset = 0;
$length = $filesize;
$lastMod=filemtime($file);
if ( isset($_SERVER['HTTP_RANGE']) ) {
// if the HTTP_RANGE header is set we're dealing with partial content
$partialContent = true;
// find the requested range
preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$offset = intval($matches[1]);
$length = (($matches[2]) ? intval($matches[2]) : $filesize) - $offset;
} else {
$partialContent = false;
}
if ( $partialContent ) {
// output the right headers for partial content
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes ' . $offset . '-' . ($offset + $length-1) . '/' . $filesize);
}else{
header('HTTP/1.1 200 OK');
}
// output the regular HTTP headers
header('Content-Type: video/mp4');
header('Content-Length: ' . $length);
header('Accept-Ranges: bytes');
header('ETag: "3410d79f-576de84c004aa"');
header('Last-Modified: '.gmdate('D, d M Y H:i:s \G\M\T', $lastMod));
// don't forget to send the data too
$file = fopen($file, 'r');
// seek to the requested offset, this is 0 if it's not a partial content request
fseek($file, $offset);
//populate $data with all except the last byte of the file
$numBytes=($length);
$dataLen=0;
while($dataLen<$numBytes){
$lenGrab=($numBytes-$dataLen);
if($lenGrab>(1024*2700)){$lenGrab=(1024*2700);}
$data=fread($file, $lenGrab);
print($data);
$dataLen+=strlen($data);
}
fclose($file);
}else{
echo "You are not authorized to view this media.";
}
?>
如果有人可以使用此工具,那么您真的是超级英雄!
If someone can get this thing to work, you are seriously a superhero!
最终更新(现在……)
经过很多小时的挫折之后,我不得不放弃这种方法,尝试一些不同的方法。幸运的是,通常有不止一种方法可以完成某件事,而我发现了另一种方法。我将doc根目录下的.mp4文件托管在使用HTTP Basic Auth保护的文件夹中。与我要达到的目标非常相似,它正在为我工作。谢谢您的建议和指导!
Well, after many, many hours of frustration, I had to abandon the approach and try something different. Luckily, there are usually more than one way to accomplish something, and I have found another way. I am hosting the .mp4 files inside the doc root in a folder protected using HTTP Basic Auth. Very similar to what I was trying to achieve and it is working for me. Thanks for your advice and direction!
推荐答案
您的标头都是一样的,这就是问题所在。使它们相同:P
Your headers are "all but identical" and there is the problem. Make them identical :P
使用浏览器上的开发人员工具(F12),并检查每个请求发出的网络标头。最可能的原因是我在类似项目中使用的以下几行,但您似乎不见了:
Use the developer tools on your browser, (F12) and check the network headers each request is making. The most likely causes are the following lines I used on a similar project and you seem to be missing:
header('Content-Description: File Transfer');
header('Content-Disposition: inline; filename=' . basename($file));
或者它可能想要
header('Content-Disposition: attachment; filename=' . basename($file));
这篇关于为什么我不能在文档根目录之外投射由PHP提供的MP4文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!