mirror of
https://github.com/cloudreve/Cloudreve.git
synced 2024-04-21 12:31:40 +00:00
Compare commits
151
Commits
1.0.0
...
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 | ||
|
|
24789ca8a9 | ||
|
|
544769bf04 | ||
|
|
85119bc54d | ||
|
|
d3061f0526 | ||
|
|
4492991bbb | ||
|
|
1e79428425 | ||
|
|
c28f08c210 | ||
|
|
0e0f7d5258 | ||
|
|
d2ca69b945 | ||
|
|
9cb572f0da | ||
|
|
9994f12aa8 | ||
|
|
20b7d67adc | ||
|
|
63cc404d74 | ||
|
|
47f334b6f4 | ||
|
|
1431f433d1 | ||
|
|
b6c1382e73 | ||
|
|
02ce111717 | ||
|
|
02d00d9b19 | ||
|
|
25c86357da | ||
|
|
bb49ff1b5f | ||
|
|
f33414c643 | ||
|
|
c1eebc7bf7 | ||
|
|
90a0b34b3e | ||
|
|
60cd53895d | ||
|
|
a97df81a9e | ||
|
|
3fdc327bb0 | ||
|
|
d02899328d | ||
|
|
34767dd9b0 | ||
|
|
85609ddbd8 | ||
|
|
d6aa3ca86f | ||
|
|
9e33129e7d | ||
|
|
8c54632ccd | ||
|
|
dda74f16ce | ||
|
|
69b540708e | ||
|
|
f290658cd0 | ||
|
|
842f7bf052 | ||
|
|
7998513e4e | ||
|
|
dd3552fefd | ||
|
|
f238dc14ca | ||
|
|
865538f437 | ||
|
|
c6fbca185d | ||
|
|
19fb84efa8 | ||
|
|
0be66f7897 | ||
|
|
ebb99e9515 | ||
|
|
6f911908ed | ||
|
|
d163808d45 |
@@ -4,5 +4,6 @@
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
|
||||
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
|
||||
</IfModule>
|
||||
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
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace CloudreveInstaller;
|
||||
|
||||
use Composer\Script\Event;
|
||||
|
||||
class Installer{
|
||||
|
||||
public static function startInstall(Event $event){
|
||||
$version = json_decode(file_get_contents("application/version.json"),true)["version"];
|
||||
$ioContext = $event->getIO();
|
||||
$welcomMsg = "
|
||||
___ _ _
|
||||
/ __\ | ___ _ _ __| |_ __ _____ _____
|
||||
/ / | |/ _ \| | | |/ _` | '__/ _ \ \ / / _ \
|
||||
/ /___| | (_) | |_| | (_| | | | __/\ V / __/
|
||||
\____/|_|\___/ \__,_|\__,_|_| \___| \_/ \___|
|
||||
|
||||
Ver $version
|
||||
================================================
|
||||
";
|
||||
$ioContext->write($welcomMsg);
|
||||
$sqlInfo = self::getSqlInformation($event);
|
||||
$ioContext->write("");
|
||||
$siteUrl=$ioContext->ask("The full-url to access to your Cloudreve (e.g. https://pan.aoaoao.me/ , 'http' must be included in the front and '/' must be included at the end):");
|
||||
$ioContext->write("");
|
||||
if(!file_exists('mysql.sql')){
|
||||
$ioContext->writeError("[Error] The file mysql.sql not exist.\nInstaller will exit.To retry, run 'composer install'");
|
||||
exit();
|
||||
}
|
||||
$sqlSource = file_get_contents('mysql.sql');
|
||||
$sqlSource = str_replace("https://cloudreve.org/", $siteUrl, $sqlSource);
|
||||
$mysqli = @new \mysqli($sqlInfo["hostname"], $sqlInfo["username"], $sqlInfo["password"], $sqlInfo["database"], $sqlInfo["hostport"]);
|
||||
$ioContext->write("=======================");
|
||||
$ioContext->write("Starting import sql file...");
|
||||
if ($mysqli->multi_query($sqlSource)) {
|
||||
$ioContext->write("Writing complete.");
|
||||
$ioContext->write("Writing database.php...");
|
||||
if(file_exists('application/database.php')){
|
||||
$ioContext->writeError("[Error] The file database.php already exist.\nInstaller will exit.To retry, run 'composer install'");
|
||||
$ioContext->write("=======================");
|
||||
exit();
|
||||
}
|
||||
self::writrConfig($event,$sqlInfo);
|
||||
$ioContext->write("=======================");
|
||||
}else{
|
||||
$ioContext->writeError("[Error] Writing failed.Installer will exit. To retry, run 'composer install'");
|
||||
$ioContext->write("=======================");
|
||||
}
|
||||
$ioContext->write("");
|
||||
$ioContext->write("Congratulations! Cloudreve has been installed successfully.");
|
||||
$ioContext->write("");
|
||||
$ioContext->write("Here's some informatioin about yor Cloudreve:");
|
||||
$ioContext->write("Homepage: $siteUrl");
|
||||
$ioContext->write("Admin Panel: ".$siteUrl."Admin");
|
||||
$ioContext->write("Default username: admin@cloudreve.org");
|
||||
$ioContext->write("Default password: admin");
|
||||
$ioContext->write("");
|
||||
$ioContext->write("=======================");
|
||||
$ioContext->write("IMPORTANT! You may still have to configure the URL Rewrite to set everthing to work.");
|
||||
$ioContext->write("Refer to the install manual for more informatioin.");
|
||||
$ioContext->write("=======================");
|
||||
self::sendFeedBack($siteUrl);
|
||||
}
|
||||
|
||||
public static function writrConfig(Event $event,$sqlInfo){
|
||||
$ioContext = $event->getIO();
|
||||
try {
|
||||
$fileContent = file_get_contents("CloudreveInstaller/database_sample.php");
|
||||
$replacement = array(
|
||||
'{hostname}' => $sqlInfo["hostname"],
|
||||
'{database}' => $sqlInfo["database"],
|
||||
'{username}' => $sqlInfo["username"],
|
||||
'{password}' => $sqlInfo["password"],
|
||||
'{hostport}' => $sqlInfo["hostport"],
|
||||
);
|
||||
$fileContent = strtr($fileContent,$replacement);
|
||||
file_put_contents('application/database.php',$fileContent);
|
||||
}catch (Exception $e) {
|
||||
$ioContext->writeError("[Error] Writing failed.Installer will exit. To retry, run 'composer install'");
|
||||
}
|
||||
$ioContext->write("Writing complete.");
|
||||
}
|
||||
|
||||
public static function getSqlInformation(Event $event){
|
||||
$ioContext = $event->getIO();
|
||||
$hostname=$ioContext->ask("Input the hostname of your MySQL server (Default:127.0.0.1):","127.0.0.1");
|
||||
$database=$ioContext->ask("The database name:","127.0.0.1");
|
||||
$username=$ioContext->ask("The username of your MySQL server (Default:root):","root");
|
||||
$password=$ioContext->ask("The password of your MySQL server:");
|
||||
$hostport=$ioContext->ask("The hostport of your MySQL server (Default:3306):","3306");
|
||||
$mysqli = @new \mysqli($hostname, $username, $password, $database, $hostport);
|
||||
if ($mysqli->connect_error) {
|
||||
$ioContext->writeError("[Error] Cannot connect to MySQL server, Message:".$mysqli->connect_error);
|
||||
$ioContext->write("");
|
||||
$ioContext->write("Please confirm your connection informatioin:");
|
||||
@$mysqli->close();
|
||||
return self::getSqlInformation($event);
|
||||
}
|
||||
return [
|
||||
"hostname" => $hostname,
|
||||
"database" => $database,
|
||||
"username" => $username,
|
||||
"password" => $password,
|
||||
"hostport" => $hostport,
|
||||
];
|
||||
}
|
||||
|
||||
public static function sendFeedBack($url){
|
||||
@file_get_contents("http://toy.aoaoao.me/feedback.php?url=".urlencode($url));
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -13,15 +13,15 @@ return [
|
||||
// 数据库类型
|
||||
'type' => 'mysql',
|
||||
// 服务器地址
|
||||
'hostname' => '127.0.0.1',
|
||||
'hostname' => '{hostname}',
|
||||
// 数据库名
|
||||
'database' => 'lite',
|
||||
'database' => '{database}',
|
||||
// 用户名
|
||||
'username' => 'root',
|
||||
'username' => '{username}',
|
||||
// 密码
|
||||
'password' => 'root',
|
||||
'password' => '{password}',
|
||||
// 端口
|
||||
'hostport' => '3306',
|
||||
'hostport' => '{hostport}',
|
||||
// 连接dsn
|
||||
'dsn' => '',
|
||||
// 数据库连接参数
|
||||
@@ -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>
|
||||
@@ -2,18 +2,21 @@
|
||||
|
||||
Cloudreve - Make the cloud easy for everyone
|
||||
=========================
|
||||
[](https://packagist.org/packages/hfo4/cloudreve)
|
||||
[](https://packagist.org/packages/hfo4/cloudreve)
|
||||
[](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,当然,还有本地存储
|
||||
* 可限制单文件最大大小、MMMEType、文件后缀、用户可用容量
|
||||
* 快速对接多家云存储,支持七牛、又拍云、阿里云OSS、AWS S3、Onedrive、自建远程服务器,当然,还有本地存储
|
||||
* 可限制单文件最大大小、MIMEType、文件后缀、用户可用容量
|
||||
* 基于Aria2的离线下载
|
||||
* 图片、音频、视频、文本、Markdown、Ofiice文档 在线预览
|
||||
* 移动端全站响应式布局
|
||||
* 文件、目录分享系统,可创建私有分享或公开分享链接
|
||||
@@ -22,19 +25,87 @@ Cloudreve - Make the cloud easy for everyone
|
||||
* 初步完善的后台,方便管理
|
||||
* 拖拽上传、分片上传、断点续传、下载限速(*实验性功能)
|
||||
* 多上传策略,可为不同用户组分配不同策略
|
||||
* 用户组基础权限设置
|
||||
* 用户组基础权限设置、二步验证
|
||||
* WebDAV协议支持
|
||||
|
||||
To-do:
|
||||
|
||||
* - [x] 重写目录分享和单文件分享页面样式
|
||||
* - [x] 增加保存其他用户的分享到自己账户(限Pro版)
|
||||
* - [x] 推出辅助程序,并借此实现:
|
||||
* - [ ] 压缩包解压缩、文件压缩
|
||||
* - [ ] 对接Ondrive、Google Drive,上传模式为先上到自己服务器,然后中转
|
||||
|
||||
安装需求
|
||||
------------
|
||||
* LNMP/LAMP With PHP5.6+
|
||||
* LNMP/AMP With PHP5.6+
|
||||
* curl、fileinfo、gd扩展
|
||||
* Composer
|
||||
|
||||
简要安装说明
|
||||
------------
|
||||
|
||||
Coming Soon...
|
||||
#### 1.使用Composer安装主程序
|
||||
```
|
||||
#安装开发版
|
||||
$ composer create-project hfo4/cloudreve:dev-master
|
||||
```
|
||||
|
||||
```
|
||||
#等待安装依赖库后,会自动执行安装脚本,按照提示输入数据库账户信息
|
||||
___ _ _
|
||||
/ __\ | ___ _ _ __| |_ __ _____ _____
|
||||
/ / | |/ _ \| | | |/ _` | '__/ _ \ \ / / _ \
|
||||
/ /___| | (_) | |_| | (_| | | | __/\ V / __/
|
||||
\____/|_|\___/ \__,_|\__,_|_| \___| \_/ \___|
|
||||
|
||||
Ver XX
|
||||
================================================
|
||||
#按提示输入信息
|
||||
......
|
||||
```
|
||||
|
||||
```
|
||||
#出现如下提示表示安装完成
|
||||
Congratulations! Cloudreve has been installed successfully.
|
||||
|
||||
Here's some informatioin about yor Cloudreve:
|
||||
Homepage: https://pan.aoaoao.me/
|
||||
Admin Panel: https://pan.aoaoao.me/Admin
|
||||
Default username: admin@cloudreve.org
|
||||
Default password: admin
|
||||
```
|
||||
|
||||
#### 2.目录权限
|
||||
`runtime`目录需要写入权限,如果你使用本地存储,`public` 目录也需要有写入权限
|
||||
|
||||
#### 3.URL重写
|
||||
对于Apache服务器,项目目录下的`.htaccess`已经配置好重写规则,如有需求酌情修改.
|
||||
对于Nginx服务器,以下是一个可供参考的配置:
|
||||
```
|
||||
location / {
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^(.*)$ /index.php?s=/$1 last;
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.完成
|
||||
后台地址:`http://您的域名/Admin` 初始用户名:`admin@cloudreve.org` 初始密码:`admin`
|
||||
#### 后续操作
|
||||
以下操作不是必须的,但仍推荐你完成这些操作:
|
||||
* 修改初始账户密码
|
||||
* 到 设置-基础设置 中更改站点URL,如果不更改,程序无法正常接受回调请求
|
||||
* 添加Crontab定时任务 :你的域名/Cron
|
||||
* 如果你打算使用本地上传策略并且不准备开启外链功能,请将·public/uploads·目录设置为禁止外部访问
|
||||
* 如需启用二步验证功能,请依次执行`composer require phpgangsta/googleauthenticator:dev-master` `composer require endroid/qr-code`安装二步验证支持库
|
||||
* 给本项目一个Star~
|
||||
|
||||
文档
|
||||
------------
|
||||
* [完整安装说明](https://github.com/HFO4/Cloudreve/wiki/%E5%AE%89%E8%A3%85%E8%AF%B4%E6%98%8E)
|
||||
* [安装及初次使用FAQ](https://github.com/HFO4/Cloudreve/wiki/%E5%AE%89%E8%A3%85%E5%8F%8A%E5%88%9D%E6%AC%A1%E4%BD%BF%E7%94%A8FAQ)
|
||||
|
||||
许可证
|
||||
------------
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
database.php
|
||||
@@ -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.'));
|
||||
}
|
||||
@@ -409,6 +445,18 @@ class Admin extends Controller{
|
||||
]);
|
||||
}
|
||||
|
||||
public function PolicyAddRemote(){
|
||||
return view('add_policy_remote', [
|
||||
'options' => $this->siteOptions,
|
||||
]);
|
||||
}
|
||||
|
||||
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', [
|
||||
@@ -444,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'));
|
||||
@@ -81,4 +82,11 @@ class Callback extends Controller{
|
||||
$handllerObj -> s3Handler($callbackKey);
|
||||
}
|
||||
|
||||
public function Remote(){
|
||||
ob_end_clean();
|
||||
header('Content-Type: application/json');
|
||||
$handllerObj = new CallbackHandler(file_get_contents("php://input"));
|
||||
$handllerObj -> remoteHandler(Request::instance()->header('Authorization'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ class Member extends Controller{
|
||||
}
|
||||
|
||||
public function ForgetPwd(){
|
||||
if(input('?post.regEmail') && input('?post.captchaCode') && !empty(input('post.captchaCode')) && !empty(input('post.regEmail'))){
|
||||
if(input('?post.regEmail') && !empty(input('post.regEmail'))){
|
||||
$findAction = User::findPwd(input('post.regEmail'),input('post.captchaCode'));
|
||||
if ($findAction[0]){
|
||||
return json(['code' => '200','message' => $findAction[1]]);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
|
||||
class B2 extends Model{
|
||||
|
||||
public $policy;
|
||||
private $ak;
|
||||
|
||||
public function __construct($policy){
|
||||
$this->policy = $policy;
|
||||
$akInfo = explode(":",$this->policy["ak"]);
|
||||
$this->ak = $akInfo[0];
|
||||
if(time()-$akInfo[1]>=86000){
|
||||
$this->updateAuth();
|
||||
}
|
||||
}
|
||||
|
||||
private function updateAuth(){
|
||||
$credentials = base64_encode($this->ak . ":" . $this->policy["sk"]);
|
||||
$url = "https://api.backblazeb2.com/b2api/v1/b2_authorize_account";
|
||||
$session = curl_init($url);
|
||||
$headers = array();
|
||||
$headers[] = "Accept: application/json";
|
||||
$headers[] = "Authorization: Basic " . $credentials;
|
||||
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($session, CURLOPT_HTTPGET, true);
|
||||
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($session, CURLOPT_SSL_VERIFYPEER, false); //不验证证书
|
||||
curl_setopt($session, CURLOPT_SSL_VERIFYHOST, false); //不验证证书
|
||||
$server_output = curl_exec($session);
|
||||
curl_close ($session);
|
||||
$authInfo = json_decode($server_output,true);
|
||||
Db::name("policy")->where("id",$this->policy["id"])
|
||||
->update([
|
||||
"ak" => $this->ak . ":" . time(),
|
||||
"op_name" => $authInfo["apiUrl"],
|
||||
"url" => $authInfo["downloadUrl"],
|
||||
"op_pwd" => $authInfo["authorizationToken"],
|
||||
]);
|
||||
$this->policy = Db::name("policy")->where("id",$this->policy["id"])->find();
|
||||
$this->updateUploadAuth();
|
||||
}
|
||||
|
||||
private function updateUploadAuth(){
|
||||
$session = curl_init($this->policy["op_name"] . "/b2api/v1/b2_get_upload_url");
|
||||
$data = array("bucketId" => $this->policy["bucketname"]);
|
||||
$post_fields = json_encode($data);
|
||||
curl_setopt($session, CURLOPT_POSTFIELDS, $post_fields);
|
||||
$headers = array();
|
||||
$headers[] = "Authorization: " . $this->policy["op_pwd"];
|
||||
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($session, CURLOPT_SSL_VERIFYPEER, false); //不验证证书
|
||||
curl_setopt($session, CURLOPT_SSL_VERIFYHOST, false); //不验证证书
|
||||
curl_setopt($session, CURLOPT_POST, true);
|
||||
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
|
||||
$server_output = curl_exec($session);
|
||||
curl_close ($session);
|
||||
$authInfo = json_decode($server_output,true);
|
||||
Db::name("policy")->where("id",$this->policy["id"])
|
||||
->update([
|
||||
"server" => $authInfo["uploadUrl"] . "|" . $authInfo["authorizationToken"],
|
||||
]);
|
||||
$this->policy = Db::name("policy")->where("id",$this->policy["id"])->find();
|
||||
die("");
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -20,6 +20,28 @@ class CallbackHandler extends Model{
|
||||
$this->CallbackData = $data;
|
||||
}
|
||||
|
||||
public function remoteHandler($header){
|
||||
$jsonData = json_decode(base64_decode($this->CallbackData),true);
|
||||
$CallbackSqlData = Db::name('callback')->where('callback_key',$jsonData['callbackkey'])->find();
|
||||
$this->policyData = Db::name('policy')->where('id',$CallbackSqlData['pid'])->find();
|
||||
if(!$this->IsRemoteCallback($header)){
|
||||
$this->setError("Undelegated Request");
|
||||
}
|
||||
if($this->policyData == null){
|
||||
$this->setError("CallbackKey Not Exist.");
|
||||
}
|
||||
if(!FileManage::sotrageCheck($CallbackSqlData["uid"],$jsonData["fsize"])){
|
||||
$this->setError("空间容量不足",true);
|
||||
}
|
||||
$picInfo = $jsonData["picinfo"];
|
||||
$addAction = FileManage::addFile($jsonData,$this->policyData,$CallbackSqlData["uid"],$picInfo);
|
||||
if(!$addAction[0]){
|
||||
$this->setError($addAction[1],true);
|
||||
}
|
||||
FileManage::storageCheckOut($CallbackSqlData["uid"],$jsonData["fsize"]);
|
||||
$this->setSuccess($jsonData['fname']);
|
||||
}
|
||||
|
||||
public function qiniuHandler($header){
|
||||
$jsonData = json_decode($this->CallbackData,true);
|
||||
$CallbackSqlData = Db::name('callback')->where('callback_key',$jsonData['callbackkey'])->find();
|
||||
@@ -172,6 +194,11 @@ class CallbackHandler extends Model{
|
||||
}
|
||||
}
|
||||
|
||||
private function IsRemoteCallback($header){
|
||||
$signKey = hash_hmac("sha256",$this->CallbackData,$this->policyData["sk"]);
|
||||
return ($signKey == $header);
|
||||
}
|
||||
|
||||
public function IsOssCallback($auth,$pubKey){
|
||||
if (empty($auth) || empty($pubKey)){
|
||||
header("http/1.1 403 Forbidden");
|
||||
|
||||
@@ -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,73 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
|
||||
class Remote extends Model{
|
||||
|
||||
public $sk;
|
||||
private $policy;
|
||||
private $serverOutput;
|
||||
private $httpCode;
|
||||
|
||||
public function __construct($policy){
|
||||
$this->policy = $policy;
|
||||
}
|
||||
|
||||
public function remove($fileList){
|
||||
$signKey = $this->sign($fileList,"DELETE");
|
||||
$this->send("manager.php",$signKey,"DELETE",base64_encode(json_encode($fileList)));
|
||||
}
|
||||
|
||||
public function preview($fname){
|
||||
return $this->signUrl($this->policy["url"]."object.php?action=preview&name=".urlencode($fname)."&expires=".(time()+(int)Option::getValue("timeout")));
|
||||
}
|
||||
|
||||
public function clean(){
|
||||
return $this->signUrl($this->policy["url"]."object.php?action=clean&expires=".(time()+(int)Option::getValue("timeout")));
|
||||
}
|
||||
|
||||
public function download($fname,$attnanme){
|
||||
return $this->signUrl($this->policy["url"]."object.php?action=download&name=".urlencode($fname)."&attaname=".urlencode($attnanme)."&expires=".(time()+(int)Option::getValue("timeout")));
|
||||
}
|
||||
|
||||
public function thumb($fname,$picInfo){
|
||||
return $this->signUrl($this->policy["url"]."object.php?action=thumb&name=".urlencode($fname)."&expires=".(time()+(int)Option::getValue("timeout"))."&w=".$picInfo[0]."&h=".$picInfo[1]);
|
||||
}
|
||||
|
||||
public function signUrl($url){
|
||||
$signKey = hash_hmac("sha256",$url,"GET".$this->policy["sk"]);
|
||||
return $url."&auth=".$signKey;
|
||||
}
|
||||
|
||||
public function updateContent($fname,$content){
|
||||
$object = ["fname"=>$fname,"content"=>$content];
|
||||
$signKey = $this->sign($object,"UPDATE");
|
||||
$this->send("manager.php",$signKey,"UPDATE",base64_encode(json_encode($object)));
|
||||
}
|
||||
|
||||
public function send($target,$auth,$action,$object){
|
||||
$session = curl_init($this->policy["server"].$target);
|
||||
$postData = array(
|
||||
"action" => $action,
|
||||
"auth" => $auth,
|
||||
"object" => $object,
|
||||
);
|
||||
curl_setopt($session, CURLOPT_POST, 1);
|
||||
curl_setopt($session, CURLOPT_POSTFIELDS, $postData);
|
||||
curl_setopt($session, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($session, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($session, CURLOPT_SSL_VERIFYHOST, false);
|
||||
$this->serverOutput = curl_exec($session);
|
||||
$this->httpCode = curl_getinfo($session,CURLINFO_HTTP_CODE);
|
||||
echo $this->serverOutput;
|
||||
}
|
||||
|
||||
public function sign($content,$method = null){
|
||||
return hash_hmac("sha256",base64_encode(json_encode($content)),$method.$this->policy["sk"]);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -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;
|
||||
@@ -228,6 +316,9 @@ class UploadHandler extends Model{
|
||||
case 's3':
|
||||
return $this->getS3Token();
|
||||
break;
|
||||
case 'remote':
|
||||
return $this->getRemoteToken();
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
@@ -295,6 +386,35 @@ class UploadHandler extends Model{
|
||||
return $token;
|
||||
}
|
||||
|
||||
private function getRemoteToken(){
|
||||
$callbackKey = $this->getRandomKey();
|
||||
$sqlData = [
|
||||
'callback_key' => $callbackKey,
|
||||
'pid' => $this->policyId,
|
||||
'uid' => $this->userId
|
||||
];
|
||||
Db::name('callback')->insert($sqlData);
|
||||
$policy = array(
|
||||
'callbackUrl' =>Option::getValue("siteURL").'Callback/Remote',
|
||||
'callbackKey' => $callbackKey,
|
||||
'callbackBodyType' => 'application/json',
|
||||
'fsizeLimit' => (int)$this->policyContent['max_size'],
|
||||
'uid' => $this->userId,
|
||||
);
|
||||
$dirName = $this->getObjName($this->policyContent['dirrule']);
|
||||
if($this->policyContent["autoname"]){
|
||||
$policy = array_merge($policy,array("saveKey" => $dirName.(empty($dirName)?"":"/").$this->getObjName($this->policyContent['namerule'])));
|
||||
}else{
|
||||
$policy = array_merge($policy,array("saveKey" => $dirName.(empty($dirName)?"":"/")."$(fname)"));
|
||||
}
|
||||
if(!empty($this->policyContent['mimetype'])){
|
||||
$policy = array_merge($policy,array("mimeLimit" => $this->policyContent['mimetype']));
|
||||
}
|
||||
$signingKey = hash_hmac("sha256",json_encode($policy),"UPLOAD".$this->policyContent['sk']);
|
||||
$token = $signingKey. ":" .base64_encode(json_encode($policy));
|
||||
return $token;
|
||||
}
|
||||
|
||||
static function upyunSign($key, $secret, $method, $uri, $date, $policy=null, $md5=null){
|
||||
$elems = array();
|
||||
foreach (array($method, $uri, $date, $policy, $md5) as $v){
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -87,7 +87,7 @@ class User extends Model{
|
||||
* @return [type] [description]
|
||||
*/
|
||||
static function register($userEmail,$userPass,$captchaCode){
|
||||
if(Option::getValue("login_captcha")=="1"){
|
||||
if(Option::getValue("reg_captcha")=="1"){
|
||||
if(!self::checkCaptcha($captchaCode)){
|
||||
return [false,"验证码错误"];
|
||||
}
|
||||
@@ -193,7 +193,7 @@ class User extends Model{
|
||||
}
|
||||
|
||||
static function findPwd($email,$captchaCode){
|
||||
if(Option::getValue("login_captcha")=="1"){
|
||||
if(Option::getValue("forget_captcha")=="1"){
|
||||
if(!self::checkCaptcha($captchaCode)){
|
||||
return [false,"验证码错误"];
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -67,11 +67,31 @@
|
||||
<img class="card-img-top" src="/static/img/s3.png" alt="Card image cap">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Amazon S3</h5>
|
||||
<p class="card-text"><a href="https://aws.amazon.com/cn/s3/?nc1=h_ls" target="_blank">Amazon S3</a>专为从任意位置存储和检索任意数量的数据而构建的对象存储</p>
|
||||
<p class="card-text"><a href="https://aws.amazon.com/cn/s3/?nc1=h_ls" target="_blank">Amazon S3</a>专为数据而构建的对象存储</p>
|
||||
<a href="/Admin/PolicyAddS3" class="btn btn-primary">添加</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 mt-2 md-2">
|
||||
<div class="card cloud">
|
||||
<img class="card-img-top" src="/static/img/remote.png" alt="Card image cap">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">远程服务器</h5>
|
||||
<p class="card-text">你可以将文件存放在不同于主程序的服务器上。<a href="https://github.com/HFO4/Cloudreve/wiki/%E8%BF%9C%E7%A8%8B%E5%AD%98%E5%82%A8%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%90%AD%E5%BB%BA">配置说明</a></p>
|
||||
<a href="/Admin/PolicyAddRemote" class="btn btn-primary">添加</a>
|
||||
</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>
|
||||
|
||||
@@ -430,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>
|
||||
@@ -440,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,170 @@
|
||||
{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="card" id="s3" >
|
||||
<div class="card-header">
|
||||
添加远程上传策略
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="qiniuPolicy">
|
||||
<input type="text" class="form-control" name="policy_type" value="remote" 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="ak" class="col-form-label col-form-label-sm">AccessToken </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="sk" required></div>
|
||||
<div class="col-md-4 option-des"> 默认随机生成,请与远程服务端配置文件中保持一致</div>
|
||||
</div>
|
||||
|
||||
<input type="text" class="form-control" name="ak" 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">
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="url" class="col-form-label col-form-label-sm">服务端URL</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="server" 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="url" class="col-form-label col-form-label-sm">下载根URL</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="url" 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">
|
||||
/public/uploads/
|
||||
</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>
|
||||
<script type="text/javascript">
|
||||
function randomString(len) {
|
||||
len = len || 32;
|
||||
var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
|
||||
var maxPos = $chars.length;
|
||||
var pwd = '';
|
||||
for (i = 0; i < len; i++) {
|
||||
pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
|
||||
}
|
||||
return pwd;
|
||||
}
|
||||
$("[name='sk']").val(randomString(32));
|
||||
</script>
|
||||
{/block}
|
||||
@@ -48,7 +48,7 @@
|
||||
</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>
|
||||
<label for="colFormLabelSm" class="col-form-label col-form-label-sm">站点描述</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="siteDes" value="{$options.siteDes}"></div>
|
||||
<div class="col-md-4 option-des"> 位于首页meta标签内的站点描述</div>
|
||||
|
||||
@@ -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}
|
||||
@@ -684,7 +684,7 @@
|
||||
{case value="s3"}
|
||||
<div class="card" id="s3" >
|
||||
<div class="card-header">
|
||||
添加S3上传策略
|
||||
编辑S3上传策略
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="Policy">
|
||||
@@ -804,6 +804,252 @@
|
||||
</div>
|
||||
|
||||
{/case}
|
||||
{case value="remote"}
|
||||
<div class="card" id="remote" >
|
||||
<div class="card-header">
|
||||
编辑远程上传策略
|
||||
</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="ak" class="col-form-label col-form-label-sm">AccessToken </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="sk" value="{$policy.sk}" 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="url" class="col-form-label col-form-label-sm">服务端URL</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="server" value="{$policy.server}" 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="url" class="col-form-label col-form-label-sm">下载根URL</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="url" value="{$policy.url}" 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">
|
||||
/public/uploads/
|
||||
</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="savePolicy">保存设置</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br> <br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<bn>
|
||||
</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>
|
||||
|
||||
@@ -42,6 +42,12 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-policy="s3">S3</a>
|
||||
</li>
|
||||
<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>
|
||||
@@ -78,6 +84,8 @@
|
||||
{case value="oss"}OSS{/case}
|
||||
{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}
|
||||
@@ -1,34 +1,23 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-ng-app="FileManagerApp">
|
||||
<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">
|
||||
<meta name="theme-color" content="#4e64d9"/>
|
||||
<title>我的文件 - {$options.siteName}</title>
|
||||
<!-- third party -->
|
||||
<script src="/static/js/angular.min.js"></script>
|
||||
<script src="/static/js/angular-translate.min.js"></script>
|
||||
|
||||
<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>
|
||||
<script src="/static/js/angular-filemanager.min.js"></script>
|
||||
<link rel="stylesheet" href="/static/css/photoswipe.css">
|
||||
<link rel="stylesheet" href="/static/css/default-skin/default-skin.css">
|
||||
|
||||
<!-- /Comment if you need to use raw source code -->
|
||||
<script type="text/javascript">
|
||||
uploadConfig={
|
||||
saveType : "{$policyData.policy_type}",
|
||||
@@ -39,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>
|
||||
@@ -106,4 +97,4 @@ upload_load=0;
|
||||
|
||||
</script>
|
||||
{$options.js_code}
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<!--Video-->
|
||||
<div class="intro-video view" id="home">
|
||||
<img src="static/img/output.jpg">
|
||||
|
||||
|
||||
|
||||
<div class="hm-gradient">
|
||||
@@ -16,7 +16,8 @@
|
||||
<hr class="hr-light">
|
||||
<h4 class="subtext-header mt-2 mb-2">只需十秒钟,注册后即可开始使用免费高速的云存储服务</h4>
|
||||
</div>
|
||||
<a href="/Login" class="btn btn-rounded btn-light-green-2" ><i class="fa fa-paper-plane-o"></i> 立即注册</a>
|
||||
<a href="/Login" class="btn btn-rounded btn-light-green-2" ><i class="fa fa-paper-plane-o"></i> 注册</a>
|
||||
<a href="/Home" class="btn btn-rounded btn-light-green-2" ><i class="fa fa-sign-in"></i> 登录</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-ng-app="FileManagerApp">
|
||||
<html lang="zh_cn" data-ng-app="FileManagerApp">
|
||||
<head>
|
||||
<!--
|
||||
* Angular FileManager v1.5.1 (https://github.com/joni2back/angular-filemanager)
|
||||
@@ -80,4 +80,4 @@ upload_load=0;
|
||||
|
||||
</script>
|
||||
{$options.js_code}
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -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}
|
||||
@@ -15,7 +15,7 @@ Route::rule([
|
||||
's/:key'=>'index/Share/index',
|
||||
'Share/Download/:key'=>'index/Share/Download',
|
||||
'Share/Preview/:key'=>'index/Share/Preview',
|
||||
'Share/List/:key'=>'index/Share/List',
|
||||
'Share/ListFile/:key'=>'index/Share/ListFile',
|
||||
'Login'=>'index/Member/LoginForm',
|
||||
'Member/emailActivate/:key'=>'index/Member/emailActivate',
|
||||
'Member/resetPwd/:key'=>'index/Member/resetPwd',
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"type":"","version":"1.0 Beta","version_id":1}
|
||||
{"type":"","version":"1.1.0","version_id":5,"db_version":3}
|
||||
+31
-19
@@ -6,33 +6,45 @@
|
||||
"type": "project",
|
||||
"license": "GPL-3.0-only",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Aaron",
|
||||
"email": "abslant@foxmail.com",
|
||||
"homepage": "https://aoaoao.me",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Qnner",
|
||||
"email": "admin@qnner.com",
|
||||
"homepage": "http://me.qnner.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "dune",
|
||||
"email": "rainaysann@gmail.com",
|
||||
"homepage": "https://github.com/rainays",
|
||||
"role": "Developer"
|
||||
}
|
||||
{
|
||||
"name": "Aaron",
|
||||
"email": "abslant@foxmail.com",
|
||||
"homepage": "https://aoaoao.me",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Qnner",
|
||||
"email": "admin@qnner.com",
|
||||
"homepage": "http://me.qnner.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "dune",
|
||||
"email": "rainaysann@gmail.com",
|
||||
"homepage": "https://github.com/rainays",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"ext-curl":"*",
|
||||
"ext-fileinfo":"*",
|
||||
"ext-gd":"*",
|
||||
"topthink/think-captcha":"1.*",
|
||||
"endroid/qrcode": "1.*",
|
||||
"aliyuncs/oss-sdk-php": "~2.0",
|
||||
"sabre/dav":"~3.2.0",
|
||||
"upyun/sdk": "^3.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"CloudreveInstaller\\Installer" : ""
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-install-cmd": [
|
||||
"CloudreveInstaller\\Installer::startInstall"
|
||||
],
|
||||
"post-create-project-cmd" : [
|
||||
"CloudreveInstaller\\Installer::startInstall"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -1,2 +1,3 @@
|
||||
*
|
||||
!.gitignore
|
||||
!.gitignore
|
||||
!chunks
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
Vendored
+2
File diff suppressed because one or more lines are too long
+1042
-1
File diff suppressed because one or more lines are too long
@@ -1 +1,4 @@
|
||||
.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{position:relative;top:-180px;z-index:4;overflow:hidden}.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}.l-block{background:#fff;border-radius:2px;max-width:350px;width:100%;vertical-align:middle;position:relative;display:none;text-align:left}.palette-Teal.bg{background-color:#009688}.card_top{border-top-left-radius:2px;border-top-right-radius:2px}.card_botom{background-color:#f7f7f7;border-bottom-left-radius:2px;border-bottom-right-radius:2px}.card-top-row{padding:25px 30px;color:#fff}.top-color{background-color:#3f51b5;margin-right:0;margin-left:0;border-top-left-radius:2px;border-top-right-radius:2px}.bottom-width{margin-right:0;margin-left:0;padding:25px;padding-top:5px}.login-icon{font-size:40px}.login-text{margin-top:10px;margin-left:-5px}.form-group{padding-bottom:0}.noWave{display:initial}.link-group{margin-left:5px;line-height:25px}[alt=captcha]{width:150px}
|
||||
.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{position:relative;top:-180px;z-index:4;overflow:hidden}.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}.l-block{background:#fff;border-radius:2px;max-width:350px;width:100%;vertical-align:middle;position:relative;display:none;text-align:left}.palette-Teal.bg{background-color:#009688}.card_top{border-top-left-radius:2px;border-top-right-radius:2px}.card_botom{background-color:#f7f7f7;border-bottom-left-radius:2px;border-bottom-right-radius:2px}.card-top-row{padding:25px 30px;color:#fff}.top-color{background-color:#3f51b5;margin-right:0;margin-left:0;border-top-left-radius:2px;border-top-right-radius:2px}.bottom-width{margin-right:0;margin-left:0;padding:25px;padding-top:5px}.login-icon{font-size:40px}.login-text{margin-top:10px;margin-left:-5px}.form-group{padding-bottom:0}.noWave{display:initial}.link-group{margin-left:5px;line-height:25px}[alt=captcha]{width:150px}
|
||||
.form-group.is-focused label, .form-group.is-focused label.control-label {
|
||||
color: #3F51B5;
|
||||
}
|
||||
+23
-1
File diff suppressed because one or more lines are too long
+4
-1
@@ -1 +1,4 @@
|
||||
.intro-page .navbar:not(.top-nav-collapse){background:0 0!important;box-shadow:none}.full-height,.full-height body,.full-height header,.full-height header .view{height:100%}.intro-page .navbar:not(.top-nav-collapse){background:0 0!important;box-shadow:none}.creative-lp .navbar{background-color:#6d7275}.grey-skin .navbar{background-color:#7d8488}.navbar{font-weight:300}.navbar.navbar-dark .navbar-brand{color:#fff}.navbar .navbar-brand{-webkit-align-self:flex-start;-ms-flex-item-align:start;align-self:flex-start;overflow:visible}.full-height,.full-height body,.full-height header,.full-height header .view{height:100%}header .view{position:relative;width:100%;height:auto;background-repeat:no-repeat;background-position:center center;-webkit-background-size:cover;-moz-background-size:cover;background-size:cover;-o-background-size:cover}header .view{position:relative;width:100%;height:auto;background-repeat:no-repeat;background-position:center center;background-size:cover}.view{overflow:hidden;position:relative;cursor:default}.creative-lp .hm-gradient .full-bg-img{background:-moz-linear-gradient(45deg,rgba(153,122,226,.6),rgba(3,3,4,.6) 100%);background:-webkit-linear-gradient(45deg,rgba(153,122,226,.6),rgba(3,3,4,.6) 100%);background:linear-gradient(to 45deg,rgba(153,122,226,.6),rgba(3,3,4,.6) 100%)}.full-bg-img{height:100%;width:100%;position:absolute;overflow:hidden;top:0;left:0}.card .card-circle,.card-overlay,.flex-center,.section.team-section .avatar,.testimonial-carousel .testimonial .avatar{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;height:100%}.white-text{color:#FFF!important}.brand-name{font-size:4.5rem}.font-bold{font-weight:500}.mb-2{margin-bottom:1.5rem!important}.hr-streak hr.hr-light,.intro hr.hr-light,.intro-video hr.hr-light{margin-left:31%;margin-right:31%;background-color:#fff;height:1px}.hr-streak hr,.intro hr,.intro-video hr{margin:1.5rem 0 1.5rem 0}.hr-light{background-color:#fff;height:.5px}.subtext-header{line-height:1.5}.btn-light-green-2{background:#00bfa5}.btn-rounded{-webkit-border-radius:10em;-moz-border-radius:10em;-ms-border-radius:10em;-o-border-radius:10em;border-radius:10em!important}.btn{border-radius:2px;border:0;transition:.2s ease-out;color:#fff!important;margin:6px;white-space:normal!important;word-wrap:break-word;text-transform:uppercase}.btn{font-size:.8rem;padding:.85rem 2.13rem}.badge,.btn,.btn-floating,.card,.card-cascade-2 .card-block,.card-cascade.wider .card-block,.card-wrapper .back,.card-wrapper .front,.cascading-media .view,.chip,.dropdown-content,.dropdown-menu,.jumbotron,.list-group,.modal-dialog.cascading-modal .modal-c-tabs .nav-tabs,.modal-dialog.modal-notify .modal-header,.navbar,.navbar .nav-item .dropdown-menu.dropdown a:active,.navbar .nav-item .dropdown-menu.dropdown a:focus,.navbar .nav-item .dropdown-menu.dropdown a:hover,.pager li a,.pagination .active .page-link,.popover,.pricing-card .price .version,.social-list,.top-nav-collapse,.z-depth-1{box-shadow:0 2px 5px 0 rgba(0,0,0,.16),0 2px 10px 0 rgba(0,0,0,.12)}.btn,.btn-floating{transition:.5s}
|
||||
.intro-page .navbar:not(.top-nav-collapse){background:0 0!important;box-shadow:none}.full-height,.full-height body,.full-height header,.full-height header .view{height:100%}.intro-page .navbar:not(.top-nav-collapse){background:0 0!important;box-shadow:none}.creative-lp .navbar{background-color:#6d7275}.grey-skin .navbar{background-color:#7d8488}.navbar{font-weight:300}.navbar.navbar-dark .navbar-brand{color:#fff}.navbar .navbar-brand{-webkit-align-self:flex-start;-ms-flex-item-align:start;align-self:flex-start;overflow:visible}.full-height,.full-height body,.full-height header,.full-height header .view{height:100%}header .view{position:relative;width:100%;height:auto;background-repeat:no-repeat;background-position:center center;-webkit-background-size:cover;-moz-background-size:cover;background-size:cover;-o-background-size:cover}header .view{position:relative;width:100%;height:auto;background-repeat:no-repeat;background-position:center center;background-size:cover}.view{overflow:hidden;position:relative;cursor:default}.creative-lp .hm-gradient .full-bg-img{background:-moz-linear-gradient(45deg,rgba(153,122,226,.6),rgba(3,3,4,.6) 100%);background:-webkit-linear-gradient(45deg,rgba(153,122,226,.6),rgba(3,3,4,.6) 100%);background:linear-gradient(to 45deg,rgba(153,122,226,.6),rgba(3,3,4,.6) 100%)}.full-bg-img{height:100%;width:100%;position:absolute;overflow:hidden;top:0;left:0}.card .card-circle,.card-overlay,.flex-center,.section.team-section .avatar,.testimonial-carousel .testimonial .avatar{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;height:100%}.white-text{color:#FFF!important}.brand-name{font-size:4.5rem}.font-bold{font-weight:500}.mb-2{margin-bottom:1.5rem!important}.hr-streak hr.hr-light,.intro hr.hr-light,.intro-video hr.hr-light{margin-left:31%;margin-right:31%;background-color:#fff;height:1px}.hr-streak hr,.intro hr,.intro-video hr{margin:1.5rem 0 1.5rem 0}.hr-light{background-color:#fff;height:.5px}.subtext-header{line-height:1.5}.btn-light-green-2{background:#00bfa5}.btn-rounded{-webkit-border-radius:10em;-moz-border-radius:10em;-ms-border-radius:10em;-o-border-radius:10em;border-radius:10em!important}.btn{border-radius:2px;border:0;transition:.2s ease-out;color:#fff!important;margin:6px;white-space:normal!important;word-wrap:break-word;text-transform:uppercase}.btn{font-size:.8rem;padding:.85rem 2.13rem}.badge,.btn,.btn-floating,.card,.card-cascade-2 .card-block,.card-cascade.wider .card-block,.card-wrapper .back,.card-wrapper .front,.cascading-media .view,.chip,.dropdown-content,.dropdown-menu,.jumbotron,.list-group,.modal-dialog.cascading-modal .modal-c-tabs .nav-tabs,.modal-dialog.modal-notify .modal-header,.navbar,.navbar .nav-item .dropdown-menu.dropdown a:active,.navbar .nav-item .dropdown-menu.dropdown a:focus,.navbar .nav-item .dropdown-menu.dropdown a:hover,.pager li a,.pagination .active .page-link,.popover,.pricing-card .price .version,.social-list,.top-nav-collapse,.z-depth-1{box-shadow:0 2px 5px 0 rgba(0,0,0,.16),0 2px 10px 0 rgba(0,0,0,.12)}.btn,.btn-floating{transition:.5s}
|
||||
.intro-video{
|
||||
background-image: url(/static/img/output.jpg);
|
||||
}
|
||||
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 |
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
Vendored
+2
File diff suppressed because one or more lines are too long
@@ -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();
|
||||
}
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user