AipSampleSigner.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <?php
  2. namespace addons\blog\library\aip\lib;
  3. class AipSampleSigner
  4. {
  5. const BCE_AUTH_VERSION = "bce-auth-v1";
  6. const BCE_PREFIX = 'x-bce-';
  7. //不指定headersToSign情况下,默认签名http头,包括:
  8. // 1.host
  9. // 2.content-length
  10. // 3.content-type
  11. // 4.content-md5
  12. public static $defaultHeadersToSign;
  13. public static function __init()
  14. {
  15. AipSampleSigner::$defaultHeadersToSign = array(
  16. "host",
  17. "content-length",
  18. "content-type",
  19. "content-md5",
  20. );
  21. }
  22. /**
  23. * 签名
  24. * @param array $credentials
  25. * @param string $httpMethod
  26. * @param string $path
  27. * @param array $headers
  28. * @param string $params
  29. * @param array $options
  30. * @return string
  31. */
  32. public static function sign(
  33. array $credentials,
  34. $httpMethod,
  35. $path,
  36. $headers,
  37. $params,
  38. $options = array()
  39. )
  40. {
  41. //设定签名有效时间
  42. if (!isset($options[AipSignOption::EXPIRATION_IN_SECONDS])) {
  43. //默认值1800秒
  44. $expirationInSeconds = AipSignOption::DEFAULT_EXPIRATION_IN_SECONDS;
  45. } else {
  46. $expirationInSeconds = $options[AipSignOption::EXPIRATION_IN_SECONDS];
  47. }
  48. //解析ak sk
  49. $accessKeyId = $credentials['ak'];
  50. $secretAccessKey = $credentials['sk'];
  51. //设定时间戳,注意:如果自行指定时间戳需要为UTC时间
  52. if (!isset($options[AipSignOption::TIMESTAMP])) {
  53. //默认值当前时间
  54. $timestamp = gmdate('Y-m-d\TH:i:s\Z');
  55. } else {
  56. $timestamp = $options[AipSignOption::TIMESTAMP];
  57. }
  58. //生成authString
  59. $authString = AipSampleSigner::BCE_AUTH_VERSION . '/' . $accessKeyId . '/'
  60. . $timestamp . '/' . $expirationInSeconds;
  61. //使用sk和authString生成signKey
  62. $signingKey = hash_hmac('sha256', $authString, $secretAccessKey);
  63. //生成标准化URI
  64. $canonicalURI = AipHttpUtil::getCanonicalURIPath($path);
  65. //生成标准化QueryString
  66. $canonicalQueryString = AipHttpUtil::getCanonicalQueryString($params);
  67. //填充headersToSign,也就是指明哪些header参与签名
  68. $headersToSign = null;
  69. if (isset($options[AipSignOption::HEADERS_TO_SIGN])) {
  70. $headersToSign = $options[AipSignOption::HEADERS_TO_SIGN];
  71. }
  72. //生成标准化header
  73. $canonicalHeader = AipHttpUtil::getCanonicalHeaders(
  74. AipSampleSigner::getHeadersToSign($headers, $headersToSign)
  75. );
  76. //整理headersToSign,以';'号连接
  77. $signedHeaders = '';
  78. if ($headersToSign !== null) {
  79. $signedHeaders = strtolower(
  80. trim(implode(";", $headersToSign))
  81. );
  82. }
  83. //组成标准请求串
  84. $canonicalRequest = "$httpMethod\n$canonicalURI\n"
  85. . "$canonicalQueryString\n$canonicalHeader";
  86. //使用signKey和标准请求串完成签名
  87. $signature = hash_hmac('sha256', $canonicalRequest, $signingKey);
  88. //组成最终签名串
  89. $authorizationHeader = "$authString/$signedHeaders/$signature";
  90. return $authorizationHeader;
  91. }
  92. /**
  93. * 根据headsToSign过滤应该参与签名的header
  94. * @param array $headers
  95. * @param array $headersToSign
  96. * @return array
  97. */
  98. public static function getHeadersToSign($headers, $headersToSign)
  99. {
  100. //value被trim后为空串的header不参与签名
  101. $filter_empty = function ($v) {
  102. return trim((string)$v) !== '';
  103. };
  104. $headers = array_filter($headers, $filter_empty);
  105. //处理headers的key:去掉前后的空白并转化成小写
  106. $trim_and_lower = function ($str) {
  107. return strtolower(trim($str));
  108. };
  109. $temp = array();
  110. $process_keys = function ($k, $v) use (&$temp, $trim_and_lower) {
  111. $temp[$trim_and_lower($k)] = $v;
  112. };
  113. array_map($process_keys, array_keys($headers), $headers);
  114. $headers = $temp;
  115. //取出headers的key以备用
  116. $header_keys = array_keys($headers);
  117. $filtered_keys = null;
  118. if ($headersToSign !== null) {
  119. //如果有headersToSign,则根据headersToSign过滤
  120. //预处理headersToSign:去掉前后的空白并转化成小写
  121. $headersToSign = array_map($trim_and_lower, $headersToSign);
  122. //只选取在headersToSign里面的header
  123. $filtered_keys = array_intersect_key($header_keys, $headersToSign);
  124. } else {
  125. //如果没有headersToSign,则根据默认规则来选取headers
  126. $filter_by_default = function ($k) {
  127. return AipSampleSigner::isDefaultHeaderToSign($k);
  128. };
  129. $filtered_keys = array_filter($header_keys, $filter_by_default);
  130. }
  131. //返回需要参与签名的header
  132. return array_intersect_key($headers, array_flip($filtered_keys));
  133. }
  134. /**
  135. * 检查header是不是默认参加签名的:
  136. * 1.是host、content-type、content-md5、content-length之一
  137. * 2.以x-bce开头
  138. * @param array $header
  139. * @return boolean
  140. */
  141. public static function isDefaultHeaderToSign($header)
  142. {
  143. $header = strtolower(trim($header));
  144. if (in_array($header, AipSampleSigner::$defaultHeadersToSign)) {
  145. return true;
  146. }
  147. return substr_compare($header, AipSampleSigner::BCE_PREFIX, 0, strlen(AipSampleSigner::BCE_PREFIX)) == 0;
  148. }
  149. }
  150. AipSampleSigner::__init();