Upyun.class.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
  10. // +----------------------------------------------------------------------
  11. namespace Think\Upload\Driver;
  12. class Upyun
  13. {
  14. /**
  15. * 上传文件根目录
  16. * @var string
  17. */
  18. private $rootPath;
  19. /**
  20. * 上传错误信息
  21. * @var string
  22. */
  23. private $error = '';
  24. private $config = array(
  25. 'host' => '', //又拍云服务器
  26. 'username' => '', //又拍云用户
  27. 'password' => '', //又拍云密码
  28. 'bucket' => '', //空间名称
  29. 'timeout' => 90, //超时时间
  30. );
  31. /**
  32. * 构造函数,用于设置上传根路径
  33. * @param array $config FTP配置
  34. */
  35. public function __construct($config)
  36. {
  37. /* 默认FTP配置 */
  38. $this->config = array_merge($this->config, $config);
  39. $this->config['password'] = md5($this->config['password']);
  40. }
  41. /**
  42. * 检测上传根目录(又拍云上传时支持自动创建目录,直接返回)
  43. * @param string $rootpath 根目录
  44. * @return boolean true-检测通过,false-检测失败
  45. */
  46. public function checkRootPath($rootpath)
  47. {
  48. /* 设置根目录 */
  49. $this->rootPath = trim($rootpath, './') . '/';
  50. return true;
  51. }
  52. /**
  53. * 检测上传目录(又拍云上传时支持自动创建目录,直接返回)
  54. * @param string $savepath 上传目录
  55. * @return boolean 检测结果,true-通过,false-失败
  56. */
  57. public function checkSavePath($savepath)
  58. {
  59. return true;
  60. }
  61. /**
  62. * 创建文件夹 (又拍云上传时支持自动创建目录,直接返回)
  63. * @param string $savepath 目录名称
  64. * @return boolean true-创建成功,false-创建失败
  65. */
  66. public function mkdir($savepath)
  67. {
  68. return true;
  69. }
  70. /**
  71. * 保存指定文件
  72. * @param array $file 保存的文件信息
  73. * @param boolean $replace 同名文件是否覆盖
  74. * @return boolean 保存状态,true-成功,false-失败
  75. */
  76. public function save($file, $replace = true)
  77. {
  78. $header['Content-Type'] = $file['type'];
  79. $header['Content-MD5'] = $file['md5'];
  80. $header['Mkdir'] = 'true';
  81. $resource = fopen($file['tmp_name'], 'r');
  82. $save = $this->rootPath . $file['savepath'] . $file['savename'];
  83. $data = $this->request($save, 'PUT', $header, $resource);
  84. return false === $data ? false : true;
  85. }
  86. /**
  87. * 获取最后一次上传错误信息
  88. * @return string 错误信息
  89. */
  90. public function getError()
  91. {
  92. return $this->error;
  93. }
  94. /**
  95. * 请求又拍云服务器
  96. * @param string $path 请求的PATH
  97. * @param string $method 请求方法
  98. * @param array $headers 请求header
  99. * @param resource $body 上传文件资源
  100. * @return boolean
  101. */
  102. private function request($path, $method, $headers = null, $body = null)
  103. {
  104. $uri = "/{$this->config['bucket']}/{$path}";
  105. $ch = curl_init($this->config['host'] . $uri);
  106. $_headers = array('Expect:');
  107. if (!is_null($headers) && is_array($headers)) {
  108. foreach ($headers as $k => $v) {
  109. array_push($_headers, "{$k}: {$v}");
  110. }
  111. }
  112. $length = 0;
  113. $date = gmdate('D, d M Y H:i:s \G\M\T');
  114. if (!is_null($body)) {
  115. if (is_resource($body)) {
  116. fseek($body, 0, SEEK_END);
  117. $length = ftell($body);
  118. fseek($body, 0);
  119. array_push($_headers, "Content-Length: {$length}");
  120. curl_setopt($ch, CURLOPT_INFILE, $body);
  121. curl_setopt($ch, CURLOPT_INFILESIZE, $length);
  122. } else {
  123. $length = @strlen($body);
  124. array_push($_headers, "Content-Length: {$length}");
  125. curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
  126. }
  127. } else {
  128. array_push($_headers, "Content-Length: {$length}");
  129. }
  130. array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length));
  131. array_push($_headers, "Date: {$date}");
  132. curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);
  133. curl_setopt($ch, CURLOPT_TIMEOUT, $this->config['timeout']);
  134. curl_setopt($ch, CURLOPT_HEADER, 1);
  135. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  136. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
  137. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
  138. if ('PUT' == $method || 'POST' == $method) {
  139. curl_setopt($ch, CURLOPT_POST, 1);
  140. } else {
  141. curl_setopt($ch, CURLOPT_POST, 0);
  142. }
  143. if ('HEAD' == $method) {
  144. curl_setopt($ch, CURLOPT_NOBODY, true);
  145. }
  146. $response = curl_exec($ch);
  147. $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  148. curl_close($ch);
  149. list($header, $body) = explode("\r\n\r\n", $response, 2);
  150. if (200 == $status) {
  151. if ('GET' == $method) {
  152. return $body;
  153. } else {
  154. $data = $this->response($header);
  155. return count($data) > 0 ? $data : true;
  156. }
  157. } else {
  158. $this->error($header);
  159. return false;
  160. }
  161. }
  162. /**
  163. * 获取响应数据
  164. * @param string $text 响应头字符串
  165. * @return array 响应数据列表
  166. */
  167. private function response($text)
  168. {
  169. $headers = explode("\r\n", $text);
  170. $items = array();
  171. foreach ($headers as $header) {
  172. $header = trim($header);
  173. if (strpos($header, 'x-upyun') !== false) {
  174. list($k, $v) = explode(':', $header);
  175. $items[trim($k)] = in_array(substr($k, 8, 5), array('width', 'heigh', 'frame')) ? intval($v) : trim($v);
  176. }
  177. }
  178. return $items;
  179. }
  180. /**
  181. * 生成请求签名
  182. * @param string $method 请求方法
  183. * @param string $uri 请求URI
  184. * @param string $date 请求时间
  185. * @param integer $length 请求内容大小
  186. * @return string 请求签名
  187. */
  188. private function sign($method, $uri, $date, $length)
  189. {
  190. $sign = "{$method}&{$uri}&{$date}&{$length}&{$this->config['password']}";
  191. return 'UpYun ' . $this->config['username'] . ':' . md5($sign);
  192. }
  193. /**
  194. * 获取请求错误信息
  195. * @param string $header 请求返回头信息
  196. */
  197. private function error($header)
  198. {
  199. list($status, $stash) = explode("\r\n", $header, 2);
  200. list($v, $code, $message) = explode(" ", $status, 3);
  201. $message = is_null($message) ? 'File Not Found' : "[{$status}]:{$message}";
  202. $this->error = $message;
  203. }
  204. }