Implementing Cross-Origin Resource Sharing Support In Your Yii Framework Application.

Cross-origin resource sharing (CORS) is a mechanism that allows JavaScript on a web page to make XMLHttpRequests to another domain, not the domain the JavaScript originated from. Such "cross-domain" requests would otherwise be forbidden by web browsers, per the same origin security policy. CORS defines a way in which the browser and the server can interact to determine whether or not to allow the cross-origin request. It is more useful than only allowing same-origin requests, but it is more secure than simply allowing all such cross-origin requests.

CorsBehavior implements cross-origin resource sharing support in your Yii Framework application.

[size="4"]Requirements[/size]

  • Yii 1.0 or above

  • PHP >= 5.4.0 Or PHP should be installed as an Apache module.

[size="4"]Installation[/size]

Add the following code to your config file (protected/config/main.php):


'behaviors' => array(

            array('class' => 'application.extensions.CorsBehavior',

                'route' => array('controller/actionA', 'controller/actionB'),

                'allowOrigin' => '*.domain.com'

                ),

        ),

  • route list of routes for CORS-requests.

  • allowOrigin the origin that is allowed to access the resource. A "" can be specified to enable access to resource from any origin. A wildcard can be used to specify list of allowed origins, e.g. ".yourdomain.com" (sub.yourdomain.com, yourdomain.com, sub.sub.yourdomain.com will be allowed origins in that case)

The source code of CorsBehavior.php :


<?php


/*

 * CorsBehavior class file

 * 

 * @author Igor Manturov, Jr. <im@youtu.me>

 */


/**

 * CorsBehavior Automatically adds the Access-Control-Allow-Origin response 

 * header for specific routes.

 * 

 * @version 1.0

 *

 */

class CorsBehavior extends CBehavior

{

    

    private $_allowOrigin;

    

    private $_route = array();

    

    

    public function events()

    {

        return array_merge(parent::events(), 

                array('onBeginRequest' => 'onBeginRequestHandler'));

    }

    

    

    public function onBeginRequestHandler($event)

    {

        if (is_null($this->_allowOrigin))

        {

            return;

        }

        

        $route = Yii::app()->getUrlManager()

                ->parseUrl(Yii::app()->getRequest());

        

        if (in_array($route, $this->_route))

        {

            

            $origin = $this->parseHeaders();

            

            if ($origin !== false)

            {

                $this->setAllowOriginHeader($origin);

            }

        }

    }

    

    

    /**

     * Sets list of routes for CORS-requests.

     * @param array $route list of routes (controllerID/actionID)

     * @throws CException

     */

    public function setRoute($route)

    {

        if (!is_array($route))

        {

            throw new CException('The value of the "route" property must be an '

                    . 'array.');

        }

        

        $this->_route = $route;

    }

    

    

    /**

     * Sets the allowed origin.

     * @param string $origin The origin that is allowed to access the resource.

     * A "*" can be specified to enable access to resource from any origin. 

     * A wildcard can be used to specify list of allowed origins, 

     * e.g. "*.yourdomain.com" (sub.yourdomain.com, yourdomain.com, 

     * sub.sub.yourdomain.com will be allowed origins in that case)

     * @throws CExecption

     */

    public function setAllowOrigin($origin)

    {

        if (!is_string($origin))

        {

            throw new CExecption('The value of the "allowOrigin" property must be '

                    . 'a string.');

        }

        

        $this->_allowOrigin = $origin;

    }

    

    

    /**

     * Parses headers and returns the value of the Origin request header.

     * @return mixed The origin that is allowed to access the resource. 

     * (the value of the Origin request header), otherwise false. 

     * @throws CException

     */

    protected function parseHeaders()

    {

        if (!function_exists('getallheaders'))

        {

            throw new CException('PHP version must be greater than or equal to '

                    . '5.4.0, or PHP should be installed as an Apache module.');

        }

        

        $headers = getallheaders();

        

        if ($headers === false)

        {

            return false;

        }

        

        $headers = array_change_key_case($headers, CASE_LOWER);

        

        if (!key_exists('origin', $headers))

        {

            return false;

        }

        

        $origin = $headers['origin'];

        $origin = parse_url($origin, PHP_URL_HOST);

        

        if (is_null($origin))

        {

            return false;

        }

        

        if(strlen($this->_allowOrigin) === 1)

        {

            return $headers['origin'];

        }

        

        if (stripos($this->_allowOrigin, '*') === false)

        {

            return $origin === $this->_allowOrigin ? $headers['origin'] : false;

        }

        

        $pattern = '/' . substr($this->_allowOrigin, 1) . '$/';

        

        if (substr($this->_allowOrigin, 2) === $origin

                || preg_match($pattern, $origin) === 1)

        {

            return $headers['origin'];

        }

        

    }

    

    

    /**

     * Sets Access-Control-Allow-Origin response header.

     * @param string $origin the value of the Access-Control-Allow-Origin response 

     * header.

     */

    protected function setAllowOriginHeader($origin)

    {

        header('Access-Control-Allow-Origin: ' . $origin);

    }

   

}

You can download it from Github github.com/iAchilles/cors-behavior