mirror of
https://github.com/cloudreve/Cloudreve.git
synced 2024-04-21 12:31:40 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddc0b6ad4b | ||
|
|
75cbbcaa10 | ||
|
|
060f7a2081 | ||
|
|
a67185c750 | ||
|
|
38b11c1651 | ||
|
|
96b7f4c97d | ||
|
|
f600b21faa | ||
|
|
1693bf800b | ||
|
|
f39334125b | ||
|
|
9ee144d870 | ||
|
|
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 | ||
|
|
2807c1c79e | ||
|
|
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://t.me/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',
|
||||
];
|
||||
|
||||
@@ -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->Doit();
|
||||
if($task->status=="error"){
|
||||
$output->writeln("[Error] ".$task->errorMsg);
|
||||
Db::name("task")->where("id",$newTaskInfo["id"])->update(["status"=>"error|".$task->errorMsg]);
|
||||
}else{
|
||||
$output->writeln("[Complete]");
|
||||
Db::name("task")->where("id",$newTaskInfo["id"])->update(["status"=>"complete"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -29,12 +29,50 @@ class Admin extends Controller{
|
||||
}
|
||||
|
||||
public function index(){
|
||||
if($this->adminObj->checkDbVersion()){
|
||||
$this->redirect(url('/Admin/UpdateDb','',''));
|
||||
exit();
|
||||
}
|
||||
if($this->adminObj->checkCron()){
|
||||
$isCronOk = true;
|
||||
}else{
|
||||
$isCronOk = false;
|
||||
}
|
||||
return view('admin_index', [
|
||||
'options' => $this->siteOptions,
|
||||
'statics' => $this->adminObj->getStatics(),
|
||||
'isCronOk' => $isCronOk,
|
||||
]);
|
||||
}
|
||||
|
||||
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 +158,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 +254,14 @@ class Admin extends Controller{
|
||||
return $this->adminObj->saveMailSetting(input('post.'));
|
||||
}
|
||||
|
||||
public function SaveAria2Setting(){
|
||||
return $this->adminObj->saveAria2Setting(input('post.'));
|
||||
}
|
||||
|
||||
public function SaveTaskOption(){
|
||||
return $this->adminObj->saveTaskOption(input('post.'));
|
||||
}
|
||||
|
||||
public function SendTestMail(){
|
||||
return $this->adminObj->sendTestMail(input('post.'));
|
||||
}
|
||||
@@ -409,6 +455,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', [
|
||||
@@ -426,6 +484,15 @@ class Admin extends Controller{
|
||||
]);
|
||||
}
|
||||
|
||||
public function Queue(){
|
||||
$taskOption = Option::getValue("task_queue_token");
|
||||
return view('task', [
|
||||
'options' => $this->siteOptions,
|
||||
'taskOption' => $taskOption,
|
||||
'task' => $this->adminObj->getTasks(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function PurchaseGroup(){
|
||||
$groupData = json_decode(Option::getValue("group_sell_data"),true);
|
||||
foreach ($groupData as $key => $value) {
|
||||
@@ -444,5 +511,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,81 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use think\Db;
|
||||
use think\Request;
|
||||
|
||||
use \app\index\model\Task;
|
||||
use \app\index\model\Option;
|
||||
|
||||
class Queue extends Controller{
|
||||
|
||||
public function __construct(\think\Request $request = null){
|
||||
$token = Option::getValue("task_queue_token");
|
||||
if($token==""){
|
||||
abort(403);
|
||||
}
|
||||
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();
|
||||
$taskID = array_column($tasks,"id");
|
||||
Db::name("task")->where("id","in",$taskID)->update(["status"=>"processing"]);
|
||||
if(empty($tasks)){
|
||||
return "none";
|
||||
}else{
|
||||
return json_encode($tasks);
|
||||
}
|
||||
}
|
||||
|
||||
public function getPolicy(){
|
||||
$id = input("get.id");
|
||||
$policy = Db::name("policy")->where("id",$id)->find();
|
||||
if(empty(($policy))){
|
||||
abort(404);
|
||||
}else{
|
||||
return json($policy);
|
||||
}
|
||||
}
|
||||
|
||||
public function setSuccess(){
|
||||
$id = input("get.id");
|
||||
$task = new Task($id);
|
||||
$task->taskModel = Db::name("task")
|
||||
->where("id",$id)
|
||||
//->where("status","processing")
|
||||
->find();
|
||||
if(empty($task->taskModel)){
|
||||
return json(["error"=>true,"msg"=>"未找到任务"]);
|
||||
}
|
||||
return json($task->setSuccess());
|
||||
}
|
||||
|
||||
public function setError(){
|
||||
$id = input("get.id");
|
||||
$task = new Task($id);
|
||||
$task->taskModel = Db::name("task")
|
||||
->where("id",$id)
|
||||
//->where("status","processing")
|
||||
->find();
|
||||
if(empty($task->taskModel)){
|
||||
return json(["error"=>true,"msg"=>"未找到任务"]);
|
||||
}
|
||||
return json($task->Error());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,30 @@ 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 checkCron(){
|
||||
$cronRecord = Db::name("corn")->where("name","delete_unseful_chunks")->find();
|
||||
if($cronRecord["last_excute"]+$cronRecord["interval_s"]+"1800"<time()){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getStatics(){
|
||||
$statics["fileNum"] = Db::name('files')->count();
|
||||
$statics["privateShareNum"] = Db::name('shares')->where("type","private")->count();
|
||||
@@ -93,6 +113,14 @@ class AdminHandler extends Model{
|
||||
return $this->saveOptions($options);
|
||||
}
|
||||
|
||||
public function saveAria2Setting($options){
|
||||
return $this->saveOptions($options);
|
||||
}
|
||||
|
||||
public function saveTaskOption($options){
|
||||
return $this->saveOptions($options);
|
||||
}
|
||||
|
||||
public function saveMailTemplate($options){
|
||||
return $this->saveOptions($options);
|
||||
}
|
||||
@@ -102,6 +130,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 +159,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 +185,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 +366,55 @@ 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 getTasks(){
|
||||
$taskData = Db::name("task")
|
||||
->order("id DESC")
|
||||
->paginate(10);
|
||||
return $taskData;
|
||||
}
|
||||
|
||||
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 +469,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 +538,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 +583,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 +729,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" => (int)$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;
|
||||
}
|
||||
@@ -162,7 +168,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota{
|
||||
$dirName = end($explode);
|
||||
$rootPath = rtrim($path,"/".$dirName);
|
||||
$rootPath = empty($rootPath) ? "/" : $rootPath;
|
||||
$dirData = Db::name('folders')->where('owner',$this->uid)->where('position',dirname($path) == "\\" ?"/":dirname($path))->where("folder_name",basename($path))->find();
|
||||
$dirData = Db::name('folders')->where('owner',$this->uid)->where('position',dirname($path) == "\\" ?"/":dirname($path))->where("folder_name",getDirName($path))->find();
|
||||
if(empty($dirData)){
|
||||
return false;
|
||||
}
|
||||
|
||||
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,412 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\FileManage;
|
||||
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
|
||||
use \Krizalys\Onedrive\Client;
|
||||
use Sabre\DAV\Mock\File;
|
||||
|
||||
class Task extends Model{
|
||||
|
||||
public $taskModel;
|
||||
public $taskName;
|
||||
public $taskType;
|
||||
public $taskContent;
|
||||
public $input;
|
||||
public $output;
|
||||
public $userId;
|
||||
|
||||
public $status = "success";
|
||||
public $errorMsg;
|
||||
public $policyModel;
|
||||
|
||||
|
||||
public function __construct($id=null){
|
||||
if($id!==null){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存任务至数据库
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function saveTask(){
|
||||
Db::name("task")->insert([
|
||||
"task_name" => $this->taskName,
|
||||
"attr" => $this->taskContent,
|
||||
"type" => $this->taskType,
|
||||
"status" => "todo",
|
||||
"uid" => $this->userId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始执行任务
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function Doit(){
|
||||
switch ($this->taskModel["type"]){
|
||||
case "uploadSingleToOnedrive":
|
||||
$this->uploadSingleToOnedrive();
|
||||
break;
|
||||
case "UploadRegularRemoteDownloadFileToOnedrive":
|
||||
$this->uploadSingleToOnedrive();
|
||||
break;
|
||||
case "uploadChunksToOnedrive":
|
||||
$this->uploadChunksToOnedrive();
|
||||
break;
|
||||
case "UploadLargeRemoteDownloadFileToOnedrive":
|
||||
$this->uploadUnchunkedFile();
|
||||
break;
|
||||
default:
|
||||
$this->output->writeln("Unknown task type (".$this->taskModel["type"].")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传未分片的大文件至Onedrive
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function uploadUnchunkedFile(){
|
||||
$this->taskContent = json_decode($this->taskModel["attr"],true);
|
||||
$policyData = Db::name("policy")->where("id",$this->taskContent["policyId"])->find();
|
||||
$this->policyModel = $policyData;
|
||||
$onedrive = new Client([
|
||||
'stream_back_end' => \Krizalys\Onedrive\StreamBackEnd::TEMP,
|
||||
'client_id' => $policyData["bucketname"],
|
||||
|
||||
// Restore the previous state while instantiating this client to proceed in
|
||||
// obtaining an access token.
|
||||
'state' => json_decode($policyData["sk"]),
|
||||
]);
|
||||
|
||||
//创建分片上传Session,获取上传URL
|
||||
try{
|
||||
$uploadUrl = $onedrive->apiPost("/me/drive/root:/".rawurlencode($this->taskContent["savePath"] . "/" . $this->taskContent["objname"]).":/createUploadSession",[])->uploadUrl;
|
||||
}catch(\Exception $e){
|
||||
$this->status="error";
|
||||
$this->errorMsg = $e->getMessage();
|
||||
$this->cleanTmpChunk();
|
||||
return;
|
||||
}
|
||||
//创建分片上传Session,获取上传URL
|
||||
try{
|
||||
$uploadUrl = $onedrive->apiPost("/me/drive/root:/".rawurlencode($this->taskContent["savePath"] . "/" . $this->taskContent["objname"]).":/createUploadSession",[])->uploadUrl;
|
||||
}catch(\Exception $e){
|
||||
$this->status="error";
|
||||
$this->errorMsg = $e->getMessage();
|
||||
$this->cleanTmpChunk();
|
||||
return;
|
||||
}
|
||||
|
||||
//每次4MB上传文件
|
||||
|
||||
if(!$file = @fopen($this->taskContent["originPath"],"r")){
|
||||
$this->status="error";
|
||||
$this->errorMsg = "File not exist.";
|
||||
$this->cleanTmpChunk();
|
||||
return;
|
||||
}
|
||||
$offset = 0;
|
||||
$totalSize = filesize($this->taskContent["originPath"]);
|
||||
while (1) {
|
||||
//移动文件指针
|
||||
fseek($file, $offset);
|
||||
|
||||
$chunksize = (($offset+4*1024*1024)>$totalSize)?($totalSize-$offset):1024*4*1024;
|
||||
$headers = [];
|
||||
$headers[] = "Content-Length: ".$chunksize;
|
||||
$headers[] = "Content-Range: bytes ".$offset."-".($offset+$chunksize-1)."/".$this->taskContent["fsize"];
|
||||
|
||||
//发送单个分片数据
|
||||
try{
|
||||
$onedrive->sendFileChunk($uploadUrl,$headers,fread($file,$chunksize));
|
||||
}catch(\Exception $e){
|
||||
$this->status="error";
|
||||
$this->errorMsg = $e->getMessage();
|
||||
$this->cleanTmpChunk();
|
||||
return;
|
||||
}
|
||||
$this->output->writeln("[Info] Chunk Uploaded. Offset:".$offset);
|
||||
$offset+=$chunksize;
|
||||
if($offset+1 >=$totalSize){
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
fclose($file);
|
||||
$jsonData = array(
|
||||
"path" => $this->taskContent["path"],
|
||||
"fname" => $this->taskContent["fname"],
|
||||
"objname" => $this->taskContent["savePath"]."/".$this->taskContent["objname"],
|
||||
"fsize" => $this->taskContent["fsize"],
|
||||
);
|
||||
|
||||
$addAction = FileManage::addFile($jsonData,$policyData,$this->taskModel["uid"],$this->taskContent["picInfo"]);
|
||||
if(!$addAction[0]){
|
||||
$this->setError($addAction[1],true,"/me/drive/root:/".rawurlencode($this->taskContent["savePath"] . "/" . $this->taskContent["objname"]),$onedrive);
|
||||
$this->cleanTmpChunk();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cleanTmpChunk();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传已分片的大文件至Onedrive
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function uploadChunksToOnedrive(){
|
||||
$this->taskContent = json_decode($this->taskModel["attr"],true);
|
||||
$policyData = Db::name("policy")->where("id",$this->taskContent["policyId"])->find();
|
||||
$this->policyModel = $policyData;
|
||||
$onedrive = new Client([
|
||||
'stream_back_end' => \Krizalys\Onedrive\StreamBackEnd::TEMP,
|
||||
'client_id' => $policyData["bucketname"],
|
||||
|
||||
// Restore the previous state while instantiating this client to proceed in
|
||||
// obtaining an access token.
|
||||
'state' => json_decode($policyData["sk"]),
|
||||
]);
|
||||
|
||||
//创建分片上传Session,获取上传URL
|
||||
try{
|
||||
$uploadUrl = $onedrive->apiPost("/me/drive/root:/".rawurlencode($this->taskContent["savePath"] . "/" . $this->taskContent["objname"]).":/createUploadSession",[])->uploadUrl;
|
||||
}catch(\Exception $e){
|
||||
$this->status="error";
|
||||
$this->errorMsg = $e->getMessage();
|
||||
$this->cleanTmpChunk();
|
||||
return;
|
||||
}
|
||||
|
||||
//逐个上传文件分片
|
||||
$offset = 0;
|
||||
foreach ($this->taskContent["chunks"] as $key => $value) {
|
||||
$chunkPath = ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk";
|
||||
if(!$file = @fopen($chunkPath,"r")){
|
||||
$this->status="error";
|
||||
$this->errorMsg = "File chunk not exist.";
|
||||
$this->cleanTmpChunk();
|
||||
return;
|
||||
}
|
||||
$headers = [];
|
||||
$chunksize = filesize($chunkPath);
|
||||
$headers[] = "Content-Length: ".$chunksize;
|
||||
$headers[] = "Content-Range: bytes ".$offset."-".($offset+$chunksize-1)."/".$this->taskContent["fsize"];
|
||||
|
||||
//发送单个分片数据
|
||||
try{
|
||||
$onedrive->sendFileChunk($uploadUrl,$headers,$file);
|
||||
}catch(\Exception $e){
|
||||
$this->status="error";
|
||||
$this->errorMsg = $e->getMessage();
|
||||
$this->cleanTmpChunk();
|
||||
return;
|
||||
}
|
||||
$this->output->writeln("[Info] Chunk Uploaded. Offset:".$offset);
|
||||
$offset += $chunksize;
|
||||
fclose($file);
|
||||
|
||||
}
|
||||
|
||||
$jsonData = array(
|
||||
"path" => $this->taskContent["path"],
|
||||
"fname" => $this->taskContent["fname"],
|
||||
"objname" => $this->taskContent["savePath"]."/".$this->taskContent["objname"],
|
||||
"fsize" => $this->taskContent["fsize"],
|
||||
);
|
||||
|
||||
$addAction = FileManage::addFile($jsonData,$policyData,$this->taskModel["uid"],$this->taskContent["picInfo"]);
|
||||
if(!$addAction[0]){
|
||||
$this->setError($addAction[1],true,"/me/drive/root:/".rawurlencode($this->taskContent["savePath"] . "/" . $this->taskContent["objname"]),$onedrive);
|
||||
$this->cleanTmpChunk();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cleanTmpChunk();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传单文件(<=4mb)至Onedrive
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function uploadSingleToOnedrive(){
|
||||
$this->taskContent = json_decode($this->taskModel["attr"],true);
|
||||
$policyData = Db::name("policy")->where("id",$this->taskContent["policyId"])->find();
|
||||
$this->policyModel = $policyData;
|
||||
$onedrive = new Client([
|
||||
'stream_back_end' => \Krizalys\Onedrive\StreamBackEnd::TEMP,
|
||||
'client_id' => $policyData["bucketname"],
|
||||
|
||||
// Restore the previous state while instantiating this client to proceed in
|
||||
// obtaining an access token.
|
||||
'state' => json_decode($policyData["sk"]),
|
||||
]);
|
||||
|
||||
$filePath = $this->taskModel["type"] == "UploadRegularRemoteDownloadFileToOnedrive"?$this->taskContent["originPath"]:ROOT_PATH . 'public/uploads/'.$this->taskContent["savePath"] . "/" . $this->taskContent["objname"];
|
||||
if($file = @fopen($filePath,"r")){
|
||||
try{
|
||||
$onedrive->createFile(rawurlencode($this->taskContent["objname"]),"/me/drive/root:/".$this->taskContent["savePath"],$file);
|
||||
}catch(\Exception $e){
|
||||
$this->status="error";
|
||||
$this->errorMsg = $e->getMessage();
|
||||
$this->cleanTmpFile();
|
||||
return;
|
||||
}
|
||||
|
||||
$jsonData = array(
|
||||
"path" => $this->taskContent["path"],
|
||||
"fname" => $this->taskContent["fname"],
|
||||
"objname" => $this->taskContent["savePath"]."/".$this->taskContent["objname"],
|
||||
"fsize" => $this->taskContent["fsize"],
|
||||
);
|
||||
|
||||
$addAction = FileManage::addFile($jsonData,$policyData,$this->taskModel["uid"],$this->taskContent["picInfo"]);
|
||||
if(!$addAction[0]){
|
||||
$this->setError($addAction[1],true,"/me/drive/root:/".$this->taskContent["savePath"]."/".rawurlencode($this->taskContent["objname"]),$onedrive);
|
||||
$this->cleanTmpFile();
|
||||
return;
|
||||
}
|
||||
|
||||
fclose($file);
|
||||
$this->cleanTmpFile();
|
||||
}else{
|
||||
$this->status = "error";
|
||||
$this->errorMsg = "Failed to open file [".$filePath."]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除本地临时文件
|
||||
*
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
private function cleanTmpFile(){
|
||||
if($this->taskModel["type"] == "UploadRegularRemoteDownloadFileToOnedrive"){
|
||||
return @unlink($this->taskContent["originPath"]);
|
||||
}else{
|
||||
return @unlink(ROOT_PATH . 'public/uploads/'.$this->taskContent["savePath"] . "/" . $this->taskContent["objname"]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除本地临时分片
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function cleanTmpChunk(){
|
||||
if($this->taskModel["type"] == "UploadLargeRemoteDownloadFileToOnedrive"){
|
||||
@unlink($this->taskContent["originPath"]);
|
||||
}else{
|
||||
foreach ($this->taskContent["chunks"] as $key => $value) {
|
||||
@unlink( ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置为出错状态并清理远程文件
|
||||
*
|
||||
* @param string $msg 错误消息
|
||||
* @param bool $delete 是否删除文件
|
||||
* @param string $path 文件路径
|
||||
* @param mixed $adapter 远程操作适配器
|
||||
* @return void
|
||||
*/
|
||||
private function setError($msg,$delete,$path,$adapter){
|
||||
$this->status="error";
|
||||
$this->errorMsg = $msg;
|
||||
if($delete){
|
||||
switch($this->taskModel["type"]){
|
||||
case "uploadSingleToOnedrive":
|
||||
$adapter->deleteObject($path);
|
||||
break;
|
||||
case "uploadChunksToOnedrive":
|
||||
$adapter->deleteObject($path);
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
FileManage::storageGiveBack($this->taskModel["uid"],$this->taskContent["fsize"]);
|
||||
}
|
||||
|
||||
public function setSuccess(){
|
||||
$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"]),
|
||||
]);
|
||||
|
||||
$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();
|
||||
|
||||
Db::name("task")->where("id",$this->taskModel["id"])->update(["status"=>"error|".$this->errorMsg]);
|
||||
|
||||
return ["error"=>true,"msg"=>$this->errorMsg];
|
||||
}
|
||||
$this->cleanTmpFile();
|
||||
if($this->taskModel["type"] == "UploadLargeRemoteDownloadFileToOnedrive" || $this->taskModel["type"] == "uploadChunksToOnedrive"){
|
||||
$this->cleanTmpChunk();
|
||||
}
|
||||
Db::name("task")->where("id",$this->taskModel["id"])->update(["status"=>"complete"]);
|
||||
return ["error"=>false,"msg"=>null];
|
||||
}
|
||||
|
||||
public function Error(){
|
||||
$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"]),
|
||||
]);
|
||||
$this->setError("",false,"/me/drive/root:/".$this->taskContent["savePath"]."/".rawurlencode($this->taskContent["objname"]),$onedrive);
|
||||
$this->cleanTmpFile();
|
||||
if($this->taskModel["type"] == "UploadLargeRemoteDownloadFileToOnedrive" || $this->taskModel["type"] == "uploadChunksToOnedrive"){
|
||||
$this->cleanTmpChunk();
|
||||
}
|
||||
Db::name("task")->where("id",$this->taskModel["id"])->update(["status"=>"error"]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -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}
|
||||
@@ -11,7 +11,14 @@
|
||||
<li class="breadcrumb-item active">数据概况</li>
|
||||
</ol>
|
||||
<!-- Icon Cards-->
|
||||
{eq name="isCronOk" value="true"}
|
||||
{else/}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<strong>警告!Cron定时任务疑似未执行</strong><p>检测到<a href="/Admin/Cron">定时任务</a>未正常执行,请检查您的定时任务配置。您可以通过Crontab或者其他网站监控服务,让 “您的域名/Cron” 此地址每隔一段时间被访问一次。</p>
|
||||
</div>
|
||||
{/eq}
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xl-3 col-sm-6 mb-3">
|
||||
<div class="card text-white bg-primary o-hidden h-100">
|
||||
<div class="card-body">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
{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> 配置</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="taskOptions">
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="fromName" class="col-form-label col-form-label-sm">Token</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="task_queue_token" id="task_queue_token" value="{$taskOption}" spellcheck="false">
|
||||
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 任务队列鉴权Token,应该与任务队列配置文件conf.yaml中的token保持一致,留空表示禁止任务队列请求</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-outline-secondary" id="generateToken">随机生成Token</button> <button type="button" class="btn btn-primary" id="saveTask">保存设置</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">创建者UID</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="listContent">
|
||||
{volist name='task' id='t'}
|
||||
<tr id="i-{$t.id}" >
|
||||
<th scope="row" class="textCenter">{$t.id}</th>
|
||||
<td>{$t.task_name}</td>
|
||||
<td class="textCenter">{$t.status}</td>
|
||||
<td class="textCenter">{$t.addtime}</td>
|
||||
<td class="textCenter">{$t.uid}</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
</tbody>
|
||||
</table>
|
||||
{$task->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/task.js"></script>
|
||||
{/block}
|
||||
@@ -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>
|
||||
@@ -116,6 +122,9 @@
|
||||
<span class="nav-link-text">其他</span>
|
||||
</a>
|
||||
<ul class="sidenav-second-level collapse" id="else">
|
||||
<li>
|
||||
<a href="/Admin/Queue">任务队列</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/Admin/Cron">定时任务</a>
|
||||
</li>
|
||||
|
||||
@@ -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.1","version_id":6,"db_version":4}
|
||||
+32
-20
@@ -4,35 +4,47 @@
|
||||
"keywords": ["php", "cloud", "ThinkPHP", "file-sharing"],
|
||||
"homepage": "https://cloudreve.org",
|
||||
"type": "project",
|
||||
"license": "GPL-3.0-only",
|
||||
"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 |
Binary file not shown.
|
Before Width: | Height: | Size: 6.2 KiB |
Vendored
+2
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user