commit
49f3fa3a88
75 changed files with 7179 additions and 828 deletions
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
473
CloudreveInstaller/index.php
Normal file
473
CloudreveInstaller/index.php
Normal file
|
@ -0,0 +1,473 @@
|
|||
<?php
|
||||
if(file_exists('../application/database.php')){
|
||||
echo "application/database.php 已存在,请备份并删除后再试";
|
||||
exit();
|
||||
}
|
||||
if(isset($_POST["mysqlServer"])){
|
||||
error_reporting(0);
|
||||
header('Content-Type:application/json; charset=utf-8');
|
||||
if(!file_exists('../mysql.sql')){
|
||||
echo json_encode(["error"=>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 = '<span style="color: #009688;"><i class="fa fa-check-circle" aria-hidden="true"></i> 满足</span>';
|
||||
$error = '<span style="color: #F44336;"><i class="fa fa-times-circle" aria-hidden="true"></i> 不满足</span>';
|
||||
|
||||
$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;
|
||||
?>
|
||||
<html lang="zh-cn" data-ng-app="FileManagerApp">
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
|
||||
<meta charset="utf-8">
|
||||
<meta name="theme-color" content="#4e64d9"/>
|
||||
<title>安装向导- Cloudreve</title>
|
||||
<!-- third party -->
|
||||
<script src="/static/js/jquery.min.js"></script>
|
||||
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="/static/css/material.css" />
|
||||
<script src="/static/js/material.js"></script>
|
||||
<script src="/static/js/bootstrap.min.js"></script>
|
||||
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
|
||||
<!-- /third party -->
|
||||
<!-- Comment if you need to use raw source code -->
|
||||
<link href="/static/css/toastr.min.css" rel="stylesheet">
|
||||
<script type="text/javascript" src="/static/js/toastr.min.js"></script>
|
||||
<!-- /Comment if you need to use raw source code -->
|
||||
|
||||
</head>
|
||||
<body data-ma-header="teal">
|
||||
<nav class="navbar navbar-inverse" style="background-color: rgb(78, 100, 217);">
|
||||
<div class="container-fluid">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<div>
|
||||
<a class="navbar-brand waves-light waves-effect waves-block" href="/">
|
||||
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
|
||||
|
||||
</div><!-- /.navbar-collapse -->
|
||||
</div><!-- /.container-fluid -->
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container" id="enviromentCheck">
|
||||
<h1>环境检查</h1><br>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">基本环境</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-hover ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>项目</th>
|
||||
<th width="50%">说明</th>
|
||||
<th>必要性</th>
|
||||
<th>当前</th>
|
||||
<th>状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr <?php echo $phpVersionCheck?"":"class='danger'"; ?>>
|
||||
<td >1</td>
|
||||
<td>PHP版本 >= 5.6</td>
|
||||
<td>满足Cloudreve基本需求的最低PHP版本为5.6</td>
|
||||
<td>必须</td>
|
||||
<td><?php echo phpversion(); ?></td>
|
||||
<td><?php echo $phpVersionCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr id="rewriteCheck">
|
||||
<td >2</td>
|
||||
<td>URL Rewrite</td>
|
||||
<td>服务器需正确配置URL重写规则(伪静态),否则各个页面将会返回404错误</td>
|
||||
<td>必须</td>
|
||||
<td id="rewriteStatus"></td>
|
||||
<td>
|
||||
<span id="rewriteSuccess" style="display:none"><?php echo $success?></span>
|
||||
<span id="rewriteError" style="display:none"><?php echo $error?></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">读写权限</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-hover ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>目录</th>
|
||||
<th width="50%">说明</th>
|
||||
<th>必要性</th>
|
||||
<th>状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr <?php echo $runtimeDirCheck?"":"class='danger'"; ?>>
|
||||
<td >1</td>
|
||||
<td>runtime 可读写</td>
|
||||
<td>runtime用于存放系统工作产生的临时文件、日志、缓存等数据</td>
|
||||
<td>必须</td>
|
||||
<td><?php echo $runtimeDirCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr <?php echo $applicationDirCheck?"":"class='danger'"; ?>>
|
||||
<td >2</td>
|
||||
<td>application 可读写</td>
|
||||
<td>application用于安装程序写入数据库配置文件,仅安装时需要写入权限</td>
|
||||
<td>必须(临时)</td>
|
||||
<td><?php echo $applicationDirCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr <?php echo $publicAvatarsDirCheck?"":"class='danger'"; ?>>
|
||||
<td >3</td>
|
||||
<td>public/avatars 可读写</td>
|
||||
<td>用于存放用户头像</td>
|
||||
<td>必须</td>
|
||||
<td><?php echo $publicAvatarsDirCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr <?php echo $publicUploadsDirCheck?"":"class='warning'"; ?>>
|
||||
<td >4</td>
|
||||
<td>public/uploads 可读写</td>
|
||||
<td>用于存放本地策略上传的文件数据</td>
|
||||
<td>可选</td>
|
||||
<td><?php echo $publicUploadsDirCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr <?php echo $publicUploadsChunksDirCheck?"":"class='warning'"; ?>>
|
||||
<td >5</td>
|
||||
<td>public/uploads/chunks 可读写</td>
|
||||
<td>用于存放本地策略上传文件的临时分片数据</td>
|
||||
<td>可选</td>
|
||||
<td><?php echo $publicUploadsChunksDirCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr <?php echo $publicDownloadsDirCheck?"":"class='warning'"; ?>>
|
||||
<td >6</td>
|
||||
<td>public/downloads 可读写</td>
|
||||
<td>用于存放离线下载的文件数据</td>
|
||||
<td>可选</td>
|
||||
<td><?php echo $publicDownloadsDirCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">PHP扩展</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-hover ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>扩展名</th>
|
||||
<th width="50%">说明</th>
|
||||
<th>必要性</th>
|
||||
<th>状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr <?php echo $curlCheck?"":"class='danger'"; ?>>
|
||||
<td >1</td>
|
||||
<td>curl</td>
|
||||
<td>发送网络请求</td>
|
||||
<td>必须</td>
|
||||
<td><?php echo $curlCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
|
||||
<tr <?php echo $pdoCheck?"":"class='danger'"; ?>>
|
||||
<td >2</td>
|
||||
<td>pdo</td>
|
||||
<td>数据库操作</td>
|
||||
<td>必须</td>
|
||||
<td><?php echo $pdoCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr <?php echo $fileinfoCheck?"":"class='warnging'"; ?>>
|
||||
<td >3</td>
|
||||
<td>fileinfo</td>
|
||||
<td>用于处理本地策略图像文件预览、用户头像展示</td>
|
||||
<td>推荐</td>
|
||||
<td><?php echo $fileinfoCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr <?php echo $gdCheck?"":"class='warnging'"; ?>>
|
||||
<td >4</td>
|
||||
<td>gd</td>
|
||||
<td>用于生成验证码</td>
|
||||
<td>推荐</td>
|
||||
<td><?php echo $gdCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">依赖库</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-hover ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>库名</th>
|
||||
<th width="50%">说明</th>
|
||||
<th>必要性</th>
|
||||
<th>状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr <?php echo $thinkCaptchaCheck?"":"class=''"; ?>>
|
||||
<td >1</td>
|
||||
<td>think-captcha</td>
|
||||
<td>生成验证码图像</td>
|
||||
<td>可选</td>
|
||||
<td><?php echo $thinkCaptchaCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
|
||||
<tr <?php echo $ossCheck?"":"class=''"; ?>>
|
||||
<td >2</td>
|
||||
<td>oss-sdk-php</td>
|
||||
<td>阿里云OSS上传策略需要使用</td>
|
||||
<td>可选</td>
|
||||
<td><?php echo $ossCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr <?php echo $davCheck?"":"class=''"; ?>>
|
||||
<td >3</td>
|
||||
<td>dav</td>
|
||||
<td>WebDAV功能需要使用</td>
|
||||
<td>可选</td>
|
||||
<td><?php echo $davCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr <?php echo $upyunCheck?"":"class=''"; ?>>
|
||||
<td >4</td>
|
||||
<td>upyun/sdk</td>
|
||||
<td>又拍云上传策略需要使用</td>
|
||||
<td>可选</td>
|
||||
<td><?php echo $upyunCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr <?php echo $googleauthenticatorCheck?"":"class=''"; ?>>
|
||||
<td >5</td>
|
||||
<td>googleauthenticator</td>
|
||||
<td>二步验证</td>
|
||||
<td>可选</td>
|
||||
<td><?php echo $googleauthenticatorCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
<tr <?php echo $qrcodeCheck?"":"class=''"; ?>>
|
||||
<td >5</td>
|
||||
<td>endroid/qrcode</td>
|
||||
<td>用于生成二步验证的二维码</td>
|
||||
<td>可选</td>
|
||||
<td><?php echo $qrcodeCheck?$success:$error; ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div style="text-align:right;"><button class="btn btn-lg btn-primary btn-raised" id="doInstall"><?php echo $isOk?"下一步":"忽略问题,继续下一步"; ?></button></div>
|
||||
</div>
|
||||
<div class="container" id="installSuccess" style="display:none">
|
||||
<div class="jumbotron">
|
||||
<h2>安装完成</h2>
|
||||
<p>您的Cloudreve站点初始管理员信息如下,请登陆后修改默认密码和邮箱。</p>
|
||||
<div class="form-group">
|
||||
<label for="adminUrl" class="col-md-2 control-label">管理后台地址</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control" id="adminUrl" name="adminUrl" value="<?php $url='http://'.$_SERVER['SERVER_NAME'].$_SERVER["REQUEST_URI"];
|
||||
$mulu= dirname($url);
|
||||
echo $mulu."/Admin";
|
||||
?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="admin" class="col-md-2 control-label">管理员账号</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control" id="admin" name="admin" value="admin@cloudreve.org">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="adminPwd" class="col-md-2 control-label">管理员密码</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control" id="adminPwd" name="adminPwd" value="admin">
|
||||
</div>
|
||||
</div>
|
||||
<br><br><br><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" id="installForm" style="display:none">
|
||||
<div class="jumbotron">
|
||||
<h2>信息填写</h2>
|
||||
<form id="setUpInfo">
|
||||
<div class="form-group">
|
||||
<label for="siteUrl" class="col-md-2 control-label">站点URL</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control" id="siteUrl" name="siteUrl" placeholder="结尾需要加 / " value="<?php $url='http://'.$_SERVER['SERVER_NAME'].$_SERVER["REQUEST_URI"];
|
||||
$mulu= dirname($url);
|
||||
echo $mulu."/";
|
||||
?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="mysqlServer" class="col-md-2 control-label">MySQL服务器</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control" id="mysqlServer" name="mysqlServer" value="localhost">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mysqlPort" class="col-md-2 control-label">MySQL端口</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<input type="number" class="form-control" id="mysqlPort" name="mysqlPort" value="3306">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mysqlUser" class="col-md-2 control-label">MySQL用户名</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control" id="mysqlUser" name="mysqlUser" value="root">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mysqlPwd" class="col-md-2 control-label">MySQL密码</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<input type="password" class="form-control" id="mysqlPwd" name="mysqlPwd">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mysqlDb" class="col-md-2 control-label">数据库名</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control" id="mysqlDb" name="mysqlDb" >
|
||||
</div>
|
||||
</div><br>
|
||||
<div style="text-align:right;"><button type="button" class="btn btn-lg btn-primary btn-raised" id="startInstall">开始安装</button></div>
|
||||
</div>
|
||||
<br><br><br><br>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$.material.init();
|
||||
$.get("/Member", function(result){
|
||||
$("#rewriteStatus").html("正常");
|
||||
$("#rewriteSuccess").show();
|
||||
}).error(function(){
|
||||
$("#rewriteStatus").html("异常");
|
||||
$("#rewriteError").show();
|
||||
$("#rewriteCheck").addClass("danger");
|
||||
});
|
||||
$("#doInstall").click(function(){
|
||||
$("#enviromentCheck").fadeOut();
|
||||
$("#installForm").fadeIn();
|
||||
})
|
||||
$("#startInstall").click(function(){
|
||||
$.post("index.php",$("#setUpInfo").serialize(),function(data){
|
||||
console.log(data);
|
||||
if(data.error == true){
|
||||
toastr["error"](data.msg);
|
||||
}else{
|
||||
$("#installForm").fadeOut();
|
||||
$("#installSuccess").fadeIn();
|
||||
}
|
||||
}).error(function(){
|
||||
toastr["error"]("安装出现未知错误");
|
||||
})
|
||||
})
|
||||
</script>
|
15
README.md
15
README.md
|
@ -6,7 +6,7 @@ Cloudreve - Make the cloud easy for everyone
|
|||
[](https://packagist.org/packages/hfo4/cloudreve)
|
||||
[](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
|
||||
================================================
|
||||
|
|
|
@ -9,4 +9,6 @@
|
|||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [];
|
||||
return [
|
||||
'app\index\command\Task',
|
||||
];
|
||||
|
|
|
@ -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
|
||||
|
|
53
application/index/command/Task.php
Normal file
53
application/index/command/Task.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
namespace app\index\command;
|
||||
|
||||
use think\Db;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
|
||||
class Task extends Command
|
||||
{
|
||||
|
||||
const SLEEP_TIME = 1;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->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"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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']),
|
||||
|
|
|
@ -19,7 +19,7 @@ class Member extends Controller{
|
|||
* @return [type] [description]
|
||||
*/
|
||||
public function index(){
|
||||
echo "hello";
|
||||
echo "Pong";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
39
application/index/controller/Queue.php
Normal file
39
application/index/controller/Queue.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use think\Db;
|
||||
use think\Request;
|
||||
|
||||
use \app\index\model\Option;
|
||||
|
||||
class Queue extends Controller{
|
||||
|
||||
public function __construct(\think\Request $request = null){
|
||||
$token = Option::getValue("task_queue_token");
|
||||
if(Request::instance()->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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
179
application/index/controller/RemoteDownload.php
Normal file
179
application/index/controller/RemoteDownload.php
Normal file
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\User;
|
||||
use \app\index\model\Aria2;
|
||||
use think\Session;
|
||||
|
||||
|
||||
class RemoteDownload extends Controller{
|
||||
|
||||
public $userObj;
|
||||
|
||||
public function _initialize(){
|
||||
$this->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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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"){
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 "<script>location.href='".$url."'</script>正在跳转至Onedrive账号授权页面,如果没有跳转,请<a href='$url'>点击这里</a>。";
|
||||
|
||||
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 "<script>location.href='/Admin/PolicyList?page=1'</script>";
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
459
application/index/model/Aria2.php
Normal file
459
application/index/model/Aria2.php
Normal file
|
@ -0,0 +1,459 @@
|
|||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
class Aria2 extends Model{
|
||||
|
||||
private $authToken;
|
||||
private $apiUrl;
|
||||
private $savePath;
|
||||
private $saveOptions;
|
||||
public $reqStatus;
|
||||
public $reqMsg;
|
||||
public $pathId;
|
||||
public $pid;
|
||||
private $uid;
|
||||
private $policy;
|
||||
|
||||
public function __construct($options){
|
||||
$this->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);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
|
@ -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);
|
||||
|
|
|
@ -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<br>");
|
||||
$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<br>");
|
||||
$this->setComplete("flush_onedrive_token");
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
|
@ -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;
|
||||
|
|
File diff suppressed because it is too large
Load diff
392
application/index/model/LocalAdapter.php
Normal file
392
application/index/model/LocalAdapter.php
Normal file
|
@ -0,0 +1,392 @@
|
|||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
use \app\index\model\Option;
|
||||
|
||||
/**
|
||||
* 本地策略文件管理适配器
|
||||
*/
|
||||
class LocalAdapter extends Model{
|
||||
|
||||
private $fileModel;
|
||||
private $policyModel;
|
||||
private $userModel;
|
||||
|
||||
public function __construct($file,$policy,$user){
|
||||
$this->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];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -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;
|
||||
|
|
140
application/index/model/OnedriveAdapter.php
Normal file
140
application/index/model/OnedriveAdapter.php
Normal file
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
use \Krizalys\Onedrive\Client;
|
||||
|
||||
use \app\index\model\Option;
|
||||
|
||||
/**
|
||||
* Onedrive策略文件管理适配器
|
||||
*/
|
||||
class OnedriveAdapter extends Model{
|
||||
|
||||
private $fileModel;
|
||||
private $policyModel;
|
||||
private $userModel;
|
||||
private $clinet;
|
||||
|
||||
public function __construct($file,$policy,$user){
|
||||
$this->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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
199
application/index/model/OssAdapter.php
Normal file
199
application/index/model/OssAdapter.php
Normal file
|
@ -0,0 +1,199 @@
|
|||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
use OSS\OssClient;
|
||||
use OSS\Core\OssException;
|
||||
|
||||
use \app\index\model\Option;
|
||||
|
||||
/**
|
||||
* 阿里云OSS策略文件管理适配器
|
||||
*/
|
||||
class OssAdapter extends Model{
|
||||
|
||||
private $fileModel;
|
||||
private $policyModel;
|
||||
private $userModel;
|
||||
|
||||
public function __construct($file,$policy,$user){
|
||||
$this->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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
149
application/index/model/QiniuAdapter.php
Normal file
149
application/index/model/QiniuAdapter.php
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
require_once 'extend/Qiniu/functions.php';
|
||||
use Qiniu\Auth;
|
||||
|
||||
use \app\index\model\Option;
|
||||
|
||||
/**
|
||||
* 七牛策略文件管理适配器
|
||||
*/
|
||||
class QiniuAdapter extends Model{
|
||||
|
||||
private $fileModel;
|
||||
private $policyModel;
|
||||
private $userModel;
|
||||
|
||||
public function __construct($file,$policy,$user){
|
||||
$this->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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
97
application/index/model/RemoteAdapter.php
Normal file
97
application/index/model/RemoteAdapter.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
use \app\index\model\Option;
|
||||
|
||||
/**
|
||||
* 远程策略文件管理适配器
|
||||
*/
|
||||
class RemoteAdapter extends Model{
|
||||
|
||||
private $fileModel;
|
||||
private $policyModel;
|
||||
private $userModel;
|
||||
|
||||
public function __construct($file,$policy,$user){
|
||||
$this->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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
109
application/index/model/S3Adapter.php
Normal file
109
application/index/model/S3Adapter.php
Normal file
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
use Upyun\Upyun;
|
||||
use Upyun\Config;
|
||||
|
||||
use \app\index\model\Option;
|
||||
|
||||
/**
|
||||
* AWS S3策略文件管理适配器
|
||||
*/
|
||||
class S3Adapter extends Model{
|
||||
|
||||
private $fileModel;
|
||||
private $policyModel;
|
||||
private $userModel;
|
||||
|
||||
public function __construct($file,$policy,$user){
|
||||
$this->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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -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,"会话过期,请刷新页面"];
|
||||
|
|
355
application/index/model/Task.php
Normal file
355
application/index/model/Task.php
Normal file
|
@ -0,0 +1,355 @@
|
|||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\FileManage;
|
||||
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
|
||||
use \Krizalys\Onedrive\Client;
|
||||
use Sabre\DAV\Mock\File;
|
||||
|
||||
class Task extends Model{
|
||||
|
||||
public $taskModel;
|
||||
public $taskName;
|
||||
public $taskType;
|
||||
public $taskContent;
|
||||
public $input;
|
||||
public $output;
|
||||
public $userId;
|
||||
|
||||
public $status = "success";
|
||||
public $errorMsg;
|
||||
public $policyModel;
|
||||
|
||||
|
||||
public function __construct($id=null){
|
||||
if($id!==null){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存任务至数据库
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function saveTask(){
|
||||
Db::name("task")->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"]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -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;
|
||||
|
|
162
application/index/model/UpyunAdapter.php
Normal file
162
application/index/model/UpyunAdapter.php
Normal file
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
use Upyun\Upyun;
|
||||
use Upyun\Config;
|
||||
|
||||
use \app\index\model\Option;
|
||||
|
||||
/**
|
||||
* 又拍云策略文件管理适配器
|
||||
*/
|
||||
class UpyunAdapter extends Model{
|
||||
|
||||
private $fileModel;
|
||||
private $policyModel;
|
||||
private $userModel;
|
||||
|
||||
public function __construct($file,$policy,$user){
|
||||
$this->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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -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');
|
||||
|
|
|
@ -113,6 +113,18 @@
|
|||
<div class="col-md-4 option-des"> 是否允许用户使用WebDAV协议同步文件。目前此功能仅支持本地上传方案</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">离线下载</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input class="" type="radio" name="aria2" value="1" id="webdav1" >
|
||||
<label class="" for="webdav1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="aria2" id="webdav0" value="0" checked>
|
||||
<label class="" for="webdav0">禁止</label></div>
|
||||
<div class="col-md-4 option-des"> 是否允许用户使用离线下载。此功能仅支持本地存储策略,开启前需要到离线下载管理页面设置Aria2接口</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">用户组标志色</label>
|
||||
|
|
|
@ -82,6 +82,16 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 mt-2 md-2">
|
||||
<div class="card cloud">
|
||||
<img class="card-img-top" src="/static/img/onedrive.png" alt="Card image cap">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Onedrive <span class="badge badge-warning">中转</span></h5>
|
||||
<p class="card-text">支持 Onedrive Bussiness 和个人版。<a href="https://github.com/HFO4/Cloudreve/wiki/Onedrive%E5%AF%B9%E6%8E%A5%E8%AF%B4%E6%98%8E">配置说明</a></p>
|
||||
<a href="/Admin/PolicyAddOnedrive" class="btn btn-primary">添加</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
155
application/index/view/admin/add_policy_onedrive.html
Normal file
155
application/index/view/admin/add_policy_onedrive.html
Normal file
|
@ -0,0 +1,155 @@
|
|||
{extend name="header_admin" /}
|
||||
{block name="title"}添加上传策略- {$options.siteName}{/block}
|
||||
{block name="content"}
|
||||
<div class="content-wrapper">
|
||||
<div class="container-fluid">
|
||||
<!-- Breadcrumbs-->
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="/Admin">管理面板</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="/Admin/PolicyAdd">上传策略</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active">添加</li>
|
||||
</ol>
|
||||
|
||||
<!-- Area Chart Example-->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2>添加上传策略</h2>
|
||||
<br>
|
||||
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<strong>添加Onedrive上传策略前请确保阅读完下面内容!</strong>
|
||||
<ul>
|
||||
<li>Onedrive策略无法直传,上传文件时,Cloudreve会先将文件暂存在服务器,之后再由任务队列上传至Onedrive;</li>
|
||||
<li>使用本策略前,请先配置并运行<a href="https://github.com/HFO4/Cloudreve/wiki/Onedrive%E5%AF%B9%E6%8E%A5%E8%AF%B4%E6%98%8E">Cloudreve任务队列</a>,否则正常无法使用;</li>
|
||||
<li>用户上传文件后不能立马看到所上传的文件,需要等待任务队列处理完毕;</li>
|
||||
<li>请确保已经正确配置好Cloudreve的Cron定时任务,以便用于刷新AccessToken信息。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card" id="s3" >
|
||||
<div class="card-header">
|
||||
添加Onedrive上传策略
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="onedrivePolicy">
|
||||
<input type="text" class="form-control" name="policy_type" value="onedrive" style="display: none">
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="policy_name" class="col-form-label col-form-label-sm">上传策略名称</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="policy_name" required></div>
|
||||
<div class="col-md-4 option-des"> 上传策略的名称,用于区别不同策略</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="bucketname" class="col-form-label col-form-label-sm">应用 ID(Client ID) </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="bucketname" required></div>
|
||||
<div class="col-md-4 option-des"> 请<a href="https://apps.dev.microsoft.com/?referrer=https%3a%2f%2fdeveloper.microsoft.com%2fzh-CN%2fgraph%2fquick-start#/quickstart/graphIO?publicClientSupport=false&appName=Cloudreve&redirectUrl={:urlencode($options.siteURL)}Admin%2FoneDriveCalllback&allowImplicitFlow=false&ru=https:%2F%2Fdeveloper.microsoft.com%2Fzh-CN%2Fgraph%2Fquick-start%3FappID%3D_appId_%26appName%3D_appName_%26redirectUrl%3D{$options.siteURL}Admin/oneDriveCalllback%26platform%3Doption-php" target="_blank">点击这里</a>获取下一步要用到的应用机密和此处的应用ID</div>
|
||||
</div>
|
||||
|
||||
<input type="text" class="form-control" name="sk" value="0" style="display: none" required>
|
||||
|
||||
<input type="text" name="bucket_private" value="1" style="display: none">
|
||||
<input type="text" name="origin_link" value="0" style="display: none">
|
||||
<input type="text" name="url" value="0" style="display: none">
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="url" class="col-form-label col-form-label-sm">应用机密(密码/公钥)</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="ak" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 同上一项一起获取</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="filetype" class="col-form-label col-form-label-sm">单文件最大大小</label>
|
||||
</div>
|
||||
<div class="col-md-4 input-group mb-3">
|
||||
<input type="number" class="form-control" name="max_size" spellcheck="false" min="0" value="10" required>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="basic-addon2">
|
||||
<select name="sizeTimes" class="selectIn">
|
||||
<option value="1">B</option>
|
||||
<option value="1024">KB</option>
|
||||
<option value="1048576" selected>MB</option>
|
||||
<option value="1073741824">GB</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 允许上传的单个文件的最大尺寸</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="filetype" class="col-form-label col-form-label-sm">文件重命名</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input class="" type="radio" name="autoname" id="autoname1" value="1" checked>
|
||||
<label class="" for="autoname1" >开启</label>
|
||||
|
||||
<input class="" type="radio" name="autoname" id="autoname2" value="0" >
|
||||
<label class="" for="autoname2">关闭</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否对存储的文件自动重命名。推荐开启,重命名不会影响用户端文件名展示,开启后可以避免文件重名</div>
|
||||
</div>
|
||||
<div class="row form-setting" id="autoname_form" >
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="url" class="col-form-label col-form-label-sm">重命名规则</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="namerule" value="{uid}_{randomkey8}_{originname}" spellcheck="false" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 你可以使用变量对照表中的字段填写</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="filetype" class="col-form-label col-form-label-sm">存储目录</label>
|
||||
</div>
|
||||
<div class="col-md-4 input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="basic-addon2">
|
||||
Onedrive根目录
|
||||
</span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="dirrule" spellcheck="false" value="{date}/{uid}" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 文件存放的目录,你可以使用目录变量对照表中的字段填写</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
</div>
|
||||
<div class="col-md-4"> <button type="submit" class="btn btn-primary" id="saveQiniu">保存并继续</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br> <br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<bn>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/add_policy.js"></script>
|
||||
{/block}
|
122
application/index/view/admin/download.html
Normal file
122
application/index/view/admin/download.html
Normal file
|
@ -0,0 +1,122 @@
|
|||
{extend name="header_admin" /}
|
||||
{block name="title"}离线下载 - {$options.siteName}{/block}
|
||||
{block name="content"}
|
||||
<div class="content-wrapper">
|
||||
<div class="container-fluid">
|
||||
<!-- Breadcrumbs-->
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="/Admin">管理面板</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active">离线下载</li>
|
||||
<li class="breadcrumb-item active">配置</li>
|
||||
</ol>
|
||||
|
||||
<!-- Area Chart Example-->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2>离线下载</h2>
|
||||
<br>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-tabs card-header-tabs">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="tab" href="#options"><i class="fa fa-cog" aria-hidden="true"></i> Aria2配置</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#list"><i class="fa fa-list" aria-hidden="true"></i> 任务列表</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="tab-content" >
|
||||
<div class="tab-pane fade show active" id="options" role="tabpanel" aria-labelledby="pills-home-tab">
|
||||
<form id="aria2Options">
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="fromName" class="col-form-label col-form-label-sm">RPC Server</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="aria2_rpcurl" value="{$optionsForSet.aria2_rpcurl}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> aria2的RPC服务器地址,请在aria2的配置文件中启用RPC服务。例如:http://127.0.0.1:6800/</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="fromName" class="col-form-label col-form-label-sm">RPC Token</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="aria2_token" value="{$optionsForSet.aria2_token}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 在配置文件中设置的RPC服务的Token</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="fromName" class="col-form-label col-form-label-sm">下载临时目录</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="aria2_tmppath" value="{$optionsForSet.aria2_tmppath}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 下载文件数据的临时存放目录,请确保PHP对该目录拥有读写权限</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="aria2_options" class="col-form-label col-form-label-sm">其他下载参数</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <textarea class="form-control" name="aria2_options" spellcheck="false">{$optionsForSet.aria2_options}</textarea></div>
|
||||
<div class="col-md-4 option-des"> aria2启动下载的其他附带参数,请以json格式书写。你可也可以将这些设置写在aria2配置文件里。可用参数请查阅<a href="https://aria2.github.io/manual/en/html/aria2c.html#options" target="_blank">官方文档</a></div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
</div>
|
||||
<div class="col-md-4"> <button type="button" class="btn btn-primary" id="saveAria2">保存设置</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br><br><br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="list" role="tabpanel" aria-labelledby="pills-profile-tab">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="textCenter">#</th>
|
||||
<th scope="col" width="50%">文件名</th>
|
||||
<th scope="col" class="textCenter">创建者</th>
|
||||
<th scope="col" class="textCenter">文件大小</th>
|
||||
<th scope="col" class="textCenter">状态</th>
|
||||
<th scope="col" class="textCenter">进度</th>
|
||||
<th scope="col" class="textCenter">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="listContent">
|
||||
{volist name='list' id='download'}
|
||||
<tr id="i-{$download.id}" data-pid="{$download.pid}">
|
||||
<th scope="row" class="textCenter">{$download.id}</th>
|
||||
<td>{:$originList[$key]['fileName']}</td>
|
||||
<td class="textCenter">{:$originList[$key]['user']["user_nick"]}</td>
|
||||
<td class="textCenter">{:countSize($download.total_size)}</td>
|
||||
<td class="textCenter">{$download.status}</td>
|
||||
<td class="textCenter">{eq name="$originList[$key]['totalLength']" value="0"}-{else/}{:floor($originList[$key]['completedLength']/$originList[$key]['totalLength']*10000)/100}%{/eq}</td>
|
||||
<td class="textCenter">{eq name="download.status" value="active"}<a href="javascript:" onclick="cancel('{$download.id}')">取消任务</a>{else/} - {/eq}</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
{$list->render()}
|
||||
</div>
|
||||
<div class="tab-pane fade" id="tools" role="tabpanel" aria-labelledby="pills-profile-tab">
|
||||
ddd
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><br>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/summernote.min.js"></script>
|
||||
<script src="/static/js/admin/summernote-zh-CN.min.js"></script>
|
||||
<script src="/static/js/admin/aria2.js"></script>
|
||||
{/block}
|
|
@ -114,6 +114,18 @@
|
|||
<div class="col-md-4 option-des"> 是否允许用户使用WebDAV协议同步文件。目前此功能仅支持本地上传方案</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">离线下载</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input class="" type="radio" name="aria2" value="1" id="webdav1" >
|
||||
<label class="" for="webdav1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="aria2" id="webdav0" value="0">
|
||||
<label class="" for="webdav0">禁止</label></div>
|
||||
<div class="col-md-4 option-des"> 是否允许用户使用离线下载。此功能仅支持本地存储策略,开启前需要到离线下载管理页面设置Aria2接口</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">用户组标志色</label>
|
||||
|
@ -162,10 +174,15 @@
|
|||
<script src="/static/js/admin/add_group.js"></script>
|
||||
<script type="text/javascript">
|
||||
$("option[value='{$group.policy_name}']").attr("selected",true);
|
||||
$("option[value='{$group.max_storage}']").attr("selected",true);
|
||||
$("option[value='{:countSize($group.max_storage,true)[1]}']").attr("selected",true);
|
||||
$("input[name='range_transfer'][value='{$group.range_transfer}']").attr("checked",true);
|
||||
$("input[name='allow_share'][value='{$group.allow_share}']").attr("checked",true);
|
||||
$("input[name='color'][value='{$group.color}']").attr("checked",true);
|
||||
$("input[name='webdav'][value='{$group.webdav}']").attr("checked",true);
|
||||
if('{$group.aria2}'=="1,1,1"){
|
||||
$("input[name='aria2'][value='1']").attr("checked",true);
|
||||
}else{
|
||||
$("input[name='aria2'][value='0']").attr("checked",true);
|
||||
}
|
||||
</script>
|
||||
{/block}
|
|
@ -928,6 +928,128 @@
|
|||
</div>
|
||||
|
||||
{/case}
|
||||
{case value="onedrive"}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<strong>添加Onedrive上传策略前请确保阅读完下面内容!</strong>
|
||||
<ul>
|
||||
<li>Onedrive策略无法直传,上传文件时,Cloudreve会先将文件暂存在服务器,之后再由任务队列上传至Onedrive;</li>
|
||||
<li>使用本策略前,请先配置并运行<a href="https://github.com/HFO4/Cloudreve/wiki/Onedrive%E5%AF%B9%E6%8E%A5%E8%AF%B4%E6%98%8E">Cloudreve任务队列</a>,否则正常无法使用;</li>
|
||||
<li>用户上传文件后不能立马看到所上传的文件,需要等待任务队列处理完毕;</li>
|
||||
<li>请确保已经正确配置好Cloudreve的Cron定时任务,以便用于刷新AccessToken信息。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card" id="s3" >
|
||||
<div class="card-header">
|
||||
添加Onedrive上传策略
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="Policy">
|
||||
<input type="text" value="{$policy.id}" name="id" style="display: none">
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="policy_name" class="col-form-label col-form-label-sm">上传策略名称</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" value="{$policy.policy_name}" name="policy_name" required></div>
|
||||
<div class="col-md-4 option-des"> 上传策略的名称,用于区别不同策略</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="bucketname" class="col-form-label col-form-label-sm">应用 ID(Client ID) </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="bucketname" value="{$policy.bucketname}" required></div>
|
||||
<div class="col-md-4 option-des"> 请<a href="https://apps.dev.microsoft.com/?referrer=https%3a%2f%2fdeveloper.microsoft.com%2fzh-CN%2fgraph%2fquick-start#/quickstart/graphIO?publicClientSupport=false&appName=Cloudreve&redirectUrl={:urlencode($options.siteURL)}Admin%2FoneDriveCalllback&allowImplicitFlow=false&ru=https:%2F%2Fdeveloper.microsoft.com%2Fzh-CN%2Fgraph%2Fquick-start%3FappID%3D_appId_%26appName%3D_appName_%26redirectUrl%3D{$options.siteURL}Admin/oneDriveCalllback%26platform%3Doption-php" target="_blank">点击这里</a>获取下一步要用到的应用机密和此处的应用ID</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="url" class="col-form-label col-form-label-sm">应用机密(密码/公钥)</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="ak" value="{$policy.ak}" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 同上一项一起获取</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="filetype" class="col-form-label col-form-label-sm">单文件最大大小</label>
|
||||
</div>
|
||||
<div class="col-md-4 input-group mb-3">
|
||||
<input type="number" class="form-control" name="max_size" spellcheck="false" min="0" value="{:countSize($policy.max_size,true)[0]}" required>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="basic-addon2">
|
||||
<select name="sizeTimes" class="selectIn" data-value="{:countSize($policy.max_size,true)[1]}">
|
||||
<option value="1">B</option>
|
||||
<option value="1024">KB</option>
|
||||
<option value="1048576" >MB</option>
|
||||
<option value="1073741824">GB</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 允许上传的单个文件的最大尺寸</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="filetype" class="col-form-label col-form-label-sm">文件重命名</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{eq name="$policy.autoname" value="1"}
|
||||
<input class="" type="radio" name="autoname" id="autoname1" value="1" checked>
|
||||
<label class="" for="autoname1" >开启</label>
|
||||
|
||||
<input class="" type="radio" name="autoname" id="autoname2" value="0" >
|
||||
<label class="" for="autoname2">关闭</label>
|
||||
{else/}
|
||||
<input class="" type="radio" name="autoname" id="autoname1" value="1" >
|
||||
<label class="" for="autoname1" >开启</label>
|
||||
|
||||
<input class="" type="radio" name="autoname" id="autoname2" value="0" checked>
|
||||
<label class="" for="autoname2" >关闭</label>
|
||||
{/eq}
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否对存储的文件自动重命名。推荐开启,重命名不会影响用户端文件名展示,开启后可以避免文件重名</div>
|
||||
</div>
|
||||
<div class="row form-setting" id="autoname_form" style=" {eq name="$policy.autoname" value="0"}display:none{/eq}">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="url" class="col-form-label col-form-label-sm">重命名规则</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="namerule" value="{$policy.namerule}" spellcheck="false" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 你可以使用<a href="javascript:void()" data-toggle="modal" data-target="#varTable">变量对照表</a>中的字段填写</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="filetype" class="col-form-label col-form-label-sm">存储目录</label>
|
||||
</div>
|
||||
<div class="col-md-4 input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="basic-addon2">
|
||||
Onedrive根目录/
|
||||
</span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="dirrule" spellcheck="false" value="{$policy.dirrule}" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 文件存放的目录,你可以使用<a href="javascript:void()" data-toggle="modal" data-target="#varTableFolder">目录变量对照表</a>中的字段填写</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
</div>
|
||||
<div class="col-md-4"> <button type="submit" class="btn btn-primary" id="saveQiniu">保存</button> <a class="btn btn-danger" href="/Admin/UpdateOnedriveToken?id={$policy.id}" id="saveQiniu">重新授权账号(请先保存)</a></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br> <br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<bn>
|
||||
</div>
|
||||
{/case}
|
||||
{/switch}
|
||||
<br>
|
||||
</div>
|
||||
|
|
|
@ -45,6 +45,9 @@
|
|||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-policy="remote">远程</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-policy="onedrive">Onedrive</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -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}
|
||||
</td>
|
||||
|
|
|
@ -76,6 +76,12 @@
|
|||
<span class="nav-link-text">分享</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="离线下载">
|
||||
<a class="nav-link" href="/Admin/RemoteDownload">
|
||||
<i class="fa fa-fw fa-cloud-download"></i>
|
||||
<span class="nav-link-text">离线下载</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="用户">
|
||||
<a class="nav-link" href="/Admin/Users" data-parent="#user">
|
||||
<i class="fa fa-fw fa-user"></i>
|
||||
|
|
81
application/index/view/home/Download.html
Normal file
81
application/index/view/home/Download.html
Normal file
|
@ -0,0 +1,81 @@
|
|||
{extend name="header_home" /}
|
||||
{block name="title"}离线下载管理- {$options.siteName}{/block}
|
||||
{block name="content"}
|
||||
<script src="/static/js/remoteDownload.js"></script>
|
||||
<style type="text/css">
|
||||
.col-md-3{
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body >
|
||||
<div id="container">
|
||||
{include file="navbar_home" /}
|
||||
|
||||
<div class="col-md-10 quota_content">
|
||||
<h1>离线下载管理</h1>
|
||||
<br>
|
||||
<div class="fix_side">
|
||||
|
||||
<div class="fix">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">正在进行中 <i class="fa fa-refresh" aria-hidden="true" title="刷新数据" onclick="refresh()"></i></div>
|
||||
<div class="panel-body centerTable" id="loadStatus">
|
||||
更新状态数据中...
|
||||
</div>
|
||||
<div class="table-responsive" style="display: none">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%" class="centerTable">#</th>
|
||||
<th width="50%" >文件名</th>
|
||||
<th class="centerTable">大小</th>
|
||||
<th class="centerTable">储存位置</th>
|
||||
<th class="centerTable">下载速度</th>
|
||||
<th class="centerTable">进度</th>
|
||||
<th class="centerTable">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="itemContent">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">已完成 </i></div>
|
||||
<div class="table-responsive" >
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%" class="centerTable">#</th>
|
||||
<th width="50%" >文件名</th>
|
||||
<th class="centerTable">大小</th>
|
||||
<th class="centerTable">储存位置</th>
|
||||
<th class="centerTable">状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="completeItemContent">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="panel-body centerTable" id="loadButton">
|
||||
<button class="btn btn-primary" id="loadFinished">点击加载已完成列表</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
</body>
|
||||
<script src="/static/js/material.js"></script>
|
||||
<script type="text/javascript">
|
||||
upload_load=0;
|
||||
</script>
|
||||
{$options.js_code}
|
||||
</html>
|
||||
{/block}
|
81
application/index/view/home/download.html
Normal file
81
application/index/view/home/download.html
Normal file
|
@ -0,0 +1,81 @@
|
|||
{extend name="header_home" /}
|
||||
{block name="title"}离线下载管理- {$options.siteName}{/block}
|
||||
{block name="content"}
|
||||
<script src="/static/js/remoteDownload.js"></script>
|
||||
<style type="text/css">
|
||||
.col-md-3{
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body >
|
||||
<div id="container">
|
||||
{include file="navbar_home" /}
|
||||
|
||||
<div class="col-md-10 quota_content">
|
||||
<h1>离线下载管理</h1>
|
||||
<br>
|
||||
<div class="fix_side">
|
||||
|
||||
<div class="fix">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">正在进行中 <i class="fa fa-refresh" aria-hidden="true" title="刷新数据" onclick="refresh()"></i></div>
|
||||
<div class="panel-body centerTable" id="loadStatus">
|
||||
更新状态数据中...
|
||||
</div>
|
||||
<div class="table-responsive" style="display: none">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%" class="centerTable">#</th>
|
||||
<th width="50%" >文件名</th>
|
||||
<th class="centerTable">大小</th>
|
||||
<th class="centerTable">储存位置</th>
|
||||
<th class="centerTable">下载速度</th>
|
||||
<th class="centerTable">进度</th>
|
||||
<th class="centerTable">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="itemContent">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">已完成 </i></div>
|
||||
<div class="table-responsive" >
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%" class="centerTable">#</th>
|
||||
<th width="50%" >文件名</th>
|
||||
<th class="centerTable">大小</th>
|
||||
<th class="centerTable">储存位置</th>
|
||||
<th class="centerTable">状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="completeItemContent">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="panel-body centerTable" id="loadButton">
|
||||
<button class="btn btn-primary" id="loadFinished">点击加载已完成列表</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
</body>
|
||||
<script src="/static/js/material.js"></script>
|
||||
<script type="text/javascript">
|
||||
upload_load=0;
|
||||
</script>
|
||||
{$options.js_code}
|
||||
</html>
|
||||
{/block}
|
|
@ -28,6 +28,8 @@
|
|||
allowSource : "{$policyData.origin_link}",
|
||||
upUrl : "{$policyData.server}",
|
||||
allowShare:"{$groupData.allow_share}",
|
||||
allowRemoteDownload:"{:explode(",",$groupData.aria2)[0]}",
|
||||
allowTorrentDownload:"{:explode(",",$groupData.aria2)[1]}",
|
||||
};
|
||||
</script>
|
||||
<script src="/static/js/home.js"></script>
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
{else/}
|
||||
{/eq}
|
||||
|
||||
</form> <button class="btn btn-raised btn-primary" id="loginButton">登录</button>
|
||||
</form> <button class="btn btn-raised btn-primary waves-light" id="loginButton">登录</button>
|
||||
<div class="link-group">
|
||||
<a href="javascript:void" class="noWave" id="create" data-change="true">创建一个账户</a><br>
|
||||
<a href="javascript:void" class="noWave" id="forgetSwitch2" data-change="true">忘记密码?</a>
|
||||
|
@ -105,7 +105,7 @@
|
|||
{else/}
|
||||
{/eq}
|
||||
|
||||
</form> <button class="btn btn-raised btn-primary" id="regButton">注册</button> <div class="link-group">
|
||||
</form> <button class="btn btn-raised btn-primary waves-light" id="regButton">注册</button> <div class="link-group">
|
||||
<a href="javascript:void" class="noWave" id="loginSwitch3" data-change="true">已有账号?立即登录</a><br>
|
||||
<a href="javascript:void" class="noWave" id="forgetSwitch" data-change="true">忘记密码?</a>
|
||||
</div>
|
||||
|
@ -163,7 +163,7 @@
|
|||
{else/}
|
||||
{/eq}
|
||||
|
||||
</form> <button class="btn btn-raised btn-primary" id="findMyFuckingPwd">找回密码</button> <div class="link-group">
|
||||
</form> <button class="btn btn-raised btn-primary waves-light" id="findMyFuckingPwd">找回密码</button> <div class="link-group">
|
||||
<a href="javascript:void" class="noWave" id="loginSwitch2" data-change="true">返回登录</a><br>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="/">
|
||||
<a class="navbar-brand waves-light" href="/">
|
||||
|
||||
</a>
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
|||
<ul class="nav navbar-nav navbar-right">
|
||||
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle avatar-a" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><img src="/Member/Avatar/{$userInfo.uid}/s" class="img-circle avatar-s"> {$userInfo.userNick} <span class="caret"></span></a>
|
||||
<a href="#" class="dropdown-toggle avatar-a waves-light" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><img src="/Member/Avatar/{$userInfo.uid}/s" class="img-circle avatar-s"> {$userInfo.userNick} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/Profile/{$userInfo.uid}">个人主页</a></li>
|
||||
<li><a href="/Member/Setting">设置</a></li>
|
||||
|
@ -63,7 +63,7 @@
|
|||
|
||||
<div id="container">
|
||||
|
||||
<button class="btn btn-raised btn-info btn-lg upload_button" id="pickfiles" >
|
||||
<button class="btn btn-raised btn-info btn-lg upload_button waves-light" id="pickfiles" >
|
||||
<i class="glyphicon glyphicon-plus"></i>
|
||||
<span id="up_text"></span>
|
||||
</button>
|
||||
|
@ -129,6 +129,11 @@
|
|||
<a href="/Home/Album" class="list-group-item">
|
||||
<i class="fa fa-picture-o" aria-hidden="true"></i> 图片集
|
||||
</a>
|
||||
{eq name=':(explode(",",$groupData.aria2)[0] OR explode(",",$groupData.aria2)[1])' value="1"}
|
||||
<a href="/Home/Download" class="list-group-item">
|
||||
<i class="fa fa-cloud-download" aria-hidden="true"></i> 离线下载
|
||||
</a>
|
||||
{/eq}
|
||||
</div>
|
||||
<div clss="usage" style=" visibility: visible;
|
||||
position: absolute;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="navbar-header">
|
||||
<div >
|
||||
<a class="navbar-brand" href="/">
|
||||
<a class="navbar-brand waves-light" href="/">
|
||||
|
||||
</a>
|
||||
</div>
|
||||
|
@ -19,7 +19,7 @@
|
|||
<ul class="nav navbar-nav navbar-right">
|
||||
{eq name="$loginStatus" value="1"}
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle avatar-a" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><img src="/Member/Avatar/{$userData.id}/s" class="img-circle avatar-s"> {$userData.user_nick} <span class="caret"></span></a>
|
||||
<a href="#" class="dropdown-toggle avatar-a waves-light" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><img src="/Member/Avatar/{$userData.id}/s" class="img-circle avatar-s"> {$userData.user_nick} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/Home">我的文件</a></li>
|
||||
<li><a href="/Profile/{$userData.id}">个人主页</a></li>
|
||||
|
@ -30,7 +30,7 @@
|
|||
</li>
|
||||
{else/}
|
||||
<li >
|
||||
<a href="/Login" class="dropdown-toggle" role="button" aria-haspopup="true" aria-expanded="false"><i class="fa fa-user mr-1"></i> 登录/注册 </a>
|
||||
<a href="/Login" class="dropdown-toggle waves-light" role="button" aria-haspopup="true" aria-expanded="false"><i class="fa fa-user mr-1"></i> 登录/注册 </a>
|
||||
|
||||
</li>
|
||||
{/eq}
|
||||
|
|
|
@ -70,34 +70,9 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="navbar navbar-inverse" >
|
||||
<div class="container-fluid">
|
||||
<div class="container" >
|
||||
{include file="navbar_public" loginStatus=$loginStatus userData=$userInfo /}
|
||||
<div class="header-panel shadow-z-2">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container main-h">
|
||||
|
||||
<div class="">
|
||||
<div class="jumbotron">
|
||||
|
||||
|
||||
<div class="card_botom">
|
||||
<div class="row bottom-width">
|
||||
|
||||
<div class="manager"><angular-filemanager></angular-filemanager>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<angular-filemanager></angular-filemanager>
|
||||
|
||||
|
||||
</body>
|
||||
<script type="text/javascript">
|
||||
shareInfo={
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"type":"","version":"1.0.3","version_id":4,"db_version":2}
|
||||
{"type":"","version":"1.1.0","version_id":5,"db_version":3}
|
1105
extend/Krizalys/Onedrive/Client.php
Normal file
1105
extend/Krizalys/Onedrive/Client.php
Normal file
File diff suppressed because it is too large
Load diff
298
extend/Krizalys/Onedrive/DriveItem.php
Normal file
298
extend/Krizalys/Onedrive/DriveItem.php
Normal file
|
@ -0,0 +1,298 @@
|
|||
<?php
|
||||
|
||||
namespace Krizalys\Onedrive;
|
||||
|
||||
/**
|
||||
* @class DriveItem
|
||||
*
|
||||
* A DriveItem instance is an entity that may be stored in a OneDrive account.
|
||||
* There are two types of drive items: file or a folder, each of which being a
|
||||
* subclass of the DriveItem class.
|
||||
*
|
||||
* Note that DriveItem instances are only "proxy" to actual OneDrive drive items
|
||||
* (eg. destroying a DriveItem instance will not delete the actual OneDrive
|
||||
* drive item it is referencing to).
|
||||
*/
|
||||
abstract class DriveItem
|
||||
{
|
||||
/**
|
||||
* @var Client The owning Client instance.
|
||||
*/
|
||||
protected $_client;
|
||||
|
||||
/**
|
||||
* @var string The unique ID assigned by OneDrive to this drive item.
|
||||
*/
|
||||
protected $_id;
|
||||
|
||||
/**
|
||||
* @var string The unique ID assigned by OneDrive to the parent folder of
|
||||
* this drive item.
|
||||
*/
|
||||
private $_parentId;
|
||||
|
||||
/**
|
||||
* @var string The name of this drive item.
|
||||
*/
|
||||
private $_name;
|
||||
|
||||
/**
|
||||
* @var string The description of this drive item.
|
||||
*/
|
||||
private $_description;
|
||||
|
||||
/**
|
||||
* @var int The size of this drive item, in bytes.
|
||||
*/
|
||||
private $_size;
|
||||
|
||||
/**
|
||||
* @var string The source link of this drive item.
|
||||
*/
|
||||
private $_source;
|
||||
|
||||
/**
|
||||
* @var int The creation time, in seconds since UNIX epoch.
|
||||
*/
|
||||
private $_createdTime;
|
||||
|
||||
/**
|
||||
* @var int The last modification time, in seconds since UNIX epoch.
|
||||
*/
|
||||
private $_updatedTime;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Client $client The Client instance owning this DriveItem
|
||||
* instance.
|
||||
* @param null|string $id The unique ID of the OneDrive drive item
|
||||
* referenced by this DriveItem instance.
|
||||
* @param array|object $options An array/object with one or more of the
|
||||
* following keys/properties:
|
||||
* - 'parent_id' (string) The unique ID of
|
||||
* the parent OneDrive folder of this drive
|
||||
* item.
|
||||
* - 'name' (string) The name of this drive
|
||||
* item.
|
||||
* - 'description' (string) The description of
|
||||
* this drive item. May be empty.
|
||||
* - 'size' (int) The size of this drive item,
|
||||
* in bytes.
|
||||
* - 'source' (string) The source link of this
|
||||
* drive item.
|
||||
* - 'created_time' (string) The creation time,
|
||||
* as a RFC date/time.
|
||||
* - 'updated_time' (string) The last
|
||||
* modification time, as a RFC date/time.
|
||||
*/
|
||||
public function __construct(Client $client, $id, $options = [])
|
||||
{
|
||||
$options = (object) $options;
|
||||
$this->_client = $client;
|
||||
$this->_id = null !== $id ? (string) $id : null;
|
||||
|
||||
$this->_parentId = property_exists($options, 'parent_id') ?
|
||||
(string) $options->parent_id : null;
|
||||
|
||||
$this->_name = property_exists($options, 'name') ?
|
||||
(string) $options->name : null;
|
||||
|
||||
$this->_description = property_exists($options, 'description') ?
|
||||
(string) $options->description : null;
|
||||
|
||||
$this->_size = property_exists($options, 'size') ?
|
||||
(int) $options->size : null;
|
||||
|
||||
$this->_source = property_exists($options, 'source') ?
|
||||
(string) $options->source : null;
|
||||
|
||||
$this->_createdTime = property_exists($options, 'created_time') ?
|
||||
strtotime($options->created_time) : null;
|
||||
|
||||
$this->_updatedTime = property_exists($options, 'updated_time') ?
|
||||
strtotime($options->updated_time) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the OneDrive drive item referenced by this DriveItem
|
||||
* instance is a folder.
|
||||
*
|
||||
* @return bool true if the OneDrive drive item referenced by this DriveItem
|
||||
* instance is a folder, false otherwise.
|
||||
*/
|
||||
public function isFolder()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the properties of the OneDrive drive item referenced by this
|
||||
* DriveItem instance. Some properties are cached for faster subsequent
|
||||
* access.
|
||||
*
|
||||
* @return array The properties of the OneDrive drive item referenced by
|
||||
* this DriveItem instance.
|
||||
*/
|
||||
public function fetchProperties()
|
||||
{
|
||||
$result = $this->_client->fetchProperties($this->_id);
|
||||
|
||||
$this->_parentId = '' != $result->parent_id ?
|
||||
(string) $result->parent_id : null;
|
||||
|
||||
$this->_name = $result->name;
|
||||
|
||||
$this->_description = '' != $result->description ?
|
||||
(string) $result->description : null;
|
||||
|
||||
$this->_size = (int) $result->size;
|
||||
|
||||
/** @todo Handle volatile existence (eg. present only for files). */
|
||||
$this->_source = (string) $result->source;
|
||||
|
||||
$this->_createdTime = strtotime($result->created_time);
|
||||
$this->_updatedTime = strtotime($result->updated_time);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique ID of the OneDrive drive item referenced by this
|
||||
* DriveItem instance.
|
||||
*
|
||||
* @return string The unique ID of the OneDrive drive item referenced by
|
||||
* this DriveItem instance.
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique ID of the parent folder of the OneDrive drive item
|
||||
* referenced by this DriveItem instance.
|
||||
*
|
||||
* @return string The unique ID of the OneDrive folder containing the drive
|
||||
* item referenced by this DriveItem instance.
|
||||
*/
|
||||
public function getParentId()
|
||||
{
|
||||
if (null === $this->_parentId) {
|
||||
$this->fetchProperties();
|
||||
}
|
||||
|
||||
return $this->_parentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the OneDrive drive item referenced by this DriveItem
|
||||
* instance.
|
||||
*
|
||||
* @return string The name of the OneDrive drive item referenced by this
|
||||
* DriveItem instance.
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
if (null === $this->_name) {
|
||||
$this->fetchProperties();
|
||||
}
|
||||
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the description of the OneDrive drive item referenced by this
|
||||
* DriveItem instance.
|
||||
*
|
||||
* @return string The description of the OneDrive drive item referenced by
|
||||
* this DriveItem instance.
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
if (null === $this->_description) {
|
||||
$this->fetchProperties();
|
||||
}
|
||||
|
||||
return $this->_description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the OneDrive drive item referenced by this DriveItem
|
||||
* instance.
|
||||
*
|
||||
* @return int The size of the OneDrive drive item referenced by this
|
||||
* DriveItem instance.
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
if (null === $this->_size) {
|
||||
$this->fetchProperties();
|
||||
}
|
||||
|
||||
return $this->_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source link of the OneDrive drive item referenced by this
|
||||
* DriveItem instance.
|
||||
*
|
||||
* @return string The source link of the OneDrive drive item referenced by
|
||||
* this DriveItem instance.
|
||||
*/
|
||||
public function getSource()
|
||||
{
|
||||
if (null === $this->_source) {
|
||||
$this->fetchProperties();
|
||||
}
|
||||
|
||||
return $this->_source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the creation time of the OneDrive drive item referenced by this
|
||||
* DriveItem instance.
|
||||
*
|
||||
* @return int The creation time of the drive item referenced by this
|
||||
* DriveItem instance, in seconds since UNIX epoch.
|
||||
*/
|
||||
public function getCreatedTime()
|
||||
{
|
||||
if (null === $this->_createdTime) {
|
||||
$this->fetchProperties();
|
||||
}
|
||||
|
||||
return $this->_createdTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last modification time of the OneDrive drive item referenced by
|
||||
* this DriveItem instance.
|
||||
*
|
||||
* @return int The last modification time of the drive item referenced by
|
||||
* this DriveItem instance, in seconds since UNIX epoch.
|
||||
*/
|
||||
public function getUpdatedTime()
|
||||
{
|
||||
if (null === $this->_updatedTime) {
|
||||
$this->fetchProperties();
|
||||
}
|
||||
|
||||
return $this->_updatedTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the OneDrive drive item referenced by this DriveItem instance into
|
||||
* another OneDrive folder.
|
||||
*
|
||||
* @param null|string $destinationId The unique ID of the OneDrive folder
|
||||
* into which to move the OneDrive drive
|
||||
* item referenced by this DriveItem
|
||||
* instance, or null to move it to the
|
||||
* OneDrive root folder. Default: null.
|
||||
*/
|
||||
public function move($destinationId = null)
|
||||
{
|
||||
$this->_client->moveObject($this->_id, $destinationId);
|
||||
}
|
||||
}
|
71
extend/Krizalys/Onedrive/File.php
Normal file
71
extend/Krizalys/Onedrive/File.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Krizalys\Onedrive;
|
||||
|
||||
/**
|
||||
* @class File
|
||||
*
|
||||
* A File instance is a DriveItem instance referencing a OneDrive file. It may
|
||||
* have content but may not contain other OneDrive drive items.
|
||||
*/
|
||||
class File extends DriveItem
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Client $client The Client instance owning this DriveItem
|
||||
* instance.
|
||||
* @param null|string $id The unique ID of the OneDrive drive item
|
||||
* referenced by this DriveItem instance.
|
||||
* @param array|object $options An array/object with one or more of the
|
||||
* following keys/properties:
|
||||
* - 'parent_id' (string) The unique ID of the
|
||||
* parent OneDrive folder of this drive item.
|
||||
* - 'name' (string) The name of this drive
|
||||
* item.
|
||||
* - 'description' (string) The description of
|
||||
* this drive item. May be empty.
|
||||
* - 'size' (int) The size of this drive item,
|
||||
* in bytes.
|
||||
* - 'created_time' (string) The creation time,
|
||||
* as a RFC date/time.
|
||||
* - 'updated_time' (string) The last
|
||||
* modification time, as a RFC date/time.
|
||||
*/
|
||||
public function __construct(Client $client, $id, $options = [])
|
||||
{
|
||||
parent::__construct($client, $id, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the content of the OneDrive file referenced by this File
|
||||
* instance.
|
||||
*
|
||||
* @param array $options Extra cURL options to apply.
|
||||
*
|
||||
* @return string The content of the OneDrive file referenced by this File
|
||||
* instance.
|
||||
*
|
||||
* @todo Should somewhat return the content-type as well; this information
|
||||
* is not disclosed by OneDrive.
|
||||
*/
|
||||
public function fetchContent($options = [])
|
||||
{
|
||||
return $this->_client->apiGet($this->_id . '/content', $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the OneDrive file referenced by this File instance into another
|
||||
* OneDrive folder.
|
||||
*
|
||||
* @param null|string $destinationId The unique ID of the OneDrive folder
|
||||
* into which to copy the OneDrive file
|
||||
* referenced by this File instance, or
|
||||
* null to copy it in the OneDrive root
|
||||
* folder. Default: null.
|
||||
*/
|
||||
public function copy($destinationId = null)
|
||||
{
|
||||
$this->_client->copyFile($this->_id, $destinationId);
|
||||
}
|
||||
}
|
143
extend/Krizalys/Onedrive/Folder.php
Normal file
143
extend/Krizalys/Onedrive/Folder.php
Normal file
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
|
||||
namespace Krizalys\Onedrive;
|
||||
|
||||
/**
|
||||
* @class Folder
|
||||
*
|
||||
* A Folder instance is a DriveItem instance referencing to a OneDrive folder.
|
||||
* It may contain other OneDrive drive items but may not have content.
|
||||
*/
|
||||
class Folder extends DriveItem
|
||||
{
|
||||
/**
|
||||
* Determines whether the OneDrive drive item referenced by this DriveItem
|
||||
* instance is a folder.
|
||||
*
|
||||
* @return bool true if the OneDrive drive item referenced by this DriveItem
|
||||
* instance is a folder, false otherwise.
|
||||
*/
|
||||
public function isFolder()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Client $client The Client instance owning this DriveItem
|
||||
* instance.
|
||||
* @param null|string $id The unique ID of the OneDrive drive item
|
||||
* referenced by this DriveItem instance, or
|
||||
* null to reference the OneDrive root folder.
|
||||
* Default: null.
|
||||
* @param array|object $options Options to pass to the DriveItem
|
||||
* constructor.
|
||||
*/
|
||||
public function __construct(Client $client, $id = null, $options = [])
|
||||
{
|
||||
parent::__construct($client, $id, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the drive items in the OneDrive folder referenced by this Folder
|
||||
* instance.
|
||||
*
|
||||
* @return array The drive items in the OneDrive folder referenced by this
|
||||
* Folder instance, as DriveItem instances.
|
||||
*
|
||||
* @deprecated Use Folder::fetchChildObjects() instead.
|
||||
*/
|
||||
public function fetchObjects()
|
||||
{
|
||||
/** @todo Log deprecation notice. */
|
||||
return $this->fetchChildObjects();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the child drive items in the OneDrive folder referenced by this
|
||||
* Folder instance.
|
||||
*
|
||||
* @return array The drive items in the OneDrive folder referenced by this
|
||||
* Folder instance, as DriveItem instances.
|
||||
*/
|
||||
public function fetchChildObjects()
|
||||
{
|
||||
return $this->_client->fetchObjects($this->_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the descendant drive items under the OneDrive folder referenced by
|
||||
* this Folder instance.
|
||||
*
|
||||
* @return array The files in the OneDrive folder referenced by this Folder
|
||||
* instance, as DriveItem instances.
|
||||
*/
|
||||
public function fetchDescendantObjects()
|
||||
{
|
||||
$driveItems = [];
|
||||
|
||||
foreach ($this->fetchChildObjects() as $driveItem) {
|
||||
if ($driveItem->isFolder()) {
|
||||
$driveItems = array_merge(
|
||||
$driveItem->fetchDescendantObjects(),
|
||||
$driveItems
|
||||
);
|
||||
} else {
|
||||
array_push($driveItems, $driveItem);
|
||||
}
|
||||
}
|
||||
|
||||
return $driveItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a folder in the OneDrive folder referenced by this Folder
|
||||
* instance.
|
||||
*
|
||||
* @param string $name The name of the OneDrive folder to be
|
||||
* created.
|
||||
* @param null|string $description The description of the OneDrive folder
|
||||
* to be created, or null to create it
|
||||
* without a description. Default: null.
|
||||
*
|
||||
* @return Folder The folder created, as a Folder instance.
|
||||
*/
|
||||
public function createFolder($name, $description = null)
|
||||
{
|
||||
return $this->_client->createFolder($name, $this->_id, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file in the OneDrive folder referenced by this Folder instance.
|
||||
*
|
||||
* @param string $name The name of the OneDrive file to be
|
||||
* created.
|
||||
* @param string|resource $content The content of the OneDrive file to be
|
||||
* created, as a string or handle to an
|
||||
* already opened file. In the latter case,
|
||||
* the responsibility to close the handle is
|
||||
* is left to the calling function. Default:
|
||||
* ''.
|
||||
* @param array $options The options.
|
||||
*
|
||||
* @return File The file created, as a File instance.
|
||||
*
|
||||
* @throws \Exception Thrown on I/O errors.
|
||||
*/
|
||||
public function createFile($name, $content = '', array $options = [])
|
||||
{
|
||||
$client = $this->_client;
|
||||
|
||||
$options = array_merge([
|
||||
'name_conflict_behavior' => $client->getNameConflictBehavior(),
|
||||
'stream_back_end' => $client->getStreamBackEnd(),
|
||||
], $options);
|
||||
|
||||
return $this->_client->createFile(
|
||||
$name, $this->_id,
|
||||
$content,
|
||||
$options
|
||||
);
|
||||
}
|
||||
}
|
17
extend/Krizalys/Onedrive/NameConflictBehavior.php
Normal file
17
extend/Krizalys/Onedrive/NameConflictBehavior.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Krizalys\Onedrive;
|
||||
|
||||
class NameConflictBehavior
|
||||
{
|
||||
// Fail behavior: fail the operation if the drive item exists.
|
||||
const FAIL = 1;
|
||||
|
||||
// Rename behavior: rename the drive item if it already exists. The drive
|
||||
// item is renamed as "<original name> 1", incrementing the trailing number
|
||||
// until an available file name is discovered.
|
||||
const RENAME = 2;
|
||||
|
||||
// Replace behavior: replace the drive item if it already exists.
|
||||
const REPLACE = 3;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Krizalys\Onedrive;
|
||||
|
||||
class NameConflictBehaviorParameterizer
|
||||
{
|
||||
/**
|
||||
* Parameterizes a given name conflict behavior.
|
||||
*
|
||||
* @param array $params The parameters.
|
||||
* @param int $nameConflictBehavior The name conflict behavior.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \Exception Thrown if the name conflict behavior given is not
|
||||
* supported.
|
||||
*/
|
||||
public function parameterize(array $params, $nameConflictBehavior)
|
||||
{
|
||||
switch ($nameConflictBehavior) {
|
||||
case NameConflictBehavior::FAIL:
|
||||
$params['overwrite'] = 'false';
|
||||
break;
|
||||
|
||||
case NameConflictBehavior::RENAME:
|
||||
$params['overwrite'] = 'ChooseNewName';
|
||||
break;
|
||||
|
||||
case NameConflictBehavior::REPLACE:
|
||||
$params['overwrite'] = 'true';
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \Exception(
|
||||
"Unsupported name conflict behavior: $nameConflictBehavior"
|
||||
);
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
}
|
13
extend/Krizalys/Onedrive/StreamBackEnd.php
Normal file
13
extend/Krizalys/Onedrive/StreamBackEnd.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Krizalys\Onedrive;
|
||||
|
||||
class StreamBackEnd
|
||||
{
|
||||
// Memory-backed stream.
|
||||
const MEMORY = 1;
|
||||
|
||||
// Temporary file-backed stream. A temporary file is actually used if the
|
||||
// stream contents exceeds 2 MiB.
|
||||
const TEMP = 2;
|
||||
}
|
30
extend/Krizalys/Onedrive/StreamOpener.php
Normal file
30
extend/Krizalys/Onedrive/StreamOpener.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Krizalys\Onedrive;
|
||||
|
||||
class StreamOpener
|
||||
{
|
||||
private static $uris = [
|
||||
StreamBackEnd::MEMORY => 'php://memory',
|
||||
StreamBackEnd::TEMP => 'php://temp',
|
||||
];
|
||||
|
||||
/**
|
||||
* Opens a stream given a stream back end.
|
||||
*
|
||||
* @param int $streamBackEnd The stream back end.
|
||||
*
|
||||
* @return bool|resource The open stream.
|
||||
*
|
||||
* @throws \Exception Thrown if the stream back end given is not supported.
|
||||
*/
|
||||
public function open($streamBackEnd)
|
||||
{
|
||||
if (!array_key_exists($streamBackEnd, self::$uris)) {
|
||||
throw new \Exception("Unsupported stream back end: $streamBackEnd");
|
||||
}
|
||||
|
||||
$uri = self::$uris[$streamBackEnd];
|
||||
return fopen($uri, 'rw+b');
|
||||
}
|
||||
}
|
64
mysql.sql
64
mysql.sql
File diff suppressed because one or more lines are too long
2
public/downloads/.gitignore
vendored
Normal file
2
public/downloads/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
2
static/css/angular-filemanager.min.css
vendored
2
static/css/angular-filemanager.min.css
vendored
|
@ -337,7 +337,7 @@ textarea.code {
|
|||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid #eee
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
|
||||
.btn-go-back {
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
static/img/onedrive.png
Normal file
BIN
static/img/onedrive.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -56,6 +56,24 @@ $("#localPolicy").submit(function() {
|
|||
});
|
||||
return false;
|
||||
})
|
||||
$("#onedrivePolicy").submit(function() {
|
||||
$("#savePolicy").attr("disabled", "true");
|
||||
$.post("/Admin/SavePolicy",
|
||||
$("#onedrivePolicy").serialize()
|
||||
, function(data) {
|
||||
if (data.error == "1") {
|
||||
toastr["warning"](data.msg);
|
||||
$("#savePolicy").removeAttr("disabled");
|
||||
} else if (data.error == "200") {
|
||||
toastr["success"]("上传策略已添加");
|
||||
location.href = "/Admin/UpdateOnedriveToken?id="+data.id;
|
||||
}else{
|
||||
toastr["warning"]("未知错误");
|
||||
$("#savePolicy").removeAttr("disabled");
|
||||
}
|
||||
});
|
||||
return false;
|
||||
})
|
||||
$("#qiniuPolicy").submit(function() {
|
||||
$("#saveQiniu").attr("disabled", "true");
|
||||
$.post("/Admin/SavePolicy",
|
||||
|
|
34
static/js/admin/aria2.js
Normal file
34
static/js/admin/aria2.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
$("#saveAria2").click(function() {
|
||||
$("#saveAria2").attr("disabled", "true");
|
||||
$.post("/Admin/SaveAria2Setting",
|
||||
$("#aria2Options").serialize()
|
||||
, function(data) {
|
||||
if (data.error == "1") {
|
||||
toastr["warning"](data.msg);
|
||||
$("#saveAria2").removeAttr("disabled");
|
||||
} else if (data.error == "200") {
|
||||
toastr["success"]("设置已保存");
|
||||
$("#saveAria2").removeAttr("disabled");
|
||||
}else{
|
||||
toastr["warning"]("未知错误");
|
||||
$("#saveAria2").removeAttr("disabled");
|
||||
}
|
||||
});
|
||||
})
|
||||
function cancel(id){
|
||||
$.post("/Admin/CancelDownload", {id:id}, function(data){
|
||||
if(data.error){
|
||||
toastr["warning"](data.message);
|
||||
}else{
|
||||
var pid = $("#i-"+id).attr("data-pid");
|
||||
$("[data-pid='"+pid+"'").remove();
|
||||
toastr["success"](data.message);
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
$(document).ready(function(){
|
||||
if(document.location.href.indexOf("page")!=-1){
|
||||
$("[href='#list']").click();
|
||||
}
|
||||
})
|
90
static/js/angular-filemanager.min.js
vendored
90
static/js/angular-filemanager.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -49,6 +49,9 @@
|
|||
changePermissions: false,
|
||||
upload: false,
|
||||
shareFile: uploadConfig.allowShare == "1" ? true : false,
|
||||
allowRemoteDownload: uploadConfig.allowRemoteDownload,
|
||||
allowTorrentDownload: uploadConfig.allowTorrentDownload,
|
||||
|
||||
}),
|
||||
});
|
||||
}]);
|
||||
|
|
|
@ -183,7 +183,7 @@ function QiniuJsSDK() {
|
|||
"https://up.qbox.me"
|
||||
]
|
||||
};
|
||||
}else if(uploadConfig.saveType == "local" || uploadConfig.saveType == "oss" ||uploadConfig.saveType == "upyun"||uploadConfig.saveType == "s3"|| uploadConfig.saveType == "remote"){
|
||||
}else if(uploadConfig.saveType == "local" || uploadConfig.saveType == "oss" ||uploadConfig.saveType == "upyun"||uploadConfig.saveType == "s3"|| uploadConfig.saveType == "remote"||uploadConfig.saveType == "onedrive"){
|
||||
qiniuUploadUrl = uploadConfig.upUrl;
|
||||
var qiniuUploadUrls = [uploadConfig.upUrl,];
|
||||
var qiniuUpHosts = {
|
||||
|
@ -994,7 +994,7 @@ function QiniuJsSDK() {
|
|||
'token': that.token,
|
||||
'x:path': file.path
|
||||
};
|
||||
}else if(uploadConfig.saveType == "local"){
|
||||
}else if(uploadConfig.saveType == "local"||uploadConfig.saveType == "onedrive"){
|
||||
multipart_params_obj = {
|
||||
'path': file.path
|
||||
};
|
||||
|
@ -1493,7 +1493,7 @@ function QiniuJsSDK() {
|
|||
}
|
||||
}
|
||||
local_path = "";
|
||||
if(uploadConfig.saveType == "local"){
|
||||
if(uploadConfig.saveType == "local"||uploadConfig.saveType == "onedrive"){
|
||||
pathTmp = file.path;
|
||||
if(file.path == ""){
|
||||
pathTmp = "ROOTDIR";
|
||||
|
@ -1501,6 +1501,8 @@ function QiniuJsSDK() {
|
|||
local_path = '/path/'+that.URLSafeBase64Encode(pathTmp);
|
||||
}
|
||||
if(uploadConfig.saveType == "remote"){
|
||||
pathTmp = file.path;
|
||||
local_path = that.URLSafeBase64Encode(pathTmp);
|
||||
var url = qiniuUploadUrl + 'mkfile.php?size=' + file.size +"&key="+ key+"&fname="+ fname +"&path="+local_path;
|
||||
}else{
|
||||
var url = qiniuUploadUrl + '/mkfile/' + file.size + key + fname + x_vars_url+local_path;
|
||||
|
|
137
static/js/remoteDownload.js
Normal file
137
static/js/remoteDownload.js
Normal file
|
@ -0,0 +1,137 @@
|
|||
function getMemory() {
|
||||
$.get("/Member/Memory", function(data) {
|
||||
var dataObj = eval("(" + data + ")");
|
||||
if (dataObj.rate >= 100) {
|
||||
$("#memory_bar").css("width", "100%");
|
||||
$("#memory_bar").addClass("progress-bar-warning");
|
||||
toastr["error"]("您的已用容量已超过容量配额,请尽快删除多余文件或购买容量");
|
||||
|
||||
} else {
|
||||
$("#memory_bar").css("width", dataObj.rate + "%");
|
||||
}
|
||||
$("#used").html(dataObj.used);
|
||||
$("#total").html(dataObj.total);
|
||||
});
|
||||
}
|
||||
|
||||
page = 1;
|
||||
window.onload = function() {
|
||||
$.material.init();
|
||||
|
||||
getMemory();
|
||||
}
|
||||
$(function() {
|
||||
$("#loadFinished").click(function(){
|
||||
$.getJSON("/RemoteDownload/ListFinished?page="+page, function(data) {
|
||||
if(data.length == 0){
|
||||
$("#loadFinished").html("已加载全部");
|
||||
$("#loadFinished").attr("disabled","true");
|
||||
}else{
|
||||
$("#loadFinished").html("继续加载");
|
||||
}
|
||||
data.forEach(function(e) {
|
||||
$("#completeItemContent").append(function() {
|
||||
var row = '<tr id="i-' + e["id"] + '" data-pid="'+e["pid"]+'"><th scope="row" class="centerTable">' + e["id"] + '</th><td>' + e["fileName"] + '</td>';
|
||||
row = row + '<td class="centerTable">' + bytesToSize(e["totalLength"]) + '</td>';
|
||||
row = row + '<td class="centerTable">' + e["save_dir"] + '</td>';
|
||||
switch(e["status"]){
|
||||
case "error":
|
||||
row = row +'<td class="centerTable"><span class="download-error" data-toggle="tooltip" data-placement="top" title="'+e["msg"]+'">失败</span></td>'
|
||||
break;
|
||||
case "canceled":
|
||||
row = row +'<td class="centerTable"><span >取消</span></td>'
|
||||
break;
|
||||
case "canceled":
|
||||
row = row +'<td class="centerTable"><span >取消</span></td>'
|
||||
break;
|
||||
case "complete":
|
||||
row = row +'<td class="centerTable"><span class="download-success">完成</span></td>'
|
||||
break;
|
||||
}
|
||||
return row + "</tr>";
|
||||
});
|
||||
switch(e["status"]){
|
||||
case "error":
|
||||
$("#i-" + e["id"]).addClass("td-error");
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
break;
|
||||
case "complete":
|
||||
$("#i-" + e["id"]).addClass("td-success");
|
||||
break;
|
||||
}
|
||||
});
|
||||
page++;
|
||||
})
|
||||
})
|
||||
})
|
||||
$.get("/RemoteDownload/FlushUser", function() {
|
||||
$("#loadStatus").html("加载下载列表中...");
|
||||
loadDownloadingList();
|
||||
})
|
||||
function loadDownloadingList() {
|
||||
$("#itemContent").html("");
|
||||
$.getJSON("/RemoteDownload/ListDownloading", function(data) {
|
||||
if(data.length == 0){
|
||||
$("#loadStatus").html("下载列表为空");
|
||||
}
|
||||
data.forEach(function(e) {
|
||||
$("#itemContent").append(function() {
|
||||
var row = '<tr id="i-' + e["id"] + '" data-pid="'+e["pid"]+'"><th scope="row" class="centerTable">' + e["id"] + '</th><td>' + e["fileName"] + '</td>';
|
||||
row = row + '<td class="centerTable">' + bytesToSize(e["totalLength"]) + '</td>';
|
||||
row = row + '<td class="centerTable">' + e["save_dir"] + '</td>';
|
||||
if (e["downloadSpeed"] == "0") {
|
||||
row = row + '<td class="centerTable">-</td>';
|
||||
} else {
|
||||
row = row + '<td class="centerTable">' + bytesToSize(e["downloadSpeed"]) + '/s</td>';
|
||||
}
|
||||
row = row + '<td class="centerTable">' + GetPercent(e["completedLength"], e["totalLength"]) + '</td>'
|
||||
row = row + '<td class="centerTable"><a href="javascript:" onclick="cancel('+e["id"]+')" >取消</a></td>'
|
||||
return row + "</tr>";
|
||||
});
|
||||
$("#i-" + e["id"]).css({
|
||||
"background-image": "-webkit-gradient(linear, left top, right top, from(#ecefff), to(white), color-stop("+e["completedLength"]/e["totalLength"]+", #ecefff), color-stop("+e["completedLength"]/e["totalLength"]+", white))",
|
||||
|
||||
});
|
||||
$(".table-responsive").slideDown();
|
||||
$("#loadStatus").slideUp();
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function bytesToSize(bytes) {
|
||||
if (bytes === 0) return '0 B';
|
||||
var k = 1024, // or 1024
|
||||
sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
|
||||
i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
function GetPercent(num, total) {
|
||||
num = parseFloat(num);
|
||||
total = parseFloat(total);
|
||||
if (isNaN(num) || isNaN(total)) {
|
||||
return "-";
|
||||
}
|
||||
return total <= 0 ? "0%" : (Math.round(num / total * 10000) / 100.00 + "%");
|
||||
}
|
||||
|
||||
function cancel(id){
|
||||
$.post("/RemoteDownload/Cancel", {id:id}, function(data){
|
||||
if(data.error){
|
||||
toastr["warning"](data.message);
|
||||
}else{
|
||||
var pid = $("#i-"+id).attr("data-pid");
|
||||
$("[data-pid='"+pid+"'").remove();
|
||||
toastr["success"](data.message);
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function refresh(){
|
||||
$.get("/RemoteDownload/FlushUser?i="+Math.random(), function() {
|
||||
$("#loadStatus").html("加载下载列表中...");
|
||||
loadDownloadingList();
|
||||
})
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
config.set({
|
||||
appName: 'angular-filemanager',
|
||||
defaultLang: 'zh_cn',
|
||||
sidebar: false,
|
||||
sidebar: true,
|
||||
pickCallback: function(item) {
|
||||
var msg = 'Picked %s "%s" for external use'
|
||||
.replace('%s', item.type)
|
||||
|
@ -18,6 +18,7 @@
|
|||
changePermissions: false,
|
||||
upload: false,
|
||||
shareFile: false,
|
||||
shareFile: false,
|
||||
}),
|
||||
});
|
||||
}]);
|
||||
|
|
17
task
Normal file
17
task
Normal file
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 定义项目路径
|
||||
define('APP_PATH', __DIR__ . '/application/');
|
||||
|
||||
// 加载框架引导文件
|
||||
require __DIR__.'/thinkphp/console.php';
|
|
@ -361,7 +361,9 @@
|
|||
<?php } else { ?>
|
||||
<div class="exception">
|
||||
|
||||
<div class="info"><h1><?php echo htmlentities($message); ?></h1></div>
|
||||
<div class="info"><h1><?php echo htmlentities($message); ?></h1>
|
||||
<p>我们都有不顺利的时候,请坐和放宽~</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
|
Loading…
Add table
Reference in a new issue