AWS SDK for PHP を使って画像アップロードをサクッと実装する

この記事は [PHP Advent Calendar 2021](https://qiita.com/advent-calendar/2021/php) 16日目の記事です。

15日目の記事は[@opy](https://qiita.com/opy)さん投稿の [PHPによる疑似的なイミュータブルとムーブセマンティクスモドキ](https://qiita.com/opy/items/f6cf96b2c0b62ab4f9a9)  、
17日目の記事は[@iamyukihiro](https://qiita.com/iamyukihiro)さん投稿の[私用のLinuxサーバーに、PHPのビルトインサーバーをデプロイした話](https://tech.quartetcom.co.jp/2021/12/17/built-in-server-deployment/)です。

# 本記事の概要

[AWS SDK for PHP](https://aws.amazon.com/jp/sdk-for-php/) を用いて **S3 の指定バケットへ画像アップロード**をできるようにします。

- AWS アカウント

を所持している前提で進めていきます。

# 1. 導入

今回使用するライブラリを導入します。

## AWS SDK for PHP の導入

参考：[Installing the AWS SDK for PHP Version 3 - AWS SDK for PHP](https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/getting-started_installation.html)

導入方法はいくつかありますが、今回はオーソドックスに [Composer](https://getcomposer.org/) を使います。

やり方は簡単で、プロジェクトのベースディレクトリ内で

```shell
composer require aws/aws-sdk-php
```

コマンドを実行するだけです。
実行後、

```shell
composer show -i
```

等で表示されるパッケージ一覧の中に `aws/aws-sdk-php` が追加されていれば成功です。

## phpdotenv の導入

環境変数設定のライブラリです。
後述するコードにて、[phpdotenv](https://github.com/vlucas/phpdotenv) を使用しているので、
未導入の方は

```shell
composer require vlucas/phpdotenv
```

にてライブラリ追加をしてください。

# 2. S3 にバケットを作る

バケットを作成します。
AWS マネジメントコンソールログイン後、S3を開き、バケット作成をします。

![s3設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218217/69f6ebd5-c9f0-bf4d-dc9f-5507a62b3bbe.png)

ここではバケット名を `php-advent2021-sdk-upload` としています。
**一意な名前が必要**なので「被っているよ！！」と怒られたら、別の名前を設定しましょう。

リージョンは何処でも大丈夫ですが、**どのリージョンを設定したか**覚えておいて下さい。

その他設定はデフォルトで大丈夫です。

確認ができたら作成しましょう。

# 3. AWS にアクセスするための鍵情報を取得

参考：[IAM ユーザーのアクセスキーの管理 - AWS Identity and Access Management](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_access-keys.html)

S3 に接続できるようにするため、

- **アクセスキー ID**
- **シークレットアクセスキー**

の2つが必要です。

セキュリティ認証情報画面を開き、**アクセスキー (アクセスキー ID とシークレットアクセスキー)**セクションを開きます。

![アクセスキーセクション](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218217/3d63ade3-9e5e-497f-70fd-7adb49b1b21c.png)

**新しいアクセスキーの作成**を行った後、キーファイルのダウンロードをします。

![mac-ss 2021-12-16 11.33.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218217/44e26e53-a7f2-462d-c699-c5efab726218.png)

`rootkey.csv` というファイルがダウンロードできるので、
ファイルを開いて**アクセスキー ID**と**シークレットアクセスキー**情報を確認しましょう。

## env ファイルの作成

上記のアクセス情報を記述した `.env` ファイルを作成し、プロジェクトのディレクトリ内に配置しておきましょう。

```env
AWS_ACCESS_KEY_ID="XXXXXXXXXXXXXXXXXXXX"
AWS_SECRET_ACCESS_KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
```

`AWS_ACCESS_KEY_ID` に **アクセスキー ID**
`AWS_SECRET_ACCESS_KEY` に **シークレットアクセスキー**
の情報を記述します。

# 4. 実装

参考：[Creating and Using Amazon S3 Buckets with the AWS SDK for PHP Version 3 - AWS SDK for PHP](https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-examples-creating-buckets.html)

以下、実際のコードです。


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

use Aws\S3\Exception\S3Exception;
use Aws\S3\S3Client;

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();

function main()
{
    $credentials = [
        'key'    => $_ENV['AWS_ACCESS_KEY_ID'],
        'secret' => $_ENV['AWS_SECRET_ACCESS_KEY'],
    ];

    $bucket        = 'php-advent2021-sdk-upload';
    $srcFilePath   = 'ソースファイルのディレクトリパスをここに記述';
    $extension     = pathinfo($srcFilePath, PATHINFO_EXTENSION);
    $key           = 'test' . '.' . $extension;

    try {
        $s3Client = new S3Client([
            'region'      => 'ap-northeast-1',
            'version'     => '2006-03-01',
            'credentials' => $credentials,
        ]);
        $result = $s3Client->putObject([
            'Bucket'     => $bucket,
            'Key'        => $key,
            'SourceFile' => $srcFilePath,
        ]);
    } catch (S3Exception $e) {
        echo $e->getMessage() . "\n";
    }

}

main();
```

**`$bucket` には自身で作成したバケット名**、
**`$srcFilePath` にはアップロードしたい画像ファイルのディレクトリパス**を記述してください。

### 解説

必須のコードブロックは2つです。

#### S3 への接続

```php
$s3Client = new S3Client([
  'region'      => 'ap-northeast-1',
  'version'     => '2006-03-01',
  'credentials' => $credentials,
]);
```

`region`　は**バケットを生成したリージョン**を記述します。
`version` ではバージョン指定をします。バージョニング設定を有効化している場合以外はこのままで大丈夫です。
`credentials` には **アクセスキー ID と シークレットアクセスキー** を入れます。


#### S3 バケットへのアップロード

```php
$result = $s3Client->putObject([
  'Bucket'     => $bucket,
  'Key'        => $key,
  'SourceFile' => $srcFilePath,
]);
```

`Bucket` には**アップロードするバケット名**を記述します。

`Key` は**バケット以下のファイルパス及びファイル名**を設定します。
そのままでは拡張子なしのファイルがアップロードされてしまうので、 **pathinfo で拡張子を取得し `$extension` に格納**するようにしています。

`SourceFile` には**アップロードするファイルの絶対パス**を指定します。

---

実行すると、S3のバケットへ画像がアップロードされました。

![s3アップロード確認](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218217/a21c3413-2508-fe2b-607a-e6fae83998c5.png)

# まとめ

本記事のコードを応用すれば
**「クライアントから画像のパスが POST されたらアップロードする」**ような API も実現出来るので
是非活用してみてください。

ちなみに、この設定のままでは**アップロードした画像をブラウザで確認することができません**。
S3 バケットの**「ブロックパブリックアクセス設定」を適切に設定する**必要がありますのでご注意ください。
（デフォルトではパブリックアクセスがブロックされます）

画像の確認に関しては**読み取り専用アクセス許可**を付与すれば大丈夫です。

※要望が多ければこの辺りについて詳しくまとめようと思います。

### アクセス設定の参考：
- [バケットポリシーの例「匿名ユーザーへの読み取り専用アクセス許可の付与」 - Amazon Simple Storage Service](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/example-bucket-policies.html#example-bucket-policies-use-case-2)
- [Amazon S3: S3 バケットのオブジェクトへの読み取りおよび書き込みアクセスを許可する - AWS Identity and Access Management](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_examples_s3_rw-bucket.html)