Setting up CORS

CORS - Cross origin resource sharing

A good flowchart for implementing CORS support Reference:

CORS server flowchart

You can test your CORS Support here: http://www.test-cors.org/

You can read the specification here: 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:

Access-Control-Allow-Origin: <domain>, … | *

The following code should enable lazy CORS.

  1. $app->options('/{routes:.+}', function ($request, $response, $args) {
  2. return $response;
  3. });
  4. $app->add(function ($req, $res, $next) {
  5. $response = $next($req, $res);
  6. return $response
  7. ->withHeader('Access-Control-Allow-Origin', 'http://mysite')
  8. ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
  9. ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
  10. });

Add the following route as the last route:

  1. // Catch-all route to serve a 404 Not Found page if none of the routes match
  2. // NOTE: make sure this route is defined last
  3. $app->map(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], '/{routes:.+}', function($req, $res) {
  4. $handler = $this->notFoundHandler; // handle using the default Slim page not found handler
  5. return $handler($req, $res);
  6. });

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:

  1. require __DIR__ . "/vendor/autoload.php";
  2. // This Slim setting is required for the middleware to work
  3. $app = new Slim\App([
  4. "settings" => [
  5. "determineRouteBeforeAppMiddleware" => true,
  6. ]
  7. ]);
  8. // This is the middleware
  9. // It will add the Access-Control-Allow-Methods header to every request
  10. $app->add(function($request, $response, $next) {
  11. $route = $request->getAttribute("route");
  12. $methods = [];
  13. if (!empty($route)) {
  14. $pattern = $route->getPattern();
  15. foreach ($this->router->getRoutes() as $route) {
  16. if ($pattern === $route->getPattern()) {
  17. $methods = array_merge_recursive($methods, $route->getMethods());
  18. }
  19. }
  20. //Methods holds all of the HTTP Verbs that a particular route handles.
  21. } else {
  22. $methods[] = $request->getMethod();
  23. }
  24. $response = $next($request, $response);
  25. return $response->withHeader("Access-Control-Allow-Methods", implode(",", $methods));
  26. });
  27. $app->get("/api/{id}", function($request, $response, $arguments) {
  28. });
  29. $app->post("/api/{id}", function($request, $response, $arguments) {
  30. });
  31. $app->map(["DELETE", "PATCH"], "/api/{id}", function($request, $response, $arguments) {
  32. });
  33. // Pay attention to this when you are using some javascript front-end framework and you are using groups in slim php
  34. $app->group('/api', function () {
  35. // Due to the behaviour of browsers when sending PUT or DELETE request, you must add the OPTIONS method. Read about preflight.
  36. $this->map(['PUT', 'OPTIONS'], '/{user_id:[0-9]+}', function ($request, $response, $arguments) {
  37. // Your code here...
  38. });
  39. });
  40. $app->run();

A big thank you to tuupola for coming up with this!