目次

Slim4 リクエスト

Version 4.5.0

y2sunlight 2020-09-23

Slim に戻る

関連記事

本章は以下のサイトの The Request のセクションを翻訳し若干の補足を加えたのもです。


Slimアプリのルート(route)とミドルウェアには、ウェブサーバーが受信した現在のHTTPリクエストを表すPSR-7リクエストオブジェクトが与えられます。リクエストオブジェクトは、HTTPリクエストメソッド、ヘッダー、およびボディを検査および操作できる PSR-7 ServerRequestInterface を実装しています。

Requestオブジェクトを取得する方法

PSR-7リクエストオブジェクトは、次のようにルート(route)コールバックの最初の引数としてSlimアプリケーションルート(route)に注入されます。

<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
 
require __DIR__ . '/../vendor/autoload.php';
 
$app = AppFactory::create();
 
$app->get('/hello', function (Request $request, Response $response) {
    $response->getBody()->write('Hello World');
    return $response;
});
 
$app->run();

PSR-7リクエストオブジェクトは、次のように呼び出し可能なミドルウェアの最初の引数としてSlimアプリケーションミドルウェアに注入されます。

<?php
 
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Factory\AppFactory;
 
require __DIR__ . '/../vendor/autoload.php';
 
$app = AppFactory::create();
 
$app->add(function (Request $request, RequestHandler $handler) {
   return $handler->handle($request);
});
 
// ...define app routes...
 
$app->run();


リクエストメソッド

すべてのHTTPリクエストには、通常、次のいずれかのメソッドがあります:

getMethod() という適切な名前の Request オブジェクトメソッドを使用して、HTTPリクエストのメソッドを検査できます。

$method = $request->getMethod();

HTTPリクエストメソッドを偽装またはオーバーライドすることが可能です。これは、たとえば、GET または POST リクエストのみをサポートする従来のWebブラウザを使用して PUT リクエストを模倣する必要がある場合に役立ちます。

注意!
リクエストメソッドのオーバーライドを有効にするには、メソッドオーバーライド・ミドルウェアをアプリケーションに注入する必要があります。

HTTPリクエストメソッドをオーバーライドする方法は2つあります。POST リクエストのボディに METHOD パラメータを含めることができます。この時、HTTPリクエストは、application/x-www-form-urlencoded コンテンツタイプを使用する必要があります。

POST /path HTTP/1.1
Host: example.com
Content-type: application/x-www-form-urlencoded
Content-length: 22

data=value&_METHOD=PUT

カスタムの X-Http-Method-Override HTTPリクエストヘッダーを使用して、HTTPリクエストメソッドをオーバーライドすることもできます。これは、任意のHTTPリクエストコンテンツタイプで機能します。

POST /path HTTP/1.1
Host: example.com
Content-type: application/json
Content-length: 16
X-Http-Method-Override: PUT

{"data":"value"}


リクエストURI

すべてのHTTPリクエストには、リクエストされたアプリケーションリソースを識別するURIがあります。HTTPリクエストURIにはいくつかの部分があります。

PSR-7リクエストオブジェクトの URIオブジェクト は、その getUri() メソッドを使用してフェッチできます。

$uri = $request->getUri();

PSR-7リクエストオブジェクトのURIは、それ自体がHTTPリクエストのURL部分を検査するための次のメソッドを提供するオブジェクトです:

getQueryParams() を使用して、Requestオブジェクトの連想配列としてクエリパラメーターを取得できます。

ペースパス
Slimアプリケーションのフロントコントローラーがドキュメントルートディレクトリ下の物理サブディレクトリにある場合は、Uriオブジェクトの getBasePath() メソッドを使用してHTTPリクエストの(ドキュメントルートを基準とした)物理ベースパスをフェッチできます。Slimアプリケーションがドキュメントルートの最上位ディレクトリにインストールされている場合、これは空の文字列になります。


リクエストヘッダー

HTTPリクエストにはヘッダーがあります。これらはHTTPリクエストを説明するメタデータですが、リクエストの本文には現れません。Slimの PSR-7 リクエストオブジェクトは、ヘッダーを検査するためのいくつかのメソッドを提供します。

全てのヘッダーの取得

PSR-7リクエストオブジェクトの getHeaders() メソッドを使用して、すべてのHTTPリクエストヘッダーを連想配列としてフェッチできます。結果として得られる連想配列のキーはヘッダー名であり、その値自体がそれぞれのヘッダー名に対する文字列値の数値配列です。

$headers = $request->getHeaders();
foreach ($headers as $name => $values) {
    echo $name . ": " . implode(", ", $values);
}


単一のヘッダーの取得

PSR-7リクエストオブジェクトの getHeader($name) メソッドを使用して、単一のヘッダーの値を取得できます。これにより、指定されたヘッダー名に対する値の配列が返されます。1つのHTTPヘッダーに複数の値が含まれる場合があることに注意してください。

$headerValueArray = $request->getHeader('Accept');

PSR-7 リクエストオブジェクトの getHeaderLine($name) メソッドを使用して、特定のヘッダーに対する全ての値を含むカンマ区切りの文字列をフェッチすることもできます。getHeader($name) メソッドとは異なり、このメソッドはカンマで区切られた文字列を返します。

$headerValueString = $request->getHeaderLine('Accept');


ヘッダーの検出

PSR-7リクエストオブジェクトの hasHeader($name) メソッドを使用して、ヘッダーの存在をテストできます。

if ($request->hasHeader('Accept')) {
    // Do something
}


リクエストボディ

すべてのHTTPリクエストには本文があります。JSONまたはXMLデータを使用するSlimアプリケーションを構築している場合は、PSR-7リクエストオブジェクトの getParsedBody() メソッドを使用して、HTTPリクエストボディをネイティブなPHP形式にパースできます。ボディ解析はPSR-7の実装ごとに異なることに注意してください。

インストールしたPSR-7実装によっては、着信入力を解析するために、ミドルウェアを実装する必要がある場合があります。以下に、着信した JSON 入力を解析する例を示します。

<?php
 
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
 
class JsonBodyParserMiddleware implements MiddlewareInterface
{
    public function process(Request $request, RequestHandler $handler): Response
    {
        $contentType = $request->getHeaderLine('Content-Type');
 
        if (strstr($contentType, 'application/json')) {
            $contents = json_decode(file_get_contents('php://input'), true);
            if (json_last_error() === JSON_ERROR_NONE) {
                $request = $request->withParsedBody($contents);
            }
        }
 
        return $handler->handle($request);
    }
}
$parsedBody = $request->getParsedBody();

技術的に言えば、PSR-7リクエストオブジェクトは、HTTPリクエストボディを Psr\Http\Message\StreamInterface のインスタンスとして表現しています。PSR-7リクエストオブジェクトの getBody() メソッドを使用して、HTTPリクエストボディの StreamInterface インスタンスを取得できます。getBody() メソッドは、着信HTTPリクエストのサイズが不明であるか、使用可能なメモリに対して大きすぎる場合に適しています。

$body = $request->getBody();

結果として得られる Psr\Http\Message\StreamInterface インスタンスは、基礎となるPHPの resource を読み取って反復するための次のメソッドを提供します。


アップロードファイル

$_FILES でのファイルのアップロードは、Requestオブジェクトの getUploadedFiles() メソッドから利用できます。これは、input 要素の名前でキー設定された配列を返します。

$files = $request->getUploadedFiles();

$files 配列内の各オブジェクトは、Psr\Http\Message\UploadedFileInterface のインスタンスであり、次のメソッドをサポートします。

POSTフォームを使用してファイルをアップロードする方法については、cookbook を参照してください。


リクエストヘルパー

SlimのPSR-7リクエストの実装は、以下の追加の独自メソッドを提供し、HTTPリクエストをさらに検査するのを助けます。

XHRリクエストの検出

リクエストの getHeaderLine() メソッドを使用して、ヘッダー X-Requested-WithXMLHttpRequest であるかどうかを確認することで、XHRリクエストを検出できます。

XHRとはXMLHttpRequestの略で、JavaScriptなどのからサーバとHTTP通信を行うためのAjaxで使われる組み込みオブジェクトの事です。
POST /path HTTP/1.1
Host: example.com
Content-type: application/x-www-form-urlencoded
Content-length: 7
X-Requested-With: XMLHttpRequest

foo=bar
if ($request->getHeaderLine('X-Requested-With') === 'XMLHttpRequest') {
    // Do something
}


コンテンツタイプ

Requestオブジェクトの getHeaderLine() メソッドを使用してHTTPリクエストコンテンツタイプをフェッチできます。

$contentType = $request->getHeaderLine('Content-Type');


コンテンツの長さ

Requestオブジェクトの getHeaderLine() メソッドを使用して、HTTPリクエストのコンテンツの長さをフェッチできます。

$length = $request->getHeaderLine('Content-Length');


サーバーパラメータ

着信リクエストの環境に関連するデータをフェッチするには、getServerParams() を使用する必要があります。

例えば、単一のサーバーパラメータを取得するには:

$params = $request->getServerParams();
$authorization = $params['HTTP_AUTHORIZATION'] ?? null;


ポストパラメータ

you can retrieve all POST parameters as follows:

リクエストメソッドが POST で、Content-Typeapplication/x-www-form-urlencoded または multipart/form-data の場合、次のように全ての POST パラメーターを取得することができます:

// Get all POST parameters
$params = (array)$request->getParsedBody();
 
// Get a single POST parameter
$foo = $params['foo'];


ルートオブジェクト

ミドルウェアでは、ルート(route)のパラメータが必要になる場合があります。

この例では、最初にユーザーがログインしていることを確認し、次にユーザーが表示しようとしている特定のビデオを表示する権限を持っていることを確認しています。

$app
  ->get('/course/{id}', Video::class . ':watch')
  ->add(PermissionMiddleware::class);
<?php
 
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Routing\RouteContext;
 
class PermissionMiddleware
{
    public function __invoke(Request $request, RequestHandler $handler)
    {
        $routeContext = RouteContext::fromRequest($request);
        $route = $routeContext->getRoute();
 
        $courseId = $route->getArgument('id');
 
        // do permission logic...
 
        return $handler->handle($request);
    }
}


ルート内からベースパスを取得する

ルート内からベースパスを取得するには、次の手順を実行します:

<?php
 
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\Routing\RouteContext;
 
require __DIR__ . '/../vendor/autoload.php';
 
$app = AppFactory::create();
 
$app->get('/', function(Request $request, Response $response) {
    $routeContext = RouteContext::fromRequest($request);
    $basePath = $routeContext->getBasePath();
    // ...
 
    return $response;
});


属性

PSR-7を使用すると、さらに処理するために、オブジェクト/値をリクエストオブジェクトに注入することができます。アプリケーションでは、ミドルウェアは多くの場合、ルート(route)クロージャーに情報を渡す必要があります。そのための方法は、属性を介してリクエストオブジェクトに情報を追加することです。

例:リクエストオブジェクトに値を設定します。

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
 
$app->add(function (Request $request, RequestHandler $handler) {
    // Add the session storage to your request as [READ-ONLY]
    $request = $request->withAttribute('session', $_SESSION);
 
    return $handler->handle($request);
});

例:値を取得する方法です。

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
 
$app->get('/test', function (Request $request, Response $response) {
    // Get the session from the request
    $session = $request->getAttribute('session');
 
    $response->getBody()->write('Yay, ' . $session['name']);
 
    return $response;
});

リクエストオブジェクトには、$request->getAttributes() 及び $request->withAttributes() と同じような一括関数もあります。