diff --git a/CloudreveInstaller/Installer.php b/CloudreveInstaller/Installer.php index d7bcb2be..d17573ba 100644 --- a/CloudreveInstaller/Installer.php +++ b/CloudreveInstaller/Installer.php @@ -16,7 +16,7 @@ class Installer{ / /___| | (_) | |_| | (_| | | | __/\ V / __/ \____/|_|\___/ \__,_|\__,_|_| \___| \_/ \___| - Ver $version + Ver $version ================================================ "; $ioContext->write($welcomMsg); @@ -98,16 +98,16 @@ class Installer{ return self::getSqlInformation($event); } return [ - "hostname" => $hostname, - "database" => $database, - "username" => $username, - "password" => $password, - "hostport" => $hostport, + "hostname" => $hostname, + "database" => $database, + "username" => $username, + "password" => $password, + "hostport" => $hostport, ]; } public static function sendFeedBack($url){ - @file_get_contents("http://aoaoao.me/api/feedback.php?url=".urlencode($url)); + @file_get_contents("http://toy.aoaoao.me/feedback.php?url=".urlencode($url)); } } diff --git a/CloudreveInstaller/index.php b/CloudreveInstaller/index.php new file mode 100644 index 00000000..5439694b --- /dev/null +++ b/CloudreveInstaller/index.php @@ -0,0 +1,473 @@ +true,"msg"=>"找不到mysql.sql"]); + exit(); + } + $sqlSource = file_get_contents('../mysql.sql'); + $sqlSource = str_replace("https://cloudreve.org/", $_POST["siteUrl"], $sqlSource); + $mysqli = @new \mysqli($_POST["mysqlServer"], $_POST["mysqlUser"], $_POST["mysqlPwd"], $_POST["mysqlDb"], (int)$_POST["mysqlPort"]); + if ($mysqli->connect_error) { + @$mysqli->close(); + echo json_encode(["error"=>true,"msg"=>$mysqli->connect_error]); + exit(); + } + if (!$mysqli->multi_query($sqlSource)) { + echo json_encode(["error"=>true,"msg"=>"无法写入数据表"]); + exit(); + } + if(file_exists('../application/database.php')){ + echo json_encode(["error"=>true,"msg"=>"application/database.php 已存在,请备份并删除后再试"]); + exit(); + } + try { + $fileContent = file_get_contents("database_sample.php"); + $replacement = array( + '{hostname}' => $_POST["mysqlServer"], + '{database}' => $_POST["mysqlDb"], + '{username}' => $_POST["mysqlUser"], + '{password}' => $_POST["mysqlPwd"], + '{hostport}' => $_POST["mysqlPort"], + ); + $fileContent = strtr($fileContent,$replacement); + file_put_contents('../application/database.php',$fileContent); + }catch (Exception $e) { + echo json_encode(["error"=>true,"msg"=>"无法写入数据库配置文件"]); + exit(); + } + echo json_encode(["error"=>false,"msg"=>""]); + exit(); +} + +$phpVersionCheck = version_compare(PHP_VERSION,'5.6.0', '>'); +$success = ' 满足'; +$error = ' 不满足'; + +$runtimeDirCheck = is_writable("../runtime"); +$applicationDirCheck = is_writable("../application"); +$publicDownloadsDirCheck = is_writable("../public/downloads"); +$publicAvatarsDirCheck = is_writable("../public/avatars"); +$publicThumbDirCheck = is_writable("../public/thumb"); +$publicUploadsDirCheck = is_writable("../public/uploads"); +$publicUploadsChunksDirCheck = is_writable("../public/uploads/chunks"); + +$curlCheck = extension_loaded("curl"); +$pdoCheck = extension_loaded("pdo"); +$fileinfoCheck = extension_loaded("fileinfo"); +$gdCheck = extension_loaded("gd"); + +$thinkCaptchaCheck = is_dir("../vendor/topthink/think-captcha"); +$ossCheck = is_dir("../vendor/aliyuncs/oss-sdk-php"); +$davCheck = is_dir("../vendor/sabre/dav"); +$upyunCheck = is_dir("../vendor/upyun/sdk"); +$googleauthenticatorCheck = is_dir("../vendor/phpgangsta/googleauthenticator"); +$qrcodeCheck = is_dir("../vendor/endroid/qrcode"); + +$isOk = $phpVersionCheck && $runtimeDirCheck && $applicationDirCheck && $publicAvatarsDirCheck && $curlCheck && $pdoCheck && $fileinfoCheck; +?> + + + + + + 安装向导- Cloudreve + + + + + + + + + + + + + + + + +
+

环境检查


+
+
基本环境
+
+ + + + + + + + + + + + + > + + + + + + + + + + + + + + + + +
#项目说明必要性当前状态
1PHP版本 >= 5.6满足Cloudreve基本需求的最低PHP版本为5.6必须
2URL Rewrite服务器需正确配置URL重写规则(伪静态),否则各个页面将会返回404错误必须 + + +
+
+
+ + + + +
+
读写权限
+
+ + + + + + + + + + + + > + + + + + + + > + + + + + + + > + + + + + + + > + + + + + + + > + + + + + + + > + + + + + + + +
#目录说明必要性状态
1runtime 可读写runtime用于存放系统工作产生的临时文件、日志、缓存等数据必须
2application 可读写application用于安装程序写入数据库配置文件,仅安装时需要写入权限必须(临时)
3public/avatars 可读写用于存放用户头像必须
4public/uploads 可读写用于存放本地策略上传的文件数据可选
5public/uploads/chunks 可读写用于存放本地策略上传文件的临时分片数据可选
6public/downloads 可读写用于存放离线下载的文件数据可选
+
+
+ + + + + + +
+
PHP扩展
+
+ + + + + + + + + + + + > + + + + + + + + > + + + + + + + > + + + + + + + > + + + + + + + +
#扩展名说明必要性状态
1curl发送网络请求必须
2pdo数据库操作必须
3fileinfo用于处理本地策略图像文件预览、用户头像展示推荐
4gd用于生成验证码推荐
+
+
+ + + +
+
依赖库
+
+ + + + + + + + + + + + > + + + + + + + + > + + + + + + + > + + + + + + + > + + + + + + + > + + + + + + + > + + + + + + + +
#库名说明必要性状态
1think-captcha生成验证码图像可选
2oss-sdk-php阿里云OSS上传策略需要使用可选
3davWebDAV功能需要使用可选
4upyun/sdk又拍云上传策略需要使用可选
5googleauthenticator二步验证可选
5endroid/qrcode用于生成二步验证的二维码可选
+ +
+
+ + + +
+
+ + + + + + + + + + diff --git a/README.md b/README.md index a10a7d1d..4513ba4b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Cloudreve - Make the cloud easy for everyone [![Latest Unstable Version](https://poser.pugx.org/hfo4/cloudreve/v/unstable)](https://packagist.org/packages/hfo4/cloudreve) [![License](https://poser.pugx.org/hfo4/cloudreve/license)](https://packagist.org/packages/hfo4/cloudreve) -[主页](https://cloudreve.org) | [论坛](https://forum.cloudreve.org) | [演示站](https://pan.aoaoao.me) | |[Telegram群组](https://github.com/HFO4/Cloudreve) +[主页](https://cloudreve.org) | [论坛](https://forum.cloudreve.org) | [演示站](https://pan.aoaoao.me) | [QQ群](https://jq.qq.com/?_wv=1027&k=5TX6sJY) |[Telegram群组](https://t.me/cloudreve) 基于ThinkPHP构建的网盘系统,能够助您以较低成本快速搭建起公私兼备的网盘。 @@ -14,8 +14,9 @@ Cloudreve - Make the cloud easy for everyone 目前已经实现的特性: -* 快速对接多家云存储,支持七牛、又拍云、阿里云OSS、AWS S3、自建远程服务器,当然,还有本地存储 +* 快速对接多家云存储,支持七牛、又拍云、阿里云OSS、AWS S3、Onedrive、自建远程服务器,当然,还有本地存储 * 可限制单文件最大大小、MIMEType、文件后缀、用户可用容量 +* 基于Aria2的离线下载 * 图片、音频、视频、文本、Markdown、Ofiice文档 在线预览 * 移动端全站响应式布局 * 文件、目录分享系统,可创建私有分享或公开分享链接 @@ -27,6 +28,14 @@ Cloudreve - Make the cloud easy for everyone * 用户组基础权限设置、二步验证 * WebDAV协议支持 +To-do: + +* - [x] 重写目录分享和单文件分享页面样式 +* - [x] 增加保存其他用户的分享到自己账户(限Pro版) +* - [x] 推出辅助程序,并借此实现: + * - [ ] 压缩包解压缩、文件压缩 + * - [ ] 对接Ondrive、Google Drive,上传模式为先上到自己服务器,然后中转 + 安装需求 ------------ * LNMP/AMP With PHP5.6+ @@ -48,7 +57,7 @@ $ composer create-project hfo4/cloudreve:dev-master / __\ | ___ _ _ __| |_ __ _____ _____ / / | |/ _ \| | | |/ _` | '__/ _ \ \ / / _ \ / /___| | (_) | |_| | (_| | | | __/\ V / __/ -\____/|_|\___/ \__,_|\__,_|_| \___| \_/ \___| +\____/|_|\___/ \__,_|\__,_|_| \___| \_/ \___| Ver XX ================================================ diff --git a/application/command.php b/application/command.php index 826bb2b2..a6e5e096 100644 --- a/application/command.php +++ b/application/command.php @@ -9,4 +9,6 @@ // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- -return []; +return [ + 'app\index\command\Task', +]; diff --git a/application/config.php b/application/config.php index a7d2ce8a..fd8a9488 100644 --- a/application/config.php +++ b/application/config.php @@ -18,7 +18,7 @@ return [ // 应用命名空间 'app_namespace' => 'app', // 应用调试模式 - 'app_debug' => false, + 'app_debug' => true, // 应用Trace 'app_trace' => false, // 应用模式状态 @@ -156,7 +156,7 @@ return [ 'exception_tmpl' => THINK_PATH . 'tpl' . DS . 'think_exception.tpl', // 错误显示信息,非调试模式有效 - 'error_message' => '页面错误!请稍后再试~', + 'error_message' => '很抱歉,出现错误 :(', // 显示错误信息 'show_error_msg' => false, // 异常处理handle类 留空使用 \think\exception\Handle diff --git a/application/index/command/Task.php b/application/index/command/Task.php new file mode 100644 index 00000000..fa3441d4 --- /dev/null +++ b/application/index/command/Task.php @@ -0,0 +1,53 @@ +setName('run')->setDescription('Start processing tasks for Cloudreve'); + } + + protected function Init(Output $output){ + $output->writeln("Cloudreve tasks processor started."); + } + + protected function setComplete($taskId,Output $output){ + $output->writeln("Cloudreve tasks processor started."); + } + + protected function execute(Input $input, Output $output) + { + self::Init($output); + while (1){ + $newTaskInfo = Db::name("task")->where("status","todo")->find(); + if(empty($newTaskInfo)){ + sleep(self::SLEEP_TIME); + continue; + } + Db::name("task")->where("id",$newTaskInfo["id"])->update(["status"=>"processing"]); + $output->writeln("[New task] Name:".$newTaskInfo["task_name"]." Type:".$newTaskInfo["type"]); + $task = new \app\index\model\Task(); + $task->taskModel = $newTaskInfo; + $task->input = $input; + $task->output = $output; + $task->Doit(); + if($task->status=="error"){ + $output->writeln("[Error] ".$task->errorMsg); + Db::name("task")->where("id",$newTaskInfo["id"])->update(["status"=>"error|".$task->errorMsg]); + }else{ + $output->writeln("[Complete]"); + Db::name("task")->where("id",$newTaskInfo["id"])->update(["status"=>"complete"]); + } + } + } +} +?> \ No newline at end of file diff --git a/application/index/controller/Admin.php b/application/index/controller/Admin.php index f7380f13..95fbb7d8 100644 --- a/application/index/controller/Admin.php +++ b/application/index/controller/Admin.php @@ -248,6 +248,10 @@ class Admin extends Controller{ return $this->adminObj->saveMailSetting(input('post.')); } + public function SaveAria2Setting(){ + return $this->adminObj->saveAria2Setting(input('post.')); + } + public function SendTestMail(){ return $this->adminObj->sendTestMail(input('post.')); } @@ -447,6 +451,12 @@ class Admin extends Controller{ ]); } + public function PolicyAddOnedrive(){ + return view('add_policy_onedrive', [ + 'options' => $this->siteOptions, + ]); + } + public function About(){ $verison = json_decode(file_get_contents(ROOT_PATH . "application/version.json"),true); return view('about', [ @@ -482,5 +492,43 @@ class Admin extends Controller{ 'policy' => $this->adminObj->getAvaliablePolicy(), ]); } + + public function RemoteDownload(){ + $this->adminObj->listDownloads(); + return view('download', [ + 'options' => $this->siteOptions, + 'optionsForSet' => Option::getValues(["aria2"]), + 'list' => $this->adminObj->pageData, + 'originList' => $this->adminObj->listData, + 'pageNow' => $this->adminObj->pageNow, + 'pageTotal' => $this->adminObj->pageTotal, + 'dataTotal' => $this->adminObj->dataTotal, + ]); + } + + public function CancelDownload(){ + $aria2Options = Option::getValues(["aria2"]); + $aria2 = new \app\index\model\Aria2($aria2Options); + $downloadItem = Db::name("download")->where("id",input("post.id"))->find(); + if(empty($downloadItem)){ + return json(['error'=>1,'message'=>"未找到下载记录"]); + } + if($aria2->Remove($downloadItem["pid"],"")){ + return json(['error'=>0,'message'=>"下载已取消"]); + }else{ + return json(['error'=>1,'message'=>"取消失败"]); + } + } + + public function UpdateOnedriveToken(){ + $policyId = input("get.id"); + $this->adminObj->updateOnedriveToken($policyId); + + } + + public function OneDriveCalllback(){ + $code = input("get.code"); + $this->adminObj->oneDriveCalllback($code); + } } diff --git a/application/index/controller/Callback.php b/application/index/controller/Callback.php index e934e470..10ae2fea 100644 --- a/application/index/controller/Callback.php +++ b/application/index/controller/Callback.php @@ -25,6 +25,7 @@ class Callback extends Controller{ public function Oss(){ ob_end_clean(); + error_log("sadasdasdsadsasadasasdasdasd"); header('Content-Type: application/json'); $handllerObj = new CallbackHandler(file_get_contents("php://input")); $handllerObj -> ossHandler(Request::instance()->header('Authorization'),Request::instance()->header('x-oss-pub-key-url')); diff --git a/application/index/controller/Explore.php b/application/index/controller/Explore.php index 2b4b3321..7f1bebe1 100644 --- a/application/index/controller/Explore.php +++ b/application/index/controller/Explore.php @@ -35,7 +35,7 @@ class Explore extends Controller{ $list = Db::name('shares') ->where('type',"public") ->where('origin_name',"like","%".$keyWords."%") - ->order('id DESC') + ->order('share_time DESC') ->paginate(10); $listData = $list->all(); foreach ($listData as $key => $value) { diff --git a/application/index/controller/Home.php b/application/index/controller/Home.php index 5f9f78c8..f73650c0 100644 --- a/application/index/controller/Home.php +++ b/application/index/controller/Home.php @@ -38,6 +38,16 @@ class Home extends Controller{ ]); } + public function Download(){ + $userInfo = $this->userObj->getInfo(); + $groupData = $this->userObj->getGroupData(); + return view('download', [ + 'options' => Option::getValues(['basic','group_sell']), + 'userInfo' => $userInfo, + 'groupData' => $groupData, + ]); + } + public function Album(){ $userInfo = $this->userObj->getInfo(); $list = Db::name("files")->where("upload_user",$this->userObj->uid) @@ -60,7 +70,7 @@ class Home extends Controller{ $listData = $list->all(); $pageNow = input("?get.page")?input("get.page"):1; if($pageNow>$pageCount){ - $this->error('页面不存在',404,Option::getValues(['basic','group_sell'])); + $this->error('您当前没有上传任何图片',404,Option::getValues(['basic','group_sell'])); } return view('album', [ 'options' => Option::getValues(['basic','group_sell']), diff --git a/application/index/controller/Member.php b/application/index/controller/Member.php index 76025bc5..4fbe7307 100644 --- a/application/index/controller/Member.php +++ b/application/index/controller/Member.php @@ -19,7 +19,7 @@ class Member extends Controller{ * @return [type] [description] */ public function index(){ - echo "hello"; + echo "Pong"; } /** diff --git a/application/index/controller/Profile.php b/application/index/controller/Profile.php index 4e2979db..458d78df 100644 --- a/application/index/controller/Profile.php +++ b/application/index/controller/Profile.php @@ -35,7 +35,7 @@ class Profile extends Controller{ $list = Db::name('shares') ->where('owner',$userId) ->where('type',"public") - ->order('id DESC') + ->order('share_time DESC') ->paginate(10); break; case 'hot': @@ -49,7 +49,7 @@ class Profile extends Controller{ $list = Db::name('shares') ->where('owner',$userId) ->where('type',"public") - ->order('id DESC') + ->order('share_time DESC') ->paginate(10); break; } diff --git a/application/index/controller/Queue.php b/application/index/controller/Queue.php new file mode 100644 index 00000000..84796827 --- /dev/null +++ b/application/index/controller/Queue.php @@ -0,0 +1,39 @@ +header("Authorization") !="Bearer ".$token){ + abort(403); + } + } + + public function index(){ + + } + + public function basicInfo(){ + return json_encode([ + "basePath" => ROOT_PATH, + ]); + } + + public function getList(){ + $size = input("get.num"); + $tasks = Db::name("task")->where("status","todo")->limit($size)->select(); + if(empty($tasks)){ + return "none"; + }else{ + return json_encode($tasks); + } + } + +} diff --git a/application/index/controller/RemoteDownload.php b/application/index/controller/RemoteDownload.php new file mode 100644 index 00000000..6bbe1222 --- /dev/null +++ b/application/index/controller/RemoteDownload.php @@ -0,0 +1,179 @@ +userObj = new User(cookie('user_id'),cookie('login_key')); + if(!$this->userObj->loginStatus){ + echo "Bad request"; + exit(); + } + } + + private function checkPerimission($permissionId){ + $permissionData = $this->userObj->groupData["aria2"]; + if(explode(",",$permissionData)[$permissionId] != "1"){ + return false; + } + return true; + } + + private function insertRecord($aria2,$url,$path){ + Db::name("download")->insert([ + "pid" => $aria2->pid, + "path_id" => $aria2->pathId, + "owner" => $this->userObj->uid, + "save_dir" => $path, + "status" => "ready", + "msg" => "", + "info"=>"", + "source" =>$url, + "file_index" => 0, + "is_single" => 1, + "total_size" => 0, + ]); + } + + public function addUrl(){ + $policyData = Db::name("policy")->where("id",$this->userObj->groupData["policy_name"])->find(); + if(!$this->checkPerimission(0) || ($policyData["policy_type"] != "local" && $policyData["policy_type"] != "onedrive")){ + return json(["result"=>['success'=>false,'error'=>"您当前的无用户无法执行此操作"]]); + } + $aria2Options = Option::getValues(["aria2"]); + $aria2 = new Aria2($aria2Options); + $downloadStart = $aria2->addUrl(input("post.url")); + if($aria2->reqStatus){ + $this->insertRecord($aria2,input("post.url"),input("post.path")); + return json(["result"=>['success'=>true,'error'=>null]]); + }else{ + return json(["result"=>['success'=>false,'error'=>$aria2->reqMsg]]); + } + } + + public function AddTorrent(){ + $policyData = Db::name("policy")->where("id",$this->userObj->groupData["policy_name"])->find(); + if(!$this->checkPerimission(0) || $policyData["policy_type"] != "local"){ + return json(['error'=>1,'message'=>'您当前的无用户无法执行此操作']); + } + $downloadingLength = Db::name("download") + ->where("owner",$this->userObj->uid) + ->where("status","<>","complete") + ->where("status","<>","error") + ->where("status","<>","canceled") + ->sum("total_size"); + if(!\app\index\model\FileManage::sotrageCheck($this->userObj->uid,$downloadingLength)){ + return json(["result"=>['success'=>false,'error'=>"容量不足"]]); + } + $aria2Options = Option::getValues(["aria2"]); + $aria2 = new Aria2($aria2Options); + $torrentObj = new \app\index\model\FileManage(input("post.id"),$this->userObj->uid,true); + $downloadStart = $aria2->addTorrent($torrentObj->signTmpUrl()); + if($aria2->reqStatus){ + $this->insertRecord($aria2,input("post.id"),input("post.savePath")); + return json(["result"=>['success'=>true,'error'=>null]]); + }else{ + return json(["result"=>['success'=>false,'error'=>$aria2->reqMsg]]); + } + } + + public function FlushStatus(){ + $aria2Options = Option::getValues(["aria2"]); + $aria2 = new Aria2($aria2Options); + if(!input("?post.id")){ + return json(['error'=>1,'message'=>"信息不完整"]); + } + $policyData = Db::name("policy")->where("id",$this->userObj->groupData["policy_name"])->find(); + if(!$aria2->flushStatus(input("post.id"),$this->userObj->uid,$policyData)){ + return json(['error'=>1,'message'=>$aria2->reqMsg]); + } + } + + public function FlushUser(){ + $aria2Options = Option::getValues(["aria2"]); + $aria2 = new Aria2($aria2Options); + $toBeFlushed = Db::name("download") + ->where("owner",$this->userObj->uid) + ->where("status","<>","complete") + ->where("status","<>","error") + ->where("status","<>","canceled") + //取消的 + ->select(); + foreach ($toBeFlushed as $key => $value) { + $aria2->flushStatus($value["id"],$this->userObj->uid,$this->userObj->getPolicy()); + } + } + + public function Cancel(){ + $aria2Options = Option::getValues(["aria2"]); + $aria2 = new Aria2($aria2Options); + $downloadItem = Db::name("download")->where("owner",$this->userObj->uid)->where("id",input("post.id"))->find(); + if(empty($downloadItem)){ + return json(['error'=>1,'message'=>"未找到下载记录"]); + } + if($aria2->Remove($downloadItem["pid"],"")){ + return json(['error'=>0,'message'=>"下载已取消"]); + }else{ + return json(['error'=>1,'message'=>"取消失败"]); + } + } + + public function ListDownloading(){ + $downloadItems = Db::name("download")->where("owner",$this->userObj->uid)->where("status","in",["active","ready","waiting"])->order('id desc')->select(); + foreach ($downloadItems as $key => $value) { + $connectInfo = json_decode($value["info"],true); + if(isset($connectInfo["dir"])){ + $downloadItems[$key]["fileName"] = basename($connectInfo["dir"]); + $downloadItems[$key]["completedLength"] = $connectInfo["completedLength"]; + $downloadItems[$key]["totalLength"] = $connectInfo["totalLength"]; + $downloadItems[$key]["downloadSpeed"] = $connectInfo["downloadSpeed"]; + }else{ + if(floor($value["source"])==$value["source"]){ + $downloadItems[$key]["fileName"] = Db::name("files")->where("id",$value["source"])->column("orign_name"); + }else{ + $downloadItems[$key]["fileName"] = $value["source"]; + } + $downloadItems[$key]["completedLength"] = 0; + $downloadItems[$key]["totalLength"] = 0; + $downloadItems[$key]["downloadSpeed"] = 0; + } + } + return json($downloadItems); + } + + public function ListFinished(){ + $page = input("get.page"); + $downloadItems = Db::name("download")->where("owner",$this->userObj->uid)->where("status","not in",["active","ready","waiting"])->order('id desc')->page($page.',10')->select(); + foreach ($downloadItems as $key => $value) { + $connectInfo = json_decode($value["info"],true); + if(isset($connectInfo["dir"])){ + $downloadItems[$key]["fileName"] = basename($connectInfo["dir"]); + $downloadItems[$key]["completedLength"] = $connectInfo["completedLength"]; + $downloadItems[$key]["totalLength"] = $connectInfo["totalLength"]; + $downloadItems[$key]["downloadSpeed"] = $connectInfo["downloadSpeed"]; + }else{ + if(floor($value["source"])==$value["source"]){ + $downloadItems[$key]["fileName"] = Db::name("files")->where("id",$value["source"])->column("orign_name"); + }else{ + $downloadItems[$key]["fileName"] = $value["source"]; + } + $downloadItems[$key]["completedLength"] = 0; + $downloadItems[$key]["totalLength"] = 0; + $downloadItems[$key]["downloadSpeed"] = 0; + } + } + return json($downloadItems); + } + + +} \ No newline at end of file diff --git a/application/index/controller/Share.php b/application/index/controller/Share.php index 67aa253b..61733de7 100644 --- a/application/index/controller/Share.php +++ b/application/index/controller/Share.php @@ -132,6 +132,21 @@ class Share extends Controller{ return $shareObj->listPic($shareId,$filePath); } + public function Thumb(){ + $shareId = input('get.shareKey'); + $filePath = input('get.path'); + if(input("get.isImg") != "true"){ + return ""; + } + $shareObj = new ShareHandler($shareId,false); + $Redirect = $shareObj->getThumb($this->userObj,$filePath); + if($Redirect[0]){ + $this->redirect($Redirect[1],302); + }else{ + $this->error($Redirect[1],403,$this->siteOptions); + } + } + public function Delete(){ $shareId = input('post.id'); $shareObj = new ShareHandler($shareId,false); @@ -163,7 +178,7 @@ class Share extends Controller{ } $userInfo = $this->userObj->getInfo(); $groupData = $this->userObj->getGroupData(); - $list = Db::name('shares')->where('owner',$this->userObj->uid)->paginate(10); + $list = Db::name('shares')->where('owner',$this->userObj->uid)->order('share_time DESC')->paginate(30); $listData = $list->all(); foreach ($listData as $key => $value) { if($value["source_type"]=="file"){ diff --git a/application/index/controller/WebDav.php b/application/index/controller/WebDav.php index ffdd15ea..7d8ca31d 100644 --- a/application/index/controller/WebDav.php +++ b/application/index/controller/WebDav.php @@ -28,7 +28,7 @@ class WebDav extends Controller{ $publicDir = new Directory($this->uid."/"); $server = new DAV\Server($publicDir); - $server->setBaseUri('/WebDav/Api/uid/'.$this->uid); + $server->setBaseUri('/WebDav/Api/uid/'.$this->uid."/"); $lockBackend = new DAV\Locks\Backend\File(ROOT_PATH.'public/locks'); $lockPlugin = new DAV\Locks\Plugin($lockBackend); $server->addPlugin($lockPlugin); diff --git a/application/index/model/AdminHandler.php b/application/index/model/AdminHandler.php index 0fa28a24..0fac613f 100644 --- a/application/index/model/AdminHandler.php +++ b/application/index/model/AdminHandler.php @@ -5,6 +5,7 @@ use think\Model; use think\Db; use \app\index\model\Mail; use \app\index\model\FileManage; +use \Krizalys\Onedrive\Client; class AdminHandler extends Model{ @@ -104,6 +105,10 @@ class AdminHandler extends Model{ return $this->saveOptions($options); } + public function saveAria2Setting($options){ + return $this->saveOptions($options); + } + public function saveMailTemplate($options){ return $this->saveOptions($options); } @@ -113,6 +118,7 @@ class AdminHandler extends Model{ unset($options["sizeTimes"]); $options["grade_policy"] = 0; $options["policy_list"] = $options["policy_name"]; + $options["aria2"] = $options["aria2"] ? "1,1,1" : "0,0,0"; try { Db::name("groups")->insert($options); } catch (Exception $e) { @@ -141,7 +147,7 @@ class AdminHandler extends Model{ } catch (Exception $e) { return ["error"=>1,"msg"=>$e->getMessage()]; } - return ["error"=>200,"msg"=>"设置已保存"]; + return ["error"=>200,"msg"=>"设置已保存","id"=>Db::name('policy')->getLastInsID()]; } public function editPolicy($options){ @@ -167,6 +173,7 @@ class AdminHandler extends Model{ unset($options["id"]); $options["max_storage"] = $options["max_storage"]*$options["sizeTimes"]; unset($options["sizeTimes"]); + $options["aria2"] = $options["aria2"] ? "1,1,1" : "0,0,0"; try { Db::name("groups")->where("id",$groupId)->update($options); } catch (Exception $e) { @@ -347,6 +354,46 @@ class AdminHandler extends Model{ return $userData; } + public function listDownloads(){ + $pageSize = 10; + $this->pageData = Db::name("download") + ->order("id desc") + ->paginate($pageSize); + $this->dataTotal = Db::name("download") + ->order("id desc") + ->count(); + $this->pageTotal = ceil($this->dataTotal/$pageSize); + $this->listData = $this->pageData->all(); + $userCache=[]; + $userCacheList=[]; + foreach ($this->listData as $key => $value) { + if(in_array($value["owner"], $userCacheList)){ + $this->listData[$key]["user"] = $userCache[$value["owner"]]; + }else{ + $this->listData[$key]["user"] = Db::name("users")->where("id",$value["owner"])->find(); + array_push($userCacheList,$value["owner"]); + $userCache[$value["owner"]] = $this->listData[$key]["user"]; + } + $connectInfo = json_decode($value["info"],true); + if(isset($connectInfo["dir"])){ + $this->listData[$key]["fileName"] = basename($connectInfo["dir"]); + $this->listData[$key]["completedLength"] = $connectInfo["completedLength"]; + $this->listData[$key]["totalLength"] = $connectInfo["totalLength"]; + $this->listData[$key]["downloadSpeed"] = $connectInfo["downloadSpeed"]; + }else{ + if(floor($value["source"])==$value["source"]){ + $this->listData[$key]["fileName"] = Db::name("files")->where("id",$value["source"])->column("orign_name"); + }else{ + $this->listData[$key]["fileName"] = $value["source"]; + } + $this->listData[$key]["completedLength"] = 0; + $this->listData[$key]["totalLength"] = 0; + $this->listData[$key]["downloadSpeed"] = 0; + } + } + $this->pageNow = input("?get.page")?input("get.page"):1; + } + public function listFile(){ $pageSize = !cookie('?pageSize') ? 10 : cookie('pageSize'); $orderType = empty(cookie('orderMethodFile')) ? "id DESC" : cookie('orderMethodFile'); @@ -473,7 +520,7 @@ class AdminHandler extends Model{ public function listShare(){ $pageSize = !cookie('?pageSize') ? 10 : cookie('pageSize'); - $orderType = empty(cookie('orderMethodShare')) ? "id DESC" : cookie('orderMethodShare'); + $orderType = empty(cookie('orderMethodShare')) ? "share_time DESC" : cookie('orderMethodShare'); $this->pageData = Db::name("shares") ->where(function ($query) { if(!empty(cookie('shareSearch'))){ @@ -663,6 +710,52 @@ class AdminHandler extends Model{ } return ["error"=>0,"msg"=>"设置已保存"]; } + + public function updateOnedriveToken($policyId){ + $policyData = Db::name("policy")->where("id",$policyId)->find(); + + if(empty($policyData)){ + throw new \think\Exception("Policy not found"); + } + $onedrive = new Client([ + 'client_id' => $policyData["bucketname"], + ]); + $url = $onedrive->getLogInUrl([ + 'offline_access', + 'files.readwrite.all', + ], Option::getValue("siteURL")."Admin/oneDriveCalllback"); + echo "正在跳转至Onedrive账号授权页面,如果没有跳转,请点击这里。"; + + Db::name("policy")->where("id",$policyId)->update([ + "sk" => json_encode($onedrive->getState()), + ]); + \think\Session::set('onedrive.pid',$policyId); + + } + + public function oneDriveCalllback($code){ + if(input("?get.error")){ + throw new \think\Exception(input("get.error_description")); + } + $policyId = \think\Session::get('onedrive.pid'); + $policyData = Db::name("policy")->where("id",$policyId)->find(); + $onedrive = new Client([ + 'client_id' => $policyData["bucketname"], + + // Restore the previous state while instantiating this client to proceed in + // obtaining an access token. + 'state' => json_decode($policyData["sk"]), + ]); + + // Obtain the token using the code received by the OneDrive API. + $onedrive->obtainAccessToken($policyData["ak"], $_GET['code']); + + // Persist the OneDrive client' state for next API requests. + Db::name("policy")->where("id",$policyId)->update([ + "sk" => json_encode($onedrive->getState()), + ]); + echo ""; + } } ?> \ No newline at end of file diff --git a/application/index/model/Aria2.php b/application/index/model/Aria2.php new file mode 100644 index 00000000..0f007ae6 --- /dev/null +++ b/application/index/model/Aria2.php @@ -0,0 +1,459 @@ +authToken = $options["aria2_token"]; + $this->apiUrl = rtrim($options["aria2_rpcurl"],"/")."/"; + $this->saveOptions = json_decode($options["aria2_options"],true); + $this->savePath = rtrim(rtrim($options["aria2_tmppath"],"/"),"\\").DS; + } + + /** + * 新建普通URL下载任务 + * + * @param string $url + * @return void + */ + public function addUrl($url){ + $this->pathId = uniqid(); + $reqFileds = [ + "params" => ["token:".$this->authToken, + [$url],["dir" => $this->savePath.$this->pathId], + ], + "jsonrpc" => "2.0", + "id" => $this->pathId, + "method" => "aria2.addUri" + ]; + $reqFileds["params"][2] = array_merge($reqFileds["params"][2],$this->saveOptions); + $reqFileds = json_encode($reqFileds,JSON_OBJECT_AS_ARRAY); + $respondData = $this->sendReq($reqFileds); + if(isset($respondData["result"])){ + $this->reqStatus = 1; + $this->pid = $respondData["result"]; + }else{ + $this->reqStatus = 0; + $this->reqMsg = isset($respondData["error"]["message"]) ? $respondData["error"]["message"] : $this->reqMsg; + } + } + + /** + * 新建种子下载任务 + * + * @param string $torrentUrl 种子URL + * @return void + */ + public function addTorrent($torrentUrl){ + $this->pathId = uniqid(); + $reqFileds = [ + "params" => ["token:".$this->authToken, + [$torrentUrl],["dir" => $this->savePath.$this->pathId], + ], + "jsonrpc" => "2.0", + "id" => $this->pathId, + "method" => "aria2.addUri" + ]; + $reqFileds["params"][2] = array_merge($reqFileds["params"][2],$this->saveOptions); + $reqFileds = json_encode($reqFileds,JSON_OBJECT_AS_ARRAY); + $respondData = $this->sendReq($reqFileds); + if(isset($respondData["result"])){ + $this->reqStatus = 1; + $this->pid = $respondData["result"]; + }else{ + $this->reqStatus = 0; + $this->reqMsg = isset($respondData["error"]["message"]) ? $respondData["error"]["message"] : $this->reqMsg; + } + } + + /** + * 刷新下载状态 + * + * @param int $id 任务ID + * @param int $uid 用户ID + * @param array $policy 上传策略 + * @return void + */ + public function flushStatus($id,$uid,$policy){ + $this->uid = $uid; + if(empty($policy)){ + $user = Db::name("users")->where("id",$uid)->find(); + $group = Db::name("groups")->where("id",$user["user_group"])->find(); + $policy = Db::name("policy")->where("id",$group["policy_name"])->find(); + } + $this->policy = $policy; + $downloadInfo = Db::name("download")->where("id",$id)->find(); + if(empty($downloadInfo)){ + $this->reqStatus = 0; + $this->reqMsg = "未找到下载记录"; + return false; + } + if(in_array($downloadInfo["status"], ["error","complete"])){ + $this->reqStatus = 1; + return true; + } + if($uid != $downloadInfo["owner"]){ + $this->reqStatus = 0; + $this->reqMsg = "无权操作"; + return false; + } + $reqFileds = [ + "params" => ["token:".$this->authToken,$downloadInfo["pid"]], + "jsonrpc" => "2.0", + "id" => uniqid(), + "method" => "aria2.tellStatus" + ]; + $reqFileds = json_encode($reqFileds,JSON_OBJECT_AS_ARRAY); + $respondData = $this->sendReq($reqFileds); + if(isset($respondData["result"])){ + if($this->storageCheck($respondData["result"],$downloadInfo)){ + if($downloadInfo["is_single"] && count($respondData["result"]["files"]) >1){ + $this->updateToMuiltpe($respondData["result"],$downloadInfo); + return false; + } + if(isset($respondData["result"]["followedBy"])){ + Db::name("download")->where("id",$id) + ->update([ + "pid" => $respondData["result"]["followedBy"][0], + ]); + return false; + } + Db::name("download")->where("id",$id) + ->update([ + "status" => $respondData["result"]["status"], + "last_update" => date("Y-m-d h:i:s"), + "info" => json_encode([ + "completedLength" => $respondData["result"]["files"][$downloadInfo["file_index"]]["completedLength"], + "totalLength" => $respondData["result"]["files"][$downloadInfo["file_index"]]["length"], + "dir" => $respondData["result"]["files"][$downloadInfo["file_index"]]["path"], + "downloadSpeed" => $respondData["result"]["downloadSpeed"], + "errorMessage" => isset($respondData["result"]["errorMessage"]) ? $respondData["result"]["errorMessage"] : "", + ]), + "msg" => isset($respondData["result"]["errorMessage"]) ? $respondData["result"]["errorMessage"] : "", + "total_size" => $respondData["result"]["files"][$downloadInfo["file_index"]]["length"], + ]); + switch ($respondData["result"]["status"]) { + case 'complete': + $this->setComplete($respondData["result"],$downloadInfo); + break; + case 'removed': + $this->setCanceled($respondData["result"],$downloadInfo); + break; + default: + # code... + break; + } + if(($respondData["result"]["files"][$downloadInfo["file_index"]]["completedLength"] == $respondData["result"]["files"][$downloadInfo["file_index"]]["length"] && ($respondData["result"]["files"][$downloadInfo["file_index"]]["length"] !=0 )) && $respondData["result"]["status"]=="active"){ + $this->setComplete($respondData["result"],$downloadInfo,$downloadInfo["file_index"]); + Db::name("download")->where("id",$id) + ->update([ + "status" => "complete", + ]); + } + }else{ + $this->reqStatus = 0; + $this->reqMsg = "空间容量不足"; + $this->setError($respondData["result"],$downloadInfo,"空间容量不足"); + return false; + } + }else{ + $this->reqStatus = 0; + $this->reqMsg = $respondData["error"]["message"]; + $this->setError($respondData,$downloadInfo,$respondData["error"]["message"],"error",true); + return false; + } + return true; + } + + /** + * 取消任务 + * + * @param array $quenInfo 任务信息(aria2) + * @param array $sqlData 任务信息(数据库) + * @return void + */ + private function setCanceled($quenInfo,$sqlData){ + @self::remove_directory($this->savePath.$sqlData["path_id"]); + if(!is_dir($this->savePath.$sqlData["path_id"])){ + Db::name("download")->where("id",$sqlData["id"])->update([ + "status" => "canceled", + ]); + } + } + + /** + * 移除整个目录 + * + * @param string $dir + * @return void + */ + static function remove_directory($dir){ + if($handle=opendir("$dir")){ + while(false!==($item=readdir($handle))){ + if($item!="."&&$item!=".."){ + if(is_dir("$dir/$item")){ + self::remove_directory("$dir/$item"); + }else{ + unlink("$dir/$item"); + } + } + } + closedir($handle); + rmdir($dir); + } + } + + /** + * 将单文件任务升级至多文件任务 + * + * @param array $quenInfo + * @param array $sqlData + * @return void + */ + private function updateToMuiltpe($quenInfo,$sqlData){ + foreach ($quenInfo["files"] as $key => $value) { + Db::name("download")->insert([ + "pid" => $sqlData["pid"], + "path_id" => $sqlData["path_id"], + "owner" => $sqlData["owner"], + "save_dir" => $sqlData["save_dir"], + "status" => "ready", + "msg" => "", + "info"=>"", + "source" =>$sqlData["source"], + "file_index" => $key, + "is_single" => 0, + "total_size" => 0, + ]); + } + Db::name("download")->where("id",$sqlData["id"])->delete(); + } + + /** + * 下载完成后续处理 + * + * @param array $quenInfo + * @param array $sqlData + * @param int $fileIndex + * @return void + */ + private function setComplete($quenInfo,$sqlData,$fileIndex=null){ + if($this->policy["policy_type"] != "local" && $this->policy["policy_type"] != "onedrive"){ + $this->setError($quenInfo,$sqlData,"您当前的上传策略无法使用离线下载"); + return false; + } + if($fileIndex==null){ + $this->forceRemove($sqlData["pid"]); + } + $suffixTmp = explode('.', $quenInfo["dir"]); + $fileSuffix = array_pop($suffixTmp); + $uploadHandller = new UploadHandler($this->policy["id"],$this->uid); + $allowedSuffix = explode(',', $uploadHandller->getAllowedExt(json_decode($this->policy["filetype"],true))); + $sufficCheck = !in_array($fileSuffix,$allowedSuffix); + if(empty($uploadHandller->getAllowedExt(json_decode($this->policy["filetype"],true)))){ + $sufficCheck = false; + } + if($sufficCheck){ + //取消任务 + $this->setError($quenInfo,$sqlData,"文件类型不被允许"); + return false; + } + if($this->policy['autoname']){ + $fileName = $uploadHandller->getObjName($this->policy['namerule'],"local",basename($quenInfo["files"][$sqlData["file_index"]]["path"])); + }else{ + $fileName = basename($quenInfo["files"][$sqlData["file_index"]]["path"]); + } + $generatePath = $uploadHandller->getDirName($this->policy['dirrule']); + + if($this->policy["policy_type"] == "onedrive"){ + + $savePath = ROOT_PATH . 'public/uploads/'.$generatePath.DS.$fileName; + $task = new Task(); + $task->taskName = "Upload RemoteDownload File " . $quenInfo["files"][$sqlData["file_index"]]["path"] . " to Onedrive"; + $task->taskType = $quenInfo["files"][$sqlData["file_index"]]["length"]<=4*1024*1024 ? "UploadRegularRemoteDownloadFileToOnedrive" :"UploadLargeRemoteDownloadFileToOnedrive"; + @list($width, $height, $type, $attr) = getimagesize($quenInfo["files"][$sqlData["file_index"]]["path"]); + $picInfo = empty($width)?"":$width.",".$height; + $task->taskContent = json_encode([ + "path" => ltrim(str_replace("/", ",", $sqlData["save_dir"]),","), + "fname" => basename($quenInfo["files"][$sqlData["file_index"]]["path"]), + "originPath" => $quenInfo["files"][$sqlData["file_index"]]["path"], + "objname" => $fileName, + "savePath" => $generatePath, + "fsize" => $quenInfo["files"][$sqlData["file_index"]]["length"], + "picInfo" => $picInfo, + "policyId" => $this->policy["id"], + ]); + $task->userId = $this->uid; + $task->saveTask(); + + }else{ + + $savePath = ROOT_PATH . 'public/uploads/'.$generatePath.DS.$fileName; + is_dir(dirname($savePath))? :mkdir(dirname($savePath),0777,true); + rename($quenInfo["files"][$sqlData["file_index"]]["path"],$savePath); + @unlink(dirname($quenInfo["files"][$sqlData["file_index"]]["path"])); + $jsonData = array( + "path" => ltrim(str_replace("/", ",", $sqlData["save_dir"]),","), + "fname" => basename($quenInfo["files"][$sqlData["file_index"]]["path"]), + "objname" => $generatePath.DS.$fileName, + "fsize" => $quenInfo["files"][$sqlData["file_index"]]["length"], + ); + @list($width, $height, $type, $attr) = getimagesize($savePath); + $picInfo = empty($width)?" ":$width.",".$height; + $addAction = FileManage::addFile($jsonData,$this->policy,$this->uid,$picInfo); + if(!$addAction[0]){ + //取消任务 + $this->setError($quenInfo,$sqlData,$addAction[1]); + return false; + } + + } + + FileManage::storageCheckOut($this->uid,$quenInfo["files"][$sqlData["file_index"]]["length"]); + } + + /** + * 设置任务为失败状态 + * + * @param array $quenInfo + * @param array $sqlData + * @param string $msg 失败消息 + * @param string $status 状态 + * @param boolean $delete 是否删除下载文件 + * @return void + */ + private function setError($quenInfo,$sqlData,$msg,$status="error",$delete=true){ + $this->Remove($sqlData["pid"],$sqlData); + $this->removeDownloadResult($sqlData["pid"],$sqlData); + if($delete){ + if(isset($quenInfo["files"][$sqlData["file_index"]]["path"]) && file_exists($quenInfo["files"][$sqlData["file_index"]]["path"])){ + @unlink($quenInfo["files"][$sqlData["file_index"]]["path"]); + @self::remove_directory(dirname($quenInfo["files"][$sqlData["file_index"]]["path"])); + } + } + Db::name("download")->where("id",$sqlData["id"])->update([ + "msg" => $msg, + "status" => $status, + ]); + } + + /** + * 移除任务 + * + * @param int $gid + * @param array $sqlData + * @return void + */ + public function Remove($gid,$sqlData){ + $reqFileds = [ + "params" => ["token:".$this->authToken,$gid], + "jsonrpc" => "2.0", + "id" => uniqid(), + "method" => "aria2.remove" + ]; + $reqFileds = json_encode($reqFileds,JSON_OBJECT_AS_ARRAY); + $respondData = $this->sendReq($reqFileds); + if(isset($respondData["result"])){ + return true; + } + return false; + } + + /** + * 删除下载结果 + * + * @param int $gid + * @param array $sqlData + * @return void + */ + public function removeDownloadResult($gid,$sqlData){ + $reqFileds = [ + "params" => ["token:".$this->authToken,$gid], + "jsonrpc" => "2.0", + "id" => uniqid(), + "method" => "aria2.removeDownloadResult" + ]; + $reqFileds = json_encode($reqFileds,JSON_OBJECT_AS_ARRAY); + $respondData = $this->sendReq($reqFileds); + if(isset($respondData["result"])){ + return true; + } + return false; + } + + /** + * 强制移除任务 + * + * @param int $gid + * @return void + */ + public function forceRemove($gid){ + $reqFileds = [ + "params" => ["token:".$this->authToken,$gid], + "jsonrpc" => "2.0", + "id" => uniqid(), + "method" => "aria2.forceRemove" + ]; + $reqFileds = json_encode($reqFileds,JSON_OBJECT_AS_ARRAY); + $respondData = $this->sendReq($reqFileds); + if(isset($respondData["result"])){ + return true; + } + return false; + } + + /** + * 检查容量 + * + * @param array $quenInfo + * @param array $sqlData + * @return void + */ + private function storageCheck($quenInfo,$sqlData){ + if(!FileManage::sotrageCheck($this->uid,$quenInfo["totalLength"])){ + return false; + } + if(!FileManage::sotrageCheck($this->uid,$quenInfo["completedLength"])){ + return false; + } + return true; + } + + /** + * 发送请求 + * + * @param string $data + * @return array + */ + private function sendReq($data){ + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $this->apiUrl."jsonrpc"); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $data); + curl_setopt($curl, CURLOPT_TIMEOUT, 15); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + $tmpInfo = curl_exec($curl); + if (curl_errno($curl)) { + $this->reqStatus = 0; + $this->reqMsg = "请求失败,".curl_error($curl); + } + curl_close($curl); + return json_decode($tmpInfo,true); + } + +} +?> \ No newline at end of file diff --git a/application/index/model/Avatar.php b/application/index/model/Avatar.php index d95f530f..2eee3cbb 100644 --- a/application/index/model/Avatar.php +++ b/application/index/model/Avatar.php @@ -4,7 +4,7 @@ namespace app\index\model; use think\Model; use think\Db; use \app\index\model\Option; -use \app\index\model\FileManage; +use \app\index\model\LocalAdapter; class Avatar extends Model{ @@ -90,7 +90,7 @@ class Avatar extends Model{ $filePath = ROOT_PATH . 'public/avatars/' . $this->fileName.$siezSuffix; if(file_exists($filePath)){ ob_end_clean(); - header('Content-Type: '.FileManage::getMimetype($filePath)); + header('Content-Type: '.LocalAdapter::getMimetype($filePath)); $fileObj = fopen($filePath,"r"); while(!feof($fileObj)){ echo fread($fileObj,2097152); @@ -131,7 +131,7 @@ class Avatar extends Model{ } ob_end_clean(); $filePath = ROOT_PATH . 'static/img/default.png' .$siezSuffix; - header('Content-Type: '.FileManage::getMimetype($filePath)); + header('Content-Type: '.LocalAdapter::getMimetype($filePath)); $fileObj = fopen($filePath,"r"); while(!feof($fileObj)){ echo fread($fileObj,2097152); diff --git a/application/index/model/CronHandler.php b/application/index/model/CronHandler.php index d57314d7..d33062f5 100644 --- a/application/index/model/CronHandler.php +++ b/application/index/model/CronHandler.php @@ -7,6 +7,8 @@ use \think\Session; use \app\index\model\FileManage; use \app\index\model\Option; use \app\index\model\Mail; +use \app\index\model\Aria2; +use think\Exception; class CronHandler extends Model{ @@ -40,6 +42,16 @@ class CronHandler extends Model{ $this->deleteCallbackData($value["interval_s"]); } break; + case 'flush_aria2': + if($this->checkInterval($value["interval_s"],$value["last_excute"])){ + $this->flushAria2($value["interval_s"]); + } + break; + case 'flush_onedrive_token': + if($this->checkInterval($value["interval_s"],$value["last_excute"])){ + $this->flushOnedriveToken($value["interval_s"]); + } + break; default: # code... break; @@ -69,5 +81,46 @@ class CronHandler extends Model{ $this->setComplete("delete_callback_data"); } + public function flushAria2($interval){ + echo("flushingAria2Status..."); + $aria2Options = Option::getValues(["aria2"]); + $aria2 = new Aria2($aria2Options); + $toBeFlushed = Db::name("download") + ->where("status","<>","complete") + ->where("status","<>","error") + ->where("status","<>","canceled") + ->select(); + foreach ($toBeFlushed as $key => $value) { + $aria2->flushStatus($value["id"],$value["owner"],null); + } + echo("Complete
"); + $this->setComplete("flush_aria2"); + } + + public function flushOnedriveToken($interval){ + echo("flushOnedriveToken..."); + $toBeFlushedPolicy = Db::name("policy")->where("policy_type","onedrive")->select(); + foreach ($toBeFlushedPolicy as $key => $value) { + $onedrive = new \Krizalys\Onedrive\Client([ + 'stream_back_end' => \Krizalys\Onedrive\StreamBackEnd::TEMP, + 'client_id' => $value["bucketname"], + + // Restore the previous state while instantiating this client to proceed in + // obtaining an access token. + 'state' => json_decode($value["sk"]), + ]); + try{ + $onedrive->renewAccessToken($value["ak"]); + }catch(\Exception $e){ + + } + Db::name("policy")->where("id",$value["id"])->update([ + "sk" => json_encode($onedrive->getState()), + ]); + } + echo("Complete
"); + $this->setComplete("flush_onedrive_token"); + } + } ?> \ No newline at end of file diff --git a/application/index/model/Directory.php b/application/index/model/Directory.php index 5880b38e..8c6e27dd 100644 --- a/application/index/model/Directory.php +++ b/application/index/model/Directory.php @@ -30,6 +30,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota{ } function createFile($name, $data = NULL){ + $name = str_replace(" ","",$name); $userData = Db::name("users")->where("id",$this->uid)->find(); $groupData = Db::name("groups")->where("id",$userData["user_group"])->find(); $policyData = Db::name("policy")->where("id",$groupData["policy_name"])->find(); @@ -47,7 +48,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota{ } $fileSize = fstat($data)["size"]; if(empty($fileSize)){ - $fileSize = 0; + $fileSize = -1; } if($fileSize>$policyData["max_size"]){ throw new DAV\Exception\InsufficientStorage('File is to large'); @@ -66,6 +67,9 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota{ mkdir($savePath,0777,true); } file_put_contents($savePath."/".$fileName, $data); + if($fileSize<=0){ + $fileSize = filesize($savePath."/".$fileName); + } $jsonData = array( "path" => str_replace("/",",",ltrim($this->myPath,"/")), "fname" => $name, @@ -134,6 +138,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota{ } function getChild($name) { + $name = str_replace(" ","",$name); if(!$this->childExists($name)){ throw new DAV\Exception\NotFound('File with name ' . $name . ' could not be located'); } @@ -147,6 +152,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota{ } function childExists($name) { + $name = str_replace(" ","",$name); $fileObj = new Objects($this->uid.rtrim($this->myPath,"/") . '/' . $name); if($this->findDir(rtrim($this->myPath,"/") . '/' . $name) || $fileObj->isExist){ return true; diff --git a/application/index/model/FileManage.php b/application/index/model/FileManage.php index 19cb669e..41639d6e 100644 --- a/application/index/model/FileManage.php +++ b/application/index/model/FileManage.php @@ -1,17 +1,10 @@ filePath = $path; - $fileInfo = $this->getFileName($path); - $fileName = $fileInfo[0]; - $path = $fileInfo[1]; - $fileRecord = Db::name('files')->where('upload_user',$uid)->where('orign_name',$fileName)->where('dir',$path)->find(); + private $adapter; + + /** + * construct function + * + * @param string $path 文件路径/文件ID + * @param int $uid 用户ID + * @param boolean $byId 是否根据文件ID寻找文件 + */ + public function __construct($path,$uid,$byId=false){ + if($byId){ + $fileRecord = Db::name('files')->where('id',$path)->find(); + $this->filePath = rtrim($fileRecord["dir"],"/")."/".$fileRecord["orign_name"]; + }else{ + $this->filePath = $path; + $fileInfo = $this->getFileName($path); + $fileName = $fileInfo[0]; + $path = $fileInfo[1]; + $fileRecord = Db::name('files')->where('upload_user',$uid)->where('orign_name',$fileName)->where('dir',$path)->find(); + } if (empty($fileRecord)){ die('{ "result": { "success": false, "error": "文件不存在" } }'); } @@ -35,8 +42,39 @@ class FileManage extends Model{ $this->userID = $uid; $this->userData = Db::name('users')->where('id',$uid)->find(); $this->policyData = Db::name('policy')->where('id',$this->fileData["policy_id"])->find(); + switch ($this->policyData["policy_type"]) { + case 'local': + $this->adapter = new \app\index\model\LocalAdapter($this->fileData,$this->policyData,$this->userData); + break; + case 'qiniu': + $this->adapter = new \app\index\model\QiniuAdapter($this->fileData,$this->policyData,$this->userData); + break; + case 'oss': + $this->adapter = new \app\index\model\OssAdapter($this->fileData,$this->policyData,$this->userData); + break; + case 'upyun': + $this->adapter = new \app\index\model\UpyunAdapter($this->fileData,$this->policyData,$this->userData); + break; + case 's3': + $this->adapter = new \app\index\model\S3Adapter($this->fileData,$this->policyData,$this->userData); + break; + case 'remote': + $this->adapter = new \app\index\model\RemoteAdapter($this->fileData,$this->policyData,$this->userData); + break; + case 'onedrive': + $this->adapter = new \app\index\model\OnedriveAdapter($this->fileData,$this->policyData,$this->userData); + break; + default: + # code... + break; + } } + /** + * 获取文件外链地址 + * + * @return void + */ public function Source(){ if(!$this->policyData["origin_link"]){ die('{"url":"此文件不支持获取源文件URL"}'); @@ -45,35 +83,22 @@ class FileManage extends Model{ } } + /** + * 获取可编辑文件内容 + * + * @return void + */ public function getContent(){ $sizeLimit=(int)Option::getValue("maxEditSize"); if($this->fileData["size"]>$sizeLimit){ die('{ "result": { "success": false, "error": "您当前用户组最大可编辑'.$sizeLimit.'字节的文件"} }'); }else{ - switch ($this->policyData["policy_type"]) { - case 'local': - $filePath = ROOT_PATH . 'public/uploads/' . $this->fileData["pre_name"]; - $fileContent = $this->getLocalFileContent($filePath); - break; - case 'qiniu': - $fileContent = $this->getQiniuFileContent(); - break; - case 'oss': - $fileContent = $this->getOssFileContent(); - break; - case 'upyun': - $fileContent = $this->getUpyunFileContent(); - break; - case 's3': - $fileContent = $this->getS3FileContent(); - break; - case 'remote': - $fileContent = $this->getRemoteFileContent(); - break; - default: - # code... - break; + try{ + $fileContent = $this->adapter->getFileContent(); + }catch(\Exception $e){ + die('{ "result": { "success": false, "error": "'.$e->getMessage().'"} }'); } + $fileContent = $this->adapter->getFileContent(); $result["result"] = $fileContent; if(empty(json_encode($result))){ $result["result"] = iconv('gb2312','utf-8',$fileContent); @@ -82,119 +107,31 @@ class FileManage extends Model{ } } - public function getLocalFileContent($path){ - $fileObj = fopen($path,"r"); - $fileContent = fread($fileObj,filesize($path)+1); - return $fileContent; - } - - public function getQiniuFileContent(){ - return file_get_contents($this->qiniuPreview()[1]); - } - - public function getOssFileContent(){ - return file_get_contents($this->ossPreview()[1]); - } - - public function getUpyunFileContent(){ - return file_get_contents($this->upyunPreview()[1]); - } - - public function getS3FileContent(){ - return file_get_contents($this->s3Preview()[1]); - } - - public function getRemoteFileContent(){ - return file_get_contents($this->remotePreview()[1]); - } - + /** + * 保存可编辑文件 + * + * @param string $content 要保存的文件内容 + * @return void + */ public function saveContent($content){ $contentSize = strlen($content); $originSize = $this->fileData["size"]; if(!FileManage::sotrageCheck($this->userID,$contentSize)){ die('{ "result": { "success": false, "error": "空间容量不足" } }'); } - switch ($this->policyData["policy_type"]) { - case 'local': - $filePath = ROOT_PATH . 'public/uploads/' . $this->fileData["pre_name"]; - file_put_contents($filePath, ""); - file_put_contents($filePath, $content); - break; - case 'qiniu': - $this->saveQiniuContent($content); - break; - case 'oss': - $this->saveOssContent($content); - break; - case 'upyun': - $this->saveUpyunContent($content); - break; - case 's3': - $this->saveS3Content($content); - break; - case 'remote': - $this->saveRemoteContent($content); - break; - default: - # code... - break; - } + $this->adapter->saveContent($content); FileManage::storageGiveBack($this->userID,$originSize); FileManage::storageCheckOut($this->userID,$contentSize); Db::name('files')->where('id', $this->fileData["id"])->update(['size' => $contentSize]); echo ('{ "result": { "success": true} }'); } - public function saveQiniuContent($content){ - $auth = new Auth($this->policyData["ak"], $this->policyData["sk"]); - $expires = 3600; - $keyToOverwrite = $this->fileData["pre_name"]; - $upToken = $auth->uploadToken($this->policyData["bucketname"], $keyToOverwrite, $expires, null, true); - $uploadMgr = new \Qiniu\Storage\UploadManager(); - list($ret, $err) = $uploadMgr->put($upToken, $keyToOverwrite, $content); - if ($err !== null) { - die('{ "result": { "success": false, "error": "编辑失败" } }'); - } else { - return true; - } - } - - public function saveOssContent($content){ - $accessKeyId = $this->policyData["ak"]; - $accessKeySecret = $this->policyData["sk"]; - $endpoint = "http".ltrim(ltrim($this->policyData["server"],"https"),"http"); - try { - $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); - } catch (OssException $e) { - die('{ "result": { "success": false, "error": "鉴权失败" } }'); - } - try{ - $ossClient->putObject($this->policyData["bucketname"], $this->fileData["pre_name"], $content); - } catch(OssException $e) { - die('{ "result": { "success": false, "error": "编辑失败" } }'); - } - } - - public function saveUpyunContent($content){ - $bucketConfig = new Config($this->policyData["bucketname"], $this->policyData["op_name"], $this->policyData["op_pwd"]); - $client = new Upyun($bucketConfig); - if(empty($content)){ - $content = " "; - } - $res=$client->write($this->fileData["pre_name"],$content); - } - - public function saveS3Content($content){ - $s3 = new \S3\S3($this->policyData["ak"], $this->policyData["sk"],false,$this->policyData["op_pwd"]); - $s3->setSignatureVersion('v4'); - $s3->putObjectString($content, $this->policyData["bucketname"], $this->fileData["pre_name"]); - } - - public function saveRemoteContent($content){ - $remote = new Remote($this->policyData); - $remote->updateContent($this->fileData["pre_name"],$content); - } - + /** + * 文件名合法性初步检查 + * + * @param string $value 文件名 + * @return bool 检查结果 + */ static function fileNameValidate($value){ $validate = new Validate([ 'val' => 'require|max:250', @@ -209,6 +146,15 @@ class FileManage extends Model{ return true; } + /** + * 处理重命名 + * + * @param string $fname 原文件路径 + * @param string $new 新文件路径 + * @param int $uid 用户ID + * @param boolean $notEcho 过程中是否不直接输出结果 + * @return mixed + */ static function RenameHandler($fname,$new,$uid,$notEcho = false){ $folderTmp = $new; $originFolder = $fname; @@ -254,6 +200,15 @@ class FileManage extends Model{ echo ('{ "result": { "success": true} }'); } + /** + * 处理目录重命名 + * + * @param string $fname 原文件路径 + * @param string $new 新文件路径 + * @param int $uid 用户ID + * @param boolean $notEcho 过程中是否不直接输出结果 + * @return void + */ static function folderRename($fname,$new,$uid,$notEcho = false){ $newTmp = $new; $nerFolderTmp = explode("/",$new); @@ -315,6 +270,12 @@ class FileManage extends Model{ echo ('{ "result": { "success": true} }'); } + /** + * 根据文件路径获取文件名和父目录路径 + * + * @param string 文件路径 + * @return array + */ static function getFileName($path){ $pathSplit = explode("/",$path); $fileName = end($pathSplit); @@ -331,91 +292,42 @@ class FileManage extends Model{ return [$fileName,$path]; } + /** + * 处理文件预览 + * + * @param boolean $isAdmin 是否为管理员预览 + * @return array 重定向信息 + */ public function PreviewHandler($isAdmin=false){ - switch ($this->policyData["policy_type"]) { - case 'qiniu': - $Redirect = $this->qiniuPreview(); - return $Redirect; - break; - case 'local': - $Redirect = $this->localPreview($isAdmin); - return $Redirect; - break; - case 'oss': - $Redirect = $this->ossPreview(); - return $Redirect; - break; - case 'upyun': - $Redirect = $this->upyunPreview(); - return $Redirect; - break; - case 's3': - $Redirect = $this->s3Preview(); - return $Redirect; - break; - case 'remote': - $Redirect = $this->remotePreview(); - return $Redirect; - break; - default: - # code... - break; - } + return $this->adapter->Preview($isAdmin); } + /** + * 获取图像缩略图 + * + * @return array 重定向信息 + */ public function getThumb(){ - switch ($this->policyData["policy_type"]) { - case 'qiniu': - $Redirect = $this->getQiniuThumb(); - return $Redirect; - case 'local': - $Redirect = $this->getLocalThumb(); - return $Redirect; - break; - case 'oss': - $Redirect = $this->getOssThumb(); - return $Redirect; - break; - case 'upyun': - $Redirect = $this->getUpyunThumb(); - return $Redirect; - break; - case 'remote': - $remote = new Remote($this->policyData); - return [1,$remote->thumb($this->fileData["pre_name"],explode(",",$this->fileData["pic_info"]))]; - break; - default: - # code... - break; - } + return $this->adapter->getThumb(); } + /** + * 处理文件下载 + * + * @param boolean $isAdmin 是否为管理员请求 + * @return array 文件下载URL + */ public function Download($isAdmin=false){ - switch ($this->policyData["policy_type"]) { - case 'qiniu': - return $DownloadHandler = $this->qiniuDownload(); - break; - case 'local': - return $DownloadHandler = $this->localDownload($isAdmin); - break; - case 'oss': - return $DownloadHandler = $this->ossDownload(); - break; - case 'upyun': - return $DownloadHandler = $this->upyunDownload(); - break; - case 's3': - return $DownloadHandler = $this->s3Download(); - break; - case 'remote': - return $DownloadHandler = $this->remoteDownload(); - break; - default: - # code... - break; - } + return $this->adapter->Download($isAdmin); } + /** + * 处理目录删除 + * + * @param string $path 目录路径 + * @param int $uid 用户ID + * @return void + */ static function DirDeleteHandler($path,$uid){ global $toBeDeleteDir; global $toBeDeleteFile; @@ -436,6 +348,13 @@ class FileManage extends Model{ } } + /** + * 列出待删除文件或目录 + * + * @param string $path 对象路径 + * @param int $uid 用户ID + * @return void + */ static function listToBeDelete($path,$uid){ global $toBeDeleteDir; global $toBeDeleteFile; @@ -456,6 +375,13 @@ class FileManage extends Model{ } } + /** + * 删除目录 + * + * @param string $path 目录路径 + * @param int $uid 用户ID + * @return void + */ static function deleteDir($path,$uid){ Db::name('folders') ->where("owner",$uid) @@ -464,6 +390,13 @@ class FileManage extends Model{ ])->delete(); } + /** + * 处理删除请求 + * + * @param string $path 路径 + * @param int $uid 用户ID + * @return array + */ static function DeleteHandler($path,$uid){ if(empty($path)){ return ["result"=>["success"=>true,"error"=>null]]; @@ -490,22 +423,40 @@ class FileManage extends Model{ } foreach ($fileListTemp as $key => $value) { if(in_array($key,$uniquePolicy["qiniuList"])){ - self::qiniuDelete($value,$uniquePolicy["qiniuPolicyData"][$key][0]); + QiniuAdapter::DeleteFile($value,$uniquePolicy["qiniuPolicyData"][$key][0]); + self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]); }else if(in_array($key,$uniquePolicy["localList"])){ - self::localDelete($value,$uniquePolicy["localPolicyData"][$key][0]); + LocalAdapter::DeleteFile($value,$uniquePolicy["localPolicyData"][$key][0]); + self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]); }else if(in_array($key,$uniquePolicy["ossList"])){ - self::ossDelete($value,$uniquePolicy["ossPolicyData"][$key][0]); + OssAdapter::DeleteFile($value,$uniquePolicy["ossPolicyData"][$key][0]); + self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]); }else if(in_array($key,$uniquePolicy["upyunList"])){ - self::upyunDelete($value,$uniquePolicy["upyunPolicyData"][$key][0]); + UpyunAdapter::DeleteFile($value,$uniquePolicy["upyunPolicyData"][$key][0]); + self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]); }else if(in_array($key,$uniquePolicy["s3List"])){ - self::s3Delete($value,$uniquePolicy["s3PolicyData"][$key][0]); + S3Adapter::DeleteFile($value,$uniquePolicy["s3PolicyData"][$key][0]); + self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]); }else if(in_array($key,$uniquePolicy["remoteList"])){ - self::remoteDelete($value,$uniquePolicy["remotePolicyData"][$key][0]); + RemoteAdapter::DeleteFile($value,$uniquePolicy["remotePolicyData"][$key][0]); + self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]); + }else if(in_array($key,$uniquePolicy["onedriveList"])){ + OnedriveAdapter::DeleteFile($value,$uniquePolicy["onedrivePolicyData"][$key][0]); + self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]); } } return ["result"=>["success"=>true,"error"=>null]]; } + /** + * 处理移动 + * + * @param array $file 文件路径列表 + * @param array $dir 目录路径列表 + * @param string $new 新路径 + * @param int $uid 用户ID + * @return void + */ static function MoveHandler($file,$dir,$new,$uid){ if(in_array($new,$dir)){ die('{ "result": { "success": false, "error": "不能移动目录到自身" } }'); @@ -552,68 +503,17 @@ class FileManage extends Model{ echo ('{ "result": { "success": true} }'); } + /** + * ToDo 移动文件 + * + * @param array $file + * @param string $path + * @return void + */ static function moveFile($file,$path){ } - static function localDelete($fileList,$policyData){ - $fileListTemp = array_column($fileList, 'pre_name'); - foreach ($fileListTemp as $key => $value) { - @unlink(ROOT_PATH . 'public/uploads/'.$value); - if(file_exists(ROOT_PATH . 'public/thumb/'.$value."_thumb")){ - @unlink(ROOT_PATH . 'public/thumb/'.$value."_thumb"); - } - } - self::deleteFileRecord(array_column($fileList, 'id'),array_sum(array_column($fileList, 'size')),$fileList[0]["upload_user"]); - } - - static function qiniuDelete($fileList,$policyData){ - $auth = new Auth($policyData["ak"], $policyData["sk"]); - $config = new \Qiniu\Config(); - $bucketManager = new \Qiniu\Storage\BucketManager($auth); - $fileListTemp = array_column($fileList, 'pre_name'); - $ops = $bucketManager->buildBatchDelete($policyData["bucketname"], $fileListTemp); - list($ret, $err) = $bucketManager->batch($ops); - self::deleteFileRecord(array_column($fileList, 'id'),array_sum(array_column($fileList, 'size')),$fileList[0]["upload_user"]); - } - - static function ossDelete($fileList,$policyData){ - $accessKeyId = $policyData["ak"]; - $accessKeySecret = $policyData["sk"]; - $endpoint = "http".ltrim(ltrim($policyData["server"],"https"),"http"); - try { - $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); - } catch (OssException $e) { - return false; - } - try{ - $ossClient->deleteObjects($policyData["bucketname"], array_column($fileList, 'pre_name')); - } catch(OssException $e) { - return false; - } - self::deleteFileRecord(array_column($fileList, 'id'),array_sum(array_column($fileList, 'size')),$fileList[0]["upload_user"]); - } - - static function upyunDelete($fileList,$policyData){ - foreach (array_column($fileList, 'pre_name') as $key => $value) { - self::deleteUpyunFile($value,$policyData); - } - self::deleteFileRecord(array_column($fileList, 'id'),array_sum(array_column($fileList, 'size')),$fileList[0]["upload_user"]); - } - - static function s3Delete($fileList,$policyData){ - foreach (array_column($fileList, 'pre_name') as $key => $value) { - self::deleteS3File($value,$policyData); - } - self::deleteFileRecord(array_column($fileList, 'id'),array_sum(array_column($fileList, 'size')),$fileList[0]["upload_user"]); - } - - static function remoteDelete($fileList,$policyData){ - $remoteObj = new Remote($policyData); - $remoteObj->remove(array_column($fileList, 'pre_name')); - self::deleteFileRecord(array_column($fileList, 'id'),array_sum(array_column($fileList, 'size')),$fileList[0]["upload_user"]); - } - static function deleteFileRecord($id,$size,$uid){ Db::name('files')->where([ 'id' => ["in",$id], @@ -628,371 +528,6 @@ class FileManage extends Model{ ])->setDec('used_storage', $size); } - static function getThumbSize($width,$height){ - $rate = $width/$height; - $maxWidth = 90; - $maxHeight = 39; - $changeWidth = 39*$rate; - $changeHeight = 90/$rate; - if($changeWidth>=$maxWidth){ - return [(int)$changeHeight,90]; - } - return [39,(int)$changeWidth]; - } - - static function outputThumb($path){ - ob_end_clean(); - if(!input("get.cache")=="no"){ - header("Cache-Control: max-age=10800"); - } - header('Content-Type: '.self::getMimetype($path)); - $fileObj = fopen($path,"r"); - echo fread($fileObj,filesize($path)); - fclose($file); - } - - public function getLocalThumb(){ - $picInfo = explode(",",$this->fileData["pic_info"]); - $picInfo = self::getThumbSize($picInfo[0],$picInfo[1]); - if(file_exists(ROOT_PATH . "public/thumb/".$this->fileData["pre_name"]."_thumb")){ - self::outputThumb(ROOT_PATH . "public/thumb/".$this->fileData["pre_name"]."_thumb"); - return [0,0]; - } - $thumbImg = new Thumb(ROOT_PATH . "public/uploads/".$this->fileData["pre_name"]); - $thumbImg->thumb($picInfo[1], $picInfo[0]); - if(!is_dir(dirname(ROOT_PATH . "public/thumb/".$this->fileData["pre_name"]))){ - mkdir(dirname(ROOT_PATH . "public/thumb/".$this->fileData["pre_name"]),0777,true); - } - $thumbImg->out(ROOT_PATH . "public/thumb/".$this->fileData["pre_name"]."_thumb"); - self::outputThumb(ROOT_PATH . "public/thumb/".$this->fileData["pre_name"]."_thumb"); - return [0,0]; - } - - public function getOssThumb(){ - if(!$this->policyData['bucket_private']){ - $fileUrl = $this->policyData["url"].$this->fileData["pre_name"]."?x-oss-process=image/resize,m_lfit,h_39,w_90"; - return[true,$fileUrl]; - }else{ - $accessKeyId = $this->policyData["ak"]; - $accessKeySecret = $this->policyData["sk"]; - $endpoint = $this->policyData["url"]; - try { - $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); - } catch (OssException $e) { - return [false,0]; - } - $baseUrl = $this->policyData["url"].$this->fileData["pre_name"]; - try{ - $signedUrl = $ossClient->signUrl($this->policyData["bucketname"], $this->fileData["pre_name"], Option::getValue("timeout"),'GET', array("x-oss-process" => 'image/resize,m_lfit,h_39,w_90')); - } catch(OssException $e) { - return [false,0]; - } - return[true,$signedUrl]; - } - } - - public function getQiniuThumb(){ - return $this->qiniuPreview("?imageView2/2/w/90/h/39"); - } - - private function getUpyunThumb(){ - $picInfo = explode(",",$this->fileData["pic_info"]); - $thumbSize = self::getThumbSize($picInfo[0],$picInfo[1]); - $baseUrl =$this->policyData["url"].$this->fileData["pre_name"]."!/fwfh/90x39"; - return [1,$this->upyunPreview($baseUrl,$this->fileData["pre_name"]."!/fwfh/90x39")[1]]; - } - - public function s3Preview(){ - $timeOut = Option::getValue("timeout"); - return [1,\S3\S3::aws_s3_link($this->policyData["ak"], $this->policyData["sk"],$this->policyData["bucketname"],"/".$this->fileData["pre_name"],3600,$this->policyData["op_name"])]; - } - - public function remotePreview(){ - $remote = new Remote($this->policyData); - return [1,$remote->preview($this->fileData["pre_name"])]; - } - - public function upyunPreview($base=null,$name=null){ - if(!$this->policyData['bucket_private']){ - $fileUrl = $this->policyData["url"].$this->fileData["pre_name"]."?auth=0"; - if(!empty($base)){ - $fileUrl = $base; - } - return[true,$fileUrl]; - }else{ - $baseUrl = $this->policyData["url"].$this->fileData["pre_name"]; - if(!empty($base)){ - $baseUrl = $base; - } - $etime = time() + Option::getValue("timeout"); - $key = $this->policyData["sk"]; - $path = "/".$this->fileData["pre_name"]; - if(!empty($name)){ - $path = "/".$name; - } - $sign = substr(md5($key.'&'.$etime.'&'.$path), 12, 8).$etime; - $signedUrl = $baseUrl."?_upt=".$sign; - return[true,$signedUrl]; - } - } - - public function qiniuPreview($thumb=null){ - if(!$this->policyData['bucket_private']){ - $fileUrl = $this->policyData["url"].$this->fileData["pre_name"].$thumb; - return[true,$fileUrl]; - }else{ - $auth = new Auth($this->policyData["ak"], $this->policyData["sk"]); - $baseUrl = $this->policyData["url"].$this->fileData["pre_name"].$thumb; - $signedUrl = $auth->privateDownloadUrl($baseUrl); - return[true,$signedUrl]; - } - } - - public function ossPreview(){ - if(!$this->policyData['bucket_private']){ - $fileUrl = $this->policyData["url"].$this->fileData["pre_name"]; - return[true,$fileUrl]; - }else{ - $accessKeyId = $this->policyData["ak"]; - $accessKeySecret = $this->policyData["sk"]; - $endpoint = $this->policyData["url"]; - try { - $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); - } catch (OssException $e) { - return [false,0]; - } - $baseUrl = $this->policyData["url"].$this->fileData["pre_name"]; - try{ - $signedUrl = $ossClient->signUrl($this->policyData["bucketname"], $this->fileData["pre_name"], Option::getValue("timeout")); - } catch(OssException $e) { - return [false,0]; - } - return[true,$signedUrl]; - } - } - - public function qiniuDownload(){ - if(!$this->policyData['bucket_private']){ - $fileUrl = $this->policyData["url"].$this->fileData["pre_name"]."?attname=".urlencode($this->fileData["orign_name"]); - return[true,$fileUrl]; - }else{ - $auth = new Auth($this->policyData["ak"], $this->policyData["sk"]); - $baseUrl = $this->policyData["url"].$this->fileData["pre_name"]."?attname=".urlencode($this->fileData["orign_name"]); - $signedUrl = $auth->privateDownloadUrl($baseUrl); - return[true,$signedUrl]; - } - } - - public function upyunDownload(){ - return [true,$this->upyunPreview()[1]."&_upd=".urlencode($this->fileData["orign_name"])]; - } - - public function s3Download(){ - $timeOut = Option::getValue("timeout"); - return [1,\S3\S3::aws_s3_link($this->policyData["ak"], $this->policyData["sk"],$this->policyData["bucketname"],"/".$this->fileData["pre_name"],3600,$this->policyData["op_name"],array(),false)]; - } - - private function remoteDownload(){ - $remote = new Remote($this->policyData); - return [1,$remote->download($this->fileData["pre_name"],$this->fileData["orign_name"])]; - } - - public function ossDownload(){ - if(!$this->policyData['bucket_private']){ - $fileUrl = $this->policyData["url"].$this->fileData["pre_name"]."?response-content-disposition=".urlencode('attachment; filename='.$this->fileData["orign_name"]); - return[true,$fileUrl]; - }else{ - $accessKeyId = $this->policyData["ak"]; - $accessKeySecret = $this->policyData["sk"]; - $endpoint = $this->policyData["url"]; - try { - $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); - } catch (OssException $e) { - return [false,0]; - } - $baseUrl = $this->policyData["url"].$this->fileData["pre_name"]; - try{ - $signedUrl = $ossClient->signUrl($this->policyData["bucketname"], $this->fileData["pre_name"], Option::getValue("timeout"),'GET', array("response-content-disposition" => 'attachment; filename='.$this->fileData["orign_name"])); - } catch(OssException $e) { - return [false,0]; - } - return[true,$signedUrl]; - } - } - - public function localPreview($isAdmin=false){ - $speedLimit = Db::name('groups')->where('id',$this->userData["user_group"])->find(); - $rangeTransfer = $speedLimit["range_transfer"]; - $speedLimit = $speedLimit["speed"]; - $sendFileOptions = Option::getValues(["download"]); - if($sendFileOptions["sendfile"] == "1" && !empty($sendFileOptions)){ - $this->sendFile($speedLimit,$rangeTransfer,false,$sendFileOptions["header"]); - }else{ - if($isAdmin){ - $speedLimit=""; - } - if($speedLimit == "0"){ - exit(); - }else if(empty($speedLimit)){ - header("Cache-Control: max-age=10800"); - $this->outputWithoutLimit(false,$rangeTransfer); - exit(); - }else if((int)$speedLimit > 0){ - header("Cache-Control: max-age=10800"); - $this->outputWithLimit($speedLimit); - } - } - } - - public function localDownload($isAdmin=false){ - $speedLimit = Db::name('groups')->where('id',$this->userData["user_group"])->find(); - $rangeTransfer = $speedLimit["range_transfer"]; - $speedLimit = $speedLimit["speed"]; - $sendFileOptions = Option::getValues(["download"]); - if($sendFileOptions["sendfile"] == "1"){ - $this->sendFile($speedLimit,$rangeTransfer,true,$sendFileOptions["header"]); - }else{ - if($isAdmin){ - $speedLimit = ""; - } - if($speedLimit == "0"){ - exit(); - }else if(empty($speedLimit)){ - $this->outputWithoutLimit(true,$rangeTransfer); - exit(); - }else if((int)$speedLimit > 0){ - $this->outputWithLimit($speedLimit,true); - } - } - } - - private function sendFile($speed,$range,$download=false,$header="X-Sendfile"){ - $filePath = ROOT_PATH . 'public/uploads/' . $this->fileData["pre_name"]; - $realPath = ROOT_PATH . 'public/uploads/' . $this->fileData["pre_name"]; - if($header == "X-Accel-Redirect"){ - $filePath = '/public/uploads/' . $this->fileData["pre_name"]; - } - if($download){ - header('Content-Disposition: attachment; filename="' . str_replace(",","",$this->fileData["orign_name"]) . '"'); - header("Content-type: application/octet-stream"); - header('Content-Length: ' .(string)(filesize($realPath)) ); - $filePath = str_replace("\\","/",$filePath); - if($header == "X-Accel-Redirect"){ - ob_flush(); - flush(); - echo "s"; - } - header($header.": ".str_replace('%2F', '/', rawurlencode($filePath))); - }else{ - $filePath = str_replace("\\","/",$filePath); - header('Content-Type: '.self::getMimetype($realPath)); - if($header == "X-Accel-Redirect"){ - ob_flush(); - flush(); - echo "s"; - } - header($header.": ".str_replace('%2F', '/', rawurlencode($filePath))); - ob_flush(); - flush(); - } - } - - public function outputWithoutLimit($download = false,$reload = false){ - ignore_user_abort(false); - $filePath = ROOT_PATH . 'public/uploads/' . $this->fileData["pre_name"]; - set_time_limit(0); - session_write_close(); - $file_size = filesize($filePath); - $ranges = $this->getRange($file_size); - if($reload == 1 && $ranges!=null){ - header('HTTP/1.1 206 Partial Content'); - header('Accept-Ranges:bytes'); - header(sprintf('content-length:%u',$ranges['end']-$ranges['start'])); - header(sprintf('content-range:bytes %s-%s/%s', $ranges['start'], $ranges['end']-1, $file_size)); - } - if($download){ - header('Cache-control: private'); - header('Content-Type: application/octet-stream'); - header('Content-Length: '.filesize($filePath)); - header('Content-Disposition: filename='.str_replace(",","",$this->fileData["orign_name"])); - ob_flush(); - flush(); - } - if(file_exists($filePath)){ - if(!$download){ - header('Content-Type: '.self::getMimetype($filePath)); - ob_flush(); - flush(); - } - $fileObj = fopen($filePath,"rb"); - if($reload == 1){ - fseek($fileObj, sprintf('%u', $ranges['start'])); - } - while(!feof($fileObj)){ - echo fread($fileObj,10240); - ob_flush(); - flush(); - } - fclose($fileObj); - } - } - - public function outputWithLimit($speed,$download = false){ - ignore_user_abort(false); - $filePath = ROOT_PATH . 'public/uploads/' . $this->fileData["pre_name"]; - set_time_limit(0); - session_write_close(); - if($download){ - header('Cache-control: private'); - header('Content-Type: application/octet-stream'); - header('Content-Length: '.filesize($filePath)); - header('Content-Disposition: filename='.$this->fileData["orign_name"]); - ob_flush(); - flush(); - }else{ - header('Content-Type: '.self::getMimetype($filePath)); - ob_flush(); - flush(); - } - if(file_exists($filePath)){ - $fileObj = fopen($filePath,"r"); - while (!feof($fileObj)){ - echo fread($fileObj,round($speed*1024)); - ob_flush(); - flush(); - sleep(1); - } - fclose($fileObj); - } - } - - static function getMimetype($path){ - $finfoObj = finfo_open(FILEINFO_MIME); - $mimetype = finfo_file($finfoObj, $path); - finfo_close($finfoObj); - return $mimetype; - } - - private function getRange($file_size){ - if(isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE'])){ - $range = $_SERVER['HTTP_RANGE']; - $range = preg_replace('/[\s|,].*/', '', $range); - $range = explode('-', substr($range, 6)); - if(count($range)<2){ - $range[1] = $file_size; - } - $range = array_combine(array('start','end'), $range); - if(empty($range['start'])){ - $range['start'] = 0; - } - if(empty($range['end'])){ - $range['end'] = $file_size; - } - return $range; - } - return null; - } - /** * [List description] * @param [type] $path [description] @@ -1100,7 +635,7 @@ class FileManage extends Model{ ->where('uid',$uid) ->where('dlay_time',">",time()) ->sum('pack_size'); - return (int)$addOnStorage+(int)$basicStronge["max_storage"]; + return $addOnStorage+$basicStronge["max_storage"]; } static function getUsedStorage($uid){ @@ -1160,16 +695,16 @@ class FileManage extends Model{ static function deleteFile($fname,$policy){ switch ($policy['policy_type']) { case 'qiniu': - return self::deleteQiniuFile($fname,$policy); + return QiniuAdapter::deleteSingle($fname,$policy); break; case 'oss': - return self::deleteOssFile($fname,$policy); + return OssAdapter::deleteOssFile($fname,$policy); break; case 'upyun': - return self::deleteUpyunFile($fname,$policy); + return UpyunAdapter::deleteUpyunFile($fname,$policy); break; case 's3': - return self::deleteS3File($fname,$policy); + return S3Adapter::deleteS3File($fname,$policy); break; default: # code... @@ -1177,47 +712,6 @@ class FileManage extends Model{ } } - static function deleteQiniuFile($fname,$policy){ - $auth = new Auth($policy["ak"], $policy["sk"]); - $config = new \Qiniu\Config(); - $bucketManager = new \Qiniu\Storage\BucketManager($auth); - $err = $bucketManager->delete($policy["bucketname"], $fname); - if ($err) { - return false; - }else{ - return true; - } - } - - static function deleteOssFile($fname,$policy){ - $accessKeyId = $policy["ak"]; - $accessKeySecret = $policy["sk"]; - $endpoint = "http".ltrim(ltrim($policy["server"],"https"),"http"); - try { - $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); - } catch (OssException $e) { - return false; - } - try{ - $ossClient->deleteObject($policy["bucketname"], $fname); - } catch(OssException $e) { - return false; - } - return true; - } - - static function deleteUpyunFile($fname,$policy){ - $bucketConfig = new Config($policy["bucketname"], $policy["op_name"], $policy["op_pwd"]); - $client = new Upyun($bucketConfig); - $res=$client->delete($fname,true); - } - - static function deleteS3File($fname,$policy){ - $s3 = new \S3\S3($policy["ak"], $policy["sk"],false,$policy["op_pwd"]); - $s3->setSignatureVersion('v4'); - return $s3->deleteObject($policy["bucketname"],$fname); - } - static function uniqueArray($data = array()){ $tempList = []; $qiniuList = []; @@ -1232,6 +726,8 @@ class FileManage extends Model{ $s3PolicyData = []; $remoteList = []; $remotePolicyData = []; + $onedriveList = []; + $onedrivePolicyData = []; foreach ($data as $key => $value) { if(!in_array($value['policy_id'],$tempList)){ array_push($tempList,$value['policy_id']); @@ -1279,6 +775,13 @@ class FileManage extends Model{ } array_push($remotePolicyData[$value['policy_id']],$policyTempData); break; + case 'onedrive': + array_push($onedriveList,$value['policy_id']); + if(empty($onedrivePolicyData[$value['policy_id']])){ + $onedrivePolicyData[$value['policy_id']] = []; + } + array_push($onedrivePolicyData[$value['policy_id']],$policyTempData); + break; default: # code... break; @@ -1299,38 +802,14 @@ class FileManage extends Model{ 's3PolicyData' => $s3PolicyData, 'remoteList' => $remoteList, 'remotePolicyData' => $remotePolicyData, + 'onedriveList' => $onedriveList, + 'onedrivePolicyData' => $onedrivePolicyData, ); return $returenValue; } public function signTmpUrl(){ - switch ($this->policyData["policy_type"]) { - case 'qiniu': - return $this->qiniuPreview()[1]; - break; - case 'oss': - return $this->ossPreview()[1]; - break; - case 'upyun': - return $this->upyunPreview()[1]; - break; - case 's3': - return $this->s3Preview()[1]; - break; - case 'local': - $options = Option::getValues(["oss","basic"]); - $timeOut = $options["timeout"]; - $delayTime = time()+$timeOut; - $key=$this->fileData["id"].":".$delayTime.":".md5($this->userData["user_pass"].$this->fileData["id"].$delayTime.config("salt")); - return $options['siteURL']."Callback/TmpPreview/key/".$key; - break; - case 'remote': - return $this->remotePreview()[1]; - break; - default: - # code... - break; - } + return $this->adapter->signTmpUrl()[1]; } } diff --git a/application/index/model/LocalAdapter.php b/application/index/model/LocalAdapter.php new file mode 100644 index 00000000..e328ec3f --- /dev/null +++ b/application/index/model/LocalAdapter.php @@ -0,0 +1,392 @@ +fileModel = $file; + $this->policyModel = $policy; + $this->userModel = $user; + } + + /** + * 获取文本文件内容 + * + * @return string 内容 + */ + public function getFileContent(){ + $filePath = ROOT_PATH . 'public/uploads/' . $this->fileModel["pre_name"]; + $fileObj = fopen($filePath,"r"); + $fileContent = fread($fileObj,filesize($filePath)+1); + return $fileContent; + } + + /** + * 保存可编辑文件 + * + * @param string $content 要保存的文件内容 + * @return void + */ + public function saveContent($content){ + $filePath = ROOT_PATH . 'public/uploads/' . $this->fileModel["pre_name"]; + file_put_contents($filePath, ""); + file_put_contents($filePath, $content); + } + + /** + * 输出预览文件 + * + * @param boolean $isAdmin 是否为管理员请求 + * @return mixed 文件数据 + */ + public function Preview($isAdmin = false){ + $speedLimit = Db::name('groups')->where('id',$this->userModel["user_group"])->find(); + $rangeTransfer = $speedLimit["range_transfer"]; + $speedLimit = $speedLimit["speed"]; + $sendFileOptions = Option::getValues(["download"]); + if($sendFileOptions["sendfile"] == "1" && !empty($sendFileOptions)){ + $this->sendFile($speedLimit,$rangeTransfer,false,$sendFileOptions["header"]); + }else{ + if($isAdmin){ + $speedLimit=""; + } + if($speedLimit == "0"){ + exit(); + }else if(empty($speedLimit)){ + header("Cache-Control: max-age=10800"); + $this->outputWithoutLimit(false,$rangeTransfer); + exit(); + }else if((int)$speedLimit > 0){ + header("Cache-Control: max-age=10800"); + $this->outputWithLimit($speedLimit); + } + } + } + + /** + * 使用Sendfile模式发送文件数据 + * + * @param int $speed 下载限速 + * @param boolean $range 是否支持断点续传 + * @param boolean $download 是否为下载请求 + * @param string $header Sendfile Header + * @return void + */ + private function sendFile($speed,$range,$download=false,$header="X-Sendfile"){ + $filePath = ROOT_PATH . 'public/uploads/' . $this->fileModel["pre_name"]; + $realPath = ROOT_PATH . 'public/uploads/' . $this->fileModel["pre_name"]; + if($header == "X-Accel-Redirect"){ + $filePath = '/public/uploads/' . $this->fileModel["pre_name"]; + } + if($download){ + $filePath = str_replace("\\","/",$filePath); + if($header == "X-Accel-Redirect"){ + ob_flush(); + flush(); + echo "s"; + } + //保证如下顺序,否则最终浏览器中得到的content-type为'text/html' + //1,写入 X-Sendfile 头信息 + $pathToFile = str_replace('%2F', '/', rawurlencode($filePath)); + header($header.": ".$pathToFile); + //2,写入Content-Type头信息 + $mime_type = self::getMimetypeOnly($realPath); + header('Content-Type: '.$mime_type); + //3,写入正确的附件文件名头信息 + $orign_fname = $this->fileModel["orign_name"]; + $ua = $_SERVER["HTTP_USER_AGENT"]; // 处理不同浏览器的兼容性 + if (preg_match("/Firefox/", $ua)) { + $encoded_filename = rawurlencode($orign_fname); + header("Content-Disposition: attachment; filename*=\"utf8''" . $encoded_filename . '"'); + } else if (preg_match("/MSIE/", $ua) || preg_match("/Edge/", $ua) || preg_match("/rv:/", $ua)) { + $encoded_filename = rawurlencode($orign_fname); + header('Content-Disposition: attachment; filename="' . $encoded_filename . '"'); + } else { + // for Chrome,Safari etc. + header('Content-Disposition: attachment;filename="'. $orign_fname .'";filename*=utf-8'."''". $orign_fname); + } + exit; + }else{ + $filePath = str_replace("\\","/",$filePath); + header('Content-Type: '.self::getMimetype($realPath)); + if($header == "X-Accel-Redirect"){ + ob_flush(); + flush(); + echo "s"; + } + header($header.": ".str_replace('%2F', '/', rawurlencode($filePath))); + ob_flush(); + flush(); + } + } + + /** + * 无限速发送文件数据 + * + * @param boolean $download 是否为下载 + * @param boolean $reload 是否支持断点续传 + * @return void + */ + public function outputWithoutLimit($download = false,$reload = false){ + ignore_user_abort(false); + $filePath = ROOT_PATH . 'public/uploads/' . $this->fileModel["pre_name"]; + set_time_limit(0); + session_write_close(); + $file_size = filesize($filePath); + $ranges = $this->getRange($file_size); + if($reload == 1 && $ranges!=null){ + header('HTTP/1.1 206 Partial Content'); + header('Accept-Ranges:bytes'); + header(sprintf('content-length:%u',$ranges['end']-$ranges['start'])); + header(sprintf('content-range:bytes %s-%s/%s', $ranges['start'], $ranges['end']-1, $file_size)); + } + if($download){ + header('Cache-control: private'); + header('Content-Type: application/octet-stream'); + header('Content-Length: '.filesize($filePath)); + $encoded_fname = rawurlencode($this->fileModel["orign_name"]); + header('Content-Disposition: attachment;filename="'.$encoded_fname.'";filename*=utf-8'."''".$encoded_fname); + ob_flush(); + flush(); + } + if(file_exists($filePath)){ + if(!$download){ + header('Content-Type: '.self::getMimetype($filePath)); + ob_flush(); + flush(); + } + $fileObj = fopen($filePath,"rb"); + if($reload == 1){ + fseek($fileObj, sprintf('%u', $ranges['start'])); + } + while(!feof($fileObj)){ + echo fread($fileObj,10240); + ob_flush(); + flush(); + } + fclose($fileObj); + } + } + + /** + * 有限速发送文件数据 + * + * @param int $speed 最大速度 + * @param boolean $download 是否为下载请求 + * @return void + */ + public function outputWithLimit($speed,$download = false){ + ignore_user_abort(false); + $filePath = ROOT_PATH . 'public/uploads/' . $this->fileModel["pre_name"]; + set_time_limit(0); + session_write_close(); + if($download){ + header('Cache-control: private'); + header('Content-Type: application/octet-stream'); + header('Content-Length: '.filesize($filePath)); + $encoded_fname = rawurlencode($this->fileModel["orign_name"]); + header('Content-Disposition: attachment;filename="'.$encoded_fname.'";filename*=utf-8'."''".$encoded_fname); + ob_flush(); + flush(); + }else{ + header('Content-Type: '.self::getMimetype($filePath)); + ob_flush(); + flush(); + } + if(file_exists($filePath)){ + $fileObj = fopen($filePath,"r"); + while (!feof($fileObj)){ + echo fread($fileObj,round($speed*1024)); + ob_flush(); + flush(); + sleep(1); + } + fclose($fileObj); + } + } + + /** + * 获取文件MIME Type + * + * @param string $path 文件路径 + * @return void + */ + static function getMimetype($path){ + //FILEINFO_MIME will output something like "image/jpeg; charset=binary" + $finfoObj = finfo_open(FILEINFO_MIME); + $mimetype = finfo_file($finfoObj, $path); + finfo_close($finfoObj); + return $mimetype; + } + + /** + * 获取文件MIME Type + * + * @param string $path 文件路径 + * @return void + */ + static function getMimetypeOnly($path){ + //FILEINFO_MIME_TYPE will output something like "image/jpeg" + $finfoObj = finfo_open(FILEINFO_MIME_TYPE); + $mimetype = finfo_file($finfoObj, $path); + finfo_close($finfoObj); + return $mimetype; + } + + /** + * 获取断点续传时HTTP_RANGE头 + * + * @param int $file_size 文件大小 + * @return void + */ + private function getRange($file_size){ + if(isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE'])){ + $range = $_SERVER['HTTP_RANGE']; + $range = preg_replace('/[\s|,].*/', '', $range); + $range = explode('-', substr($range, 6)); + if(count($range)<2){ + $range[1] = $file_size; + } + $range = array_combine(array('start','end'), $range); + if(empty($range['start'])){ + $range['start'] = 0; + } + if(empty($range['end'])){ + $range['end'] = $file_size; + } + return $range; + } + return null; + } + + /** + * 生成/返回 文件缩略图 + * + * @return array 重定向信息 + */ + public function getThumb(){ + $picInfo = explode(",",$this->fileModel["pic_info"]); + $picInfo = self::getThumbSize($picInfo[0],$picInfo[1]); + if(file_exists(ROOT_PATH . "public/thumb/".$this->fileModel["pre_name"]."_thumb")){ + self::outputThumb(ROOT_PATH . "public/thumb/".$this->fileModel["pre_name"]."_thumb"); + return [0,0]; + } + $thumbImg = new Thumb(ROOT_PATH . "public/uploads/".$this->fileModel["pre_name"]); + $thumbImg->thumb($picInfo[1], $picInfo[0]); + if(!is_dir(dirname(ROOT_PATH . "public/thumb/".$this->fileModel["pre_name"]))){ + mkdir(dirname(ROOT_PATH . "public/thumb/".$this->fileModel["pre_name"]),0777,true); + } + $thumbImg->out(ROOT_PATH . "public/thumb/".$this->fileModel["pre_name"]."_thumb"); + self::outputThumb(ROOT_PATH . "public/thumb/".$this->fileModel["pre_name"]."_thumb"); + return [0,0]; + } + + /** + * 计算缩略图大小 + * + * @param int $width 原始宽 + * @param int $height 原始高 + * @return array + */ + static function getThumbSize($width,$height){ + $rate = $width/$height; + $maxWidth = 90; + $maxHeight = 39; + $changeWidth = 39*$rate; + $changeHeight = 90/$rate; + if($changeWidth>=$maxWidth){ + return [(int)$changeHeight,90]; + } + return [39,(int)$changeWidth]; + } + + /** + * 输出缩略图 + * + * @param string $path 缩略图文件路径 + * @return void + */ + static function outputThumb($path){ + ob_end_clean(); + if(!input("get.cache")=="no"){ + header("Cache-Control: max-age=10800"); + } + header('Content-Type: '.self::getMimetype($path)); + $fileObj = fopen($path,"r"); + echo fread($fileObj,filesize($path)); + fclose($file); + } + + /** + * 处理下载请求 + * + * @param boolean $isAdmin 是否为管理员请求 + * @return void + */ + public function Download($isAdmin=false){ + $speedLimit = Db::name('groups')->where('id',$this->userModel["user_group"])->find(); + $rangeTransfer = $speedLimit["range_transfer"]; + $speedLimit = $speedLimit["speed"]; + $sendFileOptions = Option::getValues(["download"]); + if($sendFileOptions["sendfile"] == "1"){ + $this->sendFile($speedLimit,$rangeTransfer,true,$sendFileOptions["header"]); + }else{ + if($isAdmin){ + $speedLimit = ""; + } + if($speedLimit == "0"){ + exit(); + }else if(empty($speedLimit)){ + $this->outputWithoutLimit(true,$rangeTransfer); + exit(); + }else if((int)$speedLimit > 0){ + $this->outputWithLimit($speedLimit,true); + } + } + } + + /** + * 删除指定本地文件 + * + * @param array $fileList 待删除文件的数据库记录 + * @param array $policyData 待删除文件的上传策略信息 + * @return void + */ + static function DeleteFile($fileList,$policyData){ + $fileListTemp = array_column($fileList, 'pre_name'); + foreach ($fileListTemp as $key => $value) { + @unlink(ROOT_PATH . 'public/uploads/'.$value); + if(file_exists(ROOT_PATH . 'public/thumb/'.$value."_thumb")){ + @unlink(ROOT_PATH . 'public/thumb/'.$value."_thumb"); + } + } + } + + /** + * 签名临时直链,用于Office365预览 + * + * @return array + */ + public function signTmpUrl(){ + $options = Option::getValues(["oss","basic"]); + $timeOut = $options["timeout"]; + $delayTime = time()+$timeOut; + $key=$this->fileModel["id"].":".$delayTime.":".md5($this->userModel["user_pass"].$this->fileModel["id"].$delayTime.config("salt")); + return [1,$options['siteURL']."Callback/TmpPreview/key/".$key]; + } + +} + +?> \ No newline at end of file diff --git a/application/index/model/Mail.php b/application/index/model/Mail.php index c7eb4dca..07f131c5 100644 --- a/application/index/model/Mail.php +++ b/application/index/model/Mail.php @@ -45,13 +45,16 @@ class Mail extends Model{ $mail->Username =$this->smtpUser; $mail->Password = $this->smtpPass; $mail->From = $this->fromAdress; + $mail->SMTPDebug = 1; + $mail->Debugoutput = function($str, $level) { + $this->errorMsg .= $str; + }; $mail->isHTML(true); $mail->addAddress($to,$name); $mail->Subject = $title; $mail->Body = $content; $status = $mail->send(); if(!$status){ - $this->errorMsg = $mail->ErrorInfo; return false; } return true; diff --git a/application/index/model/OnedriveAdapter.php b/application/index/model/OnedriveAdapter.php new file mode 100644 index 00000000..5091485d --- /dev/null +++ b/application/index/model/OnedriveAdapter.php @@ -0,0 +1,140 @@ +fileModel = $file; + $this->policyModel = $policy; + $this->userModel = $user; + $this->clinet = new Client([ + 'stream_back_end' => \Krizalys\Onedrive\StreamBackEnd::TEMP, + 'client_id' => $this->policyModel["bucketname"], + + // Restore the previous state while instantiating this client to proceed in + // obtaining an access token. + 'state' => json_decode($this->policyModel["sk"]), + ]); + } + + /** + * 获取文本文件内容 + * + * @return string 文件内容 + */ + public function getFileContent(){ + $file = new \Krizalys\Onedrive\File($this->clinet,"/me/drive/root:/".$this->fileModel["pre_name"].":"); + return $file->fetchContent(); + } + + /** + * 签名预览URL + * + * @return void + */ + public function Preview($base=null,$name=null){ + $preview = json_decode(json_encode($this->clinet->apiGet("/me/drive/root:/".rawurlencode($this->fileModel["pre_name"]).":")),true); + return [1,$preview["@microsoft.graph.downloadUrl"]]; + } + + /** + * 保存文件内容 + * + * @param string $content 文件内容 + * @return void + */ + public function saveContent($content){ + $this->clinet->createFile(rawurldecode($this->fileModel["pre_name"]),"/me/drive/root:/",$content); + } + + /** + * 计算缩略图大小 + * + * @param int $width 原始宽 + * @param int $height 原始高 + * @return array + */ + static function getThumbSize($width,$height){ + $rate = $width/$height; + $maxWidth = 90; + $maxHeight = 39; + $changeWidth = 39*$rate; + $changeHeight = 90/$rate; + if($changeWidth>=$maxWidth){ + return [(int)$changeHeight,90]; + } + return [39,(int)$changeWidth]; + } + + + /** + * 获取缩略图地址 + * + * @return string 缩略图地址 + */ + public function getThumb(){ + $picInfo = explode(",",$this->fileModel["pic_info"]); + $thumbSize = self::getThumbSize($picInfo[0],$picInfo[1]); + $thumb = json_decode(json_encode($this->clinet->apiGet("/me/drive/root:/".rawurlencode($this->fileModel["pre_name"]).":/thumbnails")),true); + return [1,$thumb["value"][0]["small"]["url"]]; + } + + /** + * 删除某一策略下的指定upyun文件 + * + * @param array $fileList 待删除文件的数据库记录 + * @param array $policyData 待删除文件的上传策略信息 + * @return void + */ + static function DeleteFile($fileList,$policyData){ + $clinet = new Client([ + 'stream_back_end' => \Krizalys\Onedrive\StreamBackEnd::TEMP, + 'client_id' => $policyData["bucketname"], + + // Restore the previous state while instantiating this client to proceed in + // obtaining an access token. + 'state' => json_decode($policyData["sk"]), + ]); + foreach (array_column($fileList, 'pre_name') as $key => $value) { + $clinet->deleteObject("/me/drive/root:/".rawurlencode($value).":"); + } + } + + /** + * 生成文件下载URL + * + * @return array + */ + public function Download(){ + $preview = json_decode(json_encode($this->clinet->apiGet("/me/drive/root:/".rawurlencode($this->fileModel["pre_name"]).":")),true); + return [1,$preview["@microsoft.graph.downloadUrl"]]; + } + + /** + * 签名临时URL用于Office预览 + * + * @return array + */ + public function signTmpUrl(){ + return $this->Preview(); + } + + +} + +?> \ No newline at end of file diff --git a/application/index/model/OssAdapter.php b/application/index/model/OssAdapter.php new file mode 100644 index 00000000..d8553a0d --- /dev/null +++ b/application/index/model/OssAdapter.php @@ -0,0 +1,199 @@ +fileModel = $file; + $this->policyModel = $policy; + $this->userModel = $user; + } + + /** + * 获取OSS策略文本文件内容 + * + * @return string 文件内容 + */ + public function getFileContent(){ + return file_get_contents($this->Preview()[1]); + } + + /** + * 签名OSS预览URL + * + * @return void + */ + public function Preview(){ + if(!$this->policyModel['bucket_private']){ + $fileUrl = $this->policyModel["url"].$this->fileModel["pre_name"]; + return[true,$fileUrl]; + }else{ + $accessKeyId = $this->policyModel["ak"]; + $accessKeySecret = $this->policyModel["sk"]; + $endpoint = $this->policyModel["url"]; + try { + $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); + } catch (OssException $e) { + return [false,0]; + } + $baseUrl = $this->policyModel["url"].$this->fileModel["pre_name"]; + try{ + $signedUrl = $ossClient->signUrl($this->policyModel["bucketname"], $this->fileModel["pre_name"], Option::getValue("timeout")); + } catch(OssException $e) { + return [false,0]; + } + return[true,$signedUrl]; + } + } + + /** + * 保存OSS文件内容 + * + * @param string $content 文件内容 + * @return void + */ + public function saveContent($content){ + $accessKeyId = $this->policyModel["ak"]; + $accessKeySecret = $this->policyModel["sk"]; + $endpoint = "http".ltrim(ltrim($this->policyModel["server"],"https"),"http"); + try { + $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); + } catch (OssException $e) { + die('{ "result": { "success": false, "error": "鉴权失败" } }'); + } + try{ + $ossClient->putObject($this->policyModel["bucketname"], $this->fileModel["pre_name"], $content); + } catch(OssException $e) { + die('{ "result": { "success": false, "error": "编辑失败" } }'); + } + } + + /** + * 获取缩略图地址 + * + * @return string 缩略图地址 + */ + public function getThumb(){ + if(!$this->policyModel['bucket_private']){ + $fileUrl = $this->policyModel["url"].$this->fileModel["pre_name"]."?x-oss-process=image/resize,m_lfit,h_39,w_90"; + return[true,$fileUrl]; + }else{ + $accessKeyId = $this->policyModel["ak"]; + $accessKeySecret = $this->policyModel["sk"]; + $endpoint = $this->policyModel["url"]; + try { + $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); + } catch (OssException $e) { + return [false,0]; + } + $baseUrl = $this->policyModel["url"].$this->fileModel["pre_name"]; + try{ + $signedUrl = $ossClient->signUrl($this->policyModel["bucketname"], $this->fileModel["pre_name"], Option::getValue("timeout"),'GET', array("x-oss-process" => 'image/resize,m_lfit,h_39,w_90')); + } catch(OssException $e) { + return [false,0]; + } + return[true,$signedUrl]; + } + } + /** + * 删除某一策略下的指定OSS文件 + * + * @param array $fileList 待删除文件的数据库记录 + * @param array $policyData 待删除文件的上传策略信息 + * @return void + */ + static function DeleteFile($fileList,$policyData){ + $accessKeyId = $policyData["ak"]; + $accessKeySecret = $policyData["sk"]; + $endpoint = "http".ltrim(ltrim($policyData["server"],"https"),"http"); + try { + $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); + } catch (OssException $e) { + return false; + } + try{ + $ossClient->deleteObjects($policyData["bucketname"], array_column($fileList, 'pre_name')); + } catch(OssException $e) { + return false; + } + } + + /** + * 生成文件下载URL + * + * @return array + */ + public function Download(){ + if(!$this->policyModel['bucket_private']){ + return[true,"/File/OssDownload?url=".urlencode($this->policyModel["url"].$this->fileModel["pre_name"])."&name=".urlencode($this->fileModel["orign_name"])]; + }else{ + $accessKeyId = $this->policyModel["ak"]; + $accessKeySecret = $this->policyModel["sk"]; + $endpoint = $this->policyModel["url"]; + try { + $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); + } catch (OssException $e) { + return [false,0]; + } + $baseUrl = $this->policyModel["url"].$this->fileModel["pre_name"]; + try{ + $signedUrl = $ossClient->signUrl($this->policyModel["bucketname"], $this->fileModel["pre_name"], Option::getValue("timeout"),'GET', array("response-content-disposition" => 'attachment; filename='.$this->fileModel["orign_name"])); + } catch(OssException $e) { + return [false,0]; + } + return[true,$signedUrl]; + } + } + + /** + * 删除临时文件 + * + * @param string $fname 文件名 + * @param array $policy 上传策略信息 + * @return boolean + */ + static function deleteOssFile($fname,$policy){ + $accessKeyId = $policy["ak"]; + $accessKeySecret = $policy["sk"]; + $endpoint = "http".ltrim(ltrim($policy["server"],"https"),"http"); + try { + $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, true); + } catch (OssException $e) { + return false; + } + try{ + $ossClient->deleteObject($policy["bucketname"], $fname); + } catch(OssException $e) { + return false; + } + return true; + } + + /** + * 签名临时URL用于Office预览 + * + * @return array + */ + public function signTmpUrl(){ + return $this->Preview(); + } + + +} + +?> \ No newline at end of file diff --git a/application/index/model/QiniuAdapter.php b/application/index/model/QiniuAdapter.php new file mode 100644 index 00000000..cfe1eae4 --- /dev/null +++ b/application/index/model/QiniuAdapter.php @@ -0,0 +1,149 @@ +fileModel = $file; + $this->policyModel = $policy; + $this->userModel = $user; + } + + /** + * 获取文本文件内容 + * + * @return string 文件内容 + */ + public function getFileContent(){ + return file_get_contents($this->Preview()[1]); + } + + /** + * 签名七牛文件预览URL + * + * @param string $thumb 缩略图参数 + * @return void + */ + public function Preview($thumb=null){ + if($thumb===true || $thumb===false){ + $thumb =null; + } + if(!$this->policyModel['bucket_private']){ + $fileUrl = $this->policyModel["url"].$this->fileModel["pre_name"].$thumb; + return[true,$fileUrl]; + }else{ + $auth = new Auth($this->policyModel["ak"], $this->policyModel["sk"]); + $baseUrl = $this->policyModel["url"].$this->fileModel["pre_name"].$thumb; + $signedUrl = $auth->privateDownloadUrl($baseUrl); + return[true,$signedUrl]; + } + } + + /** + * 保存七牛文件内容 + * + * @param string $content 文件内容 + * @return bool + */ + public function saveContent($content){ + $auth = new Auth($this->policyModel["ak"], $this->policyModel["sk"]); + $expires = 3600; + $keyToOverwrite = $this->fileModel["pre_name"]; + $upToken = $auth->uploadToken($this->policyModel["bucketname"], $keyToOverwrite, $expires, null, true); + $uploadMgr = new \Qiniu\Storage\UploadManager(); + list($ret, $err) = $uploadMgr->put($upToken, $keyToOverwrite, $content); + if ($err !== null) { + die('{ "result": { "success": false, "error": "编辑失败" } }'); + } else { + return true; + } + } + + /** + * 获取缩略图地址 + * + * @return string 缩略图地址 + */ + public function getThumb(){ + return $this->Preview("?imageView2/2/w/90/h/39"); + } + +/** + * 删除某一策略下的指定七牛文件 + * + * @param array $fileList 待删除文件的数据库记录 + * @param array $policyData 待删除文件的上传策略信息 + * @return void + */ + static function deleteFile($fileList,$policyData){ + $auth = new Auth($policyData["ak"], $policyData["sk"]); + $config = new \Qiniu\Config(); + $bucketManager = new \Qiniu\Storage\BucketManager($auth); + $fileListTemp = array_column($fileList, 'pre_name'); + $ops = $bucketManager->buildBatchDelete($policyData["bucketname"], $fileListTemp); + list($ret, $err) = $bucketManager->batch($ops); + } + + /** + * 生成文件下载URL + * + * @return array + */ + public function Download(){ + if(!$this->policyModel['bucket_private']){ + $fileUrl = $this->policyModel["url"].$this->fileModel["pre_name"]."?attname=".urlencode($this->fileModel["orign_name"]); + return[true,$fileUrl]; + }else{ + $auth = new Auth($this->policyModel["ak"], $this->policyModel["sk"]); + $baseUrl = $this->policyModel["url"].$this->fileModel["pre_name"]."?attname=".urlencode($this->fileModel["orign_name"]); + $signedUrl = $auth->privateDownloadUrl($baseUrl); + return[true,$signedUrl]; + } + } + + /** + * 删除临时文件 + * + * @param string $fname 文件名 + * @param array $policy 上传策略信息 + * @return void + */ + static function deleteSingle($fname,$policy){ + $auth = new Auth($policy["ak"], $policy["sk"]); + $config = new \Qiniu\Config(); + $bucketManager = new \Qiniu\Storage\BucketManager($auth); + $err = $bucketManager->delete($policy["bucketname"], $fname); + if ($err) { + return false; + }else{ + return true; + } + } + + /** + * 签名临时URL用于Office预览 + * + * @return array + */ + public function signTmpUrl(){ + return $this->Preview(); + } + +} + +?> \ No newline at end of file diff --git a/application/index/model/RemoteAdapter.php b/application/index/model/RemoteAdapter.php new file mode 100644 index 00000000..a2d9a334 --- /dev/null +++ b/application/index/model/RemoteAdapter.php @@ -0,0 +1,97 @@ +fileModel = $file; + $this->policyModel = $policy; + $this->userModel = $user; + } + + /** + * 获取文本文件内容 + * + * @return string 文件内容 + */ + public function getFileContent(){ + return file_get_contents($this->Preview()[1]); + } + + /** + * 签名文件预览URL + * + * @return void + */ + public function Preview(){ + $remote = new Remote($this->policyModel); + return [1,$remote->preview($this->fileModel["pre_name"])]; + } + + /** + * 保存文件内容 + * + * @param string $content 文件内容 + * @return bool + */ + public function saveContent($content){ + $remote = new Remote($this->policyModel); + $remote->updateContent($this->fileModel["pre_name"],$content); + } + + /** + * 获取缩略图地址 + * + * @return string 缩略图地址 + */ + public function getThumb(){ + $remote = new Remote($this->policyModel); + return [1,$remote->thumb($this->fileModel["pre_name"],explode(",",$this->fileModel["pic_info"]))]; + } + +/** + * 删除某一策略下的指定文件 + * + * @param array $fileList 待删除文件的数据库记录 + * @param array $policyData 待删除文件的上传策略信息 + * @return void + */ + static function deleteFile($fileList,$policyData){ + $remoteObj = new Remote($policyData); + $remoteObj->remove(array_column($fileList, 'pre_name')); + } + + /** + * 生成文件下载URL + * + * @return array + */ + public function Download(){ + $remote = new Remote($this->policyModel); + return [1,$remote->download($this->fileModel["pre_name"],$this->fileModel["orign_name"])]; + } + + /** + * 签名临时URL用于Office预览 + * + * @return array + */ + public function signTmpUrl(){ + return $this->Preview(); + } + +} + +?> \ No newline at end of file diff --git a/application/index/model/S3Adapter.php b/application/index/model/S3Adapter.php new file mode 100644 index 00000000..b9c7a3c0 --- /dev/null +++ b/application/index/model/S3Adapter.php @@ -0,0 +1,109 @@ +fileModel = $file; + $this->policyModel = $policy; + $this->userModel = $user; + } + + /** + * 获取又拍云策略文本文件内容 + * + * @return string 文件内容 + */ + public function getFileContent(){ + return file_get_contents($this->Preview()[1]); + } + + /** + * 签名S3预览URL + * + * @return void + */ + public function Preview($base=null,$name=null){ + if($base===true || $base ===false){ + $base = null; + } + $timeOut = Option::getValue("timeout"); + return [1,\S3\S3::aws_s3_link($this->policyModel["ak"], $this->policyModel["sk"],$this->policyModel["bucketname"],"/".$this->fileModel["pre_name"],3600,$this->policyModel["op_name"])]; + } + + /** + * 保存文件内容 + * + * @param string $content 文件内容 + * @return void + */ + public function saveContent($content){ + $s3 = new \S3\S3($this->policyModel["ak"], $this->policyModel["sk"],false,$this->policyModel["op_pwd"]); + $s3->setSignatureVersion('v4'); + $s3->putObjectString($content, $this->policyModel["bucketname"], $this->fileModel["pre_name"]); + } + + /** + * 删除某一策略下的指定文件 + * + * @param array $fileList 待删除文件的数据库记录 + * @param array $policyData 待删除文件的上传策略信息 + * @return void + */ + static function DeleteFile($fileList,$policyData){ + foreach (array_column($fileList, 'pre_name') as $key => $value) { + self::deleteS3File($value,$policyData); + } + } + + /** + * 生成文件下载URL + * + * @return array + */ + public function Download(){ + $timeOut = Option::getValue("timeout"); + return [1,\S3\S3::aws_s3_link($this->policyModel["ak"], $this->policyModel["sk"],$this->policyModel["bucketname"],"/".$this->fileModel["pre_name"],3600,$this->policyModel["op_name"],array(),false)]; + } + + /** + * 删除临时文件 + * + * @param string $fname 文件名 + * @param array $policy 上传策略信息 + * @return boolean + */ + static function deleteS3File($fname,$policy){ + $s3 = new \S3\S3($policy["ak"], $policy["sk"],false,$policy["op_pwd"]); + $s3->setSignatureVersion('v4'); + return $s3->deleteObject($policy["bucketname"],$fname); + } + + /** + * 签名临时URL用于Office预览 + * + * @return array + */ + public function signTmpUrl(){ + return $this->Preview(); + } + + +} + +?> \ No newline at end of file diff --git a/application/index/model/ShareHandler.php b/application/index/model/ShareHandler.php index ebbd27cd..876c17b9 100644 --- a/application/index/model/ShareHandler.php +++ b/application/index/model/ShareHandler.php @@ -81,6 +81,20 @@ class ShareHandler extends Model{ } } + public function getThumb($user,$path,$folder=false){ + $checkStatus = $this->checkSession($user); + if(!$checkStatus[0]){ + return [$checkStatus[0],$checkStatus[1]]; + } + $reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find(); + if($folder){ + $fileObj = new FileManage($path,$this->shareData["owner"]); + }else{ + $fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]); + } + return $fileObj->getThumb(); + } + public function checkSession($user){ if($this->lockStatus){ return [false,"会话过期,请刷新页面"]; diff --git a/application/index/model/Task.php b/application/index/model/Task.php new file mode 100644 index 00000000..7c0ffe9e --- /dev/null +++ b/application/index/model/Task.php @@ -0,0 +1,355 @@ +insert([ + "task_name" => $this->taskName, + "attr" => $this->taskContent, + "type" => $this->taskType, + "status" => "todo", + "uid" => $this->userId, + ]); + } + + /** + * 开始执行任务 + * + * @return void + */ + public function Doit(){ + switch ($this->taskModel["type"]){ + case "uploadSingleToOnedrive": + $this->uploadSingleToOnedrive(); + break; + case "UploadRegularRemoteDownloadFileToOnedrive": + $this->uploadSingleToOnedrive(); + break; + case "uploadChunksToOnedrive": + $this->uploadChunksToOnedrive(); + break; + case "UploadLargeRemoteDownloadFileToOnedrive": + $this->uploadUnchunkedFile(); + break; + default: + $this->output->writeln("Unknown task type (".$this->taskModel["type"].")"); + break; + } + } + + /** + * 上传未分片的大文件至Onedrive + * + * @return void + */ + private function uploadUnchunkedFile(){ + $this->taskContent = json_decode($this->taskModel["attr"],true); + $policyData = Db::name("policy")->where("id",$this->taskContent["policyId"])->find(); + $this->policyModel = $policyData; + $onedrive = new Client([ + 'stream_back_end' => \Krizalys\Onedrive\StreamBackEnd::TEMP, + 'client_id' => $policyData["bucketname"], + + // Restore the previous state while instantiating this client to proceed in + // obtaining an access token. + 'state' => json_decode($policyData["sk"]), + ]); + + //创建分片上传Session,获取上传URL + try{ + $uploadUrl = $onedrive->apiPost("/me/drive/root:/".rawurlencode($this->taskContent["savePath"] . "/" . $this->taskContent["objname"]).":/createUploadSession",[])->uploadUrl; + }catch(\Exception $e){ + $this->status="error"; + $this->errorMsg = $e->getMessage(); + $this->cleanTmpChunk(); + return; + } + //创建分片上传Session,获取上传URL + try{ + $uploadUrl = $onedrive->apiPost("/me/drive/root:/".rawurlencode($this->taskContent["savePath"] . "/" . $this->taskContent["objname"]).":/createUploadSession",[])->uploadUrl; + }catch(\Exception $e){ + $this->status="error"; + $this->errorMsg = $e->getMessage(); + $this->cleanTmpChunk(); + return; + } + + //每次4MB上传文件 + + if(!$file = @fopen($this->taskContent["originPath"],"r")){ + $this->status="error"; + $this->errorMsg = "File not exist."; + $this->cleanTmpChunk(); + return; + } + $offset = 0; + $totalSize = filesize($this->taskContent["originPath"]); + while (1) { + //移动文件指针 + fseek($file, $offset); + + $chunksize = (($offset+4*1024*1024)>$totalSize)?($totalSize-$offset):1024*4*1024; + $headers = []; + $headers[] = "Content-Length: ".$chunksize; + $headers[] = "Content-Range: bytes ".$offset."-".($offset+$chunksize-1)."/".$this->taskContent["fsize"]; + + //发送单个分片数据 + try{ + $onedrive->sendFileChunk($uploadUrl,$headers,fread($file,$chunksize)); + }catch(\Exception $e){ + $this->status="error"; + $this->errorMsg = $e->getMessage(); + $this->cleanTmpChunk(); + return; + } + $this->output->writeln("[Info] Chunk Uploaded. Offset:".$offset); + $offset+=$chunksize; + if($offset+1 >=$totalSize){ + break; + } + + } + fclose($file); + $jsonData = array( + "path" => $this->taskContent["path"], + "fname" => $this->taskContent["fname"], + "objname" => $this->taskContent["savePath"]."/".$this->taskContent["objname"], + "fsize" => $this->taskContent["fsize"], + ); + + $addAction = FileManage::addFile($jsonData,$policyData,$this->taskModel["uid"],$this->taskContent["picInfo"]); + if(!$addAction[0]){ + $this->setError($addAction[1],true,"/me/drive/root:/".rawurlencode($this->taskContent["savePath"] . "/" . $this->taskContent["objname"]),$onedrive); + $this->cleanTmpChunk(); + return; + } + + $this->cleanTmpChunk(); + + } + + /** + * 上传已分片的大文件至Onedrive + * + * @return void + */ + private function uploadChunksToOnedrive(){ + $this->taskContent = json_decode($this->taskModel["attr"],true); + $policyData = Db::name("policy")->where("id",$this->taskContent["policyId"])->find(); + $this->policyModel = $policyData; + $onedrive = new Client([ + 'stream_back_end' => \Krizalys\Onedrive\StreamBackEnd::TEMP, + 'client_id' => $policyData["bucketname"], + + // Restore the previous state while instantiating this client to proceed in + // obtaining an access token. + 'state' => json_decode($policyData["sk"]), + ]); + + //创建分片上传Session,获取上传URL + try{ + $uploadUrl = $onedrive->apiPost("/me/drive/root:/".rawurlencode($this->taskContent["savePath"] . "/" . $this->taskContent["objname"]).":/createUploadSession",[])->uploadUrl; + }catch(\Exception $e){ + $this->status="error"; + $this->errorMsg = $e->getMessage(); + $this->cleanTmpChunk(); + return; + } + + //逐个上传文件分片 + $offset = 0; + foreach ($this->taskContent["chunks"] as $key => $value) { + $chunkPath = ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk"; + if(!$file = @fopen($chunkPath,"r")){ + $this->status="error"; + $this->errorMsg = "File chunk not exist."; + $this->cleanTmpChunk(); + return; + } + $headers = []; + $chunksize = filesize($chunkPath); + $headers[] = "Content-Length: ".$chunksize; + $headers[] = "Content-Range: bytes ".$offset."-".($offset+$chunksize-1)."/".$this->taskContent["fsize"]; + + //发送单个分片数据 + try{ + $onedrive->sendFileChunk($uploadUrl,$headers,$file); + }catch(\Exception $e){ + $this->status="error"; + $this->errorMsg = $e->getMessage(); + $this->cleanTmpChunk(); + return; + } + $this->output->writeln("[Info] Chunk Uploaded. Offset:".$offset); + $offset += $chunksize; + fclose($file); + + } + + $jsonData = array( + "path" => $this->taskContent["path"], + "fname" => $this->taskContent["fname"], + "objname" => $this->taskContent["savePath"]."/".$this->taskContent["objname"], + "fsize" => $this->taskContent["fsize"], + ); + + $addAction = FileManage::addFile($jsonData,$policyData,$this->taskModel["uid"],$this->taskContent["picInfo"]); + if(!$addAction[0]){ + $this->setError($addAction[1],true,"/me/drive/root:/".rawurlencode($this->taskContent["savePath"] . "/" . $this->taskContent["objname"]),$onedrive); + $this->cleanTmpChunk(); + return; + } + + $this->cleanTmpChunk(); + + + } + + /** + * 上传单文件(<=4mb)至Onedrive + * + * @return void + */ + private function uploadSingleToOnedrive(){ + $this->taskContent = json_decode($this->taskModel["attr"],true); + $policyData = Db::name("policy")->where("id",$this->taskContent["policyId"])->find(); + $this->policyModel = $policyData; + $onedrive = new Client([ + 'stream_back_end' => \Krizalys\Onedrive\StreamBackEnd::TEMP, + 'client_id' => $policyData["bucketname"], + + // Restore the previous state while instantiating this client to proceed in + // obtaining an access token. + 'state' => json_decode($policyData["sk"]), + ]); + + $filePath = $this->taskModel["type"] == "UploadRegularRemoteDownloadFileToOnedrive"?$this->taskContent["originPath"]:ROOT_PATH . 'public/uploads/'.$this->taskContent["savePath"] . "/" . $this->taskContent["objname"]; + if($file = @fopen($filePath,"r")){ + try{ + $onedrive->createFile(rawurlencode($this->taskContent["objname"]),"/me/drive/root:/".$this->taskContent["savePath"],$file); + }catch(\Exception $e){ + $this->status="error"; + $this->errorMsg = $e->getMessage(); + $this->cleanTmpFile(); + return; + } + + $jsonData = array( + "path" => $this->taskContent["path"], + "fname" => $this->taskContent["fname"], + "objname" => $this->taskContent["savePath"]."/".$this->taskContent["objname"], + "fsize" => $this->taskContent["fsize"], + ); + + $addAction = FileManage::addFile($jsonData,$policyData,$this->taskModel["uid"],$this->taskContent["picInfo"]); + if(!$addAction[0]){ + $this->setError($addAction[1],true,"/me/drive/root:/".$this->taskContent["savePath"]."/".rawurlencode($this->taskContent["objname"]),$onedrive); + $this->cleanTmpFile(); + return; + } + + fclose($file); + $this->cleanTmpFile(); + }else{ + $this->status = "error"; + $this->errorMsg = "Failed to open file [".$filePath."]"; + } + + } + + /** + * 删除本地临时文件 + * + * @return bool 是否成功 + */ + private function cleanTmpFile(){ + if($this->taskModel["type"] == "UploadRegularRemoteDownloadFileToOnedrive"){ + return @unlink($this->taskContent["originPath"]); + }else{ + return @unlink(ROOT_PATH . 'public/uploads/'.$this->taskContent["savePath"] . "/" . $this->taskContent["objname"]); + } + + } + + /** + * 删除本地临时分片 + * + * @return void + */ + private function cleanTmpChunk(){ + if($this->taskModel["type"] == "UploadLargeRemoteDownloadFileToOnedrive"){ + @unlink($this->taskContent["originPath"]); + }else{ + foreach ($this->taskContent["chunks"] as $key => $value) { + @unlink( ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk"); + } + } + } + + /** + * 设置为出错状态并清理远程文件 + * + * @param string $msg 错误消息 + * @param bool $delete 是否删除文件 + * @param string $path 文件路径 + * @param mixed $adapter 远程操作适配器 + * @return void + */ + private function setError($msg,$delete,$path,$adapter){ + $this->status="error"; + $this->errorMsg = $msg; + if($delete){ + switch($this->taskModel["type"]){ + case "uploadSingleToOnedrive": + $adapter->deleteObject($path); + break; + case "uploadChunksToOnedrive": + $adapter->deleteObject($path); + break; + default: + + break; + } + } + FileManage::storageGiveBack($this->taskModel["uid"],$this->taskContent["fsize"]); + } + +} + +?> \ No newline at end of file diff --git a/application/index/model/UploadHandler.php b/application/index/model/UploadHandler.php index 671e260e..e209f80c 100644 --- a/application/index/model/UploadHandler.php +++ b/application/index/model/UploadHandler.php @@ -8,6 +8,7 @@ use think\Db; use Qiniu\Auth; use \app\index\model\Option; use \app\index\model\FileManage; +use \app\index\model\Task; class UploadHandler extends Model{ @@ -75,13 +76,25 @@ class UploadHandler extends Model{ return 0; } + /** + * 组合分片并生成最终文件 + * + * @param array $ctx 文件片校验码 + * @param string $fname 最终文件名 + * @param string $path 储存目录 + * @return void + */ public function generateFile($ctx,$fname,$path){ $ctxTmp = explode(",",$ctx); $chunks = Db::name('chunks')->where([ 'ctx' => ["in",$ctxTmp], ])->order('id asc')->select(); - $file = $this->combineChunks($chunks); - $this->filterCheck($file,$fname); + $file = null; + if($this->policyContent["policy_type"] != "onedrive"){ + $file = $this->combineChunks($chunks); + } + + $this->filterCheck($file,$fname,$chunks); $suffixTmp = explode('.', $fname); $fileSuffix = array_pop($suffixTmp); if($this->policyContent['autoname']){ @@ -95,28 +108,67 @@ class UploadHandler extends Model{ if(file_exists($savePath.DS.$fileName)){ $this->setError("文件重名",true,$file,ROOT_PATH . 'public/uploads/chunks/'); } - if(!@rename(ROOT_PATH . 'public/uploads/chunks/'.$file,$savePath.DS.$fileName)){ - $this->setError("文件创建失败",true,$file,ROOT_PATH . 'public/uploads/chunks/'); - }else{ + if($this->policyContent["policy_type"] == "onedrive"){ if($path == "ROOTDIR"){ $path = ""; } - $jsonData = array( + $task = new Task(); + $task->taskName = "Upload Big File " . $fname . " to Onedrive"; + $task->taskType = "uploadChunksToOnedrive"; + $task->taskContent = json_encode([ "path" => $path, "fname" => $fname, - "objname" => $generatePath."/".$fileName, + "objname" => $fileName, + "savePath" => $generatePath, "fsize" => $this->fileSizeTmp, - ); - $addAction = FileManage::addFile($jsonData,$this->policyContent,$this->userId); + "picInfo" => "", + "chunks" => $chunks, + "policyId" => $this->policyContent['id'] + ]); + $task->userId = $this->userId; + $task->saveTask(); + echo json_encode(array("key" => $fname)); + }else{ + if(!@rename(ROOT_PATH . 'public/uploads/chunks/'.$file,$savePath.DS.$fileName)){ + $this->setError("文件创建失败",true,$file,ROOT_PATH . 'public/uploads/chunks/'); + }else{ + if($path == "ROOTDIR"){ + $path = ""; + } + $jsonData = array( + "path" => $path, + "fname" => $fname, + "objname" => $generatePath."/".$fileName, + "fsize" => $this->fileSizeTmp, + ); + @list($width, $height, $type, $attr) = getimagesize($savePath.DS.$fileName); + $picInfo = empty($width)?" ":$width.",".$height; + $addAction = FileManage::addFile($jsonData,$this->policyContent,$this->userId,$picInfo); if(!$addAction[0]){ $this->setError($addAction[1],true,$fileName,$savePath); } - echo json_encode(array("key" => $fname)); + echo json_encode(array("key" => $fname)); + } } + } - public function filterCheck($file,$fname){ - $fileSize = filesize(ROOT_PATH . 'public/uploads/chunks/'.$file); + protected function countTotalChunkSize($chunks){ + $size = 0; + foreach ($chunks as $key => $value) { + $size += @filesize(ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk"); + } + + return $size; + } + + public function filterCheck($file,$fname,$chunks){ + if($file !=null){ + $fileSize = filesize(ROOT_PATH . 'public/uploads/chunks/'.$file); + }else{ + $fileSize = $this->countTotalChunkSize($chunks); + } + $suffixTmp = explode('.', $fname); $fileSuffix = array_pop($suffixTmp); $allowedSuffix = explode(',', self::getAllowedExt(json_decode($this->policyContent["filetype"],true))); @@ -131,6 +183,12 @@ class UploadHandler extends Model{ $this->fileSizeTmp = $fileSize; } + /** + * 组合文件分片 + * + * @param array $fname 文件分片数据库记录 + * @return void + */ public function combineChunks($fname){ $fileName = "file_".self::getRandomKey(8); $fileObj=fopen (ROOT_PATH . 'public/uploads/chunks/'.$fileName,"a+"); @@ -181,12 +239,39 @@ class UploadHandler extends Model{ ); @list($width, $height, $type, $attr) = getimagesize(rtrim($savePath, DS).DS.$Uploadinfo->getSaveName()); $picInfo = empty($width)?" ":$width.",".$height; + + //处理Onedrive等非直传 + if($this->policyContent['policy_type'] == "onedrive"){ + $task = new Task(); + $task->taskName = "Upload" . $info["name"] . " to Onedrive"; + $task->taskType = "uploadSingleToOnedrive"; + $task->taskContent = json_encode([ + "path" => $info["path"], + "fname" => $info["name"], + "objname" => $Uploadinfo->getSaveName(), + "savePath" => $generatePath, + "fsize" => $Uploadinfo->getSize(), + "picInfo" => $picInfo, + "policyId" => $this->policyContent['id'] + ]); + $task->userId = $this->userId; + + $task->saveTask(); + + echo json_encode(array("key" => $info["name"])); + FileManage::storageCheckOut($this->userId,$jsonData["fsize"],$Uploadinfo->getInfo('size')); + return; + } + + //向数据库中添加文件记录 $addAction = FileManage::addFile($jsonData,$this->policyContent,$this->userId,$picInfo); if(!$addAction[0]){ $tmpFileName = $Uploadinfo->getSaveName(); unset($Uploadinfo); $this->setError($addAction[1],true,$tmpFileName,$savePath); } + + //扣除容量 FileManage::storageCheckOut($this->userId,$jsonData["fsize"],$Uploadinfo->getInfo('size')); echo json_encode(array("key" => $info["name"])); }else{ @@ -219,6 +304,9 @@ class UploadHandler extends Model{ case 'local': return $this->getLocalToken(); break; + case 'onedrive': + return 'nazGTT91tboaLWBC549$:tHSsNyTBxoV4HDfELJeKH1EUmEY=:eyJjYWxsYmFja0JvZHkiOiJ7XCJwYXRoXCI6XCJcIn0iLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb25cL2pzb24iLCJzY29wZSI6ImMxNjMyMTc3LTQ4NGEtNGU1OS1hZDBhLWUwNDc4ZjZhY2NjZSIsImRlYWRsaW5lIjoxNTM2ODMxOTEwfQ=='; + break; case 'oss': return $this->getOssToken(); break; diff --git a/application/index/model/UpyunAdapter.php b/application/index/model/UpyunAdapter.php new file mode 100644 index 00000000..4ef091ed --- /dev/null +++ b/application/index/model/UpyunAdapter.php @@ -0,0 +1,162 @@ +fileModel = $file; + $this->policyModel = $policy; + $this->userModel = $user; + } + + /** + * 获取又拍云策略文本文件内容 + * + * @return string 文件内容 + */ + public function getFileContent(){ + return file_get_contents($this->Preview()[1]); + } + + /** + * 签名又拍云预览URL + * + * @return void + */ + public function Preview($base=null,$name=null){ + if($base===true || $base===false){ + $base =null; + } + if(!$this->policyModel['bucket_private']){ + $fileUrl = $this->policyModel["url"].$this->fileModel["pre_name"]."?auth=0"; + if(!empty($base)){ + $fileUrl = $base; + } + return[true,$fileUrl]; + }else{ + $baseUrl = $this->policyModel["url"].$this->fileModel["pre_name"]; + if(!empty($base)){ + $baseUrl = $base; + } + $etime = time() + Option::getValue("timeout"); + $key = $this->policyModel["sk"]; + $path = "/".$this->fileModel["pre_name"]; + if(!empty($name)){ + $path = "/".$name; + } + $sign = substr(md5($key.'&'.$etime.'&'.$path), 12, 8).$etime; + $signedUrl = $baseUrl."?_upt=".$sign; + return[true,$signedUrl]; + } + } + + /** + * 保存文件内容 + * + * @param string $content 文件内容 + * @return void + */ + public function saveContent($content){ + $bucketConfig = new Config($this->policyModel["bucketname"], $this->policyModel["op_name"], $this->policyModel["op_pwd"]); + $client = new Upyun($bucketConfig); + if(empty($content)){ + $content = " "; + } + $res=$client->write($this->fileModel["pre_name"],$content); + } + + /** + * 计算缩略图大小 + * + * @param int $width 原始宽 + * @param int $height 原始高 + * @return array + */ + static function getThumbSize($width,$height){ + $rate = $width/$height; + $maxWidth = 90; + $maxHeight = 39; + $changeWidth = 39*$rate; + $changeHeight = 90/$rate; + if($changeWidth>=$maxWidth){ + return [(int)$changeHeight,90]; + } + return [39,(int)$changeWidth]; + } + + + /** + * 获取缩略图地址 + * + * @return string 缩略图地址 + */ + public function getThumb(){ + $picInfo = explode(",",$this->fileModel["pic_info"]); + $thumbSize = self::getThumbSize($picInfo[0],$picInfo[1]); + $baseUrl =$this->policyModel["url"].$this->fileModel["pre_name"]."!/fwfh/90x39"; + return [1,$this->Preview($baseUrl,$this->fileModel["pre_name"]."!/fwfh/90x39")[1]]; + } + + /** + * 删除某一策略下的指定upyun文件 + * + * @param array $fileList 待删除文件的数据库记录 + * @param array $policyData 待删除文件的上传策略信息 + * @return void + */ + static function DeleteFile($fileList,$policyData){ + foreach (array_column($fileList, 'pre_name') as $key => $value) { + self::deleteUpyunFile($value,$policyData); + } + } + + /** + * 生成文件下载URL + * + * @return array + */ + public function Download(){ + return [true,$this->Preview()[1]."&_upd=".urlencode($this->fileModel["orign_name"])]; + } + + /** + * 删除临时文件 + * + * @param string $fname 文件名 + * @param array $policy 上传策略信息 + * @return boolean + */ + static function deleteUpyunFile($fname,$policy){ + $bucketConfig = new Config($policy["bucketname"], $policy["op_name"], $policy["op_pwd"]); + $client = new Upyun($bucketConfig); + $res=$client->delete($fname,true); + } + + /** + * 签名临时URL用于Office预览 + * + * @return array + */ + public function signTmpUrl(){ + return $this->Preview(); + } + + +} + +?> \ No newline at end of file diff --git a/application/index/model/User.php b/application/index/model/User.php index 49d9370c..0a87ad6f 100644 --- a/application/index/model/User.php +++ b/application/index/model/User.php @@ -308,8 +308,8 @@ class User extends Model{ public function getMemory($notEcho = false){ $usedMemory = $this->userSQLData["used_storage"]; - $groupStorage = (int)$this->groupData["max_storage"]; - $packetStorage = (int)Db::name('storage_pack') + $groupStorage = $this->groupData["max_storage"]; + $packetStorage = Db::name('storage_pack') ->where('uid',$this->uid) ->where('dlay_time',">",time()) ->sum('pack_size'); diff --git a/application/index/view/admin/add_group.html b/application/index/view/admin/add_group.html index 7e190809..b4c2aee8 100644 --- a/application/index/view/admin/add_group.html +++ b/application/index/view/admin/add_group.html @@ -113,6 +113,18 @@
是否允许用户使用WebDAV协议同步文件。目前此功能仅支持本地上传方案
+
+
+ +
+
+ +     + +
+
是否允许用户使用离线下载。此功能仅支持本地存储策略,开启前需要到离线下载管理页面设置Aria2接口
+
+
diff --git a/application/index/view/admin/add_policy.html b/application/index/view/admin/add_policy.html index b2cc41e2..5dedd067 100644 --- a/application/index/view/admin/add_policy.html +++ b/application/index/view/admin/add_policy.html @@ -82,6 +82,16 @@
+
+
+ Card image cap +
+
Onedrive 中转
+

支持 Onedrive Bussiness 和个人版。配置说明

+ 添加 +
+
+
diff --git a/application/index/view/admin/add_policy_onedrive.html b/application/index/view/admin/add_policy_onedrive.html new file mode 100644 index 00000000..56e397b7 --- /dev/null +++ b/application/index/view/admin/add_policy_onedrive.html @@ -0,0 +1,155 @@ +{extend name="header_admin" /} +{block name="title"}添加上传策略- {$options.siteName}{/block} +{block name="content"} +
+
+ + + + +
+
+

添加上传策略

+
+ + +
+
+ 添加Onedrive上传策略 +
+
+
+ +
+
+ +
+
+
上传策略的名称,用于区别不同策略
+
+ +
+
+ +
+
+
点击这里获取下一步要用到的应用机密和此处的应用ID
+
+ + + + + + +
+
+ +
+
+ +
+
同上一项一起获取
+
+ +
+
+ +
+
+ +
+ + + +
+
+
允许上传的单个文件的最大尺寸
+
+ +
+
+ +
+
+ + +     + + +
+
是否对存储的文件自动重命名。推荐开启,重命名不会影响用户端文件名展示,开启后可以避免文件重名
+
+
+
+ +
+
+ +
+
你可以使用变量对照表中的字段填写
+
+
+
+ +
+
+
+ + Onedrive根目录 + +
+ +
+
文件存放的目录,你可以使用目录变量对照表中的字段填写
+
+ + +
+
+
+
+
+

+
+
+
+ +
+ + + + +
+
+
+ + +
+ +
+ +{/block} +{block name="js"} + +{/block} \ No newline at end of file diff --git a/application/index/view/admin/download.html b/application/index/view/admin/download.html new file mode 100644 index 00000000..add5692b --- /dev/null +++ b/application/index/view/admin/download.html @@ -0,0 +1,122 @@ +{extend name="header_admin" /} +{block name="title"}离线下载 - {$options.siteName}{/block} +{block name="content"} +
+
+ + + + +
+
+

离线下载

+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
aria2的RPC服务器地址,请在aria2的配置文件中启用RPC服务。例如:http://127.0.0.1:6800/
+
+
+
+ +
+
+
在配置文件中设置的RPC服务的Token
+
+
+
+ +
+
+
下载文件数据的临时存放目录,请确保PHP对该目录拥有读写权限
+
+
+
+ +
+
+
aria2启动下载的其他附带参数,请以json格式书写。你可也可以将这些设置写在aria2配置文件里。可用参数请查阅官方文档
+
+
+
+
+
+
+


+
+
+
+ +
+ + + + + + + + + + + + + + {volist name='list' id='download'} + + + + + + + + + + {/volist} + + +
#文件名创建者文件大小状态进度操作
{$download.id}{:$originList[$key]['fileName']}{:$originList[$key]['user']["user_nick"]}{:countSize($download.total_size)}{$download.status}{eq name="$originList[$key]['totalLength']" value="0"}-{else/}{:floor($originList[$key]['completedLength']/$originList[$key]['totalLength']*10000)/100}%{/eq}{eq name="download.status" value="active"}取消任务{else/} - {/eq}
+ {$list->render()} +
+
+ ddd +
+
+
+

+ +
+
+ + +
+ +
+{/block} +{block name="js"} + + + +{/block} \ No newline at end of file diff --git a/application/index/view/admin/edit_group.html b/application/index/view/admin/edit_group.html index 56a625cc..ad678ec2 100644 --- a/application/index/view/admin/edit_group.html +++ b/application/index/view/admin/edit_group.html @@ -114,6 +114,18 @@
是否允许用户使用WebDAV协议同步文件。目前此功能仅支持本地上传方案
+
+
+ +
+
+ +     + +
+
是否允许用户使用离线下载。此功能仅支持本地存储策略,开启前需要到离线下载管理页面设置Aria2接口
+
+
@@ -162,10 +174,15 @@ {/block} \ No newline at end of file diff --git a/application/index/view/admin/edit_policy.html b/application/index/view/admin/edit_policy.html index 3078c954..29266716 100644 --- a/application/index/view/admin/edit_policy.html +++ b/application/index/view/admin/edit_policy.html @@ -928,6 +928,128 @@
{/case} + {case value="onedrive"} + +
+
+ 添加Onedrive上传策略 +
+
+
+ +
+
+ +
+
+
上传策略的名称,用于区别不同策略
+
+ +
+
+ +
+
+
点击这里获取下一步要用到的应用机密和此处的应用ID
+
+ + +
+
+ +
+
+ +
+
同上一项一起获取
+
+ +
+
+ +
+
+ +
+ + + +
+
+
允许上传的单个文件的最大尺寸
+
+ +
+
+ +
+
+ {eq name="$policy.autoname" value="1"} + + +     + + + {else/} + + +     + + + {/eq} +
+
是否对存储的文件自动重命名。推荐开启,重命名不会影响用户端文件名展示,开启后可以避免文件重名
+
+
+
+ +
+
+ +
+
你可以使用变量对照表中的字段填写
+
+
+
+ +
+
+
+ + Onedrive根目录/ + +
+ +
+
文件存放的目录,你可以使用目录变量对照表中的字段填写
+
+ + + +
+
+ +
+ {/case} {/switch}
diff --git a/application/index/view/admin/policy_list.html b/application/index/view/admin/policy_list.html index 9ad84000..f02c990d 100644 --- a/application/index/view/admin/policy_list.html +++ b/application/index/view/admin/policy_list.html @@ -45,6 +45,9 @@ + @@ -82,6 +85,7 @@ {case value="upyun"}又拍云{/case} {case value="s3"}Amazon S3{/case} {case value="remote"}远程{/case} + {case value="onedrive"}Onedrive{/case} {default /}其他 {/switch} diff --git a/application/index/view/header_admin.html b/application/index/view/header_admin.html index e6803ffc..cc0fb556 100644 --- a/application/index/view/header_admin.html +++ b/application/index/view/header_admin.html @@ -76,6 +76,12 @@ 分享 +