奇怪的错误:在提供视频文件的PHP脚本中,在发送“video / mp4”标题并输出MP4文件之前,我有一些测试条件(验证令牌,确保文件存在等)。
如果任何测试失败,$fail
将被赋予非假值。
在测试结束时,有if
声明:
if ($fail) {
exit;
}
此代码在Chrome中按预期工作,但在Safari中无效。但是(如果我只是注释掉exit;
,请相信我,我相信我的每一个方向),如:
if ($fail) {
//exit;
}
...代码在Safari中完美运行 - 视频立即开始加载。
我确信永远不会输入if
块,否则脚本会停止执行,我不会看到video/mp4
标题(更不用说,它不会起作用)在Chrome中)。此外,无论PHP在幕后做什么,都应该对浏览器完全透明。我想也许输出存在一些问题,但如果我在标题之前输出任何内容,我会收到警告。
我已经连续几天看到这种行为 - 我难以置信地检查了25次。
肯定有一些我想念的东西?
更新
为了澄清这个问题,我改变了一下代码:
$fail = true;
if ($fail) {
die('Fail');
}
现在我们保证会点击die()
语句,并输出“Fail”。以下是标题,如Safari所示:
Connection:Keep-Alive
Content-Type:text/html
Date:Thu, 24 Jun 2010 23:31:28 GMT
Keep-Alive:timeout=10, max=29
Server:Apache/2.2.15 (CentOS) mod_ssl/2.2.15 0.9.8l DAV/2 mod_auth_passthrough/2.1 FrontPage/5.0.2.2635
Transfer-Encoding:Identity
X-Powered-By:PHP/5.2.13
(“失败”也按预期输出。)
现在,当我发表评论$fail = true;
时,标题会更改为:
Connection:Keep-Alive
Content-Length:47406944
Content-Type:video/mp4
Date:Thu, 24 Jun 2010 23:32:58 GMT
Keep-Alive:timeout=10, max=30
Server:Apache/2.2.15 (CentOS) mod_ssl/2.2.15 0.9.8l DAV/2 mod_auth_passthrough/2.1 FrontPage/5.0.2.2635
X-Powered-By:PHP/5.2.13
但视频仍然无法播放! (QuickTime徽标上面有问号。)
我认为足够的证据表明$fail
仍然是假的,die()
永远不会被执行。
现在,得到这个:如果我再次发表评论die()
(功能上等同于exit
),那么我的最终代码为:
//$fail = true;
if ($fail) {
//die('Fail');
}
...视频在Safari中播放!
更新2
如果我将代码更改为:
$fail = false;
if ($fail) {
die('Fail');
}
...绝对保证$fail
为false
,它在Safari中播放!
这种行为对我没有意义,b / c如果由于我的某个验证条件而设置$fail
,那么它将永远不会输出video/mp4
标头,就像我明确设置{ {1}}到$fail
- 相反,它会输出一个带有“失败”字样的true
页面 - 对吗?
更新3
以下是所有相关代码,只是为了完全清楚:
text/html
希望最后更新/摘要
这个问题可能已经太长了,但我想我最后一次尝试总结这是多么奇怪。有3个不同的回答:
1)如果我在// verify
$fail = false;
$token = false;
$file_name = [rest assured that $file_name is correct];
if (!$file_name) {
$fail = true;
} else {
$file_name = '../video/'.$file_name;
}
if (!isset($_REQUEST['ts'])) {
$fail = true;
}
if (isset($_POST['token']) || isset($_GET['token'])) {
$token = isset($_POST['token']) ? $_POST['token'] : $_GET['token'];
} else if (isset($_COOKIE['token'])) {
$token = $_COOKIE['token'];
}
if ($token != md5(SALT_HASH.$_REQUEST['ts'])) {
$fail = true;
}
if (((int)($_REQUEST['ts']) + 60 * 10) < mktime()) {
$fail = true;
}
if (!is_file($file_name)) {
$fail = true;
}
if ($fail) {
die('Fail');
}
// output
$file_size = (string)(filesize($file_name));
header('Content-Type: video/mp4');
header('Content-Length: '.$file_size);
readfile_chunked($file_name);
exit;
之前硬连线$fail = true;
,那么我有一个失败的基线,我得到一个if ($fail) die('Fail');
标题,并按预期输出“失败”一词
2)如果我保留上面的代码,我会得到一个text/html
标题,但Safari中的视频已损坏(它将在Chrome中播放)。
3)最后(这是基于我今天做的新测试),如果我在令牌验证条件中注释video/mp4
,我会得到一个$fail = true;
标题,视频会播放苹果浏览器。现在,我认为必须令牌验证有问题 - 但是当我在另一个测试中硬连线以在测试后回显$ fail的值时,它仍然是假的!从未输入条件(我也只是直接video/mp4
而不是die('!');
- 我仍然会得到$fail = true;
标题。
我简直无法相信注释掉永远不会被执行的代码会导致明显的响应 - 此外,将在Chrome中播放,而不是在Safari中播放;无论服务器端发生什么,PHP应该对浏览器完全透明。
疯狂。
AHA!
我在我的脚本中添加了一些日志记录,结果发现,在提供HTML5视频时,浏览器会发出两个请求。
以下是来自Chrome的两个(成功)请求:
video/mp4
这是两个来自Safari(第一次成功,第二次失败):
Fri Jun 25 17:41:22 2010 Browser: [Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4] Fail: [0] Token: [83e50b519c0ed4662b6b7fabb8f6671e] Timestamp: [1277509282]
Fri Jun 25 17:41:22 2010 Verification passed
Fri Jun 25 17:41:22 2010 Browser: [Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4] Fail: [0] Token: [83e50b519c0ed4662b6b7fabb8f6671e] Timestamp: [1277509282]
Fri Jun 25 17:41:22 2010 Verification passed
我现在必须出去,但我几乎可以肯定这种行为是bug的根源。出于某种原因,第二个Safari请求找不到令牌。
答案 0 :(得分:3)
事实证明,浏览器在播放前向<video>
源发出两个请求。我只看到第一次请求的标题,因此我的困惑。视频在Chrome中播放而不是Safari的原因是因为在Safari中发出第二个请求的代理(“QuickTime / 7.6.6(qtver = 7.6.6; cpu = IA32; os = Mac 10.6.4)”)显然可以读同样的$ _COOKIEs;而对于Chrome,$ _COOKIE在两个请求中都是完整的。
我仍然有一个严重的问题,因为视频只能在桌面浏览器上播放,而不能在iPhone上播放。我确定这不是编码问题,因为如果我直接访问MP4,它就可以正常运行;只有当视频通过PHP输出时才会出现问题。无论如何,这完全是另一个问题。
答案 1 :(得分:0)
它呈现空白页面的唯一原因是它确实进入了退出区;声明。你提到了一个身份验证令牌,在safari中测试时可能会丢失吗? Firebug和Safari的开发人员工具也可以帮助您进行调试(检查响应标头等)。
答案 2 :(得分:0)
如果没有video/mp4
标头,服务器将发送默认内容类型标头,通常为text/html
,某些浏览器可能会查看正在提供的内容并忽略MIME类型。
将error_reporting(E_ALL);
添加到脚本的开头,并使用firebug或类似方法检查正在发送的标头。