Skip to content

Commit

Permalink
init package files
Browse files Browse the repository at this point in the history
  • Loading branch information
BMTmohammedtaha committed Jan 5, 2024
0 parents commit 68f52f2
Show file tree
Hide file tree
Showing 4 changed files with 479 additions and 0 deletions.
96 changes: 96 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Effectra/cors

Effectra/cors is a PHP package that provides middleware and service classes for handling Cross-Origin Resource Sharing (CORS) in web applications. CORS is a security feature implemented by web browsers to control access to resources on a different origin.

## Installation

You can install the Effectra/cors package via Composer:

```bash
composer require effectra/cors
```

## Usage

### CorsMiddleware

The `CorsMiddleware` class is a PSR-15 middleware that can be used in a middleware stack to handle CORS requests. It checks incoming requests for CORS-related headers and adds appropriate headers to the response.

#### Example:

```php
use Effectra\Cors\CorsMiddleware;
use Effectra\Cors\CorsService;
use Psr\Http\Server\MiddlewareInterface;

// Create a CorsService instance with desired configuration
$corsService = new CorsService([
'allowedOrigins' => ['https://example.com'],
'allowedMethods' => ['GET', 'POST'],
'allowedHeaders' => ['Content-Type'],
]);

// Create the CorsMiddleware instance
$corsMiddleware = new CorsMiddleware($corsService, ['/api']);

// Add the middleware to your middleware stack
$middlewareStack = [
// Other middleware...
$corsMiddleware,
// Other middleware...
];
```

### CorsService

The `CorsService` class provides the core functionality for handling CORS requests. It allows you to configure various CORS-related settings.

#### Example:

```php
use Effectra\Cors\CorsService;

// Create a CorsService instance with desired configuration
$corsService = new CorsService([
'allowedOrigins' => ['https://example.com'],
'allowedMethods' => ['GET', 'POST'],
'allowedHeaders' => ['Content-Type'],
]);

// Check if a request is a CORS request
$isCorsRequest = $corsService->isCorsRequest($request);

// Check if a request is a preflight request
$isPreflightRequest = $corsService->isPreflightRequest($request);

// Handle a preflight request and add necessary headers to the response
$preflightResponse = $corsService->handlePreflightRequest($request);

// Check if a specific origin is allowed
$isOriginAllowed = $corsService->isOriginAllowed($request);

// Add CORS headers to the actual response
$actualResponse = $corsService->addActualRequestHeaders($response, $request);
```

## Configuration

The `CorsService` class allows you to configure various CORS-related settings using an options array.

### Available Options:

- `allowedOrigins`: An array of allowed origins.
- `allowedOriginsPatterns`: An array of allowed origin patterns (wildcards).
- `allowedMethods`: An array of allowed HTTP methods.
- `allowedHeaders`: An array of allowed headers.
- `supportsCredentials`: Whether credentials (cookies, HTTP authentication) should be supported.
- `maxAge`: Maximum time (in seconds) that the results of a preflight request can be cached.
- `exposedHeaders`: An array of headers exposed to the response.

## Contributing

If you'd like to contribute to this project, please follow our [contribution guidelines](CONTRIBUTING.md).

## License

The Effectra/cors package is open-sourced software licensed under the [MIT license](LICENSE).
23 changes: 23 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "effectra/cors",
"description": "PHP library for enabling CORS (Cross-Origin Resource Sharing) in HTTP requests/responses. It follows PSR guidelines, and can be easily integrated into PHP projects.",
"type": "library",
"license": "MIT",
"autoload": {
"psr-4": {
"Effectra\\Cors\\": "src/"
}
},
"authors": [
{
"name": "Mohammed Taha",
"email": "info@mohammedtaha.net"
}
],
"require": {
"psr/http-message": "^2.0@dev",
"psr/http-server-handler": "^1.0@dev",
"psr/http-server-middleware": "^1.0@dev"
},
"minimum-stability": "stable"
}
119 changes: 119 additions & 0 deletions src/CorsMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?php

namespace Effectra\Cors;

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class CorsMiddleware implements MiddlewareInterface
{
/** @var CorsService $cors */
protected $cors;


protected array $paths = [];

public function __construct(CorsService $cors, array $paths = [])
{
$this->cors = $cors;
$this->paths = $paths;
}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
// Check if we're dealing with CORS and if we should handle it
if (!$this->shouldRun($request)) {
return $handler->handle($request);
}

// For Preflight, return the Preflight response
if ($this->cors->isPreflightRequest($request)) {
$response = $this->cors->handlePreflightRequest($request);

$this->cors->varyHeader($response, 'Access-Control-Request-Method');

return $response;
}

// Handle the request
$response = $handler->handle($request);

if ($request->getMethod() === 'OPTIONS') {
$this->cors->varyHeader($response, 'Access-Control-Request-Method');
}

return $this->addHeaders($request, $response);
}

/**
* Add the headers to the Response, if they don't exist yet.
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
protected function addHeaders(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
if (!$response->hasHeader('Access-Control-Allow-Origin')) {
// Add the CORS headers to the Response
$response = $this->cors->addActualRequestHeaders($response, $request);
}

return $response;
}

/**
* Determine if the request has a URI that should pass through the CORS flow.
*
* @param ServerRequestInterface $request
* @return bool
*/
protected function shouldRun(ServerRequestInterface $request): bool
{
return $this->isMatchingPath($request);
}

/**
* The path from the config, to see if the CORS Service should run
*
* @param ServerRequestInterface $request
* @return bool
*/
protected function isMatchingPath(ServerRequestInterface $request): bool
{
// Get the paths from the config or the middleware
$paths = $this->getPathsByHost($request->getUri()->getHost());

foreach ($paths as $path) {
if ($path !== '/') {
$path = trim($path, '/');
}

if ($request->getUri()->getPath() === $path || $request->getUri()->getPath() === $path) {
return true;
}
}

return false;
}

/**
* Paths by given host or string values in config by default
*
* @param string $host
* @return array
*/
protected function getPathsByHost(string $host): array
{
// If there are paths by the given host
if (isset($this->paths[$host])) {
return $this->paths[$host];
}
// Defaults
return array_filter($this->paths, function ($path) {
return is_string($path);
});
}
}
Loading

0 comments on commit 68f52f2

Please sign in to comment.