client = new Client([ 'timeout' => 1200, ]); } /** * 通用请求方法:内部完成火山引擎签名并发送 HTTP 请求 * * @param string $method HTTP 方法:GET / POST / PUT ... * @param string $host 目标 Host,例如:iam.volcengineapi.com * @param string $path 请求路径,例如:"/" 或 "/" * @param array $query 查询参数(不含 Action/Version) * @param string $body 请求 Body 字符串(GET 一般为空字符串) * @param string $ak AccessKeyId * @param string $sk SecretAccessKey * @param string $service 服务名,例如:iam / vod / sms 等 * @param string $region 区域,例如:cn-north-1 * @param string $action 公共参数 Action * @param string $version 公共参数 Version * @param string $contentType Content-Type,默认 application/json * * @return array [ * 'status' => int, * 'headers' => array, * 'body' => string, * ] * @throws GuzzleException */ public function request( string $method, string $host, string $path, array $query, string $body, string $ak, string $sk, string $service, string $region, string $action, string $version, string $contentType = 'application/json' ): array { // 初始化身份证明结构体 $credential = [ 'accessKeyId' => $ak, 'secretKeyId' => $sk, 'service' => $service, 'region' => $region, ]; // 合并公共参数,并按 key 排序 $query = array_merge($query, [ 'Action' => $action, 'Version' => $version ]); ksort($query); // 初始化请求参数 $requestParam = [ 'body' => $body, 'host' => $host, 'path' => $path, 'method' => $method, 'contentType' => $contentType, 'date' => gmdate('Ymd\\THis\\Z'), 'query' => $query ]; // 计算签名 $xDate = $requestParam['date']; $shortXDate = substr($xDate, 0, 8); $xContentSha256 = hash('sha256', $requestParam['body']); $signResult = [ 'Host' => $requestParam['host'], 'X-Content-Sha256' => $xContentSha256, 'X-Date' => $xDate, 'Content-Type' => $requestParam['contentType'] ]; // 计算 Signature 签名 $signedHeaderStr = join(';', ['content-type', 'host', 'x-content-sha256', 'x-date']); $canonicalRequestStr = join("\n", [ $requestParam['method'], $requestParam['path'], http_build_query($requestParam['query']), join("\n", [ 'content-type:'. $requestParam['contentType'], 'host:'. $requestParam['host'], 'x-content-sha256:'. $xContentSha256, 'x-date:'. $xDate ]), '', $signedHeaderStr, $xContentSha256 ]); $hashedCanonicalRequest = hash("sha256", $canonicalRequestStr); $credentialScope = join('/', [$shortXDate, $credential['region'], $credential['service'], 'request']); $stringToSign = join("\n", [ 'HMAC-SHA256', $xDate, $credentialScope, $hashedCanonicalRequest ]); $kDate = hash_hmac("sha256", $shortXDate, $credential['secretKeyId'], true); $kRegion = hash_hmac("sha256", $credential['region'], $kDate, true); $kService = hash_hmac("sha256", $credential['service'], $kRegion, true); $kSigning = hash_hmac("sha256", 'request', $kService, true); $signature = hash_hmac("sha256", $stringToSign, $kSigning); $signResult['Authorization'] = sprintf( "HMAC-SHA256 Credential=%s, SignedHeaders=%s, Signature=%s", $credential['accessKeyId']. '/'. $credentialScope, $signedHeaderStr, $signature ); $header = array_merge([], $signResult); // 空的$header数组 // 发送 HTTP 请求 $client = new Client([ 'base_uri' => 'https://'. $requestParam['host'], 'timeout' => 1200, ]); $response = $client->request($method, $requestParam['path'], [ 'headers' => $header, 'query' => $requestParam['query'], 'body' => $requestParam['body'] ]); $responseContent = $response->getBody()->getContents(); // 转换 \u0026 为 & $responseContent = str_replace('\u0026', '&', $responseContent); return [ 'status' => $response->getStatusCode(), 'headers' => $response->getHeaders(), 'body' => $responseContent, ]; } }