Signature.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <?php
  2. /**
  3. * +----------------------------------------------------------------------
  4. * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  5. * +----------------------------------------------------------------------
  6. * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
  7. * +----------------------------------------------------------------------
  8. * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  9. * +----------------------------------------------------------------------
  10. * | Author: CRMEB Team <admin@crmeb.com>
  11. * +----------------------------------------------------------------------
  12. */
  13. namespace crmeb\services\upload\extend\cos;
  14. /**
  15. * Class 生成签名
  16. * @author 等风来
  17. * @email 136327134@qq.com
  18. * @date 2022/9/26
  19. * @package crmeb\services\upload\extend\cos
  20. */
  21. class Signature
  22. {
  23. /**
  24. * @var string
  25. */
  26. private $accessKey;
  27. /**
  28. * @var string
  29. */
  30. private $secretKey;
  31. /**
  32. * @var array
  33. */
  34. private $options;
  35. /**
  36. * Signature constructor.
  37. * @param string $accessKey
  38. * @param string $secretKey
  39. * @param array $options
  40. * @param string $token
  41. */
  42. public function __construct(string $accessKey, string $secretKey, array $options = [], string $token = '')
  43. {
  44. $this->accessKey = $accessKey;
  45. $this->secretKey = $secretKey;
  46. $this->options = $options;
  47. $this->token = $token;
  48. $this->signHeader = [
  49. 'cache-control',
  50. 'content-disposition',
  51. 'content-encoding',
  52. 'content-length',
  53. 'content-md5',
  54. 'content-type',
  55. 'expect',
  56. 'expires',
  57. 'host',
  58. 'if-match',
  59. 'if-modified-since',
  60. 'if-none-match',
  61. 'if-unmodified-since',
  62. 'origin',
  63. 'range',
  64. 'response-cache-control',
  65. 'response-content-disposition',
  66. 'response-content-encoding',
  67. 'response-content-language',
  68. 'response-content-type',
  69. 'response-expires',
  70. 'transfer-encoding',
  71. 'versionid',
  72. ];
  73. date_default_timezone_set('PRC');
  74. }
  75. public function needCheckHeader($header)
  76. {
  77. if ($this->startWith($header, 'x-cos-')) {
  78. return true;
  79. }
  80. if (in_array($header, $this->signHeader)) {
  81. return true;
  82. }
  83. return false;
  84. }
  85. /**
  86. * @author 等风来
  87. * @email 136327134@qq.com
  88. * @date 2022/9/29
  89. * @param $haystack
  90. * @param $needle
  91. * @return bool
  92. */
  93. protected function startWith($haystack, $needle)
  94. {
  95. $length = strlen($needle);
  96. if ($length == 0) {
  97. return true;
  98. }
  99. return (substr($haystack, 0, $length) === $needle);
  100. }
  101. /**
  102. * @param string $method
  103. * @param string $urlPath
  104. * @param array $querys
  105. * @param array $headers
  106. * @return string[]
  107. * @author 等风来
  108. * @email 136327134@qq.com
  109. * @date 2022/9/26
  110. */
  111. public function signRequest(string $method, string $urlPath, array $querys = [], array $headers = [])
  112. {
  113. $authorization = $this->createAuthorization($method, $urlPath, $querys, $headers);
  114. return ['Authorization' => $authorization];
  115. }
  116. /**
  117. * @param string $method
  118. * @param string $urlPath
  119. * @param array $querys
  120. * @param array $headers
  121. * @param string $expires
  122. * @return string
  123. * @author 等风来
  124. * @email 136327134@qq.com
  125. * @date 2022/9/26
  126. */
  127. public function createAuthorization(string $method, string $urlPath, array $querys = [], array $headers = [], $expires = '+30 minutes')
  128. {
  129. if (is_null($expires) || !strtotime($expires)) {
  130. $expires = '+30 minutes';
  131. }
  132. $signTime = ( string )(time() - 60) . ';' . ( string )(strtotime($expires));
  133. $urlParamListArray = [];
  134. foreach ($querys as $query) {
  135. if (!empty($query)) {
  136. $tmpquery = explode('=', $query);
  137. //为了保证CI的key中有=号的情况也能正常通过,ci在这层之前已经encode了,这里需要拆开重新encode,防止上方explode拆错
  138. $key = strtolower(rawurlencode(urldecode($tmpquery[0])));
  139. if (count($tmpquery) >= 2) {
  140. $value = $tmpquery[1];
  141. } else {
  142. $value = "";
  143. }
  144. //host开关
  145. if (!$this->options['signHost'] && $key == 'host') {
  146. continue;
  147. }
  148. $urlParamListArray[$key] = $key . '=' . $value;
  149. }
  150. }
  151. ksort($urlParamListArray);
  152. $urlParamList = join(';', array_keys($urlParamListArray));
  153. $httpParameters = join('&', array_values($urlParamListArray));
  154. $headerListArray = [];
  155. foreach ($headers as $key => $value) {
  156. $key = strtolower(urlencode($key));
  157. $value = rawurlencode($value);
  158. if (!$this->options['signHost'] && $key == 'host') {
  159. continue;
  160. }
  161. if ($this->needCheckHeader($key)) {
  162. $headerListArray[$key] = $key . '=' . $value;
  163. }
  164. }
  165. ksort($headerListArray);
  166. $headerList = join(';', array_keys($headerListArray));
  167. $httpHeaders = join('&', array_values($headerListArray));
  168. $httpString = strtolower($method) . "\n" . urldecode($urlPath) . "\n" . $httpParameters .
  169. "\n" . $httpHeaders . "\n";
  170. $sha1edHttpString = sha1($httpString);
  171. $stringToSign = "sha1\n$signTime\n$sha1edHttpString\n";
  172. $signKey = hash_hmac('sha1', $signTime, trim($this->secretKey));
  173. $signature = hash_hmac('sha1', $stringToSign, $signKey);
  174. $authorization = 'q-sign-algorithm=sha1&q-ak=' . trim($this->accessKey) .
  175. "&q-sign-time=$signTime&q-key-time=$signTime&q-header-list=$headerList&q-url-param-list=$urlParamList&" .
  176. "q-signature=$signature";
  177. return $authorization;
  178. }
  179. /**
  180. * @param string $url
  181. * @param string $method
  182. * @param string $urlPath
  183. * @param array $querys
  184. * @param array $headers
  185. * @param string $expires
  186. * @return string[]
  187. * @author 等风来
  188. * @email 136327134@qq.com
  189. * @date 2022/9/26
  190. */
  191. public function createPresignedUrl(string $url, string $method, string $urlPath, array $querys = [], array $headers = [], string $expires = '+30 minutes')
  192. {
  193. $authorization = $this->createAuthorization($method, $urlPath, $querys, $headers, $expires);
  194. $uri = $url;
  195. $query = 'sign=' . urlencode($authorization) . '&' . implode('&', $querys);
  196. if ($this->token != null) {
  197. $query = $query . '&x-cos-security-token=' . $this->token;
  198. }
  199. return [$uri, $query];
  200. }
  201. }