0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LaravelでAzure Blob Storageのデータを取得・更新・削除する

Posted at

はじめに

この記事はAzure Blob Storageの操作方法について書いています。
LaravelのHTTPクライアントとAzure Storage REST APIを使って説明しています。

前提

  • Laravelの環境構築が済んでいる
  • Azure Blob Storageを構築が済んでいる

操作方法

取得、更新、削除でそれぞれ細かい処理の違いはありますが、大まかに次の流れになっています。

  1. 署名文字列を作成
  2. ヘッダーを作成
  3. リクエスト

署名文字列はアクセスする際に承認を得るために必要なものです。
詳しく知りたい方は下記を参照してみてください。

更新する方法について

Azure Storage REST APIPut 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への接続処理を実装した際に、署名文字列の作成がうまくいかず苦戦しました。解決する過程で色々な記事を見ましたが、同じように苦戦している方が多かったので記事にしようと思いました。

内容がほぼ同じにはなりますが、PHPcurl_setoptでもアクセス方法もそのうち書こうと思っています。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?