PHP sessions lost on deployment

I am running a web app on this setup:

  • PHP

  • Apache

  • APC

  • Yii - Auto login and cookie validation enabled. Yii-lite is being included.

  • Redis for session handling

And I’m doing the following for deployments:

[list=1]

[*]Stop Apache

[*]Extract archived code

[*]Remove current www symlink and replace with new symlink pointing to new release

[*]Start Apache

[/list]

When I do this, every logged in user on the site is logged out and their sessions are destroyed. At first I suspected the PHP Redis extension I’m using, but I see the same behavior with the default PHP session handler.

Is there something about Yii or APC that would cause this? Restarting Apache without a new code deployment does not cause the sessions to be destroyed.

Take a look at your protected/runtime/ directory. I suspect that the cause for this behavior is that some file there has important data for your sessions.

I’d bet that it is state.bin, that holds your automatically generated encryption key.

If you specify an encryption key, you will fix this behavior.

Thanks for the reply. Yes, I noticed the state.bin file. I tried deleting it to see if doing so would log me out, but it didn’t. Even so, how do I specify an encryption key?

I tried changing the encryption key, but am still seeing the problem.

It seems that just renaming the symlink source is causing the issue. Here’s what I narrowed it down to:

  • Symlink www currently points to /usr/local/src/releases/mysite-1/www

  • I rename /usr/local/src/releases/mysite-1/www to /usr/local/src/releases/mysite-2/www

  • I remove the www symlink: rm -f www

  • I create a new symlink: ln -s /usr/local/src/releases/mysite-2/www www

And just doing that causes the session to get destroyed, without even restarting Apache. Any ideas?

That’s a tricky one. I have no idea on what could be going on.

I wonder if it has something to do with getting the path of yiilite and the config file dynamically? I have this in my index.php:


$yii = dirname(__FILE__) . '/../yii/framework/yiilite.php';

$config = dirname(__FILE__) . '/../application/config/main.php';

My protected/runtime directory resides outside of the directory that I’m renaming when I switch the symlink.

Sorry, but I don’t think that this is the problem. And can’t think of anything else, too.

I have Googled around and found nothing.

I suggest you to reduce your setup to the simplest (use file-based sessions, disable APC) and then enable one by one and test some combinations.

Good luck!

Now that I am looking at APC, I thought: if the file path is the file identifier in the opcode cache, APC may be the guilty in this case. But I still can’t see how the sessions are destroyed.

After some further testing, it doesn’t look like the session data is actually getting destroyed. And I have switched to file based sessions. Here is what I’m seeing:

  1. User logs in, and session id is set to tdv3l6jgf2sb1dnutt7updhfo1

  2. Session data looks like:


array(5) { 

["20b30da82f6dcc260a66f6a1044a5c3a__id"]=> string(1) "2" 

["20b30da82f6dcc260a66f6a1044a5c3a__name"]=> string(<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='8)' /> "ewest fb" 

["20b30da82f6dcc260a66f6a1044a5c3afbId"]=> string(10) "1028251971" 

["20b30da82f6dcc260a66f6a1044a5c3aisFbUser"]=> bool(true) 

["20b30da82f6dcc260a66f6a1044a5c3a__states"]=> array(3) { 

       ["fbId"]=> bool(true) ["isFbUser"]=> bool(true) ["avatar"]=> bool(true) 

} 

} 

  1. Session file is created under /tmp

  2. I change the www symlink as described above. The session id stays the same, and the session data is intact! But Yii::app()->user->isGuest is evaluating to true. So the session data is still there but Yii thinks I’m logged out!

Is there another location Yii writes user data to?

And if I log back in again, then I have two entries in $_SESSION:


["7dea7f6dfcf54cdd3c3fd6f7c88478b6__id"]=> string(1) "2" ["7dea7f6dfcf54cdd3c3fd6f7c88478b6__name"]=> string(<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='8)' /> "ewest fb"

and


["20b30da82f6dcc260a66f6a1044a5c3a__id"]=> string(1) "2" ["20b30da82f6dcc260a66f6a1044a5c3a__name"]=> string(<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='8)' /> "ewest fb"

How is "7dea7f6dfcf54cdd3c3fd6f7c88478b6__id" created? It seems that unique identifier gets lost when I change the symlinks. Perhaps I set the encryption key incorrectly? I added this to main.php under components:


'securityManager' => array(

	'encryptionKey' => '...'

),

EDIT: I also see "7dea7f6dfcf54cdd3c3fd6f7c88478b6" written to a cookie. And that cookie gets overwritten with a new key when the symlinks/code changes.

I think all of this is tied to having allowAutoLogin enabled. Changing the symlink is somehow causing the cookie id used by Yii to be lost. It does not result in the PHP session being lost though.

Try setting the securityManager validationKey (used to validate hashes, e.g from the cookie for autologin) or keep the original global state bin file in runtime (where a random validation key is stored if not provided)

I set both the validationKey and encryptionKey. I don’t see state.bin being created after I do that.

I am seeing the same thing happen though-- the cookie set by allowAutoLogin gets ignored after the symlink is changed.

A hypothesis is that some code is path dependent (i’m out of ideas on the yii side without more extensive looks). Can you try to retrace the codes that generate and accepts the login cookie?

Actually, when you say new release, it is your own code release or a yii release?

I meant a new release of my code.

Thanks for all of the help guys. Unfortunately, I was not able to figure out what was causing the issue, but I did come up with a workaround.

Instead of:

  1. Change www symlink to d-xxx where xxx is the release version

I now:

  1. Move old release directory "d" to d-yyy where yyy is the old release version

  2. Extract new release to "d"

  3. "www" symlink then still points to "d"

So the real path of the "www" symlink never changes. This fixes the issue, and I have no idea why this works. Along with that, I am manually setting the validationKey and encryptionKey.

The only thing I suspect at this point is something wonky going on with APC and my setup.

Thanks again.

Hello again.

Check if setting an application id helps. See http://www.yiiframework.com/doc/api/1.1/CApplication#getId-detail.

When it is auto generated, it uses the application path as a base.

The application id is used when creating keys in other components.

Indeed - I’ve just discovered this as well and you’re correct it - fixes the problem since by default the ID is used as the cookie prefix and it is dependent on the absolute filesystem location of the ‘protected/’ directory.

More info here:

http://www.yiiframework.com/forum/index.php/topic/17474-anyone-here-deploys-yii-webapp-with-capistrano/page__gopid__142899#entry142899

Great !! Finally I found the solution. I was having this problem since I began to deploy Yii apps. You should definitely mark this topic as "resolved" to help others quickly find this solution.

Thanks