はじめに
この記事はAWS S3の署名付きURLをPHPで作成する方法を紹介します。
署名付きURLとは
署名付きURLは、S3のファイルに一時的に入るための通行証つきリンクです。
サーバーがこのリンクを作って渡すと、ユーザーはログイン無しで直接S3からダウンロード/アップロードできます(有効期限内だけ)。
期限が切れたら無効。第三者に渡すと使われてしまうので、短い期限にするのが基本です。
メリットは、アプリのサーバーに負荷をかけずに大きなファイルを配れる/受け取れることです。
AWS マネジメントコンソールからは以下の画面から署名付きURLを発行することができます。
それでは、PHPで署名付きURLを発行する手順を紹介します。
PHPで署名付きURLを発行する
準備するもの
- AWS SDK
- PHP
サンプルプログラム
use Aws\S3\Exception\S3Exception;
use Aws\S3\S3Client;
Class Amazon_S3
{
protected string $s3_bucket_name = "";
const MODE_READ = 'r';
const MODE_DOWNLOAD = 'o';
public function __construct($options = null)
{
$config = [
'region' => 'ap-northeast-1',
'version' => 'latest',
];
$this->s3_bucket_name = getenv('AWS_BUCKET_NAME');
$this->s3Client = new S3Client($config);
}
/**
* 署名付きのurlを取得
* @param string $object_key
* @param string $minute
* @param string $mode
* @return string
*/
public function getPreSignedUrl(string $object_key, string $minute = '5', string $mode = self::MODE_READ): string
{
try {
$s3Client = $this->s3Client;
$params = [
'Bucket' => $this->s3_bucket_name,
'Key' => $object_key
];
if ($mode === self::MODE_DOWNLOAD) {
$download_filename = basename($object_key);
// ダウンロードを強制
$disp = 'attachment';
// UTF-8 ファイル名(RFC 5987)
$disp .= "; filename*=UTF-8''" . rawurlencode($download_filename);
// 互換用(ASCII 範囲のみ有効)
$ascii = preg_match('/^[\x20-\x7E]+$/', $download_filename) ? $download_filename : 'download';
$disp .= '; filename="' . $ascii . '"';
$params['ResponseContentDisposition'] = $disp;
$params['ResponseContentType'] = 'application/octet-stream';
}
$cmd = $s3Client->getCommand('GetObject', $params);
$request = $s3Client->createPresignedRequest($cmd, '+'.$minute.' minutes');
return (string)$request->getUri();
} catch (Exception $e) {
return "";
}
}
}
このプログラムを利用すると、S3の署名付きURLを取得することができます。
第三引数$modeがMODE_READ(r)の場合もMODE_DOWNLOAD(o)の場合も、AWSマネジメントコンソールから発行した署名付きURLと同じものを発行することができます。
modeによる違いは、「一度ファイルをブラウザ上で開く必要があるか」か「そのままファイルのダウンロードを開始する」かの違いです。
容量の重いファイルを取り扱う場合は、一度ブラウザ上で開いてからダウンロードだと時間がかかってしまうので、
$modeにMODE_DOWNLOAD(o)を指定して、そのままファイルをダウンロードするやり方が向いています。
一方、画像ファイルのようなファイルをwebページに表示したいなどの場合は、$modeにMODE_READ(r)を指定する必要があります。
さいごに
CloudFrontとS3を接続してアクセスする方法もあります。
こちらは最初の手順準備が大変ですが構築したあとは簡単にファイルにアクセスができます。
どちらの方法を利用するかはご検討ください。

