单个PHP“退出"声明阻止 Safari 中的 HTML5 视频 [英] Single PHP "exit;" statement prevents HTML5 video in Safari

查看:46
本文介绍了单个PHP“退出"声明阻止 Safari 中的 HTML5 视频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

奇怪的错误:在提供视频文件的 PHP 脚本中,在发送video/mp4"标头和输出 MP4 文件之前,我有一些测试条件(验证令牌、确保文件存在等).

Bizarre bug: in a PHP script that serves video files, I have a few test conditions (authenticate token, make sure file exists, etc.) before sending a "video/mp4" header and outputting an MP4 file.

如果任何测试失败,$fail 将被赋予一个非假值.

If any of the tests fail, $fail is given a non-false value.

在测试结束时有这个 if 语句:

At the end of the tests there's this if statement:

if ($fail) {
    exit;
}

此代码在 Chrome 中按预期工作,但在 Safari 中无效.然而(相信我,我已经测试了这一切),如果我简单地注释掉 exit;,如:

This code works as expected in Chrome, but not in Safari. However (and believe me, I've tested this every which way), if I simply comment out exit;, as in:

if ($fail) {
    //exit;
}

...代码在 Safari 中完美运行 - 视频立即开始加载.

... the code works perfectly in Safari — the video immediately starts loading.

我确信 if 块从未被输入,否则脚本将停止执行,并且我不会看到 video/mp4 标头(不是值得一提的是,它在 Chrome 中不起作用).此外,无论 PHP 在幕后做什么,都应该对浏览器完全透明.我想可能是输出有问题,但如果我在标题之前输出了任何内容,我会收到警告.

I'm sure that that if block is never entered, otherwise the script would stop executing, and I wouldn't be seeing the video/mp4 header (not to mention, it wouldn't work in Chrome). Further, whatever PHP is doing behind the scenes should be totally transparent to the browser. I thought maybe there was some issue with output, but I would have received a warning if I had outputted anything before the headers.

我几天来一直看到这种行为 - 我怀疑地检查了它大约 25 次.

I've been seeing this behavior consistently for days — I've checked it probably 25 times in disbelief.

肯定有我遗漏的东西吗?

Surely there's something I'm missing?

更新

为了澄清问题,我稍微更改了代码:

To clarify the problem, I changed the code a bit:

$fail = true;
if ($fail) {
    die('Fail');
}

现在我们保证命中die() 语句,并输出Fail".以下是 Safari 看到的标题:

Now we're guaranteed to hit the die() statement, and output "Fail". Here are the headers, as seen by 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" is outputted as expected, too.)

现在,当我注释掉 $fail = true; 时,标题变为:

Now, when I comment-out $fail = true;, the headers change to:

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 徽标.)

But the video still won't play! (QuickTime logo with a question mark over it.)

我认为这足以证明 $fail 仍然是假的,并且 die() 永远不会被执行.

I think that's evidence enough that $fail remains false, and that die() is never executed.

现在,得到这个:如果我再次注释掉 die()(功能上等同于 exit),那么我的最终代码是:

Now, get this: if I again comment out die() (functionally equivalent to exit), so that my final code is:

//$fail = true;
if ($fail) {
    //die('Fail');
}

...视频在 Safari 中播放!

... the video plays in Safari!

更新 2

如果我将代码更改为:

$fail = false;
if ($fail) {
    die('Fail');
}

... 绝对保证 $failfalse,它在 Safari 中播放!

... to absolutely guarantee that $fail is false, it plays in Safari!

这种行为对我来说毫无意义,如果 $fail 由于我的验证条件之一被设置,那么它永远不会输出 video/mp4 标头,当我将 $fail 显式设置为 true 时,它会输出一个带有Fail"字样的 text/html 页面— 对吗?

This behavior makes no sense to me, b/c if $fail was being set due to one of my verification conditions, then it would never output the video/mp4 header, as when I explicitly set $fail to true — and instead it would output a text/html page with the word "Fail" — right?

更新 3

这里是所有相关代码,只是为了完全清楚:

Here's all of the relevant code, just to be totally clear:

// 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;

希望是最后一次更新/总结

这个问题可能已经太长了,但我想我最后一次尝试总结一下这是多么奇怪.有 3 个不同的响应:

This question is probably already too long, but I thought I'd try one last time to summarize how weird this is. There are 3 distinct responses:

1) 如果我在 if ($fail) die('Fail'); 之前硬连线 $fail = true;,这样我就有了失败的基准, 我得到一个 text/html 标题,并按预期输出失败"一词.

1) If I hardwire a $fail = true; before if ($fail) die('Fail');, just so I have a baseline for failure, I get a text/html header, and the word "Fail" is outputted as expected.

2) 如果我保留上面的代码,我会得到一个 video/mp4 标头,但在 Safari 中得到一个损坏的视频(它将在 Chrome 中播放).

2) If I leave the code as it is above, I get a video/mp4 header, but a broken video in Safari (it will play in Chrome).

3) 最后(这是基于我今天所做的新测试),如果我在令牌验证条件中注释掉 $fail = true;,我会得到一个 video/mp4 标题,视频在 Safari 中播放.现在,我认为令牌验证一定有问题——但是当我在另一个测试中硬连线以在测试后回显 $fail 的值时,它仍然是错误的!从来没有输入条件(我也只是直接输入了 die('!'); 而不是 $fail = true; — 而且我仍然得到一个 video/mp4 标题).

3) Finally (and this is based on new testing I did today), if I comment out $fail = true; in the token-verification conditional, I get a video/mp4 header, and the video plays in Safari. Now, I figured there must something wrong with the token verification — but when I hardwire in another test to echo the value of $fail after the test, it's still false! The conditional is never entered (I also just put a straight die('!'); instead of $fail = true; — and I still get a video/mp4 header).

我简直不敢相信注释掉永远不会执行的代码会导致明显的响应——而且,它可以在 Chrome 中播放,但不能在 Safari 中播放;PHP 服务器端发生的任何事情都应该对浏览器完全透明.

I simply cannot believe that commenting out code that never gets executed could cause a distinct response — and furthermore, that it would play in Chrome, but not in Safari; whatever's happening server-side with PHP should be completely transparent to the browser.

疯了.

啊哈!

我在脚本中添加了一些日志记录,结果发现在提供 HTML5 视频时,浏览器发出两个请求.

I added some logging to my script, and it turns out that when serving HTML5 video, the browser makes two requests.

以下是来自 Chrome 的两个(成功)请求:

Here's the two (successful) requests from Chrome:

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

这是来自 Safari 的两个(第一次成功,第二次失败):

And here's the two from Safari (first successful, 2nd fails):

Fri Jun 25 17:41:32 2010 Browser: [Apple Mac OS X v10.6.4 CoreMedia v1.0.0.10F569] Fail: [0] Token: [6374fba3d9eac7d94de9741db76953c6] Timestamp: [1277509291]
Fri Jun 25 17:41:32 2010 Verification passed

Fri Jun 25 17:41:33 2010 Browser: [QuickTime/7.6.6 (qtver=7.6.6;cpu=IA32;os=Mac 10.6.4)] Fail: [1] Token: [] Timestamp: [1277509291]

我现在必须出去,但我几乎可以肯定这种行为是错误的根源.出于某种原因,第二个 Safari 请求找不到令牌.

I have to go out right now, but I'm almost certain this behavior is the root of the bug. For some reason, the 2nd Safari request can't find the token.

推荐答案

事实证明,浏览器在播放之前向 源发出两次请求.我只看到第一个请求的标题,因此我很困惑.视频在 Chrome 而不是 Safari 中播放的原因是因为在 Safari 中发出第二个请求的代理(QuickTime/7.6.6 (qtver=7.6.6;cpu=IA32;os=Mac 10.6.4)")显然可以' 不读取相同的 $_COOKIEs;而在 Chrome 中,$_COOKIE 在两个请求中都完好无损.

It turns out that browsers make two requests to a <video> source before playing it. I was only seeing the headers for the first requests, hence my confusion. The reason the video played in Chrome but not Safari is because the agent that makes the 2nd request in Safari ("QuickTime/7.6.6 (qtver=7.6.6;cpu=IA32;os=Mac 10.6.4)") apparently can't read the same $_COOKIEs; whereas with Chrome, the $_COOKIEs are intact across both requests.

我仍然有一个严重的问题,视频只能在桌面浏览器上播放,而不能在 iPhone 上播放.我确定这不是编码问题,因为如果我直接访问 MP4,它可以正常播放;只有通过PHP输出视频时才会出现问题.无论如何,这完全是另一个问题.

I still have a serious problem, in that the video plays only on desktop browsers, and not on the iPhone. I'm sure it's not an encoding problem, because if I access the MP4 directly, it plays fine; the problem occurs only when the video is outputted through PHP. Anyway, that's another question altogether.

这篇关于单个PHP“退出"声明阻止 Safari 中的 HTML5 视频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆