Cosapi.php 25 KB

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