PHP + NGINX 控制视频文件播放,并防止文件下载

最简单的方法是使用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工具进行处理,把元数据放回文件头部即可。

转载于:https://www.cnblogs.com/liliuguang/p/10576000.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/252091.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#:委托基础与事件

通过以下思维导图&#xff0c;学习委托的基本概念&#xff0c;后面着重讲解委托的运用&#xff0c;希望通过最简单的方式收获更多的知识。 1.委托的各种写法 1、委托 委托名new 委托&#xff08;会调用的方法名); 委托名&#xff08;参数&#xff09;; 2、委托 委托名 会调用…

Django基本命令

Django基本命令 1.创建一个Django 项目 django_admin.py startproject mysite当前目录下会生成mysite的工程&#xff0c;目录结构如下&#xff1a; manage.py ----- Django项目里面的工具&#xff0c;通过它可以调用django shell和数据库等。settings.py ---- 包含了项目的默认…

reactor模式:多线程的reactor模式

上文说到单线程的reactor模式 reactor模式&#xff1a;单线程的reactor模式 单线程的reactor模式并没有解决IO和CPU处理速度不匹配问题&#xff0c;所以多线程的reactor模式引入线程池的概念&#xff0c;把耗时的IO操作交由线程池处理&#xff0c;处理完了之后再同步到selecti…

Elasticsearch实战篇——Spring Boot整合ElasticSearch

2019独角兽企业重金招聘Python工程师标准>>> 当前Spring Boot很是流行&#xff0c;包括我自己&#xff0c;也是在用Spring Boot集成其他框架进行项目开发&#xff0c;所以这一节&#xff0c;我们一起来探讨Spring Boot整合ElasticSearch的问题。 本文主要讲以下内容…

Python: pip升级报错了:You are using pip version 10.0.1, however version 20.3.3 is available.

1,Python使用命令&#xff1a;python -m pip install --upgrade pip升级pip的时候报了下面这个错 2,换了个命令&#xff1a; python -m pip install --upgrade pip -i https://pypi.douban.com/simple 更新成功了&#xff0c;但又报了一个新的错误&#xff1a; AttributeError:…

新手上路之Hibernate:第一个Hibernate例子

一、Hibernate概述 &#xff08;一&#xff09;什么是Hibernate&#xff1f; Hibernate核心内容是ORM&#xff08;关系对象模型&#xff09;。可以将对象自动的生成数据库中的信息&#xff0c;使得开发更加的面向对象。这样作为程序员就可以使用面向对象的思想来操作数据库&…

模板标签及模板的继承与引用

1.常用的模板标签 - 作用是什么:提供各种逻辑 view.py: def index(request):#模板标签 --常用标签 总结&#xff1a;语法 {% tag %} {% endtag %} {% tag 参数 参数 %} 示例 展示页index.html&#xff0c;包含for标签&#xff0c;if标签&#xff0c;url标签 {% extends teacher…

Golang实现一个密码生成器

小地鼠防止有人偷他的果实&#xff0c;在家里上了一把锁。这个锁怎么来的呢&#xff1f;请往下看。。 package mainimport ("flag""fmt""math/rand""time" )var (length intcharset string )const (NUmStr "0123456789"C…

C# WPF:初识布局容器

StackPanel堆叠布局 StackPanel是简单布局方式之一&#xff0c;可以很方便的进行纵向布局和横向布局 StackPanel默认是纵向布局的 <Window x:Class"WpfApplication1.MainWindow" xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation" …

Kibana源码分析--Hapijs路由设置理解笔记

【ES6解构赋值】&#xff1a;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment 【Joi APi】&#xff1a;https://github.com/hapijs/joi/blob/v13.1.2/API.md 转载于:https://www.cnblogs.com/lishidefengchen/p/866874…

Python打包EXE神器 pyinstaller

最近由于项目需要&#xff0c;以前的python文件需要编辑为EXE供前端客户使用。 由于最早接触的是distutils&#xff0c;所以一开始准备使用distutils和py2exe搭配来进行python的exe化&#xff0c;也就是传统的使用setup.py的方式来进行exe安装。但是结果都不是很好&#xff0c;…

20种PLC元件编号和Modbus编号地址对应表

1、三菱&#xff1a; X元件支持Modbus之02功能码&#xff1b; Y元件支持Modbus之01、05、15功能码&#xff1b; D元件支持Modbus之03、06、16功能码。 2、西门子&#xff1a; I元件支持Modbus之02功能码&#xff1b; Q元件支持Modbus之01、05、15功能码&#xff1b; V元件…

暑期学习

由于最后大作业的呈现情况与短学期所完成的还相差甚远&#xff0c;所以在暑期的时候开始进一步的细化。 在这个过程之中产生了如下的问题&#xff1a; 已解决的有&#xff1a; 1.用a标签在同一页面实现跳转。 要点&#xff1a;标记<a href"../home#pre">的时候…

五、RabbitMQ的消息属性(读书笔记)

2019独角兽企业重金招聘Python工程师标准>>> 简介 当使用RabbitMQ发布消息时&#xff0c;消息又AMQP规范中的三个低层帧类型组成&#xff1a; Basic.publish方法帧&#xff1b;内容头帧&#xff1b;消息体帧&#xff1b;这三种帧类型按顺序一起工作&#xff0c;以便…

异步和单线程

转载于:https://www.cnblogs.com/sunmarvell/p/8674748.html

C#:把dll封入exe中方法

在这个事件中,可以重新为加载失败的程序集手动加载 如果你将dll作为资源文件打包的你的应用程序中(或者类库中) 就可以在硬盘加载失败的时候 从资源文件中加载对应的dll 就像这样: class Program {static Program(){ //这个绑定事件必须要在引用到TestLibrary1这个程序…

C#结构类型图

转载于:https://www.cnblogs.com/kangao/p/8674838.html

使用gradle多渠道打包

以友盟的多渠道打包为例&#xff0c;如果我们须要打包出例如以下渠道&#xff1a;UMENG, WANDOUJIA, YINGYONGBAO。 第一种方法。是须要创建文件的。我们在写完我们的代码之后&#xff0c;在app/src以下。分别创建和main同级目录的目录umeng, wandoujia, yingyongbao,这三个目录…

四大步骤,彻底关闭Win10自动更新

尽管Win11已经发布了一段时间&#xff0c;但目前互联网上大部分电脑用户所使用的的操作系统仍是Win10&#xff0c;对于Win10&#xff0c;笔者相信大部分人应该都不陌生&#xff0c;作为目前市面上占比最高的电脑系统&#xff0c;Win10的许多功能和操作逻辑都十分优秀&#xff0…

虚拟机windows7安装启动MYSQL5.7

一.环境 环境&#xff1a;虚拟机VMVare 系统&#xff1a;windows7旗舰版 MYSQL版本&#xff1a;mysql5.7.25 二.具体步骤 1.首先下载安装mysql5.7.25&#xff0c;这里用的是安装版的mysql&#xff0c;网上大多数都是推荐去官网下载&#xff0c;这里推荐的是清华大学开源镜像站…