简体   繁体   English

CakePHP中的HTML5视频搜索

[英]HTML5 video seeking in CakePHP

I have video streaming working just fine in CakePHP. 我的视频流在CakePHP中运行良好。 Since the videos are private to each user, I have a CakePHP controller serve up the files if the users are authenticated. 由于视频对每个用户都是私有的,因此,如果用户通过了身份验证,我有一个CakePHP控制器来提供文件。 I also notice that all requests sent to the server have a Cookie: CAKEPHP=<stuff> header in their request. 我还注意到,所有发送到服务器的请求在其请求中都有一个Cookie: CAKEPHP=<stuff>头。

The problem is that when a user pauses, then plays the video or when the user seeks along the video, Chrome sends a Range request with a certain byte range for my server to deliver. 问题在于,当用户暂停播放然后播放视频时,或者当用户搜索视频时,Chrome都会发送带有一定字节范围的Range请求供我的服务器发送。 The request gets cancelled immediately. 该请求将立即被取消。 It should be noted that this request has no Cookie: CAKEPHP=<stuff> header. 应当注意,该请求没有 Cookie: CAKEPHP=<stuff>头。

I believe the request is denied because there is no session cookie. 我认为该请求被拒绝,因为没有会话cookie。 How can I force chrome (and possibly other browsers) to send a session cookie? 如何强制chrome(可能还有其他浏览器)发送会话cookie?

My CakePHP Version is 2.4.1 我的CakePHP版本是2.4.1

EDIT : 编辑

view_media.ctp 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>

(The view_media function in the Controller is blank) (Controller中的view_media函数为空白)

Relevant section of PagesController 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 has no view) (get_media没有视图)

These are the requests. 这些是要求。 manage_media.js is blank for now, I will use it to load all media files one this video thing is working. manage_media.js目前还是空白,我将使用它来加载所有与此视频有关的媒体文件。

link 链接

I think the request is actually made correctly, it's just the console not displaying it properly as the servers response is not correct. 我认为请求实际上是正确发出的,只是控制台未正确显示请求,因为服务器响应不正确。 Try using a debug proxy like Charles to check the request. 尝试使用像Charles这样的调试代理来检查请求。

Invalid response range 无效的响应范围

The response always serves starting from byte 0 and it uses the first byte position as the last byte position, both because the wrong indices are used on the regex matches. 响应始终从字节0开始,并且使用第一个字节位置作为最后一个字节位置,这都是因为正则表达式匹配使用了错误的索引。 Index 0 contains the whole matched subject, ie the complete bytes=xyz string, and index 1 contains the first capture, ie the first byte position. 索引0包含整个匹配的主题,即完整的bytes=xyz字符串,索引1包含第一个捕获内容,即第一个字节位置。

The actual captured values you are looking for are located at index 1 and 2 . 您正在寻找的实际捕获值位于索引12

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

Invalid content range 无效的内容范围

Also the Content-Range header is wrong, the last byte position must be end - 1 as the first byte starts at 0 . 同样, Content-Range标头是错误的,由于第一个字节从0开始,最后一个字节的位置必须为end - 1

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

See also http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 另请参见http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35

A byte-content-range-spec with a byte-range-resp-spec whose last- byte-pos value is less than its first-byte-pos value, or whose instance-length value is less than or equal to its last-byte-pos value, is invalid. 字节范围-resp-spec的字节内容范围规范,其最后一个字节-pos值小于其第一个字节-pos值,或者其实例长度值小于或等于其最后一个-pos-spec byte-pos值,无效。 The recipient of an invalid byte-content-range- spec MUST ignore it and any content transferred along with it. 无效的字节内容范围规范的接收者必须忽略它以及与之一起传输的任何内容。

[...] [...]

Examples of byte-content-range-spec values, assuming that the entity contains a total of 1234 bytes: 假设实体总共包含1234个字节,则为byte-content-range-spec值的示例:

. 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

Use CakePHP instead 改用CakePHP

btw, is there a reason why you aren't using the CakePHP functionality for querying the database and serving files? 顺便说一句,您为什么不使用CakePHP功能来查询数据库和提供文件? You would save yourself a lot of trouble that way. 这样可以为您省去很多麻烦。

See http://book.cakephp.org/2.0/en/controllers/request-response.html#cakeresponse 参见http://book.cakephp.org/2.0/en/controllers/request-response.html#cakeresponse

Some (untested) example code: 一些(未经测试的)示例代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM