|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Class DirScanner
|
|
|
|
*/
|
|
|
|
|
|
|
|
Class DirScanner {
|
|
|
|
private $nginxSecureOn = false; //Nginx防盗链开启状态
|
|
|
|
private $nginxSecret = 'foo=bar'; //Nginx防盗链密钥
|
|
|
|
private $userIp = '127.0.0.1'; //用户IP地址
|
|
|
|
private $nginxSecureTimeout = 1800; //Nginx防盗链有效期,单位:秒
|
|
|
|
private $nginxSecureLinkMd5Pattern = '{secure_link_expires}{uri}{remote_addr} {secret}'; //Nginx防盗链MD5加密方式
|
|
|
|
private $allowReadContentFileExtensions = [ //允许读取文件内容的文件类型
|
|
|
|
'txt',
|
|
|
|
'md',
|
|
|
|
'url',
|
|
|
|
];
|
|
|
|
private $fields = [ //私有属性字段名和说明
|
|
|
|
'directory' => '目录名',
|
|
|
|
'filename' => '文件名',
|
|
|
|
'realpath' => '完整路径',
|
|
|
|
'path' => '相对网址',
|
|
|
|
'extension' => '文件后缀',
|
|
|
|
'fstat' => '资源状态', //同php方法fstat: https://www.php.net/manual/en/function.fstat.php
|
|
|
|
'content' => 'MD文件内容',
|
|
|
|
'shortcut' => 'URL快捷方式',
|
|
|
|
|
|
|
|
'description' => '描述',
|
|
|
|
'keywords' => '关键词',
|
|
|
|
'snapshot' => '快照图片',
|
|
|
|
];
|
|
|
|
private $scanResults = []; //目录扫描结果
|
|
|
|
|
|
|
|
|
|
|
|
protected $supportFileExtensions = [ //支持的文件类型
|
|
|
|
'txt', //纯文本
|
|
|
|
'md', //纯文本
|
|
|
|
'url', //快捷方式
|
|
|
|
'jpg', //图片
|
|
|
|
'png', //图片
|
|
|
|
'gif', //图片
|
|
|
|
'ico', //图标
|
|
|
|
'mp4', //视频
|
|
|
|
'ts', //视频
|
|
|
|
'm3u8', //视频
|
|
|
|
];
|
|
|
|
protected $maxReadFilesize = [ //默认每种文件读取内容最大大小
|
|
|
|
'txt' => 100*1024, //纯文本
|
|
|
|
'md' => 5*1024*1024, //纯文本
|
|
|
|
'url' => 20*1024, //快捷方式
|
|
|
|
'jpg' => 500*1024, //图片
|
|
|
|
'png' => 500*1024, //图片
|
|
|
|
'gif' => 500*1024, //图片
|
|
|
|
'ico' => 50*1024, //图标
|
|
|
|
'mp4' => 100*1024*1024, //视频
|
|
|
|
'ts' => 10*1024*1024, //视频
|
|
|
|
'm3u8' => 10*1024*1024, //视频
|
|
|
|
];
|
|
|
|
protected $securedFileExtensions = [ //开启Nginx防盗链的文件类型
|
|
|
|
'jpg', //图片
|
|
|
|
'png', //图片
|
|
|
|
'gif', //图片
|
|
|
|
'ico', //图标
|
|
|
|
'mp4', //视频
|
|
|
|
'ts', //视频
|
|
|
|
'm3u8', //视频
|
|
|
|
];
|
|
|
|
|
|
|
|
public $scanTimeCost = 0; //上一次目录扫描耗时,单位:微秒
|
|
|
|
|
|
|
|
|
|
|
|
//解析描述文件内容
|
|
|
|
private function parseDescriptionFiles($realpath) {
|
|
|
|
}
|
|
|
|
|
|
|
|
//解析快捷方式文件内容
|
|
|
|
private function parseShortCuts($realpath) {
|
|
|
|
}
|
|
|
|
|
|
|
|
//根据文件路径生成唯一编号
|
|
|
|
private function getId($realpath) {
|
|
|
|
return !empty($realpath) ? md5($realpath) : '';
|
|
|
|
}
|
|
|
|
|
|
|
|
//判断Nginx防盗链MD5加密方式字符串是否合格
|
|
|
|
private function isNginxSecureLinkMd5PatternValid($pattern) {
|
|
|
|
$valid = true;
|
|
|
|
|
|
|
|
$fieldsNeeded = [
|
|
|
|
'{secure_link_expires}',
|
|
|
|
'{uri}',
|
|
|
|
'{remote_addr}',
|
|
|
|
'{secret}',
|
|
|
|
];
|
|
|
|
foreach($fieldsNeeded as $needle) {
|
|
|
|
if (strstr($pattern, $needle) === false) {
|
|
|
|
$valid = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//根据文件生成防盗链网址
|
|
|
|
//参考:https://nginx.org/en/docs/http/ngx_http_secure_link_module.html#secure_link
|
|
|
|
//防盗链参数名:md5, expires
|
|
|
|
protected function getSecureLink($path) {
|
|
|
|
$expires = time() + $this->nginxSecureTimeout;
|
|
|
|
$originStr = str_replace([
|
|
|
|
'{secure_link_expires}',
|
|
|
|
'{uri}',
|
|
|
|
'{remote_addr}',
|
|
|
|
'{secret}',
|
|
|
|
], [
|
|
|
|
$expires,
|
|
|
|
$path,
|
|
|
|
$this->userIp,
|
|
|
|
$this->nginxSecret,
|
|
|
|
], $this->nginxSecureLinkMd5Pattern);
|
|
|
|
|
|
|
|
$md5 = base64_encode( md5($originStr, true) );
|
|
|
|
$md5 = strtr($md5, '+/', '-_');
|
|
|
|
$md5 = str_replace('=', '', $md5);
|
|
|
|
|
|
|
|
return "{$path}?md5={$md5}&expires={$expires}";
|
|
|
|
}
|
|
|
|
|
|
|
|
//根据文件生成相对路径
|
|
|
|
protected function getFilePath($directory, $filename, $extension) {
|
|
|
|
$extensionPathMap = [ //默认每种文件读取内容最大大小
|
|
|
|
'txt' => '',
|
|
|
|
'md' => '/view/',
|
|
|
|
'url' => '/link/',
|
|
|
|
'm3u8' => '/m3u8/',
|
|
|
|
'jpg' => "{$directory}{$filename}.{$extension}",
|
|
|
|
'png' => "{$directory}{$filename}.{$extension}",
|
|
|
|
'gif' => "{$directory}{$filename}.{$extension}",
|
|
|
|
'ico' => "{$directory}{$filename}.{$extension}",
|
|
|
|
'mp4' => "{$directory}{$filename}.{$extension}",
|
|
|
|
'ts' => "{$directory}{$filename}.{$extension}",
|
|
|
|
];
|
|
|
|
|
|
|
|
$path = isset($extensionPathMap[$extension]) ? $extensionPathMap[$extension] : '';
|
|
|
|
|
|
|
|
if (!empty($path) && in_array($extension, ['md', 'url', 'm3u8'])) {
|
|
|
|
if ($this->nginxSecureOn && $extension == 'm3u8') {
|
|
|
|
$path = $this->getSecureLink($path);
|
|
|
|
$path = "{$path}&file=" . urlencode($filename);
|
|
|
|
}else {
|
|
|
|
$path = "{$path}?file=" . urlencode($filename);
|
|
|
|
}
|
|
|
|
}else if (!empty($path) && $this->nginxSecureOn) {
|
|
|
|
$path = $this->getSecureLink($path);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $path;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//设置Nginx防盗链开启或关闭,以及密钥、加密方式、超时时长
|
|
|
|
public function setNginxSecure($secureOn, $secret = '', $userIp = '', $pattern = '', $timeout = 0) {
|
|
|
|
$status = false;
|
|
|
|
if (is_string($secureOn) && strtolower($secureOn) == 'on') {
|
|
|
|
$status = true;
|
|
|
|
}else if (is_string($secureOn) && strtolower($secureOn) == 'off') {
|
|
|
|
$status = false;
|
|
|
|
}else if ((bool)$secureOn == true) {
|
|
|
|
$status = true;
|
|
|
|
}
|
|
|
|
$this->nginxSecureOn = $status;
|
|
|
|
|
|
|
|
if (!empty($secret) && is_string($secret)) {
|
|
|
|
$this->nginxSecret = $secret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!empty($userIp) && is_string($userIp)) {
|
|
|
|
$this->userIp = $userIp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!empty($pattern) && is_string($pattern)) {
|
|
|
|
if ($this->isNginxSecureLinkMd5PatternValid($pattern) == false) {
|
|
|
|
throw new Exception("Invalid Nginx secure link md5 pattern: {$pattern}", 500);
|
|
|
|
}
|
|
|
|
$this->nginxSecureLinkMd5Pattern = $pattern;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((int)$timeout > 0) {
|
|
|
|
$this->nginxSecureTimeout = (int)$timeout;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//设置Nginx防盗链密钥
|
|
|
|
public function setNginxSecret($secret) {
|
|
|
|
if (!empty($secret) && is_string($secret)) {
|
|
|
|
$this->nginxSecret = $secret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//获取Nginx防盗链密钥
|
|
|
|
public function getNginxSecret() {
|
|
|
|
return $this->nginxSecret;
|
|
|
|
}
|
|
|
|
|
|
|
|
//设置Nginx防盗链密钥
|
|
|
|
public function setUserIp($userIp) {
|
|
|
|
if (!empty($userIp) && is_string($userIp)) {
|
|
|
|
$this->userIp = $userIp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//获取Nginx防盗链密钥
|
|
|
|
public function getUserIp() {
|
|
|
|
return $this->userIp;
|
|
|
|
}
|
|
|
|
|
|
|
|
//设置Nginx防盗链MD5加密方式
|
|
|
|
/**
|
|
|
|
* Nginx防盗链MD5加密方式参考下面网址中的示例,
|
|
|
|
* 将Nginx的变量替换$符号为英文大括号;
|
|
|
|
*
|
|
|
|
* 示例:
|
|
|
|
* ```
|
|
|
|
* {secure_link_expires}{uri}{remote_addr} {secret}
|
|
|
|
* ```
|
|
|
|
* Nginx文档参考:http://nginx.org/en/docs/http/ngx_http_secure_link_module.html#secure_link_md5
|
|
|
|
*/
|
|
|
|
public function setNginxSecureLinkMd5Pattern($pattern) {
|
|
|
|
if (!empty($pattern) && is_string($pattern)) {
|
|
|
|
if ($this->isNginxSecureLinkMd5PatternValid($pattern) == false) {
|
|
|
|
throw new Exception("Invalid Nginx secure link md5 pattern: {$pattern}", 500);
|
|
|
|
}
|
|
|
|
$this->nginxSecureLinkMd5Pattern = $pattern;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//获取Nginx防盗链MD5加密方式
|
|
|
|
public function getNginxSecureLinkMd5Pattern() {
|
|
|
|
return $this->nginxSecureLinkMd5Pattern;
|
|
|
|
}
|
|
|
|
|
|
|
|
//设置Nginx防盗链超时时长,单位:秒
|
|
|
|
public function setNginxSecureTimeout($timeout) {
|
|
|
|
if ((int)$timeout > 0) {
|
|
|
|
$this->nginxSecureTimeout = (int)$timeout;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//获取Nginx防盗链超时时长,单位:秒
|
|
|
|
public function getNginxSecureTimeout() {
|
|
|
|
return $this->nginxSecureTimeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
//获取是否开启防盗链
|
|
|
|
public function isSecureOn() {
|
|
|
|
return $this->nginxSecureOn;
|
|
|
|
}
|
|
|
|
|
|
|
|
//扫描目录获取目录和文件列表,支持指定目录扫描深度(目录级数)
|
|
|
|
public function scan($dir, $levels = 3) {
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|