Open Source | Technology | Web

One session across sub domains in eZ Publish

When a user visits a website, website.com for example, (or website.local for development purposes) and wants to log in to the site to access personal profile, this user should be logged in to all proper subdomains in case the user switches to another language.

Below is an example on how to use sub domains to define a language.

For example:
There is a main production domain, example.com, which uses English as default locale.

With a list of subdomains, such as:
www.example.com – uses English
en.example.com – uses English
ru.example.com – uses Russian
*.example.com – uses any locales as needed

Also, we need to have the stage domains and list of some development installations:
*.stage.example.com – stage server which can be hosted on different server.
*.example.local – development servers hosted locally
*.example.dev.com – development servers

By default PHP does not allow to have the same cookies in main domain and its subdomains, e.g. example.com and ru.example.com. These hosts will produce different session IDs, and as a result different sessions.

To have one sessions for subdomains use session.cookie_domain, http://www.php.net/manual/en/session.configuration.php#ini.session.cookie-domain

If we want to have the same session for subdomains we need to define cookie domain like “.example.com”

eZ Publish configuration

To properly define locales in eZ Publish, one needs to use siteaccesses.
The example below illustrates how to set up the configuration in ez Publish.

Create one siteaccess per locale:
site_en – English
site_no – Norwegian

Enable one session per all siteaccesses
site.ini.[Session].SessionNamePerSiteAccess=disabled

Settings/override/site.ini.append.php will contain like following:

Source code    
  1. [SiteAccessSettings]
  2. DefaultAccess=site_en
  3. AvailableSiteAccessList[]=site_en
  4. AvailableSiteAccessList[]=site_no
  5. CheckValidity=false
  6. # Names of siteacceses can be passed in url, like example.com/site_no
  7. # And also no.example.com will work
  8. MatchOrder=uri;host
  9. HostMatchMapItems[]=example.com;site_en
  10. HostMatchMapItems[]=www.example.com;site_en
  11. HostMatchMapItems[]=en.example.com;site_en
  12. HostMatchMapItems[]=no.example.com;site_no
  13. # Also we need to have settings for devs and stages
  14. HostMatchMapItems[]=stage.example.com;site_en
  15. HostMatchMapItems[]=en.stage.example.com;site_en
  16. HostMatchMapItems[]=no.stage.example.com;site_no
  17. # …. and so on for all dev or stage site
  18.  
  19. [Session]
  20. SessionNameHandler=custom
  21. # This must be disabled to have one session for all siteaccesses
  22. SessionNamePerSiteAccess=disabled

And just as an example settings/siteaccess/site_no/site.ini.append.php will contain something like:

Source code    
  1. [RegionalSettings]
  2. Locale=nor-NO
  3. ContentObjectLocale=nor-NO
  4. ShowUntranslatedObjects=disabled
  5. SiteLanguageList[]
  6. SiteLanguageList[]=eng-US
  7. TextTranslation=enabled

eZ System’s solution

eZ System has proposed the following solution on how to resolve this issue, for most cases:

Have one session for subdomains in PHP, session.cookie_domainhttp://www.php.net/manual/en/session.configuration.php#ini.session.cookie-domain

eZ Publish provides a wrapper of for this configuration setting, which can be used per siteaccess:

site.ini[Session].CookieDomain

This means we need to define this setting per each installation.

For example:
The Production server settings/override/site.ini.append.php should contain:

Source code    
  1. [Session]
  2. CookieDomain=.example.com

On stage

Source code    
  1. [Session]
  2. CookieDomain=.stage.example.com

On local installations

Source code    
  1. [Session]
  2. CookieDomain=.example.local

This requires different settings on the dev, stage and productions installations.

To avoid any additional configuration the following solutions are available:

- Hack setting files on each installations. It will have local modifications.
– Creating dev, stage and production branches in CVS where the project is located.
– Creating not committed setting files for example in an extension: extension/nxc/settings/site.ini.append.php

All the above methods will work, though not ideal, since it requires additional configuration of already overconfigured project.

Alternate solution

Instead of additional configuration files or settings, we could use the custom session handler.

For this example, we’ll name it nxcSessionHandlerPHP and inherit it from the standard ezpSessionHandlerPHP.

This session handler will initialize php session.cookie_domain setting before calling session_set_cookie_params in eZ Publish.

settings/override/site.ini.append.php will contain like following:

Source code    
  1. [Session]
  2. SessionNameHandler=custom
  3. SessionNamePerSiteAccess=disabled
  4. Handler=nxcSessionHandlerPHP
  5.  
  6. [ExtensionSettings]
  7. # Activate custom extension to store a class there
  8. ActiveExtensions[]=nxc_session

extension/nxc_session/classes/nxcSessionHandlerPHP.php

Source code    
  1. <?php
  2. /**
  3.  * @author VaL <vd@nxc.no>
  4.  * @copyright Copyright (C) 2013 NXC AS
  5.  * @license GNU GPL v2
  6.  * @package nxc
  7.  */
  8.  
  9. /**
  10.  * Custom session handler to initialize cookie domain
  11.  * @see site.ini[Session].Handler
  12.  */
  13. class nxcSessionHandlerPHP extends ezpSessionHandlerPHP
  14. {
  15.     /**
  16.      * @reimp
  17.      */
  18.     public function setSaveHandler()
  19.     {
  20.         self::initCookieDomain();
  21.  
  22.         return parent::setSaveHandler();
  23.     }
  24.  
  25.     /**
  26.      * Sets cookie domain to use the same cookies for all subdomains, like en.* or de.*
  27.      *
  28.      * @return (void)
  29.      */
  30.     public static function initCookieDomain()
  31.     {
  32.         $host = eZSys::hostname();
  33.         $e = explode( '.', $host );
  34.         // We agreed that we have two chars language specific subdomain, like en.*, de.*, es.*, ru.*, no.*
  35.         // So it is just an example how to remove language from host
  36.         // Also there is a need to handle www.* domains
  37.         if ( strlen( $e[0] ) == 2 )
  38.         {
  39.             // Remove lang from domain
  40.             unset( $e[0] );
  41.  
  42.             $host = implode( '.', $e );
  43.         }
  44.  
  45.         ini_set( 'session.cookie_domain', '.' . $host );
  46.     }
  47. }
  48. ?>

After this, we need to run

Source code    
  1. php ./bin/php/ezpgenerateautoloads.php -e

it should allow to have one session for all language specific subdomians for all installations, without additional configuring.

Another alternate solution

If it is not possible or not suitable to install custom session handler, there is an ability to use custom config file.

Need to Create [eZPublishRoot]/config.php or to append to existing one following:

Source code    
  1. <?php
  2. /**
  3.  * @author VaL <vd@nxc.no>
  4.  * @copyright Copyright (C) 2011 NXC AS
  5.  * @license GNU GPL v2
  6.  * @package nxc
  7.  */
  8.  
  9. /**
  10.  * Configuration part to set automatically cookie domain to handle sessions for subdomains
  11.  */
  12.  
  13. $host = false;
  14. $forwardedHostsString = isset( $_SERVER['HTTP_X_FORWARDED_HOST'] ) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : false;
  15. if ( $forwardedHostsString )
  16. {
  17.     $forwardedHosts = explode( ',', $forwardedHostsString );
  18.     $host = trim( $forwardedHosts[0] );
  19. }
  20.  
  21. if ( !$host and isset( $_SERVER['HTTP_HOST'] ) )
  22. {
  23.     $host = $_SERVER['HTTP_HOST'];
  24. }
  25.  
  26. if ( $host )
  27. {
  28.     $e = explode( '.', $host );
  29.     // We agreed that we have two chars language specific subdomain, like en.*, de.*, es.*, ru.*, no.*
  30.     // So it is just an example how to remove language from host
  31.     // Also there is a need to handle www.* domains
  32.     if ( strlen( $e[0] ) == 2 )
  33.     {
  34.         // Remove lang from domain
  35.         unset( $e[0] );
  36.  
  37.         $host = implode( '.', $e );
  38.     }
  39.  
  40.     ini_set( 'session.cookie_domain', '.' . $host );
  41. }
  42. ?>
Print this post

1 Responses to "One session across sub domains in eZ Publish"

  1. MIkaël DELSOL   on Friday, May 17

    Great, I was just looking for a tip on how to achieve this sort of thing,

    Thanks a lot !

    (reply)

Post a Comment:

Get latest news