PHP上传文件

本文介绍如何在受版本控制的存储空间(Bucket)中上传文件(Object)。

注意事项

  • 本文以华东1(杭州)外网Endpoint为例。如果您希望通过与OSS同地域的其他阿里云产品访问OSS,请使用内网Endpoint。关于OSS支持的Region与Endpoint的对应关系,请参见OSS访问域名、数据中心、开放端口

  • 本文以OSS域名新建OSSClient为例。如果您希望通过自定义域名、STS等方式新建OSSClient,请参见新建OssClient

  • 要上传文件,您必须有oss:PutObject权限。具体操作,请参见为RAM用户授权自定义的权限策略

简单上传

在已开启版本控制的Bucket中,OSS将为新上传的Object生成全局唯一的随机字符串版本ID,并在响应Header中通过x-oss-version-id形式返回。

在暂停了版本控制的Bucket中,OSS将为新上传的Object生成特殊字符串为“null”的版本ID。上传同名Object时,后一次会覆盖前一次上传的文件内容,即同一个Object仅有一个版本的ID为“null”。

以下代码用于简单上传:

<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;

// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以杭州为例,其它Region请按实际情况填写。
$endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
// 填写不包含Bucket名称在内的Object的完整路径,例如example/test.txt。
$object = "<yourObjectName>";
$content = "hello world";

$config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
        "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
        "region"=> "cn-hangzhou"
    );
    $ossClient = new OssClient($config);

try {
    // 在受版本控制的Bucket中上传Object。
    $ret = $ossClient->putObject($bucket, $object, $content);

    // 查看Object的版本信息。
    print("versionId:" .$ret[OssClient::OSS_HEADER_VERSION_ID]);
} catch (OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}

print(__FUNCTION__ . ": OK" . "\n");

简单上传的详细信息请参见PutObject

追加上传

在受版本控制的Bucket中对Object进行追加上传(AppendObject)操作时,有如下注意事项:

  • 仅支持对当前版本为Appendable类型的Object执行AppendObject操作。

  • 不支持对历史版本为Appendable类型或当前版本为非Appendable类型的Object(包括Normal Object、Delete Marker等)执行AppendObject操作。

  • 对当前版本为Appendable类型的Object执行AppendObject操作时,OSS不会为该Appendable类型的Object生成历史版本。

  • 对当前版本为Appendable类型的Object执行PutObject或DeleteObject操作时,OSS会将该Appendable类型的Object保留为历史版本,且该Object不允许继续追加。

以下代码用于追加上传:

<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;

// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以杭州为例,其它Region请按实际情况填写。
$endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
$object = "<yourObjectName>";
// 表示第一次、第二次以及第三次追加上传后获取的文件内容分别为Hello OSS、Hi OSS以及OSS OK。
$content_array = array('Hello OSS', 'Hi OSS', 'OSS OK');
try{
    $config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
        "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
        "region"=> "cn-hangzhou"
    );
    $ossClient = new OssClient($config);

    // 第一次追加上传。第一次追加的位置是0,返回值为下一次追加的位置。后续追加的位置是追加前文件的长度。
    $position = $ossClient->appendObject($bucket, $object, $content_array[0], 0);    
    $position = $ossClient->appendObject($bucket, $object, $content_array[1], $position);   
    $position = $ossClient->appendObject($bucket, $object, $content_array[2], $position);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . ": OK" . "\n");

追加上传的详细信息请参见AppendObject

分片上传

在受版本控制的Bucket中,调用CompleteMultipartUpload接口来完成整个文件的分片上传,OSS会为整个文件生成唯一的版本ID,并在响应Header中以x-oss-version-id的形式返回。

以下代码用于分片上传:

<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;
use OSS\Core\OssUtil;

// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以杭州为例,其它Region请按实际情况填写。
$endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
$object = "<yourObjectName>";
// 填写本地文件的完整路径。
$uploadFile = "<yourLocalFile>";

/**
 *  步骤1:初始化一个分片上传事件,获取uploadId。
 */
try{
    $config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
        "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
        "region"=> "cn-hangzhou"
    );
    $ossClient = new OssClient($config);

    // 返回uploadId。uploadId是分片上传事件的唯一标识。您可以根据uploadId发起相关的操作,如取消分片上传、查询分片上传等。
    $uploadId = $ossClient->initiateMultipartUpload($bucket, $object);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": initiateMultipartUpload FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . ": initiateMultipartUpload OK" . "\n");
/*
 * 步骤2:上传分片。
 */
$partSize = 10 * 1024 * 1024;
$uploadFileSize = sprintf('%u',filesize($uploadFile));
$pieces = $ossClient->generateMultiuploadParts($uploadFileSize, $partSize);
$responseUploadPart = array();
$uploadPosition = 0;
$isCheckMd5 = true;
foreach ($pieces as $i => $piece) {
    $fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
    $toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
    $upOptions = array(
        // 上传文件。
        $ossClient::OSS_FILE_UPLOAD => $uploadFile,
        // 设置分片号。
        $ossClient::OSS_PART_NUM => ($i + 1),
        // 指定分片上传起始位置。
        $ossClient::OSS_SEEK_TO => $fromPos,
        // 指定文件长度。
        $ossClient::OSS_LENGTH => $toPos - $fromPos + 1,
        // 是否开启MD5校验,true表示开启,false表示未开启。
        $ossClient::OSS_CHECK_MD5 => $isCheckMd5,
    );
    // 开启MD5校验。
    if ($isCheckMd5) {
        $contentMd5 = OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
        $upOptions[$ossClient::OSS_CONTENT_MD5] = $contentMd5;
    }
    try {
        // 上传分片。
        $responseUploadPart[] = $ossClient->uploadPart($bucket, $object, $uploadId, $upOptions);
    } catch(OssException $e) {
        printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} FAILED\n");
        printf($e->getMessage() . "\n");
        return;
    }
    printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} OK\n");
}
// $uploadParts是由每个分片的ETag和分片号(PartNumber)组成的数组。
$uploadParts = array();
foreach ($responseUploadPart as $i => $eTag) {
    $uploadParts[] = array(
        'PartNumber' => ($i + 1),
        'ETag' => $eTag,
    );
}
/**
 * 步骤3:完成上传。
 */
try {
    // 执行completeMultipartUpload操作时,需要提供所有有效的$uploadParts。OSS收到提交的$uploadParts后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
    $ret = $ossClient->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts);
    // 查看Object版本信息。
    print("versionId:" .$ret[OssClient::OSS_HEADER_VERSION_ID]);
}  catch(OssException $e) {
    printf(__FUNCTION__ . ": completeMultipartUpload FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
printf(__FUNCTION__ . ": completeMultipartUpload OK\n");   

分片上传的详细信息请参见InitiateMultipartUploadUploadPartCompleteMultipartUpload等接口。