4

UPDATE:

I am wondering if anyone can review my answer and see if there are any holes in it.

There is a well documented issue when using codeingiter and sessions at:

Duplicated "set-cookie: ci-session" fields in header by codeigniter

In summary codeigniter does a set-cookie each time set_userdata is called.

I found a partial solution at:

http://ha17.com/1745-bigip-f5-header-max-size-collides-with-codeigniters-bizarre-session-class/

The only problem with this solution is that code needs to be inserted everywhere. Is there a simple way to clear all the headers? I have modified the code a little to remove php errors, but is there a way I can use a hook or something?

<?php
class MY_Controller extends CI_Controller
{

    public function __construct()
    {
        parent:: __construct();
    }

     //See (modified from) http://ha17.com/1745-bigip-f5-header-max-size-collides-with-codeigniters-bizarre-session-class/
    protected function _removeDuplicateCookieHeaders ()
    {
        // clean up all the cookies that are set...
        $headers             = headers_list();
        $cookies_to_output   = array ();
        $header_session_cookie = '';
        $session_cookie_name = $this->config->item('sess_cookie_name');

        foreach ($headers as $header)
        {
            list ($header_type, $data) = explode (':', $header, 2);
            $header_type = trim ($header_type);
            $data        = trim ($data);

            if (strtolower ($header_type) == 'set-cookie')
            {
                header_remove ('Set-Cookie'); 

                $cookie_value = current(explode (';', $data));
                list ($key, $val) = explode ('=', $cookie_value);
                $key = trim ($key);

                if ($key == $session_cookie_name)
                {
                   // OVERWRITE IT (yes! do it!)
                   $header_session_cookie = $data;
                   continue;
                } 
                    else 
                    {
                   // Not a session related cookie, add it as normal. Might be a CSRF or some other cookie we are setting
                   $cookies_to_output[] = array ('header_type' => $header_type, 'data' => $data);
                }
            }
        }

        if ( ! empty ($header_session_cookie))
        {
            $cookies_to_output[] = array ('header_type' => 'Set-Cookie', 'data' => $header_session_cookie);
        }

        foreach ($cookies_to_output as $cookie)
        {
            header ("{$cookie['header_type']}: {$cookie['data']}", false);
        }
     }
}
Community
  • 1
  • 1
Chris Muench
  • 17,444
  • 70
  • 209
  • 362

2 Answers2

1

EDIT: Only use this code if you are are using $this->load->view(). if you are using echo right in a controller this will cause output before removing the headers can even get deleted.

EDIT requires php 5.3 or newer.

I have found a way that I think I help others with this issue. I haven't test it perfectly yet, but it appears to work.

application/hooks/session_cookie_fixer.php

<?php
class SessionCookieFixer
{   
     //See (modified from) http://ha17.com/1745-bigip-f5-header-max-size-collides-with-codeigniters-bizarre-session-class/
    function removeDuplicateSessionCookieHeaders ()
    {
         $CI = &get_instance();

        // clean up all the cookies that are set...
        $headers             = headers_list();
        $cookies_to_output   = array ();
        $header_session_cookie = '';
        $session_cookie_name = $CI->config->item('sess_cookie_name');

        foreach ($headers as $header)
        {
            list ($header_type, $data) = explode (':', $header, 2);
            $header_type = trim ($header_type);
            $data        = trim ($data);

            if (strtolower ($header_type) == 'set-cookie')
            {
                header_remove ('Set-Cookie'); 

                $cookie_value = current(explode (';', $data));
                list ($key, $val) = explode ('=', $cookie_value);
                $key = trim ($key);

                if ($key == $session_cookie_name)
                {
                   // OVERWRITE IT (yes! do it!)
                   $header_session_cookie = $data;
                   continue;
                } 
                    else 
                    {
                   // Not a session related cookie, add it as normal. Might be a CSRF or some other cookie we are setting
                   $cookies_to_output[] = array ('header_type' => $header_type, 'data' => $data);
                }
            }
        }

        if ( ! empty ($header_session_cookie))
        {
            $cookies_to_output[] = array ('header_type' => 'Set-Cookie', 'data' => $header_session_cookie);
        }

        foreach ($cookies_to_output as $cookie)
        {
            header ("{$cookie['header_type']}: {$cookie['data']}", false);
        }
     }
}
?>

application/config/hooks.php

$hook['post_controller'][] = array(
                               'class'    => 'SessionCookieFixer',
                               'function' => 'removeDuplicateSessionCookieHeaders',
                               'filename' => 'session_cookie_fixer.php',
                               'filepath' => 'hooks',
                               'params'   => array()
                               );
Chris Muench
  • 17,444
  • 70
  • 209
  • 362
  • to enable hooks must change config/config.php $config['enable_hooks'] = TRUE; – alo Malbarez Apr 07 '17 at 14:48
  • the hook won't trigger if you do a redirect('/someurl'); in that case you can call the function before every redirect statement like in: $this->removeDuplicateSessionCookieHeaders(); redirect('/'); – alo Malbarez Apr 07 '17 at 15:16
0

If I understand your code correctly you are planning on making all of your controllers extend MY_Controller and then in each (or possibly only the relevant) Controller you are going to call

$this->_removeDuplicateCookieHeaders()

Other alternatives

add a hook (http://ellislab.com/codeigniter/user-guide/general/hooks.html)

$hook['post_controller_constructor'][] = array(
                            'class'    => '',
                            'function' => 'removeDuplicateCookies',
                            'filename' => 'removeDuplicateCookies.php',
                            'filepath' => 'hooks',
                            );

or create a helper (or library depending on your preference) you can autoload these in by editing application/config/autoload.php

P4ul
  • 770
  • 5
  • 15