メインメニュー
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/
シンプル ソリューション
単純なCORSリクエストの場合、サーバーはレスポンスに次のヘッダーを追加するだけで済みます。
Access-Control-Allow-Origin: <domain>, ...
The following code should enable lazy CORS.
次のコードは、Lazy 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'); });
最後のルートとして次のルートを追加します:
<?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
次のミドルウェアを使用して、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
リクエストに資格情報(Cookie、承認ヘッダー、またはTLSクライアント証明書)が含まれている場合は、レスポンスオブジェクトに
Access-Control-Allow-Credentials
ヘッダーを追加する必要がある場合があります。$response = $response->withHeader('Access-Control-Allow-Credentials', 'true');
POSTフォームを使ったファイルのアップロード
POSTリクエストのフォームを使用してアップロードされたファイルは、Requestメソッド
getUploadedFiles()
を使用して取得できます。POSTリクエストを使用してファイルをアップロードする場合は、ファイルアップロードフォームに属性
enctype=“multipart/form-data”
があることを確認してください。そうでない場合、getUploadedFiles()
は空の配列を返します。同じ input name に対して複数のファイルがアップロードされる場合は、HTMLのinput nameの後に鍵括弧(
[]
)を追加します。そうでない場合、getUploadedFiles()
によってinput nameに対してアップロードされたファイルが1つだけ返されます。以下は、単一ファイルと複数ファイルの両方のアップロードを含む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>
アップロードされたファイルは、
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.txt · 最終更新: 2020/10/13 21:59 by y2sunlight
コメント