mirror of
https://github.com/cloudreve/Cloudreve.git
synced 2024-04-21 12:31:40 +00:00
Compare commits
237
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a530f5d58 | ||
|
|
88fac85ca5 | ||
|
|
9f658e86ec | ||
|
|
ebee2b09d9 | ||
|
|
836cb1a9c7 | ||
|
|
3c7aedc195 | ||
|
|
a11f81966d | ||
|
|
2c2e8b6052 | ||
|
|
3b7e9298b5 | ||
|
|
b341d3bc2c | ||
|
|
fd03047ed2 | ||
|
|
f15499d274 | ||
|
|
889b65163b | ||
|
|
1c05b9a0d3 | ||
|
|
00a2b452c4 | ||
|
|
721dad4abe | ||
|
|
ebb95b31c2 | ||
|
|
d854913cd2 | ||
|
|
94c3dd7420 | ||
|
|
9d8646c6f6 | ||
|
|
560e455618 | ||
|
|
51f8be8681 | ||
|
|
df8581e238 | ||
|
|
bf2f5e621f | ||
|
|
a4439ba210 | ||
|
|
822d9b4bba | ||
|
|
18bcd93d97 | ||
|
|
76ea49890d | ||
|
|
74d0afb441 | ||
|
|
b2d5547199 | ||
|
|
ef636bc2d1 | ||
|
|
3a4912083c | ||
|
|
737665c62c | ||
|
|
df42ac0e96 | ||
|
|
4880972d77 | ||
|
|
84e2ec0f19 | ||
|
|
53c79bfa65 | ||
|
|
41d1294ebf | ||
|
|
d84b00f35d | ||
|
|
da4f152438 | ||
|
|
3d82929a3b | ||
|
|
2e2357e794 | ||
|
|
c94e17a4da | ||
|
|
c741d79677 | ||
|
|
e0b4b42ec6 | ||
|
|
65dcedb3ca | ||
|
|
422f9d8d6a | ||
|
|
1fc4956a3f | ||
|
|
564578aefb | ||
|
|
12f98dd0f5 | ||
|
|
c33b6d587f | ||
|
|
277f882e8d | ||
|
|
68399a5877 | ||
|
|
6b4f999bc4 | ||
|
|
3514ff437c | ||
|
|
8c344b456d | ||
|
|
ff4fa3f9b2 | ||
|
|
d9fa51a615 | ||
|
|
6dd49fce09 | ||
|
|
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 | ||
|
|
f46684495c | ||
|
|
884949dad4 | ||
|
|
3f30ec3c7e | ||
|
|
93abecd2cb | ||
|
|
9395228a66 | ||
|
|
79c78a90f4 | ||
|
|
dcd392e70f | ||
|
|
935f74fa52 | ||
|
|
64f6cff7ce | ||
|
|
76c5d9ad8a | ||
|
|
3c90b83d11 | ||
|
|
224c2a66c6 | ||
|
|
7d6e026280 | ||
|
|
e9201d85f7 | ||
|
|
3b9040028d | ||
|
|
a7691a1d1d |
@@ -1 +0,0 @@
|
||||
custom: ["https://cloudreve.org/buy.php"]
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -1,59 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.13
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.13
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
clean: false
|
||||
submodules: 'recursive'
|
||||
- run: |
|
||||
git fetch --prune --unshallow --tags
|
||||
|
||||
- name: Get dependencies and build
|
||||
run: |
|
||||
go get github.com/rakyll/statik
|
||||
export PATH=$PATH:~/go/bin/
|
||||
statik -src=models -f
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install gcc-mingw-w64-x86-64
|
||||
sudo apt-get -y install gcc-arm-linux-gnueabihf libc6-dev-armhf-cross
|
||||
sudo apt-get -y install gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||
chmod +x ./build.sh
|
||||
./build.sh -r b
|
||||
|
||||
- name: Upload binary files (windows_amd64)
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: cloudreve_windows_amd64
|
||||
path: release/cloudreve*windows_amd64.*
|
||||
|
||||
- name: Upload binary files (linux_amd64)
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: cloudreve_linux_amd64
|
||||
path: release/cloudreve*linux_amd64.*
|
||||
|
||||
- name: Upload binary files (linux_arm)
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: cloudreve_linux_arm
|
||||
path: release/cloudreve*linux_arm.*
|
||||
|
||||
- name: Upload binary files (linux_arm64)
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: cloudreve_linux_arm64
|
||||
path: release/cloudreve*linux_arm64.*
|
||||
@@ -1,47 +0,0 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.13
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.13
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
go get github.com/rakyll/statik
|
||||
export PATH=$PATH:~/go/bin/
|
||||
statik -src=models -f
|
||||
|
||||
- name: Test
|
||||
run: go test -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
|
||||
- name: Upload binary files (linux_arm)
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: cloudreve_linux_arm
|
||||
path: release/cloudreve*linux_arm.*
|
||||
|
||||
- name: Upload binary files (linux_arm64)
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: cloudreve_linux_arm64
|
||||
path: release/cloudreve*linux_arm64.*
|
||||
+5
-30
@@ -1,30 +1,5 @@
|
||||
# Binaries for programs and plugins
|
||||
cloudreve
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
*.db
|
||||
*.bin
|
||||
/release/
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Development enviroment
|
||||
.idea/*
|
||||
uploads/*
|
||||
temp
|
||||
|
||||
# Version control
|
||||
version.lock
|
||||
|
||||
# Config file
|
||||
*.ini
|
||||
conf/conf.ini
|
||||
/statik/
|
||||
.vscode/
|
||||
*.map
|
||||
composer.lock
|
||||
*.chunk.js
|
||||
*.chunk.css
|
||||
runtime~*.js
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "assets"]
|
||||
path = assets
|
||||
url = https://github.com/cloudreve/frontend.git
|
||||
@@ -0,0 +1,9 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
Options +FollowSymlinks -Multiviews
|
||||
RewriteEngine On
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
|
||||
</IfModule>
|
||||
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
|
||||
+6
-29
@@ -1,30 +1,7 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.13.x
|
||||
node_js: "12.16.3"
|
||||
git:
|
||||
depth: 1
|
||||
install:
|
||||
- go get github.com/rakyll/statik
|
||||
language: php
|
||||
php:
|
||||
- 7.1
|
||||
before_script:
|
||||
- statik -src=models -f
|
||||
script:
|
||||
- go test -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
before_deploy:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y install gcc-mingw-w64-x86-64
|
||||
- sudo apt-get -y install gcc-arm-linux-gnueabihf libc6-dev-armhf-cross
|
||||
- sudo apt-get -y install gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||
- chmod +x ./build.sh
|
||||
- ./build.sh -r b
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key: $GITHUB_TOKEN
|
||||
file_glob: true
|
||||
file: release/*
|
||||
draft: true
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
- composer install
|
||||
- chmod +x ./deploy.sh
|
||||
script: ./deploy.sh
|
||||
@@ -0,0 +1,164 @@
|
||||
<?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);
|
||||
self::prepareStatic($event);
|
||||
$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 prepareStatic(Event $event){
|
||||
$ioContext = $event->getIO();
|
||||
$ioContext->write("Fetching static files from cloudreve.org...");
|
||||
if(!is_writable("runtime") || !is_writable("static")){
|
||||
$ioContext->writeError("[Error] 'runtime' or 'static' directory is not writable. To retry, run 'composer install'");
|
||||
exit();
|
||||
}
|
||||
if(file_exists("runtime/static.zip")){
|
||||
$ioContext->writeError("[Error] 'runtime/static.zip' already exist. To retry, run 'composer install'");
|
||||
exit();
|
||||
}
|
||||
if(file_exists("runtime/static")){
|
||||
$ioContext->writeError("[Error] directory 'runtime/static' already exist. To retry, run 'composer install'");
|
||||
exit();
|
||||
}
|
||||
try{
|
||||
file_put_contents("runtime/static.zip",file_get_contents("https://cloudreve.org/download.php?newestStatic"));
|
||||
}catch (Exception $e) {
|
||||
$ioContext->writeError("[Error] Failed to download static file. To retry, run 'composer install'");
|
||||
exit();
|
||||
}
|
||||
$ioContext->write("Unzip static files...");
|
||||
$zip = new \ZipArchive;
|
||||
$res = $zip->open('runtime/static.zip');
|
||||
if ($res === TRUE) {
|
||||
$zip->extractTo('runtime/static/');
|
||||
$zip->close();
|
||||
}else {
|
||||
$ioContext->writeError("[Error] Failed to open runtime/static.zip. To retry, run 'composer install'");
|
||||
exit();
|
||||
}
|
||||
self::recurse_copy("runtime/static/build/static", "static");
|
||||
}
|
||||
|
||||
public static function recurse_copy($src,$dst) {
|
||||
$dir = opendir($src);
|
||||
@mkdir($dst);
|
||||
while(false !== ( $file = readdir($dir)) ) {
|
||||
if (( $file != '.' ) && ( $file != '..' )) {
|
||||
if ( is_dir($src . '/' . $file) ) {
|
||||
self::recurse_copy($src . '/' . $file,$dst . '/' . $file);
|
||||
}else {
|
||||
copy($src . '/' . $file,$dst . '/' . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($dir);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 数据库类型
|
||||
'type' => 'mysql',
|
||||
// 服务器地址
|
||||
'hostname' => '{hostname}',
|
||||
// 数据库名
|
||||
'database' => '{database}',
|
||||
// 用户名
|
||||
'username' => '{username}',
|
||||
// 密码
|
||||
'password' => '{password}',
|
||||
// 端口
|
||||
'hostport' => '{hostport}',
|
||||
// 连接dsn
|
||||
'dsn' => '',
|
||||
// 数据库连接参数
|
||||
'params' => [],
|
||||
// 数据库编码默认采用utf8
|
||||
'charset' => 'utf8',
|
||||
// 数据库表前缀
|
||||
'prefix' => 'sd_',
|
||||
// 数据库调试模式
|
||||
'debug' => true,
|
||||
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
|
||||
'deploy' => 0,
|
||||
// 数据库读写是否分离 主从式有效
|
||||
'rw_separate' => false,
|
||||
// 读写分离后 主服务器数量
|
||||
'master_num' => 1,
|
||||
// 指定从服务器序号
|
||||
'slave_no' => '',
|
||||
// 是否严格检查字段是否存在
|
||||
'fields_strict' => true,
|
||||
// 数据集返回类型
|
||||
'resultset_type' => 'array',
|
||||
// 自动写入时间戳字段
|
||||
'auto_timestamp' => false,
|
||||
// 时间字段取出后的默认时间格式
|
||||
'datetime_format' => 'Y-m-d H:i:s',
|
||||
// 是否需要进行SQL性能分析
|
||||
'sql_explain' => false,
|
||||
];
|
||||
File diff suppressed because one or more lines are too long
-72
@@ -1,72 +0,0 @@
|
||||
# build frontend
|
||||
FROM node:lts-buster AS fe-builder
|
||||
|
||||
COPY ./assets /assets
|
||||
|
||||
WORKDIR /assets
|
||||
|
||||
# If encountered problems like JavaScript heap out of memory, please uncomment the following options
|
||||
ENV NODE_OPTIONS --max_old_space_size=4096
|
||||
|
||||
# yarn repo connection is unstable, adjust the network timeout to 10 min.
|
||||
RUN set -ex \
|
||||
&& yarn install --network-timeout 600000 \
|
||||
&& yarn run build
|
||||
|
||||
# build backend
|
||||
FROM golang:1.15.1-alpine3.12 AS be-builder
|
||||
|
||||
ENV GO111MODULE on
|
||||
|
||||
COPY . /go/src/github.com/cloudreve/Cloudreve/v3
|
||||
COPY --from=fe-builder /assets/build/ /go/src/github.com/cloudreve/Cloudreve/v3/assets/build/
|
||||
|
||||
WORKDIR /go/src/github.com/cloudreve/Cloudreve/v3
|
||||
|
||||
RUN set -ex \
|
||||
&& apk upgrade \
|
||||
&& apk add gcc libc-dev git \
|
||||
&& export COMMIT_SHA=$(git rev-parse --short HEAD) \
|
||||
&& export VERSION=$(git describe --tags) \
|
||||
&& (cd && go get github.com/rakyll/statik) \
|
||||
&& statik -src=assets/build/ -include=*.html,*.js,*.json,*.css,*.png,*.svg,*.ico -f \
|
||||
&& go install -ldflags "-X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.BackendVersion=${VERSION}' \
|
||||
-X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.LastCommit=${COMMIT_SHA}'\
|
||||
-w -s"
|
||||
|
||||
# build final image
|
||||
FROM alpine:3.12 AS dist
|
||||
|
||||
LABEL maintainer="mritd <mritd@linux.com>"
|
||||
|
||||
# we use the Asia/Shanghai timezone by default, you can be modified
|
||||
# by `docker build --build-arg=TZ=Other_Timezone ...`
|
||||
ARG TZ="Asia/Shanghai"
|
||||
|
||||
ENV TZ ${TZ}
|
||||
|
||||
COPY --from=be-builder /go/bin/Cloudreve /cloudreve/cloudreve
|
||||
COPY docker-bootstrap.sh /cloudreve/bootstrap.sh
|
||||
|
||||
RUN apk upgrade \
|
||||
&& apk add bash tzdata aria2 \
|
||||
&& ln -s /cloudreve/cloudreve /usr/bin/cloudreve \
|
||||
&& ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime \
|
||||
&& echo ${TZ} > /etc/timezone \
|
||||
&& rm -rf /var/cache/apk/* \
|
||||
&& mkdir /etc/cloudreve \
|
||||
&& ln -s /etc/cloudreve/cloureve.db /cloudreve/cloudreve.db \
|
||||
&& ln -s /etc/cloudreve/conf.ini /cloudreve/conf.ini
|
||||
|
||||
# cloudreve use tcp 5212 port by default
|
||||
EXPOSE 5212/tcp
|
||||
|
||||
# cloudreve stores all files(including executable file) in the `/cloudreve`
|
||||
# directory by default; users should mount the configfile to the `/etc/cloudreve`
|
||||
# directory by themselves for persistence considerations, and the data storage
|
||||
# directory recommends using `/data` directory.
|
||||
VOLUME /etc/cloudreve
|
||||
|
||||
VOLUME /data
|
||||
|
||||
ENTRYPOINT ["sh", "/cloudreve/bootstrap.sh"]
|
||||
@@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
@@ -1,135 +1,106 @@
|
||||
<h1 align="center">
|
||||
<br>
|
||||
<a href="https://cloudreve.org/" alt="logo" ><img src="https://raw.githubusercontent.com/cloudreve/frontend/master/public/static/img/logo192.png" width="150"/></a>
|
||||
<br>
|
||||
Cloudreve
|
||||
<br>
|
||||
</h1>
|
||||

|
||||
|
||||
<h4 align="center">支持多家云存储驱动的公有云文件系统.</h4>
|
||||
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)
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.com/github/cloudreve/Cloudreve/">
|
||||
<img src="https://img.shields.io/travis/com/cloudreve/Cloudreve?style=flat-square"
|
||||
alt="travis">
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/cloudreve/Cloudreve"><img src="https://img.shields.io/codecov/c/github/cloudreve/Cloudreve?style=flat-square"></a>
|
||||
<a href="https://goreportcard.com/report/github.com/cloudreve/Cloudreve">
|
||||
<img src="https://goreportcard.com/badge/github.com/cloudreve/Cloudreve?style=flat-square">
|
||||
</a>
|
||||
<a href="https://github.com/cloudreve/Cloudreve/releases">
|
||||
<img src="https://img.shields.io/github/v/release/cloudreve/Cloudreve?include_prereleases&style=flat-square">
|
||||
</a>
|
||||
</p>
|
||||
[主页](https://cloudreve.org) | [论坛](https://forum.cloudreve.org) | [演示站](https://drive.aoaoao.me) | [QQ群](https://jq.qq.com/?_wv=1027&k=5TX6sJY)
|
||||
|
||||
<p align="center">
|
||||
<a href="https://demo.cloudreve.org">演示站</a> •
|
||||
<a href="https://forum.cloudreve.org/">讨论社区</a> •
|
||||
<a href="https://docs.cloudreve.org/">文档</a> •
|
||||
<a href="https://github.com/cloudreve/Cloudreve/releases">下载</a> •
|
||||
<a href="https://t.me/cloudreve_official">Telegram 群组</a> •
|
||||
<a href="#scroll-许可证">许可证</a>
|
||||
</p>
|
||||
使用ThinkPHP + React + Redux + Material-UI构建的网盘系统,能够助您以较低成本快速搭建起公私兼备的网盘。
|
||||
|
||||

|
||||

|
||||
|
||||
## :sparkles: 特性
|
||||
目前已经实现的特性:
|
||||
|
||||
* :cloud: 支持本机、从机、七牛、阿里云 OSS、腾讯云 COS、又拍云、OneDrive (包括世纪互联版) 作为存储端
|
||||
* :outbox_tray: 上传/下载 支持客户端直传,支持下载限速
|
||||
* 💾 可对接 Aria2 离线下载,可使用多个从机机点分担下载任务
|
||||
* 📚 在线 压缩/解压缩、多文件打包下载
|
||||
* 💻 覆盖全部存储策略的 WebDAV 协议支持
|
||||
* :zap: 拖拽上传、目录上传、流式上传处理
|
||||
* :card_file_box: 文件拖拽管理
|
||||
* :family_woman_girl_boy: 多用户、用户组
|
||||
* :link: 创建文件、目录的分享链接,可设定自动过期
|
||||
* :eye_speech_bubble: 视频、图像、音频、文本、Office 文档在线预览
|
||||
* :art: 自定义配色、黑暗模式、PWA 应用、全站单页应用
|
||||
* :rocket: All-In-One 打包,开箱即用
|
||||
* 🌈 ... ...
|
||||
* 快速对接多家云存储,支持七牛、又拍云、阿里云OSS、AWS S3、Onedrive、自建远程服务器,当然,还有本地存储
|
||||
* 可限制单文件最大大小、MIMEType、文件后缀、用户可用容量
|
||||
* 自定义主题配色
|
||||
* 基于Aria2的离线下载
|
||||
* 图片、音频、视频、文本、Markdown、Ofiice文档 在线预览
|
||||
* 移动端全站响应式布局
|
||||
* 文件、目录分享系统,可创建私有分享或公开分享链接
|
||||
* 用户个人主页,可查看用户所有分享
|
||||
* 多用户系统、用户组支持
|
||||
* 初步完善的后台,方便管理
|
||||
* 拖拽上传、分片上传、断点续传、下载限速(*实验性功能)
|
||||
* 多上传策略,可为不同用户组分配不同策略
|
||||
* 用户组基础权限设置、二步验证
|
||||
* WebDAV协议支持
|
||||
|
||||
## :hammer_and_wrench: 部署
|
||||
|
||||
下载适用于您目标机器操作系统、CPU架构的主程序,直接运行即可。
|
||||
安装需求
|
||||
------------
|
||||
* LNMP/AMP With PHP5.6+
|
||||
* curl、fileinfo、gd扩展
|
||||
* Composer
|
||||
|
||||
```shell
|
||||
# 解压程序包
|
||||
tar -zxvf cloudreve_VERSION_OS_ARCH.tar.gz
|
||||
简要安装说明
|
||||
------------
|
||||
|
||||
# 赋予执行权限
|
||||
chmod +x ./cloudreve
|
||||
|
||||
# 启动 Cloudreve
|
||||
./cloudreve
|
||||
#### 1.使用Composer安装主程序
|
||||
```
|
||||
#安装开发版
|
||||
$ composer create-project hfo4/cloudreve:dev-master
|
||||
```
|
||||
|
||||
以上为最简单的部署示例,您可以参考 [文档 - 起步](https://docs.cloudreve.org/) 进行更为完善的部署。
|
||||
|
||||
## :gear: 构建
|
||||
|
||||
自行构建前需要拥有 `Go >= 1.13`、`yarn`等必要依赖。
|
||||
|
||||
#### 克隆代码
|
||||
|
||||
```shell
|
||||
git clone --recurse-submodules https://github.com/cloudreve/Cloudreve.git
|
||||
```
|
||||
#等待安装依赖库后,会自动执行安装脚本,按照提示输入数据库账户信息
|
||||
___ _ _
|
||||
/ __\ | ___ _ _ __| |_ __ _____ _____
|
||||
/ / | |/ _ \| | | |/ _` | '__/ _ \ \ / / _ \
|
||||
/ /___| | (_) | |_| | (_| | | | __/\ V / __/
|
||||
\____/|_|\___/ \__,_|\__,_|_| \___| \_/ \___|
|
||||
|
||||
Ver XX
|
||||
================================================
|
||||
#按提示输入信息
|
||||
......
|
||||
```
|
||||
|
||||
#### 构建静态资源
|
||||
```
|
||||
#出现如下提示表示安装完成
|
||||
Congratulations! Cloudreve has been installed successfully.
|
||||
|
||||
```shell
|
||||
# 进入前端子模块
|
||||
cd assets
|
||||
# 安装依赖
|
||||
yarn install
|
||||
# 开始构建
|
||||
yarn run build
|
||||
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` 目录也需要有写入权限
|
||||
|
||||
```shell
|
||||
# 回到项目主目录
|
||||
cd ../
|
||||
|
||||
# 安装 statik, 用于嵌入静态资源
|
||||
go get github.com/rakyll/statik
|
||||
|
||||
# 开始嵌入
|
||||
statik -src=assets/build/ -include=*.html,*.js,*.json,*.css,*.png,*.svg,*.ico -f
|
||||
#### 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~
|
||||
|
||||
```shell
|
||||
# 获得当前版本号、Commit
|
||||
export COMMIT_SHA=$(git rev-parse --short HEAD)
|
||||
export VERSION=$(git describe --tags)
|
||||
文档
|
||||
------------
|
||||
* [完整安装说明](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)
|
||||
|
||||
# 开始编译
|
||||
go build -a -o cloudreve -ldflags " -X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.BackendVersion=$VERSION' -X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.LastCommit=$COMMIT_SHA'"
|
||||
```
|
||||
|
||||
你也可以使用项目根目录下的`build.sh`快速开始构建:
|
||||
|
||||
```shell
|
||||
./build.sh [-a] [-c] [-b] [-r]
|
||||
a - 构建静态资源
|
||||
c - 编译二进制文件
|
||||
b - 构建前端 + 编译二进制文件
|
||||
r - 交叉编译,构建用于release的版本
|
||||
```
|
||||
|
||||
## :alembic: 技术栈
|
||||
|
||||
* [Go ](https://golang.org/) + [Gin](https://github.com/gin-gonic/gin)
|
||||
* [React](https://github.com/facebook/react) + [Redux](https://github.com/reduxjs/redux) + [Material-UI](https://github.com/mui-org/material-ui)
|
||||
|
||||
## :scroll: 许可证
|
||||
|
||||
GPL V3
|
||||
|
||||
---
|
||||
> GitHub [@HFO4](https://github.com/HFO4) ·
|
||||
> Twitter [@abslant00](https://twitter.com/abslant00)
|
||||
许可证
|
||||
------------
|
||||
GPLV3
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
database.php
|
||||
@@ -0,0 +1 @@
|
||||
deny from all
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: yunwuxin <448901948@qq.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
'app\index\command\Task',
|
||||
];
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: 流年 <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 应用公共文件
|
||||
function array_column_fix($array,$key){
|
||||
if(count($array) == count($array,1)){
|
||||
return array(0 =>$array[$key]);
|
||||
}else{
|
||||
return array_column($array,$key);
|
||||
}
|
||||
}
|
||||
function getAllowedExt($ext){
|
||||
$returnValue = "";
|
||||
foreach (json_decode($ext,true) as $key => $value) {
|
||||
$returnValue .= $value["ext"].",";
|
||||
}
|
||||
return rtrim($returnValue, ",");
|
||||
}
|
||||
function getDirName($name){
|
||||
$explode = explode("/", $name);
|
||||
return end($explode);
|
||||
}
|
||||
function getSize($bit,$array=false){
|
||||
$type = array('Bytes','KB','MB','GB','TB');
|
||||
$box = array('1','1024','1048576','1073741824','TB');
|
||||
for($i = 0; $bit >= 1024; $i++) {
|
||||
$bit/=1024;
|
||||
}
|
||||
if($array){
|
||||
return [(floor($bit*100)/100),$box[$i]];
|
||||
}
|
||||
return (floor($bit*100)/100).$type[$i];
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// +----------------------------------------------------------------------
|
||||
// | 应用设置
|
||||
// +----------------------------------------------------------------------
|
||||
//密码加盐
|
||||
'salt' => 'sdshare',
|
||||
// 应用命名空间
|
||||
'app_namespace' => 'app',
|
||||
// 应用调试模式
|
||||
'app_debug' => true,
|
||||
// 应用Trace
|
||||
'app_trace' => false,
|
||||
// 应用模式状态
|
||||
'app_status' => '',
|
||||
// 是否支持多模块
|
||||
'app_multi_module' => true,
|
||||
// 入口自动绑定模块
|
||||
'auto_bind_module' => false,
|
||||
// 注册的根命名空间
|
||||
'root_namespace' => [],
|
||||
// 扩展函数文件
|
||||
'extra_file_list' => [THINK_PATH . 'helper' . EXT],
|
||||
// 默认输出类型
|
||||
'default_return_type' => 'html',
|
||||
// 默认AJAX 数据返回格式,可选json xml ...
|
||||
'default_ajax_return' => 'json',
|
||||
// 默认JSONP格式返回的处理方法
|
||||
'default_jsonp_handler' => 'jsonpReturn',
|
||||
// 默认JSONP处理方法
|
||||
'var_jsonp_handler' => 'callback',
|
||||
// 默认时区
|
||||
'default_timezone' => 'PRC',
|
||||
// 是否开启多语言
|
||||
'lang_switch_on' => false,
|
||||
// 默认全局过滤方法 用逗号分隔多个
|
||||
'default_filter' => '',
|
||||
// 默认语言
|
||||
'default_lang' => 'zh-cn',
|
||||
// 应用类库后缀
|
||||
'class_suffix' => false,
|
||||
// 控制器类后缀
|
||||
'controller_suffix' => false,
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模块设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 默认模块名
|
||||
'default_module' => 'index',
|
||||
// 禁止访问模块
|
||||
'deny_module_list' => ['common'],
|
||||
// 默认控制器名
|
||||
'default_controller' => 'Index',
|
||||
// 默认操作名
|
||||
'default_action' => 'index',
|
||||
// 默认验证器
|
||||
'default_validate' => '',
|
||||
// 默认的空控制器名
|
||||
'empty_controller' => 'Error',
|
||||
// 操作方法后缀
|
||||
'action_suffix' => '',
|
||||
// 自动搜索控制器
|
||||
'controller_auto_search' => false,
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | URL设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// PATHINFO变量名 用于兼容模式
|
||||
'var_pathinfo' => 's',
|
||||
'url_convert' => false,
|
||||
// 兼容PATH_INFO获取
|
||||
'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
|
||||
// pathinfo分隔符
|
||||
'pathinfo_depr' => '/',
|
||||
// URL伪静态后缀
|
||||
'url_html_suffix' => '',
|
||||
// URL普通方式参数 用于自动生成
|
||||
'url_common_param' => false,
|
||||
// URL参数方式 0 按名称成对解析 1 按顺序解析
|
||||
'url_param_type' => 0,
|
||||
// 是否开启路由
|
||||
'url_route_on' => true,
|
||||
// 路由使用完整匹配
|
||||
'route_complete_match' => false,
|
||||
// 路由配置文件(支持配置多个)
|
||||
'route_config_file' => ['route'],
|
||||
// 是否强制使用路由
|
||||
'url_route_must' => false,
|
||||
// 域名部署
|
||||
'url_domain_deploy' => false,
|
||||
// 域名根,如thinkphp.cn
|
||||
'url_domain_root' => '',
|
||||
// 是否自动转换URL中的控制器和操作名
|
||||
'url_convert' => false,
|
||||
// 默认的访问控制器层
|
||||
'url_controller_layer' => 'controller',
|
||||
// 表单请求类型伪装变量
|
||||
'var_method' => '_method',
|
||||
// 表单ajax伪装变量
|
||||
'var_ajax' => '_ajax',
|
||||
// 表单pjax伪装变量
|
||||
'var_pjax' => '_pjax',
|
||||
// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
|
||||
'request_cache' => false,
|
||||
// 请求缓存有效期
|
||||
'request_cache_expire' => null,
|
||||
// 全局请求缓存排除规则
|
||||
'request_cache_except' => [],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模板设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'template' => [
|
||||
// 模板引擎类型 支持 php think 支持扩展
|
||||
'type' => 'Think',
|
||||
// 模板路径
|
||||
'view_path' => '',
|
||||
// 模板后缀
|
||||
'view_suffix' => 'html',
|
||||
// 模板文件名分隔符
|
||||
'view_depr' => DS,
|
||||
// 模板引擎普通标签开始标记
|
||||
'tpl_begin' => '{',
|
||||
// 模板引擎普通标签结束标记
|
||||
'tpl_end' => '}',
|
||||
// 标签库标签开始标记
|
||||
'taglib_begin' => '{',
|
||||
// 标签库标签结束标记
|
||||
'taglib_end' => '}',
|
||||
],
|
||||
|
||||
// 视图输出字符串内容替换
|
||||
'view_replace_str' => [],
|
||||
// 默认跳转页面对应的模板文件
|
||||
'dispatch_success_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
|
||||
'dispatch_error_tmpl' => "application/index/view/error.html",
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 异常及错误设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// 异常页面的模板文件
|
||||
'exception_tmpl' => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',
|
||||
|
||||
// 错误显示信息,非调试模式有效
|
||||
'error_message' => '很抱歉,出现错误 :(',
|
||||
// 显示错误信息
|
||||
'show_error_msg' => false,
|
||||
// 异常处理handle类 留空使用 \think\exception\Handle
|
||||
'exception_handle' => '',
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 日志设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'log' => [
|
||||
// 日志记录方式,内置 file socket 支持扩展
|
||||
'type' => 'File',
|
||||
// 日志保存目录
|
||||
'path' => LOG_PATH,
|
||||
// 日志记录级别
|
||||
'level' => ["error"],
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | Trace设置 开启 app_trace 后 有效
|
||||
// +----------------------------------------------------------------------
|
||||
'trace' => [
|
||||
// 内置Html Console 支持扩展
|
||||
'type' => 'Html',
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 缓存设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'cache' => [
|
||||
// 驱动方式
|
||||
'type' => 'File',
|
||||
// 缓存保存目录
|
||||
'path' => CACHE_PATH,
|
||||
// 缓存前缀
|
||||
'prefix' => '',
|
||||
// 缓存有效期 0表示永久缓存
|
||||
'expire' => 0,
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 会话设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
'session' => [
|
||||
'id' => '',
|
||||
// SESSION_ID的提交变量,解决flash上传跨域
|
||||
'var_session_id' => '',
|
||||
// SESSION 前缀
|
||||
'prefix' => 'sd',
|
||||
// 驱动方式 支持redis memcache memcached
|
||||
'type' => '',
|
||||
// 是否自动开启 SESSION
|
||||
'auto_start' => true,
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | Cookie设置
|
||||
// +----------------------------------------------------------------------
|
||||
'cookie' => [
|
||||
// cookie 名称前缀
|
||||
'prefix' => '',
|
||||
// cookie 保存时间
|
||||
'expire' => 0,
|
||||
// cookie 保存路径
|
||||
'path' => '/',
|
||||
// cookie 有效域名
|
||||
'domain' => '',
|
||||
// cookie 启用安全传输
|
||||
'secure' => false,
|
||||
// httponly设置
|
||||
'httponly' => '',
|
||||
// 是否使用 setcookie
|
||||
'setcookie' => true,
|
||||
],
|
||||
|
||||
//分页配置
|
||||
'paginate' => [
|
||||
'type' => 'bootstrap',
|
||||
'var_page' => 'page',
|
||||
'list_rows' => 15,
|
||||
],
|
||||
|
||||
//分片上传大小(只对本地策略有效)
|
||||
'upload'=>[
|
||||
'chunk_size' => 10*1024*1024,
|
||||
],
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 验证码设置
|
||||
// +----------------------------------------------------------------------
|
||||
'captcha'=>[
|
||||
'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY',
|
||||
// 验证码字符集合
|
||||
'expire' => 1800,
|
||||
// 验证码过期时间(s)
|
||||
'useZh' => false,
|
||||
// 使用背景图片
|
||||
'fontSize' => 25,
|
||||
// 验证码字体大小(px)
|
||||
'useCurve' => true,
|
||||
// 是否画混淆曲线
|
||||
'useNoise' => true,
|
||||
// 是否添加杂点
|
||||
'imageH' => 0,
|
||||
// 验证码图片高度
|
||||
'imageW' => 0,
|
||||
// 验证码图片宽度
|
||||
'length' => 4,
|
||||
// 验证码位数
|
||||
'fontttf' => '',
|
||||
// 验证码字体,不设置随机获取
|
||||
'bg' => [243, 251, 254],
|
||||
// 背景颜色
|
||||
'reset' => true],
|
||||
];
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 数据库类型
|
||||
'type' => 'mysql',
|
||||
// 服务器地址
|
||||
'hostname' => '127.0.0.1',
|
||||
// 数据库名
|
||||
'database' => 'tp',
|
||||
// 用户名
|
||||
'username' => 'root',
|
||||
// 密码
|
||||
'password' => 'root',
|
||||
// 端口
|
||||
'hostport' => '3306',
|
||||
// 连接dsn
|
||||
'dsn' => '',
|
||||
// 数据库连接参数
|
||||
'params' => [],
|
||||
// 数据库编码默认采用utf8
|
||||
'charset' => 'utf8',
|
||||
// 数据库表前缀
|
||||
'prefix' => 'sd_',
|
||||
// 数据库调试模式
|
||||
'debug' => true,
|
||||
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
|
||||
'deploy' => 0,
|
||||
// 数据库读写是否分离 主从式有效
|
||||
'rw_separate' => false,
|
||||
// 读写分离后 主服务器数量
|
||||
'master_num' => 1,
|
||||
// 指定从服务器序号
|
||||
'slave_no' => '',
|
||||
// 是否严格检查字段是否存在
|
||||
'fields_strict' => true,
|
||||
// 数据集返回类型
|
||||
'resultset_type' => 'array',
|
||||
// 自动写入时间戳字段
|
||||
'auto_timestamp' => false,
|
||||
// 时间字段取出后的默认时间格式
|
||||
'datetime_format' => 'Y-m-d H:i:s',
|
||||
// 是否需要进行SQL性能分析
|
||||
'sql_explain' => false,
|
||||
];
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
function classLoader($class)
|
||||
{
|
||||
$path = str_replace('\\', DIRECTORY_SEPARATOR, $class);
|
||||
$file = __DIR__ . '/src/' . $path . '.php';
|
||||
|
||||
if (file_exists($file)) {
|
||||
require_once $file;
|
||||
}
|
||||
}
|
||||
spl_autoload_register('classLoader');
|
||||
|
||||
require_once __DIR__ . '/src/Qiniu/functions.php';
|
||||
@@ -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"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
function countSize($bit,$array=false){
|
||||
$type = array('Bytes','KB','MB','GB','TB');
|
||||
$box = array('1','1024','1048576','1073741824','TB');
|
||||
for($i = 0; $bit >= 1024; $i++) {
|
||||
$bit/=1024;
|
||||
}
|
||||
if($array){
|
||||
return [(floor($bit*100)/100),$box[$i]];
|
||||
}
|
||||
return (floor($bit*100)/100).$type[$i];
|
||||
}
|
||||
|
||||
function isPreview($fileName){
|
||||
$allowedSuffix=["jpg","jpeg","gif","bmp","png","svg","mp4","mp3","ogg"];
|
||||
$suffix = explode(".",$fileName);
|
||||
if(in_array(end($suffix),$allowedSuffix)){
|
||||
return "yes";
|
||||
}
|
||||
return "no";
|
||||
}
|
||||
function getDay($sec){
|
||||
return floor($sec/86400);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,566 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use app\index\model\User;
|
||||
use think\Cookie;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\AdminHandler;
|
||||
use \app\index\model\FileManage;
|
||||
|
||||
class Admin extends Controller{
|
||||
|
||||
public $userObj;
|
||||
public $siteOptions;
|
||||
public $adminObj;
|
||||
|
||||
public function _initialize(){
|
||||
$this->siteOptions = Option::getValues(["basic","admin"]);
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
if(!$this->userObj->loginStatus){
|
||||
$this->redirect(url('/Login','',''));
|
||||
exit();
|
||||
}
|
||||
if($this->userObj->groupData["id"] != 1){
|
||||
$this->error('你无权访问此页面',403,$this->siteOptions);
|
||||
}
|
||||
$this->adminObj = new AdminHandler($this->siteOptions);
|
||||
}
|
||||
|
||||
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,
|
||||
]);
|
||||
}
|
||||
|
||||
public function Config(){
|
||||
$configType=input("?param.type") ? input("param.type") : "common";
|
||||
$configFile = $this->adminObj->getConfigFile($configType);
|
||||
return view('config_file', [
|
||||
'options' => $this->siteOptions,
|
||||
'type' => $configType,
|
||||
'content' => $configFile[0],
|
||||
'path' => $configFile[1],
|
||||
]);
|
||||
}
|
||||
|
||||
public function SaveConfigFile(){
|
||||
return $this->adminObj->saveConfigFile(input('post.'));
|
||||
}
|
||||
|
||||
public function SettingReg(){
|
||||
return view('reg_setting', [
|
||||
'options' => $this->siteOptions,
|
||||
'optionsForSet' => Option::getValues(["login","register"]),
|
||||
'groups' => $this->adminObj->getAvaliableGroup(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function Color(){
|
||||
$options = Option::getValues(["basic"]);
|
||||
return view('color', [
|
||||
'options' => $this->siteOptions,
|
||||
'optionsForSet' => $options,
|
||||
'colors'=> \json_decode($options["themes"],true)
|
||||
]);
|
||||
}
|
||||
|
||||
public function Theme(){
|
||||
$fileName=input("?param.name") ? input("param.name") : "error";
|
||||
$dir = ROOT_PATH."application/index/view/";
|
||||
if(!function_exists("scandir")){
|
||||
return "scandir被禁用";
|
||||
}
|
||||
$fileList=[];
|
||||
$fileList=$fileList+scandir($dir);
|
||||
$pathList=["/"=>$fileList];
|
||||
foreach (["admin","explore","file","home","index","member","profile","share"] as $key => $value) {
|
||||
$childPath = scandir($dir.$value."/");
|
||||
$fileList=array_merge($fileList,$childPath);
|
||||
$pathList = array_merge($pathList,[$value => $childPath]);
|
||||
}
|
||||
foreach ($fileList as $key => $value) {
|
||||
if(substr_compare($value, ".html", -strlen(".html")) != 0){
|
||||
unset($fileList[$key]);
|
||||
}
|
||||
}
|
||||
foreach($pathList as $key=>$val){
|
||||
if(in_array($fileName.".html",$val)){
|
||||
$parentPath = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$fileContent = file_get_contents($dir.rtrim($parentPath,"/")."/".$fileName.".html");
|
||||
return view('theme', [
|
||||
'options' => $this->siteOptions,
|
||||
'list' => $fileList,
|
||||
'content' => $fileContent,
|
||||
'path' => $parentPath,
|
||||
'name' => $fileName,
|
||||
]);
|
||||
}
|
||||
|
||||
public function SaveThemeFile(){
|
||||
return $this->adminObj->saveThemeFile(input('post.'));
|
||||
}
|
||||
|
||||
public function SaveColorSetting(){
|
||||
return $this->adminObj->saveColorSetting(input('post.'));
|
||||
}
|
||||
|
||||
public function SettingMail(){
|
||||
return view('mail_setting', [
|
||||
'options' => $this->siteOptions,
|
||||
'optionsForSet' => Option::getValues(["mail_template","mail"]),
|
||||
]);
|
||||
}
|
||||
|
||||
public function SettingPay(){
|
||||
return view('pay_setting', [
|
||||
'options' => $this->siteOptions,
|
||||
'optionsForSet' => Option::getValues(["payment"]),
|
||||
]);
|
||||
}
|
||||
|
||||
public function SettingOther(){
|
||||
return view('other_setting', [
|
||||
'options' => $this->siteOptions,
|
||||
'optionsForSet' => Option::getValues(["file_edit","share","avatar","admin","storage_policy","download"]),
|
||||
]);
|
||||
}
|
||||
|
||||
public function Files(){
|
||||
$this->adminObj->listFile();
|
||||
return view('file_list', [
|
||||
'options' => $this->siteOptions,
|
||||
'groups' => $this->adminObj->getAvaliableGroup(),
|
||||
'list' => $this->adminObj->pageData,
|
||||
'originList' => $this->adminObj->listData,
|
||||
'pageNow' => $this->adminObj->pageNow,
|
||||
'pageTotal' => $this->adminObj->pageTotal,
|
||||
'dataTotal' => $this->adminObj->dataTotal,
|
||||
'policy' => $this->adminObj->getAvaliablePolicy(),
|
||||
]);
|
||||
}
|
||||
|
||||
Public function Users(){
|
||||
$this->adminObj->listUser();
|
||||
$group = $this->adminObj->getAvaliableGroup();
|
||||
return view('user_list', [
|
||||
'options' => $this->siteOptions,
|
||||
'group' => $group,
|
||||
'groups' => $group,
|
||||
'list' => $this->adminObj->pageData,
|
||||
'originList' => $this->adminObj->listData,
|
||||
'pageNow' => $this->adminObj->pageNow,
|
||||
'pageTotal' => $this->adminObj->pageTotal,
|
||||
'dataTotal' => $this->adminObj->dataTotal,
|
||||
'policy' => $this->adminObj->getAvaliablePolicy(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function Shares(){
|
||||
$this->adminObj->listShare();
|
||||
return view('share_list', [
|
||||
'options' => $this->siteOptions,
|
||||
'groups' => $this->adminObj->getAvaliableGroup(),
|
||||
'list' => $this->adminObj->pageData,
|
||||
'originList' => $this->adminObj->listData,
|
||||
'pageNow' => $this->adminObj->pageNow,
|
||||
'pageTotal' => $this->adminObj->pageTotal,
|
||||
'dataTotal' => $this->adminObj->dataTotal,
|
||||
]);
|
||||
}
|
||||
|
||||
public function PolicyList(){
|
||||
$this->adminObj->listPolicy();
|
||||
return view('policy_list', [
|
||||
'options' => $this->siteOptions,
|
||||
'groups' => $this->adminObj->getAvaliableGroup(),
|
||||
'list' => $this->adminObj->pageData,
|
||||
'originList' => $this->adminObj->listData,
|
||||
'pageNow' => $this->adminObj->pageNow,
|
||||
'pageTotal' => $this->adminObj->pageTotal,
|
||||
'dataTotal' => $this->adminObj->dataTotal,
|
||||
]);
|
||||
}
|
||||
|
||||
public function GroupList(){
|
||||
$this->adminObj->listGroup();
|
||||
return view('group_list', [
|
||||
'options' => $this->siteOptions,
|
||||
'list' => $this->adminObj->pageData,
|
||||
'originList' => $this->adminObj->listData,
|
||||
'pageNow' => $this->adminObj->pageNow,
|
||||
'pageTotal' => $this->adminObj->pageTotal,
|
||||
'dataTotal' => $this->adminObj->dataTotal,
|
||||
]);
|
||||
}
|
||||
|
||||
public function OrderList(){
|
||||
$this->adminObj->listOrder();
|
||||
return view('order_list', [
|
||||
'options' => $this->siteOptions,
|
||||
'list' => $this->adminObj->pageData,
|
||||
'originList' => $this->adminObj->listData,
|
||||
'pageNow' => $this->adminObj->pageNow,
|
||||
'pageTotal' => $this->adminObj->pageTotal,
|
||||
'dataTotal' => $this->adminObj->dataTotal,
|
||||
]);
|
||||
}
|
||||
|
||||
public function SaveBasicSetting(){
|
||||
return $this->adminObj->saveBasicSetting(input('post.'));
|
||||
}
|
||||
|
||||
public function SaveRegSetting(){
|
||||
return $this->adminObj->saveRegSetting(input('post.'));
|
||||
}
|
||||
|
||||
public function SaveMailSetting(){
|
||||
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.'));
|
||||
}
|
||||
|
||||
public function SaveMailTemplate(){
|
||||
return $this->adminObj->saveMailTemplate(input('post.'));
|
||||
}
|
||||
|
||||
public function GetFileInfo(){
|
||||
return $this->adminObj->getFileInfo(input('post.id'));
|
||||
}
|
||||
|
||||
public function GetUserInfo(){
|
||||
return $this->adminObj->getUserInfo(input('post.id'));
|
||||
}
|
||||
|
||||
public function savePolicy(){
|
||||
return $this->adminObj->addPolicy(input('post.'));
|
||||
}
|
||||
|
||||
public function SaveEditPolicy(){
|
||||
return $this->adminObj->editPolicy(input('post.'));
|
||||
}
|
||||
|
||||
public function SaveGroup(){
|
||||
return $this->adminObj->saveGroup(input('post.'));
|
||||
}
|
||||
|
||||
public function AddPack(){
|
||||
return $this->adminObj->addPack(input('post.'));
|
||||
}
|
||||
|
||||
public function AddGroupPurchase(){
|
||||
return $this->adminObj->addGroupPurchase(input('post.'));
|
||||
}
|
||||
|
||||
public function SaveCron(){
|
||||
$this->adminObj->saveCron(input('post.'));
|
||||
$this->redirect("/Admin/Cron",302);
|
||||
}
|
||||
|
||||
public function SaveUser(){
|
||||
return $this->adminObj->saveUser(input('post.'));
|
||||
}
|
||||
|
||||
public function BanUser(){
|
||||
return $this->adminObj->banUser(input('post.id'),$this->userObj->uid);
|
||||
}
|
||||
|
||||
public function AddUser(){
|
||||
return $this->adminObj->addUser(input('post.'));
|
||||
}
|
||||
|
||||
public function Preview(){
|
||||
$fileId = input('param.id');
|
||||
$fileRecord = Db::name("files")->where("id",$fileId)->find();
|
||||
$fileObj = new FileManage(rtrim($fileRecord["dir"],"/")."/".$fileRecord["orign_name"],$fileRecord["upload_user"]);
|
||||
$previewHandler = $fileObj->PreviewHandler(true);
|
||||
if($previewHandler[0]){
|
||||
$this->redirect($previewHandler[1],302);
|
||||
}
|
||||
}
|
||||
|
||||
public function Download(){
|
||||
$fileId = input('param.id');
|
||||
$fileRecord = Db::name("files")->where("id",$fileId)->find();
|
||||
$fileObj = new FileManage(rtrim($fileRecord["dir"],"/")."/".$fileRecord["orign_name"],$fileRecord["upload_user"]);
|
||||
$FileHandler = $fileObj->Download(true);
|
||||
if($FileHandler[0]){
|
||||
$this->redirect($FileHandler[1],302);
|
||||
}
|
||||
}
|
||||
|
||||
public function Delete(){
|
||||
return $this->adminObj->deleteSingle(input('post.id'));
|
||||
}
|
||||
|
||||
public function DeleteShare(){
|
||||
return $this->adminObj->deleteShare([0=>input('post.id')]);
|
||||
}
|
||||
|
||||
public function DeleteShareMultiple(){
|
||||
return $this->adminObj->deleteShare(\json_decode(input('post.id'),true));
|
||||
}
|
||||
|
||||
public function DeleteMultiple(){
|
||||
return $this->adminObj->deleteMultiple(input('post.id'));
|
||||
}
|
||||
|
||||
public function DeletePolicy(){
|
||||
return $this->adminObj->deletePolicy(input('post.id'));
|
||||
}
|
||||
|
||||
public function DeleteGroup(){
|
||||
return $this->adminObj->deleteGroup(input('post.id'));
|
||||
}
|
||||
|
||||
public function DeleteOrder(){
|
||||
return $this->adminObj->deleteOrder(input('post.id'));
|
||||
}
|
||||
|
||||
public function ChangeShareType(){
|
||||
return $this->adminObj->changeShareType(input('post.id'));
|
||||
}
|
||||
|
||||
public function DeletePack(){
|
||||
return $this->adminObj->deletePack(input('post.id'));
|
||||
}
|
||||
|
||||
public function DeleteGroupPurchase(){
|
||||
return $this->adminObj->deleteGroupPurchase(input('post.id'));
|
||||
}
|
||||
|
||||
public function DeleteUser(){
|
||||
return $this->adminObj->deleteUser(input('post.id'),$this->userObj->uid);
|
||||
}
|
||||
|
||||
public function DeleteUsers(){
|
||||
$uidGroup = \json_decode(input('post.id'),true);
|
||||
foreach ($uidGroup as $key => $value) {
|
||||
$this->adminObj->deleteUser($value,$this->userObj->uid);
|
||||
}
|
||||
return ["error"=>false,"msg"=>"删除成功"];
|
||||
}
|
||||
|
||||
public function SwitchColor(){
|
||||
$colorNow = Option::getValues(["admin"]);
|
||||
if($colorNow["admin_color_body"] == "fixed-nav sticky-footer bg-light"){
|
||||
$colorNew = [
|
||||
"admin_color_body" => "fixed-nav sticky-footer bg-dark",
|
||||
"admin_color_nav" => "navbar navbar-expand-lg fixed-top navbar-dark bg-dark",
|
||||
];
|
||||
}else{
|
||||
$colorNew = [
|
||||
"admin_color_body" => "fixed-nav sticky-footer bg-light",
|
||||
"admin_color_nav" => "navbar navbar-expand-lg fixed-top navbar-light bg-light",
|
||||
];
|
||||
}
|
||||
foreach ($colorNew as $key => $value) {
|
||||
Db::name("options")->where("option_name",$key)->update(["option_value" => $value]);
|
||||
}
|
||||
}
|
||||
|
||||
public function EditPolicy(){
|
||||
$policyId = input('param.id');
|
||||
$policyRecord = Db::name("policy")->where("id",$policyId)->find();
|
||||
return view('edit_policy', [
|
||||
'options' => $this->siteOptions,
|
||||
'policy' => $policyRecord,
|
||||
]);
|
||||
}
|
||||
|
||||
public function EditGroup(){
|
||||
$groupId = input('param.id');
|
||||
$groupRecord = Db::name("groups")->where("id",$groupId)->find();
|
||||
return view('edit_group', [
|
||||
'options' => $this->siteOptions,
|
||||
'group' => $groupRecord,
|
||||
'policy' => $this->adminObj->getAvaliablePolicy(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function AddGroup(){
|
||||
return $this->adminObj->addGroup(input('post.'));
|
||||
}
|
||||
|
||||
public function PolicyAdd(){
|
||||
return view('add_policy', [
|
||||
'options' => $this->siteOptions,
|
||||
]);
|
||||
}
|
||||
|
||||
public function Cron(){
|
||||
$cronData = Db::name("corn")->select();
|
||||
$neverExcute = true;
|
||||
foreach ($cronData as $key => $value) {
|
||||
if($value["last_excute"] !=0){
|
||||
$neverExcute = false;
|
||||
}
|
||||
}
|
||||
return view('cron_list', [
|
||||
'options' => $this->siteOptions,
|
||||
'cron' => $cronData,
|
||||
'neverExcute' => $neverExcute,
|
||||
]);
|
||||
}
|
||||
|
||||
public function PolicyAddS3(){
|
||||
return view('add_policy_s3', [
|
||||
'options' => $this->siteOptions,
|
||||
]);
|
||||
}
|
||||
|
||||
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', [
|
||||
'options' => $this->siteOptions,
|
||||
'programVersion' => $verison,
|
||||
"dbsVersion" => Option::getValue("database_version"),
|
||||
]);
|
||||
}
|
||||
|
||||
public function Purchase(){
|
||||
$packData = \json_decode(Option::getValue("pack_data"),true);
|
||||
return view('purchase', [
|
||||
'options' => $this->siteOptions,
|
||||
'pack' => $packData,
|
||||
]);
|
||||
}
|
||||
|
||||
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) {
|
||||
$groupData[$key]["group"] = Db::name("groups")->where("id",$value["goup_id"])->find();
|
||||
}
|
||||
return view('purchase_group', [
|
||||
'options' => $this->siteOptions,
|
||||
'group' => $groupData,
|
||||
'group_list' => $this->adminObj->getAvaliableGroup(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function GroupAdd(){
|
||||
return view('add_group', [
|
||||
'options' => $this->siteOptions,
|
||||
'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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use think\Db;
|
||||
use think\Request;
|
||||
use \app\index\model\CallbackHandler;
|
||||
use \app\index\model\User;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\FileManage;
|
||||
use think\Session;
|
||||
|
||||
class Callback extends Controller{
|
||||
|
||||
public function index(){
|
||||
return "";
|
||||
}
|
||||
|
||||
public function Qiniu(){
|
||||
ob_end_clean();
|
||||
header('Content-Type: application/json');
|
||||
$handllerObj = new CallbackHandler(file_get_contents("php://input"));
|
||||
$handllerObj -> qiniuHandler(Request::instance()->header('Authorization'));
|
||||
}
|
||||
|
||||
public function Oss(){
|
||||
ob_end_clean();
|
||||
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'));
|
||||
}
|
||||
|
||||
public function TmpPreview(){
|
||||
$basicOptions = Option::getValues(['basic']);
|
||||
$params = explode(":",input("param.key"));
|
||||
$fileData = Db::name("files")->where("id",$params[0])->find();
|
||||
if (empty($fileData)){
|
||||
abort(404);
|
||||
}
|
||||
$userData = Db::name("users")->where("id",$fileData["upload_user"])->find();
|
||||
if(md5($userData["user_pass"].$fileData["id"].$params[1].config("salt")) != $params[2] || time()<$params[0]){
|
||||
abort(403);
|
||||
}
|
||||
$fileObj = new FileManage(rtrim($fileData["dir"],"/")."/".$fileData["orign_name"],$userData["id"]);
|
||||
$Redirect = $fileObj->PreviewHandler();
|
||||
}
|
||||
|
||||
public function Upyun(){
|
||||
$signToken = Request::instance()->header('Authorization');
|
||||
$reqDate = Request::instance()->header('Date');
|
||||
$contentMd5 = Request::instance()->header('Content-MD5');
|
||||
ob_end_clean();
|
||||
header('Content-Type: application/json');
|
||||
$callbackData = [
|
||||
"code" => input("post.code"),
|
||||
"file_size" => input("post.file_size"),
|
||||
"url" => input("post.url"),
|
||||
"image-width" => input("post.image-width"),
|
||||
"image-height" => input("post.image-height"),
|
||||
"ext-param" => json_decode(input("post.ext-param"),true),
|
||||
];
|
||||
$handllerObj = new CallbackHandler($callbackData);
|
||||
$handllerObj -> upyunHandler($signToken,$reqDate,$contentMd5);
|
||||
}
|
||||
|
||||
public function S3(){
|
||||
$request = Request::instance();
|
||||
if($request->method() == "OPTIONS"){
|
||||
ob_end_clean();
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
exit();
|
||||
}
|
||||
ob_end_clean();
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
$callbackKey = input("param.key");
|
||||
$callbackData = [
|
||||
"bucket" => input("get.bucket"),
|
||||
"key" => input("get.key"),
|
||||
];
|
||||
$handllerObj = new CallbackHandler($callbackData);
|
||||
$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'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use think\Db;
|
||||
use think\Request;
|
||||
use \app\index\model\CronHandler;
|
||||
use think\Session;
|
||||
|
||||
class Cron extends Controller{
|
||||
|
||||
public function index(){
|
||||
$cornObj = new CronHandler();
|
||||
$cornObj->Doit();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use app\index\model\User;
|
||||
use think\Cookie;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
|
||||
class Explore extends Controller{
|
||||
|
||||
public $visitorObj;
|
||||
public $userObj;
|
||||
public $siteOptions;
|
||||
|
||||
public function _initialize(){
|
||||
}
|
||||
|
||||
public function Search(){
|
||||
$this->visitorObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->siteOptions = Option::getValues(["basic"],$this->visitorObj->userSQLData);
|
||||
$keyWords=input("param.key");
|
||||
if(empty($keyWords)){
|
||||
$this->error("搜索词不为空",200,$this->siteOptions);
|
||||
}else{
|
||||
$list = Db::name('shares')
|
||||
->where('type',"public")
|
||||
->where('origin_name',"like","%".$keyWords."%")
|
||||
->order('share_time DESC')
|
||||
->select();
|
||||
}
|
||||
$listData = $list;
|
||||
foreach ($listData as $key => $value) {
|
||||
unset($listData[$key]["source_name"]);
|
||||
if($value["source_type"]=="file"){
|
||||
$listData[$key]["fileData"] = $value["origin_name"];
|
||||
|
||||
}else{
|
||||
$pathDir = explode("/",$value["source_name"]);
|
||||
$listData[$key]["fileData"] = end($pathDir);
|
||||
}
|
||||
}
|
||||
return view("result",[
|
||||
"options" => $this->siteOptions,
|
||||
'loginStatus' => $this->visitorObj->loginStatus,
|
||||
'userData' => $this->visitorObj->getInfo(),
|
||||
'list' => json_encode($listData),
|
||||
'keyWords' => $keyWords,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use think\Db;
|
||||
use think\Request;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\User;
|
||||
use \app\index\model\FileManage;
|
||||
use \app\index\model\ShareHandler;
|
||||
use think\Session;
|
||||
|
||||
|
||||
class File extends Controller{
|
||||
|
||||
public $userObj;
|
||||
|
||||
/**
|
||||
* [_initialize description]
|
||||
* @return [type] [description]
|
||||
*/
|
||||
public function _initialize(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
if(!$this->userObj->loginStatus){
|
||||
echo "Bad request";
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
public function index(){
|
||||
return "";
|
||||
}
|
||||
|
||||
public function ListFile(){
|
||||
$reqPath = stripslashes(json_decode(file_get_contents("php://input"),true)['path']);
|
||||
return json(FileManage::ListFile($reqPath,$this->userObj->uid));
|
||||
}
|
||||
|
||||
public function SearchFile(){
|
||||
$keyWords = stripslashes(json_decode(file_get_contents("php://input"),true)['path']);
|
||||
return json(FileManage::searchFile($keyWords,$this->userObj->uid));
|
||||
}
|
||||
|
||||
public function Delete(){
|
||||
$reqData = json_decode(file_get_contents("php://input"),true);
|
||||
$reqPath = array_key_exists("dirs",$reqData)?$reqData["items"]:array();
|
||||
$dirPath = array_key_exists("dirs",$reqData)?$reqData["dirs"]:array();
|
||||
FileManage::DirDeleteHandler($dirPath,$this->userObj->uid);
|
||||
return json(FileManage::DeleteHandler($reqPath,$this->userObj->uid));
|
||||
}
|
||||
|
||||
public function Move(){
|
||||
$reqData = json_decode(file_get_contents("php://input"),true);
|
||||
$reqPath = array_key_exists("dirs",$reqData)?$reqData["items"]:array();
|
||||
$dirPath = array_key_exists("dirs",$reqData)?$reqData["dirs"]:array();
|
||||
$newPath = $reqData['newPath'];
|
||||
return FileManage::MoveHandler($reqPath,$dirPath,$newPath,$this->userObj->uid);
|
||||
}
|
||||
|
||||
public function Rename(){
|
||||
$reqPath = json_decode(file_get_contents("php://input"),true)['item'];
|
||||
$newPath = json_decode(file_get_contents("php://input"),true)['newItemPath'];
|
||||
return FileManage::RenameHandler($reqPath,$newPath,$this->userObj->uid);
|
||||
}
|
||||
|
||||
public function Preview(){
|
||||
$reqPath =$_GET["path"];
|
||||
$fileObj = new FileManage($reqPath,$this->userObj->uid);
|
||||
$Redirect = $fileObj->PreviewHandler();
|
||||
if($Redirect[0]){
|
||||
$this->redirect($Redirect[1],302);
|
||||
}
|
||||
}
|
||||
|
||||
public function ListPic(){
|
||||
$reqPath = $_GET["path"];
|
||||
return json(FileManage::listPic($reqPath,$this->userObj->uid));
|
||||
}
|
||||
|
||||
public function Download(){
|
||||
$reqPath = $_GET["path"];
|
||||
$fileObj = new FileManage($reqPath,$this->userObj->uid);
|
||||
$FileHandler = $fileObj->Download();
|
||||
if($FileHandler[0]){
|
||||
$this->redirect($FileHandler[1],302);
|
||||
}
|
||||
}
|
||||
|
||||
public function Share(){
|
||||
$reqData = json_decode(file_get_contents("php://input"),true);
|
||||
$reqPath = $reqData['item'];
|
||||
$shareType = $reqData['shareType'];
|
||||
$sharePwd = $reqData['pwd'];
|
||||
ShareHandler::createShare($reqPath,$shareType,$sharePwd,$this->userObj->getSQLData(),$this->userObj->getGroupData());
|
||||
}
|
||||
|
||||
public function gerSource(){
|
||||
$reqData = json_decode(file_get_contents("php://input"),true);
|
||||
$reqPath = $reqData['path'];
|
||||
$fileObj = new FileManage($reqPath,$this->userObj->uid);
|
||||
$FileHandler = $fileObj->Source();
|
||||
}
|
||||
|
||||
public function Content(){
|
||||
$reqPath = urldecode(input("get.path"));
|
||||
$fileObj = new FileManage($reqPath,$this->userObj->uid);
|
||||
$FileHandler = $fileObj->getContent();
|
||||
}
|
||||
|
||||
public function Edit(){
|
||||
$reqPath = json_decode(file_get_contents("php://input"),true)['item'];
|
||||
$fileContent = json_decode(file_get_contents("php://input"),true)['content'];
|
||||
$fileObj = new FileManage($reqPath,$this->userObj->uid);
|
||||
$FileHandler = $fileObj->saveContent($fileContent);
|
||||
}
|
||||
|
||||
public function OssDownload(){
|
||||
return view('oss_download', [
|
||||
'url' => urldecode(input("get.url")),
|
||||
'name' => urldecode(input("get.name")),
|
||||
]);
|
||||
}
|
||||
|
||||
public function DocPreview(){
|
||||
$filePath = input("get.path");
|
||||
$fileObj = new FileManage($filePath,$this->userObj->uid);
|
||||
$tmpUrl = $fileObj->signTmpUrl();
|
||||
$this->redirect("http://view.officeapps.live.com/op/view.aspx?src=".urlencode($tmpUrl),302);
|
||||
}
|
||||
|
||||
public function Thumb(){
|
||||
$filePath = input("get.path");
|
||||
if(input("get.isImg") != "true"){
|
||||
return "";
|
||||
}
|
||||
$fileObj = new FileManage($filePath,$this->userObj->uid);
|
||||
$Redirect = $fileObj->getThumb();
|
||||
if($Redirect[0]){
|
||||
$this->redirect($Redirect[1],302);
|
||||
}
|
||||
}
|
||||
|
||||
public function GoogleDocPreview(){
|
||||
$filePath = input("get.path");
|
||||
$fileObj = new FileManage($filePath,$this->userObj->uid);
|
||||
$tmpUrl = $fileObj->signTmpUrl();
|
||||
$this->redirect("https://docs.google.com/viewer?url=".urlencode($tmpUrl),302);
|
||||
}
|
||||
|
||||
/**
|
||||
* [createFolder description]
|
||||
* @Author Aaron
|
||||
* @DateTime 2017-07-03
|
||||
* @return [type] [description]
|
||||
*/
|
||||
public function createFolder(){
|
||||
$reqPath = stripslashes(json_decode(file_get_contents("php://input"),true)['newPath']);
|
||||
$pathSplit = explode("/",$reqPath);
|
||||
$dirName = end($pathSplit);
|
||||
$dirPosition="/";
|
||||
foreach ($pathSplit as $key => $value) {
|
||||
if (empty($value)){
|
||||
|
||||
}else if($key == (count($pathSplit)-2)){
|
||||
$dirPosition = $dirPosition.$value;
|
||||
}else if($key == (count($pathSplit)-1)){
|
||||
}else{
|
||||
$dirPosition = $dirPosition.$value."/";
|
||||
}
|
||||
|
||||
}
|
||||
return json(FileManage::createFolder($dirName,$dirPosition,$this->userObj->uid));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\User;
|
||||
use think\Session;
|
||||
|
||||
class Home extends Controller{
|
||||
|
||||
public $userObj;
|
||||
|
||||
public function _initialize(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
if(!$this->userObj->loginStatus){
|
||||
$this->redirect(url('/Login','',''));
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
public function index(){
|
||||
$userInfo = $this->userObj->getInfo();
|
||||
$policyData = $this->userObj->getPolicy();
|
||||
$groupData = $this->userObj->getGroupData();
|
||||
$extJson = json_decode($policyData["filetype"],true);
|
||||
$extLimit="";
|
||||
foreach ($extJson as $key => $value) {
|
||||
$extLimit.='{ title : "'.$value["title"].'", extensions : "'.$value["ext"].'" },';
|
||||
}
|
||||
$policyData["max_size"] = $policyData["max_size"]/(1024*1024);
|
||||
return view('home', [
|
||||
'options' => Option::getValues(['basic','upload'],$this->userObj->userSQLData),
|
||||
'userInfo' => $userInfo,
|
||||
'extLimit' => $extLimit,
|
||||
'policyData' => $policyData,
|
||||
'groupData' => $groupData,
|
||||
'chunkSize' => config('upload.chunk_size'),
|
||||
'path' => empty(input("get.path"))?"/":input("get.path"),
|
||||
]);
|
||||
}
|
||||
|
||||
public function Download(){
|
||||
$userInfo = $this->userObj->getInfo();
|
||||
$groupData = $this->userObj->getGroupData();
|
||||
return view('download', [
|
||||
'options' => Option::getValues(['basic','group_sell'],$this->userObj->userSQLData),
|
||||
'userInfo' => $userInfo,
|
||||
'groupData' => $groupData,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\User;
|
||||
|
||||
class Index extends Controller{
|
||||
|
||||
public $userObj;
|
||||
|
||||
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']),
|
||||
'userInfo' => $userInfo,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use app\index\model\User;
|
||||
use think\Cookie;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\Avatar;
|
||||
use \PHPGangsta_GoogleAuthenticator;
|
||||
use \app\index\model\TwoFactor;
|
||||
|
||||
class Member extends Controller{
|
||||
|
||||
public $userObj;
|
||||
|
||||
|
||||
public function index(){
|
||||
echo "Pong";
|
||||
}
|
||||
|
||||
public function Register(){
|
||||
if(input('?post.username-reg') && input('?post.password-reg')){
|
||||
$regAction = User::register(input('post.username-reg'),input('post.password-reg'),input('post.captchaCode'));
|
||||
if ($regAction[0]){
|
||||
return json(['code' => '200','message' => $regAction[1]]);
|
||||
}else{
|
||||
return json(['code' => '1','message' => $regAction[1]]);
|
||||
}
|
||||
}else{
|
||||
return json(['code' => '1','message' => "信息不完整"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function ForgetPwd(){
|
||||
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]]);
|
||||
}else{
|
||||
return json(['code' => '1','message' => $findAction[1]]);
|
||||
}
|
||||
}else{
|
||||
return json(['code' => '1','message' => "信息不完整"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function Login(){
|
||||
if(input('?post.userMail') && input('?post.userPass')){
|
||||
$logAction = User::login(input('post.userMail'),input('post.userPass'),input('post.captchaCode'));
|
||||
if ($logAction[0]){
|
||||
return json(['code' => '200','message' => '登陆成功']);
|
||||
}else{
|
||||
return json(['code' => '1','message' => $logAction[1]]);
|
||||
}
|
||||
}else{
|
||||
return json(['code' => '1','message' => "信息不完整"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function LogOut(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->userObj->clear();
|
||||
$this->redirect("/Login",302);
|
||||
|
||||
}
|
||||
|
||||
public function Memory(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->userObj->getMemory();
|
||||
}
|
||||
|
||||
public function SignUp(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->isLoginStatusCheck();
|
||||
return view('login', [
|
||||
'options' => Option::getValues(['basic'],$this->userObj->userSQLData),
|
||||
'RegOptions' => Option::getValues(['register','login']),
|
||||
'loginStatus' => $this->userObj->loginStatus,
|
||||
'pageId' => "register",
|
||||
]);
|
||||
}
|
||||
|
||||
public function FindPwd(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->isLoginStatusCheck();
|
||||
return view('login', [
|
||||
'options' => Option::getValues(['basic'],$this->userObj->userSQLData),
|
||||
'RegOptions' => Option::getValues(['register','login']),
|
||||
'loginStatus' => $this->userObj->loginStatus,
|
||||
'pageId' => "resetPwd",
|
||||
]);
|
||||
}
|
||||
|
||||
public function LoginForm(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->isLoginStatusCheck();
|
||||
return view('login', [
|
||||
'options' => Option::getValues(['basic'],$this->userObj->userSQLData),
|
||||
'RegOptions' => Option::getValues(['register','login']),
|
||||
'loginStatus' => $this->userObj->loginStatus,
|
||||
'pageId' => "login",
|
||||
]);
|
||||
}
|
||||
|
||||
public function TwoStepCheck(){
|
||||
$checkCode = input("post.code");
|
||||
if(empty($checkCode)){
|
||||
return json(['code' => '1','message' => "验证码不能为空"]);
|
||||
}
|
||||
$userId = session("user_id_tmp");
|
||||
$userData = Db::name('users')->where('id',$userId)->find();
|
||||
$ga = new PHPGangsta_GoogleAuthenticator();
|
||||
$checkResult = $ga->verifyCode($userData["two_step"], $checkCode, 2);
|
||||
if($checkResult) {
|
||||
cookie('user_id',session("user_id_tmp"),604800);
|
||||
cookie('login_status',session("login_status_tmp"),604800);
|
||||
cookie('login_key',session("login_key_tmp"),604800);
|
||||
return json(['code' => '200','message' => '登陆成功']);
|
||||
}else{
|
||||
return json(['code' => '1','message' => "验证失败"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function TwoStep(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->isLoginStatusCheck();
|
||||
return view('login', [
|
||||
'options' => Option::getValues(['basic'],$this->userObj->userSQLData),
|
||||
'RegOptions' => Option::getValues(['register','login']),
|
||||
'loginStatus' => $this->userObj->loginStatus,
|
||||
'pageId' => "TwoStep",
|
||||
]);
|
||||
}
|
||||
|
||||
public function setWebdavPwd(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->loginStatusCheck();
|
||||
Db::name("users")->where("id",$this->userObj->uid)
|
||||
->update([
|
||||
"webdav_key" => md5($this->userObj->userSQLData["user_email"].":CloudreveWebDav:".input("post.pwd")),
|
||||
]);
|
||||
return json(['error' => '200','msg' => '设置成功']);
|
||||
}
|
||||
|
||||
public function emailActivate(){
|
||||
$activationKey = input('param.key');
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->isLoginStatusCheck();
|
||||
$basicOptions = Option::getValues(['basic','register','login'],$this->userObj->userSQLData);
|
||||
$activeAction = User::activicateUser($activationKey);
|
||||
if($activeAction[0]){
|
||||
return view('login', [
|
||||
'options' => $basicOptions,
|
||||
'RegOptions' => $basicOptions,
|
||||
'loginStatus' => $this->userObj->loginStatus,
|
||||
'pageId' => "emailActivate",
|
||||
]);
|
||||
}else{
|
||||
$this->error($activeAction[1],403,$basicOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public function resetPwd(){
|
||||
$resetKey = input('param.key');
|
||||
$userId = input('get.uid');
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$basicOptions = Option::getValues(['basic','register','login'],$this->userObj->userSQLData);
|
||||
$this->isLoginStatusCheck();
|
||||
$resetAction = User::resetUser($resetKey,$userId);
|
||||
if($resetAction[0]){
|
||||
return view('login', [
|
||||
'options' => $basicOptions,
|
||||
'RegOptions' => $basicOptions,
|
||||
'loginStatus' => $this->userObj->loginStatus,
|
||||
'key' => $resetKey."_".$userId,
|
||||
'pageId' => "resetPwdForm",
|
||||
]);
|
||||
}else{
|
||||
$this->error($resetAction[1],403,$basicOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public function Reset(){
|
||||
$newPwd = input('post.pwd');
|
||||
$resetKey = input('post.key');
|
||||
$resetAction = User::resetPwd($resetKey,$newPwd);
|
||||
if($resetAction[0]){
|
||||
return json(['code' => '200','message' => '重设成功,请前往登录页登录']);
|
||||
}else{
|
||||
return json(['code' => '1','message' => $resetAction[1]]);
|
||||
}
|
||||
}
|
||||
|
||||
public function Setting(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$userInfo = $this->userObj->getInfo();
|
||||
$this->loginStatusCheck();
|
||||
$policyList=[];
|
||||
foreach (explode(",",$this->userObj->groupData["policy_list"]) as $key => $value) {
|
||||
$policyList[$key] = $value;
|
||||
}
|
||||
$avaliablePolicy = Db::name("policy")->where("id","in",$policyList)->select();
|
||||
$basicOptions = Option::getValues(['basic'],$this->userObj->userSQLData);
|
||||
return view('setting', [
|
||||
'options' => $basicOptions,
|
||||
'userInfo' => $userInfo,
|
||||
'userSQL' => $this->userObj->userSQLData,
|
||||
'groupData' => $this->userObj->groupData,
|
||||
'loginStatus' => $this->userObj->loginStatus,
|
||||
'avaliablePolicy' => $avaliablePolicy,
|
||||
]);
|
||||
}
|
||||
|
||||
public function SaveAvatar(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$file = request()->file("avatar");
|
||||
$avatarObj = new Avatar(true,$file);
|
||||
if(!$avatarObj->SaveAvatar()){
|
||||
return json_encode($avatarObj->errorMsg);
|
||||
}else{
|
||||
$avatarObj->bindUser($this->userObj->uid);
|
||||
return json_encode(["result" => "success"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function Avatar(){
|
||||
if(!input("get.cache")=="no"){
|
||||
header("Cache-Control: max-age=10800");
|
||||
}
|
||||
$userId = input("param.uid");
|
||||
$avatarObj = new Avatar(false,$userId);
|
||||
$avatarImg = $avatarObj->Out(input("param.size"));
|
||||
$this->redirect($avatarImg,302);
|
||||
}
|
||||
|
||||
public function SetGravatar(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$avatarObj = new Avatar(false,$this->userObj->uid);
|
||||
$avatarObj->setGravatar();
|
||||
}
|
||||
|
||||
public function Nick(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$userInfo = $this->userObj->getInfo();
|
||||
$this->loginStatusCheck();
|
||||
$saveAction = $this->userObj->changeNick(input("post.nick"));
|
||||
if($saveAction[0]){
|
||||
return json(['error' => '200','msg' => '设置成功']);
|
||||
}else{
|
||||
return json(['error' => '1','msg' => $saveAction[1]]);
|
||||
}
|
||||
}
|
||||
|
||||
public function ChangeThemeColor(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->loginStatusCheck();
|
||||
$saveAction = $this->userObj->changeOption("preferTheme",input("post.theme"));
|
||||
if($saveAction[0]){
|
||||
return json(['error' => '200','msg' => '设置成功']);
|
||||
}else{
|
||||
return json(['error' => '1','msg' => $saveAction[1]]);
|
||||
}
|
||||
}
|
||||
|
||||
public function HomePage(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$userInfo = $this->userObj->getInfo();
|
||||
$this->loginStatusCheck();
|
||||
$saveAction = $this->userObj->homePageToggle(input("post.status"));
|
||||
if($saveAction[0]){
|
||||
return json(['error' => '200','msg' => '设置成功']);
|
||||
}else{
|
||||
return json(['error' => '1','msg' => $saveAction[1]]);
|
||||
}
|
||||
}
|
||||
|
||||
public function EnableTwoFactor(){
|
||||
$twoFactor = new TwoFactor();
|
||||
$twoFactor->qrcodeRender();
|
||||
}
|
||||
|
||||
public function TwoFactorConfirm(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$userInfo = $this->userObj->getInfo();
|
||||
$this->loginStatusCheck();
|
||||
$twoFactor = new TwoFactor();
|
||||
$confirmResult = $twoFactor->confirmCode(session("two_factor_enable"),input("post.code"));
|
||||
if($confirmResult[0]){
|
||||
$twoFactor->bindUser($this->userObj->uid);
|
||||
return json(['error' => '200','msg' => '设置成功']);
|
||||
}else{
|
||||
return json(['error' => '1','msg' => $confirmResult[1]]);
|
||||
}
|
||||
}
|
||||
|
||||
public function ChangePwd(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$userInfo = $this->userObj->getInfo();
|
||||
$this->loginStatusCheck();
|
||||
$changeAction = $this->userObj->changePwd(input("post.origin"),input("post.new"));
|
||||
if($changeAction[0]){
|
||||
return json(['error' => '200','msg' => '设置成功']);
|
||||
}else{
|
||||
return json(['error' => '1','msg' => $changeAction[1]]);
|
||||
}
|
||||
}
|
||||
|
||||
private function loginStatusCheck($login=true){
|
||||
if(!$this->userObj->loginStatus){
|
||||
if($login){
|
||||
$this->redirect(url('/Login','',''));
|
||||
}else{
|
||||
$this->redirect(url('/Home','',''));
|
||||
}
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
private function isLoginStatusCheck(){
|
||||
if($this->userObj->loginStatus){
|
||||
$this->redirect(url('/Home','',''));
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use app\index\model\User;
|
||||
use think\Cookie;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
|
||||
class Profile extends Controller{
|
||||
|
||||
public $visitorObj;
|
||||
public $userObj;
|
||||
public $siteOptions;
|
||||
|
||||
public function _initialize(){
|
||||
}
|
||||
|
||||
public function getList(){
|
||||
$userId = (string)input("post.uid");
|
||||
$userData = Db::name("users")->where("id",$userId)->find();
|
||||
$page = (int)input("post.page");
|
||||
if (empty($userId) || empty($userData) || $userData["profile"] == 0){
|
||||
$this->error('用户主页不存或者用户关闭了个人主页',404,$this->siteOptions);
|
||||
}
|
||||
switch (input("post.type")) {
|
||||
case 'all':
|
||||
$list = Db::name('shares')
|
||||
->where('owner',$userId)
|
||||
->where('type',"public")
|
||||
->order('share_time DESC')
|
||||
->page($page.',10')
|
||||
->select();
|
||||
break;
|
||||
case 'hot':
|
||||
$num = Option::getValue("hot_share_num");
|
||||
$list = Db::name('shares')
|
||||
->where('owner',$userId)
|
||||
->where('type',"public")
|
||||
->order('download_num DESC')
|
||||
->limit($num)
|
||||
->select();
|
||||
break;
|
||||
default:
|
||||
$list = Db::name('shares')
|
||||
->where('owner',$userId)
|
||||
->where('type',"public")
|
||||
->order('share_time DESC')
|
||||
->page($page.',10')
|
||||
->select();
|
||||
break;
|
||||
}
|
||||
$listData = $list;
|
||||
foreach ($listData as $key => $value) {
|
||||
unset($listData[$key]["share_pwd"]);
|
||||
unset($listData[$key]["source_name"]);
|
||||
if($value["source_type"]=="file"){
|
||||
$listData[$key]["fileData"] = Db::name('files')->where('id',$value["source_name"])->find()["orign_name"];
|
||||
|
||||
}else{
|
||||
$pathDir = explode("/",$value["source_name"]);
|
||||
$listData[$key]["fileData"] = end($pathDir);
|
||||
}
|
||||
}
|
||||
|
||||
return json($listData);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function index(){
|
||||
$this->visitorObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->siteOptions = Option::getValues(["basic"],$this->visitorObj->userSQLData);
|
||||
$userId = (string)input("param.uid");
|
||||
$userData = Db::name("users")->where("id",$userId)->find();
|
||||
if (empty($userId) || empty($userData) || $userData["profile"] == 0){
|
||||
$this->error('用户主页不存或者用户关闭了个人主页',404,$this->siteOptions);
|
||||
}
|
||||
$groupData = Db::name("groups")->where("id",$userData["user_group"])->find();
|
||||
$shareCount = Db::name('shares')
|
||||
->where('owner',$userId)
|
||||
->where('type',"public")
|
||||
->count();
|
||||
$regDays = (int)((time()-strtotime($userData["user_date"]))/86400);
|
||||
|
||||
return view("profile",[
|
||||
"options" => $this->siteOptions,
|
||||
'loginStatus' => $this->visitorObj->loginStatus,
|
||||
'targetUserInfo' => $userData,
|
||||
'userSQL' => $this->visitorObj->userSQLData,
|
||||
'userInfo' => $this->visitorObj->getInfo(),
|
||||
'groupData' => $groupData,
|
||||
'type' => input("get.type"),
|
||||
'shareCount' => $shareCount,
|
||||
'regDays' => $regDays,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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" && $policyData["policy_type"] != "onedrive"){
|
||||
return json(["result"=>['success'=>false,'error'=>"您当前的无用户无法执行此操作"]]);
|
||||
}
|
||||
$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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
<?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\ShareHandler;
|
||||
use think\Session;
|
||||
use think\Request;
|
||||
|
||||
class Share extends Controller{
|
||||
|
||||
public $userObj;
|
||||
public $siteOptions;
|
||||
|
||||
public function _initialize(){
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
$this->siteOptions = Option::getValues(["basic","share"]);
|
||||
}
|
||||
|
||||
public function index(){
|
||||
$shareKey = input('param.key');
|
||||
$shareObj = new ShareHandler($shareKey);
|
||||
if(!$shareObj->querryStatus){
|
||||
header('HTTP/1.1 404 Not Found');
|
||||
$this->error('当前分享不存在或者已经失效',404,$this->siteOptions);
|
||||
}
|
||||
if(!$shareObj->lockStatus){
|
||||
$shareObj->numIncrease("view_num");
|
||||
if($shareObj->shareData["source_type"] == "dir"){
|
||||
return view('share_dir', [
|
||||
'options' => Option::getValues(['basic','share'],$this->userObj->userSQLData),
|
||||
'userInfo' => $shareObj->shareOwner->userSQLData,
|
||||
'dirData' => $shareObj->dirData,
|
||||
'shareData' => $shareObj->shareData,
|
||||
'loginStatus' => $this->userObj->loginStatus,
|
||||
'userData' => $this->userObj->getInfo(),
|
||||
'groupData' => $shareObj->shareOwner->groupData,
|
||||
'allowPreview' => Option::getValue("allowdVisitorDownload"),
|
||||
'path' => empty(input("get.path"))?"/":input("get.path"),
|
||||
]);
|
||||
}else{
|
||||
return view('share_single', [
|
||||
'options' => Option::getValues(['basic','share'],$this->userObj->userSQLData),
|
||||
'userInfo' => $shareObj->shareOwner->userSQLData,
|
||||
'fileData' => $shareObj->fileData,
|
||||
'shareData' => $shareObj->shareData,
|
||||
'loginStatus' => $this->userObj->loginStatus,
|
||||
'userData' => $this->userObj->getInfo(),
|
||||
'allowPreview' => Option::getValue("allowdVisitorDownload"),
|
||||
'path' => empty(input("get.path"))?"/":input("get.path"),
|
||||
]);
|
||||
}
|
||||
}else{
|
||||
return view('share_lock', [
|
||||
'options' => Option::getValues(['basic','share'],$this->userObj->userSQLData),
|
||||
'userInfo' => $shareObj->shareOwner->userSQLData,
|
||||
'fileData' => $shareObj->fileData,
|
||||
'shareData' => $shareObj->shareData,
|
||||
'loginStatus' => $this->userObj->loginStatus,
|
||||
'userData' => $this->userObj->getInfo(),
|
||||
'pwd' => input("?get.pwd") ? input("get.pwd") : "",
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function getDownloadUrl(){
|
||||
$shareId = input('key');
|
||||
$shareObj = new ShareHandler($shareId,false);
|
||||
return json($shareObj->getDownloadUrl($this->userObj));
|
||||
}
|
||||
|
||||
public function Download(){
|
||||
$shareId = input('param.key');
|
||||
$filePath = input('get.path');
|
||||
if($this->siteOptions["refererCheck"]=="true"){
|
||||
$check = $this->referCheck();
|
||||
if(!$check){
|
||||
$this->error("来源非法",403,$this->siteOptions);
|
||||
}
|
||||
}
|
||||
$shareObj = new ShareHandler($shareId,false);
|
||||
if(empty($filePath)){
|
||||
$DownloadHandler = $shareObj->Download($this->userObj);
|
||||
}else{
|
||||
$DownloadHandler = $shareObj->DownloadFolder($this->userObj,$filePath);
|
||||
}
|
||||
if($DownloadHandler[0]){
|
||||
$this->redirect($DownloadHandler[1],302);
|
||||
}else{
|
||||
$this->error($DownloadHandler[1],404,$this->siteOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public function Content(){
|
||||
$shareId = input('param.key');
|
||||
$filePath = input('get.path');
|
||||
if($this->siteOptions["refererCheck"]=="true"){
|
||||
$check = $this->referCheck();
|
||||
if(!$check){
|
||||
$this->error("来源非法",403,$this->siteOptions);
|
||||
}
|
||||
}
|
||||
$shareObj = new ShareHandler($shareId,false);
|
||||
if(empty($filePath)){
|
||||
$contentHandller = $shareObj->getContent($this->userObj,$filePath,false);
|
||||
}else{
|
||||
$contentHandller = $shareObj->getContent($this->userObj,$filePath,true);
|
||||
}
|
||||
if(!$contentHandller[0]){
|
||||
return json(["result"=>["success"=>false,"error"=>$contentHandller[1]]]);
|
||||
}
|
||||
}
|
||||
|
||||
public function chekPwd(){
|
||||
$shareId = input('key');
|
||||
$inputPwd = input('password');
|
||||
$shareObj = new ShareHandler($shareId,false);
|
||||
if(!$shareObj->querryStatus){
|
||||
return array(
|
||||
"error" => 1,
|
||||
"msg" => "分享不存在"
|
||||
);
|
||||
}
|
||||
return json($shareObj->checkPwd($inputPwd));
|
||||
}
|
||||
|
||||
private function referCheck(){
|
||||
$agent = Request::instance()->header('referer');
|
||||
if(substr($agent, 0, strlen($this->siteOptions["siteURL"])) !== $this->siteOptions["siteURL"]){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function Preview(){
|
||||
$shareId = input('param.key');
|
||||
$filePath = input('get.path');
|
||||
if($this->siteOptions["refererCheck"]=="true"){
|
||||
$check = $this->referCheck();
|
||||
if(!$check){
|
||||
$this->error("来源非法",403,$this->siteOptions);
|
||||
}
|
||||
}
|
||||
$shareObj = new ShareHandler($shareId,false);
|
||||
if(empty($filePath)){
|
||||
$previewHandler = $shareObj->Preview($this->userObj);
|
||||
}else{
|
||||
if(!empty(input('get.folder'))){
|
||||
$previewHandler = $shareObj->PreviewFolder($this->userObj,$filePath,true);
|
||||
}else{
|
||||
$previewHandler = $shareObj->PreviewFolder($this->userObj,$filePath);
|
||||
}
|
||||
}
|
||||
if($previewHandler[0]){
|
||||
$this->redirect($previewHandler[1],302);
|
||||
}else{
|
||||
$this->error($previewHandler[1],404,$this->siteOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public function ListFile(){
|
||||
$shareId = input('param.key');
|
||||
$reqPathTo = stripslashes(json_decode(file_get_contents("php://input"),true)['path']);
|
||||
$shareObj = new ShareHandler($shareId,false);
|
||||
return json($shareObj->ListFile($reqPathTo));
|
||||
}
|
||||
|
||||
public function ListPic(){
|
||||
$filePath = input('get.path');
|
||||
$shareId = input('get.id');
|
||||
$shareObj = new ShareHandler($shareId,false);
|
||||
return $shareObj->listPic($shareId,$filePath);
|
||||
}
|
||||
|
||||
public function Thumb(){
|
||||
$shareId = input('param.key');
|
||||
$filePath = urldecode(input('get.path'));
|
||||
if(input("get.isImg") != "true"){
|
||||
return "";
|
||||
}
|
||||
if($this->siteOptions["refererCheck"]=="true"){
|
||||
$check = $this->referCheck();
|
||||
if(!$check){
|
||||
$this->error("来源非法",403,$this->siteOptions);
|
||||
}
|
||||
}
|
||||
$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 DocPreview(){
|
||||
$shareId = input('param.key');
|
||||
$filePath = urldecode(input('get.path'));
|
||||
if($this->siteOptions["refererCheck"]=="true"){
|
||||
$check = $this->referCheck();
|
||||
if(!$check){
|
||||
$this->error("来源非法",403,$this->siteOptions);
|
||||
}
|
||||
}
|
||||
$shareObj = new ShareHandler($shareId,false);
|
||||
if(empty($filePath)){
|
||||
$Redirect = $shareObj->getDocPreview($this->userObj,$filePath,false);
|
||||
}else{
|
||||
$Redirect = $shareObj->getDocPreview($this->userObj,$filePath,true);
|
||||
}
|
||||
|
||||
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);
|
||||
if(!$shareObj->querryStatus){
|
||||
return json(array(
|
||||
"error" => 1,
|
||||
"msg" => "分享不存在"
|
||||
));
|
||||
}
|
||||
return json($shareObj->deleteShare($this->userObj->uid));
|
||||
}
|
||||
|
||||
public function ChangePromission(){
|
||||
$shareId = input('post.id');
|
||||
$shareObj = new ShareHandler($shareId,false);
|
||||
if(!$shareObj->querryStatus){
|
||||
return json(array(
|
||||
"error" => 1,
|
||||
"msg" => "分享不存在"
|
||||
));
|
||||
}
|
||||
return json($shareObj->changePromission($this->userObj->uid));
|
||||
}
|
||||
|
||||
public function ListMyShare(){
|
||||
if(!$this->userObj->loginStatus){
|
||||
$this->redirect(url('/Login','',''));
|
||||
exit();
|
||||
}
|
||||
$list = Db::name('shares')
|
||||
->where('owner',$this->userObj->uid)
|
||||
->order('share_time DESC')
|
||||
->page(input("post.page").",18")
|
||||
->select();
|
||||
$listData = $list;
|
||||
foreach ($listData as $key => $value) {
|
||||
unset($listData[$key]["source_name"]);
|
||||
if($value["source_type"]=="file"){
|
||||
$listData[$key]["fileData"] = Db::name('files')->where('id',$value["source_name"])->find()["orign_name"];
|
||||
|
||||
}else{
|
||||
$listData[$key]["fileData"] = $value["source_name"];
|
||||
}
|
||||
}
|
||||
return json($listData);
|
||||
}
|
||||
|
||||
public function My(){
|
||||
if(!$this->userObj->loginStatus){
|
||||
$this->redirect(url('/Login','',''));
|
||||
exit();
|
||||
}
|
||||
$userInfo = $this->userObj->getInfo();
|
||||
$groupData = $this->userObj->getGroupData();
|
||||
return view('share_home', [
|
||||
'options' => Option::getValues(['basic','share'],$this->userObj->userSQLData),
|
||||
'userData' => $userInfo,
|
||||
'groupData' => $groupData,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use think\Db;
|
||||
use think\Request;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\User;
|
||||
use \app\index\model\UploadHandler;
|
||||
use think\Session;
|
||||
|
||||
class Upload 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();
|
||||
}
|
||||
}
|
||||
|
||||
public function index(){
|
||||
ob_end_clean();
|
||||
$file = request()->file('file');
|
||||
$fileInfo = Request::instance()->request();
|
||||
$UploadHandler = new UploadHandler($this->userObj->groupData['policy_name'],$this->userObj->uid);
|
||||
return $UploadHandler->fileReceive($file,$fileInfo);
|
||||
}
|
||||
|
||||
public function Token(){
|
||||
$uploadObj = new UploadHandler($this->userObj->groupData['policy_name'],$this->userObj->uid);
|
||||
$upToken = $uploadObj->getToken();
|
||||
if(!empty($uploadObj->upyunPolicy)){
|
||||
return json([
|
||||
"token" => $upToken,
|
||||
"policy" => $uploadObj->upyunPolicy,
|
||||
]);
|
||||
}
|
||||
if(!empty($uploadObj->s3Policy)){
|
||||
return json([
|
||||
"policy" => $uploadObj->s3Policy,
|
||||
"sign" => $uploadObj->s3Sign,
|
||||
"key" => $uploadObj->dirName,
|
||||
"credential" => $uploadObj->s3Credential,
|
||||
"x_amz_date" => $uploadObj->x_amz_date,
|
||||
"siteUrl"=>$uploadObj->siteUrl,
|
||||
"callBackKey" => $uploadObj->callBackKey,
|
||||
]);
|
||||
}
|
||||
if(!$uploadObj->getToken()){
|
||||
return json([
|
||||
"uptoken" => $uploadObj->ossToken,
|
||||
"sign" => $uploadObj->ossSign,
|
||||
"id" => $uploadObj->ossAccessId,
|
||||
"key" => $uploadObj->ossFileName,
|
||||
"callback" => $uploadObj->ossCallBack,
|
||||
]);
|
||||
}
|
||||
return json(["uptoken" => $uploadObj->getToken()]);
|
||||
}
|
||||
|
||||
public function chunk(){
|
||||
$file = file_get_contents('php://input');
|
||||
$uploadObj = new UploadHandler($this->userObj->groupData['policy_name'],$this->userObj->uid);
|
||||
$uploadObj->setChunk(input('param.chunk'),input('param.chunks'),$file);
|
||||
}
|
||||
|
||||
public function mkFile(){
|
||||
$ctx = file_get_contents('php://input');
|
||||
$originName = UploadHandler::b64Decode(input('param.fname'));
|
||||
$filePath = UploadHandler::b64Decode(input('param.path'));
|
||||
$uploadObj = new UploadHandler($this->userObj->groupData['policy_name'],$this->userObj->uid);
|
||||
$uploadObj->generateFile($ctx,$originName,$filePath);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace app\index\controller;
|
||||
|
||||
use think\Controller;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\User;
|
||||
use think\Session;
|
||||
use \app\index\model\FileManage;
|
||||
use \app\index\model\ShareHandler;
|
||||
|
||||
class Viewer extends Controller{
|
||||
|
||||
public $userObj;
|
||||
|
||||
public function _initialize(){
|
||||
// $this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
// if(!$this->userObj->loginStatus){
|
||||
// $this->redirect(url('/Login','',''));
|
||||
// exit();
|
||||
// }
|
||||
$this->userObj = new User(cookie('user_id'),cookie('login_key'));
|
||||
}
|
||||
|
||||
public function Video(){
|
||||
$path = input("get.path");
|
||||
$pathSplit = explode("/",urldecode($path));
|
||||
$userInfo = $this->userObj->getInfo();
|
||||
$groupData = $this->userObj->getGroupData();
|
||||
$url = "/File/Preview?action=preview&path=".$path;
|
||||
if(input("get.share")==true){
|
||||
$url = "/Share/Preview/".input("get.shareKey")."/?path=".$path;
|
||||
}else if(input("get.single")==true){
|
||||
$url = "/Share/Preview/".input("get.shareKey");
|
||||
}
|
||||
return view('video', [
|
||||
'options' => Option::getValues(['basic'],$this->userObj->userSQLData),
|
||||
'userInfo' => $userInfo,
|
||||
'groupData' => $groupData,
|
||||
'url' => $url,
|
||||
'fileName' => end($pathSplit),
|
||||
'isSharePage' => input("?get.share")?"true":"false",
|
||||
]);
|
||||
}
|
||||
|
||||
public function Markdown(){
|
||||
$path = input("get.path");
|
||||
$pathSplit = explode("/",urldecode($path));
|
||||
$userInfo = $this->userObj->getInfo();
|
||||
$groupData = $this->userObj->getGroupData();
|
||||
$url = "/File/Content?action=preview&path=".$path;
|
||||
if(input("get.share")==true){
|
||||
$url = "/Share/Content/".input("get.shareKey")."/?path=".$path;
|
||||
}else if(input("get.single")==true){
|
||||
$url = "/Share/Content/".input("get.shareKey");
|
||||
}
|
||||
return view('markdown', [
|
||||
'options' => Option::getValues(['basic'],$this->userObj->userSQLData),
|
||||
'userInfo' => $userInfo,
|
||||
'groupData' => $groupData,
|
||||
'url' => $url,
|
||||
'fileName' => end($pathSplit),
|
||||
'path' => urldecode($path),
|
||||
'isSharePage' => input("?get.share")?"true":"false",
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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\Directory;
|
||||
use \app\index\model\Objects;
|
||||
use \app\index\model\DavAuth;
|
||||
use \app\index\model\BasicCallBack;
|
||||
|
||||
use Sabre\DAV;
|
||||
use Sabre\DAV\Auth;
|
||||
|
||||
class WebDav extends Controller{
|
||||
|
||||
public $userObj;
|
||||
public $uid;
|
||||
|
||||
public function index(){
|
||||
|
||||
}
|
||||
|
||||
public function Api(){
|
||||
$this->uid = input("param.uid");
|
||||
$publicDir = new Directory($this->uid."/");
|
||||
|
||||
$server = new DAV\Server($publicDir);
|
||||
$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);
|
||||
$check = new DavAuth($this->uid);
|
||||
$callBack = new BasicCallBack($check);
|
||||
$authPlugin = new Auth\Plugin($callBack);
|
||||
$server->addPlugin($authPlugin);
|
||||
$server->addPlugin(new DAV\Browser\Plugin());
|
||||
$server->addPlugin(new \Sabre\DAV\Browser\GuessContentType());
|
||||
ob_end_clean();
|
||||
$server->exec();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,811 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use \app\index\model\Mail;
|
||||
use \app\index\model\FileManage;
|
||||
use \Krizalys\Onedrive\Client;
|
||||
|
||||
class AdminHandler extends Model{
|
||||
|
||||
public $siteOptions;
|
||||
public $pageData;
|
||||
public $listData;
|
||||
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();
|
||||
$statics["publicShareNum"] = Db::name('shares')->where("type","public")->count();
|
||||
$statics["userNum"] = Db::name('users')->where("user_status",0)->count();
|
||||
if($statics["fileNum"]==0){
|
||||
$statics["imgRate"] = 0;
|
||||
$statics["audioRate"] = 0;
|
||||
$statics["videoRate"] = 0;
|
||||
$statics['otherRate'] = 0;
|
||||
}else{
|
||||
$statics["imgRate"] =floor(Db::name('files')
|
||||
->where('pic_info',"<>"," ")
|
||||
->where('pic_info',"<>","0,0")
|
||||
->where('pic_info',"<>","null,null")
|
||||
->count()/$statics["fileNum"]*10000)/100;
|
||||
$statics["audioRate"] =floor(Db::name('files')
|
||||
->where(function ($query) {
|
||||
$query->where('orign_name', "like","%mp3")
|
||||
->whereor('orign_name', "like","%flac")
|
||||
->whereor('orign_name', "like","%wma")
|
||||
->whereor('orign_name', "like","%aac")
|
||||
->whereor('orign_name', "like","%wav")
|
||||
->whereor('orign_name', "like","%ogg");
|
||||
})
|
||||
->count()/$statics["fileNum"]*10000)/100;
|
||||
$statics["videoRate"] =floor(Db::name('files')
|
||||
->where(function ($query) {
|
||||
$query->where('orign_name', "like","%mp4")
|
||||
->whereor('orign_name', "like","%avi")
|
||||
->whereor('orign_name', "like","%rmvb")
|
||||
->whereor('orign_name', "like","%aac")
|
||||
->whereor('orign_name', "like","%wav")
|
||||
->whereor('orign_name', "like","%mkv");
|
||||
})
|
||||
->count()/$statics["fileNum"]*10000)/100;
|
||||
$statics['otherRate'] = 100-($statics["videoRate"]+$statics["audioRate"]+$statics["imgRate"]);
|
||||
}
|
||||
$timeNow=time();
|
||||
$statics["trendFile"]="";
|
||||
$statics["trendUser"]="";
|
||||
$statics["trendDate"]="";
|
||||
for ($i=0; $i < 13; $i++) {
|
||||
$statics["trendFile"].= Db::name('files')->where('upload_date','between time',[date("Y-m-d",$timeNow-(12-$i)*3600*24),date("Y-m-d",$timeNow-(11-$i)*3600*24)])->count().",";
|
||||
}
|
||||
for ($i=0; $i < 13; $i++) {
|
||||
$statics["trendUser"].= Db::name('users')->where('user_date','between time',[date("Y-m-d",$timeNow-(12-$i)*3600*24),date("Y-m-d",$timeNow-(11-$i)*3600*24)])->count().",";
|
||||
}
|
||||
for ($i=0; $i < 13; $i++) {
|
||||
$statics["trendDate"].='"'.date("m月d日",$timeNow-(12-$i)*3600*24).'",';
|
||||
}
|
||||
$statics["trendFile"] = rtrim($statics["trendFile"],",");
|
||||
$statics["trendDate"] = rtrim($statics["trendDate"],",");
|
||||
$statics["trendUser"] = rtrim($statics["trendUser"],",");
|
||||
return $statics;
|
||||
}
|
||||
|
||||
public function saveBasicSetting($options){
|
||||
$siteUrl = rtrim($options["siteURL"],"/")."/";
|
||||
$options["siteURL"]=$siteUrl;
|
||||
return $this->saveOptions($options);
|
||||
}
|
||||
|
||||
public function saveColorSetting($options){
|
||||
$colorOptions = [];
|
||||
foreach ($options["color"] as $key => $value) {
|
||||
$color = \json_decode($value,true);
|
||||
$validate = ($color!==null)&&array_key_exists("palette",$color) &&
|
||||
array_key_exists("common",$color["palette"]) &&
|
||||
array_key_exists("black",$color["palette"]["common"]) &&
|
||||
array_key_exists("white",$color["palette"]["common"]) &&
|
||||
array_key_exists("background",$color["palette"]) &&
|
||||
array_key_exists("primary",$color["palette"]) &&
|
||||
array_key_exists("secondary",$color["palette"]) &&
|
||||
array_key_exists("error",$color["palette"]) &&
|
||||
array_key_exists("text",$color["palette"]) &&
|
||||
array_key_exists("explorer",$color["palette"]) &&
|
||||
array_key_exists("main",$color["palette"]["primary"]) &&
|
||||
array_key_exists("main",$color["palette"]["secondary"]);
|
||||
if(!$validate){
|
||||
return ["error"=>1,"msg"=>"第 ".($key+1)." 行配色方案格式有误"];
|
||||
}
|
||||
$colorOptions[$color["palette"]["primary"]["main"]] = $color;
|
||||
}
|
||||
if(!array_key_exists($options["header"],$colorOptions)){
|
||||
return ["error"=>1,"msg"=>"第 ".($key+1)." 默认配色不存在"];
|
||||
}
|
||||
$optionsForSet = [
|
||||
"defaultTheme" => $options["header"],
|
||||
"themes" => json_encode($colorOptions),
|
||||
];
|
||||
return $this->saveOptions($optionsForSet);
|
||||
}
|
||||
|
||||
public function saveRegSetting($options){
|
||||
foreach(["email_active","login_captcha","reg_captcha","forget_captcha"] as $key){
|
||||
$options[$key] = array_key_exists($key,$options) ? $options[$key] : 0;
|
||||
}
|
||||
return $this->saveOptions($options);
|
||||
}
|
||||
|
||||
public function saveMailSetting($options){
|
||||
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);
|
||||
}
|
||||
|
||||
public function AddGroup($options){
|
||||
$options["max_storage"] = $options["max_storage"]*$options["sizeTimes"];
|
||||
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) {
|
||||
return ["error"=>1,"msg"=>$e->getMessage()];
|
||||
}
|
||||
return ["error"=>200,"msg"=>"设置已保存"];
|
||||
}
|
||||
|
||||
public function addPolicy($options){
|
||||
$options["max_size"] = $options["max_size"]*$options["sizeTimes"];
|
||||
unset($options["sizeTimes"]);
|
||||
$options["server"] = isset($options["server"]) ? $options["server"] : "/Upload";
|
||||
foreach (["bucketname","bucket_private","bucketname","ak","sk","op_name","op_pwd","mimetype","namerule"] as $key => $value) {
|
||||
$options[$value] = isset($options[$value]) ? $options[$value] : "0";
|
||||
}
|
||||
if(empty($options["filetype"])){
|
||||
$options["filetype"]="[]";
|
||||
}else{
|
||||
$options["filetype"] = json_encode([0=>["ext"=>$options["filetype"],"title"=>"default"]]);
|
||||
}
|
||||
if($options["policy_type"] == "upyun"){
|
||||
$options["server"] = "https://v0.api.upyun.com/".$options["bucketname"];
|
||||
}
|
||||
try {
|
||||
Db::name("policy")->insert($options);
|
||||
} catch (Exception $e) {
|
||||
return ["error"=>1,"msg"=>$e->getMessage()];
|
||||
}
|
||||
return ["error"=>200,"msg"=>"设置已保存","id"=>Db::name('policy')->getLastInsID()];
|
||||
}
|
||||
|
||||
public function editPolicy($options){
|
||||
$policyId = $options["id"];
|
||||
$options["max_size"] = $options["max_size"]*$options["sizeTimes"];
|
||||
unset($options["sizeTimes"]);
|
||||
unset($options["id"]);
|
||||
if(empty($options["filetype"])){
|
||||
$options["filetype"]="[]";
|
||||
}else{
|
||||
$options["filetype"] = json_encode([0=>["ext"=>$options["filetype"],"title"=>"default"]]);
|
||||
}
|
||||
try {
|
||||
Db::name("policy")->where("id",$policyId)->update($options);
|
||||
} catch (Exception $e) {
|
||||
return ["error"=>1,"msg"=>$e->getMessage()];
|
||||
}
|
||||
return ["error"=>200,"msg"=>"设置已保存"];
|
||||
}
|
||||
|
||||
public function saveGroup($options){
|
||||
$groupId = $options["id"];
|
||||
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) {
|
||||
return ["error"=>1,"msg"=>$e->getMessage()];
|
||||
}
|
||||
return ["error"=>200,"msg"=>"设置已保存"];
|
||||
}
|
||||
|
||||
public function saveOptions($options){
|
||||
try {
|
||||
foreach ($options as $key => $value) {
|
||||
Db::name("options")->where("option_name",$key)->update(["option_value"=>$value]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return ["error"=>1,"msg"=>$e->getMessage()];
|
||||
}
|
||||
return ["error"=>200,"msg"=>"设置已保存"];
|
||||
}
|
||||
|
||||
public function getAvaliableGroup(){
|
||||
$groupData = Db::name("groups")->where("id","neq",2)->select();
|
||||
return $groupData;
|
||||
}
|
||||
|
||||
public function saveCron($options){
|
||||
$cronId = $options["id"];
|
||||
unset($options["id"]);
|
||||
Db::name("corn")->where("id",$cronId)->update($options);
|
||||
}
|
||||
|
||||
public function getAvaliablePolicy(){
|
||||
$policyData = Db::name("policy")->select();
|
||||
return $policyData;
|
||||
}
|
||||
|
||||
public function sendTestMail($options){
|
||||
$mailObj = new Mail();
|
||||
if(empty($options["receiveMail"])){
|
||||
return ["error"=>1,"msg"=>"接收邮箱不能为空"];
|
||||
}
|
||||
$sendResult = $mailObj->Send($options["receiveMail"],"发信测试",$options["subject"],$options["content"]);
|
||||
if($sendResult){
|
||||
return ["error"=>200,"msg"=>"发送成功"];
|
||||
}else{
|
||||
return ["error"=>1,"msg"=>$mailObj->errorMsg];
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteSingle($id){
|
||||
$fileRecord = Db::name("files")->where("id",$id)->find();
|
||||
return FileManage::DeleteHandler([0 => rtrim($fileRecord["dir"],"/")."/".$fileRecord["orign_name"]],$fileRecord["upload_user"]);
|
||||
}
|
||||
|
||||
public function deletePolicy($id){
|
||||
$groupData = Db::name("groups")->where("policy_name",$id)->select();
|
||||
if(!empty($groupData)){
|
||||
return ["error"=>true,"msg"=>"此上传策略正在被以下用户组使用:".join(",",array_column($groupData, "group_name"))];
|
||||
}
|
||||
Db::name("policy")->where("id",$id)->delete();
|
||||
return ["error"=>false,"msg"=>"已删除"];
|
||||
}
|
||||
|
||||
public function deleteGroup($id){
|
||||
$userData = Db::name("users")->where("user_group",$id)->find();
|
||||
if(!empty($userData)){
|
||||
return ["error"=>true,"msg"=>"此用户组下仍有用户,请先删除这些用户"];
|
||||
}
|
||||
if($id == 1 || $id == 2){
|
||||
return ["error"=>true,"msg"=>"系统保留用户组,无法删除"];
|
||||
}
|
||||
Db::name("groups")->where("id",$id)->delete();
|
||||
return ["error"=>false,"msg"=>"已删除"];
|
||||
}
|
||||
|
||||
public function getConfigFile($type){
|
||||
switch ($type) {
|
||||
case 'common':
|
||||
$configPath = ROOT_PATH ."application/config.php";
|
||||
$basicPath = "application/config.php";
|
||||
break;
|
||||
case 'database':
|
||||
if(file_exists( ROOT_PATH ."application/database.lock")){
|
||||
return ["出于安全考虑,默认禁止直接编辑数据库配置文件。如果需要开启编辑,请手动删除 application/database.lock 文件。","application/database.php"];
|
||||
}
|
||||
$configPath = ROOT_PATH ."application/database.php";
|
||||
$basicPath = "application/database.php";
|
||||
break;
|
||||
case 'route':
|
||||
$configPath = ROOT_PATH ."application/route.php";
|
||||
$basicPath = "application/route.php";
|
||||
break;
|
||||
case 'tags':
|
||||
$configPath = ROOT_PATH ."application/tags.php";
|
||||
$basicPath = "application/tags.php";
|
||||
break;
|
||||
default:
|
||||
die("");
|
||||
break;
|
||||
}
|
||||
return [file_get_contents($configPath),$basicPath];
|
||||
}
|
||||
|
||||
public function saveConfigFile($options){
|
||||
switch ($options["type"]) {
|
||||
case 'common':
|
||||
file_put_contents(ROOT_PATH ."application/config.php",$options["content"]);
|
||||
break;
|
||||
case 'route':
|
||||
file_put_contents(ROOT_PATH ."application/route.php",$options["content"]);
|
||||
break;
|
||||
case 'tags':
|
||||
file_put_contents(ROOT_PATH ."application/tags.php",$options["content"]);
|
||||
break;
|
||||
case 'database':
|
||||
if(file_exists( ROOT_PATH ."application/database.lock")){
|
||||
return ["error"=>true,"msg"=>"出于安全考虑,默认禁止直接编辑数据库配置文件。如果需要开启编辑,请手动删除 application/database.lock 文件。"];
|
||||
}
|
||||
file_put_contents(ROOT_PATH ."application/database.php",$options["content"]);
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
return ["error"=>false,"msg"=>""];
|
||||
}
|
||||
|
||||
public function deleteMultiple($id){
|
||||
$fileInfo = json_decode($id,true);
|
||||
$pathGroup = [];
|
||||
foreach ($fileInfo as $key => $value) {
|
||||
$pathGroup[$value["uid"]] = isset($pathGroup[$value["uid"]]) ? $pathGroup[$value["uid"]] : [];
|
||||
array_push($pathGroup[$value["uid"]], $value["path"]);
|
||||
}
|
||||
foreach ($pathGroup as $key => $value) {
|
||||
FileManage::DeleteHandler($value,$key);
|
||||
}
|
||||
return ["error"=>200,"msg"=>"删除成功"];
|
||||
}
|
||||
|
||||
public function deleteShare($ids){
|
||||
Db::name("shares")->where("id","in",$ids)->delete();
|
||||
return ["error"=>false,"msg"=>"删除成功"];
|
||||
}
|
||||
|
||||
public function deleteOrder($id){
|
||||
Db::name("order")->where("id",$id)->delete();
|
||||
return ["error"=>false,"msg"=>"删除成功"];
|
||||
}
|
||||
|
||||
public function deleteUser($id,$userNow){
|
||||
if($userNow == $id){
|
||||
return ["error"=>true,"msg"=>"我的老伙计,你可不能删除你自己"];
|
||||
}
|
||||
//删除用户所有文件及目录
|
||||
FileManage::DirDeleteHandler([0 => "/"],$id);
|
||||
//删除此用户所有分享
|
||||
Db::name("shares")->where("owner",$id)->delete();
|
||||
//删除此用户
|
||||
Db::name("users")->where("id",$id)->delete();
|
||||
return ["error"=>false,"msg"=>"删除成功"];
|
||||
}
|
||||
|
||||
public function changeShareType($id){
|
||||
$shareId = $id;
|
||||
$shareObj = new ShareHandler($shareId,false);
|
||||
if(!$shareObj->querryStatus){
|
||||
return array(
|
||||
"error" => 1,
|
||||
"msg" => "分享不存在"
|
||||
);
|
||||
}
|
||||
return $shareObj->changePromission(0,true);
|
||||
}
|
||||
|
||||
public function getUserInfo($id){
|
||||
$userData = Db::name("users")->where("id",$id)->find();
|
||||
$userData["used_storage"] =getSize($userData["used_storage"]);
|
||||
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 = !cookie('?pageSize') ? 10 : cookie('pageSize');
|
||||
$orderType = empty(cookie('orderMethodFile')) ? "id DESC" : cookie('orderMethodFile');
|
||||
$this->pageData = Db::name("files")
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('fileSearch'))){
|
||||
$query->where('orign_name', "like","%".cookie('fileSearch')."%");
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('filePolicy'))){
|
||||
$query->where('policy_id', cookie('filePolicy'));
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('searchValue'))){
|
||||
$query->where(cookie('searchCol'),"like", cookie('searchValue'));
|
||||
}
|
||||
})
|
||||
->order($orderType)
|
||||
->paginate($pageSize);
|
||||
$this->dataTotal = Db::name("files")
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('fileSearch'))){
|
||||
$query->where('orign_name', "like","%".cookie('fileSearch')."%");
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('filePolicy'))){
|
||||
$query->where('policy_id', cookie('filePolicy'));
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('searchValue'))){
|
||||
$query->where(cookie('searchCol'),"like", cookie('searchValue'));
|
||||
}
|
||||
})
|
||||
->order($orderType)
|
||||
->count();
|
||||
$this->pageTotal = ceil($this->dataTotal/$pageSize);
|
||||
$this->listData = $this->pageData->all();
|
||||
$userCache=[];
|
||||
$userCacheList=[];
|
||||
foreach ($this->listData as $key => $value) {
|
||||
if(in_array($value["upload_user"], $userCacheList)){
|
||||
$this->listData[$key]["user"] = $userCache[$value["upload_user"]];
|
||||
}else{
|
||||
$this->listData[$key]["user"] = Db::name("users")->where("id",$value["upload_user"])->find();
|
||||
array_push($userCacheList,$value["upload_user"]);
|
||||
$userCache[$value["upload_user"]] = $this->listData[$key]["user"];
|
||||
}
|
||||
}
|
||||
$this->pageNow = input("?get.page")?input("get.page"):1;
|
||||
}
|
||||
|
||||
public function listUser(){
|
||||
$pageSize = !cookie('?pageSize') ? 10 : cookie('pageSize');
|
||||
$orderType = empty(cookie('orderMethodUser')) ? "id DESC" : cookie('orderMethodUser');
|
||||
$this->pageData = Db::name("users")
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('userStatus'))){
|
||||
$query->where('user_status', cookie('userStatus')-1);
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('userSearch'))){
|
||||
$query->where('user_nick', "like","%".cookie('userSearch')."%")
|
||||
->whereOr("id",cookie('userSearch'))
|
||||
->whereOr("user_email","like","%".cookie('userSearch')."%");
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('userGroup'))){
|
||||
$query->where('user_group', cookie('userGroup'));
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('searchValueUser'))){
|
||||
$query->where(cookie('searchColUser'),"like", cookie('searchValueUser'));
|
||||
}
|
||||
})
|
||||
->order($orderType)
|
||||
->paginate($pageSize);
|
||||
$this->dataTotal = Db::name("users")
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('userStatus'))){
|
||||
$query->where('user_status', cookie('userStatus')-1);
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('userSearch'))){
|
||||
$query->where('user_nick', "like","%".cookie('userSearch')."%")
|
||||
->whereOr("id",cookie('userSearch'))
|
||||
->whereOr("user_email","like","%".cookie('userSearch')."%");
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('userGroup'))){
|
||||
$query->where('user_group', cookie('userGroup'));
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('searchValueUser'))){
|
||||
$query->where(cookie('searchColUser'),"like", cookie('searchValueUser'));
|
||||
}
|
||||
})
|
||||
->order($orderType)
|
||||
->count();
|
||||
$this->pageTotal = ceil($this->dataTotal/$pageSize);
|
||||
$this->listData = $this->pageData->all();
|
||||
$groupCache=[];
|
||||
$groupCacheList=[];
|
||||
foreach ($this->listData as $key => $value) {
|
||||
if(in_array($value["user_group"], $groupCacheList)){
|
||||
$this->listData[$key]["group"] = $groupCache[$value["user_group"]];
|
||||
}else{
|
||||
$this->listData[$key]["group"] = Db::name("groups")->where("id",$value["user_group"])->find();
|
||||
array_push($groupCacheList,$value["user_group"]);
|
||||
$groupCache[$value["user_group"]] = $this->listData[$key]["group"];
|
||||
}
|
||||
}
|
||||
$this->pageNow = input("?get.page")?input("get.page"):1;
|
||||
}
|
||||
|
||||
public function listShare(){
|
||||
$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'))){
|
||||
$query->where('source_name', "like","%".cookie('shareSearch')."%")->whereOr('origin_name', "like","%".cookie('shareSearch')."%");
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('shareType'))){
|
||||
$query->where('type', cookie('shareType'));
|
||||
}
|
||||
})
|
||||
->order($orderType)
|
||||
->paginate($pageSize);
|
||||
$this->dataTotal = Db::name("shares")
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('shareSearch'))){
|
||||
$query->where('source_name', "like","%".cookie('shareSearch')."%")->whereOr('origin_name', "like","%".cookie('shareSearch')."%");
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('shareType'))){
|
||||
$query->where('type', cookie('shareType'));
|
||||
}
|
||||
})
|
||||
->order($orderType)
|
||||
->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"];
|
||||
}
|
||||
}
|
||||
$this->pageNow = input("?get.page")?input("get.page"):1;
|
||||
}
|
||||
|
||||
public function listPolicy(){
|
||||
$pageSize =!cookie('?pageSize') ? 10 : cookie('pageSize');
|
||||
$this->pageData = Db::name("policy")
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('policySearch'))){
|
||||
$query->where('policy_name', "like","%".cookie('policySearch')."%");
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('policyType'))){
|
||||
$query->where('policy_type', cookie('policyType'));
|
||||
}
|
||||
})
|
||||
->order("id DESC")
|
||||
->paginate($pageSize);
|
||||
$this->dataTotal = Db::name("policy")
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('policySearch'))){
|
||||
$query->where('policy_name', "like","%".cookie('policySearch')."%");
|
||||
}
|
||||
})
|
||||
->where(function ($query) {
|
||||
if(!empty(cookie('policyType'))){
|
||||
$query->where('policy_type', cookie('policyType'));
|
||||
}
|
||||
})
|
||||
->order("id DESC")
|
||||
->count();
|
||||
$this->pageTotal = ceil($this->dataTotal/$pageSize);
|
||||
$this->listData = $this->pageData->all();
|
||||
$this->pageNow = input("?get.page")?input("get.page"):1;
|
||||
foreach ($this->listData as $key => $value) {
|
||||
$this->listData[$key]["file_num"] = Db::name("files")->where("policy_id",$value["id"])->count();
|
||||
$this->listData[$key]["file_size"] = Db::name("files")->where("policy_id",$value["id"])->sum("size");
|
||||
}
|
||||
}
|
||||
|
||||
public function getFileInfo($id){
|
||||
$fileRecord = Db::name("files")->where("id",$id)->find();
|
||||
$policyRecord = Db::name("policy")->where("id",$fileRecord["policy_id"])->find();
|
||||
$fileRecord["policy"] = $policyRecord;
|
||||
return $fileRecord;
|
||||
}
|
||||
|
||||
public function saveThemeFile($options){
|
||||
$fileName=$options["name"];
|
||||
$dir = ROOT_PATH."application/index/view/";
|
||||
$fileList=[];
|
||||
$fileList=$fileList+scandir($dir);
|
||||
$pathList=["/"=>$fileList];
|
||||
foreach (["admin","explore","file","home","index","member","profile","share"] as $key => $value) {
|
||||
$childPath = scandir($dir.$value."/");
|
||||
$fileList=array_merge($fileList,$childPath);
|
||||
$pathList = array_merge($pathList,[$value => $childPath]);
|
||||
}
|
||||
foreach ($fileList as $key => $value) {
|
||||
if(substr_compare($value, ".html", -strlen(".html")) != 0){
|
||||
unset($fileList[$key]);
|
||||
}
|
||||
}
|
||||
foreach($pathList as $key=>$val){
|
||||
if(in_array($fileName.".html",$val)){
|
||||
$parentPath = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
file_put_contents($dir.rtrim($parentPath,"/")."/".$fileName.".html",$options["content"]);
|
||||
return ["error"=>false,"msg"=>"成功"];
|
||||
}
|
||||
|
||||
public function saveUser($options){
|
||||
if(empty($options["user_pass"])){
|
||||
unset($options["user_pass"]);
|
||||
}else{
|
||||
$options["user_pass"] = md5(config('salt').$options["user_pass"]);
|
||||
}
|
||||
$userId = $options["uid"];
|
||||
unset($options["uid"]);
|
||||
try {
|
||||
Db::name("users")->where("id",$userId)->update($options);
|
||||
} catch (Exception $e) {
|
||||
return ["error"=>1,"msg"=>$e->getMessage()];
|
||||
}
|
||||
return ["error"=>200,"msg"=>"设置已保存"];
|
||||
}
|
||||
|
||||
public function banUser($id,$uid){
|
||||
if($id == $uid){
|
||||
return ["error"=>1,"msg"=>"我的老伙计,你怎么能封禁你自己?"];
|
||||
}
|
||||
$userData = Db::name("users")->where("id",$id)->find();
|
||||
$statusNew = $userData["user_status"] == 1 ? 0 : 1;
|
||||
Db::name("users")->where("id",$id)->update(["user_status" => $statusNew]);
|
||||
return ["error"=>200,"msg"=>"设置已保存"];
|
||||
}
|
||||
|
||||
public function listGroup(){
|
||||
$pageSize = empty(cookie('pageSize')) ? 10 : cookie('pageSize');
|
||||
$this->pageData = Db::name("groups")
|
||||
->order("id DESC")
|
||||
->paginate($pageSize);
|
||||
$this->dataTotal = Db::name("groups")
|
||||
->order("id DESC")
|
||||
->count();
|
||||
$this->pageTotal = ceil($this->dataTotal/$pageSize);
|
||||
$this->listData = $this->pageData->all();
|
||||
$this->pageNow = input("?get.page")?input("get.page"):1;
|
||||
foreach ($this->listData as $key => $value) {
|
||||
$this->listData[$key]["policy"] = Db::name("policy")->where("id",$value["policy_name"])->find();
|
||||
$this->listData[$key]["user_num"] = Db::name("users")->where("user_group",$value["id"])->count();
|
||||
}
|
||||
}
|
||||
|
||||
public function addUser($options){
|
||||
$options["user_pass"] = md5(config('salt').$options["user_pass"]);
|
||||
if(Db::name('users')->where('user_email',$options["user_email"])->find() !=null){
|
||||
return ["error" => true,"msg"=>"该邮箱已被注册"];
|
||||
}
|
||||
$sqlData = [
|
||||
'user_email' => $options["user_email"],
|
||||
'user_pass' => $options["user_pass"],
|
||||
'user_status' => $options["user_status"],
|
||||
'user_group' => $options["user_group"],
|
||||
'group_primary' => $options["user_group"],
|
||||
'user_date' => date("Y-m-d H:i:s"),
|
||||
'user_nick' => $options["user_nick"],
|
||||
'user_activation_key' => "n",
|
||||
'used_storage' => 0,
|
||||
'two_step'=>"0",
|
||||
'webdav_key' =>$options["user_pass"],
|
||||
'delay_time' =>0,
|
||||
'avatar' => "default",
|
||||
'profile' => true,
|
||||
];
|
||||
if(Db::name('users')->insert($sqlData)){
|
||||
$userId = Db::name('users')->getLastInsID();
|
||||
Db::name('folders')->insert( [
|
||||
'folder_name' => '根目录',
|
||||
'parent_folder' => 0,
|
||||
'position' => '.',
|
||||
'owner' => $userId,
|
||||
'date' => date("Y-m-d H:i:s"),
|
||||
'position_absolute' => '/',
|
||||
]);
|
||||
}
|
||||
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,469 @@
|
||||
<?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"])){
|
||||
$deleteAction = @unlink($quenInfo["files"][$sqlData["file_index"]]["path"]);
|
||||
@self::remove_directory(dirname($quenInfo["files"][$sqlData["file_index"]]["path"]));
|
||||
if(file_exists(dirname($quenInfo["files"][$sqlData["file_index"]]["path"]))){
|
||||
$task = new Task();
|
||||
$task->taskName = "Delete remote download temp file";
|
||||
$task->taskType = "deleteFolder";
|
||||
$task->taskContent = json_encode([
|
||||
"folder" => dirname($quenInfo["files"][$sqlData["file_index"]]["path"]),
|
||||
]);
|
||||
$task->userId = $this->uid;
|
||||
$task->saveTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\LocalAdapter;
|
||||
|
||||
class Avatar extends Model{
|
||||
|
||||
public $avatarObj;
|
||||
public $errorMsg;
|
||||
public $fileName;
|
||||
public $avatarKey;
|
||||
public $userData;
|
||||
public $avatarType;
|
||||
|
||||
public function __construct($new=false,$obj){
|
||||
$this->avatarObj = $obj;
|
||||
if(!$new){
|
||||
$userData = Db::name("users")->where('id',$obj)->find();
|
||||
$this->userData = $userData;
|
||||
if(empty($userData)||$userData["avatar"] == "default"){
|
||||
$this->avatarType = "default";
|
||||
}else{
|
||||
$avatarPrarm = explode(".",$userData["avatar"]);
|
||||
$this->avatarType = $avatarPrarm[0];
|
||||
$this->fileName = ltrim(ltrim($userData["avatar"],"g."),"f.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function SaveAvatar(){
|
||||
$info = $this->avatarObj->validate(['size'=>2097152,'ext'=>'jpg,png,gif.bmp'])->rule('uniqid')->move(ROOT_PATH . 'public' . DS . 'avatars');
|
||||
if($info){
|
||||
$_path = ROOT_PATH.'public/avatars/'.$info->getSaveName();
|
||||
$_img = new Image($_path);
|
||||
$_img->thumb(200, 200);
|
||||
$_img->output();
|
||||
$_img = new Image($_path);
|
||||
$_img->thumb(130, 130);
|
||||
$_img->output("_130");
|
||||
$_img = new Image($_path);
|
||||
$_img->thumb(50, 50);
|
||||
$_img->output("_50");
|
||||
$this->fileName = $info->getSaveName();
|
||||
return true;
|
||||
}else{
|
||||
$this->errorMsg=["result"=>"error","msg"=>$this->avatarObj->getError()];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function bindUser($uid){
|
||||
$this->avatarKey = "f.".$this->fileName;
|
||||
Db::name("users")->where('id',$uid)->update(["avatar" => $this->avatarKey]);
|
||||
}
|
||||
|
||||
public function Out($size){
|
||||
switch ($this->avatarType) {
|
||||
case 'f':
|
||||
$this->outPutFile($size);
|
||||
exit();
|
||||
break;
|
||||
case 'default':
|
||||
$this->defaultAvatar($size);
|
||||
exit();
|
||||
break;
|
||||
case 'g':
|
||||
return $this->outGravatar($size);
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function outPutFile($size){
|
||||
switch ($size) {
|
||||
case 's':
|
||||
$siezSuffix = "_50";
|
||||
break;
|
||||
case 'm':
|
||||
$siezSuffix = "_130";
|
||||
break;
|
||||
default:
|
||||
$siezSuffix = "";
|
||||
break;
|
||||
}
|
||||
$filePath = ROOT_PATH . 'public/avatars/' . $this->fileName.$siezSuffix;
|
||||
if(file_exists($filePath)){
|
||||
ob_end_clean();
|
||||
header('Content-Type: '.LocalAdapter::getMimetype($filePath));
|
||||
$fileObj = fopen($filePath,"r");
|
||||
while(!feof($fileObj)){
|
||||
echo fread($fileObj,2097152);
|
||||
}
|
||||
}else{
|
||||
$this->defaultAvatar($siezSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
public function outGravatar($size){
|
||||
switch ($size) {
|
||||
case 's':
|
||||
$siezSuffix = "50";
|
||||
break;
|
||||
case 'm':
|
||||
$siezSuffix = "130";
|
||||
break;
|
||||
default:
|
||||
$siezSuffix = "200";
|
||||
break;
|
||||
}
|
||||
ob_end_clean();
|
||||
$gravatarServer = Option::getValue("gravatar_server");
|
||||
return $gravatarServer.$this->fileName."?d=mm&s=".$siezSuffix;
|
||||
}
|
||||
|
||||
public function defaultAvatar($size){
|
||||
switch ($size) {
|
||||
case 's':
|
||||
$siezSuffix = "_50";
|
||||
break;
|
||||
case 'm':
|
||||
$siezSuffix = "_130";
|
||||
break;
|
||||
default:
|
||||
$siezSuffix = "";
|
||||
break;
|
||||
}
|
||||
ob_end_clean();
|
||||
$filePath = ROOT_PATH . 'static/img/default.png' .$siezSuffix;
|
||||
header('Content-Type: '.LocalAdapter::getMimetype($filePath));
|
||||
$fileObj = fopen($filePath,"r");
|
||||
while(!feof($fileObj)){
|
||||
echo fread($fileObj,2097152);
|
||||
}
|
||||
}
|
||||
|
||||
public function setGravatar(){
|
||||
$this->avatarKey="g.".md5($this->userData["user_email"]);
|
||||
Db::name("users")->where('id',$this->userData["id"])->update(["avatar" => $this->avatarKey]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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("");
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use Sabre\DAV;
|
||||
use Sabre\DAV\Auth\Backend;
|
||||
|
||||
class BasicCallBack extends \Sabre\DAV\Auth\Backend\AbstractDigest {
|
||||
|
||||
/**
|
||||
* Callback
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
protected $callBack;
|
||||
|
||||
/**
|
||||
* Creates the backend.
|
||||
*
|
||||
* A callback must be provided to handle checking the username and
|
||||
* password.
|
||||
*
|
||||
* @param callable $callBack
|
||||
* @return void
|
||||
*/
|
||||
function __construct(callable $callBack) {
|
||||
|
||||
$this->callBack = $callBack;
|
||||
$this->realm = 'CloudreveWebDav';
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function getDigestHash($realm, $username){
|
||||
$cb = $this->callBack;
|
||||
return $cb($realm,$username);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
require_once 'extend/Qiniu/functions.php';
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use Qiniu\Auth;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\FileManage;
|
||||
use \app\index\model\UploadHandler;
|
||||
|
||||
class CallbackHandler extends Model{
|
||||
|
||||
public $CallbackData;
|
||||
public $policyData;
|
||||
public $userData;
|
||||
|
||||
public function __construct($data){
|
||||
$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();
|
||||
$this->policyData = Db::name('policy')->where('id',$CallbackSqlData['pid'])->find();
|
||||
|
||||
if(!$this->IsQiniuCallback($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"];
|
||||
$picInfo = $picInfo==="null,null"?"":$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 ossHandler($auth,$pubKey){
|
||||
if(!$this->IsOssCallback($auth,$pubKey)){
|
||||
$this->setError("Undelegated Request");
|
||||
}
|
||||
$jsonData = json_decode($this->CallbackData,true);
|
||||
$jsonData["fname"] = urldecode($jsonData["fname"]);
|
||||
$jsonData["objname"] = urldecode($jsonData["objname"]);
|
||||
$jsonData["path"] = urldecode($jsonData["path"]);
|
||||
$CallbackSqlData = Db::name('callback')->where('callback_key',$jsonData['callbackkey'])->find();
|
||||
$this->policyData = Db::name('policy')->where('id',$CallbackSqlData['pid'])->find();
|
||||
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 upyunHandler($token,$date,$md5){
|
||||
$this->policyData = Db::name("policy")->where("id",$this->CallbackData["ext-param"]["pid"])->find();
|
||||
if(!$this->IsUpyunCallback($token,$date,$md5)){
|
||||
$this->setError("Undelegated Request",false,true);
|
||||
}
|
||||
if(!FileManage::sotrageCheck($this->CallbackData["ext-param"]["uid"],$this->CallbackData["file_size"])){
|
||||
FileManage::deleteFile($this->CallbackData["url"],$this->policyData);
|
||||
$this->setError("空间容量不足",false,true);
|
||||
}
|
||||
$picInfo = empty($this->CallbackData["image-width"]) ? "" :$this->CallbackData["image-width"].",".$this->CallbackData["image-height"];
|
||||
$fileNameExplode = explode("CLSUFF",$this->CallbackData["url"]);
|
||||
$jsonData["fname"] = end($fileNameExplode);
|
||||
$jsonData["objname"] = $this->CallbackData["url"];
|
||||
$jsonData["path"] = $this->CallbackData["ext-param"]["path"];
|
||||
$jsonData["fsize"] = $this->CallbackData["file_size"];
|
||||
$addAction = FileManage::addFile($jsonData,$this->policyData,$this->CallbackData["ext-param"]["uid"],$picInfo);
|
||||
if(!$addAction[0]){
|
||||
FileManage::deleteFile($this->CallbackData["url"],$this->policyData);
|
||||
$this->setError($addAction[1],false,true);
|
||||
}
|
||||
FileManage::storageCheckOut($this->CallbackData["ext-param"]["uid"],$jsonData["fsize"]);
|
||||
$this->setSuccess($jsonData['fname']);
|
||||
}
|
||||
|
||||
public function s3Handler($key){
|
||||
$CallbackSqlData = Db::name('callback')->where('callback_key',$key)->find();
|
||||
//删除callback记录
|
||||
if(empty($CallbackSqlData)){
|
||||
$this->setError("Undelegated Request",false,true);
|
||||
}
|
||||
Db::name('callback')->where('callback_key',$key)->delete();
|
||||
$this->policyData = Db::name('policy')->where('id',$CallbackSqlData['pid'])->find();
|
||||
$this->userData = Db::name('users')->where('id',$CallbackSqlData['uid'])->find();
|
||||
$paths = explode("/",$this->CallbackData["key"]);
|
||||
$jsonData["fname"] = end($paths);
|
||||
$jsonData["objname"] = $this->CallbackData["key"];
|
||||
$jsonData["path"] ="";
|
||||
foreach ($paths as $key => $value) {
|
||||
if($key == 0 || $key == count($paths)-1) continue;
|
||||
$jsonData["path"].=$value.",";
|
||||
}
|
||||
$jsonData["path"] = rtrim($jsonData["path"],",");
|
||||
$jsonData["fsize"] = $this->getS3FileInfo();
|
||||
if(!$jsonData["fsize"]){
|
||||
$this->setError("File not exist",false,true);
|
||||
}
|
||||
$jsonData["fsize"] = $jsonData["fsize"];
|
||||
$picInfo = "";
|
||||
$addAction = FileManage::addFile($jsonData,$this->policyData,$this->userData["id"],"");
|
||||
if(!$addAction[0]){
|
||||
FileManage::deleteFile($this->CallbackData["key"],$this->policyData);
|
||||
$this->setError($addAction[1],false,true);
|
||||
}
|
||||
FileManage::storageCheckOut($this->userData["id"],$jsonData["fsize"]);
|
||||
$this->setSuccess($jsonData['fname']);
|
||||
}
|
||||
|
||||
private function getS3FileInfo(){
|
||||
$s3 = new \Aws\S3\S3Client([
|
||||
'version' => 'latest',
|
||||
'region' => $this->policyData["op_name"],
|
||||
'endpoint' => $this->policyData["op_pwd"],
|
||||
'use_path_style_endpoint' => true,
|
||||
'credentials' => [
|
||||
'key' => $this->policyData["ak"],
|
||||
'secret' => $this->policyData["sk"],
|
||||
],
|
||||
]);
|
||||
try {
|
||||
$returnVal = $s3->headObject([
|
||||
'Bucket'=>$this->policyData["bucketname"],
|
||||
'Key'=>$this->CallbackData["key"]
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
return $returnVal["ContentLength"];
|
||||
}
|
||||
|
||||
public function setSuccess($fname){
|
||||
die(json_encode(["key"=> $fname]));
|
||||
}
|
||||
|
||||
public function setError($text,$delete = false,$ignore=false){
|
||||
header("HTTP/1.1 401 Unauthorized");
|
||||
if(!$ignore){
|
||||
$deletedFile = json_decode($this->CallbackData,true);
|
||||
$fileNmae = $deletedFile['objname'];
|
||||
if($delete){
|
||||
FileManage::deleteFile($fileNmae,$this->policyData);
|
||||
}
|
||||
}
|
||||
die(json_encode(["error"=> $text]));
|
||||
}
|
||||
|
||||
private function isUpyunCallback($token,$date,$md5){
|
||||
if(UploadHandler::upyunSign($this->policyData["op_name"],md5($this->policyData["op_pwd"]),"POST","/Callback/Upyun",$date,$md5) != $token){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsQiniuCallback($httpHeader){
|
||||
$auth = new Auth($this->policyData['ak'], $this->policyData['sk']);
|
||||
$callbackBody = $this->CallbackData;
|
||||
$contentType = 'application/json';
|
||||
$authorization = $httpHeader;
|
||||
$url = Option::getValue("siteUrl")."Callback/Qiniu";
|
||||
$isQiniuCallback = $auth->verifyCallback($contentType, $authorization, $url,$callbackBody);
|
||||
if ($isQiniuCallback) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
exit();
|
||||
}
|
||||
$authorization = base64_decode($auth);
|
||||
$pubKeyUrl = base64_decode($pubKey);
|
||||
$pubOssKey = file_get_contents($pubKeyUrl);
|
||||
if ($pubOssKey == ""){
|
||||
return false;
|
||||
}
|
||||
$body = file_get_contents('php://input');
|
||||
$authStr = '';
|
||||
$path = $_SERVER['REQUEST_URI'];
|
||||
$pos = strpos($path, '?');
|
||||
if ($pos === false){
|
||||
$authStr = urldecode($path)."\n".$body;
|
||||
}else{
|
||||
$authStr = urldecode(substr($path, 0, $pos)).substr($path, $pos, strlen($path) - $pos)."\n".$body;
|
||||
}
|
||||
$ok = openssl_verify($authStr, $authorization, $pubOssKey, OPENSSL_ALGO_MD5);
|
||||
if ($ok == 1){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
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{
|
||||
|
||||
public $cornTasks;
|
||||
public $timeNow;
|
||||
public $notifiedUid = [];
|
||||
|
||||
public function __construct(){
|
||||
$this->cornTasks = Db::name('corn')->where('enable',1)->order('rank desc')->select();
|
||||
$this->timeNow = time();
|
||||
}
|
||||
|
||||
public function checkInterval($interval,$last){
|
||||
return ($last+$interval)<= $this->timeNow ? true : false;
|
||||
}
|
||||
|
||||
public function setComplete($name){
|
||||
Db::name('corn')->where('name', $name)->update(['last_excute' => $this->timeNow]);
|
||||
}
|
||||
|
||||
public function Doit(){
|
||||
foreach ($this->cornTasks as $key => $value) {
|
||||
switch ($value["name"]) {
|
||||
case 'delete_unseful_chunks':
|
||||
if($this->checkInterval($value["interval_s"],$value["last_excute"])){
|
||||
$this->deleteUnsefulChunks($value["interval_s"]);
|
||||
}
|
||||
break;
|
||||
case 'delete_callback_data':
|
||||
if($this->checkInterval($value["interval_s"],$value["last_excute"])){
|
||||
$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;
|
||||
case 'delete_remote_downloader_failed_folder':
|
||||
if($this->checkInterval($value["interval_s"],$value["last_excute"])){
|
||||
$this->deleteRemoteDownloaderFailedFolder($value["interval_s"]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function deleteUnsefulChunks($interval){
|
||||
echo("deleteUnsefulChunks...");
|
||||
$chunkInfo = Db::name('chunks')->whereTime('time', '<', date('Y-m-d', time()-86400))->select();
|
||||
$deleteList=[];
|
||||
foreach ($chunkInfo as $key => $value) {
|
||||
$fileSize = @filesize(ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk");
|
||||
@unlink(ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk");
|
||||
FileManage::storageGiveBack($value["user"],$fileSize?$fileSize:0);
|
||||
$deleteList["$key"] = $value["id"];
|
||||
}
|
||||
Db::name('chunks')->where(['id' => ["in",$deleteList],])->delete();
|
||||
$this->setComplete("delete_unseful_chunks");
|
||||
echo("Complete<br>");
|
||||
}
|
||||
|
||||
private function deleteCallbackData($interval){
|
||||
echo("deleteCallbackData...");
|
||||
Db::name("callback")->delete(true);
|
||||
echo("Complete<br>");
|
||||
$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 deleteRemoteDownloaderFailedFolder($interval){
|
||||
echo("flushOnedriveToken...");
|
||||
$toBeDeleted = Db::name("task")
|
||||
->where("type","deleteFolder")
|
||||
->where("status","todo")
|
||||
->select();
|
||||
$success=[];
|
||||
$todo = [];
|
||||
foreach ($toBeDeleted as $key => $value) {
|
||||
$attr = json_decode($value["attr"],true);
|
||||
if(file_exists($attr["folder"])){
|
||||
self::remove_directory($attr["folder"]);
|
||||
}
|
||||
if(file_exists($attr["folder"])){
|
||||
$todo[] = $value["id"];
|
||||
}else{
|
||||
$success[] = $value["id"];
|
||||
}
|
||||
}
|
||||
|
||||
Db::name("task")->where("id","in",$success)->update(["status"=>"success"]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除整个目录
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use app\index\model\User;
|
||||
|
||||
class DavAuth extends Model{
|
||||
|
||||
public $uid;
|
||||
|
||||
function __construct($id) {
|
||||
$this->uid = $id;
|
||||
}
|
||||
|
||||
public function __invoke($realm,$um){
|
||||
$userData = Db::name("users")->where("id",$this->uid)->find();
|
||||
if(empty($userData) || $userData["user_email"] != $um){
|
||||
return null;
|
||||
}
|
||||
$userGroup = Db::name("groups")->where("id",$userData["user_group"])->find();
|
||||
if(!$userGroup["webdav"]){
|
||||
return null;
|
||||
}
|
||||
return $userData["webdav_key"];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use Sabre\DAV;
|
||||
use \app\index\model\FileManage;
|
||||
use \app\index\model\User;
|
||||
use \app\index\model\UploadHandler;
|
||||
|
||||
class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota{
|
||||
|
||||
private $myPath;
|
||||
public $uid;
|
||||
public $userObj;
|
||||
|
||||
function __construct($path) {
|
||||
$ex = explode("/",$path);
|
||||
$this->uid = $ex[0];
|
||||
if(empty($this->uid)){
|
||||
return false;
|
||||
}
|
||||
$t = strpos($path,$this->uid);
|
||||
if($t == 0){
|
||||
$this->myPath = substr($path,$t+strlen($this->uid));
|
||||
}else{
|
||||
$this->myPath = $path;
|
||||
}
|
||||
$this->myPath = empty($this->myPath) ? "/" : $this->myPath;
|
||||
}
|
||||
|
||||
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();
|
||||
$uploadHandle = new UploadHandler($groupData["policy_name"],$this->uid);
|
||||
$allowedExt = UploadHandler::getAllowedExt(json_decode($policyData["filetype"],true));
|
||||
if(!empty($allowedExt)){
|
||||
$ex = explode(".",$name);
|
||||
$fileSuffix = end($ex);
|
||||
if(!in_array($fileSuffix, explode(",",$allowedExt))){
|
||||
throw new DAV\Exception\InvalidResourceType('File type not allowed');
|
||||
}
|
||||
}
|
||||
if($policyData["policy_type"] !="local"){
|
||||
throw new DAV\Exception\Forbidden('Poliyc not supported yet');
|
||||
}
|
||||
$fileSize = fstat($data)["size"];
|
||||
if(empty($fileSize)){
|
||||
$fileSize = -1;
|
||||
}
|
||||
if($fileSize>$policyData["max_size"]){
|
||||
throw new DAV\Exception\InsufficientStorage('File is to large');
|
||||
}
|
||||
if(!FileManage::sotrageCheck($this->uid,$fileSize)){
|
||||
throw new DAV\Exception\InsufficientStorage('Quota is not enough');
|
||||
}
|
||||
if($policyData['autoname']){
|
||||
$fileName = $uploadHandle->getObjName($policyData['namerule'],"local",$name);
|
||||
}else{
|
||||
$fileName = $name;
|
||||
}
|
||||
$generatePath = $uploadHandle->getDirName($policyData['dirrule']);
|
||||
$savePath = ROOT_PATH . 'public/uploads/'.$generatePath;
|
||||
if(!file_exists($savePath)){
|
||||
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,
|
||||
"objname" => $generatePath."/".$fileName,
|
||||
"fsize" => $fileSize,
|
||||
);
|
||||
@list($width, $height, $type, $attr) = getimagesize(rtrim($savePath, DS).DS.$fileName);
|
||||
$picInfo = empty($width)?" ":$width.",".$height;
|
||||
$addAction = FileManage::addFile($jsonData,$policyData,$this->uid,$picInfo);
|
||||
if(!$addAction[0]){
|
||||
unlink($savePath."/".$fileName);
|
||||
throw new DAV\Exception\Conflict($addAction[1]);
|
||||
}
|
||||
FileManage::storageCheckOut($this->uid,$jsonData["fsize"]);
|
||||
//echo json_encode(array("key" => $info["name"]));
|
||||
}
|
||||
|
||||
function getQuotaInfo() {
|
||||
$this->userObj = new User($this->uid,"",true);
|
||||
$quotaInfo = json_decode($this->userObj->getMemory(true),true);
|
||||
return [
|
||||
$quotaInfo["used"],
|
||||
$quotaInfo["total"]
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
function setName($name){
|
||||
$reqPath = $this->myPath;
|
||||
$ex = explode("/",$reqPath);
|
||||
$newPath = rtrim(dirname($reqPath) == "\\" ?"/":dirname($reqPath),"/")."/".$name;
|
||||
$renameAction = json_decode(FileManage::RenameHandler($reqPath,$newPath,$this->uid,true),true);
|
||||
if(!$renameAction["result"]["success"]){
|
||||
throw new DAV\Exception\InvalidResourceType($renameAction["result"]["error"]);
|
||||
}
|
||||
}
|
||||
|
||||
function getChildren() {
|
||||
$children = array();
|
||||
$fileList = Db::name('files')->where('upload_user',$this->uid)->where('dir',$this->myPath)->select();
|
||||
$dirList = Db::name('folders')->where('owner',$this->uid)->where('position',$this->myPath)->select();
|
||||
foreach($fileList as $node) {
|
||||
// Ignoring files staring with .
|
||||
$children[] = $this->getChildFile($node,false);
|
||||
}
|
||||
foreach($dirList as $node) {
|
||||
// Ignoring files staring with .
|
||||
$children[] = $this->getChildDir($node,true);
|
||||
}
|
||||
return $children;
|
||||
}
|
||||
|
||||
function getChildFile($name){
|
||||
$path = $this->uid.rtrim($this->myPath,"/") . '/' . $name["orign_name"];
|
||||
return new Objects($path);
|
||||
}
|
||||
|
||||
function getChildDir($name){
|
||||
$path = $this->uid.rtrim($this->myPath,"/") . '/' . $name["folder_name"];
|
||||
return new Directory($path);
|
||||
}
|
||||
|
||||
function delete(){
|
||||
foreach ($this->getChildren() as $child) $child->delete();
|
||||
FileManage::DirDeleteHandler([0=>$this->myPath],$this->uid);
|
||||
}
|
||||
|
||||
function getChild($name) {
|
||||
$name = str_replace(" ","",$name);
|
||||
if(!$this->childExists($name)){
|
||||
throw new DAV\Exception\NotFound('File with name ' . $name . ' could not be located');
|
||||
}
|
||||
$path = $this->uid.rtrim($this->myPath,"/") . '/' . $name;
|
||||
if($this->findDir(rtrim($this->myPath,"/") . '/' . $name)){
|
||||
$returnObj = new Directory($path);
|
||||
return $returnObj;
|
||||
}else{
|
||||
return new Objects($path);
|
||||
}
|
||||
}
|
||||
|
||||
function childExists($name) {
|
||||
$name = str_replace(" ","",$name);
|
||||
$fileObj = new Objects($this->uid.rtrim($this->myPath,"/") . '/' . $name);
|
||||
if($this->findDir(rtrim($this->myPath,"/") . '/' . $name) || $fileObj->isExist){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function findDir($path){
|
||||
if($path == "/"){
|
||||
return true;
|
||||
}
|
||||
$explode = explode("/",$path);
|
||||
$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",getDirName($path))->find();
|
||||
if(empty($dirData)){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getName() {
|
||||
$explode = explode("/", $this->myPath);
|
||||
return end($explode);
|
||||
|
||||
}
|
||||
|
||||
function createDirectory($name) {
|
||||
$createAction = FileManage::createFolder($name,$this->myPath,$this->uid);
|
||||
if(!$createAction["result"]["success"]){
|
||||
die($this->myPath);
|
||||
throw new DAV\Exception\InvalidResourceType($createAction["result"]["error"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,941 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use think\Validate;
|
||||
use \app\index\model\Option;
|
||||
|
||||
class FileManage extends Model{
|
||||
|
||||
public $filePath;
|
||||
public $fileData;
|
||||
public $userID;
|
||||
public $userData;
|
||||
public $policyData;
|
||||
public $deleteStatus = true;
|
||||
|
||||
private $adapter;
|
||||
|
||||
/**
|
||||
* construct function
|
||||
*
|
||||
* @param string $path 文件路径/文件ID
|
||||
* @param int $uid 用户ID
|
||||
* @param boolean $byId 是否根据文件ID寻找文件
|
||||
*/
|
||||
public function __construct($path,$uid,$byId=false){
|
||||
if($byId){
|
||||
$fileRecord = Db::name('files')->where('id',$path)->find();
|
||||
$this->filePath = rtrim($fileRecord["dir"],"/")."/".$fileRecord["orign_name"];
|
||||
}else{
|
||||
$this->filePath = $path;
|
||||
$fileInfo = $this->getFileName($path);
|
||||
$fileName = $fileInfo[0];
|
||||
$path = $fileInfo[1];
|
||||
$fileRecord = Db::name('files')->where('upload_user',$uid)->where('orign_name',$fileName)->where('dir',$path)->find();
|
||||
}
|
||||
if (empty($fileRecord)){
|
||||
die('{ "result": { "success": false, "error": "文件不存在" } }');
|
||||
}
|
||||
$this->fileData = $fileRecord;
|
||||
$this->userID = $uid;
|
||||
$this->userData = Db::name('users')->where('id',$uid)->find();
|
||||
$this->policyData = Db::name('policy')->where('id',$this->fileData["policy_id"])->find();
|
||||
switch ($this->policyData["policy_type"]) {
|
||||
case 'local':
|
||||
$this->adapter = new \app\index\model\LocalAdapter($this->fileData,$this->policyData,$this->userData);
|
||||
break;
|
||||
case 'qiniu':
|
||||
$this->adapter = new \app\index\model\QiniuAdapter($this->fileData,$this->policyData,$this->userData);
|
||||
break;
|
||||
case 'oss':
|
||||
$this->adapter = new \app\index\model\OssAdapter($this->fileData,$this->policyData,$this->userData);
|
||||
break;
|
||||
case 'upyun':
|
||||
$this->adapter = new \app\index\model\UpyunAdapter($this->fileData,$this->policyData,$this->userData);
|
||||
break;
|
||||
case 's3':
|
||||
$this->adapter = new \app\index\model\S3Adapter($this->fileData,$this->policyData,$this->userData);
|
||||
break;
|
||||
case 'remote':
|
||||
$this->adapter = new \app\index\model\RemoteAdapter($this->fileData,$this->policyData,$this->userData);
|
||||
break;
|
||||
case 'onedrive':
|
||||
$this->adapter = new \app\index\model\OnedriveAdapter($this->fileData,$this->policyData,$this->userData);
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件外链地址
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function Source(){
|
||||
if(!$this->policyData["origin_link"]){
|
||||
die('{"url":"此文件不支持获取源文件URL"}');
|
||||
}else{
|
||||
echo ('{"url":"'.$this->policyData["url"].$this->fileData["pre_name"].'"}');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可编辑文件内容
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getContent(){
|
||||
$sizeLimit=(int)Option::getValue("maxEditSize");
|
||||
if($this->fileData["size"]>$sizeLimit){
|
||||
die('{ "result": { "success": false, "error": "您当前用户组最大可编辑'.$sizeLimit.'字节的文件"} }');
|
||||
}else{
|
||||
try{
|
||||
$fileContent = $this->adapter->getFileContent();
|
||||
}catch(\Exception $e){
|
||||
die('{ "result": { "success": false, "error": "'.$e->getMessage().'"} }');
|
||||
}
|
||||
$fileContent = $this->adapter->getFileContent();
|
||||
$result["result"] = $fileContent;
|
||||
if(empty(json_encode($result))){
|
||||
$result["result"] = iconv('gb2312','utf-8',$fileContent);
|
||||
}
|
||||
echo json_encode($result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存可编辑文件
|
||||
*
|
||||
* @param string $content 要保存的文件内容
|
||||
* @return void
|
||||
*/
|
||||
public function saveContent($content){
|
||||
$contentSize = strlen($content);
|
||||
$originSize = $this->fileData["size"];
|
||||
if(!FileManage::sotrageCheck($this->userID,$contentSize)){
|
||||
die('{ "result": { "success": false, "error": "空间容量不足" } }');
|
||||
}
|
||||
$this->adapter->saveContent($content);
|
||||
FileManage::storageGiveBack($this->userID,$originSize);
|
||||
FileManage::storageCheckOut($this->userID,$contentSize);
|
||||
Db::name('files')->where('id', $this->fileData["id"])->update(['size' => $contentSize]);
|
||||
echo ('{ "result": { "success": true} }');
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件名合法性初步检查
|
||||
*
|
||||
* @param string $value 文件名
|
||||
* @return bool 检查结果
|
||||
*/
|
||||
static function fileNameValidate($value){
|
||||
$validate = new Validate([
|
||||
'val' => 'require|max:250',
|
||||
'val' => 'chsDash'
|
||||
]);
|
||||
$data = [
|
||||
'val' => $value
|
||||
];
|
||||
if (!$validate->check($data)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理重命名
|
||||
*
|
||||
* @param string $fname 原文件路径
|
||||
* @param string $new 新文件路径
|
||||
* @param int $uid 用户ID
|
||||
* @param boolean $notEcho 过程中是否不直接输出结果
|
||||
* @return mixed
|
||||
*/
|
||||
static function RenameHandler($fname,$new,$uid,$notEcho = false){
|
||||
$folderTmp = $new;
|
||||
$originFolder = $fname;
|
||||
$new = str_replace("/", "", self::getFileName($new)[0]);
|
||||
if(!$notEcho){
|
||||
$newToBeVerify = str_replace(" ", "", $new);
|
||||
}
|
||||
//检查是否全为空格
|
||||
$varifyExplode = explode(".",$newToBeVerify);
|
||||
$isFullBlackspace = false;
|
||||
foreach ($varifyExplode as $key => $value) {
|
||||
if($value == ""){
|
||||
$isFullBlackspace = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$toBeValidated = str_replace(".","",$newToBeVerify);
|
||||
if(!self::fileNameValidate($toBeValidated) || $isFullBlackspace){
|
||||
if($notEcho){
|
||||
return '{ "result": { "success": false, "error": "文件名只支持汉字、字母、数字和下划线_及破折号-" } }';
|
||||
}
|
||||
die('{ "result": { "success": false, "error": "文件名只支持汉字、字母、数字和下划线_及破折号-" } }');
|
||||
}
|
||||
$path = self::getFileName($fname)[1];
|
||||
$fname = self::getFileName($fname)[0];
|
||||
$fileRecord = Db::name('files')->where('upload_user',$uid)->where('orign_name',$fname)->where('dir',$path)->find();
|
||||
if (empty($new)){
|
||||
if($notEcho){
|
||||
return '{ "result": { "success": false, "error": "文件重名或文件名非法" } }';
|
||||
}
|
||||
die('{ "result": { "success": false, "error": "文件重名或文件名非法" } }');
|
||||
}
|
||||
if(empty($fileRecord)){
|
||||
self::folderRename($originFolder,$folderTmp,$uid,$notEcho);
|
||||
die();
|
||||
}
|
||||
$newSuffix = explode(".",$new);
|
||||
$originSuffix = explode(".",$fileRecord["orign_name"]);
|
||||
if(end($originSuffix) != end($newSuffix)){
|
||||
if($notEcho){
|
||||
return '{ "result": { "success": false, "error": "请不要更改文件扩展名" } }';
|
||||
}
|
||||
die('{ "result": { "success": false, "error": "请不要更改文件扩展名" } }');
|
||||
}
|
||||
Db::name('files')->where([
|
||||
'upload_user' => $uid,
|
||||
'dir' => $path,
|
||||
'orign_name' =>$fname,
|
||||
])->setField('orign_name', $new);
|
||||
if($notEcho){
|
||||
return '{ "result": { "success": true} }';
|
||||
}
|
||||
echo ('{ "result": { "success": true} }');
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理目录重命名
|
||||
*
|
||||
* @param string $fname 原文件路径
|
||||
* @param string $new 新文件路径
|
||||
* @param int $uid 用户ID
|
||||
* @param boolean $notEcho 过程中是否不直接输出结果
|
||||
* @return void
|
||||
*/
|
||||
static function folderRename($fname,$new,$uid,$notEcho = false){
|
||||
$newTmp = $new;
|
||||
$nerFolderTmp = explode("/",$new);
|
||||
$new = array_pop($nerFolderTmp);
|
||||
$oldFolderTmp = explode("/",$fname);
|
||||
$old = array_pop($oldFolderTmp);
|
||||
if(!self::fileNameValidate($new)){
|
||||
if($notEcho){
|
||||
return '{ "result": { "success": false, "error": "目录名只支持数字、字母、下划线" } }';
|
||||
}
|
||||
die('{ "result": { "success": false, "error": "目录名只支持数字、字母、下划线" } }');
|
||||
}
|
||||
$folderRecord = Db::name('folders')->where('owner',$uid)->where('position_absolute',$fname)->find();
|
||||
if(empty($folderRecord)){
|
||||
if($notEcho){
|
||||
return '{ "result": { "success": false, "error": "目录不存在" } }';
|
||||
}
|
||||
die('{ "result": { "success": false, "error": "目录不存在" } }');
|
||||
}
|
||||
$newPositionAbsolute = substr($fname, 0, strrpos( $fname, '/'))."/".$new;
|
||||
Db::name('folders')->where('owner',$uid)->where('position_absolute',$fname)->update([
|
||||
'folder_name' => $new,
|
||||
'position_absolute' => $newPositionAbsolute,
|
||||
]);
|
||||
$childFolder = Db::name('folders')->where('owner',$uid)->where('position',"like",$fname."%")->select();
|
||||
foreach ($childFolder as $key => $value) {
|
||||
$tmpPositionAbsolute = "";
|
||||
$tmpPosition = "";
|
||||
$pos = strpos($value["position_absolute"], $fname);
|
||||
if ($pos === false) {
|
||||
$tmpPositionAbsolute = $value["position_absolute"];
|
||||
}
|
||||
$tmpPositionAbsolute = substr_replace($value["position_absolute"], $newTmp, $pos, strlen($fname));
|
||||
$pos = strpos($value["position"], $fname);
|
||||
if ($pos === false) {
|
||||
$tmpPosition = $value["position"];
|
||||
}
|
||||
$tmpPosition = substr_replace($value["position"], $newTmp, $pos, strlen($fname));
|
||||
Db::name('folders')->where('id',$value["id"])->update([
|
||||
'position_absolute' => $tmpPositionAbsolute,
|
||||
'position' =>$tmpPosition,
|
||||
]);
|
||||
}
|
||||
$childFiles = Db::name('files')->where('upload_user',$uid)->where('dir',"like",$fname."%")->select();
|
||||
foreach ($childFiles as $key => $value) {
|
||||
$tmpPosition = "";
|
||||
$pos = strpos($value["dir"], $fname);
|
||||
if ($pos === false) {
|
||||
$tmpPosition = $value["dir"];
|
||||
}
|
||||
$tmpPosition = substr_replace($value["dir"], $newTmp, $pos, strlen($fname));
|
||||
Db::name('files')->where('id',$value["id"])->update([
|
||||
'dir' =>$tmpPosition,
|
||||
]);
|
||||
}
|
||||
if($notEcho){
|
||||
return '{ "result": { "success": true} }';
|
||||
}
|
||||
echo ('{ "result": { "success": true} }');
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件路径获取文件名和父目录路径
|
||||
*
|
||||
* @param string 文件路径
|
||||
* @return array
|
||||
*/
|
||||
static function getFileName($path){
|
||||
$pathSplit = explode("/",$path);
|
||||
$fileName = end($pathSplit);
|
||||
$pathSplitDelete = array_pop($pathSplit);
|
||||
$path="";
|
||||
foreach ($pathSplit as $key => $value) {
|
||||
if (empty($value)){
|
||||
|
||||
}else{
|
||||
$path =$path."/".$value;
|
||||
}
|
||||
}
|
||||
$path = empty($path)?"/":$path;
|
||||
return [$fileName,$path];
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件预览
|
||||
*
|
||||
* @param boolean $isAdmin 是否为管理员预览
|
||||
* @return array 重定向信息
|
||||
*/
|
||||
public function PreviewHandler($isAdmin=false){
|
||||
return $this->adapter->Preview($isAdmin);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图像缩略图
|
||||
*
|
||||
* @return array 重定向信息
|
||||
*/
|
||||
public function getThumb(){
|
||||
return $this->adapter->getThumb();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件下载
|
||||
*
|
||||
* @param boolean $isAdmin 是否为管理员请求
|
||||
* @return array 文件下载URL
|
||||
*/
|
||||
public function Download($isAdmin=false){
|
||||
return $this->adapter->Download($isAdmin);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理目录删除
|
||||
*
|
||||
* @param string $path 目录路径
|
||||
* @param int $uid 用户ID
|
||||
* @return void
|
||||
*/
|
||||
static function DirDeleteHandler($path,$uid){
|
||||
global $toBeDeleteDir;
|
||||
global $toBeDeleteFile;
|
||||
$toBeDeleteDir = [];
|
||||
$toBeDeleteFile = [];
|
||||
foreach ($path as $key => $value) {
|
||||
array_push($toBeDeleteDir,$value);
|
||||
}
|
||||
|
||||
foreach ($path as $key => $value) {
|
||||
self::listToBeDelete($value,$uid);
|
||||
}
|
||||
if(!empty($toBeDeleteFile)){
|
||||
self::DeleteHandler($toBeDeleteFile,$uid);
|
||||
}
|
||||
if(!empty($toBeDeleteDir)){
|
||||
self::deleteDir($toBeDeleteDir,$uid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出待删除文件或目录
|
||||
*
|
||||
* @param string $path 对象路径
|
||||
* @param int $uid 用户ID
|
||||
* @return void
|
||||
*/
|
||||
static function listToBeDelete($path,$uid){
|
||||
global $toBeDeleteDir;
|
||||
global $toBeDeleteFile;
|
||||
$fileData = Db::name('files')->where([
|
||||
'dir' => $path,
|
||||
'upload_user' => $uid,
|
||||
])->select();
|
||||
foreach ($fileData as $key => $value) {
|
||||
array_push($toBeDeleteFile,$path."/".$value["orign_name"]);
|
||||
}
|
||||
$dirData = Db::name('folders')->where([
|
||||
'position' => $path,
|
||||
'owner' => $uid,
|
||||
])->select();
|
||||
foreach ($dirData as $key => $value) {
|
||||
array_push($toBeDeleteDir,$value["position_absolute"]);
|
||||
self::listToBeDelete($value["position_absolute"],$uid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除目录
|
||||
*
|
||||
* @param string $path 目录路径
|
||||
* @param int $uid 用户ID
|
||||
* @return void
|
||||
*/
|
||||
static function deleteDir($path,$uid){
|
||||
Db::name('folders')
|
||||
->where("owner",$uid)
|
||||
->where([
|
||||
'position_absolute' => ["in",$path],
|
||||
])->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理删除请求
|
||||
*
|
||||
* @param string $path 路径
|
||||
* @param int $uid 用户ID
|
||||
* @return array
|
||||
*/
|
||||
static function DeleteHandler($path,$uid){
|
||||
if(empty($path)){
|
||||
return ["result"=>["success"=>true,"error"=>null]];
|
||||
}
|
||||
foreach ($path as $key => $value) {
|
||||
$fileInfo = self::getFileName($value);
|
||||
$fileName = $fileInfo[0];
|
||||
$filePath = $fileInfo[1];
|
||||
$fileNames[$key] = $fileName;
|
||||
$filePathes[$key] = $filePath;
|
||||
}
|
||||
$fileData = Db::name('files')->where([
|
||||
'orign_name' => ["in",$fileNames],
|
||||
'dir' => ["in",$filePathes],
|
||||
'upload_user' => $uid,
|
||||
])->select();
|
||||
$fileListTemp=[];
|
||||
$uniquePolicy = self::uniqueArray($fileData);
|
||||
foreach ($fileData as $key => $value) {
|
||||
if(empty($fileListTemp[$value["policy_id"]])){
|
||||
$fileListTemp[$value["policy_id"]] = [];
|
||||
}
|
||||
array_push($fileListTemp[$value["policy_id"]],$value);
|
||||
}
|
||||
foreach ($fileListTemp as $key => $value) {
|
||||
if(in_array($key,$uniquePolicy["qiniuList"])){
|
||||
QiniuAdapter::DeleteFile($value,$uniquePolicy["qiniuPolicyData"][$key][0]);
|
||||
self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]);
|
||||
}else if(in_array($key,$uniquePolicy["localList"])){
|
||||
LocalAdapter::DeleteFile($value,$uniquePolicy["localPolicyData"][$key][0]);
|
||||
self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]);
|
||||
}else if(in_array($key,$uniquePolicy["ossList"])){
|
||||
OssAdapter::DeleteFile($value,$uniquePolicy["ossPolicyData"][$key][0]);
|
||||
self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]);
|
||||
}else if(in_array($key,$uniquePolicy["upyunList"])){
|
||||
UpyunAdapter::DeleteFile($value,$uniquePolicy["upyunPolicyData"][$key][0]);
|
||||
self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]);
|
||||
}else if(in_array($key,$uniquePolicy["s3List"])){
|
||||
S3Adapter::DeleteFile($value,$uniquePolicy["s3PolicyData"][$key][0]);
|
||||
self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]);
|
||||
}else if(in_array($key,$uniquePolicy["remoteList"])){
|
||||
RemoteAdapter::DeleteFile($value,$uniquePolicy["remotePolicyData"][$key][0]);
|
||||
self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]);
|
||||
}else if(in_array($key,$uniquePolicy["onedriveList"])){
|
||||
OnedriveAdapter::DeleteFile($value,$uniquePolicy["onedrivePolicyData"][$key][0]);
|
||||
self::deleteFileRecord(array_column($value, 'id'),array_sum(array_column($value, 'size')),$value[0]["upload_user"]);
|
||||
}
|
||||
}
|
||||
return ["result"=>["success"=>true,"error"=>null]];
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理移动
|
||||
*
|
||||
* @param array $file 文件路径列表
|
||||
* @param array $dir 目录路径列表
|
||||
* @param string $new 新路径
|
||||
* @param int $uid 用户ID
|
||||
* @return void
|
||||
*/
|
||||
static function MoveHandler($file,$dir,$new,$uid){
|
||||
if(in_array($new,$dir)){
|
||||
die('{ "result": { "success": false, "error": "不能移动目录到自身" } }');
|
||||
}
|
||||
$newFolder=Db::name('folders')->where('owner',$uid)->where('position_absolute',$new)->find();
|
||||
if($newFolder== null){
|
||||
die('{ "result": { "success": false, "error": "目录不存在" } }');
|
||||
}
|
||||
$moveName=[];
|
||||
$movePath=[];
|
||||
foreach ($file as $key => $value) {
|
||||
$fileInfo = self::getFileName($value);
|
||||
$moveName[$key] = $fileInfo[0];
|
||||
$movePath[$key] = $fileInfo[1];
|
||||
}
|
||||
$dirName=[];
|
||||
$dirPa=[];
|
||||
foreach ($dir as $key => $value) {
|
||||
$dirInfo = self::getFileName($value);
|
||||
$dirName[$key] = $dirInfo[0];
|
||||
$dirPar[$key] = $dirInfo[1];
|
||||
}
|
||||
$nameCheck = Db::name('files')->where([
|
||||
'upload_user' => $uid,
|
||||
'dir' => $new,
|
||||
'orign_name' =>["in",$moveName],
|
||||
])->find();
|
||||
$dirNameCheck = array_merge($dirName,$moveName);
|
||||
$dirCheck = Db::name('folders')->where([
|
||||
'owner' => $uid,
|
||||
'position' => $new,
|
||||
'folder_name' =>["in",$dirNameCheck],
|
||||
])->find();
|
||||
if($nameCheck || $dirCheck){
|
||||
die('{ "result": { "success": false, "error": "文件名冲突,请检查是否重名" } }');
|
||||
}
|
||||
if(!empty($dir)){
|
||||
die('{ "result": { "success": false, "error": "暂不支持移动目录" } }');
|
||||
}
|
||||
Db::name('files')->where([
|
||||
'upload_user' => $uid,
|
||||
'dir' => ["in",$movePath],
|
||||
'orign_name' =>["in",$moveName],
|
||||
])->update([
|
||||
'dir'=> $new,
|
||||
"parent_folder" => $newFolder["id"]
|
||||
]);
|
||||
echo ('{ "result": { "success": true} }');
|
||||
}
|
||||
|
||||
/**
|
||||
* ToDo 移动文件
|
||||
*
|
||||
* @param array $file
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
static function moveFile($file,$path){
|
||||
|
||||
}
|
||||
|
||||
static function deleteFileRecord($id,$size,$uid){
|
||||
Db::name('files')->where([
|
||||
'id' => ["in",$id],
|
||||
])->delete();
|
||||
Db::name('shares')
|
||||
->where(['owner' => $uid])
|
||||
->where(['source_type' => "file"])
|
||||
->where(['source_name' => ["in",$id],])
|
||||
->delete();
|
||||
Db::name('users')->where([
|
||||
'id' => $uid,
|
||||
])->setDec('used_storage', $size);
|
||||
}
|
||||
|
||||
static function filterFile($keyWords,$uid){
|
||||
switch ($keyWords) {
|
||||
case '{filterType:video}':
|
||||
$fileList = Db::name('files')
|
||||
->where('upload_user',$uid)
|
||||
->where('orign_name',"like","%.mp4")
|
||||
->whereOr('orign_name',"like","%.flv")
|
||||
->whereOr('orign_name',"like","%.avi")
|
||||
->whereOr('orign_name',"like","%.wmv")
|
||||
->whereOr('orign_name',"like","%.mkv")
|
||||
->whereOr('orign_name',"like","%.rm")
|
||||
->whereOr('orign_name',"like","%.rmvb")
|
||||
->whereOr('orign_name',"like","%.mov")
|
||||
->whereOr('orign_name',"like","%.ogv")
|
||||
->select();
|
||||
break;
|
||||
case '{filterType:audio}':
|
||||
$fileList = Db::name('files')
|
||||
->where('upload_user',$uid)
|
||||
->where('orign_name',"like","%.mp3")
|
||||
->whereOr('orign_name',"like","%.flac")
|
||||
->whereOr('orign_name',"like","%.ape")
|
||||
->whereOr('orign_name',"like","%.wav")
|
||||
->whereOr('orign_name',"like","%.acc")
|
||||
->whereOr('orign_name',"like","%.ogg")
|
||||
->select();
|
||||
break;
|
||||
case '{filterType:image}':
|
||||
$fileList = Db::name('files')
|
||||
->where('upload_user',$uid)
|
||||
->where('orign_name',"like","%.bmp")
|
||||
->whereOr('orign_name',"like","%.flac")
|
||||
->whereOr('orign_name',"like","%.iff")
|
||||
->whereOr('orign_name',"like","%.png")
|
||||
->whereOr('orign_name',"like","%.gif")
|
||||
->whereOr('orign_name',"like","%.jpg")
|
||||
->whereOr('orign_name',"like","%.jpge")
|
||||
->whereOr('orign_name',"like","%.psd")
|
||||
->whereOr('orign_name',"like","%.svg")
|
||||
->whereOr('orign_name',"like","%.webp")
|
||||
->select();
|
||||
break;
|
||||
case '{filterType:doc}':
|
||||
$fileList = Db::name('files')
|
||||
->where('upload_user',$uid)
|
||||
->where('orign_name',"like","%.txt")
|
||||
->whereOr('orign_name',"like","%.md")
|
||||
->whereOr('orign_name',"like","%.pdf")
|
||||
->whereOr('orign_name',"like","%.doc")
|
||||
->whereOr('orign_name',"like","%.docx")
|
||||
->whereOr('orign_name',"like","%.ppt")
|
||||
->whereOr('orign_name',"like","%.pptx")
|
||||
->whereOr('orign_name',"like","%.xls")
|
||||
->whereOr('orign_name',"like","%.xlsx")
|
||||
->select();
|
||||
break;
|
||||
default:
|
||||
$fileList = [];
|
||||
break;
|
||||
}
|
||||
return $fileList;
|
||||
}
|
||||
|
||||
static function searchFile($keyWords,$uid){
|
||||
if (0 === strpos($keyWords, '{filterType:')) {
|
||||
$fileList = self::filterFile($keyWords,$uid);
|
||||
}else{
|
||||
$fileList = Db::name('files')
|
||||
->where('upload_user',$uid)
|
||||
->where('orign_name',"like","%$keyWords%")
|
||||
->select();
|
||||
}
|
||||
|
||||
$count= 0;
|
||||
$fileListData=[
|
||||
"result"=>[],
|
||||
];
|
||||
foreach ($fileList as $key => $value) {
|
||||
$fileListData['result'][$count]['name'] = $value['orign_name'];
|
||||
$fileListData['result'][$count]['rights'] = "drwxr-xr-x";
|
||||
$fileListData['result'][$count]['size'] = $value['size'];
|
||||
$fileListData['result'][$count]['date'] = $value['upload_date'];
|
||||
$fileListData['result'][$count]['type'] = 'file';
|
||||
$fileListData['result'][$count]['name2'] = $value["dir"];
|
||||
$fileListData['result'][$count]['id'] = $value["id"];
|
||||
$fileListData['result'][$count]['pic'] = $value["pic_info"];
|
||||
$fileListData['result'][$count]['path'] = $value['dir'];
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $fileListData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出文件
|
||||
*
|
||||
* @param 路径 $path
|
||||
* @param 用户UID $uid
|
||||
* @param boolean $isShare 是否为分享模式下列出文件
|
||||
* @return void
|
||||
*/
|
||||
static function ListFile($path,$uid,$isShare=false,$originPath=null){
|
||||
$fileList = Db::name('files')->where('upload_user',$uid)->where('dir',$path)->select();
|
||||
$dirList = Db::name('folders')->where('owner',$uid)->where('position',$path)->select();
|
||||
$count= 0;
|
||||
$fileListData=[
|
||||
"result"=>[],
|
||||
];
|
||||
foreach ($dirList as $key => $value) {
|
||||
$fileListData['result'][$count]['name'] = $value['folder_name'];
|
||||
$fileListData['result'][$count]['rights'] = "drwxr-xr-x";
|
||||
$fileListData['result'][$count]['size'] = "0";
|
||||
$fileListData['result'][$count]['date'] = $value['date'];
|
||||
$fileListData['result'][$count]['type'] = 'dir';
|
||||
$fileListData['result'][$count]['name2'] = "";
|
||||
$fileListData['result'][$count]['id'] = $value['id'];
|
||||
$fileListData['result'][$count]['pic'] = "";
|
||||
$fileListData['result'][$count]['path'] = $value['position'];
|
||||
if($isShare){
|
||||
if (substr($value['position'], 0, strlen($originPath)) == $originPath) {
|
||||
$value['position'] = substr($value['position'], strlen($originPath));
|
||||
}
|
||||
$fileListData['result'][$count]['path'] = ($value['position']=="")?"/":$value['position'];
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
foreach ($fileList as $key => $value) {
|
||||
$fileListData['result'][$count]['name'] = $value['orign_name'];
|
||||
$fileListData['result'][$count]['rights'] = "drwxr-xr-x";
|
||||
$fileListData['result'][$count]['size'] = $value['size'];
|
||||
$fileListData['result'][$count]['date'] = $value['upload_date'];
|
||||
$fileListData['result'][$count]['type'] = 'file';
|
||||
$fileListData['result'][$count]['id'] = $value["id"];
|
||||
$fileListData['result'][$count]['pic'] = $value["pic_info"];
|
||||
$fileListData['result'][$count]['path'] = $value['dir'];
|
||||
if($isShare){
|
||||
if (substr($value['dir'], 0, strlen($originPath)) == $originPath) {
|
||||
$value['dir'] = substr($value['dir'], strlen($originPath));
|
||||
}
|
||||
$fileListData['result'][$count]['path'] = ($value['dir']=="")?"/":$value['dir'];
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $fileListData;
|
||||
}
|
||||
|
||||
static function listPic($path,$uid,$url="/File/Preview?"){
|
||||
$firstPreview = self::getFileName($path);
|
||||
$path=$firstPreview[1];
|
||||
$fileList = Db::name('files')
|
||||
->where('upload_user',$uid)
|
||||
->where('dir',$path)
|
||||
->where('pic_info',"<>"," ")
|
||||
->where('pic_info',"<>","0,0")
|
||||
->where('pic_info',"<>","null,null")
|
||||
->select();
|
||||
$count= 0;
|
||||
$fileListData=[];
|
||||
foreach ($fileList as $key => $value) {
|
||||
if($value["orign_name"] == $firstPreview[0]){
|
||||
$previewPicInfo = explode(",",$value["pic_info"]);
|
||||
$previewSrc = $url."action=preview&path=".urlencode($path."/".$value["orign_name"]);
|
||||
}else{
|
||||
$picInfo = explode(",",$value["pic_info"]);
|
||||
$fileListData[$count]['src'] = $url."action=preview&path=".$path."/".$value["orign_name"];
|
||||
$fileListData[$count]['w'] = 0;
|
||||
$fileListData[$count]['h'] = 0;
|
||||
$fileListData[$count]['title'] = $value["orign_name"];
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
array_unshift($fileListData,array(
|
||||
'src' => $previewSrc,
|
||||
'w' => 0,
|
||||
'h' => 0,
|
||||
'title' => $firstPreview[0],
|
||||
));
|
||||
return $fileListData;
|
||||
}
|
||||
|
||||
/**
|
||||
* [createFolder description]
|
||||
* @param [type] $dirName [description]
|
||||
* @param [type] $dirPosition [description]
|
||||
* @param [type] $uid [description]
|
||||
* @return [type] [description]
|
||||
*/
|
||||
static function createFolder($dirName,$dirPosition,$uid){
|
||||
$dirName = str_replace(" ","",$dirName);
|
||||
$dirName = str_replace("/","",$dirName);
|
||||
if(empty($dirName)){
|
||||
return ["result"=>["success"=>false,"error"=>"目录名不能为空"]];
|
||||
}
|
||||
if(Db::name('folders')->where('position_absolute',$dirPosition)->where('owner',$uid)->find() ==null || Db::name('folders')->where('owner',$uid)->where('position',$dirPosition)->where('folder_name',$dirName)->find() !=null || Db::name('files')->where('upload_date',$uid)->where('dir',$dirPosition)->where('pre_name',$dirName)->find() !=null){
|
||||
return ["result"=>["success"=>false,"error"=>"路径不存在或文件已存在"]];
|
||||
}
|
||||
$sqlData = [
|
||||
'folder_name' => $dirName,
|
||||
'parent_folder' => Db::name('folders')->where('position_absolute',$dirPosition)->value('id'),
|
||||
'position' => $dirPosition,
|
||||
'owner' => $uid,
|
||||
'date' => date("Y-m-d H:i:s"),
|
||||
'position_absolute' => ($dirPosition == "/")?($dirPosition.$dirName):($dirPosition."/".$dirName),
|
||||
];
|
||||
if(Db::name('folders')->insert($sqlData)){
|
||||
return ["result"=>["success"=>true,"error"=>null]];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static function getTotalStorage($uid){
|
||||
$userData = Db::name('users')->where('id',$uid)->find();
|
||||
$basicStronge = Db::name('groups')->where('id',$userData['user_group'])->find();
|
||||
$addOnStorage = Db::name('storage_pack')
|
||||
->where('uid',$uid)
|
||||
->where('dlay_time',">",time())
|
||||
->sum('pack_size');
|
||||
return $addOnStorage+$basicStronge["max_storage"];
|
||||
}
|
||||
|
||||
static function getUsedStorage($uid){
|
||||
$userData = Db::name('users')->where('id',$uid)->find();
|
||||
return $userData['used_storage'];
|
||||
}
|
||||
|
||||
static function sotrageCheck($uid,$fsize){
|
||||
$totalStorage = self::getTotalStorage($uid);
|
||||
$usedStorage = self::getUsedStorage($uid);
|
||||
return ($totalStorage > ($usedStorage + $fsize)) ? True : False;
|
||||
}
|
||||
|
||||
static function storageCheckOut($uid,$size){
|
||||
Db::name('users')->where('id',$uid)->setInc('used_storage',$size);
|
||||
}
|
||||
|
||||
static function storageGiveBack($uid,$size){
|
||||
Db::name('users')->where('id',$uid)->setDec('used_storage',$size);
|
||||
}
|
||||
|
||||
static function addFile($jsonData,$policyData,$uid,$picInfo=" "){
|
||||
$dir = "/".str_replace(",","/",$jsonData['path']);
|
||||
$fname = $jsonData['fname'];
|
||||
if(self::isExist($dir,$fname,$uid)){
|
||||
return[false,"文件已存在"];
|
||||
}
|
||||
$folderBelong = Db::name('folders')->where('owner',$uid)->where('position_absolute',$dir)->find();
|
||||
if($folderBelong ==null){
|
||||
return[false,"目录不存在"];
|
||||
}
|
||||
$sqlData = [
|
||||
'orign_name' => $jsonData['fname'],
|
||||
'pre_name' => $jsonData['objname'],
|
||||
'upload_user' => $uid,
|
||||
'size' => $jsonData['fsize'],
|
||||
'upload_date' => date("Y-m-d H:i:s"),
|
||||
'parent_folder' => $folderBelong['id'],
|
||||
'policy_id' => $policyData['id'],
|
||||
'dir' => $dir,
|
||||
'pic_info' => $picInfo,
|
||||
];
|
||||
if(Db::name('files')->insert($sqlData)){
|
||||
return [true,"上传成功"];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static function isExist($dir,$fname,$uid){
|
||||
if(Db::name('files')->where('upload_user',$uid)->where('dir',$dir)->where('orign_name',$fname)->find() !=null){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static function deleteFile($fname,$policy){
|
||||
switch ($policy['policy_type']) {
|
||||
case 'qiniu':
|
||||
return QiniuAdapter::deleteSingle($fname,$policy);
|
||||
break;
|
||||
case 'oss':
|
||||
return OssAdapter::deleteOssFile($fname,$policy);
|
||||
break;
|
||||
case 'upyun':
|
||||
return UpyunAdapter::deleteUpyunFile($fname,$policy);
|
||||
break;
|
||||
case 's3':
|
||||
return S3Adapter::deleteS3File($fname,$policy);
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static function uniqueArray($data = array()){
|
||||
$tempList = [];
|
||||
$qiniuList = [];
|
||||
$qiniuPolicyData = [];
|
||||
$localList = [];
|
||||
$localPolicyData = [];
|
||||
$ossList = [];
|
||||
$ossPolicyData = [];
|
||||
$upyunList = [];
|
||||
$upyunPolicyData = [];
|
||||
$s3List = [];
|
||||
$s3PolicyData = [];
|
||||
$remoteList = [];
|
||||
$remotePolicyData = [];
|
||||
$onedriveList = [];
|
||||
$onedrivePolicyData = [];
|
||||
foreach ($data as $key => $value) {
|
||||
if(!in_array($value['policy_id'],$tempList)){
|
||||
array_push($tempList,$value['policy_id']);
|
||||
$policyTempData = Db::name('policy')->where('id',$value['policy_id'])->find();
|
||||
switch ($policyTempData["policy_type"]) {
|
||||
case 'qiniu':
|
||||
array_push($qiniuList,$value['policy_id']);
|
||||
if(empty($qiniuPolicyData[$value['policy_id']])){
|
||||
$qiniuPolicyData[$value['policy_id']] = [];
|
||||
}
|
||||
array_push($qiniuPolicyData[$value['policy_id']],$policyTempData);
|
||||
break;
|
||||
case 'local':
|
||||
array_push($localList,$value['policy_id']);
|
||||
if(empty($localPolicyData[$value['policy_id']])){
|
||||
$localPolicyData[$value['policy_id']] = [];
|
||||
}
|
||||
array_push($localPolicyData[$value['policy_id']],$policyTempData);
|
||||
break;
|
||||
case 'oss':
|
||||
array_push($ossList,$value['policy_id']);
|
||||
if(empty($ossPolicyData[$value['policy_id']])){
|
||||
$ossPolicyData[$value['policy_id']] = [];
|
||||
}
|
||||
array_push($ossPolicyData[$value['policy_id']],$policyTempData);
|
||||
break;
|
||||
case 'upyun':
|
||||
array_push($upyunList,$value['policy_id']);
|
||||
if(empty($upyunPolicyData[$value['policy_id']])){
|
||||
$upyunPolicyData[$value['policy_id']] = [];
|
||||
}
|
||||
array_push($upyunPolicyData[$value['policy_id']],$policyTempData);
|
||||
break;
|
||||
case 's3':
|
||||
array_push($s3List,$value['policy_id']);
|
||||
if(empty($s3PolicyData[$value['policy_id']])){
|
||||
$s3PolicyData[$value['policy_id']] = [];
|
||||
}
|
||||
array_push($s3PolicyData[$value['policy_id']],$policyTempData);
|
||||
break;
|
||||
case 'remote':
|
||||
array_push($remoteList,$value['policy_id']);
|
||||
if(empty($remotePolicyData[$value['policy_id']])){
|
||||
$remotePolicyData[$value['policy_id']] = [];
|
||||
}
|
||||
array_push($remotePolicyData[$value['policy_id']],$policyTempData);
|
||||
break;
|
||||
case 'onedrive':
|
||||
array_push($onedriveList,$value['policy_id']);
|
||||
if(empty($onedrivePolicyData[$value['policy_id']])){
|
||||
$onedrivePolicyData[$value['policy_id']] = [];
|
||||
}
|
||||
array_push($onedrivePolicyData[$value['policy_id']],$policyTempData);
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$returenValue=array(
|
||||
'policyId' => $tempList ,
|
||||
'qiniuList' => $qiniuList,
|
||||
'qiniuPolicyData' => $qiniuPolicyData,
|
||||
'localList' => $localList,
|
||||
'localPolicyData' => $localPolicyData,
|
||||
'ossList' => $ossList,
|
||||
'ossPolicyData' => $ossPolicyData,
|
||||
'upyunList' => $upyunList,
|
||||
'upyunPolicyData' => $upyunPolicyData,
|
||||
's3List' => $s3List,
|
||||
's3PolicyData' => $s3PolicyData,
|
||||
'remoteList' => $remoteList,
|
||||
'remotePolicyData' => $remotePolicyData,
|
||||
'onedriveList' => $onedriveList,
|
||||
'onedrivePolicyData' => $onedrivePolicyData,
|
||||
);
|
||||
return $returenValue;
|
||||
}
|
||||
|
||||
public function signTmpUrl(){
|
||||
return $this->adapter->signTmpUrl()[1];
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Image extends Model{
|
||||
private $file; //图片地址
|
||||
private $width; //图片长度
|
||||
private $height; //图片长度
|
||||
private $itype; //图片类型
|
||||
private $img; //原图的资源句柄
|
||||
private $new; //新图的资源句柄
|
||||
|
||||
//构造方法,初始化
|
||||
public function __construct($_file) {
|
||||
$this->file = $_file;
|
||||
list($this->width, $this->height, $this->itype) = getimagesize($this->file);
|
||||
$this->img = $this->getFromImg($this->file, $this->itype);
|
||||
}
|
||||
//缩略图(固定长高容器,图像等比例,扩容填充,裁剪)[固定了大小,不失真,不变形]
|
||||
public function thumb($new_width = 0,$new_height = 0) {
|
||||
|
||||
if (empty($new_width) && empty($new_height)) {
|
||||
$new_width = $this->width;
|
||||
$new_height = $this->height;
|
||||
}
|
||||
|
||||
if (!is_numeric($new_width) || !is_numeric($new_height)) {
|
||||
$new_width = $this->width;
|
||||
$new_height = $this->height;
|
||||
}
|
||||
|
||||
//创建一个容器
|
||||
$_n_w = $new_width;
|
||||
$_n_h = $new_height;
|
||||
|
||||
//创建裁剪点
|
||||
$_cut_width = 0;
|
||||
$_cut_height = 0;
|
||||
|
||||
if ($this->width < $this->height) {
|
||||
$new_width = ($new_height / $this->height) * $this->width;
|
||||
} else {
|
||||
$new_height = ($new_width / $this->width) * $this->height;
|
||||
}
|
||||
if ($new_width < $_n_w) { //如果新高度小于新容器高度
|
||||
$r = $_n_w / $new_width; //按长度求出等比例因子
|
||||
$new_width *= $r; //扩展填充后的长度
|
||||
$new_height *= $r; //扩展填充后的高度
|
||||
$_cut_height = ($new_height - $_n_h) / 2; //求出裁剪点的高度
|
||||
}
|
||||
|
||||
if ($new_height < $_n_h) { //如果新高度小于容器高度
|
||||
$r = $_n_h / $new_height; //按高度求出等比例因子
|
||||
$new_width *= $r; //扩展填充后的长度
|
||||
$new_height *= $r; //扩展填充后的高度
|
||||
$_cut_width = ($new_width - $_n_w) / 2; //求出裁剪点的长度
|
||||
}
|
||||
|
||||
$this->new = imagecreatetruecolor($_n_w,$_n_h);
|
||||
imagecopyresampled($this->new,$this->img,0,0,$_cut_width,$_cut_height,$new_width,$new_height,$this->width,$this->height);
|
||||
}
|
||||
|
||||
//加载图片,各种类型,返回图片的资源句柄
|
||||
public function getFromImg($_file, $_type) {
|
||||
switch ($_type) {
|
||||
case 1 :
|
||||
$img = imagecreatefromgif($_file);
|
||||
break;
|
||||
case 2 :
|
||||
$img = imagecreatefromjpeg($_file);
|
||||
break;
|
||||
case 3 :
|
||||
$img = imagecreatefrompng($_file);
|
||||
break;
|
||||
default:
|
||||
$img = '';
|
||||
}
|
||||
return $img;
|
||||
}
|
||||
|
||||
//图像输出
|
||||
public function output($name = "") {
|
||||
imagepng($this->new,$this->file.$name);//第二个参数为新生成的图片名
|
||||
imagedestroy($this->img);
|
||||
imagedestroy($this->new);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -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 = 280;
|
||||
// $maxHeight = 150;
|
||||
// $changeWidth = 150*$rate;
|
||||
// $changeHeight = 280/$rate;
|
||||
// if($changeWidth>=$maxWidth){
|
||||
// return [(int)$changeHeight,280];
|
||||
// }
|
||||
return [230,200];
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出缩略图
|
||||
*
|
||||
* @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];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \PHPMailer\PHPMailer\PHPMailer;
|
||||
use \PHPMailer\PHPMailer\Exception;
|
||||
|
||||
class Mail extends Model{
|
||||
|
||||
public $fromName;
|
||||
public $fromAdress;
|
||||
public $smtpHost;
|
||||
public $smtpPort;
|
||||
public $replyTo;
|
||||
public $smtpUser;
|
||||
public $smtpPass;
|
||||
public $encriptionType;
|
||||
public $errorMsg;
|
||||
|
||||
public function __construct(){
|
||||
$mailOptions = Option::getValues(["mail"]);
|
||||
$this->fromName = $mailOptions["fromName"];
|
||||
$this->fromAdress = $mailOptions["fromAdress"];
|
||||
$this->smtpHost = $mailOptions["smtpHost"];
|
||||
$this->smtpPort = $mailOptions["smtpPort"];
|
||||
$this->replyTo = $mailOptions["replyTo"];
|
||||
$this->smtpUser = $mailOptions["smtpUser"];
|
||||
$this->smtpPass = $mailOptions["smtpPass"];
|
||||
$this->encriptionType = $mailOptions["encriptionType"];
|
||||
}
|
||||
|
||||
public function Send($to,$name,$title,$content){
|
||||
$mail = new PHPMailer();
|
||||
$mail->isSMTP();
|
||||
$mail->SMTPAuth=true;
|
||||
$mail->Host = $this->smtpHost;
|
||||
if(!empty($this->encriptionType) && $this->encriptionType != "no"){
|
||||
$mail->SMTPSecure = $this->encriptionType;
|
||||
}
|
||||
$mail->Port = $this->smtpPort;
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->FromName = $this->fromName;
|
||||
$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){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use Sabre\DAV;
|
||||
use \app\index\model\FileManage;
|
||||
|
||||
class Objects extends DAV\File{
|
||||
|
||||
private $myPath;
|
||||
public $id;
|
||||
public $fileData;
|
||||
public $uid;
|
||||
public $fileName;
|
||||
public $dir;
|
||||
public $actualPath;
|
||||
public $isExist;
|
||||
|
||||
function __construct($path) {
|
||||
$ex = explode("/",$path);
|
||||
$this->uid = $ex[0];
|
||||
$t = strpos($path,$this->uid);
|
||||
if($t == 0){
|
||||
$this->myPath = substr($path,$t+strlen($this->uid));
|
||||
}else{
|
||||
$this->myPath = $path;
|
||||
}
|
||||
$this->fileName = end($ex);
|
||||
$this->dir = dirname($this->myPath) == "\\" ? "/" :dirname($this->myPath);
|
||||
$this->fileData = Db::name('files')->where('upload_user',$this->uid)->where('dir',$this->dir)->where('orign_name',$this->fileName)->find();
|
||||
if(empty($this->fileData)){
|
||||
$this->isExist = false;
|
||||
}else{
|
||||
$this->isExist = true;
|
||||
}
|
||||
$this->actualPath = ROOT_PATH . 'public/uploads/'.$this->fileData["pre_name"];
|
||||
}
|
||||
|
||||
function getName() {
|
||||
return $this->fileName;
|
||||
}
|
||||
|
||||
function get() {
|
||||
return fopen($this->actualPath, 'r');
|
||||
}
|
||||
|
||||
function getSize() {
|
||||
return $this->fileData["size"];
|
||||
}
|
||||
|
||||
function setName($name){
|
||||
$reqPath = $this->myPath;
|
||||
$ex = explode("/",$reqPath);
|
||||
$newPath = rtrim($reqPath,end($ex)).$name;
|
||||
$renameAction = json_decode(FileManage::RenameHandler($reqPath,$newPath,$this->uid,true),true);
|
||||
if(!$renameAction["result"]["success"]){
|
||||
throw new DAV\Exception\Forbidden($renameAction["result"]["error"]);
|
||||
}
|
||||
}
|
||||
|
||||
function getContentType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
function put($data){
|
||||
$fileSize = (int)$_SERVER['CONTENT_LENGTH'];
|
||||
if(!FileManage::sotrageCheck($this->uid,$fileSize)){
|
||||
throw new DAV\Exception\InsufficientStorage("Quota is not enough");
|
||||
}
|
||||
$filePath = ROOT_PATH . 'public/uploads/' . $this->fileData["pre_name"];
|
||||
file_put_contents($filePath, "");
|
||||
file_put_contents($filePath, $data);
|
||||
FileManage::storageGiveBack($this->uid,$this->fileData["size"]);
|
||||
FileManage::storageCheckOut($this->uid,$fileSize);
|
||||
@list($width, $height, $type, $attr) = getimagesize($filePath);
|
||||
$picInfo = empty($width)?" ":$width.",".$height;
|
||||
Db::name('files')->where('id', $this->fileData["id"])->update(['size' => $fileSize,'pic_info' => $picInfo]);
|
||||
}
|
||||
|
||||
function delete(){
|
||||
FileManage::DeleteHandler([0=>$this->myPath],$this->uid);
|
||||
}
|
||||
|
||||
function getETag() {
|
||||
|
||||
return '"' . sha1(
|
||||
fileinode($this->actualPath) .
|
||||
filesize($this->actualPath) .
|
||||
filemtime($this->actualPath)
|
||||
) . '"';
|
||||
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -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,34 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
class Option extends Model{
|
||||
|
||||
static function getValues($groups = ['basic'],$userInfo=null){
|
||||
$t = Db::name('options')->where('option_type','in',$groups)->column('option_value','option_name');
|
||||
if(in_array("basic",$groups)){
|
||||
return array_merge($t,self::getThemeOptions($t,$userInfo));
|
||||
}
|
||||
return $t;
|
||||
}
|
||||
|
||||
static function getThemeOptions($basicOptions,$userInfo){
|
||||
$themes = json_decode($basicOptions["themes"],true);
|
||||
if($userInfo==null){
|
||||
return ["themeColor"=>$basicOptions["defaultTheme"],"themeConfig"=>$themes[$basicOptions["defaultTheme"]]];
|
||||
}else{
|
||||
$userOptions = json_decode($userInfo["options"],true);
|
||||
if(empty($userOptions)||!array_key_exists("preferTheme",$userOptions)||!array_key_exists($userOptions["preferTheme"],$themes)){
|
||||
return ["themeColor"=>$basicOptions["defaultTheme"],"themeConfig"=>$themes[$basicOptions["defaultTheme"]]];
|
||||
}
|
||||
return ["themeColor"=>$userOptions["preferTheme"],"themeConfig"=>$themes[$userOptions["preferTheme"]]];
|
||||
}
|
||||
}
|
||||
|
||||
static function getValue($optionName){
|
||||
return Db::name('options')->where('option_name',$optionName)->value('option_value');
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -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/1/w/230/h/200");
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除某一策略下的指定七牛文件
|
||||
*
|
||||
* @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,166 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
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;
|
||||
}
|
||||
$s3 = new \Aws\S3\S3Client([
|
||||
'version' => 'latest',
|
||||
'region' => $this->policyModel["op_name"],
|
||||
'endpoint' => $this->policyModel["op_pwd"],
|
||||
'use_path_style_endpoint' => true,
|
||||
'credentials' => [
|
||||
'key' => $this->policyModel["ak"],
|
||||
'secret' => $this->policyModel["sk"],
|
||||
],
|
||||
]);
|
||||
$cmd = $s3->getCommand('GetObject', [
|
||||
'Bucket' => $this->policyModel["bucketname"],
|
||||
'Key' => $this->fileModel["pre_name"],
|
||||
]);
|
||||
$timeOut = Option::getValue("timeout");
|
||||
$req = $s3->createPresignedRequest($cmd, '+'.($timeOut/60).' minutes');
|
||||
$url = (string)$req->getUri();
|
||||
|
||||
return [1,$url];
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存文件内容
|
||||
*
|
||||
* @param string $content 文件内容
|
||||
* @return void
|
||||
*/
|
||||
public function saveContent($content){
|
||||
$s3 = new \Aws\S3\S3Client([
|
||||
'version' => 'latest',
|
||||
'region' => $this->policyModel["op_name"],
|
||||
'endpoint' => $this->policyModel["op_pwd"],
|
||||
'use_path_style_endpoint' => true,
|
||||
'credentials' => [
|
||||
'key' => $this->policyModel["ak"],
|
||||
'secret' => $this->policyModel["sk"],
|
||||
],
|
||||
]);
|
||||
$s3->putObject([
|
||||
'Bucket' => $this->policyModel["bucketname"],
|
||||
'Key' => $this->fileModel["pre_name"],
|
||||
'Body' => $content,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除某一策略下的指定文件
|
||||
*
|
||||
* @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");
|
||||
$s3 = new \Aws\S3\S3Client([
|
||||
'version' => 'latest',
|
||||
'region' => $this->policyModel["op_name"],
|
||||
'endpoint' => $this->policyModel["op_pwd"],
|
||||
'use_path_style_endpoint' => true,
|
||||
'credentials' => [
|
||||
'key' => $this->policyModel["ak"],
|
||||
'secret' => $this->policyModel["sk"],
|
||||
],
|
||||
]);
|
||||
$cmd = $s3->getCommand('GetObject', [
|
||||
'Bucket' => $this->policyModel["bucketname"],
|
||||
'Key' => $this->fileModel["pre_name"],
|
||||
'ResponseContentDisposition' => 'attachment; filename='.$this->fileModel["orign_name"],
|
||||
]);
|
||||
$timeOut = Option::getValue("timeout");
|
||||
$req = $s3->createPresignedRequest($cmd, '+'.($timeOut/60).' minutes');
|
||||
$url = (string)$req->getUri();
|
||||
|
||||
return [1,$url];
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除临时文件
|
||||
*
|
||||
* @param string $fname 文件名
|
||||
* @param array $policy 上传策略信息
|
||||
* @return boolean
|
||||
*/
|
||||
static function deleteS3File($fname,$policy){
|
||||
$s3 = new \Aws\S3\S3Client([
|
||||
'version' => 'latest',
|
||||
'region' => $policy["op_name"],
|
||||
'endpoint' => $policy["op_pwd"],
|
||||
'use_path_style_endpoint' => true,
|
||||
'credentials' => [
|
||||
'key' => $policy["ak"],
|
||||
'secret' => $policy["sk"],
|
||||
],
|
||||
]);
|
||||
$result = $s3->deleteObject([
|
||||
'Bucket' => $policy["bucketname"],
|
||||
'Key' => $fname,
|
||||
]);
|
||||
return $result["DeleteMarker"];
|
||||
}
|
||||
|
||||
/**
|
||||
* 签名临时URL用于Office预览
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function signTmpUrl(){
|
||||
return $this->Preview();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,366 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use \think\Session;
|
||||
use \app\index\model\FileManage;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\User;
|
||||
|
||||
class ShareHandler extends Model{
|
||||
|
||||
public $shareData;
|
||||
public $querryStatus = true;
|
||||
public $shareOwner;
|
||||
public $fileData;
|
||||
public $dirData;
|
||||
public $lockStatus = false;
|
||||
|
||||
public function __construct($key,$notExist=true){
|
||||
$this->shareData = Db::name('shares')->where('share_key',$key)->find();
|
||||
if(empty($this->shareData)){
|
||||
$this->querryStatus = false;
|
||||
}else{
|
||||
if($notExist){
|
||||
if($this->shareData["source_type"] == "file"){
|
||||
$this->fileShareHandler();
|
||||
}else{
|
||||
$this->dirShareHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
if($this->shareData["type"] == "private"){
|
||||
$this->lockStatus = Session::has("share".$this->shareData["id"])?false:true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function deleteShare($uid){
|
||||
if($this->shareData["owner"] != $uid){
|
||||
return array(
|
||||
"error" => 1,
|
||||
"msg" => "无权操作"
|
||||
);
|
||||
}
|
||||
Db::name('shares')->where('share_key',$this->shareData["share_key"])->delete();
|
||||
return array(
|
||||
"error" => 0,
|
||||
"msg" => "分享取消成功"
|
||||
);
|
||||
}
|
||||
|
||||
public function changePromission($uid,$ignore=false){
|
||||
if($this->shareData["owner"] != $uid && $ignore == false){
|
||||
return array(
|
||||
"error" => 1,
|
||||
"msg" => "无权操作"
|
||||
);
|
||||
}
|
||||
$newPwd = self::getRandomKey(6);
|
||||
Db::name('shares')->where('share_key',$this->shareData["share_key"])->update([
|
||||
'type' => $this->shareData["type"] == "public"?"private":"public",
|
||||
'share_pwd' => $newPwd
|
||||
]);
|
||||
return array(
|
||||
"error" =>0,
|
||||
"msg" => "更改成功",
|
||||
"newPwd" => $newPwd,
|
||||
);
|
||||
}
|
||||
|
||||
public function checkPwd($pwd){
|
||||
if($pwd == $this->shareData["share_pwd"]){
|
||||
Session::set("share".$this->shareData["id"],"1");
|
||||
return array(
|
||||
"error" =>0,
|
||||
);
|
||||
}else{
|
||||
return array(
|
||||
"error" =>1,
|
||||
"msg" => "密码错误"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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 getDocPreview($user,$path,$inFolder){
|
||||
$checkStatus = $this->checkSession($user);
|
||||
if(!$checkStatus[0]){
|
||||
return [$checkStatus[0],$checkStatus[1]];
|
||||
}
|
||||
if($inFolder){
|
||||
$reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find();
|
||||
$fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]);
|
||||
}else{
|
||||
$reqPath = Db::name('files')->where('id',$this->shareData["source_name"])->find();
|
||||
if($reqPath["dir"] == "/"){
|
||||
$reqPath["dir"] = $reqPath["dir"].$reqPath["orign_name"];
|
||||
}else{
|
||||
$reqPath["dir"] = $reqPath["dir"]."/".$reqPath["orign_name"];
|
||||
}
|
||||
$fileObj = new FileManage($reqPath["dir"],$this->shareData["owner"]);
|
||||
}
|
||||
$tmpUrl = $fileObj->signTmpUrl();
|
||||
return[true,"http://view.officeapps.live.com/op/view.aspx?src=".urlencode($tmpUrl)];
|
||||
}
|
||||
|
||||
public function getContent($user,$path=null,$inFolder){
|
||||
$checkStatus = $this->checkSession($user);
|
||||
if(!$checkStatus[0]){
|
||||
return [$checkStatus[0],$checkStatus[1]];
|
||||
}
|
||||
if($inFolder){
|
||||
$reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find();
|
||||
$fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]);
|
||||
}else{
|
||||
$reqPath = Db::name('files')->where('id',$this->shareData["source_name"])->find();
|
||||
if($reqPath["dir"] == "/"){
|
||||
$reqPath["dir"] = $reqPath["dir"].$reqPath["orign_name"];
|
||||
}else{
|
||||
$reqPath["dir"] = $reqPath["dir"]."/".$reqPath["orign_name"];
|
||||
}
|
||||
$fileObj = new FileManage($reqPath["dir"],$this->shareData["owner"]);
|
||||
}
|
||||
$fileObj->getContent();
|
||||
exit();
|
||||
}
|
||||
|
||||
public function checkSession($user){
|
||||
if($this->lockStatus){
|
||||
return [false,"会话过期,请刷新页面"];
|
||||
}
|
||||
if(Option::getValue("allowdVisitorDownload") == "false" && !$user->loginStatus){
|
||||
return [false,"未登录用户禁止下载,请先登录"];
|
||||
}
|
||||
if(!$this->querryStatus){
|
||||
return [false,"分享不存在,请检查链接是否正确"];
|
||||
}
|
||||
return[true,null];
|
||||
}
|
||||
|
||||
public function Download($user){
|
||||
$checkStatus = $this->checkSession($user);
|
||||
if(!$checkStatus[0]){
|
||||
return [$checkStatus[0],$checkStatus[1]];
|
||||
}
|
||||
$reqPath = Db::name('files')->where('id',$this->shareData["source_name"])->find();
|
||||
if($reqPath["dir"] == "/"){
|
||||
$reqPath["dir"] = $reqPath["dir"].$reqPath["orign_name"];
|
||||
}else{
|
||||
$reqPath["dir"] = $reqPath["dir"]."/".$reqPath["orign_name"];
|
||||
}
|
||||
$fileObj = new FileManage($reqPath["dir"],$this->shareData["owner"]);
|
||||
$FileHandler = $fileObj->Download();
|
||||
return $FileHandler;
|
||||
}
|
||||
|
||||
public function DownloadFolder($user,$path){
|
||||
$checkStatus = $this->checkSession($user);
|
||||
if(!$checkStatus[0]){
|
||||
return [$checkStatus[0],$checkStatus[1]];
|
||||
}
|
||||
$reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find();
|
||||
$path = $path == "/"?"":$path;
|
||||
$fileObj = new FileManage($reqPath["position_absolute"].$path,$this->shareData["owner"]);
|
||||
$this->numIncrease("download_num");
|
||||
$FileHandler = $fileObj->Download();
|
||||
return $FileHandler;
|
||||
}
|
||||
|
||||
public function ListFile($path){
|
||||
if($this->lockStatus){
|
||||
die('{ "result": { "success": false, "error": "会话过期,请重新登陆" } }');
|
||||
}
|
||||
if(!$this->querryStatus){
|
||||
return [false,"分享不存在,请检查链接是否正确"];
|
||||
}
|
||||
$reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find();
|
||||
$path = $path == "/"?"":$path;
|
||||
return FileManage::ListFile($this->shareData["source_name"].$path,$this->shareData["owner"],true,$this->shareData["source_name"]);
|
||||
}
|
||||
|
||||
public function Preview($user){
|
||||
$checkStatus = $this->checkSession($user);
|
||||
if(!$checkStatus[0]){
|
||||
return [$checkStatus[0],$checkStatus[1]];
|
||||
}
|
||||
$reqPath = Db::name('files')->where('id',$this->shareData["source_name"])->find();
|
||||
if($reqPath["dir"] == "/"){
|
||||
$reqPath["dir"] = $reqPath["dir"].$reqPath["orign_name"];
|
||||
}else{
|
||||
$reqPath["dir"] = $reqPath["dir"]."/".$reqPath["orign_name"];
|
||||
}
|
||||
$fileObj = new FileManage($reqPath["dir"],$this->shareData["owner"]);
|
||||
return $fileObj->PreviewHandler();
|
||||
}
|
||||
|
||||
public function PreviewFolder($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->PreviewHandler();
|
||||
}
|
||||
|
||||
public function listPic($id,$path){
|
||||
if($this->lockStatus){
|
||||
die('{ "result": { "success": false, "error": "会话过期,请重新登陆" } }');
|
||||
}
|
||||
if(!$this->querryStatus){
|
||||
return [false,"分享不存在,请检查链接是否正确"];
|
||||
}
|
||||
$reqPath = Db::name('folders')->where('position_absolute',$this->shareData["source_name"])->find();
|
||||
$path = $path == "/"?"":$path;
|
||||
return FileManage::listPic($this->shareData["source_name"].$path,$this->shareData["owner"],"/Share/Preview/".$this->shareData["share_key"]."?folder=true");
|
||||
}
|
||||
|
||||
public function numIncrease($name){
|
||||
Db::name('shares')->where('share_key',$this->shareData["share_key"])->setInc($name);
|
||||
}
|
||||
|
||||
public function getDownloadUrl($user){
|
||||
if(Option::getValue("allowdVisitorDownload") == "false" && !$user->loginStatus){
|
||||
return array(
|
||||
"error" => 1,
|
||||
"msg" => "未登录用户禁止下载,请先登录",
|
||||
);
|
||||
}else{
|
||||
$this->numIncrease("download_num");
|
||||
return array(
|
||||
"error" => 0,
|
||||
"result" => "/Share/Download/".$this->shareData["share_key"],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function fileShareHandler(){
|
||||
$this->shareOwner = new User($this->shareData["owner"],null,true);
|
||||
$this->fileData = Db::name('files')
|
||||
->where('upload_user',$this->shareData["owner"])
|
||||
->where('id',(int)$this->shareData["source_name"])
|
||||
->find();
|
||||
if(!$this->shareOwner->loginStatus || empty($this->fileData)){
|
||||
$this->querryStatus = false;
|
||||
}else{
|
||||
$this->querryStatus = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function dirShareHandler(){
|
||||
$this->shareOwner = new User($this->shareData["owner"],null,true);
|
||||
$this->dirData = Db::name('folders')
|
||||
->where('owner',$this->shareData["owner"])
|
||||
->where('position_absolute',$this->shareData["source_name"])
|
||||
->find();
|
||||
if(!$this->shareOwner->loginStatus || empty($this->dirData)){
|
||||
$this->querryStatus = false;
|
||||
}else{
|
||||
$this->querryStatus = true;
|
||||
}
|
||||
}
|
||||
|
||||
static function createShare($fname,$type,$pwd,$user,$group){
|
||||
if(!$group["allow_share"]){
|
||||
self::setError("您当前的用户组无权分享文件");
|
||||
}
|
||||
$path = FileManage::getFileName($fname)[1];
|
||||
$fnameTmp = FileManage::getFileName($fname)[0];
|
||||
$fileRecord = Db::name('files')->where('upload_user',$user["id"])->where('orign_name',$fnameTmp)->where('dir',$path)->find();
|
||||
if(empty($fileRecord)){
|
||||
self::createDirShare($fname,$type,$pwd,$user,$group);
|
||||
}else{
|
||||
self::createFileShare($fileRecord,$type,$pwd,$user,$group);
|
||||
}
|
||||
}
|
||||
|
||||
static function setError($text){
|
||||
die('{ "result": { "success": false, "error": "'.$text.'" } }');
|
||||
}
|
||||
|
||||
static function setSuccess($text){
|
||||
die('{ "result": "'.$text.'" }');
|
||||
}
|
||||
|
||||
static function createDirShare($fname,$type,$pwd,$user,$group){
|
||||
$dirRecord = Db::name('folders')->where('owner',$user["id"])->where('position_absolute',$fname)->find();
|
||||
if(empty($dirRecord)){
|
||||
self::setError("目录不存在");
|
||||
}
|
||||
$shareKey = self::getRandomKey(8);
|
||||
$sharePwd = $type=="public" ? "0" : $pwd;
|
||||
$SQLData = [
|
||||
'type' => $type=="public" ? "public" : "private",
|
||||
'share_time' => date("Y-m-d H:i:s"),
|
||||
'owner' => $user["id"],
|
||||
'source_name' => $fname,
|
||||
'origin_name' => $fname,
|
||||
'download_num' => 0,
|
||||
'view_num' => 0,
|
||||
'source_type' => "dir",
|
||||
'share_key' => $shareKey,
|
||||
'share_pwd' => $sharePwd,
|
||||
];
|
||||
if(Db::name('shares')->insert($SQLData)){
|
||||
if($sharePwd == "0"){
|
||||
self::setSuccess(Option::getValue("siteURL")."s/".$shareKey);
|
||||
}else{
|
||||
self::setSuccess("链接:".Option::getValue("siteURL")."s/".$shareKey." 密码:".$sharePwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function createFileShare($file,$type,$pwd,$user,$group){
|
||||
$shareKey = self::getRandomKey(8);
|
||||
$sharePwd = $type=="public" ? "0" : $pwd;
|
||||
$SQLData = [
|
||||
'type' => $type=="public" ? "public" : "private",
|
||||
'share_time' => date("Y-m-d H:i:s"),
|
||||
'owner' => $user["id"],
|
||||
'source_name' => $file["id"],
|
||||
'origin_name' => $file["orign_name"],
|
||||
'download_num' => 0,
|
||||
'view_num' => 0,
|
||||
'source_type' => "file",
|
||||
'share_key' => $shareKey,
|
||||
'share_pwd' => $sharePwd,
|
||||
];
|
||||
if(Db::name('shares')->insert($SQLData)){
|
||||
if($sharePwd == "0"){
|
||||
self::setSuccess(Option::getValue("siteURL")."s/".$shareKey);
|
||||
}else{
|
||||
self::setSuccess("链接:".Option::getValue("siteURL")."s/".$shareKey." 密码:".$sharePwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function getRandomKey($length = 16){
|
||||
$charTable = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||
$result = "";
|
||||
for ( $i = 0; $i < $length; $i++ ){
|
||||
$result .= $charTable[ mt_rand(0, strlen($charTable) - 1) ];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -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"]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
class Thumb extends Model{
|
||||
|
||||
private $file; //图片地址
|
||||
private $width; //图片长度
|
||||
private $height; //图片长度
|
||||
private $img_type; //图片类型
|
||||
private $img; //原图的资源句柄
|
||||
private $new; //新图的资源句柄
|
||||
|
||||
//构造方法,初始化
|
||||
public function __construct($_file) {
|
||||
$this->file = $_file;
|
||||
list($this->width, $this->height, $this->img_type) = getimagesize($this->file);
|
||||
$this->img = $this->getFromImg($this->file, $this->img_type);
|
||||
}
|
||||
//缩略图(固定长高容器,图像等比例,扩容填充,裁剪)[固定了大小,不失真,不变形]
|
||||
public function thumb($new_width = 0,$new_height = 0) {
|
||||
|
||||
if (empty($new_width) && empty($new_height)) {
|
||||
$new_width = $this->width;
|
||||
$new_height = $this->height;
|
||||
}
|
||||
|
||||
if (!is_numeric($new_width) || !is_numeric($new_height)) {
|
||||
$new_width = $this->width;
|
||||
$new_height = $this->height;
|
||||
}
|
||||
|
||||
//创建一个容器
|
||||
$_n_w = $new_width;
|
||||
$_n_h = $new_height;
|
||||
|
||||
//创建裁剪点
|
||||
$_cut_width = 0;
|
||||
$_cut_height = 0;
|
||||
|
||||
if ($this->width < $this->height) {
|
||||
$new_width = ($new_height / $this->height) * $this->width;
|
||||
} else {
|
||||
$new_height = ($new_width / $this->width) * $this->height;
|
||||
}
|
||||
if ($new_width < $_n_w) { //如果新高度小于新容器高度
|
||||
$r = $_n_w / $new_width; //按长度求出等比例因子
|
||||
$new_width *= $r; //扩展填充后的长度
|
||||
$new_height *= $r; //扩展填充后的高度
|
||||
$_cut_height = ($new_height - $_n_h) / 2; //求出裁剪点的高度
|
||||
}
|
||||
|
||||
if ($new_height < $_n_h) { //如果新高度小于容器高度
|
||||
$r = $_n_h / $new_height; //按高度求出等比例因子
|
||||
$new_width *= $r; //扩展填充后的长度
|
||||
$new_height *= $r; //扩展填充后的高度
|
||||
$_cut_width = ($new_width - $_n_w) / 2; //求出裁剪点的长度
|
||||
}
|
||||
|
||||
$this->new = imagecreatetruecolor($_n_w,$_n_h);
|
||||
imagecopyresampled($this->new,$this->img,0,0,$_cut_width,$_cut_height,$new_width,$new_height,$this->width,$this->height);
|
||||
}
|
||||
|
||||
//加载图片,各种类型,返回图片的资源句柄
|
||||
private function getFromImg($_file, $_type) {
|
||||
switch ($_type) {
|
||||
case 1 :
|
||||
$img = imagecreatefromgif($_file);
|
||||
break;
|
||||
case 2 :
|
||||
$img = imagecreatefromjpeg($_file);
|
||||
break;
|
||||
case 3 :
|
||||
$img = imagecreatefrompng($_file);
|
||||
break;
|
||||
default:
|
||||
$img = '';
|
||||
}
|
||||
return $img;
|
||||
}
|
||||
|
||||
//图像输出
|
||||
public function out($name) {
|
||||
imagepng($this->new,$name);//第二个参数为新生成的图片名
|
||||
imagedestroy($this->img);
|
||||
imagedestroy($this->new);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use \think\Session;
|
||||
use \PHPGangsta_GoogleAuthenticator;
|
||||
use \Endroid\QrCode\QrCode;
|
||||
use \app\index\model\Option;
|
||||
|
||||
class TwoFactor extends Model{
|
||||
|
||||
public $ga;
|
||||
public $secretKey;
|
||||
public $checkResult;
|
||||
|
||||
public function __construct(){
|
||||
$this->ga = new PHPGangsta_GoogleAuthenticator();
|
||||
}
|
||||
|
||||
public function qrcodeRender(){
|
||||
ob_end_clean();
|
||||
$this->secretKey = $this->ga->createSecret();
|
||||
session("two_factor_enable",$this->secretKey);
|
||||
$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)){
|
||||
return [0,"验证码不能为空"];
|
||||
}
|
||||
if(empty($key)){
|
||||
return [0,"二维码过期,请刷新页面后重新扫描"];
|
||||
}
|
||||
$this->checkResult = $this->ga->verifyCode($key, $code, 2);
|
||||
if($this->checkResult){
|
||||
return [1,"验证成功"];
|
||||
}else{
|
||||
return [0,"验证码错误"];
|
||||
}
|
||||
}
|
||||
|
||||
public function bindUser($uid){
|
||||
Db::name("users")->where("id",$uid)->update(["two_step" => $this->secretKey]);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,572 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
require_once 'extend/Qiniu/functions.php';
|
||||
|
||||
use think\Model;
|
||||
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{
|
||||
|
||||
public $policyId;
|
||||
public $policyContent;
|
||||
public $userId;
|
||||
public $chunkData;
|
||||
public $fileSizeTmp;
|
||||
public $ossToken;
|
||||
public $ossSign;
|
||||
public $ossCallback;
|
||||
public $ossAccessId;
|
||||
public $ossFileName;
|
||||
public $ossCallBack;
|
||||
public $upyunPolicy;
|
||||
public $s3Policy;
|
||||
public $s3Sign;
|
||||
public $dirName;
|
||||
public $s3Credential;
|
||||
public $siteUrl;
|
||||
public $callBackKey;
|
||||
|
||||
public function __construct($id,$uid){
|
||||
$this->policyId = $id;
|
||||
$this->userId = $uid;
|
||||
$this->policyContent = Db::name('policy')->where('id',$id)->find();
|
||||
}
|
||||
|
||||
public function setChunk($chunkId,$chunkSum,$file){
|
||||
$sqlData = [
|
||||
'user' => $this->userId,
|
||||
'ctx' => self::getRandomKey(),
|
||||
'obj_name' => self::getRandomKey(8),
|
||||
'time' => date("Y-m-d H:i:s"),
|
||||
'chunk_id' => $chunkId,
|
||||
'sum' => $chunkSum,
|
||||
];
|
||||
$this->chunkData = $sqlData;
|
||||
Db::name('chunks')->insert($sqlData);
|
||||
$this->saveChunk($file);
|
||||
$this->chunkInfo();
|
||||
}
|
||||
|
||||
public function saveChunk($file){
|
||||
$chunkSize = strlen($file);
|
||||
if(!FileManage::sotrageCheck($this->userId,$chunkSize)){
|
||||
$this->setError("空间容量不足",false);
|
||||
}
|
||||
FileManage::storageCheckOut($this->userId,$chunkSize);
|
||||
if($chunkSize >config('upload.chunk_size')){
|
||||
$this->setError("分片错误",false);
|
||||
}
|
||||
$chunkObj=fopen (ROOT_PATH . 'public/uploads/chunks/'.$this->chunkData["obj_name"].".chunk","w+");
|
||||
$chunkObjWrite = fwrite ($chunkObj,$file);
|
||||
if(!$chunkObj || !$chunkObjWrite){
|
||||
$this->setError("分片创建错误",false);
|
||||
}
|
||||
}
|
||||
|
||||
public function chunkInfo(){
|
||||
$returnJson = array(
|
||||
"ctx" => $this->chunkData["ctx"],
|
||||
);
|
||||
echo json_encode($returnJson);
|
||||
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 = 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']){
|
||||
$fileName = $this->getObjName($this->policyContent['namerule'],"local",$fname).".".$fileSuffix;
|
||||
}else{
|
||||
$fileName = $fname;
|
||||
}
|
||||
$generatePath = $this->getDirName($this->policyContent['dirrule']);
|
||||
$savePath = ROOT_PATH . 'public/uploads/'.$generatePath;
|
||||
is_dir($savePath)? :mkdir($savePath,0777,true);
|
||||
if(file_exists($savePath.DS.$fileName)){
|
||||
$this->setError("文件重名",true,$file,ROOT_PATH . 'public/uploads/chunks/');
|
||||
}
|
||||
if($this->policyContent["policy_type"] == "onedrive"){
|
||||
if($path == "ROOTDIR"){
|
||||
$path = "";
|
||||
}
|
||||
$task = new Task();
|
||||
$task->taskName = "Upload Big File " . $fname . " to Onedrive";
|
||||
$task->taskType = "uploadChunksToOnedrive";
|
||||
$task->taskContent = json_encode([
|
||||
"path" => $path,
|
||||
"fname" => $fname,
|
||||
"objname" => $fileName,
|
||||
"savePath" => $generatePath,
|
||||
"fsize" => $this->fileSizeTmp,
|
||||
"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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)));
|
||||
$sufficCheck = !in_array($fileSuffix,$allowedSuffix);
|
||||
if(empty(self::getAllowedExt(json_decode($this->policyContent["filetype"],true)))){
|
||||
$sufficCheck = false;
|
||||
}
|
||||
if(($fileSize >= (int)$this->policyContent["max_size"]) || $sufficCheck){
|
||||
FileManage::storageGiveBack($this->userId,$fileSize);
|
||||
$this->setError("文件效验失败",true,$file,ROOT_PATH . 'public/uploads/chunks/');
|
||||
}
|
||||
$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+");
|
||||
$deleteList=[];
|
||||
foreach ($fname as $key => $value) {
|
||||
$chunkObj = fopen(ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk", "rb");
|
||||
if(!$fileObj || !$chunkObj){
|
||||
$this->setError("文件创建失败",false);
|
||||
}
|
||||
$content = fread($chunkObj, config('upload.chunk_size'));
|
||||
fwrite($fileObj, $content, config('upload.chunk_size'));
|
||||
unset($content);
|
||||
fclose($chunkObj);
|
||||
unlink(ROOT_PATH . 'public/uploads/chunks/'.$value["obj_name"].".chunk");
|
||||
array_push($deleteList, $value["id"]);
|
||||
}
|
||||
$chunks = Db::name('chunks')->where([
|
||||
'id' => ["in",$deleteList],
|
||||
])->delete();
|
||||
return $fileName;
|
||||
}
|
||||
|
||||
public function fileReceive($file,$info){
|
||||
$allowedExt = self::getAllowedExt(json_decode($this->policyContent["filetype"],true));
|
||||
$filter = array('size'=>(int)$this->policyContent["max_size"]);
|
||||
if(!empty($allowedExt)){
|
||||
$filter = array_merge($filter,array("ext" => $allowedExt));
|
||||
}
|
||||
if(!FileManage::sotrageCheck($this->userId,$file->getInfo('size'))){
|
||||
$this->setError("空间容量不足",false);
|
||||
}
|
||||
if($this->policyContent['autoname']){
|
||||
$fileName = $this->getObjName($this->policyContent['namerule'],"local",$file->getInfo('name'));
|
||||
}else{
|
||||
$fileName = $file->getInfo('name');
|
||||
}
|
||||
$generatePath = $this->getDirName($this->policyContent['dirrule']);
|
||||
$savePath = ROOT_PATH . 'public/uploads/'.$generatePath;
|
||||
$Uploadinfo = $file
|
||||
->validate($filter)
|
||||
->move($savePath,$fileName,false);
|
||||
if($Uploadinfo){
|
||||
$jsonData = array(
|
||||
"path" => $info["path"],
|
||||
"fname" => $info["name"],
|
||||
"objname" => $generatePath."/".$Uploadinfo->getSaveName(),
|
||||
"fsize" => $Uploadinfo->getSize(),
|
||||
);
|
||||
@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{
|
||||
header("HTTP/1.1 401 Unauthorized");
|
||||
echo json_encode(array("error" => $file->getError()));
|
||||
}
|
||||
}
|
||||
|
||||
public function setError($text,$delete = false,$fname="",$path=""){
|
||||
header("HTTP/1.1 401 Unauthorized");
|
||||
if($delete){
|
||||
unlink(rtrim($path, DS).DS.$fname);
|
||||
}
|
||||
die(json_encode(["error"=> $text]));
|
||||
}
|
||||
|
||||
static function getAllowedExt($ext){
|
||||
$returnValue = "";
|
||||
foreach ($ext as $key => $value) {
|
||||
$returnValue .= $value["ext"].",";
|
||||
}
|
||||
return rtrim($returnValue, ",");
|
||||
}
|
||||
|
||||
public function getToken(){
|
||||
switch ($this->policyContent['policy_type']) {
|
||||
case 'qiniu':
|
||||
return $this->getQiniuToken();
|
||||
break;
|
||||
case 'local':
|
||||
return $this->getLocalToken();
|
||||
break;
|
||||
case 'onedrive':
|
||||
return 'nazGTT91tboaLWBC549$:tHSsNyTBxoV4HDfELJeKH1EUmEY=:eyJjYWxsYmFja0JvZHkiOiJ7XCJwYXRoXCI6XCJcIn0iLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb25cL2pzb24iLCJzY29wZSI6ImMxNjMyMTc3LTQ4NGEtNGU1OS1hZDBhLWUwNDc4ZjZhY2NjZSIsImRlYWRsaW5lIjoxNTM2ODMxOTEwfQ==';
|
||||
break;
|
||||
case 'oss':
|
||||
return $this->getOssToken();
|
||||
break;
|
||||
case 'upyun':
|
||||
return $this->getUpyunToken();
|
||||
break;
|
||||
case 's3':
|
||||
return $this->getS3Token();
|
||||
break;
|
||||
case 'remote':
|
||||
return $this->getRemoteToken();
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function getObjName($expression,$type = "qiniu",$origin = ""){
|
||||
$policy = array(
|
||||
'{date}' =>date("Ymd"),
|
||||
'{datetime}' =>date("YmdHis"),
|
||||
'{uid}' =>$this->userId,
|
||||
'{timestamp}' =>time(),
|
||||
'{randomkey16}' =>self::getRandomKey(16),
|
||||
'{randomkey8}' =>self::getRandomKey(8),
|
||||
);
|
||||
if($type == "qiniu"){
|
||||
$policy = array_merge($policy,array("{originname}" => "$(fname)"));
|
||||
}else if($type == "local"){
|
||||
$policy = array_merge($policy,array("{originname}" => $origin));
|
||||
}else if ($type="oss"){
|
||||
$policy = array_merge($policy,array("{originname}" => '${filename}'));
|
||||
}else if ($type="upyun"){
|
||||
$policy = array_merge($policy,array("{originname}" => '{filename}{.suffix}'));
|
||||
}
|
||||
return strtr($expression,$policy);
|
||||
}
|
||||
|
||||
public function getDirName($expression){
|
||||
$policy = array(
|
||||
'{date}' =>date("Ymd"),
|
||||
'{datetime}' =>date("YmdHis"),
|
||||
'{uid}' =>$this->userId,
|
||||
'{timestamp}' =>time(),
|
||||
'{randomkey16}' =>self::getRandomKey(16),
|
||||
'{randomkey8}' =>self::getRandomKey(8),
|
||||
);
|
||||
return trim(strtr($expression,$policy),"/");
|
||||
}
|
||||
|
||||
public function getQiniuToken(){
|
||||
$callbackKey = $this->getRandomKey();
|
||||
$sqlData = [
|
||||
'callback_key' => $callbackKey,
|
||||
'pid' => $this->policyId,
|
||||
'uid' => $this->userId
|
||||
];
|
||||
Db::name('callback')->insert($sqlData);
|
||||
$auth = new Auth($this->policyContent['ak'], $this->policyContent['sk']);
|
||||
$policy = array(
|
||||
'callbackUrl' =>Option::getValue("siteURL").'Callback/Qiniu',
|
||||
'callbackBody' => '{"fname":"$(fname)","objname":"$(key)","fsize":"$(fsize)","callbackkey":"'.$callbackKey.'","path":"$(x:path)","picinfo":"$(imageInfo.width),$(imageInfo.height)"}',
|
||||
'callbackBodyType' => 'application/json',
|
||||
'fsizeLimit' => (int)$this->policyContent['max_size'],
|
||||
);
|
||||
$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']));
|
||||
}
|
||||
$token = $auth->uploadToken($this->policyContent['bucketname'], null, 3600, $policy);
|
||||
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){
|
||||
if ($v){
|
||||
$elems[] = $v;
|
||||
}
|
||||
}
|
||||
$value = implode('&', $elems);
|
||||
$sign = base64_encode(hash_hmac('sha1', $value, $secret, true));
|
||||
return 'UPYUN ' . $key . ':' . $sign;
|
||||
}
|
||||
|
||||
|
||||
public function getUpyunToken(){
|
||||
$callbackKey = $this->getRandomKey();
|
||||
$sqlData = [
|
||||
'callback_key' => $callbackKey,
|
||||
'pid' => $this->policyId,
|
||||
'uid' => $this->userId
|
||||
];
|
||||
Db::name('callback')->insert($sqlData);
|
||||
$options = Option::getValues(["oss","basic"]);
|
||||
$dateNow = gmdate('D, d M Y H:i:s \G\M\T');
|
||||
$policy=[
|
||||
"bucket" => $this->policyContent['bucketname'],
|
||||
"expiration" => time()+$options["timeout"],
|
||||
"notify-url" => $options["siteURL"]."Callback/Upyun",
|
||||
"content-length-range" =>"0,".$this->policyContent['max_size'],
|
||||
"date" => $dateNow,
|
||||
"ext-param"=>json_encode([
|
||||
"path"=>cookie("path"),
|
||||
"uid" => $this->userId,
|
||||
"pid" => $this->policyId,
|
||||
]),
|
||||
];
|
||||
$allowedExt = self::getAllowedExt(json_decode($this->policyContent["filetype"],true));
|
||||
if(!empty($allowedExt)){
|
||||
$policy = array_merge($policy,array("allow-file-type" => $allowedExt));
|
||||
}
|
||||
$dirName = $this->getObjName($this->policyContent['dirrule']);
|
||||
$policy = array_merge($policy,array("save-key" => $dirName.(empty($dirName)?"":"/").uniqid()."CLSUFF{filename}{.suffix}"));
|
||||
$this->upyunPolicy = base64_encode(json_encode($policy));
|
||||
return self::upyunSign($this->policyContent['op_name'], md5($this->policyContent['op_pwd']), "POST", "/".$this->policyContent['bucketname'],$dateNow,$this->upyunPolicy);
|
||||
}
|
||||
|
||||
public function ossCallback(){
|
||||
$callbackKey = $this->getRandomKey();
|
||||
$sqlData = [
|
||||
'callback_key' => $callbackKey,
|
||||
'pid' => $this->policyId,
|
||||
'uid' => $this->userId
|
||||
];
|
||||
Db::name('callback')->insert($sqlData);
|
||||
$returnValue["callbackUrl"] = Option::getValue("siteUrl").'Callback/Oss';
|
||||
$returnValue["callbackBody"] = '{"fname":"${x:fname}","objname":"${object}","fsize":"${size}","callbackkey":"'.$callbackKey.'","path":"${x:path}","picinfo":"${imageInfo.width},${imageInfo.height}"}';
|
||||
$this->ossCallBack = base64_encode(json_encode($returnValue));
|
||||
return base64_encode(json_encode($returnValue));
|
||||
}
|
||||
|
||||
public function getS3Token(){
|
||||
$dirName = $this->getDirName($this->policyContent['dirrule']);
|
||||
$longDate = gmdate('Ymd\THis\Z');
|
||||
$shortDate = gmdate('Ymd');
|
||||
$credential = $this->policyContent['ak'] . '/' . $shortDate . '/' . $this->policyContent['op_name'] . '/s3/aws4_request';
|
||||
$callbackKey = $this->getRandomKey();
|
||||
$sqlData = [
|
||||
'callback_key' => $callbackKey,
|
||||
'pid' => $this->policyId,
|
||||
'uid' => $this->userId
|
||||
];
|
||||
Db::name('callback')->insert($sqlData);
|
||||
$this->siteUrl = Option::getValue("siteUrl");
|
||||
$returnValue = [
|
||||
"expiration" => date("Y-m-d",time()+1800)."T".date("H:i:s",time()+1800).".000Z",
|
||||
"conditions" => [
|
||||
0 => ["bucket" => $this->policyContent['bucketname']],
|
||||
1 => ["starts-with",'$key', $dirName],
|
||||
2 => ["starts-with",'$success_action_redirect' ,$this->siteUrl."Callback/S3/key/".$callbackKey],
|
||||
3 => ["content-length-range",1,(int)$this->policyContent['max_size']],
|
||||
4 => ['x-amz-algorithm' => 'AWS4-HMAC-SHA256'],
|
||||
5 => ['x-amz-credential' => $credential],
|
||||
6 => ['x-amz-date' => $longDate],
|
||||
7 => ["starts-with", '$name', ""],
|
||||
8 => ["starts-with", '$Content-Type', ""],
|
||||
]
|
||||
];
|
||||
$this->s3Policy = base64_encode(json_encode($returnValue));
|
||||
$signingKey = hash_hmac("sha256",$shortDate,"AWS4".$this->policyContent['sk'],true);
|
||||
$signingKey = hash_hmac("sha256",$this->policyContent['op_name'],$signingKey,true);
|
||||
$signingKey = hash_hmac("sha256","s3",$signingKey,true);
|
||||
$signingKey = hash_hmac("sha256","aws4_request",$signingKey,true);
|
||||
$signingKey = hash_hmac("sha256",$this->s3Policy,$signingKey);
|
||||
$this->s3Sign = $signingKey;
|
||||
$this->dirName = $dirName;
|
||||
$this->s3Credential = $credential;
|
||||
$this->x_amz_date = $longDate;
|
||||
$this->callBackKey = $callbackKey;
|
||||
}
|
||||
|
||||
public function getOssToken(){
|
||||
$dirName = $this->getObjName($this->policyContent['dirrule']);
|
||||
$returnValu["expiration"] = date("Y-m-d",time()+1800)."T".date("H:i:s",time()+1800).".000Z";
|
||||
$returnValu["conditions"][0]["bucket"] = $this->policyContent['bucketname'];
|
||||
$returnValu["conditions"][1][0]="starts-with";
|
||||
$returnValu["conditions"][1][1]='$key';
|
||||
if($this->policyContent["autoname"]){
|
||||
$this->ossFileName = $dirName.(empty($dirName)?"":"/").$this->getObjName($this->policyContent['namerule'],"oss");;
|
||||
}else{
|
||||
$this->ossFileName = $dirName.(empty($dirName)?"":"/").'${filename}';
|
||||
}
|
||||
$returnValu["conditions"][1][2]=$dirName.(empty($dirName)?"":"/");
|
||||
$returnValu["conditions"][2]=["content-length-range",1,(int)$this->policyContent['max_size']];
|
||||
$returnValu["conditions"][3]["callback"] = $this->ossCallback();
|
||||
$this->ossToken=base64_encode(json_encode($returnValu));
|
||||
$this->ossSignToken();
|
||||
$this->ossAccessId = $this->policyContent['ak'];
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ossSignToken(){
|
||||
$this->ossSign = base64_encode(hash_hmac("sha1", $this->ossToken, $this->policyContent['sk'],true));
|
||||
}
|
||||
|
||||
public function getLocalToken(){
|
||||
$auth = new Auth($this->policyContent['ak'], $this->policyContent['sk']);
|
||||
$policy = array(
|
||||
'callbackBody' => '{"path":"'.cookie('path').'"}',
|
||||
'callbackBodyType' => 'application/json',
|
||||
);
|
||||
$token = $auth->uploadToken($this->policyContent['bucketname'], null, 3600, $policy);
|
||||
return $token;
|
||||
}
|
||||
|
||||
static function getRandomKey($length = 16){
|
||||
$charTable = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$result = "";
|
||||
for ( $i = 0; $i < $length; $i++ ){
|
||||
$result .= $charTable[ mt_rand(0, strlen($charTable) - 1) ];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
static function b64Decode($string) {
|
||||
$data = str_replace(array('-','_'),array('+','/'),$string);
|
||||
$mod4 = strlen($data) % 4;
|
||||
if ($mod4) {
|
||||
$data .= substr('====', $mod4);
|
||||
}
|
||||
return base64_decode($data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,381 @@
|
||||
<?php
|
||||
namespace app\index\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
use \app\index\model\Option;
|
||||
use \app\index\model\Mail;
|
||||
use think\Validate;
|
||||
|
||||
class User extends Model{
|
||||
|
||||
public $uid;
|
||||
public $varifyKey;
|
||||
public $groupId;
|
||||
public $regDate;
|
||||
public $loginStatus = false;
|
||||
public $userNick;
|
||||
public $userMail;
|
||||
public $groupData;
|
||||
public $userSQLData;
|
||||
|
||||
/**
|
||||
* [__construct description]
|
||||
* @param [type] $userId [description]
|
||||
* @param [type] $userKey [description]
|
||||
*/
|
||||
public function __construct($userId,$userKey,$ignoreLogin = false){
|
||||
$userData = Db::name('users')->where('id',$userId)->where('user_status',0)->find();
|
||||
if(empty($userData)){
|
||||
$this->loginStatus = false;
|
||||
$this->setUser();
|
||||
return false;
|
||||
}
|
||||
if(!$ignoreLogin){
|
||||
if(md5($userData['user_email'].$userData['user_pass'].config('salt')) != $userKey){
|
||||
$this->loginStatus = false;
|
||||
$this->setUser();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$this->groupData = Db::name('groups')->where('id',$userData['user_group'])->find();
|
||||
$this->loginStatus = true;
|
||||
$this->uid = $userId;
|
||||
$this->groupId = $userData['user_group'];
|
||||
$this->regDate = $userData['user_date'];
|
||||
$this->userNick = $userData['user_nick'];
|
||||
$this->userMail = $userData['user_email'];
|
||||
$this->varifyKey = $userKey;
|
||||
$this->userSQLData = $userData;
|
||||
}
|
||||
|
||||
|
||||
public function setUser(){
|
||||
$this->groupData = Db::name('groups')->where('id',2)->find();
|
||||
$this->uid = -1;
|
||||
}
|
||||
|
||||
static function resetPwd($key,$pwd){
|
||||
$key = explode("_",$key);
|
||||
$resetKey = $key[0]."_".$key[1];
|
||||
$userId = $key[2];
|
||||
$keyCheck = self::resetUser($resetKey,$userId);
|
||||
if(!$keyCheck[0]){
|
||||
return $keyCheck;
|
||||
}else{
|
||||
if ((mb_strlen($pwd,'UTF8')>64) || (mb_strlen($pwd,'UTF8')<4)){
|
||||
return [false,"密码不符合规范"];
|
||||
}
|
||||
self::Reset($userId,$pwd);
|
||||
return [true,"密码重设成功"];
|
||||
}
|
||||
}
|
||||
|
||||
static function Reset($uid,$pwd){
|
||||
Db::name('users')->where('id',$uid)
|
||||
->update([
|
||||
'user_pass' => md5(config('salt').$pwd),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* [register description]
|
||||
* @param [type] $userEmail [description]
|
||||
* @param [type] $userPass [description]
|
||||
* @return [type] [description]
|
||||
*/
|
||||
static function register($userEmail,$userPass,$captchaCode){
|
||||
if(Option::getValue("reg_captcha")=="1"){
|
||||
if(!self::checkCaptcha($captchaCode)){
|
||||
return [false,"验证码错误"];
|
||||
}
|
||||
}
|
||||
if (\app\index\model\Option::getValue("regStatus") == '1'){
|
||||
return [false,"当前站点关闭注册"];
|
||||
}
|
||||
$userName = str_replace(" ", "", $userEmail);
|
||||
$passWord = $userPass;
|
||||
if ( !filter_var($userName,FILTER_VALIDATE_EMAIL) || (mb_strlen($userName,'UTF8')>32) || (mb_strlen($userName,'UTF8')<4) || (mb_strlen($passWord,'UTF8')>64) || (mb_strlen($passWord,'UTF8')<4)){
|
||||
return [false,"邮箱或密码不符合规范"];
|
||||
}
|
||||
if(Db::name('users')->where('user_email',$userName)->find() !=null){
|
||||
return [false,"该邮箱已被注册"];
|
||||
}
|
||||
$defaultGroup = (int)\app\index\model\Option::getValue("defaultGroup");
|
||||
$regOptions = Option::getValues(["register"]);
|
||||
if($regOptions["email_active"] == "1"){
|
||||
$activationKey = md5(uniqid(rand(), TRUE));
|
||||
$userStatus = 1;
|
||||
}else{
|
||||
$activationKey = "n";
|
||||
$userStatus = 0;
|
||||
}
|
||||
$sqlData = [
|
||||
'user_email' => $userName,
|
||||
'user_pass' => md5(config('salt').$passWord),
|
||||
'user_status' => $userStatus,
|
||||
'user_group' => $defaultGroup,
|
||||
'group_primary' => 0,
|
||||
'user_date' => date("Y-m-d H:i:s"),
|
||||
'user_nick' => explode("@",$userName)[0],
|
||||
'user_activation_key' => $activationKey,
|
||||
'used_storage' => 0,
|
||||
'two_step'=>"0",
|
||||
'webdav_key' =>md5(config('salt').$passWord),
|
||||
'delay_time' =>0,
|
||||
'avatar' => "default",
|
||||
'profile' => true,
|
||||
'options' => "{}",
|
||||
];
|
||||
if(Db::name('users')->insert($sqlData)){
|
||||
$userId = Db::name('users')->getLastInsID();
|
||||
Db::name('folders')->insert( [
|
||||
'folder_name' => '根目录',
|
||||
'parent_folder' => 0,
|
||||
'position' => '.',
|
||||
'owner' => $userId,
|
||||
'date' => date("Y-m-d H:i:s"),
|
||||
'position_absolute' => '/',
|
||||
]);
|
||||
if($regOptions["email_active"] == "1"){
|
||||
$options = Option::getValues(["basic","mail_template"]);
|
||||
$replace = array(
|
||||
'{siteTitle}' =>$options["siteName"],
|
||||
'{userName}' =>explode("@",$userName)[0],
|
||||
'{siteUrl}' =>$options["siteURL"],
|
||||
'{siteSecTitle}' =>$options["siteTitle"],
|
||||
'{activationUrl}' =>$options["siteURL"]."Member/emailActivate/".$activationKey,
|
||||
);
|
||||
$mailContent = strtr($options["mail_activation_template"],$replace);
|
||||
$mailObj = new Mail();
|
||||
$mailObj->Send($userName,explode("@",$userName)[0],"【".$options["siteName"]."】"."注册激活",$mailContent);
|
||||
return [true,"ec"];
|
||||
}
|
||||
return [true,"注册成功"];
|
||||
}
|
||||
}
|
||||
|
||||
static function activicateUser($key){
|
||||
$userData = Db::name('users')
|
||||
->where('user_activation_key','neq','n')
|
||||
->where("user_activation_key",$key)->find();
|
||||
if(empty($userData)){
|
||||
return [0,"激活失败,用户在不存在"];
|
||||
}else{
|
||||
Db::name('users')->where("id",$userData["id"])->update([
|
||||
"user_activation_key" => "n",
|
||||
"user_status" => 0,
|
||||
]);
|
||||
return [1,1];
|
||||
}
|
||||
}
|
||||
|
||||
static function resetUser($key,$uid){
|
||||
$timeNow = time();
|
||||
if(empty($key)||empty($uid)){
|
||||
return [0,"URL参数错误"];
|
||||
}
|
||||
$key = explode("_",$key);
|
||||
$userData = Db::name('users')
|
||||
->where('user_status',0)
|
||||
->where("id",$uid)->find();
|
||||
if(empty($userData)){
|
||||
return [0,"用户不存在"];
|
||||
}
|
||||
if(md5($userData["user_pass"].$key[1]) != $key[0]){
|
||||
return [0,"参数无效,请检查邮件链接"];
|
||||
}
|
||||
if(($timeNow - $key[1])>7200){
|
||||
return [0,"重设链接过期,请重新提交"];
|
||||
}
|
||||
return [1,1];
|
||||
}
|
||||
|
||||
static function findPwd($email,$captchaCode){
|
||||
if(Option::getValue("forget_captcha")=="1"){
|
||||
if(!self::checkCaptcha($captchaCode)){
|
||||
return [false,"验证码错误"];
|
||||
}
|
||||
}
|
||||
$userData = Db::name('users')->where('user_email',$email)->find();
|
||||
if(empty($userData)){
|
||||
return [1,1];
|
||||
}
|
||||
$timeNow = time();
|
||||
$resetHash = md5($userData["user_pass"].$timeNow);
|
||||
$resetKey = $resetHash."_".$timeNow;
|
||||
$options = Option::getValues(["basic","mail_template"]);
|
||||
$replace = array(
|
||||
'{siteTitle}' =>$options["siteName"],
|
||||
'{userName}' =>$userData["user_nick"],
|
||||
'{siteUrl}' =>$options["siteURL"],
|
||||
'{siteSecTitle}' =>$options["siteTitle"],
|
||||
'{resetUrl}' =>$options["siteURL"]."Member/resetPwd/".$resetKey."?uid=".$userData["id"],
|
||||
);
|
||||
$mailContent = strtr($options["mail_reset_pwd_template"],$replace);
|
||||
$mailObj = new Mail();
|
||||
$mailObj->Send($email,$userData["user_nick"],"【".$options["siteName"]."】"."密码重置",$mailContent);
|
||||
return [true,"ec"];
|
||||
}
|
||||
|
||||
/**
|
||||
* [login description]
|
||||
* @param [type] $userEmail [description]
|
||||
* @param [type] $userPass [description]
|
||||
* @return [type] [description]
|
||||
*/
|
||||
static function login($userEmail,$userPass,$captchaCode){
|
||||
$userEmail = str_replace(" ", "", $userEmail);
|
||||
$userData =Db::name('users')->where('user_email',$userEmail)->find();
|
||||
if(empty($userEmail) || empty($userPass)){
|
||||
return [false,"表单不完整"];
|
||||
}
|
||||
if(Option::getValue("login_captcha")=="1"){
|
||||
if(!self::checkCaptcha($captchaCode)){
|
||||
return [false,"验证码错误"];
|
||||
}
|
||||
}
|
||||
if(Db::name('users')->where('user_email',$userEmail)->value('user_pass') != md5(config('salt').$userPass)){
|
||||
return [false,"用户名或密码错误"];
|
||||
}
|
||||
if(Db::name('users')->where('user_email',$userEmail)->value('user_status') != 0){
|
||||
return [false,"账号被禁用或未激活"];
|
||||
}
|
||||
if($userData["two_step"] != "0"){
|
||||
session("user_id_tmp",Db::name('users')->where('user_email',$userEmail)->value('id'));
|
||||
session("login_status_tmp","ok");
|
||||
session("login_key_tmp",md5($userEmail.md5(config('salt').$userPass).config('salt')));
|
||||
return [false,"tsp"];
|
||||
}
|
||||
$loginKey = md5($userEmail.md5(config('salt').$userPass).config('salt'));
|
||||
cookie('user_id',Db::name('users')->where('user_email',$userEmail)->value('id'),604800);
|
||||
cookie('login_status','ok',604800);
|
||||
cookie('login_key',$loginKey,604800);
|
||||
return [true,"登录成功",$loginKey];
|
||||
}
|
||||
|
||||
static function checkCaptcha($code){
|
||||
if(!captcha_check($code)){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* [clear description]
|
||||
* @return [type] [description]
|
||||
*/
|
||||
public function clear(){
|
||||
$this->loginStatus = false;
|
||||
$this->uid = null;
|
||||
$this->groupId = null;
|
||||
$this->regDate = null;
|
||||
$this->varifyKey = null;
|
||||
cookie('user_id', null);
|
||||
cookie('login_status', null);
|
||||
cookie('login_key', null);
|
||||
}
|
||||
|
||||
/**
|
||||
* [getInfo description]
|
||||
* @return [type] [description]
|
||||
*/
|
||||
public function getInfo(){
|
||||
return [
|
||||
'uid' => $this->uid,
|
||||
'groupId' => $this->groupId,
|
||||
'regDate' => $this->regDate,
|
||||
'loginStatus' => $this->loginStatus,
|
||||
'userNick' => $this->userNick,
|
||||
'userMail' => $this->userMail,
|
||||
'groupData' => $this->groupData,
|
||||
'sqlData' => $this->userSQLData,
|
||||
];
|
||||
}
|
||||
|
||||
public function getSQLData(){
|
||||
return $this->userSQLData;
|
||||
}
|
||||
|
||||
public function getPolicy(){
|
||||
return Db::name('policy')->where('id',$this->groupData["policy_name"])->find();
|
||||
}
|
||||
|
||||
public function getGroupData(){
|
||||
return $this->groupData;
|
||||
}
|
||||
|
||||
public function getMemory($notEcho = false){
|
||||
$usedMemory = $this->userSQLData["used_storage"];
|
||||
$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($usedMemory);
|
||||
$returnData["total"] = self::countSize($groupStorage+$packetStorage);
|
||||
$returnData["rate"] = floor($usedMemory/($groupStorage+$packetStorage)*100);
|
||||
$returnData["basic"] = self::countSize($groupStorage);
|
||||
$returnData["pack"] = self::countSize($packetStorage);
|
||||
if($usedMemory > $groupStorage){
|
||||
$returnData["r1"] = floor($usedMemory/($groupStorage+$packetStorage)*100);
|
||||
$returnData["r2"] = 0;
|
||||
$returnData["r3"] = 100-$returnData["r1"];
|
||||
}else{
|
||||
$returnData["r1"] = floor($usedMemory/($groupStorage+$packetStorage)*100);
|
||||
$returnData["r2"] = floor(($groupStorage-$usedMemory)/($groupStorage+$packetStorage)*100);;
|
||||
$returnData["r3"] = 100-$returnData["r1"]-$returnData["r2"];
|
||||
}
|
||||
if($notEcho){
|
||||
return json_encode($returnData);
|
||||
}
|
||||
echo json_encode($returnData);
|
||||
}
|
||||
|
||||
static function countSize($bit) {
|
||||
$type = array('Bytes','KB','MB','GB','TB');
|
||||
for($i = 0; $bit >= 1024; $i++) {
|
||||
$bit/=1024;
|
||||
}
|
||||
return (floor($bit*100)/100).$type[$i];
|
||||
}
|
||||
|
||||
public function changeNick($nick){
|
||||
$nick=["nick" => $nick];
|
||||
$rules = [
|
||||
'nick' => ['require','max'=>'25','chsDash'],
|
||||
];
|
||||
$validate = new Validate($rules);
|
||||
if (!$validate->check($nick)) {
|
||||
return [0,"昵称必须是1-25位字符,只能包含中英文等常见字符"];
|
||||
}else{
|
||||
Db::name("users")->where("id",$this->uid)->update(["user_nick" => $nick["nick"]]);
|
||||
return [1,1];
|
||||
}
|
||||
}
|
||||
|
||||
public function changeOption($optionKey,$optionValue){
|
||||
$options = json_decode($this->userSQLData["options"],true);
|
||||
$options[$optionKey] = $optionValue;
|
||||
Db::name("users")->where("id",$this->uid)->update(["options" => json_encode($options)]);
|
||||
return [1,1];
|
||||
}
|
||||
|
||||
public function changePwd($origin,$new){
|
||||
if(md5(config('salt').$origin) != $this->userSQLData["user_pass"]){
|
||||
return [0,"原密码错误"];
|
||||
}
|
||||
if ((mb_strlen($new,'UTF8')>64) || (mb_strlen($new,'UTF8')<4)){
|
||||
return [false,"密码不符合规范"];
|
||||
}
|
||||
self::Reset($this->uid,$new);
|
||||
return [true,"密码重设成功"];
|
||||
}
|
||||
|
||||
public function homePageToggle($status){
|
||||
Db::name("users")->where("id",$this->uid)->update(["profile" => $status=="true"?1:0]);
|
||||
return [1,1];
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,72 @@
|
||||
{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="row">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header" >
|
||||
<i class="fa fa-eye fa-fw" aria-hidden="true"></i>
|
||||
系统信息
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>服务器信息:{:$_SERVER ['SERVER_SOFTWARE']}</li>
|
||||
<li>服务端系统:{:PHP_OS}</li>
|
||||
<li>最大上传限制:{:get_cfg_var ("upload_max_filesize")?get_cfg_var ("upload_max_filesize"):"不允许上传"}</li>
|
||||
<li>脚本最大执行时间:{:get_cfg_var("max_execution_time")."s "}</li>
|
||||
<li>脚本最大内存:{:get_cfg_var ("memory_limit")?get_cfg_var("memory_limit"):"无"}</li>
|
||||
<li>PHP扩展:curl{eq name=":extension_loaded('curl')" value="true"}√{else/}×{/eq} openssl{eq name=":extension_loaded('openssl')" value="true"}√{else/}×{/eq} GD{eq name=":extension_loaded('gd')" value="true"}√{else/}×{/eq} fileinfo{eq name=":extension_loaded('fileinfo')" value="true"}√{else/}×{/eq}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card" style="min-height: 269px;">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-cloud fa-fw" aria-hidden="true"></i>
|
||||
关于Cloudreve
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Cloudreve {$programVersion.type} {$programVersion.version}</h5>
|
||||
<ul>
|
||||
<li>主页:<a href="https://cloudreve.org" target="_blank">https://cloudreve.org</a></li>
|
||||
<li>Github:<a href="https://github.com/HFO4/Cloudreve" target="_blank">https://github.com/HFO4/Cloudreve</a></li>
|
||||
<li>许可证:<a href="https://github.com/HFO4/Cloudreve/LICENSE" target="_blank">GPL V3</a>(社区版)</li>
|
||||
<li>其他链接:<a href="https://github.com/HFO4/Cloudreve/graphs/contributors" target="_blank">代码贡献者</a> <a href="https://cloudreve.org/joingroup" target="_blank">Telegram群组</a> <a href="https://forum.cloudreve.org" target="_blank">社区</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,176 @@
|
||||
{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>
|
||||
<form id="addGroup">
|
||||
|
||||
<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 type="text" class="form-control" name="group_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="colFormLabelSm" class="col-form-label col-form-label-sm">上传策略</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select name="policy_name" required class="form-control">
|
||||
{volist name="policy" id="p"}
|
||||
<option value="{$p.id}">{$p.policy_name}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 为该用户组绑定一个上传策略</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-group mb-3">
|
||||
<input type="number" class="form-control" name="max_storage" 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="colFormLabelSm" 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="speed" spellcheck="false" min="0" placeholder="留空表示不限速,0表示禁止下载">
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="basic-addon2">
|
||||
Kb/s
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 限制该用户组下的用户上传的文件的下载速度,<strong>此设置仅对本地上传方案有效</strong></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="range_transfer" value="1" id="allow_range_1" checked>
|
||||
<label class="" for="allow_range_1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="range_transfer" id="allow_range_0" value="0" >
|
||||
<label class="" for="allow_range_0">禁止</label></div>
|
||||
<div class="col-md-4 option-des"> 是否断点续传及多线程下载,关闭后预览视频不支持拖拽播放,<strong>此设置仅对本地上传方案有效</strong></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="allow_share" value="1" id="allow_share_1" checked>
|
||||
<label class="" for="allow_share_1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="allow_share" id="allow_share_0" value="0" >
|
||||
<label class="" for="allow_share_0">禁止</label></div>
|
||||
<div class="col-md-4 option-des"> 是否允许创建文件分享链接</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">WebDAV支持</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input class="" type="radio" name="webdav" value="1" id="webdav1" checked>
|
||||
<label class="" for="webdav1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="webdav" id="webdav0" value="0" >
|
||||
<label class="" for="webdav0">禁止</label></div>
|
||||
<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>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input class="" type="radio" name="color" value="default" id="default" checked>
|
||||
<label class="" for="default" ><span class="badge badge-primary">蓝色</span></label>
|
||||
|
||||
<input class="" type="radio" name="color" value="primary" id="primary">
|
||||
<label class="" for="primary" ><span class="badge badge-secondary">灰色</span></label>
|
||||
|
||||
<input class="" type="radio" name="color" value="success" id="success">
|
||||
<label class="" for="success" ><span class="badge badge-success">绿色</span></label>
|
||||
|
||||
<input class="" type="radio" name="color" value="danger" id="danger">
|
||||
<label class="" for="danger" ><span class="badge badge-danger">红色</span></label>
|
||||
<br>
|
||||
<input class="" type="radio" name="color" value="warning" id="warning">
|
||||
<label class="" for="warning" ><span class="badge badge-warning">黄色</span></label>
|
||||
|
||||
<input class="" type="radio" name="color" value="info" id="info">
|
||||
<label class="" for="info" ><span class="badge badge-info">浅蓝色</span></label>
|
||||
|
||||
</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="saveGroup">添加</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br><br><br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
<!-- /.content-wrapper-->
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/add_group.js"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,835 @@
|
||||
{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 id="choose">
|
||||
<div class="row">
|
||||
<div class="col-md-3 md-2 mt-2">
|
||||
<div class="card cloud">
|
||||
<img class="card-img-top" src="/static/img/local.png" alt="Card image cap">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">本地服务器</h5>
|
||||
<p class="card-text">将文件存放在Cloudreve主程序的同一个服务器上</p>
|
||||
<a href="javascript:void()" class="btn btn-primary" id="addLocal">添加</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 md-2 mt-2">
|
||||
<div class="card cloud">
|
||||
<img class="card-img-top" src="/static/img/qiniu.png" alt="Card image cap">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">七牛云存储</h5>
|
||||
<p class="card-text">使用<a href="https://www.qiniu.com/" target="_blank">七牛云</a>提供的云存储及CDN服务</p>
|
||||
<a href="javascript:void();" class="btn btn-primary" id="addQiniu">添加</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 md-2 mt-2">
|
||||
<div class="card cloud">
|
||||
<img class="card-img-top" src="/static/img/oss.png" alt="Card image cap">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">阿里云OSS</h5>
|
||||
<p class="card-text">使用<a href="https://www.aliyun.com/product/oss?spm=5176.doc54464.765261.286.v2y7Hk" target="_blank">OSS对象存储</a>存放文件,推荐配合阿里云CDN使用</p>
|
||||
<a href="javascript:void()" class="btn btn-primary" id="addOss">添加</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 md-2 mt-2">
|
||||
<div class="card cloud">
|
||||
<img class="card-img-top" src="/static/img/upyun.png" alt="Card image cap">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">又拍云</h5>
|
||||
<p class="card-text">使用<a href="https://console.upyun.com/register/?invite=ryPX265PW" target="_blank">又拍云存储</a>提供的服务,每月有一定免费额度</p>
|
||||
<a href="javascript:void()" class="btn btn-primary" id="addUpyun">添加</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/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>
|
||||
<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>
|
||||
|
||||
|
||||
|
||||
<div class="card" id="local" style="display: none">
|
||||
<div class="card-header">
|
||||
添加本地上传策略
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="localPolicy">
|
||||
<input type="text" class="form-control" name="policy_type" value="local" 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="policy_name" class="col-form-label col-form-label-sm">允许获取外链</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input class="" type="radio" name="origin_link" id="local_allowd_origin1" value="1" >
|
||||
<label class="" for="local_allowd_origin1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="origin_link" id="local_allowd_origin2" value="0" checked>
|
||||
<label class="" for="local_allowd_origin2">禁止</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否允许获取文件的源URL,推荐禁止</div>
|
||||
</div>
|
||||
<div class="row form-setting" id="localOrigin" style="display: none">
|
||||
<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="{$options.siteURL}public/uploads/">
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 一般保持默认。如果你设置了融合CDN等产品,这里可以填写CDN域名,结尾要加"/"</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 type="text" class="form-control" name="filetype" value="image/*,jpg,png,gif,bmp,mp4,mp3,txt" spellcheck="false">
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 多个请以半角逗号","隔开,留空表示不限制。如果允许图片类型文件,除了图片类型后缀外,请额外添加一项"image/*"</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"> 你可以使用<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="{date}/{uid}" 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>
|
||||
|
||||
<div class="card" id="qiniu" style="display: none">
|
||||
<div class="card-header">
|
||||
添加七牛上传策略
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="qiniuPolicy">
|
||||
<input type="text" class="form-control" name="policy_type" value="qiniu" 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">AccessKey </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="ak" required></div>
|
||||
<div class="col-md-4 option-des"> 七牛账号的AccessKey,请在七牛控制面板查看</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="sk" class="col-form-label col-form-label-sm">SecretKey </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="sk" required></div>
|
||||
<div class="col-md-4 option-des"> 七牛账号的SecretKey,请在七牛控制面板查看</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">存储空间名称 </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="bucketname" 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="policy_name" class="col-form-label col-form-label-sm">空间属性</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input class="" type="radio" name="bucket_private" id="bucket_private_1" value="1" checked>
|
||||
<label class="" for="bucket_private_1" >私有空间</label>
|
||||
|
||||
<input class="" type="radio" name="bucket_private" id="bucket_private_0" value="0">
|
||||
<label class="" for="bucket_private_0">公开空间</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 与七牛空间访问控制设置保持一致,推荐设置为私有空间</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting" id="outlink" style="display: none">
|
||||
<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 class="" type="radio" name="origin_link" id="qiniu_allowd_origin1" value="1" >
|
||||
<label class="" for="qiniu_allowd_origin1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="origin_link" id="qiniu_allowd_origin2" value="0" checked>
|
||||
<label class="" for="qiniu_allowd_origin2">禁止</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否允许获取文件的源URL,推荐禁止</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="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 type="text" class="form-control" name="filetype" value="image/*,jpg,png,gif,bmp,mp4,mp3,txt" spellcheck="false">
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 多个请以半角逗号","隔开,留空表示不限制。如果允许图片类型文件,除了图片类型后缀外,请额外添加一项"image/*"</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="mimetype" class="col-form-label col-form-label-sm">允许的mimeType</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="mimetype" spellcheck="false">
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 多个请以半角分号";"隔开,留空表示不限制。示例:image/*表示只允许上传图片类型,image/jpeg;image/png表示只允许上传jpg和png类型的图片,!application/json;text/plain表示禁止上传json文本和纯文本。注意最前面的感叹号!</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="qiniu_autoname1" value="1" checked>
|
||||
<label class="" for="qiniu_autoname1" >开启</label>
|
||||
|
||||
<input class="" type="radio" name="autoname" id="qiniu_autoname2" value="0" >
|
||||
<label class="" for="qiniu_autoname2">关闭</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否对存储的文件自动重命名。推荐开启,重命名不会影响用户端文件名展示,开启后可以避免文件重名</div>
|
||||
</div>
|
||||
<div class="row form-setting" id="qiniu_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"> 你可以使用<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">
|
||||
|
||||
<input type="text" class="form-control" name="dirrule" spellcheck="false" value="{date}/{uid}" 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></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br> <br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<bn>
|
||||
</div>
|
||||
<div id="oss" style="display: none">
|
||||
<div class="alert alert-primary" role="alert">
|
||||
阿里云OSS创建空间后请进行如下操作,否则无法正常上传。
|
||||
<ul>
|
||||
<li>转到 空间管理 - 基础设置 - 跨域设置;</li>
|
||||
<li>创建规则,其中来源填写“*”,允许 Methods全部勾选,允许 Headers填写“*”,其他保持默认,点击确定保存.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card" >
|
||||
<div class="card-header">
|
||||
添加阿里云OSS上传策略
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="ossPolicy">
|
||||
<input type="text" class="form-control" name="policy_type" value="oss" 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">Access Key ID </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="ak" pattern="[^\s]+" title="请不要包含空格" required></div>
|
||||
<div class="col-md-4 option-des"> 阿里云账号的Access Key ID,请在阿里云控制面板-Access Key管理中创建或查看</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="sk" class="col-form-label col-form-label-sm"> Access Key Secret </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="sk" pattern="[^\s]+" title="请不要包含空格" 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">Bucket名称 </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="bucketname" required></div>
|
||||
<div class="col-md-4 option-des"> 创建空间时填写的Bucket名</div>
|
||||
</div>
|
||||
|
||||
<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 class="" type="radio" name="bucket_private" id="oss_private_1" value="1" checked>
|
||||
<label class="" for="oss_private_1" >私有</label>
|
||||
|
||||
<input class="" type="radio" name="bucket_private" id="oss_private_0" value="0">
|
||||
<label class="" for="oss_private_0">公共读</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 与OSS空间访问控制设置保持一致,推荐设置为私有空间</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting" id="oss_outlink" style="display: none">
|
||||
<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 class="" type="radio" name="origin_link" id="oss_allowd_origin1" value="1" >
|
||||
<label class="" for="oss_allowd_origin1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="origin_link" id="oss_allowd_origin2" value="0" checked>
|
||||
<label class="" for="oss_allowd_origin2">禁止</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否允许获取文件的源URL,推荐禁止</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="url" value="http(s)://" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> OSS空间绑定的域名,用于文件下载、访问,结尾要加"/"(推荐配合阿里云CDN使用,此处填写CDN域名)</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<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" value="http(s)://" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> OSS空间的域名,一般与上一项保持一致。(如果上一项填写的是CDN域名,则此处与上一项不应相同)</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 type="text" class="form-control" name="filetype" value="image/*,jpg,png,gif,bmp,mp4,mp3,txt" spellcheck="false">
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 多个请以半角逗号","隔开,留空表示不限制。如果允许图片类型文件,除了图片类型后缀外,请额外添加一项"image/*"</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="oss_autoname1" value="1" checked>
|
||||
<label class="" for="oss_autoname1" >开启</label>
|
||||
|
||||
<input class="" type="radio" name="autoname" id="oss_autoname2" value="0" >
|
||||
<label class="" for="oss_autoname2">关闭</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否对存储的文件自动重命名。推荐开启,重命名不会影响用户端文件名展示,开启后可以避免文件重名</div>
|
||||
</div>
|
||||
<div class="row form-setting" id="oss_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"> 你可以使用<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">
|
||||
|
||||
<input type="text" class="form-control" name="dirrule" spellcheck="false" value="{date}/{uid}" 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="saveOss">保存设置</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br> <br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<bn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" id="upyun" style="display: none">
|
||||
<div class="card-header">
|
||||
又拍云
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="upyunPolicy">
|
||||
<input type="text" class="form-control" name="policy_type" value="upyun" 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">操作员名称 </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="op_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="sk" class="col-form-label col-form-label-sm">操作员密码 </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="op_pwd" 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">存储服务名 </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="bucketname" 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="policy_name" class="col-form-label col-form-label-sm">Token 防盗链</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input class="" type="radio" name="bucket_private" id="upyun_bucket_private_1" value="1" checked>
|
||||
<label class="" for="upyun_bucket_private_1" >开启</label>
|
||||
|
||||
<input class="" type="radio" name="bucket_private" id="upyun_bucket_private_0" value="0">
|
||||
<label class="" for="upyun_bucket_private_0">关闭</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 与 功能配置-访问配置-Token 防盗链 保持一致,推荐设置为开启</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting" id="upyun_token" style="">
|
||||
<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="sk"></div>
|
||||
<div class="col-md-4 option-des"> 与 功能配置-访问配置-Token防盗链 中的密钥保持一致</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting" id="upyun_outlink" style="display: none">
|
||||
<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 class="" type="radio" name="origin_link" id="upyun_allowd_origin1" value="1" >
|
||||
<label class="" for="upyun_allowd_origin1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="origin_link" id="upyun_allowd_origin2" value="0" checked>
|
||||
<label class="" for="upyun_allowd_origin2">禁止</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否允许获取文件的源URL,推荐禁止</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="url" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 绑定的域名,开头要加http(s)://结尾要加"/"</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 type="text" class="form-control" name="filetype" value="image/*,jpg,png,gif,bmp,mp4,mp3,txt" spellcheck="false">
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 多个请以半角逗号","隔开,留空表示不限制。如果允许图片类型文件,除了图片类型后缀外,请额外添加一项"image/*"</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>
|
||||
<input type="text" name="autoname" value="1" style="display: none">
|
||||
<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="text" class="form-control" name="dirrule" spellcheck="false" value="{date}/{uid}" 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="saveUpyun">保存设置</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>
|
||||
<!-- /.content-wrapper-->
|
||||
<div class="modal fade" tabindex="-1" role="dialog" id="varTable">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">自动重命名变量对照表</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th >变量字段</th>
|
||||
<th >说明</th>
|
||||
<th >示例</th>
|
||||
<th >适用范围</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td >{date}</td>
|
||||
<td>上传日期</td>
|
||||
<td>20180118</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >{datetime}</td>
|
||||
<td>上传日期时间</td>
|
||||
<td>20180118121049</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >{uid}</td>
|
||||
<td>上传者UID</td>
|
||||
<td>154</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >{timestamp}</td>
|
||||
<td>时间戳</td>
|
||||
<td>1516277624</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >{randomkey16}</td>
|
||||
<td>16位随机字符</td>
|
||||
<td>16D8lhjErTDWAQjW</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >{randomkey8}</td>
|
||||
<td>8位随机字符</td>
|
||||
<td>hM4Tpdh6</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >{originname}</td>
|
||||
<td>原始文件名</td>
|
||||
<td>plus1s.jpg</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" tabindex="-1" role="dialog" id="varTableFolder">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">目录变量对照表</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th >变量字段</th>
|
||||
<th >说明</th>
|
||||
<th >示例</th>
|
||||
<th >适用范围</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td >{date}</td>
|
||||
<td>上传日期</td>
|
||||
<td>20180118</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >{datetime}</td>
|
||||
<td>上传日期时间</td>
|
||||
<td>20180118121049</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >{uid}</td>
|
||||
<td>上传者UID</td>
|
||||
<td>154</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >{timestamp}</td>
|
||||
<td>时间戳</td>
|
||||
<td>1516277624</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >{randomkey16}</td>
|
||||
<td>16位随机字符</td>
|
||||
<td>16D8lhjErTDWAQjW</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >{randomkey8}</td>
|
||||
<td>8位随机字符</td>
|
||||
<td>hM4Tpdh6</td>
|
||||
<td>全部</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/add_policy.js"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -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}
|
||||
@@ -0,0 +1,175 @@
|
||||
{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-primary" role="alert">
|
||||
创建储存桶后请在储存桶控制面板添加CORS跨域规则,允许本站的POST请求。请确保您的服务器和用户可以正常连接到AWS服务器。
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card" id="s3" >
|
||||
<div class="card-header">
|
||||
添加S3上传策略
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="qiniuPolicy">
|
||||
<input type="text" class="form-control" name="policy_type" value="s3" 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">AWSAccessKeyId </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="ak" required></div>
|
||||
<div class="col-md-4 option-des"> AWS账户的访问秘钥信息,请在 控制面板 - 您的安全凭证 中创建</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="sk" class="col-form-label col-form-label-sm">AWSSecretKey </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>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="bucketname" class="col-form-label col-form-label-sm">存储桶名称 </label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="bucketname" required></div>
|
||||
<div class="col-md-4 option-des"> 创建桶时填写的名称</div>
|
||||
</div>
|
||||
|
||||
<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="url" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 一般格式为:https://s3-分区名.amazonaws.com/储存桶名/ 结尾要加"/"</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" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 一般格式为:https://储存桶名.s3-分区代号.amazonaws.com/</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="op_name" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 例如:ap-southeast-1</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">EndPoint</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" name="op_name" required>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 一般格式为:s3-储存区域.amazonaws.com,只填写域名部分</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 type="text" class="form-control" name="filetype" value="image/*,jpg,png,gif,bmp,mp4,mp3,txt" spellcheck="false">
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 多个请以半角逗号","隔开,留空表示不限制。如果允许图片类型文件,除了图片类型后缀外,请额外添加一项"image/*"</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>
|
||||
|
||||
<input type="text" name="autoname" value="0" style="display: none">
|
||||
|
||||
<input type="text" class="form-control" name="dirrule" spellcheck="false" value="{uid}" style="display: none" required>
|
||||
|
||||
|
||||
<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">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,236 @@
|
||||
{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="#">管理面板</a>
|
||||
</li>
|
||||
<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">
|
||||
<div class="card-body-icon">
|
||||
<i class="fa fa-fw fa-users"></i>
|
||||
</div>
|
||||
<div class="mr-5">{$statics.userNum} 位用户</div>
|
||||
</div>
|
||||
<a class="card-footer text-white clearfix small z-1" href="/Admin/Users">
|
||||
<span class="float-left">查看详情</span>
|
||||
<span class="float-right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-sm-6 mb-3">
|
||||
<div class="card text-white bg-warning o-hidden h-100">
|
||||
<div class="card-body">
|
||||
<div class="card-body-icon">
|
||||
<i class="fa fa-fw fa-file"></i>
|
||||
</div>
|
||||
<div class="mr-5">{$statics.fileNum} 个文件</div>
|
||||
</div>
|
||||
<a class="card-footer text-white clearfix small z-1" href="/Admin/Files">
|
||||
<span class="float-left">查看详情</span>
|
||||
<span class="float-right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-sm-6 mb-3">
|
||||
<div class="card text-white bg-success o-hidden h-100">
|
||||
<div class="card-body">
|
||||
<div class="card-body-icon">
|
||||
<i class="fa fa-fw fa-share-alt"></i>
|
||||
</div>
|
||||
<div class="mr-5">{$statics.publicShareNum} 个公开分享</div>
|
||||
</div>
|
||||
<a class="card-footer text-white clearfix small z-1" href="/Admin/Shares">
|
||||
<span class="float-left">查看详情</span>
|
||||
<span class="float-right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-sm-6 mb-3">
|
||||
<div class="card text-white bg-danger o-hidden h-100">
|
||||
<div class="card-body">
|
||||
<div class="card-body-icon">
|
||||
<i class="fa fa-fw fa-lock"></i>
|
||||
</div>
|
||||
<div class="mr-5">{$statics.privateShareNum} 个私密分享</div>
|
||||
</div>
|
||||
<a class="card-footer text-white clearfix small z-1" href="/Admin/Shares">
|
||||
<span class="float-left">查看详情</span>
|
||||
<span class="float-right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Area Chart Example-->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-area-chart"></i> 近期趋势</div>
|
||||
<div class="card-body">
|
||||
<canvas id="myAreaChart" width="100%" height="30"></canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<!-- Example Bar Chart Card-->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-bell-o"></i> 订阅新闻</div>
|
||||
<div class="list-group list-group-flush small" id="news">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- Card Columns Example Social Feed-->
|
||||
|
||||
|
||||
|
||||
<!-- /Card Columns-->
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<!-- Example Pie Chart Card-->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-pie-chart"></i> 文件组成</div>
|
||||
<div class="card-body">
|
||||
<canvas id="myPieChart" width="100%" height="80"></canvas>
|
||||
</div>
|
||||
<div class="card-footer small text-muted">*此结果仅供参考</div>
|
||||
</div>
|
||||
<!-- Example Notifications Card-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- Example DataTables Card-->
|
||||
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
<!-- /.content-wrapper-->
|
||||
<footer class="sticky-footer">
|
||||
<div class="container">
|
||||
<div class="text-center">
|
||||
<small>Copyright © Cloudreve {php}echo date("Y");{/php} </small>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Scroll to Top Button-->
|
||||
<a class="scroll-to-top rounded" href="#page-top">
|
||||
<i class="fa fa-angle-up"></i>
|
||||
</a>
|
||||
<!-- Logout Modal-->
|
||||
|
||||
<!-- Bootstrap core JavaScript-->
|
||||
|
||||
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$.getJSON("https://cloudreve.org/api/notice/?callback=?", function(data){
|
||||
|
||||
$("#news").html(data[0]);
|
||||
|
||||
})
|
||||
})
|
||||
Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif',
|
||||
Chart.defaults.global.defaultFontColor = "#292b2c";
|
||||
var ctx = document.getElementById("myAreaChart"),
|
||||
myLineChart = new Chart(ctx, {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: [{$statics.trendDate}],
|
||||
datasets: [{
|
||||
label: "上传文件",
|
||||
lineTension: .3,
|
||||
backgroundColor: "rgba(2,117,216,0.2)",
|
||||
borderColor: "rgba(2,117,216,1)",
|
||||
pointRadius: 5,
|
||||
pointBackgroundColor: "rgba(2,117,216,1)",
|
||||
pointBorderColor: "rgba(255,255,255,0.8)",
|
||||
pointHoverRadius: 5,
|
||||
pointHoverBackgroundColor: "rgba(2,117,216,1)",
|
||||
pointHitRadius: 20,
|
||||
pointBorderWidth: 2,
|
||||
data: [{$statics.trendFile}]
|
||||
},{
|
||||
label: "注册用户",
|
||||
lineTension: .3,
|
||||
backgroundColor: "rgba(83, 216, 2, 0.2)",
|
||||
borderColor: "#4CAF50",
|
||||
pointRadius: 5,
|
||||
pointBackgroundColor: "#4CAF50",
|
||||
pointBorderColor: "rgba(255,255,255,0.8)",
|
||||
pointHoverRadius: 5,
|
||||
pointHoverBackgroundColor: "#4CAF50",
|
||||
pointHitRadius: 20,
|
||||
pointBorderWidth: 2,
|
||||
data: [{$statics.trendUser}]
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
time: {
|
||||
unit: "date"
|
||||
},
|
||||
gridLines: {
|
||||
display: !1
|
||||
},
|
||||
ticks: {
|
||||
maxTicksLimit: 7
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
|
||||
maxTicksLimit: 5
|
||||
},
|
||||
gridLines: {
|
||||
color: "rgba(0, 0, 0, .125)"
|
||||
}
|
||||
}]
|
||||
},
|
||||
legend: {
|
||||
display: !1
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
ctx = document.getElementById("myPieChart"),
|
||||
myPieChart = new Chart(ctx, {
|
||||
type: "pie",
|
||||
data: {
|
||||
labels: ["其他", "图片", "音频", "视频"],
|
||||
datasets: [{
|
||||
data: [{$statics.otherRate}, {$statics.imgRate}, {$statics.audioRate}, {$statics.videoRate}],
|
||||
backgroundColor: ["#007bff", "#dc3545", "#ffc107", "#28a745"]
|
||||
}]
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,83 @@
|
||||
{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>
|
||||
<form id="basicOptionsForm">
|
||||
<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 type="text" class="form-control" name="siteName" value="{$options.siteName}"></div>
|
||||
<div class="col-md-4 option-des"> 站点的主标题,将会展示在个页面的标题尾部、邮件中。</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 type="text" class="form-control" name="siteTitle" value="{$options.siteTitle}"></div>
|
||||
<div class="col-md-4 option-des"> 只会展示在首页的副标题。</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">站点URL</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="siteURL" value="{$options.siteURL}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 站点的URL,此设置很重要,请如实填写,否则会影响系统正常工作.</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 type="text" class="form-control" name="siteKeywords" value="{$options.siteKeywords}"></div>
|
||||
<div class="col-md-4 option-des"> 位于首页meta标签内的站点关键词</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 type="text" class="form-control" name="siteDes" value="{$options.siteDes}"></div>
|
||||
<div class="col-md-4 option-des"> 位于首页meta标签内的站点描述</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"> <textarea class="form-control" name="js_code" rows="4" spellcheck="false">{$options.js_code}</textarea></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="button" class="btn btn-primary" id="saveBasic">保存设置</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br> <br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/setting.js"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,98 @@
|
||||
{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>
|
||||
</ol>
|
||||
|
||||
<!-- Area Chart Example-->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2>配色方案</h2>
|
||||
<div class="alert alert-primary" role="alert">
|
||||
<ul>
|
||||
<li>你可以使用<a href="https://theme.cloudreve.org">Cloudreve配色工具</a>创建配色,并将生成的配置信息填写在下方;</li>
|
||||
<li>主色调为不同配色的区分标识,请不要创建主色调相同的配色方案。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<form id="colorForm">
|
||||
<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"><select class="form-control" name="header">
|
||||
{volist name="colors" id="theme"}
|
||||
<option value="{$key}" {eq name="optionsForSet.defaultTheme" value="$key"}selected{/eq}>{$key}</option>
|
||||
{/volist}
|
||||
|
||||
</select></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-8">
|
||||
<table class="table" id="colorTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">主色调</th>
|
||||
<th scope="col">颜色配置</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{volist name="colors" id="theme"}
|
||||
<tr>
|
||||
<th scope="row" style="color:{$key}">{$key}
|
||||
<br><button id="removeRow" type="button" data-action="removeRow" class="btn btn-default">删除</button>
|
||||
</th>
|
||||
<td><textarea class="form-control" rows="4" name="color[]">{:json_encode($theme)}</textarea></td>
|
||||
</tr>
|
||||
{/volist}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="text-align:right;"><button id="addRow" type="button" class="btn btn-default">增加一行</button></div>
|
||||
|
||||
</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="saveColor">保存设置</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br> <br>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<br><br>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="file_side">
|
||||
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/color.js"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,51 @@
|
||||
{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>
|
||||
{$path}
|
||||
<br> <br>
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<input type="text" id="configType" value="{$type}" style="display: none">
|
||||
<textarea rows="15" class="form-control" spellcheck="false">{$content}</textarea>
|
||||
<br>
|
||||
<button class="btn btn-primary" id="save">保存</button>
|
||||
<br><br>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||
<a class="nav-link" id="v-pills-home-tab" href="/Admin/Config/type/common" role="tab" data-type="common">系统公共配置</a>
|
||||
<a class="nav-link" id="v-pills-profile-tab" href="/Admin/Config/type/database" role="tab" data-type="database">数据库</a>
|
||||
<a class="nav-link" id="v-pills-messages-tab" href="/Admin/Config/type/route" role="tab" data-type="route">路由</a>
|
||||
<a class="nav-link" id="v-pills-settings-tab" href="/Admin/Config/type/tags" role="tab" data-type="tags">行为扩展</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/config.js"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,84 @@
|
||||
{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>
|
||||
{eq name="neverExcute" value="true"}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
定时任务从未执行!请将 {$options.siteURL}Cron 加入到您的定时任务列队中(如Crontab)。
|
||||
</div>
|
||||
{/eq}
|
||||
{volist name="cron" id="c"}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
{$c.name}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<blockquote class="blockquote mb-0">
|
||||
<p>{$c.des}</p>
|
||||
</blockquote><form id="cronForm" method="post" action="/Admin/SaveCron">
|
||||
<div class="row">
|
||||
|
||||
<input type="text" name="id" value="{$c.id}" style="display: none;">
|
||||
<div class="col-md-4">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="basic-addon1">优先级</span>
|
||||
</div>
|
||||
<input type="number" min="0" class="form-control" name="rank" placeholder="值越高越优先" value="{$c.rank}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="basic-addon1">执行间隔(s)</span>
|
||||
</div>
|
||||
<input type="number" min="1" class="form-control" name="interval_s" value="{$c.interval_s}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="basic-addon1">启用</span>
|
||||
</div>
|
||||
<input type="number" min="0" max="1" class="form-control" name="enable" value="{$c.enable}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<input type="submit" class="btn btn-primary" value="保存">
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-footer text-muted">
|
||||
上次执行:{eq name="c.last_excute" value="0"}从未执行{else/}{:date("Y-m-d H:i:s",$c.last_excute)}{/eq}
|
||||
</div>
|
||||
</div><br>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,122 @@
|
||||
{extend name="header_admin" /}
|
||||
{block name="title"}离线下载 - {$options.siteName}{/block}
|
||||
{block name="content"}
|
||||
<div class="content-wrapper">
|
||||
<div class="container-fluid">
|
||||
<!-- Breadcrumbs-->
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="/Admin">管理面板</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active">离线下载</li>
|
||||
<li class="breadcrumb-item active">配置</li>
|
||||
</ol>
|
||||
|
||||
<!-- Area Chart Example-->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2>离线下载</h2>
|
||||
<br>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-tabs card-header-tabs">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="tab" href="#options"><i class="fa fa-cog" aria-hidden="true"></i> Aria2配置</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#list"><i class="fa fa-list" aria-hidden="true"></i> 任务列表</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="tab-content" >
|
||||
<div class="tab-pane fade show active" id="options" role="tabpanel" aria-labelledby="pills-home-tab">
|
||||
<form id="aria2Options">
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="fromName" class="col-form-label col-form-label-sm">RPC Server</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="aria2_rpcurl" value="{$optionsForSet.aria2_rpcurl}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> aria2的RPC服务器地址,请在aria2的配置文件中启用RPC服务。例如:http://127.0.0.1:6800/</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="fromName" class="col-form-label col-form-label-sm">RPC Token</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="aria2_token" value="{$optionsForSet.aria2_token}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 在配置文件中设置的RPC服务的Token</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="fromName" class="col-form-label col-form-label-sm">下载临时目录</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="aria2_tmppath" value="{$optionsForSet.aria2_tmppath}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 下载文件数据的临时存放目录,请确保PHP对该目录拥有读写权限</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="aria2_options" class="col-form-label col-form-label-sm">其他下载参数</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <textarea class="form-control" name="aria2_options" spellcheck="false">{$optionsForSet.aria2_options}</textarea></div>
|
||||
<div class="col-md-4 option-des"> aria2启动下载的其他附带参数,请以json格式书写。你可也可以将这些设置写在aria2配置文件里。可用参数请查阅<a href="https://aria2.github.io/manual/en/html/aria2c.html#options" target="_blank">官方文档</a></div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
</div>
|
||||
<div class="col-md-4"> <button type="button" class="btn btn-primary" id="saveAria2">保存设置</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br><br><br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="list" role="tabpanel" aria-labelledby="pills-profile-tab">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="textCenter">#</th>
|
||||
<th scope="col" width="50%">文件名</th>
|
||||
<th scope="col" class="textCenter">创建者</th>
|
||||
<th scope="col" class="textCenter">文件大小</th>
|
||||
<th scope="col" class="textCenter">状态</th>
|
||||
<th scope="col" class="textCenter">进度</th>
|
||||
<th scope="col" class="textCenter">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="listContent">
|
||||
{volist name='list' id='download'}
|
||||
<tr id="i-{$download.id}" data-pid="{$download.pid}">
|
||||
<th scope="row" class="textCenter">{$download.id}</th>
|
||||
<td>{:is_array($originList[$key]['fileName'])?"未知":$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}
|
||||
@@ -0,0 +1,188 @@
|
||||
{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>
|
||||
<form id="editGroup">
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<input type="text" name="id" value="{$group.id}" style="display: none">
|
||||
<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="group_name" value="{$group.group_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="colFormLabelSm" class="col-form-label col-form-label-sm">上传策略</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select name="policy_name" required class="form-control" >
|
||||
{volist name="policy" id="p"}
|
||||
<option value="{$p.id}">{$p.policy_name}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 为该用户组绑定一个上传策略</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-group mb-3">
|
||||
<input type="number" class="form-control" name="max_storage" spellcheck="false" min="0" value="{:countSize($group.max_storage,true)[0]}" required>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="basic-addon2">
|
||||
<select name="sizeTimes" class="selectIn" data-value="{:countSize($group.max_storage,true)[1]}">
|
||||
<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="colFormLabelSm" 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="speed" spellcheck="false" min="0" placeholder="留空表示不限速,0表示禁止下载" value="{$group.speed}">
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="basic-addon2">
|
||||
Kb/s
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 限制该用户组下的用户上传的文件的下载速度,<strong>此设置仅对本地上传方案有效</strong></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="range_transfer" value="1" id="allow_range_1">
|
||||
<label class="" for="allow_range_1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="range_transfer" id="allow_range_0" value="0" >
|
||||
<label class="" for="allow_range_0">禁止</label></div>
|
||||
<div class="col-md-4 option-des"> 是否断点续传及多线程下载,关闭后预览视频不支持拖拽播放,<strong>此设置仅对本地上传方案有效</strong></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="allow_share" value="1" id="allow_share_1" checked>
|
||||
<label class="" for="allow_share_1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="allow_share" id="allow_share_0" value="0" >
|
||||
<label class="" for="allow_share_0">禁止</label></div>
|
||||
<div class="col-md-4 option-des"> 是否允许创建文件分享链接</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">WebDAV支持</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input class="" type="radio" name="webdav" value="1" id="webdav1" checked>
|
||||
<label class="" for="webdav1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="webdav" id="webdav0" value="0" >
|
||||
<label class="" for="webdav0">禁止</label></div>
|
||||
<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>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input class="" type="radio" name="color" value="default" id="default" checked>
|
||||
<label class="" for="default" ><span class="badge badge-primary">蓝色</span></label>
|
||||
|
||||
<input class="" type="radio" name="color" value="primary" id="primary">
|
||||
<label class="" for="primary" ><span class="badge badge-secondary">灰色</span></label>
|
||||
|
||||
<input class="" type="radio" name="color" value="success" id="success">
|
||||
<label class="" for="success" ><span class="badge badge-success">绿色</span></label>
|
||||
|
||||
<input class="" type="radio" name="color" value="danger" id="danger">
|
||||
<label class="" for="danger" ><span class="badge badge-danger">红色</span></label>
|
||||
<br>
|
||||
<input class="" type="radio" name="color" value="warning" id="warning">
|
||||
<label class="" for="warning" ><span class="badge badge-warning">黄色</span></label>
|
||||
|
||||
<input class="" type="radio" name="color" value="info" id="info">
|
||||
<label class="" for="info" ><span class="badge badge-info">浅蓝色</span></label>
|
||||
|
||||
</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="saveGroup">保存</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br><br><br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
<!-- /.content-wrapper-->
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/add_group.js"></script>
|
||||
<script type="text/javascript">
|
||||
$("option[value='{$group.policy_name}']").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}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,194 @@
|
||||
{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>
|
||||
</ol>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2>文件</h2>
|
||||
<br>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-tags"></i> 条件检索</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-1 form-label-search mb-2">排序方式</div>
|
||||
<div class="col-md-10">
|
||||
<ul class="nav nav-pills" id="order">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-method="id DESC">日期</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-method="orign_name ASC">文件名</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-method="size DESC">大小</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-1 form-label-search mb-2">上传策略</div>
|
||||
<div class="col-md-10">
|
||||
<ul class="nav nav-pills" id="policy_select">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-policy="">全部</a>
|
||||
</li>
|
||||
{volist name="policy" id="policy"}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-policy="{$policy.id}">{$policy.policy_name}</a>
|
||||
</li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 5px;">
|
||||
<div class="col-1 form-label-search mb-2">高级检索</div>
|
||||
<div class="col-md-10">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<select class="form-control form-control-sm" id="searchCol">
|
||||
<option value="id" selected>ID</option>
|
||||
<option value="orign_name">文件名</option>
|
||||
<option value="pre_name">实际文件名</option>
|
||||
<option value="upload_user">上传者UID</option>
|
||||
<option value="upload_date">上传日期</option>
|
||||
<option value="pic_info">图像尺寸</option>
|
||||
<option value="parent_folder">所属目录ID</option>
|
||||
<option value="policy_id">上传策略ID</option>
|
||||
<option value="dir">目录路径</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input type="text" class="form-control form-control-sm" placeholder="检索表达式" id="searchValue">
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<button type="button" class="btn btn-primary btn-sm" id="applySearch">应用</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-table"></i> 文件列表</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<div id="dataTable_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4"><div class="row"><div class="col-sm-12 col-md-6"><div class="dataTables_length" ><label>每页展示 <select id="dataTable_length" aria-controls="dataTable" class="form-control form-control-sm"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select> 个</label></div></div><div class="col-sm-12 col-md-6"><div id="dataTable_filter" class="dataTables_filter"><label>搜索:<input type="search" class="form-control form-control-sm" placeholder="" id="searchFrom"></label></div></div></div><div class="row"><div class="col-sm-12">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered dataTable" id="dataTable" width="100%" cellspacing="0" role="grid" aria-describedby="dataTable_info" style="width: 100%;">
|
||||
<thead>
|
||||
<tr role="row" class="textCenter"><th><input type="checkbox" data-type="all"></th><th>文件名</th><th class="textCenter">大小</th><th class="textCenter">上传者</th><th class="textCenter">日期</th><th class="textCenter">操作</th></tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr><th rowspan="1" colspan="1" class="textCenter"><input type="checkbox" data-type="all"></th><th rowspan="1" colspan="1">文件名</th><th rowspan="1" colspan="1" class="textCenter">大小</th><th rowspan="1" colspan="1" class="textCenter">上传者</th><th rowspan="1" colspan="1" class="textCenter">日期</th><th rowspan="1" colspan="1" class="textCenter">操作</th></tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<tr role="row" class="odd" id="fileList">
|
||||
|
||||
{volist name='list' id='file'}
|
||||
<tr role="row" class="odd">
|
||||
<td class="sorting_1 textCenter"><input type="checkbox" data-type="mark" data-path="{:rtrim($file.dir,'/')}/{$file.orign_name}" data-uid="{$file.upload_user}"></td>
|
||||
<td>
|
||||
{eq name=":isPreview($file.orign_name)" value="yes"}
|
||||
<a href="/Admin/Preview/id/{$file.id}" class="noAColor" target="_blank">{$file.orign_name|htmlspecialchars=ENT_NOQUOTES}</a>
|
||||
{else}
|
||||
<a href="/Admin/Download/id/{$file.id}" class="noAColor" target="_blank">{$file.orign_name|htmlspecialchars=ENT_NOQUOTES}</a>
|
||||
{/eq}
|
||||
</td>
|
||||
<td class="textCenter">{:countSize($file.size)}</td>
|
||||
<td class="textCenter">{$originList[$key]["user"]["user_nick"]}</td>
|
||||
<td class="textCenter">{$file.upload_date}</td>
|
||||
<td class="textCenter"><button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="删除" data-action="delete" data-id="{$file.id}"><i class="fa fa-trash" aria-hidden="true"></i></button>
|
||||
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="下载" data-action="download" data-id="{$file.id}"><i class="fa fa-download" aria-hidden="true"></i></button>
|
||||
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="详情" data-action="info" data-id="{$file.id}"><i class="fa fa-info-circle" aria-hidden="true"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-5 mb-2 mt-2" style="display: none" id="del">
|
||||
<button type="button" class="btn btn-danger" id="delAll"><i class="fa fa-trash" aria-hidden="true"></i> 删除选中文件</button>
|
||||
</div>
|
||||
</div></div><div class="row"><div class="col-sm-12 col-md-5"><div class="dataTables_info" id="dataTable_info" role="status" aria-live="polite">展示第 {$pageNow} 页,共 {$pageTotal} 页 {$dataTotal} 条数据</div></div><div class="col-sm-12 col-md-7">
|
||||
<div class="dataTables_paginate paging_simple_numbers" id="dataTable_paginate">
|
||||
{$list->render()}
|
||||
</div></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
<div class="modal fade bd-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true" id="fileInfo">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">文件详情</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>ID:</strong></div>
|
||||
<div class="col-md-12 break" id="fileId">12</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>文件名:</strong></div>
|
||||
<div class="col-md-12 break" id="fileName">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>源文件名:</strong></div>
|
||||
<div class="col-md-12 break" id="fileOrigin">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>上传者UID:</strong></div>
|
||||
<div class="col-md-12 break" id="fileUID">17</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>大小(字节):</strong></div>
|
||||
<div class="col-md-12 break" id="fileSize">7481817</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>图像尺寸:</strong></div>
|
||||
<div class="col-md-12 break" id="filePic">147,445</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>上传策略:</strong></div>
|
||||
<div class="col-md-12 break" id="filePolicy">147,445</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>所属目录:</strong></div>
|
||||
<div class="col-md-12 break" id="fileDir">147,445</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.content-wrapper-->
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/files.js"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,131 @@
|
||||
{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>
|
||||
</ol>
|
||||
|
||||
<!-- Area Chart Example-->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2>用户组</h2>
|
||||
<br>
|
||||
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-table"></i> 用户组列表</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<div id="dataTable_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4"><div class="row"><div class="col-sm-12 col-md-6"><div class="dataTables_length" ><label>每页展示 <select id="dataTable_length" aria-controls="dataTable" class="form-control form-control-sm"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select> 个</label></div></div></div><div class="row"><div class="col-sm-12">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered dataTable" id="dataTable" width="100%" cellspacing="0" role="grid" aria-describedby="dataTable_info" style="width: 100%;">
|
||||
<thead>
|
||||
<tr role="row" class="textCenter"><th>#</th><th>名称</th><th class="textCenter">上传策略</th><th class="textCenter">最大容量</th><th class="textCenter">下属用户数</th><th class="textCenter">操作</th></tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr><th rowspan="1" colspan="1" class="textCenter">#</th><th rowspan="1" colspan="1">名称</th><th rowspan="1" colspan="1" class="textCenter">上传策略</th><th rowspan="1" colspan="1" class="textCenter">最大容量</th><th rowspan="1" colspan="1" class="textCenter">下属用户数</th><th rowspan="1" colspan="1" class="textCenter">操作</th></tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<tr role="row" class="odd" id="fileList">
|
||||
|
||||
{volist name='list' id='group'}
|
||||
<tr role="row" class="odd">
|
||||
<td class="sorting_1 textCenter">{$group.id}</td>
|
||||
<td>
|
||||
{$group.group_name}
|
||||
</td>
|
||||
<td class="textCenter">
|
||||
{$originList[$key]["policy"]["policy_name"]}
|
||||
</td>
|
||||
<td class="textCenter">{:countSize($group["max_storage"])}</td>
|
||||
<td class="textCenter">{$originList[$key]["user_num"]}</td>
|
||||
<td class="textCenter"><button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="删除" data-action="delete" data-id="{$group.id}" data-unable="{eq name="$originList[$key]['user_num']" value="0"}0{else}1{/eq}"><i class="fa fa-trash" aria-hidden="true"></i></button>
|
||||
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="编辑" data-action="edit" data-id="{$group.id}"><i class="fa fa-edit" aria-hidden="true"></i></button>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-5 mb-2 mt-2" style="display: none" id="del">
|
||||
<button type="button" class="btn btn-danger" id="delAll"><i class="fa fa-trash" aria-hidden="true"></i> 删除选中文件</button>
|
||||
</div>
|
||||
</div></div><div class="row"><div class="col-sm-12 col-md-5"><div class="dataTables_info" id="dataTable_info" role="status" aria-live="polite">展示第 {$pageNow} 页,共 {$pageTotal} 页 {$dataTotal} 条数据</div></div><div class="col-sm-12 col-md-7">
|
||||
<div class="dataTables_paginate paging_simple_numbers" id="dataTable_paginate">
|
||||
{$list->render()}
|
||||
</div></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
<div class="modal fade bd-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true" id="fileInfo">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">文件详情</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>ID:</strong></div>
|
||||
<div class="col-md-12 break" id="fileId">12</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>文件名:</strong></div>
|
||||
<div class="col-md-12 break" id="fileName">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>源文件名:</strong></div>
|
||||
<div class="col-md-12 break" id="fileOrigin">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>上传者UID:</strong></div>
|
||||
<div class="col-md-12 break" id="fileUID">17</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>大小(字节):</strong></div>
|
||||
<div class="col-md-12 break" id="fileSize">7481817</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>图像尺寸:</strong></div>
|
||||
<div class="col-md-12 break" id="filePic">147,445</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>上传策略:</strong></div>
|
||||
<div class="col-md-12 break" id="filePolicy">147,445</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>所属目录:</strong></div>
|
||||
<div class="col-md-12 break" id="fileDir">147,445</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.content-wrapper-->
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/group_list.js"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,206 @@
|
||||
{extend name="header_admin" /}
|
||||
{block name="title"}邮件收发- {$options.siteName}{/block}
|
||||
{block name="content"}
|
||||
<link href="/static/css/admin/summernote.css" rel="stylesheet">
|
||||
<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>
|
||||
<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="pills-home-tab" data-toggle="pill" href="#basic" role="tab" aria-controls="pills-home" aria-selected="true">基本设置</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="pills-profile-tab" data-toggle="pill" href="#test" role="tab" aria-controls="pills-profile" aria-selected="false">发信测试</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="pills-contact-tab" data-toggle="pill" href="#template" role="tab" aria-controls="pills-contact" aria-selected="false">邮件模板</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content" >
|
||||
<div class="tab-pane fade show active" id="basic" role="tabpanel" aria-labelledby="pills-home-tab">
|
||||
<form id="basicOptionsForm">
|
||||
<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="fromName" value="{$optionsForSet.fromName}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 显示在邮件发件邮箱旁的发件人姓名</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="fromAdress" class="col-form-label col-form-label-sm">发件人邮箱</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="email" class="form-control" name="fromAdress" value="{$optionsForSet.fromAdress}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 发件邮箱的地址</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="smtpHost" class="col-form-label col-form-label-sm">SMTP服务器</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="email" class="form-control" name="smtpHost" value="{$optionsForSet.smtpHost}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 发信邮箱的SMTP服务器地址</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="smtpPort" class="col-form-label col-form-label-sm">端口</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="text" class="form-control" name="smtpPort" value="{$optionsForSet.smtpPort}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 发信邮箱SMTP服务器的端口</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="smtpPort" class="col-form-label col-form-label-sm">加密方式</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select class="form-control" name="encriptionType">
|
||||
<option value="no" {eq name="$optionsForSet.encriptionType" value="no"}selected{/eq}>不启用</option>
|
||||
<option value="tls" {eq name="$optionsForSet.encriptionType" value="tls"}selected{/eq}>TLS</option>
|
||||
<option value="ssl" {eq name="$optionsForSet.encriptionType" value="ssl"}selected{/eq}>SSL</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="smtpUser" class="col-form-label col-form-label-sm">用户名</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="email" class="form-control" name="smtpUser" value="{$optionsForSet.smtpUser}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 发信邮箱用户名,一般与邮箱相同</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="smtpPass" class="col-form-label col-form-label-sm">密码</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="password" class="form-control" name="smtpPass" value="{$optionsForSet.smtpPass}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 发信邮箱密码</div>
|
||||
</div>
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="replyTo" class="col-form-label col-form-label-sm">回信邮箱</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="email" class="form-control" name="replyTo" value="{$optionsForSet.replyTo}" spellcheck="false"></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="button" class="btn btn-primary" id="saveMail">保存设置</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br><br><br>
|
||||
</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">
|
||||
|
||||
<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="receiveMail" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 接受测试邮件的收件人邮箱</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="subject" spellcheck="false" value="这是一封测试邮件"></div>
|
||||
<div class="col-md-4 option-des"> 测试邮件的主题</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-8"> <textarea class="form-control" name="content" spellcheck="false" id="content" > 这是一封由Cloudreve发出的测试邮件,用于测试邮件设置是否正常工作。</textarea></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="sendMail">发送测试邮件</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br><br><br>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="template" role="tabpanel" aria-labelledby="pills-profile-tab">
|
||||
<form id="mailTemplate">
|
||||
|
||||
|
||||
|
||||
<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-8"> <textarea class="form-control textEdit" name="mail_activation_template" spellcheck="false" > {$optionsForSet.mail_activation_template}</textarea>
|
||||
</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-8"> <textarea class="form-control textEdit" name="mail_reset_pwd_template" spellcheck="false" > {$optionsForSet.mail_reset_pwd_template}</textarea>
|
||||
</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="saveTemplate">保存设置</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br><br><br>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</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/setting.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('#content').summernote({
|
||||
lang:"zh-CN",
|
||||
height: 150,
|
||||
});
|
||||
});
|
||||
$(document).ready(function() {
|
||||
$('.textEdit').summernote({
|
||||
lang:"zh-CN",
|
||||
height: 300,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,127 @@
|
||||
{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>
|
||||
<form id="mailTemplate">
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="maxEditSize" class="col-form-label col-form-label-sm">文本编辑大小限制</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="email" class="form-control" name="maxEditSize" value="{$optionsForSet.maxEditSize}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 用户可在线编辑的文本类文件的最大尺寸。单位:字节</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="maxEditSize" class="col-form-label col-form-label-sm">允许游客下载</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{eq name="$optionsForSet.allowdVisitorDownload" value="true"}
|
||||
<input class="" type="radio" name="allowdVisitorDownload" id="inlineRadio1" value="true" checked>
|
||||
<label class="" for="inlineRadio1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="allowdVisitorDownload" id="inlineRadio2" value="false">
|
||||
<label class="" for="inlineRadio2">拒绝</label>
|
||||
{else}
|
||||
<input class="" type="radio" name="allowdVisitorDownload" id="inlineRadio1" value="true">
|
||||
<label class="" for="inlineRadio1" >允许</label>
|
||||
|
||||
<input class="" type="radio" name="allowdVisitorDownload" id="inlineRadio2" value="false" checked>
|
||||
<label class="" for="inlineRadio2">拒绝</label>
|
||||
{/eq}
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否允许未登录用户下载被分享的文件</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-setting">
|
||||
<div class="col-md-1 form-label ">
|
||||
<label for="hot_share_num" class="col-form-label col-form-label-sm">热门分享展示数量</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="email" class="form-control" name="hot_share_num" value="{$optionsForSet.hot_share_num}" spellcheck="false"></div>
|
||||
<div class="col-md-4 option-des"> 在用户个人主页展示的热门分享的个数</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">Gravatar服务器</label>
|
||||
</div>
|
||||
<div class="col-md-4"> <input type="email" class="form-control" name="gravatar_server" value="{$optionsForSet.gravatar_server}" spellcheck="false"></div>
|
||||
<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>
|
||||
<div class="col-md-4"> <button type="button" class="btn btn-primary" id="saveTemplate">保存设置</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br><br><br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
|
||||
<!-- /.content-wrapper-->
|
||||
|
||||
|
||||
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/setting.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,176 @@
|
||||
{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>
|
||||
</ol>
|
||||
|
||||
<!-- Area Chart Example-->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2>上传策略</h2>
|
||||
<br>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-tags"></i> 条件检索</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-1 form-label-search mb-2">类型</div>
|
||||
<div class="col-md-10">
|
||||
<ul class="nav nav-pills" id="policyType">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-policy="">全部</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-policy="local">本地</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-policy="qiniu">七牛</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-policy="oss">OSS</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-policy="upyun">又拍云</a>
|
||||
</li>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-table"></i> 上传策略列表</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<div id="dataTable_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4"><div class="row"><div class="col-sm-12 col-md-6"><div class="dataTables_length" ><label>每页展示 <select id="dataTable_length" aria-controls="dataTable" class="form-control form-control-sm"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select> 个</label></div></div><div class="col-sm-12 col-md-6"><div id="dataTable_filter" class="dataTables_filter"><label>搜索:<input type="search" class="form-control form-control-sm" placeholder="" id="searchFrom"></label></div></div></div><div class="row"><div class="col-sm-12">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered dataTable" id="dataTable" width="100%" cellspacing="0" role="grid" aria-describedby="dataTable_info" style="width: 100%;">
|
||||
<thead>
|
||||
<tr role="row" class="textCenter"><th>#</th><th>名称</th><th class="textCenter">类型</th><th class="textCenter">下属文件数</th><th class="textCenter">数据量</th><th class="textCenter">操作</th></tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr><th rowspan="1" colspan="1" class="textCenter">#</th><th rowspan="1" colspan="1">名称</th><th rowspan="1" colspan="1" class="textCenter">类型</th><th rowspan="1" colspan="1" class="textCenter">下属文件数</th><th rowspan="1" colspan="1" class="textCenter">数据量</th><th rowspan="1" colspan="1" class="textCenter">操作</th></tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<tr role="row" class="odd" id="fileList">
|
||||
|
||||
{volist name='list' id='policy'}
|
||||
<tr role="row" class="odd">
|
||||
<td class="sorting_1 textCenter">{$policy.id}</td>
|
||||
<td>
|
||||
{$policy.policy_name}
|
||||
</td>
|
||||
<td class="textCenter">
|
||||
{switch name="policy.policy_type"}
|
||||
{case value="local"}本地{/case}
|
||||
{case value="qiniu"}七牛{/case}
|
||||
{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>
|
||||
<td class="textCenter">{$originList[$key]["file_num"]}</td>
|
||||
<td class="textCenter">{:countSize($originList[$key]["file_size"])}</td>
|
||||
<td class="textCenter"><button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="删除" data-action="delete" data-id="{$policy.id}" data-unable="{eq name="$originList[$key]['file_num']" value="0"}0{else}1{/eq}"><i class="fa fa-trash" aria-hidden="true"></i></button>
|
||||
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="编辑" data-action="edit" data-id="{$policy.id}"><i class="fa fa-edit" aria-hidden="true"></i></button>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-5 mb-2 mt-2" style="display: none" id="del">
|
||||
<button type="button" class="btn btn-danger" id="delAll"><i class="fa fa-trash" aria-hidden="true"></i> 删除选中文件</button>
|
||||
</div>
|
||||
</div></div><div class="row"><div class="col-sm-12 col-md-5"><div class="dataTables_info" id="dataTable_info" role="status" aria-live="polite">展示第 {$pageNow} 页,共 {$pageTotal} 页 {$dataTotal} 条数据</div></div><div class="col-sm-12 col-md-7">
|
||||
<div class="dataTables_paginate paging_simple_numbers" id="dataTable_paginate">
|
||||
{$list->render()}
|
||||
</div></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
<div class="modal fade bd-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true" id="fileInfo">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">文件详情</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>ID:</strong></div>
|
||||
<div class="col-md-12 break" id="fileId">12</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>文件名:</strong></div>
|
||||
<div class="col-md-12 break" id="fileName">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>源文件名:</strong></div>
|
||||
<div class="col-md-12 break" id="fileOrigin">5c06e532e7afdb4389e4ae846ea7876c_w - 副本 - 副本.jpg</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>上传者UID:</strong></div>
|
||||
<div class="col-md-12 break" id="fileUID">17</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>大小(字节):</strong></div>
|
||||
<div class="col-md-12 break" id="fileSize">7481817</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>图像尺寸:</strong></div>
|
||||
<div class="col-md-12 break" id="filePic">147,445</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>上传策略:</strong></div>
|
||||
<div class="col-md-12 break" id="filePolicy">147,445</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12"><strong>所属目录:</strong></div>
|
||||
<div class="col-md-12 break" id="fileDir">147,445</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.content-wrapper-->
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/policy.js"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,134 @@
|
||||
{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>
|
||||
<form id="basicOptionsForm">
|
||||
<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">
|
||||
{eq name="$optionsForSet.regStatus" value="0"}
|
||||
<input class="" type="radio" name="regStatus" id="inlineRadio1" value="0"checked>
|
||||
<label class="" for="inlineRadio1" >是</label>
|
||||
|
||||
<input class="" type="radio" name="regStatus" id="inlineRadio2" value="1">
|
||||
<label class="" for="inlineRadio2">否</label>
|
||||
{else}
|
||||
<input class="" type="radio" name="regStatus" id="inlineRadio1" value="0">
|
||||
<label class="" for="inlineRadio1" >是</label>
|
||||
|
||||
<input class="" type="radio" name="regStatus" id="inlineRadio2" value="1" checked>
|
||||
<label class="" for="inlineRadio2">否</label>
|
||||
{/eq}
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否允许新用户注册</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">
|
||||
<select class="form-control" name="defaultGroup">
|
||||
{volist name="groups" id="group"}
|
||||
{eq name="$group.id" value="$optionsForSet.defaultGroup"}
|
||||
<option value="{$group.id}" selected>{$group.group_name}</option>
|
||||
{else}
|
||||
<option value="{$group.id}">{$group.group_name}</option>
|
||||
{/eq}
|
||||
{/volist}
|
||||
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 用户注册后默认属于的用户组</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 type="checkbox" id="inlineCheckbox3" name="email_active" value="1" {eq name="$optionsForSet.email_active" value="1" }checked{/eq}>
|
||||
<label for="inlineCheckbox3">启用</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 启用后,新用户注册需要点击邮件中的激活链接才能完成。请确认邮件发送设置是否正确,否则激活邮件无法送达</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 type="checkbox" id="login_captcha" name="login_captcha" value="1" {eq name="$optionsForSet.login_captcha" value="1" }checked{/eq}>
|
||||
<label for="login_captcha">启用</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否启用登录表单验证码</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 type="checkbox" id="reg_captcha" name="reg_captcha" value="1" {eq name="$optionsForSet.reg_captcha" value="1" }checked{/eq}>
|
||||
<label for="reg_captcha">启用</label>
|
||||
</div>
|
||||
<div class="col-md-4 option-des"> 是否启用注册表单验证码</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 type="checkbox" id="forget_captcha" name="forget_captcha" value="1" {eq name="$optionsForSet.forget_captcha" value="1" }checked{/eq}>
|
||||
<label for="forget_captcha">启用</label>
|
||||
</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="button" class="btn btn-primary" id="saveReg">保存设置</button></div>
|
||||
<div class="col-md-4 option-des"> </div>
|
||||
<br><br><br>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
|
||||
<!-- /.content-wrapper-->
|
||||
|
||||
|
||||
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/setting.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,110 @@
|
||||
{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>
|
||||
</ol>
|
||||
|
||||
<!-- Area Chart Example-->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2>分享</h2>
|
||||
<br>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-tags"></i> 条件检索</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-1 form-label-search mb-2">排序方式</div>
|
||||
<div class="col-md-10">
|
||||
<ul class="nav nav-pills" id="order">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-method="id DESC">日期</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-method="download_num DESC">下载次数</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-method="view_num DESC">浏览次数</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-table"></i> 分享列表</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<div id="dataTable_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4"><div class="row"><div class="col-sm-12 col-md-6"><div class="dataTables_length" ><label>每页展示 <select id="dataTable_length" aria-controls="dataTable" class="form-control form-control-sm"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select> 个</label></div></div><div class="col-sm-12 col-md-6"><div id="dataTable_filter" class="dataTables_filter"><label>搜索:<input type="search" class="form-control form-control-sm" placeholder="" id="searchFrom"></label></div></div></div><div class="row"><div class="col-sm-12">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered dataTable" id="dataTable" width="100%" cellspacing="0" role="grid" aria-describedby="dataTable_info" style="width: 100%;">
|
||||
<thead>
|
||||
<tr role="row" class="textCenter"><th><input type="checkbox" data-type="all"></th><th>分享名称</th><th class="textCenter">分享者</th><th class="textCenter">类型</th><th class="textCenter">日期</th><th class="textCenter">浏览次数</th><th class="textCenter">下载次数</th><th class="textCenter">操作</th></tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr><th rowspan="1" colspan="1" class="textCenter"><input type="checkbox" data-type="all"></th><th rowspan="1" colspan="1" class="textCenter">分享名称</th><th rowspan="1" colspan="1" class="textCenter">分享者</th><th rowspan="1" colspan="1" class="textCenter">类型</th><th rowspan="1" colspan="1" class="textCenter">日期</th><th rowspan="1" colspan="1" class="textCenter">浏览次数</th><th rowspan="1" colspan="1" class="textCenter">下载次数</th><th rowspan="1" colspan="1" class="textCenter">操作</th></tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<tr role="row" class="odd" id="fileList">
|
||||
|
||||
{volist name='list' id='share'}
|
||||
<tr role="row" class="odd">
|
||||
<td class="sorting_1 textCenter"><input type="checkbox" data-type="mark" data-id="{$share.id}"></td>
|
||||
<td>
|
||||
{eq name="$share.source_type" value="dir"}
|
||||
<i class="fa fa-folder-open-o" aria-hidden="true"></i> <a href="/S/{$share.share_key}?pwd={$share.share_pwd}" class="noAColor" target="_blank">{:htmlspecialchars(getDirName($share.source_name),ENT_NOQUOTES)}</a>
|
||||
{else}
|
||||
<i class="fa fa-file" aria-hidden="true"></i> <a href="/S/{$share.share_key}?pwd={$share.share_pwd}" class="noAColor" target="_blank">{$share.origin_name|htmlspecialchars=ENT_NOQUOTES}</a>
|
||||
{/eq}
|
||||
</td>
|
||||
<td class="textCenter">{$originList[$key]["user"]["user_nick"]}</td>
|
||||
<td class="textCenter">
|
||||
{eq name="share.type" value="public"}
|
||||
<i class="fa fa-eye" aria-hidden="true"></i> 公开
|
||||
{else/}
|
||||
<i class="fa fa-lock" aria-hidden="true"></i> 私密
|
||||
{/eq}
|
||||
</td>
|
||||
<td class="textCenter">{$share.share_time}</td>
|
||||
<td class="textCenter">{$share.view_num}</td>
|
||||
<td class="textCenter">{$share.download_num}</td>
|
||||
<td class="textCenter"><button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="删除" data-action="delete" data-id="{$share.id}"><i class="fa fa-trash" aria-hidden="true"></i></button> <button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="变更分享类型" data-action="change" data-id="{$share.share_key}"><i class="fa fa-lock" aria-hidden="true"></i></button></td>
|
||||
</tr>
|
||||
{/volist}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-5 mb-2 mt-2" style="display: none" id="del">
|
||||
<button type="button" class="btn btn-danger" id="delAll"><i class="fa fa-trash" aria-hidden="true"></i> 删除选中文件</button>
|
||||
</div>
|
||||
</div></div><div class="row"><div class="col-sm-12 col-md-5"><div class="dataTables_info" id="dataTable_info" role="status" aria-live="polite">展示第 {$pageNow} 页,共 {$pageTotal} 页 {$dataTotal} 条数据</div></div><div class="col-sm-12 col-md-7">
|
||||
<div class="dataTables_paginate paging_simple_numbers" id="dataTable_paginate">
|
||||
{$list->render()}
|
||||
</div></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
<!-- /.content-wrapper-->
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/shares.js"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -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}
|
||||
@@ -0,0 +1,51 @@
|
||||
{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>
|
||||
</ol>
|
||||
|
||||
<!-- Area Chart Example-->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2>编辑模板</h2>
|
||||
application/index/view/{:rtrim($path,"/")}/{$name}.html
|
||||
<br> <br>
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<input type="text" id="fileName" value="{$name}" style="display: none">
|
||||
<textarea rows="15" class="form-control" spellcheck="false" style=" font-family: 'Courier New';">{:htmlspecialchars($content)}</textarea>
|
||||
<br>
|
||||
<button class="btn btn-primary" id="saveTheme">保存</button>
|
||||
<br><br>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="file_side">
|
||||
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||
{volist name="list" id="file"}
|
||||
<a class="nav-link" id="v-pills-home-tab" href="/Admin/Theme/name/{:str_replace(".html","",$file)}" role="tab" data-name="{:str_replace(".html","",$file)}">{$file}</a>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/config.js"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,298 @@
|
||||
{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>
|
||||
</ol>
|
||||
|
||||
<!-- Area Chart Example-->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2>用户 <button class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#addUser"><li class="fa fa-plus"></li></button></h2>
|
||||
<br>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-tags"></i> 条件检索</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-1 form-label-search mb-2">排序方式</div>
|
||||
<div class="col-md-10">
|
||||
<ul class="nav nav-pills" id="order">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-method="user_nick ASC">用户名</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-method="id DESC">注册日期</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-method="used_storage DESC">已用空间</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-1 form-label-search mb-2">用户组</div>
|
||||
<div class="col-md-10">
|
||||
<ul class="nav nav-pills" id="groupS">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-group="">全部</a>
|
||||
</li>
|
||||
{volist name="group" id="group"}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-group="{$group.id}">{$group.group_name}</a>
|
||||
</li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-1 form-label-search mb-2">用户状态</div>
|
||||
<div class="col-md-10">
|
||||
<ul class="nav nav-pills" id="status">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-status="">全部</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-status="1">正常</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link selectLab" href="javascript:void()" data-status="2">封禁/未激活</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 5px;">
|
||||
<div class="col-1 form-label-search mb-2">高级检索</div>
|
||||
<div class="col-md-10">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<select class="form-control form-control-sm" id="searchColUser">
|
||||
<option value="id">用户UID</option>
|
||||
<option value="user_nick">用户昵称</option>
|
||||
<option value="user_date">注册日期</option>
|
||||
<option value="user_email">邮箱</option>
|
||||
<option value="group_primary">初始用户组</option>
|
||||
<option value="user_activation_key">邮箱激活密钥</option>
|
||||
<option value="used_storage">已用空间</option>
|
||||
<option value="delay_time">用户组过期日期</option>
|
||||
<option value="avatar">头像标识</option>
|
||||
<option value="profile">个人主页状态</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input type="text" class="form-control form-control-sm" placeholder="检索表达式" id="searchValueUser">
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<button type="button" class="btn btn-primary btn-sm" id="applySearch">应用</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-table"></i> 用户列表 </div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<div id="dataTable_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4"><div class="row"><div class="col-sm-12 col-md-6"><div class="dataTables_length" ><label>每页展示 <select id="dataTable_length" aria-controls="dataTable" class="form-control form-control-sm"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select> 个</label></div></div><div class="col-sm-12 col-md-6"><div id="dataTable_filter" class="dataTables_filter"><label>搜索:<input type="search" class="form-control form-control-sm" placeholder="" id="searchFrom"></label></div></div></div><div class="row"><div class="col-sm-12">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered dataTable" id="dataTable" width="100%" cellspacing="0" role="grid" aria-describedby="dataTable_info" style="width: 100%;">
|
||||
<thead>
|
||||
<tr role="row" class="textCenter"><th><input type="checkbox" data-type="all"></th><th>UID</th><th>昵称</th><th class="textCenter">邮箱</th><th class="textCenter">用户组</th><th class="textCenter">空间用量</th><th class="textCenter">状态</th><th class="textCenter">操作</th></tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr><th rowspan="1" colspan="1" class="textCenter"><input type="checkbox" data-type="all"></th><th rowspan="1" colspan="1" class="textCenter">UID</th><th rowspan="1" colspan="1" class="textCenter">昵称</th><th rowspan="1" colspan="1" class="textCenter">邮箱</th><th rowspan="1" colspan="1" class="textCenter">用户组</th><th rowspan="1" colspan="1" class="textCenter">空间用量</th><th rowspan="1" colspan="1" class="textCenter">状态</th><th rowspan="1" colspan="1" class="textCenter">操作</th></tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<tr role="row" class="odd" id="userList">
|
||||
|
||||
{volist name='list' id='user'}
|
||||
<tr role="row" class="odd">
|
||||
<td class="sorting_1 textCenter"><input type="checkbox" data-type="mark" data-id="{$user.id}"></td>
|
||||
<td class="textCenter">{$user.id}</td>
|
||||
<td class="textCenter">{$user.user_nick}</td>
|
||||
<td class="textCenter">{$user.user_email}</td>
|
||||
<td class="textCenter">{:$originList[$key]["group"]["group_name"]}</td>
|
||||
<td class="textCenter">{:countSize($user.used_storage)}</td>
|
||||
<td class="textCenter">
|
||||
{eq name="user.user_status" value="0"}
|
||||
<span class="order_success">正常</span>
|
||||
{else/}
|
||||
<span class="order_warning">封禁/未激活</span>
|
||||
{/eq}
|
||||
</td>
|
||||
<td class="textCenter">
|
||||
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="删除" data-action="delete" data-id="{$user.id}" data-unable="{eq name="user.used_storage" value="0"}0{else/}1{/eq}"><i class="fa fa-trash" aria-hidden="true"></i></button>
|
||||
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="编辑" data-action="edit" data-id="{$user.id}"><i class="fa fa-id-card" aria-hidden="true"></i></button>
|
||||
<button type="button" class="btn btn-secondary fix" data-toggle="tooltip" data-placement="top" title="封号/解封" data-action="ban" data-id="{$user.id}"><i class="fa fa-ban" aria-hidden="true"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-5 mb-2 mt-2" style="display: none" id="del">
|
||||
<button type="button" class="btn btn-danger" id="delAll"><i class="fa fa-trash" aria-hidden="true"></i> 删除选中用户</button>
|
||||
</div>
|
||||
</div></div><div class="row"><div class="col-sm-12 col-md-5"><div class="dataTables_info" id="dataTable_info" role="status" aria-live="polite">展示第 {$pageNow} 页,共 {$pageTotal} 页 {$dataTotal} 条数据</div></div><div class="col-sm-12 col-md-7">
|
||||
<div class="dataTables_paginate paging_simple_numbers" id="dataTable_paginate">
|
||||
{$list->render()}
|
||||
</div></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Example DataTables Card-->
|
||||
</div>
|
||||
<!-- /.container-fluid-->
|
||||
</div>
|
||||
<div class="modal fade bd-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true" id="editUser">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">用户详情</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="editUserForm">
|
||||
<div class="form-group">
|
||||
<label>
|
||||
头像
|
||||
</label>
|
||||
<img src="" id="user_avatar">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="name">UID</label>
|
||||
<input type="text" name="uid" id="uid" style="display: none;">
|
||||
<input class="form-control" id="id" type="text" value="17" readonly>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="lovelyname">昵称</label>
|
||||
<input type="text " class="form-control" id="user_nick" name="user_nick" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="InputPassword1">密码</label>
|
||||
<input type="password" class="form-control" id="user_pass" name="user_pass" placeholder="如果不修改密码则留空" >
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="InputEmail1">邮箱</label>
|
||||
<input type="email" class="form-control" id="user_email" name="user_email" placeholder="Email" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="date">注册日期</label>
|
||||
<input class="form-control" id="user_date" type="text" value="2017.12.31" readonly>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="space">已用空间</label>
|
||||
<input class="form-control" id="used_storage" type="text" value="500M" readonly>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="openid">二步验证秘钥</label>
|
||||
<input type="text " class="form-control" id="two_step" name="two_step" placeholder="取消二步验证请填写0" required="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputState">用户状态</label>
|
||||
<select class="form-control" id="user_status" name="user_status">
|
||||
<option value="0">正常</option>
|
||||
<option value="1">封禁/未激活</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputState">用户组</label>
|
||||
<select id="user_group" class="form-control" name="user_group">
|
||||
{foreach $groups as $g}
|
||||
<option value="{$g.id}">{$g.group_name}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputState">个人主页状态</label>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="profile" id="profile1" value="1">
|
||||
开启
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="profile" id="profile0" value="0">
|
||||
关闭
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
|
||||
<button type="submit" class="btn btn-primary" id="editUserSubmit">保存</button>
|
||||
</div></form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade bd-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true" id="addUser">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">添加用户</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="addUserForm">
|
||||
<div class="form-group">
|
||||
<label for="lovelyname">昵称</label>
|
||||
<input type="text " class="form-control" id="user_nick" name="user_nick" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="InputPassword1">密码</label>
|
||||
<input type="password" class="form-control" id="user_pass" name="user_pass" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="InputEmail1">邮箱</label>
|
||||
<input type="email" class="form-control" id="user_email" name="user_email" placeholder="Email" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputState">用户状态</label>
|
||||
<select class="form-control" name="user_status">
|
||||
<option value="0">正常</option>
|
||||
<option value="1">封禁/未激活</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputState">用户组</label>
|
||||
<select class="form-control" name="user_group">
|
||||
{foreach $groups as $g}
|
||||
<option value="{$g.id}">{$g.group_name}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
|
||||
<button type="submit" class="btn btn-primary" id="addUserSubmit">保存</button>
|
||||
</div></form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.content-wrapper-->
|
||||
{/block}
|
||||
{block name="js"}
|
||||
<script src="/static/js/admin/users.js"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,23 @@
|
||||
{extend name="header_public" /}
|
||||
{block name="title"}支付成功 - {$options.siteName}{/block}
|
||||
{block name="content"}
|
||||
<link rel="stylesheet" href="/static/css/error.css" />
|
||||
</head>
|
||||
<body data-ma-header="teal">
|
||||
|
||||
<div class="container" align="center">
|
||||
<header align="left">
|
||||
<br>
|
||||
<img src="/img/logo_s.png" style="width:192px;">
|
||||
</header>
|
||||
<div class="error_content" >
|
||||
<div class="jumbotron animated bounce" style="padding-left:30px;">
|
||||
<h1>支付成功</h1>
|
||||
<br>
|
||||
<p> 付款成功,您所购买的服务已开通。</p>
|
||||
<p><a class="btn btn-primary btn-lg" href="/Home/Quota">查看详情</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
{/block}
|
||||
@@ -0,0 +1,19 @@
|
||||
<link rel="stylesheet" href="/static/css/error.css" />
|
||||
</head>
|
||||
<body data-ma-header="teal">
|
||||
|
||||
<div class="container" align="center">
|
||||
<header align="left">
|
||||
<br>
|
||||
<img src="/static/img/logo_s.png" style="width:192px;">
|
||||
</header>
|
||||
<div class="error_content" >
|
||||
<div class="jumbotron animated bounce" style="padding-left:30px;">
|
||||
<h1>发生错误</h1>
|
||||
<br>
|
||||
<p> {$msg}</p>
|
||||
<p><a class="btn btn-primary btn-lg" onclick="history.go(-1);"><< 返回</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
@@ -0,0 +1,24 @@
|
||||
{extend name="header_public" /}
|
||||
{block name="title"}错误提示 - {$options.siteName}{/block}
|
||||
{block name="content"}
|
||||
<link rel="stylesheet" href="/static/css/error.css" />
|
||||
</head>
|
||||
<body data-ma-header="teal">
|
||||
|
||||
<div class="container" align="center">
|
||||
<header align="left">
|
||||
<br>
|
||||
<img src="/static/img/logo_s.png" style="width:192px;">
|
||||
</header>
|
||||
<div class="error_content" >
|
||||
<div class="jumbotron animated bounce" style="padding-left:30px;">
|
||||
<h1>发生错误</h1>
|
||||
<br>
|
||||
<p> {$msg}</p>
|
||||
<p><a class="btn btn-primary btn-lg" onclick="history.go(-1);"><< 返回</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{$options.js_code}
|
||||
</body>
|
||||
{/block}
|
||||
@@ -0,0 +1,23 @@
|
||||
<!doctype html><html lang="zh-cn"><head><meta charset="utf-8"><link rel="shortcut icon" href="/favicon.ico"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="{$options.themeColor}"/><link rel="manifest" href="/manifest.json"><title>“{$keyWords}”搜索结果 - {$options.siteName}</title><script type="text/javascript">colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = false;
|
||||
isSharePage = false;
|
||||
pageId="shareLock";
|
||||
list = {$list};
|
||||
userInfo = {
|
||||
uid: {$userData.uid},
|
||||
nick: "{$userData.userNick}",
|
||||
email: "{$userData.userMail}",
|
||||
group: "{$userData.groupData.group_name}",
|
||||
groupId: {$userData.groupData.id},
|
||||
groupColor: "{$userData.groupData.color}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "{$options.siteName}",
|
||||
};
|
||||
uploadConfig = {
|
||||
allowSource: false,
|
||||
allowShare: false,
|
||||
allowRemoteDownload: "0",
|
||||
allowTorrentDownload: "0",
|
||||
};
|
||||
isMobile = window.innerWidth < 600;</script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(l){function e(e){for(var r,t,n=e[0],o=e[1],u=e[2],f=0,i=[];f<n.length;f++)t=n[f],p[t]&&i.push(p[t][0]),p[t]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(l[r]=o[r]);for(s&&s(e);i.length;)i.shift()();return c.push.apply(c,u||[]),a()}function a(){for(var e,r=0;r<c.length;r++){for(var t=c[r],n=!0,o=1;o<t.length;o++){var u=t[o];0!==p[u]&&(n=!1)}n&&(c.splice(r--,1),e=f(f.s=t[0]))}return e}var t={},p={21:0},c=[];function f(e){if(t[e])return t[e].exports;var r=t[e]={i:e,l:!1,exports:{}};return l[e].call(r.exports,r,r.exports,f),r.l=!0,r.exports}f.m=l,f.c=t,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(r,e){if(1&e&&(r=f(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var n in r)f.d(t,n,function(e){return r[e]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var r=window.webpackJsonp=window.webpackJsonp||[],n=r.push.bind(r);r.push=e,r=r.slice();for(var o=0;o<r.length;o++)e(r[o]);var s=n;a()}([])</script><script src="/static/js/0.chunk.js"></script><script src="/static/js/2.chunk.js"></script><script src="/static/js/search.chunk.js"></script></body></html>
|
||||
@@ -0,0 +1,5 @@
|
||||
下载已开始...
|
||||
<a href="{$url}" download="" id="downloadA">手动下载</a>
|
||||
<script type="text/javascript">
|
||||
document.getElementById("downloadA").click();
|
||||
</script>
|
||||
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="full-height">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<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 -->
|
||||
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="/static/css/bootstrap4/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Material Design Bootstrap -->
|
||||
<link href="/static/css/mdb.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
<body class="grey-skin intro-page creative-lp">
|
||||
<!--Navigation & Intro-->
|
||||
<header>
|
||||
|
||||
<!--Navbar-->
|
||||
<nav class="navbar fixed-top navbar-dark ">
|
||||
|
||||
<div class="container">
|
||||
|
||||
|
||||
<a class="navbar-brand" href="#">
|
||||
<img src="static/img/logo_s.png" style=" width: 192px;">
|
||||
</a>
|
||||
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
<!--/Navbar-->
|
||||
@@ -0,0 +1,211 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh_cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<title>{block name="title"}{/block}</title>
|
||||
<!-- Bootstrap core CSS-->
|
||||
<link href="/static/css/bootstrap4/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Custom fonts for this template-->
|
||||
<link href="/static/css/font-awesome.min.css" rel="stylesheet" type="text/css">
|
||||
<!-- Page level plugin CSS-->
|
||||
<link href="/static/css/datatables/dataTables.bootstrap4.css" rel="stylesheet">
|
||||
<link href="/static/css/toastr.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Custom styles for this template-->
|
||||
<link href="/static/css/sb-admin.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body class="{$options.admin_color_body}" id="page-top">
|
||||
<!-- Navigation-->
|
||||
<nav class="{$options.admin_color_nav}" id="mainNav">
|
||||
<a class="navbar-brand" href="index.html">Cloudreve</a>
|
||||
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<ul class="navbar-nav navbar-sidenav" id="exampleAccordion">
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="面板首页">
|
||||
<a class="nav-link" href="/Admin">
|
||||
<i class="fa fa-fw fa-dashboard"></i>
|
||||
<span class="nav-link-text">面板首页</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="设置">
|
||||
<a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#collapseComponents" data-parent="#exampleAccordion">
|
||||
<i class="fa fa-fw fa-wrench"></i>
|
||||
<span class="nav-link-text">设置</span>
|
||||
</a>
|
||||
<ul class="sidenav-second-level collapse" id="collapseComponents">
|
||||
<li>
|
||||
<a href="/Admin/Setting">基础设置</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/Admin/SettingReg">注册访问</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/Admin/SettingMail">邮件发送</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/Admin/Config">配置文件</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/Admin/SettingOther">杂项</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="模板">
|
||||
<a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#theme">
|
||||
<i class="fa fa-fw fa-paint-brush"></i>
|
||||
<span class="nav-link-text">模板</span>
|
||||
</a>
|
||||
<ul class="sidenav-second-level collapse" id="theme">
|
||||
<li>
|
||||
<a href="/Admin/Theme">模板</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/Admin/Color">配色方案</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="文件">
|
||||
<a class="nav-link" href="/Admin/Files">
|
||||
<i class="fa fa-fw fa-folder"></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/Shares">
|
||||
<i class="fa fa-fw fa-send"></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/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>
|
||||
<span class="nav-link-text">用户</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="用户组">
|
||||
<a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#group" data-parent="#group">
|
||||
<i class="fa fa-fw fa-users"></i>
|
||||
<span class="nav-link-text">用户组</span>
|
||||
</a>
|
||||
<ul class="sidenav-second-level collapse" id="group">
|
||||
<li>
|
||||
<a href="/Admin/GroupList">管理</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/Admin/GroupAdd">添加</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="上传策略">
|
||||
<a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#policy" data-parent="#policy">
|
||||
<i class="fa fa-fw fa-upload"></i>
|
||||
<span class="nav-link-text">上传策略</span>
|
||||
</a>
|
||||
<ul class="sidenav-second-level collapse" id="policy">
|
||||
<li>
|
||||
<a href="/Admin/PolicyList">管理</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/Admin/PolicyAdd">添加</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="其他">
|
||||
<a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#else" data-parent="#else">
|
||||
<i class="fa fa-fw fa-ellipsis-h"></i>
|
||||
<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>
|
||||
<li>
|
||||
<a href="/Admin/About">关于</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav sidenav-toggler">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-center" id="sidenavToggler">
|
||||
<i class="fa fa-fw fa-angle-left"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="javascript:void" id="toggleNavColor">
|
||||
<i class="fa fa-fw fa-toggle-on" aria-hidden="true"></i>切换配色</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">
|
||||
<i class="fa fa-fw fa-home"></i>返回首页</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="modal" data-target="#exampleModal">
|
||||
<i class="fa fa-fw fa-sign-out"></i>登出</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
{block name="content"}{/block}
|
||||
<footer class="sticky-footer">
|
||||
<div class="container">
|
||||
<div class="text-center">
|
||||
<small>Copyright © Cloudreve {php}echo date("Y");{/php} </small>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Scroll to Top Button-->
|
||||
<a class="scroll-to-top rounded" href="#page-top">
|
||||
<i class="fa fa-angle-up"></i>
|
||||
</a>
|
||||
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">确认</h5>
|
||||
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">点击“登出”按钮退出当前账户。</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" type="button" data-dismiss="modal">取消</button>
|
||||
<a class="btn btn-primary" href="/Member/LogOut">登出</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/js/jquery.min.js"></script>
|
||||
<script src="/static/js/bootstrap4/bootstrap.bundle.min.js"></script>
|
||||
<!-- Core plugin JavaScript-->
|
||||
<script src="/static/js/chart.js/Chart.min.js"></script>
|
||||
<!-- Custom scripts for all pages-->
|
||||
<script src="/static/js/sb-admin.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/toastr.min.js"></script>
|
||||
{block name="js"}
|
||||
{/block}
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
<html lang="zh-cn" data-ng-app="FileManagerApp">
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
|
||||
<meta charset="utf-8">
|
||||
<title>{block name="title"}{/block}</title>
|
||||
<!-- third party -->
|
||||
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="/static/css/material.css" />
|
||||
<link rel="stylesheet" href="/static/css/animate.css" />
|
||||
<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">
|
||||
<!-- /Comment if you need to use raw source code -->
|
||||
{block name="content"}{/block}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user