├── LICENSE ├── Qcloud_cos ├── Auth.php ├── Conf.php ├── Cosapi.php └── Http.php ├── README.md ├── composer.json ├── include.php └── sample.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Qcloud_cos/Auth.php: -------------------------------------------------------------------------------- 1 | self::COSAPI_PARAMS_ERROR, 55 | 'message' => 'file '.$srcPath.' not exists', 56 | 'data' => array()); 57 | } 58 | 59 | //文件大于20M则使用分片传输 60 | if (filesize($srcPath) < self::MAX_UNSLICE_FILE_SIZE ) { 61 | return self::uploadfile($bucketName, $srcPath, $dstPath, $bizAttr, $insertOnly); 62 | } else { 63 | $sliceSize = self::getSliceSize($slicesize); 64 | return self::upload_slice($bucketName, $srcPath, $dstPath, $bizAttr, $sliceSize, $insertOnly); 65 | } 66 | } 67 | 68 | /* 69 | * 创建目录 70 | * @param string $bucketName bucket名称 71 | * @param string $path 目录路径 72 | * @param string $bizAttr 目录属性 73 | */ 74 | public static function createFolder($bucketName, $path, $bizAttr = null) { 75 | $path = self::normalizerPath($path, True); 76 | $path = self::cosUrlEncode($path); 77 | $expired = time() + self::EXPIRED_SECONDS; 78 | $url = self::generateResUrl($bucketName, $path); 79 | $sign = Auth::appSign($expired, $bucketName); 80 | 81 | $data = array( 82 | 'op' => 'create', 83 | 'biz_attr' => (isset($bizAttr) ? $bizAttr : ''), 84 | ); 85 | 86 | $data = json_encode($data); 87 | 88 | $req = array( 89 | 'url' => $url, 90 | 'method' => 'post', 91 | 'timeout' => self::$timeout, 92 | 'data' => $data, 93 | 'header' => array( 94 | 'Authorization:'.$sign, 95 | 'Content-Type: application/json', 96 | ), 97 | ); 98 | 99 | return self::sendRequest($req); 100 | } 101 | 102 | /* 103 | * 目录列表 104 | * @param string $bucketName bucket名称 105 | * @param string $path 目录路径,sdk会补齐末尾的 '/' 106 | * @param int $num 拉取的总数 107 | * @param string $pattern eListBoth,ListDirOnly,eListFileOnly 默认both 108 | * @param int $order 默认正序(=0), 填1为反序, 109 | * @param string $offset 透传字段,用于翻页,前端不需理解,需要往前/往后翻页则透传回来 110 | */ 111 | public static function listFolder( 112 | $bucketName, $path, $num = 20, 113 | $pattern = 'eListBoth', $order = 0, 114 | $context = null) { 115 | $path = self::normalizerPath($path,True); 116 | 117 | return self::listBase($bucketName, $path, $num, 118 | $pattern, $order, $context); 119 | } 120 | 121 | /* 122 | * 目录列表(前缀搜索) 123 | * @param string $bucketName bucket名称 124 | * @param string $prefix 列出含此前缀的所有文件 125 | * @param int $num 拉取的总数 126 | * @param string $pattern eListBoth(默认),ListDirOnly,eListFileOnly 127 | * @param int $order 默认正序(=0), 填1为反序, 128 | * @param string $offset 透传字段,用于翻页,前端不需理解,需要往前/往后翻页则透传回来 129 | */ 130 | public static function prefixSearch( 131 | $bucketName, $prefix, $num = 20, 132 | $pattern = 'eListBoth', $order = 0, 133 | $context = null) { 134 | $path = self::normalizerPath($prefix); 135 | 136 | return self::listBase($bucketName, $prefix, $num, 137 | $pattern, $order, $context); 138 | } 139 | 140 | /* 141 | * 目录更新 142 | * @param string $bucketName bucket名称 143 | * @param string $path 文件夹路径,SDK会补齐末尾的 '/' 144 | * @param string $bizAttr 目录属性 145 | */ 146 | public static function updateFolder($bucketName, $path, $bizAttr = null) { 147 | $path = self::normalizerPath($path, True); 148 | 149 | return self::updateBase($bucketName, $path, $bizAttr); 150 | } 151 | 152 | /* 153 | * 查询目录信息 154 | * @param string $bucketName bucket名称 155 | * @param string $path 目录路径 156 | */ 157 | public static function statFolder($bucketName, $path) { 158 | $path = self::normalizerPath($path, True); 159 | 160 | return self::statBase($bucketName, $path); 161 | } 162 | 163 | /* 164 | * 删除目录 165 | * @param string $bucketName bucket名称 166 | * @param string $path 目录路径 167 | * 注意不能删除bucket下根目录/ 168 | */ 169 | public static function delFolder($bucketName, $path) { 170 | $path = self::normalizerPath($path, True); 171 | 172 | return self::delBase($bucketName, $path); 173 | } 174 | 175 | /* 176 | * 更新文件 177 | * @param string $bucketName bucket名称 178 | * @param string $path 文件路径 179 | * @param string $authority: eInvalid(继承Bucket的读写权限)/eWRPrivate(私有读写)/eWPrivateRPublic(公有读私有写) 180 | * @param array $customer_headers_array 携带的用户自定义头域,包括 181 | * 'Cache-Control' => '*' 182 | * 'Content-Type' => '*' 183 | * 'Content-Disposition' => '*' 184 | * 'Content-Language' => '*' 185 | * 'x-cos-meta-自定义内容' => '*' 186 | */ 187 | public static function update($bucketName, $path, 188 | $bizAttr = null, $authority=null,$customer_headers_array=null) { 189 | $path = self::normalizerPath($path); 190 | 191 | return self::updateBase($bucketName, $path, $bizAttr, $authority, $customer_headers_array); 192 | } 193 | 194 | /* 195 | * 移动(重命名)文件 196 | * @param string $bucketName bucket名称 197 | * @param string $srcPath 源文件路径 198 | * @param string $dstPath 目的文件名(可以是单独文件名也可以是带目录的文件名) 199 | * @param string $toOverWrite 是否覆盖(当目的文件名已经存在同名文件时是否覆盖) 200 | */ 201 | public static function move($bucketName, $srcPath, $dstPath, $toOverWrite = 0) 202 | { 203 | $srcPath = self::cosUrlEncode($srcPath); 204 | $url = self::generateResUrl($bucketName,$srcPath); 205 | $sign = Auth::appSign_once($srcPath, $bucketName); 206 | $expired = time() + self::EXPIRED_SECONDS; 207 | 208 | $data = array( 209 | 'op' => 'move', 210 | 'dest_fileid' => $dstPath, 211 | 'to_over_write' => $toOverWrite, 212 | ); 213 | 214 | $data = json_encode($data); 215 | 216 | $req = array( 217 | 'url' => $url, 218 | 'method' => 'post', 219 | 'timeout' => self::$timeout, 220 | 'data' => $data, 221 | 'header' => array( 222 | 'Authorization: '.$sign, 223 | 'Content-Type: application/json', 224 | ), 225 | ); 226 | 227 | return self::sendRequest($req); 228 | } 229 | 230 | /* 231 | * 查询文件信息 232 | * @param string $bucketName bucket名称 233 | * @param string $path 文件路径 234 | */ 235 | public static function stat($bucketName, $path) { 236 | $path = self::normalizerPath($path); 237 | 238 | return self::statBase($bucketName, $path); 239 | } 240 | 241 | /* 242 | * 删除文件 243 | * @param string $bucketName 244 | * @param string $path 文件路径 245 | */ 246 | public static function delFile($bucketName, $path) { 247 | $path = self::normalizerPath($path); 248 | 249 | return self::delBase($bucketName, $path); 250 | } 251 | 252 | /** 253 | * 内部方法, 上传文件 254 | * @param string $bucketName bucket名称 255 | * @param string $srcPath 本地文件路径 256 | * @param string $dstPath 上传的文件路径 257 | * @param string $bizAttr 文件属性 258 | * @param int $insertOnly 是否覆盖同名文件:0 覆盖,1:不覆盖 259 | * @return [type] [description] 260 | */ 261 | private static function uploadfile($bucketName, $srcPath, $dstPath, $bizAttr = null, $insertOnly = null) 262 | { 263 | $srcPath = realpath($srcPath); 264 | $dstPath = self::cosUrlEncode($dstPath); 265 | 266 | if (filesize($srcPath) >= self::MAX_UNSLICE_FILE_SIZE ) 267 | { 268 | return array( 269 | 'code' => self::COSAPI_PARAMS_ERROR, 270 | 'message' => 'file '.$srcPath.' larger then 20M, please use upload_slice interface', 271 | 'data' => array()); 272 | } 273 | 274 | $expired = time() + self::EXPIRED_SECONDS; 275 | $url = self::generateResUrl($bucketName, $dstPath); 276 | $sign = Auth::appSign($expired, $bucketName); 277 | $sha1 = hash_file('sha1', $srcPath); 278 | 279 | $data = array( 280 | 'op' => 'upload', 281 | 'sha' => $sha1, 282 | 'biz_attr' => (isset($bizAttr) ? $bizAttr : ''), 283 | ); 284 | 285 | if (function_exists('curl_file_create')) { 286 | $data['filecontent'] = curl_file_create($srcPath); 287 | } else { 288 | $data['filecontent'] = '@'.$srcPath; 289 | } 290 | 291 | if (isset($insertOnly) && strlen($insertOnly) > 0) 292 | $data['insertOnly'] = (($insertOnly == 0 || $insertOnly == '0' ) ? 0 : 1); 293 | 294 | $req = array( 295 | 'url' => $url, 296 | 'method' => 'post', 297 | 'timeout' => self::$timeout, 298 | 'data' => $data, 299 | 'header' => array( 300 | 'Authorization:'.$sign, 301 | ), 302 | ); 303 | 304 | return self::sendRequest($req); 305 | } 306 | 307 | /** 308 | * 内部方法,上传文件 309 | * @param string $bucketName bucket名称 310 | * @param string $srcPath 本地文件路径 311 | * @param string $dstPath 上传的文件路径 312 | * @param string $bizAttr 文件属性 313 | * @param string $sliceSize 分片大小 314 | * @param int $insertOnly 是否覆盖同名文件:0 覆盖,1:不覆盖 315 | * @return [type] [description] 316 | */ 317 | private static function upload_slice( 318 | $bucketName, $srcPath, $dstPath, 319 | $bizAttr = null, $sliceSize = null, $insertOnly=null) { 320 | 321 | $srcPath = realpath($srcPath); 322 | $fileSize = filesize($srcPath); 323 | $dstPath = self::cosUrlEncode($dstPath); 324 | 325 | $expired = time() + self::EXPIRED_SECONDS; 326 | $url = self::generateResUrl($bucketName, $dstPath); 327 | $sign = Auth::appSign($expired, $bucketName); 328 | $sha1 = hash_file('sha1', $srcPath); 329 | 330 | $ret = self::upload_prepare( 331 | $fileSize, $sha1, $sliceSize, 332 | $sign, $url, $bizAttr, $insertOnly); 333 | 334 | if($ret['code'] != 0) { 335 | return $ret; 336 | } 337 | 338 | if(isset($ret['data']) 339 | && isset($ret['data']['url'])) { 340 | //秒传命中,直接返回了url 341 | return $ret; 342 | } 343 | 344 | $sliceSize = $ret['data']['slice_size']; 345 | if ($sliceSize > self::SLICE_SIZE_3M || 346 | $sliceSize <= 0) { 347 | $ret['code'] = self::COSAPI_PARAMS_ERROR; 348 | $ret['message'] = 'illegal slice size'; 349 | return $ret; 350 | } 351 | 352 | $session = $ret['data']['session']; 353 | $offset = $ret['data']['offset']; 354 | 355 | $sliceCnt = ceil($fileSize / $sliceSize); 356 | // expired seconds for one slice mutiply by slice count 357 | // will be the expired seconds for whole file 358 | $expired = time() + (self::EXPIRED_SECONDS * $sliceCnt); 359 | $sign = Auth::appSign($expired, $bucketName); 360 | 361 | $ret = self::upload_data( 362 | $fileSize, $sha1, $sliceSize, 363 | $sign, $url, $srcPath, 364 | $offset, $session); 365 | return $ret; 366 | } 367 | 368 | /** 369 | * 第一个分片控制消息 370 | * @param string $fileSize 文件大小 371 | * @param string $sha1 文件sha值 372 | * @param string $sliceSize 分片大小 373 | * @param string $sign 签名 374 | * @param string $url URL 375 | * @param string $bizAttr 文件属性 376 | * @param string $insertOnly 同名文件是否覆盖 377 | * @return [type] 378 | */ 379 | private static function upload_prepare( 380 | $fileSize, $sha1, $sliceSize, 381 | $sign, $url, $bizAttr = null, $insertOnly = null) { 382 | 383 | $data = array( 384 | 'op' => 'upload_slice', 385 | 'filesize' => $fileSize, 386 | 'sha' => $sha1, 387 | ); 388 | 389 | if (isset($bizAttr) && strlen($bizAttr)) 390 | $data['biz_attr'] = $bizAttr; 391 | 392 | if (isset($insertOnly)) 393 | $data['insertOnly'] = (($insertOnly == 0) ? 0 : 1); 394 | 395 | if ($sliceSize <= self::SLICE_SIZE_3M) { 396 | $data['slice_size'] = $sliceSize; 397 | } else { 398 | $data['slice_size'] = self::SLICE_SIZE_3M; 399 | } 400 | 401 | $req = array( 402 | 'url' => $url, 403 | 'method' => 'post', 404 | 'timeout' => self::$timeout, 405 | 'data' => $data, 406 | 'header' => array( 407 | 'Authorization:'.$sign, 408 | ), 409 | ); 410 | 411 | $ret = self::sendRequest($req); 412 | return $ret; 413 | } 414 | 415 | /** 416 | * 分片上传 417 | * @param int $fileSize 文件大小 418 | * @param string $sha1 文件sha值 419 | * @param int $sliceSize 文件分片大小 420 | * @param string $sign 签名 421 | * @param string $url url 422 | * @param string $srcPath 源文件路径 423 | * @param int $offset 文件偏移offset 424 | * @param string $session session 425 | * @return [type] array 426 | */ 427 | private static function upload_data( 428 | $fileSize, $sha1, $sliceSize, 429 | $sign, $url, $srcPath, 430 | $offset, $session) { 431 | 432 | while ($fileSize > $offset) { 433 | $filecontent = file_get_contents( 434 | $srcPath, false, null, 435 | $offset, $sliceSize); 436 | 437 | if ($filecontent === false) { 438 | return array( 439 | 'code' => self::COSAPI_PARAMS_ERROR, 440 | 'message' => 'read file '.$srcPath.' error', 441 | 'data' => array(), 442 | ); 443 | } 444 | 445 | $boundary = '---------------------------' . substr(md5(mt_rand()), 0, 10); 446 | $data = self::generateSliceBody( 447 | $filecontent, $offset, $sha1, 448 | $session, basename($srcPath), $boundary); 449 | 450 | $req = array( 451 | 'url' => $url, 452 | 'method' => 'post', 453 | 'timeout' => self::$timeout, 454 | 'data' => $data, 455 | 'header' => array( 456 | 'Authorization:'.$sign, 457 | 'Content-Type: multipart/form-data; boundary=' . $boundary, 458 | ), 459 | ); 460 | 461 | $retry_times = 0; 462 | do { 463 | $ret = self::sendRequest($req); 464 | if ($ret['code'] == 0) { 465 | break; 466 | } 467 | $retry_times++; 468 | } while($retry_times < self::MAX_RETRY_TIMES); 469 | 470 | if($ret['code'] != 0) { 471 | return $ret; 472 | } 473 | 474 | if ($ret['data']['session']) { 475 | $session = $ret['data']['session']; 476 | } 477 | 478 | $offset += $sliceSize; 479 | } 480 | 481 | return $ret; 482 | } 483 | 484 | 485 | /** 486 | * 构造分片body体 487 | * @param string $fileContent 文件内容 488 | * @param string $offset 文件偏移 489 | * @param string $sha 文件sha值 490 | * @param string $session session 491 | * @param string $fileName 文件名 492 | * @param string $boundary 分隔符 493 | * @return [type] 494 | */ 495 | private static function generateSliceBody( 496 | $fileContent, $offset, $sha, 497 | $session, $fileName, $boundary) { 498 | $formdata = ''; 499 | 500 | $formdata .= '--' . $boundary . "\r\n"; 501 | $formdata .= "content-disposition: form-data; name=\"op\"\r\n\r\nupload_slice\r\n"; 502 | 503 | $formdata .= '--' . $boundary . "\r\n"; 504 | $formdata .= "content-disposition: form-data; name=\"offset\"\r\n\r\n" . $offset. "\r\n"; 505 | 506 | $formdata .= '--' . $boundary . "\r\n"; 507 | $formdata .= "content-disposition: form-data; name=\"session\"\r\n\r\n" . $session . "\r\n"; 508 | 509 | $formdata .= '--' . $boundary . "\r\n"; 510 | $formdata .= "content-disposition: form-data; name=\"fileContent\"; filename=\"" . $fileName . "\"\r\n"; 511 | $formdata .= "content-type: application/octet-stream\r\n\r\n"; 512 | 513 | $data = $formdata . $fileContent . "\r\n--" . $boundary . "--\r\n"; 514 | 515 | return $data; 516 | } 517 | 518 | /* 519 | * 内部公共函数 520 | * @param string $bucketName bucket名称 521 | * @param string $path 文件夹路径 522 | * @param int $num 拉取的总数 523 | * @param string $pattern eListBoth(默认),ListDirOnly,eListFileOnly 524 | * @param int $order 默认正序(=0), 填1为反序, 525 | * @param string $context 在翻页查询时候用到 526 | */ 527 | private static function listBase( 528 | $bucketName, $path, $num = 20, 529 | $pattern = 'eListBoth', $order = 0, $context = null) { 530 | 531 | $path = self::cosUrlEncode($path); 532 | $expired = time() + self::EXPIRED_SECONDS; 533 | $url = self::generateResUrl($bucketName, $path); 534 | $sign = Auth::appSign($expired, $bucketName); 535 | 536 | $data = array( 537 | 'op' => 'list', 538 | ); 539 | 540 | if (self::isPatternValid($pattern) == false) 541 | { 542 | return array( 543 | 'code' => self::COSAPI_PARAMS_ERROR, 544 | 'message' => 'parameter pattern invalid', 545 | ); 546 | } 547 | $data['pattern'] = $pattern; 548 | 549 | if ($order != 0 && $order != 1) 550 | { 551 | return array( 552 | 'code' => self::COSAPI_PARAMS_ERROR, 553 | 'message' => 'parameter order invalid', 554 | ); 555 | } 556 | $data['order'] = $order; 557 | 558 | if ($num < 0 || $num > 199) 559 | { 560 | return array( 561 | 'code' => self::COSAPI_PARAMS_ERROR, 562 | 'message' => 'parameter num invalid, num need less then 200', 563 | ); 564 | } 565 | $data['num'] = $num; 566 | 567 | if (isset($context)) 568 | { 569 | $data['context'] = $context; 570 | } 571 | 572 | $url = $url . '?' . http_build_query($data); 573 | 574 | $req = array( 575 | 'url' => $url, 576 | 'method' => 'get', 577 | 'timeout' => self::$timeout, 578 | 'header' => array( 579 | 'Authorization:'.$sign, 580 | ), 581 | ); 582 | 583 | return self::sendRequest($req); 584 | } 585 | 586 | /* 587 | * 内部公共方法(更新文件和更新文件夹) 588 | * @param string $bucketName bucket名称 589 | * @param string $path 路径 590 | * @param string $bizAttr 文件/目录属性 591 | * @param string $authority: eInvalid/eWRPrivate(私有)/eWPrivateRPublic(公有读写) 592 | * @param array $customer_headers_array 携带的用户自定义头域,包括 593 | * 'Cache-Control' => '*' 594 | * 'Content-Type' => '*' 595 | * 'Content-Disposition' => '*' 596 | * 'Content-Language' => '*' 597 | * 'x-cos-meta-自定义内容' => '*' 598 | */ 599 | private static function updateBase($bucketName, $path, 600 | $bizAttr = null, $authority = null, $custom_headers_array = null) { 601 | 602 | $path = self::cosUrlEncode($path); 603 | $expired = time() + self::EXPIRED_SECONDS; 604 | $url = self::generateResUrl($bucketName, $path); 605 | $sign = Auth::appSign_once( 606 | $path, $bucketName); 607 | 608 | $data = array( 609 | 'op' => 'update', 610 | ); 611 | 612 | $flag = 0; 613 | if (isset($bizAttr)) 614 | { 615 | $data['biz_attr'] = $bizAttr; 616 | $flag = $flag | 0x01; 617 | } 618 | 619 | if (isset($authority) && strlen($authority) > 0) 620 | { 621 | if(self::isAuthorityValid($authority) == false) 622 | { 623 | return array( 624 | 'code' => self::COSAPI_PARAMS_ERROR, 625 | 'message' => 'parameter authority invalid', 626 | ); 627 | } 628 | 629 | $data['authority'] = $authority; 630 | $flag = $flag | 0x80; 631 | } 632 | 633 | if (isset($custom_headers_array)) 634 | { 635 | $data['custom_headers'] = array(); 636 | self::add_customer_header($data['custom_headers'], $custom_headers_array); 637 | $flag = $flag | 0x40; 638 | } 639 | 640 | if ($flag != 0 && $flag != 1) 641 | { 642 | $data['flag'] = $flag; 643 | } 644 | 645 | $data = json_encode($data); 646 | 647 | $req = array( 648 | 'url' => $url, 649 | 'method' => 'post', 650 | 'timeout' => self::$timeout, 651 | 'data' => $data, 652 | 'header' => array( 653 | 'Authorization:'.$sign, 654 | 'Content-Type: application/json', 655 | ), 656 | ); 657 | 658 | return self::sendRequest($req); 659 | } 660 | 661 | 662 | /* 663 | * 内部方法 664 | * @param string $bucketName bucket名称 665 | * @param string $path 文件/目录路径 666 | */ 667 | private static function statBase($bucketName, $path) { 668 | 669 | $path = self::cosUrlEncode($path); 670 | $expired = time() + self::EXPIRED_SECONDS; 671 | $url = self::generateResUrl($bucketName, $path); 672 | $sign = Auth::appSign($expired, $bucketName); 673 | 674 | $data = array( 675 | 'op' => 'stat', 676 | ); 677 | 678 | $url = $url . '?' . http_build_query($data); 679 | 680 | $req = array( 681 | 'url' => $url, 682 | 'method' => 'get', 683 | 'timeout' => self::$timeout, 684 | 'header' => array( 685 | 'Authorization:'.$sign, 686 | ), 687 | ); 688 | 689 | return self::sendRequest($req); 690 | } 691 | 692 | /* 693 | * 内部私有方法 694 | * @param string $bucketName bucket名称 695 | * @param string $path 文件/目录路径路径 696 | */ 697 | private static function delBase($bucketName, $path) { 698 | if ($path == "/") { 699 | return array( 700 | 'code' => self::COSAPI_PARAMS_ERROR, 701 | 'message' => 'can not delete bucket using api! go to http://console.qcloud.com/cos to operate bucket', 702 | ); 703 | } 704 | 705 | $path = self::cosUrlEncode($path); 706 | $expired = time() + self::EXPIRED_SECONDS; 707 | $url = self::generateResUrl($bucketName, $path); 708 | $sign = Auth::appSign_once( 709 | $path, $bucketName); 710 | 711 | $data = array( 712 | 'op' => 'delete', 713 | ); 714 | 715 | $data = json_encode($data); 716 | 717 | $req = array( 718 | 'url' => $url, 719 | 'method' => 'post', 720 | 'timeout' => self::$timeout, 721 | 'data' => $data, 722 | 'header' => array( 723 | 'Authorization:'.$sign, 724 | 'Content-Type: application/json', 725 | ), 726 | ); 727 | 728 | return self::sendRequest($req); 729 | } 730 | 731 | /* 732 | * 内部公共方法, 路径编码 733 | * @param string $path 待编码路径 734 | */ 735 | private static function cosUrlEncode($path) { 736 | return str_replace('%2F', '/', rawurlencode($path)); 737 | } 738 | 739 | /* 740 | * 内部公共方法, 构造URL 741 | * @param string $bucketName 742 | * @param string $dstPath 743 | */ 744 | private static function generateResUrl($bucketName, $dstPath) { 745 | return Conf::API_COSAPI_END_POINT . Conf::APPID . '/' . $bucketName . $dstPath; 746 | } 747 | 748 | /* 749 | * 内部公共方法, 发送消息 750 | * @param string $req 751 | */ 752 | private static function sendRequest($req) { 753 | $rsp = Http::send($req); 754 | $info = Http::info(); 755 | $ret = json_decode($rsp, true); 756 | 757 | if ($ret) { 758 | if (0 === $ret['code']) { 759 | return $ret; 760 | } else { 761 | return array( 762 | 'code' => $ret['code'], 763 | 'message' => $ret['message'], 764 | 'data' => array() 765 | ); 766 | } 767 | } else { 768 | return array( 769 | 'code' => self::COSAPI_NETWORK_ERROR, 770 | 'message' => $rsp, 771 | 'data' => array() 772 | ); 773 | } 774 | } 775 | 776 | /** 777 | * 设置分片大小 778 | * @param string $sliceSize 779 | * @return [type] int 780 | */ 781 | private static function getSliceSize($sliceSize) 782 | { 783 | $size = self::SLICE_SIZE_1M; 784 | if (!isset($sliceSize)) 785 | { 786 | return $size; 787 | } 788 | 789 | if ($sliceSize <= self::SLICE_SIZE_512K) 790 | { 791 | $size = self::SLICE_SIZE_512K; 792 | } 793 | else if ($sliceSize <= self::SLICE_SIZE_1M) 794 | { 795 | $size = self::SLICE_SIZE_1M; 796 | } 797 | else if ($sliceSize <= self::SLICE_SIZE_2M) 798 | { 799 | $size = self::SLICE_SIZE_2M; 800 | } 801 | else 802 | { 803 | $size = self::SLICE_SIZE_3M; 804 | } 805 | 806 | return $size; 807 | } 808 | 809 | /* 810 | * 内部方法, 规整文件路径 811 | * @param string $path 文件路径 812 | * @param string $isfolder 是否为文件夹 813 | */ 814 | private static function normalizerPath($path, $isfolder = False) { 815 | 816 | if (preg_match('/^\//', $path) == 0) { 817 | $path = '/' . $path; 818 | } 819 | 820 | if ($isfolder == True) 821 | { 822 | if (preg_match('/\/$/', $path) == 0) { 823 | $path = $path . '/'; 824 | } 825 | } 826 | 827 | return $path; 828 | } 829 | 830 | /** 831 | * 判断authority值是否正确 832 | * @param string $authority 833 | * @return [type] bool 834 | */ 835 | private static function isAuthorityValid($authority) 836 | { 837 | if ($authority == 'eInvalid' 838 | || $authority == 'eWRPrivate' 839 | || $authority == 'eWPrivateRPublic') 840 | { 841 | return true; 842 | } 843 | return false; 844 | } 845 | 846 | /** 847 | * 判断pattern值是否正确 848 | * @param string $authority 849 | * @return [type] bool 850 | */ 851 | private static function isPatternValid($pattern) 852 | { 853 | if ($pattern == 'eListBoth' 854 | || $pattern == 'eListDirOnly' 855 | || $pattern == 'eListFileOnly') 856 | { 857 | return true; 858 | } 859 | return false; 860 | } 861 | 862 | /** 863 | * 判断是否符合自定义属性 864 | * @param string $key 865 | * @return [type] bool 866 | */ 867 | private static function isCustomer_header($key) 868 | { 869 | if ($key == 'Cache-Control' 870 | || $key == 'Content-Type' 871 | || $key == 'Content-Disposition' 872 | || $key == 'Content-Language' 873 | || substr($key,0,strlen('x-cos-meta-')) == 'x-cos-meta-') 874 | { 875 | return true; 876 | } 877 | return false; 878 | } 879 | 880 | /** 881 | * 增加自定义属性到data中 882 | * @param array $data 883 | * @param array $customer_headers_array 884 | * @return [type] void 885 | */ 886 | private static function add_customer_header(&$data, &$customer_headers_array) 887 | { 888 | if (count($customer_headers_array) < 1) return; 889 | foreach($customer_headers_array as $key=>$value) 890 | { 891 | if(self::isCustomer_header($key)) 892 | { 893 | $data[$key] = $value; 894 | } 895 | } 896 | } 897 | } 898 | 899 | -------------------------------------------------------------------------------- /Qcloud_cos/Http.php: -------------------------------------------------------------------------------- 1 | "no", 59 | 'Content-Type' => "application/pdf", 60 | 'Content-Language' => "ch", 61 | ); 62 | $updateRet = Cosapi::update($bucketName, $dstPath, $bizAttr,$authority, $customer_headers_array); 63 | var_dump($updateRet); 64 | 65 | //查询目录信息 66 | $statRet = Cosapi::statFolder($bucketName, $dstFolder); 67 | var_dump($statRet); 68 | 69 | //查询文件信息 70 | $statRet = Cosapi::stat($bucketName, $dstPath); 71 | var_dump($statRet); 72 | 73 | //删除文件 74 | $delRet = Cosapi::delFile($bucketName, $dstPath); 75 | var_dump($delRet); 76 | 77 | //删除目录 78 | $delRet = Cosapi::delFolder($bucketName, $dstFolder); 79 | var_dump($delRet); 80 | ``` 81 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tencentyun/cos-php-sdk", 3 | "keywords": ["tencentyun", "qcloud", "sdk"], 4 | "homepage": "http://www.qcloud.com/", 5 | "license": "MIT", 6 | "description": "php sdk for www.qcloud.com cos service", 7 | "require": { 8 | "php": ">=5.3.0" 9 | }, 10 | "autoload": { 11 | "psr-4": {"Qcloud_cos\\": "Qcloud_cos"} 12 | } 13 | } -------------------------------------------------------------------------------- /include.php: -------------------------------------------------------------------------------- 1 | = php 5.3.0 4 | spl_autoload_register(function($class){ 5 | $dir = dirname(__FILE__); 6 | $class = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'; 7 | include($dir.DIRECTORY_SEPARATOR.$class); 8 | }); -------------------------------------------------------------------------------- /sample.php: -------------------------------------------------------------------------------- 1 | "no", 42 | 'Content-Type' => "application/pdf", 43 | 'Content-Language' => "ch", 44 | ); 45 | $updateRet = Cosapi::update($bucketName, $dstPath, $bizAttr,$authority, $customer_headers_array); 46 | var_dump($updateRet); 47 | 48 | //查询目录信息 49 | $statRet = Cosapi::statFolder($bucketName, $dstFolder); 50 | var_dump($statRet); 51 | 52 | //查询文件信息 53 | $statRet = Cosapi::stat($bucketName, $dstPath); 54 | var_dump($statRet); 55 | 56 | //删除文件 57 | $delRet = Cosapi::delFile($bucketName, $dstPath); 58 | var_dump($delRet); 59 | 60 | //删除目录 61 | $delRet = Cosapi::delFolder($bucketName, $dstFolder); 62 | var_dump($delRet); --------------------------------------------------------------------------------