Skip to content

Commit af38fe3

Browse files
support signature v4
--------- Co-authored-by: yangpeng <[email protected]>
1 parent bb6d2e5 commit af38fe3

35 files changed

+4009
-1210
lines changed

src/OSS/Core/OssUtil.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,4 +531,13 @@ public static function decodeKey($key, $encoding)
531531
throw new OssException("Unrecognized encoding type: " . $encoding);
532532
}
533533
}
534+
535+
public static function unparseUrl($parsed_url) {
536+
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
537+
$host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
538+
$port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
539+
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
540+
$query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
541+
return "$scheme$host$port$path$query";
542+
}
534543
}

src/OSS/OssClient.php

Lines changed: 503 additions & 555 deletions
Large diffs are not rendered by default.

src/OSS/Result/CreateBucketCnameTokenResult.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class CreateBucketCnameTokenResult extends Result
88
{
99
/**
10-
* @return CnameConfig
10+
* @return CnameTokenInfo
1111
*/
1212
protected function parseDataFromResponse()
1313
{

src/OSS/Result/GetBucketInfoResult.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class GetBucketInfoResult extends Result
1616
/**
1717
* Parse data from response
1818
*
19-
* @return string
19+
* @return BucketInfo
2020
* @throws OssException
2121
*/
2222
protected function parseDataFromResponse()

src/OSS/Result/GetLiveChannelHistoryResult.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class GetLiveChannelHistoryResult extends Result
88
{
99
/**
10-
* @return
10+
* @return GetLiveChannelHistory
1111
*/
1212
protected function parseDataFromResponse()
1313
{

src/OSS/Result/GetLiveChannelInfoResult.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class GetLiveChannelInfoResult extends Result
88
{
99
/**
10-
* @return
10+
* @return GetLiveChannelInfo
1111
*/
1212
protected function parseDataFromResponse()
1313
{

src/OSS/Result/ListObjectVersionsResult.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace OSS\Result;
44

5+
use OSS\Core\OssException;
56
use OSS\Core\OssUtil;
67
use OSS\Model\ObjectVersionInfo;
78
use OSS\Model\ObjectVersionListInfo;
@@ -17,11 +18,12 @@ class ListObjectVersionsResult extends Result
1718
/**
1819
* Parse the xml data returned by the ListObjectVersions interface
1920
*
20-
* return ObjectVersionListInfo
21+
* @return ObjectVersionListInfo
22+
* @throws OssException
2123
*/
2224
protected function parseDataFromResponse()
2325
{
24-
$xml = simplexml_load_string($this->rawResponse->body);
26+
$xml = simplexml_load_string($this->rawResponse->body);
2527
$encodingType = isset($xml->EncodingType) ? strval($xml->EncodingType) : "";
2628
$objectVersionList = $this->parseObjecVersionList($xml, $encodingType);
2729
$deleteMarkerList = $this->parseDeleteMarkerList($xml, $encodingType);
@@ -40,8 +42,8 @@ protected function parseDataFromResponse()
4042
$delimiter = OssUtil::decodeKey($delimiter, $encodingType);
4143
$isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : "";
4244

43-
return new ObjectVersionListInfo($bucketName, $prefix, $keyMarker, $nextKeyMarker,
44-
$versionIdMarker, $nextVersionIdMarker,$maxKeys, $delimiter, $isTruncated,
45+
return new ObjectVersionListInfo($bucketName, $prefix, $keyMarker, $nextKeyMarker,
46+
$versionIdMarker, $nextVersionIdMarker, $maxKeys, $delimiter, $isTruncated,
4547
$objectVersionList, $deleteMarkerList, $prefixList);
4648
}
4749

src/OSS/Result/ListObjectsResult.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace OSS\Result;
44

5+
use OSS\Core\OssException;
56
use OSS\Core\OssUtil;
67
use OSS\Model\ObjectInfo;
78
use OSS\Model\ObjectListInfo;
@@ -16,7 +17,8 @@ class ListObjectsResult extends Result
1617
/**
1718
* Parse the xml data returned by the ListObjects interface
1819
*
19-
* return ObjectListInfo
20+
* @return ObjectListInfo
21+
* @throws OssException
2022
*/
2123
protected function parseDataFromResponse()
2224
{

src/OSS/Result/ListObjectsV2Result.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace OSS\Result;
44

5+
use OSS\Core\OssException;
56
use OSS\Core\OssUtil;
67
use OSS\Model\ObjectInfo;
78
use OSS\Model\ObjectListInfoV2;
@@ -16,7 +17,8 @@ class ListObjectsV2Result extends Result
1617
/**
1718
* Parse the xml data returned by the ListObjectsV2 interface
1819
*
19-
* return ObjectListInfoV2
20+
* @return ObjectListInfoV2
21+
* @throws OssException
2022
*/
2123
protected function parseDataFromResponse()
2224
{
@@ -34,7 +36,7 @@ protected function parseDataFromResponse()
3436
$continuationToken = isset($xml->ContinuationToken) ? strval($xml->ContinuationToken) : "";
3537
$nextContinuationToken = isset($xml->NextContinuationToken) ? strval($xml->NextContinuationToken) : "";
3638
$startAfter = isset($xml->StartAfter) ? strval($xml->StartAfter) : "";
37-
$startAfter = OssUtil::decodeKey($startAfter, $encodingType);
39+
$startAfter = OssUtil::decodeKey($startAfter, $encodingType);
3840
$keyCount = isset($xml->KeyCount) ? intval($xml->KeyCount) : 0;
3941
return new ObjectListInfoV2($bucketName, $prefix, $maxKeys, $delimiter, $isTruncated, $objectList, $prefixList, $continuationToken, $nextContinuationToken, $startAfter, $keyCount);
4042
}

src/OSS/Signer/SignerInterface.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
namespace OSS\Signer;
3+
4+
use OSS\Http\RequestCore;
5+
use OSS\Credentials\Credentials;
6+
7+
interface SignerInterface
8+
{
9+
public function sign(RequestCore $request, Credentials $credentials, array &$options);
10+
11+
public function presign(RequestCore $request, Credentials $credentials, array &$options);
12+
}

src/OSS/Signer/SignerV1.php

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<?php
2+
3+
namespace OSS\Signer;
4+
5+
use OSS\Core\OssUtil;
6+
use OSS\Http\RequestCore;
7+
use OSS\Credentials\Credentials;
8+
9+
class SignerV1 implements SignerInterface
10+
{
11+
public function sign(RequestCore $request, Credentials $credentials, array &$options)
12+
{
13+
// Date
14+
if (!isset($request->request_headers['Date'])) {
15+
$request->add_header('Date', gmdate('D, d M Y H:i:s \G\M\T'));
16+
}
17+
// Credentials information
18+
if (strlen($credentials->getSecurityToken()) > 0) {
19+
$request->add_header("x-oss-security-token", $credentials->getSecurityToken());
20+
}
21+
$headers = $request->request_headers;
22+
$method = strtoupper($request->method);
23+
$date = $headers['Date'];
24+
$resourcePath = $this->getResourcePath($options);
25+
$queryString = parse_url($request->request_url, PHP_URL_QUERY);
26+
$query = array();
27+
parse_str($queryString, $query);
28+
$stringToSign = $this->calcStringToSign($method, $date, $headers, $resourcePath, $query);
29+
// printf("sign str:%s" . PHP_EOL, $stringToSign);
30+
$options['string_to_sign'] = $stringToSign;
31+
$signature = base64_encode(hash_hmac('sha1', $stringToSign, $credentials->getAccessKeySecret(), true));
32+
$request->add_header('Authorization', 'OSS ' . $credentials->getAccessKeyId() . ':' . $signature);
33+
}
34+
35+
public function presign(RequestCore $request, Credentials $credentials, array &$options)
36+
{
37+
$headers = $request->request_headers;
38+
// Date
39+
$expiration = $options['expiration'];
40+
if (!isset($request->request_headers['Date'])) {
41+
$request->add_header('Date', gmdate('D, d M Y H:i:s \G\M\T'));
42+
}
43+
$parsed_url = parse_url($request->request_url);
44+
$queryString = isset($parsed_url['query']) ? $parsed_url['query'] : '';
45+
$query = array();
46+
parse_str($queryString, $query);
47+
// Credentials information
48+
if (strlen($credentials->getSecurityToken()) > 0) {
49+
$query["security-token"] = $credentials->getSecurityToken();
50+
}
51+
$method = strtoupper($request->method);
52+
$date = $expiration . "";
53+
$resourcePath = $this->getResourcePath($options);
54+
$stringToSign = $this->calcStringToSign($method, $date, $headers, $resourcePath, $query);
55+
$options['string_to_sign'] = $stringToSign;
56+
$signature = base64_encode(hash_hmac('sha1', $stringToSign, $credentials->getAccessKeySecret(), true));
57+
$query['OSSAccessKeyId'] = $credentials->getAccessKeyId();
58+
$query['Expires'] = $date;
59+
$query['Signature'] = $signature;
60+
$queryString = OssUtil::toQueryString($query);
61+
$parsed_url['query'] = $queryString;
62+
$request->request_url = OssUtil::unparseUrl($parsed_url);
63+
}
64+
65+
private function getResourcePath(array $options)
66+
{
67+
$resourcePath = '/';
68+
if (strlen($options['bucket']) > 0) {
69+
$resourcePath .= $options['bucket'] . '/';
70+
}
71+
if (strlen($options['key']) > 0) {
72+
$resourcePath .= $options['key'];
73+
}
74+
return $resourcePath;
75+
}
76+
77+
private function calcStringToSign($method, $date, array $headers, $resourcePath, array $query)
78+
{
79+
/*
80+
SignToString =
81+
VERB + "\n"
82+
+ Content-MD5 + "\n"
83+
+ Content-Type + "\n"
84+
+ Date + "\n"
85+
+ CanonicalizedOSSHeaders
86+
+ CanonicalizedResource
87+
Signature = base64(hmac-sha1(AccessKeySecret, SignToString))
88+
*/
89+
$contentMd5 = '';
90+
$contentType = '';
91+
// CanonicalizedOSSHeaders
92+
$signheaders = array();
93+
foreach ($headers as $key => $value) {
94+
$lowk = strtolower($key);
95+
if (strncmp($lowk, "x-oss-", 6) == 0) {
96+
$signheaders[$lowk] = $value;
97+
} else if ($lowk === 'content-md5') {
98+
$contentMd5 = $value;
99+
} else if ($lowk === 'content-type') {
100+
$contentType = $value;
101+
}
102+
}
103+
ksort($signheaders);
104+
$canonicalizedOSSHeaders = '';
105+
foreach ($signheaders as $key => $value) {
106+
$canonicalizedOSSHeaders .= $key . ':' . $value . "\n";
107+
}
108+
// CanonicalizedResource
109+
$signquery = array();
110+
foreach ($query as $key => $value) {
111+
if (in_array($key, $this->signKeyList)) {
112+
$signquery[$key] = $value;
113+
}
114+
}
115+
ksort($signquery);
116+
$sortedQueryList = array();
117+
foreach ($signquery as $key => $value) {
118+
if (strlen($value) > 0) {
119+
$sortedQueryList[] = $key . '=' . $value;
120+
} else {
121+
$sortedQueryList[] = $key;
122+
}
123+
}
124+
$queryStringSorted = implode('&', $sortedQueryList);
125+
$canonicalizedResource = $resourcePath;
126+
if (!empty($queryStringSorted)) {
127+
$canonicalizedResource .= '?' . $queryStringSorted;
128+
}
129+
return $method . "\n" . $contentMd5 . "\n" . $contentType . "\n" . $date . "\n" . $canonicalizedOSSHeaders . $canonicalizedResource;
130+
}
131+
132+
private $signKeyList = array(
133+
"acl", "uploads", "location", "cors",
134+
"logging", "website", "referer", "lifecycle",
135+
"delete", "append", "tagging", "objectMeta",
136+
"uploadId", "partNumber", "security-token", "x-oss-security-token",
137+
"position", "img", "style", "styleName",
138+
"replication", "replicationProgress",
139+
"replicationLocation", "cname", "bucketInfo",
140+
"comp", "qos", "live", "status", "vod",
141+
"startTime", "endTime", "symlink",
142+
"x-oss-process", "response-content-type", "x-oss-traffic-limit",
143+
"response-content-language", "response-expires",
144+
"response-cache-control", "response-content-disposition",
145+
"response-content-encoding", "udf", "udfName", "udfImage",
146+
"udfId", "udfImageDesc", "udfApplication",
147+
"udfApplicationLog", "restore", "callback", "callback-var", "qosInfo",
148+
"policy", "stat", "encryption", "versions", "versioning", "versionId", "requestPayment",
149+
"x-oss-request-payer", "sequential",
150+
"inventory", "inventoryId", "continuation-token", "asyncFetch",
151+
"worm", "wormId", "wormExtend", "withHashContext",
152+
"x-oss-enable-md5", "x-oss-enable-sha1", "x-oss-enable-sha256",
153+
"x-oss-hash-ctx", "x-oss-md5-ctx", "transferAcceleration",
154+
"regionList", "cloudboxes", "x-oss-ac-source-ip", "x-oss-ac-subnet-mask", "x-oss-ac-vpc-id", "x-oss-ac-forward-allow",
155+
"metaQuery", "resourceGroup", "rtc", "x-oss-async-process", "responseHeader"
156+
);
157+
}

0 commit comments

Comments
 (0)