Fixed session-restore failure for symlinked Yii apps (like Capistrano deployments) #493

Closed
wants to merge 1 commit into
from

5 participants

In its current state, Yii is not compatible with apps that are deployed via changing symlinks; for example, Capistrano maintains a releases/ folder with each deployed version of your app, and a current/ symlink that points to your current version of the app, so you can revert quickly if there is a problem, and maintain a history of the deployed version of the app. When you change the absolute location of your protected folder, Yii's session prefix changes, and no pre-existing sessions will be resolved, so all users will be logged out and auto-logins will fail.

Prior to this commit, the config param basePath would pass through realpath() and symlinks are resolved (actually nearly impossible to get the un-symlink-resolved location of the current file in PHP), then this path would be used in CApplication::getId() to generate a unique ID for the application. When a user visits your Yii app, CWebUser::getStateKeyPrefix() is used to generate a session key prefix - this function uses the aforementioned CApplication::getId() function, which is filesystem location-dependent. If you change the absolute path of your protected/ folder (aka basePath) by syminking or otherwise, getId() is changed, so getStateKeyPrefix() is changed, so your session variables cannot be restored. This means that 1) all your users are logged out; and 2) the auto-login feature will not work since the key prefix is different.

This commit changes the CApplication::getId() method to use php_uname() (works on all platforms) instead of the getBasePath() to keep similar uniqueness, while removing the need for the absolute filesystem location of protected/ to remain the same.

@kamermans kamermans Changed ID so it remains consistent even if the app is moved or symli…
…nked elsewhere, preserving user sessions and auto-login. This is a problem when using Capistrano to deploy Yii projects since the current/ => releases/* symlinks change with every deployment.

Prior to this commit, the config param 'basePath' would pass through realpath() and symlinks are resolved, then this path would be used in CApplication::getId() to generate a unique ID for the application.  When a user visits your Yii app, CWebUser::getStateKeyPrefix() is used to generate a session key prefix - this function uses the aforementioned getId() function, which is filesystem location-dependent.  If you change the absolute path of your 'protected/' folder (aka basePath) by syminking or otherwise, getId() is changed, so getStateKeyPrefix() is changed, so your session variables cannot be restored.  This means that 1) all your users are logged out; and 2) the auto-login feature will not work since the key prefix is different.

This commit changes the CApplication::getId() method to use php_uname() instead of the getBasePath() to keep similar uniqueness, while removing the need for the filesystem location to remain the same.
f237dd7
Owner

Although your change will fix your specific problem, it breaks its original design purpose and may also break existing applications.

In your case, you should configure the id property of application.

@qiangxue qiangxue closed this Mar 12, 2012

Although I'm not sure why this was part of the original design purpose to begin with, your suggestion does work, and it is compatible with at least version 1.1.8-1.1.10 (probably many more versions as well). Better yet, it's just a simple one-line addition to my config file. Thanks!

For those finding this page from google, can you guys be specific as to what 'id' property is being set that fixes this issue?

Member
mdomba commented May 3, 2012

It's the ID of the application (CApplication) - http://www.yiiframework.com/doc/api/1.1/CApplication#id-detail

@mdomba mdomba was assigned May 3, 2012
Contributor

The original design purpose is most likely that every physical installation is identifyable. This is used when handing session data (also containing user login state), for example. Normally you don't want two different installations of the same project to share all session data.

We have a similar case where we switch symlinks for a production project, setting a fixed application ID is the solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment