Странная ошибка: в сценарии PHP, который обслуживает видеофайлы, у меня есть несколько условий тестирования (проверка подлинности токена, убедитесь, что файл существует и т. Д.) Перед отправкой заголовка "video / mp4" и выводом файла MP4.
Если какой-либо из тестов не пройден, $fail
присваивается неверное значение.
В конце тестов есть if
утверждение:
if ($fail) {
exit;
}
Этот код работает как положено в Chrome, но не в Safari. Однако (и поверьте мне, я проверял это в любом случае), если я просто закомментировал exit;
, как в:
if ($fail) {
//exit;
}
... код отлично работает в Safari - видео сразу начинает загружаться.
Я уверен, что этот блок if
никогда не будет введен, в противном случае сценарий прекратит выполнение, и я бы не увидел заголовок video/mp4
(не говоря уже о том, что он не будет работать в Chrome). Кроме того, все, что PHP делает за кулисами, должно быть полностью прозрачным для браузера. Я подумал, что может быть какая-то проблема с выводом, но я бы получил предупреждение, если бы выводил что-либо до заголовков.
Я видел это поведение в течение нескольких дней - я проверял это, вероятно, 25 раз в неверии.
Конечно, я что-то упускаю?
UPDATE
Чтобы прояснить проблему, я немного изменил код:
$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» выводится также, как и ожидалось.)
Теперь, когда я комментирую $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
, как если бы я явно установил $fail
в true
- и вместо этого он вывел бы text/html
страницу со словом «Fail» - верно?
ОБНОВЛЕНИЕ 3
Вот весь соответствующий код, просто для полной ясности:
// 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 различных ответа:
1) Если я прошил $fail = true;
до if ($fail) die('Fail');
, просто у меня есть базовая линия для сбоя, я получаю заголовок text/html
, и слово "Fail" выводится, как и ожидалось.
2) Если я оставлю код, как указано выше, я получу заголовок video/mp4
, но неработающее видео в Safari (оно будет воспроизводиться в Chrome).
3) Наконец (и это основано на новом тестировании, которое я провел сегодня), если я закомментирую $fail = true;
в условной проверке токена, я получу заголовок video/mp4
, и видео будет воспроизведено в Safari. Теперь я понял, что must что-то не так с проверкой токена - но когда я провожу в другом тесте, чтобы повторить значение $ fail после теста, это все равно false! Условие никогда не вводится (я также просто ставлю прямую die('!');
вместо $fail = true;
- и я все еще получаю заголовок video/mp4
).
Я просто не могу поверить, что комментирование кода, который никогда не выполняется, может вызвать отчетливый ответ - и более того, что будет воспроизводиться в Chrome, но не в Safari; что бы ни происходило на стороне сервера с PHP, он должен быть полностью прозрачным для браузера.
Сумасшедший.
AHA!
Я добавил таквходя в мой скрипт, и получается, что при обслуживании видео HTML5 браузер делает два запроса.
Вот два (успешных) запроса из 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 (первый успешный, второй неудачный):
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]
Я должен уйти прямо сейчас, но я почти уверен, что это поведение является причиной ошибки.По какой-то причине 2-й запрос Safari не может найти токен.