最简单的方法是使用NGINX的 internal 功能

server {
    listen 80;
    server_name www.xxx.com;
 
    location / {
        index index.php index.html index.htm;
        root  /xxx;

if (!-e $request_filename) {
         rewrite ^/index.php(.*)$ /index.php?s=$1 last;
         rewrite ^(.*)$ /index.php?s=$1 last;
         break;
        }
    }

 # 这里使用internal做下载防护,只允许内部程序(PHP等)访问,这样外部直接访问这个地址就会提示404错误
    location ~ \.mp4$ {
        internal;
  # 这里的路径配置是可选的,可以配置到网站外部,和其他location里的配置路径是一个意思,可以更好的防止文件被通过网址下载
        root /bbb; 
    }

location ~ \.php$ {
        root  /xxx;
        try_files $uri =404;
        fastcgi_pass  unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

然后在PHP中通过header('Location: /xxx/aa.mp4')访问,但这个只适合于小文件,因为这种方式不支持Content-Range和HTTP 206,导致不支持断点续传和视频文件的边下边播

最好的方式是通过header('X-Accel-Redirect: /xxx/aa.mp4')访问,X-Accel-Redirect支持Content-Range和HTTP 206,Apache里面是X-Sendfile

如果不能配置nginx的internal选项,或者nginx不支持X-Accel-Redirect,却要使用断点续传、边下边播和下载防护,那么就要通过PHP代码来控制

思路上是使用token鉴权,首先下载文件前由前端请求一个token,这个token由用户ID+时间戳+视频ID组成,然后存储到session并加密后发送给前端

$token = $_SESSION['uid'] . '|' . time() . '|' . $id;
// 保存未加密token到seesion
$_SESSION['video_token'] = $token;
// 加密token以便发送到客户端
$token = Mcrypt::encode($token, 'lbnnbs');

前端收到token,向下载控制器网址发送token请求文件下载,控制器对token解码,判断Session是否一致、用户ID是否正确、是否超时、视频ID是否正确

然后将视频ID转换为文件地址,通过PHP读取文件发送给前端下载。并通过发送Content-Range和HTTP 206来支持断点续传、边下边播等操作

$id = decodeIdFromToken($token);

$file = getFilePath($id);

SendVideo($file);
    private function SendVideo($file) {
header("Content-type: video/mp4");
header("Accept-Ranges: bytes"); $size = filesize($file);
if (isset($_SERVER['HTTP_RANGE'])) {
header("HTTP/1.1 206 Partial Content");
list($name, $range) = explode("=", $_SERVER['HTTP_RANGE']);
list($begin, $end) = explode("-", $range);
if ($end == 0)
$end = $size - 1;
}else {
$begin = 0;
$end = $size - 1;
}
header("Content-Length: " . ($end - $begin + 1));
header("Content-Disposition: filename=" . basename($file));
header("Content-Range: bytes " . $begin . "-" . $end . "/" . $size); $fp = fopen($file, 'rb');
fseek($fp, $begin);
while (!feof($fp)) {
$p = min(1024, $end - $begin + 1);
$begin += $p;
echo fread($fp, $p);
}
fclose($fp);
} private function decodeIdFromToken($token) {
if (empty($_SESSION['uid'])) {
return false;
} $token = Mcrypt::decode($token, 'lbnnbs'); if ($token != $_SESSION['video_token']) {
//token解密失败,判定失效
return false;
} $token_arr = explode('|', $token); if (intval($token_arr[0]) != $_SESSION['uid']) {
// token不是当前用户,判定失效
return false;
} if (intval($token_arr[1]) < time() - 10) {
// token生成于10秒前,判定失效
return false;
} unset($_SESSION['video_token']); return $token_arr[2]; // 返回id
}

另外需要注意的是,很多时候mp4文件会无法支持边下边播,这是因为在转码或者压缩视频文件到mp4的时候把文件的元数据移除了或者放到了文件的末尾,导致前端播放器不能第一时间获取到视频文件的播放时长等信息,只能全部下载完毕后或者直到读取到了元数据后才能播放。这个时候可以使用qt-faststart.exe工具进行处理,把元数据放回文件头部即可。

PHP + NGINX 控制视频文件播放,并防止文件下载的更多相关文章

  1. 网站上flv,MP4等格式的视频文件播放不出来的解决办法

    在做一个网站时,发现视频文件,比如flv,MP4格式在本地可以正常的播放,但是传到了开发机器上,就不行了.播放器的文件地址是对的,就是一直没有反应. 经过长时间的实验,发现问题在与iis的设置问题.i ...

  2. Emgu 学习(2) 视频文件播放

    播放AVI视频文件 static void Main(string[] args) { CvInvoke.NamedWindow("TestVideo", NamedWindowT ...

  3. JS控制视频的播放

    在用js定时器控制视频时, html部分: <video id="video_1"> <source id="source_1" src=&q ...

  4. C#获取视频文件播放长度

    下面两种方法只支持部分视频格式,一般格式mp3,wma等等支持 1.使用Shell32 添加引用,选择COM中的Microsoft Shell Controls And Automation引用 // ...

  5. Video组件:控制视频的播放与暂停

    来自<sencha touch权威指南>第10章,315页开始 app.js代码如下: Ext.require(['Ext.Video','Ext.MessageBox','Ext.Too ...

  6. H5网页播放器播不了服务器上的mp4视频文件

    打开IIS,在功能视图里找到MIME类型菜单,打开该菜单后鼠标右键添加.mp4扩展名的MIME类型video/mp4 其他视频文件播放不了估计也得在IIS里添加对应的MIME类型(从服务器下载文件时也 ...

  7. C# WPF 用MediaElement控件实现视频循环播放

    在WPF里用MediaElement控件,实现一个循环播放单一视频的程序,同时可以控制视频的播放.暂停.停止. 一种方式,使用MediaElement.MediaEnded事件,在视频播放结束后,自动 ...

  8. Unity中带有alpha通道的视频叠加播放

    问题: 如何让两个透明视频叠加播放 解决播放: 1:使用Unity自带的shader,shader代码如下所示 Shader "Unlit/MaskVideo" { Propert ...

  9. 深入理解MVC C#+HtmlAgilityPack+Dapper走一波爬虫 StackExchange.Redis 二次封装 C# WPF 用MediaElement控件实现视频循环播放 net 异步与同步

    深入理解MVC   MVC无人不知,可很多程序员对MVC的概念的理解似乎有误,换言之他们一直在错用MVC,尽管即使如此软件也能被写出来,然而软件内部代码的组织方式却是不科学的,这会影响到软件的可维护性 ...

随机推荐

  1. PREV-3_蓝桥杯_带分数

    问题描述 100 可以表示为带分数的形式:100 = 3 + 69258 / 714. 还可以表示为:100 = 82 + 3546 / 197. 注意特征:带分数中,数字1~9分别出现且只出现一次( ...

  2. 在64位平台上的Lucene,应该使用MMapDirectory[转]

    http://blog.thetaphi.de/2012/07/use-lucenes-mmapdirectory-on-64bit.html 从3.1版本开始,Lucene和Solr开始在64位的W ...

  3. gcc编译工具生成动态库和静态库之一----介绍

     1.库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. ...

  4. 一个源文件可以写出多个class吗?编译后,会不会生成多个class文件?

    会.一个.java源文件里面可以有内部类.其他类(有且仅有一个类可以声明为public),所以编译后,可以有多个class文件.

  5. Golang值传递和指针传递

    Golang值传递和指针传递 package main import ( "fmt" ) func swap1(x, y, p *int) { if *x > *y { *x ...

  6. MySQL 之数据库增量数据恢复案例

    MySQL 数据库增量数据恢复案例 一.场景概述 MySQL数据库每日零点自动全备 某天上午10点,小明莫名其妙地drop了一个数据库 我们需要通过全备的数据文件,以及增量的binlog文件进行数据恢 ...

  7. Ext.net combobox 的disabled

    C#:禁用combobox this.ComboBox7.Disabled =true; C#:隐藏 <ext:RadioGroup ID="RadioG_sfzg" run ...

  8. Android---页面跳转

    1.首先在一个布局文件(.XML)中绘画了一个跳转按钮(id为btn1): <Button         android:id="@+id/btn1"         an ...

  9. 电商系统架构总结3(webapi授权机制)

    三 Web API 授权方式 web api的客户端,包括 android,ios,h5,自然对访问权限要加上授权机制.对于h5,要求把h5站点和web api部署在同一个域名下,然后对web api ...

  10. python+selenium+PhantomJS批量投递智联简历(不要用自己的账号进行测试,请使用小号,很烦人的,哈哈哈)

    1.环境python2.7+selenium+PhantomJS(软件安装和库的安装网上都有教程我们跳过,so easy) 2.原理 绕过首页登录需要验证码,直接进入搜索栏,输入搜索的职位+地区搜索出 ...