初始化
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Certify extends Model
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,432 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Exception;
|
||||
|
||||
class FileManage
|
||||
{
|
||||
|
||||
/**
|
||||
* 获取上级目录ID
|
||||
* @param $folder_id
|
||||
* @param $uid
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getFolderPid($folder_id,$uid){
|
||||
if(empty($folder_id)){
|
||||
$folder_id = Folders::where('uid',$uid)->where('parent_folder',$folder_id)->value('id');
|
||||
}
|
||||
return $folder_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取有效的目录ID
|
||||
* @param $folder_id
|
||||
* @param $uid
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getFolderAllowPid($folder_id,$uid){
|
||||
if(empty($folder_id)){
|
||||
$folder_id = Folders::where('uid',$uid)->where('parent_folder',$folder_id)->value('id');
|
||||
}else{
|
||||
$folder_id = Folders::where('uid',$uid)->where('id',$folder_id)->value('id');
|
||||
}
|
||||
|
||||
return $folder_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件列表
|
||||
* @param $folder_id
|
||||
* @param $search
|
||||
* @param $uid
|
||||
* @param $page
|
||||
* @param $limit
|
||||
* @return array|array[]
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws \think\exception\DbException
|
||||
*/
|
||||
public static function ListFile($folder_id,$search,$uid,$page,$limit): array
|
||||
{
|
||||
|
||||
//获取当前根目录
|
||||
$folder_id = self::getFolderPid($folder_id,$uid);
|
||||
|
||||
|
||||
$maps = [
|
||||
['uid','=',$uid],
|
||||
['parent_folder','=',$folder_id],
|
||||
['delete_time','null','']
|
||||
];
|
||||
|
||||
|
||||
$files_sql = db('stores')
|
||||
->where($maps)
|
||||
->where('origin_name','like','%'.$search.'%')
|
||||
->field('id,uid,shares_id,origin_name as name,ext,size,count_down,count_open,update_time')
|
||||
->fetchSql(true)
|
||||
->select();
|
||||
|
||||
$list = db('folders')
|
||||
->where($maps)
|
||||
->where('folder_name','like','%'.$search.'%')
|
||||
->field('id,uid,shares_id,folder_name as name,ext,size,count_down,count_open,update_time')
|
||||
->union($files_sql,true)
|
||||
->page($page,$limit)
|
||||
->select();
|
||||
|
||||
$files_count = db('stores')
|
||||
->where($maps)
|
||||
->where('origin_name','like','%'.$search.'%')
|
||||
->field('id')
|
||||
->count();
|
||||
|
||||
$folder_count = db('folders')
|
||||
->where($maps)
|
||||
->where('folder_name','like','%'.$search.'%')
|
||||
->field('id')
|
||||
->count();
|
||||
|
||||
$data = ['data' => []];
|
||||
|
||||
foreach ($list as $item){
|
||||
|
||||
$file_item = [
|
||||
'file_name' => '',
|
||||
'file_size' => '-',
|
||||
'url' => '',
|
||||
'url_pass' => '',
|
||||
'count_down' => '<font color="#f81" size="4">'.$item['count_down'].'</font>',
|
||||
'count_open' => $item['count_open'],
|
||||
'update_time' => date('Y-m-d H:i',$item['update_time'])
|
||||
];
|
||||
|
||||
if($item['ext'] == 755){
|
||||
$file_item['file_name'] = '
|
||||
<img class="file-icon" src="'.getFileIcon('dir','index').'" />
|
||||
<text class="filename folder" id="t'.$item['id'].'" data-id="'.$item['id'].'" data-filename="'.$item['name'].'" data-folder="1">'.$item['name'].'</text>
|
||||
<div class="gengduo" onclick="clickGengduo(event,'.$item['id'].')">
|
||||
<span><em class="icon icon-more icon-color" title="更多"></em></span>
|
||||
</div>';
|
||||
$share_info = Shares::getShare($item['uid'],$item['id'],1);
|
||||
}else{
|
||||
$file_item['file_name'] = '
|
||||
<img class="file-icon" src="'.getFileIcon($item['ext'],'index').'" />
|
||||
<text class="filename" id="t'.$item['id'].'" data-id="'.$item['id'].'" data-filename="'.$item['name'].'" data-folder="0">'.$item['name'].'</text>
|
||||
<div class="gengduo" onclick="clickGengduo(event,'.$item['id'].')">
|
||||
<span><em class="icon icon-more icon-color" title="更多"></em></span>
|
||||
</div>';
|
||||
$share_info = Shares::getShare($item['uid'],$item['id'],0);
|
||||
$file_item['file_size'] = countSize($item['size']);
|
||||
}
|
||||
|
||||
$is_folder = $item['ext'] == 755 ? 1 : 0;
|
||||
|
||||
if(!empty($share_info)){
|
||||
$share_url = getShareUrl($share_info['code']);
|
||||
$file_item['url'] = '<a id="'.$item['id'].'-url" data-id="'.$item['id'].'" data-pass="'.$share_info['pwd'].'" data-pass-status="'.$share_info['pwd_status'].'" href="'.$share_url.'" target="_blank">'.$share_url.'</a>';
|
||||
if(empty($share_info['pwd']) || $share_info['pwd_status'] == 0){
|
||||
$share_info['pwd'] = '-';
|
||||
}
|
||||
$file_item['url_pass'] = '<a id="'.$item['id'].'-pass" onclick="if($(\'#'.$item['id'].'-pass\').html() != \'-\'){CopyText($(\'#'.$item['id'].'-pass\').html(),\'复制提取码成功~\')}else{setPass('.$item['id'].',$(\'#t'.$item['id'].'\').html(),'.$is_folder.')}">'.$share_info['pwd'].'</a>';
|
||||
}
|
||||
|
||||
$data['data'][] = $file_item;
|
||||
}
|
||||
|
||||
//查询上级目录
|
||||
$data['parent'] = "";
|
||||
|
||||
if($folder_id != 0){
|
||||
$parent_ids = self::getUserDirParents($uid,$folder_id);
|
||||
if(!empty($parent_ids)){
|
||||
$folder_parents = Folders::where('id','in',$parent_ids)
|
||||
->where('uid',$uid)
|
||||
->field('id,folder_name')
|
||||
->order('id desc')
|
||||
->select()->toArray();
|
||||
|
||||
$folder_parents = array_reverse($folder_parents);
|
||||
$data['parent'] = $folder_parents;
|
||||
}
|
||||
}
|
||||
|
||||
$data['total'] = $files_count + $folder_count;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public static function ShareListFile($folder_id,$uid){
|
||||
//获取当前根目录
|
||||
$folder_id = self::getFolderPid($folder_id,$uid);
|
||||
|
||||
$maps = [
|
||||
['uid','=',$uid],
|
||||
['parent_folder','=',$folder_id],
|
||||
['delete_time','null','']
|
||||
];
|
||||
|
||||
$files_sql = db('stores')
|
||||
->where($maps)
|
||||
->field('id,uid,shares_id,origin_name as name,ext,size,update_time')
|
||||
->fetchSql(true)
|
||||
->select();
|
||||
|
||||
$list = db('folders')
|
||||
->where($maps)
|
||||
->field('id,uid,shares_id,folder_name as name,ext,size,update_time')
|
||||
->union($files_sql,true)
|
||||
->select();
|
||||
|
||||
|
||||
$share_ids = array_column($list,'shares_id');
|
||||
// 查询分享代码
|
||||
$share_list = Shares::where('id','in',$share_ids)->column('code','id');
|
||||
|
||||
// 返回数据
|
||||
$data = [];
|
||||
|
||||
foreach ($list as $item){
|
||||
$type = $item['ext'] == 755 ? 'dir' : $item['ext'];
|
||||
|
||||
$files = [
|
||||
'id' => $item['id'],
|
||||
'type' => $item['ext'] == 755 ? 'dir' : 'file',
|
||||
'icon' => getFileIcon($type,'index'),
|
||||
'name' => $item['name'],
|
||||
'size' => empty($item['size']) ? '-' : countSize($item['size']),
|
||||
'time' => friendDate($item['update_time'])
|
||||
];
|
||||
|
||||
$code = $share_list[$item['shares_id']] ?? '';
|
||||
|
||||
if(empty($code)){
|
||||
$files['url'] = 'javascript:;';
|
||||
}else{
|
||||
$files['url'] = getShareUrl($code);
|
||||
}
|
||||
|
||||
$data[] = $files;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public static function FolderList($folder_id,$uid): array
|
||||
{
|
||||
//获取当前根目录
|
||||
$folder_id = self::getFolderPid($folder_id,$uid);
|
||||
|
||||
$maps = [
|
||||
['uid','=',$uid],
|
||||
['parent_folder','=',$folder_id],
|
||||
['delete_time','null','']
|
||||
];
|
||||
|
||||
return Folders::withTrashed()
|
||||
->where($maps)
|
||||
->field('id,folder_name')
|
||||
->select()->each(function($item) use ($uid){
|
||||
if(Folders::withTrashed()->where('parent_folder',$item['id'])->where('uid',$uid)->count() > 0){
|
||||
$item['down'] = 1;
|
||||
}else{
|
||||
$item['down'] = 0;
|
||||
}
|
||||
return $item;
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收站文件列表
|
||||
* @param $search
|
||||
* @param $uid
|
||||
* @param $page
|
||||
* @param $limit
|
||||
* @return array|array[]
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* @throws \think\exception\DbException
|
||||
*/
|
||||
public static function RecycleFile($search,$uid,$page,$limit){
|
||||
|
||||
$file_sql = db('stores')
|
||||
->where('uid',$uid)
|
||||
->where('delete_time','not null')
|
||||
->where('origin_name','like','%'.$search.'%')
|
||||
->field('id,uid,shares_id,origin_name as name,ext,size,count_down,count_open,update_time')
|
||||
->fetchSql(true)
|
||||
->select();
|
||||
|
||||
$list = db('folders')
|
||||
->where('uid',$uid)
|
||||
->where('delete_time','not null')
|
||||
->where('folder_name','like','%'.$search.'%')
|
||||
->field('id,uid,shares_id,folder_name as name,ext,size,count_down,count_open,update_time')
|
||||
->union($file_sql,true)
|
||||
->page($page,$limit)
|
||||
->select();
|
||||
|
||||
$stores_count = db('stores')
|
||||
->where('uid',$uid)
|
||||
->where('delete_time','not null')
|
||||
->where('origin_name','like','%'.$search.'%')
|
||||
->field('id')
|
||||
->count();
|
||||
|
||||
$folders_count = db('folders')
|
||||
->where('uid',$uid)
|
||||
->where('delete_time','not null')
|
||||
->where('folder_name','like','%'.$search.'%')
|
||||
->field('id')
|
||||
->count();
|
||||
|
||||
$data = ['data' => []];
|
||||
|
||||
foreach ($list as $item){
|
||||
|
||||
$file_item = [
|
||||
'file_name' => '',
|
||||
'file_size' => '-',
|
||||
'url' => '',
|
||||
'url_pass' => '',
|
||||
'count_down' => '<font color="#f81" size="4">'.$item['count_down'].'</font>',
|
||||
'count_open' => $item['count_open'],
|
||||
'update_time' => date('Y-m-d H:i',$item['update_time'])
|
||||
];
|
||||
|
||||
if($item['ext'] == 755){
|
||||
$file_item['file_name'] = '
|
||||
<img class="file-icon" src="'.getFileIcon('dir','index').'" />
|
||||
<text class="filename folder" id="t'.$item['id'].'" data-id="'.$item['id'].'" data-filename="'.$item['name'].'" data-folder="1">'.$item['name'].'</text>
|
||||
<div class="gengduo" onclick="clickGengduo(event,'.$item['id'].')">
|
||||
<span><em class="icon icon-more icon-color" title="更多"></em></span>
|
||||
</div>';
|
||||
$share_info = Shares::getShare($item['uid'],$item['id'],1);
|
||||
}else{
|
||||
$file_item['file_name'] = '
|
||||
<img class="file-icon" src="'.getFileIcon($item['ext'],'index').'" />
|
||||
<text class="filename" id="t'.$item['id'].'" data-id="'.$item['id'].'" data-filename="'.$item['name'].'" data-folder="0">'.$item['name'].'</text>
|
||||
<div class="gengduo" onclick="clickGengduo(event,'.$item['id'].')">
|
||||
<span><em class="icon icon-more icon-color" title="更多"></em></span>
|
||||
</div>';
|
||||
$share_info = Shares::getShare($item['uid'],$item['id'],0);
|
||||
$file_item['file_size'] = countSize($item['size']);
|
||||
}
|
||||
|
||||
$is_folder = $item['ext'] == 755 ? 1 : 0;
|
||||
|
||||
if(!empty($share_info)){
|
||||
$share_url = getShareUrl($share_info['code']);
|
||||
$file_item['url'] = '<a id="'.$item['id'].'-url" data-id="'.$item['id'].'" data-pass="'.$share_info['pwd'].'" data-pass-status="'.$share_info['pwd_status'].'" href="'.$share_url.'" target="_blank">'.$share_url.'</a>';
|
||||
if(empty($share_info['pwd']) || $share_info['pwd_status'] == 0){
|
||||
$share_info['pwd'] = '-';
|
||||
}
|
||||
$file_item['url_pass'] = '<a id="'.$item['id'].'-pass" onclick="if($(\'#'.$item['id'].'-pass\').html() != \'-\'){CopyText($(\'#'.$item['id'].'-pass\').html(),\'复制提取码成功~\')}else{setPass('.$item['id'].',$(\'#t'.$item['id'].'\').html(),'.$is_folder.')}">'.$share_info['pwd'].'</a>';
|
||||
}
|
||||
|
||||
$data['data'][] = $file_item;
|
||||
}
|
||||
|
||||
//查询上级目录
|
||||
$data['parent'] = "";
|
||||
|
||||
$data['total'] = $stores_count + $folders_count;
|
||||
|
||||
return $data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建目录
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createFolder($folder_pid, $folder_name, $folder_desc, $uid){
|
||||
|
||||
$folder_name = str_replace(" ","",$folder_name);
|
||||
$folder_name = str_replace("/","",$folder_name);
|
||||
|
||||
//获取当前根目录
|
||||
$folder_pid = self::getFolderPid($folder_pid,$uid);
|
||||
|
||||
if(empty($folder_name)){
|
||||
throw new Exception('目录名不能为空');
|
||||
}
|
||||
|
||||
|
||||
// 判断路径
|
||||
if(Folders::where('id',$folder_pid)->where('uid',$uid)->find() == null){
|
||||
throw new Exception('文件夹路径不存在');
|
||||
}
|
||||
|
||||
// 是否重复
|
||||
if(
|
||||
Folders::where('parent_folder',$folder_pid)
|
||||
->where('folder_name',$folder_name)
|
||||
->where('uid',$uid)->find() != null
|
||||
){
|
||||
throw new Exception('文件夹已存在');
|
||||
}
|
||||
|
||||
$dir_id = (new Folders)->insertGetId([
|
||||
'uid' => $uid,
|
||||
'folder_name' => $folder_name,
|
||||
'parent_folder' => $folder_pid,
|
||||
'desc' => $folder_desc,
|
||||
'create_time' => time(),
|
||||
'update_time' => time()
|
||||
]);
|
||||
|
||||
$share_id = Shares::addShare($uid,$dir_id,1);
|
||||
|
||||
(new Folders)->where('id',$dir_id)->update(['shares_id' => $share_id]);
|
||||
|
||||
return $dir_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户上级目录列表
|
||||
* @param $uid
|
||||
* @param $folder_id
|
||||
* @return array
|
||||
*/
|
||||
protected static function getUserDirParents($uid,$folder_id): array
|
||||
{
|
||||
$folders = self::getUserDirs($uid);
|
||||
return self::getDirParents($folders,$folder_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归获取上级目录
|
||||
* @param $folders
|
||||
* @param $folder_id
|
||||
* @return array
|
||||
*/
|
||||
protected static function getDirParents($folders,$folder_id): array
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($folders as $item){
|
||||
if($item['id'] == $folder_id){
|
||||
if($item['pid']){
|
||||
$ids[] = $item['id'];
|
||||
$ids = array_merge(self::getDirParents($folders,$item['pid']),$ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户目录
|
||||
* @param $uid
|
||||
* @return array
|
||||
*/
|
||||
protected static function getUserDirs($uid): array
|
||||
{
|
||||
return Folders::where('uid',$uid)->field('id,parent_folder as pid')->select()->toArray();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use app\common\model\driver\AliyunOss;
|
||||
use app\common\model\driver\Local;
|
||||
use app\common\model\driver\TxyunOss;
|
||||
use think\Exception;
|
||||
|
||||
class FileUpload
|
||||
{
|
||||
|
||||
/**
|
||||
* @var int 储存策略
|
||||
*/
|
||||
protected $policy;
|
||||
|
||||
/**
|
||||
* @var int 上传用户
|
||||
*/
|
||||
protected $uid;
|
||||
|
||||
/**
|
||||
* @var array 上传数据
|
||||
*/
|
||||
protected $info;
|
||||
|
||||
/**
|
||||
* @var int 最大上传大小
|
||||
*/
|
||||
protected $max_size;
|
||||
|
||||
|
||||
/**
|
||||
* 设置来源信息
|
||||
* @param $uid
|
||||
* @param $policy
|
||||
* @param $max_size
|
||||
* @return FileUpload
|
||||
*/
|
||||
public function source($uid,$policy,$max_size): FileUpload
|
||||
{
|
||||
$this->uid = $uid;
|
||||
$this->policy = $policy;
|
||||
$this->max_size = $max_size;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件信息
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function check(){
|
||||
|
||||
if(empty($this->info['file']['folder'])){
|
||||
throw new Exception('上传目标文件夹不存在');
|
||||
}
|
||||
|
||||
if(empty($this->info['file']['data'])){
|
||||
throw new Exception('请选择上传的文件');
|
||||
}
|
||||
|
||||
if(empty($this->info['file']['size'])){
|
||||
throw new Exception('文件大小异常');
|
||||
}
|
||||
|
||||
if(empty($this->info['file']['name'])){
|
||||
throw new Exception('上传文件名异常');
|
||||
}
|
||||
|
||||
if($this->policy['type'] == 'remote'){
|
||||
throw new Exception('您不可以使用该存储策略');
|
||||
}
|
||||
|
||||
if(!empty($this->max_size)){
|
||||
if($this->info['file']['size'] > $this->max_size){
|
||||
throw new Exception('单文件最大上传大小'.countSize($this->max_size));
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($this->policy['filetype'])){
|
||||
$file_ext = $this->getFileExt($this->info['file']['name']);
|
||||
$allow_ext = explode(',',$this->policy['filetype']);
|
||||
if(!in_array($file_ext,$allow_ext)){
|
||||
throw new Exception('不允许上传'.$file_ext.'类型的文件');
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($this->info['chunk']['key'])){
|
||||
throw new Exception('分片密钥错误');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件后缀名
|
||||
* @param $filename
|
||||
* @return string
|
||||
*/
|
||||
protected function getFileExt($filename): string
|
||||
{
|
||||
return strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机文件名
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
protected function getRandomKey(int $length = 16): string
|
||||
{
|
||||
$charTable = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$result = "";
|
||||
for ( $i = 0; $i < $length; $i++ ){
|
||||
$result .= $charTable[ mt_rand(0, strlen($charTable) - 1) ];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传目录
|
||||
* @param $key
|
||||
* @return string|string[]
|
||||
*/
|
||||
protected function getPath($key)
|
||||
{
|
||||
// 目录分割
|
||||
$ds = DIRECTORY_SEPARATOR;
|
||||
|
||||
// 配置目录
|
||||
$save_dir = str_replace('/',$ds,$this->policy['config']['save_dir']);
|
||||
|
||||
// 根目录
|
||||
$root_path = realpath(env('root_path') . './public') . $save_dir;
|
||||
|
||||
// 临时存储目录
|
||||
$temp_path = realpath(env('root_path') . './public') . str_replace('/',$ds,'/temp/');
|
||||
|
||||
// 当前保存目录
|
||||
$file_path = date('Ymd') . $ds . $this->uid . $ds;
|
||||
|
||||
//文件名
|
||||
$file_name = uniqid( "file_") . time();
|
||||
|
||||
$data = [
|
||||
'root' => $root_path,
|
||||
'temp' => $temp_path,
|
||||
'file' => $file_path,
|
||||
'path' => $root_path . $file_path,
|
||||
'temp_path' => $temp_path . $file_path,
|
||||
'name' => $file_name,
|
||||
'filename' => $file_name .'.'. $this->getFileExt($this->info['file']['name'])
|
||||
];
|
||||
|
||||
if($key == 'all'){
|
||||
return $data;
|
||||
}
|
||||
|
||||
return $data[$key] ?? '';
|
||||
}
|
||||
|
||||
|
||||
public function upload(){
|
||||
// 超时时间5分钟
|
||||
@set_time_limit(5 * 60);
|
||||
|
||||
// 获取有效的目录ID
|
||||
$this->info['file']['folder'] = FileManage::getFolderAllowPid(input('post.folder_id',0),$this->uid);
|
||||
|
||||
// 获取上传文件大小
|
||||
$this->info['file']['size'] = input('post.size',0);
|
||||
|
||||
// 获取上传文件名
|
||||
$this->info['file']['name'] = input('post.name','');
|
||||
|
||||
// 上传文件对象获取
|
||||
$this->info['file']['data'] = request()->file('file');
|
||||
|
||||
// 分片上传
|
||||
$this->info['chunk']['key'] = input('post.chunks_key');
|
||||
$this->info['chunk']['chunk'] = input('post.chunk',0);
|
||||
$this->info['chunk']['chunks'] = input('post.chunks',0);
|
||||
|
||||
$this->info['uid'] = $this->uid;
|
||||
|
||||
// 参数校验
|
||||
$this->check();
|
||||
|
||||
// 目录
|
||||
$path = $this->getPath('all');
|
||||
|
||||
// 上传驱动
|
||||
switch ($this->policy['type']){
|
||||
// 阿里云
|
||||
case 'aliyunoss':
|
||||
$upload = new AliyunOss($this->info,$this->policy,$path);
|
||||
break;
|
||||
// 腾讯云
|
||||
case 'txyunoss':
|
||||
$upload = new TxyunOss($this->info,$this->policy,$path);
|
||||
break;
|
||||
// 本地
|
||||
default:
|
||||
$upload = new Local($this->info,$this->policy,$path);
|
||||
break;
|
||||
}
|
||||
|
||||
// 上传文件
|
||||
$file_object = $upload->upload();
|
||||
|
||||
// 插入数据库
|
||||
if($file_object != 'chunk_file' && $file_object != null){
|
||||
// 加入数据库
|
||||
$data = [
|
||||
'uid' => $this->uid,
|
||||
'origin_name' => $this->info['file']['name'],
|
||||
'file_name' => $file_object,
|
||||
'size' => $this->info['file']['size'],
|
||||
'ext' => $this->getFileExt($this->info['file']['name']),
|
||||
'parent_folder' => $this->info['file']['folder'],
|
||||
'policy_id' => $this->policy['id'],
|
||||
'create_time' => time(),
|
||||
'update_time' => time()
|
||||
];
|
||||
|
||||
$file_id = (new Stores)->insertGetId($data);
|
||||
|
||||
$share_id = Shares::addShare($this->uid,$file_id,0);
|
||||
|
||||
Stores::where('id',$file_id)->update(['shares_id' => $share_id]);
|
||||
|
||||
return ['code' => 1,'msg' => '文件上传成功'];
|
||||
}
|
||||
|
||||
return ['code' => 1,'chunks' => 'chunk 文件上传成功'];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Exception;
|
||||
use think\Model;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class Folders extends Model
|
||||
{
|
||||
|
||||
use SoftDelete;
|
||||
|
||||
protected $deleteTime = 'delete_time';
|
||||
|
||||
protected $autoWriteTimestamp = true;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Groups extends Model
|
||||
{
|
||||
|
||||
public function addGroup($data){
|
||||
$data["max_storage"] = $data["max_storage"] * $data["storage_size"];
|
||||
unset($data["storage_size"]);
|
||||
self::insert($data);
|
||||
}
|
||||
|
||||
public function editGroup($id,$data){
|
||||
$data["max_storage"] = $data["max_storage"] * $data["storage_size"];
|
||||
unset($data["storage_size"]);
|
||||
self::where('id',$id)->update($data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Order extends Model
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Policys extends Model
|
||||
{
|
||||
|
||||
public function addPolicy($data){
|
||||
//基础参数
|
||||
$keys = ['name','type','filetype'];
|
||||
|
||||
// 附加参数
|
||||
$field = [];
|
||||
|
||||
foreach ($data as $key => $item){
|
||||
if(!in_array($key,$keys)){
|
||||
$field[$key] = $item;
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$data['config'] = json_encode($field);
|
||||
|
||||
self::insert($data);
|
||||
}
|
||||
|
||||
public function editPolicy($id,$data){
|
||||
//基础参数
|
||||
$keys = ['name','type','filetype'];
|
||||
// 附加参数
|
||||
$field = [];
|
||||
foreach ($data as $key => $item){
|
||||
if(!in_array($key,$keys)){
|
||||
$field[$key] = $item;
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
$data['config'] = json_encode($field);
|
||||
self::where('id',$id)->update($data);
|
||||
}
|
||||
|
||||
public function getConfigAttr($value){
|
||||
return json_decode($value,true);
|
||||
}
|
||||
|
||||
public static function getPolicyAll(): array
|
||||
{
|
||||
return self::field('id,name')->select()->toArray();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Profit extends Model
|
||||
{
|
||||
|
||||
|
||||
public static function record($uid,$file_id,$field,$value = 1): bool
|
||||
{
|
||||
|
||||
$fp = fopen('record_lock.txt', "w+");
|
||||
|
||||
if(flock($fp,LOCK_EX | LOCK_NB)){
|
||||
// 判断今日是否统计
|
||||
$rec = self::where('uid',$uid)->where('file_id',$file_id)->whereTime('create_time','d')->find();
|
||||
|
||||
// 补全字段
|
||||
$field = 'count_'.$field;
|
||||
|
||||
if($field == 'count_view'){
|
||||
Stores::where('id',$file_id)->where('uid',$uid)->setInc('count_open',1);
|
||||
}
|
||||
|
||||
if($field == 'count_down'){
|
||||
Stores::where('id',$file_id)->where('uid',$uid)->setInc('count_down',1);
|
||||
}
|
||||
|
||||
|
||||
if(!empty($rec)){
|
||||
|
||||
self::where('uid',$uid)->where('file_id',$file_id)->setInc($field,$value);
|
||||
|
||||
flock($fp,LOCK_UN);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 插入新统计
|
||||
$data = [
|
||||
'uid' => $uid,
|
||||
'file_id' => $file_id,
|
||||
'create_time' => time(),
|
||||
$field => $value
|
||||
];
|
||||
|
||||
// 插入统计
|
||||
self::insert($data);
|
||||
|
||||
flock($fp,LOCK_UN);
|
||||
return true;
|
||||
} else{
|
||||
fclose($fp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Record extends Model
|
||||
{
|
||||
|
||||
public static function addRecord($uid,$type,$source,$money,$remark){
|
||||
$user = Users::where('id',$uid)->find();
|
||||
|
||||
// 操作前金额
|
||||
$before_money = $user['amount'];
|
||||
// 操作
|
||||
if($type){
|
||||
$after_money = floatval($user['amount']) - floatval($money);
|
||||
}else{
|
||||
$after_money = floatval($user['amount']) + floatval($money);
|
||||
}
|
||||
|
||||
if($after_money < 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($type){
|
||||
Users::where('id',$uid)->setDec('amount',$money);
|
||||
}else{
|
||||
Users::where('id',$uid)->setInc('amount',$money);
|
||||
}
|
||||
|
||||
return self::create([
|
||||
'uid' => $uid,
|
||||
'type' => $type,
|
||||
'source' => $source,
|
||||
'money' => $money,
|
||||
'before_money' => $before_money,
|
||||
'after_money' => $after_money,
|
||||
'remark' => $remark,
|
||||
'create_time' => time()
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Reports extends Model
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Setting extends Model
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Exception;
|
||||
use think\Model;
|
||||
|
||||
class Shares extends Model
|
||||
{
|
||||
|
||||
public static function addShare($uid,$source,$type){
|
||||
|
||||
$share_code = '';
|
||||
|
||||
for ($i = 0;$i < 5;$i++){
|
||||
$code = shortUrl($uid.'_'.$source.'_'.$type.time());
|
||||
if(self::where('code',$code)->count() == 0){
|
||||
$share_code = $code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($share_code)){
|
||||
throw new Exception('分享连接生成失败,请稍后重试');
|
||||
}
|
||||
|
||||
$pwd = getRndSharePwd();
|
||||
|
||||
$data = [
|
||||
'uid' => $uid,
|
||||
'source_id' => $source,
|
||||
'type' => $type,
|
||||
'speed' => 0,
|
||||
'code' => $code,
|
||||
'pwd' => $pwd,
|
||||
'pwd_status' => 0
|
||||
];
|
||||
|
||||
return self::insertGetId($data);
|
||||
}
|
||||
|
||||
public static function getShare($uid,$source,$type){
|
||||
return self::where([
|
||||
['uid','=',$uid],
|
||||
['source_id','=',$source],
|
||||
['type','=',$type]
|
||||
])->field('id,code,pwd,pwd_status,speed')->find();
|
||||
}
|
||||
|
||||
public function delShare(){
|
||||
|
||||
}
|
||||
|
||||
public static function updateShare($id,$data){
|
||||
return self::where('id',$id)->update($data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class Stores extends Model
|
||||
{
|
||||
|
||||
use SoftDelete;
|
||||
|
||||
protected $deleteTime = 'delete_time';
|
||||
|
||||
protected $autoWriteTimestamp = true;
|
||||
|
||||
public function getPolicy(){
|
||||
$policy = Policys::get($this->policy_id);
|
||||
if(empty($policy)){
|
||||
return false;
|
||||
}
|
||||
return $policy;
|
||||
}
|
||||
|
||||
public function getLocalSaveFilePath($save_dir,$filename): string
|
||||
{
|
||||
return env('root_path').'public'.getSafeDirSeparator($save_dir . $filename);
|
||||
}
|
||||
|
||||
public function getLocalSaveFile($save_dir,$filename){
|
||||
return str_replace(['/','\\','//','\\\\'],'/',($save_dir.$filename));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use app\common\exception\LoginError;
|
||||
use think\Exception;
|
||||
use think\facade\Session;
|
||||
use think\Model;
|
||||
|
||||
class Users extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* 用户注册方法
|
||||
* @param $username
|
||||
* @param $email
|
||||
* @param $password
|
||||
* @param $group
|
||||
* @param array $other
|
||||
* @throws Exception
|
||||
*/
|
||||
public function register($username, $email, $password, $group, array $other = [],$group_expire=0){
|
||||
|
||||
if(self::where('username',$username)->count() > 0){
|
||||
throw new Exception('当前帐号已被注册');
|
||||
}
|
||||
|
||||
if(self::where('email',$email)->count() > 0){
|
||||
throw new Exception('当前安全邮箱已被绑定');
|
||||
}
|
||||
|
||||
$en_password = md5($password . config('app.pass_salt'));
|
||||
|
||||
$nickname = ucfirst($username);
|
||||
|
||||
if(isset($other['nickname'])){
|
||||
$nickname = $other['nickname'];
|
||||
}
|
||||
|
||||
$user = [
|
||||
'nickname' => $nickname,
|
||||
'username' => $username,
|
||||
'email' => $email,
|
||||
'group' => $group,
|
||||
'password' => $en_password,
|
||||
'create_time' => time(),
|
||||
'group_expire' => $group_expire,
|
||||
'status' => 1
|
||||
];
|
||||
|
||||
self::insert($user);
|
||||
|
||||
$user_id = self::getLastInsID();
|
||||
|
||||
//添加基础目录
|
||||
if($group != 1){
|
||||
Folders::insert([
|
||||
'uid' => $user_id,
|
||||
'folder_name' => '根目录',
|
||||
'parent_folder' => 0,
|
||||
'create_time' => time()
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用户登录登录方法
|
||||
* @param $username
|
||||
* @param $password
|
||||
* @param string $login_type
|
||||
* @return bool
|
||||
* @throws LoginError
|
||||
*/
|
||||
public function login($username,$password,$login_type = 'default'){
|
||||
// 登录用户组类型
|
||||
if($login_type == 'admin'){
|
||||
$group = 1;
|
||||
}else{
|
||||
$group = config('register.default_group') .','.config('vip.vip_group');
|
||||
}
|
||||
// 查找用户
|
||||
$user = self::where('username',$username)->where('group','in',$group)->find();
|
||||
// 用户不存在
|
||||
if(empty($user)){
|
||||
throw new LoginError('登录帐号或者密码错误,请重试');
|
||||
}
|
||||
// 加密密码
|
||||
$password = md5($password . config('app.pass_salt'));
|
||||
|
||||
if($user['password'] != $password){
|
||||
throw new LoginError('登录帐号或者密码错误,请重试');
|
||||
}
|
||||
|
||||
// 不允许登录
|
||||
if($login_type == 'default' && $user['status'] == 0){
|
||||
throw new LoginError('登录帐号已被管理员封禁,请联系管理员处理!');
|
||||
}
|
||||
|
||||
// 登录成功
|
||||
Session::set($login_type .'_uid',$user['id']);
|
||||
Session::set($login_type .'_lkey',md5($username . $password . $user['status']));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 退出登录方法
|
||||
* @param string $type
|
||||
*/
|
||||
public function logout(string $type = 'default'){
|
||||
Session::delete($type .'_uid');
|
||||
Session::delete($type .'_lkey');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*登录验证方法
|
||||
* @param string $type
|
||||
* @return bool
|
||||
*/
|
||||
public function login_auth(string $type = 'default'): bool
|
||||
{
|
||||
$uid = Session::get($type .'_uid');
|
||||
$key = Session::get($type .'_lkey');
|
||||
|
||||
$user = self::where('id',$uid)->find();
|
||||
|
||||
if(empty($user)){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($key != md5($user['username'] . $user['password'] . $user['status'])){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
* @param string $type
|
||||
* @return Users|false
|
||||
*/
|
||||
public function login_info(string $type = 'default'){
|
||||
$uid = Session::get($type .'_uid');
|
||||
|
||||
$user = self::where('id',$uid)->find();
|
||||
|
||||
if(empty($user)){
|
||||
return false;
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
||||
public function getCertify(){
|
||||
return Certify::where('uid',$this->id)
|
||||
->where('status',1)
|
||||
->field('name,idcard,create_time')
|
||||
->find();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Withdraw extends Model
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model\driver;
|
||||
|
||||
use OSS\Core\OssException;
|
||||
use OSS\OssClient;
|
||||
use think\Exception;
|
||||
use think\facade\Cache;
|
||||
|
||||
class AliyunOss extends PolicyStore
|
||||
{
|
||||
|
||||
public function uploadSimple(){
|
||||
|
||||
// 临时文件地址
|
||||
$temp_file = $this->path['temp_path'] . $this->path['filename'];
|
||||
|
||||
// 保存临时文件
|
||||
$file_info = $this->info['file']['data']->move($this->path['temp_path'],$this->path['filename']);
|
||||
|
||||
if(!$file_info){
|
||||
throw new Exception($this->info['file']['data']->getError());
|
||||
}
|
||||
|
||||
$accessKeyId = $this->policy['config']['access_key'];
|
||||
$accessKeySecret = $this->policy['config']['access_secret'];
|
||||
$endpoint = $this->policy['config']['endpoint'];
|
||||
$bucket = $this->policy['config']['bucket'];
|
||||
|
||||
$policy_save_dir = ltrim($this->policy['config']['save_dir'],'/');
|
||||
|
||||
$object = getDiyDirSeparator('/',$policy_save_dir. $this->path['file'].$this->path['filename']);
|
||||
|
||||
try{
|
||||
$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
|
||||
|
||||
$ossClient->uploadFile($bucket,$object,$temp_file);
|
||||
|
||||
// 删除临时文件
|
||||
@unlink($temp_file);
|
||||
|
||||
// 返回文件存储地址
|
||||
return '/'. $object;
|
||||
|
||||
} catch(OssException $e) {
|
||||
throw new Exception('FAILED:'.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function uploadPart()
|
||||
{
|
||||
|
||||
// 临时文件地址
|
||||
$temp_file = $this->path['temp_path'] . $this->path['filename'];
|
||||
|
||||
// 保存临时文件
|
||||
$file_info = $this->info['file']['data']->move($this->path['temp_path'],$this->path['filename']);
|
||||
|
||||
if(!$file_info){
|
||||
throw new Exception($this->info['file']['data']->getError());
|
||||
}
|
||||
|
||||
$accessKeyId = $this->policy['config']['access_key'];
|
||||
$accessKeySecret = $this->policy['config']['access_secret'];
|
||||
$endpoint = $this->policy['config']['endpoint'];
|
||||
$bucket = $this->policy['config']['bucket'];
|
||||
|
||||
$policy_save_dir = ltrim($this->policy['config']['save_dir'],'/');
|
||||
|
||||
// 缓存分片上传地址
|
||||
$chunks_object_keys = 'aliyun_oss_chunks_'.$this->info['chunk']['key'];
|
||||
$multi_upload_object = Cache::get($chunks_object_keys);
|
||||
|
||||
|
||||
try {
|
||||
$client = new OssClient($accessKeyId,$accessKeySecret,$endpoint);
|
||||
|
||||
// 缓存防止重复文件地址
|
||||
if(empty($multi_upload_object)){
|
||||
$upload_object_path = getDiyDirSeparator('/',$policy_save_dir. $this->path['file'].$this->path['filename']);
|
||||
|
||||
$uploadId = $client->initiateMultipartUpload($bucket,$upload_object_path);
|
||||
|
||||
$multi_upload_object = [
|
||||
'object' => $upload_object_path,
|
||||
'upload_id' => $uploadId
|
||||
];
|
||||
|
||||
Cache::set($chunks_object_keys,$multi_upload_object);
|
||||
}
|
||||
|
||||
// 分片上传配置
|
||||
$options = [
|
||||
// 上传文件地址
|
||||
OssClient::OSS_FILE_UPLOAD => $temp_file,
|
||||
// 分片号
|
||||
OssClient::OSS_PART_NUM => $this->info['chunk']['chunk'] + 1,
|
||||
];
|
||||
|
||||
$client->uploadPart($bucket, $multi_upload_object['object'], $multi_upload_object['upload_id'], $options);
|
||||
|
||||
// 组合文件
|
||||
if(($this->info['chunk']['chunk'] + 1) == $this->info['chunk']['chunks']){
|
||||
|
||||
// 获取所有分片信息
|
||||
$listPartsInfo = $client->listParts($bucket, $multi_upload_object['object'], $multi_upload_object['upload_id']);
|
||||
|
||||
$uploadParts = [];
|
||||
|
||||
foreach ($listPartsInfo->getListPart() as $partInfo) {
|
||||
|
||||
$uploadParts[] = [
|
||||
'PartNumber' => $partInfo->getPartNumber(),
|
||||
'ETag' => $partInfo->getETag()
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
// 合并分片
|
||||
$client->completeMultipartUpload($bucket, $multi_upload_object['object'], $multi_upload_object['upload_id'], $uploadParts);
|
||||
|
||||
// 删除分片缓存信息
|
||||
Cache::rm($chunks_object_keys);
|
||||
// 删除临时文件
|
||||
@unlink($temp_file);
|
||||
|
||||
// 返回结果
|
||||
return '/' . $multi_upload_object['object'];
|
||||
}
|
||||
|
||||
// 删除临时文件
|
||||
@unlink($temp_file);
|
||||
|
||||
return 'chunk_file';
|
||||
|
||||
}catch (OssException $e){
|
||||
throw new Exception('FAILED:'.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function download($stores, $speed, $policy)
|
||||
{
|
||||
|
||||
$accessKeyId = $policy['config']['access_key'];
|
||||
$accessKeySecret = $policy['config']['access_secret'];
|
||||
$endpoint = $policy['config']['endpoint'];
|
||||
$bucket = $policy['config']['bucket'];
|
||||
|
||||
$object = ltrim($stores['file_name'],'/');
|
||||
|
||||
// 限速下载
|
||||
if($speed !== ""){
|
||||
// 下载速度
|
||||
$down_speed = round(intval($speed) * 8192);
|
||||
|
||||
// 最小限速100kb/s
|
||||
if($down_speed < 819200){
|
||||
$down_speed = 819200;
|
||||
}
|
||||
|
||||
$options = [
|
||||
OssClient::OSS_TRAFFIC_LIMIT => $down_speed
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
$ossClient = new OssClient($accessKeyId,$accessKeySecret,$endpoint);
|
||||
|
||||
$options['response-content-disposition'] = 'attachment; filename='.$stores['origin_name'];
|
||||
|
||||
// 120s有效期
|
||||
$timeout = 120;
|
||||
$signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "GET", $options);
|
||||
|
||||
// 跳转下载地址
|
||||
return redirect($signedUrl);
|
||||
|
||||
}catch (OssException $e){
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model\driver;
|
||||
|
||||
use think\Exception;
|
||||
use think\facade\Cache;
|
||||
|
||||
class Local extends PolicyStore
|
||||
{
|
||||
|
||||
public function uploadSimple()
|
||||
{
|
||||
// 保存文件
|
||||
$file_info = $this->info['file']['data']->move($this->path['path'],$this->path['name']);
|
||||
|
||||
if(!$file_info){
|
||||
throw new Exception($this->info['file']['data']->getError());
|
||||
}
|
||||
|
||||
$policy_save_dir = $this->policy['config']['save_dir'];
|
||||
|
||||
return getDiyDirSeparator('/',$policy_save_dir. $this->path['file'].$this->path['filename']);
|
||||
}
|
||||
|
||||
public function uploadPart()
|
||||
{
|
||||
// 分片数据存储名称
|
||||
$chunks_saveKey = 'chunks_'.$this->info['uid'].'_'.$this->info['chunk']['key'];
|
||||
|
||||
// 文件名称
|
||||
$temp_filename = 'chunks_'.md5($this->info['chunk']['key']).'_'.$this->getRandomKey(4) . '_part_'.$this->info['chunk']['chunk'].'.chunk';
|
||||
// 临时文件地址
|
||||
$temp_file = $this->path['temp_path'] . $temp_filename;
|
||||
|
||||
// 保存临时文件
|
||||
$file_info = $this->info['file']['data']->move($this->path['temp_path'],$temp_filename);
|
||||
|
||||
if(!$file_info){
|
||||
throw new Exception('分片创建错误:'.$this->info['file']['data']->getError());
|
||||
}
|
||||
|
||||
// 分片存储列表
|
||||
$chunk_list = Cache::get($chunks_saveKey) ?? [];
|
||||
|
||||
// 加入分片文件
|
||||
$chunk_list[] = $temp_file;
|
||||
|
||||
// 保存分片临时存储列表
|
||||
Cache::set($chunks_saveKey,$chunk_list);
|
||||
|
||||
// 分片上传成功
|
||||
if($this->info['chunk']['chunk'] == ($this->info['chunk']['chunks'] - 1)){
|
||||
|
||||
$save_file = $this->path['path'] . $this->path['filename'];
|
||||
|
||||
// 融合文件路径
|
||||
$fileObj = fopen($save_file,"a+");
|
||||
|
||||
// 融合文件
|
||||
foreach ($chunk_list as $value) {
|
||||
$chunkObj = fopen($value, "rb");
|
||||
|
||||
if(!($fileObj && $chunkObj)){
|
||||
throw new Exception('分片融合文件创建失败');
|
||||
}
|
||||
|
||||
$content = fread($chunkObj, (2 * 1024 * 1024));
|
||||
fwrite($fileObj, $content, (2 * 1024 * 1024));
|
||||
unset($content);
|
||||
fclose($chunkObj);
|
||||
// 删除分片文件
|
||||
unlink($value);
|
||||
}
|
||||
|
||||
// 清空分片临时存储列表
|
||||
Cache::rm($chunks_saveKey);
|
||||
|
||||
$policy_save_dir = $this->policy['config']['save_dir'];
|
||||
|
||||
return getDiyDirSeparator('/',$policy_save_dir. $this->path['file'] . $this->path['filename']);
|
||||
}
|
||||
|
||||
return 'chunk_file';
|
||||
|
||||
}
|
||||
|
||||
protected function getRandomKey($length = 16){
|
||||
$charTable = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$result = "";
|
||||
for ( $i = 0; $i < $length; $i++ ){
|
||||
$result .= $charTable[ mt_rand(0, strlen($charTable) - 1) ];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function download($stores,$speed,$policy)
|
||||
{
|
||||
//存储文件地址
|
||||
$_file = getSafeDirSeparator(env('root_path').'public'.$stores['file_name']);
|
||||
|
||||
// 文件不存在
|
||||
if(!is_file($_file)){
|
||||
throw new Exception('文件不存在,可能已被删除');
|
||||
}
|
||||
|
||||
$_file_path = $stores['file_name'];
|
||||
|
||||
$_file_limit_size = round(intval($speed) * 1024);
|
||||
|
||||
// 启用 nginx X-Accel 下载
|
||||
header('Content-Type: application/octet-stream');
|
||||
$encoded_fname = rawurlencode($stores['origin_name']);
|
||||
header('Content-Disposition: attachment;filename="'.$encoded_fname.'";filename*=utf-8'."''".$encoded_fname);
|
||||
|
||||
header('X-Accel-Redirect: '. $_file_path);
|
||||
header('X-Accel-Buffering: yes');
|
||||
|
||||
// 不限速下载
|
||||
if($speed !== ""){
|
||||
header('X-Accel-Limit-Rate:'.$_file_limit_size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model\driver;
|
||||
|
||||
abstract class PolicyStore
|
||||
{
|
||||
|
||||
protected $info;
|
||||
|
||||
protected $policy;
|
||||
|
||||
protected $path;
|
||||
|
||||
|
||||
public function __construct($info,$policy,$path)
|
||||
{
|
||||
$this->info = $info;
|
||||
$this->policy = $policy;
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
public function upload()
|
||||
{
|
||||
if(!empty($this->info['chunk']['chunks'])){
|
||||
return $this->uploadPart();
|
||||
}else{
|
||||
return $this->uploadSimple();
|
||||
}
|
||||
}
|
||||
|
||||
public function uploadSimple()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function uploadPart()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function download($stores,$speed,$policy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model\driver;
|
||||
|
||||
use Qcloud\Cos\Client;
|
||||
use Qcloud\Cos\Exception\ServiceResponseException;
|
||||
use think\Exception;
|
||||
use think\facade\Cache;
|
||||
|
||||
class TxyunOss extends PolicyStore
|
||||
{
|
||||
|
||||
public function uploadSimple(){
|
||||
|
||||
$secretId = $this->policy['config']['secret_id'];
|
||||
$secretKey = $this->policy['config']['secret_key'];
|
||||
$region = $this->policy['config']['region'];
|
||||
$bucket = $this->policy['config']['bucket'];
|
||||
|
||||
// 文件路径
|
||||
$file_path = $this->info['file']['data']->getInfo('tmp_name');
|
||||
$file = fopen($file_path, 'rb');
|
||||
|
||||
// 存储路径
|
||||
$policy_save_dir = ltrim($this->policy['config']['save_dir'],'/');
|
||||
$object = getDiyDirSeparator('/',$policy_save_dir. $this->path['file'].$this->path['filename']);
|
||||
|
||||
try {
|
||||
// COS对象
|
||||
$client = new Client([
|
||||
'region' => $region,
|
||||
'schema' => 'http',
|
||||
'credentials' => [
|
||||
'secretId' => $secretId,
|
||||
'secretKey' => $secretKey
|
||||
]
|
||||
]);
|
||||
|
||||
if ($file) {
|
||||
// 上传文件
|
||||
$client->putObject([
|
||||
'Bucket' => $bucket,
|
||||
'Key' => $object,
|
||||
'Body' => $file
|
||||
]);
|
||||
|
||||
// 返回文件存储地址
|
||||
return '/'. $object;
|
||||
}else{
|
||||
throw new Exception('上传文件路径错误');
|
||||
}
|
||||
|
||||
}catch (ServiceResponseException $e){
|
||||
throw new Exception($e->getMessage());
|
||||
}catch (\Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function uploadPart()
|
||||
{
|
||||
|
||||
// 配置信息
|
||||
$secretId = $this->policy['config']['secret_id'];
|
||||
$secretKey = $this->policy['config']['secret_key'];
|
||||
$region = $this->policy['config']['region'];
|
||||
$bucket = $this->policy['config']['bucket'];
|
||||
|
||||
// 分片数据存储名称
|
||||
$chunks_saveKey = 'txyunoss_chunks_'.$this->info['uid'].'_'.$this->info['chunk']['key'];
|
||||
|
||||
// 文件名称
|
||||
$temp_filename = 'chunks_'.md5($this->info['chunk']['key']).'_'.$this->getRandomKey(4) . '_part_'.$this->info['chunk']['chunk'].'.chunk';
|
||||
// 临时文件地址
|
||||
$temp_file = $this->path['temp_path'] . $temp_filename;
|
||||
|
||||
// 保存临时文件
|
||||
$file_info = $this->info['file']['data']->move($this->path['temp_path'],$temp_filename);
|
||||
|
||||
if(!$file_info){
|
||||
throw new Exception('分片创建错误:'.$this->info['file']['data']->getError());
|
||||
}
|
||||
|
||||
// 分片存储列表
|
||||
$chunk_list = Cache::get($chunks_saveKey) ?? [];
|
||||
|
||||
// 加入分片文件
|
||||
$chunk_list[] = $temp_file;
|
||||
|
||||
// 保存分片临时存储列表
|
||||
Cache::set($chunks_saveKey,$chunk_list);
|
||||
|
||||
// 分片上传成功
|
||||
if($this->info['chunk']['chunk'] == ($this->info['chunk']['chunks'] - 1)){
|
||||
|
||||
// COS对象
|
||||
$client = new Client([
|
||||
'region' => $region,
|
||||
'schema' => 'http',
|
||||
'credentials' => [
|
||||
'secretId' => $secretId,
|
||||
'secretKey' => $secretKey
|
||||
]
|
||||
]);
|
||||
|
||||
$save_file = $this->path['temp_path'] . 'cos_cob_'.substr(md5($this->info['chunk']['key']),0,8).'_t_'.time().'.bak';
|
||||
|
||||
// 融合文件路径
|
||||
$fileObj = fopen($save_file,"a+");
|
||||
|
||||
// 融合文件
|
||||
foreach ($chunk_list as $value) {
|
||||
$chunkObj = fopen($value, "rb");
|
||||
|
||||
if(!($fileObj && $chunkObj)){
|
||||
throw new Exception('分片融合文件创建失败');
|
||||
}
|
||||
|
||||
$content = fread($chunkObj, (2 * 1024 * 1024));
|
||||
fwrite($fileObj, $content, (2 * 1024 * 1024));
|
||||
unset($content);
|
||||
fclose($chunkObj);
|
||||
// 删除分片文件
|
||||
unlink($value);
|
||||
}
|
||||
|
||||
// 清空分片临时存储列表
|
||||
Cache::rm($chunks_saveKey);
|
||||
|
||||
try {
|
||||
$policy_save_dir = $this->policy['config']['save_dir'];
|
||||
$upload_object_path = getDiyDirSeparator('/',$policy_save_dir. $this->path['file'].$this->path['filename']);
|
||||
|
||||
if ($fileObj) {
|
||||
// 上传文件
|
||||
$client->Upload($bucket,$upload_object_path,$fileObj);
|
||||
|
||||
// 删除临时组合文件
|
||||
@unlink($save_file);
|
||||
|
||||
return $upload_object_path;
|
||||
}else{
|
||||
throw new Exception('上传文件路径错误');
|
||||
}
|
||||
|
||||
}catch (ServiceResponseException $e){
|
||||
throw new Exception($e->getMessage());
|
||||
}catch (\Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return 'chunk_file';
|
||||
}
|
||||
|
||||
protected function getRandomKey($length = 16){
|
||||
$charTable = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$result = "";
|
||||
for ( $i = 0; $i < $length; $i++ ){
|
||||
$result .= $charTable[ mt_rand(0, strlen($charTable) - 1) ];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function download($stores, $speed, $policy)
|
||||
{
|
||||
|
||||
$secretId = $policy['config']['secret_id'];
|
||||
$secretKey = $policy['config']['secret_key'];
|
||||
$region = $policy['config']['region'];
|
||||
$bucket = $policy['config']['bucket'];
|
||||
|
||||
$object = ltrim($stores['file_name'],'/');
|
||||
|
||||
// COS对象
|
||||
$client = new Client([
|
||||
'region' => $region,
|
||||
'schema' => 'http',
|
||||
'credentials' => [
|
||||
'secretId' => $secretId,
|
||||
'secretKey' => $secretKey
|
||||
]
|
||||
]);
|
||||
|
||||
$disposition = 'attachment; filename='.$stores['origin_name'];
|
||||
|
||||
$url = $client->getPresignedUrl('GetObject',[
|
||||
'Bucket' => $bucket,
|
||||
'Key' => $object
|
||||
],'+10 minutes')->__toString();
|
||||
|
||||
$url .= 'response-content-disposition='.urlencode($disposition).'&';
|
||||
|
||||
// 限速下载
|
||||
if($speed !== ""){
|
||||
// 下载速度
|
||||
$down_speed = round(intval($speed) * 8192);
|
||||
|
||||
// 最小限速100kb/s
|
||||
if($down_speed < 819200){
|
||||
$down_speed = 819200;
|
||||
}
|
||||
|
||||
$url .= 'x-cos-traffic-limit='.$down_speed;
|
||||
}
|
||||
|
||||
// 跳转下载地址
|
||||
return redirect($url);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user