AWS SDK for PHP v3 の ObjectUploader の使い方としきい値
AWS SDK for PHP にはファイルアップロードのための ObjectUploader
メソッドがあって、ファイルサイズによって最適なアップロード方法で処理してくれる。
自分が携わっている開発中の Web アプリでは、 ( S3 へ) 小さなファイルも大きなサイズのファイルもアップロードされるので、 ObjectUploader
を使ってみた。また、アップロード方法が切り替わる境界となるファイルサイズ (しきい値) を調べた。
ObjectUploader とは
AWS SDK for PHP には、 5 GB までのファイルをアップロードできる PutObject
と、大容量ファイルをアップロードするための MultipartUploader
メソッドが用意されている。
ObjectUploader
は、アップロードされたファイルサイズによって、 PutObject
と MultipartUploader
のどっちを使うか選んで処理してくれるというもの。
PutObject または MultipartUploader がタスクに最適かどうかが不明な場合は、ObjectUploader を使用します。ObjectUploader は、ペイロードサイズに基づいてどれが最適かにより、PutObject または MultipartUploader を使用して大きなファイルを Amazon S3 にアップロードします。
AWS SDK for PHP バージョン 3 での Amazon S3 マルチパートアップロードの使用 より
PutObject
は 5 GB までのファイルが扱えるとあるが、公式ドキュメントには以下の記述があるため、 100 MB 以上のファイルがアップロードされるなら ObjectUploader
を使った方がいいと判断した。
(大きいサイズのファイルしかアップロードされないのであれば、 MultipartUploader
だけ使えばいいと思う。)
Amazon S3 のユーザーには、100 MB を超えるオブジェクトに対してマルチパートアップロードを使用することをお勧めします。
ObjectUploader でファイルアップロードする方法
アップロード処理は ファイルアップロードの例外処理はこれぐらいしないと気が済まない を参照。
コード
require 'vendor/autoload.php';
use Aws\S3\Exception\S3Exception;
use Aws\S3\S3Client;
use Aws\S3\ObjectUploader;
$s3Client = new S3Client([
'version' => 'latest',
'region' => 'your-region'
]);
$bucket = 'your-bucket';
try {
if (!isset($_FILES['upfile']['error']) || !is_int($_FILES['upfile']['error'])) {
throw new RuntimeException('パラメータが不正です');
}
switch ($_FILES['upfile']['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
throw new RuntimeException('ファイルが選択されていません');
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new RuntimeException('ファイルサイズが大きすぎます');
default:
throw new RuntimeException('その他のエラーが発生しました');
}
// 1 GB まで
if ($_FILES['upfile']['size'] > 1073741825) {
throw new RuntimeException('ファイルサイズが大きすぎます');
}
$filename = $_FILES['upfile']['name'];
$minetype = mime_content_type($_FILES['upfile']['tmp_name']);
// Using stream instead of file path
$source = fopen($_FILES['upfile']['tmp_name'], 'rb');
try {
$uploader = new ObjectUploader(
$s3Client,
$bucket,
$filename,
$source,
'private',
array('params' => array('ContentType' => $minetype))
);
do {
try {
$result = $uploader->upload();
if ($result["@metadata"]["statusCode"] == '200') {
print('ファイルアップロード成功. アップロード先 : ' . $result["ObjectURL"] . '.
');
}
} catch (MultipartUploadException $e) {
rewind($source);
$uploader = new MultipartUploader($s3Client, $source, [
'state' => $e->getState(),
]);
}
} while (!isset($result));
} catch (S3Exception $e) {
echo $e->getMessage();
}
} catch (RuntimeException $e) {
echo $e->getMessage();
}
解説
ObjectUploader()
の引数に渡すもの
第一引数 : S3 インスタンス
第二引数 : バケット名
第三引数 : オブジェクトキー名(ファイル名)
第四引数 : ファイルデータ
第五引数 : アクセスコントロールリスト ( ACL ) [デフォルト: private ] 省略可
第六引数 : オプション(設定値) 省略可
ここでは、第六引数で、 Content-Type
を指定している。
Content-Type
を指定しないでファイルアップロードすると、 Content-Type
は application/octet-stream
となっていた。
( Content-Type
e は、 AWS S3 管理画面から対象のオブジェクト画面にいき、「プロパティ」→「メタデータ」で確認できる。)
Content-Type
を指定した場合、
xlsx ファイルだと、 Content-Type
は application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
docx は、 application/vnd.openxmlformats-officedocument.wordprocessingml.document
となっていた。
しきい値( Threshold )について
ObjectUploader
を使った場合、どのくらいのファイルサイズなら MultipartUploader
が選択されるのか?
デフォルトでは 16777216 Byte
( 16 MB )がしきい値になっている。
( 100 MB 以上ならマルチパートアップロード推奨だけど、ここでの閾値は全然小さいんだな。。。)
ObjectUploader.php を少しいじって、 15 MB と 16 MB のファイルをアップロードして PutObject
と MultipartUploader
のどちらが使われるのか確かめた。
アップロードファイル作成 ( Mac )
$ mkfile 15m test15m.txt
$ mkfile 16m test16m.txt
aws-sdk-php/src/S3/ObjectUploader.php
echo させてみた。
public function promise()
{
/** @var int $mup_threshold */
$mup_threshold = $this->options['mup_threshold'];
if ($this->requiresMultipart($this->body, $mup_threshold)) {
// ココ
echo "
Perform a multipart upload. size:".$this->body->getSize();
// Perform a multipart upload.
return (new MultipartUploader($this->client, $this->body, [
'bucket' => $this->bucket,
'key' => $this->key,
'acl' => $this->acl
] + $this->options))->promise();
}
// Perform a regular PutObject operation.
$command = $this->client->getCommand('PutObject', [
'Bucket' => $this->bucket,
'Key' => $this->key,
'Body' => $this->body,
'ACL' => $this->acl,
] + $this->options['params']);
if (is_callable($this->options['before_upload'])) {
$this->options['before_upload']($command);
}
// ココ
echo "
Perform a regular PutObject operation. size:".$this->body->getSize();
return $this->client->executeAsync($command);
}
結果
test15m.txt をアップロード Perform a regular PutObject operation. size:15728640 test16m.txt をアップロード Perform a multipart upload. size:16777216
15MB のファイルは PutObject
が使われ、 16 MB のファイルは MultipartUploader
が使われた。
しきい値を変更
ObjectUploader
のインスタンス作成時に、第六引数の $options
の mup_threshold
パラメータでしきい値を指定できる。
しきい値を 31 MB
( 32505856 Byte) に設定して、 30 MB と 31 MB のファイルをアップロードする。
$uploader = new ObjectUploader(
$s3Client,
$bucket,
$filename,
$source,
'private',
array('mup_threshold' => 32505856, 'params' => array('ContentType' => $minetype))
);
結果
test30m.txt をアップロード Perform a regular PutObject operation. size:31457280 test31m.txt をアップロード Perform a multipart upload. size:32505856
しきい値が変更され、 31 MB 以上のファイルをアップロードすると、 MultipartUploader
が使われる。