2013-11-22 2 views
0

У меня есть потоковое видео, прекрасно работающее в CakePHP. Поскольку видеоролики являются частными для каждого пользователя, у меня есть контроллер CakePHP, который обслуживает файлы, если пользователи аутентифицированы. Я также замечаю, что все запросы, отправленные на сервер, имеют заголовок Cookie: CAKEPHP=<stuff> в их запросе.HTML5 видео в CakePHP

Проблема заключается в том, что когда пользователь останавливается, затем воспроизводит видео или когда пользователь ищет видео, Chrome отправляет запрос диапазона с определенным диапазоном байтов для моего сервера. Запрос немедленно отменяется. Следует отметить, что этот запрос не имеет заголовкаCookie: CAKEPHP=<stuff>.

Я считаю, что запрос отклонен, потому что нет cookie сеанса. Как заставить хром (и, возможно, другие браузеры) отправлять файлы cookie сеанса?

Мои CakePHP версии 2.4.1

EDIT:

view_media.ctp

<?php echo $this->Html->script(array('//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js', 'mediaelement-and-player'), array('inline' => false)); 
echo $this->Html->css(array('mediaelementplayer.min'), array('inline' => false)); 
?> 
<video width="320" height="240" controls preload="none"> 
<?php 
    if(isset($_SERVER['HTTP_USER_AGENT'])){ 
     $agent = $_SERVER['HTTP_USER_AGENT']; 
     if (strpos($agent,'Chrome') !== false) { 
      echo '<source src="/pages/get_media/264/webm" type="video/webm">'; 
     } 
     if (strpos($agent,'Mozilla') !== false) { 
      echo '<source src="/pages/get_media/264/mp4" type="video/mp4">'; 
     } 
    } 
?> 
Your browser does not support HTML5. 
</video> 

(Функция view_media в контроллере пустым)

Соответствующий раздел PagesController

public function get_media($id, $type){ 
    $dbh = new PDO('mysql:host='.$dbhost;dbname=$dbname, $username, $password); 
    //get media info 
    $sth = $dbh->prepare("SELECT `owner`, `type` FROM media WHERE id=:id"); 
    $sth->bindParam(':id', $id); 
    $sth->execute(); 
    $row = $sth->fetch(); 
    if($row['owner'] == $this->Auth->user('id')){ 
     if($row['type'] == 'png'){ 
      header("Content-type: image/png"); 
      echo file_get_contents("/srv/Ads/Ad_".$id.".png"); 
     }else if($row['type'] == 'mp4'){ 
      if($type == "mp4"){ 
       header("Content-type: video/mp4"); 
       $filename = "/srv/Ads/Ad_".$id.".mp4"; 
      }else if($type == "webm"){ 
       header("Content-type: video/webm"); 
       $filename = "/srv/Ads/Ad_".$id.".webm"; 
      }else{ 
       die; 
      } 
      $this->send_video($filename); 
     } 
     die; 
    } 
} 
//thanks to http://stackoverflow.com/questions/16732419/mp4-from-php-not-playing-in-html5-video-tag 
private function send_video($path){ 
    if (file_exists($path)){ 
     $size=filesize($path); 
     [email protected]($path,'rb'); 
     if(!$fm) { 
      // You can also redirect here 
      header ("HTTP/1.0 404 Not Found"); 
      die; 
     } 
     $begin=0; 
     $end=$size; 
     if(isset($_SERVER['HTTP_RANGE'])) { 
      if(preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', 
      $_SERVER['HTTP_RANGE'],$matches)){ 
       $begin=intval($matches[0]); 
       if(!empty($matches[1])) { 
        $end=intval($matches[1]); 
       } 
      } 
     } 
     if($begin>0||$end<$size) 
      header('HTTP/1.0 206 Partial Content'); 
     else 
      header('HTTP/1.0 200 OK'); 
     header('Accept-Ranges: bytes'); 
     header('Content-Length:'.($end-$begin)); 
     header("Content-Disposition: inline;"); 
     header("Content-Range: bytes $begin-$end/$size"); 
     header("Content-Transfer-Encoding: binary\n"); 
     header('Connection: close'); 
     $cur=$begin; 
     fseek($fm,$begin,0); 
     while(!feof($fm)&&$cur<$end&&(connection_status()==0)){ 
      echo fread($fm,min(1024*16,$end-$cur)); 
      $cur+=1024*16; 
      usleep(1000); 
     } 
     die; 
    } 
} 

(get_media не имеет вид)

Эти запросы. На данный момент manage_media.js пуст, я буду использовать его для загрузки всех медиафайлов, в которых работает эта видео.

link

+0

Я был только о том, чтобы предложить некоторые детали для нового вопроса :) Чем будет полезно следующее: OS/Версия браузера, заголовки успешного, а также проблемного запроса, заголовки и содержимое ответов для этих запросов, код PHP, который обрабатывает файлы, и, возможно, также образец HTML. Кстати, я просто попробовал CakePHP 2.4.1 и Chrome 31.0.1650.57 м на Windows 7 x64, и он отлично работает для меня, cookie сеанса отправляется, как ожидалось. Вы пробовали его с чистым профилем и другими браузерами? – ndm

+0

Я добавил информацию. Моя версия Chrome также 31.0.1650.57m на Windows 8 – dudeofea

+0

Пара точек: вам не нужно, чтобы PHP проверял браузер при печати тега ''; просто распечатайте их оба, и браузер будет использовать первый соответствующий. А во-вторых, вы действительно * создаете экземпляр PDO и жестко-кодирующие запросы в своих действиях контроллера ?! –

ответ

1

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

Недопустимого диапазон отклика

Ответ всегда служит начиная с байта 0 и он использует первую позицию байта в качестве последней позиции байта, как из-за неправильные индексы используются на регулярных выражениях спичек. Индекс 0 содержит весь соответствующий предмет, то есть полную строку bytes=xyz, а индекс 1 содержит первый захват, то есть положение первого байта.

Фактические данные, которые вы ищете, находятся по индексу 1 и 2.

$begin=intval($matches[1]); 
if(!empty($matches[2])) { 
    $end=intval($matches[2]); 
} 

Недопустимый диапазон

Кроме того, заголовок Content-Range является неправильным содержанием, последнее положение байт должен быть end - 1, как первый байт начинается в 0.

$last = $end - 1; 
header("Content-Range: bytes $begin-$last/$size"); 

Смотрите также http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35

Байт-контент-диапазона спецификации с байт-диапазона-соотв-спецификации которого last- байт-полюсная значение меньше, чем его первый байт- pos или значение длины экземпляра которого меньше или равно его последнему байту-значению, является недопустимым. Получатель недействительного байта-content-range-spec ДОЛЖЕН игнорировать его и любой переданный вместе с ним контент.

[...]

Примеры значений байт-контента диапазона спецификации, если предположить, что объект содержит в общей сложности 1234 байт:

. The first 500 bytes:
bytes 0-499/1234

. The second 500 bytes:
bytes 500-999/1234

. All except for the first 500 bytes:
bytes 500-1233/1234

. The last 500 bytes:
bytes 734-1233/1234

Использование CakePHP вместо

кстати, есть причина, почему вы не используете функциональные возможности CakePHP для запросов к базе данных и обслуживает файлы? Таким образом, вы сэкономили бы массу неприятностей.

См http://book.cakephp.org/2.0/en/controllers/request-response.html#cakeresponse

Некоторые (непроверенные) Пример кода:

public function get_media($id, $type) 
{ 
    $media = $this->Media->findById($id, array('Media.owner', 'Media.type')); 
    if($media['Media']['owner'] !== $this->Auth->user('id')) 
    { 
     throw new ForbiddenException(); 
    } 

    $file = null; 
    if($media['Media']['type'] == 'png') 
    { 
     $file = "/srv/Ads/Ad_".$id.".png"; 
    } 
    else if($media['Media']['type'] == 'mp4') 
    { 
     if($type == "mp4") 
     { 
      $file = "/srv/Ads/Ad_".$id.".mp4"; 
     } 
     else if($type == "webm") 
     { 
      $file = "/srv/Ads/Ad_".$id.".webm"; 
     } 
    } 

    $this->response->file($file, array('download' => true)); 
    return $this->response; 
} 
+0

Я изменил функцию get_media на выше, работает. По-видимому, модели не бесполезны. – dudeofea