phpでlocalstackのs3にファイルをアップロード

AWS周りのものをローカルで開発する場合 localstack を使うと便利だというのを聞いたので試してみました。

github.com

localstackは、GUIはあまり提供されていない用で、主にawscliコマンドを使います。
s3にファイルをアップロードしたい場合は、 --endpoint-url=http://localhost:4572 を付けてあげてアップロード先を変えることができます。

試しに awscli で test というバケットを作ってファイルをアップロードしてみます。

$ aws --endpoint-url=http://localhost:4572 s3 mb s3://test
make_bucket: test
$ aws --endpoint-url=http://localhost:4572 s3 ls s3://
2006-02-04 01:45:09 test
$ touch hoge.txt
$ aws --endpoint-url=http://localhost:4572 s3 cp hoge.txt s3://test/hoge.txt
upload: ./hoge.txt to s3://test/hoge.txt
$ aws --endpoint-url=http://localhost:4572 s3 ls s3://test/
2017-12-08 20:00:00          0 hoge.txt

localstack上のs3にファイルがアップロードされていることが確認できます。

phpを使ってlocalstackのs3にファイルをアップロードしてみます。
awscliのときと同様に、endpointを localstack のs3用エンドポイントを指定してみます。
aws-sdk-php は composer を使って入れてます。

put.php

<?php
require_once 'vendor/autoload.php';
use Aws\S3\S3Client as S3Client;

$s3 = S3Client::factory(array(
    'endpoint' => 'http://localhost:4572',
    'credentials' => array(
        'key' => '',
        'secret' => '',
    ),
    'version' => 'latest'
));
$pamans = array(
    'Bucket' => 'test',
    'Key' => 'hello.txt',
    'Body' => 'Hello World',
    'CacheControl' => 'max-age=1',
);
$s3->putObject($pamans);

実行してみるとエラーが出ます。

Could not resolve host: test.localhost [url] http://test.localhost:4572/hello.txt

hostsが解決できないようなので、/etc/hosts

127.0.0.1 test.localhost

を追記します。

再度実行してみるとエラーが出ずに終了し、ファイルが作られていることが確認できました。

$ php put.php
$ aws --endpoint-url=http://localhost:4572 s3 ls s3://test/
2017-12-08 21:00:00         11 hello.txt

javascriptやgoを使う方法を参考にしていると

  • s3ForcePathStyle
  • endpoint

のオプションを設定してあげればいいと出るのですが、 aws-sdk-php には s3ForcePathStyle というオプションが無いです。
s3ForcePathStyle というオプションを設定しないでアップロードしようとすると、先ほどのエラーにも出てましたが、s3バケット名.localhost:4572 となり、hostsが解決できなくなってしまいます。

php と localstack を使って開発したい場合は hosts を書いてあげて localstack が提供する各URLを指定してあげないといけなさそうです。

追記

コメントで指摘頂いた通り、PHPでは use_path_style_endpoint があり、そちらのオプションを有効にすることで hosts を設定すること無くテストすることができました。
id:imunew さん、ご指摘ありがとうございます。

put.php を下記の様に 'use_path_style_endpoint' => true とオプションを追加することでhostsの設定をすることなくテストが可能になりました。

<?php
require_once 'vendor/autoload.php';
use Aws\S3\S3Client as S3Client;

$s3 = S3Client::factory(array(
    'endpoint' => 'http://localhost:4572',
    'credentials' => array(
        'key' => '',
        'secret' => '',
    ),
    'version' => 'latest',
    'use_path_style_endpoint' => true
));
$pamans = array(
    'Bucket' => 'test',
    'Key' => 'hello.txt',
    'Body' => 'Hello World',
    'CacheControl' => 'max-age=1',
);
$s3->putObject($pamans);

参考

Testable Lambda: Working Effectively with Legacy Lambda // Speaker Deck

Testable Lambda|AWS Summit Tokyo 2017 - YouTube

LaravelでS3への画像アップロードをLocalStackを使って開発 - Qiita

S3互換のストレージソフトMinioを試してみる | モテモテテクノロジーブログ