[pmwiki-users] pmwiki and 'user' php session handler (sharedanced)

Patrick R. Michaud pmichaud at pobox.com
Sun May 20 10:23:06 CDT 2007


On Fri, May 18, 2007 at 11:16:48AM +0200, Jean-Fabrice [gmail] wrote:
> Well.
>  After some investigations, I found this error in the log : "Fatal
> error: session_start(): Failed to initialize storage module: user".
> Calling session_start twice when working with 'user'  set_save_handler
> seems to have bad effect.
> 
> I patched my pmwiki.php (2.2.0 beta 42) with the following :
> ===================================================================
> --- pmwiki.php  (revision 1098)
> +++ pmwiki.php  (working copy)
> @@ -1736,7 +1736,7 @@
>    if (!$auth && ($called > 1 || !@$_REQUEST[session_name()])) return;
> 
>    $sid = session_id();
> -  @session_start();
> +  if (!$sid) @session_start();
>    foreach((array)$auth as $k => $v)
>      if ($k) $_SESSION[$k] = (array)$v + (array)@$_SESSION[$k];
> ...
> and now it works. Patrick : do you see any bad effect with this patch ?

Unfortunately, yes.

PHP doesn't provide a reliable way to know if a session is currently
open.  All that session_id() does is determine if a session has _ever_
been opened in the current PHP execution.  It doesn't tell you if 
the session was subsequently closed (e.g., via session_write_close() ).

So, consider the following sequence:

    $sid = session_id();
    if (!$sid) @session_start();
    ## ...stuff with $_SESSION...
    session_write_close();
    ## ...and then later...
    $sid = session_id();
    if (!$sid) @session_start();
    ## ...

The second call to session_id() will return a non-empty string,
therefore the second session_start() won't be executed, and the
session won't be opened for further changes.  So, we have to execute
the call to session_start() even when $sid returns a non-empty value.

Of course, some people will then ask why we are doing session_write_close() .
Well, another nasty feature of PHP sessions is that they are self-locking.
This means that any given session can be opened by only one process
(e.g., browser window or tab) at a time.  So, if a visitor opens multiple
browser windows or tabs to the site (as I frequently do), then only one of 
those may have a session open at a time.  Thus, if we open the session at 
the beginning of the script, and don't close the session until the end of
processing, then a lot of processes end up waiting on the session lock.
Using session_write_close() releases the lock so that other browser 
windows may proceed.

It gets worse.  Since PHP's locks on session files are not detectable or 
breakable, if sessions aren't closed then we often run into deadlocks
with the transaction lock that PmWiki uses for edit and write operations.
In other words, we can easily end up with the situation where one process
has the session lock and is waiting on the transaction lock, and another
process has a transaction lock but is waiting on the session lock.
And while this deadlock exists, no other processes can obtain the
transaction lock to perform other updates.

PmWiki avoids the deadlock by explicitly closing any open session
with session_write_close() prior to obtaining a transaction lock.

So, we can't easily get rid of session_write_close().  

What PmWiki does is to simply call @session_start() whenever it needs
access to session variables, and ignore any "session already open"
warning that results.  Unfortunately, this doesn't seem to work when
PHP is using the 'user' session handler -- in that case, it seems
to generate a fatal error instead.

I don't have a good solution for this, as it appears to be a
fundamental design flaw in PHP's sessions implementation.
I'm open for suggestions.

In the past we considered creating a custom wrapper function
around session_start() that handles session management, but this
breaks down somewhat if there are any recipes that bypass the
wrapper and call session_start() directly on their own.

Hope this helps explain the problem -- perhaps we can come up with
a solution from there.

Pm



More information about the pmwiki-users mailing list