一部ストレージをさくらBaseStorageに移管する改修をしました。

iconDecotterで最も悩ましかったのが、ユーザーの元アイコンを保存するという性質上、
ストレージ容量がユーザーの増加に伴いひたすら増加していくところでした。

現状のVPSプランがSSDプランなこともあって、
実はストレージにあまり余裕のない状態でした。
(実質80%くらいを消費していました)

さすがにこのままでは、ということで、同じさくらインターネットで
サービス開始しそうな風味のさくらBaseStorageを利用し、
ユーザーの元アイコン画像のみをそちらに保存するような構成に改修してみることにしました。

さくらのBASE Storage | ストレージならさくらインターネット

※現時点ではβの模様

AWSのS3と互換性のあるIF、ということらしいのですが、
そもそもS3も使ったこと無い初心者でしたので、まずどうやってこのストレージサービスと
ファイルをやり取りするものなのだろうかというところからお勉強でした。

AWS SDK for PHPで、さくらBaseStorageを使う

まずS3用の便利なPHPライブラリがあるようなので、それをダウンロードしました。

AWS SDK for PHP | アマゾン ウェブ サービス(AWS 日本語)

//SDK読み込み
require_once("aws.phar");
//名前空間はこんな感じで指定
use Aws\S3\S3Client;
use Aws\Common\Enum\Region;
use Aws\S3\Exception\S3Exception;
use Guzzle\Http\EntityBody;

aws.pharをrequireするだけで色々できるようになります。

このライブラリを使い、S3Clientの生成時にパラメータでbase_urlを指定すれば
そのままさくらBaseStorageに接続出来るようです。

$client = S3Client::factory(array(
'key' =>"ユーザ名",
'secret' => "トークン",
"base_url"=>"http://b.storage.sakura.ad.jp"
)
);

ユーザー名とトークンは、さくらBaseStorageのアカウントを取得すれば管理画面で確認できます。
さくらBaseStorageに限らず、同様のREST API対応のストレージサービスであれば、
この「独自のエンドポイントの設定」で対応出来るようですね。

設定 — NIFTY Cloud SDK for PHP 2.4.7 documentation

クライアントオブジェクトを作成したら、
各種メソッドでファイルを受信したり、送信したりします。

// バケット名
$bucket = "BucketName";
// ダウンロード対象のキー(ファイル識別子)
$key = "test.jpg";

$result = $client->getObject(array(
    'Bucket' => $bucket,
    'Key' => $key
        ));

バケット名もさくらBaseStorageの管理画面でわかります。
ちなみにディレクトリは作成するという概念はないんですね。
キーに/があれば、管理画面上ではそこまでをディレクトリ扱いのように見せてくれはします。

画像を保存する

保存には、putObjectを使います。

//ファイル読み込み
$file = fopen("test.jpg",'r');
//バケットとキーを指定して保存
$result = $client->putObject(array(
	'Bucket' => $bucket,
	'Key' => $key,
	'Body' => EntityBody::factory($file),
	));

バケット名、キー名を指定し、Bodyにデータを渡します。
EntityBody::factoryに渡すのは、fopenしたファイルストリームでもOKですし、
バイナリデータでもいいみたいです。

保存出来たかどうかは管理画面から確認できます。
また、HTTP/HTTPSアクセスもできるようになります。

https://[バケット名].b.storage.sakura.ad.jp/[キー名]

URLはこんな感じになると思います。

画像を表示する

phpでデータを引き出し、画像ヘッダとデータをechoしてやれば、
さくらBaseStorage上のデータを表示できます。

普通なら、前述のようにインターネットアクセスでいいのですけど、
同じドメイン上に存在するファイルという扱いをしなくてはならない事情があるので、
そういう手法を取ってます。
(CORSの指定はさくらBaseStorageで出来るのか不明だったので現時点で考慮してません)

//バケットとキーを指定してファイル呼び出し
$result = $client->getObject(array(
	'Bucket' => $bucket,
	'Key' => $key
	));
	//ファイルサイズ
	$length = $result['ContentLength'];
	//ファイルポインタを先頭に戻し、ファイルを読み込む
	$result['Body']->rewind();
	$data = $result['Body']->read($length);
	//出力
	header('Content-Type: '.$result['ContentType']);
	echo $data;

ちなみに、存在しないキーに対してgetObjectするとPHP Fatal Errorが発生するっぽいので、
怪しい場合は事前に検索した方がいいです。

$file_name = 'test.jpg';
$test_prefix = 'test/';
//指定のPrefix以下のファイルリストを返す
$list = $client->listObjects(array(
		'Bucket' => $bucket,
		'Delimiter' => '/',
		'Prefix' => $test_prefix,
	));
//ファイルリストの中から一致するファイルを検索
if($list['Contents']){
	foreach($list['Contents'] as $k=>$v ){
		if(preg_match("/".$file_name."/i", $v['Key'])){
			$exists = true;
			break;
		}
	}

キーに「/」が含まれている場合、Prefixというパラメータで
そこで指定した「~~/」以下のファイルリストを返して貰えるので、
そのリストから該当するファイル名を検索しています。
Delimiterは必ず’/’を指定する必要があるみたいです。

まとめ

色々と勉強することが多かったですが、
非常にいい感じに稼働しているようなので安心しました。
若干CPU負荷は上がりましたが…。

もとより、Twitterのアイコン画像のサイズも底上げされていたので
従来240pxに制限していたiconDecotterもこれを期に512pxに変更しました。

※なおそれのせいか、Zopfli圧縮処理をかけるとタイムアウトエラーが出るように
 なったっぽいので、今は一旦Zopfli圧縮は経由しないようにしてます…。

これでVPSのストレージについてはあまり心配なくなりました。
不要になったファイルの掃除をそのうちやらなくてはなりませんね。

あとの心配事といえば、さくらBaseStorageが正式稼働したら
おいくらかかるのか、ということですね……。

コメント

タイトルとURLをコピーしました