diff --git a/.travis.yml b/.travis.yml index b32c5893..399de88c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,5 +8,6 @@ before_script: - export QINIU_SECRET_KEY="b5b5vNg5nnkwkPfW5ayicPE_pj6hqgKMQEaWQ6JD" - export QINIU_BUCKET_NAME="phpsdk" - export QINIU_KEY_NAME="file_name" + - export QINIU_TEST_ENV="travis" script: - cd tests; phpunit . diff --git a/CHANGELOG.md b/CHANGELOG.md index b4c7ff01..42b55da8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ ## CHANGE LOG +### v6.1.9 + +2014-4-8 issues [#75](https://github.com/qiniu/php-sdk/pull/75) + +- [#69] 增加User Agent以方便日志查询。 +- [#70] 增加Reqid信息以方便错误追溯。 +- [#71] Qiniu_RS_Stat返回411问题。 + ### v6.1.8 2014-4-6 issues [#68](https://github.com/qiniu/php-sdk/pull/68) @@ -92,3 +100,4 @@ - 待增加:rsf, batch, resumable io 的支持 - bugfix: 修复 crc32 为负数的错误 - 增加 `Qiniu_RS_Put/PutFile` 辅助函数,用于服务端上传 + diff --git a/composer.json b/composer.json index 7dbf50ef..3ee4d3fc 100644 --- a/composer.json +++ b/composer.json @@ -9,6 +9,6 @@ "php": ">=5.2.4" }, "autoload": { - "psr-0": { "qiniu\\": "/" } + "psr-0": { "qiniu\\": "qiniu" } } } diff --git a/docs/README.gist.md b/docs/README.gist.md new file mode 100644 index 00000000..5a2b15c7 --- /dev/null +++ b/docs/README.gist.md @@ -0,0 +1,483 @@ +--- +title: PHP SDK +--- + +# PHP SDK 使用指南 + +此 SDK 适用于 PHP 5.1.0 及其以上版本。基于 [七牛云存储官方API](http://docs.qiniu.com) 构建。使用此 SDK 构建您的网络应用程序,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。无论您的网络应用是一个网站程序,还是包括从云端(服务端程序)到终端(手持设备应用)的架构的服务或应用,通过七牛云存储及其 SDK,都能让您应用程序的终端用户高速上传和下载,同时也让您的服务端更加轻盈。 + +SDK源码地址: + + +- [应用接入](#install) + - [获取Access Key 和 Secret Key](#acc-appkey) +- [资源管理接口](#rs-api) + - [1 查看单个文件属性信息](#rs-stat) + - [2 复制单个文件](#rs-copy) + - [3 移动单个文件](#rs-move) + - [4 删除单个文件](#rs-delete) + - [5 批量操作](#batch) + - [5.1 批量获取文件信息](#batch_stat) + - [5.2 批量复制文件](#batch_copy) + - [5.3 批量删除文件](#batch_delete) + - [5.4 批量移动文件](#batch_move) +- [上传下载接口](#get-and-put-api) + - [1 文件上传](#upload) + - [1.1 上传流程](#io-put-flow) + - [1.2 上传策略](#io-put-policy) + - [1.3 断点续上传](#rio-putfile) + - [2 文件下载](#io-download) + - [2.1 公有资源下载](#public-download) + - [2.2 私有资源下载](#private-download) +- [数据处理接口](#fop-api) + - [1 图像](#fop-image) + - [1.1 查看图像属性](#fop-image-info) + - [1.2 查看图片EXIF信息](#fop-exif) + - [1.3 生成图片预览](#fop-image-view) +- [贡献代码](#contribution) +- [许可证](#license) + + + + +## 应用接入 + + + +### 1. 获取Access Key 和 Secret Key + +要接入七牛云存储,您需要拥有一对有效的 Access Key 和 Secret Key 用来进行签名认证。可以通过如下步骤获得: + +1. [开通七牛开发者帐号](https://portal.qiniu.com/signup) +2. [登录七牛开发者自助平台,查看 Access Key 和 Secret Key](https://portal.qiniu.com/setting/key) 。 + + +## 资源管理接口 + + +### 1.查看单个文件属性信息 + +示例代码如下: + +``` +{php} + +@gist(gist/demo.php#require_rs) + +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#key1) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#mac_client) +@gist(gist/demo.php#stat) +``` + +### 2. 复制单个文件 + +示例代码如下: + +``` +{php} + +@gist(gist/demo.php#require_rs) + +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#key1) +@gist(gist/demo.php#key2) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#mac_client) +@gist(gist/demo.php#copy) +``` + +### 3. 移动单个文件 + +示例代码如下: + +``` +{php} + +@gist(gist/demo.php#require_rs) + +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#key1) +@gist(gist/demo.php#key2) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#mac_client) +@gist(gist/demo.php#move) +``` + +### 4. 删除单个文件 + +示例代码如下: + +``` +{php} + +@gist(gist/demo.php#require_rs) + +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#key1) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#mac_client) +@gist(gist/demo.php#delete) +``` + +### 5.批量操作 +当您需要一次性进行多个操作时,可以使用批量操作。 + +#### 5.1 批量获取文件属性信息 +示例代码如下: + +``` +{php} + +@gist(gist/demo.php#require_rs) + +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#key1) +@gist(gist/demo.php#key2) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#entrypath1) +@gist(gist/demo.php#entrypath2) +@gist(gist/demo.php#mac_client) +@gist(gist/demo.php#batch_stat) +``` + +#### 5.2 批量复制文件 +示例代码如下: + +``` +{php} + +@gist(gist/demo.php#require_rs) + +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#key1) +@gist(gist/demo.php#key2) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#entrypath1) +@gist(gist/demo.php#entrypath2) +@gist(gist/demo.php#entrypath3) +@gist(gist/demo.php#mac_client) +@gist(gist/demo.php#batch_copy) +``` + +#### 5.3 批量删除文件 +示例代码如下: + +``` +{php} + +@gist(gist/demo.php#require_rs) + +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#key1) +@gist(gist/demo.php#key2) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#entrypath1) +@gist(gist/demo.php#entrypath2) +@gist(gist/demo.php#mac_client) +@gist(gist/demo.php#batch_delete) + +``` + +#### 5.4 批量移动文件 +示例代码如下: + +``` +{php} + +@gist(gist/demo.php#require_rs) + +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#key1) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#entrypath1) +@gist(gist/demo.php#entrypath3) +@gist(gist/demo.php#mac_client) +@gist(gist/demo.php#batch_move) + +``` + +## 上传下载接口 + + +### 1. 文件上传 + +为了尽可能地改善终端用户的上传体验,七牛云存储首创了客户端直传功能。一般云存储的上传流程是: + + 客户端(终端用户) => 业务服务器 => 云存储服务 + +这样多了一次上传的流程,和本地存储相比,会相对慢一些。但七牛引入了客户端直传,将整个上传过程调整为: + + 客户端(终端用户) => 七牛 => 业务服务器 + +客户端(终端用户)直接上传到七牛的服务器,通过DNS智能解析,七牛会选择到离终端用户最近的ISP服务商节点,速度会比本地存储快很多。文件上传成功以后,七牛的服务器使用回调功能,只需要将非常少的数据(比如Key)传给应用服务器,应用服务器进行保存即可。 + + +#### 1.1上传流程 + +在七牛云存储中,整个上传流程大体分为这样几步: + +1. 业务服务器颁发 [uptoken(上传授权凭证)](http://docs.qiniu.com/api/put.html#uploadToken)给客户端(终端用户) +2. 客户端凭借 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 上传文件到七牛 +3. 在七牛获得完整数据后,发起一个 HTTP 请求回调到业务服务器 +4. 业务服务器保存相关信息,并返回一些信息给七牛 +5. 七牛原封不动地将这些信息转发给客户端(终端用户) + +需要注意的是,回调到业务服务器的过程是可选的,它取决于业务服务器颁发的 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken)。如果没有回调,七牛会返回一些标准的信息(比如文件的 hash)给客户端。如果上传发生在业务服务器,以上流程可以自然简化为: + +1. 业务服务器生成 uptoken(不设置回调,自己回调到自己这里没有意义) +2. 凭借 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 上传文件到七牛 +3. 善后工作,比如保存相关的一些信息 + +服务端生成 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 代码如下: + +``` +{php} + +@gist(gist/demo.php#require_rs) + +@gist(gist/demo.php#set_keys) +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#putpolicy) + +``` +上传文件到七牛(通常是客户端完成,但也可以发生在服务端): + + +上传字符串 + +``` +{php} + +@gist(gist/demo.php#require_rs) +@gist(gist/demo.php#require_io) + +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#key1) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#putpolicy) +@gist(gist/demo.php#put) +``` + +上传本地文件 + +``` +{php} + +@gist(gist/demo.php#require_rs) +@gist(gist/demo.php#require_io) + +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#key1) +@gist(gist/demo.php#file) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#putpolicy) +@gist(gist/demo.php#putfile) +``` + +### 1.2 上传策略 + +[uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 实际上是用 AccessKey/SecretKey 进行数字签名的上传策略(`Qiniu_RS_PutPolicy`),它控制则整个上传流程的行为。让我们快速过一遍你都能够决策啥: + + class Qiniu_RS_PutPolicy + { + public $Scope; // 必选项。可以是 bucketName 或者 bucketName:key + public $CallbackUrl; // 可选 + public $CallbackBody; // 可选 + public $ReturnUrl; // 可选, 更贴切的名字是 redirectUrl。 + public $ReturnBody; // 可选 + public $AsyncOps; // 可选 + public $EndUser; // 可选 + public $Expires; // 可选。默认是 3600 秒 + public $PersistentOps; // 可选。 + public $PersistentNotifyUrl; // 如果设置了PersistentOps,必须同时设置此项。 + public $InsertOnly; // 可选。如果设置为非0值,则无论scope设置为何种形式,都只能以`新增`方式上传,不能覆盖。 + public $DetectMime; // 可选。如果设为非0值,则忽略上传端传递的文件MimeType信息,使用七牛服务器侦测内容后的判断结果。 + public $FsizeLimit; // 可选。int类型,超过限制大小的上传内容会被判为上传失败,返回413状态码。 + public $SaveKey; // 可选。自定义资源名格式。 + public $Transform; // 可选。指定资源经过怎样的处理后再保存。 + public $FopTimeout; // 可选。int类型,指定transform的超时时间,如果文件处理超过此值,则认为上传失败。 + public $MimeLimit; // 可选。限定上传的文件类型。 + } + +* `scope` 限定客户端的权限。如果 `scope` 是 bucket,则客户端只能新增文件到指定的 bucket,不能修改文件。如果 `scope` 为 bucket:key,则客户端可以修改指定的文件。**注意: key必须采用utf8编码,如使用非utf8编码访问七牛云存储将反馈错误** +* `callbackUrl` 设定业务服务器的回调地址,这样业务服务器才能感知到上传行为的发生。 +* `callbackBody` 设定业务服务器的回调信息。文件上传成功后,七牛向业务服务器的callbackUrl发送的POST请求携带的数据。支持 [魔法变量](http://docs.qiniu.com/api/put.html#MagicVariables) 和 [自定义变量](http://docs.qiniu.com/api/put.html#xVariables)。 +* `returnUrl` 设置用于浏览器端文件上传成功后,浏览器执行301跳转的URL,一般为 HTML Form 上传时使用。文件上传成功后浏览器会自动跳转到 `returnUrl?upload_ret=returnBody`。 +* `returnBody` 可调整返回给客户端的数据包,支持 [魔法变量](http://docs.qiniu.com/api/put.html#MagicVariables) 和 [自定义变量](http://docs.qiniu.com/api/put.html#xVariables)。`returnBody` 只在没有 `callbackUrl` 时有效(否则直接返回 `callbackUrl` 返回的结果)。不同情形下默认返回的 `returnBody` 并不相同。在一般情况下返回的是文件内容的 `hash`,也就是下载该文件时的 `etag`;但指定 `returnUrl` 时默认的 `returnBody` 会带上更多的信息。 +* `asyncOps` 可指定上传完成后,需要自动执行哪些数据处理。这是因为有些数据处理操作(比如音视频转码)比较慢,如果不进行预转可能第一次访问的时候效果不理想,预转可以很大程度改善这一点。 +* `persistentOps` 可指定音视频文件上传完成后,需要进行的转码持久化操作。asyncOps的处理结果保存在缓存当中,有可能失效。而persistentOps的处理结果以文件形式保存在bucket中,体验更佳。[数据处理(持久化)](http://docs.qiniu.com/api/persistent-ops.html) +* `persistentNotifyUrl` 音视频转码持久化完成后,七牛的服务器会向用户发送处理结果通知。这里指定的url就是用于接收通知的接口。设置了`persistentOps`,则需要同时设置此字段。 + +关于上传策略更完整的说明,请参考 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken)。 + + +### 1.3 断点续上传 +示例代码如下 + +``` +{php} + +@gist(gist/demo.php#require_rs) +@gist(gist/demo.php#require_rio) + +@gist(gist/demo.php#bucket) +@gist(gist/demo.php#key1) +@gist(gist/demo.php#file) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#putpolicy) +@gist(gist/demo.php#rio_putfile) +``` + + +### 2. 文件下载 +七牛云存储上的资源下载分为 公有资源下载 和 私有资源下载 。 + +私有(private)是 Bucket(空间)的一个属性,一个私有 Bucket 中的资源为私有资源,私有资源不可匿名下载。 + +新创建的空间(Bucket)缺省为私有,也可以将某个 Bucket 设为公有,公有 Bucket 中的资源为公有资源,公有资源可以匿名下载。 + + +#### 2.1 公有资源下载 +如果在给bucket绑定了域名的话,可以通过以下地址访问。 + + [GET] http:/// + +示例代码: + + @gist(gist/demo.php#key1) + @gist(gist/demo.php#domain) + @gist(gist/demo.php#base_url) + +其中\是bucket所对应的域名。七牛云存储为每一个bucket提供一个默认域名。默认域名可以到[七牛云存储开发者平台](https://portal.qiniu.com/)中,空间设置的域名设置一节查询。用户也可以将自有的域名绑定到bucket上,通过自有域名访问七牛云存储。 + +**注意: key必须采用utf8编码,如使用非utf8编码访问七牛云存储将反馈错误** + + +#### 2.2 私有资源下载 +私有资源必须通过临时下载授权凭证(downloadToken)下载,如下: + + [GET] http:///?e=&token= + +注意,尖括号不是必需,代表替换项。 +私有下载链接可以使用 SDK 提供的如下方法生成: + +``` +{php} + +@gist(gist/demo.php#require_rs) + +@gist(gist/demo.php#key1) +@gist(gist/demo.php#domain) + +@gist(gist/demo.php#set_keys) +@gist(gist/demo.php#base_url) +@gist(gist/demo.php#getpolicy) + +``` + + +## 数据处理接口 +七牛支持在云端对图像, 视频, 音频等富媒体进行个性化处理 + + +### 1. 图像 + +#### 1.1 查看图像属性 + +``` +{php} + +@gist(gist/demo.php#require_rs) +@gist(gist/demo.php#require_fop) + +@gist(gist/demo.php#key1) +@gist(gist/demo.php#domain) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#base_url) +@gist(gist/demo.php#image_info) +``` + +将`$imgInfoPrivateUrl`粘贴到浏览器地址栏中就可以查看该图像的信息了。 + + +#### 1.2 查看图片EXIF信息 + +``` +{php} + +@gist(gist/demo.php#require_rs) +@gist(gist/demo.php#require_fop) + +@gist(gist/demo.php#key1) +@gist(gist/demo.php#domain) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#base_url) +@gist(gist/demo.php#image_exif) +``` + + +#### 1.3 生成图片预览 + +``` +{php} + +@gist(gist/demo.php#require_rs) +@gist(gist/demo.php#require_fop) + +@gist(gist/demo.php#key1) +@gist(gist/demo.php#domain) + +@gist(gist/demo.php#set_keys) + +@gist(gist/demo.php#base_url) +@gist(gist/demo.php#image_view) +``` + + +## 贡献代码 + +1. Fork +2. 创建您的特性分支 (`git checkout -b my-new-feature`) +3. 提交您的改动 (`git commit -am 'Added some feature'`) +4. 将您的修改记录提交到远程 `git` 仓库 (`git push origin my-new-feature`) +5. 然后到 github 网站的该 `git` 远程仓库的 `my-new-feature` 分支下发起 Pull Request + + + +## 许可证 + +Copyright (c) 2013 qiniu.com + +基于 MIT 协议发布: + +* [www.opensource.org/licenses/MIT](http://www.opensource.org/licenses/MIT) + + diff --git a/docs/README.md b/docs/README.md index ae560b9d..e8292767 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,5 @@ --- -title: PHP SDK +title: PHP SDK --- # PHP SDK 使用指南 @@ -16,10 +16,16 @@ SDK源码地址: - [2 复制单个文件](#rs-copy) - [3 移动单个文件](#rs-move) - [4 删除单个文件](#rs-delete) + - [5 批量操作](#batch) + - [5.1 批量获取文件信息](#batch_stat) + - [5.2 批量复制文件](#batch_copy) + - [5.3 批量删除文件](#batch_delete) + - [5.4 批量移动文件](#batch_move) - [上传下载接口](#get-and-put-api) - [1 文件上传](#upload) - [1.1 上传流程](#io-put-flow) - [1.2 上传策略](#io-put-policy) + - [1.3 断点续上传](#rio-putfile) - [2 文件下载](#io-download) - [2.1 公有资源下载](#public-download) - [2.2 私有资源下载](#private-download) @@ -53,98 +59,233 @@ SDK源码地址: 示例代码如下: - require_once("qiniu/rs.php"); - - $bucket = "phpsdk"; - $key = "pic.jpg"; - $accessKey = ''; - $secretKey = ''; - - Qiniu_SetKeys($accessKey, $secretKey); - $client = new Qiniu_MacHttpClient(null); - - list($ret, $err) = Qiniu_RS_Stat($client, $bucket, $key); - echo "Qiniu_RS_Stat result: \n"; - if ($err !== null) { - var_dump($err); - } else { - var_dump($ret); - } - +``` +{php} + +require_once('qiniu/rs.php'); + +$bucket = 'phpsdk'; +$key1 = 'file_name_1'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +$client = new Qiniu_MacHttpClient(null); +list($ret, $err) = Qiniu_RS_Stat($client, $bucket, $key1); +echo "\n\n====> Qiniu_RS_Stat result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} +``` ### 2. 复制单个文件 示例代码如下: - require_once("qiniu/rs.php"); - - $bucket = "phpsdk"; - $key = "pic.jpg"; - $key1 = "file_name1"; - $accessKey = ''; - $secretKey = ''; - - Qiniu_SetKeys($accessKey, $secretKey); - $client = new Qiniu_MacHttpClient(null); - - $err = Qiniu_RS_Copy($client, $bucket, $key, $bucket, $key1); - echo "====> Qiniu_RS_Copy result: \n"; - if ($err !== null) { - var_dump($err); - } else { - echo "Success!"; - } +``` +{php} + +require_once('qiniu/rs.php'); + +$bucket = 'phpsdk'; +$key1 = 'file_name_1'; +$key2 = 'file_name_2'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); +$client = new Qiniu_MacHttpClient(null); +$err = Qiniu_RS_Copy($client, $bucket, $key1, $bucket, $key2); +echo "\n\n====> Qiniu_RS_Copy result: \n"; +if ($err !== null) { + var_dump($err); +} else { + echo "Success! \n"; +} +``` ### 3. 移动单个文件 示例代码如下: - require_once("qiniu/rs.php"); - - $bucket = "phpsdk"; - $key = "pic.jpg"; - $key1 = "file_name1"; - $accessKey = ''; - $secretKey = ''; - - Qiniu_SetKeys($accessKey, $secretKey); - $client = new Qiniu_MacHttpClient(null); - - $err = Qiniu_RS_Move($client, $bucket, $key, $bucket, $key1); - echo "====> Qiniu_RS_Move result: \n"; - if ($err !== null) { - var_dump($err); - } else { - echo "Success!"; - } - +``` +{php} + +require_once('qiniu/rs.php'); + +$bucket = 'phpsdk'; +$key1 = 'file_name_1'; +$key2 = 'file_name_2'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +$client = new Qiniu_MacHttpClient(null); +$err = Qiniu_RS_Move($client, $bucket, $key2, $bucket, $key1); +echo "\n\n====> Qiniu_RS_Move result: \n"; +if ($err !== null) { + var_dump($err); +} else { + echo "Success! \n"; +} +``` ### 4. 删除单个文件 示例代码如下: - require_once("qiniu/rs.php"); - - $bucket = "phpsdk"; - $key1 = "file_name1"; - $accessKey = ''; - $secretKey = ''; - - Qiniu_SetKeys($accessKey, $secretKey); - $client = new Qiniu_MacHttpClient(null); - - $err = Qiniu_RS_Delete($client, $bucket, $key1); - echo "====> Qiniu_RS_Delete result: \n"; - if ($err !== null) { - var_dump($err); - } else { - echo "Success!"; - } +``` +{php} + +require_once('qiniu/rs.php'); + +$bucket = 'phpsdk'; +$key1 = 'file_name_1'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +$client = new Qiniu_MacHttpClient(null); +$err = Qiniu_RS_Delete($client, $bucket, $key1); +echo "\n\n====> Qiniu_RS_Delete result: \n"; +if ($err !== null) { + var_dump($err); +} else { + echo "Success! \n"; +} +``` + +### 5.批量操作 +当您需要一次性进行多个操作时,可以使用批量操作。 + +#### 5.1 批量获取文件属性信息 +示例代码如下: +``` +{php} + +require_once('qiniu/rs.php'); + +$bucket = 'phpsdk'; +$key1 = 'file_name_1'; +$key2 = 'file_name_2'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +$e1 = new Qiniu_RS_EntryPath($bucket, $key1); +$e2 = new Qiniu_RS_EntryPath($bucket, $key2); +$client = new Qiniu_MacHttpClient(null); +$entries = array($e1, $e2); +list($ret, $err) = Qiniu_RS_BatchStat($client, $entries); +echo "\n\n====> Qiniu_RS_BatchStat result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} +``` + +#### 5.2 批量复制文件 +示例代码如下: + +``` +{php} + +require_once('qiniu/rs.php'); + +$bucket = 'phpsdk'; +$key1 = 'file_name_1'; +$key2 = 'file_name_2'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +$e1 = new Qiniu_RS_EntryPath($bucket, $key1); +$e2 = new Qiniu_RS_EntryPath($bucket, $key2); +$key3 = $key1 . '3'; +$e3 = new Qiniu_RS_EntryPath($bucket, $key3); +$client = new Qiniu_MacHttpClient(null); +$entryPairs = array(new Qiniu_RS_EntryPathPair($e1, $e2), new Qiniu_RS_EntryPathPair($e1, $e3)); +list($ret, $err) = Qiniu_RS_BatchCopy($client, $entryPairs); +echo "\n\n====> Qiniu_RS_BatchCopy result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} +``` + +#### 5.3 批量删除文件 +示例代码如下: + +``` +{php} + +require_once('qiniu/rs.php'); + +$bucket = 'phpsdk'; +$key1 = 'file_name_1'; +$key2 = 'file_name_2'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +$e1 = new Qiniu_RS_EntryPath($bucket, $key1); +$e2 = new Qiniu_RS_EntryPath($bucket, $key2); +$client = new Qiniu_MacHttpClient(null); +$entries = array($e1, $e2); +list($ret, $err) = Qiniu_RS_BatchDelete($client, $entries); +echo "\n\n====> Qiniu_RS_BatchDelete result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} + +``` + +#### 5.4 批量移动文件 +示例代码如下: + +``` +{php} + +require_once('qiniu/rs.php'); + +$bucket = 'phpsdk'; +$key1 = 'file_name_1'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +$e1 = new Qiniu_RS_EntryPath($bucket, $key1); +$key3 = $key1 . '3'; +$e3 = new Qiniu_RS_EntryPath($bucket, $key3); +$client = new Qiniu_MacHttpClient(null); +$entryPairs = array(new Qiniu_RS_EntryPathPair($e3, $e1)); +list($ret, $err) = Qiniu_RS_BatchMove($client, $entryPairs); +echo "\n\n====> Qiniu_RS_BatchMove result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} + +``` ## 上传下载接口 - + ### 1. 文件上传 @@ -175,67 +316,78 @@ SDK源码地址: 2. 凭借 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 上传文件到七牛 3. 善后工作,比如保存相关的一些信息 -服务端生成 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 代码如下: +服务端生成 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 代码如下: + +``` +{php} +require_once('qiniu/rs.php'); - require_once("qiniu/rs.php"); - - $bucket = 'phpsdk'; - $accessKey = ''; - $secretKey = ''; - - Qiniu_SetKeys($accessKey, $secretKey); - $putPolicy = new Qiniu_RS_PutPolicy($bucket); - $upToken = $putPolicy->Token(null); - +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); +$bucket = 'phpsdk'; +$putPolicy = new Qiniu_RS_PutPolicy($bucket); +$upToken = $putPolicy->Token(null); + +``` 上传文件到七牛(通常是客户端完成,但也可以发生在服务端): 上传字符串 - require_once("qiniu/io.php"); - require_once("qiniu/rs.php"); - - $bucket = "phpsdk"; - $key1 = "file_name1"; - $accessKey = ''; - $secretKey = ''; - - Qiniu_SetKeys($accessKey, $secretKey); - $putPolicy = new Qiniu_RS_PutPolicy($bucket); - $upToken = $putPolicy->Token(null); - list($ret, $err) = Qiniu_Put($upToken, $key1, "Qiniu Storage!", null); - echo "====> Qiniu_Put result: \n"; - if ($err !== null) { - var_dump($err); - } else { - var_dump($ret); - } +``` +{php} -上传本地文件 +require_once('qiniu/rs.php'); +require_once('qiniu/io.php'); - require_once("qiniu/io.php"); - require_once("qiniu/rs.php"); - - $bucket = "phpsdk"; - $key1 = "file_name1"; - $accessKey = ''; - $secretKey = ''; - - Qiniu_SetKeys($accessKey, $secretKey); - $putPolicy = new Qiniu_RS_PutPolicy($bucket); - $upToken = $putPolicy->Token(null); - $putExtra = new Qiniu_PutExtra(); - $putExtra->Crc32 = 1; - list($ret, $err) = Qiniu_PutFile($upToken, $key1, __file__, $putExtra); - echo "====> Qiniu_PutFile result: \n"; - if ($err !== null) { - var_dump($err); - } else { - var_dump($ret); - } +$bucket = 'phpsdk'; +$key1 = 'file_name_1'; +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); +$putPolicy = new Qiniu_RS_PutPolicy($bucket); +$upToken = $putPolicy->Token(null); +list($ret, $err) = Qiniu_Put($upToken, $key1, 'Qiniu Storage!', null); +echo "\n\n====> Qiniu_Put result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} +``` + +上传本地文件 + +``` +{php} + +require_once('qiniu/rs.php'); +require_once('qiniu/io.php'); + +$bucket = 'phpsdk'; +$key1 = 'file_name_1'; +$file = 'docs/gist/logo.jpg'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +$putPolicy = new Qiniu_RS_PutPolicy($bucket); +$upToken = $putPolicy->Token(null); +$putExtra = new Qiniu_PutExtra(); +$putExtra->Crc32 = 1; +list($ret, $err) = Qiniu_PutFile($upToken, $key1, $file, $putExtra); +echo "\n\n====> Qiniu_PutFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} +``` ### 1.2 上传策略 @@ -267,12 +419,41 @@ SDK源码地址: * `callbackBody` 设定业务服务器的回调信息。文件上传成功后,七牛向业务服务器的callbackUrl发送的POST请求携带的数据。支持 [魔法变量](http://docs.qiniu.com/api/put.html#MagicVariables) 和 [自定义变量](http://docs.qiniu.com/api/put.html#xVariables)。 * `returnUrl` 设置用于浏览器端文件上传成功后,浏览器执行301跳转的URL,一般为 HTML Form 上传时使用。文件上传成功后浏览器会自动跳转到 `returnUrl?upload_ret=returnBody`。 * `returnBody` 可调整返回给客户端的数据包,支持 [魔法变量](http://docs.qiniu.com/api/put.html#MagicVariables) 和 [自定义变量](http://docs.qiniu.com/api/put.html#xVariables)。`returnBody` 只在没有 `callbackUrl` 时有效(否则直接返回 `callbackUrl` 返回的结果)。不同情形下默认返回的 `returnBody` 并不相同。在一般情况下返回的是文件内容的 `hash`,也就是下载该文件时的 `etag`;但指定 `returnUrl` 时默认的 `returnBody` 会带上更多的信息。 -* `asyncOps` 可指定上传完成后,需要自动执行哪些数据处理。这是因为有些数据处理操作(比如音视频转码)比较慢,如果不进行预转可能第一次访问的时候效果不理想,预转可以很大程度改善这一点。 -* `persistentOps` 可指定音视频文件上传完成后,需要进行的转码持久化操作。asyncOps的处理结果保存在缓存当中,有可能失效。而persistentOps的处理结果以文件形式保存在bucket中,体验更佳。[数据处理(持久化)](http://docs.qiniu.com/api/persistent-ops.html) +* `asyncOps` 可指定上传完成后,需要自动执行哪些数据处理。这是因为有些数据处理操作(比如音视频转码)比较慢,如果不进行预转可能第一次访问的时候效果不理想,预转可以很大程度改善这一点。 +* `persistentOps` 可指定音视频文件上传完成后,需要进行的转码持久化操作。asyncOps的处理结果保存在缓存当中,有可能失效。而persistentOps的处理结果以文件形式保存在bucket中,体验更佳。[数据处理(持久化)](http://docs.qiniu.com/api/persistent-ops.html) * `persistentNotifyUrl` 音视频转码持久化完成后,七牛的服务器会向用户发送处理结果通知。这里指定的url就是用于接收通知的接口。设置了`persistentOps`,则需要同时设置此字段。 关于上传策略更完整的说明,请参考 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken)。 + +### 1.3 断点续上传 +示例代码如下 + +``` +{php} + +require_once('qiniu/rs.php'); +require_once('qiniu/resumable_io.php'); + +$bucket = 'phpsdk'; +$key1 = 'file_name_1'; +$file = 'docs/gist/logo.jpg'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +$putPolicy = new Qiniu_RS_PutPolicy($bucket); +$upToken = $putPolicy->Token(null); +$putExtra = new Qiniu_Rio_PutExtra($bucket); +list($ret, $err) = Qiniu_Rio_PutFile($upToken, $key1, $file, $putExtra); +echo "\n\n====> Qiniu_Rio_PutFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} +``` ### 2. 文件下载 @@ -287,13 +468,13 @@ SDK源码地址: 如果在给bucket绑定了域名的话,可以通过以下地址访问。 [GET] http:/// - + 示例代码: - $key = 'pic.jpg'; + $key1 = 'file_name_1'; $domain = 'phpsdk.qiniudn.com'; //$baseUrl 就是您要访问资源的地址 - $baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key); + $baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key1); 其中\是bucket所对应的域名。七牛云存储为每一个bucket提供一个默认域名。默认域名可以到[七牛云存储开发者平台](https://portal.qiniu.com/)中,空间设置的域名设置一节查询。用户也可以将自有的域名绑定到bucket上,通过自有域名访问七牛云存储。 @@ -305,23 +486,29 @@ SDK源码地址: [GET] http:///?e=&token= -注意,尖括号不是必需,代表替换项。 +注意,尖括号不是必需,代表替换项。 私有下载链接可以使用 SDK 提供的如下方法生成: - require_once("qiniu/rs.php"); +``` +{php} - $key = 'pic.jpg'; - $domain = 'phpsdk.qiniudn.com'; - $accessKey = ''; - $secretKey = ''; - - Qiniu_SetKeys($accessKey, $secretKey); - $baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key); - $getPolicy = new Qiniu_RS_GetPolicy(); - $privateUrl = $getPolicy->MakeRequest($baseUrl, null); - echo "====> getPolicy result: \n"; - echo $privateUrl . "\n"; +require_once('qiniu/rs.php'); + +$key1 = 'file_name_1'; +$domain = 'phpsdk.qiniudn.com'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); +//$baseUrl 就是您要访问资源的地址 + $baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key1); +$baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key1); +$getPolicy = new Qiniu_RS_GetPolicy(); +$privateUrl = $getPolicy->MakeRequest($baseUrl, null); +echo "\n\n====> getPolicy result: \n"; +echo $privateUrl . "\n"; +``` ## 数据处理接口 @@ -332,85 +519,97 @@ SDK源码地址: #### 1.1 查看图像属性 - require_once("qiniu/rs.php"); - require_once("qiniu/fop.php"); +``` +{php} - $key = 'pic.jpg'; - $domain = 'phpsdk.qiniudn.com'; - $accessKey = ''; - $secretKey = ''; - - Qiniu_SetKeys($accessKey, $secretKey); - //生成baseUrl - $baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key); - - //生成fopUrl - $imgInfo = new Qiniu_ImageInfo; - $imgInfoUrl = $imgInfo->MakeRequest($baseUrl); - - //对fopUrl 进行签名,生成privateUrl。 公有bucket 此步可以省去。 - $getPolicy = new Qiniu_RS_GetPolicy(); - $imgInfoPrivateUrl = $getPolicy->MakeRequest($imgInfoUrl, null); - echo "====> imageInfo privateUrl: \n"; - echo $imgInfoPrivateUrl . "\n"; +require_once('qiniu/rs.php'); +require_once('qiniu/fop.php'); + +$key1 = 'file_name_1'; +$domain = 'phpsdk.qiniudn.com'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +//$baseUrl 就是您要访问资源的地址 + $baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key1); +$getPolicy = new Qiniu_RS_GetPolicy(); +$imgInfo = new Qiniu_ImageInfo; + +//生成fopUrl +$imgInfoUrl = $imgInfo->MakeRequest($baseUrl); + +//对fopUrl 进行签名,生成privateUrl。 公有bucket 此步可以省去。 +$imgInfoPrivateUrl = $getPolicy->MakeRequest($imgInfoUrl, null); +echo "\n\n====> imageInfo privateUrl: \n"; +echo $imgInfoPrivateUrl . "\n"; +``` 将`$imgInfoPrivateUrl`粘贴到浏览器地址栏中就可以查看该图像的信息了。 #### 1.2 查看图片EXIF信息 +``` +{php} - require_once("qiniu/rs.php"); - require_once("qiniu/fop.php"); +require_once('qiniu/rs.php'); +require_once('qiniu/fop.php'); + +$key1 = 'file_name_1'; +$domain = 'phpsdk.qiniudn.com'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +//$baseUrl 就是您要访问资源的地址 + $baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key1); +$getPolicy = new Qiniu_RS_GetPolicy(); +$imgExif = new Qiniu_Exif; + +//生成fopUrl +$imgExifUrl = $imgExif->MakeRequest($baseUrl); +//对fopUrl 进行签名,生成privateUrl。 公有bucket 此步可以省去。 +$imgExifPrivateUrl = $getPolicy->MakeRequest($imgExifUrl, null); +echo "\n\n====> imageView privateUrl: \n"; +echo $imgExifPrivateUrl . "\n"; +``` - $key = 'pic.jpg'; - $domain = 'phpsdk.qiniudn.com'; - $accessKey = ''; - $secretKey = ''; - - Qiniu_SetKeys($accessKey, $secretKey); - //生成baseUrl - $baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key); - - //生成fopUrl - $imgExif = new Qiniu_Exif; - $imgExifUrl = $imgExif->MakeRequest($baseUrl); - - //对fopUrl 进行签名,生成privateUrl。 公有bucket 此步可以省去。 - $getPolicy = new Qiniu_RS_GetPolicy(); - $imgExifPrivateUrl = $getPolicy->MakeRequest($imgExifUrl, null); - echo "====> imageView privateUrl: \n"; - echo $imgExifPrivateUrl . "\n"; - #### 1.3 生成图片预览 - require_once("qiniu/rs.php"); - require_once("qiniu/fop.php"); +``` +{php} + +require_once('qiniu/rs.php'); +require_once('qiniu/fop.php'); + +$key1 = 'file_name_1'; +$domain = 'phpsdk.qiniudn.com'; + +$accessKey = ''; +$secretKey = ''; +Qiniu_setKeys($accessKey, $secretKey); + +//$baseUrl 就是您要访问资源的地址 + $baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key1); +$getPolicy = new Qiniu_RS_GetPolicy(); +$imgView = new Qiniu_ImageView; +$imgView->Mode = 1; +$imgView->Width = 60; +$imgView->Height = 30; + +//生成fopUrl +$imgViewUrl = $imgView->MakeRequest($baseUrl); + +//对fopUrl 进行签名,生成privateUrl。 公有bucket 此步可以省去。 +$imgViewPrivateUrl = $getPolicy->MakeRequest($imgViewUrl, null); +echo "\n\n====> imageView privateUrl: \n"; +echo $imgViewPrivateUrl . "\n"; +``` - $key = 'pic.jpg'; - $domain = 'phpsdk.qiniudn.com'; - $accessKey = ''; - $secretKey = ''; - - Qiniu_SetKeys($accessKey, $secretKey); - //生成baseUrl - $baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key); - - //生成fopUrl - $imgView = new Qiniu_ImageView; - $imgView->Mode = 1; - $imgView->Width = 60; - $imgView->Height = 120; - $imgViewUrl = $imgView->MakeRequest($baseUrl); - - //对fopUrl 进行签名,生成privateUrl。 公有bucket 此步可以省去。 - $getPolicy = new Qiniu_RS_GetPolicy(); - $imgViewPrivateUrl = $getPolicy->MakeRequest($imgViewUrl, null); - echo "====> imageView privateUrl: \n"; - echo $imgViewPrivateUrl . "\n"; - - ## 贡献代码 @@ -430,3 +629,5 @@ Copyright (c) 2013 qiniu.com * [www.opensource.org/licenses/MIT](http://www.opensource.org/licenses/MIT) + + diff --git a/docs/gist.py b/docs/gist.py new file mode 100755 index 00000000..a09520aa --- /dev/null +++ b/docs/gist.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +import os +import re + +re_md_gist = re.compile(r"@gist\(([^\)]+)\)") +re_strip = re.compile(r"^\n*(.*)\n\t*$", re.S) +re_indent = re.compile(r"^(\t*)[^\t\s\n\r]") +line_start = r"(?:^|\n)\s*" +re_gist_comment = dict( + c = dict( + start = re.compile(r"%s\/\*\s*@gist\s+([\w\-_]+)\s*\*/.*?\n+" % line_start), + end = re.compile(r"%s\/\*\s*@endgist\s*\*/" % line_start), + ), + bash = dict( + start = re.compile(r"%s#\s*@gist\s+([\w\-_]+).*?\n+" % line_start), + end = re.compile(r"%s#\s*@endgist" % line_start), + ), + cpp = dict( + start = re.compile(r"%s//\s*@gist\s+([\w\-_]+).*?\n+" % line_start), + end = re.compile(r"%s//\s*@endgist" % line_start) + ), + html = dict( + start = re.compile(r"%s.*?\n+" % line_start), + end = re.compile(r"%s" % line_start), + ), +) +cpath = sys.path[0] + +def openfile(path): + if not os.path.exists(path): + return None + f = open(path, "r") + body = f.read() + f.close() + return body + +def get_gist_block(path): + gists = dict() + body = openfile(path) + if body is None: + return gists + start = 0 + while True: + a = search_one_block(body[start:]) + if a is None: + break + name, content, new_start = a + start += new_start + if not name in gists: + gists[name] = content + else: + gists[name].extend(["", "...", ""]) + gists[name].extend(content) + gists[""] = body.split("\n") + return gists + +def search_one_block(body): + if len(body) == 0: + return None + for n, regs in re_gist_comment.iteritems(): + a = regs["start"].search(body) + if a is None: + continue + start = a.span()[1] + b = regs["end"].search(body[start:]) + if b is None: + continue + break + if a is None or b is None: + return None + + body = body[start: b.span()[0]+start] + body = re_strip.sub("\\1", body) + start_indent = len(re_indent.findall(body)[0]) + body = [i[start_indent:] for i in body.split("\n")] + return a.group(1), body, b.span()[1] + start + +def dirname(path): + name = os.path.dirname(path) + if name == "": + name = "." + return name + +if __name__ == "__main__": + if len(sys.argv) <= 1: + sys.stderr.write("Usage: %s GistFile > OutputFile\n" % os.path.basename(sys.argv[0])) + exit(2) + + body = openfile(sys.argv[1]) + if body is None: + sys.stderr.write("Not such File.") + exit(2) + + rpath = dirname(sys.argv[1]) + body_gist_ref = [] + ref_files = [] + for i in re_md_gist.findall(body): + file_path = i + if i.find("#") > 0: + file_path = file_path.split("#")[0] + ref_files.append("%s/%s" % (rpath, file_path)) + body_gist_ref.append(i) + ref_files = list(set(ref_files)) + + match_gists = {} + for f in ref_files: + blocks = get_gist_block(f) + for block_key in blocks: + key = "%s#%s" % (f, block_key) + if len(block_key) == 0: + key = "%s%s" % (f, block_key) + match_gists[key] = blocks[block_key] + + errors = [] + for i in body_gist_ref: + key = "%s/%s" % (rpath, i) + if key in match_gists: + match_results = re_md_gist.search(body) + if match_results is None: + continue + s = match_results.span()[0] + s = body[body[s-50: s].rfind("\n")+s-50+1: s] + content = (("\n%s" % s).join(match_gists[key])).strip() + content = content.replace("\\", "\\\\") + + body = re.sub(r"@gist\s*\(%s\)" % i, content, body) + else: + errors.append(i) + + if len(errors) > 0: + sys.stderr.write("error: No Such File or Anchor\n") + for i, error in enumerate(errors): + sys.stderr.write("%s: '%s'\n" % (i+1, error)) + exit(2) + print body diff --git a/docs/gist/demo.php b/docs/gist/demo.php index 9c130305..b72e9e2d 100644 --- a/docs/gist/demo.php +++ b/docs/gist/demo.php @@ -1,108 +1,258 @@ '; +$secretKey = ''; Qiniu_setKeys($accessKey, $secretKey); - +# @endgist +# @gist mac_client $client = new Qiniu_MacHttpClient(null); +# @endgist +Qiniu_RS_Delete($client, $bucket, $key1); +Qiniu_RS_Delete($client, $bucket, $key2); -//------------------------------------rs----------------------------------------- +//------------------------------------io----------------------------------------- +# @gist putpolicy +$putPolicy = new Qiniu_RS_PutPolicy($bucket); +$upToken = $putPolicy->Token(null); +# @endgist + +# @gist put +list($ret, $err) = Qiniu_Put($upToken, $key1, 'Qiniu Storage!', null); +echo "\n\n====> Qiniu_Put result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} +# @endgist +Qiniu_RS_Delete($client, $bucket, $key1); + +# @gist putfile +$putExtra = new Qiniu_PutExtra(); +$putExtra->Crc32 = 1; +list($ret, $err) = Qiniu_PutFile($upToken, $key1, $file, $putExtra); +echo "\n\n====> Qiniu_PutFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} +# @endgist +Qiniu_RS_Delete($client, $bucket, $key1); + +# @gist getpolicy +$baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key1); +$getPolicy = new Qiniu_RS_GetPolicy(); +$privateUrl = $getPolicy->MakeRequest($baseUrl, null); +echo "\n\n====> getPolicy result: \n"; +echo $privateUrl . "\n"; +# @endgist + + +//------------------------------------rio----------------------------------------- +//Qiniu_Rio_PutFile($upToken, $key1, $localFile, $putExtra) // => ($putRet, $err) +# @gist rio_putfile +$putExtra = new Qiniu_Rio_PutExtra($bucket); +list($ret, $err) = Qiniu_Rio_PutFile($upToken, $key1, $file, $putExtra); +echo "\n\n====> Qiniu_Rio_PutFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} +# @endgist -list($ret, $err) = Qiniu_RS_Stat($client, $bucket, $key); +//------------------------------------rs----------------------------------------- +# @gist stat +list($ret, $err) = Qiniu_RS_Stat($client, $bucket, $key1); echo "\n\n====> Qiniu_RS_Stat result: \n"; if ($err !== null) { var_dump($err); } else { var_dump($ret); } +# @endgist -$err = Qiniu_RS_Copy($client, $bucket, $key, $bucket, $key1); +# @gist copy +$err = Qiniu_RS_Copy($client, $bucket, $key1, $bucket, $key2); echo "\n\n====> Qiniu_RS_Copy result: \n"; if ($err !== null) { var_dump($err); } else { echo "Success! \n"; } +# @endgist -$err = Qiniu_RS_Delete($client, $bucket, $key); +# @gist delete +$err = Qiniu_RS_Delete($client, $bucket, $key1); echo "\n\n====> Qiniu_RS_Delete result: \n"; if ($err !== null) { var_dump($err); } else { echo "Success! \n"; } +# @endgist -$err = Qiniu_RS_Move($client, $bucket, $key1, $bucket, $key); +# @gist move +$err = Qiniu_RS_Move($client, $bucket, $key2, $bucket, $key1); echo "\n\n====> Qiniu_RS_Move result: \n"; if ($err !== null) { var_dump($err); } else { echo "Success! \n"; } +# @endgist +# @gist entrypath1 +$e1 = new Qiniu_RS_EntryPath($bucket, $key1); +# @endgist +# @gist entrypath2 +$e2 = new Qiniu_RS_EntryPath($bucket, $key2); +# @endgist +# @gist entrypath3 +$key3 = $key1 . '3'; +$e3 = new Qiniu_RS_EntryPath($bucket, $key3); +# @endgist -//------------------------------------io----------------------------------------- +# @gist batch_stat +$entries = array($e1, $e2); +list($ret, $err) = Qiniu_RS_BatchStat($client, $entries); +echo "\n\n====> Qiniu_RS_BatchStat result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} +# @endgist -$putPolicy = new Qiniu_RS_PutPolicy($bucket); -$upToken = $putPolicy->Token(null); -list($ret, $err) = Qiniu_Put($upToken, $key1, "Qiniu Storage!", null); -echo "\n\n====> Qiniu_Put result: \n"; +# @gist batch_copy +$entryPairs = array(new Qiniu_RS_EntryPathPair($e1, $e2), new Qiniu_RS_EntryPathPair($e1, $e3)); +list($ret, $err) = Qiniu_RS_BatchCopy($client, $entryPairs); +echo "\n\n====> Qiniu_RS_BatchCopy result: \n"; if ($err !== null) { var_dump($err); } else { var_dump($ret); } -Qiniu_RS_Delete($client, $bucket, $key1); +# @endgist -$putExtra = new Qiniu_PutExtra(); -$putExtra->Crc32 = 1; -list($ret, $err) = Qiniu_PutFile($upToken, $key1, __file__, null); -echo "\n\n====> Qiniu_PutFile result: \n"; +# @gist batch_delete +$entries = array($e1, $e2); +list($ret, $err) = Qiniu_RS_BatchDelete($client, $entries); +echo "\n\n====> Qiniu_RS_BatchDelete result: \n"; if ($err !== null) { var_dump($err); } else { var_dump($ret); } -Qiniu_RS_Delete($client, $bucket, $key1); +# @endgist -$baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key); -$getPolicy = new Qiniu_RS_GetPolicy(); -$privateUrl = $getPolicy->MakeRequest($baseUrl, null); -echo "\n\n====> getPolicy result: \n"; -echo $privateUrl . "\n"; +# @gist batch_move +$entryPairs = array(new Qiniu_RS_EntryPathPair($e3, $e1)); +list($ret, $err) = Qiniu_RS_BatchMove($client, $entryPairs); +echo "\n\n====> Qiniu_RS_BatchMove result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} +# @endgist + + +//------------------------------------rsf----------------------------------------- + +list($iterms, $markerOut, $err) = Qiniu_RSF_ListPrefix($client, $bucket); +echo "\n\n====> Qiniu_RSF result: \n"; +if ($err != null) { + if ($err === Qiniu_RSF_EOF) { + var_dump($iterms); + } else { + var_dump(err); + } +} else { + var_dump($iterms); +} //------------------------------------fop----------------------------------------- +# @gist base_url +//$baseUrl 就是您要访问资源的地址 +$baseUrl = Qiniu_RS_MakeBaseUrl($domain, $key1); +# @endgist +# @gist image_info +$getPolicy = new Qiniu_RS_GetPolicy(); $imgInfo = new Qiniu_ImageInfo; + +//生成fopUrl $imgInfoUrl = $imgInfo->MakeRequest($baseUrl); + +//对fopUrl 进行签名,生成privateUrl。 公有bucket 此步可以省去。 $imgInfoPrivateUrl = $getPolicy->MakeRequest($imgInfoUrl, null); echo "\n\n====> imageInfo privateUrl: \n"; echo $imgInfoPrivateUrl . "\n"; +# @endgist +# @gist image_exif +$getPolicy = new Qiniu_RS_GetPolicy(); $imgExif = new Qiniu_Exif; + +//生成fopUrl $imgExifUrl = $imgExif->MakeRequest($baseUrl); +//对fopUrl 进行签名,生成privateUrl。 公有bucket 此步可以省去。 $imgExifPrivateUrl = $getPolicy->MakeRequest($imgExifUrl, null); echo "\n\n====> imageView privateUrl: \n"; echo $imgExifPrivateUrl . "\n"; +# @endgist +# @gist image_view +$getPolicy = new Qiniu_RS_GetPolicy(); $imgView = new Qiniu_ImageView; $imgView->Mode = 1; $imgView->Width = 60; $imgView->Height = 30; + +//生成fopUrl $imgViewUrl = $imgView->MakeRequest($baseUrl); + +//对fopUrl 进行签名,生成privateUrl。 公有bucket 此步可以省去。 $imgViewPrivateUrl = $getPolicy->MakeRequest($imgViewUrl, null); echo "\n\n====> imageView privateUrl: \n"; echo $imgViewPrivateUrl . "\n"; +# @endgist diff --git a/qiniu/conf.php b/qiniu/conf.php index 254137a1..67ff068c 100644 --- a/qiniu/conf.php +++ b/qiniu/conf.php @@ -1,4 +1,5 @@ URL = $url; $this->Header = array(); $this->Body = $body; + $this->UA = Qiniu_UserAgent(); } } @@ -86,6 +89,8 @@ function Qiniu_ResponseError($resp) // => $error } } } + $err->Reqid = $reqId; + $err->Details = $details; return $err; } @@ -111,9 +116,12 @@ function Qiniu_Client_do($req) // => ($resp, $error) $ch = curl_init(); $url = $req->URL; $options = array( + CURLOPT_USERAGENT => $req->UA, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, + CURLOPT_HEADER => true, + CURLOPT_NOBODY => false, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_URL => $url['path'] ); @@ -129,6 +137,8 @@ function Qiniu_Client_do($req) // => ($resp, $error) $body = $req->Body; if (!empty($body)) { $options[CURLOPT_POSTFIELDS] = $body; + } else { + $options[CURLOPT_POSTFIELDS] = ""; } curl_setopt_array($ch, $options); $result = curl_exec($ch); @@ -141,11 +151,37 @@ function Qiniu_Client_do($req) // => ($resp, $error) $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); curl_close($ch); - $resp = new Qiniu_Response($code, $result); + + $responseArray = explode("\r\n\r\n", $result); + $responseArraySize = sizeof($responseArray); + $respHeader = $responseArray[$responseArraySize-2]; + $respBody = $responseArray[$responseArraySize-1]; + + list($reqid, $xLog) = getReqInfo($respHeader); + + $resp = new Qiniu_Response($code, $respBody); $resp->Header['Content-Type'] = $contentType; + $resp->Header["X-Reqid"] = $reqid; return array($resp, null); } +function getReqInfo($headerContent) { + $headers = explode("\r\n", $headerContent); + $reqid = null; + $xLog = null; + foreach($headers as $header) { + $header = trim($header); + if(strpos($header, 'X-Reqid') !== false) { + list($k, $v) = explode(':', $header); + $reqid = trim($v); + } elseif(strpos($header, 'X-Log') !== false) { + list($k, $v) = explode(':', $header); + $xLog = trim($v); + } + } + return array($reqid, $xLog); +} + class Qiniu_HttpClient { public function RoundTrip($req) // => ($resp, $error) @@ -278,6 +314,21 @@ function Qiniu_Build_MultipartForm($fields, $files) // => ($contentType, $body) return array($contentType, $body); } +function Qiniu_UserAgent() { + global $SDK_VER; + $sdkInfo = "QiniuPHP/$SDK_VER"; + + $systemInfo = php_uname("s"); + $machineInfo = php_uname("m"); + + $envInfo = "($systemInfo/$machineInfo)"; + + $phpVer = phpversion(); + + $ua = "$sdkInfo $envInfo PHP/$phpVer"; + return $ua; +} + function Qiniu_escapeQuotes($str) { $find = array("\\", "\""); diff --git a/qiniu/resumable_io.php b/qiniu/resumable_io.php index 6314231f..fa83c8c3 100644 --- a/qiniu/resumable_io.php +++ b/qiniu/resumable_io.php @@ -12,7 +12,7 @@ class Qiniu_Rio_PutExtra public $Params = null; public $MimeType = null; public $ChunkSize = 0; // 可选。每次上传的Chunk大小 - public $TryTimes = 0; // 可选。尝试次数 + public $TryTimes = 3; // 可选。尝试次数 public $Progresses = null; // 可选。上传进度:[]BlkputRet public $Notify = null; // 进度通知:func(blkIdx int, blkSize int, ret *BlkputRet) public $NotifyErr = null; // 错误通知:func(blkIdx int, blkSize int, err error) @@ -41,7 +41,7 @@ function Qiniu_Rio_Mkblock($self, $host, $reader, $size) // => ($blkputRet, $err if (is_resource($reader)) { $body = fread($reader, $size); if ($body === false) { - $err = Qiniu_NewError(0, 'fread failed'); + $err = new Qiniu_Error(0, 'fread failed'); return array(null, $err); } } else { @@ -51,7 +51,7 @@ function Qiniu_Rio_Mkblock($self, $host, $reader, $size) // => ($blkputRet, $err } } if (strlen($body) != $size) { - $err = Qiniu_NewError(0, 'fread failed: unexpected eof'); + $err = new Qiniu_Error(0, 'fread failed: unexpected eof'); return array(null, $err); } @@ -117,13 +117,30 @@ function Qiniu_Rio_Put($upToken, $key, $body, $fsize, $putExtra) // => ($putRet, $progresses = array(); $uploaded = 0; while ($uploaded < $fsize) { + $tried = 0; + $tryTimes = ($putExtra->TryTimes > 0) ? $putExtra->TryTimes : 1; + $blkputRet = null; + $err = null; if ($fsize < $uploaded + QINIU_RIO_BLOCK_SIZE) { $bsize = $fsize - $uploaded; } else { $bsize = QINIU_RIO_BLOCK_SIZE; } - list($blkputRet, $err) = Qiniu_Rio_Mkblock($self, $QINIU_UP_HOST, $body, $bsize); - $host = $blkputRet['host']; + while ($tried < $tryTimes) { + list($blkputRet, $err) = Qiniu_Rio_Mkblock($self, $QINIU_UP_HOST, $body, $bsize); + if ($err === null) { + break; + } + $tried += 1; + continue; + } + if ($err !== null) { + return array(null, $err); + } + if ($blkputRet === null ) { + $err = new Qiniu_Error(0, "rio: uploaded without ret"); + return array(null, $err); + } $uploaded += $bsize; $progresses []= $blkputRet; } @@ -136,7 +153,7 @@ function Qiniu_Rio_PutFile($upToken, $key, $localFile, $putExtra) // => ($putRet { $fp = fopen($localFile, 'rb'); if ($fp === false) { - $err = Qiniu_NewError(0, 'fopen failed'); + $err = new Qiniu_Error(0, 'fopen failed'); return array(null, $err); } diff --git a/tests/IoTest.php b/tests/IoTest.php index 305bbf2c..746f1aca 100644 --- a/tests/IoTest.php +++ b/tests/IoTest.php @@ -14,6 +14,15 @@ public function setUp() $this->bucket = getenv("QINIU_BUCKET_NAME"); } + public function testReqid() + { + $key = 'testReqid' . getTid(); + list($ret, $err) = Qiniu_PutFile("", $key, __file__, null); + $this->assertNotNull($err); + $this->assertNotNull($err->Reqid); + var_dump($err); + } + public function testPutFile() { $key = 'testPutFile' . getTid(); @@ -91,7 +100,7 @@ public function testPut_mime_save() list($ret, $err) = Qiniu_RS_Stat($this->client, $this->bucket, $key); $this->assertNull($err); - $this->assertEquals($ret['mimeType'], 'application/x-php'); + $this->assertEquals($ret['mimeType'], 'application/x-httpd-php'); var_dump($ret); $err = Qiniu_RS_Delete($this->client, $this->bucket, $key); diff --git a/tests/RioTest.php b/tests/RioTest.php index 28a44e1d..b6474bb5 100644 --- a/tests/RioTest.php +++ b/tests/RioTest.php @@ -26,6 +26,9 @@ public function testMockReader() public function testPut() { + if (getTestEnv() == "travis") { + return; + } $key = 'testRioPut' . getTid(); $err = Qiniu_RS_Delete($this->client, $this->bucket, $key); @@ -50,6 +53,9 @@ public function testPut() public function testLargePut() { + if (getTestEnv() == "travis") { + return; + } $key = 'testRioLargePut' . getTid(); $err = Qiniu_RS_Delete($this->client, $this->bucket, $key); diff --git a/tests/RsTest.php b/tests/RsTest.php index a941a09e..2368198c 100644 --- a/tests/RsTest.php +++ b/tests/RsTest.php @@ -19,6 +19,11 @@ public function setUp() public function testStat() { + $putPolicy = new Qiniu_RS_PutPolicy($this->bucket . ":" . $this->key); + $upToken = $putPolicy->Token(null); + list($ret, $err) = Qiniu_PutFile($upToken, $this->key, __file__, null); + $this->assertNull($err); + Qiniu_RS_Delete($this->client, $this->bucket, $this->notExistKey); list($ret, $err) = Qiniu_RS_Stat($this->client, $this->bucket, $this->key); $this->assertArrayHasKey('hash', $ret); $this->assertNull($err); diff --git a/tests/RsUtilsTest.php b/tests/RsUtilsTest.php index 6b8123a5..75a8b7f5 100644 --- a/tests/RsUtilsTest.php +++ b/tests/RsUtilsTest.php @@ -16,6 +16,9 @@ public function setUp() public function testRput() { + if (getTestEnv() == "travis") { + return; + } $key = 'tmp/testRput' . getTid(); $err = Qiniu_RS_Delete($this->client, $this->bucket, $key); @@ -35,6 +38,9 @@ public function testRput() public function testRputFile() { + if (getTestEnv() == "travis") { + return; + } $key = 'tmp/testRputFile' . getTid(); $err = Qiniu_RS_Delete($this->client, $this->bucket, $key); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 014fc851..d555531d 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -8,10 +8,13 @@ $secretKey = getenv("QINIU_SECRET_KEY"); $tid = getenv("TRAVIS_JOB_NUMBER"); + +$testEnv = getenv("QINIU_TEST_ENV"); + if (!empty($tid)) { - $pid = getmypid(); + $pid = getmypid(); $tid = strstr($tid, "."); - $tid .= "." . $pid; + $tid .= "." . $pid; } function initKeys() { @@ -26,6 +29,11 @@ function getTid() { return $tid; } +function getTestEnv() { + global $testEnv; + return $testEnv; +} + class MockReader { private $off = 0;