====== PSR-7: HTTP message interfaces ====== --- //[[http://www.y2sunlight.com|y2sunlight]] 2020-05-25// 本章は、若干の補足を加筆してはいるものの単に[[https://www.php-fig.org/psr/|PSRのサイト]]を日本語に翻訳したものに過ぎません。英語が堪能な方は原文をご参照下さい。翻訳に当たっては、基本的に機械翻訳を使い、理解できない部分は独断で意訳しております。拙い訳では御座いますが恥を忍んで投稿しておりますので、ご指摘など御座いましたらコメントを頂ければ幸いです。 関連記事 * [[psr:top|PSR - PHP標準勧告]] * [[psr:psr1|PSR-1: Basic Coding Standard - 基本コーディング規約]] * [[psr:psr3|PSR-3: Logger Interface - ロガーインターフェイス]] * [[psr:psr4|PSR-4: Autoloading Standard - オートローディング規約]] * [[psr:psr5|PSR-5: PHPDoc Standard(Draft) - PHPDoc規約]] * [[psr:psr6|PSR-6: Caching Interface - キャッシングインターフェイス]] * PSR-7: HTTP Message Interface - HTTPメッセージインターフェイス * [[psr:psr11|PSR-11: Container Interface - コンテナインターフェイス]] * [[psr:psr12|PSR-12: Extended Coding Style - 拡張コーディングスタイル]] * [[psr:psr13|PSR-13: Link definition interfaces - リンク定義インターフェース]] * [[psr:psr14|PSR-14: Event Dispatcher - イベントディスパッチャー]] * [[psr:psr15|PSR-15: HTTP Server Request Handlers - HTTPサーバーリクエストハンドラー]] * [[psr:psr16|PSR-16: Common Interface for Caching Libraries - キャッシングライブラリのための共通インターフェース]] * [[psr:psr17|PSR-17: HTTP Factories - HTTPファクトリー]] * [[psr:psr18|PSR-18: HTTP Client - HTTPクライアント]] * [[psr:psr19|PSR-19: PHPDoc tags(Draft) - PHPDocタグ]] ----- ====== PSR-7: HTTPメッセージインターフェイス ====== --- // 原文より翻訳 [[https://www.php-fig.org/psr/psr-7/|PSR-7: HTTP message interfaces]] 2020-05-25 現在 // このドキュメントでは、[[https://tools.ietf.org/html/rfc7230|RFC 7230]] および [[https://tools.ietf.org/html/rfc7231|RFC 7231]] で説明されているHTTPメッセージを表すための一般的なインターフェイスと、[[https://tools.ietf.org/html/rfc3986|RFC 3986]] で説明されているHTTPメッセージで使用するURIについて説明します。 HTTPメッセージはWeb開発の基礎です。WebブラウザーとcURLなどのHTTPクライアントは、HTTPレスポンスメッセージを提供するWebサーバーに送信されるHTTPリクエストメッセージを作成します。サーバー側コードは、HTTPリクエストメッセージを受信し、HTTPレスポンスメッセージを返します。 HTTPメッセージは通常、エンドユーザー(コンシューマー)からは抽象化されていますが、開発者は通常、HTTP APIにリクエストを送信する場合でも、または着信リクエストを処理する場合でも、タスクを実行するために、それらの構造とアクセスまたは操作の方法を知る必要があります。 > 原文では、コンシューマー(consumer)と言う表現が多く見られます。これはエンドユーザーと同じ意味で使用されていると思われます。 すべてのHTTPリクエストメッセージには特定の形式があります: POST /path HTTP/1.1 Host: example.com foo=bar&baz=bat リクエストの最初の行は「リクエストライン」であり、HTTPリクエストメソッド、リクエストターゲット(通常は絶対URIまたはWebサーバー上のパス)、HTTPプロトコルバージョンが順に含まれます。この後には、1行以上のHTTPヘッダー、空行、およびメッセージボディが続きます。 HTTPレスポンスメッセージも同様の構造を持っています: HTTP/1.1 200 OK Content-Type: text/plain This is the response body 最初の行は「ステータスライン」で、HTTPプロトコルのバージョン、HTTPステータスコード、「理由フレーズ」が順に含まれます。「理由フレーズ」とは、ステータスコードの人間が読める説明のことです。 リクエストメッセージと同様に、この後に1行以上のHTTPヘッダー、空行、およびメッセージボディが続きます。 このドキュメントで説明されているインターフェースは、HTTPメッセージとそれらを構成する要素に関する抽象化です。 このドキュメントのキーワード ''MUST'' , ''MUST NOT'' , ''REQUIRED'' , ''SHALL'' , ''SHALL NOT'' , ''SHOULD'' , ''SHOULD NOT'' , ''RECOMMENDED'' , ''MAY'' 及び ''OPTIONAL'' は、 [[https://www.ietf.org/rfc/rfc2119.txt|RFC 2119]]で説明されているように解釈して下さい。 > **RFC 2119の説明** > ''MUST'', ''REQUIRED'', ''SHALL'' --- 絶対必要 > ''MUST NOT'', ''SHALL NOT'' --- 絶対禁止 > ''SHOULD'', ''RECOMMENDED'' --- 推奨(但し、無視できる特定の正当な理由が存在するかもしれない) > ''SHOULD NOT'' --- 推奨できない(但し、許可できる特定の正当な理由が存在するかもしれない) > ''MAY'', ''OPTIONAL'' --- オプション === References === * [[https://tools.ietf.org/html/rfc2119|RFC 2119]] ・・・ Key words for use in RFCs to Indicate Requirement Levels * [[https://tools.ietf.org/html/rfc3986|RFC 3986]] ・・・ Uniform Resource Identifier (URI): Generic Syntax * [[https://tools.ietf.org/html/rfc7230|RFC 7230]] ・・・ Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing * [[https://tools.ietf.org/html/rfc7231|RFC 7231]] ・・・ Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content \\ ===== 1. 仕様 ====== ==== 1.1 メッセージ ==== HTTPメッセージは、クライアントからサーバーへのリクエスト、またはサーバーからクライアントへのレスポンスです。この仕様は、HTTPメッセージ ''Psr\Http\Message\RequestInterface''''コード'' および ''Psr\Http\Message\ResponseInterface'' に対するインターフェースをそれぞれ定義します。 ''Psr\Http\Message\RequestInterface'' と ''Psr\Http\Message\ResponseInterface'' はどちらも ''Psr\Http\Message\MessageInterface'' を拡張(extends)します。''Psr\Http\Message\MessageInterface'' を直接実装(implements)してもかまいませんが( ''MAY'' )、実装者は ''Psr\Http\Message\RequestInterface'' と ''Psr\Http\Message\ResponseInterface'' を実装する必要があります ( ''SHOULD'' )。 これ以降、これらのインターフェースを参照する場合、名前空間 ''Psr\Http\Message'' は省略されます。 \\ ==== 1.2 HTTPヘッダー ==== === Case-insensitiveなヘッダーフィールド名 === HTTPメッセージには、Case-insensitiveな(大文字と小文字を区別しない)ヘッダーフィールド名が含まれます。ヘッダーは、Case-insensitiveな方法で ''MessageInterface'' を実装しているクラスから名前で取得されます。たとえば、''foo''ヘッダーを取得する場合、''FoO''''コード''ヘッダーを取得した場合と同じ結果が返されます。 同様に、''Foo''ヘッダーを設定すると、先に設定された''foo''ヘッダー値が上書きされます。   $message = $message->withHeader('foo', 'bar'); echo $message->getHeaderLine('foo'); // Outputs: bar echo $message->getHeaderLine('FOO'); // Outputs: bar $message = $message->withHeader('fOO', 'baz'); echo $message->getHeaderLine('foo'); // Outputs: baz ヘッダーは大文字と小文字を区別せずに取得できますが、特に ''getHeaders()'' を使用して取得する場合は、実装によって元の大文字と小文字を維持する必要があります( ''MUST'' )。 非準拠のHTTPアプリケーションはある特定のケースに依存するかもしれません。従って、ユーザーがリクエストまたはレスポンスを作成する時に、そのケースのHTTPヘッダーを指定できることは有益です。 === 複数の値を持つヘッダー === 複数の値を持つヘッダーに対応しつつ、ヘッダーを文字列として操作する便利さを提供するために、ヘッダーは ''MessageInterface'' のインスタンスから配列または文字列として取得できます。''getHeaderLine()'' メソッドを使用して、名前によってCase-insensitiveなヘッダーに対するヘッダー値を文字列として取得して下さい。その文字列には、カンマで連結されたすべてのヘッダー値が含まれています。''getHeader()'' を使用して、名前によって特定のCase-insensitiveなヘッダーに対するすべてのヘッダー値を配列で取得して下さい。 $message = $message ->withHeader('foo', 'bar') ->withAddedHeader('foo', 'baz'); $header = $message->getHeaderLine('foo'); // $header contains: 'bar,baz'   $header = $message->getHeader('foo'); // ['bar', 'baz'] 注意:すべてのヘッダー値をカンマを使用して連結できるわけではありません(例えば、''Set-Cookie'')。このようなヘッダーを操作する場合、''MessageInterface'' ベースのクラスのコンシューマーは、そのような複数値のヘッダーを取得するために ''getHeader()'' メソッドに頼るべきです ( ''SHOULD'' )。 === ホストヘッダー === リクエストでは、''Host''ヘッダーは通常、URIのホストコンポーネントと、TCP接続を確立するときに使用されたホストをミラーリングします。 ただし、HTTP仕様では、''Host''ヘッダーが2つのそれぞれのヘッダーと異なることを許可しています。 (リクエストオブジェクトの)構築中、'Host''ヘッダーが提供されていない場合、実装は提供されたURIから'Host''ヘッダーを設定しようと試みる必要があります( ''MUST'' )。 ''RequestInterface::withUri()'' は、デフォルトでは、返すべきリクエストの''Host''ヘッダーを、(引数で)渡された ''UriInterface'' のホストコンポーネントと一致するHostヘッダーに置き換えます。 ''withUri()'' の2番目の( ''$preserveHost'' )引数に ''true'' を渡すことで、''Host''ヘッダーの元の状態を保持するように選択できます。この引数が ''true'' に設定されている場合、返すべきリクエストは返されたメッセージのホストヘッダーを更新しません(メッセージに''Host''ヘッダーが含まれていない場合を除きます)。 > 上記の原文\\ You can opt-in to preserving the original state of the Host header by passing true for the second ($preserveHost) argument. When this argument is set to true, the returned request will not update the Host header of the returned message – unless the message contains no Host header. この表は、様々な初期リクエストとURIに対して ''$preserveHost'' 引数を ''true'' に設定して、''withUri()'' によって返されたリクエストに対して ''getHeaderLine('Host')'' が返すものを示しています。 ^REQUEST HOST HEADER※1^REQUEST HOST COMPONENT※2^URI HOST COMPONENT※3^RESULT^ |''|''|''|''| |''|foo.com|''|foo.com| |''|foo.com|bar.com|foo.com| |foo.com|''|bar.com|foo.com| |foo.com|bar.com|bar.com|foo.com|
※1 操作前のホストヘッダ値\\ ※2 操作前のリクエストに含まれるURIのホストコンポーネント\\ ※3 withUri()を介して注入されるURIのホストコンポーネント\\
\\ ==== 1.3 ストリーム ==== HTTPメッセージは、開始行、ヘッダー、および本文で構成されます。HTTPメッセージの本文は、非常に小さい場合と非常に大きい場合があります。メッセージの本文を完全にメモリに格納する必要があるため、メッセージの本文を文字列として表現しようとすると、意図したよりも多くのメモリが消費されます。リクエストまたはレスポンスの本文をメモリに保存しようとすると、その実装を使用して大きなメッセージ本文を処理できなくなります。''StreamInterface'' は、データストリームの読み取りまたは書き込み時、実装の詳細を隠蔽するために使用されます。文字列が適切なメッセージ実装である状況では、''php://memory'' や ''php:php://temp'' などの組み込みストリームを使用できます。 ''StreamInterface'' は、ストリームの読み取り、書き込み、および効率的なトラバース(通過)を可能にするいくつかのメソッドを公開しています。 ストリームは、''isReadable()''、''isWritable()''、''isSeekable()'' の3つのメソッドを使用してその機能を公開します。ストリームの共同作業者はこれらのメソッドを使用して、ストリームが要件を満たしているかどうかを判断できます。 各ストリームのインスタンスには様々な機能があります。読み取り専用、書き込み専用、または読み書き可能です。 また、任意のランダムアクセス(任意の場所への前方または後方へのシーク)またはシーケンシャルアクセス(たとえば、ソケット、パイプ、またはコールバックベースのストリームの場合)のみを許可することもできます。 最後に、''StreamInterface'' は ''__toString()'' メソッドを定義して、ボディコンテンツ全体を一度に取得(読み込み)または送出(書き込み)することを簡素化します。 リクエストおよびレスポンスインターフェイスとは異なり、''StreamInterface'' は不変性(immutability)をモデル化していません。 実際のPHPストリームがラップされている状況では、リソースとやり取りするコードがその状態(カーソルの位置、内容など)を変更する可能性があるため、不変性を強制することは不可能です。実装では、サーバー側の(HTTP)要求とクライアント側の(HTTP)応答に読み取り専用ストリームを使用することをお勧めします。コンシューマーは、ストリームのインスタンスが変更可能であり、メッセージの状態を変更する可能性があることを認識しておく必要があります。不確かな場合は、新しいストリームのインスタンスを作成し、それをメッセージにアタッチして状態を強制します。 \\ ==== 1.4 リクエストターゲットとリクエストURI ==== RFC 7230に従い、リクエストメッセージには、リクエストラインの2番目のセグメントとして「リクエストターゲット」が含まれています。 リクエストターゲットは、次のいずれかの形式になります。 * **origin-form** (基本形式): パスと、クエリ文字列(存在する場合)で構成されます。これは多くの場合、相対URLと呼ばれます。TCPを介して送信されるメッセージは、通常は origin-form です。スキームと権限データは通常、CGI変数を介してのみ提供されます。 * **absolute-form** (絶対形式): スキーム、権限(「[user-info@]host[:port]」、角括弧内の項目はオプション)、パス(存在する場合)、クエリ文字列(存在する場合)、およびフラグメント(存在する場合)で構成されます。これは、多くの場合、絶対URIと呼ばれ、RFC 3986で詳述されているようにURIを指定する唯一のフォームです。このフォームは一般的に、HTTPプロキシへのリクエストを行うときに使用されます。 * **authority-form** (権限形式): 権限のみで構成されます。これは通常、HTTPクライアントとプロキシサーバー間の接続を確立するために、CONNECTリクエストでのみ使用されます。 * **asterisk-form** (アスタリスク形式): 単独の ''*'' 文字のみで構成されます。OPTIONSメソッドで使われ、Webサーバーの一般的な機能を判断します。 これらのリクエストターゲットとは別に、リクエストターゲットとは異なる「有効なURL」が存在することがよくあります。有効なURLはHTTPメッセージ内では送信されませんが、リクエストを行うためにプロトコル (http/https)、ポート、およびホスト名を決定するために使用されます。 有効なURLは ''UriInterface'' で表されます。''UriInterface'' は、RFC 3986(the primary use case)で指定されているHTTPおよびHTTPS URIをモデル化します。このインターフェースは、さまざまなURI部分と対話するためのメソッドを提供します。これにより、URIを繰り返し解析する必要がなくなります。また、モデル化されたURIをその文字列表現にキャストするための__toString() メソッドも仕様に含んでいます。 ''getRequestTarget()'' を使用してリクエストターゲットを取得する場合、デフォルトでは、このメソッドはURIオブジェクトを使用し、必要なすべてのコンポーネントを抽出して origin-form を構築します。origin-form は、最も一般的なリクエストターゲットです。 エンドユーザーが他の3つの形式(origin-form以外)のいずれかを使用したい場合、またはユーザーがリクエストターゲットを明示的にオーバーライドしたい場合は、''withRequestTarget()'' を使用してこれを行うことができます。 このメソッドを呼び出しは、''getUri()'' から返されるURIには影響しません。 たとえば、ユーザーがサーバーに asterisk-form のリクエストを行う場合があります: $request = $request ->withMethod('OPTIONS') ->withRequestTarget('*') ->withUri(new Uri('https://example.org/')); この例では、最終的に次のようなHTTPリクエストになります: OPTIONS * HTTP/1.1 しかし、HTTPクライアントは、( ''getUri()'' からの ) 有効なURLを使用して、プロトコル、ホスト名、およびTCPポートを決定することができます。 HTTPクライアントは、''Uri::getPath()'' および ''Uri::getQuery()'' の値を無視し、代わりに ''getRequestTarget()'' によって返される値を使用する必要があります ( ''MUST'' )。''getRequestTarget()'' はデフォルトでは、これら2つの値が連結されます。 4つのリクエストターゲット形式の1つ以上を実装しないことを選択したクライアントは、引き続き ''getRequestTarget()'' を使用する必要があります ( ''MUST'' )。これらのクライアントは、サポートしていないリクエストターゲットを拒否する必要があり( ''MUST'' )、''getUri()'' からの値にフォールバックしてはなりません ( ''MUST NOT'' )。 >''上記の原文'' \\ Clients that choose to not implement 1 or more of the 4 request-target forms, MUST still use getRequestTarget(). These clients MUST reject request-targets they do not support, and MUST NOT fall back on the values from getUri(). ''RequestInterface'' は、リクエストターゲットを取得するメソッド、または指定されたリクエストターゲットを使用して新しいインスタンスを作成するメソッドを提供します。デフォルトでは、リクエストターゲットがインスタンス内で具体的に構成されていない場合、''getRequestTarget()'' は、構成されたURIの origin-form(または構成されていない場合は「/」)を返します。 ''withRequestTarget($requestTarget)'' は、指定されたリクエストターゲットを使用して新しいインスタンスを作成するので、開発者は他の3つのリクエストターゲット形式 ( absolute-form、authority-form、およびasterisk-form ) を表すリクエストメッセージを作成できます。これが使用された場合、構成されたURIインスタンスは、特にクライアント引き続き使用でき、サーバーへの接続を作成するために使用できます。 \\ ==== 1.5 サーバーサイドリクエスト ==== ''RequestInterface'' は、HTTPリクエストメッセージの一般的な表現を提供します。ただし、サーバー側の環境の性質上、サーバー側のリクエストには追加の処理が必要です。サーバー側の処理では、Common Gateway Interface(CGI)と、さらに具体的には、PHPのサーバーAPI(SAPI)を介したCGIの抽象化と拡張を考慮する必要があります。PHPは、次のようなスーパーグローバル変数を経由して入力のマーシャリングを簡素化しました。 * **$_COOKIE**: HTTPCookieへのデシリアル化と簡略化されたアクセスを提供します。 * **$_GET**: クエリ文字列引数へのデシリアル化と簡略化されたアクセスを提供します。 * **$_POST**: HTTP POST経由で送信されたURLエンコードされたパラメーターへのデシリアル化と簡略化されたアクセスを提供します。 一般的には、メッセージ本文の解析結果と考えることができます。 * **$_FILES**: ファイルのアップロードに関するシリアル化されたメタデータを提供します。 * **$_SERVER**: CGI / SAPI環境変数へのアクセスを提供します。これには、通常、リクエストメソッド、リクエストスキーム、リクエストURI、およびヘッダーが含まれます。 ''ServerRequestInterface'' は ''RequestInterface'' を拡張して、これらのさまざまなスーパーグローバル変数に関する抽象化を提供します。このプラクティスは、コンシューマーによるスーパーグローバル変数への結合を減らすのに役立ち、リクエストコンシューマーをテストする為の能力を奨励し促進します。 サーバーリクエストは、「attributes」という1つの追加プロパティを提供して、コンシューマーがアプリケーション固有のルール(パスマッチング、スキームマッチング、ホストマッチングなど)に対してリクエストを内省(introspect)、分解(decompose)、および照合(match)できるようにします。従って、サーバーリクエストは、複数のリクエストコンシューマー間のメッセージングを提供することもできます。 \\ ==== 1.6 アップロードファイル ==== ''ServerRequestInterface'' は、正規化された構造でアップロードファイルのツリーを取得するメソッドを規定します。そのツリーの各リーフには ''UploadedFileInterface'' のインスタンスがあります。 ''$_FILES'' スーパーグローバル変数には、ファイル入力の配列を処理するときによく知られた問題がいくつかあります。例として、ファイルの配列を送信するフォームがある場合(例えば入力名を「files」とする)、''files[0]'' と ''files[1]'' を送信すると、PHPはこれを次のように表します: array( 'files' => array( 'name' => array( 0 => 'file0.txt', 1 => 'file1.html', ), 'type' => array( 0 => 'text/plain', 1 => 'text/html', ), /* etc. */ ), ) 期待されるのは次のようです: array( 'files' => array( 0 => array( 'name' => 'file0.txt', 'type' => 'text/plain', /* etc. */ ), 1 => array( 'name' => 'file1.html', 'type' => 'text/html', /* etc. */ ), ), ) その結果、コンシューマーはこの言語実装(PHP)の詳細を知って、与えられたアップロードのデータを収集するためのコードを書く必要があります。 さらに、ファイルのアップロードが発生したときに ''$_FILES'' が設定されない状況があります: * HTTPメソッドが ''POST'' でない場合 * ユニットテストの時 * [[https://reactphp.org/|ReactPHP]]のように非SAPI環境下で操作する場合 そのような場合、データを別の方法でシード(特別な処理)する必要があります。例としては: * プロセスがメッセージ本文を解析して、ファイルのアップロードを検出する場合があります。 このような場合、実装では、ファイルアップロードをファイルシステムに書き込まず、代わりにストリームにラップして、メモリ、I/O、ストレージのオーバーヘッドを削減します。 * ユニットテストのシナリオでは、さまざまなシナリオを検証および検査するために、開発者はファイルアップロードのメタデータをスタブ化および/またはモックできる必要があります。 ''getUploadedFiles()'' は、コンシューマに正規化された構造を提供します。実装では、次のことが期待されます: * 与えられたファイルアップロードのすべての情報を集約し、それを使用して ''Psr\Http\Message\UploadedFileInterface'' インスタンスに設定します。 * 送信されたツリー構造を再作成します。その時各リーフは、ツリー内の与えられた場所に対して適切な''Psr\Http\Message\UploadedFileInterface'' のインスタンスになります。 参照されるツリー構造は、ファイルが送信されたときのネーミング構造を模倣する必要があります。 最も単純な例では、これは次のように送信された単一の名前付きフォーム要素でしょう: この場合、''$_FILES'' の構造は次のようになります: array( 'avatar' => array( 'tmp_name' => 'phpUxcOty', 'name' => 'my-avatar.png', 'size' => 90996, 'type' => 'image/png', 'error' => 0, ), ) ''getUploadedFiles()'' によって返される正規化された形式は次のようになります: array( 'avatar' => /* UploadedFileInterface instance */ ) 名前に配列表記を使用した入力の場合: $_FILESは次のようになります: array ( 'my-form' => array ( 'name' => array ( 'details' => array ( 'avatar' => 'my-avatar.png', ), ), 'type' => array ( 'details' => array ( 'avatar' => 'image/png', ), ), 'tmp_name' => array ( 'details' => array ( 'avatar' => 'phpmFLrzD', ), ), 'error' => array ( 'details' => array ( 'avatar' => 0, ), ), 'size' => array ( 'details' => array ( 'avatar' => 90996, ), ), ), ) そして、''getUploadedFiles()'' によって返される対応するツリーは次のようになります: array( 'my-form' => array( 'details' => array( 'avatar' => /* UploadedFileInterface instance */ ), ), ) 場合によっては、ファイルの配列を指定できます: Upload an avatar: Upload an avatar: (例として、JavaScriptコントロールは、複数のファイルを一度にアップロードできるように、追加のファイルアップロード入力を生成する場合があります。) このような場合、仕様の実装では、指定されたインデックスにあるファイルに関連するすべての情報を集約する必要があります。その理由は、''$_FILES'' は通常の構造から逸脱しているためです。それは、次のような場合です: array ( 'my-form' => array ( 'name' => array ( 'details' => array ( 'avatar' => array ( 0 => 'my-avatar.png', 1 => 'my-avatar2.png', 2 => 'my-avatar3.png', ), ), ), 'type' => array ( 'details' => array ( 'avatar' => array ( 0 => 'image/png', 1 => 'image/png', 2 => 'image/png', ), ), ), 'tmp_name' => array ( 'details' => array ( 'avatar' => array ( 0 => 'phpmFLrzD', 1 => 'phpV2pBil', 2 => 'php8RUG8v', ), ), ), 'error' => array ( 'details' => array ( 'avatar' => array ( 0 => 0, 1 => 0, 2 => 0, ), ), ), 'size' => array ( 'details' => array ( 'avatar' => array ( 0 => 90996, 1 => 90996, 3 => 90996, ), ), ), ), ) 上記の ''$_FILES'' 配列は、''getUploadedFiles()'' によって返される次の構造に対応します: array( 'my-form' => array( 'details' => array( 'avatars' => array( 0 => /* UploadedFileInterface instance */, 1 => /* UploadedFileInterface instance */, 2 => /* UploadedFileInterface instance */, ), ), ), ) コンシューマーは、ネストされた配列のインデックス1に次のようにしてアクセスします: $request->getUploadedFiles()['my-form']['details']['avatars'][1]; アップロードされたファイルデータは派生型(''$_FILES'' またはリクエストボディからの派生)であるため、インターフェイスにはミューテーターメソッド(mutator method) として ''withUploadedFiles()'' も存在し、正規化を別のプロセスに委譲できます。 冒頭の例の場合、使用方法は次のようになります: $file0 = $request->getUploadedFiles()['files'][0]; $file1 = $request->getUploadedFiles()['files'][1]; printf( "Received the files %s and %s", $file0->getClientFilename(), $file1->getClientFilename() ); // "Received the files file0.txt and file1.html" この提案は、実装が非SAPI環境で動作する可能性があることも認識しています。従って、''UploadedFileInterface'' は、環境に関係なく操作が確実に機能するためのメソッドを提供します。 特に: * ''moveTo($targetPath)'' は、一時的なアップロードファイルで直接 ''move_uploaded_file()'' を呼び出すより安全で推奨される代替手段として提供されています。実装は、環境に基づいて使用する正しい操作を検出します。 * ''getStream()'' は ''StreamInterface'' インスタンスを返します。非SAPIの環境下では、個々のアップロードファイルを解析して直接ファイルにではなく ''php://temp'' ストリームにすることが提案されています。このような場合、アップロードファイルは存在しないことになり、従って、''getStream()'' は環境に関係なく動作することが保証されています。 例として: // Move a file to an upload directory // ファイルをアップロードディレクトリに移動する $filename = sprintf( '%s.%s', create_uuid(), pathinfo($file0->getClientFilename(), PATHINFO_EXTENSION) ); $file0->moveTo(DATA_DIR . '/' . $filename); // Stream a file to Amazon S3. // Assume $s3wrapper is a PHP stream that will write to S3, and that // Psr7StreamWrapper is a class that will decorate a StreamInterface as a PHP // StreamWrapper. // // ファイルを Amazon S3 にストリーミングします。 // $s3wrapper が S3 に書き込むPHPストリームであり、 // Psr7StreamWrapper が StreamInterface を // PHP StreamWrapper として装飾するクラスであると仮定します。 $stream = new Psr7StreamWrapper($file1->getStream()); stream_copy_to_stream($stream, $s3wrapper); \\ ===== 2. パッケージ ===== 説明されているインターフェースとクラスは、[[https://packagist.org/packages/psr/http-message|psr/http-message]] パッケージの一部として提供されます。 \\ ===== 3. インターフェース ===== ここでは、原本に記載されているインターフェースの要約とメソッド一覧を示します。詳細は[[https://www.php-fig.org/psr/psr-7/#3-interfaces|php-fig.org]]を参照してください。 ==== 3.1 MessageInterface ==== 完全クラス名
[[https://www.php-fig.org/psr/psr-7/#31-psrhttpmessagemessageinterface|Psr\Http\Message\MessageInterface]]
要約
HTTPメッセージは、クライアントからサーバーへの要求と、サーバーからクライアントへの応答で構成されます。 このインターフェースは、それぞれに共通するメソッドを定義します。 メッセージは不変と見なされます。 状態を変更する可能性のあるすべてのメソッドは、現在のメッセージの内部状態を保持し、変更された状態を含むインスタンスを返すように実装する必要があります。
参照
* [[http://www.ietf.org/rfc/rfc7230.txt]] * [[http://www.ietf.org/rfc/rfc7231.txt]]
{{tablelayout?colwidth="16em"}} ^メソッド^要約^ |getProtocolVersion\\ ():string|HTTPプロトコルのバージョンを文字列として取得します。| |withProtocolVersion\\ ($version):static|指定されたHTTPプロトコルバージョンのインスタンスを返します。| |getHeaders\\ ():string[][]|すべてのメッセージヘッダー値を取得します。| |hasHeader\\ ($name):bool|指定された名前(case-insensitive)でヘッダーが存在するかどうかの確認します。| |getHeader\\ ($name):string[]|指定された名前(case-insensitive)でメッセージヘッダー値を取得します。| |getHeaderLine\\ ($name):string|単一ヘッダーに対するカンマ区切りの文字列の値を取得します。| |withHeader\\ ($name, $value):static|指定されたヘッダーを指定いた値に置き換えたインスタンスを返します。| |withAddedHeader\\ ($name, $value):static|指定されたヘッダーに指定された値を追加したインスタンスを返します。| |withoutHeader\\ ($name):static|指定されたヘッダーのないインスタンスを返します。| |getBody\\ ():StreamInterface|メッセージの本文を取得します。| |withBody\\ (StreamInterface $body):static|指定されたメッセージ本文を持つインスタンスを返します。| \\ ==== 3.2 RequestInterface ==== 完全クラス名
[[https://www.php-fig.org/psr/psr-7/#32-psrhttpmessagerequestinterface|Psr\Http\Message\RequestInterface]]
要約
クライアント側(発信側)のリクエストの表現 HTTP仕様に従って、このインターフェイスには次の各プロパティが含まれています: * Protocol version\\ * HTTP method\\ * URI\\ * Headers\\ * Message body\\ インスタンス構築時、Hostヘッダーが提供されていない場合、実装は提供されたURIからHostヘッダーを設定しようとする必要があります( ''MUST'' )。 リクエストは不変と見なされます。状態を変更する可能性のあるすべてのメソッドは、現在のメッセージの内部状態を保持し、変更された状態を含むインスタンスを返すように実装する必要があります( ''MUST'' )。
{{tablelayout?colwidth="16em"}} ^メソッド^要約^ |getRequestTarget\\ ():string|メッセージのリクエストターゲットを取得します。| |withRequestTarget\\ ($requestTarget):static|特定のリクエストターゲットを持つインスタンスを返します。| |getMethod\\ ():string|リクエストのHTTPメソッドを取得します。| |withMethod\\ ($method):static|指定されたHTTPメソッドを持つインスタンスを返します。| |getUri\\ ():UriInterface|URIインスタンスを取得します。| |withUri\\ (UriInterface $uri, $preserveHost = false):static|指定されたURIを持つインスタンスを返します。| \\ === 3.2.1 ServerRequestInterface === 完全クラス名
[[https://www.php-fig.org/psr/psr-7/#321-psrhttpmessageserverrequestinterface|Psr\Http\Message\ServerRequestInterface]]
要約
サーバー側(受信側)のHTTPリクエストの表現 HTTP仕様に従って、このインターフェイスには次の各プロパティが含まれています: * Protocol version\\ * HTTP method\\ * URI\\ * Headers\\ * Message body\\ さらに、CGIやPHP環境からアプリケーションに到達したすべてのデータをカプセル化します: * $_SERVER変数で表される値\\ * 提供されるクッキー(通常は$_COOKIE変数)\\ * クエリ文字列引数(通常は$_GET変数、または parse_str()関数 を介して解析される)\\ * ファイルがあればアップロードします($_FILES変数で表される)\\ * デシリアライズされた本体パラメーター(通常は$_POST変数)\\ $_SERVERの値は、リクエスト時のアプリケーションの状態を表すため、不変として扱う必要があります( ''MUST'' )。 そのため、これらの値を変更できるメソッドは提供されていません。 他の値は、$_SERVER またはリクエストボディから復元できるので、このようなメソッドを提供し、アプリケーション中の処理が必要になる場合があります(たとえば、本文のパラメーターはコンテンツタイプに基づいてデシリアル化される場合があります)。 さらに、このインターフェイスは、追加のパラメータを取得して照合するリクエストを内省(イントロスペクト)するユーティリティを認識します(例えば、URIパスマッチング、Cookie値の復号、フォームエンコードされていない本文コンテンツのデシリル化、認証ヘッダーとユーザーの照合など)。 これらのパラメーターは ''attributes'' プロパティーに保管されます。 >''上記の原文''\\ Additionally, this interface recognizes the utility of introspecting a request to derive and match additional parameters (e.g., via URI path matching, decrypting cookie values, deserializing non-form-encoded body content, matching authorization headers to users, etc). These parameters are stored in an "attributes" property. リクエストは不変と見なされます。状態を変更する可能性のあるすべてのメソッドは、現在のメッセージの内部状態を保持し、変更された状態を含むインスタンスを返すように実装する必要があります( ''MUST'' )。
{{tablelayout?colwidth="16em"}} ^メソッド^要約^ |getServerParams\\ ():array|サーバーパラメータを取得します。| |getCookieParams\\ ():array|Cookieを取得します。| |withCookieParams\\ (array $cookies):static|指定されたCookieを持つインスタンスを返します。| |getQueryParams\\ ():array|クエリ文字列引数を取得します。| |withQueryParams\\ (array $query):static|指定されたクエリ文字列引数を持つインスタンスを返します。| |getUploadedFiles\\ ():array|正規化されたファイルアップロードデータを取得します。| |withUploadedFiles\\ (array $uploadedFiles):static|指定されたアップロードファイルを使用して新しいインスタンスを作成します。| |getParsedBody\\ ():null|array|object|リクエストボディで提供されているパラメータを取得します。| |withParsedBody\\ ($data):static|指定されたボディパラメーターを持つインスタンスを返します。| |getAttributes\\ ():mixed[]|リクエストから派生した属性(attributesプロパティー)を取得します。| |getAttribute\\ ($name, $default = null):mixed|単一の派生リクエスト属性を取得します。| |withAttribute\\ ($name, $value):static|指定された派生リクエスト属性を持つインスタンスを返します。| |withoutAttribute\\ ($name):static|指定された派生リクエスト属性を除いたインスタンスを返します。| \\ ==== 3.3 ResponseInterface ==== 完全クラス名
[[https://www.php-fig.org/psr/psr-7/#33-psrhttpmessageresponseinterface|Psr\Http\Message\ResponseInterface]]
要約
サーバー側(送信側)のレスポンスの表現 HTTP仕様に従って、このインターフェイスには次の各プロパティが含まれています: * Protocol version\\ * Status code and reason phrase\\ * Headers\\ * Message body\\ レスポンスは不変と見なされます。状態を変更する可能性のあるすべてのメソッドは、現在のメッセージの内部状態を保持し、変更された状態を含むインスタンスを返すように実装する必要があります( ''MUST'' )。
{{tablelayout?colwidth="17em"}} ^メソッド^要約^ |getStatusCode\\ ():int|レスポンスステータスコードを取得します。| |withStatus\\ ($code, $reasonPhrase = ''):static|指定されたステータスコードと、オプションで理由フレーズを含むインスタンスを返します。| |getReasonPhrase\\ ():string|ステータスコードに関連付けられたレスポンスの理由フレーズを取得します。| \\ ==== 3.4 StreamInterface ==== 完全クラス名
[[https://www.php-fig.org/psr/psr-7/#34-psrhttpmessagestreaminterface|Psr\Http\Message\StreamInterface]]
要約
データストリームを表します。 通常、インスタンスはPHPストリームをラップします。このインターフェイスは、ストリーム全体の文字列へのシリアル化を含む、最も一般的な操作のラッパーを提供します。
{{tablelayout?colwidth="16em"}} ^メソッド^要約^ |__toString():string|ストリームからすべてのデータを最初から最後まで文字列に読み込みます。| |close():void|ストリームとその下層にあるリソースを閉じます。| |detach():resource|null|ストリームからその下層にあるリソースを分離します。| |getSize():int|null|既知の場合、ストリームのサイズを取得します。| |tell():int|ファイルの読み込み/書き込みポインタの現在の位置を返します。| |eof():bool|ストリームが最後にある場合はtrueを返します。| |isSeekable():bool|ストリームがシーク可能かどうかを返します。| |seek\\ ($offset, $whence = SEEK_SET)|ストリーム内の位置をシークします。| |rewind()|ストリームの先頭に移動します。| |isWritable():bool|ストリームが書き込み可能かどうかを返します。| |write($string):string|ストリームにデータを書き込みます。| |isReadable():bool|ストリームが読み込み可能かどうかを返します。| |read($length):string|ストリームから(指定されたバイト数までの)データを読み取ります。| |getContents():string|文字列の残りの内容を返します。| |getMetadata\\ ($key = null):array|mixed|null|ストリームメタデータを連想配列として取得するか、または特定のキーのデータを取得します。| \\ ==== 3.5 UriInterface ==== 完全クラス名
[[https://www.php-fig.org/psr/psr-7/#35-psrhttpmessageuriinterface|Psr\Http\Message\UriInterface]]
要約
URIを表す値オブジェクト(Value Object)です。 このインターフェースは、[[https://tools.ietf.org/html/rfc3986|RFC 3986]] に従ってURIを表し、最も一般的な操作のメソッドを提供することを目的としています。 URIを操作するための追加機能は、インターフェースの上部または外部で提供できます。 その主な用途はHTTPリクエストですが、他のコンテキストでも使用できます。 このインターフェースのインスタンスは不変と見なされます。状態を変更する可能性のあるすべてのメソッドは、現在のインスタンスの内部状態を保持し、変更された状態を含むインスタンスを返すように実装する必要があります( ''MUST'' )。 通常、Hostヘッダーはリクエストメッセージにも含まれます。サーバー側のリクエストの場合、通常、スキームはサーバーパラメータで検出できます。
参照
* [[http://tools.ietf.org/html/rfc3986|http://tools.ietf.org/html/rfc3986 (the URI specification)]]
{{tablelayout?colwidth="18em"}} ^メソッド^要約^ |getScheme():string|URIのスキームコンポーネントを取得します。| |getAuthority():string|URIの権限コンポーネントを取得します。| |getUserInfo():string|URIのユーザー情報コンポーネントを取得します。| |getHost():string|URIのホストコンポーネントを取得します。| |getPort():null|int|URIのポートコンポーネントを取得します。| |getPath():string|URIのパスコンポーネントを取得します。| |getQuery():string|URIのクエリ文字列を取得します。| |getFragment():string|URIのフラグメントコンポーネントを取得します。| |withScheme($scheme):static|指定されたスキームを持つインスタンスを返します。| |withUserInfo\\ ($user, $password = null):null|string|指定されたユーザー情報を持つインスタンスを返します。| |withHost($host):static|指定されたホストを持つインスタンスを返します。| |withPort($port):static|指定されたポートを持つインスタンスを返します。| |withPath($path):static|指定されたパスを持つインスタンスを返します。| |withQuery($query):static|指定されたクエリ文字列を持つインスタンスを返します。| |withFragment($fragment):static|指定されたURIフラグメントを持つインスタンスを返します。| |__toString():string|文字列表現をURI参照として返します。| \\ ==== 3.6 UploadedFileInterface ==== 完全クラス名
[[https://www.php-fig.org/psr/psr-7/#36-psrhttpmessageuploadedfileinterface|Psr\Http\Message\UploadedFileInterface]]
要約
HTTPリクエストによるアップロードファイルを表す値オブジェクト(Value object)です。 このインターフェースのインスタンスは不変と見なされます。状態を変更する可能性のあるすべてのメソッドは、現在のインスタンスの内部状態を保持し、変更された状態を含むインスタンスを返すように実装する必要があります( ''MUST'' )。
{{tablelayout?colwidth="16em"}} ^メソッド^要約^ |getStream():StreamInterface|アップロードファイルを表すストリームを取得します。| |moveTo($targetPath):string|アップロードファイルを新しい場所に移動します。| |getSize():int|null|ファイルサイズを取得します。| |getError():int|アップロードファイルに関連するエラーを取得します。| |getClientFilename():string|null|クライアントから送信されたファイル名を取得します。| |getClientMediaType():string|null|クライアントから送信されたメディアタイプを取得します。| \\