さくらのオブジェクトストレージに画像を格納する機会があり、WebAPIとかで簡単にアップロードできるんだろうなと思っていたらめちゃくちゃ苦戦したので、忘れないうちに動くソースを記事に残しておきます。
さくらのオブジェクトストレージは、Amazon S3互換APIで提供されているとのことで、通常ならAmazon S3をサポートするクライアント導入すればそのまま動くんだと思います。
自分の場合、AWS関連の知識が皆無だったのと、今回は画像アップロードしか使わないつもりだったので、そのためにS3クライアントについて調べたりするより、一個リクエスト投げる処理書いちゃったほうが速いのでは?と思ってCurlで書くことにしました。
多分それが、急がばなんとやらでした。
まずS3互換APIって言うけどS3 APIのドキュメントどこにあるの??ってところから躓く。。
結局見つけられなかったので、同じことをやろうとしている人の記事をかろうじていくつか見つけ、参考にリクエスト組み立ててみることに。
リクエスト内容に署名してヘッダに添付するタイプのAPIなのですが、これを自分で組み立てるのが中々難しく苦戦。
例えば公開設定でアップロードするためのこのヘッダx-amz-acl:public-read
、普段HTTPリクエストヘッダ書くノリで:
の後にスペース入れただけで受け付けてもらえなくなりました。
他にも色々詰まった気がするのですが、とりあえず動くソースをそのまま残しておきます。
$endpoint = 'https://s3.isk01.sakurastorage.jp'; // 固定
$accessKeyId = 'xxxxx';
$accessKeyToken = 'xxxxx';
$bucketName = 'xxxxx';
$fileName = 'xxxxx.jpg';
$method = 'PUT';
$contentType = 'image/jpeg';
$content = file_get_contents('path to file');
$md5Content = base64_encode(md5($content, true));
$date = gmdate(\DateTime::RFC2822);
$resource = '/'.$bucketName.'/'.$fileName;
$aclHeader = 'x-amz-acl:public-read'; // 公開設定でアップロード
// リクエスト内容に署名してヘッダに含める
$stringToSign = $method."\n".$md5Content."\n".$contentType."\n".$date."\n".$aclHeader."\n".$resource;
$signature = base64_encode(hash_hmac('sha1', $stringToSign, $accessKeyToken, true));
$auth = 'AWS '.$accessKeyId.':'.$signature;
$headers = [
'Date: '.$date,
'Content-Type: '.$contentType,
'Content-MD5: '.$md5Content,
'Content-Length: '.strlen($content),
'Authorization: '.$auth,
$aclHeader
];
// Curlでリクエスト
$options = [
CURLOPT_URL => $endpoint.$resource,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POSTFIELDS => $content
];
$ch = curl_init();
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
curl_close($ch);