From 2e7257b7b29011ab985bb9c0553b6d72d2a10e50 Mon Sep 17 00:00:00 2001 From: droomo Date: Wed, 30 Sep 2015 03:26:19 +0800 Subject: [PATCH] first commit --- AliOssSdk/alioss.class.php | 3 + AliOssSdk/conf.inc.php | 13 + AliOssSdk/docs/oss-php-sdk.md | 2140 +++++++++++++++++ AliOssSdk/lang/zh.inc.php | 99 + AliOssSdk/lib/requestcore/LICENSE | 25 + AliOssSdk/lib/requestcore/README.md | 15 + .../lib/requestcore/requestcore.class.php | 1030 ++++++++ AliOssSdk/sdk.class.php | 2104 ++++++++++++++++ AliOssSdk/thirdparty/xml2array.class.php | 139 ++ AliOssSdk/util/mimetypes.class.php | 240 ++ AliOssSdk/util/oss_util.class.php | 434 ++++ Plugin.php | 586 +++++ 12 files changed, 6828 insertions(+) create mode 100644 AliOssSdk/alioss.class.php create mode 100644 AliOssSdk/conf.inc.php create mode 100644 AliOssSdk/docs/oss-php-sdk.md create mode 100644 AliOssSdk/lang/zh.inc.php create mode 100644 AliOssSdk/lib/requestcore/LICENSE create mode 100644 AliOssSdk/lib/requestcore/README.md create mode 100644 AliOssSdk/lib/requestcore/requestcore.class.php create mode 100644 AliOssSdk/sdk.class.php create mode 100644 AliOssSdk/thirdparty/xml2array.class.php create mode 100644 AliOssSdk/util/mimetypes.class.php create mode 100644 AliOssSdk/util/oss_util.class.php create mode 100644 Plugin.php diff --git a/AliOssSdk/alioss.class.php b/AliOssSdk/alioss.class.php new file mode 100644 index 0000000..9428f14 --- /dev/null +++ b/AliOssSdk/alioss.class.php @@ -0,0 +1,3 @@ +set_enable_domain_style(true); + + ` + +* 使用sts方式初始化ALIOSS + * 如果是移动端的开发者,需要使用sts服务,只需要在初始化的时候调用sts的api生成临时的accessId,accessKey,以及securityToken即可。 + + ` + $access_id = "调用sts接口得到的临时access_id"; + $access_key = "调用sts接口得到的临时access_key"; + $end_point = "操作集群的endpoint"; + $security_token = "调用sts接口得到的临时security_token"; + $client = ALIOSS($access_id,$access_key,$end_point,$security_token); + + ` + +## Bucket相关操作 +* 获取bucket列表 + * 示例代码 + + ` + $options = null; + $response = $client->list_bucket($options); + + ` + * 参数说明 + + ` + $options 可选参数,无需设置 + + ` + * 响应结果 + 、 + 将结果Response转换成array得到,下同 + Array( + [status] => 200 + [header] => Array( + [date] => Wed, 01 Jul 2015 09:21:15 GMT + [content-type] => application/xml + [content-length] => 6266 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5593B10B58DB3AB752154A62 + ) + [body] => Array( + [ListAllMyBucketsResult] => Array( + [Owner] => Array ( + [ID] => 128257 + [DisplayName] => 128257 + ) + [Buckets] => Array( + [Bucket] => Array( + [0] => Array( + [Location] => oss-cn-hangzhou + [Name] => 33331111 + [CreationDate] => 2014-08-27T03:04:20.000Z + ) + [1] => Array ( + [Location] => oss-cn-qingdao + [Name] => a-00000000000000000001 + [CreationDate] => 2015-05-22T05:30:40.000Z + ) + + ) + + ) + + ) + + ) + + ) + 、 +* 创建bucket + * 示例代码 + + ` + $bucket_name = "bucket name"; + $acl = ALIOSS::OSS_ACL_TYPE_PRIVATE; + $options = null; + $response = $client->create_bucket($bucket_name,$acl,$options); + + ` + * 参数说明 + + ` + + $bucket_name 必选参数,需要符合bucket命名规范 + $acl 必选参数,只能从private,public-read,public-read-write中任选一个,分别和以下常量映射 + ALIOSS::OSS_ACL_TYPE_PRIVATE, + ALIOSS::OSS_ACL_TYPE_PUBLIC_READ, + ALIOSS::OSS_ACL_TYPE_PUBLIC_READ_WRITE + $options 可选参数,无需设置 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + Array( + [status] => 200 + [header] => Array( + [date] => Wed, 01 Jul 2015 09:55:18 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5593B906031C87E546154CC1 + ) + + [body] => + ) + + ` + +* 删除bucket + * 示例代码 + + ` + + $bucket_name = "bucket name"; + $options = null; + $response = $client->delete_bucket($bucket_name,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,需要符合bucket命名规范 + $options 可选参数,无需设置 + + ` + * 响应结果 + + ` + + 将结果Response转换成array得到,下同 + Array( + [status] => 204 + [header] => Array( + [date] => Wed, 01 Jul 2015 10:08:45 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5593BC2D58DB3AB752155156 + ) + + [body] => + ) + + ` +* 获取bucket Acl + * 示例代码 + + ` + + $bucket_name = "bucket name"; + $options = null; + $response = $client->get_bucket_acl($bucket_name,$options); + + + ` + * 参数说明 + + ` + $bucket_name 必选参数,需要符合bucket命名规范 + $options 可选参数,无需设置 + + ` + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Wed, 01 Jul 2015 10:17:41 GMT + [content-type] => application/xml + [content-length] => 239 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5593BE45031C87E54615500F + ) + + [body] => Array( + [AccessControlPolicy] => Array( + [Owner] => Array( + [ID] => 128257 + [DisplayName] => 128257 + ) + + [AccessControlList] => Array( + [Grant] => public-read + ) + ) + ) + ) + + ` + +* 设置bucket Acl + * 示例代码 + + ` + $bucket_name = "bucket name"; + $options = null; + $response = $client->set_bucket_acl($bucket_name,$options); + ` + + * 参数说明 + + ` + $bucket_name 必选参数,需要符合bucket命名规范 + $options 可选参数,无需设置 + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + Array( + [status] => 200 + [header] => Array( + [date] => Wed, 01 Jul 2015 11:08:31 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5593CA2F031C87E5461557B5 + ) + + [body] => + ) + ` + +## Object相关操作 +* 获取Object列表 + * 示例代码 + + ` + $bucket_name = 'bucket name'; + $options = array( + 'delimiter' => '/', + 'prefix' => '', + 'max-keys' => 5, + 'marker' => '', + ); + + $response = $client->list_object($$bucket_name,$options); + + ` + + + * 参数说明 + + + ` + + $bucket_name 必选参数,需要符合bucket命名规范 + $options 可选参数,其中的参数说明如下 + delimiter 是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter + 字符之间的object作为一组元素——CommonPrefixes。 + prefix 限定返回的object key必须以prefix作为前缀。注意使用prefix查询时,返回的key中 + 仍会包含prefix + max-keys 限定此次返回object的最大数,如果不设定,默认为100,max-keys取值不能大于1000 + marker 设定结果从marker之后按字母排序的第一个开始返回 + + ` + + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 07:59:32 GMT + [content-type] => application/xml + [content-length] => 1466 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594EF64031C87E546160F24 + ) + + [body] => Array( + [ListBucketResult] => Array( + [Name] => common-bucket + [Prefix] => + [Marker] => + [MaxKeys] => 5 + [Delimiter] => / + [IsTruncated] => true + [NextMarker] => metro_driver.dll + [Contents] => Array( + [0] => Array( + [Key] => chrome_elf.dll + [LastModified] => 2015-07-01T03:44:58.000Z + [ETag] => "78CE940FD1CCDF6F743EE1A9AED8AAD8" + [Type] => Normal + [Size] => 133960 + [StorageClass] => Standard + [Owner] => Array( + [ID] => 128257 + [DisplayName] => 128257 + ) + ) + + [1] => Array( + [Key] => delegate_execute.exe + [LastModified] => 2015-06-29T09:18:41.000Z + [ETag] => "37C49C4E0EC4E0D96B6EBBA2190E8824" + [Type] => Normal + [Size] => 692040 + [StorageClass] => Standard + [Owner] => Array( + [ID] => 128257 + [DisplayName] => 128257 + ) + ) + } + + [CommonPrefixes] => Array( + [0] => Array( + [Prefix] => common-folder/ + ) + + [1] => Array( + [Prefix] => common-folder2/ + ) + ) + ) + ) + ) + + ` + + +* 创建虚拟文件夹 + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $dir_name = 'directory name'; + $options = null; + $response = $client->create_object_dir($bucket_name,$dir_name,$options); + + ` + + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $dir_name 必选参数,必须符合object命名规范 + $options 可选参数,对于虚拟文件夹而言,无需设置一些header头 + + + ` + + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 08:10:16 GMT + [content-length] => 0 + [connection] => close + [etag] => "D41D8CD98F00B204E9800998ECF8427E" + [server] => AliyunOSS + [x-oss-request-id] => 5594F1E8031C87E5461610B9 + ) + + [body] => + ) + + ` + + +* 上传文件(直接指定内容) + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name = 'object name'; + $content = 'object content'; + $options = array( + 'content' => $content, + 'length' => strlen($content), + ALIOSS::OSS_HEADERS => array( + 'Expires' => 'Fri, 28 Feb 2012 05:38:42 GMT', + 'Cache-Control' => 'no-cache', + 'Content-Disposition' => 'attachment;filename=oss_download.log', + 'Content-Encoding' => 'utf-8', + 'Content-Language' => 'zh-CN', + 'x-oss-server-side-encryption' => 'AES256', + ), + ); + $response = $obj->upload_file_by_content($bucket_name,$object_name,$options); + + ` + + * 参数说明 + + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $object_name 必选参数,必须符合object命名规范 + $options 必选参数,该参内指定上传所需要的各种信息,具体各参数说明如下 + content 上传object的内容 + length 上传object的大小 + ALIOSS::OSS_HEADERS 该参数可选,如果指定,则可以设置该object的一些meta信息,可以设置的头信息如下: + Expires 过期时间(milliseconds) + Cache-Control 指定该Object被下载时的网页的缓存行为 + Content-Disposition 指定该Object被下载时的名称 + Content-Encoding 指定该Object被下载时的内容编码格式 + Content-Language 指定object被下载时候的语言 + x-oss-server-side-encryption 指定oss创建object时的服务器端加密编码算法 + + ` + + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 08:24:11 GMT + [content-length] => 0 + [connection] => close + [etag] => "9BA9EF6DDFBE14916FA2D3337B427774" + [server] => AliyunOSS + [x-oss-request-id] => 5594F52B031C87E5461612D1 + ) + + [body] => + ) + + ` + +* 上传文件(指定上传路径) + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name = 'object name'; + $file_path = "upload file path"; + $options = array( + ALIOSS::OSS_HEADERS => array( + 'Expires' => 'Fri, 28 Feb 2012 05:38:42 GMT', + 'Cache-Control' => 'no-cache', + 'Content-Disposition' => 'attachment;filename=oss_download.gz', + 'Content-Encoding' => 'utf-8', + 'Content-Language' => 'zh-CN', + 'x-oss-server-side-encryption' => 'AES256', + + ), + ); + $response = $obj->upload_file_by_file($bucket,$object,$file_path,$upload_file_options); + + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $object_name 必选参数,必须符合object命名规范 + $file_path 必选参数,文件所在的路径 + $options 必选参数,该参内指定上传所需要的各种信息,具体各参数说明如下 + content 上传object的内容 + length 上传object的大小 + ALIOSS::OSS_HEADERS 该参数可选,如果指定,则可以设置该object的一些meta信息,可以设置的头信息如下: + Expires 过期时间(milliseconds) + Cache-Control 指定该Object被下载时的网页的缓存行为 + Content-Disposition 指定该Object被下载时的名称 + Content-Encoding 指定该Object被下载时的内容编码格式 + Content-Language 指定object被下载时候的语言 + x-oss-server-side-encryption 指定oss创建object时的服务器端加密编码算法 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 08:41:10 GMT + [content-length] => 0 + [connection] => close + [etag] => "4B12FF064A3BBFE0AE5A1314E77FF0DF" + [server] => AliyunOSS + [x-oss-request-id] => 5594F91358DB3AB7521617CA + ) + + [body] => + ) + + ` + + +* 拷贝Object + * 示例代码 + + ` + + $from_bucket = 'copy from bucket'; + $from_object = 'copy from object'; + $to_bucket = 'copy to bucket'; + $to_object = 'copy to object'; + $options = array( + ALIOSS::OSS_HEADERS => array( + 'x-oss-copy-source-if-match' => 'E024E425254F1EEDB237F69F854CE883', + 'x-oss-copy-source-if-none-match' => 'Thu, 18 Jun 2015 08:50:31 GMT', + 'x-oss-copy-source-if-unmodified-since' => 'Thu, 18 Jun 2015 08:50:31 GMT', + 'x-oss-copy-source-if-modified-since' => 'Thu, 18 Jun 2015 09:50:31 GMT', + 'x-oss-metadata-directive' => 'COPY', + 'x-oss-server-side-encryption' => 'AES256' + ) + ); + + $response = $obj->copy_object($from_bucket,$from_object,$to_bucket,$to_object,$options); + + ` + + * 参数说明 + + ` + + $from_bucket 必选参数,源bucket,必须符合bucket命名规范 + $from_object 必选参数,源object,必须符合object命名规范 + $to_bucket 必选参数,目标bucket,必须符合bucket命名规范 + $to_object 必选参数,目标object,必须符合object命名规范 + $options 可选参数,如果需要设置,可以设置 ALIOSS::OSS_HEADERS 头参数,参数有如下的几个选项 + x-oss-copy-source-if-match 如果源Object的ETAG值和用户提供的ETAG相等,则执行拷贝操作; + 否则返回412 HTTP错误码(预处理失败) + x-oss-copy-source-if-none-match 如果源Object自从用户指定的时间以后就没有被修改过,则执行拷贝操作; + 否则返回412 HTTP错误码(预处理失败) + x-oss-copy-source-if-unmodified-since 如果传入参数中的时间等于或者晚于文件实际修改时间,则正常传输文件, + 并返回200 OK;否则返回412 precondition failed错误 + x-oss-copy-source-if-modified-since 如果源Object自从用户指定的时间以后被修改过,则执行拷贝操作; + 否则返回412 HTTP错误码(预处理失败) + x-oss-metadata-directive 有效值为COPY和REPLACE。如果该值设为COPY,则新的Object的meta都从源Object复制过来; + 如果设为REPLACE,则忽视所有源Object的meta值,而采用用户这次请求中指定的meta值;其他值则返回400 HTTP错误码。 + 注意该值为COPY时,源Object的x-oss-server-side-encryption的meta值不会进行拷贝;默认值为COPY + x-oss-server-side-encryption 指定oss创建目标object时的服务器端熵编码加密算法,目前仅支持AES256 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [content-type] => application/xml + [content-length] => 184 + [connection] => close + [date] => Thu, 02 Jul 2015 09:26:28 GMT + [etag] => "E024E425254F1EEDB237F69F854CE883" + [server] => AliyunOSS + [x-oss-request-id] => 559503C458DB3AB752161E83 + [x-oss-server-side-encryption] => AES256 + ) + + [body] => Array( + [CopyObjectResult] => Array( + [LastModified] => 2015-07-02T09:26:28.000Z + [ETag] => "E024E425254F1EEDB237F69F854CE883" + ) + ) + ) + + ` + + +* 获取Object MetaData + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name = 'object name'; + $options = null; + $response = $client->get_object_meta($bucket_name,$object_name,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $object_name 必选参数,必须符合object命名规范 + $options 可选参数,无需设置 + + ` + + * 响应结果 + + ` + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 09:03:40 GMT + [content-type] => plain/text + [content-length] => 10 + [connection] => close + [accept-ranges] => bytes + [cache-control] => no-cache + [content-disposition] => attachment;filename=oss_download.log + [content-encoding] => utf-8 + [content-language] => zh-CN + [etag] => "9BA9EF6DDFBE14916FA2D3337B427774" + [expires] => Fri, 28 Feb 2012 05:38:42 GMT + [last-modified] => Thu, 02 Jul 2015 08:38:10 GMT + [server] => AliyunOSS + [x-oss-object-type] => Normal + [x-oss-request-id] => 5594FE6C031C87E5461618B6 + [x-oss-server-side-encryption] => AES256 + ) + + [body] => + ) + + ` + +* 删除单个Object + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name = 'object name'; + $options = null; + $response = $client->delete_object($bucket_name,$object_name,$options); + + ` + + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $object_name 必选参数,必须符合object命名规范 + $options 可选参数,无需设置 + + ` + + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 204 + [header] => Array( + [content-length] => 0 + [connection] => close + [date] => Thu, 02 Jul 2015 10:01:00 GMT + [server] => AliyunOSS + [x-oss-request-id] => 55950BDC58DB3AB75216239D + ) + + [body] => + ) + + + ` + + +* 删除多个Object + * 示例代码 + + + ` + + $bucket_name = 'bucket name'; + $objects = array( + 'delete object 1', + 'delete object 2', + ... + ); + + $options = array( + 'quiet' => false, + ); + + $response = $client->delete_objects($bucket_name,$objects,$options); + + ` + + + * 参数说明 + + ` + $bucket_name 必选参数,必须符合bucket命名规范 + $objects 必选参数,其中的object必须符合object命名规范 + $options 可选参数,此处可以根据实际情况选择删除的两种模式,quite 参数可有true|false两种选择, + true OSS返回的消息体中只包含删除过程中出错的Object结果;如果所有删除都成功的话,则没有消息体。 + false OSS返回的消息体中会包含每一个删除Object的结果 + + ` + + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [content-type] => application/xml + [content-length] => 188 + [connection] => close + [date] => Thu, 02 Jul 2015 10:06:00 GMT + [server] => AliyunOSS + [x-oss-request-id] => 55950D0858DB3AB752162459 + ) + + [body] => Array( + [DeleteResult] => Array( + [Deleted] => Array( + [0] => Array( + [Key] => delegate_execute.exe + ) + + [1] => Array( + [Key] => metro_driver.dll + ) + ) + ) + ) + + + ` + + +* 下载Object + * 示例代码 + + ` + + $bucket_name = 'download bucket'; + $object_name = 'download object'; + + $options = array( + ALIOSS::OSS_FILE_DOWNLOAD => "download path", + ALIOSS::OSS_RANGE => '0-1', + ); + + $response = $client>get_object($bucket_name,$object_name,$options); + + ` + + * 参数说明 + + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $object_name 必选参数,必须符合object命名规范 + $options 必选参数,该参数中必须设置ALIOSS::OSS_FILE_DOWNLOAD,ALIOSS::OSS_RANGE可选,可以根据实际情况设置; + 如果不设置,默认会下载全部内容 + + + ` + + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 206 + [header] => Array( + ) + + [body] => + ) + + ` + + +## MultipartUpload相关操作 +* 初始化 multipartUpload + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name = 'object name'; + $options = array( + ALIOSS::OSS_HEADERS => array( + 'Expires' => 'Fri, 28 Feb 2012 05:38:42 GMT', + 'Cache-Control' => 'no-cache', + 'Content-Disposition' => 'attachment;filename=oss_download.log', + 'Content-Encoding' => 'utf-8', + 'Content-Type' => 'plain/text', + 'Content-Language' => 'zh-CN', + 'x-oss-server-side-encryption' => 'AES256', + ), + ); + $response = $client->initiate_multipart_upload($bucket_name,$object_name,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $object_name 必选参数,必须符合object命名规范 + $options 必选参数,该参内指定上传所需要的各种信息,具体各参数说明如下 + ALIOSS::OSS_HEADERS 该参数可选,如果指定,则可以设置该object的一些meta信息,可以设置的头信息如下: + Expires 过期时间(milliseconds) + Cache-Control 指定该Object被下载时的网页的缓存行为 + Content-Disposition 指定该Object被下载时的名称 + Content-Encoding 指定该Object被下载时的内容编码格式 + 'Content-Type' => 'plain/text'指定Object响应时的MIME类型 + Content-Language 指定object被下载时候的语言 + x-oss-server-side-encryption 指定oss创建object时的服务器端加密编码算法 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [content-type] => application/xml + [content-length] => 234 + [connection] => close + [date] => Thu, 02 Jul 2015 11:35:36 GMT + [server] => AliyunOSS + [x-oss-request-id] => 5595220858DB3AB7521631B1 + [x-oss-server-side-encryption] => AES256 + ) + + [body] => Array( + [InitiateMultipartUploadResult] => Array( + [Bucket] => common-bucket + [Key] => multipart-upload-1435836936 + [UploadId] => 154A34BD1FE24A90A025EB800AA392CC + ) + ) + ) + + ` + + +* 上传Part + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name = 'object name'; + $upload_id = 'upload id'; + $options = array( + 'fileUpload' => 'upload path', + 'partNumber' => 1, + 'seekTo' => 1, + 'length' => 5242880, + ); + + $response = $client->upload_part($bucket_name,$object_name, $upload_id, $options); + + ` + + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $object_name 必选参数,必须符合object命名规范 + $upload_id 必选参数,上传part对应的multipart uploads Id + $options 必选参数,该参内指定上传所需要的各种信息,具体各参数说明如下 + fileUpload 上传文件的路径 + partNumber 上传part的序号 + seekTo 读取上传文件的起始字节 + length 切片大小 + + ` + + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [content-length] => 0 + [connection] => close + [date] => Thu, 02 Jul 2015 11:35:36 GMT + [etag] => "3AE3AD480200A26738F10CBF2FFBE8B6" + [server] => AliyunOSS + [x-oss-request-id] => 5595220858DB3AB7521631B3 + [x-oss-server-side-encryption] => AES256 + ) + + [body] => + ) + + ` + + +* 拷贝Upload Part + * 示例代码 + + ` + + $from_bucket = 'copy from bucket'; + $from_object = 'copy from object'; + $to_bucket = 'copy to bucket'; + $to_object = 'copy to object'; + $part_number = 1; + $upload_id = 'copy to upload id'; + $options = array( + 'start' => 0, + 'end' => 25000032, + ); + + $response = $client->copy_upload_part($from_bucket,$from_object,$to_bucket,$to_object,$part_number,$upload_id,$options); + + + ` + + * 参数说明 + + ` + + $from_bucket 必选参数,源bucket,必须符合bucket命名规范 + $from_object 必选参数,源object,必须符合object命名规范 + $to_bucket 必选参数,目标bucket,必须符合bucket命名规范 + $to_object 必选参数,目标object,必须符合object命名规范 + $part_number 必选参数,范围是1~10,000 + $upload_id 必选参数,初始化multipartupload返回的uploadid + $options 可选参数,如果需要设置,可以设置isFullCopy,startRange,endRange和 + ALIOSS::OSS_HEADERS 等参数,其中ALIOSS::OSS_HEADERS中可以设置的参数如下: + x-oss-copy-source-if-match 如果源Object的ETAG值和用户提供的ETAG相等,则执行拷贝操作; + 否则返回412 HTTP错误码(预处理失败) + x-oss-copy-source-if-none-match 如果源Object自从用户指定的时间以后就没有被修改过,则执行拷贝操作; + 否则返回412 HTTP错误码(预处理失败) + x-oss-copy-source-if-unmodified-since 如果传入参数中的时间等于或者晚于文件实际修改时间,则正常传输文件, + 并返回200 OK;否则返回412 precondition failed错误 + x-oss-copy-source-if-modified-since 如果源Object自从用户指定的时间以后被修改过,则执行拷贝操作; + 否则返回412 HTTP错误码(预处理失败) + isFullCopy 是否启用全部拷贝,如果设置为true,则无需设置startRange和endRange + startRange 如果isFullCopy为false,该参数有效,指的是拷贝来源object的起始位置 + endRange 如果isFullCopy为false,该参数有效,指的是拷贝开源object的终止位置 + + ` + + * 响应结果 + ` + 将结果Response转换成array得到,下同 + + Array + ( + [success] => 1 + [status] => 200 + [header] => Array + ( + [date] => Thu, 06 Aug 2015 18:13:59 GMT + [content-type] => application/xml + [content-length] => 180 + [connection] => keep-alive + [content-range] => bytes 11304368-11534335/11534336 + [etag] => "E95C28888F15B92B9C49C9ECEC53C958" + [server] => AliyunOSS + [x-oss-bucket-version] => 1438864637 + [x-oss-request-id] => 55C3A3E79646C3C03F40EA5E + ) + + [body] => Array + ( + [CopyPartResult] => Array + ( + [LastModified] => 2015-08-06T18:13:59.000Z + [ETag] => "E95C28888F15B92B9C49C9ECEC53C958" + ) + + ) + + ) + ` +* 获取Part列表 + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name = 'object name'; + $upload_id = 'upload id'; + $options = null; + $response = $client->list_parts($bucket_name,$object_name, $upload_id,$options); + + ` + + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $object_name 必选参数,必须符合object命名规范 + $upload_id 必选参数,上传part对应的multipart uploads Id + $options 可选参数,无需设置 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [content-type] => application/xml + [content-length] => 584 + [connection] => close + [date] => Thu, 02 Jul 2015 11:35:40 GMT + [server] => AliyunOSS + [x-oss-request-id] => 5595220C031C87E546162F44 + ) + + [body] => Array( + [ListPartsResult] => Array( + [Bucket] => common-bucket + [Key] => multipart-upload-1435836813 + [UploadId] => B4D4B89F8B064A3D835D83D7805B49F3 + [StorageClass] => Standard + [PartNumberMarker] => 0 + [NextPartNumberMarker] => 1 + [MaxParts] => 1000 + [IsTruncated] => false + [Part] => Array( + [PartNumber] => 1 + [LastModified] => 2015-07-02T11:35:40.000Z + [ETag] => "3AE3AD480200A26738F10CBF2FFBE8B6" + [Size] => 5242880 + ) + ) + ) + ) + + ` + + +* 获取mulipartUpload列表 + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $options = array( + 'delimiter' => '/', + 'max-uploads' => 2, + 'key-marker' => '', + 'prefix' => '', + 'upload-id-marker' => '' + ); + $response = $client->list_multipart_uploads($bucket_name,$options); + + + ` + + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $options 可选参数,如果需要设置,可以设置如下参数 + delimiter 是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素—— + CommonPrefixes max-uploads 限定此次返回Multipart Uploads事件的最大数目,如果不设定,默认为1000,max-keys取值不能大于1000 + key-marker 与upload-id-marker参数一同使用来指定返回结果的起始位置。 l 如果upload-id-marker参数未设置,查询结果中包含: + 所有Object名字的字典序大于key-marker参数值的Multipart事件。 l 如果upload-id-marker参数被设置,查询结果中包含: + 所有Object名字的字典序大于key-marker参数值的Multipart事件和Object名字等于key-marker参数值,但是Upload ID比upload-id-marker + 参数值大的Multipart Uploads事件 + prefix 限定返回的object key必须以prefix作为前缀。注意使用prefix查询时,返回的key中仍会包含prefix + upload-id-marker 与key-marker参数一同使用来指定返回结果的起始位置。 l 如果key-marker参数未设置,则OSS忽略upload-id-marker参数。 + 如果key-marker参数被设置,查询结果中包含:所有Object名字的字典序大于key-marker参数值的Multipart事件和Object名字等于key-marker + 参数值,但是Upload ID比upload-id-marker参数值大的Multipart Uploads事件 + + ` + + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [content-type] => application/xml + [content-length] => 876 + [connection] => close + [date] => Thu, 02 Jul 2015 12:01:50 GMT + [server] => AliyunOSS + [x-oss-request-id] => 5595282E031C87E546163301 + ) + + [body] => Array( + [ListMultipartUploadsResult] => Array( + [Bucket] => common-bucket + [KeyMarker] => + [UploadIdMarker] => + [NextKeyMarker] => multipart-upload-1435835648 + [NextUploadIdMarker] => 5C79DDEC71DE478AA4AD9E9AA8BFE6DE + [Delimiter] => / + [Prefix] => + [MaxUploads] => 2 + [IsTruncated] => true + [Upload] => Array( + [0] => Array( + [Key] => multipart-upload-1435835395 + [UploadId] => 799C914C0EC3448BAC126849A1B1D6D0 + [StorageClass] => Standard + [Initiated] => 2015-07-02T11:09:55.000Z + ) + + [1] => Array( + [Key] => multipart-upload-1435835648 + [UploadId] => 5C79DDEC71DE478AA4AD9E9AA8BFE6DE + [StorageClass] => Standard + [Initiated] => 2015-07-02T11:14:08.000Z + ) + ) + ) + ) + ) + + ` + + +* 终止multipartUpload + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name = 'object name'; + $upload_id = 'upload id'; + $options = null; + $response = $client->abort_multipart_upload($bucket_name,$object_name,$upload_id,$options); + + + ` + + + * 参数说明 + * + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $object_name 必选参数,必须符合object命名规范 + $upload_id 必选参数,上传part对应的multipart uploads Id + $options 可选参数,无需设置 + + ` + + + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 204 + [header] => Array( + [content-length] => 0 + [connection] => close + [date] => Thu, 02 Jul 2015 11:53:52 GMT + [server] => AliyunOSS + [x-oss-request-id] => 55952650031C87E5461631E7 + ) + + [body] => + ) + + ` + + +* 完成multipartUpload + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name = 'object name'; + $upload_id = 'upload id'; + + $upload_parts = array(); + $upload_parts[] = array( + 'PartNumber' => 1, + 'ETag' => '3AE3AD480200A26738F10CBF2FFBE8B6' + ); + $options = null; + $response = $client->complete_multipart_upload($bucket_name,$object_name,$upload_id,$upload_parts,$options); + + ` + + * 参数说明 + + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $object_name 必选参数,必须符合object命名规范 + $upload_id 必选参数,上传part对应的multipart uploads Id + $upload_parts 包含part的数组,其中必须包含PartNumber和Etag + $options 可选参数,无需设置 + + ` + + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [content-type] => application/xml + [content-length] => 331 + [connection] => close + [date] => Thu, 02 Jul 2015 11:35:40 GMT + [etag] => "003B6AEB546001A97D838E411025239A-1" + [server] => AliyunOSS + [x-oss-request-id] => 5595220C031C87E546162F45 + [x-oss-server-side-encryption] => AES256 + ) + + [body] => Array( + [CompleteMultipartUploadResult] => Array( + [Location] => http://common-bucket.oss-cn-shanghai.aliyuncs.com/multipart-upload-1435836813 + [Bucket] => common-bucket + [Key] => multipart-upload-1435836813 + [ETag] => "003B6AEB546001A97D838E411025239A-1" + ) + ) + ) + + ` +## 生命周期管理(LifeCycle) +* 创建Lifecycle规则 + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $lifecycle = " + + + DaysRule + days/ + Enabled + + 1 + + + " ; + $options = null; + $response = $client->set_bucket_lifecycle($bucket_name,$lifecycle,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $lifecycle 必选参数,lifecycle规则,具体请xml元素说明请参阅oss api文档: + http://docs.aliyun.com/?spm=5176.383663.9.2.1hkILe#/pub/oss/api-reference/bucket&PutBucketLifecycle + $options 可选参数,无需设置 + + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 06:32:57 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594DB19031C87E5461601D1 + ) + + [body] => + ) + + ` + +* 获取lifeCycle规则 + * 示例代码 + + ` + + $bucket_name = "bucket name"; + $options = null; + $response = $client->get_bucket_lifecycle($bucket_name,$options); + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $options 可选参数,无需设置 + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 06:32:57 GMT + [content-type] => application/xml + [content-length] => 243 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594DB1958DB3AB75216045C + ) + + [body] => Array( + [LifecycleConfiguration] => Array( + [Rule] => Array( + [ID] => DaysRule + [Prefix] => days/ + [Status] => Enabled + [Expiration] => Array( + [Days] => 1 + ) + ) + ) + ) + ) + + ` + +* 删除lifeCycle规则 + * 示例代码 + + ` + + $bucket_name = "bucket name"; + $options = null; + $response = $client->delete_bucket_lifecycle($bucket_name,$options); + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $options 可选参数,无需设置 + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 204 + [header] => Array( + [date] => Thu, 02 Jul 2015 06:32:58 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594DB1A58DB3AB75216045D + ) + + [body] => + ) + + ` + +## 跨域资源管理(CORS) +* 创建CORS规则 + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + + $cors_rule = array(); + + $cors_rule[ALIOSS::OSS_CORS_ALLOWED_HEADER]=array("x-oss-test"); + $cors_rule[ALIOSS::OSS_CORS_ALLOWED_METHOD]=array("GET"); + $cors_rule[ALIOSS::OSS_CORS_ALLOWED_ORIGIN]=array("http://www.b.com"); + $cors_rule[ALIOSS::OSS_CORS_EXPOSE_HEADER]=array("x-oss-test1"); + $cors_rule[ALIOSS::OSS_CORS_MAX_AGE_SECONDS] = 10; + + $cors_rules=array($cors_rule); + + $options = null; + $response = $obj->set_bucket_cors($bucket_name, $cors_rules,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $cors_rules 定义一个cors规则数组,每条规则中需要包含以下元素 + ALIOSS::OSS_CORS_ALLOWED_ORIGIN 必选,指定允许的跨域请求的来源,每条规则最多能有一个"*"符号 + ALIOSS::OSS_CORS_ALLOWED_METHOD 必选,指定允许的跨域请求方法,仅能从GET,PUT,POST,DELETE,HEAD中选择一个或多个 + ALIOSS::OSS_CORS_ALLOWED_HEADER 可选,控制在OPTIONS预取指令中Access-Control-Request-Headers头中指定的header是否允许。 + 在Access-Control-Request-Headers中指定的每个header都必须在AllowedHeader中有一条对应的项。允许使用最多一个“*”通配符 + ALIOSS::OSS_CORS_EXPOSE_HEADER 可选,指定允许用户从应用程序中访问的响应头(例如一个Javascript的XMLHttpRequest对象。) + 不允许使用“*”通配符。 + ALIOSS::OSS_CORS_MAX_AGE_SECONDS 可选,指定浏览器对特定资源的预取(OPTIONS)请求返回结果的缓存时间,单位为秒。 + 一个CORSRule里面最多允许出现一个。 + + $options 可选参数,无需设置 + + ` + + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 07:03:29 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594E241031C87E546160697 + ) + + [body] => + ) + + + ` + +* 获取CORS规则 + * 示例代码 + + ` + + $bucket = 'bucket name'; + $options = null; + $response = $client->get_bucket_cors($bucket_name,$options); + + ` + + + * 参数说明 + + ` + + $bucket_name 必须参数,必须符合bucket命名规范 + $options 可选参数,无需设置 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 07:03:39 GMT + [content-type] => application/xml + [content-length] => 327 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594E24B58DB3AB752160920 + ) + + [body] => Array( + [CORSConfiguration] => Array( + [CORSRule] => Array( + [AllowedOrigin] => http://www.b.com + [AllowedMethod] => GET + [AllowedHeader] => x-oss-test + [ExposeHeader] => x-oss-test1 + [MaxAgeSeconds] => 10 + ) + ) + ) + ) + + ` + +* 评估是否允许跨域请求 + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name ='object name'; + $origin = 'http://www.b.com'; + $request_method = ALIOSS::OSS_HTTP_GET; + $request_headers = 'x-oss-test'; + $options = null; + + $response = $obj->options_object($bucket_name, $object_name, $origin, $request_method, $request_headers,$options); + + + ` + + * 参数说明 + + ` + + $bucket_name 必须参数,必须符合bucket命名规范 + $object_name 必选参数,必须符合object命名规范 + $origin 必选参数,请求来源域,用来标示跨域请求 + $request_method 必选参数,表示在实际请求中将会用到的方法 + $request_headers 必选参数,表示在实际请求中会用到的除了简单头部之外的headers + $options 可选参数,无需设置 + + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 07:03:39 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594E24B031C87E5461606A1 + ) + + [body] => + ) + + ` + + +* 删除CORS规则 + * 示例代码 + + ` + + $bucket_name = "bucket name"; + $options = null; + $response = $client->delete_bucket_cors($bucket_name,$options); + + ` + * 参数说明 + + ` + + $bucket_name 必须参数,必须符合bucket命名规范 + $options 可选参数,无需设置 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array + ( + [status] => 204 + [header] => Array( + [date] => Thu, 02 Jul 2015 07:03:39 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594E24B031C87E5461606A2 + ) + + [body] => + ) + + ` + +## 静态网站托管(WebSite) +* 设置WebSite + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $index_document = 'index.html'; + $error_document = 'error.html'; + $options = null; + $response = $client->set_bucket_website($bucket_name,$index_document,$error_document,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必须参数,必须符合bucket命名规范 + $index_document 必选参数,开启website功能,必须设置index_document + $error_document 可选参数,自行决定在开启website功能时,是否设置error_document + $options 可选参数,无需设置 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 02:39:23 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594A45B58DB3AB75215E239 + ) + + [body] => + ) + + ` + +* 获取WebSite设置 + * 示例代码 + + ` + + $bucket_name = "bucket name"; + $options = null; + $response = $client->get_bucket_website($bucket_name,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必须参数,必须符合bucket命名规范 + $options 可选参数,无需设置 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 02:39:24 GMT + [content-type] => application/xml + [content-length] => 218 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594A45C031C87E54615DF98 + ) + + [body] => Array( + [WebsiteConfiguration] => Array( + [IndexDocument] => Array( + [Suffix] => index.html + ) + + [ErrorDocument] => Array( + [Key] => error.html + ) + ) + ) + ) + + + ` + +* 删除WebSite + * 示例代码 + + ` + + $bucket_name = "bucket name"; + $options = null; + $response = $client->delete_bucket_website($bucket_name,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必须参数,必须符合bucket命名规范 + $options 可选参数,无需设置 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 204 + [header] => Array( + [date] => Thu, 02 Jul 2015 02:39:24 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594A45C031C87E54615DF99 + ) + [body] => + ) + + ` + +## 日志管理(Logging) +* 设置Logging + * 示例代码 + + ` + + $bucket_name = "bucket name"; + $target_bucket_name = "logging target bucket"; + $target_prefix = "logging file prefix"; + $options = null; + $response = $client->set_bucket_logging($bucket_name,$target_bucket_name,$target_prefix,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必须参数,必须符合bucket命名规范;且必须是属于owner的存在的bucket + $target_bucket_name 必须参数,日志保存的目标bucket,且必须和要记录日志的bucket在同一集群 + $target_prefix 可选参数,如果设置,日志文件的名称为 $target_prefix + oss日志规范命名 + $options 可选参数,无需设置 + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 01:59:06 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 55949AEA031C87E54615D996 + ) + + [body] => + ) + + ` + +* 获取logging设置 + * 示例代码 + + ` + + $bucket_name = "bucket name"; + $options = null; + $response = $client->get_bucket_logging($bucket_name,$options); + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $options 可选参数,无需设置 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 02:14:09 GMT + [content-length] => 235 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 55949E7158DB3AB75215DE78 + ) + + [body] => Array( + [BucketLoggingStatus] => Array( + [LoggingEnabled] => Array( + [TargetBucket] => a-00000000000000000003 + [TargetPrefix] => common-bucket-logging- + ) + ) + ) + ) + + ` + +* 删除Logging + * 示例代码 + + ` + + $bucket_name = "bucket name"; + $options = null; + $response = $client->get_bucket_logging($bucket_name,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $options 可选参数,无需设置 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 204 + [header] => Array( + [date] => Thu, 02 Jul 2015 02:29:12 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594A1F858DB3AB75215E0C4 + ) + + [body] => + ) + + ` + + +## 防盗链(Referer) +* 设置Referer防盗链 + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $is_allow_empty_referer = true; + $referer_list = array( + 'http://aliyun.com', + 'http://sina.com.cn' + ); + $options = null; + $response = $client->set_bucket_referer($bucket_name,$is_allow_empty_referer,$referer_list,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $is_allow_empty_referer 必选参数,是否允许空referer,默认为true + $referer_list 可选参数,允许的refer白名单列表,注意每条记录均需以http://开头 + $options 可选参数,无需设置 + + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 03:30:46 GMT + [content-length] => 0 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594B06658DB3AB75215E9EC + ) + + [body] => + ) + + ` + +* 获取Referer设置 + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $options = null; + $response = $client->get_bucket_referer($bucket_name,$options); + + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,必须符合bucket命名规范 + $options 可选参数,无需设置 + + ` + + * 响应结果 + + ` + 将结果Response转换成array得到,下同 + + Array( + [status] => 200 + [header] => Array( + [date] => Thu, 02 Jul 2015 03:30:46 GMT + [content-type] => application/xml + [content-length] => 248 + [connection] => close + [server] => AliyunOSS + [x-oss-request-id] => 5594B06658DB3AB75215E9F2 + ) + + [body] => Array( + [RefererConfiguration] => Array( + [AllowEmptyReferer] => true + [RefererList] => Array( + [Referer] => Array( + [0] => http://aliyun.com + [1] => http://sina.com.cn + ) + ) + ) + ) + ) + + ` + +## URL签名操作 +* 获取Get签名URL + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name = 'object name'; + $timeout = 3600; + $options = null; + $signed_url = $client->get_sign_url($bucket_name,$object_name,$timeout,$options); + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,参数需要符合bucket命名规范 + $object_name 必选参数,参数需要符合object命名规范 + $timeout 必选参数,过期时间 + $options 可选参数,无需设置 + + ` + + + * 响应结果 + + ` + + http://common-bucket.oss-cn-shanghai.aliyuncs.com/my_get_file.log?OSSAccessKeyId=ACSb***&Expires=1435820652& + Signature=AW5z87zmaLulEmvMzf6ZOUrVboE%3D + + ` + +* 获取Get或Put签名URL + * 示例代码 + + ` + + $bucket_name = 'bucket name'; + $object_name = 'object name'; + $timeout = 3600; + $method = ALIOSS::OSS_HTTP_GET; + $options = null; + $signed_url = $client->get_sign_url($bucket_name,$object_name,$timeout,$method,$options); + ` + + * 参数说明 + + ` + + $bucket_name 必选参数,参数需要符合bucket命名规范 + $object_name 必选参数,参数需要符合object命名规范 + $timeout 必选参数,过期时间 + $method 必选参数,方法类型,目前支持GET、PUT + $options 可选参数,无需设置 + + ` + + + * 响应结果 + + ` + + http://common-bucket.oss-cn-shanghai.aliyuncs.com/my_get_file.log?OSSAccessKeyId=ACSb***&Expires=1435820652& + Signature=AW5z87zmaLulEmvMzf6ZOUrVboE%3D + + ` + diff --git a/AliOssSdk/lang/zh.inc.php b/AliOssSdk/lang/zh.inc.php new file mode 100644 index 0000000..368ea2a --- /dev/null +++ b/AliOssSdk/lang/zh.inc.php @@ -0,0 +1,99 @@ +. You can get the code from . + +### License and Copyright + +This code is Copyright (c) 2008-2010, Ryan Parman. However, I'm licensing this code for others to use under the [Simplified BSD license](http://www.opensource.org/licenses/bsd-license.php). diff --git a/AliOssSdk/lib/requestcore/requestcore.class.php b/AliOssSdk/lib/requestcore/requestcore.class.php new file mode 100644 index 0000000..f475859 --- /dev/null +++ b/AliOssSdk/lib/requestcore/requestcore.class.php @@ -0,0 +1,1030 @@ +). + */ + public $request_class = 'RequestCore'; + + /** + * The default class to use for HTTP Responses (defaults to ). + */ + public $response_class = 'ResponseCore'; + + /** + * Default useragent string to use. + */ + public $useragent = 'RequestCore/1.4.3'; + + /** + * File to read from while streaming up. + */ + public $read_file = null; + + /** + * The resource to read from while streaming up. + */ + public $read_stream = null; + + /** + * The size of the stream to read from. + */ + public $read_stream_size = null; + + /** + * The length already read from the stream. + */ + public $read_stream_read = 0; + + /** + * File to write to while streaming down. + */ + public $write_file = null; + + /** + * The resource to write to while streaming down. + */ + public $write_stream = null; + + /** + * Stores the intended starting seek position. + */ + public $seek_position = null; + + /** + * The location of the cacert.pem file to use. + */ + public $cacert_location = false; + + /** + * The state of SSL certificate verification. + */ + public $ssl_verification = true; + + /** + * The user-defined callback function to call when a stream is read from. + */ + public $registered_streaming_read_callback = null; + + /** + * The user-defined callback function to call when a stream is written to. + */ + public $registered_streaming_write_callback = null; + + + /*%******************************************************************************************%*/ + // CONSTANTS + + /** + * GET HTTP Method + */ + const HTTP_GET = 'GET'; + + /** + * POST HTTP Method + */ + const HTTP_POST = 'POST'; + + /** + * PUT HTTP Method + */ + const HTTP_PUT = 'PUT'; + + /** + * DELETE HTTP Method + */ + const HTTP_DELETE = 'DELETE'; + + /** + * HEAD HTTP Method + */ + const HTTP_HEAD = 'HEAD'; + + + /*%******************************************************************************************%*/ + // CONSTRUCTOR/DESTRUCTOR + + /** + * Constructs a new instance of this class. + * + * @param string $url (Optional) The URL to request or service endpoint to query. + * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` + * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class. + * @return $this A reference to the current instance. + */ + public function __construct($url = null, $proxy = null, $helpers = null) + { + // Set some default values. + $this->request_url = $url; + $this->method = self::HTTP_GET; + $this->request_headers = array(); + $this->request_body = ''; + + // Set a new Request class if one was set. + if (isset($helpers['request']) && !empty($helpers['request'])) + { + $this->request_class = $helpers['request']; + } + + // Set a new Request class if one was set. + if (isset($helpers['response']) && !empty($helpers['response'])) + { + $this->response_class = $helpers['response']; + } + + if ($proxy) + { + $this->set_proxy($proxy); + } + + return $this; + } + + /** + * Destructs the instance. Closes opened file handles. + * + * @return $this A reference to the current instance. + */ + public function __destruct() + { + if (isset($this->read_file) && isset($this->read_stream)) + { + fclose($this->read_stream); + } + + if (isset($this->write_file) && isset($this->write_stream)) + { + fclose($this->write_stream); + } + + return $this; + } + + + /*%******************************************************************************************%*/ + // REQUEST METHODS + + /** + * Sets the credentials to use for authentication. + * + * @param string $user (Required) The username to authenticate with. + * @param string $pass (Required) The password to authenticate with. + * @return $this A reference to the current instance. + */ + public function set_credentials($user, $pass) + { + $this->username = $user; + $this->password = $pass; + return $this; + } + + /** + * Adds a custom HTTP header to the cURL request. + * + * @param string $key (Required) The custom HTTP header to set. + * @param mixed $value (Required) The value to assign to the custom HTTP header. + * @return $this A reference to the current instance. + */ + public function add_header($key, $value) + { + $this->request_headers[$key] = $value; + return $this; + } + + /** + * Removes an HTTP header from the cURL request. + * + * @param string $key (Required) The custom HTTP header to set. + * @return $this A reference to the current instance. + */ + public function remove_header($key) + { + if (isset($this->request_headers[$key])) + { + unset($this->request_headers[$key]); + } + return $this; + } + + /** + * Set the method type for the request. + * + * @param string $method (Required) One of the following constants: , , , , . + * @return $this A reference to the current instance. + */ + public function set_method($method) + { + $this->method = strtoupper($method); + return $this; + } + + /** + * Sets a custom useragent string for the class. + * + * @param string $ua (Required) The useragent string to use. + * @return $this A reference to the current instance. + */ + public function set_useragent($ua) + { + $this->useragent = $ua; + return $this; + } + + /** + * Set the body to send in the request. + * + * @param string $body (Required) The textual content to send along in the body of the request. + * @return $this A reference to the current instance. + */ + public function set_body($body) + { + $this->request_body = $body; + return $this; + } + + /** + * Set the URL to make the request to. + * + * @param string $url (Required) The URL to make the request to. + * @return $this A reference to the current instance. + */ + public function set_request_url($url) + { + $this->request_url = $url; + return $this; + } + + /** + * Set additional CURLOPT settings. These will merge with the default settings, and override if + * there is a duplicate. + * + * @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings. + * @return $this A reference to the current instance. + */ + public function set_curlopts($curlopts) + { + $this->curlopts = $curlopts; + return $this; + } + + /** + * Sets the length in bytes to read from the stream while streaming up. + * + * @param integer $size (Required) The length in bytes to read from the stream. + * @return $this A reference to the current instance. + */ + public function set_read_stream_size($size) + { + $this->read_stream_size = $size; + + return $this; + } + + /** + * Sets the resource to read from while streaming up. Reads the stream from its current position until + * EOF or `$size` bytes have been read. If `$size` is not given it will be determined by and + * . + * + * @param resource $resource (Required) The readable resource to read from. + * @param integer $size (Optional) The size of the stream to read. + * @return $this A reference to the current instance. + */ + public function set_read_stream($resource, $size = null) + { + if (!isset($size) || $size < 0) + { + $stats = fstat($resource); + + if ($stats && $stats['size'] >= 0) + { + $position = ftell($resource); + + if ($position !== false && $position >= 0) + { + $size = $stats['size'] - $position; + } + } + } + + $this->read_stream = $resource; + + return $this->set_read_stream_size($size); + } + + /** + * Sets the file to read from while streaming up. + * + * @param string $location (Required) The readable location to read from. + * @return $this A reference to the current instance. + */ + public function set_read_file($location) + { + $this->read_file = $location; + $read_file_handle = fopen($location, 'r'); + + return $this->set_read_stream($read_file_handle); + } + + /** + * Sets the resource to write to while streaming down. + * + * @param resource $resource (Required) The writeable resource to write to. + * @return $this A reference to the current instance. + */ + public function set_write_stream($resource) + { + $this->write_stream = $resource; + + return $this; + } + + /** + * Sets the file to write to while streaming down. + * + * @param string $location (Required) The writeable location to write to. + * @return $this A reference to the current instance. + */ + public function set_write_file($location) + { + $this->write_file = $location; + $write_file_handle = fopen($location, 'w'); + + return $this->set_write_stream($write_file_handle); + } + + /** + * Set the proxy to use for making requests. + * + * @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` + * @return $this A reference to the current instance. + */ + public function set_proxy($proxy) + { + $proxy = parse_url($proxy); + $proxy['user'] = isset($proxy['user']) ? $proxy['user'] : null; + $proxy['pass'] = isset($proxy['pass']) ? $proxy['pass'] : null; + $proxy['port'] = isset($proxy['port']) ? $proxy['port'] : null; + $this->proxy = $proxy; + return $this; + } + + /** + * Set the intended starting seek position. + * + * @param integer $position (Required) The byte-position of the stream to begin reading from. + * @return $this A reference to the current instance. + */ + public function set_seek_position($position) + { + $this->seek_position = isset($position) ? (integer) $position : null; + + return $this; + } + + /** + * Register a callback function to execute whenever a data stream is read from using + * . + * + * The user-defined callback function should accept three arguments: + * + *
    + *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • + *
  • $file_handle - resource - Required - The file handle resource that represents the file on the local file system.
  • + *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • + *
+ * + * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    + *
  • The name of a global function to execute, passed as a string.
  • + *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • + *
  • An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance. + */ + public function register_streaming_read_callback($callback) + { + $this->registered_streaming_read_callback = $callback; + + return $this; + } + + /** + * Register a callback function to execute whenever a data stream is written to using + * . + * + * The user-defined callback function should accept two arguments: + * + *
    + *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • + *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • + *
+ * + * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    + *
  • The name of a global function to execute, passed as a string.
  • + *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • + *
  • An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance. + */ + public function register_streaming_write_callback($callback) + { + $this->registered_streaming_write_callback = $callback; + + return $this; + } + + + /*%******************************************************************************************%*/ + // PREPARE, SEND, AND PROCESS REQUEST + + /** + * A callback function that is invoked by cURL for streaming up. + * + * @param resource $curl_handle (Required) The cURL handle for the request. + * @param resource $file_handle (Required) The open file handle resource. + * @param integer $length (Required) The maximum number of bytes to read. + * @return binary Binary data from a stream. + */ + public function streaming_read_callback($curl_handle, $file_handle, $length) + { + // Once we've sent as much as we're supposed to send... + if ($this->read_stream_read >= $this->read_stream_size) + { + // Send EOF + return ''; + } + + // If we're at the beginning of an upload and need to seek... + if ($this->read_stream_read == 0 && isset($this->seek_position) && $this->seek_position !== ftell($this->read_stream)) + { + if (fseek($this->read_stream, $this->seek_position) !== 0) + { + throw new RequestCore_Exception('The stream does not support seeking and is either not at the requested position or the position is unknown.'); + } + } + + $read = fread($this->read_stream, min($this->read_stream_size - $this->read_stream_read, $length)); // Remaining upload data or cURL's requested chunk size + $this->read_stream_read += strlen($read); + + $out = $read === false ? '' : $read; + + // Execute callback function + if ($this->registered_streaming_read_callback) + { + call_user_func($this->registered_streaming_read_callback, $curl_handle, $file_handle, $out); + } + + return $out; + } + + /** + * A callback function that is invoked by cURL for streaming down. + * + * @param resource $curl_handle (Required) The cURL handle for the request. + * @param binary $data (Required) The data to write. + * @return integer The number of bytes written. + */ + public function streaming_write_callback($curl_handle, $data) + { + $length = strlen($data); + $written_total = 0; + $written_last = 0; + + while ($written_total < $length) + { + $written_last = fwrite($this->write_stream, substr($data, $written_total)); + + if ($written_last === false) + { + return $written_total; + } + + $written_total += $written_last; + } + + // Execute callback function + if ($this->registered_streaming_write_callback) + { + call_user_func($this->registered_streaming_write_callback, $curl_handle, $written_total); + } + + return $written_total; + } + + /** + * Prepares and adds the details of the cURL request. This can be passed along to a + * function. + * + * @return resource The handle for the cURL object. + */ + public function prep_request() + { + $curl_handle = curl_init(); + + // Set default options. + curl_setopt($curl_handle, CURLOPT_URL, $this->request_url); + curl_setopt($curl_handle, CURLOPT_FILETIME, true); + curl_setopt($curl_handle, CURLOPT_FRESH_CONNECT, false); + curl_setopt($curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED); + curl_setopt($curl_handle, CURLOPT_MAXREDIRS, 5); + curl_setopt($curl_handle, CURLOPT_HEADER, true); + curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl_handle, CURLOPT_TIMEOUT, 5184000); + curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 120); + curl_setopt($curl_handle, CURLOPT_NOSIGNAL, true); + curl_setopt($curl_handle, CURLOPT_REFERER, $this->request_url); + curl_setopt($curl_handle, CURLOPT_USERAGENT, $this->useragent); + curl_setopt($curl_handle, CURLOPT_READFUNCTION, array($this, 'streaming_read_callback')); + + // Verification of the SSL cert + if ($this->ssl_verification) + { + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, 2); + } + else + { + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, false); + } + + // chmod the file as 0755 + if ($this->cacert_location === true) + { + curl_setopt($curl_handle, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem'); + } + elseif (is_string($this->cacert_location)) + { + curl_setopt($curl_handle, CURLOPT_CAINFO, $this->cacert_location); + } + + // Debug mode + if ($this->debug_mode) + { + curl_setopt($curl_handle, CURLOPT_VERBOSE, true); + } + + // Handle open_basedir & safe mode + if (!ini_get('safe_mode') && !ini_get('open_basedir')) + { + curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true); + } + + // Enable a proxy connection if requested. + if ($this->proxy) + { + curl_setopt($curl_handle, CURLOPT_HTTPPROXYTUNNEL, true); + + $host = $this->proxy['host']; + $host .= ($this->proxy['port']) ? ':' . $this->proxy['port'] : ''; + curl_setopt($curl_handle, CURLOPT_PROXY, $host); + + if (isset($this->proxy['user']) && isset($this->proxy['pass'])) + { + curl_setopt($curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy['user'] . ':' . $this->proxy['pass']); + } + } + + // Set credentials for HTTP Basic/Digest Authentication. + if ($this->username && $this->password) + { + curl_setopt($curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_setopt($curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password); + } + + // Handle the encoding if we can. + if (extension_loaded('zlib')) + { + curl_setopt($curl_handle, CURLOPT_ENCODING, ''); + } + + // Process custom headers + if (isset($this->request_headers) && count($this->request_headers)) + { + $temp_headers = array(); + + foreach ($this->request_headers as $k => $v) + { + $temp_headers[] = $k . ': ' . $v; + } + + curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $temp_headers); + } + + switch ($this->method) + { + case self::HTTP_PUT: + //unset($this->read_stream); + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT'); + if (isset($this->read_stream)) + { + if (!isset($this->read_stream_size) || $this->read_stream_size < 0) + { + throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.'); + } + + curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size); + curl_setopt($curl_handle, CURLOPT_UPLOAD, true); + } + else + { + curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); + } + break; + + case self::HTTP_POST: + curl_setopt($curl_handle, CURLOPT_POST, true); + curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); + break; + + case self::HTTP_HEAD: + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD); + curl_setopt($curl_handle, CURLOPT_NOBODY, 1); + break; + + default: // Assumed GET + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, $this->method); + if (isset($this->write_stream)) + { + curl_setopt($curl_handle, CURLOPT_WRITEFUNCTION, array($this, 'streaming_write_callback')); + curl_setopt($curl_handle, CURLOPT_HEADER, false); + } + else + { + curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); + } + break; + } + + // Merge in the CURLOPTs + if (isset($this->curlopts) && sizeof($this->curlopts) > 0) + { + foreach ($this->curlopts as $k => $v) + { + curl_setopt($curl_handle, $k, $v); + } + } + + return $curl_handle; + } + + /** + * Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the + * data stored in the `curl_handle` and `response` properties unless replacement data is passed in via + * parameters. + * + * @param resource $curl_handle (Optional) The reference to the already executed cURL request. + * @param string $response (Optional) The actual response content itself that needs to be parsed. + * @return ResponseCore A object containing a parsed HTTP response. + */ + public function process_response($curl_handle = null, $response = null) + { + // Accept a custom one if it's passed. + if ($curl_handle && $response) + { + $this->curl_handle = $curl_handle; + $this->response = $response; + } + + // As long as this came back as a valid resource... + if (is_resource($this->curl_handle)) + { + // Determine what's what. + $header_size = curl_getinfo($this->curl_handle, CURLINFO_HEADER_SIZE); + $this->response_headers = substr($this->response, 0, $header_size); + $this->response_body = substr($this->response, $header_size); + $this->response_code = curl_getinfo($this->curl_handle, CURLINFO_HTTP_CODE); + $this->response_info = curl_getinfo($this->curl_handle); + + // Parse out the headers + $this->response_headers = explode("\r\n\r\n", trim($this->response_headers)); + $this->response_headers = array_pop($this->response_headers); + $this->response_headers = explode("\r\n", $this->response_headers); + array_shift($this->response_headers); + + // Loop through and split up the headers. + $header_assoc = array(); + foreach ($this->response_headers as $header) + { + $kv = explode(': ', $header); + $header_assoc[strtolower($kv[0])] = isset($kv[1])?$kv[1]:''; + } + + // Reset the headers to the appropriate property. + $this->response_headers = $header_assoc; + $this->response_headers['_info'] = $this->response_info; + $this->response_headers['_info']['method'] = $this->method; + + if ($curl_handle && $response) + { + return new $this->response_class($this->response_headers, $this->response_body, $this->response_code, $this->curl_handle); + } + } + + // Return false + return false; + } + + /** + * Sends the request, calling necessary utility functions to update built-in properties. + * + * @param boolean $parse (Optional) Whether to parse the response with ResponseCore or not. + * @return string The resulting unparsed data from the request. + */ + public function send_request($parse = false) + { + set_time_limit(0); + + $curl_handle = $this->prep_request(); + $this->response = curl_exec($curl_handle); + + if ($this->response === false) + { + throw new RequestCore_Exception('cURL resource: ' . (string) $curl_handle . '; cURL error: ' . curl_error($curl_handle) . ' (' . curl_errno($curl_handle) . ')'); + } + + $parsed_response = $this->process_response($curl_handle, $this->response); + + curl_close($curl_handle); + + if ($parse) + { + return $parsed_response; + } + + return $this->response; + } + + /** + * Sends the request using , enabling parallel requests. Uses the "rolling" method. + * + * @param array $handles (Required) An indexed array of cURL handles to process simultaneously. + * @param array $opt (Optional) An associative array of parameters that can have the following keys:
    + *
  • callback - string|array - Optional - The string name of a function to pass the response data to. If this is a method, pass an array where the [0] index is the class and the [1] index is the method name.
  • + *
  • limit - integer - Optional - The number of simultaneous requests to make. This can be useful for scaling around slow server responses. Defaults to trusting cURLs judgement as to how many to use.
+ * @return array Post-processed cURL responses. + */ + public function send_multi_request($handles, $opt = null) + { + set_time_limit(0); + + // Skip everything if there are no handles to process. + if (count($handles) === 0) return array(); + + if (!$opt) $opt = array(); + + // Initialize any missing options + $limit = isset($opt['limit']) ? $opt['limit'] : -1; + + // Initialize + $handle_list = $handles; + $http = new $this->request_class(); + $multi_handle = curl_multi_init(); + $handles_post = array(); + $added = count($handles); + $last_handle = null; + $count = 0; + $i = 0; + + // Loop through the cURL handles and add as many as it set by the limit parameter. + while ($i < $added) + { + if ($limit > 0 && $i >= $limit) break; + curl_multi_add_handle($multi_handle, array_shift($handles)); + $i++; + } + + do + { + $active = false; + + // Start executing and wait for a response. + while (($status = curl_multi_exec($multi_handle, $active)) === CURLM_CALL_MULTI_PERFORM) + { + // Start looking for possible responses immediately when we have to add more handles + if (count($handles) > 0) break; + } + + // Figure out which requests finished. + $to_process = array(); + + while ($done = curl_multi_info_read($multi_handle)) + { + // Since curl_errno() isn't reliable for handles that were in multirequests, we check the 'result' of the info read, which contains the curl error number, (listed here http://curl.haxx.se/libcurl/c/libcurl-errors.html ) + if ($done['result'] > 0) + { + throw new RequestCore_Exception('cURL resource: ' . (string) $done['handle'] . '; cURL error: ' . curl_error($done['handle']) . ' (' . $done['result'] . ')'); + } + + // Because curl_multi_info_read() might return more than one message about a request, we check to see if this request is already in our array of completed requests + elseif (!isset($to_process[(int) $done['handle']])) + { + $to_process[(int) $done['handle']] = $done; + } + } + + // Actually deal with the request + foreach ($to_process as $pkey => $done) + { + $response = $http->process_response($done['handle'], curl_multi_getcontent($done['handle'])); + $key = array_search($done['handle'], $handle_list, true); + $handles_post[$key] = $response; + + if (count($handles) > 0) + { + curl_multi_add_handle($multi_handle, array_shift($handles)); + } + + curl_multi_remove_handle($multi_handle, $done['handle']); + curl_close($done['handle']); + } + } + while ($active || count($handles_post) < $added); + + curl_multi_close($multi_handle); + + ksort($handles_post, SORT_NUMERIC); + return $handles_post; + } + + + /*%******************************************************************************************%*/ + // RESPONSE METHODS + + /** + * Get the HTTP response headers from the request. + * + * @param string $header (Optional) A specific header value to return. Defaults to all headers. + * @return string|array All or selected header values. + */ + public function get_response_header($header = null) + { + if ($header) + { + return $this->response_headers[strtolower($header)]; + } + return $this->response_headers; + } + + /** + * Get the HTTP response body from the request. + * + * @return string The response body. + */ + public function get_response_body() + { + return $this->response_body; + } + + /** + * Get the HTTP response code from the request. + * + * @return string The HTTP response code. + */ + public function get_response_code() + { + return $this->response_code; + } +} + + +/** + * Container for all response-related methods. + */ +class ResponseCore +{ + /** + * Stores the HTTP header information. + */ + public $header; + + /** + * Stores the SimpleXML response. + */ + public $body; + + /** + * Stores the HTTP response code. + */ + public $status; + + /** + * Constructs a new instance of this class. + * + * @param array $header (Required) Associative array of HTTP headers (typically returned by ). + * @param string $body (Required) XML-formatted response from AWS. + * @param integer $status (Optional) HTTP response status code from the request. + * @return object Contains an `header` property (HTTP headers as an associative array), a or `body` property, and an `status` code. + */ + public function __construct($header, $body, $status = null) + { + $this->header = $header; + $this->body = $body; + $this->status = $status; + + return $this; + } + + /** + * Did we receive the status code we expected? + * + * @param integer|array $codes (Optional) The status code(s) to expect. Pass an for a single acceptable value, or an of integers for multiple acceptable values. + * @return boolean Whether we received the expected status code or not. + */ + public function isOK($codes = array(200, 201, 204, 206)) + { + if (is_array($codes)) + { + return in_array($this->status, $codes); + } + + return $this->status === $codes; + } +} + +/** + * Default RequestCore Exception. + */ +class RequestCore_Exception extends Exception {} diff --git a/AliOssSdk/sdk.class.php b/AliOssSdk/sdk.class.php new file mode 100644 index 0000000..1663638 --- /dev/null +++ b/AliOssSdk/sdk.class.php @@ -0,0 +1,2104 @@ +access_id = $access_id; + $this->access_key = $access_key; + }elseif (defined('OSS_ACCESS_ID') && defined('OSS_ACCESS_KEY')){ + $this->access_id = OSS_ACCESS_ID; + $this->access_key = OSS_ACCESS_KEY; + }else{ + throw new OSS_Exception(NOT_SET_OSS_ACCESS_ID_AND_ACCESS_KEY); + } + if(empty($this->access_id) || empty($this->access_key)){ + throw new OSS_Exception(OSS_ACCESS_ID_OR_ACCESS_KEY_EMPTY); + } + if ($hostname) { + $this->hostname = $hostname; + } + else if (!$hostname and defined('OSS_ENDPOINT')) { + $this->hostname = OSS_ENDPOINT; + }else{ + $this->hostname = self::DEFAULT_OSS_ENDPOINT; + } + + //支持sts的security token + $this->security_token = $security_token; + } + + + /*%******************************************************************************************************%*/ + //Service Operation + /** + * 获取bucket列表 + * @param array $options (Optional) + * @throws OSS_Exception + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function list_bucket($options = NULL) { + $this->precheck_options($options); + $options[self::OSS_BUCKET] = ''; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $response = $this->auth($options); + return $response; + } + + /*%******************************************************************************************************%*/ + //Bucket Operation + /** + * 创建bucket + * @param string $bucket (Required) + * @param string $acl (Optional) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function create_bucket($bucket, $acl = self::OSS_ACL_TYPE_PRIVATE, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_HEADERS] = array(self::OSS_ACL => $acl); + $response = $this->auth($options); + return $response; + } + + /** + * 删除bucket + * @param string $bucket (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function delete_bucket($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = '/'; + $response = $this->auth($options); + return $response; + } + + /** + * 获取bucket的acl + * @param string $bucket (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function get_bucket_acl($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'acl'; + $response = $this->auth($options); + return $response; + } + + /** + * 设置bucket的acl + * @param string $bucket (Required) + * @param string $acl (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function set_bucket_acl($bucket, $acl, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_HEADERS] = array(self::OSS_ACL => $acl); + $response = $this->auth($options); + return $response; + } + + /** + * 获取bucket logging + * @param string $bucket (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @author lijie.ma@alibaba-inc.com + * @since 2014-05-04 + * @return ResponseCore + */ + public function get_bucket_logging($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'logging'; + $response = $this->auth($options); + return $response; + } + + /** + * 设置bucket Logging + * @param string $bucket (Required) + * @param string $target_bucket (Required) + * @param string $target_prefix (Optional) + * @param array $options (Optional) + * @throws OSS_Exception + * @author lijie.ma@alibaba-inc.com + * @since 2014-05-04 + * @return ResponseCore + */ + public function set_bucket_logging($bucket, $target_bucket, $target_prefix, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $this->precheck_bucket($target_bucket, OSS_TARGET_BUCKET_IS_NOT_ALLOWED_EMPTY); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'logging'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + $xml = new SimpleXMLElement(''); + $logging_enabled_part=$xml->addChild('LoggingEnabled'); + $logging_enabled_part->addChild('TargetBucket', $target_bucket); + $logging_enabled_part->addChild('TargetPrefix', $target_prefix); + $options[self::OSS_CONTENT] = $xml->asXML(); + return $this->auth($options); + } + + /** + * 删除bucket logging + * @param string $bucket (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @author lijie.ma@alibaba-inc.com + * @since 2014-05-04 + * @return ResponseCore + */ + public function delete_bucket_logging($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'logging'; + $response = $this->auth($options); + return $response; + } + + /** + * 设置bucket website + * @param string $bucket (Required) + * @param string $index_document (Required) + * @param string $error_document (Optional) + * @param array $options (Optional) + * @throws OSS_Exception + * @author lijie.ma@alibaba-inc.com + * @since 2014-05-04 + * @return ResponseCore + */ + public function set_bucket_website($bucket, $index_document, $error_document, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + OSSUtil::is_empty($index_document, OSS_INDEX_DOCUMENT_IS_NOT_ALLOWED_EMPTY); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'website'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + + $xml = new SimpleXMLElement(''); + $index_document_part=$xml->addChild('IndexDocument'); + $error_document_part=$xml->addChild('ErrorDocument'); + $index_document_part->addChild('Suffix', $index_document); + $error_document_part->addChild('Key', $error_document); + $options[self::OSS_CONTENT] = $xml->asXML(); + return $this->auth($options); + } + + /** + * 获取bucket website + * @param string $bucket (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @author lijie.ma@alibaba-inc.com + * @since 2014-05-04 + * @return ResponseCore + */ + public function get_bucket_website($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'website'; + $response = $this->auth($options); + return $response; + } + + /** + * 删除bucket website + * @param string $bucket (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @author lijie.ma@alibaba-inc.com + * @since 2014-05-04 + * @return ResponseCore + */ + public function delete_bucket_website($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'website'; + $response = $this->auth($options); + return $response; + } + + /** + * 设置bucket cors + * @param string $bucket (Required) + * @param array $cors_rules (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @author lijie.ma@alibaba-inc.com + * @since 2014-05-04 + * @return ResponseCore + */ + public function set_bucket_cors($bucket, $cors_rules, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'cors'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + $xml = new SimpleXMLElement(''); + foreach ($cors_rules as $cors_rule){ + $cors_rule_part = $xml->addChild('CORSRule'); + foreach ($cors_rule[self::OSS_CORS_ALLOWED_ORIGIN] as $value){ + $cors_rule_part->addChild(self::OSS_CORS_ALLOWED_ORIGIN, $value); + } + foreach ($cors_rule[self::OSS_CORS_ALLOWED_HEADER] as $value){ + $cors_rule_part->addChild(self::OSS_CORS_ALLOWED_HEADER, $value); + } + foreach ($cors_rule[self::OSS_CORS_ALLOWED_METHOD] as $value){ + $cors_rule_part->addChild(self::OSS_CORS_ALLOWED_METHOD, $value); + } + foreach ($cors_rule[self::OSS_CORS_EXPOSE_HEADER] as $value){ + $cors_rule_part->addChild(self::OSS_CORS_EXPOSE_HEADER, $value); + } + $cors_rule_part->addChild(self::OSS_CORS_MAX_AGE_SECONDS, $cors_rule[self::OSS_CORS_MAX_AGE_SECONDS]); + } + $options[self::OSS_CONTENT] = $xml->asXML(); + return $this->auth($options); + } + /** + * 获取bucket cors + * @param string $bucket (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @author lijie.ma@alibaba-inc.com + * @since 2014-05-04 + * @return ResponseCore + */ + public function get_bucket_cors($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'cors'; + $response = $this->auth($options); + return $response; + } + + /** + * 删除bucket cors + * @param string $bucket (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @author lijie.ma@alibaba-inc.com + * @since 2014-05-04 + * @return ResponseCore + */ + public function delete_bucket_cors($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'cors'; + $response = $this->auth($options); + return $response; + } + + /** + * 检验跨域资源请求 + * @param string $bucket (Required) + * @param string $object (Required) + * @param string $origin (Required) + * @param string $request_method (Required) + * @param string $request_headers (Required) + * @param array $options (Optional) + * @return ResponseCore + * @throws OSS_Exception + */ + public function options_object($bucket, $object, $origin, $request_method, $request_headers, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_OPTIONS; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_HEADERS] = array( + self::OSS_OPTIONS_ORIGIN => $origin, + self::OSS_OPTIONS_REQUEST_HEADERS => $request_headers, + self::OSS_OPTIONS_REQUEST_METHOD => $request_method + ); + $response = $this->auth($options); + return $response; + } + + /** + * 设置bucket lifecycle + * @param string $bucket (Required) + * @param string $lifecycle_xml (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @since 2015-03-11 + * @return ResponseCore + */ + public function set_bucket_lifecycle($bucket, $lifecycle_xml, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'lifecycle'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + $options[self::OSS_CONTENT] = $lifecycle_xml; + return $this->auth($options); + } + + /** + * 获取bucket lifecycle + * @param string $bucket (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @since 2015-03-11 + * @return ResponseCore + */ + public function get_bucket_lifecycle($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'lifecycle'; + return $this->auth($options); + } + + /** + * 删除bucket lifecycle + * @param string $bucket (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @since 2015-03-11 + * @return ResponseCore + */ + public function delete_bucket_lifecycle($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'lifecycle'; + return $this->auth($options); + } + + /** + * 设置bucket referer + * @param string $bucket (Required) + * @param bool $is_allow_empty_referer (Required) + * @param array $referer_list (Optional) + * @param array $options (Optional) + * @return ResponseCore + * @throws OSS_Exception + */ + public function set_bucket_referer($bucket, $is_allow_empty_referer = true, $referer_list = NULL, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'referer'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + + $xml = new SimpleXMLElement(''); + $list = $xml->addChild('RefererList'); + if ($referer_list){ + foreach ($referer_list as $value){ + $list->addChild('Referer', $value); + } + } + else{ + $list->addChild('Referer', ''); + } + $value = "true"; + if (!$is_allow_empty_referer){ + $value = "false"; + } + $xml->addChild('AllowEmptyReferer', $value); + $options[self::OSS_CONTENT] = $xml->asXML(); + return $this->auth($options); + } + + /** + * 获取bucket referer + * @param string $bucket (Required) + * @param array $options (Optional) + * @throws OSS_Exception + * @since 2015-03-11 + * @return ResponseCore + */ + public function get_bucket_referer($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'referer'; + return $this->auth($options); + } + + /*%******************************************************************************************************%*/ + //Object Operation + + /** + * 获取bucket下的object列表 + * @param string $bucket (Required) + * @param array $options (Optional) + * 其中options中的参数如下 + * $options = array( + * 'max-keys' => max-keys用于限定此次返回object的最大数,如果不设定,默认为100,max-keys取值不能大于100。 + * 'prefix' => 限定返回的object key必须以prefix作为前缀。注意使用prefix查询时,返回的key中仍会包含prefix。 + * 'delimiter' => 是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素 + * 'marker' => 用户设定结果从marker之后按字母排序的第一个开始返回。 + *) + * 其中 prefix,marker用来实现分页显示效果,参数的长度必须小于256字节。 + * @throws OSS_Exception + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function list_object($bucket, $options = NULL){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_HEADERS] = array( + self::OSS_DELIMITER => isset($options[self::OSS_DELIMITER])?$options[self::OSS_DELIMITER]:'/', + self::OSS_PREFIX => isset($options[self::OSS_PREFIX])?$options[self::OSS_PREFIX]:'', + self::OSS_MAX_KEYS => isset($options[self::OSS_MAX_KEYS])?$options[self::OSS_MAX_KEYS]:self::OSS_MAX_KEYS_VALUE, + self::OSS_MARKER => isset($options[self::OSS_MARKER])?$options[self::OSS_MARKER]:'', + ); + return $this->auth($options); + } + + /** + * 创建目录(目录和文件的区别在于,目录最后增加'/') + * @param string $bucket (Required) + * @param string $object (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function create_object_dir($bucket, $object, $options = NULL){ + $this->precheck_common($bucket, $object, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = $object . '/'; //虚拟目录需要以'/结尾' + $options[self::OSS_CONTENT_LENGTH] = array(self::OSS_CONTENT_LENGTH => 0); + return $this->auth($options); + } + + /** + * 通过在http body中添加内容来上传文件,适合比较小的文件 + * 根据api约定,需要在http header中增加content-length字段 + * @param string $bucket (Required) + * @param string $object (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function upload_file_by_content($bucket, $object, $options = NULL){ + $this->precheck_common($bucket, $object, $options); + + //内容校验 + OSSUtil::validate_content($options); + $content_type = $this->get_mime_type($object); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = $object; + + if(!isset($options[self::OSS_LENGTH])){ + $options[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]); + }else{ + $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH]; + } + + if(!isset($options[self::OSS_CONTENT_TYPE]) && isset($content_type) && !empty($content_type)){ + $options[self::OSS_CONTENT_TYPE] = $content_type; + } + return $this->auth($options); + } + + /** + * 上传文件,适合比较大的文件 + * @throws OSS_Exception + * @param string $bucket (Required) + * @param string $object (Required) + * @param string $file (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2012-02-28 + * @return ResponseCore + */ + public function upload_file_by_file($bucket, $object, $file, $options = NULL){ + $this->precheck_common($bucket, $object, $options); + OSSUtil::is_empty($file, OSS_FILE_PATH_IS_NOT_ALLOWED_EMPTY); + //Windows系统下进行转码 + $file = OSSUtil::encoding_path($file); + $options[self::OSS_FILE_UPLOAD] = $file; + if(!file_exists($options[self::OSS_FILE_UPLOAD])){ + throw new OSS_Exception($options[self::OSS_FILE_UPLOAD].OSS_FILE_NOT_EXIST); + } + $file_size = filesize($options[self::OSS_FILE_UPLOAD]); + $is_check_md5 = $this->is_check_md5($options); + if ($is_check_md5){ + $content_md5 = base64_encode(md5_file($options[self::OSS_FILE_UPLOAD], true)); + $options[self::OSS_CONTENT_MD5] = $content_md5; + } + $content_type = $this->get_mime_type($file); + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_CONTENT_TYPE] = $content_type; + $options[self::OSS_CONTENT_LENGTH] = $file_size; + $response = $this->auth($options); + return $response; + } + + /** + * 拷贝object + * @param string $from_bucket (Required) + * @param string $from_object (Required) + * @param string $to_bucket (Required) + * @param string $to_object (Required) + * @param array $options (Optional) + * @return ResponseCore + * @throws OSS_Exception + */ + public function copy_object($from_bucket, $from_object, $to_bucket, $to_object, $options = NULL){ + $this->precheck_common($from_bucket, $from_object, $options); + $this->precheck_common($to_bucket, $to_object, $options); + $options[self::OSS_BUCKET] = $to_bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = $to_object; + if(isset($options[self::OSS_HEADERS])){ + $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE] = '/'.$from_bucket.'/'.$from_object; + } + else { + $options[self::OSS_HEADERS] = array(self::OSS_OBJECT_COPY_SOURCE => '/'.$from_bucket.'/'.$from_object); + } + + return $this->auth($options); + } + + /** + * 获得object的meta信息 + * @param string $bucket (Required) + * @param string $object (Required) + * @param string $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function get_object_meta($bucket, $object, $options = NULL){ + $this->precheck_common($bucket, $object, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_HEAD; + $options[self::OSS_OBJECT] = $object; + return $this->auth($options); + } + + /** + * 删除object + * @param string $bucket(Required) + * @param string $object (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function delete_object($bucket, $object, $options = NULL){ + $this->precheck_common($bucket, $object, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = $object; + return $this->auth($options); + } + + /** + * 批量删除objects + * @throws OSS_Exception + * @param string $bucket(Required) + * @param array $objects (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2012-03-09 + * @return ResponseCore + */ + public function delete_objects($bucket, $objects, $options = null){ + $this->precheck_common($bucket, NULL, $options, false); + //objects + if(!is_array($objects) || !$objects){ + throw new OSS_Exception('The ' . __FUNCTION__ . ' method requires the "objects" option to be set as an array.'); + } + + $options[self::OSS_METHOD] = self::OSS_HTTP_POST; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'delete'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + $xml = new SimpleXMLElement(''); + // Quiet mode + if (isset($options['quiet'])){ + $quiet = 'false'; + if (is_bool($options['quiet'])) { //Boolean + $quiet = $options['quiet'] ? 'true' : 'false'; + }elseif (is_string($options['quiet'])){ // String + $quiet = ($options['quiet'] === 'true') ? 'true' : 'false'; + } + $xml->addChild('Quiet', $quiet); + } + // Add the objects + foreach ($objects as $object){ + $sub_object = $xml->addChild('Object'); + $object = OSSUtil::s_replace($object); + $sub_object->addChild('Key', $object); + } + $options[self::OSS_CONTENT] = $xml->asXML(); + return $this->auth($options); + } + + /** + * 获得Object内容 + * @param string $bucket(Required) + * @param string $object (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function get_object($bucket, $object, $options = NULL){ + $this->precheck_common($bucket, $object, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = $object; + if(isset($options[self::OSS_LAST_MODIFIED])){ + $options[self::OSS_HEADERS][self::OSS_IF_MODIFIED_SINCE] = $options[self::OSS_LAST_MODIFIED]; + unset($options[self::OSS_LAST_MODIFIED]); + } + if(isset($options[self::OSS_ETAG])){ + $options[self::OSS_HEADERS][self::OSS_IF_NONE_MATCH] = $options[self::OSS_ETAG]; + unset($options[self::OSS_ETAG]); + } + if(isset($options[self::OSS_RANGE])){ + $range = $options[self::OSS_RANGE]; + $options[self::OSS_HEADERS][self::OSS_RANGE] = "bytes=$range"; + unset($options[self::OSS_RANGE]); + } + + return $this->auth($options); + } + + /** + * 检测Object是否存在 + * @param string $bucket(Required) + * @param string $object (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function is_object_exist($bucket, $object, $options = NULL){ + return $this->get_object_meta($bucket, $object, $options); + } + + /** + * 获取分片大小 + * @param int $part_size (Required) + * @return int + */ + private function get_part_size($part_size){ + $part_size = (integer)$part_size; + if($part_size <= self::OSS_MIN_PART_SIZE){ + $part_size = self::OSS_MIN_PART_SIZE; + }elseif ($part_size > self::OSS_MAX_PART_SIZE){ + $part_size = self::OSS_MAX_PART_SIZE; + }else{ + $part_size = self::OSS_MID_PART_SIZE; + } + return $part_size; + } + + /*%******************************************************************************************************%*/ + //Multi Part相关操作 + /** + * 计算文件可以分成多少个part,以及每个part的长度以及起始位置 + * 方法必须在 中调用 + * + * @param integer $file_size (Required) 文件大小 + * @param integer $part_size (Required) part大小,默认5M + * @return array An array 包含 key-value 键值对. Key 为 `seekTo` 和 `length`. + */ + public function get_multipart_counts($file_size, $part_size = 5242880){ + $i = 0; + $size_count = $file_size; + $values = array(); + $part_size = $this->get_part_size($part_size); + while ($size_count > 0) + { + $size_count -= $part_size; + $values[] = array( + self::OSS_SEEK_TO => ($part_size * $i), + self::OSS_LENGTH => (($size_count > 0) ? $part_size : ($size_count + $part_size)), + ); + $i++; + } + return $values; + } + + /** + * 初始化multi-part upload + * @param string $bucket (Required) Bucket名称 + * @param string $object (Required) Object名称 + * @param array $options (Optional) Key-Value数组 + * @return ResponseCore + */ + public function initiate_multipart_upload($bucket, $object, $options = NULL){ + $this->precheck_common($bucket, $object, $options); + $options[self::OSS_METHOD] = self::OSS_HTTP_POST; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_SUB_RESOURCE] = 'uploads'; + $options[self::OSS_CONTENT] = ''; + $content_type = $this->get_mime_type($object); + if(!isset($options[self::OSS_HEADERS])){ + $options[self::OSS_HEADERS] = array(); + } + $options[self::OSS_HEADERS][self::OSS_CONTENT_TYPE] = $content_type; + + return $this->auth($options); + } + + /** + * 初始化multi-part upload,并且返回uploadId + * @param string $bucket (Required) Bucket名称 + * @param string $object (Required) Object名称 + * @param array $options (Optional) Key-Value数组 + * @return string uploadId + * @throws OSS_Exception + */ + public function init_multipart_upload($bucket, $object, $options = NULL){ + $res = $this->initiate_multipart_upload($bucket, $object, $options); + if (!$res->isOK()){ + throw new OSS_Exception('Init multi-part upload failed...'); + } + $xml = new SimpleXmlIterator($res->body); + $uploadId = (string)$xml->UploadId; + return $uploadId; + } + + /** + * 上传part + * @param string $bucket (Required) Bucket名称 + * @param string $object (Required) Object名称 + * @param string $upload_id (Required) uploadId + * @param array $options (Optional) Key-Value数组 + * @return ResponseCore + */ + public function upload_part($bucket, $object, $upload_id, $options = null){ + $this->precheck_common($bucket, $object, $options); + $this->precheck_param($options, self::OSS_FILE_UPLOAD, __FUNCTION__); + $this->precheck_param($options, self::OSS_PART_NUM, __FUNCTION__); + + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_UPLOAD_ID] = $upload_id; + + if(isset($options[self::OSS_LENGTH])){ + $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH]; + } + return $this->auth($options); + } + + /** + * 获取已成功上传的part + * @param string $bucket (Required) Bucket名称 + * @param string $object (Required) Object名称 + * @param string $upload_id (Required) uploadId + * @param array $options (Optional) Key-Value数组 + * @return ResponseCore + */ + public function list_parts($bucket, $object, $upload_id, $options = null){ + $this->precheck_common($bucket, $object, $options); + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_UPLOAD_ID] = $upload_id; + $options[self::OSS_QUERY_STRING] = array(); + foreach (array('max-parts', 'part-number-marker') as $param){ + if (isset($options[$param])){ + $options[self::OSS_QUERY_STRING][$param] = $options[$param]; + unset($options[$param]); + } + } + return $this->auth($options); + } + + /** + * 中止上传mulit-part upload + * @param string $bucket (Required) Bucket名称 + * @param string $object (Required) Object名称 + * @param string $upload_id (Required) uploadId + * @param array $options (Optional) Key-Value数组 + * @return ResponseCore + */ + public function abort_multipart_upload($bucket, $object, $upload_id, $options = NULL){ + $this->precheck_common($bucket, $object, $options); + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_UPLOAD_ID] = $upload_id; + return $this->auth($options); + } + + /** + * 完成multi-part上传 + * @param string $bucket (Required) Bucket名称 + * @param string $object (Required) Object名称 + * @param string $upload_id (Required) uploadId + * @param array | xml $parts 可以是一个上传成功part的数组,或者是一个ReponseCore对象 + * @param array $options (Optional) Key-Value数组 + * @return ResponseCore + */ + public function complete_multipart_upload($bucket, $object, $upload_id, $parts, $options = NULL){ + $this->precheck_common($bucket, $object, $options); + $options[self::OSS_METHOD] = self::OSS_HTTP_POST; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_UPLOAD_ID] = $upload_id; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + + if(is_string($parts)){ + $options[self::OSS_CONTENT] = $parts; + }else if($parts instanceof SimpleXMLElement){ + $options[self::OSS_CONTENT] = $parts->asXML(); + }else if((is_array($parts) || $parts instanceof ResponseCore)){ + $xml = new SimpleXMLElement(''); + + if (is_array($parts)){ + foreach ($parts as $node){ + $part = $xml->addChild('Part'); + $part->addChild('PartNumber', $node['PartNumber']); + $part->addChild('ETag', $node['ETag']); + } + }elseif ($parts instanceof ResponseCore){ + foreach ($parts->body->Part as $node){ + $part = $xml->addChild('Part'); + $part->addChild('PartNumber', (string) $node->PartNumber); + $part->addChild('ETag', (string) $node->ETag); + } + } + $options[self::OSS_CONTENT] = $xml->asXML(); + } + return $this->auth($options); + } + + /** + * 列出multipart上传 + * @param string $bucket (Requeired) bucket + * @param array $options (Optional) 关联数组 + * @author xiaobing + * @since 2012-03-05 + * @return ResponseCore + */ + public function list_multipart_uploads($bucket, $options = null){ + $this->precheck_common($bucket, NULL, $options, false); + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'uploads'; + + foreach (array('delimiter','key-marker', 'max-uploads', 'prefix','upload-id-marker') as $param){ + if (isset($options[$param])){ + $options[self::OSS_QUERY_STRING][$param] = $options[$param]; + unset($options[$param]); + } + } + return $this->auth($options); + } + + /** + * 从已存在的object拷贝part + * @param string $from_bucket (Required) + * @param string $from_object (Required) + * @param string $to_bucket (Required) + * @param string $to_object (Required) + * @param int $part_number (Required) + * @param string $upload_id (Required) + * @param array $options (Optional) Key-Value数组 + * @return ResponseCore + * @throws OSS_Exception + */ + public function copy_upload_part($from_bucket, $from_object, $to_bucket, $to_object, $part_number, $upload_id, $options = NULL){ + $this->precheck_common($from_bucket, $from_object, $options); + $this->precheck_common($to_bucket, $to_object, $options); + + //如果没有设置$options['isFullCopy'],则需要强制判断copy的起止位置 + $start_range = "0"; + if(isset($options['start'])){ + $start_range = $options['start']; + } + $end_range = ""; + if(isset($options['end'])){ + $end_range = $options['end']; + } + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_BUCKET] = $to_bucket; + $options[self::OSS_OBJECT] = $to_object; + $options[self::OSS_PART_NUM] = $part_number; + $options[self::OSS_UPLOAD_ID] = $upload_id; + + if(!isset($options[self::OSS_HEADERS])){ + $options[self::OSS_HEADERS] = array(); + } + + $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE] = '/' . $from_bucket . '/' . $from_object; + $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE_RANGE] = "bytes=" . $start_range . "-" . $end_range; + return $this->auth($options); + } + + /** + * multipart上传统一封装,从初始化到完成multipart,以及出错后中止动作 + * @param string $bucket (Required) + * @param string $object (Required) + * @param array $options (Optional) Key-Value数组 + * @return ResponseCore + * @throws OSS_Exception + */ + public function create_mpu_object($bucket, $object, $options = null){ + $this->precheck_common($bucket, $object, $options); + if(isset($options[self::OSS_LENGTH])){ + $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH]; + unset($options[self::OSS_LENGTH]); + } + + if(isset($options[self::OSS_FILE_UPLOAD])){ + //Windows系统下进行转码 + $options[self::OSS_FILE_UPLOAD] = OSSUtil::encoding_path($options[self::OSS_FILE_UPLOAD]); + } + + $this->precheck_param($options, self::OSS_FILE_UPLOAD, __FUNCTION__); + $upload_position = isset($options[self::OSS_SEEK_TO]) ? (integer) $options[self::OSS_SEEK_TO] : 0; + + if (isset($options[self::OSS_CONTENT_LENGTH])){ + $upload_file_size = (integer) $options[self::OSS_CONTENT_LENGTH]; + } else { + $filename = $options[self::OSS_FILE_UPLOAD]; + $upload_file_size = filesize($filename); + if ($upload_file_size !== false) { + $upload_file_size -= $upload_position; + } + } + + if ($upload_position === false || !isset($upload_file_size) || $upload_file_size === false || $upload_file_size < 0){ + throw new OSS_Exception('The size of `fileUpload` cannot be determined in ' . __FUNCTION__ . '().'); + } + // 处理partSize + if (isset($options[self::OSS_PART_SIZE])){ + $options[self::OSS_PART_SIZE] = $this->get_part_size($options[self::OSS_PART_SIZE]); + } + else{ + $options[self::OSS_PART_SIZE] = self::OSS_MID_PART_SIZE; + } + + $is_check_md5 = $this->is_check_md5($options); + // 如果上传的文件小于partSize,则直接使用普通方式上传 + if ($upload_file_size < $options[self::OSS_PART_SIZE] && !isset($options[self::OSS_UPLOAD_ID])){ + $local_file = $options[self::OSS_FILE_UPLOAD]; + $options = array( + self::OSS_CHECK_MD5 => $is_check_md5, + ); + return $this->upload_file_by_file($bucket, $object, $local_file, $options); + } + + // 初始化multipart + if (isset($options[self::OSS_UPLOAD_ID])){ + $upload_id = $options[self::OSS_UPLOAD_ID]; + }else{ + //初始化 + $init_options = array(); + $upload_id = $this->init_multipart_upload($bucket, $object, $init_options); + } + + // 获取的分片 + $pieces = $this->get_multipart_counts($upload_file_size, (integer) $options[self::OSS_PART_SIZE]); + + $response_upload_part = array(); + foreach ($pieces as $i => $piece){ + $from_pos = $upload_position + (integer) $piece[self::OSS_SEEK_TO]; + $to_pos = (integer) $piece[self::OSS_LENGTH] + $from_pos - 1; + $up_options = array( + self::OSS_FILE_UPLOAD => $options[self::OSS_FILE_UPLOAD], + self::OSS_PART_NUM => ($i + 1), + self::OSS_SEEK_TO => $from_pos, + self::OSS_LENGTH => $to_pos - $from_pos + 1, + self::OSS_CHECK_MD5 => $is_check_md5, + ); + if ($is_check_md5) { + $content_md5 = OSSUtil::get_content_md5_of_file($options[self::OSS_FILE_UPLOAD], $from_pos, $to_pos); + $up_options[self::OSS_CONTENT_MD5] = $content_md5; + } + $response_upload_part[] = $this->upload_part($bucket, $object, $upload_id, $up_options); + } + + $upload_parts = array(); + $upload_part_result = true; + foreach ($response_upload_part as $i => $response){ + $upload_part_result = $upload_part_result && $response->isOk(); + if(!$upload_part_result){ + throw new OSS_Exception('any part upload failed, please try again'); + } + $upload_parts[] = array( + 'PartNumber' => ($i + 1), + 'ETag' => (string) $response->header['etag'] + ); + } + return $this->complete_multipart_upload($bucket, $object, $upload_id, $upload_parts); + } + + /** + * 通过Multi-Part方式上传整个目录,其中的object默认为文件名 + * @param string $bucket (Required) + * @param string $dir (Required) + * @param bool $recursive 是否递归,如果为true,则递归读取所有目录,默认为不递归读取 + * @param string $exclude + * @param array $options (Optional) Key-Value数组,其中可以包括以下的key + * @return bool + * @throws OSS_Exception + */ + public function create_mtu_object_by_dir($bucket, $dir, $recursive = false, $exclude = ".|..|.svn", $options = null){ + $this->precheck_common($bucket, NULL, $options, false); + //Windows系统下进行转码 + $dir = OSSUtil::encoding_path($dir); + //判断是否目录 + if(!is_dir($dir)){ + throw new OSS_Exception($dir.' is not a directory, please check it'); + } + + $file_list_array = $this->read_dir($dir, $exclude, $recursive); + + + if(empty($file_list_array)){ + throw new OSS_Exception($dir.' is empty...'); + } + + $is_upload_ok = true; + $index = 1; + + foreach ($file_list_array as $k=>$item){ + echo $index++.". "; + echo "Multiupload file ".$item['path']." "; + if (is_dir($item['path'])) { + echo " skipped, because it is directory...\n"; + } + else { + $options = array( + self::OSS_FILE_UPLOAD => $item['path'], + self::OSS_PART_SIZE => self::OSS_MIN_PART_SIZE, + ); + + $response = $this->create_mpu_object($bucket, $item['file'], $options); + if($response->isOK()){ + echo " successful..\n"; + } + else { + echo " failed..\n"; + $is_upload_ok = false; + continue; + } + } + } + return $is_upload_ok; + } + + /** + * 上传目录 + * @param array $options + * $options = array( + * 'bucket' => (Required) string + * 'object' => (Optional) string + * 'directory' => (Required) string + * 'exclude' => (Optional) string + * 'recursive' => (Optional) string + * 'checkmd5' => (Optional) boolean + * ) + * @return bool + * @throws OSS_Exception + */ + public function batch_upload_file($options = NULL){ + if((NULL == $options) || !isset($options['bucket']) || empty($options['bucket']) || !isset($options['directory']) ||empty($options['directory'])){ + throw new OSS_Exception('Bad Request', 400); + } + + $is_batch_upload_ok = true; + $bucket = $this->get_value($options, 'bucket'); + $directory = $this->get_value($options, 'directory'); + //Windows系统下进行转码 + $directory = OSSUtil::encoding_path($directory); + + //判断是否目录 + if(!is_dir($directory)){ + throw new OSS_Exception($directory . ' is not a directory, please check it'); + } + + $object = $this->get_value($options, 'object', ''); + $exclude = $this->get_value($options, 'exclude', '.|..|.svn', true); + $recursive = $this->get_value($options, 'recursive', false, true, true); + + //read directory + $file_list_array = $this->read_dir($directory, $exclude, $recursive); + + if(!$file_list_array){ + throw new OSS_Exception($directory.' is empty...'); + } + + $index = 1; + $is_check_md5 = $this->is_check_md5($options); + + foreach ($file_list_array as $k=>$item){ + echo $index++.". "; + echo "Upload file ".$item['path']." "; + if (is_dir($item['path'])) { + echo " skipped, because it is directory...\n"; + } + else { + $options = array( + self::OSS_FILE_UPLOAD => $item['path'], + self::OSS_PART_SIZE => self::OSS_MIN_PART_SIZE, + self::OSS_CHECK_MD5 => $is_check_md5, + ); + $real_object = (!empty($object)?$object.'/':'').$item['file']; + $response = $this->create_mpu_object($bucket, $real_object, $options); + if($response->isOK()){ + echo " successful..\n"; + }else{ + echo " failed..\n"; + $is_batch_upload_ok = false; + continue; + } + } + } + return $is_batch_upload_ok; + } + + /*%******************************************************************************************************%*/ + //Object Group相关操作, 不建议再使用,官方API文档中已经无相关介绍 + /** + * 转化object数组为固定个xml格式 + * @param string $bucket (Required) + * @param array $object_array (Required) + * @throws OSS_Exception + * @author xiaobing + * @since 2011-12-27 + * @return string + */ + public function make_object_group_xml($bucket, $object_array){ + $xml = ''; + $xml .= ''; + + if($object_array){ + if(count($object_array) > self::OSS_MAX_OBJECT_GROUP_VALUE){ + throw new OSS_Exception(OSS_OBJECT_GROUP_TOO_MANY_OBJECT, '-401'); + } + $index = 1; + foreach ($object_array as $key => $value){ + $object_meta = (array)$this->get_object_meta($bucket, $value); + if(isset($object_meta) && isset($object_meta['status']) && isset($object_meta['header']) && isset($object_meta['header']['etag']) && $object_meta['status'] == 200){ + $xml .= ''; + $xml .= ''.intval($index).''; + $xml .= ''.$value.''; + $xml .= ''.$object_meta['header']['etag'].''; + $xml .= ''; + + $index++; + } + } + }else{ + throw new OSS_Exception(OSS_OBJECT_ARRAY_IS_EMPTY, '-400'); + } + $xml .= ''; + return $xml; + } + /** + * 创建Object Group, 不建议再使用,官方API文档中已经无相关介绍 + * @param string $object_group (Required) Object Group名称 + * @param string $bucket (Required) Bucket名称 + * @param array $object_arry (Required) object数组,所有的object必须在同一个bucket下 + * 其中$object_arrya 格式如下: + * $object = array( + * $object1, + * $object2, + * ... + * ) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function create_object_group($bucket, $object_group, $object_arry, $options = NULL){ + $this->precheck_common($bucket, $object_group, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_POST; + $options[self::OSS_OBJECT] = $object_group; + $options[self::OSS_CONTENT_TYPE] = $this->get_mime_type($object_group); //重设Content-Type + $options[self::OSS_SUB_RESOURCE] = 'group'; //设置?group + $options[self::OSS_CONTENT] = $this->make_object_group_xml($bucket, $object_arry); //格式化xml + return $this->auth($options ); + } + + /** + * 获取Object Group, 不建议再使用,官方API文档中已经无相关介绍 + * @param string $object_group (Required) + * @param string $bucket (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function get_object_group($bucket, $object_group, $options = NULL){ + $this->precheck_common($bucket, $object_group, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = $object_group; + $options[self::OSS_HEADERS] = array(self::OSS_OBJECT_GROUP => self::OSS_OBJECT_GROUP); //header中的x-oss-file-group不能为空,否则返回值错误 + return $this->auth($options); + } + + /** + * 获取Object Group 的Object List信息, 不建议再使用,官方API文档中已经无相关介绍 + * @param string $object_group (Required) + * @param string $bucket (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function get_object_group_index($bucket, $object_group, $options = NULL){ + $this->precheck_common($bucket, $object_group, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = $object_group; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; //重设Content-Type + $options[self::OSS_HEADERS] = array(self::OSS_OBJECT_GROUP => self::OSS_OBJECT_GROUP); + return $this->auth($options); + } + + /** + * 获得object group的meta信息, 不建议再使用,官方API文档中已经无相关介绍 + * @param string $bucket (Required) + * @param string $object_group (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function get_object_group_meta($bucket, $object_group, $options = NULL){ + return $this->get_object_meta($bucket, $object_group, $options); + } + + /** + * 删除Object Group, 不建议再使用,官方API文档中已经无相关介绍 + * @param string $bucket(Required) + * @param string $object_group (Required) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-11-14 + * @return ResponseCore + */ + public function delete_object_group($bucket, $object_group, $options = NULL){ + return $this->delete_object($bucket, $object_group, $options); + } + + /*%******************************************************************************************************%*/ + //带签名的url相关 + + /** + * 获取GET签名的url + * @param string $bucket (Required) + * @param string $object (Required) + * @param int $timeout (Optional) + * @param array $options (Optional) + * @author xiaobing + * @since 2011-12-21 + * @return string + */ + public function get_sign_url($bucket, $object, $timeout = 60, $options = NULL){ + return $this->presign_url($bucket, $object, $timeout, self::OSS_HTTP_GET, $options); + } + + /** + * 获取签名url,支持生成get和put签名 + * @param string $bucket + * @param string $object + * @param int $timeout + * @param array $options (Optional) Key-Value数组 + * @param string $method + * @return ResponseCore + * @throws OSS_Exception + */ + public function presign_url($bucket, $object, $timeout = 60, $method = self::OSS_HTTP_GET, $options = NULL){ + $this->precheck_common($bucket, $object, $options); + //method + if (self::OSS_HTTP_GET !== $method && self::OSS_HTTP_PUT !== $method) { + throw new OSS_Exception(OSS_INVALID_METHOD); + } + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_METHOD] = $method; + if (!isset($options[self::OSS_CONTENT_TYPE])) { + $options[self::OSS_CONTENT_TYPE] = ''; + } + $timeout = time() + $timeout; + $options[self::OSS_PREAUTH] = $timeout; + $options[self::OSS_DATE] = $timeout; + $this->set_sign_sts_in_url(true); + return $this->auth($options); + } + + /** + * 检测options参数 + * @param array $options + * @throws OSS_Exception + */ + private function precheck_options(&$options) { + OSSUtil::validate_options($options); + if (!$options) { + $options = array(); + } + } + + /** + * 校验bucket参数 + * @param string $bucket + * @param string $err_msg + * @throws OSS_Exception + */ + private function precheck_bucket($bucket, $err_msg = OSS_BUCKET_IS_NOT_ALLOWED_EMPTY) { + OSSUtil::is_empty($bucket, $err_msg); + } + + /** + * 校验object参数 + * @param string $object + * @throws OSS_Exception + */ + private function precheck_object($object) { + OSSUtil::is_empty($object, OSS_OBJECT_IS_NOT_ALLOWED_EMPTY); + } + + /** + * 校验bucket,options参数 + * @param string $bucket + * @param string $object + * @param array $options + * @param bool $is_check_object + */ + private function precheck_common($bucket, $object, &$options, $is_check_object = true) { + if ($is_check_object){ + $this->precheck_object($object); + } + $this->precheck_options($options); + $this->precheck_bucket($bucket); + } + + /** + * 参数校验 + * @param array $options + * @param string $param + * @param string $func_name + * @throws OSS_Exception + */ + private function precheck_param($options, $param, $func_name){ + if (!isset($options[$param])){ + throw new OSS_Exception('The `' . $param . '` options is required in ' . $func_name . '().'); + } + } + + /** + * 检测md5 + * @param array $options + * @return bool|null + */ + private function is_check_md5($options){ + return $this->get_value($options, self::OSS_CHECK_MD5, false, true, true); + } + + /** + * 获取value + * @param array $options + * @param string $key + * @param string $default + * @param bool $is_check_empty + * @param bool $is_check_bool + * @return bool|null + */ + private function get_value($options, $key, $default = NULL, $is_check_empty = false, $is_check_bool = false) { + $value = $default; + if (isset($options[$key])){ + if ($is_check_empty){ + if (!empty($options[$key])){ + $value= $options[$key]; + } + } + else{ + $value= $options[$key]; + } + unset($options[$key]); + } + if ($is_check_bool){ + if ($value !== true && $value !== false){ + $value = false; + } + } + return $value; + } + + /** + * 获取mimetype类型 + * @param string $object + * @return string + */ + private function get_mime_type($object) { + $extension = explode('.', $object); + $extension = array_pop($extension); + $mime_type = MimeTypes::get_mimetype(strtolower($extension)); + return $mime_type; + } + + /** + * 读取目录 + * @param $dir + * @param string $exclude + * @param bool $recursive + * @return array + */ + private function read_dir($dir, $exclude = ".|..|.svn", $recursive = false){ + $file_list_array = array(); + $base_path=$dir; + $exclude_array = explode("|", $exclude); + // filter out "." and ".." + $exclude_array = array_unique(array_merge($exclude_array,array('.','..'))); + + if($recursive){ + foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $new_file) + { + if ($new_file->isDir()) continue; + echo "$new_file\n"; + $object = str_replace($base_path, '', $new_file); + if(!in_array(strtolower($object), $exclude_array)){ + $object = ltrim($object, '/'); + if (is_file($new_file)){ + $key = md5($new_file.$object, false); + $file_list_array[$key] = array('path' => $new_file,'file' => $object,); + } + } + } + } + else if($handle = opendir($dir)){ + while ( false !== ($file = readdir($handle))){ + if(!in_array(strtolower($file), $exclude_array)){ + $new_file = $dir.'/'.$file; + + $object = $file; + $object = ltrim($object, '/'); + if (is_file($new_file)){ + $key = md5($new_file.$object, false); + $file_list_array[$key] = array('path' => $new_file,'file' => $object,); + } + } + } + closedir($handle); + } + return $file_list_array; + } + + + /*%******************************************************************************************************%*/ + //请求 + + /** + * auth接口 + * @param array $options + * @return ResponseCore + * @throws OSS_Exception + * @throws RequestCore_Exception + */ + public function auth($options){ + OSSUtil::validate_options($options); + + //验证Bucket,list_bucket时不需要验证 + if(!( ('/' == $options[self::OSS_OBJECT]) && ('' == $options[self::OSS_BUCKET]) && ('GET' == $options[self::OSS_METHOD])) && !OSSUtil::validate_bucket($options[self::OSS_BUCKET])){ + throw new OSS_Exception('"'.$options[self::OSS_BUCKET].'"'.OSS_BUCKET_NAME_INVALID); + } + //验证Object + if(isset($options[self::OSS_OBJECT]) && !OSSUtil::validate_object($options[self::OSS_OBJECT])){ + throw new OSS_Exception($options[self::OSS_OBJECT].OSS_OBJECT_NAME_INVALID); + } + //Object编码为UTF-8 + $tmp_object = $options[self::OSS_OBJECT]; + try { + if(OSSUtil::is_gb2312($options[self::OSS_OBJECT])){ + $options[self::OSS_OBJECT] = iconv('GB2312', "UTF-8//IGNORE",$options[self::OSS_OBJECT]); + }elseif(OSSUtil::check_char($options[self::OSS_OBJECT],true)){ + $options[self::OSS_OBJECT] = iconv('GBK', "UTF-8//IGNORE",$options[self::OSS_OBJECT]); + } + } catch (Exception $e) { + try{ + $tmp_object = iconv(mb_detect_encoding($tmp_object), "UTF-8", $tmp_object); + } + catch(Exception $e) { + } + } + $options[self::OSS_OBJECT] = $tmp_object; + + //验证ACL + if(isset($options[self::OSS_HEADERS][self::OSS_ACL]) && !empty($options[self::OSS_HEADERS][self::OSS_ACL])){ + if(!in_array(strtolower($options[self::OSS_HEADERS][self::OSS_ACL]), self::$OSS_ACL_TYPES)){ + throw new OSS_Exception($options[self::OSS_HEADERS][self::OSS_ACL].':'.OSS_ACL_INVALID); + } + } + + //定义scheme + $scheme = $this->use_ssl ? 'https://' : 'http://'; + if($this->enable_domain_style){ + $hostname = $this->vhost ? $this->vhost : (($options[self::OSS_BUCKET] == '') ? $this->hostname : ($options[self::OSS_BUCKET].'.').$this->hostname); + }else{ + $hostname = (isset($options[self::OSS_BUCKET]) && '' !== $options[self::OSS_BUCKET]) ? $this->hostname.'/'.$options[self::OSS_BUCKET] : $this->hostname; + } + + //请求参数 + $signable_resource = ''; + $query_string_params = array(); + $signable_query_string_params = array(); + $string_to_sign = ''; + + $oss_host = $this->hostname; + if ($this->enable_domain_style){ + $oss_host = $hostname; + } + $headers = array ( + self::OSS_CONTENT_MD5 => '', + self::OSS_CONTENT_TYPE => isset($options[self::OSS_CONTENT_TYPE]) ? $options[self::OSS_CONTENT_TYPE] : 'application/x-www-form-urlencoded', + self::OSS_DATE => isset($options[self::OSS_DATE]) ? $options[self::OSS_DATE] : gmdate('D, d M Y H:i:s \G\M\T'), + self::OSS_HOST => $oss_host, + ); + + if (isset($options[self::OSS_CONTENT_MD5])){ + $headers[self::OSS_CONTENT_MD5] = $options[self::OSS_CONTENT_MD5]; + } + + //增加stsSecurityToken + if((!is_null($this->security_token)) && (!$this->enable_sts_in_url)){ + $headers[self::OSS_SECURITY_TOKEN] = $this->security_token; + } + + if (isset($options[self::OSS_OBJECT]) && '/' !== $options[self::OSS_OBJECT]){ + $signable_resource = '/'.str_replace(array('%2F', '%25'), array('/', '%'), rawurlencode($options[self::OSS_OBJECT])); + } + + if(isset($options[self::OSS_QUERY_STRING])){ + $query_string_params = array_merge($query_string_params, $options[self::OSS_QUERY_STRING]); + } + $query_string = OSSUtil::to_query_string($query_string_params); + + $signable_list = array( + self::OSS_PART_NUM, + 'response-content-type', + 'response-content-language', + 'response-cache-control', + 'response-content-encoding', + 'response-expires', + 'response-content-disposition', + self::OSS_UPLOAD_ID, + ); + + foreach ($signable_list as $item){ + if(isset($options[$item])){ + $signable_query_string_params[$item] = $options[$item]; + } + } + + if ($this->enable_sts_in_url && (!is_null($this->security_token))) { + $signable_query_string_params["security-token"] = $this->security_token; + } + $signable_query_string = OSSUtil::to_query_string($signable_query_string_params); + + //合并 HTTP headers + if (isset($options[self::OSS_HEADERS])) { + $headers = array_merge($headers, $options[self::OSS_HEADERS]); + } + + //生成请求URL + $conjunction = '?'; + + $non_signable_resource = ''; + + if (isset($options[self::OSS_SUB_RESOURCE])){ + $signable_resource .= $conjunction . $options[self::OSS_SUB_RESOURCE]; + $conjunction = '&'; + } + + if($signable_query_string !== ''){ + $signable_query_string = $conjunction . $signable_query_string; + $conjunction = '&'; + } + + if($query_string !== ''){ + $non_signable_resource .= $conjunction . $query_string; + $conjunction = '&'; + } + + $this->request_url = $scheme . $hostname . $signable_resource . $signable_query_string . $non_signable_resource; + + //创建请求 + $request = new RequestCore($this->request_url); + $user_agent = OSS_NAME."/".OSS_VERSION." (".php_uname('s')."/".php_uname('r')."/".php_uname('m').";".PHP_VERSION.")"; + $request->set_useragent($user_agent); + + // Streaming uploads + if (isset($options[self::OSS_FILE_UPLOAD])){ + if (is_resource($options[self::OSS_FILE_UPLOAD])){ + $length = null; + + if (isset($options[self::OSS_CONTENT_LENGTH])){ + $length = $options[self::OSS_CONTENT_LENGTH]; + }elseif (isset($options[self::OSS_SEEK_TO])){ + $stats = fstat($options[self::OSS_FILE_UPLOAD]); + if ($stats && $stats[self::OSS_SIZE] >= 0){ + $length = $stats[self::OSS_SIZE] - (integer) $options[self::OSS_SEEK_TO]; + } + } + + $request->set_read_stream($options[self::OSS_FILE_UPLOAD], $length); + + if ($headers[self::OSS_CONTENT_TYPE] === 'application/x-www-form-urlencoded'){ + $headers[self::OSS_CONTENT_TYPE] = 'application/octet-stream'; + } + }else{ + $request->set_read_file($options[self::OSS_FILE_UPLOAD]); + $length = $request->read_stream_size; + if (isset($options[self::OSS_CONTENT_LENGTH])){ + $length = $options[self::OSS_CONTENT_LENGTH]; + }elseif (isset($options[self::OSS_SEEK_TO]) && isset($length)){ + $length -= (integer) $options[self::OSS_SEEK_TO]; + } + $request->set_read_stream_size($length); + if (isset($headers[self::OSS_CONTENT_TYPE]) && ($headers[self::OSS_CONTENT_TYPE] === 'application/x-www-form-urlencoded')){ + $mime_type = self::get_mime_type($options[self::OSS_FILE_UPLOAD]); + $headers[self::OSS_CONTENT_TYPE] = $mime_type; + } + } + } + + if (isset($options[self::OSS_SEEK_TO])){ + $request->set_seek_position((integer)$options[self::OSS_SEEK_TO]); + } + + if (isset($options[self::OSS_FILE_DOWNLOAD])){ + if (is_resource($options[self::OSS_FILE_DOWNLOAD])){ + $request->set_write_stream($options[self::OSS_FILE_DOWNLOAD]); + }else{ + $request->set_write_file($options[self::OSS_FILE_DOWNLOAD]); + } + } + + if(isset($options[self::OSS_METHOD])){ + $request->set_method($options[self::OSS_METHOD]); + $string_to_sign .= $options[self::OSS_METHOD] . "\n"; + } + + if (isset($options[self::OSS_CONTENT])) { + $request->set_body($options[self::OSS_CONTENT]); + if ($headers[self::OSS_CONTENT_TYPE] === 'application/x-www-form-urlencoded'){ + $headers[self::OSS_CONTENT_TYPE] = 'application/octet-stream'; + } + + $headers[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]); + $headers[self::OSS_CONTENT_MD5] = base64_encode(md5($options[self::OSS_CONTENT], true)); + } + + uksort($headers, 'strnatcasecmp'); + + foreach($headers as $header_key => $header_value){ + $header_value = str_replace(array ("\r", "\n"), '', $header_value); + if ($header_value !== '') { + $request->add_header($header_key, $header_value); + } + + if ( + strtolower($header_key) === 'content-md5' || + strtolower($header_key) === 'content-type' || + strtolower($header_key) === 'date' || + (isset($options['self::OSS_PREAUTH']) && (integer) $options['self::OSS_PREAUTH'] > 0) + ){ + $string_to_sign .= $header_value . "\n"; + }elseif (substr(strtolower($header_key), 0, 6) === self::OSS_DEFAULT_PREFIX){ + $string_to_sign .= strtolower($header_key) . ':' . $header_value . "\n"; + } + } + + $string_to_sign .= '/' . $options[self::OSS_BUCKET]; + $string_to_sign .= $this->enable_domain_style ? ($options[self::OSS_BUCKET] != '' ? ($options[self::OSS_OBJECT]=='/'?'/':'') :''): ''; + $string_to_sign .= rawurldecode($signable_resource) . urldecode($signable_query_string); + + $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $this->access_key, true)); + $request->add_header('Authorization', 'OSS ' . $this->access_id . ':' . $signature); + + if (isset($options[self::OSS_PREAUTH]) && (integer) $options[self::OSS_PREAUTH] > 0){ + $signed_url = $this->request_url . $conjunction . self::OSS_URL_ACCESS_KEY_ID.'=' . rawurlencode($this->access_id) . '&'.self::OSS_URL_EXPIRES.'=' . $options[self::OSS_PREAUTH] . '&'.self::OSS_URL_SIGNATURE.'=' . rawurlencode($signature); + return $signed_url; + }elseif (isset($options[self::OSS_PREAUTH])){ + return $this->request_url; + } + + if ($this->debug_mode){ + $request->debug_mode = $this->debug_mode; + } + + $request->send_request(); + + $response_header = $request->get_response_header(); + $response_header['oss-request-url'] = $this->request_url; + $response_header['oss-redirects'] = $this->redirects; + $response_header['oss-stringtosign'] = $string_to_sign; + $response_header['oss-requestheaders'] = $request->request_headers; + + $data = new ResponseCore($response_header , $request->get_response_body(), $request->get_response_code()); + + //retry if OSS Internal Error + if((integer)$request->get_response_code() === 500){ + if($this->redirects <= $this->max_retries){ + //设置休眠 + $delay = (integer) (pow(4, $this->redirects) * 100000); + usleep($delay); + $this->redirects++; + $data = $this->auth($options); + } + } + + $this->redirects = 0; + return $data; + } + + /*%******************************************************************************************************%*/ + //属性 + + /** + * 设置debug模式 + * @param boolean $debug_mode (Optional) + * @author xiaobing + * @since 2012-05-29 + * @return void + */ + public function set_debug_mode($debug_mode = false){ + $this->debug_mode = $debug_mode; + } + public function get_debug_mode(){ + return $this->debug_mode; + } + + /** + * 设置最大尝试次数 + * @param int $max_retries + * @author xiaobing + * @since 2012-05-29 + * @return void + */ + public function set_max_retries($max_retries = 3){ + $this->max_retries = $max_retries; + } + + /** + * 获取最大尝试次数 + * @author xiaobing + * @since 2012-05-29 + * @return int + */ + public function get_max_retries(){ + return $this->max_retries; + } + + /** + * 设置host地址 + * @author xiaobing + * @param string $hostname host name + * @param int $port int + * @since 2012-06-11 + * @return void + */ + public function set_host_name($hostname, $port = null){ + $this->hostname = $hostname; + + if($port){ + $this->port = $port; + $this->hostname .= ':'.$port; + } + } + + public function get_host(){ + return $this->hostname; + } + + public function get_port(){ + return $this->port; + } + + public function get_id(){ + return $this->access_id; + } + + /** + * 设置vhost地址 + * @author xiaobing + * @param string $vhost vhost + * @since 2012-06-11 + * @return void + */ + public function set_vhost($vhost){ + $this->vhost = $vhost; + } + + public function get_vhost(){ + return $this->vhost; + } + /** + * 设置路径形式,如果为true,则启用三级域名,如bucket.oss.aliyuncs.com + * @author xiaobing + * @param boolean $enable_domain_style + * @since 2012-06-11 + * @return void + */ + public function set_enable_domain_style($enable_domain_style = true){ + $this->enable_domain_style = $enable_domain_style; + } + + public function get_enable_domain_style(){ + return $this->enable_domain_style; + } + + public function set_sign_sts_in_url($enable){ + if ($enable) { + $this->enable_sts_in_url = true; + } else { + $this->enable_sts_in_url = false; + } + } + + /*%******************************************************************************************************%*/ + const DEFAULT_OSS_HOST = 'oss.aliyuncs.com'; + const DEFAULT_OSS_ENDPOINT = 'oss.aliyuncs.com'; + const NAME = OSS_NAME; + const BUILD = OSS_BUILD; + const VERSION = OSS_VERSION; + const AUTHOR = OSS_AUTHOR; + //OSS 内部常量 + const OSS_BUCKET = 'bucket'; + const OSS_OBJECT = 'object'; + const OSS_HEADERS = OSSUtil::OSS_HEADERS; + const OSS_METHOD = 'method'; + const OSS_QUERY = 'query'; + const OSS_BASENAME = 'basename'; + const OSS_MAX_KEYS = 'max-keys'; + const OSS_UPLOAD_ID = 'uploadId'; + const OSS_PART_NUM = 'partNumber'; + const OSS_MAX_KEYS_VALUE = 100; + const OSS_MAX_OBJECT_GROUP_VALUE = OSSUtil::OSS_MAX_OBJECT_GROUP_VALUE; + const OSS_MAX_PART_SIZE = OSSUtil::OSS_MAX_PART_SIZE; + const OSS_MID_PART_SIZE = OSSUtil::OSS_MID_PART_SIZE; + const OSS_MIN_PART_SIZE = OSSUtil::OSS_MIN_PART_SIZE; + const OSS_FILE_SLICE_SIZE = 8192; + const OSS_PREFIX = 'prefix'; + const OSS_DELIMITER = 'delimiter'; + const OSS_MARKER = 'marker'; + const OSS_CONTENT_MD5 = 'Content-Md5'; + const OSS_SELF_CONTENT_MD5 = 'x-oss-meta-md5'; + const OSS_CONTENT_TYPE = 'Content-Type'; + const OSS_CONTENT_LENGTH = 'Content-Length'; + const OSS_IF_MODIFIED_SINCE = 'If-Modified-Since'; + const OSS_IF_UNMODIFIED_SINCE = 'If-Unmodified-Since'; + const OSS_IF_MATCH = 'If-Match'; + const OSS_IF_NONE_MATCH = 'If-None-Match'; + const OSS_CACHE_CONTROL = 'Cache-Control'; + const OSS_EXPIRES = 'Expires'; + const OSS_PREAUTH = 'preauth'; + const OSS_CONTENT_COING = 'Content-Coding'; + const OSS_CONTENT_DISPOSTION = 'Content-Disposition'; + const OSS_RANGE = 'range'; + const OSS_ETAG = 'etag'; + const OSS_LAST_MODIFIED = 'lastmodified'; + const OS_CONTENT_RANGE = 'Content-Range'; + const OSS_CONTENT = OSSUtil::OSS_CONTENT; + const OSS_BODY = 'body'; + const OSS_LENGTH = OSSUtil::OSS_LENGTH; + const OSS_HOST = 'Host'; + const OSS_DATE = 'Date'; + const OSS_AUTHORIZATION = 'Authorization'; + const OSS_FILE_DOWNLOAD = 'fileDownload'; + const OSS_FILE_UPLOAD = 'fileUpload'; + const OSS_PART_SIZE = 'partSize'; + const OSS_SEEK_TO = 'seekTo'; + const OSS_SIZE = 'size'; + const OSS_QUERY_STRING = 'query_string'; + const OSS_SUB_RESOURCE = 'sub_resource'; + const OSS_DEFAULT_PREFIX = 'x-oss-'; + const OSS_CHECK_MD5 = 'checkmd5'; + /*%******************************************************************************************%*/ + //私有URL变量 + const OSS_URL_ACCESS_KEY_ID = 'OSSAccessKeyId'; + const OSS_URL_EXPIRES = 'Expires'; + const OSS_URL_SIGNATURE = 'Signature'; + /*%******************************************************************************************%*/ + //HTTP方法 + const OSS_HTTP_GET = 'GET'; + const OSS_HTTP_PUT = 'PUT'; + const OSS_HTTP_HEAD = 'HEAD'; + const OSS_HTTP_POST = 'POST'; + const OSS_HTTP_DELETE = 'DELETE'; + const OSS_HTTP_OPTIONS = 'OPTIONS'; + /*%******************************************************************************************%*/ + //其他常量 + const OSS_ACL = 'x-oss-acl'; + const OSS_OBJECT_GROUP = 'x-oss-file-group'; + const OSS_MULTI_PART = 'uploads'; + const OSS_MULTI_DELETE = 'delete'; + const OSS_OBJECT_COPY_SOURCE = 'x-oss-copy-source'; + const OSS_OBJECT_COPY_SOURCE_RANGE = "x-oss-copy-source-range"; + //支持STS SecurityToken + const OSS_SECURITY_TOKEN = "x-oss-security-token"; + + const OSS_ACL_TYPE_PRIVATE = 'private'; + const OSS_ACL_TYPE_PUBLIC_READ = 'public-read'; + const OSS_ACL_TYPE_PUBLIC_READ_WRITE = 'public-read-write'; + //OSS ACL数组 + static $OSS_ACL_TYPES = array( + self::OSS_ACL_TYPE_PRIVATE, + self::OSS_ACL_TYPE_PUBLIC_READ, + self::OSS_ACL_TYPE_PUBLIC_READ_WRITE + ); + + //CORS 相关 + const OSS_CORS_ALLOWED_ORIGIN='AllowedOrigin'; + const OSS_CORS_ALLOWED_METHOD='AllowedMethod'; + const OSS_CORS_ALLOWED_HEADER='AllowedHeader'; + const OSS_CORS_EXPOSE_HEADER='ExposeHeader'; + const OSS_CORS_MAX_AGE_SECONDS='MaxAgeSeconds'; + const OSS_OPTIONS_ORIGIN = 'Origin'; + const OSS_OPTIONS_REQUEST_METHOD = 'Access-Control-Request-Method'; + const OSS_OPTIONS_REQUEST_HEADERS = 'Access-Control-Request-Headers'; + + + /*%******************************************************************************************%*/ + //是否使用SSL + public $version = OSS_VERSION; + protected $use_ssl = false; + //是否使用debug模式 + private $debug_mode = false; + private $max_retries = 3; + private $redirects = 0; + private $vhost; + //路径表现方式 + private $enable_domain_style = false; + private $request_url; + private $access_id; + private $access_key; + private $hostname; + private $port; + private $security_token; + private $enable_sts_in_url = false; +} diff --git a/AliOssSdk/thirdparty/xml2array.class.php b/AliOssSdk/thirdparty/xml2array.class.php new file mode 100644 index 0000000..1e9f773 --- /dev/null +++ b/AliOssSdk/thirdparty/xml2array.class.php @@ -0,0 +1,139 @@ +formatOutput = $format_output; + self::$encoding = $encoding; + } + + /** + * @param $input_xml + * @return mixed + * @throws Exception + */ + public static function &createArray($input_xml) { + $xml = self::getXMLRoot(); + if(is_string($input_xml)) { + $parsed = $xml->loadXML($input_xml); + if(!$parsed) { + throw new Exception('[XML2Array] Error parsing the XML string.'); + } + } else { + if(get_class($input_xml) != 'DOMDocument') { + throw new Exception('[XML2Array] The input XML object should be of type: DOMDocument.'); + } + $xml = self::$xml = $input_xml; + } + $array[$xml->documentElement->tagName] = self::convert($xml->documentElement); + self::$xml = null; // clear the xml node in the class for 2nd time use. + return $array; + } + + /** + * Convert an Array to XML + * @param mixed $node - XML as a string or as an object of DOMDocument + * @return mixed + */ + private static function &convert($node) { + $output = array(); + + switch ($node->nodeType) { + case XML_CDATA_SECTION_NODE: + $output['@cdata'] = trim($node->textContent); + break; + + case XML_TEXT_NODE: + $output = trim($node->textContent); + break; + + case XML_ELEMENT_NODE: + + // for each child node, call the covert function recursively + for ($i=0, $m=$node->childNodes->length; $i<$m; $i++) { + $child = $node->childNodes->item($i); + $v = self::convert($child); + if(isset($child->tagName)) { + $t = $child->tagName; + + // assume more nodes of same kind are coming + if(!isset($output[$t])) { + $output[$t] = array(); + } + $output[$t][] = $v; + } else { + //check if it is not an empty text node + if($v !== '') { + $output = $v; + } + } + } + + if(is_array($output)) { + // if only one node of its kind, assign it directly instead if array($value); + foreach ($output as $t => $v) { + if(is_array($v) && count($v)==1) { + $output[$t] = $v[0]; + } + } + if(empty($output)) { + //for empty nodes + $output = ''; + } + } + + // loop through the attributes and collect them + if($node->attributes->length) { + $a = array(); + foreach($node->attributes as $attrName => $attrNode) { + $a[$attrName] = (string) $attrNode->value; + } + // if its an leaf node, store the value in @value instead of directly storing it. + if(!is_array($output)) { + $output = array('@value' => $output); + } + $output['@attributes'] = $a; + } + break; + } + return $output; + } + + /* + * Get the root XML node, if there isn't one, create it. + */ + private static function getXMLRoot(){ + if(empty(self::$xml)) { + self::init(); + } + return self::$xml; + } +} diff --git a/AliOssSdk/util/mimetypes.class.php b/AliOssSdk/util/mimetypes.class.php new file mode 100644 index 0000000..f90a6e2 --- /dev/null +++ b/AliOssSdk/util/mimetypes.class.php @@ -0,0 +1,240 @@ + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'apk' => 'application/vnd.android.package-archive', + + 'hqx' => 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'doc' => 'application/msword', + 'ogg' => 'application/ogg', + 'pdf' => 'application/pdf', + 'rtf' => 'text/rtf', + 'mif' => 'application/vnd.mif', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'sxw' => 'application/vnd.sun.xml.writer', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sxc' => 'application/vnd.sun.xml.calc', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'sxd' => 'application/vnd.sun.xml.draw', + 'std' => 'application/vnd.sun.xml.draw.template', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxm' => 'application/vnd.sun.xml.math', + 'sis' => 'application/vnd.symbian.install', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'bcpio' => 'application/x-bcpio', + 'torrent' => 'application/x-bittorrent', + 'bz2' => 'application/x-bzip2', + 'vcd' => 'application/x-cdlink', + 'pgn' => 'application/x-chess-pgn', + 'cpio' => 'application/x-cpio', + 'csh' => 'application/x-csh', + 'dvi' => 'application/x-dvi', + 'spl' => 'application/x-futuresplash', + 'gtar' => 'application/x-gtar', + 'hdf' => 'application/x-hdf', + 'jar' => 'application/x-java-archive', + 'jnlp' => 'application/x-java-jnlp-file', + 'js' => 'application/x-javascript', + 'ksp' => 'application/x-kspread', + 'chrt' => 'application/x-kchart', + 'kil' => 'application/x-killustrator', + 'latex' => 'application/x-latex', + 'rpm' => 'application/x-rpm', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'tar' => 'application/x-tar', + 'tcl' => 'application/x-tcl', + 'tex' => 'application/x-tex', + 'man' => 'application/x-troff-man', + 'me' => 'application/x-troff-me', + 'ms' => 'application/x-troff-ms', + 'ustar' => 'application/x-ustar', + 'src' => 'application/x-wais-source', + 'zip' => 'application/zip', + 'm3u' => 'audio/x-mpegurl', + 'ra' => 'audio/x-pn-realaudio', + 'wav' => 'audio/x-wav', + 'wma' => 'audio/x-ms-wma', + 'wax' => 'audio/x-ms-wax', + 'pdb' => 'chemical/x-pdb', + 'xyz' => 'chemical/x-xyz', + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'ief' => 'image/ief', + 'png' => 'image/png', + 'wbmp' => 'image/vnd.wap.wbmp', + 'ras' => 'image/x-cmu-raster', + 'pnm' => 'image/x-portable-anymap', + 'pbm' => 'image/x-portable-bitmap', + 'pgm' => 'image/x-portable-graymap', + 'ppm' => 'image/x-portable-pixmap', + 'rgb' => 'image/x-rgb', + 'xbm' => 'image/x-xbitmap', + 'xpm' => 'image/x-xpixmap', + 'xwd' => 'image/x-xwindowdump', + 'css' => 'text/css', + 'rtx' => 'text/richtext', + 'tsv' => 'text/tab-separated-values', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'wml' => 'text/vnd.wap.wml', + 'wmls' => 'text/vnd.wap.wmlscript', + 'etx' => 'text/x-setext', + 'mxu' => 'video/vnd.mpegurl', + 'flv' => 'video/x-flv', + 'wm' => 'video/x-ms-wm', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wvx' => 'video/x-ms-wvx', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie', + 'ice' => 'x-conference/x-cooltalk', + '3gp' => 'video/3gpp', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'asc' => 'text/plain', + 'atom' => 'application/atom+xml', + 'au' => 'audio/basic', + 'bin' => 'application/octet-stream', + 'cdf' => 'application/x-netcdf', + 'cgm' => 'image/cgm', + 'class' => 'application/octet-stream', + 'dcr' => 'application/x-director', + 'dif' => 'video/x-dv', + 'dir' => 'application/x-director', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/octet-stream', + 'dmg' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'dtd' => 'application/xml-dtd', + 'dv' => 'video/x-dv', + 'dxr' => 'application/x-director', + 'eps' => 'application/postscript', + 'exe' => 'application/octet-stream', + 'ez' => 'application/andrew-inset', + 'gram' => 'application/srgs', + 'grxml' => 'application/srgs+xml', + 'gz' => 'application/x-gzip', + 'htm' => 'text/html', + 'html' => 'text/html', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ifb' => 'text/calendar', + 'iges' => 'model/iges', + 'igs' => 'model/iges', + 'jp2' => 'image/jp2', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'kar' => 'audio/midi', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'm4a' => 'audio/mp4a-latm', + 'm4p' => 'audio/mp4a-latm', + 'm4u' => 'video/vnd.mpegurl', + 'm4v' => 'video/x-m4v', + 'mac' => 'image/x-macpaint', + 'mathml' => 'application/mathml+xml', + 'mesh' => 'model/mesh', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mov' => 'video/quicktime', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpga' => 'audio/mpeg', + 'msh' => 'model/mesh', + 'nc' => 'application/x-netcdf', + 'oda' => 'application/oda', + 'ogv' => 'video/ogv', + 'pct' => 'image/pict', + 'pic' => 'image/pict', + 'pict' => 'image/pict', + 'pnt' => 'image/x-macpaint', + 'pntg' => 'image/x-macpaint', + 'ps' => 'application/postscript', + 'qt' => 'video/quicktime', + 'qti' => 'image/x-quicktime', + 'qtif' => 'image/x-quicktime', + 'ram' => 'audio/x-pn-realaudio', + 'rdf' => 'application/rdf+xml', + 'rm' => 'application/vnd.rn-realmedia', + 'roff' => 'application/x-troff', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'silo' => 'model/mesh', + 'skd' => 'application/x-koan', + 'skm' => 'application/x-koan', + 'skp' => 'application/x-koan', + 'skt' => 'application/x-koan', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'snd' => 'audio/basic', + 'so' => 'application/octet-stream', + 'svg' => 'image/svg+xml', + 't' => 'application/x-troff', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tr' => 'application/x-troff', + 'txt' => 'text/plain', + 'vrml' => 'model/vrml', + 'vxml' => 'application/voicexml+xml', + 'webm' => 'video/webm', + 'wrl' => 'model/vrml', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xml' => 'application/xml', + 'xsl' => 'application/xml', + 'xslt' => 'application/xslt+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + ); + + public static function get_mimetype($ext) { + return (isset ( self::$mime_types [$ext] ) ? self::$mime_types [$ext] : 'application/octet-stream'); + } +} diff --git a/AliOssSdk/util/oss_util.class.php b/AliOssSdk/util/oss_util.class.php new file mode 100644 index 0000000..a6b9d82 --- /dev/null +++ b/AliOssSdk/util/oss_util.class.php @@ -0,0 +1,434 @@ +IsTruncated; + $object_list = array(); + $marker = $xml->NextMarker; + foreach ( $xml->Contents as $content) { + array_push($object_list, $content->Key); + } + return $object_list; + } + + public static function print_res($response, $msg = "", $is_simple_print = true){ + if ($is_simple_print){ + if ((int)($response->status / 100) == 2){ + echo $msg." OK\n"; + } + else{ + echo "ret:".$response->status."\n"; + echo $msg." FAIL\n"; + } + } + else { + echo '|-----------------------Start---------------------------------------------------------------------------------------------------'."\n"; + echo '|-Status:' . $response->status . "\n"; + echo '|-Body:' ."\n"; + $body = $response->body . "\n"; + echo $body . "\n"; + echo "|-Header:\n"; + print_r ($response->header); + echo '-----------------------End-----------------------------------------------------------------------------------------------------'."\n\n"; + } + } + + /*%******************************************************************************************************%*/ + //工具类相关 + + /** + * 生成query params + * @param array $array 关联数组 + * @return string 返回诸如 key1=value1&key2=value2 + */ + public static function to_query_string($options = array()){ + $temp = array(); + uksort($options, 'strnatcasecmp'); + foreach ($options as $key => $value){ + if (is_string($key) && !is_array($value)){ + $temp[] = rawurlencode($key) . '=' . rawurlencode($value); + } + } + return implode('&', $temp); + } + + /** + * @param $str + * @return string + */ + public static function hex_to_base64($str){ + $result = ''; + for ($i = 0; $i < strlen($str); $i += 2){ + $result .= chr(hexdec(substr($str, $i, 2))); + } + return base64_encode($result); + } + + public static function s_replace($subject){ + $search = array('<', '>', '&', '\'', '"'); + $replace = array('<', '>', '&', ''', '"'); + return str_replace($search, $replace, $subject); + } + + /** + * @param $subject + * @return mixed + */ + public static function replace_invalid_xml_char($subject){ + $search = array( + '', '', '', '', '', '', '', '', ' ', ' ', ' ', ' ', ' ', + '', '', '', '', '', '', '', '', '', '', '', '', '', + '', '', '', '', '', '' + ); + $replace = array( + '%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0A', '%0B', '%0C', '%0D', + '%0E', '%0F', '%10', '%11', '%12', '%13', '%14', '%15', '%16', '%17', '%18', '%19', '%1A', + '%1B', '%1C', '%1D', '%1E', '%1F', '%7F' + ); + + return str_replace($search, $replace, $subject); + } + + /** + * @param $str + * @return int + */ + public static function chk_chinese($str){ + return preg_match('/[\x80-\xff]./', $str); + } + + /** + * 检测是否GB2312编码 + * @param string $str + * @author xiaobing + * @since 2012-03-20 + * @return boolean false UTF-8编码 TRUE GB2312编码 + */ + public static function is_gb2312($str) { + for($i=0; $i 127) { + if( ($v >= 228) && ($v <= 233)){ + if( ($i+2) >= (strlen($str) - 1)) return true; // not enough characters + $v1 = ord( $str[$i+1]); + $v2 = ord( $str[$i+2]); + if( ($v1 >= 128) && ($v1 <=191) && ($v2 >=128) && ($v2 <= 191)) + return false; //UTF-8编码 + else + return true; //GB编码 + } + } + } + } + + /** + * 检测是否GBK编码 + * @param string $str + * @param boolean $gbk + * @author xiaobing + * @since 2012-06-04 + * @return boolean + */ + public static function check_char($str, $gbk = true){ + for($i=0; $i 127){ + if( ($v >= 228) && ($v <= 233)){ + if(($i+2)>= (strlen($str)-1)) return $gbk?true:FALSE; // not enough characters + $v1 = ord( $str[$i+1]); $v2 = ord( $str[$i+2]); + if($gbk){ + return (($v1 >= 128) && ($v1 <=191) && ($v2 >=128) && ($v2 <= 191))?FALSE:TRUE;//GBK + }else{ + return (($v1 >= 128) && ($v1 <=191) && ($v2 >=128) && ($v2 <= 191))?TRUE:FALSE; + } + } + } + } + return $gbk?TRUE:FALSE; + } + + + /** + * 检验bucket名称是否合法 + * bucket的命名规范: + * 1. 只能包括小写字母,数字 + * 2. 必须以小写字母或者数字开头 + * 3. 长度必须在3-63字节之间 + * @param string $bucket (Required) + * @author xiaobing + * @since 2011-12-27 + * @return boolean + */ + public static function validate_bucket($bucket){ + $pattern = '/^[a-z0-9][a-z0-9-]{2,62}$/'; + if (!preg_match($pattern, $bucket)) { + return false; + } + return true; + } + + /** + * 检验object名称是否合法 + * object命名规范: + * 1. 规则长度必须在1-1023字节之间 + * 2. 使用UTF-8编码 + * @param string $object (Required) + * @author xiaobing + * @since 2011-12-27 + * @return boolean + */ + public static function validate_object($object){ + $pattern = '/^.{1,1023}$/'; + if (empty($object) || !preg_match($pattern, $object)) { + return false; + } + return true; + } + + /** + * 检验$options + * @param array $options (Optional) + * @throws OSS_Exception + * @author xiaobing + * @since 2011-12-27 + * @return boolean + */ + public static function validate_options($options){ + //$options + if ($options != NULL && !is_array($options)) { + throw new OSS_Exception ($options.':'.OSS_OPTIONS_MUST_BE_ARRAY); + } + } + + /** + * 检测上传文件的内容 + * @param array $options (Optional) + * @throws OSS_Exception + * @author xiaobing + * @since 2011-12-27 + * @return string + */ + public static function validate_content($options){ + if(isset($options[self::OSS_CONTENT])){ + if($options[self::OSS_CONTENT] == '' || !is_string($options[self::OSS_CONTENT])){ + throw new OSS_Exception(OSS_INVALID_HTTP_BODY_CONTENT,'-600'); + } + }else{ + throw new OSS_Exception(OSS_NOT_SET_HTTP_CONTENT, '-601'); + } + } + + /** + * @param $options + * @throws OSS_Exception + */ + public static function validate_content_length($options){ + if(isset($options[self::OSS_LENGTH]) && is_numeric($options[self::OSS_LENGTH])){ + if( !$options[self::OSS_LENGTH] > 0){ + throw new OSS_Exception(OSS_CONTENT_LENGTH_MUST_MORE_THAN_ZERO, '-602'); + } + }else{ + throw new OSS_Exception(OSS_INVALID_CONTENT_LENGTH, '-602'); + } + } + + /** + * 校验BUCKET/OBJECT/OBJECT GROUP是否为空 + * @param string $name (Required) + * @param string $errMsg (Required) + * @throws OSS_Exception + * @author xiaobing + * @since 2011-12-27 + * @return void + */ + public static function is_empty($name,$errMsg){ + if(empty($name)){ + throw new OSS_Exception($errMsg); + } + } + + /** + * 设置http header + * @param string $key (Required) + * @param string $value (Required) + * @param array $options (Required) + * @throws OSS_Exception + * @author xiaobing + * @return void + */ + public static function set_options_header($key, $value, &$options) { + if (isset($options[self::OSS_HEADERS])) { + if (!is_array($options[self::OSS_HEADERS])) { + throw new OSS_Exception(OSS_INVALID_OPTION_HEADERS, '-600'); + } + } else { + $options[self::OSS_HEADERS] = array (); + } + $options[self::OSS_HEADERS][$key] = $value; + } + + /** + * 仅供测试使用的接口,请勿使用 + */ + public static function generate_file($filename, $size) { + if (file_exists($filename) && $size == filesize($filename)) { + echo $filename." already exists, no need to create again. "; + return; + } + $part_size = 1*1024*1024; + $write_size = 0; + $fp = fopen($filename, "w"); + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $charactersLength = strlen($characters); + if($fp) + { + while ($size > 0) { + if ($size < $part_size) { + $write_size = $size; + } else { + $write_size = $part_size; + } + $size -= $write_size; + $a = $characters[rand(0, $charactersLength - 1)]; + $content = str_repeat($a, $write_size); + $flag = fwrite($fp, $content); + if(!$flag) + { + echo "write to ". $filename . " failed.
"; + break; + } + } + } + else + { + echo "open ". $filename . " failed.
"; + } + fclose($fp); + } + + public static function get_content_md5_of_file($filename, $from_pos, $to_pos) { + $content_md5 = ""; + if (($to_pos - $from_pos) > self::OSS_MAX_PART_SIZE) { + return $content_md5; + } + $filesize = filesize($filename); + if ($from_pos >= $filesize || $to_pos >= $filesize || $from_pos < 0 || $to_pos < 0) { + return $content_md5; + } + + $total_length = $to_pos - $from_pos + 1; + $buffer = 8192; + $left_length = $total_length; + if (!file_exists($filename)) { + return $content_md5; + } + + if (false === $fh = fopen($filename, 'rb')) { + return $content_md5; + } + + fseek($fh, $from_pos); + $data = ''; + while (!feof($fh)) { + if ($left_length >= $buffer) { + $read_length = $buffer; + } + else { + $read_length = $left_length; + } + if ($read_length <= 0) { + break; + } + else { + $data .= fread($fh, $read_length); + $left_length = $left_length - $read_length; + } + } + fclose($fh); + $content_md5 = base64_encode(md5($data, true)); + return $content_md5; + } + + /** + * 检测是否windows系统,因为windows系统默认编码为GBK + * @return bool + */ + public static function is_win(){ + return strtoupper(substr(PHP_OS,0,3)) == "WIN"; + } + + /** + * 主要是由于windows系统编码是gbk,遇到中文时候,如果不进行转换处理会出现找不到文件的问题 + * @param $file_path + * @return string + */ + public static function encoding_path($file_path){ + if(self::chk_chinese($file_path) && self::is_win()){ + $file_path = iconv('utf-8', 'gbk',$file_path); + } + return $file_path; + } + + /** + * 转换响应 + * @param $response + * @return array + * @throws Exception + */ + public static function parse_response($response, $format="array"){ + //如果启用响应结果转换,则进行转换,否则原样返回 + $body = $response->body; + $headers = $response->header; + + switch (strtolower($format)) { + case 'array': + $body = empty($body) ? $body : XML2Array::createArray($body); + break; + case "json": + $body = empty($body) ? $body : json_encode(XML2Array::createArray($body)); + break; + default: + break; + } + + return array( + 'success' => $response->isOk(), + 'status' => $response->status, + 'header' => $headers, + 'body' => $body + ); + return $response; + } +} diff --git a/Plugin.php b/Plugin.php new file mode 100644 index 0000000..08b7254 --- /dev/null +++ b/Plugin.php @@ -0,0 +1,586 @@ +uploadHandle = array('AliOssForTypecho_Plugin', 'uploadHandle'); + Typecho_Plugin::factory('Widget_Upload')->modifyHandle = array('AliOssForTypecho_Plugin', 'modifyHandle'); + Typecho_Plugin::factory('Widget_Upload')->deleteHandle = array('AliOssForTypecho_Plugin', 'deleteHandle'); + Typecho_Plugin::factory('Widget_Upload')->attachmentHandle = array('AliOssForTypecho_Plugin', 'attachmentHandle'); + Typecho_Plugin::factory('Widget_Upload')->attachmentDataHandle = array('AliOssForTypecho_Plugin', 'attachmentDataHandle'); + + return _t('启用成功,请进行相应设置!'); + } + + /** + * 禁用插件方法,如果禁用失败,直接抛出异常 + * + * @static + * @access public + * @return void + * @throws Typecho_Plugin_Exception + */ + public static function deactivate(){} + + /** + * 获取插件配置面板 + * + * @access public + * @param Typecho_Widget_Helper_Form $form 配置面板 + * @return void + */ + public static function config(Typecho_Widget_Helper_Form $form) + { $des = new Typecho_Widget_Helper_Form_Element_Text('des', NULL, '', _t('插件使用说明;'), + _t('
    +
  1. 插件基于阿里云oss_php_sdk_20150819开发包开发,若以后SDK开发包更新导致插件不可用,请到 我的博客 ^ - ^获取新版本插件,如果我还用typecho还用阿里云就会更新。

  2. +
  3. 阿里云OSS支持自定义域名到OSS获取文件,如果你的站点运行在阿里云ECS或ACE并十分清楚阿里云服务的内网互通规则,配置连接Bucket与获取文件使用不同的链接可以节省流量。如果你不清楚这些,那么就选择Bucket所在节点的外网地址。

  4. +
  5. 运行在云应用引擎上的站点可以使用本插件,插件不会保存文件到服务器,“在服务器保留备份”选项无效。

  6. +
  7. 若开启“在服务器保留备份”功能:
    插件尽在上传到OSS失败或者遇到其他错误时会返回错误信息,成功保存到OSS但是没有成功保存到服务器的情况下,插件不会抛出异常,上传过程会继续进行,但是会在' . __TYPECHO_ROOT_DIR__ . self::log_path . '目录下生成错误日志"error.log",请定期查阅并清理。

  8. +
  9. 未作容错性检测,配置错误会导致上传失败。

  10. +
  11. Typecho原因无法上传大写扩展名文件,本插件不做修补,等待Typecho更新。

  12. +
  13. 如有问题请到 我的博客 留言
  14. +
')); + $form->addInput($des); + + $buketName = new Typecho_Widget_Helper_Form_Element_Text('bucketName', NULL, 'yourself bucketName', + _t('Bucket名称'), _t('请填写Buket名称')); + $form->addInput($buketName->addRule('required', _t('必须填写Bucket名称'))); + + $accessId = new Typecho_Widget_Helper_Form_Element_Text('accessId', NULL, 'yourself AccessId', + _t('ACCESS_ID'), _t('请填写ACCESS_ID')); + $form->addInput($accessId->addRule('required', _t('必须填写ACCESS_ID'))); + + $accessKey = new Typecho_Widget_Helper_Form_Element_Text('accessKey', NULL, 'yourself AccessKey', + _t('ACCESS_KEY'), _t('请填写请填写ACCESS_KEY')); + $form->addInput($accessKey->addRule('required', _t('必须填写ACCESS_KEY'))); + + $endPoint = new Typecho_Widget_Helper_Form_Element_Select('endPoint', + array( + "oss-cn-qingdao.aliyuncs.com" => '青岛节点外网地址: oss-cn-qingdao.aliyuncs.com', + "oss-cn-qingdao-internal.aliyuncs.com" => '青岛节点内网地址: oss-cn-qingdao-internal.aliyuncs.com', + "oss-cn-beijing.aliyuncs.com" => '北京节点外网地址: oss-cn-beijing.aliyuncs.com', + "oss-cn-beijing-internal.aliyuncs.com" => '北京节点内网地址: oss-cn-beijing-internal.aliyuncs.com', + "oss-cn-hangzhou.aliyuncs.com" => '杭州节点外网地址: oss-cn-hangzhou.aliyuncs.com', + "oss-cn-hangzhou-internal.aliyuncs.com" => '杭州节点内网地址: oss-cn-hangzhou-internal.aliyuncs.com', + "oss-cn-hongkong.aliyuncs.com" => '香港节点外网地址: oss-cn-hongkong.aliyuncs.com', + "oss-cn-hongkong-internal.aliyuncs.com" => '香港节点内网地址: oss-cn-hongkong-internal.aliyuncs.com', + "oss-cn-shenzhen.aliyuncs.com" => '深圳节点外网地址: oss-cn-shenzhen.aliyuncs.com', + "oss-cn-shenzhen-internal.aliyuncs.com" => '深圳节点内网地址: oss-cn-shenzhen-internal.aliyuncs.com', + "oss-cn-shanghai.aliyuncs.com" => '上海节点外网地址: oss-cn-shanghai.aliyuncs.com', + "oss-cn-shanghai-internal.aliyuncs.com" => '上海节点内网地址: oss-cn-shanghai-internal.aliyuncs.com', + "oss-us-west-1.aliyuncs.com" => '美国硅谷节点外网地址: oss-us-west-1.aliyuncs.com', + "oss-us-west-1-internal.aliyuncs.com" => '美国硅谷节点内网地址: oss-us-west-1-internal.aliyuncs.com', + "oss-ap-southeast-1.aliyuncs.com" => '亚太(新加坡)节点外网地址: oss-ap-southeast-1.aliyuncs.com', + "oss-ap-southeast-1-internal.aliyuncs.com" => '亚太(新加坡)节点内网地址: oss-ap-southeast-1-internal.aliyuncs.com', + "other" => '其他' + ), + 'oss-cn-qingdao.aliyuncs.com', _t('连接Bucket结点所用地址'), _t('参见使用说明第二条')); + $form->addInput($endPoint); + + $otherEndPoint = new Typecho_Widget_Helper_Form_Element_Text('otherEndPoint', NULL, '填写其他节点', + '', _t('不包含http://,结尾不包含"/"')); + $form->addInput($otherEndPoint); + + $userDir = new Typecho_Widget_Helper_Form_Element_Text('userDir', NULL, 'typecho/', + _t('要储存的路径'), _t('请填写文件储存的路径(相对OSS根目录),以字母或数字开头,以"/"结尾。留空则上传到根目录。')); + $form->addInput($userDir); + + $cdnUrl = new Typecho_Widget_Helper_Form_Element_Text('cdnUrl', NULL, '', + _t('自定义域名'), _t('请填写自定义域名,留空则访问OSS源,不包含http://,结尾不包含"/"')); + $form->addInput($cdnUrl); + + $ifLoaclSave = new Typecho_Widget_Helper_Form_Element_Radio('ifLoaclSave', array( "1" => '保留', "0" => '不保留' ), "1", + _t('在服务器保留备份'), _t('是否在服务器保留备份')); + $form->addInput($ifLoaclSave); + + echo ''; + } + + /** + * 个人用户的配置面板 + * + * @access public + * @param Typecho_Widget_Helper_Form $form + * @return void + */ + public static function personalConfig(Typecho_Widget_Helper_Form $form){} + + /** + * 上传文件处理函数 + * + * @access public + * @param array $file 上传的文件 + * @return mixed + */ + public static function uploadHandle($file) + { + if (empty($file['name'])) + { + return FALSE; + } + + $ext = self::getSafeName($file['name']); + + if (!self::checkFileType($ext)) + { + return FALSE; + } + + $options = Typecho_Widget::widget('Widget_Options'); + $date = new Typecho_Date($options->gmtTime); + $path = $date->year . '/' . $date->month. '/' . $date->day . '/'; + + //获取文件名 + $fileName = substr(time(), 5) . sprintf('%u', crc32(uniqid())) . '.' . $ext; + + $userDir = $options->plugin('AliOssForTypecho')->userDir; + $bucket_name = $options->plugin('AliOssForTypecho')->bucketName; + $end_point = ($options->plugin('AliOssForTypecho')->endPoint === "other") ? + $options->plugin('AliOssForTypecho')->otherEndPoint : + $options->plugin('AliOssForTypecho')->endPoint; + $access_id = $options->plugin('AliOssForTypecho')->accessId; + $access_key = $options->plugin('AliOssForTypecho')->accessKey; + + $localFile = $path . $fileName; + $object_name = $userDir . $localFile; + + if (isset($file['tmp_name'])) + { + $content = file_get_contents($file['tmp_name']); + } else if (isset($file['bytes'])) + { + $content = $file['bytes']; + } else + { + return FALSE; + } + + $fileSize = strlen($content); + $ali_options = array( + 'content' => $content, + 'length' => $fileSize, + ALIOSS::OSS_HEADERS => array( + 'Content-Encoding' => 'utf-8', + 'Content-Language' => 'zh-CN', + ), + ); + + $client = new ALIOSS($access_id, $access_key, $end_point); + $client->set_enable_domain_style(TRUE); + + $ali_response = $client->upload_file_by_content($bucket_name, $object_name, $ali_options); + + if (200 != $ali_response->status) + { + return FALSE; + } else + { + $object_url = $ali_response->header["_info"]["url"]; + + $ifLoaclSave = $options->plugin('AliOssForTypecho')->ifLoaclSave; + + if ($ifLoaclSave === "1" && !Typecho_Common::isAppEngine()) + { + + $localPath = Typecho_Common::url(defined('__TYPECHO_UPLOAD_DIR__') ? __TYPECHO_UPLOAD_DIR__ : self::UPLOAD_DIR, + defined('__TYPECHO_UPLOAD_ROOT_DIR__') ? __TYPECHO_UPLOAD_ROOT_DIR__ : __TYPECHO_ROOT_DIR__) + . '/' . $path; + $mkdirSuccess = TRUE; + //创建上传目录 + if (!is_dir($localPath)) + { + if (!self::makeUploadDir($localPath)) + { + $mkdirSuccess = FALSE; + } + } + + $saveOnServerSuccess = FALSE; + + //保存文件到服务器 + + if ($mkdirSuccess) + { + if (file_put_contents($localPath.$fileName, $content)) + { + $saveOnServerSuccess = TRUE; + } else + { + $error = '错误:保存文件失败' . "\r\n" . + '远程文件:' . $object_url . "\r\n" . + '时间:' . date('Y-m-d h:i:sa') . "\r\n\r\n"; + error_log($error, 3, $error_log_path . "error.log"); + } + } else + { + $error = '错误:创建目录失败' . "\r\n" . + '创建路径:' . $localPath . "\r\n" . + '远程文件:' . $object_url . "\r\n" . + '时间:' . date('Y-m-d h:i:sa') . "\r\n\r\n"; + error_log($error, 3, $error_log_path . "error.log"); + } + } + } + + $name = $file['name']; + //返回相对存储路径 + return array( + 'name' => $name, + 'path' => $localFile, + 'size' => $fileSize, + 'type' => $ext, + 'mime' => Typecho_Common::mimeContentType($localPath . $fileName) + ); + } + + /** + * 修改文件处理函数 + * + * @access public + * @param array $content 老文件 + * @param array $file 新上传的文件 + * @return mixed + */ + public static function modifyHandle($content, $file) + { + if (empty($file['name'])) { + return false; + } + + $ext = self::getSafeName($file['name']); + + if ($content['attachment']->type != $ext) { + return false; + } + + if (isset($file['tmp_name'])) { + $newContent = file_get_contents($file['tmp_name']); + } else if (isset($file['bytes'])) { + $newContent = $file['bytes']; + } else { + return false; + } + + $options = Typecho_Widget::widget('Widget_Options'); + $date = new Typecho_Date($options->gmtTime); + + $path = $content['attachment']->path; + + $userDir = $options->plugin('AliOssForTypecho')->userDir; + $bucket_name = $options->plugin('AliOssForTypecho')->bucketName; + $end_point = ($options->plugin('AliOssForTypecho')->endPoint === "other") ? + $options->plugin('AliOssForTypecho')->otherEndPoint : + $options->plugin('AliOssForTypecho')->endPoint; + $access_id = $options->plugin('AliOssForTypecho')->accessId; + $access_key = $options->plugin('AliOssForTypecho')->accessKey; + + $object_name = $userDir . $path; + + $fileSize = strlen($newContent); + $ali_options = array( + 'content' => $newContent, + 'length' => $fileSize, + ALIOSS::OSS_HEADERS => array( + 'Content-Encoding' => 'utf-8', + 'Content-Language' => 'zh-CN', + ), + ); + + $client = new ALIOSS($access_id, $access_key, $end_point); + $client->set_enable_domain_style(TRUE); + + $ali_response = $client->upload_file_by_content($bucket_name, $object_name, $ali_options); + + if (200 != $ali_response->status) + { + return FALSE; + } else + { + $object_url = $ali_response->header["_info"]["url"]; + + $ifLoaclSave = $options->plugin('AliOssForTypecho')->ifLoaclSave; + + if ($ifLoaclSave === "1" && !Typecho_Common::isAppEngine()) + { + $localFile = Typecho_Common::url(self::UPLOAD_DIR . $path, + defined('__TYPECHO_UPLOAD_ROOT_DIR__') ? __TYPECHO_UPLOAD_ROOT_DIR__ : __TYPECHO_ROOT_DIR__); + $localPath = dirname($localFile); + + $mkdirSuccess = TRUE; + //创建上传目录 + if (!is_dir($localPath)) + { + if (!self::makeUploadDir($localPath)) + { + $mkdirSuccess = FALSE; + } + } + + $saveOnServerSuccess = FALSE; + + //保存文件到服务器 + $error_log_path = self::log_path; + if ($mkdirSuccess) + { + + $deleteLacalFileSuccess = unlink($localFile); + if (!$deleteLacalFileSuccess) + { + $error_log_path = self::log_path; + if (!is_dir($error_log_path)) + { + self::makeUploadDir($error_log_path); + } + $error = '错误:删除文件失败导致无法修改文件' . "\r\n" . + '文件:' . $localFile . "\r\n" . + '远程文件:' . $object_url . "\r\n" . + '时间:' . date('Y-m-d h:i:sa') . "\r\n\r\n"; + error_log($error, 3, $error_log_path . "error.log"); + } else { + if (file_put_contents($localFile, $newContent)) + { + $saveOnServerSuccess = TRUE; + } else + { + $error = '错误:保存文件失败' . "\r\n" . + '远程文件:' . $object_url . "\r\n" . + '时间:' . date('Y-m-d h:i:sa') . "\r\n\r\n"; + error_log($error, 3, $error_log_path . "error.log"); + } + } + } else + { + $error = '错误:创建目录失败' . "\r\n" . + '创建路径:' . $localPath . "\r\n" . + '远程文件:' . $object_url . "\r\n" . + '时间:' . date('Y-m-d h:i:sa') . "\r\n\r\n"; + error_log($error, 3, $error_log_path . "error.log"); + } + } + } + + //返回相对存储路径 + return array( + 'name' => $content['attachment']->name, + 'path' => $path, + 'size' => $fileSize, + 'type' => $content['attachment']->type, + 'mime' => $content['attachment']->mime + ); + } + + /** + * 删除文件 + * + * @access public + * @param array $content 文件相关信息 + * @return string + */ + public static function deleteHandle(array $content) + { + $options = Typecho_Widget::widget('Widget_Options'); + + $userDir = $options->plugin('AliOssForTypecho')->userDir; + $access_id = $options->plugin('AliOssForTypecho')->accessId; + $access_key = $options->plugin('AliOssForTypecho')->accessKey; + $bucket_name = $options->plugin('AliOssForTypecho')->bucketName; + $end_point = ($options->plugin('AliOssForTypecho')->endPoint === "other") ? + $options->plugin('AliOssForTypecho')->otherEndPoint : + $options->plugin('AliOssForTypecho')->endPoint; + $ali_options = null; + + $client = new ALIOSS($access_id, $access_key, $end_point); + + $path = $content['attachment']->path; + $object_name = $userDir . $path; + $ali_response = $client->delete_object($bucket_name, $object_name, $ali_options); + + $ifLoaclSave = $options->plugin('AliOssForTypecho')->ifLoaclSave; + if ($ifLoaclSave === "1" && !Typecho_Common::isAppEngine()) + { + $localPath = Typecho_Common::url(defined('__TYPECHO_UPLOAD_DIR__') ? __TYPECHO_UPLOAD_DIR__ : self::UPLOAD_DIR, + defined('__TYPECHO_UPLOAD_ROOT_DIR__') ? __TYPECHO_UPLOAD_ROOT_DIR__ : __TYPECHO_ROOT_DIR__) + . $path; + + $deleteLacalFileSuccess = unlink($localPath); + + if (!$deleteLacalFileSuccess) + { + $error_log_path = self::log_path; + if (!is_dir($error_log_path)) + { + self::makeUploadDir($error_log_path); + } + $error = '错误:删除文件失败' . "\r\n" . + '文件:' . $localPath . "\r\n" . + '时间:' . date('Y-m-d h:i:sa') . "\r\n\r\n"; + error_log($error, 3, $error_log_path . "error.log"); + } + } + return ($ali_response->status == 200); + } + + /** + * 获取实际文件绝对访问路径 + * + * @access public + * @param array $content 文件相关信息 + * @return string + */ + public static function attachmentHandle(array $content) + { + $options = Typecho_Widget::widget('Widget_Options'); + + $cdnUrl = $options->plugin('AliOssForTypecho')->cdnUrl; + $userDir = $options->plugin('AliOssForTypecho')->userDir; + if ($cdnUrl == '') + { + $bucket_name = $options->plugin('AliOssForTypecho')->bucketName; + $end_point = ($options->plugin('AliOssForTypecho')->endPoint === "other") ? + $options->plugin('AliOssForTypecho')->otherEndPoint : + $options->plugin('AliOssForTypecho')->endPoint; + return 'http://' . $bucket_name . '.' . $end_point . '/' . $userDir . $content['attachment']->path; + } else + { + return 'http://' . $cdnUrl . '/' . $userDir . $content['attachment']->path; + } + } + + /** + * 获取实际文件数据 + * + * @access public + * @param array $content + * @return string + */ + public static function attachmentDataHandle(array $content) + { + $options = Typecho_Widget::widget('Widget_Options'); + + $cdnUrl = $options->plugin('AliOssForTypecho')->cdnUrl; + $userDir = $options->plugin('AliOssForTypecho')->userDir; + if ($cdnUrl == '') + { + $bucket_name = $options->plugin('AliOssForTypecho')->bucketName; + $end_point = ($options->plugin('AliOssForTypecho')->endPoint === "other") ? + $options->plugin('AliOssForTypecho')->otherEndPoint : + $options->plugin('AliOssForTypecho')->endPoint; + $filePath = 'http://' . $bucket_name . '.' . $end_point . $userDir . $content['attachment']->path; + } else + { + $filePath = 'http://' . $cdnUrl . $userDir . $content['attachment']->path; + } + + return file_get_contents($filePath); + } + + /** + * 检查文件名 + * + * @access private + * @param string $ext 扩展名 + * @return boolean + */ + private static function checkFileType($ext) + { + $options = Typecho_Widget::widget('Widget_Options'); + return in_array($ext, $options->allowedAttachmentTypes); + } + + /** + * 创建上传路径 + * + * @access private + * @param string $path 路径 + * @return boolean + */ + private static function makeUploadDir($path) + { + $path = preg_replace("/\\\+/", '/', $path); + $current = rtrim($path, '/'); + $last = $current; + + while (!is_dir($current) && false !== strpos($path, '/')) + { + $last = $current; + $current = dirname($current); + } + + if ($last == $current) + { + return true; + } + + if (!@mkdir($last)) + { + return false; + } + + $stat = @stat($last); + $perms = $stat['mode'] & 0007777; + @chmod($last, $perms); + + return self::makeUploadDir($path); + } + + /** + * 获取安全的文件名 + * + * @param string $name + * @static + * @access private + * @return string + */ + private static function getSafeName(&$name) + { + $name = str_replace(array('"', '<', '>'), '', $name); + $name = str_replace('\\', '/', $name); + $name = false === strpos($name, '/') ? ('a' . $name) : str_replace('/', '/a', $name); + $info = pathinfo($name); + $name = substr($info['basename'], 1); + + return isset($info['extension']) ? $info['extension'] : ''; + } +}