はじめに
この記事はAzure Blob Storage
の操作方法について書いています。
Laravel
のHTTPクライアントとAzure Storage REST API
を使って説明しています。
前提
- Laravelの環境構築が済んでいる
- Azure Blob Storageを構築が済んでいる
操作方法
取得、更新、削除でそれぞれ細かい処理の違いはありますが、大まかに次の流れになっています。
- 署名文字列を作成
- ヘッダーを作成
- リクエスト
署名文字列はアクセスする際に承認を得るために必要なものです。
詳しく知りたい方は下記を参照してみてください。
更新する方法について
Azure Storage REST API
のPut Blob
を使います。
下記のようなコードになります。
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Http;
class AzureBlobController extends Controller
{
public function save_blob()
{
$accesskey = ''; // アクセスキーを入れてください
$storage_account = ''; // ストレージアカウント名を入れてください
$container_name = ''; // コンテナ名を入れてください
$current_date = gmdate('D, d M Y H:i:s T', time());
$file_to_upload = realpath(''); // ファイルのパスを入れてください(storage/app/public配下のファイル等)
$blob_name = ''; // Blob名を入れてください
$destination_url = "https://$storage_account.blob.core.windows.net/$container_name/$blob_name";
$handle = fopen($file_to_upload, 'r');
$file_len = filesize($file_to_upload);
$header_resource = "x-ms-blob-cache-control:max-age=3600\nx-ms-blob-type:BlockBlob\nx-ms-date:$current_date\nx-ms-version:2019-12-12";
$url_resource = "/$storage_account/$container_name/$blob_name";
$array_sign = [];
$array_sign[] = 'PUT'; /*HTTP Verb*/
$array_sign[] = ''; /*Content-Encoding*/
$array_sign[] = ''; /*Content-Language*/
$array_sign[] = $file_len; /*Content-Length (include value when zero)*/
$array_sign[] = ''; /*Content-MD5*/
$array_sign[] = 'image/plain'; /*Content-Type*/
$array_sign[] = ''; /*Date*/
$array_sign[] = ''; /*If-Modified-Since */
$array_sign[] = ''; /*If-Match*/
$array_sign[] = ''; /*If-None-Match*/
$array_sign[] = ''; /*If-Unmodified-Since*/
$array_sign[] = ''; /*Range*/
$array_sign[] = $header_resource; /*CanonicalizedHeaders*/
$array_sign[] = $url_resource; /*CanonicalizedResource*/
$str_to_sign = implode("\n", $array_sign);
$sig = base64_encode(hash_hmac('sha256', urldecode(utf8_encode($str_to_sign)), base64_decode($accesskey), true));
$auth_header = "SharedKey $storage_account:$sig";
$headers = [
'Authorization' => $auth_header,
'x-ms-blob-cache-control' => 'max-age=3600',
'x-ms-blob-type' => 'BlockBlob',
'x-ms-date' => $current_date,
'x-ms-version' => '2019-12-12',
'Content-Type' => 'image/plain',
'Content-Length' => $file_len,
];
$response = Http::withHeaders($headers)->withOptions([
'verify' => false,
])
->withBody($handle, 'image/plain')
->put($destination_url);
var_dump($response->body()); // 空文字であれば成功
}
}
}
実行後に下記のようなエラーメッセージが出力される場合は、署名文字列が正しく作成できているか、ヘッダーの内容が正しいかを確認してみてください。
<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
// 略
取得する方法について
2パターンの取得方法について説明します。1つはBlobをxml
のリストで取得するList Blobs
について、もう一つは指定したBlobを1件取得するGet Blob
についてです。
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Http;
class AzureBlobController extends Controller
{
public function get_blobs()
{
$accesskey = ''; // アクセスキーを入れてください
$storage_account = ''; // ストレージアカウント名を入れてください
$container_name = ''; // コンテナ名を入れてください
$current_date = gmdate('D, d M Y H:i:s T', time());
$destination_url = "https://$storage_account.blob.core.windows.net/$container_name?restype=container&comp=list";
$header_resource = "x-ms-date:$current_date\nx-ms-version:2023-08-03";
$url_resource = "/$storage_account/$container_name\ncomp:list\nrestype:container";
$array_sign = [];
$array_sign[] = 'GET'; /*HTTP Verb*/
$array_sign[] = ''; /*Content-Encoding*/
$array_sign[] = ''; /*Content-Language*/
$array_sign[] = ''; /*Cont ent-Length (include value when zero)*/
$array_sign[] = ''; /*Content-MD5*/
$array_sign[] = ''; /*Content-Type*/
$array_sign[] = ''; /*Date*/
$array_sign[] = ''; /*If-Modified-Since */
$array_sign[] = ''; /*If-Match*/
$array_sign[] = ''; /*If-None-Match*/
$array_sign[] = ''; /*If-Unmodified-Since*/
$array_sign[] = ''; /*Range*/
$array_sign[] = $header_resource; /*CanonicalizedHeaders*/
$array_sign[] = $url_resource; /*CanonicalizedResource*/
$str_to_sign = implode("\n", $array_sign);
$sig = base64_encode(hash_hmac('sha256', urldecode(utf8_encode($str_to_sign)), base64_decode($accesskey), true));
$auth_header = "SharedKey $storage_account:$sig";
$headers = [
'Authorization' => $auth_header,
'x-ms-date' => $current_date,
'x-ms-version' => '2023-08-03',
];
$response = Http::withHeaders($headers)->get($destination_url);
// xml文字列でレスポンスが返ってくるためオブジェクトに変換
$response_blobs = [];
$xml = simplexml_load_string($response->body());
// xmlのリストからBlob名を取り出して、1件ずつBlobを取得している
foreach ($xml->Blobs->Blob as $blob) {
$encoded_name = (string) $blob->Name;
array_push($response_blobs, $this->get_blob($encoded_name));
}
echo '<pre>';
var_dump($response_blobs); // ファイルの中身が配列に格納されていれば成功
echo '</pre>';
}
public function get_blob($blob_name)
{
$accesskey = ''; // アクセスキーを入れてください
$storage_account = ''; // ストレージアカウント名を入れてください
$container_name = ''; // コンテナ名を入れてください
$current_date = gmdate('D, d M Y H:i:s T', time());
$destination_url = "https://$storage_account.blob.core.windows.net/$container_name/$blob_name";
$blob_name_encoded = urlencode($blob_name);
$header_resource = "x-ms-date:$current_date\nx-ms-version:2023-08-03";
$url_resource = "/$storage_account/$container_name/$blob_name_encoded";
$array_sign = [];
$array_sign[] = 'GET'; /*HTTP Verb*/
$array_sign[] = ''; /*Content-Encoding*/
$array_sign[] = ''; /*Content-Language*/
$array_sign[] = ''; /*Cont ent-Length (include value when zero)*/
$array_sign[] = ''; /*Content-MD5*/
$array_sign[] = ''; /*Content-Type*/
$array_sign[] = ''; /*Date*/
$array_sign[] = ''; /*If-Modified-Since */
$array_sign[] = ''; /*If-Match*/
$array_sign[] = ''; /*If-None-Match*/
$array_sign[] = ''; /*If-Unmodified-Since*/
$array_sign[] = ''; /*Range*/
$array_sign[] = $header_resource; /*CanonicalizedHeaders*/
$array_sign[] = $url_resource; /*CanonicalizedResource*/
$str_to_sign = implode("\n", $array_sign);
$sig = base64_encode(hash_hmac('sha256', urldecode(utf8_encode($str_to_sign)), base64_decode($accesskey), true));
$auth_header = "SharedKey $storage_account:$sig";
$headers = [
'Authorization' => $auth_header,
'x-ms-date' => $current_date,
'x-ms-version' => '2023-08-03',
];
$response = Http::withHeaders($headers)->get($destination_url);
return $response->body();
}
}
削除する方法について
最後に削除する方法について、こちらはDelete Blob
を使用します。
下記のようなコードになります。
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Http;
class AzureBlobController extends Controller
{
public function delete_blob()
{
$blob_name = ''; // 削除したいBlob名を入れてください
$accesskey = ''; // アクセスキーを入れてください
$storage_account = ''; // ストレージアカウント名を入れてください
$container_name = ''; // コンテナ名を入れてください
$current_date = gmdate('D, d M Y H:i:s T', time());
$destination_url = "https://$storage_account.blob.core.windows.net/$container_name/$blob_name";
$blob_name_encoded = urlencode($blob_name);
$header_resource = "x-ms-date:$current_date\nx-ms-version:2023-08-03";
$url_resource = "/$storage_account/$container_name/$blob_name_encoded";
$array_sign = [];
$array_sign[] = 'DELETE'; /*HTTP Verb*/
$array_sign[] = ''; /*Content-Encoding*/
$array_sign[] = ''; /*Content-Language*/
$array_sign[] = ''; /*Cont ent-Length (include value when zero)*/
$array_sign[] = ''; /*Content-MD5*/
$array_sign[] = ''; /*Content-Type*/
$array_sign[] = ''; /*Date*/
$array_sign[] = ''; /*If-Modified-Since */
$array_sign[] = ''; /*If-Match*/
$array_sign[] = ''; /*If-None-Match*/
$array_sign[] = ''; /*If-Unmodified-Since*/
$array_sign[] = ''; /*Range*/
$array_sign[] = $header_resource; /*CanonicalizedHeaders*/
$array_sign[] = $url_resource; /*CanonicalizedResource*/
$str_to_sign = implode("\n", $array_sign);
$sig = base64_encode(hash_hmac('sha256', urldecode(utf8_encode($str_to_sign)), base64_decode($accesskey), true));
$auth_header = "SharedKey $storage_account:$sig";
$headers = [
'Authorization' => $auth_header,
'x-ms-date' => $current_date,
'x-ms-version' => '2023-08-03',
];
$response = Http::withHeaders($headers)->delete($destination_url);
var_dump($response->body()); // 空文字であれば成功
}
}
終わりに
ここまで見ていただきありがとうございました。
Azure Blob Storage
への接続処理を実装した際に、署名文字列の作成がうまくいかず苦戦しました。解決する過程で色々な記事を見ましたが、同じように苦戦している方が多かったので記事にしようと思いました。
内容がほぼ同じにはなりますが、PHP
のcurl_setopt
でもアクセス方法もそのうち書こうと思っています。
参考