Cosapi.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. <?php
  2. namespace app\common\services\cos\Qcloud_cos;
  3. class Cosapi
  4. {
  5. //计算sign签名的时间参数
  6. const EXPIRED_SECONDS = 180;
  7. //512K
  8. const SLICE_SIZE_512K = 524288;
  9. //1M
  10. const SLICE_SIZE_1M = 1048576;
  11. //2M
  12. const SLICE_SIZE_2M = 2097152;
  13. //3M
  14. const SLICE_SIZE_3M = 3145728;
  15. //20M 大于20M的文件需要进行分片传输
  16. const MAX_UNSLICE_FILE_SIZE = 20971520;
  17. //失败尝试次数
  18. const MAX_RETRY_TIMES = 3;
  19. //返回的错误码
  20. const COSAPI_PARAMS_ERROR = -1;
  21. const COSAPI_NETWORK_ERROR = -2;
  22. //HTTP请求超时时间
  23. private static $timeout = 60;
  24. /*
  25. * 设置HTTP请求超时时间
  26. * @param int $timeout 超时时长
  27. */
  28. public static function setTimeout($timeout = 60) {
  29. if (!is_int($timeout) || $timeout < 0) {
  30. return false;
  31. }
  32. self::$timeout = $timeout;
  33. return true;
  34. }
  35. /**
  36. * 上传文件,自动判断文件大小,如果小于20M则使用普通文件上传,大于20M则使用分片上传
  37. * @param string $bucketName bucket名称
  38. * @param string $srcPath 本地文件路径
  39. * @param string $dstPath 上传的文件路径
  40. * @param string $bizAttr 文件属性
  41. * @param string $slicesize 分片大小(512k,1m,2m,3m),默认:1m
  42. * @param string $insertOnly 同名文件是否覆盖
  43. * @return [type] [description]
  44. */
  45. public static function upload($bucketName, $srcPath, $dstPath,
  46. $bizAttr = null, $slicesize = null, $insertOnly = null)
  47. {
  48. if (!file_exists($srcPath)) {
  49. return array(
  50. 'code' => self::COSAPI_PARAMS_ERROR,
  51. 'message' => 'file '.$srcPath.' not exists',
  52. 'data' => array());
  53. }
  54. //文件大于20M则使用分片传输
  55. if (filesize($srcPath) < self::MAX_UNSLICE_FILE_SIZE ) {
  56. return self::uploadfile($bucketName, $srcPath, $dstPath, $bizAttr, $insertOnly);
  57. } else {
  58. $sliceSize = self::getSliceSize($slicesize);
  59. return self::upload_slice($bucketName, $srcPath, $dstPath, $bizAttr, $sliceSize, $insertOnly);
  60. }
  61. }
  62. /*
  63. * 创建目录
  64. * @param string $bucketName bucket名称
  65. * @param string $path 目录路径
  66. * @param string $bizAttr 目录属性
  67. */
  68. public static function createFolder($bucketName, $path, $bizAttr = null) {
  69. $path = self::normalizerPath($path, True);
  70. $path = self::cosUrlEncode($path);
  71. $expired = time() + self::EXPIRED_SECONDS;
  72. $url = self::generateResUrl($bucketName, $path);
  73. $sign = Auth::appSign($expired, $bucketName);
  74. $data = array(
  75. 'op' => 'create',
  76. 'biz_attr' => (isset($bizAttr) ? $bizAttr : ''),
  77. );
  78. $data = json_encode($data);
  79. $req = array(
  80. 'url' => $url,
  81. 'method' => 'post',
  82. 'timeout' => self::$timeout,
  83. 'data' => $data,
  84. 'header' => array(
  85. 'Authorization:'.$sign,
  86. 'Content-Type: application/json',
  87. ),
  88. );
  89. return self::sendRequest($req);
  90. }
  91. /*
  92. * 目录列表
  93. * @param string $bucketName bucket名称
  94. * @param string $path 目录路径,sdk会补齐末尾的 '/'
  95. * @param int $num 拉取的总数
  96. * @param string $pattern eListBoth,ListDirOnly,eListFileOnly 默认both
  97. * @param int $order 默认正序(=0), 填1为反序,
  98. * @param string $offset 透传字段,用于翻页,前端不需理解,需要往前/往后翻页则透传回来
  99. */
  100. public static function listFolder(
  101. $bucketName, $path, $num = 20,
  102. $pattern = 'eListBoth', $order = 0,
  103. $context = null) {
  104. $path = self::normalizerPath($path,True);
  105. return self::listBase($bucketName, $path, $num,
  106. $pattern, $order, $context);
  107. }
  108. /*
  109. * 目录列表(前缀搜索)
  110. * @param string $bucketName bucket名称
  111. * @param string $prefix 列出含此前缀的所有文件
  112. * @param int $num 拉取的总数
  113. * @param string $pattern eListBoth(默认),ListDirOnly,eListFileOnly
  114. * @param int $order 默认正序(=0), 填1为反序,
  115. * @param string $offset 透传字段,用于翻页,前端不需理解,需要往前/往后翻页则透传回来
  116. */
  117. public static function prefixSearch(
  118. $bucketName, $prefix, $num = 20,
  119. $pattern = 'eListBoth', $order = 0,
  120. $context = null) {
  121. $path = self::normalizerPath($prefix);
  122. return self::listBase($bucketName, $prefix, $num,
  123. $pattern, $order, $context);
  124. }
  125. /*
  126. * 目录更新
  127. * @param string $bucketName bucket名称
  128. * @param string $path 文件夹路径,SDK会补齐末尾的 '/'
  129. * @param string $bizAttr 目录属性
  130. */
  131. public static function updateFolder($bucketName, $path, $bizAttr = null) {
  132. $path = self::normalizerPath($path, True);
  133. return self::updateBase($bucketName, $path, $bizAttr);
  134. }
  135. /*
  136. * 查询目录信息
  137. * @param string $bucketName bucket名称
  138. * @param string $path 目录路径
  139. */
  140. public static function statFolder($bucketName, $path) {
  141. $path = self::normalizerPath($path, True);
  142. return self::statBase($bucketName, $path);
  143. }
  144. /*
  145. * 删除目录
  146. * @param string $bucketName bucket名称
  147. * @param string $path 目录路径
  148. * 注意不能删除bucket下根目录/
  149. */
  150. public static function delFolder($bucketName, $path) {
  151. $path = self::normalizerPath($path, True);
  152. return self::delBase($bucketName, $path);
  153. }
  154. /*
  155. * 更新文件
  156. * @param string $bucketName bucket名称
  157. * @param string $path 文件路径
  158. * @param string $authority: eInvalid(继承Bucket的读写权限)/eWRPrivate(私有读写)/eWPrivateRPublic(公有读私有写)
  159. * @param array $customer_headers_array 携带的用户自定义头域,包括
  160. * 'Cache-Control' => '*'
  161. * 'Content-Type' => '*'
  162. * 'Content-Disposition' => '*'
  163. * 'Content-Language' => '*'
  164. * 'x-cos-meta-自定义内容' => '*'
  165. */
  166. public static function update($bucketName, $path,
  167. $bizAttr = null, $authority=null,$customer_headers_array=null) {
  168. $path = self::normalizerPath($path);
  169. return self::updateBase($bucketName, $path, $bizAttr, $authority, $customer_headers_array);
  170. }
  171. /*
  172. * 移动(重命名)文件
  173. * @param string $bucketName bucket名称
  174. * @param string $srcPath 源文件路径
  175. * @param string $dstPath 目的文件名(可以是单独文件名也可以是带目录的文件名)
  176. * @param string $toOverWrite 是否覆盖(当目的文件名已经存在同名文件时是否覆盖)
  177. */
  178. public static function move($bucketName, $srcPath, $dstPath, $toOverWrite = 0)
  179. {
  180. $srcPath = self::cosUrlEncode($srcPath);
  181. $url = self::generateResUrl($bucketName,$srcPath);
  182. $sign = Auth::appSign_once($srcPath, $bucketName);
  183. $expired = time() + self::EXPIRED_SECONDS;
  184. $data = array(
  185. 'op' => 'move',
  186. 'dest_fileid' => $dstPath,
  187. 'to_over_write' => $toOverWrite,
  188. );
  189. $data = json_encode($data);
  190. $req = array(
  191. 'url' => $url,
  192. 'method' => 'post',
  193. 'timeout' => self::$timeout,
  194. 'data' => $data,
  195. 'header' => array(
  196. 'Authorization: '.$sign,
  197. 'Content-Type: application/json',
  198. ),
  199. );
  200. return self::sendRequest($req);
  201. }
  202. /*
  203. * 查询文件信息
  204. * @param string $bucketName bucket名称
  205. * @param string $path 文件路径
  206. */
  207. public static function stat($bucketName, $path) {
  208. $path = self::normalizerPath($path);
  209. return self::statBase($bucketName, $path);
  210. }
  211. /*
  212. * 删除文件
  213. * @param string $bucketName
  214. * @param string $path 文件路径
  215. */
  216. public static function delFile($bucketName, $path) {
  217. $path = self::normalizerPath($path);
  218. return self::delBase($bucketName, $path);
  219. }
  220. /**
  221. * 内部方法, 上传文件
  222. * @param string $bucketName bucket名称
  223. * @param string $srcPath 本地文件路径
  224. * @param string $dstPath 上传的文件路径
  225. * @param string $bizAttr 文件属性
  226. * @param int $insertOnly 是否覆盖同名文件:0 覆盖,1:不覆盖
  227. * @return [type] [description]
  228. */
  229. private static function uploadfile($bucketName, $srcPath, $dstPath, $bizAttr = null, $insertOnly = null)
  230. {
  231. $srcPath = realpath($srcPath);
  232. $dstPath = self::cosUrlEncode($dstPath);
  233. if (filesize($srcPath) >= self::MAX_UNSLICE_FILE_SIZE )
  234. {
  235. return array(
  236. 'code' => self::COSAPI_PARAMS_ERROR,
  237. 'message' => 'file '.$srcPath.' larger then 20M, please use upload_slice interface',
  238. 'data' => array());
  239. }
  240. $expired = time() + self::EXPIRED_SECONDS;
  241. $url = self::generateResUrl($bucketName, $dstPath);
  242. $sign = Auth::appSign($expired, $bucketName);
  243. $sha1 = hash_file('sha1', $srcPath);
  244. $data = array(
  245. 'op' => 'upload',
  246. 'sha' => $sha1,
  247. 'biz_attr' => (isset($bizAttr) ? $bizAttr : ''),
  248. );
  249. if (function_exists('curl_file_create')) {
  250. $data['filecontent'] = curl_file_create($srcPath);
  251. } else {
  252. $data['filecontent'] = '@'.$srcPath;
  253. }
  254. if (isset($insertOnly) && strlen($insertOnly) > 0)
  255. $data['insertOnly'] = (($insertOnly == 0 || $insertOnly == '0' ) ? 0 : 1);
  256. $req = array(
  257. 'url' => $url,
  258. 'method' => 'post',
  259. 'timeout' => self::$timeout,
  260. 'data' => $data,
  261. 'header' => array(
  262. 'Authorization:'.$sign,
  263. ),
  264. );
  265. return self::sendRequest($req);
  266. }
  267. /**
  268. * 内部方法,上传文件
  269. * @param string $bucketName bucket名称
  270. * @param string $srcPath 本地文件路径
  271. * @param string $dstPath 上传的文件路径
  272. * @param string $bizAttr 文件属性
  273. * @param string $sliceSize 分片大小
  274. * @param int $insertOnly 是否覆盖同名文件:0 覆盖,1:不覆盖
  275. * @return [type] [description]
  276. */
  277. private static function upload_slice(
  278. $bucketName, $srcPath, $dstPath,
  279. $bizAttr = null, $sliceSize = null, $insertOnly=null) {
  280. $srcPath = realpath($srcPath);
  281. $fileSize = filesize($srcPath);
  282. $dstPath = self::cosUrlEncode($dstPath);
  283. $expired = time() + self::EXPIRED_SECONDS;
  284. $url = self::generateResUrl($bucketName, $dstPath);
  285. $sign = Auth::appSign($expired, $bucketName);
  286. $sha1 = hash_file('sha1', $srcPath);
  287. $ret = self::upload_prepare(
  288. $fileSize, $sha1, $sliceSize,
  289. $sign, $url, $bizAttr, $insertOnly);
  290. if($ret['code'] != 0) {
  291. return $ret;
  292. }
  293. if(isset($ret['data'])
  294. && isset($ret['data']['url'])) {
  295. //秒传命中,直接返回了url
  296. return $ret;
  297. }
  298. $sliceSize = $ret['data']['slice_size'];
  299. if ($sliceSize > self::SLICE_SIZE_3M ||
  300. $sliceSize <= 0) {
  301. $ret['code'] = self::COSAPI_PARAMS_ERROR;
  302. $ret['message'] = 'illegal slice size';
  303. return $ret;
  304. }
  305. $session = $ret['data']['session'];
  306. $offset = $ret['data']['offset'];
  307. $sliceCnt = ceil($fileSize / $sliceSize);
  308. // expired seconds for one slice mutiply by slice count
  309. // will be the expired seconds for whole file
  310. $expired = time() + (self::EXPIRED_SECONDS * $sliceCnt);
  311. $sign = Auth::appSign($expired, $bucketName);
  312. $ret = self::upload_data(
  313. $fileSize, $sha1, $sliceSize,
  314. $sign, $url, $srcPath,
  315. $offset, $session);
  316. return $ret;
  317. }
  318. /**
  319. * 第一个分片控制消息
  320. * @param string $fileSize 文件大小
  321. * @param string $sha1 文件sha值
  322. * @param string $sliceSize 分片大小
  323. * @param string $sign 签名
  324. * @param string $url URL
  325. * @param string $bizAttr 文件属性
  326. * @param string $insertOnly 同名文件是否覆盖
  327. * @return [type]
  328. */
  329. private static function upload_prepare(
  330. $fileSize, $sha1, $sliceSize,
  331. $sign, $url, $bizAttr = null, $insertOnly = null) {
  332. $data = array(
  333. 'op' => 'upload_slice',
  334. 'filesize' => $fileSize,
  335. 'sha' => $sha1,
  336. );
  337. if (isset($bizAttr) && strlen($bizAttr))
  338. $data['biz_attr'] = $bizAttr;
  339. if (isset($insertOnly))
  340. $data['insertOnly'] = (($insertOnly == 0) ? 0 : 1);
  341. if ($sliceSize <= self::SLICE_SIZE_3M) {
  342. $data['slice_size'] = $sliceSize;
  343. } else {
  344. $data['slice_size'] = self::SLICE_SIZE_3M;
  345. }
  346. $req = array(
  347. 'url' => $url,
  348. 'method' => 'post',
  349. 'timeout' => self::$timeout,
  350. 'data' => $data,
  351. 'header' => array(
  352. 'Authorization:'.$sign,
  353. ),
  354. );
  355. $ret = self::sendRequest($req);
  356. return $ret;
  357. }
  358. /**
  359. * 分片上传
  360. * @param int $fileSize 文件大小
  361. * @param string $sha1 文件sha值
  362. * @param int $sliceSize 文件分片大小
  363. * @param string $sign 签名
  364. * @param string $url url
  365. * @param string $srcPath 源文件路径
  366. * @param int $offset 文件偏移offset
  367. * @param string $session session
  368. * @return [type] array
  369. */
  370. private static function upload_data(
  371. $fileSize, $sha1, $sliceSize,
  372. $sign, $url, $srcPath,
  373. $offset, $session) {
  374. while ($fileSize > $offset) {
  375. $filecontent = file_get_contents(
  376. $srcPath, false, null,
  377. $offset, $sliceSize);
  378. if ($filecontent === false) {
  379. return array(
  380. 'code' => self::COSAPI_PARAMS_ERROR,
  381. 'message' => 'read file '.$srcPath.' error',
  382. 'data' => array(),
  383. );
  384. }
  385. $boundary = '---------------------------' . substr(md5(mt_rand()), 0, 10);
  386. $data = self::generateSliceBody(
  387. $filecontent, $offset, $sha1,
  388. $session, basename($srcPath), $boundary);
  389. $req = array(
  390. 'url' => $url,
  391. 'method' => 'post',
  392. 'timeout' => self::$timeout,
  393. 'data' => $data,
  394. 'header' => array(
  395. 'Authorization:'.$sign,
  396. 'Content-Type: multipart/form-data; boundary=' . $boundary,
  397. ),
  398. );
  399. $retry_times = 0;
  400. do {
  401. $ret = self::sendRequest($req);
  402. if ($ret['code'] == 0) {
  403. break;
  404. }
  405. $retry_times++;
  406. } while($retry_times < self::MAX_RETRY_TIMES);
  407. if($ret['code'] != 0) {
  408. return $ret;
  409. }
  410. if ($ret['data']['session']) {
  411. $session = $ret['data']['session'];
  412. }
  413. $offset += $sliceSize;
  414. }
  415. return $ret;
  416. }
  417. /**
  418. * 构造分片body体
  419. * @param string $fileContent 文件内容
  420. * @param string $offset 文件偏移
  421. * @param string $sha 文件sha值
  422. * @param string $session session
  423. * @param string $fileName 文件名
  424. * @param string $boundary 分隔符
  425. * @return [type]
  426. */
  427. private static function generateSliceBody(
  428. $fileContent, $offset, $sha,
  429. $session, $fileName, $boundary) {
  430. $formdata = '';
  431. $formdata .= '--' . $boundary . "\r\n";
  432. $formdata .= "content-disposition: form-data; name=\"op\"\r\n\r\nupload_slice\r\n";
  433. $formdata .= '--' . $boundary . "\r\n";
  434. $formdata .= "content-disposition: form-data; name=\"offset\"\r\n\r\n" . $offset. "\r\n";
  435. $formdata .= '--' . $boundary . "\r\n";
  436. $formdata .= "content-disposition: form-data; name=\"session\"\r\n\r\n" . $session . "\r\n";
  437. $formdata .= '--' . $boundary . "\r\n";
  438. $formdata .= "content-disposition: form-data; name=\"fileContent\"; filename=\"" . $fileName . "\"\r\n";
  439. $formdata .= "content-type: application/octet-stream\r\n\r\n";
  440. $data = $formdata . $fileContent . "\r\n--" . $boundary . "--\r\n";
  441. return $data;
  442. }
  443. /*
  444. * 内部公共函数
  445. * @param string $bucketName bucket名称
  446. * @param string $path 文件夹路径
  447. * @param int $num 拉取的总数
  448. * @param string $pattern eListBoth(默认),ListDirOnly,eListFileOnly
  449. * @param int $order 默认正序(=0), 填1为反序,
  450. * @param string $context 在翻页查询时候用到
  451. */
  452. private static function listBase(
  453. $bucketName, $path, $num = 20,
  454. $pattern = 'eListBoth', $order = 0, $context = null) {
  455. $path = self::cosUrlEncode($path);
  456. $expired = time() + self::EXPIRED_SECONDS;
  457. $url = self::generateResUrl($bucketName, $path);
  458. $sign = Auth::appSign($expired, $bucketName);
  459. $data = array(
  460. 'op' => 'list',
  461. );
  462. if (self::isPatternValid($pattern) == false)
  463. {
  464. return array(
  465. 'code' => self::COSAPI_PARAMS_ERROR,
  466. 'message' => 'parameter pattern invalid',
  467. );
  468. }
  469. $data['pattern'] = $pattern;
  470. if ($order != 0 && $order != 1)
  471. {
  472. return array(
  473. 'code' => self::COSAPI_PARAMS_ERROR,
  474. 'message' => 'parameter order invalid',
  475. );
  476. }
  477. $data['order'] = $order;
  478. if ($num < 0 || $num > 199)
  479. {
  480. return array(
  481. 'code' => self::COSAPI_PARAMS_ERROR,
  482. 'message' => 'parameter num invalid, num need less then 200',
  483. );
  484. }
  485. $data['num'] = $num;
  486. if (isset($context))
  487. {
  488. $data['context'] = $context;
  489. }
  490. $url = $url . '?' . http_build_query($data);
  491. $req = array(
  492. 'url' => $url,
  493. 'method' => 'get',
  494. 'timeout' => self::$timeout,
  495. 'header' => array(
  496. 'Authorization:'.$sign,
  497. ),
  498. );
  499. return self::sendRequest($req);
  500. }
  501. /*
  502. * 内部公共方法(更新文件和更新文件夹)
  503. * @param string $bucketName bucket名称
  504. * @param string $path 路径
  505. * @param string $bizAttr 文件/目录属性
  506. * @param string $authority: eInvalid/eWRPrivate(私有)/eWPrivateRPublic(公有读写)
  507. * @param array $customer_headers_array 携带的用户自定义头域,包括
  508. * 'Cache-Control' => '*'
  509. * 'Content-Type' => '*'
  510. * 'Content-Disposition' => '*'
  511. * 'Content-Language' => '*'
  512. * 'x-cos-meta-自定义内容' => '*'
  513. */
  514. private static function updateBase($bucketName, $path,
  515. $bizAttr = null, $authority = null, $custom_headers_array = null) {
  516. $path = self::cosUrlEncode($path);
  517. $expired = time() + self::EXPIRED_SECONDS;
  518. $url = self::generateResUrl($bucketName, $path);
  519. $sign = Auth::appSign_once(
  520. $path, $bucketName);
  521. $data = array(
  522. 'op' => 'update',
  523. );
  524. $flag = 0;
  525. if (isset($bizAttr))
  526. {
  527. $data['biz_attr'] = $bizAttr;
  528. $flag = $flag | 0x01;
  529. }
  530. if (isset($authority) && strlen($authority) > 0)
  531. {
  532. if(self::isAuthorityValid($authority) == false)
  533. {
  534. return array(
  535. 'code' => self::COSAPI_PARAMS_ERROR,
  536. 'message' => 'parameter authority invalid',
  537. );
  538. }
  539. $data['authority'] = $authority;
  540. $flag = $flag | 0x80;
  541. }
  542. if (isset($custom_headers_array))
  543. {
  544. $data['custom_headers'] = array();
  545. self::add_customer_header($data['custom_headers'], $custom_headers_array);
  546. $flag = $flag | 0x40;
  547. }
  548. if ($flag != 0 && $flag != 1)
  549. {
  550. $data['flag'] = $flag;
  551. }
  552. $data = json_encode($data);
  553. $req = array(
  554. 'url' => $url,
  555. 'method' => 'post',
  556. 'timeout' => self::$timeout,
  557. 'data' => $data,
  558. 'header' => array(
  559. 'Authorization:'.$sign,
  560. 'Content-Type: application/json',
  561. ),
  562. );
  563. return self::sendRequest($req);
  564. }
  565. /*
  566. * 内部方法
  567. * @param string $bucketName bucket名称
  568. * @param string $path 文件/目录路径
  569. */
  570. private static function statBase($bucketName, $path) {
  571. $path = self::cosUrlEncode($path);
  572. $expired = time() + self::EXPIRED_SECONDS;
  573. $url = self::generateResUrl($bucketName, $path);
  574. $sign = Auth::appSign($expired, $bucketName);
  575. $data = array(
  576. 'op' => 'stat',
  577. );
  578. $url = $url . '?' . http_build_query($data);
  579. $req = array(
  580. 'url' => $url,
  581. 'method' => 'get',
  582. 'timeout' => self::$timeout,
  583. 'header' => array(
  584. 'Authorization:'.$sign,
  585. ),
  586. );
  587. return self::sendRequest($req);
  588. }
  589. /*
  590. * 内部私有方法
  591. * @param string $bucketName bucket名称
  592. * @param string $path 文件/目录路径路径
  593. */
  594. private static function delBase($bucketName, $path) {
  595. if ($path == "/") {
  596. return array(
  597. 'code' => self::COSAPI_PARAMS_ERROR,
  598. 'message' => 'can not delete bucket using api! go to http://console.qcloud.com/cos to operate bucket',
  599. );
  600. }
  601. $path = self::cosUrlEncode($path);
  602. $expired = time() + self::EXPIRED_SECONDS;
  603. $url = self::generateResUrl($bucketName, $path);
  604. $sign = Auth::appSign_once(
  605. $path, $bucketName);
  606. $data = array(
  607. 'op' => 'delete',
  608. );
  609. $data = json_encode($data);
  610. $req = array(
  611. 'url' => $url,
  612. 'method' => 'post',
  613. 'timeout' => self::$timeout,
  614. 'data' => $data,
  615. 'header' => array(
  616. 'Authorization:'.$sign,
  617. 'Content-Type: application/json',
  618. ),
  619. );
  620. return self::sendRequest($req);
  621. }
  622. /*
  623. * 内部公共方法, 路径编码
  624. * @param string $path 待编码路径
  625. */
  626. private static function cosUrlEncode($path) {
  627. return str_replace('%2F', '/', rawurlencode($path));
  628. }
  629. /*
  630. * 内部公共方法, 构造URL
  631. * @param string $bucketName
  632. * @param string $dstPath
  633. */
  634. private static function generateResUrl($bucketName, $dstPath) {
  635. return Conf::API_COSAPI_END_POINT . Conf::APPID . '/' . $bucketName . $dstPath;
  636. }
  637. /*
  638. * 内部公共方法, 发送消息
  639. * @param string $req
  640. */
  641. private static function sendRequest($req) {
  642. $rsp = Http::send($req);
  643. $info = Http::info();
  644. $ret = json_decode($rsp, true);
  645. if ($ret) {
  646. if (0 === $ret['code']) {
  647. return $ret;
  648. } else {
  649. return array(
  650. 'code' => $ret['code'],
  651. 'message' => $ret['message'],
  652. 'data' => array()
  653. );
  654. }
  655. } else {
  656. return array(
  657. 'code' => self::COSAPI_NETWORK_ERROR,
  658. 'message' => $rsp,
  659. 'data' => array()
  660. );
  661. }
  662. }
  663. /**
  664. * 设置分片大小
  665. * @param string $sliceSize
  666. * @return [type] int
  667. */
  668. private static function getSliceSize($sliceSize)
  669. {
  670. $size = self::SLICE_SIZE_1M;
  671. if (!isset($sliceSize))
  672. {
  673. return $size;
  674. }
  675. if ($sliceSize <= self::SLICE_SIZE_512K)
  676. {
  677. $size = self::SLICE_SIZE_512K;
  678. }
  679. else if ($sliceSize <= self::SLICE_SIZE_1M)
  680. {
  681. $size = self::SLICE_SIZE_1M;
  682. }
  683. else if ($sliceSize <= self::SLICE_SIZE_2M)
  684. {
  685. $size = self::SLICE_SIZE_2M;
  686. }
  687. else
  688. {
  689. $size = self::SLICE_SIZE_3M;
  690. }
  691. return $size;
  692. }
  693. /*
  694. * 内部方法, 规整文件路径
  695. * @param string $path 文件路径
  696. * @param string $isfolder 是否为文件夹
  697. */
  698. private static function normalizerPath($path, $isfolder = False) {
  699. if (preg_match('/^\//', $path) == 0) {
  700. $path = '/' . $path;
  701. }
  702. if ($isfolder == True)
  703. {
  704. if (preg_match('/\/$/', $path) == 0) {
  705. $path = $path . '/';
  706. }
  707. }
  708. return $path;
  709. }
  710. /**
  711. * 判断authority值是否正确
  712. * @param string $authority
  713. * @return [type] bool
  714. */
  715. private static function isAuthorityValid($authority)
  716. {
  717. if ($authority == 'eInvalid'
  718. || $authority == 'eWRPrivate'
  719. || $authority == 'eWPrivateRPublic')
  720. {
  721. return true;
  722. }
  723. return false;
  724. }
  725. /**
  726. * 判断pattern值是否正确
  727. * @param string $authority
  728. * @return [type] bool
  729. */
  730. private static function isPatternValid($pattern)
  731. {
  732. if ($pattern == 'eListBoth'
  733. || $pattern == 'eListDirOnly'
  734. || $pattern == 'eListFileOnly')
  735. {
  736. return true;
  737. }
  738. return false;
  739. }
  740. /**
  741. * 判断是否符合自定义属性
  742. * @param string $key
  743. * @return [type] bool
  744. */
  745. private static function isCustomer_header($key)
  746. {
  747. if ($key == 'Cache-Control'
  748. || $key == 'Content-Type'
  749. || $key == 'Content-Disposition'
  750. || $key == 'Content-Language'
  751. || substr($key,0,strlen('x-cos-meta-')) == 'x-cos-meta-')
  752. {
  753. return true;
  754. }
  755. return false;
  756. }
  757. /**
  758. * 增加自定义属性到data中
  759. * @param array $data
  760. * @param array $customer_headers_array
  761. * @return [type] void
  762. */
  763. private static function add_customer_header(&$data, &$customer_headers_array)
  764. {
  765. if (count($customer_headers_array) < 1) return;
  766. foreach($customer_headers_array as $key=>$value)
  767. {
  768. if(self::isCustomer_header($key))
  769. {
  770. $data[$key] = $value;
  771. }
  772. }
  773. }
  774. }