Session Manager - 2 session IDs

Hi, could anyone explain why I have 2 session IDs with the same name?
It only happens on the 1st load when there is no cookie in the browser yet.

Set-Cookie: myapp=mi2br5sumb15obr9iohkdlt2e2; path=/; HttpOnly
Set-Cookie: myapp=0i4b636g1601fnrhesv0l20qlj; path=/; HttpOnly

I am following the example on this page:
https://zf2.readthedocs.io/en/latest/modules/zend.session.manager.html

Thank you.

  1. The official and current documentation is https://docs.zendframework.com/zend-session/
  2. Can you described which code you have inserted into your application? I guess you have copied everything. But only the first configuration example is needed.

Hi,

I’m still on Zend 2.4, and I believe the link you’ve provided is for Zend 3. Nevertheless, the code is quite similar.

I have this piece of code in module.config.php

return array(
    'session' => array(
        'config' => array(
            'class' => 'Zend\Session\Config\SessionConfig',
            'options' => array(
                'name' => 'myapp',
            ),
        ),
        'storage' => 'Zend\Session\Storage\SessionArrayStorage',
        'validators' => array(
            'Zend\Session\Validator\RemoteAddr',
            'Zend\Session\Validator\HttpUserAgent',
        ),
    ),
);

and this in Module.php of the same Album module. All as per guidelines.

use Zend\Session\SessionManager;
use Zend\Session\Container;

class Module
{
    public function onBootstrap($e)
    {
        $eventManager        = $e->getApplication()->getEventManager();
        $moduleRouteListener = new ModuleRouteListener();
        $moduleRouteListener->attach($eventManager);
        $this->bootstrapSession($e);
    }

    public function bootstrapSession($e)
    {
        $session = $e->getApplication()
                     ->getServiceManager()
                     ->get('Zend\Session\SessionManager');
        $session->start();

        $container = new Container('initialized');
        if (!isset($container->init)) {
            $serviceManager = $e->getApplication()->getServiceManager();
            $request        = $serviceManager->get('Request');

            $session->regenerateId(true);
            $container->init          = 1;
            $container->remoteAddr    = $request->getServer()->get('REMOTE_ADDR');
            $container->httpUserAgent = $request->getServer()->get('HTTP_USER_AGENT');

            $config = $serviceManager->get('Config');
            if (!isset($config['session'])) {
                return;
            }

            $sessionConfig = $config['session'];
            if (isset($sessionConfig['validators'])) {
                $chain   = $session->getValidatorChain();

                foreach ($sessionConfig['validators'] as $validator) {
                    switch ($validator) {
                        case 'Zend\Session\Validator\HttpUserAgent':
                            $validator = new $validator($container->httpUserAgent);
                            break;
                        case 'Zend\Session\Validator\RemoteAddr':
                            $validator  = new $validator($container->remoteAddr);
                            break;
                        default:
                            $validator = new $validator();
                    }

                    $chain->attach('session.validate', array($validator, 'isValid'));
                }
            }
        }
    }

    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'Zend\Session\SessionManager' => function ($sm) {
                    $config = $sm->get('config');
                    if (isset($config['session'])) {
                        $session = $config['session'];

                        $sessionConfig = null;
                        if (isset($session['config'])) {
                            $class = isset($session['config']['class'])  ? $session['config']['class'] : 'Zend\Session\Config\SessionConfig';
                            $options = isset($session['config']['options']) ? $session['config']['options'] : array();
                            $sessionConfig = new $class();
                            $sessionConfig->setOptions($options);
                        }

                        $sessionStorage = null;
                        if (isset($session['storage'])) {
                            $class = $session['storage'];
                            $sessionStorage = new $class();
                        }

                        $sessionSaveHandler = null;
                        if (isset($session['save_handler'])) {
                            // class should be fetched from service manager since it will require constructor arguments
                            $sessionSaveHandler = $sm->get($session['save_handler']);
                        }

                        $sessionManager = new SessionManager($sessionConfig, $sessionStorage, $sessionSaveHandler);
                    } else {
                        $sessionManager = new SessionManager();
                    }
                    Container::setDefaultManager($sessionManager);
                    return $sessionManager;
                },
            ),
        );
    }
}

Do you know if I am missing something?
The reason why I did this example is because I have to support two applications, one running on Zend 2 and another running still on Zend 1. Both are sending 2 cookies with the same name, but ONLY when there is no cookie in the browser, i.e. on the 1st request. I can’t understand the reason for this behavior.

I think you missed the sentence before the second code example related to the Module class:

The following illustrates how you might utilize the above configuration to create the session manager:

This means you can remove all code from the Module class which is related to sessions.

I moved this code from module.config.php to config/autolaod/local.php, if that’s what you meant.

return array(
    'session' => array(
        'config' => array(
            'class' => 'Zend\Session\Config\SessionConfig',
            'options' => array(
                'name' => 'myapp',
            ),
        ),
        'storage' => 'Zend\Session\Storage\SessionArrayStorage',
        'validators' => array(
            'Zend\Session\Validator\RemoteAddr',
            'Zend\Session\Validator\HttpUserAgent',
        ),
    ),
);

It’s the same behavior though. Did I understand you right?

No, I mean the code in the file Module.php which contains the class Module with the methods onBootstrap, bootstrapSession and getServiceConfig.
You do not the configuration module.config.php and the code in the Module.php. The code in your configuration (module.config.php) is enough.

There are no cookies at all if I follow your suggestions…

I will check this in a skeleton application. In the meantime you can recheck the file config/application.config.php if the entry for Zend\Session is included.

Btw this version is no longer support. See: https://framework.zend.com/long-term-support

I checked the version 2.4 and you must add all factories by hand to your application configuration. All configuration options are listed in the documentation of session config.

If you are using the factories then you do not need the code from the session manager documentation.

Hi,
I reduced the code to bare minimum and now I only have the following in Module.php, no other code in any other files. Still, I don’t understand why I have two session cookies…

 public function onBootstrap($e)
 {
	$serviceManager = $e->getApplication()->getServiceManager();

	$options = $options =array(  'cookie_httponly' => 1);
	$sessionConfig = new SessionConfig();
	$sessionConfig->setOptions($options);


	$sessionManager = new SessionManager($sessionConfig, null, null);
	$sessionManager->start();
	$sessionManager->regenerateId(true);

	Container::setDefaultManager($sessionManager);
 }


Set-Cookie:	PHPSESSID=o4ei7kh5toatcpu3r3t66lkr9l; path=/; HttpOnly
Set-Cookie:	PHPSESSID=m55adkrb8dv0m9pqt5ashtp8cr; path=/; HttpOnly

I know it’s late, at least where I am located, but why waste your time with sessions?
I gave up on sessions a long time ago and switched to tokens and/or JWT.
For example, use “Authorization” in your html header or JWT in every single request. All you do is gain security and separation between browser tabs. In my personal opinion, sessions don’t give you much, besides security problems.

I created a new project with the skeleton-application and added zend-session. With your code I only get one cookie, also if I use the factories and the related configuration.

Do you use zend-authentication with the Zend\Authentication\AuthenticationService class in your application?

I have Authentication module as part of vendor/zendframework/library, but I do not explicitly use it in the sample application I set up. Do you think it could be some php.ini configurations that produce 2 cookies? I am really surprised to hear you have a different outcome, considering we have the same code…

Thank you, that’s something to consider. In the meantime I’d really like to solve the problem at hand.

Did you make any modifications to the “default” php.ini?
If possible, could you try to compare your php.ini in question with an unchanged version and post the difference?