2010-06-24 2 views
4

Необычная ошибка: в скрипте PHP, обслуживающем видеофайлы, у меня есть несколько условий тестирования (аутентификация токена, убедитесь, что файл существует и т. д.) перед отправкой заголовка «video/mp4» и вывод MP4-файл.Отдельный PHP-выход; заявление предотвращает видео HTML5 в Safari

Если какой-либо из тестов завершился с ошибкой, $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() заявление, и выход "провал". Вот заголовки, как видно 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!

UPDATE 2

Если изменить код:

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

... абсолютно гарантировать, что $fail является false, он играет в Safari!

Такое поведение не имеет смысла для меня, б/с, если $fail был быть установлен из-за одного из моих условий проверки, то он никогда не будет выводить video/mp4 заголовок, так как, когда я явно установить $fail к true - и вместо этого будет выведите страницу text/html со словом «Сбой» - правильно?

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

надеюсь, последний UPDATE/СУЩНОСТЬ

Этот вопрос, вероятно, уже слишком но я подумал, что в последний раз попробую подвести итог тому, как это странно. Есть 3 различных ответов:

1) Если я $fail = true; проводных перед тем if ($fail) die('Fail');, просто так, у меня есть базовый уровень для отказа, я получаю text/html заголовок, и слово «нормально» выводится, как и ожидалось.

2) Если я оставляю код, как он выше, я получаю заголовок video/mp4, но сломанное видео в Safari (оно будет воспроизводиться в Chrome).

3) Наконец (и это основано на новом тестировании, которое я сделал сегодня), если я прокомментирую $fail = true; в условной проверке токена, я получаю заголовок video/mp4, и видео воспроизводится в Safari. Теперь я понял, что должен что-то не в порядке с проверкой маркера - но когда я затрудняюсь в другом тесте, чтобы повторить значение $ fail после теста, он по-прежнему остается ложным! Условие не вводится (я также просто положил прямой 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] 

Я должен выйти прямо сейчас, но я почти уверен, что это поведение является корнем ошибки. По какой-то причине второй запрос Safari не может найти токен.

+0

Используйте [Wireshark] (http://www.wireshark.org/) или еще один инструмент, чтобы узнать, что действительно происходит по сети. –

+0

Укажите, что вы делаете: не используйте $ _REQUEST --- используйте $ _GET и $ _POST и $ _COOKIE – alexanderpas

+0

Есть ли веская причина не использовать $ _REQUEST? В любом случае, ни один из фактических условий проверки не имеет значения, когда я изменяю значение $ fail перед окончательным «if ($ fail) {}». – JKS

ответ

3

Оказывается, браузеры делают два запроса на источник <video>, прежде чем играть в него. Я только видел заголовки для первых запросов, отсюда и мое замешательство. Причина, по которой видео, воспроизводимое в Chrome, но не в Safari, заключается в том, что агент, который делает второй запрос в Safari («QuickTime/7.6.6 (qtver = 7.6.6; cpu = IA32; os = Mac 10.6.4)»), по-видимому, может Не читайте те же $ _COOKIE; тогда как с Chrome, $ _COOKIEs неповреждены в обоих запросах.

У меня все еще есть серьезная проблема: видео воспроизводится только на настольных браузерах, а не на iPhone. Я уверен, что это не проблема кодирования, потому что, если я получаю доступ к MP4 напрямую, он отлично работает; проблема возникает только тогда, когда видео выводится через PHP. Во всяком случае, это еще один вопрос.

+0

Полезно знать, сделано для решения проблемы – Pete

+0

Спасибо. Эта же проблема возникает в текущих версиях Firefox 27 и IE 11 на Win 7. – Haprog

+0

Спасибо за информацию. Но что может быть решением проблемы? – JackFuchs

0

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

+0

Это *. * Показывает пустую страницу, когда я добавляю '$ fail = true;' перед моим 'die()' условным (см. Пояснение в исходном вопросе). Существует 3 различных ответа: text/html, video/mp4 (воспроизведение видео) и видео/mp4 (видео нарушено). Так странно. – JKS

0

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

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

+0

Правильно - это именно то, что он делает: без заголовка 'video/mp4' он возвращается к' text/html'. Но тогда в Safari есть такой странный случай, когда он * отправляет 'video/mp4' заголовок, но не воспроизводит видео (если не комментировать« exit/die'). Раздражаю голову на стол. – JKS

+0

Вы определяете '$ fail = FALSE' в самом начале или пытаетесь оценить (потенциально) неопределенную переменную? – Pete

+0

Да, в начале скрипта есть '$ fail = false;', даже когда я добавляю его во второй раз перед оператором 'if'. – JKS

Смежные вопросы