├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── dist
└── index.php
├── docs
├── index.html
└── install.html
├── index.php
├── nodejs
├── .env
├── .gitignore
├── README.md
├── babel.config.js
├── build
│ └── webpack.config.js
├── index.js
├── package.json
├── platforms
│ ├── aliyun_fc.js
│ ├── aws_sc.js
│ ├── azure_functions.js
│ ├── cloudflare_workers.js
│ ├── google_cf.js
│ ├── heroku.js
│ └── qcloud_scf.js
├── tests
│ └── test1.js
└── utils
│ ├── helper.js
│ └── http-client.js
└── php
├── .gitignore
├── .htaccess
├── README.md
├── composer.json
├── config.example.php
├── index.php
├── library
├── Ext.php
├── Lang.php
├── OneDrive.php
└── functions.php
├── platforms
├── AliyunSC
│ └── AliyunSC.php
├── Heroku
│ └── Heroku.php
├── Normal
│ └── Normal.php
├── PlatformInterface.php
└── QCloudSCF
│ ├── QCloudSCF.php
│ └── scfapi.php
├── scripts
├── dist.php
└── preloader.php
└── vendor
└── .gitignore
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: generic
2 |
3 | php:
4 | - '7.0'
5 |
6 | node_js:
7 | - '10'
8 |
9 | before_script:
10 | - curl -sL http://getcomposer.org/installer | php
11 |
12 | script:
13 | - cd php; composer create-project
14 | - cd nodejs; npm i && npm build
15 |
16 | notifications:
17 | email: false
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 风铃 逸笙
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
OneDriveFly
2 |
3 |
4 |
5 |
6 |
7 |
8 | Install
9 |
10 |
11 |
12 | ## About
13 |
14 | OneDriver Index Anywhere.
15 |
16 | ## Support
17 |
18 | [QCloud SCF](https://cloud.tencent.com/product/scf)
19 |
20 | [Aliyun FC](https://www.aliyun.com/product/fc)
21 |
22 | [Heroku](https://www.heroku.com/)
23 |
24 | will support in future
25 |
26 | [Cloudflare Workers](https://workers.cloudflare.com/)
27 |
28 | [Google Cloud Functions](https://cloud.google.com/functions)
29 |
30 | [Azure Functions](https://azure.microsoft.com/en-us/services/functions/)
31 |
32 | # Dev
33 | ```shell
34 | git clone https://github.com/Tai7sy/OneDriveFly.git
35 | ```
36 |
37 | ```shell
38 | cd OneDriveFly/php
39 | composer create-project
40 | ```
41 |
42 | ```shell
43 | cd OneDriveFly/nodejs
44 | npm i && npm build
45 | ```
46 |
47 | The generated files will be output to the `dist` folder
48 |
49 | ## License
50 | MIT
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | OneDriveFly
8 |
9 |
10 |
11 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | OneDrive Fly
29 |
30 |
31 |
35 |
36 |
37 |
38 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/docs/install.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Install
4 |
5 |
6 |
7 |
16 |
17 |
--------------------------------------------------------------------------------
/nodejs/.env:
--------------------------------------------------------------------------------
1 | NODE_ENV=production
2 | PROJECT="'1.0'"
3 |
--------------------------------------------------------------------------------
/nodejs/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/nodejs/README.md:
--------------------------------------------------------------------------------
1 | # OneDriveFly - NodeJS
2 |
3 | ```shell
4 | npm i && npm build
5 | ```
6 |
--------------------------------------------------------------------------------
/nodejs/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | "@babel/preset-env",
4 | ],
5 | plugins: [
6 | "@babel/plugin-transform-regenerator",
7 | "@babel/plugin-transform-runtime"
8 | ]
9 | };
10 |
--------------------------------------------------------------------------------
/nodejs/build/webpack.config.js:
--------------------------------------------------------------------------------
1 |
2 | const fs = require('fs');
3 | const path = require('path');
4 | const webpack = require('webpack');
5 |
6 | // const nodeExternals = require('webpack-node-externals');
7 |
8 | function resolve (...dir) {
9 | return path.join(__dirname, '..', ...dir)
10 | }
11 |
12 | module.exports = {
13 | entry: [
14 | resolve('src/index.js')
15 | ],
16 | target: 'node',
17 | node: {
18 | __dirname: false
19 | },
20 | externals: {
21 | 'axios': 'commonjs axios',
22 | 'noogger': 'commonjs noogger',
23 | },
24 | devtool: 'source-map',
25 | output: {
26 | path: resolve('dist'),
27 | filename: 'app.js',
28 | publicPath: 'dist/',
29 | devtoolModuleFilenameTemplate: '[absolute-resource-path]'
30 | },
31 | resolve: {
32 | extensions: ['.js', '.json'],
33 | alias: {
34 | '@': resolve('src'),
35 | },
36 | },
37 | resolveLoader: {
38 | modules: [resolve('node_modules')],
39 | },
40 | plugins: [
41 | new webpack.DefinePlugin({
42 | 'process.env': process.env
43 | }),
44 | {
45 | apply: (compiler) => {
46 | compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
47 | const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json')).toString());
48 | const generatedPackageJson = {
49 | name: packageJson.name,
50 | apiConfig: packageJson.apiConfig,
51 | dependencies: packageJson.dependencies,
52 | description: packageJson.description,
53 | repository: '',
54 | license: packageJson.license,
55 | };
56 | if (compilation.options.mode === 'production') {
57 | Object.assign(generatedPackageJson.apiConfig, {
58 | "log": {
59 | "level" : "WARNING"
60 | },
61 | })
62 | }
63 | fs.writeFileSync(path.join(compilation.options.output.path, 'package.json'), JSON.stringify(generatedPackageJson, null, 2));
64 | });
65 | }
66 | }
67 | ],
68 | module: {
69 | rules: [
70 | {
71 | use: 'babel-loader',
72 | exclude: /(node_modules)/,
73 | test: /\.js$/
74 | }
75 | ]
76 | }
77 | };
--------------------------------------------------------------------------------
/nodejs/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import * as Logger from "noogger";
4 |
5 | if (process.env.NODE_ENV === 'development') {
6 | require('source-map-support').install({
7 | environment: 'node',
8 | hookRequire: true
9 | });
10 | }
11 |
12 | import * as fs from 'fs';
13 | import * as path from 'path';
14 | import * as Listener from './listener';
15 |
--------------------------------------------------------------------------------
/nodejs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "onedrive-fly",
3 | "author": "",
4 | "version": "1.0.0",
5 | "description": "onedrive index anywhere",
6 | "license": "MIT",
7 | "private": true,
8 | "main": "index.js",
9 | "apiConfig": {
10 |
11 | },
12 | "dependencies": {
13 | "axios": "^0.19.2",
14 | "google-protobuf": "^3.11.2",
15 | "grpc": "^1.24.0",
16 | "noogger": "^0.1.8",
17 | "systeminformation": "^4.21.0"
18 | },
19 | "devDependencies": {
20 | "@babel/core": "^7.8.3",
21 | "@babel/plugin-transform-regenerator": "^7.8.3",
22 | "@babel/plugin-transform-runtime": "^7.8.3",
23 | "@babel/preset-env": "^7.8.3",
24 | "@babel/runtime": "^7.8.3",
25 | "babel-eslint": "^10.0.3",
26 | "babel-loader": "^8.0.6",
27 | "grpc-tools": "^1.8.1",
28 | "source-map-support": "^0.5.16",
29 | "webpack": "^4.41.5",
30 | "webpack-cli": "^3.3.10"
31 | },
32 | "scripts": {
33 | "test": "echo \"Error: no test specified\" && exit 1",
34 | "build:production": "webpack --config build/webpack.config.js --mode=production --watch",
35 | "build:development": "webpack --config build/webpack.config.js --mode=development --watch"
36 | },
37 | "eslintConfig": {
38 | "root": true,
39 | "env": {
40 | "node": true,
41 | "es6": true
42 | },
43 | "extends": [
44 | "eslint:recommended"
45 | ],
46 | "rules": {
47 | "no-console": "off",
48 | "no-unused-vars": "off",
49 | "no-irregular-whitespace": "off",
50 | "no-constant-condition": "off"
51 | },
52 | "parser": "babel-eslint"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/nodejs/platforms/aliyun_fc.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Aliyun - Function Compute
4 | *
5 | */
--------------------------------------------------------------------------------
/nodejs/platforms/aws_sc.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * AWS Lambda – Serverless Compute
4 | *
5 | */
--------------------------------------------------------------------------------
/nodejs/platforms/azure_functions.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Azure Functions
4 | *
5 | */
--------------------------------------------------------------------------------
/nodejs/platforms/cloudflare_workers.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Cloudflare Workers
4 | *
5 | */
--------------------------------------------------------------------------------
/nodejs/platforms/google_cf.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Google - Cloud Functions
4 | *
5 | */
--------------------------------------------------------------------------------
/nodejs/platforms/heroku.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Heroku
4 | * (Just some api)
5 | *
6 | */
--------------------------------------------------------------------------------
/nodejs/platforms/qcloud_scf.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Tencent Cloud - Serverless Cloud Function
4 | *
5 | */
6 |
7 |
8 | export function request() {
9 |
10 | }
--------------------------------------------------------------------------------
/nodejs/tests/test1.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 |
--------------------------------------------------------------------------------
/nodejs/utils/helper.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Date.prototype.format = function (format) {
4 | if (!format) format = 'yyyy-MM-dd hh:mm:ss';
5 | const o = {
6 | 'M+': this.getMonth() + 1, // month
7 | 'd+': this.getDate(), // day
8 | 'h+': this.getHours(), // hour
9 | 'm+': this.getMinutes(), // minute
10 | 's+': this.getSeconds(), // second
11 | 'q+': Math.floor((this.getMonth() + 3) / 3), // quarter
12 | S: this.getMilliseconds() // millisecond
13 | };
14 | if (/(y+)/.test(format)) {
15 | format = format.replace(RegExp.$1,
16 | (this.getFullYear() + '').substr(4 - RegExp.$1.length));
17 | }
18 | for (const k in o) {
19 | if (new RegExp('(' + k + ')').test(format)) {
20 | format = format.replace(RegExp.$1,
21 | RegExp.$1.length === 1 ? o[k] :
22 | ('00' + o[k]).substr(('' + o[k]).length));
23 | }
24 | }
25 | return format;
26 | };
27 | const date = {
28 | getMonthDay (date) {
29 | return (date || new Date()).format('MM-dd');
30 | },
31 | getDateTime (date) {
32 | return (date || new Date()).format('yyyy-MM-dd hh:mm:ss');
33 | }
34 | };
35 |
36 | export { date }
37 |
38 | export function randomString (len) {
39 | len = len || 16;
40 | const $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
41 | /** **默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
42 | const maxPos = $chars.length;
43 | let pwd = '';
44 | for (let i = 0; i < len; i++) {
45 | pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
46 | }
47 | return pwd;
48 | }
49 |
50 | String.prototype.random = randomString;
51 |
52 |
53 | /**
54 | * Simple param, (cannot handle array)
55 | * @param {Object} data
56 | * @param {string|boolean} parent
57 | * @returns {string}
58 | */
59 | export function param (data = {}, parent = false) {
60 | const arr = [];
61 | for (let key in data) {
62 | if (!data.hasOwnProperty(key)) continue;
63 |
64 | if (data[key] && typeof data[key] === 'object') {
65 | if (parent === false) {
66 | arr.push(param(data[key], encodeURIComponent(key)));
67 | } else {
68 | arr.push(param(data[key], parent + '[' + encodeURIComponent(key) + ']'));
69 | }
70 | } else {
71 | const value = encodeURIComponent((data[key] === null || data[key] === undefined) ? '' : data[key]);
72 | if (parent === false) {
73 | key = encodeURIComponent(key)
74 | } else {
75 | key = parent + '[' + encodeURIComponent(key) + ']'
76 | }
77 | arr.push(key + '=' + value)
78 | }
79 | }
80 | return arr.join('&');
81 | }
82 |
83 | export function sizeFormatter (byteSize) {
84 | byteSize = byteSize * 1;
85 | let i = 0;
86 | while (Math.abs(byteSize) >= 1024) {
87 | byteSize = byteSize / 1024;
88 | i++;
89 | if (i === 4)
90 | break
91 | }
92 | const units = [' B', ' KB', ' MB', ' GB', ' TB'];
93 | const newSize = byteSize.toFixed(2);
94 | return (newSize + units[i])
95 | }
96 |
97 | export async function sleep (timeout) {
98 | return new Promise(resolve => {
99 | setTimeout(resolve, timeout)
100 | })
101 | }
102 |
--------------------------------------------------------------------------------
/nodejs/utils/http-client.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import { param, randomString } from '@/utils/helper'
3 |
4 | export function createHttpClient (baseURL, token) {
5 | const service = axios.create({
6 | baseURL, // api的base_url
7 | timeout: 15000, // 请求超时时间
8 | transformRequest: [data => {
9 | // Do whatever you want to transform the data
10 | // console.debug(data);
11 | if (data && data.constructor !== global['FormData']) data = param(data);
12 | // console.debug(data);
13 | return data;
14 | }]
15 | });
16 |
17 | // request拦截器
18 | service.interceptors.request.use(config => {
19 | config.headers['X-Server-Token'] = token;
20 | config.headers['X-XSRF-Token'] = randomString(32); // 假装有 csrf
21 | config.headers['X-Requested-With'] = 'XMLHttpRequest';
22 | return config;
23 | }, error => {
24 | // Do something with request error
25 | // console.log(error); // for debug
26 | Promise.reject(error);
27 | });
28 |
29 | // response 拦截器
30 | service.interceptors.response.use(
31 | response => {
32 | return response.data
33 | },
34 | error => {
35 | if (error.response && error.response.data) {
36 | if (error.response.data.message) {
37 | return Promise.reject(error.response.data);
38 | }
39 | return Promise.reject({
40 | message: JSON.stringify(error.response.data)
41 | });
42 | } else {
43 | console.error('fetch.error:');
44 | console.error(error);
45 | return Promise.reject({
46 | message: error.response ? error.response.statusText : error.message
47 | });
48 | }
49 | }
50 | );
51 | return service;
52 | }
53 |
--------------------------------------------------------------------------------
/php/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /composer.phar
3 | /composer.lock
4 | /vendor
5 | /config.php
6 |
--------------------------------------------------------------------------------
/php/.htaccess:
--------------------------------------------------------------------------------
1 |
2 |
3 | Options -MultiViews -Indexes
4 |
5 |
6 | RewriteEngine On
7 |
8 | # Handle Authorization Header
9 | RewriteCond %{HTTP:Authorization} .
10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
11 |
12 | # Redirect Trailing Slashes If Not A Folder...
13 | RewriteCond %{REQUEST_FILENAME} !-d
14 | RewriteCond %{REQUEST_URI} (.+)/$
15 | RewriteRule ^ %1 [L,R=301]
16 |
17 | # Handle Front Controller...
18 | RewriteCond %{REQUEST_FILENAME} !-d
19 | RewriteCond %{REQUEST_FILENAME} !-f
20 | RewriteRule ^ index.php [L]
21 |
22 |
--------------------------------------------------------------------------------
/php/README.md:
--------------------------------------------------------------------------------
1 | # OneDriveFly - NodeJS
2 |
3 | ```shell
4 | composer create-project
5 | composer build
6 | ```
7 |
--------------------------------------------------------------------------------
/php/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tai7sy/onedrive-fly",
3 | "description": "OneDrive index anywhere",
4 | "license": "MIT",
5 | "type": "project",
6 | "require": {
7 | "php": "^7.0.0",
8 | "ext-json": "*",
9 | "ext-curl": "*",
10 | "classpreloader/classpreloader": "~4.0.1",
11 | "classpreloader/console": "~3.0.1",
12 | "doctrine/cache": "~1.6.2",
13 | "symfony/http-foundation": "~3.3"
14 | },
15 | "require-dev": {
16 | },
17 | "autoload": {
18 | "classmap": [
19 | "config.php"
20 | ],
21 | "files": [
22 | "library/functions.php"
23 | ],
24 | "psr-4": {
25 | "Platforms\\": "platforms/",
26 | "Library\\": "library/"
27 | }
28 | },
29 | "scripts": {
30 | "post-root-package-install": [
31 | "@php -r \"file_exists('config.php') || copy('config.example.php', 'config.php');\""
32 | ],
33 | "post-autoload-dump": "classpreloader compile --config=scripts/preloader.php --output=../dist/vendor.php && php scripts/dist.php",
34 | "build": "composer dump-autoload --optimize"
35 | },
36 | "repositories": {
37 | "packagist": {
38 | "type": "composer",
39 | "url": "https://mirrors.aliyun.com/composer/"
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/php/config.example.php:
--------------------------------------------------------------------------------
1 | 'OneDriveFly',
13 | 'platform' => 'Normal',
14 | 'multi' => 0,
15 | 'accounts' => [
16 | [
17 | 'name' => 'disk_1',
18 | 'path' => '',
19 | 'path_image' => ['/some_public/image'],
20 | 'refresh_token' => '',
21 | ],
22 | ],
23 | 'debug' => true,
24 | 'proxy' => '',
25 | 'password_file' => 'password',
26 | 'admin_password' => '123456',
27 | ];
28 | }
--------------------------------------------------------------------------------
/php/index.php:
--------------------------------------------------------------------------------
1 | cookies->get('language'));
84 | date_default_timezone_set(get_timezone($request->cookies->get('timezone')));
85 |
86 | $path = array_values(array_filter(
87 | explode('/', $request->getPathInfo()),
88 | function ($path) {
89 | return !empty($path);
90 | }
91 | ));
92 |
93 | $relative_path = join('/', $path);
94 | $account = null;
95 | // multi-account enabled
96 | if ($config['multi']) {
97 | if (empty($path[0])) {
98 | $account = $config['accounts'][0];
99 | return redirect($request->getUriForPath('/' . $account['name']));
100 | } else {
101 | foreach ($config['accounts'] as $i) {
102 | if ($i['name'] === $path[0]) {
103 | $account = $i;
104 | break;
105 | }
106 | }
107 | if ($account == null) {
108 | return message('此账号未找到', 'Error', null, 500);
109 | }
110 | }
111 | array_shift($path);
112 | } else {
113 | $account = $config['accounts'][0];
114 | }
115 |
116 | if (empty($account['path'])) {
117 | $account['path'] = '/';
118 | }
119 |
120 |
121 | $path = [
122 | 'relative' => $relative_path,
123 | 'absolute' => path_format($account['path'] . '/' . join('/', $path))
124 | ];
125 | $is_admin = $config['is_admin'] = !empty($config['admin_password']) && $request->cookies->get('admin_password') === $config['admin_password'];
126 | $is_image_path = $config['is_image_path'] = in_array($path['absolute'], $account['path_image']);
127 |
128 | try {
129 | $account['driver'] = new OneDrive($account['refresh_token'],
130 | !empty($account['provider']) ? $account['provider'] : 'MS',
131 | !empty($account['oauth']) ? $account['oauth'] : []);
132 |
133 | // get thumbnails for image file
134 | if ($request->query->has('thumbnails')) {
135 | return redirect($account['driver']->info($path['absolute'], true)['url']);
136 | }
137 |
138 | // install -> go to oauth
139 | if ($request->query->has('install') ||
140 | ($request->query->has('oauth_callback'))
141 | || empty($account['refresh_token'])) {
142 |
143 | if ($request->query->has('oauth_callback')) {
144 | if (($oauth = @json_decode($request->query->get('oauth_callback'), true)['oauth'])) {
145 | $account['driver'] = new OneDrive(null, 'MS', $oauth);
146 | }
147 | }
148 | return install($request, $account);
149 | }
150 |
151 | // ajax request
152 | if ($request->isXmlHttpRequest()) {
153 | $response = false;
154 | if ($is_admin) {
155 | switch ($request->get('action')) {
156 | case trans('Create'):
157 | $file_path = path_format($path['absolute'] . '/' . $request->get('create_name'), true);
158 | switch ($request->get('create_type')) {
159 | default:
160 | case 'file':
161 | $response = $account['driver']->put($file_path, $request->get('create_content'));
162 | break;
163 | case 'folder':
164 | $response = $account['driver']->makeDirectory($file_path);
165 | break;
166 | }
167 | break;
168 | case trans('Encrypt'):
169 | $file_path = path_format($path['absolute'] . '/' . $request->get('encrypt_folder') . '/' . $config['password_file'], true);
170 | $response = $account['driver']->put($file_path, $request->get('encrypt_newpass'));
171 | break;
172 | case trans('Move'):
173 | $file_path = path_format($path['absolute'] . '/' . $request->get('move_name'), true);
174 | if ($request->get('move_folder') === '/../') {
175 | if ($path['absolute'] == '/') {
176 | $response = ['error' => 'cannot move'];
177 | break;
178 | }
179 | $new_path = $path['absolute'] . '/../';
180 |
181 | } else {
182 | $new_path = $path['absolute'] . '/' . $request->get('move_folder');
183 | }
184 | $new_path = path_format($new_path . '/' . $request->get('move_name'), true);
185 | $response = $account['driver']->move($file_path, $new_path);
186 | break;
187 | case trans('Rename'):
188 | $file_path = path_format($path['absolute'] . '/' . $request->get('rename_oldname'), true);
189 | $response = $account['driver']->move($file_path, path_format($path['absolute'] . '/' . $request->get('rename_newname')));
190 | break;
191 | case trans('Delete'):
192 | $file_path = path_format($path['absolute'] . '/' . $request->get('delete_name'), true);
193 | $response = $account['driver']->delete($file_path);
194 | break;
195 | }
196 | }
197 |
198 | if ($is_admin || $is_image_path) {
199 | switch ($request->get('action')) {
200 | case 'upload': // create a upload session
201 | $file_path = path_format($path['absolute'] . '/' . $request->get('filename'), true);
202 | $response = $account['driver']->uploadUrl($file_path);
203 | break;
204 | }
205 | }
206 |
207 | if ($response)
208 | return response($response, !$response || isset($response['error']) ? 500 : 200);
209 | }
210 |
211 | // preview -> edit file
212 | if ($is_admin && $request->isMethod('POST')) {
213 | if ($request->query->has('preview')) {
214 | $account['driver']->put($path['absolute'], $request->get('content'));
215 | }
216 | }
217 |
218 | // default -> fetch files
219 | $files = $account['driver']->infos($path['absolute'], (int)$request->get('page', 1));
220 |
221 | if (!$request->query->has('preview')) {
222 | if (isset($files['@microsoft.graph.downloadUrl'])) {
223 | return redirect($files['@microsoft.graph.downloadUrl']);
224 | }
225 | }
226 | return render($account, $path, $files);
227 | } catch (Throwable $e) {
228 | @ob_get_clean();
229 | try {
230 | $error = ['error' => ['message' => $e->getMessage()]];
231 | if ($config['debug']) {
232 | $error['error']['message'] = $e->getMessage() . error_trace($e);
233 | }
234 | return render($account, $path, $error);
235 | } catch (Throwable $e) {
236 | @ob_get_clean();
237 | return message($e->getMessage(), 'Error', $config['debug'] ? error_trace($e) : null, 500);
238 | }
239 | }
240 | }
241 |
242 | /**
243 | * @param Request $request
244 | * @param [OneD] $account
245 | * @return Response
246 | */
247 | function install($request, $account)
248 | {
249 | $state = [];
250 | if ($request->query->has('oauth_callback')) {
251 | $callback = json_decode($request->query->get('oauth_callback'), true);
252 | if ($callback && !empty($callback['code'])) {
253 | $state = [
254 | 'name' => $callback['name'],
255 | 'refresh_token' => $account['driver']->get_refresh_token($callback['code'])
256 | ];
257 | }
258 | }
259 | @ob_start();
260 | // @formatter:off
261 | ?>
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
284 | OneDriveFly
285 |
286 |
287 |
288 |
289 | 安装
290 |
291 | {{error}}
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
增加
305 |
306 |
307 |
308 |
309 | X
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 | 名称:
326 |
328 |
329 |
330 |
331 | 路径:
332 |
333 |
334 |
335 |
336 | 图床路径:
337 |
339 |
340 |
341 |
363 |
364 |
登录:
365 |
366 |
点击登录
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 | 生成配置
387 |
388 |
389 |
390 |
391 |
392 |
393 |
569 |
570 |
571 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
611 |
612 |
613 |
619 |
620 |
621 | 'text/html'], $headers);
640 | if (is_array($content)) $content = json_encode($content);
641 | return new Response(
642 | $content,
643 | $status,
644 | $headers
645 | );
646 | }
647 |
648 | function redirect($to = null, $status = 302, $headers = [])
649 | {
650 | return response('redirecting', $status, array_merge($headers, [
651 | 'location' => $to
652 | ]));
653 | }
654 |
655 | function trans($key = null, $replace = array())
656 | {
657 | return Lang::get($key, $replace);
658 | }
659 |
660 | /**
661 | * render view
662 | * @param array $account
663 | * @param array $path
664 | * @param array $files
665 | * @return array|Response
666 | * @throws Exception
667 | */
668 | function render($account, $path, $files)
669 | {
670 | global $config;
671 |
672 | $request = request();
673 | $is_admin = $config['is_admin'] === true;
674 | $is_image_path = $config['is_image_path'] === true;
675 | $base_url = $request->getBaseUrl();
676 | if ($base_url == '') $base_url = '/';
677 | $status_code = 200;
678 | $is_video = false;
679 | $readme = false;
680 | @ob_start();
681 | // @formatter:off
682 | ?>
683 |
684 |
685 |
686 |
687 |
690 |
691 |
692 |
693 |
695 |
696 |
697 |
736 |
741 |
742 |
743 |
744 |
748 |
749 |
751 |
752 |
778 |
779 |
783 |
784 |
785 | Language
786 | $value1) {
788 | echo '' . $value1 . ' ';
789 | }
790 | ?>
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
819 |
820 |
822 |
829 | get(path_format($path['absolute'] . '/' . $config['password_file']));
834 | }
835 | if ($is_admin || empty($folder_password) || $folder_password === request()->cookies->get('password')) {
836 | if (isset($files['error'])) {
837 | echo '
' . $files['error']['message'] . '
';
838 | $status_code = 404;
839 | } else {
840 | if (isset($files['file'])) {
841 | // request is a file
842 | ?>
843 |
844 |
855 |
856 | document.getElementById(\'url\').offsetWidth) this.style.width=\'100%\';" />';
860 | } elseif (in_array($ext, Ext::VIDEO)) {
861 | //echo '
';
862 | $is_video = true;
863 | echo '
';
864 | } elseif (in_array($ext, Ext::MUSIC)) {
865 | echo '
';
866 | } elseif (in_array($ext, ['pdf'])) {
867 | echo '
';
868 | } elseif (in_array($ext, Ext::OFFICE)) {
869 | echo '';
870 | } elseif (in_array($ext, Ext::TXT)) {
871 | $txt_content = htmlspecialchars(curl($files['@microsoft.graph.downloadUrl']));
872 | ?>
873 |
886 | ' . curl($files['@microsoft.graph.downloadUrl']) . ' ';
888 | } else {
889 | echo '
' . trans('FileNotSupport') . ' ';
890 | } ?>
891 |
892 |
893 |
897 |
898 |
899 |
900 |
901 |
902 |
903 |
905 |
907 |
908 |
909 |
915 |
916 |
917 |
918 |
919 |
920 |
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 |
931 |
932 |
933 |
934 |
935 |
936 |
938 |
939 |
940 |
941 |
942 | ';
945 | foreach ($files['children'] as $file) {
946 | // Files
947 | if (isset($file['file'])) {
948 | if ($is_admin || (substr($file['name'], 0, 1) !== '.' && $file['name'] !== $config['password_file'])) {
949 | if (strtolower($file['name']) === 'readme.md' || strtolower($file['name']) === 'readme') {
950 | $readme = $file;
951 | }
952 | if (strtolower($file['name']) === 'index.html' || strtolower($file['name']) === 'index.htm') {
953 | $html = $account['driver']->get(path_format($path['absolute'] . '/' . $file['name']));
954 | @ob_get_clean();
955 | return response($html);
956 | }
957 | $index++;
958 | ?>
959 |
960 |
961 |
962 |
963 |
964 |
965 |
966 |
967 |
968 |
969 |
970 |
971 |
972 |
973 |
974 |
975 |
978 |
979 |
980 |
981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 |
989 |
990 |
991 |
992 |
993 |
994 |
995 |
996 |
997 |
998 |
1002 |
1003 |
1004 |
1005 |
1006 |
1007 |
1008 |
1009 |
1012 |
1013 |
1014 | $files['folder']['perPage']) {
1016 | $pageForm = '
1017 |
1018 |
1019 |
1020 |
1021 | ';
1022 | if ($files['folder']['currentPage'] !== 1) {
1023 | $pageForm .= '
1024 | ' . trans('PrePage') . ' ';
1025 | }
1026 | $pageForm .= '
1027 |
1028 | ';
1029 | for ($page = 1; $page <= $files['folder']['lastPage']; $page++) {
1030 | if ($page == $files['folder']['currentPage']) {
1031 | $pageForm .= '
1032 | ' . $page . ' ';
1033 | } else {
1034 | $pageForm .= '
1035 | ' . $page . ' ';
1036 | }
1037 | }
1038 | $pageForm .= '
1039 |
1040 | ';
1041 | if ($files['folder']['currentPage'] != $files['folder']['lastPage']) {
1042 | $pageForm .= '
1043 | ' . trans('NextPage') . ' ';
1044 | }
1045 | $pageForm .= '
1046 |
1047 |
1048 |
1049 | ';
1050 | echo $pageForm;
1051 | }
1052 | ?>
1053 |
1054 |
1056 |
1065 |
1074 |
1075 |
1076 |
1077 |
1078 |
1079 |
1106 |
1107 |
1108 |
1109 | query->has('preview')) { ?>
1112 |
1126 |
1127 |
1128 |
1129 |
1131 |
1132 |
1133 | ?
1134 |
1135 |
1136 |
1138 |
1139 |
1140 |
1141 |
1142 |
1161 |
1162 |
1163 |
1164 |
1165 |
1166 |
1167 |
1168 |
1169 |
1170 |
1171 |
1172 |
1173 |
1176 |
1177 |
1179 |
1180 |
1182 |
1183 |
1184 |
1185 |
1186 |
1187 |
1188 |
1189 |
1190 |
1191 |
1192 |
1230 |
1231 |
1232 |
1233 |
1234 |
1237 |
1238 |
1239 |
1241 |
1242 |
1243 |
1244 |
1245 |
1246 |
1247 |
1248 |
1249 |
1251 | getClientIp(); ?>
1252 |
1253 |
1254 |
1255 |
1256 |
1911 |
1912 |
1913 | $val) {
49 | $string = str_replace(":$var", $val, $string);
50 | }
51 | return $string;
52 | }
53 | }
54 |
55 | global $LANG;
56 |
57 | $LANG = [
58 | 'languages' => [
59 | 'en-US' => 'English',
60 | 'zh-CN' => '中文',
61 | ],
62 | 'Week' => [
63 | '0' => [
64 | 'en-US' => 'Sunday',
65 | 'zh-CN' => '星期日',
66 | ],
67 | '1' => [
68 | 'en-US' => 'Monday',
69 | 'zh-CN' => '星期一',
70 | ],
71 | '2' => [
72 | 'en-US' => 'Tuesday',
73 | 'zh-CN' => '星期二',
74 | ],
75 | '3' => [
76 | 'en-US' => 'Wednesday',
77 | 'zh-CN' => '星期三',
78 | ],
79 | '4' => [
80 | 'en-US' => 'Thursday',
81 | 'zh-CN' => '星期四',
82 | ],
83 | '5' => [
84 | 'en-US' => 'Friday',
85 | 'zh-CN' => '星期五',
86 | ],
87 | '6' => [
88 | 'en-US' => 'Saturday',
89 | 'zh-CN' => '星期六',
90 | ],
91 | ],
92 | 'EnvironmentsDescription' => [
93 | 'admin' => [
94 | 'en-US' => 'The admin password, Login button will not show when empty',
95 | 'zh-CN' => '管理密码,不添加时不显示登录页面且无法登录。',
96 | ],
97 | 'adminloginpage' => [
98 | 'en-US' => 'if set, the Login button will not display, and the login page no longer \'?admin\', it is \'?{this value}\'.',
99 | 'zh-CN' => '如果设置,登录按钮及页面隐藏。管理登录的页面不再是\'?admin\',而是\'?此设置的值\'。',
100 | ],
101 | 'domain_path' => [
102 | 'en-US' => 'more custom domain, format is a1.com:/dirto/path1|b2.com:/path2',
103 | 'zh-CN' => '使用多个自定义域名时,指定每个域名看到的目录。格式为a1.com:/dirto/path1|b1.com:/path2,比private_path优先。',
104 | ],
105 | 'imgup_path' => [
106 | 'en-US' => 'Set guest upload dir, before set this, the files in this dir will show as normal.',
107 | 'zh-CN' => '设置图床路径,不设置这个值时该目录内容会正常列文件出来,设置后只有上传界面,不显示其中文件(登录后显示)。',
108 | ],
109 | 'passfile' => [
110 | 'en-US' => 'The password of dir will save in this file.',
111 | 'zh-CN' => '自定义密码文件的名字,可以是\'pppppp\',也可以是\'aaaa.txt\'等等;列目录时不会显示,只有知道密码才能查看或下载此文件。密码是这个文件的内容,可以空格、可以中文;',
112 | ],
113 | 'private_path' => [
114 | 'en-US' => 'Show this Onedrive dir when through custom domain, default is \'/\'.',
115 | 'zh-CN' => '使用自定义域名访问时,显示网盘文件的路径,不设置时默认为根目录。',
116 | ],
117 | 'public_path' => [
118 | 'en-US' => 'Show this Onedrive dir when through the long url of API Gateway; public show files less than private.',
119 | 'zh-CN' => '使用API长链接访问时,显示网盘文件的路径,不设置时默认为根目录;不能是private_path的上级(public看到的不能比private多,要么看到的就不一样)。',
120 | ],
121 | 'sitename' => [
122 | 'en-US' => 'sitename',
123 | 'zh-CN' => '网站的名称',
124 | ],
125 | 'language' => [
126 | 'en-US' => 'en or zh-CN',
127 | 'zh-CN' => '目前en 或 zh-CN',
128 | ],
129 | 'SecretId' => [
130 | 'en-US' => 'the SecretId of tencent cloud',
131 | 'zh-CN' => '腾讯云API的Id',
132 | ],
133 | 'SecretKey' => [
134 | 'en-US' => 'the SecretKey of tencent cloud',
135 | 'zh-CN' => '腾讯云API的Key',
136 | ],
137 | 'Region' => [
138 | 'en-US' => 'the Region of SCF',
139 | 'zh-CN' => 'SCF程序所在地区',
140 | ],
141 | 'Onedrive_ver' => [
142 | 'en-US' => 'Onedrive version',
143 | 'zh-CN' => 'Onedrive版本',
144 | ],
145 | ],
146 | 'SetSecretsFirst' => [
147 | 'en-US' => 'Set SecretId & SecretKey in Environments first! Then reflesh.',
148 | 'zh-CN' => '先在环境变量设置SecretId和SecretKey!再刷新。',
149 | ],
150 | 'RefleshtoLogin' => [
151 | 'en-US' => 'Reflesh and login.',
152 | 'zh-CN' => '请刷新 页面后重新登录',
153 | ],
154 | 'AdminLogin' => [
155 | 'en-US' => 'Admin Login',
156 | 'zh-CN' => '管理登录',
157 | ],
158 | 'LoginSuccess' => [
159 | 'en-US' => 'Login Success!',
160 | 'zh-CN' => '登录成功,正在跳转',
161 | ],
162 | 'InputPassword' => [
163 | 'en-US' => 'Input Password',
164 | 'zh-CN' => '输入密码',
165 | ],
166 | 'Login' => [
167 | 'en-US' => 'Login',
168 | 'zh-CN' => '登录',
169 | ],
170 | 'Encrypt' => [
171 | 'en-US' => 'Encrypt',
172 | 'zh-CN' => '加密',
173 | ],
174 | 'SetpassfileBfEncrypt' => [
175 | 'en-US' => 'Your should set \'password_file\' before encrypt',
176 | 'zh-CN' => '先在设置password_file才能加密',
177 | ],
178 | 'updateProgram' => [
179 | 'en-US' => 'Update Program',
180 | 'zh-CN' => '一键更新',
181 | ],
182 | 'UpdateSuccess' => [
183 | 'en-US' => 'Program update Success!',
184 | 'zh-CN' => '程序升级成功!',
185 | ],
186 | 'Setup' => [
187 | 'en-US' => 'Setup',
188 | 'zh-CN' => '设置',
189 | ],
190 | 'NotNeedUpdate' => [
191 | 'en-US' => 'Not Need Update',
192 | 'zh-CN' => '不需要更新',
193 | ],
194 | 'Back' => [
195 | 'en-US' => 'Back',
196 | 'zh-CN' => '返回',
197 | ],
198 | 'Home' => [
199 | 'en-US' => 'Home',
200 | 'zh-CN' => '首页',
201 | ],
202 | 'NeedUpdate' => [
203 | 'en-US' => 'Program can update Click setup in Operate at top.',
204 | 'zh-CN' => '可以升级程序 在上方管理菜单中 进入设置页面升级',
205 | ],
206 | 'Operate' => [
207 | 'en-US' => 'Operate',
208 | 'zh-CN' => '管理',
209 | ],
210 | 'Logout' => [
211 | 'en-US' => 'Logout',
212 | 'zh-CN' => '登出',
213 | ],
214 | 'Create' => [
215 | 'en-US' => 'Create',
216 | 'zh-CN' => '新建',
217 | ],
218 | 'Download' => [
219 | 'en-US' => 'download',
220 | 'zh-CN' => '下载',
221 | ],
222 | 'ClickToEdit' => [
223 | 'en-US' => 'Click to edit',
224 | 'zh-CN' => '点击后编辑',
225 | ],
226 | 'Save' => [
227 | 'en-US' => 'Save',
228 | 'zh-CN' => '保存',
229 | ],
230 | 'FileNotSupport' => [
231 | 'en-US' => 'File not support preview.',
232 | 'zh-CN' => '文件格式不支持预览',
233 | ],
234 | 'File' => [
235 | 'en-US' => 'File',
236 | 'zh-CN' => '文件',
237 | ],
238 | 'ShowThumbnails' => [
239 | 'en-US' => 'Thumbnails',
240 | 'zh-CN' => '图片缩略',
241 | ],
242 | 'EditTime' => [
243 | 'en-US' => 'EditTime',
244 | 'zh-CN' => '修改时间',
245 | ],
246 | 'Size' => [
247 | 'en-US' => 'Size',
248 | 'zh-CN' => '大小',
249 | ],
250 | 'Rename' => [
251 | 'en-US' => 'Rename',
252 | 'zh-CN' => '重命名',
253 | ],
254 | 'Move' => [
255 | 'en-US' => 'Move',
256 | 'zh-CN' => '移动',
257 | ],
258 | 'Delete' => [
259 | 'en-US' => 'Delete',
260 | 'zh-CN' => '删除',
261 | ],
262 | 'PrePage' => [
263 | 'en-US' => 'PrePage',
264 | 'zh-CN' => '上一页',
265 | ],
266 | 'NextPage' => [
267 | 'en-US' => 'NextPage',
268 | 'zh-CN' => '下一页',
269 | ],
270 | 'Upload' => [
271 | 'en-US' => 'Upload',
272 | 'zh-CN' => '上传',
273 | ],
274 | 'Submit' => [
275 | 'en-US' => 'Submit',
276 | 'zh-CN' => '确认',
277 | ],
278 | 'Close' => [
279 | 'en-US' => 'Close',
280 | 'zh-CN' => '关闭',
281 | ],
282 | 'InputPasswordUWant' => [
283 | 'en-US' => 'Input Password you Want',
284 | 'zh-CN' => '输入想要设置的密码',
285 | ],
286 | 'ParentDir' => [
287 | 'en-US' => 'Parent Dir',
288 | 'zh-CN' => '上一级目录',
289 | ],
290 | 'Folder' => [
291 | 'en-US' => 'Folder',
292 | 'zh-CN' => '文件夹',
293 | ],
294 | 'Name' => [
295 | 'en-US' => 'Name',
296 | 'zh-CN' => '名称',
297 | ],
298 | 'Content' => [
299 | 'en-US' => 'Content',
300 | 'zh-CN' => '内容',
301 | ],
302 | 'CancelEdit' => [
303 | 'en-US' => 'Cancel Edit',
304 | 'zh-CN' => '取消编辑',
305 | ],
306 | 'GetFileNameFail' => [
307 | 'en-US' => 'Fail to Get File Name!',
308 | 'zh-CN' => '获取文件名失败!',
309 | ],
310 | 'GetUploadLink' => [
311 | 'en-US' => 'Get Upload Link',
312 | 'zh-CN' => '获取上传链接',
313 | ],
314 | 'UpFileTooLarge' => [
315 | 'en-US' => 'The File is too Large!',
316 | 'zh-CN' => '大于15G,终止上传。',
317 | ],
318 | 'UploadStart' => [
319 | 'en-US' => 'Upload Start',
320 | 'zh-CN' => '开始上传',
321 | ],
322 | 'UploadStartAt' => [
323 | 'en-US' => 'Start At',
324 | 'zh-CN' => '开始于',
325 | ],
326 | 'ThisTime' => [
327 | 'en-US' => 'This Time',
328 | 'zh-CN' => '本次',
329 | ],
330 | 'LastUpload' => [
331 | 'en-US' => 'Last time Upload',
332 | 'zh-CN' => '上次上传',
333 | ],
334 | 'AverageSpeed' => [
335 | 'en-US' => 'AverageSpeed',
336 | 'zh-CN' => '平均速度',
337 | ],
338 | 'CurrentSpeed' => [
339 | 'en-US' => 'CurrentSpeed',
340 | 'zh-CN' => '即时速度',
341 | ],
342 | 'Expect' => [
343 | 'en-US' => 'Expect',
344 | 'zh-CN' => '预计还要',
345 | ],
346 | 'EndAt' => [
347 | 'en-US' => 'End At',
348 | 'zh-CN' => '结束于',
349 | ],
350 | 'UploadErrorUpAgain' => [
351 | 'en-US' => 'Maybe error, do upload again.',
352 | 'zh-CN' => '可能出错,重新上传。',
353 | ],
354 | 'UploadComplete' => [
355 | 'en-US' => 'Upload Complete',
356 | 'zh-CN' => '上传完成',
357 | ],
358 | 'UploadFail23' => [
359 | 'en-US' => 'Upload Fail, contain #.',
360 | 'zh-CN' => '目录或文件名含有#,上传失败。',
361 | ],
362 | 'defaultSitename' => [
363 | 'en-US' => 'Set sitename in Environments',
364 | 'zh-CN' => '请在环境变量添加sitename',
365 | ],
366 | 'MayinEnv' => [
367 | 'en-US' => 'The \'Onedrive_ver\' may in Environments',
368 | 'zh-CN' => 'Onedrive_ver应该已经写入环境变量',
369 | ],
370 | 'Wait' => [
371 | 'en-US' => 'Wait',
372 | 'zh-CN' => '稍等',
373 | ],
374 | 'WaitJumpIndex' => [
375 | 'en-US' => 'Wait 5s jump to Home page',
376 | 'zh-CN' => '等5s跳到首页',
377 | ],
378 | 'JumptoOffice' => [
379 | 'en-US' => 'Login Office and Get a refresh_token',
380 | 'zh-CN' => '跳转到Office,登录获取refresh_token',
381 | ],
382 | 'OndriveVerMS' => [
383 | 'en-US' => 'default(Onedrive, Onedrive for business)',
384 | 'zh-CN' => '默认(支持商业版与个人版)',
385 | ],
386 | 'OndriveVerCN' => [
387 | 'en-US' => 'Onedrive in China',
388 | 'zh-CN' => '世纪互联版',
389 | ],
390 | 'OndriveVerMSC' => [
391 | 'en-US' => 'default but use customer app id & secret',
392 | 'zh-CN' => '国际版,自己申请应用ID与机密',
393 | ],
394 | 'GetSecretIDandKEY' => [
395 | 'en-US' => 'Get customer app id & secret',
396 | 'zh-CN' => '申请应用ID与机密',
397 | ],
398 | 'Reflesh' => [
399 | 'en-US' => 'Reflesh',
400 | 'zh-CN' => '刷新',
401 | ],
402 | 'SelectLanguage' => [
403 | 'en-US' => 'Select Language',
404 | 'zh-CN' => '选择语言',
405 | ],
406 | ];
407 |
408 |
--------------------------------------------------------------------------------
/php/library/OneDrive.php:
--------------------------------------------------------------------------------
1 | 'https://onedrivefly.github.io',
29 | 'client_id' => '298004f7-c751-4d56-aba3-b058c0154fd2',
30 | 'client_secret' => '-^(!BpF-l9/z#[+*5t)alg;[V@;;)_];)@j#^E;T(&^4uD;*&?#2)>H?',
31 | 'oauth_url' => 'https://login.microsoftonline.com/common/oauth2/v2.0/',
32 | 'api_url' => 'https://graph.microsoft.com/v1.0/me/drive/root',
33 | 'scope' => 'https://graph.microsoft.com/Files.ReadWrite.All offline_access',
34 | ];
35 |
36 | const APP_MS_CN = [
37 | 'redirect_uri' => 'https://onedrivefly.github.io',
38 | 'client_id' => '5010206d-75ac-4af1-8fc7-70d1576326f0',
39 | 'client_secret' => 'Gz5JsJkR6L-rA]w23RMPeQdL:.iZ1Pja',
40 | 'oauth_url' => 'https://login.partner.microsoftonline.cn/common/oauth2/v2.0/',
41 | 'api_url' => 'https://microsoftgraph.chinacloudapi.cn/v1.0/me/drive/root',
42 | 'scope' => 'https://microsoftgraph.chinacloudapi.cn/Files.ReadWrite.All offline_access',
43 | ];
44 |
45 | /**
46 | * OneDrive constructor.
47 | * @param $refresh_token
48 | * @param string $provider
49 | * @param array $oauth
50 | * @throws Exception
51 | */
52 | public function __construct($refresh_token, $provider = 'MS', $oauth = [])
53 | {
54 | self::$instance = $this;
55 |
56 | switch ($provider) {
57 | default:
58 | case 'MS':
59 | // MS
60 | // https://portal.azure.com
61 | $this->oauth = self::APP_MS;
62 | break;
63 | case 'CN':
64 | // CN
65 | // https://portal.azure.cn
66 | $this->oauth = self::APP_MS_CN;
67 | break;
68 | }
69 | $this->oauth = array_merge($this->oauth, $oauth);
70 |
71 | // 只能用个文件缓存代替
72 |
73 | if (is_writable(sys_get_temp_dir())) {
74 | $this->cache = new FilesystemCache(sys_get_temp_dir(), '.qdrive');
75 | } elseif (is_writable('/tmp/')) {
76 | $this->cache = new FilesystemCache('/tmp/', '.qdrive');
77 | } else {
78 | $this->cache = new VoidCache();
79 | }
80 |
81 | if ($refresh_token && isset($refresh_token{1})) {
82 | $this->cache_prefix = dechex(crc32($refresh_token)) . '_';
83 | if (!($this->access_token = $this->cache->fetch($this->cache_prefix . 'access_token'))) {
84 | $response = curl(
85 | $this->oauth['oauth_url'] . 'token',
86 | 'POST',
87 | 'client_id=' . $this->oauth['client_id'] .
88 | '&client_secret=' . urlencode($this->oauth['client_secret']) .
89 | '&grant_type=refresh_token&requested_token_use=on_behalf_of&refresh_token=' . $refresh_token
90 | );
91 | $json = json_decode($response, true);
92 |
93 | if (empty($json['access_token'])) {
94 | error_log('failed to get access_token. response:' . $response);
95 |
96 | if (!empty($json['error_description'])) {
97 | throw new Exception('failed to get access_token: ' . $json['error_description']);
98 | }
99 | throw new Exception(APP_DEBUG ? $response : 'failed to get access_token.');
100 | }
101 | $this->access_token = $json['access_token'];
102 | $this->cache->save($this->cache_prefix . 'access_token', $json['access_token'], $json['expires_in'] - 60);
103 | }
104 | }
105 | }
106 |
107 | public static function instance()
108 | {
109 | return self::$instance;
110 | }
111 |
112 | public function authUrl($return_url)
113 | {
114 | return $this->oauth['oauth_url'] . 'authorize?scope=' . $this->oauth['scope'] .
115 | '&response_type=code&client_id=' . $this->oauth['client_id'] .
116 | '&redirect_uri=' . $this->oauth['redirect_uri'] . '&state=' . urlencode($return_url);
117 | }
118 |
119 | /**
120 | * @param $authorization_code
121 | * @return array|string
122 | * @throws Exception
123 | */
124 | function get_refresh_token($authorization_code)
125 | {
126 | $response = curl($this->oauth['oauth_url'] . 'token',
127 | 'POST',
128 | 'client_id=' . $this->oauth['client_id'] .
129 | '&client_secret=' . urlencode($this->oauth['client_secret']) .
130 | '&grant_type=authorization_code&requested_token_use=on_behalf_of&redirect_uri=' . $this->oauth['redirect_uri'] .
131 | '&code=' . $authorization_code);
132 | $ret = json_decode($response, true);
133 | if (!$ret || !isset($ret['refresh_token'])) {
134 | return is_array($ret) ? $ret : ['error' => $response];
135 | }
136 | return $ret['refresh_token'];
137 | }
138 |
139 | private function urlPrefix($path)
140 | {
141 | $url = $this->oauth['api_url'];
142 | if ($path && $path !== '/') {
143 | $url .= ':' . $path;
144 | while (substr($url, -1) == '/') $url = substr($url, 0, -1);
145 | }
146 | return $url;
147 | }
148 |
149 | /**
150 | * @param string $path
151 | * @param int $page
152 | * @return mixed
153 | * @throws Exception
154 | */
155 | public function infos($path = '/', $page = 1)
156 | {
157 | $files = $this->getFullInfo($path);
158 | // die($path . '' . json_encode($files, JSON_PRETTY_PRINT) . ' ');
159 | if (isset($files['folder'])) {
160 | // is folder
161 | $files['folder']['currentPage'] = $page;
162 | $files['folder']['perPage'] = self::PAGE_SIZE;
163 | $files['folder']['lastPage'] = ceil($files['folder']['childCount'] / $files['folder']['perPage']);
164 |
165 | if ($files['folder']['childCount'] > $files['folder']['perPage'] && $page > 1) {
166 | $files['children'] = $this->getFullChildren($path, $page);
167 | }
168 | } elseif (isset($files['file'])) {
169 | // is file
170 | } else {
171 | error_log('failed to get files. response: ' . json_encode($files));
172 | if (!empty($files['error']) && !empty($files['error']['message'])) {
173 | throw new Exception($files['error']['message']);
174 | }
175 | throw new Exception(APP_DEBUG ? json_encode($files) : 'failed to get files.');
176 | }
177 |
178 | return $files;
179 | }
180 |
181 | /**
182 | * get info of target file
183 | * @param string $path
184 | * @param bool $thumbnails
185 | * @return mixed
186 | * @throws Exception
187 | */
188 | public function info($path, $thumbnails = false)
189 | {
190 | $cache_key = $this->cache_prefix . 'path_' . $path;
191 | if (!($files = $this->cache->fetch($cache_key))) {
192 | $url = $this->urlPrefix($path);
193 | if ($thumbnails) {
194 | $url .= ':/thumbnails/0/medium';
195 | }
196 |
197 | $files = json_decode(curl($url, 0, null, ['Authorization' => 'Bearer ' . $this->access_token]), true);
198 | if (is_array($files)) {
199 | $this->cache->save($cache_key, $files, 60);
200 | } else {
201 | if ($files == null) {
202 | $files = [
203 | 'error' => [
204 | 'message' => 'timeout'
205 | ]
206 | ];
207 | }
208 | }
209 | }
210 | return $files;
211 | }
212 |
213 | /**
214 | * Get the contents of a file.
215 | *
216 | * @param string $path
217 | * @return bool|false|string
218 | * @throws Exception
219 | */
220 | public function get($path)
221 | {
222 | $info = $this->info($path);
223 | if (isset($info['error'])) {
224 | if ($info['error']['code'] === 'itemNotFound') {
225 | return false;
226 | }
227 | throw new Exception($info['error']['message']);
228 | }
229 | if (empty($info['@microsoft.graph.downloadUrl'])) {
230 |
231 | throw new Exception('get_content failed');
232 | }
233 | return file_get_contents($info['@microsoft.graph.downloadUrl']);
234 | }
235 |
236 | /**
237 | * Write the contents of a file.
238 | *
239 | * @param string $path
240 | * @param string $contents
241 | * @return array
242 | * @throws Exception
243 | */
244 | public function put($path, $contents)
245 | {
246 | $url = $this->urlPrefix($path) . ':/content';
247 |
248 | $response = curl($url, 'PUT', $contents, [
249 | 'Content-Type' => 'text/plain',
250 | 'Content-Length' => strlen($contents),
251 | 'Authorization' => 'Bearer ' . $this->access_token
252 | ]);
253 | return json_decode($response, true) ?? $response;
254 | }
255 |
256 | /**
257 | * Create a directory.
258 | *
259 | * @param string $path
260 | * @return bool
261 | * @static
262 | * @throws Exception
263 | */
264 | public function makeDirectory($path)
265 | {
266 | $parent = substr($path, 0, strrpos($path, '/') + 1);
267 | $url = $this->urlPrefix($parent) . ($parent !== '/' ? ':' : '') . '/children';
268 | $response = curl($url, 'POST', json_encode([
269 | 'name' => urldecode(substr($path, strrpos($path, '/') + 1)),
270 | 'folder' => new \stdClass,
271 | '@microsoft.graph.conflictBehavior' => 'rename'
272 | ]), [
273 | 'Content-Type' => 'application/json',
274 | 'Authorization' => 'Bearer ' . $this->access_token
275 | ]);
276 | return json_decode($response, true) ?? $response;
277 | }
278 |
279 | /**
280 | * Move a file to a new location.
281 | *
282 | * @param string $path
283 | * @param string $target
284 | * @return array
285 | * @static
286 | * @throws Exception
287 | */
288 | public function move($path, $target)
289 | {
290 | $url = $this->urlPrefix($path);
291 | $data = [];
292 |
293 | $parent = substr($path, 0, strrpos($path, '/') + 1);
294 | $parent_new = substr($target, 0, strrpos($target, '/') + 1);
295 | if ($parent !== $parent_new) {
296 | // parent changed
297 | $data['parentReference'] = [
298 | 'path' => '/drive/root:' . urldecode($parent_new)
299 | ];
300 | } else {
301 | // name changed
302 | $data['name'] = urldecode(substr($target, strrpos($target, '/') + 1));
303 | }
304 | $response = curl($url, 'PATCH', json_encode($data), [
305 | 'Content-Type' => 'application/json',
306 | 'Authorization' => 'Bearer ' . $this->access_token
307 | ]);
308 | return json_decode($response, true) ?? $response;
309 | }
310 |
311 | /**
312 | * Delete the file at a given path.
313 | *
314 | * @param string $path
315 | * @return array
316 | * @static
317 | * @throws Exception
318 | */
319 | public function delete($path)
320 | {
321 | $url = $this->urlPrefix($path);
322 |
323 | $response = curl($url, 'DELETE', null, [
324 | 'Content-Type' => 'application/json',
325 | 'Authorization' => 'Bearer ' . $this->access_token
326 | ], $status);
327 | return json_decode($response, true) ?? ['status' => $status];
328 | }
329 |
330 | /**
331 | * Delete a directory.
332 | *
333 | * @param string $directory
334 | * @return array
335 | * @static
336 | * @throws Exception
337 | */
338 | public function deleteDirectory($directory)
339 | {
340 | $url = $this->urlPrefix($directory);
341 |
342 | $response = curl($url, 'DELETE', null, [
343 | 'Content-Type' => 'application/json',
344 | 'Authorization' => 'Bearer ' . $this->access_token
345 | ]);
346 | return json_decode($response, true) ?? $response;
347 | }
348 |
349 | /**
350 | * get a direct link for upload
351 | *
352 | * @param string $path
353 | * @return bool|mixed|string
354 | * @throws Exception
355 | */
356 | public function uploadUrl($path)
357 | {
358 | // $file = [
359 | // 'name' => urldecode(substr($path, strrpos($path, '/') + 1)),
360 | // 'size' => $size,
361 | // 'lastModified' => $lastModified
362 | // ];
363 | // '{"item": { "@microsoft.graph.conflictBehavior": "fail" }}',$_SERVER['access_token']);
364 |
365 | $url = $this->urlPrefix($path) . ':/createUploadSession';
366 | $response = curl($url, 'POST', json_encode([
367 | 'item' => [
368 | '@microsoft.graph.conflictBehavior' => 'fail'
369 | ]
370 | ]), [
371 | 'Content-Type' => 'application/json',
372 | 'Authorization' => 'Bearer ' . $this->access_token
373 | ]);
374 | return json_decode($response, true) ?? $response;
375 | }
376 |
377 |
378 | // https://docs.microsoft.com/en-us/graph/api/driveitem-get?view=graph-rest-1.0
379 | // https://docs.microsoft.com/zh-cn/graph/api/driveitem-put-content?view=graph-rest-1.0&tabs=http
380 | // https://developer.microsoft.com/zh-cn/graph/graph-explorer
381 |
382 | /**
383 | * get path with count of children
384 | * @param $path
385 | * @return mixed
386 | * @throws Exception
387 | */
388 | private function getFullInfo($path)
389 | {
390 | $cache_key = $this->cache_prefix . 'path_' . $path;
391 | if (!($files = $this->cache->fetch($cache_key))) {
392 | $url = $this->urlPrefix($path);
393 | $url .= '?expand=children(select=name,size,file,folder,parentReference,lastModifiedDateTime)';
394 |
395 | $files = json_decode(curl($url, 0, null, ['Authorization' => 'Bearer ' . $this->access_token]), true);
396 | if (is_array($files)) {
397 | $this->cache->save($cache_key, $files, 60);
398 | } else {
399 | if ($files == null) {
400 | $files = [
401 | 'error' => [
402 | 'message' => 'timeout'
403 | ]
404 | ];
405 | }
406 | }
407 | }
408 | return $files;
409 | }
410 |
411 | /**
412 | * get children with page but there is no total count....
413 | * @param $path
414 | * @param int $page
415 | * @return mixed
416 | * @throws Exception
417 | */
418 | private function getFullChildren($path, $page = 1)
419 | {
420 | $url = $this->urlPrefix($path);
421 | $url .= ($path !== '/' ? ':' : '') . '/children?$select=name,size,file,folder,parentReference,lastModifiedDateTime';
422 |
423 | $children = [];
424 | for ($current_page = 1; $current_page <= $page; $current_page++) {
425 | $cache_key = $this->cache_prefix . 'path_' . $path . '_page_' . $current_page;
426 | if (!($children = $this->cache->fetch($cache_key))) {
427 | $response = curl($url, 0, null, ['Authorization' => 'Bearer ' . $this->access_token]);
428 | $children = json_decode($response, true);
429 | if (isset($children['error'])) {
430 | throw new Exception($children['error']['message']);
431 | }
432 | $this->cache->save($cache_key, $children, 60);
433 | if ($current_page === $page) {
434 | break;
435 | }
436 | if (empty($children['@odata.nextLink'])) {
437 | throw new Exception(APP_DEBUG ? $response : 'get children failed');
438 | }
439 | $url = $children['@odata.nextLink'];
440 | }
441 | }
442 | return $children['value'];
443 | }
444 | }
--------------------------------------------------------------------------------
/php/library/functions.php:
--------------------------------------------------------------------------------
1 | 'Pacific/Kwajalein',
7 | '-11' => 'Pacific/Samoa',
8 | '-10' => 'Pacific/Honolulu',
9 | '-9' => 'America/Anchorage',
10 | '-8' => 'America/Los_Angeles',
11 | '-7' => 'America/Denver',
12 | '-6' => 'America/Mexico_City',
13 | '-5' => 'America/New_York',
14 | '-4' => 'America/Caracas',
15 | '-3.5' => 'America/St_Johns',
16 | '-3' => 'America/Argentina/Buenos_Aires',
17 | '-2' => 'America/Noronha',
18 | '-1' => 'Atlantic/Azores',
19 | '0' => 'UTC',
20 | '1' => 'Europe/Paris',
21 | '2' => 'Europe/Helsinki',
22 | '3' => 'Europe/Moscow',
23 | '3.5' => 'Asia/Tehran',
24 | '4' => 'Asia/Baku',
25 | '4.5' => 'Asia/Kabul',
26 | '5' => 'Asia/Karachi',
27 | '5.5' => 'Asia/Calcutta', //Asia/Colombo
28 | '6' => 'Asia/Dhaka',
29 | '6.5' => 'Asia/Rangoon',
30 | '7' => 'Asia/Bangkok',
31 | '8' => 'Asia/Shanghai',
32 | '9' => 'Asia/Tokyo',
33 | '9.5' => 'Australia/Darwin',
34 | '10' => 'Pacific/Guam',
35 | '11' => 'Asia/Magadan',
36 | '12' => 'Asia/Kamchatka'
37 | );
38 | if (empty($timezone)) $timezone = '8';
39 | return $timezones[$timezone];
40 | }
41 |
42 | /**
43 | * @param \Exception $e
44 | * @return string
45 | */
46 | function error_trace($e)
47 | {
48 | $str = '' . $e->getTraceAsString() . ' ';
49 | $str = str_replace(realpath(__DIR__ . '/../') . DIRECTORY_SEPARATOR, '', $str);
50 | return $str;
51 | }
52 |
53 | function path_format($path, $encode = false, $split = '/')
54 | {
55 |
56 | $items = explode($split, $path);
57 | $result = [];
58 |
59 | foreach ($items as $item) {
60 | if (empty($item)) continue;
61 |
62 | if ($item === '.') continue;
63 |
64 | if ($item === '..') {
65 | if (count($result) > 0) {
66 | array_pop($result);
67 | continue;
68 | }
69 | }
70 | if ($encode && strpos($path, '%') === FALSE) {
71 |
72 | $item = urlencode($item);
73 | $item = str_replace('+', '%20', $item);
74 | array_push($result, $item);
75 |
76 |
77 | } else {
78 | array_push($result, $item);
79 | }
80 | }
81 | return $split . join($split, $result);
82 | }
83 |
84 | function size_format($byte)
85 | {
86 | $i = 0;
87 | while (abs($byte) >= 1024) {
88 | $byte = $byte / 1024;
89 | $i++;
90 | if ($i == 3) break;
91 | }
92 | $units = array('B', 'KB', 'MB', 'GB', 'TB');
93 | $ret = round($byte, 2);
94 | return ($ret . ' ' . $units[$i]);
95 | }
96 |
97 | function time_format($ISO)
98 | {
99 | $ISO = str_replace('T', ' ', $ISO);
100 | $ISO = str_replace('Z', ' ', $ISO);
101 | //return $ISO;
102 | return date('Y-m-d H:i:s', strtotime($ISO . " UTC"));
103 | }
104 |
105 | /**
106 | * curl
107 | * @param string $url
108 | * @param string|int $method
109 | * @param bool $data
110 | * @param array $headers
111 | * @param null $status
112 | * @return bool|string
113 | * @throws \Exception
114 | */
115 | function curl($url, $method = 0, $data = null, $headers = [], &$status = null)
116 | {
117 | if (!isset($headers['Accept'])) $headers['Accept'] = '*/*';
118 | if (!isset($headers['Referer'])) $headers['Referer'] = $url;
119 | if (!isset($headers['Content-Type'])) $headers['Content-Type'] = 'application/x-www-form-urlencoded';
120 | $sendHeaders = array();
121 | foreach ($headers as $headerName => $headerVal) {
122 | $sendHeaders[] = $headerName . ': ' . $headerVal;
123 | }
124 |
125 | $ch = curl_init();
126 | curl_setopt($ch, CURLOPT_URL, $url);
127 |
128 | if ($data !== null || $method === 1) {
129 | curl_setopt($ch, CURLOPT_POST, 1);
130 | curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
131 | }
132 |
133 | if (is_string($method)) {
134 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
135 | }
136 |
137 | global $config;
138 | if (!empty($config['proxy'])) {
139 | $proxy = $config['proxy'];
140 | if (strpos($proxy, 'socks4://')) {
141 | $proxy = str_replace('socks4://', $proxy, $proxy);
142 | $proxy_type = CURLPROXY_SOCKS4;
143 | } elseif (strpos($proxy, 'socks4a://')) {
144 | $proxy = str_replace('socks4a://', $proxy, $proxy);
145 | $proxy_type = CURLPROXY_SOCKS4A;
146 | } elseif (strpos($proxy, 'socks5://')) {
147 | $proxy = str_replace('socks5://', $proxy, $proxy);
148 | $proxy_type = CURLPROXY_SOCKS5_HOSTNAME;
149 | } else {
150 | $proxy = str_replace('http://', $proxy, $proxy);
151 | $proxy = str_replace('https://', $proxy, $proxy);
152 | $proxy_type = CURLPROXY_HTTP;
153 | }
154 | curl_setopt($ch, CURLOPT_PROXY, $proxy); // '121.1.1.1:58082'
155 | curl_setopt($ch, CURLOPT_PROXYTYPE, $proxy_type); // 默认值: CURLPROXY_HTTP
156 | }
157 |
158 | curl_setopt($ch, CURLOPT_TIMEOUT, 10);
159 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
160 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
161 | curl_setopt($ch, CURLOPT_HEADER, 0);
162 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
163 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
164 | curl_setopt($ch, CURLOPT_HTTPHEADER, $sendHeaders);
165 | $response = curl_exec($ch);
166 | $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
167 | if (curl_errno($ch)) {
168 | throw new \Exception(curl_error($ch), 0);
169 | }
170 | curl_close($ch);
171 | return $response;
172 | }
--------------------------------------------------------------------------------
/php/platforms/AliyunSC/AliyunSC.php:
--------------------------------------------------------------------------------
1 | getHeaders();
15 | $headers = array_column(array_map(function ($k, $v) {
16 | return [strtolower($k), is_array($v) ? $v[0] : $v];
17 | }, array_keys($headers), $headers), 1, 0);
18 |
19 | foreach ($headers as $header => $value) {
20 | $_SERVER['HTTP_' . str_replace('-', '_', strtoupper($header))] = $value;
21 | }
22 | $_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST'];
23 | $_SERVER['SERVER_ADDR'] = '127.0.0.1';
24 | $_SERVER['SERVER_PORT'] = strpos($_SERVER['SERVER_NAME'], ':') === FALSE ? 80 : (int)explode(':', $_SERVER['SERVER_NAME'])[1];
25 | $_SERVER['REMOTE_ADDR'] = $request->getAttribute('clientIP');
26 | $_SERVER['DOCUMENT_ROOT'] = '/tmp/';
27 | $_SERVER['REQUEST_SCHEME'] = isset($_SERVER['HTTP_ORIGIN']) && strpos($_SERVER['HTTP_ORIGIN'], 'https://') !== FALSE ? 'https' : 'http';
28 | $_SERVER['SERVER_ADMIN'] = 'https://github.com/Tai7sy/OneDriveFly';
29 | $_SERVER['DOCUMENT_ROOT'] = dirname(__FILE__);
30 | $_SERVER['SCRIPT_FILENAME'] = __FILE__;
31 | $_SERVER['REDIRECT_URL'] = path_format($request->getAttribute('path'), true);
32 | $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
33 | $_SERVER['REQUEST_METHOD'] = $request->getMethod();
34 | $_SERVER['QUERY_STRING'] = http_build_query($request->getQueryParams());
35 | $_SERVER['REQUEST_URI'] = $_SERVER['REDIRECT_URL'] . ($_SERVER['QUERY_STRING'] ? '?' : '') . $_SERVER['QUERY_STRING'];
36 |
37 | $_POST = [];
38 | if ($headers['content-type'] === 'application/x-www-form-urlencoded') {
39 | $posts = explode('&', $request->getBody()->getContents());
40 | foreach ($posts as $post) {
41 | $pos = strpos($post, '=');
42 | $_POST[urldecode(substr($post, 0, $pos))] = urldecode(substr($post, $pos + 1));
43 | }
44 | } elseif (substr($headers['content-type'], 0, 19) === 'multipart/form-data') {
45 | // improve like this
46 | // https://gist.github.com/jas-/5c3fdc26fedd11cb9fb5#file-class-stream-php
47 | throw new \Exception('unsupported [multipart/form-data]');
48 | }
49 |
50 | $_COOKIE = [];
51 | if (isset($headers['cookie'])) {
52 | $cookies = explode('; ', $headers['cookie']);
53 | foreach ($cookies as $cookie) {
54 | $pos = strpos($cookie, '=');
55 | $_COOKIE[urldecode(substr($cookie, 0, $pos))] = urldecode(substr($cookie, $pos + 1));
56 | }
57 | }
58 |
59 | return new Request(
60 | $request->getQueryParams(),
61 | $_POST,
62 | [],
63 | $_COOKIE,
64 | [],
65 | $_SERVER,
66 | $request->getBody()->getContents()
67 | );
68 | }
69 |
70 | /**
71 | * @param Response $response
72 | * @return array|mixed
73 | */
74 | public static function response($response)
75 | {
76 | return new \RingCentral\Psr7\Response(
77 | $response->getStatusCode(),
78 | $response->headers->all(),
79 | $response->getContent()
80 | );
81 | }
82 | }
--------------------------------------------------------------------------------
/php/platforms/Heroku/Heroku.php:
--------------------------------------------------------------------------------
1 | getHeaders();
15 | $headers = array_column(array_map(function ($k, $v) {
16 | return [strtolower($k), is_array($v) ? $v[0] : $v];
17 | }, array_keys($headers), $headers), 1, 0);
18 |
19 | foreach ($headers as $header => $value) {
20 | $_SERVER['HTTP_' . str_replace('-', '_', strtoupper($header))] = $value;
21 | }
22 | $_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST'];
23 | $_SERVER['SERVER_ADDR'] = '127.0.0.1';
24 | $_SERVER['SERVER_PORT'] = strpos($_SERVER['SERVER_NAME'], ':') === FALSE ? 80 : (int)explode(':', $_SERVER['SERVER_NAME'])[1];
25 | $_SERVER['REMOTE_ADDR'] = $request->getAttribute('clientIP');
26 | $_SERVER['DOCUMENT_ROOT'] = '/tmp/';
27 | $_SERVER['REQUEST_SCHEME'] = isset($_SERVER['HTTP_ORIGIN']) && strpos($_SERVER['HTTP_ORIGIN'], 'https://') !== FALSE ? 'https' : 'http';
28 | $_SERVER['SERVER_ADMIN'] = 'https://github.com/Tai7sy/OneDriveFly';
29 | $_SERVER['DOCUMENT_ROOT'] = dirname(__FILE__);
30 | $_SERVER['SCRIPT_FILENAME'] = __FILE__;
31 | $_SERVER['REDIRECT_URL'] = path_format($request->getAttribute('path'), true);
32 | $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
33 | $_SERVER['REQUEST_METHOD'] = $request->getMethod();
34 | $_SERVER['QUERY_STRING'] = http_build_query($request->getQueryParams());
35 | $_SERVER['REQUEST_URI'] = $_SERVER['REDIRECT_URL'] . ($_SERVER['QUERY_STRING'] ? '?' : '') . $_SERVER['QUERY_STRING'];
36 |
37 | $_POST = [];
38 | if ($headers['content-type'] === 'application/x-www-form-urlencoded') {
39 | $posts = explode('&', $request->getBody()->getContents());
40 | foreach ($posts as $post) {
41 | $pos = strpos($post, '=');
42 | $_POST[urldecode(substr($post, 0, $pos))] = urldecode(substr($post, $pos + 1));
43 | }
44 | } elseif (substr($headers['content-type'], 0, 19) === 'multipart/form-data') {
45 | // improve like this
46 | // https://gist.github.com/jas-/5c3fdc26fedd11cb9fb5#file-class-stream-php
47 | throw new \Exception('unsupported [multipart/form-data]');
48 | }
49 |
50 | $_COOKIE = [];
51 | if (isset($headers['cookie'])) {
52 | $cookies = explode('; ', $headers['cookie']);
53 | foreach ($cookies as $cookie) {
54 | $pos = strpos($cookie, '=');
55 | $_COOKIE[urldecode(substr($cookie, 0, $pos))] = urldecode(substr($cookie, $pos + 1));
56 | }
57 | }
58 |
59 | return new Request(
60 | $request->getQueryParams(),
61 | $_POST,
62 | [],
63 | $_COOKIE,
64 | [],
65 | $_SERVER,
66 | $request->getBody()->getContents()
67 | );
68 | }
69 |
70 | /**
71 | * @param Response $response
72 | * @return array|mixed
73 | */
74 | public static function response($response)
75 | {
76 | return new \RingCentral\Psr7\Response(
77 | $response->getStatusCode(),
78 | $response->headers->all(),
79 | $response->getContent()
80 | );
81 | }
82 | }
--------------------------------------------------------------------------------
/php/platforms/Normal/Normal.php:
--------------------------------------------------------------------------------
1 | get('s')){
23 | $new_uri = self::$request->getBaseUrl() . self::$request->get('s');
24 | if(!empty($_SERVER['UNENCODED_URL'])){
25 | $_SERVER['UNENCODED_URL'] = $new_uri;
26 | }else{
27 | $_SERVER['REQUEST_URI'] = $new_uri;
28 | }
29 | self::$request = Request::createFromGlobals();
30 | }
31 | }
32 | return self::$request;
33 | }
34 |
35 | /**
36 | * @param Response $response
37 | * @return mixed
38 | */
39 | public static function response($response)
40 | {
41 | return $response->send();
42 | }
43 | }
--------------------------------------------------------------------------------
/php/platforms/PlatformInterface.php:
--------------------------------------------------------------------------------
1 | $value) {
15 | $_SERVER['HTTP_' . str_replace('-', '_', strtoupper($header))] = $value;
16 | }
17 | $_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST'];
18 | $_SERVER['SERVER_ADDR'] = '127.0.0.1';
19 | $_SERVER['SERVER_PORT'] = strpos($_SERVER['SERVER_NAME'], ':') === FALSE ? 80 : (int)explode(':', $_SERVER['SERVER_NAME'])[1];
20 | $_SERVER['REMOTE_ADDR'] = $event['requestContext']['sourceIp'];
21 | $_SERVER['DOCUMENT_ROOT'] = '/tmp/';
22 | $_SERVER['REQUEST_SCHEME'] = isset($_SERVER['HTTP_ORIGIN']) && strpos($_SERVER['HTTP_ORIGIN'], 'https://') !== FALSE ? 'https' : 'http';
23 | $_SERVER['SERVER_ADMIN'] = 'https://github.com/Tai7sy/OneDriveFly';
24 | $_SERVER['DOCUMENT_ROOT'] = dirname(__FILE__);
25 | $_SERVER['SCRIPT_FILENAME'] = __FILE__;
26 | $_SERVER['REDIRECT_URL'] = $event['requestContext']['path'] === '/' ? $event['path'] : substr($event['path'], strlen($event['requestContext']['path']));
27 | $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
28 | $_SERVER['REQUEST_METHOD'] = $event['httpMethod'];
29 | $_SERVER['QUERY_STRING'] = http_build_query($event['queryString']);
30 | $_SERVER['REQUEST_URI'] = $_SERVER['REDIRECT_URL'] . ($_SERVER['QUERY_STRING'] ? '?' : '') . $_SERVER['QUERY_STRING'];
31 |
32 | $_POST = [];
33 | if ($event['headers']['content-type'] === 'application/x-www-form-urlencoded') {
34 | $posts = explode('&', $event['body']);
35 | foreach ($posts as $post) {
36 | $pos = strpos($post, '=');
37 | $_POST[urldecode(substr($post, 0, $pos))] = urldecode(substr($post, $pos + 1));
38 | }
39 | } elseif (substr($event['headers']['content-type'], 0, 19) === 'multipart/form-data') {
40 | // improve like this
41 | // https://gist.github.com/jas-/5c3fdc26fedd11cb9fb5#file-class-stream-php
42 | throw new \Exception('unsupported [multipart/form-data]');
43 | }
44 |
45 | $_COOKIE = [];
46 | $cookies = explode('; ', $event['headers']['cookie']);
47 | foreach ($cookies as $cookie) {
48 | $pos = strpos($cookie, '=');
49 | $_COOKIE[urldecode(substr($cookie, 0, $pos))] = urldecode(substr($cookie, $pos + 1));
50 | }
51 |
52 | return new Request(
53 | isset($event['queryString']) ? $event['queryString'] : [],
54 | $_POST,
55 | [],
56 | $_COOKIE,
57 | [],
58 | $_SERVER
59 | );
60 | }
61 |
62 | /**
63 | * @param Response $response
64 | * @return array|mixed
65 | */
66 | public static function response($response)
67 | {
68 | return [
69 | 'isBase64Encoded' => false,
70 | 'statusCode' => $response->getStatusCode(),
71 | 'headers' => array_map(function ($values) {
72 | return $values[0];
73 | }, $response->headers->all()),
74 | 'body' => $response->getContent()
75 | ];
76 | }
77 | }
--------------------------------------------------------------------------------
/php/platforms/QCloudSCF/scfapi.php:
--------------------------------------------------------------------------------
1 | $v1) {
27 | $str .= '&' . $k1 . '=' . $v1;
28 | }
29 | $str = substr($str, 1);
30 | return $str;
31 | }
32 |
33 | function scf_get_function($function_name, $Region, $Namespace)
34 | {
35 | //$meth = 'GET';
36 | $meth = 'POST';
37 | $host = 'scf.tencentcloudapi.com';
38 | $tmpdata['Action'] = 'GetFunction';
39 | $tmpdata['FunctionName'] = $function_name;
40 | $tmpdata['Namespace'] = $Namespace;
41 | $tmpdata['Nonce'] = time();
42 | $tmpdata['Region'] = getenv('Region');
43 | $tmpdata['SecretId'] = getenv('SecretId');
44 | $tmpdata['Timestamp'] = time();
45 | $tmpdata['Token'] = '';
46 | $tmpdata['Version'] = '2018-04-16';
47 | $data = params($tmpdata);
48 | $signStr = base64_encode(hash_hmac('sha1', $meth . $host . '/?' . $data, getenv('SecretKey'), true));
49 | //echo urlencode($signStr);
50 | //return file_get_contents('https://'.$url.'&Signature='.urlencode($signStr));
51 | return post2url('https://' . $host, $data . '&Signature=' . urlencode($signStr));
52 | }
53 |
54 | function scf_update_env($Envs, $function_name, $Region, $Namespace)
55 | {
56 | //print_r($Envs);
57 | //json_decode($a,true)['Response']['Environment']['Variables'][0]['Key']
58 | $tmp = json_decode(scf_get_function($function_name, $Region, $Namespace), true)['Response']['Environment']['Variables'];
59 | $tmp_env = [];
60 | foreach ($tmp as $tmp1) {
61 | $tmp_env[$tmp1['Key']] = $tmp1['Value'];
62 | }
63 | foreach ($Envs as $key1 => $value1) {
64 | $tmp_env[$key1] = $value1;
65 | }
66 | $tmp_env = array_filter($tmp_env, function ($arr) {
67 | return !empty($arr);
68 | });
69 | $tmp_env['Region'] = getenv('Region');
70 | ksort($tmp_env);
71 |
72 | $i = 0;
73 | foreach ($tmp_env as $key1 => $value1) {
74 | $tmpdata['Environment.Variables.' . $i . '.Key'] = $key1;
75 | $tmpdata['Environment.Variables.' . $i . '.Value'] = $value1;
76 | $i++;
77 | }
78 | $meth = 'POST';
79 | $host = 'scf.tencentcloudapi.com';
80 | $tmpdata['Action'] = 'UpdateFunctionConfiguration';
81 | $tmpdata['FunctionName'] = $function_name;
82 | $tmpdata['Namespace'] = $Namespace;
83 | $tmpdata['Nonce'] = time();
84 | $tmpdata['Region'] = getenv('Region');
85 | $tmpdata['SecretId'] = getenv('SecretId');
86 | $tmpdata['Timestamp'] = time();
87 | $tmpdata['Token'] = '';
88 | $tmpdata['Version'] = '2018-04-16';
89 | $data = params($tmpdata);
90 | $signStr = base64_encode(hash_hmac('sha1', $meth . $host . '/?' . $data, getenv('SecretKey'), true));
91 | //echo urlencode($signStr);
92 | return post2url('https://' . $host, $data . '&Signature=' . urlencode($signStr));
93 | }
94 |
95 | function scf_update_configuration($function_name, $Region, $Namespace)
96 | {
97 | $meth = 'POST';
98 | $host = 'scf.tencentcloudapi.com';
99 | $tmpdata['Action'] = 'UpdateFunctionConfiguration';
100 | $tmpdata['FunctionName'] = $function_name;
101 | $tmpdata['Description'] = 'Onedrive index in SCF. SCF上的Onedrive目录网站程序。';
102 | $tmpdata['MemorySize'] = 128;
103 | $tmpdata['Timeout'] = 30;
104 | $tmpdata['Namespace'] = $Namespace;
105 | $tmpdata['Nonce'] = time();
106 | $tmpdata['Region'] = getenv('Region');
107 | $tmpdata['SecretId'] = getenv('SecretId');
108 | $tmpdata['Timestamp'] = time();
109 | $tmpdata['Token'] = '';
110 | $tmpdata['Version'] = '2018-04-16';
111 | $data = params($tmpdata);
112 | $signStr = base64_encode(hash_hmac('sha1', $meth . $host . '/?' . $data, getenv('SecretKey'), true));
113 | //echo urlencode($signStr);
114 | return post2url('https://' . $host, $data . '&Signature=' . urlencode($signStr));
115 | }
116 |
117 | function scf_update_code($function_name, $Region, $Namespace)
118 | {
119 | $meth = 'POST';
120 | $host = 'scf.tencentcloudapi.com';
121 | $tmpdata['Action'] = 'UpdateFunctionCode';
122 | $tmpdata['Code.GitUrl'] = 'https://github.com/qkqpttgf/OneManager-php';
123 | $tmpdata['CodeSource'] = 'Git';
124 | $tmpdata['FunctionName'] = $function_name;
125 | $tmpdata['Handler'] = 'index.main_handler';
126 | $tmpdata['Namespace'] = $Namespace;
127 | $tmpdata['Nonce'] = time();
128 | $tmpdata['Region'] = getenv('Region');
129 | $tmpdata['SecretId'] = getenv('SecretId');
130 | $tmpdata['Timestamp'] = time();
131 | $tmpdata['Token'] = '';
132 | $tmpdata['Version'] = '2018-04-16';
133 | $data = params($tmpdata);
134 | $signStr = base64_encode(hash_hmac('sha1', $meth . $host . '/?' . $data, getenv('SecretKey'), true));
135 | //echo urlencode($signStr);
136 | return post2url('https://' . $host, $data . '&Signature=' . urlencode($signStr));
137 | }
138 |
139 |
140 |
141 | function EnvOpt($function_name, $Region, $namespace = 'default', $needUpdate = 0)
142 | {
143 | $constEnv = [
144 | //'admin',
145 | 'adminloginpage', 'domain_path', 'imgup_path', 'passfile', 'private_path', 'public_path', 'sitename', 'language'
146 | ];
147 | asort($constEnv);
148 | $html = 'SCF ' . trans('Setup') . ' ';
149 | if ($_POST['updateProgram'] == trans('updateProgram')) {
150 | $response = json_decode(scf_update_code($function_name, $Region, $namespace), true)['Response'];
151 | if (isset($response['Error'])) {
152 | $html = $response['Error']['Code'] . '
153 | ' . $response['Error']['Message'] . '
154 | function_name:' . $_SERVER['function_name'] . '
155 | Region:' . $_SERVER['Region'] . '
156 | namespace:' . $namespace . '
157 | ' . trans('Reflesh') . ' ';
158 | $title = 'Error';
159 | } else {
160 | $html .= trans('UpdateSuccess') . '
161 | ' . trans('Reflesh') . ' ';
162 | $title = trans('Setup');
163 | }
164 | return message($html, $title);
165 | }
166 | if ($_POST['submit1']) {
167 | foreach ($_POST as $k => $v) {
168 | if (in_array($k, $constEnv)) {
169 | $tmp[$k] = $v;
170 | }
171 | }
172 | echo scf_update_env($tmp, $function_name, $Region, $namespace);
173 | $html .= '';
174 | }
175 | if ($_GET['preview']) {
176 | $preurl = $_SERVER['PHP_SELF'] . '?preview';
177 | } else {
178 | $preurl = path_format($_SERVER['PHP_SELF'] . '/');
179 | }
180 | $html .= '
181 | ' . trans('Back') . '
182 | Github ';
183 | if ($needUpdate) {
184 | $html .= '' . $_SERVER['github_version'] . '
185 |
186 |
187 | ';
188 | } else {
189 | $html .= trans('NotNeedUpdate');
190 | }
191 | $html .= '
192 |
193 |
216 |
217 | ';
218 | return message($html, trans('Setup'));
219 | }
--------------------------------------------------------------------------------
/php/scripts/dist.php:
--------------------------------------------------------------------------------
1 | \r\n"
13 | . "\r\n"
15 | . php_strip_whitespace($vendor_path)
16 | . "?>\r\n"
17 | . "register();
11 |
12 | require __DIR__ . '/../index.php';
13 | global $config;
14 | $config['multi'] = 0;
15 | $config['accounts'][0]['refresh_token'] = '';
16 |
17 | try {
18 | new \Library\Ext();
19 | new \Library\Lang();
20 | new \Library\OneDrive(null);
21 |
22 | new \Platforms\Normal\Normal();
23 | new \Platforms\QCloudSCF\QCloudSCF();
24 | new \Platforms\AliyunSC\AliyunSC();
25 |
26 | new \Doctrine\Common\Cache\FilesystemCache(sys_get_temp_dir(),'.delete_me');
27 | new \Doctrine\Common\Cache\VoidCache();
28 | new \Symfony\Component\HttpFoundation\Request();
29 | new \Symfony\Component\HttpFoundation\Response();
30 |
31 | @ob_start();
32 | @cgi_entry();
33 | } finally {
34 | @ob_clean();
35 | }
36 | @ob_clean();
37 |
38 | });
39 |
40 | // Add a regex filter that requires all classes to match the regex.
41 | // $config->addInclusiveFilter('/Foo/');
42 |
43 | // Add a regex filter that requires that a class does not match the filter.
44 | // $config->addExclusiveFilter('/Foo/');
45 |
46 |
47 | $config->addExclusiveFilter('/config\.php/');
48 | return $config;
--------------------------------------------------------------------------------
/php/vendor/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------