47

Per request, there are a few different ways that you can tell whether or not a session has been started, such as:

$isSessionActive = (session_id() != "");

Or:

$isSessionActive = defined('SID');

However, these both fail if you start a session, then close it; session_id() will return the prior session's ID, while SID will be defined. Likewise, calling session_start() at this point will generate an E_NOTICE if you already have a session active. Is there a sane way to check if a session is currently active, without having to resort to output buffering, the shut-up operator (@session_start()), or something else equally as hacky?

EDIT: I wrote a patch to try to get this functionality included in PHP: http://bugs.php.net/bug.php?id=52982

EDIT 8/29/2011: New function added to PHP 5.4 to fix this: "Expose session status via new function, session_status"

// as of 8/29/2011
$isSessionActive = (session_status() == PHP_SESSION_ACTIVE);

EDIT 12/5/11: session_status() on the PHP manual.

ken
  • 3,650
  • 1
  • 30
  • 43
  • This is maybe hacky: [`session_is_active()`](http://stackoverflow.com/questions/3788369/how-to-tell-if-a-session-is-active/7656468#7656468), but at least something I found. Thanks for the bug report anyway, nice to see this solved in 5.4. – hakre Oct 05 '11 at 04:26
  • Still a relevant question w/ the 5.4 addition, as I've just pushed to a 5.3 box and found `session_status()` missing! – quickshiftin Mar 18 '13 at 19:30
  • That's certainly odd, as it is indeed present on my 5.4 build. Areyou saying you're using 5.3 or 5.4? Was it a custom or prebuilt PHP binary? In `phpinfo()`, do you have a "session" section? In action: http://codepad.viper-7.com/PiZmcw – ken Mar 18 '13 at 21:04

7 Answers7

29

See edits to the original question; basically, PHP 5.4 and above now has a function called session_status() to solve this problem!

"Expose session status via new function, session_status" (SVN Revision 315745)

If you need this functionality in a pre-PHP 5.4 version, see hakre's answer.

Community
  • 1
  • 1
ken
  • 3,650
  • 1
  • 30
  • 43
15

I worked around this by adding a couple wrapper functions around the various session creation/closing/destroying functions. Basically:

function open_session() {
     session_start();
     $_SESSION['is_open'] = TRUE;
}

function close_session() {
   session_write_close();
   $_SESSION['is_open'] = FALSE;
}

function destroy_session() {
   session_destroy();
   $_SESSION['is_open'] = FALSE;
}

function session_is_open() {
   return($_SESSION['is_open']);
}

Hackish, but accomplished what I needed.

typeoneerror
  • 55,990
  • 32
  • 132
  • 223
Marc B
  • 356,200
  • 43
  • 426
  • 500
  • Well, this is also the solution that I have chosen... the alternative would probably have been implementing a session write handler that modifies an internal flag that you can then check, but this would have sort of defeated its own purpose because it would have to be defined in the beginning. – Arc Sep 25 '10 at 22:39
  • in the session_close function there is a stray curly bracket that needs to be a semicolon. SO won't let me edit because not enough characters need editing. :/ – ShadeTreeDeveloper Mar 15 '13 at 17:05
11

I'm running into this as well, and a setting in $_SESSION is not an option for me. For PHP 5.3.8:

  1. If any session has been started with the request, define('SID') will return FALSE, as well as $_SESSION is unset.
  2. This is independent whether or not session_id() has been used to set a session id or not.
  3. After the first session_start(), SID is defined and $_SESSION is set to an empty array.
  4. session_destroy() does unset the session_id(), it's an empty string then. SID will remain defined (and set to it's previous value which might be an empty string). $_SESSION is left unchanged. It will get reset/populated next time session_start is called.

With these states, especially as session_id() can be called in between to set the id for the next session, it's not possible to safely determine the session status with SID, $_SESSION and session_id().

"Trying" with session_start() (e.g. with @) might not be really helpful, as this will change the session status and changing the contents of $_SESSION (and adding a set-cookie header if the cookie was not part of the request). It was not fitting in my case.

While I was running tests, I came across the behaviour, that you can not try to change the ini setting of session.serialize_handler when the session is active, not even when you set it to the same value. Same is true for session.use_trans_sidDocs which is more lightweight. This lead me to the following function:

/**
 * @return bool
 */
function session_is_active()
{
    $setting = 'session.use_trans_sid';
    $current = ini_get($setting);
    if (FALSE === $current)
    {
        throw new UnexpectedValueException(sprintf('Setting %s does not exists.', $setting));
    }
    $result = @ini_set($setting, $current); 
    return $result !== $current;
}

As far as I can see, the error is checking for active session status only (not disabled), so this should not return a false positive when sessions are disabled.

To get this function compatible with PHP 5.2, it needs a little modification:

/**
 * @return bool
 */
function session_is_active()
{
    $setting = 'session.use_trans_sid';
    $current = ini_get($setting);
    if (FALSE === $current)
    {
        throw new UnexpectedValueException(sprintf('Setting %s does not exists.', $setting));
    }
    $testate = "mix$current$current";
    $old = @ini_set($setting, $testate);
    $peek = @ini_set($setting, $current);
    $result = $peek === $current || $peek === FALSE;
    return $result;
}

Some sandbox.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • 1
    While this is still somewhat 'hacky', I'm impressed by your technique. It was my thinking that there were some attributes of the problem that would lend itself to inference (such as what you're doing here), I was just unable to find them. Very nice! – ken Oct 05 '11 at 15:17
  • Also, is the sandbox your site? The opcode analysis is sweet. – ken Oct 05 '11 at 15:18
  • No, that's not my site, but I like it, too. :) Right now I'm unsure with that hack if it works for PHP 5.1 (I might need that). – hakre Oct 05 '11 at 15:39
  • 1
    @Salathe was very kind and measure the routine against various PHP 5.1 versions (https://gist.github.com/1265615#gistfile1.txt), looks really like something useful for backward compat. – hakre Oct 05 '11 at 20:44
5

The following code only dumps one session_id() for me, not two

session_start();
echo session_id();
session_destroy();
echo session_id();

If you're having difficulties with this still you can try creating a variable to check, that you destroy when you destroy the session.

session_start();
$_SESSION['intialized'] = 'This will not print';
$_SESSION = array(); // Unset all variables
session_destroy();
echo $_SESSION['initialized']; // No output
Robert
  • 21,110
  • 9
  • 55
  • 65
  • 3
    But if you use session_write_close(), the session's closed, but $_SESSION data is still there, which is what I think the OP's getting at... how do you check if the session file itself is still in-use? – Marc B Sep 24 '10 at 15:26
  • Yeah, you basically posted the same solution I did, setting a variable before closing it (in any way) and checking that variable... – Robert Sep 24 '10 at 15:35
1

Here's a good drop in replacement that won't break stuff when you move to 5.4:

if(!function_exists('session_status')){
    function session_active(){
        return defined('SID');   
    }
}else{
    function session_active(){
        return (session_status() == PHP_SESSION_ACTIVE);   
    }        
}
Beachhouse
  • 4,972
  • 3
  • 25
  • 39
  • As I stated in my original question, that's an inadequate solution; if you call `session_start()` and then call `session_write_close()`, then `defined("SID") === true` even though the session is not open. Such a technique can only determine if a session has been started during the request cycle -- and not whether or not one is presently open. It may work for some use-cases, but it's not a replacement for `session_status()`. – ken Feb 06 '13 at 18:34
0

There are multiple places you need to check to verify the session is active:

1- cookie exists and is not expired 2- underlying session storage mechanism (file system or database) has a record matching the cookie.

beiller
  • 3,105
  • 1
  • 11
  • 19
  • I think you misunderstood the goal/intention. – ken May 07 '13 at 20:19
  • Perhaps yes. I am more used to dealing with sessions that have custom functionality. It would be good to encapsulate the session into a class so that when the destructor is called, or session_write_closed member function is called you update a boolean flag in that class showing active or not. – beiller May 08 '13 at 14:28
  • It's to avoid `Notice: A session had already been started - ignoring session_start()`. This bug has more information on the use-case: http://bugs.php.net/bug.php?id=52982 – ken May 08 '13 at 14:59
0

Ken, if the session is destroyed, the $_SESSION array should not be available...or at the very least, your values should be unset. So, in theory (untested) you should be able to check the array for a value to know if anything is currently set.

bpeterson76
  • 12,918
  • 5
  • 49
  • 82