diff --git a/application/index/controller/RemoteDownload.php b/application/index/controller/RemoteDownload.php index 8046c9f3..6bbe1222 100644 --- a/application/index/controller/RemoteDownload.php +++ b/application/index/controller/RemoteDownload.php @@ -47,7 +47,7 @@ class RemoteDownload extends Controller{ public function addUrl(){ $policyData = Db::name("policy")->where("id",$this->userObj->groupData["policy_name"])->find(); - if(!$this->checkPerimission(0) || $policyData["policy_type"] != "local"){ + if(!$this->checkPerimission(0) || ($policyData["policy_type"] != "local" && $policyData["policy_type"] != "onedrive")){ return json(["result"=>['success'=>false,'error'=>"您当前的无用户无法执行此操作"]]); } $aria2Options = Option::getValues(["aria2"]); diff --git a/application/index/model/AdminHandler.php b/application/index/model/AdminHandler.php index 91470f70..730a75ce 100644 --- a/application/index/model/AdminHandler.php +++ b/application/index/model/AdminHandler.php @@ -756,35 +756,5 @@ class AdminHandler extends Model{ ]); } - public function oneDriveTest(){ - $policyId =1; - $policyData = Db::name("policy")->where("id",$policyId)->find(); - - $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"]), - ]); - $onedrive->renewAccessToken($policyData["ak"]); - Db::name("policy")->where("id",$policyId)->update([ - "sk" => json_encode($onedrive->getState()), - ]); - // $file = fopen("C:/Users/i/Downloads/Video/test.mp4","r"); - // $onedrive->createFile(urlencode("Git提交代码简教程.txt"),"/me/drive/root:/sdfdsf",$file); - //$uploadUrl = $onedrive->apiPost("/me/drive/root:/test.m4a:/createUploadSession",[])->uploadUrl; - //echo $uploadUrl; - // $file = fopen("F:/qampp/htdocs/public/uploads/chunks/oDAjV3vT.chunk","r"); - // $chunksize = filesize("F:/qampp/htdocs/public/uploads/chunks/oDAjV3vT.chunk"); - // $headers[] = "Content-Length: ".$chunksize; - // $headers[] = "Content-Range: bytes 8388608-".(8388608+$chunksize-1)."/11628372"; - // var_dump($headers); - // var_dump($onedrive->sendFileChunk("https://cquedu-my.sharepoint.com/personal/abslant_cquedu_onmicrosoft_com/_api/v2.0/drive/items/013RFVFIF6Y2GOVW7725BZO354PWSELRRZ/uploadSession?guid='0fa969a7-72d6-411f-9538-fc456913ff34'&path='~tmp41_test.m4a'&overwrite=True&rename=False&dc=0&tempauth=eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJhdWQiOiIwMDAwMDAwMy0wMDAwLTBmZjEtY2UwMC0wMDAwMDAwMDAwMDAvY3F1ZWR1LW15LnNoYXJlcG9pbnQuY29tQGQwZDgxY2Q1LTgwNjUtNDYwNS1hODg2LTFjODllN2UwNzc4ZSIsImlzcyI6IjAwMDAwMDAzLTAwMDAtMGZmMS1jZTAwLTAwMDAwMDAwMDAwMCIsIm5iZiI6IjE1MzYyMjM4NDYiLCJleHAiOiIxNTM2MzEwMjQ2IiwiZW5kcG9pbnR1cmwiOiJ6Q1psKy9nVTJwdVErbFd3Q29hM0dlOEMxMzgxNjJFcVJ5ZVdkNzFKUE40PSIsImVuZHBvaW50dXJsTGVuZ3RoIjoiMjQzIiwiaXNsb29wYmFjayI6IlRydWUiLCJjaWQiOiJOalppWlRVeE9UQXRNVGM1T1MwME0yVmtMV0U0T1RJdFpqZzFZbUpoT0RSbU9HRmwiLCJ2ZXIiOiJoYXNoZWRwcm9vZnRva2VuIiwic2l0ZWlkIjoiWXpVNE1UTTNOekF0WlRZNE1pMDBNVE14TFdFME5UVXRaVE5rWldVM1ptWmxPR1JrIiwiYXBwX2Rpc3BsYXluYW1lIjoiQ2xvdWRyZXZlRGV2IiwiYXBwaWQiOiJjNWM0Zjk3ZC1mOWIwLTQzNjAtOWEzZS0xM2JiM2MyNzZkYWEiLCJ0aWQiOiJkMGQ4MWNkNS04MDY1LTQ2MDUtYTg4Ni0xYzg5ZTdlMDc3OGUiLCJ1cG4iOiJhYnNsYW50QGNxdWVkdS5vbm1pY3Jvc29mdC5jb20iLCJwdWlkIjoiMTAwMzdGRkVBRDdGRjJDMyIsInNjcCI6ImFsbGZpbGVzLndyaXRlIiwidHQiOiIyIiwidXNlUGVyc2lzdGVudENvb2tpZSI6bnVsbH0.aWh2N2szZE4rRDhXdUp3Vm9GWnlUcHczMzhaWXJrY1diVklyRWtzTlhTOD0",$headers,$file)); - // fclose($file); - } - - } ?> \ No newline at end of file diff --git a/application/index/model/Aria2.php b/application/index/model/Aria2.php index 1340b9a1..0f007ae6 100644 --- a/application/index/model/Aria2.php +++ b/application/index/model/Aria2.php @@ -24,6 +24,12 @@ class Aria2 extends Model{ $this->savePath = rtrim(rtrim($options["aria2_tmppath"],"/"),"\\").DS; } + /** + * 新建普通URL下载任务 + * + * @param string $url + * @return void + */ public function addUrl($url){ $this->pathId = uniqid(); $reqFileds = [ @@ -46,6 +52,12 @@ class Aria2 extends Model{ } } + /** + * 新建种子下载任务 + * + * @param string $torrentUrl 种子URL + * @return void + */ public function addTorrent($torrentUrl){ $this->pathId = uniqid(); $reqFileds = [ @@ -68,6 +80,14 @@ class Aria2 extends Model{ } } + /** + * 刷新下载状态 + * + * @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)){ @@ -159,6 +179,13 @@ class Aria2 extends Model{ 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"])){ @@ -168,6 +195,12 @@ class Aria2 extends Model{ } } + /** + * 移除整个目录 + * + * @param string $dir + * @return void + */ static function remove_directory($dir){ if($handle=opendir("$dir")){ while(false!==($item=readdir($handle))){ @@ -184,6 +217,13 @@ class Aria2 extends Model{ } } + /** + * 将单文件任务升级至多文件任务 + * + * @param array $quenInfo + * @param array $sqlData + * @return void + */ private function updateToMuiltpe($quenInfo,$sqlData){ foreach ($quenInfo["files"] as $key => $value) { Db::name("download")->insert([ @@ -203,8 +243,16 @@ class Aria2 extends Model{ 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"){ + if($this->policy["policy_type"] != "local" && $this->policy["policy_type"] != "onedrive"){ $this->setError($quenInfo,$sqlData,"您当前的上传策略无法使用离线下载"); return false; } @@ -230,27 +278,64 @@ class Aria2 extends Model{ $fileName = basename($quenInfo["files"][$sqlData["file_index"]]["path"]); } $generatePath = $uploadHandller->getDirName($this->policy['dirrule']); - $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; + + 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); @@ -266,6 +351,13 @@ class Aria2 extends Model{ ]); } + /** + * 移除任务 + * + * @param int $gid + * @param array $sqlData + * @return void + */ public function Remove($gid,$sqlData){ $reqFileds = [ "params" => ["token:".$this->authToken,$gid], @@ -281,6 +373,13 @@ class Aria2 extends Model{ return false; } + /** + * 删除下载结果 + * + * @param int $gid + * @param array $sqlData + * @return void + */ public function removeDownloadResult($gid,$sqlData){ $reqFileds = [ "params" => ["token:".$this->authToken,$gid], @@ -296,6 +395,12 @@ class Aria2 extends Model{ return false; } + /** + * 强制移除任务 + * + * @param int $gid + * @return void + */ public function forceRemove($gid){ $reqFileds = [ "params" => ["token:".$this->authToken,$gid], @@ -311,6 +416,13 @@ class Aria2 extends Model{ return false; } + /** + * 检查容量 + * + * @param array $quenInfo + * @param array $sqlData + * @return void + */ private function storageCheck($quenInfo,$sqlData){ if(!FileManage::sotrageCheck($this->uid,$quenInfo["totalLength"])){ return false; @@ -321,6 +433,12 @@ class Aria2 extends Model{ return true; } + /** + * 发送请求 + * + * @param string $data + * @return array + */ private function sendReq($data){ $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $this->apiUrl."jsonrpc"); diff --git a/application/index/model/CronHandler.php b/application/index/model/CronHandler.php index 64263a46..5f7233ce 100644 --- a/application/index/model/CronHandler.php +++ b/application/index/model/CronHandler.php @@ -46,6 +46,11 @@ class CronHandler extends Model{ $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; @@ -91,5 +96,26 @@ class CronHandler extends Model{ $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"]), + ]); + $onedrive->renewAccessToken($value["ak"]); + 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/Task.php b/application/index/model/Task.php index 20413bad..9aa04561 100644 --- a/application/index/model/Task.php +++ b/application/index/model/Task.php @@ -58,17 +58,114 @@ class Task extends Model{ 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->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 + * 上传已分片的大文件至Onedrive * * @return void */ @@ -162,7 +259,7 @@ class Task extends Model{ 'state' => json_decode($policyData["sk"]), ]); - $filePath = ROOT_PATH . 'public/uploads/'.$this->taskContent["savePath"] . "/" . $this->taskContent["objname"]; + $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); @@ -202,7 +299,12 @@ class Task extends Model{ * @return bool 是否成功 */ private function cleanTmpFile(){ - return @unlink(ROOT_PATH . 'public/uploads/'.$this->taskContent["savePath"] . "/" . $this->taskContent["objname"]); + if($this->taskModel["type"] == "UploadRegularRemoteDownloadFileToOnedrive"){ + return @unlink($this->taskContent["originPath"]); + }else{ + return @unlink(ROOT_PATH . 'public/uploads/'.$this->taskContent["savePath"] . "/" . $this->taskContent["objname"]); + } + } /** @@ -211,8 +313,12 @@ class Task extends Model{ * @return void */ private function cleanTmpChunk(){ - foreach ($this->taskContent["chunks"] as $key => $value) { - @unlink( ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk"); + 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"); + } } } diff --git a/application/index/view/member/login.html b/application/index/view/member/login.html index 193afd30..467c7dd1 100644 --- a/application/index/view/member/login.html +++ b/application/index/view/member/login.html @@ -57,7 +57,7 @@ {else/} {/eq} - +