全部产品
对象存储 OSS

上传文件

更新时间:2017-06-07 13:26:11   分享:   

在OSS中,用户操作的基本数据单元是文件(Object)。OSS PHP SDK提供了丰富的文件上传接口,可以通过以下方式上传文件:

  • 字符串上传
  • 文件上传
  • 追加上传
  • 分片上传

字符串上传、文件上传、追加上传的文件最大不能超过5GB。当文件较大时,请使用分片上传,分片上传文件大小不能超过48.8TB。

字符串上传

下面的代码实现了上传指定字符串中的内容到文件中:

  1. <?php
  2. /**
  3. * 上传字符串作为object的内容
  4. *
  5. * @param OssClient $ossClient OSSClient实例
  6. * @param string $bucket 存储空间名称
  7. * @return null
  8. */
  9. function putObject($ossClient, $bucket)
  10. {
  11. $object = "oss-php-sdk-test/upload-test-object-name.txt";
  12. $content = file_get_contents(__FILE__);
  13. try{
  14. $ossClient->putObject($bucket, $object, $content);
  15. } catch(OssException $e) {
  16. printf(__FUNCTION__ . ": FAILED\n");
  17. printf($e->getMessage() . "\n");
  18. return;
  19. }
  20. print(__FUNCTION__ . ": OK" . "\n");
  21. }

上传本地文件

下面的代码实现了上传指定的本地文件到文件中:

  1. <?php
  2. /**
  3. * 上传指定的本地文件内容
  4. *
  5. * @param OssClient $ossClient OSSClient实例
  6. * @param string $bucket 存储空间名称
  7. * @return null
  8. */
  9. function uploadFile($ossClient, $bucket)
  10. {
  11. $object = "oss-php-sdk-test/upload-test-object-name.txt";
  12. $filePath = __FILE__;
  13. try{
  14. $ossClient->uploadFile($bucket, $object, $filePath);
  15. } catch(OssException $e) {
  16. printf(__FUNCTION__ . ": FAILED\n");
  17. printf($e->getMessage() . "\n");
  18. return;
  19. }
  20. print(__FUNCTION__ . ": OK" . "\n");
  21. }

提示:

  • 使用上述方法上传最大文件不能超过5G, 如果超过可以使用分片文件上传

追加上传

简单上传,分片上传,断点续传上传,创建的Object都是Normal类型,这种Object在上传结束之后内容就是固定的,只能读取,不能修改。如果Object内容发生了改变,只能重新上传同名的Object来覆盖之前的内容,这也是OSS和普通文件系统使用的一个重大区别。正因为这种特性,在很多应用场景下会很不方便,典型比如视频监控、视频直播领域等,视频数据在实时的不断产生。

OSS提供了用户通过追加上传(Append Object)的方式在一个Object后面直接追加内容的功能。通过这种方式操作的Object的类型为Appendable Object,而其他的方式上传的Object类型为Normal Object。每次追加上传的数据都能够即时可读。

追加上传字符串

下面的代码实现了追加上传指定字符串到文件(Object)中:

  1. <?php
  2. /**
  3. * 字符串追加上传
  4. *
  5. * @param OssClient $ossClient OSSClient实例
  6. * @param string $bucket 存储空间名称
  7. * @return null
  8. */
  9. function putObject($ossClient, $bucket)
  10. {
  11. $object = "oss-php-sdk-test/append-test-object-name.txt";
  12. $content_array = array('Hello OSS', 'Hi OSS', 'OSS OK');
  13. try{
  14. $position = $this->ossClient->appendObject($this->bucket, $object, $content_array[0], 0);
  15. $position = $this->ossClient->appendObject($this->bucket, $object, $content_array[1], $position);
  16. $position = $this->ossClient->appendObject($this->bucket, $object, $content_array[2], $position);
  17. } catch(OssException $e) {
  18. printf(__FUNCTION__ . ": FAILED\n");
  19. printf($e->getMessage() . "\n");
  20. return;
  21. }
  22. print(__FUNCTION__ . ": OK" . "\n");
  23. }

追加上传文件

下面的代码实现了追加上传本地文件(File)到OSS文件(Object):

  1. /**
  2. * 文件追加上传
  3. *
  4. * @param OssClient $ossClient OSSClient实例
  5. * @param string $bucket 存储空间名称
  6. * @return null
  7. */
  8. function putObject($ossClient, $bucket)
  9. {
  10. $object = "oss-php-sdk-test/append-test-object-name.txt";
  11. try{
  12. $position = $this->ossClient->appendFile($this->bucket, $object, __FILE__, 0);
  13. $position = $this->ossClient->appendFile($this->bucket, $object, __FILE__, $position);
  14. } catch(OssException $e) {
  15. printf(__FUNCTION__ . ": FAILED\n");
  16. printf($e->getMessage() . "\n");
  17. return;
  18. }
  19. print(__FUNCTION__ . ": OK" . "\n");
  20. }

提示:

  • 追加上传的次数没有限制,文件大小上限为5GB。更大的文件请使用分片上传;
  • 追加类型的文件(Append Object)暂时不支持copyObject操作。

分片上传

除了通过PutObject接口上传文件到OSS以外,OSS还提供了另外一种上传模式 —— Multipart Upload。用户可以在如下的应用场景内(但不仅限于此),使用Multipart Upload上传模式,如:

  • 需要支持断点上传。
  • 上传超过100MB大小的文件。
  • 网络条件较差,和OSS的服务器之间的链接经常断开。
  • 上传文件之前,无法确定上传文件的大小。

提示:

  • 分片上传的完整代码请参见:GitHub

分片上传本地文件

下面代码通过封装后的易用接口进行分片上传文件操作:

  1. <?php
  2. /**
  3. * 通过multipart上传文件
  4. *
  5. * @param OssClient $ossClient OSSClient实例
  6. * @param string $bucket 存储空间名称
  7. * @return null
  8. */
  9. function multiuploadFile($ossClient, $bucket)
  10. {
  11. $object = "test/multipart-test.txt";
  12. $file = __FILE__;
  13. try{
  14. $ossClient->multiuploadFile($bucket, $object, $file);
  15. } catch(OssException $e) {
  16. printf(__FUNCTION__ . ": FAILED\n");
  17. printf($e->getMessage() . "\n");
  18. return;
  19. }
  20. print(__FUNCTION__ . ": OK" . "\n");
  21. }

分片上传本地目录

下面代码通过封装后的易用接口进行分片上传目录操作:

  1. <?php
  2. /**
  3. * 按照目录上传文件
  4. *
  5. * @param OssClient $ossClient OssClient
  6. * @param string $bucket 存储空间名称
  7. *
  8. */
  9. function uploadDir($ossClient, $bucket) {
  10. $localDirectory = ".";
  11. $prefix = "samples/codes";
  12. try {
  13. $ossClient->uploadDir($bucket, $prefix, $localDirectory);
  14. } catch(OssException $e) {
  15. printf(__FUNCTION__ . ": FAILED\n");
  16. printf($e->getMessage() . "\n");
  17. return;
  18. }
  19. printf(__FUNCTION__ . ": completeMultipartUpload OK\n");
  20. }

原始接口分片上传

分片上传(MultipartUpload)一般的流程如下:

  • 初始化一个分片上传任务(InitiateMultipartUpload)
  • 逐个或并行上传分片(UploadPart)
  • 完成上传(CompleteMultipartUpload)或取消分片上传(AbortMultipartUpload)

下面通过一个完整的示例说明了如何通过原始的api接口一步一步的进行分片上传操作,如果用户需要做断点续传等高级操作,可以参考下面代码:

  1. <?php
  2. /**
  3. * 使用基本的api分阶段进行分片上传
  4. *
  5. * @param OssClient $ossClient OSSClient实例
  6. * @param string $bucket 存储空间名称
  7. * @throws OssException
  8. */
  9. function putObjectByRawApis($ossClient, $bucket)
  10. {
  11. $object = "test/multipart-test.txt";
  12. /**
  13. * step 1. 初始化一个分块上传事件, 也就是初始化上传Multipart, 获取upload id
  14. */
  15. try{
  16. $uploadId = $ossClient->initiateMultipartUpload($bucket, $object);
  17. } catch(OssException $e) {
  18. printf(__FUNCTION__ . ": initiateMultipartUpload FAILED\n");
  19. printf($e->getMessage() . "\n");
  20. return;
  21. }
  22. print(__FUNCTION__ . ": initiateMultipartUpload OK" . "\n");
  23. /*
  24. * step 2. 上传分片
  25. */
  26. $partSize = 10 * 1024 * 1024;
  27. $uploadFile = __FILE__;
  28. $uploadFileSize = filesize($uploadFile);
  29. $pieces = $ossClient->generateMultiuploadParts($uploadFileSize, $partSize);
  30. $responseUploadPart = array();
  31. $uploadPosition = 0;
  32. $isCheckMd5 = true;
  33. foreach ($pieces as $i => $piece) {
  34. $fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
  35. $toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
  36. $upOptions = array(
  37. $ossClient::OSS_FILE_UPLOAD => $uploadFile,
  38. $ossClient::OSS_PART_NUM => ($i + 1),
  39. $ossClient::OSS_SEEK_TO => $fromPos,
  40. $ossClient::OSS_LENGTH => $toPos - $fromPos + 1,
  41. $ossClient::OSS_CHECK_MD5 => $isCheckMd5,
  42. );
  43. if ($isCheckMd5) {
  44. $contentMd5 = OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
  45. $upOptions[$ossClient::OSS_CONTENT_MD5] = $contentMd5;
  46. }
  47. //2. 将每一分片上传到OSS
  48. try {
  49. $responseUploadPart[] = $ossClient->uploadPart($bucket, $object, $uploadId, $upOptions);
  50. } catch(OssException $e) {
  51. printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} FAILED\n");
  52. printf($e->getMessage() . "\n");
  53. return;
  54. }
  55. printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} OK\n");
  56. }
  57. $uploadParts = array();
  58. foreach ($responseUploadPart as $i => $eTag) {
  59. $uploadParts[] = array(
  60. 'PartNumber' => ($i + 1),
  61. 'ETag' => $eTag,
  62. );
  63. }
  64. /**
  65. * step 3. 完成上传
  66. */
  67. try {
  68. $ossClient->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts);
  69. } catch(OssException $e) {
  70. printf(__FUNCTION__ . ": completeMultipartUpload FAILED\n");
  71. printf($e->getMessage() . "\n");
  72. return;
  73. }
  74. printf(__FUNCTION__ . ": completeMultipartUpload OK\n");
  75. }

提示:

  • 上面程序一共分为三个步骤:1. initiate 2. uploadPart 3. complete
  • 第二步UploadPart方法用来上传每一个分片,但是要注意以下几点:
  • UploadPart 方法要求除最后一个Part以外,其他的Part大小都要大于或等于100KB。但是Upload Part接口并不会立即校验上传Part的大小(因为不知道是否为最后一块);只有当Complete Multipart Upload的时候才会校验。
  • OSS会将服务器端收到Part数据的MD5值在OssClient的UploadPart接口中返回;
  • Part号码的范围是1~10000。如果超出这个范围,OSS将返回InvalidArgument的错误码。
  • 每次上传Part时都要把流定位到此次上传块开头所对应的位置。
  • 每次上传Part之后,OSS的返回结果会包含一个 PartETag 对象,它是上传块的ETag与块编号(PartNumber)的组合。在后续完成分片上传的步骤中会用到它,因此我们需要将其保存起来,然后在第三步complete的时候使用,具体操作参考上面代码。
  • 分片上传任务初始化或上传部分分片后,可以使用abortMultipartUpload接口中止分片上传事件。当分片上传事件被中止后,就不能再使用这个Upload ID做任何操作,已经上传的分片数据也会被删除。

查看已上传的分片

查看上传的分片可以罗列出指定Upload ID所属的所有已经上传成功的分片。

通过下面代码,可以查看一次上传任务已上传的分片:

  1. /**
  2. * 查看已上传的分片
  3. *
  4. * @param OssClient $ossClient OSSClient实例
  5. * @param string $bucket 存储空间名称
  6. * @param string $uploadId upload Id
  7. * @return null
  8. */
  9. function putObject($ossClient, $bucket, $uploadId)
  10. {
  11. $object = "oss-php-sdk-test/upload-test-object-name.txt";
  12. try{
  13. $listPartsInfo = $ossClient->listParts($bucket, $object, $upload_id);
  14. foreach ($listPartsInfo->getListPart() as $partInfo) {
  15. print($partInfo->getPartNumber() . "\t" . $partInfo->getSize() . "\t" . $partInfo->getETag() . "\t" . $partInfo->getLastModified() . "\n");
  16. }
  17. } catch(OssException $e) {
  18. printf(__FUNCTION__ . ": FAILED\n");
  19. printf($e->getMessage() . "\n");
  20. return;
  21. }
  22. print(__FUNCTION__ . ": OK" . "\n");
  23. }

查看当前正在进行的分片上传任务

通过下面代码,可以得到当前正在进行中,还未完成的分片上传:

  1. <?php
  2. /**
  3. * 获取当前未完成的分片上传列表
  4. *
  5. * @param $ossClient OssClient
  6. * @param $bucket string
  7. */
  8. function listMultipartUploads($ossClient, $bucket) {
  9. $options = array(
  10. 'delimiter' => '/',
  11. 'max-uploads' => 100,
  12. 'key-marker' => '',
  13. 'prefix' => '',
  14. 'upload-id-marker' => ''
  15. );
  16. try {
  17. $listMultipartUploadInfo = $ossClient->listMultipartUploads($bucket, $options);
  18. } catch(OssException $e) {
  19. printf(__FUNCTION__ . ": listMultipartUploads FAILED\n");
  20. printf($e->getMessage() . "\n");
  21. return;
  22. }
  23. printf(__FUNCTION__ . ": listMultipartUploads OK\n");
  24. $listUploadInfo = $listMultipartUploadInfo->getUploads();
  25. var_dump($listUploadInfo);
  26. }

上述例子中提到的$options参数说明:

key 说明
delimiter 是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素——CommonPrefixes。
key-marker 与upload-id-marker参数一同使用来指定返回结果的起始位置。
max-uploads 限定此次返回Multipart Uploads事件的最大数目,如果不设定,默认为1000,max-uploads取值不能大于1000。
prefix 限定返回的object key必须以prefix作为前缀。注意使用prefix查询时,返回的key中仍会包含prefix。
upload-id-marker 与key-marker参数一同使用来指定返回结果的起始位置。

设置文件元信息(Object Meta)

文件元信息(Object Meta),是对用户上传到OSS的文件的属性描述,分为两种:HTTP标准属性(HTTP Headers)和User Meta(用户自定义元信息)。 文件元信息可以在各种方式上传(字符串上传、文件上传、追加上传、分片上传),或拷贝文件时进行设置。元信息的名称大小写不敏感。更多文件元信息的介绍,请参看 文件元信息

设定Http Header

OSS允许用户自定义Http header。Http header请参考 RFC2616。几个常用的http header说明如下:

名称 描述 默认值
Content-MD5 文件数据校验,设置了该值后OSS会启用文件内容MD5校验,把您提供的MD5与文件的MD5比较,不一致会抛出错误
Content-Type 文件的MIME,定义文件的类型及网页编码,决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成,如果没有扩展名则填默认值 application/octet-stream
Content-Disposition 指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称
Content-Length 上传的文件的长度,超过流/文件的长度会截断,不足为实际值 流/文件时间长度
Expires 缓存过期时间,OSS未使用,格式是格林威治时间(GMT)
Cache-Control 指定该Object被下载时的网页的缓存行为

下面的代码实现了上传时设置文件的Http Headers:

  1. /**
  2. * 上传时设置文件的元数据
  3. *
  4. * @param OssClient $ossClient OSSClient实例
  5. * @param string $bucket 存储空间名称
  6. * @return null
  7. */
  8. function putObject($ossClient, $bucket)
  9. {
  10. $object = "oss-php-sdk-test/upload-test-object-name.txt";
  11. $content = file_get_contents(__FILE__);
  12. $options = array(
  13. OssClient::OSS_HEADERS => array(
  14. 'Expires' => '2012-10-01 08:00:00',
  15. 'Content-Disposition' => 'attachment; filename="xxxxxx"',
  16. ));
  17. try{
  18. $ossClient->putObject($bucket, $object, $content, $options);
  19. } catch(OssException $e) {
  20. printf(__FUNCTION__ . ": FAILED\n");
  21. printf($e->getMessage() . "\n");
  22. return;
  23. }
  24. print(__FUNCTION__ . ": OK" . "\n");
  25. }

提示:

  • 通过设置文件的Content-Type,可以修改文件的类型;
  • 通过设置文件的Content-Disposition,可以控制文件的下载行为;
  • putObject、uploadFile、appendObject、appendFile、multiuploadFile、initiateMultipartUpload操作支持设定Http Header。

用户自定义元信息

OSS支持用户自定义Object的元信息,对Object进行描述。

下面的代码实现了上传时设置文件的自定义元数据:

  1. <?php
  2. /**
  3. * 上传时设置文件的自定义元数据
  4. *
  5. * @param OssClient $ossClient OSSClient实例
  6. * @param string $bucket 存储空间名称
  7. * @return null
  8. */
  9. function putObject($ossClient, $bucket)
  10. {
  11. $object = "oss-php-sdk-test/upload-test-object-name.txt";
  12. $content = file_get_contents(__FILE__);
  13. $options = array(OssClient::OSS_HEADERS => array(
  14. 'x-oss-meta-self-define-title' => 'user define meta info',
  15. ));
  16. try{
  17. $ossClient->putObject($bucket, $object, $content, $options);
  18. } catch(OssException $e) {
  19. printf(__FUNCTION__ . ": FAILED\n");
  20. printf($e->getMessage() . "\n");
  21. return;
  22. }
  23. print(__FUNCTION__ . ": OK" . "\n");
  24. }

提示:

  • 文件的元信息可以通过OssClient::getObjectMeta获取;
  • user meta的名称大小写不敏感,例如设置为:’x-oss-meta-name’,读取名字为x-oss-meta-name的参数即可;
  • 一个文件可以有多个元信息,总大小不能超过8KB;
  • putObject、uploadFile、appendObject、appendFile、multiuploadFile、initiateMultipartUpload操作支持设定自定义元信息。

上传时使用MD5校验

为了确保PHP SDK发送的数据和OSS服务端接收到的数据一致,OSS支持MD5校验。文件上传时(字符串上传、文件上传、追加上传、分片上传)默认关闭MD5,如果您需要打开MD5校验,请上传文件的options设置。

下面的代码实现了上传时开启MD5校验:

  1. <?php
  2. /**
  3. * 上传时开启MD5校验
  4. *
  5. * @param OssClient $ossClient OSSClient实例
  6. * @param string $bucket 存储空间名称
  7. * @return null
  8. */
  9. function putObject($ossClient, $bucket)
  10. {
  11. $object = "oss-php-sdk-test/upload-test-object-name.txt";
  12. $options = array(OssClient::OSS_CHECK_MD5 => true);
  13. try{
  14. $ossClient->uploadFile($bucket, $object, __FILE__, $options);
  15. } catch(OssException $e) {
  16. printf(__FUNCTION__ . ": FAILED\n");
  17. printf($e->getMessage() . "\n");
  18. return;
  19. }
  20. print(__FUNCTION__ . ": OK" . "\n");
  21. }

提示:

  • 使用Md5校验时,性能会有所损失;
  • putObject、uploadFile、appendObject、appendFile、multiuploadFile操作支持 OSS_CHECK_MD5 选择。
本文导读目录
本文导读目录
以上内容是否对您有帮助?