You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

171 lines
5.9 KiB

  1. <?php
  2. namespace Kuxin\Storage;
  3. use Kuxin\Helper\File;
  4. use Kuxin\Helper\Http;
  5. class Oss
  6. {
  7. public function __construct($config)
  8. {
  9. if (empty($config['key'])) {
  10. trigger_error('access key 未设置');
  11. }
  12. if (empty($config['secret'])) {
  13. trigger_error('access secret 未设置');
  14. }
  15. if (empty($config['bucket'])) {
  16. trigger_error('bucket 未设置');
  17. }
  18. if (empty($config['endpoint'])) {
  19. trigger_error('endpoint 未设置');
  20. }
  21. if (empty($config['url'])) {
  22. trigger_error('访问域名 未设置');
  23. }
  24. $this->accessKeyId = $config['key'];
  25. $this->accessKeySecret = $config['secret'];
  26. $this->bucket = $config['bucket'];
  27. $this->host = $config['bucket'] . '.' . $config['endpoint'];
  28. $this->api = 'http://' . $this->host . '/';
  29. $this->preUrl = $config['url'];
  30. $this->path = '/' . ltrim($config['path'], '/');
  31. }
  32. public function getPath($object)
  33. {
  34. return $object;
  35. }
  36. public function exist($object)
  37. {
  38. $data = $this->getObjectMeta($object);
  39. return !empty($data['last-modified']);
  40. }
  41. public function mtime($object)
  42. {
  43. $data = $this->getObjectMeta($object);
  44. return $data['x-oss-meta-mtime'] ?? (isset($data['last-modified']) ? strtotime($data['last-modified']) : 0);
  45. }
  46. public function read($object)
  47. {
  48. $path = $this->path . '/' . $object;
  49. $method = 'GET';
  50. $options[CURLOPT_HEADER] = 1;
  51. $headers = $this->genHeaders($object);
  52. $sign = $this->sign($method, $headers, '/' . $this->bucket . $path);
  53. $headers['Authorization'] = "OSS {$this->accessKeyId}:{$sign}";
  54. $url = $this->api . $path;
  55. $res = Http::curl($url, [], $method, $headers, $options);
  56. if (strpos($res, 'Content-MD5')) {
  57. return Http::parse_content($res);
  58. } else {
  59. return false;
  60. }
  61. }
  62. public function write($object, $content)
  63. {
  64. $path = $this->path . '/' . $object;
  65. $method = 'PUT';
  66. $options[CURLOPT_HEADER] = 1;
  67. $headers = $this->genHeaders($object);
  68. $headers['Content-MD5'] = base64_encode(md5($content, true));
  69. $sign = $this->sign($method, $headers, '/' . $this->bucket . $path);
  70. $headers['Authorization'] = "OSS {$this->accessKeyId}:{$sign}";
  71. $url = $this->api . $path;
  72. $res = Http::curl($url, $content, $method, $headers, $options);
  73. return strpos($res, '200 OK');
  74. }
  75. public function append($object, $content)
  76. {
  77. $data = $this->getObjectMeta($object);
  78. $path = $this->path . '/' . $object . '?append&position=0' . $data['content-length'];
  79. $method = 'POST';
  80. $options[CURLOPT_HEADER] = 1;
  81. $headers = $this->genHeaders($object);
  82. $headers['Content-MD5'] = base64_encode(md5($content, true));
  83. $headers['Accept-Encoding'] = '';
  84. $sign = $this->sign($method, $headers, '/' . $this->bucket . $path);
  85. $headers['Authorization'] = "OSS {$this->accessKeyId}:{$sign}";
  86. $url = $this->api . $path;
  87. $res = Http::curl($url, $content, $method, $headers, $options);
  88. return strpos($res, '200 OK');
  89. }
  90. public function remove($object)
  91. {
  92. $path = $this->path . '/' . $object;
  93. $method = 'DELETE';
  94. $options[CURLOPT_HEADER] = 1;
  95. $headers = $this->genHeaders($object);
  96. $sign = $this->sign($method, $headers, '/' . $this->bucket . $path);
  97. $headers['Authorization'] = "OSS {$this->accessKeyId}:{$sign}";
  98. $url = $this->api . $path;
  99. $res = Http::curl($url, [], $method, $headers, $options);
  100. $headers = Http::parse_headers($res);
  101. if ($headers['x-oss-meta-mtime']) {
  102. return Http::parse_content($res);
  103. } else {
  104. return false;
  105. }
  106. }
  107. public function getUrl($object)
  108. {
  109. return $this->preUrl . $this->path . '/' . $object;
  110. }
  111. public function error()
  112. {
  113. return '';
  114. }
  115. private function getObjectMeta($object)
  116. {
  117. $path = $this->path . '/' . $object . '?objectMeta';
  118. $method = 'HEAD';
  119. $options[CURLOPT_HEADER] = 1;
  120. $headers = $this->genHeaders($object);
  121. $sign = $this->sign($method, $headers, '/' . $this->bucket . $path);
  122. $headers['Authorization'] = "OSS {$this->accessKeyId}:{$sign}";
  123. $url = $this->api . $path;
  124. $res = Http::curl($url, [], $method, $headers, $options);
  125. return Http::parse_headers($res);
  126. }
  127. private function sign($method, $headers, $object)
  128. {
  129. $param = [];
  130. $param[] = $method;
  131. $param[] = $headers['Content-MD5'] ?? "";
  132. $param[] = $headers['Content-Type'] ?? "";
  133. $param[] = $headers['Date'];
  134. //$param[] = $headers['Host'];
  135. $param[] = $object;
  136. return base64_encode(hash_hmac('sha1', join("\n", $param), $this->accessKeySecret, true));
  137. }
  138. private function genHeaders($object)
  139. {
  140. return [
  141. 'Date' => gmdate('D, d M Y H:i:s \G\M\T'),
  142. 'Host' => $this->host,
  143. 'Content-Type' => File::getMimeByName($object),
  144. ];
  145. }
  146. }