フォームアップロードを使用すると、Web アプリケーションから標準の HTML フォームを使用して、オブジェクトを Object Storage Service (OSS) に直接アップロードできます。 このトピックでは、PHP 2.0 用 OSS SDK を使用して署名やアップロードポリシーなどの情報を生成し、HTTP Post メソッドを使用してオブジェクトを OSS にアップロードする方法について説明します。
注意事項
このトピックのサンプルコードでは、中国 (杭州) リージョンのリージョン ID
cn-hangzhou
を使用しています。 デフォルトでは、バケット内のリソースにアクセスするためにパブリックエンドポイントが使用されます。 同じリージョン内の他の Alibaba Cloud サービスからバケット内のリソースにアクセスする場合は、内部エンドポイントを使用します。 サポートされているリージョンとエンドポイントの詳細については、「OSS のリージョンとエンドポイント」をご参照ください。フォームアップロードを使用してアップロードするオブジェクトのサイズは 5 GB を超えることはできません。
このトピックでは、アクセス認証情報は環境変数から取得されます。 詳細な手順については、「PHP でアクセス認証情報を構成する」をご参照ください。
サンプルコード
次のサンプルコードは、フォームアップロードを実行する方法を示しています。 フォームアップロードの完全なプロセスは、次の手順で構成されます。
ポストポリシー を作成する 投稿ポリシー: アップロードリクエストの有効期間と条件を指定します。これには、バケット名、署名バージョン、認証情報、リクエスト日付、リクエスト本文の長さの範囲などが含まれます。
アップロードポリシーを処理する: アップロードポリシーを JSON 文字列に変換し、文字列を Base64 エンコードします。
署名キーを生成する: HMAC-SHA256 アルゴリズムを使用して、日付、リージョン、サービス、リクエストタイプを含む署名キーを生成します。
署名を計算する: 生成されたキーを使用して Base64 エンコードされたポリシー文字列に署名し、署名を 16 進数文字列に変換します。
リクエスト本文を構築する: multipart フォームライターを作成し、オブジェクトキー、ポリシー、署名バージョン、認証情報、リクエスト日付、署名をフォームで指定し、アップロードするデータをフォームに書き込みます。
リクエストを作成して実行する: HTTP POST リクエストを作成し、リクエストヘッダーを指定します。 リクエストを送信し、応答状態コードをチェックして、リクエストが成功したことを確認します。
<?php
// 依存関係を読み込むために、オートロードファイルを含めます。
require_once __DIR__ . '/../vendor/autoload.php';
use AlibabaCloud\Oss\V2 as Oss;
// コマンドラインパラメータを定義し、記述します。
$optsdesc = [
"region" => ['help' => 'バケットが配置されているリージョン。', 'required' => True], // (必須) バケットが配置されているリージョン。
"bucket" => ['help' => 'バケットの名前', 'required' => True], // (必須) バケット名。
"key" => ['help' => 'オブジェクトの名前', 'required' => True], // (必須) オブジェクト名。
];
// getopt で必要な長いオプションのリストに説明を変換します。
// 各パラメータの末尾にコロン (:) を追加して、値が必要であることを示します。
$longopts = \array_map(function ($key) {
return "$key:";
}, array_keys($optsdesc));
// コマンドラインパラメータを解析します。
$options = getopt("", $longopts);
// 必要なパラメータが構成されているかどうかを確認します。
foreach ($optsdesc as $key => $value) {
if ($value['required'] === True && empty($options[$key])) {
$help = $value['help']; // パラメータのヘルプ情報を取得します。
echo "Error: the following arguments are required: --$key, $help" . PHP_EOL;
exit(1); // 必要なパラメータがない場合はプログラムを終了します
}
}
// 解析されたパラメータから値を抽出します
$region = $options["region"]; // バケットが配置されているリージョン
$bucket = $options["bucket"]; // バケット名
$key = $options["key"]; // オブジェクト名
$product = 'oss'; // OSS サービスとして固定
// 環境変数から認証情報を読み込みます
// EnvironmentVariableCredentialsProvider を使用して、環境変数からアクセスキー ID とアクセスキーシークレットを読み取ります
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
$cred = $credentialsProvider->getCredentials();
// アップロードされるデータコンテンツ
$data = 'hi oss'; // サンプルデータ。実際の使用では他のコンテンツに置き換えることができます
// 現在の UTC 時刻を取得してフォーマットします
$utcTime = new DateTime('now', new DateTimeZone('UTC'));
$date = $utcTime->format('Ymd'); // 現在の日付。署名の計算に使用されます
$expiration = clone $utcTime;
$expiration->add(new DateInterval('PT1H')); // 有効期限を 1 時間後に設定します
// ポリシードキュメントを構築します
$policyMap = [
"expiration" => $expiration->format('Y-m-d\TH:i:s.000\Z'), // ポリシーの有効期限
"conditions" => [
["bucket" => $bucket], // バケット名を指定します
["x-oss-signature-version" => "OSS4-HMAC-SHA256"], // 署名バージョン
["x-oss-credential" => sprintf("%s/%s/%s/%s/aliyun_v4_request",
$cred->getAccessKeyId(), $date, $region, $product)], // 認証情報
["x-oss-date" => $utcTime->format('Ymd\THis\Z')], // 現在のタイムスタンプ
// その他の条件
["content-length-range", 1, 1024], // ファイルサイズ範囲の制限
// ["eq", "$success_action_status", "201"], // オプション: 成功状態コードを指定します
// ["starts-with", "$key", "user/eric/"], // オプション: オブジェクトキープレフィックスを指定します
// ["in", "$content-type", ["image/jpg", "image/png"]], // オプション: 許可されるコンテンツタイプを指定します
// ["not-in", "$cache-control", ["no-cache"]], // オプション: 特定のキャッシュコントロールヘッダーを除外します
],
];
// ポリシードキュメントを JSON 文字列としてエンコードします
$jsonOptions = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; // スラッシュと Unicode 文字のエスケープを防ぎます
$policy = json_encode($policyMap, $jsonOptions);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log("json_encode fail, err: " . json_last_error_msg()); // JSON エンコードが失敗したかどうかを確認します
exit(1);
}
// 署名に必要な情報を計算します
$stringToSign = base64_encode($policy); // ポリシーを Base64 エンコードします
$signingKey = "aliyun_v4" . $cred->getAccessKeySecret(); // 署名キーを構築します
$h1Key = hmacSign($signingKey, $date); // ステップ 1: 日付に署名します
$h2Key = hmacSign($h1Key, $region); // ステップ 2: リージョンに署名します
$h3Key = hmacSign($h2Key, $product); // ステップ 3: プロダクトに署名します
$h4Key = hmacSign($h2Key, "aliyun_v4_request"); // ステップ 4: リクエストに署名します
// 最終的な署名を計算します
$signature = hash_hmac('sha256', $stringToSign, $h4Key);
// POST リクエストのフォームデータを構築します
$bodyWriter = new CURLFileUpload(); // フォームビルダーインスタンスを作成します
// フォームにフィールドを追加します
$bodyWriter->addField('key', $key); // オブジェクト名
$bodyWriter->addField('policy', $stringToSign); // Base64 エンコードされたポリシー
$bodyWriter->addField('x-oss-signature-version', 'OSS4-HMAC-SHA256'); // 署名バージョン
$bodyWriter->addField('x-oss-credential', sprintf("%s/%s/%s/%s/aliyun_v4_request",
$cred->getAccessKeyId(), $date, $region, $product)); // 認証情報
$bodyWriter->addField('x-oss-date', $utcTime->format('Ymd\THis\Z')); // タイムスタンプ
$bodyWriter->addField('x-oss-signature', $signature); // 最終的な署名
// フォームにファイルコンテンツを追加します
$bodyWriter->addFileFromString('file', $data); // ファイルコンテンツをアップロードします
$postData = $bodyWriter->getFormData(); // 完全なフォームデータを取得します
// POST リクエストを送信します
$client = new \GuzzleHttp\Client(); // HTTP クライアントを作成します
$response = $client->post(
sprintf("http://%s.oss-%s.aliyuncs.com/", $bucket, $region), // OSS アップロード URL
[
'headers' => [
'content-type' => $bodyWriter->getContentType(), // Content-Type を設定します
],
'body' => $postData // リクエスト本文を設定します
]
);
// 応答状態コードを確認します
if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
echo "Post Object Fail, status code:" . $response->getStatusCode() . ", reason: " . $response->getReasonPhrase() . PHP_EOL;
exit(1); // 状態コードが 2xx の範囲にない場合はプログラムを終了します
}
// アップロード結果を出力します
echo "post object done, status code:" . $response->getStatusCode() . ", request id:" . $response->getHeaderLine('x-oss-request-id') . PHP_EOL;
/**
* HMAC 署名関数
* @param string $key 署名キー
* @param string $data 署名されるデータ
* @return string 署名結果を返します
*/
function hmacSign($key, $data)
{
return hash_hmac('sha256', $data, $key, true); // SHA256 アルゴリズムを使用して HMAC 署名を生成します
}
/**
* multipart/form-data 形式のリクエスト本文を生成するためのフォームビルダークラス
*/
class CURLFileUpload
{
private $fields = []; // 通常のフィールドを格納します
private $files = []; // ファイルフィールドを格納します
private $boundary; // 区切り文字
public function __construct()
{
$this->boundary = uniqid(); // 一意の区切り文字を生成します
}
/**
* 通常のフィールドを追加します
* @param string $name フィールド名
* @param string $value フィールド値
*/
public function addField($name, $value)
{
$this->fields[$name] = $value;
}
/**
* ファイルフィールドを追加します
* @param string $name フィールド名
* @param string $content ファイルコンテンツ
*/
public function addFileFromString($name, $content)
{
$this->files[$name] = [
'content' => $content,
'filename' => $name,
'type' => 'application/octet-stream' // デフォルトの MIME タイプ
];
}
/**
* 完全なフォームデータを取得します
* @return string multipart/form-data 形式のリクエスト本文を返します
*/
public function getFormData()
{
$data = '';
foreach ($this->fields as $name => $value) {
$data .= "--{$this->boundary}\r\n";
$data .= "Content-Disposition: form-data; name=\"$name\"\r\n\r\n";
$data .= $value . "\r\n";
}
foreach ($this->files as $name => $file) {
$data .= "--{$this->boundary}\r\n";
$data .= "Content-Disposition: form-data; name=\"$name\"; filename=\"{$file['filename']}\"\r\n";
$data .= "Content-Type: {$file['type']}\r\n\r\n";
$data .= $file['content'] . "\r\n";
}
$data .= "--{$this->boundary}--\r\n";
return $data;
}
/**
* Content-Type ヘッダーを取得します
* @return string Content-Type 値を返します
*/
public function getContentType()
{
return "multipart/form-data; boundary={$this->boundary}";
}
}
参照
フォームアップロードの完全な例については、「Github の例」をご参照ください。