| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- <?php
- namespace App\Services;
- use GuzzleHttp\Client;
- use GuzzleHttp\Exception\GuzzleException;
- class VolcEngineService
- {
- /** @var Client */
- protected $client;
- public function __construct()
- {
- $this->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,
- ];
- }
- }
|