CosService.php 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <?php
  2. namespace app\utils\Service\Tencent;
  3. use Qcloud\Cos\Client;
  4. use QCloud\COSSTS\Sts;
  5. class CosService
  6. {
  7. private $config;
  8. public function __construct()
  9. {
  10. $this->config = get_addon_config('cos');
  11. }
  12. public function getToken()
  13. {
  14. $config = $this->stsToken();
  15. $uploadUrl = $this->config['uploadurl'];//上传域名因存储区域不同而节点不同
  16. $cdnUrl = $this->config['cdnurl'];//上传域名因存储区域不同而节点不同
  17. $appId = $this->config['appId'] ?? '';
  18. $bucket = $this->config['bucket'] ?? '';//存储桶,格式:BucketName-APPID
  19. $region = $this->config['region'] ?? '';
  20. $key = str_replace('-'.$appId,'',$bucket);//对象在存储桶中的位置,即对象键
  21. $tmpSecretId = $config['credentials']['tmpSecretId']; //使用临时密钥需要填入,临时密钥生成和使用指引参见https://cloud.tencent.com/document/product/436/14048
  22. $tmpSecretKey = $config['credentials']['tmpSecretKey']; //使用临时密钥需要填入,临时密钥生成和使用指引参见https://cloud.tencent.com/document/product/436/14048
  23. $tmpToken = $config['credentials']['sessionToken']; //使用临时密钥需要填入,临时密钥生成和使用指引参见https://cloud.tencent.com/document/product/436/14048
  24. $cosClient = new Client(
  25. array(
  26. 'region' => $region,
  27. 'scheme' => 'https', //协议头部,默认为 http
  28. 'signHost' => true, //默认签入Header Host;您也可以选择不签入Header Host,但可能导致请求失败或安全漏洞,若不签入host则填false
  29. 'credentials'=> array(
  30. 'secretId' => $tmpSecretId,
  31. 'secretKey' => $tmpSecretKey,
  32. 'token' => $tmpToken)));
  33. ### 简单上传预签名
  34. try {
  35. $signedUrl = $cosClient->getPreSignedUrl('putObject', array(
  36. 'Bucket' => $bucket, //存储桶,格式:BucketName-APPID
  37. 'Key' => $key, //对象在存储桶中的位置,即对象键
  38. 'Body' => 'string',
  39. 'Params'=> array(), //http 请求参数,传入的请求参数需与实际请求相同,能够防止用户篡改此HTTP请求的参数,默认为空
  40. 'Headers'=> array(), //http 请求头部,传入的请求头部需包含在实际请求中,能够防止用户篡改签入此处的HTTP请求头部,默认已签入host
  41. ), '+10 minutes'); //签名的有效时间
  42. // 请求成功
  43. // 请求成功
  44. return [true,[
  45. 'bucket' => $bucket,
  46. 'region' => $region,
  47. 'uploadUrl' => $uploadUrl,
  48. 'cdnUrl' => $cdnUrl,
  49. 'signUrl' => $signedUrl,
  50. ]];
  51. } catch (\Exception $e) {
  52. // 请求失败
  53. return [false,$e->getMessage()];
  54. }
  55. }
  56. /**
  57. * 腾讯云预签名URL
  58. */
  59. public function getSignedUrl($dir = 'uploads/')
  60. {
  61. $uploadUrl = $this->config['uploadurl'];//上传域名因存储区域不同而节点不同
  62. $cdnUrl = $this->config['cdnurl'];//上传域名因存储区域不同而节点不同
  63. $secretId = $this->config['secretId'] ?? '';
  64. $secretKey = $this->config['secretKey'] ?? '';
  65. $bucket = $this->config['bucket'] ?? '';
  66. $region = $this->config['region'] ?? '';
  67. $time = time();
  68. // $cosClient = new Client([
  69. // 'region' => $region,
  70. // 'schema' => $ssl, //协议头部,默认为http
  71. // 'signHost' => true, //默认签入Header Host;您也可以选择不签入Header Host,但可能导致请求失败或安全漏洞,若不签入host则填false
  72. // 'credentials' => [
  73. // 'secretId' => $secretId,
  74. // 'secretKey' => $secretKey
  75. // ]
  76. // ]);
  77. try {
  78. // $signedUrl = $cosClient->getPreSignedUrl('putObject', [
  79. // 'Bucket' => $bucket, //存储桶,格式:BucketName-APPID
  80. // 'Key' => $dir, //对象在存储桶中的位置,即对象键
  81. // 'Body' => 'string',
  82. // 'Params' => [], //http 请求参数,传入的请求参数需与实际请求相同,能够防止用户篡改此HTTP请求的参数,默认为空
  83. // 'Headers' => [], //http 请求头部,传入的请求头部需包含在实际请求中,能够防止用户篡改签入此处的HTTP请求头部,默认已签入host
  84. // ], '+10 minutes'); //签名的有效时间
  85. //设置该policy超时时间是10s. 即这个policy过了这个有效时间,将不能访问。
  86. $addTime = 30 * 60;//三十分钟
  87. $expiration = $this->gmt_iso8601($time + $addTime);
  88. $StartTimestamp = $time;
  89. $EndTimestamp = $StartTimestamp + $addTime;
  90. $KeyTime = "$StartTimestamp;$EndTimestamp";
  91. $conditions = [
  92. ['content-length-range', 0, 1048576000],//最大文件大小.用户可以自己设置
  93. ["bucket" => $bucket],
  94. ["starts-with", '$key', $dir],// 表示用户上传的数据,必须是以$dir开始,不然上传会失败,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录。
  95. ["q-sign-algorithm" => "sha1"],
  96. ["q-ak" => $secretId],
  97. ["q-sign-time" => $KeyTime]
  98. ];
  99. $arr = ['expiration' => $expiration, 'conditions' => $conditions];
  100. $policy = json_encode($arr);
  101. $policyBase64 = base64_encode($policy);
  102. // 签名
  103. $SignKey = hash_hmac('sha1', $KeyTime, $secretKey);
  104. $StringToSign = sha1($policy);
  105. $Signature = hash_hmac('sha1', $StringToSign, $SignKey);
  106. // 请求成功
  107. return [true, [
  108. 'upload_url' => $uploadUrl,
  109. 'cdn_url' => $cdnUrl,
  110. 'region' => $region,
  111. 'policy' => $policyBase64,
  112. 'q_sign_algorithm' => 'sha1',
  113. 'q_ak' => $secretId,
  114. 'q_key_time' => $KeyTime,
  115. 'q_signature' => $Signature,
  116. ]];
  117. } catch (\Exception $e) {
  118. return [false, $e->getMessage()];
  119. }
  120. }
  121. public function stsToken()
  122. {
  123. $uploadUrl = $this->config['uploadurl'];//上传域名因存储区域不同而节点不同
  124. $cdnUrl = $this->config['cdnurl'];//上传域名因存储区域不同而节点不同
  125. $secretId = $this->config['secretId'] ?? '';
  126. $secretKey = $this->config['secretKey'] ?? '';
  127. $bucket = $this->config['bucket'] ?? '';
  128. $region = $this->config['region'] ?? '';
  129. $sts = new Sts();
  130. $config = array(
  131. 'url' => 'https://sts.tencentcloudapi.com/', // url和domain保持一致
  132. 'domain' => 'sts.tencentcloudapi.com', // 域名,非必须,默认为 sts.tencentcloudapi.com
  133. 'proxy' => '',
  134. 'secretId' => $secretId, // 固定密钥,若为明文密钥,请直接以'xxx'形式填入,不要填写到getenv()函数中
  135. 'secretKey' => $secretKey, // 固定密钥,若为明文密钥,请直接以'xxx'形式填入,不要填写到getenv()函数中
  136. 'bucket' => $bucket,//'test-1253653367', // 换成你的 bucket
  137. 'region' => $region,//'ap-guangzhou', // 换成 bucket 所在园区
  138. 'durationSeconds' => 1800, // 密钥有效期
  139. 'allowPrefix' => array('exampleobject.jpg','exampleobject.png','exampleobject/*'), // 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径,例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
  140. // 密钥的权限列表。简单上传和分片需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
  141. 'allowActions' => array (
  142. // 简单上传
  143. 'name/cos:PutObject',
  144. 'name/cos:PostObject',
  145. // 分片上传
  146. 'name/cos:InitiateMultipartUpload',
  147. 'name/cos:ListMultipartUploads',
  148. 'name/cos:ListParts',
  149. 'name/cos:UploadPart',
  150. 'name/cos:CompleteMultipartUpload'
  151. ),
  152. // 临时密钥生效条件,关于condition的详细设置规则和COS支持的condition类型可以参考 https://cloud.tencent.com/document/product/436/71306
  153. // "condition" => array(
  154. // "ip_equal" => array(
  155. // "qcs:ip" => array(
  156. // "10.217.182.3/24",
  157. // "111.21.33.72/24",
  158. // )
  159. // )
  160. // )
  161. );
  162. // 获取临时密钥,计算签名
  163. $tempKeys = $sts->getTempKeys($config);
  164. return $tempKeys;
  165. }
  166. private function xml_parser($str)
  167. {
  168. $xml_parser = xml_parser_create();
  169. if (!xml_parse($xml_parser, $str, true)) {
  170. xml_parser_free($xml_parser);
  171. return $str;
  172. } else {
  173. $res = json_decode(json_encode(simplexml_load_string($str, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
  174. return $res['Message'] ?? '请求错误';
  175. }
  176. }
  177. /**
  178. * @param $time
  179. * @return string
  180. * @throws \Exception
  181. */
  182. private function gmt_iso8601($time)
  183. {
  184. $dtStr = date("c", $time);
  185. $dateTime = new \DateTime($dtStr);
  186. $expiration = $dateTime->format(\DateTime::ISO8601);
  187. $pos = strpos($expiration, '+');
  188. $expiration = substr($expiration, 0, $pos);
  189. return $expiration . "Z";
  190. }
  191. }