【PHP】BlobSharedAccessSignatureHelper::generateBlobServiceSharedAccessSignatureToken()の解説

[BlobSharedAccessSignatureHelper::generateBlobServiceSharedAccessSignatureToken()](https://github.com/Azure/azure-storage-blob-php/blob/v1.5.4/src/Blob/BlobSharedAccessSignatureHelper.php#L87)の使い方がわからなくて死にそうだったので調査した結果です。

# そもそも何これ？

[Azure Storage BLOB](https://learn.microsoft.com/ja-jp/azure/storage/blobs/storage-blobs-overview)にアクセスするための[SAS](https://learn.microsoft.com/ja-jp/azure/storage/common/storage-sas-overview)を発行する関数です。
有効期限などを好きに決められるので、1時間だけ見せたいみたいなことが簡単にできます。


# BlobSharedAccessSignatureHelper::generateBlobServiceSharedAccessSignatureToken()

```php:シグネチャ
    public function generateBlobServiceSharedAccessSignatureToken(
        string $signedResource,
        string $resourceName,
        string $signedPermissions,
        \Datetime|string $signedExpiry,
        \Datetime|string $signedStart = "",
        string $signedIP = "",
        string $signedProtocol = "",
        string $signedIdentifier = "",
        string $cacheControl = "",
        string $contentDisposition = "",
        string $contentEncoding = "",
        string $contentLanguage = "",
        string $contentType = ""
    )
    {}
```

## $signedResource

`Resources::RESOURCE_TYPE_CONTAINER`もしくは`Resources::RESOURCE_TYPE_BLOB`のいずれか。

`Resources::RESOURCE_TYPE_CONTAINER`だとコンテナ単位の許可を与える。
`Resources::RESOURCE_TYPE_BLOB`だとBLOB単位の許可を与える。


## $resourceName

`RESOURCE_TYPE_CONTAINER`の場合はコンテナ名。
`foo`とか`bar`とか。

`RESOURCE_TYPE_BLOB`の場合はフルパス。
`foo/path/to/image.png`みたいになる。


## $signedPermissions

`RESOURCE_TYPE_CONTAINER`の場合は`racwdl`のいずれか1文字。
`RESOURCE_TYPE_BLOB`の場合は`racwd`のいずれか1文字。

rは読み取りのみ。
a・c・wはadd・create・writeで書き込み権限。
それぞれできることが違うみたいだけどよくわからない。
dは削除できる。
lはBLOBの一覧を取得する場合。


## $signedExpiry

SASの有効期限。UTC。
文字列の場合は'Y-m-d\TH:i:s\Z'とかいうよくわからない形式でないと動かないので、DateTimeで渡した方が安全。
DateTimeImmutableは渡せない。

ここまで必須。


## $signedStart

SASが有効になる時刻。UTC。
明日から有効にしたいとかの場合に指定する。


## $signedIP

リクエスト元のIPアドレスを限定したいときに指定する。


## $signedProtocol

値は'https'か'https,http'のどちらかだけ。
[デフォルトは'https,http'と書いてある](https://learn.microsoft.com/en-us/rest/api/storageservices/create-service-sas)のだが、未指定でhttpアクセスしてみたら`The account being accessed does not support http`って言われたのでよくわからない。


## $signedIdentifier

64文字以内の文字列。

BLOBに対して[さらに別のアクセス制限を追加](https://learn.microsoft.com/ja-jp/rest/api/storageservices/define-stored-access-policy)することができ、そのアクセスポリシーIDが一致しないとアクセスできない。

ということらしいのだが、使ったことがないのでよくわからない。
どうもコンテナ単位でしか設定できないっぽい？


## $cacheControl

BLOBにリクエストした際に返されるレスポンスにおいて、HTTPヘッダフィールド[Cache-Control](https://developer.mozilla.org/docs/Web/HTTP/Headers/Cache-Control)を変更したい場合に指定する。

## $contentDisposition

BLOBにリクエストした際に返されるレスポンスにおいて、HTTPヘッダフィールド[Content-Disposition](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Disposition)を変更したい場合に指定する。

## $contentEncoding

BLOBにリクエストした際に返されるレスポンスにおいて、HTTPヘッダフィールド[Content-Encoding](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Encoding)を変更したい場合に指定する。

## $contentLanguage

BLOBにリクエストした際に返されるレスポンスにおいて、HTTPヘッダフィールド[Content-Language](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Language)を変更したい場合に指定する。

## $contentType

BLOBにリクエストした際に返されるレスポンスにおいて、HTTPヘッダフィールド[Content-Type](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Type)を変更したい場合に指定する。

# 使い方

```php
$sas = (new BlobSharedAccessSignatureHelper())->generateBlobServiceSharedAccessSignatureToken(
    Resources::RESOURCE_TYPE_CONTAINER,
    'samplecontainer',
    'r',
    new \DateTime('+1 hour'),
);
$url = 'https://example.blob.core.windows.net/samplecontainer/foo/bar/image.png?' . $sas;

echo "<img src='{$url}'>";
```


# 感想

とてもつらい。

とはいえ昔は`BlobSharedAccessSignatureHelper::generateBlobServiceSharedAccessSignatureToken()`自体が存在しておらず、自力でSASを実装しようとして死んだことがあるので、そのころに比べたらだいぶマシです。

ちなみに死んだ理由ですが[公式ドキュメント](https://learn.microsoft.com/ja-jp/rest/api/storageservices/service-sas-examples)が嘘っぱちであり、seが`2023-01-01T00:00:00Z`とかいう形でないと駄目なんですよね。
そんなもんわかるか。

なお、[Microsoft Azure Storage PHP Client Libraries](https://github.com/azure/azure-storage-php)は[既に死んだ](https://aka.ms/AzStoragePHPSDKRetirement)ので、今後は[Azure-OSS Storage PHP Client Libraries](https://github.com/Azure-OSS/azure-storage-php)などを使うとよいでしょう。
まあAzureかつPHPのコミュニティなんてどのくらい続くか怪しいものですが。
そもそもこれが必要な人って世界に10人くらいでは？