$v) { //跳过Authorization字段 if (strcasecmp('Authorization', $k) == 0) { continue; } if (!isset($k)) { throw new \InvalidArgumentException( "parameter key should not be null" ); } if (isset($v)) { //对于有值的,编码后放在=号两边 $parameterStrings[] = HttpUtil::urlEncode($k) . '=' . HttpUtil::urlEncode((string) $v); } else { //对于没有值的,只将key编码后放在=号的左边,右边留空 $parameterStrings[] = HttpUtil::urlEncode($k) . '='; } } //按照字典序排序 sort($parameterStrings); //使用'&'符号连接它们 return implode('&', $parameterStrings); } //生成标准化uri public static function getCanonicalURIPath($path) { //空路径设置为'/' if (empty($path)) { return '/'; } else { //所有的uri必须以'/'开头 if ($path[0] == '/') { return HttpUtil::urlEncodeExceptSlash($path); } else { return '/' . HttpUtil::urlEncodeExceptSlash($path); } } } //生成标准化http请求头串 public static function getCanonicalHeaders($headers) { //如果没有headers,则返回空串 if (count($headers) == 0) { return ''; } $headerStrings = array(); foreach ($headers as $k => $v) { //跳过key为null的 if ($k === null) { continue; } //如果value为null,则赋值为空串 if ($v === null) { $v = ''; } //trim后再encode,之后使用':'号连接起来 $headerStrings[] = HttpUtil::urlEncode(strtolower(trim($k))) . ':' . HttpUtil::urlEncode(trim($v)); } //字典序排序 sort($headerStrings); //用'\n'把它们连接起来 return implode("\n", $headerStrings); } } HttpUtil::__init(); class SampleSigner { const BCE_AUTH_VERSION = "bce-auth-v1"; const BCE_PREFIX = 'x-bce-'; //不指定headersToSign情况下,默认签名http头,包括: // 1.host // 2.content-length // 3.content-type // 4.content-md5 public static $defaultHeadersToSign; public static function __init() { SampleSigner::$defaultHeadersToSign = array( "host", "content-length", "content-type", "content-md5", ); } //签名函数 public function sign( array $credentials, $httpMethod, $path, $headers, $params, $options = array() ) { //设定签名有效时间 if (!isset($options[SignOption::EXPIRATION_IN_SECONDS])) { //默认值1800秒 $expirationInSeconds = SignOption::DEFAULT_EXPIRATION_IN_SECONDS; } else { $expirationInSeconds = $options[SignOption::EXPIRATION_IN_SECONDS]; } //解析ak sk $accessKeyId = $credentials['ak']; $secretAccessKey = $credentials['sk']; //设定时间戳,注意:如果自行指定时间戳需要为UTC时间 if (!isset($options[SignOption::TIMESTAMP])) { //默认值当前时间 $timestamp = new \DateTime(); } else { $timestamp = $options[SignOption::TIMESTAMP]; } $timestamp->setTimezone(new \DateTimeZone("UTC")); //生成authString $authString = SampleSigner::BCE_AUTH_VERSION . '/' . $accessKeyId . '/' . $timestamp->format("Y-m-d\TH:i:s\Z") . '/' . $expirationInSeconds; //使用sk和authString生成signKey $signingKey = hash_hmac('sha256', $authString, $secretAccessKey); //生成标准化URI $canonicalURI = HttpUtil::getCanonicalURIPath($path); //生成标准化QueryString $canonicalQueryString = HttpUtil::getCanonicalQueryString($params); //填充headersToSign,也就是指明哪些header参与签名 $headersToSignOption = null; if (isset($options[SignOption::HEADERS_TO_SIGN])) { $headersToSignOption = $options[SignOption::HEADERS_TO_SIGN]; } $headersToSign = SampleSigner::getHeadersToSign($headers, $headersToSignOption); //生成标准化header $canonicalHeader = HttpUtil::getCanonicalHeaders($headersToSign); $headersToSign = array_keys($headersToSign); sort($headersToSign); //整理headersToSign,以';'号连接 $signedHeaders = ''; if ($headersToSignOption !== null) { $signedHeaders = strtolower( trim(implode(";", $headersToSign)) ); } //组成标准请求串 $canonicalRequest = "$httpMethod\n$canonicalURI\n" . "$canonicalQueryString\n$canonicalHeader"; //使用signKey和标准请求串完成签名 $signature = hash_hmac('sha256', $canonicalRequest, $signingKey); //组成最终签名串 $authorizationHeader = "$authString/$signedHeaders/$signature"; return $authorizationHeader; } /** 根据headsToSign过滤应该参与签名的header * * @param $headers array * @param $headersToSign array * @return array */ public static function getHeadersToSign($headers, $headersToSign) { $ret = array(); if ($headersToSign !== null) { $tmp = array(); //处理headers的key:去掉前后的空白并转化成小写 foreach ($headersToSign as $header) { $tmp[] = strtolower(trim($header)); } $headersToSign = $tmp; } foreach ($headers as $k => $v) { if (trim((string) $v) !== '') { if ($headersToSign !== null) { //预处理headersToSign:去掉前后的空白并转化成小写 if (in_array(strtolower(trim($k)), $headersToSign)) { $ret[$k] = $v; } } else { //如果没有headersToSign,则根据默认规则来选取headers if (SampleSigner::isDefaultHeaderToSign($k, $headersToSign)) { $ret[$k] = $v; } } } } return $ret; } /** * 检查header是不是默认参加签名的: * 1.是host、content-type、content-md5、content-length之一 * 2.以x-bce开头 * * @param $header string * @return bool */ public static function isDefaultHeaderToSign($header) { $header = strtolower(trim($header)); if (in_array($header, SampleSigner::$defaultHeadersToSign)) { return true; } $prefix = substr($header, 0, strlen(SampleSigner::BCE_PREFIX)); if ($prefix === SampleSigner::BCE_PREFIX) { return true; } else { return false; } } } SampleSigner::__init();