feat(upload): 添加华为 OBS 对象存储支持
- 在 addons.php 中添加了与华为 OBS 相关的钩子 - 新增了对华为 OBS 上传功能的实现,包括分片上传和合并 - 优化了上传参数处理和错误处理 - 支持客户端和服务端两种上传模式
This commit is contained in:
199
addons/hwobs/library/Obs/Internal/Signature/V4Signature.php
Normal file
199
addons/hwobs/library/Obs/Internal/Signature/V4Signature.php
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2019 Huawei Technologies Co.,Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of the
|
||||
* License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Obs\Internal\Signature;
|
||||
|
||||
use Obs\Internal\Common\Model;
|
||||
|
||||
class V4Signature extends AbstractSignature
|
||||
{
|
||||
const CONTENT_SHA256 = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
|
||||
|
||||
protected $region;
|
||||
|
||||
protected $utcTimeZone;
|
||||
|
||||
public function __construct($ak, $sk, $pathStyle, $endpoint, $region, $methodName, $signature, $securityToken=false, $isCname=false)
|
||||
{
|
||||
parent::__construct($ak, $sk, $pathStyle, $endpoint, $methodName, $signature, $securityToken, $isCname);
|
||||
$this->region = $region;
|
||||
$this->utcTimeZone = new \DateTimeZone ('UTC');
|
||||
}
|
||||
|
||||
public function doAuth(array &$requestConfig, array &$params, Model $model)
|
||||
{
|
||||
$result = $this -> prepareAuth($requestConfig, $params, $model);
|
||||
|
||||
$result['headers']['x-amz-content-sha256'] = self::CONTENT_SHA256;
|
||||
|
||||
$bucketName = $result['dnsParam'];
|
||||
|
||||
$result['headers']['Host'] = $result['host'];
|
||||
|
||||
$time = null;
|
||||
if(array_key_exists('x-amz-date', $result['headers'])){
|
||||
$time = $result['headers']['x-amz-date'];
|
||||
}else if(array_key_exists('X-Amz-Date', $result['headers'])){
|
||||
$time = $result['headers']['X-Amz-Date'];
|
||||
}
|
||||
$timestamp = $time ? date_create_from_format('Ymd\THis\Z', $time, $this->utcTimeZone) -> getTimestamp()
|
||||
:time();
|
||||
|
||||
$result['headers']['Date'] = gmdate('D, d M Y H:i:s \G\M\T', $timestamp);
|
||||
|
||||
$longDate = gmdate('Ymd\THis\Z', $timestamp);
|
||||
$shortDate = substr($longDate, 0, 8);
|
||||
|
||||
$credential = $this-> getCredential($shortDate);
|
||||
|
||||
$signedHeaders = $this->getSignedHeaders($result['headers']);
|
||||
|
||||
$canonicalstring = $this-> makeCanonicalstring($result['method'], $result['headers'], $result['pathArgs'], $bucketName, $result['uriParam'], $signedHeaders);
|
||||
|
||||
$result['cannonicalRequest'] = $canonicalstring;
|
||||
|
||||
$signature = $this -> getSignature($canonicalstring, $longDate, $shortDate);
|
||||
|
||||
$authorization = 'AWS4-HMAC-SHA256 ' . 'Credential=' . $credential. ',' . 'SignedHeaders=' . $signedHeaders . ',' . 'Signature=' . $signature;
|
||||
|
||||
$result['headers']['Authorization'] = $authorization;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getSignature($canonicalstring, $longDate, $shortDate)
|
||||
{
|
||||
$stringToSign = [];
|
||||
$stringToSign[] = 'AWS4-HMAC-SHA256';
|
||||
|
||||
$stringToSign[] = "\n";
|
||||
|
||||
$stringToSign[] = $longDate;
|
||||
|
||||
$stringToSign[] = "\n";
|
||||
$stringToSign[] = $this -> getScope($shortDate);
|
||||
$stringToSign[] = "\n";
|
||||
|
||||
$stringToSign[] = hash('sha256', $canonicalstring);
|
||||
|
||||
$dateKey = hash_hmac('sha256', $shortDate, 'AWS4' . $this -> sk, true);
|
||||
$regionKey = hash_hmac('sha256', $this->region, $dateKey, true);
|
||||
$serviceKey = hash_hmac('sha256', 's3', $regionKey, true);
|
||||
$signingKey = hash_hmac('sha256', 'aws4_request', $serviceKey, true);
|
||||
$signature = hash_hmac('sha256', implode('', $stringToSign), $signingKey);
|
||||
return $signature;
|
||||
}
|
||||
|
||||
public function getCanonicalQueryString($pathArgs)
|
||||
{
|
||||
$queryStr = '';
|
||||
|
||||
ksort($pathArgs);
|
||||
$index = 0;
|
||||
foreach ($pathArgs as $key => $value){
|
||||
$queryStr .= $key . '=' . $value;
|
||||
if($index++ !== count($pathArgs) - 1){
|
||||
$queryStr .= '&';
|
||||
}
|
||||
}
|
||||
return $queryStr;
|
||||
}
|
||||
|
||||
public function getCanonicalHeaders($headers)
|
||||
{
|
||||
$_headers = [];
|
||||
foreach ($headers as $key => $value) {
|
||||
$_headers[strtolower($key)] = $value;
|
||||
}
|
||||
ksort($_headers);
|
||||
|
||||
$canonicalHeaderStr = '';
|
||||
|
||||
foreach ($_headers as $key => $value){
|
||||
$value = is_array($value) ? implode(',', $value) : $value;
|
||||
$canonicalHeaderStr .= $key . ':' . $value;
|
||||
$canonicalHeaderStr .= "\n";
|
||||
}
|
||||
return $canonicalHeaderStr;
|
||||
}
|
||||
|
||||
public function getCanonicalURI($bucketName, $objectKey)
|
||||
{
|
||||
$uri = '';
|
||||
if($this -> pathStyle && $bucketName){
|
||||
$uri .= '/' . $bucketName;
|
||||
}
|
||||
|
||||
if($objectKey){
|
||||
$uri .= '/' . $objectKey;
|
||||
}
|
||||
|
||||
if($uri === ''){
|
||||
$uri = '/';
|
||||
}
|
||||
return $uri;
|
||||
}
|
||||
|
||||
public function makeCanonicalstring($method, $headers, $pathArgs, $bucketName, $objectKey, $signedHeaders=null, $payload=null)
|
||||
{
|
||||
$buffer = [];
|
||||
$buffer[] = $method;
|
||||
$buffer[] = "\n";
|
||||
$buffer[] = $this->getCanonicalURI($bucketName, $objectKey);
|
||||
$buffer[] = "\n";
|
||||
$buffer[] = $this->getCanonicalQueryString($pathArgs);
|
||||
$buffer[] = "\n";
|
||||
$buffer[] = $this->getCanonicalHeaders($headers);
|
||||
$buffer[] = "\n";
|
||||
$buffer[] = $signedHeaders ? $signedHeaders : $this->getSignedHeaders($headers);
|
||||
$buffer[] = "\n";
|
||||
$buffer[] = $payload ? strval($payload) : self::CONTENT_SHA256;
|
||||
|
||||
return implode('', $buffer);
|
||||
}
|
||||
|
||||
public function getSignedHeaders($headers)
|
||||
{
|
||||
$_headers = [];
|
||||
|
||||
foreach ($headers as $key => $value) {
|
||||
$_headers[] = strtolower($key);
|
||||
}
|
||||
|
||||
sort($_headers);
|
||||
|
||||
$signedHeaders = '';
|
||||
|
||||
foreach ($_headers as $key => $value){
|
||||
$signedHeaders .= $value;
|
||||
if($key !== count($_headers) - 1){
|
||||
$signedHeaders .= ';';
|
||||
}
|
||||
}
|
||||
return $signedHeaders;
|
||||
}
|
||||
|
||||
public function getScope($shortDate)
|
||||
{
|
||||
return $shortDate . '/' . $this->region . '/s3/aws4_request';
|
||||
}
|
||||
|
||||
public function getCredential($shortDate)
|
||||
{
|
||||
return $this->ak . '/' . $this->getScope($shortDate);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user