Единственный PHP "выход";заявление запрещает HTML5 видео в Safari - PullRequest
4 голосов
/ 25 июня 2010

Странная ошибка: в сценарии 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 не может найти токен.

Ответы [ 3 ]

3 голосов
/ 27 июня 2010

Оказывается, браузеры перед воспроизведением делают два запроса к источнику <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. Во всяком случае, это совсем другой вопрос.

0 голосов
/ 25 июня 2010

Без заголовка video/mp4 сервер отправит заголовок типа контента по умолчанию, обычно text/html, некоторые браузеры могут посмотреть, что обслуживается, и игнорировать тип MIME.

Добавьте error_reporting(E_ALL); в начало скрипта и используйте firebug или аналогичный для проверки отправляемых заголовков.

0 голосов
/ 25 июня 2010

Единственная причина, по которой он отображает пустую страницу, состоит в том, что он действительно входит в выход;заявление.Вы упомянули токен аутентификации, может ли он отсутствовать при тестировании в сафари?Инструменты разработчика Firebug и Safari также могут помочь вам в отладке (проверьте заголовки ответов и т. Д.).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...