要求

Slim app 的路由和中間件給予一個 PSR-7 請求物件,代表網路伺服器接收到的目前 HTTP 請求。請求物件實作 PSR-7 ServerRequestInterface,您可以使用它來檢視和操作 HTTP 請求方法、標頭和主體。

如何取得 Request 物件

PSR-7 請求物件注入至 Slim 應用程式路由,作為路由回呼的第一個參數,如下所示

<?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 應用程式「中間件」,作為中間件可呼叫物件的第一個參數,如下所示

將 PSR-7 請求注入應用程式中間件

<?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();

Request HTTP 方法

每個 HTTP 請求都有一個方法,通常為下列之一

  • GET
  • POST
  • PUT
  • DELETE
  • HEAD
  • PATCH
  • OPTIONS

您可以使用 Request 物件方法,適當地命名為 getMethod(),來檢視 HTTP 請求的方法。

$method = $request->getMethod();

可以偽造或「覆寫」HTTP 請求方法。這很有用,例如,如果您需要模擬使用只支援 GETPOST 請求的傳統網路瀏覽器進行的 PUT 請求。

注意: 要啟用請求方法替代,必須在應用程式中注入Method Overriding Middleware

有兩種方法可以替代 HTTP 請求方法。你可以在 POST 請求主體中包含 METHOD 參數。HTTP 請求必須使用 application/x-www-form-urlencoded 內容類型。

使用 _METHOD 參數替代 HTTP 方法

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"}

伺服器參數

若要擷取與傳入請求環境相關的資料,你將需要使用 getServerParams()。例如,若要取得單一伺服器參數

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

POST 參數

如果請求方法是 POSTContent-Typeapplication/x-www-form-urlencodedmultipart/form-data,你可以照下列範例擷取所有 POST 參數

// Get all POST parameters
$params = (array)$request->getParsedBody();

// Get a single POST parameter
$foo = $params['foo'];

請求 URI

每個 HTTP 請求都有 URI,用於識別請求的應用程式資源。HTTP 請求 URI 包含下列幾個部分

  • 架構 (例如 httphttps)
  • 主機 (例如 example.com)
  • 連接埠 (例如 80443)
  • 路徑 (例如 /users/1)
  • 查詢字串 (例如 sort=created&dir=asc)

你可以使用 getUri() 方法擷取 PSR-7 請求物件的 URI 物件

$uri = $request->getUri();

PSR-7 請求物件的 URI 本身是一個物件,提供下列方法以檢查 HTTP 請求 URL 的部分

  • getScheme()
  • getAuthority()
  • getUserInfo()
  • getHost()
  • getPort()
  • getPath()
  • getQuery() (傳回完整的查詢字串,例如 a=1&b=2)
  • getFragment()

你可以在請求物件上使用 getQueryParams(),以關聯式陣列取得查詢參數。

查詢字串參數

getQueryParams() 方法會以關聯式陣列擷取 HTTP 請求 URI 中的所有查詢參數。

如果沒有查詢參數,它會傳回一個空陣列。

在內部,此方法使用 parse_str 將查詢字串解析為一個陣列。

用法

// URL: https://example.com/search?key1=value1&key2=value2
$queryParams = $request->getQueryParams();
Array
(
    [key1] => value1
    [key2] => value2
)

要從查詢參數陣列讀取單一值,則可以使用參數的名稱作為金鑰。

// Output: value1
$key1 = $queryParams['key1'] ?? null;

// Output: value2
$key2 = $queryParams['key2'] ?? null;

// Output: null
$key3 = $queryParams['key3'] ?? null;

注意: ?? null 可確保如果查詢參數不存在,則會傳回 null,而不是導致警告。

要求標頭

每個 HTTP 要求都有標頭。這些是描述 HTTP 要求的元資料,但不會顯示在要求的主體中。Slim 的 PSR-7 要求物件提供多種方法來檢查其標頭。

取得所有標頭

您可以使用 PSR-7 要求物件的 getHeaders() 方法,以關聯式陣列的形式擷取所有 HTTP 要求標頭。產生的關聯式陣列的金鑰是標頭名稱,而其值是一個數字陣列,其中包含各自標頭名稱的字串值。

$headers = $request->getHeaders();
foreach ($headers as $name => $values) {
    echo $name . ": " . implode(", ", $values);
}
圖 5:以關聯式陣列的形式擷取和反覆處理所有 HTTP 要求標頭。

取得一個標頭

您可以使用 PSR-7 要求物件的 getHeader($name) 方法取得單一標頭的值。這會傳回給定標頭名稱的值陣列。請記住,單一 HTTP 標頭可能會有多個值!

取得特定 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
}

偵測 XHR 要求

您可以使用要求物件的 getHeaderLine() 方法,查看標頭 X-Requested-With 是否是 XMLHttpRequest 來偵測 XHR 要求。

XHR 要求範例

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
}

內容類型

可以使用要求物件的 getHeaderLine() 方法擷取 HTTP 要求內容類型。

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

內容長度

可以使用要求物件的 getHeaderLine() 方法擷取 HTTP 要求內容長度。

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

要求主體

每個 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);
    }
}

將 HTTP 要求內文剖析為原生的 PHP 格式

$parsedBody = $request->getParsedBody();

技術上來說,PSR-7 Request 物件會將 HTTP 要求內文表示為 Psr\Http\Message\StreamInterface 的執行個體。您可以透過 PSR-7 Request 物件的 getBody() 方法取得 HTTP 要求內文的 StreamInterface 執行個體。如果傳入的 HTTP 要求大小不明,或太大以致無法使用現有記憶體,則建議使用 getBody() 方法。

取得 HTTP 要求內文

$body = $request->getBody();

結果的 Psr\Http\Message\StreamInterface 執行個體會提供以下方法,以讀取並反覆運算其底層的 PHP 資源

  • getSize()
  • tell()
  • eof()
  • isSeekable()
  • seek()
  • rewind()
  • isWritable()
  • write($string)
  • isReadable()
  • read($length)
  • getContents()
  • getMetadata($key = null)

上傳的檔案

上傳至 $_FILES 中的檔案,可透過 Request 物件的 getUploadedFiles() 方法取得。這會傳回一個陣列,其金鑰為 input 元素的名稱。

取得上傳的檔案

$files = $request->getUploadedFiles();

$files 陣列中的每個物件都是 Psr\Http\Message\UploadedFileInterface 的執行個體,支援以下方法

  • getStream()
  • moveTo($targetPath)
  • getSize()
  • getError()
  • getClientFilename()
  • getClientMediaType()

請參閱食譜,了解如何使用 POST 檔案上傳檔案。

屬性

透過 PSR-7,您可以將物件/數值注入 request 物件以進行進一步處理。在您的應用程式中,中間件常常需要將資訊傳遞給您的路由封閉,而這麼做的方式是透過屬性將其加入 request 物件。

範例,設定您的 request 物件上的數值。

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 物件也有批次函式。 $request->getAttributes()$request->withAttributes()