zestic / cors-middleware
PSR-7 and PSR-15 CORS middleware
Requires
- php: ^8.3
- apploud/cors-psr7: ^3.0
- psr/http-message: ^1.0.1|^2.0
- psr/http-server-middleware: ^1.0
- tuupola/callable-handler: ^1.0
- tuupola/http-factory: ^1.0.2
Requires (Dev)
- equip/dispatch: ^2.0
- nyholm/psr7: ^1.8
- overtrue/phplint: ^3.0
- phpstan/phpstan: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^8.5.30|^9.0
- rector/rector: ^2.0
- symplify/easy-coding-standard: ^11.1
This package is auto-updated.
Last update: 2024-12-26 21:19:06 UTC
README
This middleware implements Cross-origin resource sharing. It supports both PSR-7 style doublepass and PSR-15 middleware standards. It has been tested with Laminas Mezzio. Internally the middleware uses neomerx/cors-psr7 library for heavy lifting.
Install
Install using composer.
$ composer require zestic/cors-middleware
Usage
Documentation assumes you have working knowledge of CORS. There are no mandatory parameters. If you are using Laminas Mezzio the skeleton middlewares are added to file called config/pipeline.php
. Note that you must disable the default ImplicitOptionsMiddleware
for this middleware to work.
use Zestic\Middleware\CorsMiddleware; #$app->pipe(ImplicitOptionsMiddleware::class); $app->pipe(CorsMiddleware::class);
Slim Framework does not have specified config files. Otherwise adding the middleware is similar with previous.
$app->add(new Zestic\Middleware\CorsMiddleware);
Rest of the examples use Slim Framework.
If called without any parameters the following defaults are used.
$app->add(new Zestic\Middleware\CorsMiddleware([ "origin" => ["*"], "methods" => ["GET", "POST", "PUT", "PATCH", "DELETE"], "headers.allow" => [], "headers.expose" => [], "credentials" => false, "cache" => 0, ]));
$ curl "https://api.example.com/" \ --request OPTIONS \ --include --header "Access-Control-Request-Method: PUT" \ --header "Origin: http://www.example.com" HTTP/1.1 200 OK Access-Control-Allow-Origin: http://www.example.com Vary: Origin Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE
However, you most likely want to change some of the defaults. For example if developing a REST API which supports caching and conditional requests you could use the following.
$app->add(new Zestic\Middleware\CorsMiddleware([ "origin" => ["*"], "methods" => ["GET", "POST", "PUT", "PATCH", "DELETE"], "headers.allow" => ["Authorization", "If-Match", "If-Unmodified-Since"], "headers.expose" => ["Etag"], "credentials" => true, "cache" => 86400 ]));
$ curl "https://api.example.com/foo" \ --request OPTIONS \ --include \ --header "Origin: http://www.example.com" \ --header "Access-Control-Request-Method: PUT" \ --header "Access-Control-Request-Headers: Authorization, If-Match" HTTP/1.1 200 OK Access-Control-Allow-Origin: http://www.example.com Access-Control-Allow-Credentials: true Vary: Origin Access-Control-Max-Age: 86400 Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE Access-Control-Allow-Headers: authorization, if-match, if-unmodified-since
$ curl "https://api.example.com/foo" \ --request PUT \ --include \ --header "Origin: http://www.example.com" HTTP/1.1 200 OK Access-Control-Allow-Origin: http://www.example.com Access-Control-Allow-Credentials: true Vary: Origin Access-Control-Expose-Headers: Etag
Parameters
Origin
By default all origins are allowed. You can limit allowed origins by passing them as an array.
$app->add(new Zestic\Middleware\CorsMiddleware([ "origin" => ["app-1.example.com", "app-2.example.com"] ]));
You can also use wildcards to define multiple origins at once. Wildcards are matched by using the fnmatch() function.
$app->add(new Zestic\Middleware\CorsMiddleware([ "origin" => ["*.example.com"] ]));
Methods
Methods can be passed either as an array or a callable which returns an array. Below example is for Zend Expressive where value of methods
is dynamic depending on the requested route.
use Zestic\Middleware\CorsMiddleware; use Zend\Expressive\Router\RouteResult; $app->pipe(new CorsMiddleware([ "origin" => ["*"], "methods" => function($request) { $result = $request->getAttribute(RouteResult::class); $route = $result->getMatchedRoute(); return $route->getAllowedMethods(); } ]));
Same thing for Slim 3. This assumes you have not defined the OPTIONS
route.
use Fastroute\Dispatcher; use Zestic\Middleware\CorsMiddleware; $app->add( new CorsMiddleware([ "origin" => ["*"], "methods" => function($request) use ($app) { $container = $app->getContainer(); $dispatch = $container["router"]->dispatch($request); if (Dispatcher::METHOD_NOT_ALLOWED === $dispatch[0]) { return $dispatch[1]; } } ]) );
Logger
The optional logger
parameter allows you to pass in a PSR-3 compatible logger to help with debugging or other application logging needs.
$logger = Monolog\Logger("slim"); $rotating = new RotatingFileHandler(__DIR__ . "/logs/slim.log", 0, Logger::DEBUG); $logger->pushHandler($rotating); $app->add(new Zestic\Middleware\CorsMiddleware([ "logger" => $logger, ]));
Error
Error is called when CORS request fails. It receives last error message in arguments. This can be used for example to create application/json
responses when CORS request fails.
$app->add(new Zestic\Middleware\CorsMiddleware([ "methods" => ["GET", "POST", "PUT"], "error" => function ($request, $response, $arguments) { $data["status"] = "error"; $data["message"] = $arguments["message"]; return $response ->withHeader("Content-Type", "application/json") ->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); } ]));
$ curl https://api.example.com/foo \
--request OPTIONS \
--include \
--header "Access-Control-Request-Method: PATCH" \
--header "Origin: http://www.example.com"
HTTP/1.1 401 Unauthorized
Content-Type: application/json
Content-Length: 83
{
"status": "error",
"message": "CORS requested method is not supported."
}
Server origin
If your same-origin requests contain an unnecessary Origin
header, they might get blocked in case the server origin is not among the allowed origins already. In this case you can use the optional origin.server
parameter to specify the origin of the server.
$app->add(new Zestic\Middleware\CorsMiddleware([ "origin.server" => "https://example.com" ]));
$ curl https://example.com/api \
--request POST \
--include \
--header "Origin: https://example.com"
HTTP/1.1 200 OK
Testing
vendor/bin/phpunit
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email develop@zestic.com instead of using the issue tracker.
License
The MIT License (MIT). Please see License File for more information.