Skip to content

Instantly share code, notes, and snippets.

@agungsugiarto
Last active September 18, 2025 05:02
Show Gist options
  • Select an option

  • Save agungsugiarto/28ff3eaf8e64b5a87de85e7f5e2e6b58 to your computer and use it in GitHub Desktop.

Select an option

Save agungsugiarto/28ff3eaf8e64b5a87de85e7f5e2e6b58 to your computer and use it in GitHub Desktop.

Revisions

  1. agungsugiarto revised this gist May 13, 2023. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion codeigniter3-cors.md
    Original file line number Diff line number Diff line change
    @@ -341,4 +341,5 @@ class API_Controller extends CI_Controller

    ### Reference
    1. [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
    2. [CORS for PHP (using the Symfony HttpFoundation)](https://github.com/fruitcake/php-cors)
    2. [CORS for PHP (using the Symfony HttpFoundation)](https://github.com/fruitcake/php-cors)
    3. [CORS Filter for CodeIgniter 4](https://github.com/agungsugiarto/codeigniter4-cors)
  2. agungsugiarto revised this gist May 13, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion codeigniter3-cors.md
    Original file line number Diff line number Diff line change
    @@ -322,7 +322,7 @@ class Cors
    }
    ```

    ### 3. In the constructor of your controller, please add this line of code.
    ### 3. In the constructor of your controller, add this line of code.

    ```php
    <?php
  3. agungsugiarto renamed this gist May 13, 2023. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. agungsugiarto revised this gist Mar 16, 2023. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions cors.md
    Original file line number Diff line number Diff line change
    @@ -45,11 +45,11 @@ $config = [
    | max_age | Sets the Access-Control-Max-Age response header. | `0` |
    | supports_credentials | Sets the Access-Control-Allow-Credentials header. | `false` |

    The _allowedMethods_ and _allowedHeaders_ options are case-insensitive.
    The _allowed_methods_ and _allowed_headers_ options are case-insensitive.

    You don't need to provide both _allowedOrigins_ and _allowedOriginsPatterns_. If one of the strings passed matches, it is considered a valid origin. A wildcard in allowedOrigins will be converted to a pattern.
    You don't need to provide both _allowed_origins_ and _allowed_origins_patterns_. If one of the strings passed matches, it is considered a valid origin. A wildcard in allowed_origins will be converted to a pattern.

    If `['*']` is provided to _allowedMethods_, _allowedOrigins_ or _allowedHeaders_ all methods / origins / headers are allowed.
    If `['*']` is provided to _allowed_methods_, _allowed_origins_ or _allowed_headers_ all methods / origins / headers are allowed.

    > Note: Allowing a single static origin will improve cacheability.
  5. agungsugiarto revised this gist Mar 16, 2023. 1 changed file with 20 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions cors.md
    Original file line number Diff line number Diff line change
    @@ -33,6 +33,26 @@ $config = [
    'supports_credentials' => false,
    ];
    ```
    #### Options

    | Option | Description | Default value |
    |------------------------|------------------------------------------------------------|---------------|
    | allowed_methods | Matches the request method. | `['*']` |
    | allowed_origins | Matches the request origin. | `['*']` |
    | allowed_origins_patterns | Matches the request origin with `preg_match`. | `[]` |
    | allowed_headers | Sets the Access-Control-Allow-Headers response header. | `['*']` |
    | exposed_headers | Sets the Access-Control-Expose-Headers response header. | `[]` |
    | max_age | Sets the Access-Control-Max-Age response header. | `0` |
    | supports_credentials | Sets the Access-Control-Allow-Credentials header. | `false` |

    The _allowedMethods_ and _allowedHeaders_ options are case-insensitive.

    You don't need to provide both _allowedOrigins_ and _allowedOriginsPatterns_. If one of the strings passed matches, it is considered a valid origin. A wildcard in allowedOrigins will be converted to a pattern.

    If `['*']` is provided to _allowedMethods_, _allowedOrigins_ or _allowedHeaders_ all methods / origins / headers are allowed.

    > Note: Allowing a single static origin will improve cacheability.

    ### 2. Next, add the Cors class to the application/libraries folder and name the file Cors.php.

  6. agungsugiarto revised this gist Mar 16, 2023. 1 changed file with 7 additions and 9 deletions.
    16 changes: 7 additions & 9 deletions cors.md
    Original file line number Diff line number Diff line change
    @@ -176,10 +176,10 @@ class Cors
    $this->configureAllowedOrigin($response, $request);

    if ($response->get_header('Access-Control-Allow-Origin')) {
    $this->configureAllowCredentials($response, $request);
    $this->configureAllowCredentials($response);
    $this->configureAllowedMethods($response, $request);
    $this->configureAllowedHeaders($response, $request);
    $this->configureMaxAge($response, $request);
    $this->configureMaxAge($response);
    }

    return $response;
    @@ -211,9 +211,8 @@ class Cors
    $this->configureAllowedOrigin($response, $request);

    if ($response->get_header('Access-Control-Allow-Origin')) {
    $this->configureAllowCredentials($response, $request);

    $this->configureExposedHeaders($response, $request);
    $this->configureAllowCredentials($response);
    $this->configureExposedHeaders($response);
    }

    return $response;
    @@ -269,21 +268,21 @@ class Cors
    $response->set_header("Access-Control-Allow-Headers: {$allowHeaders}");
    }

    private function configureAllowCredentials(CI_Output $response, CI_Input $request): void
    private function configureAllowCredentials(CI_Output $response): void
    {
    if ($this->supportsCredentials) {
    $response->set_header('Access-Control-Allow-Credentials: true');
    }
    }

    private function configureExposedHeaders(CI_Output $response, CI_Input $request): void
    private function configureExposedHeaders(CI_Output $response): void
    {
    if ($this->exposedHeaders) {
    $response->set_header(sprintf('Access-Control-Expose-Headers: %s', implode(', ', $this->exposedHeaders)));
    }
    }

    private function configureMaxAge(CI_Output $response, CI_Input $request): void
    private function configureMaxAge(CI_Output $response): void
    {
    if ($this->maxAge !== null) {
    $response->set_header("Access-Control-Max-Age: {$this->maxAge}");
    @@ -301,7 +300,6 @@ class Cors
    return $response;
    }
    }

    ```

    ### 3. In the constructor of your controller, please add this line of code.
  7. agungsugiarto revised this gist Mar 16, 2023. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion cors.md
    Original file line number Diff line number Diff line change
    @@ -319,4 +319,8 @@ class API_Controller extends CI_Controller
    $this->cors->handle();
    }
    }
    ```
    ```

    ### Reference
    1. [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
    2. [CORS for PHP (using the Symfony HttpFoundation)](https://github.com/fruitcake/php-cors)
  8. agungsugiarto revised this gist Mar 16, 2023. 1 changed file with 3 additions and 4 deletions.
    7 changes: 3 additions & 4 deletions cors.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    Add a config file named cors.php in the application/config directory.
    ### 1. Add a config file named cors.php in the application/config directory.

    ```php
    <?php
    @@ -34,7 +34,7 @@ $config = [
    ];
    ```

    Next, add the Cors class to the application/libraries folder and name the file Cors.php.
    ### 2. Next, add the Cors class to the application/libraries folder and name the file Cors.php.

    ```php
    <?php
    @@ -304,8 +304,7 @@ class Cors

    ```

    ## Usage
    In the constructor of your controller, please add this line of code.
    ### 3. In the constructor of your controller, please add this line of code.

    ```php
    <?php
  9. agungsugiarto revised this gist Mar 16, 2023. 2 changed files with 323 additions and 31 deletions.
    323 changes: 323 additions & 0 deletions cors.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,323 @@
    Add a config file named cors.php in the application/config directory.

    ```php
    <?php

    defined('BASEPATH') or exit('No direct script access allowed');

    $config = [
    /*
    |--------------------------------------------------------------------------
    | Cross-Origin Resource Sharing (CORS) Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your settings for cross-origin resource sharing
    | or "CORS". This determines what cross-origin operations may execute
    | in web browsers. You are free to adjust these settings as needed.
    |
    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
    |
    */
    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => false,
    ];
    ```

    Next, add the Cors class to the application/libraries folder and name the file Cors.php.

    ```php
    <?php

    defined('BASEPATH') or exit('No direct script access allowed');

    class Cors
    {
    /** @var CI_Controller */
    protected $ci;

    /** @var string[] */
    private array $allowedOrigins = [];
    /** @var string[] */
    private array $allowedOriginsPatterns = [];
    /** @var string[] */
    private array $allowedMethods = [];
    /** @var string[] */
    private array $allowedHeaders = [];
    /** @var string[] */
    private array $exposedHeaders = [];
    private bool $supportsCredentials = false;
    private ?int $maxAge = 0;

    private bool $allowAllOrigins = false;
    private bool $allowAllMethods = false;
    private bool $allowAllHeaders = false;

    public function __construct()
    {
    $this->ci = &get_instance();
    $this->ci->load->config('cors', true);

    $this->setOptions($this->ci->config->item('cors'));
    }

    public function handle()
    {
    // For Preflight, return the Preflight response
    if ($this->isPreflightRequest($this->ci->input)) {
    $this->handlePreflightRequest($this->ci->input);
    $this->varyHeader($this->ci->output, 'Access-Control-Request-Method');
    }

    if ($this->ci->input->method(true) === 'OPTIONS') {
    $this->varyHeader($this->ci->output, 'Access-Control-Request-Method');
    }

    if (!$this->ci->output->get_header('Access-Control-Allow-Origin')) {
    // Add the CORS headers to the Response
    $this->addActualRequestHeaders($this->ci->output, $this->ci->input);
    }
    }

    public function setOptions(array $options): void
    {
    $this->allowedOrigins = $options['allowed_origins'] ?? $this->allowedOrigins;
    $this->allowedOriginsPatterns = $options['allowed_origins_patterns'] ?? $this->allowedOriginsPatterns;
    $this->allowedMethods = $options['allowed_methods'] ?? $this->allowedMethods;
    $this->allowedHeaders = $options['allowed_headers'] ?? $this->allowedHeaders;
    $this->supportsCredentials = $options['supports_credentials'] ?? $this->supportsCredentials;

    $maxAge = $this->maxAge;
    if (array_key_exists('maxAge', $options)) {
    $maxAge = $options['maxAge'];
    } elseif (array_key_exists('max_age', $options)) {
    $maxAge = $options['max_age'];
    }
    $this->maxAge = $maxAge === null ? null : (int)$maxAge;

    $exposedHeaders = $options['exposed_headers'] ?? $this->exposedHeaders;
    $this->exposedHeaders = $exposedHeaders === false ? [] : $exposedHeaders;

    $this->normalizeOptions();
    }

    private function normalizeOptions(): void
    {
    // Normalize case
    $this->allowedHeaders = array_map('strtolower', $this->allowedHeaders);
    $this->allowedMethods = array_map('strtoupper', $this->allowedMethods);

    // Normalize ['*'] to true
    $this->allowAllOrigins = in_array('*', $this->allowedOrigins);
    $this->allowAllHeaders = in_array('*', $this->allowedHeaders);
    $this->allowAllMethods = in_array('*', $this->allowedMethods);

    // Transform wildcard pattern
    if (!$this->allowAllOrigins) {
    foreach ($this->allowedOrigins as $origin) {
    if (strpos($origin, '*') !== false) {
    $this->allowedOriginsPatterns[] = $this->convertWildcardToPattern($origin);
    }
    }
    }
    }

    /**
    * Create a pattern for a wildcard, based on Str::is() from Laravel
    *
    * @see https://github.com/laravel/framework/blob/5.5/src/Illuminate/Support/Str.php
    * @param string $pattern
    * @return string
    */
    private function convertWildcardToPattern($pattern)
    {
    $pattern = preg_quote($pattern, '#');

    // Asterisks are translated into zero-or-more regular expression wildcards
    // to make it convenient to check if the strings starts with the given
    // pattern such as "*.example.com", making any string check convenient.
    $pattern = str_replace('\*', '.*', $pattern);

    return '#^' . $pattern . '\z#u';
    }

    public function isCorsRequest(CI_Input $request): bool
    {
    return $request->get_request_header('Origin') !== null;
    }

    public function isPreflightRequest(CI_Input $request): bool
    {
    return $request->method(true) === 'OPTIONS' && $request->get_request_header('Access-Control-Request-Method');
    }

    public function handlePreflightRequest(CI_Input $request): CI_Output
    {
    /** @var CI_Output $response */
    $response = $this->ci->output;

    $response->set_status_header(204);

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

    public function addPreflightRequestHeaders(CI_Output $response, CI_Input $request): CI_Output
    {
    $this->configureAllowedOrigin($response, $request);

    if ($response->get_header('Access-Control-Allow-Origin')) {
    $this->configureAllowCredentials($response, $request);
    $this->configureAllowedMethods($response, $request);
    $this->configureAllowedHeaders($response, $request);
    $this->configureMaxAge($response, $request);
    }

    return $response;
    }

    public function isOriginAllowed(CI_Input $request): bool
    {
    if ($this->allowAllOrigins === true) {
    return true;
    }

    $origin = $request->get_request_header('Origin');

    if (in_array($origin, $this->allowedOrigins)) {
    return true;
    }

    foreach ($this->allowedOriginsPatterns as $pattern) {
    if (preg_match($pattern, $origin)) {
    return true;
    }
    }

    return false;
    }

    public function addActualRequestHeaders(CI_Output $response, CI_Input $request): CI_Output
    {
    $this->configureAllowedOrigin($response, $request);

    if ($response->get_header('Access-Control-Allow-Origin')) {
    $this->configureAllowCredentials($response, $request);

    $this->configureExposedHeaders($response, $request);
    }

    return $response;
    }

    private function configureAllowedOrigin(CI_Output $response, CI_Input $request): void
    {
    if ($this->allowAllOrigins === true && !$this->supportsCredentials) {
    // Safe+cacheable, allow everything
    $response->set_header('Access-Control-Allow-Origin: *');
    } elseif ($this->isSingleOriginAllowed()) {
    // Single origins can be safely set
    $response->set_header(sprintf('Access-Control-Allow-Origin: %s', array_values($this->allowedOrigins)[0]));
    } else {
    // For dynamic headers, set the requested Origin header when set and allowed
    if ($this->isCorsRequest($request) && $this->isOriginAllowed($request)) {
    $response->set_header("Access-Control-Allow-Origin: {$request->get_request_header('origin')}");
    }

    $this->varyHeader($response, 'Origin');
    }
    }

    private function isSingleOriginAllowed(): bool
    {
    if ($this->allowAllOrigins === true || count($this->allowedOriginsPatterns) > 0) {
    return false;
    }

    return count($this->allowedOrigins) === 1;
    }

    private function configureAllowedMethods(CI_Output $response, CI_Input $request): void
    {
    if ($this->allowAllMethods === true) {
    $allowMethods = strtoupper($request->get_request_header('Access-Control-Request-Method'));
    $this->varyHeader($response, 'Access-Control-Request-Method');
    } else {
    $allowMethods = implode(', ', $this->allowedMethods);
    }

    $response->set_header("Access-Control-Allow-Methods: {$allowMethods}");
    }

    private function configureAllowedHeaders(CI_Output $response, CI_Input $request): void
    {
    if ($this->allowAllHeaders === true) {
    $allowHeaders = $request->get_request_header('Access-Control-Request-Headers');
    $this->varyHeader($response, 'Access-Control-Request-Headers');
    } else {
    $allowHeaders = implode(', ', $this->allowedHeaders);
    }
    $response->set_header("Access-Control-Allow-Headers: {$allowHeaders}");
    }

    private function configureAllowCredentials(CI_Output $response, CI_Input $request): void
    {
    if ($this->supportsCredentials) {
    $response->set_header('Access-Control-Allow-Credentials: true');
    }
    }

    private function configureExposedHeaders(CI_Output $response, CI_Input $request): void
    {
    if ($this->exposedHeaders) {
    $response->set_header(sprintf('Access-Control-Expose-Headers: %s', implode(', ', $this->exposedHeaders)));
    }
    }

    private function configureMaxAge(CI_Output $response, CI_Input $request): void
    {
    if ($this->maxAge !== null) {
    $response->set_header("Access-Control-Max-Age: {$this->maxAge}");
    }
    }

    public function varyHeader(CI_Output $response, string $header): CI_Output
    {
    if (!$response->get_header('Vary')) {
    $response->set_header("Vary: {$header}");
    } elseif (!in_array($header, explode(', ', $response->get_header('Vary')))) {
    $response->set_header("Vary: {$response->get_header('Vary')}, {$header}");
    }

    return $response;
    }
    }

    ```

    ## Usage
    In the constructor of your controller, please add this line of code.

    ```php
    <?php

    class API_Controller extends CI_Controller
    {
    public function __construct()
    {
    parent::__construct();

    $this->load->library('cors');
    $this->cors->handle();
    }
    }
    ```
    31 changes: 0 additions & 31 deletions cors.php
    Original file line number Diff line number Diff line change
    @@ -1,31 +0,0 @@
    <?php

    defined('BASEPATH') or exit('No direct script access allowed');

    $config = [
    /*
    |--------------------------------------------------------------------------
    | Cross-Origin Resource Sharing (CORS) Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your settings for cross-origin resource sharing
    | or "CORS". This determines what cross-origin operations may execute
    | in web browsers. You are free to adjust these settings as needed.
    |
    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
    |
    */
    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => false,
    ];
  10. agungsugiarto renamed this gist Mar 16, 2023. 1 changed file with 1 addition and 6 deletions.
    7 changes: 1 addition & 6 deletions Cors.php → cors.php
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,3 @@
    // Add a config file named cors.php in the application/config directory.

    ```php
    <?php

    defined('BASEPATH') or exit('No direct script access allowed');
    @@ -31,6 +28,4 @@
    'max_age' => 0,

    'supports_credentials' => false,
    ];

    ```
    ];
  11. agungsugiarto created this gist Mar 16, 2023.
    36 changes: 36 additions & 0 deletions Cors.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    // Add a config file named cors.php in the application/config directory.

    ```php
    <?php

    defined('BASEPATH') or exit('No direct script access allowed');

    $config = [
    /*
    |--------------------------------------------------------------------------
    | Cross-Origin Resource Sharing (CORS) Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your settings for cross-origin resource sharing
    | or "CORS". This determines what cross-origin operations may execute
    | in web browsers. You are free to adjust these settings as needed.
    |
    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
    |
    */
    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => false,
    ];

    ```