From abfe215999ae9252cdc165051a2ccc07e369f843 Mon Sep 17 00:00:00 2001 From: BingoKingo Date: Mon, 13 Jul 2020 20:07:31 +0800 Subject: [PATCH] update 2020.7.13 --- common.php | 609 +++++++---- conststr.php | 36 +- index.php | 87 +- platform/AliyunFC.php | 414 ++++++++ platform/HuaweiFG.php | 743 ++++++++++++++ platform/{scf.php => TencentSCF.php} | 25 +- platform/heroku.php | 18 +- platform/normal.php | 82 +- readme.md | 17 +- theme/classic.html | 144 +-- theme/nchyn_grey.html | 1414 ++++++++++++++++++++++++++ theme/nexmoe1.html | 377 +++++++ theme/nexmoe2.html | 580 +++++++++++ theme/onemoe.html | 166 +-- theme/renexmoe.html | 606 +++++++++++ version | 1 + 16 files changed, 4975 insertions(+), 344 deletions(-) create mode 100644 platform/AliyunFC.php create mode 100644 platform/HuaweiFG.php rename platform/{scf.php => TencentSCF.php} (94%) create mode 100644 theme/nchyn_grey.html create mode 100644 theme/nexmoe1.html create mode 100644 theme/nexmoe2.html create mode 100644 theme/renexmoe.html diff --git a/common.php b/common.php index b23233d..be54b63 100644 --- a/common.php +++ b/common.php @@ -5,10 +5,17 @@ $Base64Env = [ //'Region', // used in SCF. //'SecretId', // used in SCF. //'SecretKey', // used in SCF. + //'AccessKeyID', // used in FC. + //'AccessKeySecret', // used in FC. + //'HW_urn', // used in FG. + //'HW_key', // used in FG. + //'HW_secret', // used in FG. //'admin', //'adminloginpage', 'background', 'diskname', + //'disableShowThumb', + //'disableChangeTheme', //'disktag', //'downloadencrypt', //'function_name', // used in heroku. @@ -18,6 +25,7 @@ $Base64Env = [ 'sitename', 'customScript', 'customCss', + 'customTheme', //'theme', //'Drive_ver', //'Drive_custom', @@ -31,6 +39,7 @@ $Base64Env = [ //'sharecookie', 'shareapiurl', //'siteid', + 'domainforproxy', 'public_path', //'refresh_token', //'token_expires', @@ -41,10 +50,17 @@ $CommonEnv = [ 'Region', // used in SCF. 'SecretId', // used in SCF. 'SecretKey', // used in SCF. + 'AccessKeyID', // used in FC. + 'AccessKeySecret', // used in FC. + 'HW_urn', // used in FG. + 'HW_key', // used in FG. + 'HW_secret', // used in FG. 'admin', 'adminloginpage', 'background', 'disktag', + 'disableShowThumb', + 'disableChangeTheme', 'function_name', // used in heroku. 'hideFunctionalityFile', 'timezone', @@ -52,6 +68,7 @@ $CommonEnv = [ 'sitename', 'customScript', 'customCss', + 'customTheme', 'theme', ]; @@ -60,10 +77,17 @@ $ShowedCommonEnv = [ //'Region', // used in SCF. //'SecretId', // used in SCF. //'SecretKey', // used in SCF. + //'AccessKeyID', // used in FC. + //'AccessKeySecret', // used in FC. + //'HW_urn', // used in FG. + //'HW_key', // used in FG. + //'HW_secret', // used in FG. //'admin', 'adminloginpage', 'background', //'disktag', + 'disableShowThumb', + 'disableChangeTheme', //'function_name', // used in heroku. 'hideFunctionalityFile', 'timezone', @@ -71,6 +95,7 @@ $ShowedCommonEnv = [ 'sitename', 'customScript', 'customCss', + 'customTheme', 'theme', ]; @@ -89,6 +114,7 @@ $InnerEnv = [ 'shareurl', //'sharecookie', 'shareapiurl', + 'domainforproxy', 'public_path', 'refresh_token', 'token_expires', @@ -109,6 +135,7 @@ $ShowedInnerEnv = [ //'shareurl', //'sharecookie', //'shareapiurl', + 'domainforproxy', 'public_path', //'refresh_token', //'token_expires', @@ -271,7 +298,8 @@ function main($path) $oldname = spurlencode($_GET['filename']); $pos = strrpos($oldname, '.'); if ($pos>0) $ext = strtolower(substr($oldname, $pos)); - $oldname = path_format(path_format($_SERVER['list_path'] . path_format($path)) . '/' . $oldname . '.scfupload' ); + //$oldname = path_format(path_format($_SERVER['list_path'] . path_format($path)) . '/' . $oldname . '.scfupload' ); + $oldname = path_format(path_format($_SERVER['list_path'] . path_format($path)) . '/' . $oldname); $data = '{"name":"' . $_GET['filemd5'] . $ext . '"}'; //echo $oldname .'
'. $data; $tmp = MSAPI('PATCH',$oldname,$data,$_SERVER['access_token']); @@ -303,13 +331,17 @@ function main($path) if (isset($_GET['thumbnails'])) { if ($_SERVER['ishidden']<4) { if (in_array(strtolower(substr($path, strrpos($path, '.') + 1)), $exts['img'])) { - return get_thumbnails_url($path); + return get_thumbnails_url($path, $_GET['location']); } else return output(json_encode($exts['img']),400); } else return output('',401); } $files = list_files($path); //echo json_encode(array_keys($files['children']), JSON_PRETTY_PRINT); + if ($_GET['json']) { + // return a json + return files_json($files); + } if (isset($_GET['random'])&&$_GET['random']!=='') { if ($_SERVER['ishidden']<4) { $tmp = []; @@ -318,14 +350,29 @@ function main($path) } $tmp = array_values($tmp); if (count($tmp)>0) { - if (isset($_GET['url'])) return output($tmp[rand(0,count($tmp)-1)], 200); - return output('', 302, [ 'Location' => $tmp[rand(0,count($tmp)-1)] ]); + $url = $tmp[rand(0,count($tmp)-1)]; + if (isset($_GET['url'])) return output($url, 200); + $domainforproxy = ''; + $domainforproxy = getConfig('domainforproxy'); + if ($domainforproxy!='') { + $url = proxy_replace_domain($url, $domainforproxy); + } + return output('', 302, [ 'Location' => $url ]); } else return output('',404); } else return output('',401); } if (isset($files['file']) && !isset($_GET['preview'])) { // is file && not preview mode - if ( $_SERVER['ishidden']<4 || (!!getConfig('downloadencrypt')&&$files['name']!=getConfig('passfile')) ) return output('', 302, [ 'Location' => $files[$_SERVER['DownurlStrName']] ]); + if ( $_SERVER['ishidden']<4 || (!!getConfig('downloadencrypt')&&$files['name']!=getConfig('passfile')) ) { + $url = $files[$_SERVER['DownurlStrName']]; + $domainforproxy = ''; + $domainforproxy = getConfig('domainforproxy'); + if ($domainforproxy!='') { + $url = proxy_replace_domain($url, $domainforproxy); + } + if ( strtolower(splitlast($files['name'],'.')[1])=='html' ) return output($files['content']['body'], $files['content']['stat']); + else return output('', 302, [ 'Location' => $url ]); + } } if ( isset($files['folder']) || isset($files['file']) ) { return render_list($path, $files); @@ -340,6 +387,54 @@ function main($path) } } +function proxy_replace_domain($url, $domainforproxy) +{ + $tmp = splitfirst($url, '//'); + $http = $tmp[0]; + $tmp = splitfirst($tmp[1], '/'); + $domain = $tmp[0]; + $uri = $tmp[1]; + if (substr($domainforproxy, 0, 7)=='http://' || substr($domainforproxy, 0, 8)=='https://') $aim = $domainforproxy; + else $aim = $http . '//' . $domainforproxy; + if (substr($aim, -1)=='/') $aim = substr($aim, 0, -1); + return $aim . '/' . $uri . '&Origindomain=' . $domain; + //$url = str_replace($tmp, $domainforproxy, $url).'&Origindomain='.$tmp; +} + +function files_json($files) +{ + //$tmp = ''; + if (isset($files['file'])) { + $tmp['file']['type'] = 0; + $tmp['file']['id'] = $files['id']; + $tmp['file']['name'] = $files['name']; + $tmp['file']['time'] = $files['lastModifiedDateTime']; + $tmp['file']['size'] = $files['size']; + $tmp['file']['mime'] = $files['file']['mimeType']; + $tmp['file']['url'] = $files[$_SERVER['DownurlStrName']]; + $tmp['url'] = $files[$_SERVER['DownurlStrName']]; + } elseif (isset($files['folder'])) { + $tmp['list'] = []; + foreach ($files['children'] as $file) { + $tmp1 = null; + $tmp1 = []; + if (isset($file['file'])) { + $tmp1['type'] = 0; + $tmp1['url'] = $file[$_SERVER['DownurlStrName']]; + } elseif (isset($file['folder'])) { + $tmp1['type'] = 1; + } + $tmp1['id'] = $file['id']; + $tmp1['name'] = $file['name']; + $tmp1['time'] = $file['lastModifiedDateTime']; + $tmp1['size'] = $file['size']; + $tmp1['mime'] = $file['file']['mimeType']; + array_push($tmp['list'], $tmp1); + } + } else return output('', 404); + return output(json_encode($tmp)); +} + function get_access_token($refresh_token) { if (getConfig('Drive_ver')=='shareurl') { @@ -362,20 +457,29 @@ function get_access_token($refresh_token) error_log('failed to get share access_token. response' . json_encode($ret)); throw new Exception($response['stat'].', failed to get share access_token.'.$response['body']); } - error_log('Get access token:'.json_encode($ret, JSON_PRETTY_PRINT)); + $tmp = $ret; + $tmp['access_token'] = '******'; + error_log('['.$_SERVER['disktag'].'] Get access token:'.json_encode($tmp, JSON_PRETTY_PRINT)); savecache('access_token', $_SERVER['access_token']); - $tmp = []; - $tmp['shareapiurl'] = $_SERVER['api_url']; - if (getConfig('shareapiurl')=='') setConfig($tmp); + $tmp1 = []; + $tmp1['shareapiurl'] = $_SERVER['api_url']; + if (getConfig('shareapiurl')=='') setConfig($tmp1); } else { - $response = curl_request( $_SERVER['oauth_url'] . 'token', 'client_id='. $_SERVER['client_id'] .'&client_secret='. $_SERVER['client_secret'] .'&grant_type=refresh_token&requested_token_use=on_behalf_of&refresh_token=' . $refresh_token ); + $p=0; + while ($response['stat']==0&&$p<3) { + $response = curl_request( $_SERVER['oauth_url'] . 'token', 'client_id='. $_SERVER['client_id'] .'&client_secret='. $_SERVER['client_secret'] .'&grant_type=refresh_token&requested_token_use=on_behalf_of&refresh_token=' . $refresh_token ); + $p++; + } if ($response['stat']==200) $ret = json_decode($response['body'], true); if (!isset($ret['access_token'])) { - error_log($_SERVER['oauth_url'] . 'token'.'?client_id='. $_SERVER['client_id'] .'&client_secret='. $_SERVER['client_secret'] .'&grant_type=refresh_token&requested_token_use=on_behalf_of&refresh_token=' . $refresh_token); - error_log('failed to get access_token. response' . json_encode($ret)); - throw new Exception($response['stat'].', failed to get access_token.'.$response['body']); + error_log($_SERVER['oauth_url'] . 'token'.'?client_id='. $_SERVER['client_id'] .'&client_secret='. $_SERVER['client_secret'] .'&grant_type=refresh_token&requested_token_use=on_behalf_of&refresh_token=' . substr($refresh_token, 0, 20) . '******' . substr($refresh_token, -20)); + error_log('failed to get ['.$_SERVER['disktag'].'] access_token. response' . json_encode($ret)); + throw new Exception($response['stat'].', failed to get ['.$_SERVER['disktag'].'] access_token.'.$response['body']); } - error_log('Get access token:'.json_encode($ret, JSON_PRETTY_PRINT)); + $tmp = $ret; + $tmp['access_token'] = '******'; + $tmp['refresh_token'] = '******'; + error_log('['.$_SERVER['disktag'].'] Get access token:'.json_encode($tmp, JSON_PRETTY_PRINT)); $_SERVER['access_token'] = $ret['access_token']; savecache('access_token', $_SERVER['access_token'], $ret['expires_in'] - 300); if (time()>getConfig('token_expires')) setConfig([ 'refresh_token' => $ret['refresh_token'], 'token_expires' => time()+7*24*60*60 ]); @@ -775,23 +879,35 @@ function time_format($ISO) return date('Y-m-d H:i:s',strtotime($ISO . " UTC")); } -function get_thumbnails_url($path = '/') +function get_thumbnails_url($path = '/', $location = 0) { $path1 = path_format($path); $path = path_format($_SERVER['list_path'] . path_format($path)); if ($path!='/'&&substr($path,-1)=='/') $path=substr($path,0,-1); $thumb_url = getcache('thumb_'.$path); - if ($thumb_url!='') return output($thumb_url); - $url = $_SERVER['api_url']; - if ($path !== '/') { - $url .= ':' . $path; - if (substr($url,-1)=='/') $url=substr($url,0,-1); + if ($thumb_url=='') { + $url = $_SERVER['api_url']; + if ($path !== '/') { + $url .= ':' . $path; + if (substr($url,-1)=='/') $url=substr($url,0,-1); + } + $url .= ':/thumbnails/0/medium'; + $files = json_decode(curl_request($url, false, ['Authorization' => 'Bearer ' . $_SERVER['access_token']])['body'], true); + if (isset($files['url'])) { + savecache('thumb_'.$path, $files['url']); + $thumb_url = $files['url']; + } } - $url .= ':/thumbnails/0/medium'; - $files = json_decode(curl_request($url, false, ['Authorization' => 'Bearer ' . $_SERVER['access_token']])['body'], true); - if (isset($files['url'])) { - savecache('thumb_'.$path, $files['url']); - return output($files['url']); + if ($thumb_url!='') { + if ($location) { + $url = $thumb_url; + $domainforproxy = ''; + $domainforproxy = getConfig('domainforproxy'); + if ($domainforproxy!='') { + $url = proxy_replace_domain($url, $domainforproxy); + } + return output('', 302, [ 'Location' => $url ]); + } else return output($thumb_url); } return output('', 404); } @@ -819,7 +935,7 @@ function bigfileupload($path) $getoldupinfo = json_decode($getoldupinfo_j['body'], true); if ( json_decode( curl_request($getoldupinfo['uploadUrl'])['body'], true)['@odata.context']!='' ) return output($getoldupinfo_j['body'], $getoldupinfo_j['stat']); } - if (!$_SERVER['admin']) $filename = spurlencode( $fileinfo['name'] ) . '.scfupload'; + //if (!$_SERVER['admin']) $filename = spurlencode( $fileinfo['name'] ) . '.scfupload'; $response=MSAPI('createUploadSession',path_format($path1 . '/' . $filename),'{"item": { "@microsoft.graph.conflictBehavior": "fail" }}',$_SERVER['access_token']); $responsearry = json_decode($response['body'],true); if (isset($responsearry['error'])) return output($response['body'], $response['stat']); @@ -987,6 +1103,7 @@ function adminoperate($path) $path1 = path_format($_SERVER['list_path'] . path_format($path)); if ($path1!='/'&&substr($path1,-1)=='/') $path1=substr($path1,0,-1); savecache('path_' . $path1 . '/?password', '', 1); + savecache('customTheme', '', 1); return message('', getconstStr('RefreshCache'), 302); } return $tmparr; @@ -1479,7 +1596,10 @@ function get_refresh_token() } } } - document.cookie=\'disktag=\'+t.disktag_add.value+\'; path=/\'; + var expd = new Date(); + expd.setTime(expd.getTime()+(2*60*60*1000)); + var expires = "expires="+expd.toGMTString(); + document.cookie=\'disktag=\'+t.disktag_add.value+\'; path=/; \'+expires; return true; } '; @@ -1528,11 +1648,10 @@ function EnvOpt($needUpdate = 0) }*/ $response = setConfigResponse( setConfig($tmp, $_SERVER['disk_oprating']) ); if (api_error($response)) { - $html = api_error_msg($response); - $title = 'Error'; - } else { + $html = api_error_msg($response); + $title = 'Error'; + } else { //WaitSCFStat(); - //sleep(3); $html .= getconstStr('Success') . '!
'; $title = getconstStr('Setup'); @@ -1567,10 +1686,11 @@ function EnvOpt($needUpdate = 0) } $html .= ' + '.getconstStr('EnvironmentsDescription')[$key].' '; } elseif ($key=='theme') { - $theme_arr = scandir('theme'); + $theme_arr = scandir(__DIR__.'/theme'); $html .= ' @@ -1583,6 +1703,7 @@ function EnvOpt($needUpdate = 0) } $html .= ' + '.getconstStr('EnvironmentsDescription')[$key].' '; } /*elseif ($key=='domain_path') { @@ -1614,8 +1735,8 @@ function EnvOpt($needUpdate = 0)
'.$disktag.': - - + +
'; @@ -1633,6 +1754,11 @@ function EnvOpt($needUpdate = 0) $html .= ' '; + } else { + $html .= ' + + Please add this disk again. + '; } $html .= '
'; @@ -1640,16 +1766,32 @@ function EnvOpt($needUpdate = 0) } $html .= ' '.getconstStr('AddDisk').'

'; - if (!((isset($_SERVER['USER'])&&$_SERVER['USER']==='qcloud')||(isset($_SERVER['HEROKU_APP_DIR'])&&$_SERVER['HEROKU_APP_DIR']==='/app'))) { + + $canOneKeyUpate = 0; + if (isset($_SERVER['USER'])&&$_SERVER['USER']==='qcloud') { + $canOneKeyUpate = 1; + } elseif (isset($_SERVER['HEROKU_APP_DIR'])&&$_SERVER['HEROKU_APP_DIR']==='/app') { + $canOneKeyUpate = 1; + } elseif (isset($_SERVER['FC_SERVER_PATH'])&&$_SERVER['FC_SERVER_PATH']==='/var/fc/runtime/php7.2') { + $canOneKeyUpate = 1; + } elseif ($_SERVER['_APP_SHARE_DIR']==='/var/share/CFF/processrouter') { + $canOneKeyUpate = 1; + } else { + $tmp = time(); + if ( mkdir(''.$tmp, 0777) ) { + rmdir(''.$tmp); + $canOneKeyUpate = 1; + } + } + if (!$canOneKeyUpate) { $html .= ' -'.getconstStr('VPSnotupdate').'
'; +'.getconstStr('CannotOneKeyUpate').'
'; } else { $html .= '
- - - - + + + @@ -1658,7 +1800,6 @@ function EnvOpt($needUpdate = 0) '; } $html = $authinfo . $html; diff --git a/conststr.php b/conststr.php index dec2067..43cf951 100644 --- a/conststr.php +++ b/conststr.php @@ -1,16 +1,16 @@ [ 'en-us' => 'English', - 'zh-cn' => '中文', + 'zh-cn' => '简体中文', 'ja' => '日本語', 'ko-kr' => '한국어', 'fa' => 'فارسی', @@ -68,14 +68,20 @@ $constStr = [ 'adminloginpage' => 'if set, the Login button will not display, and the login page no longer \'?admin\', it is \'?{this value}\'.', 'customScript' => ' + ', 'Program updating', 201); + } + return output('Jump + + ', 302); + } + if ($_GET['install1']) { + //if ($_POST['admin']!='') { + $tmp['timezone'] = $_COOKIE['timezone']; + $AccessKeyID = getConfig('AccessKeyID'); + if ($AccessKeyID=='') { + $AccessKeyID = $_POST['AccessKeyID']; + $tmp['AccessKeyID'] = $AccessKeyID; + } + $AccessKeySecret = getConfig('AccessKeySecret'); + if ($AccessKeySecret=='') { + $AccessKeySecret = $_POST['AccessKeySecret']; + $tmp['AccessKeySecret'] = $AccessKeySecret; + } + $response = json_decode(SetbaseConfig($tmp, $_SERVER['accountId'], $_SERVER['region'], $_SERVER['service_name'], $_SERVER['function_name'], $AccessKeyID, $AccessKeySecret), true); + if (api_error($response)) { + $html = api_error_msg($response); + $title = 'Error'; + return message($html, $title, 201); + } else { + $html .= ' + +
+ +
+ '; + $title = getconstStr('SetAdminPassword'); + return message($html, $title, 201); + } + //} + } + if ($_GET['install0']) { + $html .= ' +
+language:
'; + foreach ($constStr['languages'] as $key1 => $value1) { + $html .= ' +
'; + } + if (getConfig('AccessKeyID')==''||getConfig('AccessKeySecret')=='') $html .= ' + '.getconstStr('Create').' AccessKeyID & AccessKeySecret
+
+
'; + $html .= ' + +
+ '; + $title = getconstStr('SelectLanguage'); + return message($html, $title, 201); + } + $html .= ''.getconstStr('ClickInstall').', '.getconstStr('LogintoBind'); + $title = 'Error'; + return message($html, $title, 201); +} + +function getfunctioninfo($accountId, $region, $service_name, $function_name, $AccessKeyID, $AccessKeySecret) +{ + $fcClient = new Client([ + "endpoint" => 'https://'.$accountId.'.'.$region.'.fc.aliyuncs.com', + "accessKeyID" => $AccessKeyID, + "accessKeySecret" => $AccessKeySecret + ]); + return $fcClient->getFunction($service_name, $function_name); +} + +function updateEnvironment($Envs, $accountId, $region, $service_name, $function_name, $AccessKeyID, $AccessKeySecret) +{ + //print_r($Envs); + $fcClient = new Client([ + "endpoint" => 'https://'.$accountId.'.'.$region.'.fc.aliyuncs.com', + "accessKeyID" => $AccessKeyID, + "accessKeySecret" => $AccessKeySecret + ]); + $tmp = $fcClient->getFunction($service_name, $function_name)['data']; + //$tmp = getfunctioninfo($accountId, $region, $service_name, $function_name, $AccessKeyID, $AccessKeySecret)['data']; + foreach ($tmp['environmentVariables'] as $key => $value ) { + $tmp_env[$key] = $value; + } + foreach ($Envs as $key1 => $value1) { + $tmp_env[$key1] = $value1; + } + $tmp_env = array_filter($tmp_env, 'array_value_isnot_null'); // remove null. 清除空值 + ksort($tmp_env); + + $tmpdata['functionName'] = $tmp['functionName']; + $tmpdata['description'] = $tmp['description']; + $tmpdata['memorySize'] = $tmp['memorySize']; + $tmpdata['timeout'] = $tmp['timeout']; + $tmpdata['runtime'] = $tmp['runtime']; + $tmpdata['handler'] = $tmp['handler']; + $tmpdata['environmentVariables'] = $tmp_env; + $tmpdata['code']['zipFile'] = base64_encode( file_get_contents($fcClient->getFunctionCode($service_name, $function_name)['data']['url']) ); + return $fcClient->updateFunction($service_name, $function_name, $tmpdata); +} + +function SetbaseConfig($Envs, $accountId, $region, $service_name, $function_name, $AccessKeyID, $AccessKeySecret) +{ + //echo json_encode($Envs,JSON_PRETTY_PRINT); + $fcClient = new Client([ + "endpoint" => 'https://'.$accountId.'.'.$region.'.fc.aliyuncs.com', + "accessKeyID" => $AccessKeyID, + "accessKeySecret" => $AccessKeySecret + ]); + $tmp = $fcClient->getFunction($service_name, $function_name)['data']; + // $tmp = getfunctioninfo($accountId, $region, $service_name, $function_name, $AccessKeyID, $AccessKeySecret)['data']; + foreach ($tmp['environmentVariables'] as $key => $value ) { + $tmp_env[$key] = $value; + } + foreach ($Envs as $key1 => $value1) { + $tmp_env[$key1] = $value1; + } + $tmp_env = array_filter($tmp_env, 'array_value_isnot_null'); // remove null. 清除空值 + ksort($tmp_env); + + $tmpdata['functionName'] = $function_name; + $tmpdata['description'] = 'Onedrive index and manager in Ali FC.'; + $tmpdata['memorySize'] = 128; + $tmpdata['timeout'] = 30; + $tmpdata['runtime'] = 'php7.2'; + $tmpdata['handler'] = 'index.handler'; + $tmpdata['environmentVariables'] = $tmp_env; + $tmpdata['code']['zipFile'] = base64_encode( file_get_contents($fcClient->getFunctionCode($service_name, $function_name)['data']['url']) ); + return $fcClient->updateFunction($service_name, $function_name, $tmpdata); +} + +function updateProgram($accountId, $region, $service_name, $function_name, $AccessKeyID, $AccessKeySecret, $source) +{ + //WaitSCFStat(); + $fcClient = new Client([ + "endpoint" => 'https://'.$accountId.'.'.$region.'.fc.aliyuncs.com', + "accessKeyID" => $AccessKeyID, + "accessKeySecret" => $AccessKeySecret + ]); + $tmp = $fcClient->getFunction($service_name, $function_name)['data']; + //$tmp = getfunctioninfo($accountId, $region, $service_name, $function_name, $AccessKeyID, $AccessKeySecret)['data']; + + $tmpdata['functionName'] = $tmp['functionName']; + $tmpdata['description'] = $tmp['description']; + $tmpdata['memorySize'] = $tmp['memorySize']; + $tmpdata['timeout'] = $tmp['timeout']; + $tmpdata['runtime'] = $tmp['runtime']; + $tmpdata['handler'] = $tmp['handler']; + $tmpdata['environmentVariables'] = $tmp['environmentVariables']; + $tmpdata['code']['zipFile'] = base64_encode( file_get_contents($source) ); + + return $fcClient->updateFunction($service_name, $function_name, $tmpdata); +} + +function api_error($response) +{ + return !isset($response['data']); +} + +function api_error_msg($response) +{ + return $response; + return $response['Error']['Code'] . '
+' . $response['Error']['Message'] . '

+function_name:' . $_SERVER['function_name'] . '
+Region:' . $_SERVER['Region'] . '
+namespace:' . $_SERVER['namespace'] . '
+'; +} + +function setConfigResponse($response) +{ + return $response; +} + +function OnekeyUpate($auth = 'BingoKingo', $project = 'Tfo', $branch = 'master') +{ + $source = '/tmp/code.zip'; + $outPath = '/tmp/'; + + // 从github下载对应tar.gz,并解压 + $url = 'https://github.com/' . $auth . '/' . $project . '/tarball/' . urlencode($branch) . '/'; + $tarfile = '/tmp/github.tar.gz'; + file_put_contents($tarfile, file_get_contents($url)); + $phar = new PharData($tarfile); + $html = $phar->extractTo($outPath, null, true);//路径 要解压的文件 是否覆盖 + + // 获取解压出的目录名 +/* + @ob_start(); + passthru('ls /tmp | grep '.$auth.'-'.$project.'',$stat); + $html.='状态:' . $stat . ' + 结果: + '; + $archivefolder = ob_get_clean(); + if (substr($archivefolder,-1)==PHP_EOL) $archivefolder = substr($archivefolder, 0, -1); + $outPath .= $archivefolder; + $html.=htmlspecialchars($archivefolder); + //return $html; +*/ + $tmp = scandir($outPath); + $name = $auth.'-'.$project; + foreach ($tmp as $f) { + if ( substr($f, 0, strlen($name)) == $name) { + $outPath .= $f; + break; + } + } + + // 将目录中文件打包成zip + $zip=new ZipArchive(); + if($zip->open($source, ZipArchive::CREATE)){ + addFileToZip($zip, $outPath); //调用方法,对要打包的根目录进行操作,并将ZipArchive的对象传递给方法 + $zip->close(); //关闭处理的zip文件 + } + + return updateProgram($_SERVER['accountId'], $_SERVER['region'], $_SERVER['service_name'], $_SERVER['function_name'], getConfig('AccessKeyID'), getConfig('AccessKeySecret'), $source); +} + +function addFileToZip($zip, $rootpath, $path = '') +{ + if (substr($rootpath,-1)=='/') $rootpath = substr($rootpath, 0, -1); + if (substr($path,0,1)=='/') $path = substr($path, 1); + $handler=opendir(path_format($rootpath.'/'.$path)); //打开当前文件夹由$path指定。 + while($filename=readdir($handler)){ + if($filename != "." && $filename != ".."){//文件夹文件名字为'.'和‘..’,不要对他们进行操作 + $nowname = path_format($rootpath.'/'.$path."/".$filename); + if(is_dir($nowname)){// 如果读取的某个对象是文件夹,则递归 + addFileToZip($zip, $rootpath, $path."/".$filename); + }else{ //将文件加入zip对象 + $zip->addFile($nowname); + $newname = $path."/".$filename; + if (substr($newname,0,1)=='/') $newname = substr($newname, 1); + $zip->renameName($nowname, $newname); + } + } + } + @closedir($path); +} diff --git a/platform/HuaweiFG.php b/platform/HuaweiFG.php new file mode 100644 index 0000000..ea14f7c --- /dev/null +++ b/platform/HuaweiFG.php @@ -0,0 +1,743 @@ +geteventID(); + $tmp['RemainingTimeInMilliSeconds'] = $context->getRemainingTimeInMilliSeconds(); + $tmp['AccessKey'] = $context->getAccessKey(); + $tmp['SecretKey'] = $context->getSecretKey(); + $tmp['UserData']['HW_urn'] = $context->getUserData('HW_urn'); + $tmp['FunctionName'] = $context->getFunctionName(); + $tmp['RunningTimeInSeconds'] = $context->getRunningTimeInSeconds(); + $tmp['Version'] = $context->getVersion(); + $tmp['MemorySize'] = $context->getMemorySize(); + $tmp['CPUNumber'] = $context->getCPUNumber(); + $tmp['ProjectID'] = $context->getProjectID(); + $tmp['Package'] = $context->Package(); + $tmp['Token'] = $context->getToken(); + $tmp['Logger'] = $context->getLogger(); + + if (strlen(json_encode($event['body']))>500) $event['body']=substr($event['body'],0,strpos($event['body'],'base64')+30) . '...Too Long!...' . substr($event['body'],-50); + echo urldecode(json_encode($event, JSON_PRETTY_PRINT)) . ' + +' . urldecode(json_encode($tmp, JSON_PRETTY_PRINT)) . ' + +'; +} + +function GetGlobalVariable($event) +{ + $_GET = $event['queryStringParameters']; + $postbody = explode("&",$event['body']); + foreach ($postbody as $postvalues) { + $pos = strpos($postvalues,"="); + $_POST[urldecode(substr($postvalues,0,$pos))]=urldecode(substr($postvalues,$pos+1)); + } + $cookiebody = explode("; ",$event['headers']['cookie']); + foreach ($cookiebody as $cookievalues) { + $pos = strpos($cookievalues,"="); + $_COOKIE[urldecode(substr($cookievalues,0,$pos))]=urldecode(substr($cookievalues,$pos+1)); + } + $_SERVER['HTTP_USER_AGENT'] = $event['headers']['user-agent']; + $_SERVER['HTTP_TRANSLATE'] = $event['headers']['translate'];//'f' + $_SERVER['_APP_SHARE_DIR'] = '/var/share/CFF/processrouter'; +} + +function GetPathSetting($event, $context) +{ + $_SERVER['firstacceptlanguage'] = strtolower(splitfirst(splitfirst($event['headers']['accept-language'],';')[0],',')[0]); + $_SERVER['function_name'] = $context->getFunctionName(); + $_SERVER['ProjectID'] = $context->getProjectID(); + $host_name = $event['headers']['host']; + $_SERVER['HTTP_HOST'] = $host_name; + $path = path_format($event['pathParameters'][''].'/'); + $_SERVER['base_path'] = path_format($event['path'].'/'); + if ( $_SERVER['base_path'] == $path ) { + $_SERVER['base_path'] = '/'; + } else { + $_SERVER['base_path'] = substr($_SERVER['base_path'], 0, -strlen($path)); + if ($_SERVER['base_path']=='') $_SERVER['base_path'] = '/'; + } + if (substr($path,-1)=='/') $path=substr($path,0,-1); + $_SERVER['is_guestup_path'] = is_guestup_path($path); + $_SERVER['PHP_SELF'] = path_format($_SERVER['base_path'] . $path); + $_SERVER['REMOTE_ADDR'] = $event['headers']['x-real-ip']; + $_SERVER['HTTP_X_REQUESTED_WITH'] = $event['headers']['x-requested-with']; + return $path; +} + +function getConfig($str, $disktag = '') +{ + global $InnerEnv; + global $Base64Env; + global $contextUserData; + if (in_array($str, $InnerEnv)) { + if ($disktag=='') $disktag = $_SERVER['disktag']; + $env = json_decode($contextUserData->getUserData($disktag), true); + if (isset($env[$str])) { + if (in_array($str, $Base64Env)) return equal_replace($env[$str],1); + else return $env[$str]; + } + } else { + if (in_array($str, $Base64Env)) return equal_replace($contextUserData->getUserData($str),1); + else return $contextUserData->getUserData($str); + } + return ''; +} + +function setConfig($arr, $disktag = '') +{ + global $InnerEnv; + global $Base64Env; + global $contextUserData; + if ($disktag=='') $disktag = $_SERVER['disktag']; + $disktags = explode("|",getConfig('disktag')); + $diskconfig = json_decode($contextUserData->getUserData($disktag), true); + $tmp = []; + $indisk = 0; + $oparetdisk = 0; + foreach ($arr as $k => $v) { + if (in_array($k, $InnerEnv)) { + if (in_array($k, $Base64Env)) $diskconfig[$k] = equal_replace($v); + else $diskconfig[$k] = $v; + $indisk = 1; + } elseif ($k=='disktag_add') { + array_push($disktags, $v); + $oparetdisk = 1; + } elseif ($k=='disktag_del') { + $disktags = array_diff($disktags, [ $v ]); + $tmp[$v] = ''; + $oparetdisk = 1; + } else { + if (in_array($k, $Base64Env)) $tmp[$k] = equal_replace($v); + else $tmp[$k] = $v; + } + } + if ($indisk) { + $diskconfig = array_filter($diskconfig, 'array_value_isnot_null'); + ksort($diskconfig); + $tmp[$disktag] = json_encode($diskconfig); + } + if ($oparetdisk) { + $disktags = array_unique($disktags); + foreach ($disktags as $disktag) if ($disktag!='') $disktag_s .= $disktag . '|'; + if ($disktag_s!='') $tmp['disktag'] = substr($disktag_s, 0, -1); + else $tmp['disktag'] = ''; + } +// echo '正式设置:'.json_encode($tmp,JSON_PRETTY_PRINT).' +//'; + $response = updateEnvironment($tmp, getConfig('HW_urn'), getConfig('HW_key'), getConfig('HW_secret')); + // WaitSCFStat(); + return $response; +} + +function WaitSCFStat() +{ + $trynum = 0; + while( json_decode(getfunctioninfo($_SERVER['function_name'], $_SERVER['Region'], $_SERVER['namespace'], getConfig('SecretId'), getConfig('SecretKey')),true)['Response']['Status']!='Active' ) echo ' +'.++$trynum; +} + +function install() +{ + global $constStr; + if ($_GET['install2']) { + $tmp['admin'] = $_POST['admin']; + setConfig($tmp); + if (needUpdate()) { + OnekeyUpate(); + return message('update to github version, reinstall. + + ', 'Program updating', 201); + } + return output('Jump + + ', 302); + } + if ($_GET['install1']) { + //if ($_POST['admin']!='') { + $tmp['timezone'] = $_COOKIE['timezone']; + $tmp['HW_urn'] = getConfig('HW_urn'); + if ($tmp['HW_urn']=='') { + $tmp['HW_urn'] = $_POST['HW_urn']; + } + $tmp['HW_key'] = getConfig('HW_key'); + if ($tmp['HW_key']=='') { + $tmp['HW_key'] = $_POST['HW_key']; + } + $tmp['HW_secret'] = getConfig('HW_secret'); + if ($tmp['HW_secret']=='') { + $tmp['HW_secret'] = $_POST['HW_secret']; + } + //$response = json_decode(SetbaseConfig($tmp, $HW_urn, $HW_name, $HW_pwd), true)['Response']; + $response = setConfigResponse( SetbaseConfig($tmp, $tmp['HW_urn'], $tmp['HW_key'], $tmp['HW_secret']) ); + if (api_error($response)) { + $html = api_error_msg($response); + $title = 'Error'; + return message($html, $title, 201); + } else { + $html .= ' +
+
+ +
+ '; + $title = getconstStr('SetAdminPassword'); + return message($html, $title, 201); + } + //} + } + if ($_GET['install0']) { + $html .= ' +
+language:
'; + foreach ($constStr['languages'] as $key1 => $value1) { + $html .= ' +
'; + } + if (getConfig('HW_urn')==''||getConfig('HW_key')==''||getConfig('HW_secret')=='') $html .= ' + 在函数代码操作页上方找到URN,鼠标放上去后显示URN,复制填入:
+
+ 点击链接,新增访问密钥, + 在下载的credentials.csv文件中找到对应信息,填入:
+
+
'; + $html .= ' + +
+ '; + $title = getconstStr('SelectLanguage'); + return message($html, $title, 201); + } + $html .= ''.getconstStr('ClickInstall').', '.getconstStr('LogintoBind'); + $title = 'Error'; + return message($html, $title, 201); +} + +function getfunctioninfo($HW_urn, $HW_key, $HW_secret) +{ + $URN = explode(':', $HW_urn); + $Region = $URN[2]; + $project_id = $URN[3]; + $url = 'https://functiongraph.' . $Region . '.myhuaweicloud.com/v2/' . $project_id . '/fgs/functions/' . $HW_urn . '/config'; + $signer = new Signer(); + $signer->Key = $HW_key; + $signer->Secret = $HW_secret; + $req = new Request('GET', $url); + $req->headers = array( + 'content-type' => 'application/json;charset=utf8', + ); + $req->body = ''; + $curl = $signer->Sign($req); + $response = curl_exec($curl); + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + return $response; +} + + +function updateEnvironment($Envs, $HW_urn, $HW_key, $HW_secret) +{ + //echo json_encode($Envs,JSON_PRETTY_PRINT); + global $contextUserData; + $tmp_env = json_decode(json_decode(getfunctioninfo($HW_urn, $HW_key, $HW_secret),true)['user_data'],true); + foreach ($Envs as $key1 => $value1) { + $tmp_env[$key1] = $value1; + } + $tmp_env = array_filter($tmp_env, 'array_value_isnot_null'); // remove null. 清除空值 + ksort($tmp_env); + + $URN = explode(':', $HW_urn); + $Region = $URN[2]; + $project_id = $URN[3]; + $url = 'https://functiongraph.' . $Region . '.myhuaweicloud.com/v2/' . $project_id . '/fgs/functions/' . $HW_urn . '/config'; + $signer = new Signer(); + $signer->Key = $HW_key; + $signer->Secret = $HW_secret; + $req = new Request('PUT', $url); + $req->headers = array( + 'content-type' => 'application/json;charset=utf8', + ); + $tmpdata['handler'] = 'index.handler'; + $tmpdata['memory_size'] = $contextUserData->getMemorySize()+1-1; + $tmpdata['runtime'] = 'PHP7.3'; + $tmpdata['timeout'] = $contextUserData->getRunningTimeInSeconds()+1-1; + $tmpdata['user_data'] = json_encode($tmp_env); + $req->body = json_encode($tmpdata); + $curl = $signer->Sign($req); + $response = curl_exec($curl); + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + return $response; +} + +function SetbaseConfig($Envs, $HW_urn, $HW_key, $HW_secret) +{ + //echo json_encode($Envs,JSON_PRETTY_PRINT); + $tmp_env = json_decode(json_decode(getfunctioninfo($HW_urn, $HW_key, $HW_secret),true)['user_data'],true); + foreach ($Envs as $key1 => $value1) { + $tmp_env[$key1] = $value1; + } + $tmp_env = array_filter($tmp_env, 'array_value_isnot_null'); // remove null. 清除空值 + ksort($tmp_env); + + // https://functiongraph.cn-north-4.myhuaweicloud.com/v2/{project_id}/fgs/functions/{function_urn}/config + $URN = explode(':', $HW_urn); + $Region = $URN[2]; + $project_id = $URN[3]; + $url = 'https://functiongraph.' . $Region . '.myhuaweicloud.com/v2/' . $project_id . '/fgs/functions/' . $HW_urn . '/config'; + $signer = new Signer(); + $signer->Key = $HW_key; + $signer->Secret = $HW_secret; + $req = new Request('PUT', $url); + $req->headers = array( + 'content-type' => 'application/json;charset=utf8', + ); + $tmpdata['handler'] = 'index.handler'; + $tmpdata['memory_size'] = 128; + $tmpdata['runtime'] = 'PHP7.3'; + $tmpdata['timeout'] = 30; + $tmpdata['user_data'] = json_encode($tmp_env); + $req->body = json_encode($tmpdata); + $curl = $signer->Sign($req); + $response = curl_exec($curl); + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + return $response; +} + +function updateProgram($HW_urn, $HW_key, $HW_secret, $source) +{ + $URN = explode(':', $HW_urn); + $Region = $URN[2]; + $project_id = $URN[3]; + $url = 'https://functiongraph.' . $Region . '.myhuaweicloud.com/v2/' . $project_id . '/fgs/functions/' . $HW_urn . '/code'; + $signer = new Signer(); + $signer->Key = $HW_key; + $signer->Secret = $HW_secret; + $req = new Request('PUT', $url); + $req->headers = array( + 'content-type' => 'application/json;charset=utf8', + ); + $tmpdata['code_type'] = 'zip'; + $tmpdata['func_code']['file'] = base64_encode( file_get_contents($source) ); + $req->body = json_encode($tmpdata); + $curl = $signer->Sign($req); + $response = curl_exec($curl); + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + return $response; +} + +function api_error($response) +{ + return isset($response['error_code']); +} + +function api_error_msg($response) +{ + return $response['error_code'] . '
+' . $response['error_msg'] . '
+request_id: ' . $response['request_id'] . '

+function_name: ' . $_SERVER['function_name'] . '
+'; +} + +function setConfigResponse($response) +{ + return json_decode( $response, true ); +} + +function OnekeyUpate($auth = 'BingoKingo', $project = 'Tfo', $branch = 'master') +{ + $source = '/tmp/code.zip'; + $outPath = '/tmp/'; + + // 从github下载对应tar.gz,并解压 + $url = 'https://github.com/' . $auth . '/' . $project . '/tarball/' . urlencode($branch) . '/'; + $tarfile = '/tmp/github.tar.gz'; + file_put_contents($tarfile, file_get_contents($url)); + $phar = new PharData($tarfile); + $html = $phar->extractTo($outPath, null, true);//路径 要解压的文件 是否覆盖 + + // 获取解压出的目录名 +/* + @ob_start(); + passthru('ls /tmp | grep '.$auth.'-'.$project.'',$stat); + $html.='状态:' . $stat . ' + 结果: + '; + $archivefolder = ob_get_clean(); + if (substr($archivefolder,-1)==PHP_EOL) $archivefolder = substr($archivefolder, 0, -1); + $outPath .= $archivefolder; + $html.=htmlspecialchars($archivefolder); + //return $html; +*/ + $tmp = scandir($outPath); + $name = $auth.'-'.$project; + foreach ($tmp as $f) { + if ( substr($f, 0, strlen($name)) == $name) { + $outPath .= $f; + break; + } + } + + // 将目录中文件打包成zip + //$zip=new ZipArchive(); + $zip=new PharData($source); + //if($zip->open($source, ZipArchive::CREATE)){ + addFileToZip($zip, $outPath); //调用方法,对要打包的根目录进行操作,并将ZipArchive的对象传递给方法 + // $zip->close(); //关闭处理的zip文件 + //} + + return updateProgram(getConfig('HW_urn'), getConfig('HW_key'), getConfig('HW_secret'), $source); +} + +function addFileToZip($zip, $rootpath, $path = '') +{ + if (substr($rootpath,-1)=='/') $rootpath = substr($rootpath, 0, -1); + if (substr($path,0,1)=='/') $path = substr($path, 1); + $handler=opendir(path_format($rootpath.'/'.$path)); //打开当前文件夹由$path指定。 + while($filename=readdir($handler)){ + if($filename != "." && $filename != ".."){//文件夹文件名字为'.'和‘..’,不要对他们进行操作 + $nowname = path_format($rootpath.'/'.$path."/".$filename); + if(is_dir($nowname)){// 如果读取的某个对象是文件夹,则递归 + $zip->addEmptyDir($path."/".$filename); + addFileToZip($zip, $rootpath, $path."/".$filename); + }else{ //将文件加入zip对象 + $newname = $path."/".$filename; + if (substr($newname,0,1)=='/') $newname = substr($newname, 1); + $zip->addFile($nowname, $newname); + //$zip->renameName($nowname, $newname); + } + } + } + @closedir($path); +} + + + + + + + + +define("BasicDateFormat", "Ymd\THis\Z"); +define("Algorithm", "SDK-HMAC-SHA256"); +define("HeaderXDate", "X-Sdk-Date"); +define("HeaderHost", "host"); +define("HeaderAuthorization", "Authorization"); +define("HeaderContentSha256", "X-Sdk-Content-Sha256"); + +class Request +{ + public $method = ''; + public $scheme = ''; + public $host = ''; + public $uri = ''; + public $query = array(); + public $headers = array(); + public $body = ''; + + function __construct() + { + $args = func_get_args(); + $i = count($args); + if ($i == 0) { + $this->construct(NULL, NULL, NULL, NULL); + } elseif ($i == 1) { + $this->construct($args[0], NULL, NULL, NULL); + } elseif ($i == 2) { + $this->construct($args[0], $args[1], NULL, NULL); + } elseif ($i == 3) { + $this->construct($args[0], $args[1], $args[2], NULL); + } else { + $this->construct($args[0], $args[1], $args[2], $args[3]); + } + } + + function construct($method, $url, $headers, $body) + { + if ($method != NULL) { + $this->method = $method; + } + if ($url != NULL) { + $spl = explode("://", $url, 2); + $scheme = 'http'; + if (count($spl) > 1) { + $scheme = $spl[0]; + $url = $spl[1]; + } + $spl = explode("?", $url, 2); + $url = $spl[0]; + $query = array(); + if (count($spl) > 1) { + foreach (explode("&", $spl[1]) as $kv) { + $spl = explode("=", $kv, 2); + $key = $spl[0]; + if (count($spl) == 1) { + $value = ""; + } else { + $value = $spl[1]; + } + if ($key != "") { + $key = urldecode($key); + $value = urldecode($value); + if (array_key_exists($key, $query)) { + array_push($query[$key], $value); + } else { + $query[$key] = array($value); + } + } + } + } + $spl = explode("/", $url, 2); + $host = $spl[0]; + if (count($spl) == 1) { + $url = "/"; + } else { + $url = "/" . $spl[1]; + } + $this->scheme = $scheme; + $this->host = $host; + $this->uri = urldecode($url); + $this->query = $query; + } + if ($headers != NULL) { + $this->headers = $headers; + } + if ($body != NULL) { + $this->body = $body; + } + } +} + +class Signer +{ + public $Key = ''; + public $Secret = ''; + + function escape($string) + { + $entities = array('+', "%7E"); + $replacements = array('%20', "~"); + return str_replace($entities, $replacements, urlencode($string)); + } + + function findHeader($r, $header) + { + foreach ($r->headers as $key => $value) { + if (!strcasecmp($key, $header)) { + return $value; + } + } + return NULL; + } + +// Build a CanonicalRequest from a regular request string +// +// CanonicalRequest = +// HTTPRequestMethod + '\n' + +// CanonicalURI + '\n' + +// CanonicalQueryString + '\n' + +// CanonicalHeaders + '\n' + +// SignedHeaders + '\n' + +// HexEncode(Hash(RequestPayload)) + function CanonicalRequest($r, $signedHeaders) + { + $CanonicalURI = $this->CanonicalURI($r); + $CanonicalQueryString = $this->CanonicalQueryString($r); + $canonicalHeaders = $this->CanonicalHeaders($r, $signedHeaders); + $signedHeadersString = join(";", $signedHeaders); + $hash = $this->findHeader($r, HeaderContentSha256); + if (!$hash) { + $hash = hash("sha256", $r->body); + } + return "$r->method\n$CanonicalURI\n$CanonicalQueryString\n$canonicalHeaders\n$signedHeadersString\n$hash"; + } + +// CanonicalURI returns request uri + function CanonicalURI($r) + { + $pattens = explode("/", $r->uri); + $uri = array(); + foreach ($pattens as $v) { + array_push($uri, $this->escape($v)); + } + $urlpath = join("/", $uri); + if (substr($urlpath, -1) != "/") { + $urlpath = $urlpath . "/"; + } + return $urlpath; + } + +// CanonicalQueryString + function CanonicalQueryString($r) + { + $keys = array(); + foreach ($r->query as $key => $value) { + array_push($keys, $key); + } + sort($keys); + $a = array(); + foreach ($keys as $key) { + $k = $this->escape($key); + $value = $r->query[$key]; + if (is_array($value)) { + sort($value); + foreach ($value as $v) { + $kv = "$k=" . $this->escape($v); + array_push($a, $kv); + } + } else { + $kv = "$k=" . $this->escape($value); + array_push($a, $kv); + } + } + return join("&", $a); + } + +// CanonicalHeaders + function CanonicalHeaders($r, $signedHeaders) + { + $headers = array(); + foreach ($r->headers as $key => $value) { + $headers[strtolower($key)] = trim($value); + } + $a = array(); + foreach ($signedHeaders as $key) { + array_push($a, $key . ':' . $headers[$key]); + } + return join("\n", $a) . "\n"; + } + + function curlHeaders($r) + { + $header = array(); + foreach ($r->headers as $key => $value) { + array_push($header, strtolower($key) . ':' . trim($value)); + } + return $header; + } + +// SignedHeaders + function SignedHeaders($r) + { + $a = array(); + foreach ($r->headers as $key => $value) { + array_push($a, strtolower($key)); + } + sort($a); + return $a; + } + +// Create a "String to Sign". + function StringToSign($canonicalRequest, $t) + { + date_default_timezone_set('UTC'); + $date = date(BasicDateFormat, $t); + $hash = hash("sha256", $canonicalRequest); + return "SDK-HMAC-SHA256\n$date\n$hash"; + } + +// Create the HWS Signature. + function SignStringToSign($stringToSign, $signingKey) + { + return hash_hmac("sha256", $stringToSign, $signingKey); + } + +// Get the finalized value for the "Authorization" header. The signature parameter is the output from SignStringToSign + function AuthHeaderValue($signature, $accessKey, $signedHeaders) + { + $signedHeadersString = join(";", $signedHeaders); + return "SDK-HMAC-SHA256 Access=$accessKey, SignedHeaders=$signedHeadersString, Signature=$signature"; + } + + public function Sign($r) + { + date_default_timezone_set('UTC'); + $date = $this->findHeader($r, HeaderXDate); + if ($date) { + $t = date_timestamp_get(date_create_from_format(BasicDateFormat, $date)); + } + if (!@$t) { + $t = time(); + $r->headers[HeaderXDate] = date(BasicDateFormat, $t); + } + $queryString = $this->CanonicalQueryString($r); + if ($queryString != "") { + $queryString = "?" . $queryString; + } + $signedHeaders = $this->SignedHeaders($r); + $canonicalRequest = $this->CanonicalRequest($r, $signedHeaders); + $stringToSign = $this->StringToSign($canonicalRequest, $t); + $signature = $this->SignStringToSign($stringToSign, $this->Secret); + $authValue = $this->AuthHeaderValue($signature, $this->Key, $signedHeaders); + $r->headers[HeaderAuthorization] = $authValue; + + $curl = curl_init(); + $uri = str_replace(array("%2F"), array("/"), rawurlencode($r->uri)); + $url = $r->scheme . '://' . $r->host . $uri . $queryString; + $headers = $this->curlHeaders($r); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $r->method); + curl_setopt($curl, CURLOPT_POSTFIELDS, $r->body); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($curl, CURLOPT_NOBODY, FALSE); + return $curl; + } +} diff --git a/platform/scf.php b/platform/TencentSCF.php similarity index 94% rename from platform/scf.php rename to platform/TencentSCF.php index 2e12733..cbeb8da 100644 --- a/platform/scf.php +++ b/platform/TencentSCF.php @@ -23,6 +23,8 @@ function GetGlobalVariable($event) $pos = strpos($cookievalues,"="); $_COOKIE[urldecode(substr($cookievalues,0,$pos))]=urldecode(substr($cookievalues,$pos+1)); } + $_SERVER['HTTP_USER_AGENT'] = $event['headers']['user-agent']; + $_SERVER['HTTP_TRANSLATE']==$event['headers']['translate'];//'f' $_SERVER['USER'] = 'qcloud'; } @@ -133,9 +135,23 @@ function install() setConfig($tmp); if (needUpdate()) { OnekeyUpate(); - return message('update to github version, reinstall.', 'Program updating', 201); + return message('update to github version, reinstall. + + ', 'Program updating', 201); } - return output('Jump', 302); + return output('Jump + + ', 302); } if ($_GET['install1']) { //if ($_POST['admin']!='') { @@ -217,7 +233,10 @@ language:
'; document.cookie="timezone="+timezone+"; path=/; "+expires; function changelanguage(str) { - document.cookie=\'language=\'+str+\'; path=/\'; + var expd = new Date(); + expd.setTime(expd.getTime()+(2*60*60*1000)); + var expires = "expires="+expd.toGMTString(); + document.cookie=\'language=\'+str+\'; path=/; \'+expires; location.href = location.href; } function notnull(t) diff --git a/platform/heroku.php b/platform/heroku.php index 15373fe..abfeb15 100644 --- a/platform/heroku.php +++ b/platform/heroku.php @@ -126,7 +126,14 @@ function install() $html = api_error_msg($response); $title = 'Error'; } else { - return output('Jump', 302); + return output('Jump + + ', 302); } return message($html, $title, 201); } @@ -156,7 +163,10 @@ language:
'; document.cookie="timezone="+timezone+"; path=/; "+expires; function changelanguage(str) { - document.cookie=\'language=\'+str+\'; path=/\'; + var expd = new Date(); + expd.setTime(expd.getTime()+(2*60*60*1000)); + var expires = "expires="+expd.toGMTString(); + document.cookie=\'language=\'+str+\'; path=/; \'+expires; location.href = location.href; } function notnull(t) @@ -251,8 +261,8 @@ function OnekeyUpate($auth = 'BingoKingo', $project = 'Tfo', $branch = 'master') { //'original:https://github.com/qkqpttgf/OneManager-php/tarball/master/'; //'mine:https://https://github.com/BingoKingo/Tfo/tarball/master/'; - $source = 'https://github.com/' . $auth . '/' . $project . '/tarball/' . $branch . '/'; - return json_decode(updateHerokuapp(getConfig('function_name'), getConfig('APIKey'), $source)['body'], true); + $source = 'https://github.com/' . $auth . '/' . $project . '/tarball/' . urlencode($branch) . '/'; + return json_decode(updateHerokuapp(getConfig('function_name'), getConfig('APIKey'), $source)['body'], true); } function setConfigResponse($response) diff --git a/platform/normal.php b/platform/normal.php index 91a7251..85bc1eb 100644 --- a/platform/normal.php +++ b/platform/normal.php @@ -128,7 +128,14 @@ function install() $title = 'Error'; return message($html, $title, 201); } else { - return output('Jump', 302); + return output('Jump + + ', 302); } } } @@ -206,7 +213,10 @@ language:
'; '; @@ -252,12 +262,70 @@ Can not write config to file.
'; } -function OnekeyUpate() -{ - return json_decode(updateHerokuapp(getConfig('function_name'), getConfig('APIKey'))['body'], true); -} - function setConfigResponse($response) { return $response; } + +function OnekeyUpate($auth = 'qkqpttgf', $project = 'OneManager-php', $branch = 'master') +{ + // __DIR__ is xxx/platform + $projectPath = splitlast(__DIR__, '/')[0]; + + // 从github下载对应tar.gz,并解压 + $url = 'https://github.com/' . $auth . '/' . $project . '/tarball/' . urlencode($branch) . '/'; + $tarfile = $projectPath.'/github.tar.gz'; + $githubfile = file_get_contents($url); + if (!$githubfile) return 0; + file_put_contents($tarfile, $githubfile); + if (splitfirst(PHP_VERSION, '.')[0] == '7') { + $phar = new PharData($tarfile); // need php7 + $phar->extractTo($projectPath, null, true);//路径 要解压的文件 是否覆盖 + } else { + ob_start(); + passthru('tar -xzvf '.$tarfile,$stat); + ob_get_clean(); + } + unlink($tarfile); + + $outPath = ''; + $tmp = scandir($projectPath); + $name = $auth.'-'.$project; + foreach ($tmp as $f) { + if ( substr($f, 0, strlen($name)) == $name) { + $outPath = $projectPath . '/' . $f; + break; + } + } + //error_log($outPath); + if ($outPath=='') return 0; + + //unlink($outPath.'/config.php'); + rename($projectPath.'/config.php', $outPath.'/config.php'); + + return moveFolder($outPath, $projectPath); +} + +function moveFolder($from, $to) +{ + if (substr($from, -1)=='/') $from = substr($from, 0, -1); + if (substr($to, -1)=='/') $to = substr($to, 0, -1); + if (!file_exists($to)) mkdir($to, 0777); + $handler=opendir($from); + while($filename=readdir($handler)) { + if($filename != '.' && $filename != '..'){ + $fromfile = $from.'/'.$filename; + $tofile = $to.'/'.$filename; + if(is_dir($fromfile)){// 如果读取的某个对象是文件夹,则递归 + moveFolder($fromfile, $tofile); + }else{ + //if (file_exists($tofile)) unlink($tofile); + rename($fromfile, $tofile); + if (file_exists($fromfile)) unlink($fromfile); + } + } + } + closedir($handler); + rmdir($from); + return 1; +} diff --git a/readme.md b/readme.md index d068f61..bc56962 100644 --- a/readme.md +++ b/readme.md @@ -1,12 +1,12 @@ # **Tfo** -###### A website for two-point filestorage online (tfo). +###### A website for two-point filestorage online (tfo)(20200713). Tfo's Logo ## List of feature files 特色文件表 Information [app.json](/app.json "app.json"),[version](/version "version"),[readme.md](/readme.md "readme.md"),[conststr.php](/conststr.php "conststr.php") -UpdateAddress [heroku.php](/platform/heroku.php "heroku.php"),[scf.php](/platform/scf.php "scf.php") +UpdateAddress [Heroku.php](/platform/Heroku.php "Heroku.php"),[TencentSCF.php](/platform/TencentSCF.php "TencentSCF.php"),[HuaweiFG.php](/platform/HuaweiFG.php "HuaweiFG.php"),[AliyunFC.php](/platform/AliyunFC.php "AliyunFC.php") Theme @@ -38,12 +38,23 @@ How to Install: ### Deploy to SCF 部署到腾讯云函数 Official: https://cloud.tencent.com/product/scf - +添加网盘时,SCF反应不过来,会添加失败,请不要删除,再添加一次相同的就可以了。 ~~How to Install: https://service-pgxgvop2-1258064400.ap-hongkong.apigateway.myqcloud.com/test/abcdef/%E6%97%A0%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%87%BD%E6%95%B0SCF%E6%90%AD%E5%BB%BAOneDrive.mp4?preview~~ 先手动在环境变量添加Region,ap-hongkong或ap-guangzhou之类,具体看 https://cloud.tencent.com/document/api/583/17238 最底下,然后再安装。 添加网盘时,SCF反应不过来,会添加失败,请不要删除,再添加一次相同的就可以了。 + +### Deploy to Aliyun Function Compute (FC 阿里函数计算) +Official: https://fc.console.aliyun.com/ +How to Install: +* 1,新建函数 -- HTTP函数 +* 2,运行环境选择php7.2 +* 3,触发器认证方式选择anonymous,请求方式里面,点一下GET,再点一下POST,最终框框里面有这2个 +* 4,上传代码 +* 5,触发器中点进去,找到配置自定义域名,点击前往,创建,路径中填 /* ,其它下拉选择。 +* 6,访问你的域名,开始安装 + ## Original Features 原始特性 When downloading files, the program produce a direct url, visitor download files from MS OFFICE via the direct url, the server expend a few bandwidth in produce. 下载时,由程序解析出直链,浏览器直接从微软Onedrive服务器下载文件,服务器只消耗与微软通信的少量流量。 diff --git a/theme/classic.html b/theme/classic.html index 066d8d4..8ce43ad 100644 --- a/theme/classic.html +++ b/theme/classic.html @@ -21,8 +21,8 @@ - - + + + + + + +
+
+   +
+ +
+ +

+ +

+
+
+
+
+
+ + + > + + + + + + + + + + +
+
+
+
+ + + + +
+
+
+
+ +
+
+
+
+ + + + +
+
+
+ +
+
+
+ + + +
+
+
+ +
+ +
+ +
+
+
+ + +
+
+
+ + + +
+
+ +
+
+ + +
+
+ +
+
+
+ + + + + +
+
+ +   +
+
+ + <!--FileName--> + + +
+ + + + + +
+ + + + + +
+ +
+ +     + + + + +
+ +
+ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +     + + +   + +
+ + + + + + +
+ + + + + + +
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + +
+
+ + + + + + + +
+
+ +
+
+ + +
+
+ +
+
+
+ + + + + +
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ + +
+
+
+
+
+ +
+
+
+
+
+ + + + + +
+
+
+ +
+ + + + + + + + +
+
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ + + +
+ +
+ + +
+ + + + + +

OneManager By 逸笙 Theme By Nchyn

+

+ + + + + + + + + + + + + + + + diff --git a/theme/nexmoe1.html b/theme/nexmoe1.html new file mode 100644 index 0000000..56998de --- /dev/null +++ b/theme/nexmoe1.html @@ -0,0 +1,377 @@ + +{ + "music":"audiotrack", + "video":"ondemand_video", + "img":"image", + "default":"insert_drive_file" +} + + + + + + + <!--Title--> + + + + + + + + +
+
+
+ + + chevron_right +
+ +
+ +
  • >
  • + +
    +
    + + + chevron_right + + +
    +
    + + +
    + +
    + +
    +
    + https + + +
    +
    + +
    +
    + + + +
    +
    + +
    +--> + + +
    + +
    + + +
    + +
    + + + +
    + +
    + + +
    +
    +
    + + +
    + +
    + + +
    + +
    + + + + +
    +
    +
    + + + +
    + + file_download + + + +
    + +
    + +
    +
    + +
    + +
    + + +
    + +
    + +
    + + format_list_bulleted + + + + + + + + diff --git a/theme/nexmoe2.html b/theme/nexmoe2.html new file mode 100644 index 0000000..3ed1f54 --- /dev/null +++ b/theme/nexmoe2.html @@ -0,0 +1,580 @@ + +{ + "music":"audiotrack", + "video":"ondemand_video", + "img":"image", + "default":"insert_drive_file" +} + + + + + + + <!--Title--> + + + + + + + + + + + + +
    +
    + menu + + + chevron_right + + +
    + + format_list_bulleted + +
    +
    + +
    +
    + +
    +
    +
    +
    OneManager
    +
    +
    +
    + +
    + + + + +
    + +
    +
    + https + + +
    +
    + +
    +
    + + + +
    + + + +--> + + + +
    + +
    + +
    + + +
    +
    +
    + + +
    + +
    + + +
    + +
    + + + + +
    +
    +
    + + + +
    + +
    +file_download + + + + +
    +
    +
    + +
    + +
    + + +
    + +
    + + + +
    +
    + +
    +
    + +
    + +
    + + +
    + +
    + +
    +
    + + + + + + + + + diff --git a/theme/onemoe.html b/theme/onemoe.html index 75c9a9f..431b2cc 100644 --- a/theme/onemoe.html +++ b/theme/onemoe.html @@ -21,29 +21,13 @@ - - - + + + - + - + @@ -125,7 +109,7 @@ -

    +

    /

    @@ -196,6 +180,7 @@     +   @@ -220,7 +205,7 @@ - + @@ -449,11 +434,14 @@ function changelanguage(str) { if (str=='Language') str = ''; - document.cookie='language='+str+'; path=/'; + var expd = new Date(); + expd.setTime(expd.getTime()+(2*60*60*1000)); + var expires = "expires="+expd.toGMTString(); + document.cookie='language='+str+'; path=/; '+expires; location.href = location.href; } - var root = ''; + /*var root = ''; function path_format(path) { path = '/' + path + '/'; while (path.indexOf('//') !== -1) { @@ -473,7 +461,7 @@ } e.innerHTML += paths[paths.length - 1]; e.innerHTML = e.innerHTML.replace(/\s\/\s$/, '') - }); + });*/ var $url = document.getElementById('url'); if ($url) { @@ -606,29 +594,37 @@ function showthumbnails(obj) { + images = []; var files=document.getElementsByName('filelist'); for ($i=0;$i]; - if (images.indexOf(ext)>-1) get_thumbnails_url(str, files[$i]); + if (images.indexOf(ext)>-1) { + if (document.getElementById('originalpic').checked==true) { + var url=files[$i].href; + url=url.substr(0,url.length-8); + files[$i].parentNode.parentNode.innerHTML=''+str+''; + $i--; + } else { + var nurl=window.location.href; + if (nurl.substr(-1)!="/") nurl+="/"; + var url=nurl+str+'?thumbnails'; + get_thumbnails_url(url, str, files[$i]); + } + } } obj.disabled='disabled'; } - function get_thumbnails_url(str, filea) { - if (!str) return; - var nurl=window.location.href; - if (nurl.substr(-1)!="/") nurl+="/"; + function get_thumbnails_url(url, name, filea) { var xhr = new XMLHttpRequest(); - xhr.open("GET", nurl+str+'?thumbnails', true); - //xhr.setRequestHeader('x-requested-with','XMLHttpRequest'); + xhr.open("GET", url, true); xhr.send(''); xhr.onload = function(e){ if (xhr.status==200) { - if (xhr.responseText!='') filea.innerHTML=''+str+''; + if (xhr.responseText!='') filea.innerHTML=''+name+''; } else console.log(xhr.status+'\n'+xhr.responseText); } } @@ -786,20 +782,55 @@ tr1.setAttribute('data-to',1); var td1=document.createElement('td'); tr1.appendChild(td1); - td1.setAttribute('style','width:30%'); + td1.setAttribute('style','width:30%;word-break:break-word;'); td1.setAttribute('id','upfile_td1_'+timea+'_'+i); td1.innerHTML=(file.webkitRelativePath||file.name)+'
    '+size_format(file.size); var td2=document.createElement('td'); tr1.appendChild(td2); td2.setAttribute('id','upfile_td2_'+timea+'_'+i); - td2.innerHTML=' ...'; if (file.size>100*1024*1024*1024) { td2.innerHTML=''; uploadbuttonshow(); return; } + upbigfilename = encodeURIComponent((file.webkitRelativePath||file.name)); + + function getext(str) { + strarry=str.split('.'); + ext=strarry[strarry.length-1].toLowerCase(); + var reg = new RegExp(".","g"); + var a = str.replace(reg,""); + if (a == ext) ext = ""; + else ext = "." + ext; + return ext; + } + var ext = getext(file.webkitRelativePath||file.name); + var spark = new SparkMD5.ArrayBuffer(); + var reader = new FileReader(); + var chunksize=10*1024*1024; + var asize = 0; + function readblob(start) { + var end=start+chunksize; + var blob = file.slice(start,end); + reader.readAsArrayBuffer(blob); + } + readblob(asize); + + reader.onload = function(e){ + td2.innerHTML=' md5: '+(asize*100/file.size).toFixed(2)+'%'; + var binary = this.result; + spark.append(binary); + asize += chunksize; + if (asize < file.size) { + readblob(asize); + } else { + var filemd5 = spark.end(); + td2.innerHTML='md5: '+filemd5; + upbigfilename = filemd5+ext; + + td2.innerHTML=' ...'; var xhr1 = new XMLHttpRequest(); - xhr1.open("GET", '?action=upbigfile&upbigfilename='+ encodeURIComponent((file.webkitRelativePath||file.name)) +'&filesize='+ file.size +'&lastModified='+ file.lastModified); + xhr1.open("GET", '?action=upbigfile&upbigfilename='+ upbigfilename +'&filesize='+ file.size +'&lastModified='+ file.lastModified); xhr1.setRequestHeader('x-requested-with','XMLHttpRequest'); xhr1.send(null); xhr1.onload = function(e){ @@ -812,14 +843,23 @@ uploadbuttonshow(); } else { td2.innerHTML=' ...'; - binupfile(file,html['uploadUrl'],timea+'_'+i); + binupfile(file,html['uploadUrl'],timea+'_'+i, upbigfilename); } } + if (xhr1.status==409) { + td2.innerHTML='md5: '+filemd5; + tdnum = timea+'_'+i; + document.getElementById('upfile_td1_'+tdnum).innerHTML='
    '+document.getElementById('upfile_td1_'+tdnum).innerHTML+'
    '; + } if (i + } + } + } } function size_format(num) { @@ -840,7 +880,7 @@ } return num.toFixed(2) + ' GB'; } - function binupfile(file,url,tdnum){ + function binupfile(file,url,tdnum,filename){ var label=document.getElementById('upfile_td2_'+tdnum); var reader = new FileReader(); var StartStr=''; @@ -861,9 +901,7 @@ var a = html['nextExpectedRanges'][0]; newstartsize = Number( a.slice(0,a.indexOf("-")) ); StartTime = new Date(); - asize = newstartsize; - if (newstartsize==0) { StartStr=':' +StartTime.toLocaleString()+'
    ' ; } else { @@ -877,19 +915,9 @@ reader.readAsArrayBuffer(blob); } readblob(asize); - - var spark = new SparkMD5.ArrayBuffer(); - + reader.onload = function(e){ var binary = this.result; - - spark.append(binary); - if (asize < newstartsize) { - asize += chunksize; - readblob(asize); - return; - } - var xhr = new XMLHttpRequest(); xhr.open("PUT", url, true); //xhr.setRequestHeader('x-requested-with','XMLHttpRequest'); @@ -910,38 +938,12 @@ if (response['size']>0) { // contain size, upload finish. 有size说明是最终返回,上传结束 var xhr3 = new XMLHttpRequest(); - xhr3.open("GET", '?action=del_upload_cache&filelastModified='+file.lastModified+'&filesize='+file.size+'&filename='+encodeURIComponent((file.webkitRelativePath||file.name))); + xhr3.open("GET", '?action=del_upload_cache&filelastModified='+file.lastModified+'&filesize='+file.size+'&filename='+filename); xhr3.setRequestHeader('x-requested-with','XMLHttpRequest'); xhr3.send(null); xhr3.onload = function(e){ console.log(xhr3.responseText+','+xhr3.status); } - - var filemd5 = spark.end(); - var xhr4 = new XMLHttpRequest(); - xhr4.open("GET", '?action=uploaded_rename&filename='+encodeURIComponent((file.webkitRelativePath||file.name))+'&filemd5='+filemd5); - xhr4.setRequestHeader('x-requested-with','XMLHttpRequest'); - xhr4.send(null); - xhr4.onload = function(e){ - console.log(xhr4.responseText+','+xhr4.status); - var filename; - //if (xhr4.status==200) filename = JSON.parse(xhr4.responseText)['name']; - //if (xhr4.status==409) filename = filemd5 + (file.webkitRelativePath||file.name).substr((file.webkitRelativePath||file.name).indexOf('.')); - filename = JSON.parse(xhr4.responseText)['name']; - if (filename=='') { - alert(''); - uploadbuttonshow(); - return; - } - var lasturl = location.href; - if (lasturl.substr(lasturl.length-1)!='/') lasturl += '/'; - lasturl += filename + '?preview'; - //window.open(lasturl); - document.getElementById('upfile_a_'+tdnum).href = lasturl; - document.getElementById('upfile_a1_'+tdnum).href = filename; - document.getElementById('upfile_cpbt_'+tdnum).style.display = ""; - } - EndTime=new Date(); MiddleStr = ':'+EndTime.toLocaleString()+'
    '; if (newstartsize==0) { @@ -969,7 +971,7 @@ xhr.send(binary); } } else { - if (window.location.pathname.indexOf('%23')>0||(file.webkitRelativePath||file.name).indexOf('%23')>0) { + if (window.location.pathname.indexOf('%23')>0||filename.indexOf('%23')>0) { label.innerHTML=''; } else { label.innerHTML=''+xhr2.responseText+''; diff --git a/theme/renexmoe.html b/theme/renexmoe.html new file mode 100644 index 0000000..94e880e --- /dev/null +++ b/theme/renexmoe.html @@ -0,0 +1,606 @@ + +{ + "music":"audiotrack", + "video":"ondemand_video", + "img":"image", + "default":"insert_drive_file" +} + + + + + + + + <!--Title--> + + + + + + + + + + + + + +
    +
    + menu + + + chevron_right + + +
    + + format_list_bulleted + +
    +
    + + + + + + +
    + +
    +
    + https + + +
    +
    + +
    +
    + + + +
    + + + +--> + + + +
    + +
    + +
    + + +
    +
    +
    + + +
    + +
    + + +
    + +
    + + + + +
    +
    +
    + + + +
    + +
    +file_download + + + + +
    +
    +
    + +
    + +
    + + +
    + + +
    + + + +
    +
    + +
    +
    + +
    + + +
    + + +
    + +
    + +
    +
    + + + + + + + + diff --git a/version b/version index c6542b8..bb425e5 100644 --- a/version +++ b/version @@ -1,5 +1,6 @@ Update Data: +20200607-1856.19 add platform: Aliyun Function Compute. add setting: replace sharepoint.com to a proxy server name. add setting: disableShowThumb,customTheme. add function: php hosting website can update by a click 现在可以安装到阿里函数计算FC了。php空间可以一键更新了。可以设置某个盘替换sharpoint.com域名为你的反代域名。新增disableShowThumb,customTheme。 20200503-1848.18 Rebuild theme. Add custom Css & custom Script, add FunctionalityFile: head.omf & foot.omf 重建主题文件结构。增加自定义css与自定义script。增加2个功能文件:head.omf、foot.omf。 20200402-1830.17 Oneclick update can select which branch to update. Now use the accept language instead of the language config.一键更新可以选择哪个分支了。现在开始使用浏览器语言,抛弃language设置。 20200326-0001.16 You can add sharepoint site drive as a disk,you must reinstall after update.可以将sharepoint网站添加成一个盘,由于结构改变,升级后只能重装。