フラグメントアップロードでは、ラージオブジェクトを複数のパートに分割し、それぞれを独立してアップロードします。すべてのパートのアップロードが完了したら、CompleteMultipartUpload を呼び出して、それらを 1 つのオブジェクトとしてアセンブルします。
前提条件
開始する前に、以下の条件を満たしていることを確認してください。
対象リージョン内の OSS バケット
バケットに対する
oss:PutObject権限 — 詳細については、「RAM ユーザーへのカスタムアクセスポリシーの付与」をご参照ください。環境変数として保存された Access Key ID および Access Key Secret — 詳細については、「PHP 向けアクセス認証情報の設定」をご参照ください。
仕組み
フラグメントアップロードは、以下の 3 つのステップで実行されます。
初期化 —
InitiateMultipartUploadを呼び出して、OSS からグローバルに一意なアップロード ID を取得します。パートのアップロード — 各パートに対して 1 回ずつ
UploadPartを呼び出し、アップロード ID とパート番号を指定します。完了 — アップロード済みのパート一覧を引数として
CompleteMultipartUploadを呼び出して、最終的なオブジェクトをアセンブルします。
パートアップロードの動作:
既存のパート番号で新しいパートをアップロードすると、そのパートの以前のデータが上書きされます。
OSS は各受信パートの MD5 ハッシュを
ETagレスポンスヘッダーで返します。OSS は、自身で計算した MD5 と SDK で計算された値を比較して整合性を検証します。一致しない場合、
InvalidDigestエラーが返されます。
大規模ファイルのパート単位でのアップロード
以下の例では、ローカルファイルを 5 MB のパートに分割し、各パートを順次アップロードして、アップロードを完了します。エンドポイントは cn-hangzhou(パブリックエンドポイント)に設定されています。同一リージョン内の他の Alibaba Cloud サービスから OSS にアクセスする場合は、代わりに内部エンドポイントをご利用ください。
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use AlibabaCloud\Oss\V2 as Oss;
// 必須コマンドライン引数の解析:--region、--bucket、--key
// オプション:--endpoint
$optsdesc = [
"region" => ['help' => 'バケットが配置されているリージョン。', 'required' => True],
"endpoint" => ['help' => '他のサービスが OSS にアクセスするために使用できるドメイン名。', 'required' => False],
"bucket" => ['help' => 'バケットの名称', 'required' => True],
"key" => ['help' => 'オブジェクトの名称', 'required' => True],
];
$longopts = \array_map(function ($key) { return "$key:"; }, array_keys($optsdesc));
$options = getopt("", $longopts);
foreach ($optsdesc as $key => $value) {
if ($value['required'] === True && empty($options[$key])) {
echo "エラー:以下の引数が必要です:--$key, " . $value['help'] . PHP_EOL;
exit(1);
}
}
$region = $options["region"];
$bucket = $options["bucket"];
$key = $options["key"];
// 環境変数 OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET から認証情報を読み込みます
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider);
$cfg->setRegion($region);
$cfg->setEndpoint('http://oss-cn-hangzhou.aliyuncs.com');
$client = new Oss\Client($cfg);
// ステップ 1:フラグメントアップロードを初期化し、アップロード ID を取得
$initResult = $client->initiateMultipartUpload(
new Oss\Models\InitiateMultipartUploadRequest(
bucket: $bucket,
key: $key
)
);
// ステップ 2:ファイルを分割して各パートをアップロード
$bigFileName = "/Users/yourLocalPath/yourFileName"; // ご利用のローカルファイルのパスに置き換えてください
$partSize = 5 * 1024 * 1024; // パートあたり 5 MB
$fileSize = filesize($bigFileName);
$partsNum = intdiv($fileSize, $partSize) + intval(1);
$parts = [];
$i = 1;
$file = new \GuzzleHttp\Psr7\LazyOpenStream($bigFileName, 'rb');
while ($i <= $partsNum) {
$partResult = $client->uploadPart(
new Oss\Models\UploadPartRequest(
bucket: $bucket,
key: $key,
partNumber: $i,
uploadId: $initResult->uploadId,
contentLength: null, // オプション:パート本体の長さ
contentMd5: null, // オプション:パートコンテンツの検証用 MD5 ハッシュ
trafficLimit: null, // オプション:トラフィック制限
requestPayer: null, // オプション:リクエスト料金の支払者
body: new \GuzzleHttp\Psr7\LimitStream($file, $partSize, ($i - 1) * $partSize)
)
);
// アップロード完了のために必要なパート番号と ETag を収集
$parts[] = new Oss\Models\UploadPart(
partNumber: $i,
etag: $partResult->etag
);
$i++;
}
// ステップ 3:すべてのパートを最終的なオブジェクトとしてアセンブル
$comResult = $client->completeMultipartUpload(
new Oss\Models\CompleteMultipartUploadRequest(
bucket: $bucket,
key: $key,
uploadId: $initResult->uploadId,
acl: null, // オプション:アセンブル後のオブジェクトの ACL を設定
completeMultipartUpload: new Oss\Models\CompleteMultipartUpload(
parts: $parts
)
)
);
printf(
'状態コード:%s' . PHP_EOL .
'リクエスト ID:%s' . PHP_EOL .
'結果:%s' . PHP_EOL,
$comResult->statusCode,
$comResult->requestId,
var_export($comResult, true)
);コードを実行する前に、以下のプレースホルダーを置き換えてください。
| プレースホルダー | 説明 |
|---|---|
/Users/yourLocalPath/yourFileName | アップロードするローカルファイルの絶対パス |
--region 引数 | バケットのリージョン ID(例:cn-hangzhou |
--bucket 引数 | 対象バケットの名称 |
--key 引数 | OSS 内で割り当てるオブジェクトキー(名称) |
コールバック付きアップロード
アップロード完了後にアプリケーションサーバーに通知するには、CompleteMultipartUpload にアップロードコールバックをアタッチします。初期化およびパートアップロードのステップは、前述の基本例と同一です。完了時の呼び出しのみが異なります。
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use AlibabaCloud\Oss\V2 as Oss;
$optsdesc = [
"region" => ['help' => 'バケットが配置されているリージョン。', 'required' => True],
"endpoint" => ['help' => '他のサービスが OSS にアクセスするために使用できるドメイン名。', 'required' => False],
"bucket" => ['help' => 'バケットの名称', 'required' => True],
"key" => ['help' => 'オブジェクトの名称', 'required' => True],
];
$longopts = \array_map(function ($key) { return "$key:"; }, array_keys($optsdesc));
$options = getopt("", $longopts);
foreach ($optsdesc as $key => $value) {
if ($value['required'] === True && empty($options[$key])) {
echo "エラー:以下の引数が必要です:--$key, " . $value['help'] . PHP_EOL;
exit(1);
}
}
$region = $options["region"];
$bucket = $options["bucket"];
$key = $options["key"];
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider);
$cfg->setRegion($region);
$cfg->setEndpoint('http://oss-cn-hangzhou.aliyuncs.com');
$client = new Oss\Client($cfg);
// 初期化
$initResult = $client->initiateMultipartUpload(
new Oss\Models\InitiateMultipartUploadRequest(
bucket: $bucket,
key: $key
)
);
// パートのアップロード(基本例と同じロジック)
$bigFileName = "/Users/yourLocalPath/yourFileName";
$partSize = 5 * 1024 * 1024;
$fileSize = filesize($bigFileName);
$partsNum = intdiv($fileSize, $partSize) + intval(1);
$parts = [];
$i = 1;
$file = new \GuzzleHttp\Psr7\LazyOpenStream($bigFileName, 'rb');
while ($i <= $partsNum) {
$partResult = $client->uploadPart(
new Oss\Models\UploadPartRequest(
bucket: $bucket,
key: $key,
partNumber: $i,
uploadId: $initResult->uploadId,
contentLength: null,
contentMd5: null,
trafficLimit: null,
requestPayer: null,
body: new \GuzzleHttp\Psr7\LimitStream($file, $partSize, ($i - 1) * $partSize)
)
);
$parts[] = new Oss\Models\UploadPart(
partNumber: $i,
etag: $partResult->etag
);
$i++;
}
// コールバックペイロードの構築 — OSS はアセンブル完了後にこのペイロードをお客様のサーバーに POST します
$call_back_url = "http://www.example.com/callback"; // お客様のサーバーのエンドポイントに置き換えてください
// コールバック本文では、OSS のシステム変数({bucket}、{object})および
// callbackVar で定義したカスタム変数({x:var1}、{x:var2})を使用できます
$callback_body_template = "bucket={bucket}&object={object}&my_var_1={var1}&my_var_2={var2}";
$callback_body = str_replace(
['{bucket}', '{object}', '{var1}', '{var2}'],
[$bucket, $key, 'value1', 'value2'],
$callback_body_template
);
// callback および callbackVar は、両方とも Base64 エンコードされた JSON 形式である必要があります
$callback = base64_encode(json_encode([
"callbackUrl" => $call_back_url,
"callbackBody" => $callback_body,
]));
$callback_var = base64_encode(json_encode([
"x:var1" => "value1",
"x:var2" => "value2",
]));
// 完了 — OSS はオブジェクトのアセンブル完了後にコールバックをトリガーします
$comResult = $client->completeMultipartUpload(
new Oss\Models\CompleteMultipartUploadRequest(
bucket: $bucket,
key: $key,
uploadId: $initResult->uploadId,
acl: null,
completeMultipartUpload: new Oss\Models\CompleteMultipartUpload(
parts: $parts
),
callback: $callback,
callbackVar: $callback_var,
)
);
printf(
'状態コード:%s' . PHP_EOL .
'リクエスト ID:%s' . PHP_EOL .
'結果:%s' . PHP_EOL,
$comResult->statusCode,
$comResult->requestId,
var_export($comResult, true)
);関連ドキュメント
完全なサンプルコードについては、GitHub サンプルをご参照ください。
サポートされているすべてのリージョンおよびそのエンドポイントについては、「OSS のリージョンとエンドポイント」をご参照ください。