CORS not working in php slim framework

17,367

Solution 1

There is no point of wrapping up header statements enabling CORS in your API with those conditions you have.

Right now it would set headers only if the REQUEST_METHOD is OPTIONS and HTTP_ACCESS_CONTROL_REQUEST_METHOD is either GET or POST, but your request wont comply to this.

So replace

if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    // return only the headers and not the content
    // only allow CORS if we're doing a GET - i.e. no saving for now.
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
        if($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'GET' || $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'POST') {
            header('Access-Control-Allow-Origin: *');
            header('Access-Control-Allow-Headers: X-Requested-With, X-authentication,Content-Type, X-client');
        }
    }
    exit;
}

from your code with

header('Access-Control-Allow-Origin: *');

header('Access-Control-Allow-Methods: GET, POST, OPTIONS');

header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');

PS: Unless you have a server variable set as HTTP_ACCESS_CONTROL_REQUEST_METHOD, change it to REQUEST_METHOD

Solution 2

I was having the same issue while working on an ionic hybrid mobile application. I added the following code below to my index.php file.

header('Access-Control-Allow-Origin:*'); 
header('Access-Control-Allow-Headers:X-Request-With');

header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');

Solution 3

I had the same problem, but at the end I achieved to get it working

I am using cors-middleware https://github.com/tuupola/cors-middleware

These are my settings:

$app->add(new \Tuupola\Middleware\Cors([
    "origin" => ["*"],
    "methods" => ["GET", "POST", "PUT", "PATCH", "DELETE"],
    "headers.allow" => ["Accept", "Content-Type"],
    "headers.expose" => [],
    "credentials" => false,
    "cache" => 0,
    "logger" => $container['logger']
]));

Pay attention to the headers.allow key. If you try using "*" it will fail. You must enumerate at least these two headers as allowed.

Solution 4

For Slim Framework 2.4 Version I did a small hack to tackle the Preflight OPTIONS request

\Slim\Slim::registerAutoloader();

$app = new \Slim\Slim();

if($app->request->isOptions()) {
   return true;
   break;
}

$app->post('/authenticate', 'authenticateUser');

$app->run();

So this will track all OPTIONS requests and return true and it worked for me.

My .htaccess file was like as follows

Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "X-Requested-With, Content-Type, Accept, Origin, Authorization"
Header add Access-Control-Allow-Methods "GET, POST, OPTIONS"

Hope this helps.

Solution 5

I ended up creating this simple middleware class:

<?php
class CorsMiddleware
{
private $router;

public function __construct(\Slim\Router $router)
{
    $this->router = $router;
}
/**
 * Cors middleware invokable class
 *
 * @param  \Psr\Http\Message\ServerRequestInterface $request  PSR7 request
 * @param  \Psr\Http\Message\ResponseInterface      $response PSR7 response
 * @param  callable                                 $next     Next middleware
 *
 * @return \Psr\Http\Message\ResponseInterface
 */
public function __invoke($request, $response, $next)
{
    // https://www.html5rocks.com/static/images/cors_server_flowchart.png
    if ($request->isOptions()
          && $request->hasHeader('Origin')
          && $request->hasHeader('Access-Control-Request-Method')) {
        return $response
                      ->withHeader('Access-Control-Allow-Origin', '*')
                      ->withHeader('Access-Control-Allow-Headers', '*')
                      ->withHeader("Access-Control-Allow-Methods", '*');
    } else {
        $response = $response
                      ->withHeader('Access-Control-Allow-Origin', '*')
                      ->withHeader('Access-Control-Expose-Headers', '*');
        return $next($request, $response);
    }
}
}

I use it like this (it's a string because of dependency-injection):

$app->add('CorsMiddleware');
Share:
17,367
Neel Kamal
Author by

Neel Kamal

Updated on June 04, 2022

Comments

  • Neel Kamal
    Neel Kamal almost 2 years

    I have created rest api using php slim framework. Here is my code

    <?php
    require 'Slim/Slim.php';
    require '../lib/cors_enable.php';
    require '../lib/logger.php';
    require '../../db_config/config.php';
    require '../lib/predis-0.8/lib/Predis/Autoloader.php';
    Predis\Autoloader::register();
    require '../lib/RedisMethods.php';
    require '../lib/APICaller.php';
    require '../lib/FosterGemOAuth.php';
    require '../lib/FosterGemUser.php';
    require '../lib/NewsFeed.php';
    require '../lib/FosterGemBookmarks.php';
    require '../lib/TopicWebsite.php';
    require '../lib/FetchFullArticle.php';
    require '../lib/PushNotification.php';
    
    
    \Slim\Slim::registerAutoloader();
    $app = new \Slim\Slim();
    
    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
        // return only the headers and not the content
        // only allow CORS if we're doing a GET - i.e. no saving for now.
        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
            if($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'GET' || $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'POST') {
                header('Access-Control-Allow-Origin: *');
                header('Access-Control-Allow-Headers: X-Requested-With, X-authentication,Content-Type, X-client');
            }
        }
        exit;
    }
    
    
    $app->post('/messagebhej(/)(:profile_id/?)(:app_auth_token/?)', 'messagebhej');
    $app->post('/login','login');
    
    
    $app->run();
    
    function messagebhej($profile_id, $app_auth_token){
        $error='';
        $request = file_get_contents('php://input');
        try {
            $request_data = json_decode($request,true);
            if($app_auth_token == APP_AUTH_TOKEN){
                $obj = new PushNotification();
                $res = $obj->sendMessage($profile_id, $request_data);
            } else {
                $error='Access Denied';
            }
        } catch (Exception $ex) {
            $error=$ex->getMessage();
            log_error($error,"index.php | sendMessage function");
        }
        if($error) {
            $return_data= '{"Status":"Failed","Message":"'.$error.'"}';
        } else {
            $return_data='{"Status":"Success"}';
        }
        echo $return_data;
    }
    
    function login() {
        $error='';
        $request = file_get_contents('php://input');
       try {
        $request_data = json_decode($request,true);
        if(isset($request_data['EmailAddress']) && isset($request_data['Password'])){
            if($request_data['EmailAddress']){
                $obj = new FosterGemUser();
                $user_data = $obj->get_user($request_data['EmailAddress'],$request_data['Password'],$request);
            } else {
                $error='Please enter your email address.';
            }      
        } else {
            $error='Wrong Data Format.';
        }
       }  catch (Exception $ex) {
                $error=$ex->getMessage();
                log_error($error,"index.php | login function");
        }
            if($error) {
                $return_data= '{"Status":"Error","Message":"'.$error.'"}';
            } else {
               $return_data=$user_data;
            }
       echo $return_data;
    }
    

    Now both the api works fine when I call it using Rest client. However when I call login api from javascript it works well but messagebhej api gives error

    XMLHttpRequest cannot load http://api.fostergem.com/messagebhej/556714b04ec0a40d3cda0118/{app_auth_token}. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63343' is therefore not allowed access. The response had HTTP status code 404.
    

    I am getting crazy. Everything is is same then how the cors is enabled for one api and not for other.

    Here is my cors_enable.php

    <?php
    
    // Specify domains from which requests are allowed
    header('Access-Control-Allow-Origin: *');
    
    // Specify which request methods are allowed
    header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
    
    // Additional headers which may be sent along with the CORS request
    // The X-Requested-With header allows jQuery requests to go through
    header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
    
    // Set the age to 1 day to improve speed/caching.
    header('Access-Control-Max-Age: 86400');
    
     ?>