CorsMiddleware.php 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. <?php
  2. namespace Middlewares;
  3. use Psr\Http\Message\ResponseInterface;
  4. use Psr\Http\Message\ServerRequestInterface;
  5. use React\Http\Message\Response;
  6. use React\Promise\PromiseInterface;
  7. class CorsMiddleware
  8. {
  9. private ?string $forcedOrigin;
  10. public function __construct()
  11. {
  12. $origin = $_ENV['CORS_ALLOWED_ORIGIN'] ?? '';
  13. $this->forcedOrigin = $origin !== '' ? $origin : null;
  14. }
  15. public function __invoke(ServerRequestInterface $request, callable $next)
  16. {
  17. $origin = $this->resolveOrigin($request);
  18. if (strtoupper($request->getMethod()) === 'OPTIONS') {
  19. return $this->preflightResponse($origin);
  20. }
  21. $response = $next($request);
  22. return $this->decorateResponse($response, $origin);
  23. }
  24. /**
  25. * @param ResponseInterface|PromiseInterface $response
  26. * @return ResponseInterface|PromiseInterface
  27. */
  28. private function decorateResponse($response, string $origin)
  29. {
  30. if ($response instanceof PromiseInterface) {
  31. return $response->then(function ($actual) use ($origin) {
  32. return $this->decorateResponse($actual, $origin);
  33. });
  34. }
  35. if ($response instanceof ResponseInterface) {
  36. return $this->applyHeaders($response, $origin);
  37. }
  38. return $response;
  39. }
  40. private function preflightResponse(string $origin): ResponseInterface
  41. {
  42. return $this->applyHeaders(
  43. Response::plaintext('')->withStatus(204),
  44. $origin
  45. );
  46. }
  47. private function applyHeaders(ResponseInterface $response, string $origin): ResponseInterface
  48. {
  49. $response = $response
  50. ->withHeader('Access-Control-Allow-Origin', $origin)
  51. ->withHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS')
  52. ->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
  53. ->withHeader('Access-Control-Max-Age', '86400')
  54. ->withHeader('Vary', 'Origin');
  55. if ($origin !== '*') {
  56. $response = $response->withHeader('Access-Control-Allow-Credentials', 'true');
  57. }
  58. return $response;
  59. }
  60. private function resolveOrigin(ServerRequestInterface $request): string
  61. {
  62. if ($this->forcedOrigin !== null) {
  63. return $this->forcedOrigin;
  64. }
  65. $origin = $request->getHeaderLine('Origin');
  66. return $origin !== '' ? $origin : '*';
  67. }
  68. }