メインメニュー
XAMPP アレンジ
IED
WSL2
-
道具箱
リポジトリ編
フレームワーク編
公開ソフトウェア
メタ
リンク
- PHP ライブラリ
- PHP 言語
slim:4:cookbook目次
文書の過去の版を表示しています。
Slim4 クックブック
Version 4.5.0
— y2sunlight 2020-09-23
関連記事
- Slim4 クックブック
本章は以下のサイトの Cook book のセクションを翻訳し若干の補足を加えたのもです。
ルートパターンの末尾のスラッシュ(/)
Slimは、末尾にスラッシュがあるURLパターンを、無いものとは異なるものとして扱います。つまり、
/user
と/user/
は異なるので、異なるコールバックをアタッチできます。For GET requests a permanent redirect is fine, but for other request methods like POST or PUT the browser will send the second request with the GET method. To avoid this you simply need to remove the trailing slash and pass the manipulated url to the next middleware.
GETリクエストの場合、パーマネント(permanent)リダイレクトは問題ありませんが、POSTやPUTなどの他のリクエストメソッドの場合、ブラウザはGETメソッドを使用して2番目のリクエストを送信します。これを回避するには、単に、末尾のスラッシュを削除し、操作されたURLを次のミドルウェアに渡す必要があります。
/
で終わるすべてのURLを、末尾以外の/
に相当するものにリダイレクトまたはリライトする場合、次のミドルウェアを追加できます。<?php use Psr\Http\Message\RequestInterface as Request; use Psr\Http\Server\RequestHandlerInterface RequestHandler; use Slim\Factory\AppFactory; use Slim\Psr7\Response; require __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); $app->add(function (Request $request, RequestHandler $handler) { $uri = $request->getUri(); $path = $uri->getPath(); if ($path != '/' && substr($path, -1) == '/') { // recursively remove slashes when its more than 1 slash $path = rtrim($path, '/'); // permanently redirect paths with a trailing slash // to their non-trailing counterpart $uri = $uri->withPath($path); if ($request->getMethod() == 'GET') { $response = new Response(); return $response ->withHeader('Location', (string) $uri) ->withStatus(301); } else { $request = $request->withUri($uri); } } return $handler->handle($request); });
あるいは、middlewares/trailing-slash ミドルウェアを検討してください。これにより、すべてのURLに末尾のスラッシュを強制的に追加することもできます。
use Middlewares\TrailingSlash; $app->add(new TrailingSlash(true)); // true adds the trailing slash (false removes it)
現在のルートの取得
アプリケーション内の現在のルートにアクセスする必要がある場合は、着信時の
ServerRequestInterface
を使用してRouteContext
オブジェクトをインスタンス化する必要があります。そこから、
$routeContext→getRoute()
を介してルートを取得し、getName()
を使用してルートの名前にアクセスするか、getMethods()
などを介してこのルートでサポートされているメソッドを取得できます。注:ルート(route)ハンドラーに到達する前にミドルウェアサイクル中に
RouteContext
オブジェクトにアクセスする必要がある場合は、エラー処理ミドルウェアの前に、RoutingMiddleware
を最も外側のミドルウェアとして追加する必要があります(以下の例を参照)。例:
<?php use Slim\Exception\HttpNotFoundException; use Slim\Factory\AppFactory; use Slim\Routing\RouteContext; require __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); // Via this middleware you could access the route and routing results from the resolved route $app->add(function (Request $request, RequestHandler $handler) { $routeContext = RouteContext::fromRequest($request); $route = $routeContext->getRoute(); // return NotFound for non existent route if (empty($route)) { throw new HttpNotFoundException($request); } $name = $route->getName(); $groups = $route->getGroups(); $methods = $route->getMethods(); $arguments = $route->getArguments(); // ... do something with the data ... return $handler->handle($request); }); // The RoutingMiddleware should be added after our CORS middleware so routing is performed first $app->addRoutingMiddleware(); // The ErrorMiddleware should always be the outermost middleware $app->addErrorMiddleware(true, true, true); // ... $app->run();
CORSの設定
CORS - クロス オリジンリソース シェアリング
- CORSサポートを実装するための適切なフローチャートリファレンス:
CORSサーバーのフローチャート - CORSサポートはここでテストできます:http://www.test-cors.org/
- ここで仕様を読むことができます:https://www.w3.org/TR/cors/
The simple solution
For simple CORS requests, the server only needs to add the following header to its response:
単純なCORSリクエストの場合、サーバーは応答に次のヘッダーを追加するだけで済みます。
Access-Control-Allow-Origin: <domain>, ...
The following code should enable lazy CORS.
次のコードは、レイジーCORSを有効にする必要があります。
$app->options('/{routes:.+}', function ($request, $response, $args) { return $response; }); $app->add(function ($request, $handler) { $response = $handler->handle($request); return $response ->withHeader('Access-Control-Allow-Origin', 'http://mysite') ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization') ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS'); });
Add the following route as the last route:
最後のルートとして次のルートを追加します:
<?php use Slim\Exception\HttpNotFoundException; /** * Catch-all route to serve a 404 Not Found page if none of the routes match * NOTE: make sure this route is defined last */ $app->map(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], '/{routes:.+}', function ($request, $response) { throw new HttpNotFoundException($request); });
Access-Control-Allow-Methods
The following middleware can be used to query Slim’s router and get a list of methods a particular pattern implements.
Here is a complete example application:
次のミドルウェアを使用して、Slimのルーターにクエリを実行し、特定のパターンが実装するメソッドのリストを取得できます。
これが完全なサンプルアプリケーションです:
<?php use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Server\RequestHandlerInterface; use Slim\Factory\AppFactory; use Slim\Routing\RouteCollectorProxy; use Slim\Routing\RouteContext; require_once __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); $app->addBodyParsingMiddleware(); // This middleware will append the response header Access-Control-Allow-Methods with all allowed methods $app->add(function (Request $request, RequestHandlerInterface $handler): Response { $routeContext = RouteContext::fromRequest($request); $routingResults = $routeContext->getRoutingResults(); $methods = $routingResults->getAllowedMethods(); $requestHeaders = $request->getHeaderLine('Access-Control-Request-Headers'); $response = $handler->handle($request); $response = $response->withHeader('Access-Control-Allow-Origin', '*'); $response = $response->withHeader('Access-Control-Allow-Methods', implode(',', $methods)); $response = $response->withHeader('Access-Control-Allow-Headers', $requestHeaders); // Optional: Allow Ajax CORS requests with Authorization header // $response = $response->withHeader('Access-Control-Allow-Credentials', 'true'); return $response; }); // The RoutingMiddleware should be added after our CORS middleware so routing is performed first $app->addRoutingMiddleware(); // The routes $app->get('/api/v0/users', function (Request $request, Response $response): Response { $response->getBody()->write('List all users'); return $response; }); $app->get('/api/v0/users/{id}', function (Request $request, Response $response, array $arguments): Response { $userId = (int)$arguments['id']; $response->getBody()->write(sprintf('Get user: %s', $userId)); return $response; }); $app->post('/api/v0/users', function (Request $request, Response $response): Response { // Retrieve the JSON data $parameters = (array)$request->getParsedBody(); $response->getBody()->write('Create user'); return $response; }); $app->delete('/api/v0/users/{id}', function (Request $request, Response $response, array $arguments): Response { $userId = (int)$arguments['id']; $response->getBody()->write(sprintf('Delete user: %s', $userId)); return $response; }); // Allow preflight requests // Due to the behaviour of browsers when sending a request, // you must add the OPTIONS method. Read about preflight. $app->options('/api/v0/users', function (Request $request, Response $response): Response { // Do nothing here. Just return the response. return $response; }); // Allow additional preflight requests $app->options('/api/v0/users/{id}', function (Request $request, Response $response): Response { return $response; }); // Using groups $app->group('/api/v0/users/{id:[0-9]+}', function (RouteCollectorProxy $group) { $group->put('', function (Request $request, Response $response, array $arguments): Response { // Your code here... $userId = (int)$arguments['id']; $response->getBody()->write(sprintf('Put user: %s', $userId)); return $response; }); $group->patch('', function (Request $request, Response $response, array $arguments): Response { $userId = (int)$arguments['id']; $response->getBody()->write(sprintf('Patch user: %s', $userId)); return $response; }); // Allow preflight requests $group->options('', function (Request $request, Response $response): Response { return $response; }); }); $app->run();
Access-Control-Allow-Credentials
If the request contains credentials (cookies, authorization headers or TLS client certificates), you might need to add an
Access-Control-Allow-Credentials
header to the response object.要求に資格情報(Cookie、承認ヘッダー、またはTLSクライアント証明書)が含まれている場合は、応答オブジェクトに
Access-Control-Allow-Credentials
ヘッダーを追加する必要がある場合があります。$response = $response->withHeader('Access-Control-Allow-Credentials', 'true');
Uploading files using POST forms
Files that are uploaded using forms in POST requests can be retrieved with the Request method getUploadedFiles().
POSTリクエストのフォームを使用してアップロードされたファイルは、Requestメソッド
getUploadedFiles()
を使用して取得できます。When uploading files using a POST request, make sure your file upload form has the attribute
enctype=“multipart/form-data”
otherwisegetUploadedFiles()
will return an empty array.POSTリクエストを使用してファイルをアップロードする場合は、ファイルアップロードフォームに属性
enctype=“multipart/form-data”
があることを確認してください。そうでない場合、getUploadedFiles()
は空の配列を返します。If multiple files are uploaded for the same input name, add brackets after the input name in the HTML, otherwise only one uploaded file will be returned for the input name by getUploadedFiles().
同じ入力名に対して複数のファイルがアップロードされる場合は、HTMLの入力名の後に括弧を追加します。そうでない場合、
getUploadedFiles()
によって入力名に対してアップロードされたファイルが1つだけ返されます。Below is an example HTML form that contains both single and multiple file uploads.
以下は、単一ファイルと複数ファイルの両方のアップロードを含むHTMLフォームの例です。
<!-- make sure the attribute enctype is set to multipart/form-data --> <form method="post" enctype="multipart/form-data"> <!-- upload of a single file --> <p> <label>Add file (single): </label><br/> <input type="file" name="example1"/> </p> <!-- multiple input fields for the same input name, use brackets --> <p> <label>Add files (up to 2): </label><br/> <input type="file" name="example2[]"/><br/> <input type="file" name="example2[]"/> </p> <!-- one file input field that allows multiple files to be uploaded, use brackets --> <p> <label>Add files (multiple): </label><br/> <input type="file" name="example3[]" multiple="multiple"/> </p> <p> <input type="submit"/> </p> </form>
Uploaded files can be moved to a directory using the moveTo method. Below is an example application that handles the uploaded files of the HTML form above.
アップロードされたファイルは、
moveTo
メソッドを使用してディレクトリに移動できます。以下は、上記のHTMLフォームのアップロードされたファイルを処理するサンプルアプリケーションです。<?php use DI\ContainerBuilder; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\UploadedFileInterface; use Slim\Factory\AppFactory; require __DIR__ . '/../vendor/autoload.php'; $containerBuilder = new ContainerBuilder(); $container = $containerBuilder->build(); $container->set('upload_directory', __DIR__ . '/uploads'); AppFactory::setContainer($container); $app = AppFactory::create(); $app->post('/', function (ServerRequestInterface $request, ResponseInterface $response) { $directory = $this->get('upload_directory'); $uploadedFiles = $request->getUploadedFiles(); // handle single input with single file upload $uploadedFile = $uploadedFiles['example1']; if ($uploadedFile->getError() === UPLOAD_ERR_OK) { $filename = moveUploadedFile($directory, $uploadedFile); $response->getBody()->write('Uploaded: ' . $filename . '<br/>'); } // handle multiple inputs with the same key foreach ($uploadedFiles['example2'] as $uploadedFile) { if ($uploadedFile->getError() === UPLOAD_ERR_OK) { $filename = moveUploadedFile($directory, $uploadedFile); $response->getBody()->write('Uploaded: ' . $filename . '<br/>'); } } // handle single input with multiple file uploads foreach ($uploadedFiles['example3'] as $uploadedFile) { if ($uploadedFile->getError() === UPLOAD_ERR_OK) { $filename = moveUploadedFile($directory, $uploadedFile); $response->getBody()->write('Uploaded: ' . $filename . '<br/>'); } } return $response; }); /** * Moves the uploaded file to the upload directory and assigns it a unique name * to avoid overwriting an existing uploaded file. * * @param string $directory The directory to which the file is moved * @param UploadedFileInterface $uploadedFile The file uploaded file to move * * @return string The filename of moved file */ function moveUploadedFile(string $directory, UploadedFileInterface $uploadedFile) { $extension = pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION); // see http://php.net/manual/en/function.random-bytes.php $basename = bin2hex(random_bytes(8)); $filename = sprintf('%s.%0.8s', $basename, $extension); $uploadedFile->moveTo($directory . DIRECTORY_SEPARATOR . $filename); return $filename; } $app->run();
slim/4/cookbook.1602590881.txt.gz · 最終更新: 2020/10/13 21:08 by y2sunlight
コメント