├── .env.test.template ├── .gitignore ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── Auth │ ├── BaiduCloudAuth.php │ └── TencentCloudAuth.php ├── Client │ ├── BaiduCloudClient.php │ ├── CloudflareClient.php │ ├── CommonClient.php │ ├── GithubClient.php │ ├── OpenAIClient.php │ └── TencentCloudClient.php ├── Exception │ └── AuthException.php ├── Tool │ ├── ClientTool.php │ └── TestCaseTool.php └── YZhanGateway.php └── tests ├── BaiduCloudTest.php ├── CloudflareTest.php ├── GithubTest.php ├── OpenAITest.php ├── TencentCloudTest.php └── YZhanGatewayTest.php /.env.test.template: -------------------------------------------------------------------------------- 1 | # Before running composer test 2 | # Please replace the following information with your information 3 | # Rename .env.test.template to .env.test 4 | BAIDUCLOUD_ACCESSKEY= 5 | BAIDUCLOUD_SECRETKEY= 6 | BAIDUCLOUD_TEST_URL= 7 | CLOUDFLARE_REGION_ID= 8 | CLOUDFLARE_APITOKEN= 9 | CLOUDFLARE_TEST_URL= 10 | GITHUB_USER_NAME= 11 | GITHUB_ACCESS_TOKEN= 12 | OPENAI_APIKEY= 13 | TENCENTCLOUD_SECRET_ID= 14 | TENCENTCLOUD_SECRET_KEY= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .phpunit.result.cache 3 | composer.lock 4 | .env.test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yzhanGateway 2 | 3 | Developing PHP SDK for any API. 4 | 为任何 API 快速开发 PHP SDK. 5 | 6 | ## Install 安装 7 | 8 | ```shell 9 | composer require mantoufan/yzhangateway 10 | ``` 11 | 12 | ## Usage 使用 13 | 14 | ### {root}/src 15 | 16 | #### Client 17 | 18 | 1. Create a `{client name}.php` in `src\Client` Directory 19 | 1. 在 `src\Client` 目录新建一个 `{客户端名称}.php` 20 | 1. Implement `request` method 21 | 1. 实现请求 `request` 方法 22 | 23 | #### Auth 24 | 25 | 如需要,新建 `.php` 提供鉴权类 26 | 例如包含获取 `authorization` 请求头的方法 27 | If necessary, create a new `.php` to provide an authentication class, 28 | such as a method to obtain the `authorization` request header 29 | 30 | #### Exception 31 | 32 | 如需要,新建 `.php` 声明新错误类型 33 | If necessary, create a new `.php` here to declare a new error type 34 | 35 | #### Tool 36 | 37 | ##### ClientTool 38 | 39 | 提供 `Request` 静态方法,发出请求和响应 40 | Provides the `Request` static method for making requests and responses 41 | 42 | ### {root}/tests 43 | 44 | #### {root}/.env.test 45 | 46 | 运行 `composer test` 前,请将`.env.test.template`重命名为`.env.test`存放测试需要的变量 47 | Before running `composer test`, rename `.env.test.template` to `env.test` to store variables needed for testing 48 | ![.env.test example](https://s2.loli.net/2022/09/10/1e7GxSlquyTPdRX.jpg) 49 | 50 | ## Example 示例 51 | 52 | ### Common 通用 53 | 54 | ```php 55 | $yzhanGateway = new YZhanGateway('Common'); 56 | $res = $yzhanGateway->request(array( 57 | 'method' => 'GET', 58 | 'url' => 'https://animechan.vercel.app/api/random' 59 | )); 60 | ``` 61 | 62 | ### Use Cache 使用缓存 63 | 64 | Cache Results for 86400 seconds 65 | 66 | ```php 67 | $yzhanGateway = new YZhanGateway('Common'); 68 | $res = $yzhanGateway->cache()->request(array( 69 | 'method' => 'GET', 70 | 'url' => 'https://animechan.vercel.app/api/random', 71 | 'cache' => array( 72 | 'maxAge' => 86400 73 | ) 74 | )); 75 | ``` 76 | 77 | ### Clear Cache 清理缓存 78 | 79 | Cache Results for 86400 seconds 80 | 81 | ```php 82 | $yzhanGateway = new YZhanGateway('Common'); 83 | $params = array( 84 | 'method' => 'GET', 85 | 'url' => 'https://animechan.vercel.app/api/random', 86 | 'cache' => array( 87 | 'maxAge' => 86400 88 | ) 89 | ); 90 | $res = $yzhanGateway->cache()->request($params); 91 | if ($res === null) { // If results is bad, using getCache to get the yzhanCache instance 92 | $yzhanGateway->getCache()->delete($yzhanGateway->getKey($params)); // Delete, set by the key 93 | } 94 | ``` 95 | 96 | ### BaiduCloud 百度智能云 97 | 98 | Purge Files by urls in Biadu Cloud CDN. 99 | 100 | ```php 101 | $yzhanGateway = new YZhanGateway('BaiduCloud', array( 102 | 'accessKey' => $_ENV['BAIDUCLOUD_ACCESSKEY'], 103 | 'secretKey' => $_ENV['BAIDUCLOUD_SECRETKEY'] 104 | )); 105 | $res = $yzhanGateway->request(array( 106 | 'method' => 'POST', 107 | 'url' => 'http://cdn.baidubce.com/v2/cache/purge', 108 | 'postFields' => array( 109 | 'tasks' => array( 110 | array('url' => $_ENV['BAIDUCLOUD_TEST_URL']) 111 | ) 112 | ) 113 | )); 114 | ``` 115 | 116 | ### Cloudflare 117 | 118 | Purge Files by urls (<= 30) in Cloudflare. 119 | 120 | ```php 121 | $yzhanGateway = new YZhanGateway('Cloudflare', array( 122 | 'apiToken' => $_ENV['CLOUDFLARE_APITOKEN'] 123 | )); 124 | $res = $yzhanGateway->request(array( 125 | 'method' => 'POST', 126 | 'url' => 'https://api.cloudflare.com/client/v4/zones/' . $_ENV['CLOUDFLARE_REGION_ID'] . '/purge_cache', 127 | 'postFields' => array( 128 | 'files' => array($_ENV['CLOUDFLARE_TEST_URL']) 129 | ) 130 | )); 131 | ``` 132 | 133 | ### Github 134 | 135 | Get user's recent activities. 136 | 137 | ```php 138 | $yzhanGateway = new YZhanGateway('Github', array( 139 | 'accessToken' => $_ENV['GITHUB_ACCESS_TOKEN'], 140 | 'userAgent' => $_ENV['GITHUB_USER_NAME'] 141 | )); 142 | $res = $yzhanGateway->request(array( 143 | 'method' => 'GET', 144 | 'url' => 'https://api.github.com/users/' . $_ENV['GITHUB_USER_NAME'] . '/events' 145 | )); 146 | ``` 147 | 148 | ### OpenAI 149 | 150 | Chat using text-davinci 151 | 152 | ```php 153 | $yzhanGateway = new YZhanGateway('OpenAI', array( 154 | 'apiKey' => $_ENV['OPENAI_APIKEY'], 155 | // 'organization' => $_ENV['OPENAI_ORGANIZATION'] // Optional 156 | )); 157 | $res = $yzhanGateway->request(array( 158 | 'method' => 'POST', 159 | 'url' => 'https://api.openai.com/v1/completions', 160 | 'postFields' => array( 161 | 'model' => 'text-davinci-003', 162 | 'prompt' => 'Hello', 163 | 'temperature'=> 0 // Optional, 0 means the most certain results 164 | ) 165 | )); 166 | ``` 167 | 168 | ### TencentCloud 腾讯云 169 | 170 | Get CVM list 171 | 172 | ```php 173 | $yzhanGateway = new YZhanGateway('TencentCloud', array( 174 | 'secretId' => $_ENV['TENCENTCLOUD_SECRET_ID'], 175 | 'secretKey' => $_ENV['TENCENTCLOUD_SECRET_KEY'] 176 | )); 177 | $res = $yzhanGateway->request(array( 178 | 'method' => 'POST', 179 | 'url' => 'https://cvm.tencentcloudapi.com', 180 | 'action' => 'DescribeInstances', 181 | 'version' => '2017-03-12', 182 | 'region' => 'ap-guangzhou', 183 | 'postFields' => array( 184 | 'Limit' => 1, 185 | 'Filters' => array( 186 | array('Values' => array('未命名'), 'Name' => 'instance-name') 187 | ), 188 | ) 189 | )); 190 | ``` 191 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mantoufan/yzhangateway", 3 | "type": "library", 4 | "description": "Developing PHP SDK for any API. 为任何 API 快速开发 PHP SDK.", 5 | "keywords": [ 6 | "Baidu Cloud", 7 | "Cloudflare", 8 | "SDK", 9 | "API Gateway", 10 | "CDN", 11 | "Purge Cache" 12 | ], 13 | "license": "MIT", 14 | "authors": [ 15 | { 16 | "name": "Shon Wu", 17 | "email": "mhjlw@126.com", 18 | "homepage": "https://github.com/mantoufan" 19 | } 20 | ], 21 | "scripts": { 22 | "test": "phpunit", 23 | "coverage": "phpunit --coverage-clover clover.xml" 24 | }, 25 | "require": { 26 | "php": ">=5.4", 27 | "vlucas/phpdotenv": "^5.4", 28 | "mantoufan/yzhancache": "^1.0" 29 | }, 30 | "require-dev": { 31 | "phpunit/phpunit": "^9.5" 32 | }, 33 | "autoload": { 34 | "psr-4": { 35 | "YZhanGateway\\": "src/" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | tests 13 | 14 | 15 | 16 | 17 | src 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Auth/BaiduCloudAuth.php: -------------------------------------------------------------------------------- 1 | ak = $accessKey; 19 | $this->sk = $secretKey; 20 | $date = new \DateTime('now'); 21 | $date->setTimezone(new \DateTimeZone('UTC')); 22 | $this->timestamp = $date->format('Y-m-d\TH:i:s\Z'); 23 | } 24 | 25 | public function setVersion($version) 26 | { 27 | $this->version = $version; 28 | } 29 | 30 | public function setExpiration($expiration) 31 | { 32 | $this->expiration = $expiration; 33 | } 34 | 35 | public function setMethod($method) 36 | { 37 | if (!empty($method)) { 38 | $this->method = strtoupper($method); 39 | } 40 | } 41 | 42 | public function setTimestamp($timestamp) 43 | { 44 | $this->timestamp = $timestamp; 45 | } 46 | 47 | public function setUri($uri) 48 | { 49 | $this->uri = $uri; 50 | } 51 | 52 | public function setParams($params) 53 | { 54 | $this->params = $this->normalizeParam($params); 55 | } 56 | 57 | public function setSignedHeaders($headers) 58 | { 59 | $this->headers = $this->normalizeHeaders($headers); 60 | } 61 | 62 | public function beLog($needLog) 63 | { 64 | $this->needLog = $needLog; 65 | } 66 | 67 | public function genAuthorization() 68 | { 69 | $signature = $this->genSignature(); 70 | $authStr = 'bce-auth-v' . $this->version . '/' . 71 | $this->ak . '/' . $this->timestamp . '/' . 72 | $this->expiration . '/' . $this->getSignedHeaderNames() . '/' . $signature; 73 | return $authStr; 74 | } 75 | 76 | public function genSignature() 77 | { 78 | if (empty($this->method)) { 79 | throw new AuthException('method is null or empty'); 80 | } 81 | $signingKey = $this->genSigningKey(); 82 | $this->signerLog('signingKey:' . $signingKey, __LINE__, __FILE__); 83 | $authStr = $this->method . "\n" . 84 | $this->getCanonicalURI() . "\n" . 85 | $this->getCanonicalParam() . "\n" . 86 | $this->getCanonicalHeaders(); 87 | $this->signerLog('auth str:' . $authStr, __LINE__, __FILE__); 88 | return $this->sha256($signingKey, $authStr); 89 | } 90 | 91 | public function genSigningKey() 92 | { 93 | if (empty($this->ak)) { 94 | throw new AuthException('Access key is null or empty'); 95 | } 96 | if (empty($this->sk)) { 97 | throw new AuthException('Secret key is null or empty'); 98 | } 99 | if (empty($this->version)) { 100 | throw new AuthException('Version is null or empty'); 101 | } 102 | if (empty($this->timestamp)) { 103 | throw new AuthException('Timestamp is null or empty'); 104 | } 105 | if (empty($this->expiration)) { 106 | throw new AuthException('Expiration is null or empty'); 107 | } 108 | $authStr = 'bce-auth-v' . $this->version . '/' . $this->ak . '/' . 109 | $this->timestamp . '/' . $this->expiration; 110 | return $this->sha256($this->sk, $authStr); 111 | } 112 | 113 | public function getCanonicalParam() 114 | { 115 | if (empty($this->params)) { 116 | return ''; 117 | } 118 | $arryLen = count($this->params); 119 | $canonicalParams = ''; 120 | foreach ($this->params as $key => $value) { 121 | if (is_array($value)) { 122 | $num = count($value); 123 | if (count($value) == 0) { 124 | $canonicalParams = $canonicalParams . $key . '='; 125 | } else { 126 | foreach ($value as $item) { 127 | $canonicalParams = $canonicalParams . $key . '=' . $item; 128 | if ($num > 1) { 129 | $canonicalParams = $canonicalParams . '&'; 130 | $num--; 131 | } 132 | } 133 | } 134 | } else { 135 | $canonicalParams = $canonicalParams . $key . '=' . $value; 136 | } 137 | if ($arryLen > 1) { 138 | $canonicalParams = $canonicalParams . '&'; 139 | $arryLen--; 140 | } 141 | } 142 | return $canonicalParams; 143 | } 144 | 145 | public function getCanonicalURI() 146 | { 147 | if (empty($this->uri)) { 148 | throw new AuthException('Uri is null or empty'); 149 | } 150 | $newUri = $this->dataEncode($this->uri, true); 151 | if (strpos($newUri, '/') === 0) { 152 | return $newUri; 153 | } 154 | return '/' . $newUri; 155 | } 156 | 157 | public function getCanonicalHeaders() 158 | { 159 | if (empty($this->headers) || !array_key_exists('host', $this->headers)) { 160 | throw new AuthException('host not in headers'); 161 | } 162 | $canonicalHeaders = ''; 163 | $strArry = array(); 164 | foreach ($this->headers as $key => $value) { 165 | if (empty($value)) { 166 | continue; 167 | } 168 | $strArry[] = $this->dataEncode($key, false) . ':' . $value; 169 | } 170 | $arryLen = count($strArry); 171 | for ($i = 0; $i < $arryLen; $i++) { 172 | if ($i < $arryLen - 1) { 173 | $canonicalHeaders = $canonicalHeaders . $strArry[$i] . "\n"; 174 | continue; 175 | } 176 | $canonicalHeaders = $canonicalHeaders . $strArry[$i]; 177 | } 178 | return $canonicalHeaders; 179 | } 180 | 181 | private function sha256($key, $data) 182 | { 183 | return hash_hmac('sha256', $data, $key); 184 | } 185 | 186 | private function dataEncode($data, $isPath) 187 | { 188 | if (empty($data)) { 189 | return ''; 190 | } 191 | $encode = mb_detect_encoding($data, array('ASCII', 'UTF-8', 'GB2312', 'GBK', 'BIG5')); 192 | if ($encode != 'UTF-8') { 193 | $data = mb_convert_encoding($data, 'utf-8', $encode); 194 | } 195 | $encodeStr = rawurlencode($data); 196 | if ($isPath) { 197 | $encodeStr = str_replace('%2F', '/', $encodeStr); 198 | } 199 | return $encodeStr; 200 | } 201 | 202 | private function normalizeHeaders($headers) 203 | { 204 | $newArray = array(); 205 | if (empty($headers)) { 206 | return $newArray; 207 | } 208 | foreach ($headers as $key => $value) { 209 | $newKey = strtolower($key); 210 | if (empty($newKey)) { 211 | continue; 212 | } 213 | $newArray[$newKey] = $this->dataEncode(trim($value), false); 214 | } 215 | ksort($newArray); 216 | return $newArray; 217 | } 218 | 219 | private function normalizeParam($params) 220 | { 221 | $newArray = array(); 222 | if (empty($params)) { 223 | return $newArray; 224 | } 225 | foreach ($params as $key => $value) { 226 | if (empty($key) || strtolower($key) == 'authorization') { 227 | continue; 228 | } 229 | if (is_array($value)) { 230 | $newSubArray = array(); 231 | foreach ($value as $item) { 232 | $newSubArray[] = $this->dataEncode($item, false); 233 | } 234 | sort($newSubArray); 235 | $newArray[$this->dataEncode($key, false)] = $newSubArray; 236 | } else { 237 | $newArray[$this->dataEncode($key, false)] = $this->dataEncode($value, false); 238 | } 239 | } 240 | ksort($newArray); 241 | return $newArray; 242 | } 243 | 244 | private function getSignedHeaderNames() 245 | { 246 | $arryLen = count($this->headers); 247 | $headerNames = ''; 248 | foreach ($this->headers as $key => $value) { 249 | $headerNames = $headerNames . $key; 250 | if ($arryLen > 1) { 251 | $headerNames = $headerNames . ';'; 252 | $arryLen--; 253 | } 254 | } 255 | return $headerNames; 256 | } 257 | 258 | private function signerLog($content, $line, $file) 259 | { 260 | if ($this->needLog) { 261 | error_log($file . ':' . $line . ':[' . $content . ']\n', 3, './signer_log'); 262 | } 263 | } 264 | } 265 | ?> -------------------------------------------------------------------------------- /src/Auth/TencentCloudAuth.php: -------------------------------------------------------------------------------- 1 | secretId = $secretId; 21 | $this->secretKey = $secretKey; 22 | } 23 | 24 | function setMethod(string $method) { 25 | $this->method = $method; 26 | } 27 | 28 | function setService(string $service) { 29 | $this->service = $service; 30 | } 31 | 32 | function setUri(string $uri) { 33 | $this->uri = $uri; 34 | } 35 | 36 | function setQueryString(string $queryString) { 37 | $this->queryString = $queryString; 38 | } 39 | 40 | function setSignedHeaders(array $signHeaders) { 41 | ksort($signHeaders); 42 | $headers = ''; 43 | $signedHeaders = array(); 44 | foreach($signHeaders as $key => $val) { 45 | $key = strtolower($key); 46 | $headers .= $key . ':' . strtolower($val) . "\n"; 47 | $signedHeaders []= $key; 48 | } 49 | $this->headers = $headers; 50 | $this->signedHeaders = implode(';', $signedHeaders); 51 | } 52 | 53 | function setBody(string $body) { 54 | $this->body = $body; 55 | } 56 | 57 | function setTimestamp(int $timestamp) { 58 | $this->timestamp = $timestamp; 59 | $this->date = gmdate('Y-m-d', $timestamp); 60 | } 61 | 62 | function getCanonicalRequest() { 63 | return $this->method . "\n" . 64 | $this->uri . "\n" . 65 | $this->queryString . "\n" . 66 | $this->headers . "\n" . 67 | $this->signedHeaders . "\n" . 68 | hash('SHA256', $this->body); 69 | } 70 | 71 | function getCredentialScope() { 72 | return $this->date . '/' . $this->service . '/tc3_request'; 73 | } 74 | 75 | function getStringToSign() { 76 | return $this->algorithm . "\n" . 77 | $this->timestamp . "\n" . 78 | $this->getCredentialScope() . "\n" . 79 | hash('SHA256', $this->getCanonicalRequest()); 80 | } 81 | 82 | function getSignature() { 83 | $secretDate = hash_hmac('SHA256', $this->date, 'TC3' . $this->secretKey, true); 84 | $secretService = hash_hmac('SHA256', $this->service, $secretDate, true); 85 | $secretSigning = hash_hmac('SHA256', 'tc3_request', $secretService, true); 86 | return hash_hmac('SHA256', $this->getStringToSign(), $secretSigning); 87 | } 88 | 89 | function getAuthorization() { 90 | return $this->algorithm . 91 | ' Credential=' . $this->secretId . '/' . $this->getCredentialScope() . 92 | ', SignedHeaders=' . $this->signedHeaders . 93 | ', Signature=' . $this->getSignature(); 94 | } 95 | } 96 | ?> -------------------------------------------------------------------------------- /src/Client/BaiduCloudClient.php: -------------------------------------------------------------------------------- 1 | auth = new BaiduCloudAuth($params['accessKey'], $params['secretKey']); 10 | } 11 | public function request(array $params) : array { 12 | ['host' => $host, 'path' => $uri] = parse_url($params['url']); 13 | $this->auth->setMethod($params['method']); 14 | $this->auth->setUri($uri); 15 | $this->auth->setSignedHeaders(array( 16 | 'host'=> $host 17 | )); 18 | try { 19 | $authorization = $this->auth->genAuthorization(); 20 | } catch (AuthException $e) { 21 | return array($e->getMessage()); 22 | } 23 | $params['httpHeaders'] = array_merge(array( 24 | 'host' => $host, 25 | 'authorization' => $authorization, 26 | 'content-type' => 'application/json' 27 | ), empty($params['httpHeaders']) ? array() : $params['httpHeaders']); 28 | $params['postFields'] = json_encode($params['postFields'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); 29 | return array(null, ClientTool::Request($params)); 30 | } 31 | } 32 | ?> -------------------------------------------------------------------------------- /src/Client/CloudflareClient.php: -------------------------------------------------------------------------------- 1 | apiToken = $params['apiToken']; 8 | } 9 | public function request(array $params) : array { 10 | $params['httpHeaders'] = array_merge(array( 11 | 'authorization' => 'Bearer ' . $this->apiToken, 12 | 'content-type' => 'application/json' 13 | ), empty($params['httpHeaders']) ? array() : $params['httpHeaders']); 14 | $params['postFields'] = json_encode($params['postFields'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); 15 | return array(null, ClientTool::Request($params)); 16 | } 17 | } 18 | ?> -------------------------------------------------------------------------------- /src/Client/CommonClient.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Client/GithubClient.php: -------------------------------------------------------------------------------- 1 | accessToken = $params['accessToken']; 9 | $this->userAgent = $params['userAgent']; 10 | } 11 | public function request(array $params) : array { 12 | $params['httpHeaders'] = array_merge(array( 13 | 'user-agent' => $this->userAgent, 14 | 'accept' => 'application/vnd.github+json', 15 | 'authorization' => 'Bearer ' . $this->accessToken, 16 | 'content-type' => 'application/json' 17 | ), empty($params['httpHeaders']) ? array() : $params['httpHeaders']); 18 | //$params['postFields'] = json_encode($params['postFields'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); 19 | return array(null, ClientTool::Request($params)); 20 | } 21 | } 22 | ?> -------------------------------------------------------------------------------- /src/Client/OpenAIClient.php: -------------------------------------------------------------------------------- 1 | apiKey = $params['apiKey']; 9 | $this->organization = empty($params['organization']) ? 'org-XIJ1T48BCBhG1ee7PiaAlIpI' : $params['organization']; 10 | } 11 | public function request(array $params) : array { 12 | $params['httpHeaders'] = array_merge(array( 13 | 'authorization' => 'Bearer ' . $this->apiKey, 14 | 'content-type' => 'application/json', 15 | 'openai-organization' => $this->organization 16 | ), empty($params['httpHeaders']) ? array() : $params['httpHeaders']); 17 | $params['postFields'] = json_encode($params['postFields'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); 18 | return array(null, ClientTool::Request($params)); 19 | } 20 | } 21 | ?> -------------------------------------------------------------------------------- /src/Client/TencentCloudClient.php: -------------------------------------------------------------------------------- 1 | auth = new TencentCloudAuth($params['secretId'], $params['secretKey']); 10 | } 11 | public function request(array $params) : array { 12 | $parsedUrl = parse_url($params['url']); 13 | $host = $parsedUrl['host']; 14 | $uri = empty($parsedUrl['path']) ? '/' : $parsedUrl['path']; 15 | $queryString = empty($parsedUrl['query']) ? '' : $parsedUrl['query']; 16 | ['method' => $method, 'action' => $action, 'version' => $version, 'region' => $region] = $params; 17 | $postFields = empty($params['postFields']) ? array() : $params['postFields']; 18 | $httpHeaders = empty($params['httpHeaders']) ? array() : $params['httpHeaders']; 19 | $contentType = empty($httpHeaders['content-type']) ? 'application/json' : $httpHeaders['content-type']; 20 | $httpHeaders = array_merge(array( 21 | 'host' => $host, 22 | 'content-type' => 'application/json' 23 | ), empty($httpHeaders) ? array() : $httpHeaders); 24 | $postFields = json_encode($postFields, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); 25 | $timestamp = time(); 26 | [$service] = explode('.', $host); 27 | $this->auth->setService($service); 28 | $this->auth->setMethod($method); 29 | $this->auth->setUri($uri); 30 | $this->auth->setQueryString($queryString); 31 | $this->auth->setSignedHeaders(array( 32 | 'host'=> $host, 33 | 'content-type' => $httpHeaders['content-type'] 34 | )); 35 | $this->auth->setBody($postFields); 36 | $this->auth->setTimestamp($timestamp); 37 | try { 38 | $authorization = $this->auth->getAuthorization(); 39 | } catch (AuthException $e) { 40 | return array($e->getMessage()); 41 | } 42 | $params['httpHeaders'] = array_merge(array( 43 | 'X-TC-Action' => $action, 44 | 'X-TC-Region' => $region, 45 | 'X-TC-Timestamp' => $timestamp, 46 | 'X-TC-Version' => $version, 47 | 'Authorization' => $authorization, 48 | ), $httpHeaders); 49 | $params['postFields'] = $postFields; 50 | return array(null, ClientTool::Request($params)); 51 | } 52 | } 53 | ?> -------------------------------------------------------------------------------- /src/Exception/AuthException.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Tool/ClientTool.php: -------------------------------------------------------------------------------- 1 | $params['url'], 8 | CURLOPT_CUSTOMREQUEST => $params['method'], 9 | CURLOPT_HTTPHEADER => empty($params['httpHeaders']) ? array() : array_map(function ($v, $k) { 10 | return $k . ':' . $v; 11 | }, array_values((array) $params['httpHeaders']), array_keys((array) $params['httpHeaders'])), 12 | CURLOPT_POST => $params['method'] === 'POST', 13 | CURLOPT_POSTFIELDS => empty($params['postFields']) ? null : $params['postFields'], 14 | CURLOPT_RETURNTRANSFER => true, 15 | CURLOPT_TIMEOUT => $params['timeout'] ?? 6, 16 | CURLOPT_SSL_VERIFYHOST => false, 17 | CURLOPT_SSL_VERIFYPEER => false, 18 | CURLOPT_HEADER => true, 19 | )); 20 | $response = curl_exec($ch); 21 | $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); 22 | return array( 23 | 'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE), 24 | 'header' => substr($response, 0, $header_size), 25 | 'body' => substr($response, $header_size), 26 | ); 27 | } 28 | } 29 | ?> -------------------------------------------------------------------------------- /src/Tool/TestCaseTool.php: -------------------------------------------------------------------------------- 1 | load(); 9 | } 10 | } 11 | ?> -------------------------------------------------------------------------------- /src/YZhanGateway.php: -------------------------------------------------------------------------------- 1 | client = new $className($params); 11 | } 12 | public function cache(string $type = 'File', array $params = array()) { 13 | $this->yzhanCache = new yzhanCache($type, $params); 14 | return $this; 15 | } 16 | public function request(array $params) { 17 | if ($this->yzhanCache === null) { 18 | return $this->client->request($params); 19 | } 20 | $key = $this->getKey($params); 21 | if ($this->yzhanCache->has($key) === false) { 22 | $maxAge = empty($params['cache']) === false ? $params['cache']['maxAge'] : null; 23 | $this->yzhanCache->set($key, $this->client->request($params), $maxAge); 24 | } 25 | return $this->yzhanCache->get($key); 26 | } 27 | public function getCache() { 28 | return $this->yzhanCache; 29 | } 30 | public function getKey(array $params) { 31 | return md5(serialize($params)); 32 | } 33 | } 34 | ?> -------------------------------------------------------------------------------- /tests/BaiduCloudTest.php: -------------------------------------------------------------------------------- 1 | $_ENV['BAIDUCLOUD_ACCESSKEY'], 9 | 'secretKey' => $_ENV['BAIDUCLOUD_SECRETKEY'] 10 | )); 11 | $res = $yzhanGateway->request(array( 12 | 'method' => 'POST', 13 | 'url' => 'http://cdn.baidubce.com/v2/cache/purge', 14 | 'postFields' => array( 15 | 'tasks' => array( 16 | array('url' => $_ENV['BAIDUCLOUD_TEST_URL']) 17 | ) 18 | ) 19 | )); 20 | $this->assertNull($res[0]); 21 | $this->assertNotNull($res[1]['code']); 22 | $this->assertNotNull($res[1]['header']); 23 | $this->assertNotNull($res[1]['body']); 24 | } 25 | } 26 | ?> -------------------------------------------------------------------------------- /tests/CloudflareTest.php: -------------------------------------------------------------------------------- 1 | $_ENV['CLOUDFLARE_APITOKEN'] 9 | )); 10 | $res = $yzhanGateway->request(array( 11 | 'method' => 'POST', 12 | 'url' => 'https://api.cloudflare.com/client/v4/zones/' . $_ENV['CLOUDFLARE_REGION_ID'] . '/purge_cache', 13 | 'postFields' => array( 14 | 'files' => array($_ENV['CLOUDFLARE_TEST_URL']) 15 | ) 16 | )); 17 | $this->assertNull($res[0]); 18 | $this->assertNotNull($res[1]['code']); 19 | $this->assertNotNull($res[1]['header']); 20 | $this->assertNotNull($res[1]['body']); 21 | } 22 | } 23 | ?> -------------------------------------------------------------------------------- /tests/GithubTest.php: -------------------------------------------------------------------------------- 1 | $_ENV['GITHUB_ACCESS_TOKEN'], 9 | 'userAgent' => $_ENV['GITHUB_USER_NAME'] 10 | )); 11 | $res = $yzhanGateway->request(array( 12 | 'method' => 'GET', 13 | 'url' => 'https://api.github.com/users/' . $_ENV['GITHUB_USER_NAME'] . '/events' 14 | )); 15 | $this->assertNull($res[0]); 16 | $this->assertNotNull($res[1]['code']); 17 | $this->assertNotNull($res[1]['header']); 18 | $this->assertNotNull($res[1]['body']); 19 | } 20 | } 21 | ?> -------------------------------------------------------------------------------- /tests/OpenAITest.php: -------------------------------------------------------------------------------- 1 | $_ENV['OPENAI_APIKEY'] 9 | )); 10 | $res = $yzhanGateway->request(array( 11 | 'method' => 'POST', 12 | 'url' => 'https://api.openai.com/v1/completions', 13 | 'postFields' => array( 14 | 'model' => 'text-davinci-003', 15 | 'prompt' => 'Hello', 16 | 'temperature'=> 0 17 | ) 18 | )); 19 | $this->assertNull($res[0]); 20 | $this->assertNotNull($res[1]['code']); 21 | $this->assertNotNull($res[1]['header']); 22 | $this->assertNotNull($res[1]['body']); 23 | $body = json_decode($res[1]['body'], true); 24 | $this->assertEquals($body['model'], 'text-davinci-003'); 25 | } 26 | } 27 | ?> -------------------------------------------------------------------------------- /tests/TencentCloudTest.php: -------------------------------------------------------------------------------- 1 | $_ENV['TENCENTCLOUD_SECRET_ID'], 9 | 'secretKey' => $_ENV['TENCENTCLOUD_SECRET_KEY'] 10 | )); 11 | $res = $yzhanGateway->request(array( 12 | 'method' => 'POST', 13 | 'url' => 'https://cvm.tencentcloudapi.com', 14 | 'action' => 'DescribeInstances', 15 | 'version' => '2017-03-12', 16 | 'region' => 'ap-guangzhou', 17 | 'postFields' => array( 18 | 'Limit' => 1, 19 | 'Filters' => array( 20 | array('Values' => array('未命名'), 'Name' => 'instance-name') 21 | ), 22 | ) 23 | )); 24 | $this->assertNull($res[0]); 25 | $this->assertNotNull($res[1]['code']); 26 | $this->assertNotNull($res[1]['header']); 27 | $this->assertNotNull($res[1]['body']); 28 | $body = json_decode($res[1]['body'], true); 29 | $this->assertIsInt($body['Response']['TotalCount']); 30 | } 31 | } 32 | ?> -------------------------------------------------------------------------------- /tests/YZhanGatewayTest.php: -------------------------------------------------------------------------------- 1 | request(array( 9 | 'method' => 'GET', 10 | 'url' => 'https://animechan.vercel.app/api/random' 11 | )); 12 | $this->assertNull($res[0]); 13 | $this->assertNotNull($res[1]['code']); 14 | $this->assertNotNull($res[1]['header']); 15 | $this->assertNotNull($res[1]['body']); 16 | } 17 | public function testCache() { 18 | $yzhanGateway = new YZhanGateway('Common'); 19 | $res = $yzhanGateway->cache()->request(array( 20 | 'method' => 'GET', 21 | 'url' => 'https://animechan.vercel.app/api/random', 22 | 'cache' => array( 23 | 'maxAge' => 86400 24 | ) 25 | )); 26 | $this->assertNull($res[0]); 27 | $this->assertNotNull($res[1]['code']); 28 | $this->assertNotNull($res[1]['header']); 29 | $this->assertNotNull($res[1]['body']); 30 | } 31 | } 32 | ?> --------------------------------------------------------------------------------