提交的内容

This commit is contained in:
2025-05-12 15:45:02 +08:00
parent 629c4750da
commit b48c692775
3043 changed files with 34732 additions and 60810 deletions

View File

@ -0,0 +1,12 @@
<?php
namespace OSS\Signer;
use OSS\Http\RequestCore;
use OSS\Credentials\Credentials;
interface SignerInterface
{
public function sign(RequestCore $request, Credentials $credentials, array &$options);
public function presign(RequestCore $request, Credentials $credentials, array &$options);
}

View File

@ -0,0 +1,161 @@
<?php
namespace OSS\Signer;
use OSS\Core\OssUtil;
use OSS\Http\RequestCore;
use OSS\Credentials\Credentials;
class SignerV1 implements SignerInterface
{
public function sign(RequestCore $request, Credentials $credentials, array &$options)
{
// Date
if (!isset($request->request_headers['Date'])) {
$request->add_header('Date', gmdate('D, d M Y H:i:s \G\M\T'));
}
// Credentials information
if (!empty($credentials->getSecurityToken())) {
$request->add_header("x-oss-security-token", $credentials->getSecurityToken());
}
$headers = $request->request_headers;
$method = strtoupper($request->method);
$date = $headers['Date'];
$resourcePath = $this->getResourcePath($options);
$queryString = parse_url($request->request_url, PHP_URL_QUERY);
$query = array();
if ($queryString !== null) {
parse_str($queryString, $query);
}
$stringToSign = $this->calcStringToSign($method, $date, $headers, $resourcePath, $query);
// printf("sign str:%s" . PHP_EOL, $stringToSign);
$options['string_to_sign'] = $stringToSign;
$signature = base64_encode(hash_hmac('sha1', $stringToSign, $credentials->getAccessKeySecret(), true));
$request->add_header('Authorization', 'OSS ' . $credentials->getAccessKeyId() . ':' . $signature);
}
public function presign(RequestCore $request, Credentials $credentials, array &$options)
{
$headers = $request->request_headers;
// Date
$expiration = $options['expiration'];
if (!isset($request->request_headers['Date'])) {
$request->add_header('Date', gmdate('D, d M Y H:i:s \G\M\T'));
}
$parsed_url = parse_url($request->request_url);
$queryString = isset($parsed_url['query']) ? $parsed_url['query'] : '';
$query = array();
if ($queryString !== null) {
parse_str($queryString, $query);
}
// Credentials information
if (!empty($credentials->getSecurityToken())) {
$query["security-token"] = $credentials->getSecurityToken();
}
$method = strtoupper($request->method);
$date = $expiration . "";
$resourcePath = $this->getResourcePath($options);
$stringToSign = $this->calcStringToSign($method, $date, $headers, $resourcePath, $query);
$options['string_to_sign'] = $stringToSign;
$signature = base64_encode(hash_hmac('sha1', $stringToSign, $credentials->getAccessKeySecret(), true));
$query['OSSAccessKeyId'] = $credentials->getAccessKeyId();
$query['Expires'] = $date;
$query['Signature'] = $signature;
$queryString = OssUtil::toQueryString($query);
$parsed_url['query'] = $queryString;
$request->request_url = OssUtil::unparseUrl($parsed_url);
}
private function getResourcePath(array $options)
{
$resourcePath = '/';
if (strlen($options['bucket']) > 0) {
$resourcePath .= $options['bucket'] . '/';
}
if (strlen($options['key']) > 0) {
$resourcePath .= $options['key'];
}
return $resourcePath;
}
private function calcStringToSign($method, $date, array $headers, $resourcePath, array $query)
{
/*
SignToString =
VERB + "\n"
+ Content-MD5 + "\n"
+ Content-Type + "\n"
+ Date + "\n"
+ CanonicalizedOSSHeaders
+ CanonicalizedResource
Signature = base64(hmac-sha1(AccessKeySecret, SignToString))
*/
$contentMd5 = '';
$contentType = '';
// CanonicalizedOSSHeaders
$signheaders = array();
foreach ($headers as $key => $value) {
$lowk = strtolower($key);
if (strncmp($lowk, "x-oss-", 6) == 0) {
$signheaders[$lowk] = $value;
} else if ($lowk === 'content-md5') {
$contentMd5 = $value;
} else if ($lowk === 'content-type') {
$contentType = $value;
}
}
ksort($signheaders);
$canonicalizedOSSHeaders = '';
foreach ($signheaders as $key => $value) {
$canonicalizedOSSHeaders .= $key . ':' . $value . "\n";
}
// CanonicalizedResource
$signquery = array();
foreach ($query as $key => $value) {
if (in_array($key, $this->signKeyList)) {
$signquery[$key] = $value;
}
}
ksort($signquery);
$sortedQueryList = array();
foreach ($signquery as $key => $value) {
if (strlen($value) > 0) {
$sortedQueryList[] = $key . '=' . $value;
} else {
$sortedQueryList[] = $key;
}
}
$queryStringSorted = implode('&', $sortedQueryList);
$canonicalizedResource = $resourcePath;
if (!empty($queryStringSorted)) {
$canonicalizedResource .= '?' . $queryStringSorted;
}
return $method . "\n" . $contentMd5 . "\n" . $contentType . "\n" . $date . "\n" . $canonicalizedOSSHeaders . $canonicalizedResource;
}
private $signKeyList = array(
"acl", "uploads", "location", "cors",
"logging", "website", "referer", "lifecycle",
"delete", "append", "tagging", "objectMeta",
"uploadId", "partNumber", "security-token", "x-oss-security-token",
"position", "img", "style", "styleName",
"replication", "replicationProgress",
"replicationLocation", "cname", "bucketInfo",
"comp", "qos", "live", "status", "vod",
"startTime", "endTime", "symlink",
"x-oss-process", "response-content-type", "x-oss-traffic-limit",
"response-content-language", "response-expires",
"response-cache-control", "response-content-disposition",
"response-content-encoding", "udf", "udfName", "udfImage",
"udfId", "udfImageDesc", "udfApplication",
"udfApplicationLog", "restore", "callback", "callback-var", "qosInfo",
"policy", "stat", "encryption", "versions", "versioning", "versionId", "requestPayment",
"x-oss-request-payer", "sequential",
"inventory", "inventoryId", "continuation-token", "asyncFetch",
"worm", "wormId", "wormExtend", "withHashContext",
"x-oss-enable-md5", "x-oss-enable-sha1", "x-oss-enable-sha256",
"x-oss-hash-ctx", "x-oss-md5-ctx", "transferAcceleration",
"regionList", "cloudboxes", "x-oss-ac-source-ip", "x-oss-ac-subnet-mask", "x-oss-ac-vpc-id", "x-oss-ac-forward-allow",
"metaQuery", "resourceGroup", "rtc", "x-oss-async-process", "responseHeader"
);
}

View File

@ -0,0 +1,244 @@
<?php
namespace OSS\Signer;
use DateTime;
use OSS\Core\OssUtil;
use OSS\Http\RequestCore;
use OSS\Credentials\Credentials;
use OSS\OssClient;
class SignerV4 implements SignerInterface
{
public function sign(RequestCore $request, Credentials $credentials, array &$options)
{
// Date
if (!isset($request->request_headers['Date'])) {
$request->add_header('Date', gmdate('D, d M Y H:i:s \G\M\T'));
}
$timestamp = strtotime($request->request_headers['Date']);
if ($timestamp === false) {
$timestamp = time();
}
$datetime = gmdate('Ymd\THis\Z', $timestamp);
$date = substr($datetime, 0, 8);
$request->add_header("x-oss-date", $datetime);
if (!isset($request->request_headers['x-oss-content-sha256'])) {
$request->add_header("x-oss-content-sha256", 'UNSIGNED-PAYLOAD');
}
// Credentials information
if (!empty($credentials->getSecurityToken())) {
$request->add_header("x-oss-security-token", $credentials->getSecurityToken());
}
$headers = $request->request_headers;
$method = strtoupper($request->method);
$region = $options['region'];
$product = $options['product'];
$scope = $this->buildScope($date, $region, $product);
$resourcePath = $this->getResourcePath($options);
$additionalHeaders = $this->getCommonAdditionalHeaders($request, $options);
$queryString = parse_url($request->request_url, PHP_URL_QUERY);
$query = array();
if ($queryString !== null) {
parse_str($queryString, $query);
}
$canonicalRequest = $this->calcCanonicalRequest($method, $resourcePath, $query, $headers, $additionalHeaders);
$stringToSign = $this->calcStringToSign($datetime, $scope, $canonicalRequest);
// printf('canonical request:%s' . PHP_EOL, $canonicalRequest);
// printf('sign str:%s' . PHP_EOL, $stringToSign);
$options['string_to_sign'] = $stringToSign;
$signature = $this->calcSignature($credentials->getAccessKeySecret(), $date, $region, $product, $stringToSign);
$authorization = 'OSS4-HMAC-SHA256 Credential=' . $credentials->getAccessKeyId() . '/' . $scope;
$additionalHeadersString = implode(';', $additionalHeaders);
if ($additionalHeadersString !== '') {
$authorization .= ',AdditionalHeaders=' . $additionalHeadersString;
}
$authorization .= ',Signature=' . $signature;
$request->add_header('Authorization', $authorization);
}
public function presign(RequestCore $request, Credentials $credentials, array &$options)
{
if (!isset($request->request_headers['Date'])) {
$request->add_header('Date', gmdate('D, d M Y H:i:s \G\M\T'));
}
$timestamp = strtotime($request->request_headers['Date']);
if ($timestamp === false) {
$timestamp = time();
}
$datetime = gmdate('Ymd\THis\Z', $timestamp);
$expiration = $options['expiration'];
$date = substr($datetime, 0, 8);
$expires = $expiration - $timestamp;
$headers = $request->request_headers;
$method = strtoupper($request->method);
$region = $options['region'];
$product = $options['product'];
$scope = $this->buildScope($date, $region, $product);
$resourcePath = $this->getResourcePath($options);
$additionalHeaders = $this->getCommonAdditionalHeaders($request, $options);
$queryString = parse_url($request->request_url, PHP_URL_QUERY);
$query = array();
if ($queryString !== null) {
parse_str($queryString, $query);
}
if (!empty($credentials->getSecurityToken())) {
$query["x-oss-security-token"] = $credentials->getSecurityToken();
}
$query["x-oss-signature-version"] = 'OSS4-HMAC-SHA256';
$query["x-oss-date"] = $datetime;
$query["x-oss-expires"] = $expires;
$query["x-oss-credential"] = $credentials->getAccessKeyId() . '/' . $scope;
if (count($additionalHeaders) > 0) {
$query["x-oss-additional-headers"] = implode(";", $additionalHeaders);
}
$canonicalRequest = $this->calcCanonicalRequest($method, $resourcePath, $query, $headers, $additionalHeaders);
$stringToSign = $this->calcStringToSign($datetime, $scope, $canonicalRequest);
// printf('canonical request:%s' . PHP_EOL, $canonicalRequest);
// printf('sign str:%s' . PHP_EOL, $stringToSign);
$options['string_to_sign'] = $stringToSign;
$signature = $this->calcSignature($credentials->getAccessKeySecret(), $date, $region, $product, $stringToSign);
$query["x-oss-signature"] = $signature;
$queryStr = OssUtil::toQueryString($query);
$explodeUrl = explode('?', $request->request_url);
$index = count($explodeUrl);
if ($index === 1) {
$request->request_url .= '?' . $queryStr;
} else {
$baseUrl = $explodeUrl[0];
$request->request_url = $baseUrl . '?' . $queryStr;
}
}
private function getResourcePath(array $options)
{
$resourcePath = '/';
if (strlen($options['bucket']) > 0) {
$resourcePath .= $options['bucket'] . '/';
}
if (strlen($options['key']) > 0) {
$resourcePath .= $options['key'];
}
return $resourcePath;
}
private function getCommonAdditionalHeaders(RequestCore $request, array $options)
{
if (isset($options[OssClient::OSS_ADDITIONAL_HEADERS])) {
$addHeaders = array();
foreach ($options[OssClient::OSS_ADDITIONAL_HEADERS] as $key) {
$lowk = strtolower($key);
if ($this->isDefaultSignedHeader($lowk)) {
continue;
}
$addHeaders[$lowk] = '';
}
$headers = array();
foreach ($request->request_headers as $key => $value) {
$lowk = strtolower($key);
if (isset($addHeaders[$lowk])) {
$headers[$lowk] = '';
}
}
ksort($headers);
return array_keys($headers);
}
return array();
}
private function isDefaultSignedHeader($low)
{
if (strncmp($low, "x-oss-", 6) == 0 ||
$low === "content-type" ||
$low === "content-md5") {
return true;
}
return false;
}
private function calcStringToSign($datetime, $scope, $canonicalRequest)
{
/*
StringToSign
"OSS4-HMAC-SHA256" + "\n" +
TimeStamp + "\n" +
Scope + "\n" +
Hex(SHA256Hash(Canonical Request))
*/
$hashedRequest = hash('sha256', $canonicalRequest);
return "OSS4-HMAC-SHA256" . "\n" . $datetime . "\n" . $scope . "\n" . $hashedRequest;
}
private function calcCanonicalRequest($method, $resourcePath, array $query, array $headers, array $additionalHeaders)
{
/*
Canonical Request
HTTP Verb + "\n" +
Canonical URI + "\n" +
Canonical Query String + "\n" +
Canonical Headers + "\n" +
Additional Headers + "\n" +
Hashed PayLoad
*/
//Canonical Uri
$canonicalUri = str_replace(array('%2F'), array('/'), rawurlencode($resourcePath));
//Canonical Query
$querySigned = array();
foreach ($query as $key => $value) {
$querySigned[rawurlencode($key)] = rawurlencode($value);
}
ksort($querySigned);
$sortedQueryList = array();
foreach ($querySigned as $key => $value) {
if (strlen($value) > 0) {
$sortedQueryList[] = $key . '=' . $value;
} else {
$sortedQueryList[] = $key;
}
}
$canonicalQuery = implode('&', $sortedQueryList);
//Canonical Headers
$headersSigned = array();
foreach ($headers as $key => $value) {
$lowk = strtolower($key);
if (SignerV4::isDefaultSignedHeader($lowk) ||
in_array($lowk, $additionalHeaders)) {
$headersSigned[$lowk] = trim($value);
}
}
ksort($headersSigned);
$canonicalizedHeaders = '';
foreach ($headersSigned as $key => $value) {
$canonicalizedHeaders .= $key . ':' . $value . "\n";
}
//Additional Headers
$canonicalAdditionalHeaders = implode(';', $additionalHeaders);
$hashPayload = "UNSIGNED-PAYLOAD";
if (isset($headersSigned['x-oss-content-sha256'])) {
$hashPayload = $headersSigned['x-oss-content-sha256'];
}
$stringToSign = $method . "\n"
. $canonicalUri . "\n"
. $canonicalQuery . "\n"
. $canonicalizedHeaders . "\n"
. $canonicalAdditionalHeaders . "\n"
. $hashPayload;
return $stringToSign;
}
private function buildScope($date, $region, $product)
{
return $date . "/" . $region . "/" . $product . "/aliyun_v4_request";
}
private function calcSignature($secret, $date, $region, $product, $stringToSign)
{
$h1Key = hash_hmac("sha256", $date, "aliyun_v4" . $secret, true);
$h2Key = hash_hmac("sha256", $region, $h1Key, true);
$h3Key = hash_hmac("sha256", $product, $h2Key, true);
$h4Key = hash_hmac("sha256", "aliyun_v4_request", $h3Key, true);
return bin2hex(hash_hmac("sha256", $stringToSign, $h4Key, true));
}
}