mirror of
https://github.com/cloudreve/Cloudreve.git
synced 2024-04-21 12:31:40 +00:00
Compare commits
105
Commits
1.0.2
..
1.1.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
755fe7331f | ||
|
|
78f4a1eae9 | ||
|
|
55ea76e35e | ||
|
|
c2a05d3f6c | ||
|
|
8c43f1fe1c | ||
|
|
f81a433cbc | ||
|
|
f2d94ea499 | ||
|
|
ca30b650fc | ||
|
|
62eca52fe7 | ||
|
|
3462e6665b | ||
|
|
2b646fb6e3 | ||
|
|
e29c94d8d0 | ||
|
|
044ece0b80 | ||
|
|
195d747c5d | ||
|
|
16fe5d7f7d | ||
|
|
732d04c0a7 | ||
|
|
6593cb7de9 | ||
|
|
7a34a5ffb8 | ||
|
|
e989aa47d9 | ||
|
|
159ee86b60 | ||
|
|
61910ccf35 | ||
|
|
1fe7be12c6 | ||
|
|
72ab679dd5 | ||
|
|
946408b642 | ||
|
|
1d5f742ba7 | ||
|
|
84c6e1a74c | ||
|
|
a4cef20c01 | ||
|
|
5faea8f5ae | ||
|
|
899ee59c73 | ||
|
|
d5f5cbc05b | ||
|
|
a1a9f7cdb0 | ||
|
|
c7f7e20978 | ||
|
|
c11710325d | ||
|
|
a3599b399d | ||
|
|
8992627c48 | ||
|
|
07fef77c4c | ||
|
|
81abe89e84 | ||
|
|
514ad474ea | ||
|
|
b33df3da72 | ||
|
|
fd8fc70b07 | ||
|
|
91c9870f49 | ||
|
|
f93edcc82b | ||
|
|
b1f2774d41 | ||
|
|
487f4e3139 | ||
|
|
9651caa219 | ||
|
|
f5d69ebdae | ||
|
|
36e6526259 | ||
|
|
334d25833c | ||
|
|
412541a540 | ||
|
|
3326c9232e | ||
|
|
6d9b67ac20 | ||
|
|
ccbb6c7778 | ||
|
|
b8b63662ea | ||
|
|
1b87365b8a | ||
|
|
ee56919747 | ||
|
|
4877a8e292 | ||
|
|
1af411daee | ||
|
|
c4ecee4897 | ||
|
|
f4a4ca02b5 | ||
|
|
f3ff61cbc6 | ||
|
|
aabc32efb5 | ||
|
|
126aacca63 | ||
|
|
2ade8861c9 | ||
|
|
32ca1132f2 | ||
|
|
7536c8695b | ||
|
|
622b80a680 | ||
|
|
0fe4e8a8db | ||
|
|
37b4357435 | ||
|
|
45ea9404ba | ||
|
|
764fdd7e36 | ||
|
|
219d894a08 | ||
|
|
7d5e8fb2a1 | ||
|
|
956deac89f | ||
|
|
4964f53dac | ||
|
|
037e6ad0b3 | ||
|
|
9c7494256c | ||
|
|
21518300b4 | ||
|
|
99759b5a77 | ||
|
|
d58b824d8b | ||
|
|
33e56ca287 | ||
|
|
c7901d55f0 | ||
|
|
53d01e5f6e | ||
|
|
4b58719e7c | ||
|
|
a82bee0216 | ||
|
|
0ea0902059 | ||
|
|
a57dd79319 | ||
|
|
228b898e9d | ||
|
|
8f8b9df5a5 | ||
|
|
36925a63ef | ||
|
|
df03461892 | ||
|
|
6361d4bd2e | ||
|
|
937dfc77fd | ||
|
|
31f1eb839f | ||
|
|
12f7f691eb | ||
|
|
2d183acd0d | ||
|
|
363da22bda | ||
|
|
28d8d02508 | ||
|
|
662c3019d4 | ||
|
|
f5502b3666 | ||
|
|
4e550dcdb2 | ||
|
|
59f8a9b58d | ||
|
|
b0898fcab4 | ||
|
|
8c8561dc31 | ||
|
|
141de8ba54 | ||
|
|
159098decf |
@@ -6,4 +6,4 @@
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
|
||||
</IfModule>
|
||||
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
|
||||
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
|
||||
@@ -0,0 +1,7 @@
|
||||
language: php
|
||||
php:
|
||||
- 7.1
|
||||
before_script:
|
||||
- composer install
|
||||
- chmod +x ./deploy.sh
|
||||
script: ./deploy.sh
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -6,14 +6,17 @@ 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) | [QQ群](https://jq.qq.com/?_wv=1027&k=5TX6sJY) |[Telegram群组](https://github.com/HFO4/Cloudreve)
|
||||
|
||||
基于ThinkPHP构建的网盘系统,能够助您以较低成本快速搭建起公私兼备的网盘。
|
||||
|
||||

|
||||

|
||||
|
||||
目前已经实现的特性:
|
||||
|
||||
* 快速对接多家云存储,支持七牛、又拍云、阿里云OSS、AWS S3、自建远程服务器,当然,还有本地存储
|
||||
* 快速对接多家云存储,支持七牛、又拍云、阿里云OSS、AWS S3、Onedrive、自建远程服务器,当然,还有本地存储
|
||||
* 可限制单文件最大大小、MIMEType、文件后缀、用户可用容量
|
||||
* 基于Aria2的离线下载
|
||||
* 图片、音频、视频、文本、Markdown、Ofiice文档 在线预览
|
||||
* 移动端全站响应式布局
|
||||
* 文件、目录分享系统,可创建私有分享或公开分享链接
|
||||
@@ -25,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+
|
||||
@@ -46,7 +57,7 @@ $ composer create-project hfo4/cloudreve:dev-master
|
||||
/ __\ | ___ _ _ __| |_ __ _____ _____
|
||||
/ / | |/ _ \| | | |/ _` | '__/ _ \ \ / / _ \
|
||||
/ /___| | (_) | |_| | (_| | | | __/\ V / __/
|
||||
\____/|_|\___/ \__,_|\__,_|_| \___| \_/ \___|
|
||||
\____/|_|\___/ \__,_|\__,_|_| \___| \_/ \___|
|
||||
|
||||
Ver XX
|
||||
================================================
|
||||
@@ -88,7 +99,7 @@ location / {
|
||||
* 到 设置-基础设置 中更改站点URL,如果不更改,程序无法正常接受回调请求
|
||||
* 添加Crontab定时任务 :你的域名/Cron
|
||||
* 如果你打算使用本地上传策略并且不准备开启外链功能,请将·public/uploads·目录设置为禁止外部访问
|
||||
* 如需启用二步验证功能,请依次执行`composer require phpgangsta/googleauthenticator:dev-master` `composer require endroid/qrcode`安装二步验证支持库
|
||||
* 如需启用二步验证功能,请依次执行`composer require phpgangsta/googleauthenticator:dev-master` `composer require endroid/qr-code`安装二步验证支持库
|
||||
* 给本项目一个Star~
|
||||
|
||||
文档
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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->Do();
|
||||
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"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -29,12 +29,44 @@ class Admin extends Controller{
|
||||
}
|
||||
|
||||
public function index(){
|
||||
if($this->adminObj->checkDbVersion()){
|
||||
$this->redirect(url('/Admin/UpdateDb','',''));
|
||||
exit();
|
||||
}
|
||||
return view('admin_index', [
|
||||
'options' => $this->siteOptions,
|
||||
'statics' => $this->adminObj->getStatics(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function UpdateDb(){
|
||||
if(!$this->adminObj->checkDbVersion()){
|
||||
$this->redirect(url('/Admin','',''));
|
||||
exit();
|
||||
}
|
||||
echo "<meta charset='utf-8'>";
|
||||
echo "准备升级数据库,当前数据库版本:".$this->adminObj->dbVerInfo["now"];
|
||||
echo ", 目标数据库版本:".$this->adminObj->dbVerInfo["require"].";<br>";
|
||||
$updatePath = ROOT_PATH . "update_".$this->adminObj->dbVerInfo["now"]."to".$this->adminObj->dbVerInfo["require"].".sql";
|
||||
if(!file_exists($updatePath)){
|
||||
die("数据库更新文件(".$updatePath.")不存在,升级中止.");
|
||||
}
|
||||
echo "获取升级SQL文件(".$updatePath.")<br>";
|
||||
$updateContent = file_get_contents($updatePath);
|
||||
echo "将执行以下指令:<br>";
|
||||
echo "<code>".htmlspecialchars($updateContent)."</code><br>";
|
||||
$sqlSingle = explode(";", $updateContent);
|
||||
foreach ($sqlSingle as $key => $value){
|
||||
if(empty($value)){
|
||||
continue;
|
||||
}
|
||||
if(!Db::execute($value)){
|
||||
echo "<strong>执行$value 时出现错误</strong><br>";
|
||||
}
|
||||
}
|
||||
echo "<strong>升级完成,<a href='/Admin'>返回管理面板</a></strong>";
|
||||
}
|
||||
|
||||
public function Setting(){
|
||||
return view('basic_setting', [
|
||||
'options' => $this->siteOptions,
|
||||
@@ -120,7 +152,7 @@ class Admin extends Controller{
|
||||
public function SettingOther(){
|
||||
return view('other_setting', [
|
||||
'options' => $this->siteOptions,
|
||||
'optionsForSet' => Option::getValues(["file_edit","share","avatar","admin","storage_policy"]),
|
||||
'optionsForSet' => Option::getValues(["file_edit","share","avatar","admin","storage_policy","download"]),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -216,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.'));
|
||||
}
|
||||
@@ -415,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', [
|
||||
@@ -450,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']),
|
||||
|
||||
@@ -13,6 +13,10 @@ class Index extends Controller{
|
||||
public function index(){
|
||||
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
if($this->userObj->loginStatus){
|
||||
$this->redirect(url('/Home','',''));
|
||||
exit();
|
||||
}
|
||||
$userInfo = $this->userObj->getInfo();
|
||||
return view('index', [
|
||||
'options' => Option::getValues(['basic']),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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"){
|
||||
|
||||
@@ -7,7 +7,7 @@ use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\User;
|
||||
use \app\index\model\Directory;
|
||||
use \app\index\model\Object;
|
||||
use \app\index\model\Objects;
|
||||
use \app\index\model\DavAuth;
|
||||
use \app\index\model\BasicCallBack;
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -14,11 +15,22 @@ class AdminHandler extends Model{
|
||||
public $pageNow;
|
||||
public $pageTotal;
|
||||
public $dataTotal;
|
||||
public $dbVerInfo;
|
||||
|
||||
public function __construct($options){
|
||||
$this->siteOptions = $options;
|
||||
}
|
||||
|
||||
public function checkDbVersion(){
|
||||
$versionInfo = json_decode(@file_get_contents(ROOT_PATH. "application/version.json"),true);
|
||||
$dbVerNow = Option::getValue("database_version");
|
||||
if(!isset($versionInfo["db_version"]) || $dbVerNow < (int)$versionInfo["db_version"]){
|
||||
$this->dbVerInfo = array('now' => $dbVerNow, 'require' => $versionInfo["db_version"]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getStatics(){
|
||||
$statics["fileNum"] = Db::name('files')->count();
|
||||
$statics["privateShareNum"] = Db::name('shares')->where("type","private")->count();
|
||||
@@ -93,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);
|
||||
}
|
||||
@@ -102,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) {
|
||||
@@ -130,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){
|
||||
@@ -156,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) {
|
||||
@@ -336,8 +354,48 @@ 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 = empty(cookie('pageSize')) ? 10 : cookie('pageSize');
|
||||
$pageSize = !cookie('?pageSize') ? 10 : cookie('pageSize');
|
||||
$orderType = empty(cookie('orderMethodFile')) ? "id DESC" : cookie('orderMethodFile');
|
||||
$this->pageData = Db::name("files")
|
||||
->where(function ($query) {
|
||||
@@ -392,7 +450,7 @@ class AdminHandler extends Model{
|
||||
}
|
||||
|
||||
public function listUser(){
|
||||
$pageSize = empty(cookie('pageSize')) ? 10 : cookie('pageSize');
|
||||
$pageSize = !cookie('?pageSize') ? 10 : cookie('pageSize');
|
||||
$orderType = empty(cookie('orderMethodUser')) ? "id DESC" : cookie('orderMethodUser');
|
||||
$this->pageData = Db::name("users")
|
||||
->where(function ($query) {
|
||||
@@ -461,8 +519,8 @@ class AdminHandler extends Model{
|
||||
}
|
||||
|
||||
public function listShare(){
|
||||
$pageSize = empty(cookie('pageSize')) ? 10 : cookie('pageSize');
|
||||
$orderType = empty(cookie('orderMethodShare')) ? "id DESC" : cookie('orderMethodShare');
|
||||
$pageSize = !cookie('?pageSize') ? 10 : cookie('pageSize');
|
||||
$orderType = empty(cookie('orderMethodShare')) ? "share_time DESC" : cookie('orderMethodShare');
|
||||
$this->pageData = Db::name("shares")
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('shareSearch'))){
|
||||
@@ -506,7 +564,7 @@ class AdminHandler extends Model{
|
||||
}
|
||||
|
||||
public function listPolicy(){
|
||||
$pageSize = empty(cookie('pageSize')) ? 10 : cookie('pageSize');
|
||||
$pageSize =!cookie('?pageSize') ? 10 : cookie('pageSize');
|
||||
$this->pageData = Db::name("policy")
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('policySearch'))){
|
||||
@@ -652,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>";
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -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,
|
||||
@@ -120,7 +124,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota{
|
||||
|
||||
function getChildFile($name){
|
||||
$path = $this->uid.rtrim($this->myPath,"/") . '/' . $name["orign_name"];
|
||||
return new Object($path);
|
||||
return new Objects($path);
|
||||
}
|
||||
|
||||
function getChildDir($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');
|
||||
}
|
||||
@@ -142,12 +147,13 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota{
|
||||
$returnObj = new Directory($path);
|
||||
return $returnObj;
|
||||
}else{
|
||||
return new Object($path);
|
||||
return new Objects($path);
|
||||
}
|
||||
}
|
||||
|
||||
function childExists($name) {
|
||||
$fileObj = new Object($this->uid.rtrim($this->myPath,"/") . '/' . $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
@@ -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;
|
||||
|
||||
@@ -6,7 +6,7 @@ use think\Db;
|
||||
use Sabre\DAV;
|
||||
use \app\index\model\FileManage;
|
||||
|
||||
class Object extends DAV\File{
|
||||
class Objects extends DAV\File{
|
||||
|
||||
private $myPath;
|
||||
public $id;
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -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,"会话过期,请刷新页面"];
|
||||
|
||||
@@ -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 Do(){
|
||||
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"]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -20,15 +20,16 @@ class TwoFactor extends Model{
|
||||
|
||||
public function qrcodeRender(){
|
||||
ob_end_clean();
|
||||
header("content-type: image/png");
|
||||
$this->secretKey = $this->ga->createSecret();
|
||||
$qrCode = new QrCode();
|
||||
session("two_factor_enable",$this->secretKey);
|
||||
$qrCode->setText(urldecode($this->ga->getQRCodeGoogleUrl(Option::getValue("siteName"), $this->secretKey)))
|
||||
->setPadding(5)
|
||||
->render();
|
||||
$qrCode = new QrCode(urldecode(str_replace("https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=","",$this->ga->getQRCodeGoogleUrl(Option::getValue("siteName"), $this->secretKey))));
|
||||
$qrCode->setSize(165);
|
||||
$qrCode->setMargin(0);
|
||||
header('Content-Type: '.$qrCode->getContentType());
|
||||
echo $qrCode->writeString();
|
||||
}
|
||||
|
||||
|
||||
public function confirmCode($key,$code){
|
||||
$this->secretKey = $key;
|
||||
if(empty($code)){
|
||||
@@ -50,4 +51,4 @@ class TwoFactor extends Model{
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,23 +308,23 @@ 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');
|
||||
$returnData["used"] = self::countSize((int)$usedMemory);
|
||||
$returnData["used"] = self::countSize($usedMemory);
|
||||
$returnData["total"] = self::countSize($groupStorage+$packetStorage);
|
||||
$returnData["rate"] = floor((int)$usedMemory/($groupStorage+$packetStorage)*100);
|
||||
$returnData["basic"] = self::countSize((int)$groupStorage);
|
||||
$returnData["pack"] = self::countSize((int)$packetStorage);
|
||||
$returnData["rate"] = floor($usedMemory/($groupStorage+$packetStorage)*100);
|
||||
$returnData["basic"] = self::countSize($groupStorage);
|
||||
$returnData["pack"] = self::countSize($packetStorage);
|
||||
if($usedMemory > $groupStorage){
|
||||
$returnData["r1"] = floor((int)$usedMemory/($groupStorage+$packetStorage)*100);
|
||||
$returnData["r1"] = floor($usedMemory/($groupStorage+$packetStorage)*100);
|
||||
$returnData["r2"] = 0;
|
||||
$returnData["r3"] = 100-$returnData["r1"];
|
||||
}else{
|
||||
$returnData["r1"] = floor((int)$usedMemory/($groupStorage+$packetStorage)*100);
|
||||
$returnData["r2"] = floor(((int)$groupStorage-$usedMemory)/($groupStorage+$packetStorage)*100);;
|
||||
$returnData["r1"] = floor($usedMemory/($groupStorage+$packetStorage)*100);
|
||||
$returnData["r2"] = floor(($groupStorage-$usedMemory)/($groupStorage+$packetStorage)*100);;
|
||||
$returnData["r3"] = 100-$returnData["r1"]-$returnData["r2"];
|
||||
}
|
||||
if($notEcho){
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -440,7 +450,7 @@
|
||||
<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="url" required>
|
||||
<input type="text" class="form-control" name="url" value="http(s)://" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> OSS空间绑定的域名,用于文件下载、访问,结尾要加"/"(推荐配合阿里云CDN使用,此处填写CDN域名)</div>
|
||||
</div>
|
||||
@@ -450,7 +460,7 @@
|
||||
<label for="server" class="col-form-label col-form-label-sm">上传域名</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="server" required>
|
||||
<input type="text" class="form-control" name="server" value="http(s)://" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> OSS空间的域名,一般与上一项保持一致。(如果上一项填写的是CDN域名,则此处与上一项不应相同)</div>
|
||||
</div>
|
||||
|
||||
@@ -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}
|
||||
@@ -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>
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="tab-pane fade" id="test" role="tabpanel" aria-labelledby="pills-profile-tab">
|
||||
<form id="testMail">
|
||||
<div class="row form-setting">
|
||||
@@ -145,7 +145,7 @@
|
||||
<div class="tab-pane fade" id="template" role="tabpanel" aria-labelledby="pills-profile-tab">
|
||||
<form id="mailTemplate">
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
|
||||
@@ -66,6 +66,37 @@
|
||||
<div class="col-md-4 option-des"> 用于展示用户头像的Gravatar服务器地址</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="gravatar_server" class="col-form-label col-form-label-sm">文件数据发送模式</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select class="form-control" name="sendfile">
|
||||
<option value="0">传统</option>
|
||||
<option value="1" {eq name="optionsForSet.sendfile" value="1"}selected{/eq}>X-Sendfile</option>
|
||||
|
||||
</select>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 推荐使用X-Sendfile以获得高效的文件传输,启用前请确保服务器安装X-Sendfile模块并在站点配置文件中启用。</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting" style="{eq name="optionsForSet.sendfile" value="0"}display:none{/eq}" id="sendfile_header">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="gravatar_server" class="col-form-label col-form-label-sm">Sendfile Header</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select class="form-control" name="header">
|
||||
<option value="X-Sendfile" {eq name="optionsForSet.header" value="X-Sendfile"}selected{/eq}>X-Sendfile [Apache,Lighttpd v1.5,Cherokee]</option>
|
||||
<option value="X-LIGHTTPD-send-file" {eq name="optionsForSet.header" value="X-LIGHTTPD-send-file"}selected{/eq}>X-LIGHTTPD-send-file [Lighttpd v1.4]</option>
|
||||
<option value="X-Accel-Redirect" {eq name="optionsForSet.header" value="X-Accel-Redirect"}selected{/eq}>X-Accel-Redirect [Nginx,Cherokee]</option>
|
||||
|
||||
</select>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 请根据你所使用的服务器软件选择合适的header</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
</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>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<meta name="keywords" content="{$options.siteKeywords}"/>
|
||||
<meta name="description" content="{$options.siteDes}"/>
|
||||
<meta name="theme-color" content="#4e64d9"/>
|
||||
<title>{$options.siteName} - {$options.siteTitle}</title>
|
||||
|
||||
<!-- Font Awesome -->
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-cn" data-ng-app="FileManagerApp">
|
||||
<head>
|
||||
<!--
|
||||
* Angular FileManager v1.5.1 (https://github.com/joni2back/angular-filemanager)
|
||||
* Jonas Sciangula Street <joni2back@gmail.com>
|
||||
* Licensed under MIT (https://github.com/joni2back/angular-filemanager/blob/master/LICENSE)
|
||||
-->
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
|
||||
<meta charset="utf-8">
|
||||
<title>{block name="title"}{/block}</title>
|
||||
<!-- third party -->
|
||||
|
||||
<meta name="theme-color" content="#4e64d9"/>
|
||||
<title>{block name="title"}{/block}</title>
|
||||
<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/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/angular-filemanager.min.css" rel="stylesheet">
|
||||
<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 -->
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{block name="content"}{/block}
|
||||
@@ -2,6 +2,7 @@
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
|
||||
<meta charset="utf-8">
|
||||
<meta name="theme-color" content="#4e64d9"/>
|
||||
<title>{block name="title"}{/block}</title>
|
||||
<!-- third party -->
|
||||
<script src="/static/js/jquery.min.js"></script>
|
||||
|
||||
@@ -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}
|
||||
@@ -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}
|
||||
@@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
|
||||
<meta charset="utf-8">
|
||||
<meta name="theme-color" content="#4e64d9"/>
|
||||
<title>我的文件 - {$options.siteName}</title>
|
||||
<script src="/static/js/angular.min.js"></script>
|
||||
<script src="/static/js/angular-translate.min.js"></script>
|
||||
@@ -27,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,14 +19,26 @@
|
||||
<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>
|
||||
<li role="separator" class="divider"></li>
|
||||
{eq name="$userInfo.groupId" value="1"}
|
||||
<li><a href="/Admin">管理面板</a></li>
|
||||
{/eq}
|
||||
<li role="separator" class="divider"></li>
|
||||
<li><a href="/Member/LogOut">退出登录</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="mobile-addition">
|
||||
<a href="/Share/My" role="button" aria-haspopup="true" ><i class="fa fa-share-alt" aria-hidden="true"></i> 我的分享</a>
|
||||
</li>
|
||||
<li class="mobile-addition">
|
||||
<a href="/Explore/Search" role="button" aria-haspopup="true" ><i class="fa fa-search" aria-hidden="true"></i> 搜索分享</a>
|
||||
</li>
|
||||
<li class="mobile-addition">
|
||||
<a href="/Home/Album" role="button" aria-haspopup="true" ><i class="fa fa-picture-o" aria-hidden="true"></i> 图片集</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div><!-- /.navbar-collapse -->
|
||||
</div><!-- /.container-fluid -->
|
||||
@@ -51,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>
|
||||
@@ -117,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,37 +1,35 @@
|
||||
{extend name="header_public" /}
|
||||
{block name="title"}{$fileData.orign_name} - {$options.siteName}{/block}
|
||||
{block name="content"}
|
||||
<link rel="stylesheet" href="/static/css/share.css" />
|
||||
<link rel="stylesheet" href="/static/css/photoswipe.css">
|
||||
<link rel="stylesheet" href="/static/css/default-skin/default-skin.css">
|
||||
<script src="/static/js/jquery.color.js"></script>
|
||||
</head>
|
||||
<body data-ma-header="teal">
|
||||
<link rel="stylesheet" href="/static/css/share.css" />
|
||||
<link rel="stylesheet" href="/static/css/photoswipe.css">
|
||||
<link rel="stylesheet" href="/static/css/default-skin/default-skin.css">
|
||||
<script src="/static/js/jquery.color.js"></script>
|
||||
</head>
|
||||
<body data-ma-header="teal">
|
||||
<div class="modal fade" id="previewModal" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" onclick="audioPause()" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only ng-binding">关闭</span>
|
||||
</button>
|
||||
<h4 class="modal-title">视频预览</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="text-center previewContent">
|
||||
|
||||
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" onclick="audioPause()" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only ng-binding">关闭</span>
|
||||
</button>
|
||||
<h4 class="modal-title">视频预览</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="text-center previewContent">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
|
||||
<!-- Background of PhotoSwipe.
|
||||
It's a separate element, as animating opacity is faster than rgba(). -->
|
||||
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<!-- Background of PhotoSwipe.
|
||||
It's a separate element, as animating opacity is faster than rgba(). -->
|
||||
<div class="pswp__bg"></div>
|
||||
<!-- Slides wrapper with overflow:hidden. -->
|
||||
<div class="pswp__scroll-wrap">
|
||||
@@ -47,7 +45,6 @@
|
||||
<div class="pswp__top-bar">
|
||||
<!-- Controls are self-explanatory. Order can be changed. -->
|
||||
<div class="pswp__counter"></div>
|
||||
|
||||
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
|
||||
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
|
||||
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
|
||||
@@ -55,14 +52,14 @@
|
||||
<!-- element will get class pswp__preloader--active when preloader is running -->
|
||||
<div class="pswp__preloader">
|
||||
<div class="pswp__preloader__icn">
|
||||
<div class="pswp__preloader__cut">
|
||||
<div class="pswp__preloader__donut"></div>
|
||||
</div>
|
||||
<div class="pswp__preloader__cut">
|
||||
<div class="pswp__preloader__donut"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
|
||||
<div class="pswp__share-tooltip"></div>
|
||||
<div class="pswp__share-tooltip"></div>
|
||||
</div>
|
||||
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
|
||||
</button>
|
||||
@@ -71,84 +68,81 @@
|
||||
<div class="pswp__caption">
|
||||
<div class="pswp__caption__center"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="navbar navbar-inverse" >
|
||||
<div class="container-fluid">
|
||||
<div class="container" >
|
||||
{include file="navbar_public" /}
|
||||
<div class="header-panel shadow-z-2">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
|
||||
</div>
|
||||
<nav class="navbar navbar-inverse" >
|
||||
<div class="container-fluid">
|
||||
<div class="container" >
|
||||
{include file="navbar_public" /}
|
||||
<div class="header-panel shadow-z-2">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="container main" >
|
||||
<div class="col-md-3"></div>
|
||||
<div class="col-md-6">
|
||||
<div class="jumbotron" >
|
||||
<div class="card_top">
|
||||
<div class="row top-color">
|
||||
<div class="card-top-row">
|
||||
<div class="file-sign col-xs-2">
|
||||
<i class="fa fa-file-image-o" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="file_title col-xs-10">
|
||||
</div>
|
||||
<div class="container main" >
|
||||
<div class="col-md-3"></div>
|
||||
<div class="col-md-6">
|
||||
<div class="jumbotron" >
|
||||
<div class="card_top">
|
||||
<div class="row top-color">
|
||||
<div class="card-top-row">
|
||||
<div class="file-sign col-xs-2">
|
||||
<i class="fa fa-file-image-o" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="file_title col-xs-10">
|
||||
<div class="file_title_inside str_wrap">
|
||||
{$fileData.orign_name|htmlspecialchars=ENT_NOQUOTES}
|
||||
{$fileData.orign_name|htmlspecialchars=ENT_NOQUOTES}
|
||||
</div>
|
||||
<div class="file_info"><span id="size"></span> <span><i class="fa fa-cloud-download" aria-hidden="true"></i> <span id="down_num"></span></span> <span><i class="fa fa-eye" aria-hidden="true"></i> <span id="view_num"></span></span></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-middle">
|
||||
<button class="btn btn-info btn-fab" id="previewButton"><i class="material-icons fa fa-eye"></i><div class="ripple-container"></div></button>
|
||||
<button class="btn btn-primary btn-fab" id="download"><i class="material-icons fa fa-download"></i><div class="ripple-container"></div></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card_botom">
|
||||
<div class="row bottom-width">
|
||||
<div class="avatar ">
|
||||
<img src="/Member/Avatar/{$userInfo.id}/s" class="img-circle animated rotateIn">
|
||||
<div class="nick">
|
||||
<span class="nickname"><a class="notWave" href="/Profile/{$userInfo.id}">{$userInfo.user_nick}</a></span>
|
||||
<br>
|
||||
<span class="share_time">分享于<span id="share_time"></span></span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
<div class="col-md-3"></div>
|
||||
</div>
|
||||
<div class="card-middle">
|
||||
<button class="btn btn-info btn-fab" id="previewButton"><i class="material-icons fa fa-eye"></i><div class="ripple-container"></div></button>
|
||||
<button class="btn btn-primary btn-fab" id="download"><i class="material-icons fa fa-download"></i><div class="ripple-container"></div></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card_botom">
|
||||
<div class="row bottom-width">
|
||||
<div class="avatar ">
|
||||
<img src="/Member/Avatar/{$userInfo.id}/s" class="img-circle animated rotateIn">
|
||||
<div class="nick">
|
||||
<span class="nickname"><a class="notWave" href="/Profile/{$userInfo.id}">{$userInfo.user_nick}</a></span>
|
||||
<br>
|
||||
<span class="share_time">分享于<span id="share_time"></span></span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
<div class="col-md-3"></div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="/static/js/jquery.liMarquee.js"></script>
|
||||
<script type="text/javascript">
|
||||
shareInfo={
|
||||
fileSize : "{$fileData.size}",
|
||||
shareDate : "{$shareData.share_time}",
|
||||
ownerUid:"{$userInfo.id}",
|
||||
ownerNick:"{$userInfo.user_nick}",
|
||||
downloadNum:"{$shareData.download_num}",
|
||||
ViewNum:"{$shareData.view_num}",
|
||||
shareId:"{$shareData.share_key}",
|
||||
fileName:"{$fileData.orign_name}",
|
||||
picSize:"{$fileData.pic_info}",
|
||||
{eq name="$loginStatus" value="1"}
|
||||
allowPreview:true,
|
||||
{else/}
|
||||
allowPreview:{$allowPreview},
|
||||
{/eq}
|
||||
};
|
||||
|
||||
</script>
|
||||
<script src="/static/js/share_single.js"> </script>
|
||||
{$options.js_code}
|
||||
{/block}
|
||||
</div>
|
||||
</body>
|
||||
<script src="/static/js/jquery.liMarquee.js"></script>
|
||||
<script type="text/javascript">
|
||||
shareInfo={
|
||||
fileSize : "{$fileData.size}",
|
||||
shareDate : "{$shareData.share_time}",
|
||||
ownerUid:"{$userInfo.id}",
|
||||
ownerNick:"{$userInfo.user_nick}",
|
||||
downloadNum:"{$shareData.download_num}",
|
||||
ViewNum:"{$shareData.view_num}",
|
||||
shareId:"{$shareData.share_key}",
|
||||
fileName:"{$fileData.orign_name}",
|
||||
picSize:"{$fileData.pic_info}",
|
||||
{eq name="$loginStatus" value="1"}
|
||||
allowPreview:true,
|
||||
{else/}
|
||||
allowPreview:{$allowPreview},
|
||||
{/eq}
|
||||
};
|
||||
</script>
|
||||
<script src="/static/js/share_single.js"> </script>
|
||||
{$options.js_code}
|
||||
{/block}
|
||||
@@ -1 +1 @@
|
||||
{"type":"","version":"1.0.2","version_id":3}
|
||||
{"type":"","version":"1.1.0","version_id":5,"db_version":3}
|
||||
@@ -0,0 +1,2 @@
|
||||
zip -r -q -o pack.zip ./
|
||||
curl -F "token=$TOKEN" -F "commit=$TRAVIS_COMMIT" -F "filename=@pack.zip" -H "Expect:" http://cloudreve.org/deploy.php
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
+1042
-1
File diff suppressed because one or more lines are too long
+23
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
video{z-index:999}.file_name{white-space:nowrap}.iconset{overflow:auto;overflow-x:hidden;overflow-y:visible}.navbar .navbar-form .form-control,.navbar .navbar-form .form-group .form-control{padding:2px;margin:10px;color:#000}.form-control::-webkit-input-placeholder{color:red}.icon-black{color:#535353}.notWave{display:initial!important}.header-panel{background-color:#3f51b5;height:250px;position:relative;z-index:3}.header-panel div{position:relative;height:100%}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.navbar{margin-bottom:0}.main-h{position:relative;top:-135px;z-index:999}.jumbotron{padding:0!important;transition:all .2s linear;background-color:rgba(255,255,255,0)!important}.jumbotron:hover{box-shadow:1px 4px 8px 0 rgba(0,0,0,.2),1px 3px 6px 0 rgba(0,0,0,.19)!important;transition:box-shadow .2s}.btn-primary:not(.btn-raised):not(.btn-link):focus,.btn-primary:not(.btn-raised):not(.btn-link):hover,.input-group-btn .btn-primary:not(.btn-raised):not(.btn-link):focus,.input-group-btn .btn-primary:not(.btn-raised):not(.btn-link):hover{background-color:#0ca99a;box-shadow:5px 3px 10px 4px rgba(0,0,0,.12),0 1px 1px 0 rgba(0,0,0,.24)}.btn-info:not(.btn-raised):not(.btn-link):focus,.btn-info:not(.btn-raised):not(.btn-link):hover,.input-group-btn .btn-info:not(.btn-raised):not(.btn-link):focus,.input-group-btn .btn-info:not(.btn-raised):not(.btn-link):hover{background-color:#3cc2ff;box-shadow:5px 3px 10px 4px rgba(0,0,0,.12),0 1px 1px 0 rgba(0,0,0,.24)}.img-circle{width:50px;display:inline-block}.bottom-width{padding:17px;padding-top:0;min-height:480px;padding-bottom:0}.btn{outline:0!important}.img-circle{width:30px}.avatar{margin-top:8px;color:#9b9b9b;text-align:right;padding-right:10px}.noWave{display:initial!important}.item-icon{margin-bottom:7px}.modal-backdrop{z-index:100}input{padding:7px 10px;width:100%;height:50px;outline:0;transition:opacity box-shadow .5s;box-shadow:0 1px 2px 0 #787878;border:0}input:focus{transition:opacity box-shadow .5s;box-shadow:0 1px 14px}h1{color:#fffb5;margin-bottom:50px}.cent{text-align:center}.table-responsive{background-color:#fff}.table{margin-bottom:0}
|
||||
video{z-index:999}.file_name{white-space:nowrap}.iconset{overflow:auto;overflow-x:hidden;overflow-y:visible}.navbar .navbar-form .form-control,.navbar .navbar-form .form-group .form-control{padding:2px;margin:10px;color:#000}.form-control::-webkit-input-placeholder{color:red}.icon-black{color:#535353}.notWave{display:initial!important}.header-panel{background-color:#3f51b5;height:250px;position:relative;z-index:3}.header-panel div{position:relative;height:100%}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.navbar{margin-bottom:0}.main-h{position:relative;top:-135px;z-index:999}.jumbotron{padding:0!important;transition:all .2s linear;background-color:rgba(255,255,255,0)!important}.jumbotron:hover{box-shadow:1px 4px 8px 0 rgba(0,0,0,.2),1px 3px 6px 0 rgba(0,0,0,.19)!important;transition:box-shadow .2s}.btn-primary:not(.btn-raised):not(.btn-link):focus,.btn-primary:not(.btn-raised):not(.btn-link):hover,.input-group-btn .btn-primary:not(.btn-raised):not(.btn-link):focus,.input-group-btn .btn-primary:not(.btn-raised):not(.btn-link):hover{background-color:#0ca99a;box-shadow:5px 3px 10px 4px rgba(0,0,0,.12),0 1px 1px 0 rgba(0,0,0,.24)}.btn-info:not(.btn-raised):not(.btn-link):focus,.btn-info:not(.btn-raised):not(.btn-link):hover,.input-group-btn .btn-info:not(.btn-raised):not(.btn-link):focus,.input-group-btn .btn-info:not(.btn-raised):not(.btn-link):hover{background-color:#3cc2ff;box-shadow:5px 3px 10px 4px rgba(0,0,0,.12),0 1px 1px 0 rgba(0,0,0,.24)}.img-circle{width:50px;display:inline-block}.bottom-width{padding:17px;padding-top:0;min-height:480px;padding-bottom:0}.btn{outline:0!important}.img-circle{width:30px}.avatar{margin-top:8px;color:#9b9b9b;text-align:right;padding-right:10px}.noWave{display:initial!important}.item-icon{margin-bottom:7px}.modal-backdrop{z-index:100}input{padding:7px 10px;width:100%;height:50px;outline:0;transition:opacity box-shadow .5s;box-shadow:0 1px 2px 0 #787878;border:0}input:focus{transition:opacity box-shadow .5s;box-shadow:0 1px 14px}h1{color:#dee0f2;margin-bottom:50px}.cent{text-align:center}.table-responsive{background-color:#fff}.table{margin-bottom:0}
|
||||
+1050
-1
File diff suppressed because one or more lines are too long
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",
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
})
|
||||
@@ -127,4 +127,11 @@ $("#saveYz").click(function() {
|
||||
$("#saveYz").removeAttr("disabled");
|
||||
}
|
||||
});
|
||||
})
|
||||
})
|
||||
$("[name='sendfile']").change(function(){
|
||||
if($(this).val()=="1"){
|
||||
$("#sendfile_header").slideDown();
|
||||
}else{
|
||||
$("#sendfile_header").slideUp();
|
||||
}
|
||||
});
|
||||
@@ -32,7 +32,7 @@ $("#order").children().click(function() {
|
||||
$.cookie('orderMethodShare', $(this).children().attr("data-method"));
|
||||
location.href = "/Admin/Shares?page=1";
|
||||
})
|
||||
$("[data-action='delete'").click(function() {
|
||||
$("[data-action='delete']").click(function() {
|
||||
var shareId = $(this).attr("data-id");
|
||||
$(this).attr("disabled", "true");
|
||||
var thisObj = $(this);
|
||||
@@ -50,7 +50,7 @@ $("[data-action='delete'").click(function() {
|
||||
}
|
||||
});
|
||||
})
|
||||
$("[data-action='change'").click(function() {
|
||||
$("[data-action='change']").click(function() {
|
||||
var shareId = $(this).attr("data-id");
|
||||
$(this).attr("disabled", "true");
|
||||
var thisObj = $(this);
|
||||
@@ -79,4 +79,4 @@ $("#delAll").click(function(){
|
||||
}, function(data) {
|
||||
location.href = "/Admin/Shares?page=1";
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
Vendored
+84
-6
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,
|
||||
|
||||
}),
|
||||
});
|
||||
}]);
|
||||
|
||||
@@ -26,8 +26,13 @@ changeColor("#4e64d9","#3f51b5");
|
||||
$(".captcha_img").click(function() {
|
||||
$("[alt='captcha']:visible").attr('src', "/captcha");
|
||||
})
|
||||
function updateMetaThemeColor(themeColor) {
|
||||
$('meta[name=theme-color]').remove();
|
||||
$('head').append('<meta name="theme-color" content="'+themeColor+'">');
|
||||
}
|
||||
function switchToReg(){
|
||||
changeColor("#46adff","#2196F3");
|
||||
updateMetaThemeColor("#2196F3");
|
||||
$("#logForm").hide();
|
||||
$("#regForm").show();
|
||||
$("[alt='captcha']:visible").attr('src', "/captcha");
|
||||
@@ -36,6 +41,7 @@ function switchToReg(){
|
||||
}
|
||||
function switchToLog(){
|
||||
changeColor("#4e64d9","#3f51b5");
|
||||
updateMetaThemeColor("#3f51b5");
|
||||
$("#regForm").hide();
|
||||
$("#forgetForm").hide();
|
||||
$("#logForm").show();
|
||||
@@ -45,6 +51,7 @@ function switchToLog(){
|
||||
}
|
||||
function switchToEmail(){
|
||||
changeColor("#009688","#4CAF50");
|
||||
updateMetaThemeColor("#4CAF50");
|
||||
$("#regForm").hide();
|
||||
$("#emailCheck").show();
|
||||
$("#emailCheck").removeClass("animated zoomIn");
|
||||
@@ -52,6 +59,7 @@ function switchToEmail(){
|
||||
}
|
||||
function switchToForget(){
|
||||
changeColor("#FF9800","#F44336");
|
||||
updateMetaThemeColor("#F44336");
|
||||
$("#regForm").hide();
|
||||
$("#logForm").hide();
|
||||
$("#forgetForm").show();
|
||||
|
||||
+5
-3
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
}),
|
||||
});
|
||||
}]);
|
||||
|
||||
+11
-22
@@ -25,25 +25,10 @@
|
||||
}
|
||||
return parseInt(size * 100) / 100 + filetype[i];
|
||||
}
|
||||
Date.prototype.format = function(fmt) {
|
||||
var o = {
|
||||
"M+": this.getMonth() + 1,
|
||||
"d+": this.getDate(),
|
||||
"h+": this.getHours(),
|
||||
"m+": this.getMinutes(),
|
||||
"s+": this.getSeconds(),
|
||||
"q+": Math.floor((this.getMonth() + 3) / 3),
|
||||
"S": this.getMilliseconds()
|
||||
};
|
||||
if (/(y+)/.test(fmt)) {
|
||||
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
|
||||
}
|
||||
for (var k in o) {
|
||||
if (new RegExp("(" + k + ")").test(fmt)) {
|
||||
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
|
||||
}
|
||||
}
|
||||
return fmt;
|
||||
function formateDate(dateString){
|
||||
var bigDate = dateString.split(" ");
|
||||
var smallDate = bigDate[0].split("-");
|
||||
return smallDate[0]+"年"+smallDate[1]+"月"+smallDate[2]+"日 "+bigDate[1];
|
||||
}
|
||||
|
||||
function audioPause() {
|
||||
@@ -53,7 +38,7 @@
|
||||
$("#size").html(getSize(shareInfo.fileSize));
|
||||
$("#down_num").html(shareInfo.downloadNum);
|
||||
$("#view_num").html(shareInfo.ViewNum);
|
||||
shareTime = new Date(shareInfo.shareDate).format("yyyy年MM月dd日 hh:mm");
|
||||
shareTime = formateDate(shareInfo.shareDate);
|
||||
$("#share_time").html(shareTime);
|
||||
$("#download").click(function() {
|
||||
$.post("/Share/getDownloadUrl", {
|
||||
@@ -95,6 +80,10 @@
|
||||
video: {
|
||||
url: url
|
||||
},
|
||||
danmaku: {
|
||||
id: 'Cloudreve_'+shareInfo.shareId,
|
||||
api: 'https://api.prprpr.me/dplayer/'
|
||||
}
|
||||
});
|
||||
dp.on("fullscreen", function(){
|
||||
$(".modal-backdrop").hide();
|
||||
@@ -148,9 +137,9 @@
|
||||
$(".file-sign").html('<i class="fa fa-file-movie-o" aria-hidden="true"></i>')
|
||||
$("#previewButton").click(function() {
|
||||
if (shareInfo.allowPreview) {
|
||||
$(".previewContent").html('<div id="preview-target" style="width: 100%;object-fit: fill" class="preview"></div>');
|
||||
$('#previewModal').modal();
|
||||
$(".previewContent").html('<div id="preview-target" style="width: 100%;object-fit: fill;height:400px" class="preview"></div>');
|
||||
loadDPlayer('/Share/Preview/' + shareInfo.shareId);
|
||||
$('#previewModal').modal();
|
||||
} else {
|
||||
toastr["error"]("请先登录")
|
||||
}
|
||||
|
||||
@@ -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 } ?>
|
||||
|
||||
Reference in New Issue
Block a user