├── .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 | release 4 | Travis 5 | Travis 6 | License 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 |
8 |

9 | 1. Download index.php from 10 | https://github.com/Tai7sy/OneDriveFly/releases 11 |

12 |

13 | 2. Put it on your server 14 |

15 |
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 | 393 | 569 | 570 | 571 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | <?php echo $title; ?> 598 | 599 | 600 | 601 | 602 | 603 | 611 | 612 | 613 |
614 |
615 |
616 | 617 |
618 |
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 | <?php echo ($path['relative'] === '' ? '/' : urldecode($path['relative'])) . ' - ' . $config['name']; ?> 687 | 690 | 691 | 692 | 693 | 695 | 696 | 697 | 736 | 741 | 742 | 743 | 744 | 748 | 749 | 751 |
  • 752 | 778 |
  • 779 | 783 | 793 | 794 |
    795 |
    796 |

    797 | 798 |

    799 |
    800 |
    801 |
    802 | getUri(); 804 | while (substr($current_url, -1) === '/') { 805 | $current_url = substr($current_url, 0, -1); 806 | } 807 | if (strpos($current_url, '/') !== FALSE) { 808 | $parent_url = substr($current_url, 0, strrpos($current_url, '/')); 809 | } else { 810 | $parent_url = $current_url; 811 | } 812 | ?> 813 | 814 | 815 | 816 | 817 |

    /

    818 |
    819 |
    820 | 822 |
    823 |
    824 | 825 | 827 |
    828 |
    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 |
    845 | 849 | 851 |   853 | 854 |
    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 |
    874 | 875 |
    876 | 878 | 880 | 881 | 882 | 884 | '; ?> 885 |
    886 |
    '; 888 | } else { 889 | echo '' . trans('FileNotSupport') . ''; 890 | } ?> 891 |
    892 |
    893 | 897 | 898 | 899 | 903 | 905 | 907 | 908 | 909 | 915 | 916 | 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 | 1006 | 1007 | 1008 | 1009 | 1012 |
    900 |     901 | 902 |
    917 | 918 |
  • 919 |
      920 |
    • 921 | 922 |
    • 923 |
    • 924 | 925 |
    • 926 |
    • 927 | 928 |
    • 929 |
    • 930 | 931 |
    • 932 |
    933 |
  •     934 | 935 | 936 | 938 |
    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 |
    1013 | 1014 | $files['folder']['perPage']) { 1016 | $pageForm = ' 1017 | 1018 | 1019 | 1020 | 1021 | 1028 | 1040 | 1047 | 1048 |
    '; 1022 | if ($files['folder']['currentPage'] !== 1) { 1023 | $pageForm .= ' 1024 | ' . trans('PrePage') . ''; 1025 | } 1026 | $pageForm .= ' 1027 | '; 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 | '; 1041 | if ($files['folder']['currentPage'] != $files['folder']['lastPage']) { 1042 | $pageForm .= ' 1043 | ' . trans('NextPage') . ''; 1044 | } 1045 | $pageForm .= ' 1046 |
    1049 | '; 1050 | echo $pageForm; 1051 | } 1052 | ?> 1053 | 1054 | 1056 |
    1057 |
    1058 | 1060 | 1063 |
    1064 |
    1065 | 1074 |
    1075 |
    1076 | 1077 |
    1078 |
    1079 |
    1080 |
    1081 | 1082 | ' . $readme['name'] . ' 1083 |
    1084 | 1087 |
    1088 |
    1089 | '; 1090 | } 1091 | } // end of if-error 1092 | } 1093 | else // end of if-password 1094 | { 1095 | echo ' 1096 |
    1097 |
    1098 | 1099 | 1100 |
    1101 |
    '; 1102 | $status_code = 401; 1103 | } 1104 | } ?> 1105 |
    1106 |
    1107 |
    1108 | 1109 | query->has('preview')) { ?> 1112 | 1126 | 1127 | 1141 | 1142 | 1161 | 1162 | 1185 | 1186 | 1233 | 1234 | 1237 | 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 | '; 158 | $title = 'Error'; 159 | } else { 160 | $html .= trans('UpdateSuccess') . '
    161 | '; 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 | '; 194 | foreach ($constEnv as $key) { 195 | if ($key == 'language') { 196 | $html .= ' 197 | 198 | 199 | 208 | '; 209 | } else $html .= ' 210 | 211 | 212 | 213 | '; 214 | } 215 | $html .= '
    200 | 207 |
    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 --------------------------------------------------------------------------------