【问题标题】:HTML5 video seeking in CakePHP在 CakePHP 中寻找 HTML5 视频
【发布时间】:2013-12-07 23:12:58
【问题描述】:

我的视频流在 CakePHP 中工作得很好。由于视频对每个用户都是私有的,如果用户通过身份验证,我有一个 CakePHP 控制器提供文件。我还注意到发送到服务器的所有请求在其请求中都有一个Cookie: CAKEPHP=<stuff> 标头。

问题在于,当用户暂停,然后播放视频或用户在视频中搜索时,Chrome 会发送一个包含特定字节范围的 Range 请求,以供我的服务器传送。请求立即被取消。需要注意的是,这个请求没有Cookie: CAKEPHP=<stuff>标头。

我认为请求被拒绝是因为没有会话 cookie。如何强制 chrome(可能还有其他浏览器)发送会话 cookie?

我的 CakePHP 版本是 2.4.1

编辑

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>

(Controller中的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);
        $fm=@fopen($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

【问题讨论】:

  • 我正要为一个新问题提出一些细节 :) 以下内容会有所帮助:操作系统/浏览器版本、成功请求的标头以及有问题的请求、响应的标头和内容对于这些请求,处理提供文件的 PHP 代码,可能还有一个 HTML 示例。顺便说一句,我刚刚在 Windows 7 x64 上使用 CakePHP 2.4.1 和 Chrome 31.0.1650.57 m,它对我来说工作正常,会话 cookie 正在按预期发送。您是否尝试过使用干净的配置文件和其他浏览器?
  • 我已添加信息。我的 Chrome 版本在 Windows 8 上也是 31.0.1650.57m
  • 几点:打印&lt;source&gt;标签时不需要PHP检查浏览器;只需将它们都打印出来,浏览器就会使用第一个合适的。其次,您是否真的在控制器操作中创建 PDO 实例并硬编码查询?!
  • 你有什么建议?

标签: php html cakephp video cookies


【解决方案1】:

我认为请求实际上是正确的,只是控制台没有正确显示它,因为服务器的响应不正确。尝试使用像Charles 这样的调试代理来检查请求。

无效的响应范围

响应始终从字节 0 开始提供服务,并且它使用第一个字节位置作为最后一个字节位置,这都是因为在正则表达式匹配中使用了错误的索引。索引0 包含整个匹配的主题,即完整的bytes=xyz 字符串,索引1 包含第一个捕获,即第一个字节位置。

您要查找的实际捕获值位于索引12

$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

具有 byte-range-resp-spec 的 byte-content-range-spec,其 last-byte-pos 值小于其 first-byte-pos 值,或者其 instance-length 值小于或等于它的 last-byte-pos 值无效。无效 byte-content-range-spec 的接收者必须忽略它以及随之传输的任何内容。

[...]

byte-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;
}

【讨论】:

  • 我将我的 get_media 函数更改为上面的函数,工作正常。显然模型不是没用的。
猜你喜欢
  • 2012-05-14
  • 1970-01-01
  • 2012-05-21
  • 1970-01-01
  • 2012-06-30
  • 1970-01-01
  • 2015-07-12
  • 1970-01-01
  • 2012-05-19
相关资源
最近更新 更多