最简单的方法是使用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. Elasticsearch Internals: Networking Introduction An Overview of the Network Topology

    This article introduces the networking part of Elasticsearch. We look at the network topology of an ...

  2. 流媒体技术笔记(DarwinStreamingServer相关)

    简介 Darwin Streaming Server简称DSS.DSS是Apple公司提供的开源实时流媒体播放服务器程序.整个程序使用C++编写,在设计上遵循高性能,简单,模块化等程序设计原则,务求做 ...

  3. Paramiko&堡垒机

    Paramiko paramiko模块,基于SSH用于连接远程服务器并执行相关操作. 一.安装 pip install paramiko 二.使用 SSHClient 用于连接远程服务器并执行基本命令 ...

  4. Java学习——包及可见性

    1.在同一个类中:创建的对象,不管成员的可见修饰符可以直接调用. package studentpackage; public class Student { public long id; prot ...

  5. [转][layui]table 的一个BUG

    转换静态表格,一直只能显示 10 行,研究发现解决方法有两个:1.参数里: limit: 30, 添加参数以确保显示更多行2.修改 table.js 里面的 F.prototype.config ,添 ...

  6. Ajax的兼容及Ajax的缓存问题

    Ajax的兼容: 在ie 6 7 8 不支持XMLHttpRequest的对象: 他的Ajax内置对象为ActiveXObject("Microsoft XMLHTTP") 除了内 ...

  7. 让可等待的计时器添加APC调用

    // TimerAPCRoutine.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <windows.h> ...

  8. MySQL学习----多版本并发mvcc

    MySQL中的大多数事务性存储引擎实现的都不是简单的行级锁.基于提升并发性能的考虑,他们一般实现了多版本并发控制(mvcc).不仅是mysql,包括oracle,postgresql等其他数据库也实现 ...

  9. Windows安装启动MySQL

    Win安装MySQL数据库将下载下来的mysql解压到指定目录下,cmd切换到bin目录下>mysqld -install 安装服务>mysqld -remove 卸载服务>net ...

  10. Install Greenplum OSS on Ubuntu

    About Greenplum Database Greenplum Database is an MPP SQL Database based on PostgreSQL.  Its used in ...