76 lines
2.4 KiB
PHP
76 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Esign;
|
|
|
|
use InvalidArgumentException;
|
|
|
|
final class EsignRequestSigner
|
|
{
|
|
public const ACCEPT = '*/*';
|
|
public const CONTENT_TYPE = 'application/json; charset=UTF-8';
|
|
|
|
public function __construct(
|
|
private readonly string $appId,
|
|
private readonly string $appSecret,
|
|
) {
|
|
if ($this->appId === '' || $this->appSecret === '') {
|
|
throw new InvalidArgumentException('E 签宝 App ID 和 AppSecret 不能为空。');
|
|
}
|
|
}
|
|
|
|
public function headers(string $method, string $pathAndParameters, string $body = ''): array
|
|
{
|
|
$method = strtoupper($method);
|
|
$pathAndParameters = $this->canonicalPath($pathAndParameters);
|
|
$contentMd5 = $body === '' ? '' : base64_encode(md5($body, true));
|
|
$stringToSign = implode("\n", [
|
|
$method,
|
|
self::ACCEPT,
|
|
$contentMd5,
|
|
self::CONTENT_TYPE,
|
|
'',
|
|
]) . "\n" . $pathAndParameters;
|
|
|
|
return [
|
|
'X-Tsign-Open-App-Id' => $this->appId,
|
|
'X-Tsign-Open-Auth-Mode' => 'Signature',
|
|
'X-Tsign-Open-Ca-Timestamp' => (string) floor(microtime(true) * 1000),
|
|
'X-Tsign-Open-Ca-Signature' => base64_encode(hash_hmac('sha256', $stringToSign, $this->appSecret, true)),
|
|
'Accept' => self::ACCEPT,
|
|
'Content-Type' => self::CONTENT_TYPE,
|
|
'Content-MD5' => $contentMd5,
|
|
];
|
|
}
|
|
|
|
public function canonicalPath(string $pathAndParameters): string
|
|
{
|
|
$parts = parse_url($pathAndParameters);
|
|
$path = (string) ($parts['path'] ?? '');
|
|
|
|
if ($path === '' || ! str_starts_with($path, '/')) {
|
|
throw new InvalidArgumentException('E 签宝 API 路径必须以 / 开头。');
|
|
}
|
|
|
|
if (! isset($parts['query']) || $parts['query'] === '') {
|
|
return $path;
|
|
}
|
|
|
|
$parameters = [];
|
|
|
|
foreach (explode('&', $parts['query']) as $pair) {
|
|
[$key, $value] = array_pad(explode('=', $pair, 2), 2, null);
|
|
|
|
if (! array_key_exists($key, $parameters)) {
|
|
$parameters[$key] = $value;
|
|
}
|
|
}
|
|
|
|
ksort($parameters, SORT_STRING);
|
|
$query = collect($parameters)->map(function (?string $value, string $key): string {
|
|
return $value === null || $value === '' ? $key : $key . '=' . $value;
|
|
})->implode('&');
|
|
|
|
return $path . '?' . $query;
|
|
}
|
|
}
|