

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 搭配第 3 版使用 Amazon S3 分段上傳 適用於 PHP 的 AWS SDK
<a name="s3-multipart-upload"></a>

透過單次 `PutObject` 操作，您最多可上傳大小 5 GB 的物件。不過，如果使用分段上傳方法 (例如，`CreateMultipartUpload`、`UploadPart`、`CompleteMultipartUpload`、`AbortMultipartUpload`)，您可以上傳大小從 5 MB 到 5 TB 的物件。

下列範例將說明：
+ 使用 [ObjectUploader](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.S3.ObjectUploader.html) 將物件上傳至 Amazon S3。
+ 使用 [MultipartUploader](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.S3.MultipartUploader.html) 為 Amazon S3 物件建立分段上傳。
+ 使用 [ObjectCopier](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.S3.ObjectCopier.html) 將物件從一個 Amazon S3 位置複製到另一個位置。

您可以在 GitHub 上 適用於 PHP 的 AWS SDK 取得 的所有範例程式碼。 [ GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/php/example_code)

## 憑證
<a name="examplecredentials"></a>

在執行範例程式碼之前，請先設定您的 AWS 登入資料，如中所述[AWS 使用第 3 適用於 PHP 的 AWS SDK 版向 驗證](credentials.md)。然後匯入 適用於 PHP 的 AWS SDK，如 中所述[安裝第 3 適用於 PHP 的 AWS SDK 版](getting-started_installation.md)。

## 物件上傳程式
<a name="object-uploader"></a>

如果您不確定 `PutObject`或 `MultipartUploader` 是否最適合任務，請使用 `ObjectUploader`。 會根據承載大小`MultipartUploader`，使用 `PutObject`或 將大型檔案`ObjectUploader`上傳至 Amazon S3。

```
require 'vendor/autoload.php';

use Aws\Exception\MultipartUploadException;
use Aws\S3\MultipartUploader;
use Aws\S3\ObjectUploader;
use Aws\S3\S3Client;
```

 **範例程式碼** 

```
// Create an S3Client.
$s3Client = new S3Client([
    'profile' => 'default',
    'region' => 'us-east-2',
    'version' => '2006-03-01'
]);

$bucket = 'your-bucket';
$key = 'my-file.zip';

// Use a stream instead of a file path.
$source = fopen('/path/to/large/file.zip', 'rb');

$uploader = new ObjectUploader(
    $s3Client,
    $bucket,
    $key,
    $source
);

do {
    try {
        $result = $uploader->upload();
        if ($result["@metadata"]["statusCode"] == '200') {
            print('<p>File successfully uploaded to ' . $result["ObjectURL"] . '.</p>');
        }
        print($result);
        // If the SDK chooses a multipart upload, try again if there is an exception.
        // Unlike PutObject calls, multipart upload calls are not automatically retried.
    } catch (MultipartUploadException $e) {
        rewind($source);
        $uploader = new MultipartUploader($s3Client, $source, [
            'state' => $e->getState(),
        ]);
    }
} while (!isset($result));

fclose($source);
```

### Configuration
<a name="object-uploader-configuration"></a>

`ObjectUploader` 物件建構函式接受下列引數：

**`$client`**  
用來執行傳輸的 `Aws\ClientInterface` 物件。這應該是 `Aws\S3\S3Client` 的執行個體。

**`$bucket`**  
(`string`，*必要*) 做為物件上傳目的地的儲存貯體的名稱。

**`$key`**  
(`string`，*必要*) 待上傳的物件所要使用的金鑰。

**`$body`**  
(`mixed`，*必要*) 要上傳的物件資料。可以是 `StreamInterface`、PHP 串流資源或要上傳的資料字串。

**`$acl`**  
(`string`) 針對待上傳的物件，所要設定的存取控制清單 (ACL)。物件預設為私有。

**`$options`**  
分段上傳的組態選項的關聯式陣列。下列組態選項為有效：    
**`add_content_md5`**  
(`bool`) 設為 true 可自動計算上傳的 MD5 檢查總和。  
**`mup_threshold`**  
(`int`，*預設*：`int(16777216)`) 檔案大小的位元組數。如果檔案大小超過此限制，則會使用分段上傳。  
**`before_complete`**  
(`callable`) 要在 `CompleteMultipartUpload` 操作之前呼叫的回呼函式。回呼應具有類似 的函數簽章：`function (Aws\Command $command) {...}`。如需可新增至`CommandInterface`物件的參數，請參閱 [CompleteMultipartUpload API 參考](https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#completemultipartupload)。  
**`before_initiate`**  
(`callable`) 要在 `CreateMultipartUpload` 操作之前呼叫的回呼函式。回呼應具有類似 的函數簽章：`function (Aws\Command $command) {...}`。如果檔案大小超過 `mup_threshold`值，軟體開發套件會叫用此回呼。如需可新增至`CommandInterface`物件的參數，請參閱 [CreateMultipartUpload API 參考](https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#createmultipartupload)。  
**`before_upload`**  
(`callable`) 回呼在 `PutObject`或 `UploadPart`操作之前叫用。回呼應具有類似 的函數簽章：`function (Aws\Command $command) {...}`。如果檔案大小小於或等於`mup_threshold`值，軟體開發套件會叫用此回呼。如需可套用至`PutObject`請求的參數，請參閱 [PutObject API 參考](https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#putobject)。如需套用至`UploadPart`請求的參數，請參閱 [UploadPart API 參考](https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#uploadpart)。SDK 會忽略任何不適用於`CommandInterface`物件所代表之操作的參數。  
**`concurrency`**  
(`int`，*預設*：`int(3)`) 分段上傳期間所允許的並行 `UploadPart` 操作的數目上限。  
**`part_size`**  
(`int`，*預設*：`int(5242880)`) 進行分段上傳時所使用的分段大小 (位元組)。該值必須介於 5 MB 到 5 GB 之間。  
**`state`**  
(`Aws\Multipart\UploadState`) 代表分段上傳狀態的物件，用來恢復先前的上傳作業。提供此選項時，會忽略 `$bucket`和 `$key`引數和 `part_size`選項。  
**`params`**  
關聯陣列，提供每個子命令的組態選項。例如：  

```
new ObjectUploader($bucket, $key, $body, $acl, ['params' => ['CacheControl' => {{<some_value>}}])
```

## MultipartUploader
<a name="multipartuploader"></a>

分段上傳是專為改善較大型物件上傳的體驗所設計。這些方法可讓您以任意順序，個別同時上傳物件的各部分。

建議 Amazon S3 客戶針對大於 100 MB 的物件使用分段上傳。

## MultipartUploader 物件
<a name="multipartuploader-object"></a>

軟體開發套件具有特殊的 `MultipartUploader` 物件，可簡化分段上傳的流程。

 **匯入** 

```
require 'vendor/autoload.php';

use Aws\Exception\MultipartUploadException;
use Aws\S3\MultipartUploader;
use Aws\S3\S3Client;
```

 **範例程式碼** 

```
$s3Client = new S3Client([
    'profile' => 'default',
    'region' => 'us-west-2',
    'version' => '2006-03-01'
]);

// Use multipart upload
$source = '/path/to/large/file.zip';
$uploader = new MultipartUploader($s3Client, $source, [
    'bucket' => 'your-bucket',
    'key' => 'my-file.zip',
]);

try {
    $result = $uploader->upload();
    echo "Upload complete: {$result['ObjectURL']}\n";
} catch (MultipartUploadException $e) {
    echo $e->getMessage() . "\n";
}
```

上傳程式會根據隨附的原始碼和組態，建立分段資料的產生器，並嘗試上傳所有部分。如果某些部分上傳失敗，上傳程式會持續上傳之後的部分，直到讀取完整個原始碼的資料。之後，上傳工具會嘗試上傳失敗的部分，或擲出包含與無法上傳之部分相關資訊的例外狀況。

## 自訂分段上傳
<a name="customizing-a-multipart-upload"></a>

您可以透過將回呼函式傳遞至其建構函式，來針對多段上傳程式所執行的 `CreateMultipartUpload`、`UploadPart` 與 `CompleteMultipartUpload` 操作，設定自訂選項。

 **匯入** 

```
require 'vendor/autoload.php';

use Aws\S3\MultipartUploader;
use Aws\S3\S3Client;
```

 **範例程式碼** 

```
// Create an S3Client
$s3Client = new S3Client([
    'profile' => 'default',
    'region' => 'us-west-2',
    'version' => '2006-03-01'
]);

// Customizing a multipart upload
$source = '/path/to/large/file.zip';
$uploader = new MultipartUploader($s3Client, $source, [
    'bucket' => 'your-bucket',
    'key' => 'my-file.zip',
    'before_initiate' => function (Command $command) {
        // $command is a CreateMultipartUpload operation
        $command['CacheControl'] = 'max-age=3600';
    },
    'before_upload' => function (Command $command) {
        // $command is an UploadPart operation
        $command['RequestPayer'] = 'requester';
    },
    'before_complete' => function (Command $command) {
        // $command is a CompleteMultipartUpload operation
        $command['RequestPayer'] = 'requester';
    },
]);
```

### 部分上傳之間的手動垃圾回收
<a name="manual-garbage-collection-between-part-uploads"></a>

如果您達到大型上傳的記憶體限制，這可能是因為在達到記憶體限制時，[PHP 廢棄項目收集器](https://www.php.net/manual/en/features.gc.php)尚未收集軟體開發套件產生的循環參考。在操作之間手動叫用集合演算法會允許在達到該限制前收集循環。以下範例會在每次分段上傳前，使用回呼叫用集合演算法。請注意，叫用廢棄項目收集器不會伴隨效能成本，最佳使用方式將取決於您的使用案例和環境。

```
$uploader = new MultipartUploader($client, $source, [
   'bucket' => 'your-bucket',
   'key' => 'your-key',
   'before_upload' => function(\Aws\Command $command) {
      gc_collect_cycles();
   }
]);
```

## 從錯誤中復原
<a name="recovering-from-errors"></a>

在分段上傳過程中發生錯誤時，會丟出 `MultipartUploadException`。此例外狀況提供了對 `UploadState` 物件的存取，而此物件包含關於分段上傳進度的資訊。`UploadState` 可用來恢復無法完成的上傳作業。

 **匯入** 

```
require 'vendor/autoload.php';

use Aws\Exception\MultipartUploadException;
use Aws\S3\MultipartUploader;
use Aws\S3\S3Client;
```

 **範例程式碼** 

```
// Create an S3Client
$s3Client = new S3Client([
    'profile' => 'default',
    'region' => 'us-west-2',
    'version' => '2006-03-01'
]);

$source = '/path/to/large/file.zip';
$uploader = new MultipartUploader($s3Client, $source, [
    'bucket' => 'your-bucket',
    'key' => 'my-file.zip',
]);

//Recover from errors
do {
    try {
        $result = $uploader->upload();
    } catch (MultipartUploadException $e) {
        $uploader = new MultipartUploader($s3Client, $source, [
            'state' => $e->getState(),
        ]);
    }
} while (!isset($result));

//Abort a multipart upload if failed
try {
    $result = $uploader->upload();
} catch (MultipartUploadException $e) {
    // State contains the "Bucket", "Key", and "UploadId"
    $params = $e->getState()->getId();
    $result = $s3Client->abortMultipartUpload($params);
}
```

透過 `UploadState` 恢復上傳的動作時，會嘗試上傳尚未上傳的部分。狀態物件會追蹤缺少的部分，即使這些部分並不連續。上傳程式會針對所提供的原始碼檔案，讀取或搜尋屬於仍需上傳部分的位元組範圍，

 `UploadState` 物件可序列化，因此您也可以在不同的程序中恢復上傳。即使不是在處理例外狀況時，您也可以透過呼叫 `$uploader->getState()`，來取得 `UploadState` 物件。

**重要**  
做為資源傳遞到 `MultipartUploader` 的串流，在上傳之前不會自動跳回開頭。如果您使用的是串流，而非類似於先前範例中迴圈內的檔案路徑，則請重設 `catch` 區塊中的 `$source` 變數。

 **匯入** 

```
require 'vendor/autoload.php';

use Aws\Exception\MultipartUploadException;
use Aws\S3\MultipartUploader;
use Aws\S3\S3Client;
```

 **範例程式碼** 

```
// Create an S3Client
$s3Client = new S3Client([
    'profile' => 'default',
    'region' => 'us-west-2',
    'version' => '2006-03-01'
]);

//Using stream instead of file path
$source = fopen('/path/to/large/file.zip', 'rb');
$uploader = new MultipartUploader($s3Client, $source, [
    'bucket' => 'your-bucket',
    'key' => 'my-file.zip',
]);

do {
    try {
        $result = $uploader->upload();
    } catch (MultipartUploadException $e) {
        rewind($source);
        $uploader = new MultipartUploader($s3Client, $source, [
            'state' => $e->getState(),
        ]);
    }
} while (!isset($result));
fclose($source);
```

### 中止分段上傳
<a name="aborting-a-multipart-upload"></a>

您可以擷取 `UploadState` 物件中包含的 `UploadId` ，並將它傳遞至 `abortMultipartUpload`，以中止分段上傳。

```
try {
    $result = $uploader->upload();
} catch (MultipartUploadException $e) {
    // State contains the "Bucket", "Key", and "UploadId"
    $params = $e->getState()->getId();
    $result = $s3Client->abortMultipartUpload($params);
}
```

## 非同步分段上傳
<a name="asynchronous-multipart-uploads"></a>

呼叫 `upload()` 的 `MultipartUploader` 是封鎖請求。如果是在非同步的情境中作業，您可以取得分段上傳的 [promise](guide_promises.md) 物件。

```
require 'vendor/autoload.php';

use Aws\S3\MultipartUploader;
use Aws\S3\S3Client;
```

 **範例程式碼** 

```
// Create an S3Client
$s3Client = new S3Client([
    'profile' => 'default',
    'region' => 'us-west-2',
    'version' => '2006-03-01'
]);

$source = '/path/to/large/file.zip';
$uploader = new MultipartUploader($s3Client, $source, [
    'bucket' => 'your-bucket',
    'key' => 'my-file.zip',
]);

$promise = $uploader->promise();
```

### Configuration
<a name="asynchronous-multipart-uploads-configuration"></a>

`MultipartUploader` 物件建構函式接受下列引數：

** `$client` **  
用來執行傳輸的 `Aws\ClientInterface` 物件。這應該是 `Aws\S3\S3Client` 的執行個體。

** `$source` **  
正在上傳的原始碼資料。這可以是路徑或 URL (例如，`/path/to/file.jpg`)、資源控制代碼 (例如，`fopen('/path/to/file.jpg', 'r)`)，或是 [PSR-7 stream](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Psr.Http.Message.StreamInterface.html) 的執行個體。

** `$config` **  
分段上傳的組態選項的關聯式陣列。  
下列組態選項為有效：    
** `acl` **  
(`string`) 針對待上傳的物件，所要設定的存取控制清單 (ACL)。物件預設為私有。  
** `before_complete` **  
(`callable`) 要在 `CompleteMultipartUpload` 操作之前呼叫的回呼函式。回呼函式應具有像是 `function (Aws\Command $command) {...}` 的函式簽章。  
** `before_initiate` **  
(`callable`) 要在 `CreateMultipartUpload` 操作之前呼叫的回呼函式。回呼函式應具有像是 `function (Aws\Command $command) {...}` 的函式簽章。  
** `before_upload` **  
(`callable`) 要在任何 `UploadPart` 操作之前呼叫的回呼函式。回呼函式應具有像是 `function (Aws\Command $command) {...}` 的函式簽章。  
** `bucket` **  
(`string`，*必要*) 做為物件上傳目的地的儲存貯體的名稱。  
** `concurrency` **  
(`int`，*預設*：`int(5)`) 分段上傳期間所允許的並行 `UploadPart` 操作的數目上限。  
** `key` **  
(`string`，*必要*) 待上傳的物件所要使用的金鑰。  
** `part_size` **  
(`int`，*預設*：`int(5242880)`) 進行分段上傳時所使用的分段大小 (位元組)。這必須介於 5 MB 到 5 GB 之間 (含)。  
** `state` **  
(`Aws\Multipart\UploadState`) 代表分段上傳狀態的物件，用來恢復先前的上傳作業。提供此選項時，會略過 `bucket`、`key` 和 `part_size` 選項。  
**`add_content_md5`**  
(`boolean`) 設為 true 可自動計算上傳的 MD5 檢查總和。  
**`params`**  
關聯陣列，提供每個子命令的組態選項。例如：  

```
new MultipartUploader($client, $source, ['params' => ['CacheControl' => {{<some_value>}}]])
```

## 分段副本
<a name="multipart-copies"></a>

 適用於 PHP 的 AWS SDK 也包含物件`MultipartCopy`，其使用方式與 類似`MultipartUploader`，但設計用於複製 Amazon S3 內大小介於 5 GB 到 5 TB 之間的物件。

```
require 'vendor/autoload.php';

use Aws\Exception\MultipartUploadException;
use Aws\S3\MultipartCopy;
use Aws\S3\S3Client;
```

 **範例程式碼** 

```
// Create an S3Client
$s3Client = new S3Client([
    'profile' => 'default',
    'region' => 'us-west-2',
    'version' => '2006-03-01'
]);

//Copy objects within S3
$copier = new MultipartCopy($s3Client, '/bucket/key?versionId=foo', [
    'bucket' => 'your-bucket',
    'key' => 'my-file.zip',
]);

try {
    $result = $copier->copy();
    echo "Copy complete: {$result['ObjectURL']}\n";
} catch (MultipartUploadException $e) {
    echo $e->getMessage() . "\n";
}
```