略微加速

PHP官方手册 - 互联网笔记

PHP - Manual: Session 函数

2024-11-15

Session 函数

目录

add a noteadd a note

User Contributed Notes 23 notes

up
14
Jeremy Speer
12 years ago
When working on a project, I found a need to switch live sessions between two different pieces of software. The documentation to do this is scattered all around different sites, especially in comments sections rather than examples. One difficulty I encountered was the session save handler for one of the applications was set, whereas the other was not. Now, I didn't code in the function session_set_save_handler(), instead I utilize that once I'm done with the function (manually), however this function could easily be extended to include that functionality. Basically, it is only overriding the system's default session save handler. To overcome this after you have used getSessionData(), just call session_write_close(), session_set_save_handler() with the appropriate values, then re-run session_name(), session_id() and session_start() with their appropriate values. If you don't know the session id, it's the string located in $_COOKIE[session_name], or $_REQUEST[session_name] if you are using trans_sid. [note: use caution with trusting data from $_REQUEST, if at all possible, use $_GET or $_POST instead depending on the page].

<?php
function getSessionData ($session_name = 'PHPSESSID', $session_save_handler = 'files') {
   
$session_data = array();
   
# did we get told what the old session id was? we can't continue it without that info
   
if (array_key_exists($session_name, $_COOKIE)) {
       
# save current session id
       
$session_id = $_COOKIE[$session_name];
       
$old_session_id = session_id();
       
       
# write and close current session
       
session_write_close();
       
       
# grab old save handler, and switch to files
       
$old_session_save_handler = ini_get('session.save_handler');
       
ini_set('session.save_handler', $session_save_handler);
       
       
# now we can switch the session over, capturing the old session name
       
$old_session_name = session_name($session_name);
       
session_id($session_id);
       
session_start();
       
       
# get the desired session data
       
$session_data = $_SESSION;
       
       
# close this session, switch back to the original handler, then restart the old session
       
session_write_close();
       
ini_set('session.save_handler', $old_session_save_handler);
       
session_name($old_session_name);
       
session_id($old_session_id);
       
session_start();
    }
   
   
# now return the data we just retrieved
   
return $session_data;
}
?>
up
10
pautzomat at web dot de
18 years ago
Be aware of the fact that absolute URLs are NOT automatically rewritten to contain the SID.

Of course, it says so in the documentation ('Passing the Session Id') and of course it makes perfectly sense to have that restriction, but here's what happened to me:
I have been using sessions for quite a while without problems. When I used a global configuration file to be included in all my scripts, it contained a line like this:

$sHomeDirectory = 'http://my.server.com/one/of/my/projects'

which was used to make sure that all automatically generated links had the right prefix (just like $cfg['PmaAbsoluteUri'] works in phpMyAdmin). After introducing that variable, no link would pass the SID anymore, causing every script to return to the login page. It took me hours (!!) to recognize that this wasn't a bug in my code or some misconfiguration in php.ini and then still some more time to find out what it was. The above restriction had completely slipped from my mind (if it ever was there...)

Skipping the 'http:' did the job.

OK, it was my own mistake, of course, but it just shows you how easily one can sabotage his own work for hours... Just don't do it ;)
up
7
Edemilson Lima <pulstar at gmail dot com>
15 years ago
Sessions and browser's tabs

May you have noticed when you open your website in two or more tabs in Firefox, Opera, IE 7.0 or use 'Control+N' in IE 6.0 to open a new window, it is using the same cookie or is passing the same session id, so the another tab is just a copy of the previous tab. What you do in one will affect the another and vice-versa. Even if you open Firefox again, it will use the same cookie of the previous session. But that is not what you need mostly of time, specially when you want to copy information from one place to another in your web application. This occurs because the default session name is "PHPSESSID" and all tabs will use it. There is a workaround and it rely only on changing the session's name.

Put these lines in the top of your main script (the script that call the subscripts) or on top of each script you have:

<?php
if(version_compare(phpversion(),'4.3.0')>=0) {
    if(!
ereg('^SESS[0-9]+$',$_REQUEST['SESSION_NAME'])) {
       
$_REQUEST['SESSION_NAME']='SESS'.uniqid('');
    }
   
output_add_rewrite_var('SESSION_NAME',$_REQUEST['SESSION_NAME']);
   
session_name($_REQUEST['SESSION_NAME']);
}
?>

How it works:

First we compare if the PHP version is at least 4.3.0 (the function output_add_rewrite_var() is not available before this release).

After we check if the SESSION_NAME element in $_REQUEST array is a valid string in the format "SESSIONxxxxx", where xxxxx is an unique id, generated by the script. If SESSION_NAME is not valid (ie. not set yet), we set a value to it.

uniqid('') will generate an unique id for a new session name. It don't need to be too strong like uniqid(rand(),TRUE), because all security rely in the session id, not in the session name. We only need here a different id for each session we open. Even getmypid() is enough to be used for this, but I don't know if this may post a treat to the web server. I don't think so.

output_add_rewrite_var() will add automatically a pair of 'SESSION_NAME=SESSxxxxx' to each link and web form in your website. But to work properly, you will need to add it manually to any header('location') and Javascript code you have, like this:

<?php
header
('location: script.php?'.session_name().'='.session_id()
      .
'&SESSION_NAME='.session_name());
?>
<input type="image" src="button.gif" onClick="javascript:open_popup('script.php?<?php
echo session_name(); ?>=<?php echo session_id(); ?>&SESSION_NAME=<?php echo session_name(); ?>')" />

The last function, session_name() will define the name of the actual session that the script will use.

So, every link, form, header() and Javascript code will forward the SESSION_NAME value to the next script and it will know which is the session it must use. If none is given, it will generate a new one (and so, create a new session to a new tab).

May you are asking why not use a cookie to pass the SESSION_NAME along with the session id instead. Well, the problem with cookie is that all tabs will share the same cookie to do it, and the sessions will mix anyway. Cookies will work partially if you set them in different paths and each cookie will be available in their own directories. But this will not make sessions in each tab completly separated from each other. Passing the session name through URL via GET and POST is the best way, I think.
up
6
hinom06 [at] hotmail.co.jp
11 years ago
simple session test version 1.1

<?php
/* [EDIT by danbrown AT php DOT net:
   The author of this note named this
   file tmp.php in his/her tests. If
   you save it as a different name,
   simply update the links at the
   bottom to reflect the change.] */

error_reporting( E_ALL );
ini_set( 'display_errors', 1);
date_default_timezone_set('Asia/Tokyo');

//ini_set( 'session.save_path', '/tmp' ); // for debug purposes
  
session_start();

// check if session_id() exists.
/*
for example, if exists and session wont read, must send session.name as parameter in URL.

Some servers configurations may have problem to recognize PHPSESSID, even if transid value is 0 or 1. 
So, this test is usefull to identify any causes.

*/
if( session_id() == '' )
{
    echo
'session_id() empty';
}else{
    echo
session_id();
}
echo
'<hr>';

$sessPath   = ini_get('session.save_path');
$sessCookie = ini_get('session.cookie_path');
$sessName   = ini_get('session.name');
$sessVar    = 'foo';

echo
'<br>sessPath: ' . $sessPath;
echo
'<br>sessCookie: ' . $sessCookie;

echo
'<hr>';

if( !isset(
$_GET['p'] ) ){
   
// instantiate new session var
   
$_SESSION[$sessVar] = 'hello world';
}else{
    if(
$_GET['p'] == 1 ){

       
// printing session value and global cookie PHPSESSID
       
echo $sessVar . ': ';
        if( isset(
$_SESSION[$sessVar] ) ){
            echo
$_SESSION[$sessVar];
        }else{
            echo
'[not exists]';
        }

        echo
'<br>' . $sessName . ': ';

        if( isset(
$_COOKIE[$sessName] ) ){
        echo
$_COOKIE[$sessName];
        }else{
            if( isset(
$_REQUEST[$sessName] ) ){
            echo
$_REQUEST[$sessName];
            }else{
                if( isset(
$_SERVER['HTTP_COOKIE'] ) ){
                echo
$_SERVER['HTTP_COOKIE'];
                }else{
                echo
'problem, check your PHP settings';
                }
            }
        }

    }else{

       
// destroy session by unset() function
       
unset( $_SESSION[$sessVar] );

       
// check if was destroyed
       
if( !isset( $_SESSION[$sessVar] ) ){
            echo
'<br>';
            echo
$sessName . ' was "unseted"';
        }else{
            echo
'<br>';
            echo
$sessName . ' was not "unseted"';
        }

    }
}
?>
<hr>
<a href=tmp.php?p=1&<?php echo $sessName . '=' . session_id();?>>test 1 (printing session value)</a>
<br>
<a href=tmp.php?p=2&<?php echo $sessName . '=' . session_id();?>>test 2 (kill session)</a>
up
6
Csar
14 years ago
There's a bug in Internet explorer in which sessions do not work if the name of the server is not a valid name. For example...if your server is called web_server (_ isn't a valid character), if you call a page which uses sessions like http://web_server/example.php your sessions won't work but sessions will work if you call the script like this
[IP NUMBER]/example.php
up
6
Sam Yong - hellclanner at live dot com
10 years ago
The following has been tested true in PHP 5.3.5.

Setting the session variables after the execution of the script i.e. in __destruct function, will not work.

<?php

class Example{

    function
__destruct(){
       
$_SESSION['test'] = true;
       
session_write_close();
    }

}

?>

The above example will write nothing into the temporary session file, as I observed through a custom Session Save Handler.
up
4
hinom - iMasters
14 years ago
simple session test

<?php
/* [EDIT by danbrown AT php DOT net:
   The author of this note named this
   file tmp.php in his/her tests. If
   you save it as a different name,
   simply update the links at the
   bottom to reflect the change.] */

session_start();

$sessPath   = ini_get('session.save_path');
$sessCookie = ini_get('session.cookie_path');
$sessName   = ini_get('session.name');
$sessVar    = 'foo';

echo
'<br>sessPath: ' . $sessPath;
echo
'<br>sessCookie: ' . $sessCookie;

echo
'<hr>';

if( !isset(
$_GET['p'] ) ){
   
// instantiate new session var
   
$_SESSION[$sessVar] = 'hello world';
}else{
    if(
$_GET['p'] == 1 ){

       
// printing session value and global cookie PHPSESSID
       
echo $sessVar . ': ';
        if( isset(
$_SESSION[$sessVar] ) ){
            echo
$_SESSION[$sessVar];
        }else{
            echo
'[not exists]';
        }

        echo
'<br>' . $sessName . ': ';

        if( isset(
$_COOKIE[$sessName] ) ){
        echo
$_COOKIE[$sessName];
        }else{
            if( isset(
$_REQUEST[$sessName] ) ){
            echo
$_REQUEST[$sessName];
            }else{
                if( isset(
$_SERVER['HTTP_COOKIE'] ) ){
                echo
$_SERVER['HTTP_COOKIE'];
                }else{
                echo
'problem, check your PHP settings';
                }
            }
        }

    }else{

       
// destroy session by unset() function
       
unset( $_SESSION[$sessVar] );

       
// check if was destroyed
       
if( !isset( $_SESSION[$sessVar] ) ){
            echo
'<br>';
            echo
$sessName . ' was "unseted"';
        }else{
            echo
'<br>';
            echo
$sessName . ' was not "unseted"';
        }

    }
}
?>
<hr>
<a href=tmp.php?p=1>test 1 (printing session value)</a>
<br>
<a href=tmp.php?p=2>test 2 (kill session)</a>
up
1
brfelipe08 at hotmail dot com
12 years ago
If you need to use sessions, and some accents required for some Latin-based languages, you should encode your files in ISO-8859-1.
You will run into some problems if you try to use UTF-8 - with or without BOM -, and ANSI will not support accents.
ISO-8859-1 will both support sessions and the accents.
up
1
carl /a/ suchideas /o/ com
14 years ago
Another gotcha to add to this list is that using a relative session.save_path is a VERY BAD idea.

You can just about pull it off, if you're very careful, but note two related points:

1) The path is taken relative to the directory of the ORIGINALLY executed script, so unless all pages are run from the same directory, you'll have to set the directory separately in each individual subfolder

2) If you call certain functions, such as session_regenerate_id(), PHP will try to take the session directory relative to the exectuable, or something like that, creating an error IN the executable. This provides slightly cryptic error messages, like this:

Warning: Unknown: open(relative_path\ilti9oq3j9ks0jvih1fmiq4sv1.session, O_RDWR) failed: No such file or directory (2) in Unknown on line 0

Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (relative_path) in Unknown on line 0

... so don't even bother. Just use

<?php ini_set("session.save_path",dirname(__FILE__)."/relative_path"); ?>

(or equivalent) in a file which you know is always in the same place relative to the file.

{PHP version 5.1.6}
up
0
LaurentT
13 years ago
For UNIX :

One might encounter some problems with sessions, having different sites on the same server : sessions would either merge if one is using more than one site at a time or crash if sites are owned by different system users. For instance :

www.example.com is stored in /home/site1/www
www.example.net is stored in /home/site2/www

Using both www.example.com and www.example.net would cause sessions to act weird.

If you're using PHP as an Apache module, you can easely use php_value in the http.conf to set a unique session.name depending on the site. If you're using suPHP though (PHP as CGI) you can't use php_value, though you can use suPHP_ConfigPath.

Here's an example :

<VirtualHost 10.10.10.10:8081>
    DocumentRoot /home/site1/www
    ServerName www.example.com
    suPHP_ConfigPath /home/site1/server_config
</VirtualHost>
<VirtualHost 10.10.10.10:8082>
    DocumentRoot /home/site2/www
    ServerName www.example.net
    suPHP_ConfigPath /home/site2/server_config
</VirtualHost>

Each server_config folder contain a php.ini file specific to the vHost. You then just have to change the values of each session.name to unique ones and you're done !
up
0
paul at shirron dot net
14 years ago
In php.ini, I have:

session.save_path="C:\DOCUME~1\pjs9486\LOCALS~1\Temp\php\session"

I was cleaning out the temp directory, and deleted the php directory. Session stuff quit working. I re-created the php directory. Still no luck. I re-created the session directory in the php directory, and session stuff resumed working.

I would have expected session_start() to have re-created directories in the path, if they didn't exist, but, it doesn't.

Note to self: Don't do that again!!!!
up
-1
ted at tedmurph dot com
11 years ago
I was having problems with $_SESSION information not being written or being lost in a seemingly random way.  There was a Location: call being made deep in a Zend OAuth module, I am using an IIS server with PHP as a CGI, etc.

The answer was simply that you need to have the domain be consistent for sessions to work consistently.  In my case, I was switching back and forth between www.EXAMPLE.com:888 and EXAMPLE.com:888.  The unusual port, the hidden Location: call, the handoff with OAuth, etc all served to confuse me, but the intermitent error was caused by this simple goof of keeping the domain consistent.
up
-1
edA-qa at disemia dot com
13 years ago
WARNING for Debian users.  Just to drive you completely crazy Debian does its own form of session management and will completely ignore all alterations to the values who do within your PHP script.

Debian sets up a <crontab /etc/cron.d/php5> which deletes all files, including those in subdirectories, which exceed the gc_maxlifetime specified in the <php.ini> file only.

That is, on Debian (and likely variants like Ubuntu) modifying the session expiration settings (like gc_maxlifetime) does *NOTHING*.  You *HAVE* to modify the global <php.ini>.  Not even a <.htaccess> file will help you.
up
-1
farhad dot pd at gmail dot com
5 years ago
<?php
class Session
{

    public static
$seesionFlashName = '__FlashBack';
   
/**
     * [__construct description]
     */
   
public function __construct() {

    }

    public static function
start() {
       
ini_set('session.use_only_cookies', 'Off');
       
ini_set('session.use_cookies', 'On');
       
ini_set('session.use_trans_sid', 'Off');
       
ini_set('session.cookie_httponly', 'On');

        if (isset(
$_COOKIE[session_name()]) && !preg_match('/^[a-zA-Z0-9,\-]{22,52}$/', $_COOKIE[session_name()])) {
            exit(
'Error: Invalid session ID!');
        }

       
session_set_cookie_params(0, '/');
       
session_start();
    }

    public static function
id() {
        return
sha1(session_id());
    }

    public static function
regenerate() {
       
session_regenerate_id(true);
    }

   
/**
     * [exists description]
     * @param  [type] $name [description]
     * @return [type]       [description]
     */
   
public static function exists($name) {
        if(isset(
$name) && $name != '') {
            if(isset(
$_SESSION[$name])) {
                return
true;
            }
        }

        return
false;
    }

   
/**
     * [set description]
     * @param [type] $name  [description]
     * @param [type] $value [description]
     */
   
public static function set($name='', $value='') {
        if(
$name != '' && $value != '') {
           
$_SESSION[$name] = $value;
        }
    }

   
/**
     * [get description]
     * @param  [type] $name [description]
     * @return [type]       [description]
     */
   
public static function get($name) {
        if(
self::exists($name)) {
            return
$_SESSION[$name];
        }

        return
false;
    }

   
/**
     * [delete description]
     * @param  [type] $name [description]
     * @return [type]       [description]
     */
   
public static function delete($name) {
        if(
self::exists($name)) {
            unset(
$_SESSION[$name]);
        }

        return
false;
    }

   
/**
     * [setFlash description]
     * @param string $value [description]
     */
   
public static function setFlash($value='') {
        if(
$value != '') {
           
self::set(self::$seesionFlashName, $value);
        }
    }

   
/**
     * [getFlash description]
     * @return [type] [description]
     */
   
public static function getFlash() {
        if(
self::exists(self::$seesionFlashName)) {
           
ob_start();
                echo
self::get(self::$seesionFlashName);
               
$content = ob_get_contents();
           
ob_end_clean();

           
self::delete(self::$seesionFlashName);

            return
$content;
        }

        return
false;
    }

   
/**
     * [flashExists description]
     * @return [type] [description]
     */
   
public static function flashExists() {
        return
self::exists(self::$seesionFlashName);
    }

   
/**
     * [destroy description]
     * @return void [description]
     */
   
public static function destroy() {
        foreach(
$_SESSION as $sessionName) {
           
self::delete($sessionName);
        }

       
session_destroy();
    }
}
?>

iranian php programmer
farhad zand moghadam
up
-1
Nigel Barlass
14 years ago
Lima's note on sessions and browser's tabs needs to be modified for my version of php as the call to uniqid('') will return an alphanumeric string.
Hence the ereg statement should be:
if(!ereg('^SESS[0-9a-z]+$',$_REQUEST['SESSION_NAME'])) {...
up
-2
session a emailaddress d cjb d net
14 years ago
It doesn't appear in the documentation, or in anyone's comment here, but setting session.gc_maxlifetime to 0 means the session will not expire until the browser is closed.

Of course this still doesn't fix the problems associated with the garbage collector doing it's own thing.
The best solution to that still appears to be changing session.save_path
up
-4
jitchavan at gmail dot com
11 years ago
IE issue :-

when form target set to iframe source and after posting form content you are setting session variables,
In this scenario if parent page having image src blank then session values set in iframe action page will be LOST surprisingly in IE ONLY.Solution is quite simple don't keep Image src blank.
up
-3
edA-qa at disemia dot com
13 years ago
Sessions may be deleted before the time limit you set in gc_maxlifetime.

If you have multiple pages on the same server, each using the session (the same or distinct named sessions, it doesn't matter), the *minimum* gc_maxlifetime of any of those scripts ends up being the effective lifetime of the session files.

This can also apply to the lifetime coming from a CLI invocation of a PHP script on that machine which happens to use the session.

This can be bothersome since even though you think all your pages include the same file which sets up the script, even a single PHP page which doesn't can invoke the GC and have the scripts deleted.

Thus, if you need to set a long gc_maxlifetime you are best doing this through the INI file or in a .htaccess file for the entire directory.
up
-4
Trevor Brown
11 years ago
A confirmation of behaviour, just in case this saves anyone else some time...

There is (potentially) a special case when session.gc_probability = 0 and session.gc_divisor = 0.  Depending on how they wanted to work their maths underneath, the coders *might* have opted to interpret 0/0 as 1 (which is sometimes assumed in certain maths proofs), but thankfully it seems they haven't.  With both values set to 0, the session code will follow the spirit of the directives and invoke the garbage collector with zero probability.  At least this is true with php 5.2.5 (which, to be certain, I inspected the source of).

To be safe, however, setting both to zero is *probably* not a good idea because usually 0/0 is undefined, so it could presumably mean anything (some arguments exist that claim 0/0 is equal to every fraction).  Wouldn't you rather know for sure what your probability was set to?  In other words, don't set gc_divisor = 0
up
-4
jsnell at e-normous dot com
14 years ago
Careful not to try to use integer as a key to the $_SESSION array (such as $_SESSION[0] = 1;)  or you will get the error "Notice: Unknown: Skipping numeric key 0. in Unknown on line 0"
up
-3
shanemayer42 at yahoo dot com
21 years ago
Session Garbage Collection Observation:

It appears that session file garbage collection occurs AFTER the current session is loaded. 

This means that:
even if session.gc_maxlifetime = 1 second,
if someone starts a session A and no one starts a session for an hour,  that person can reconnect to session A and all of their previous session values will be available (That is, session A will not be cleaned up even though it is older than gc_maxlifetime).
up
-6
Ray.Paseur sometimes uses Gmail
5 years ago
PHP 5+ you cannot store StdClass and similar built-in objects in the session.  The class definitions do not exist in a way that allows PHP to serialize/unserialize the information.  This results in a fatal error; the entire contents of the session is lost.

<?php
error_reporting
(E_ALL);
session_start();
var_dump($_SESSION); // INITIAL STATE
$_SESSION['hello'] = 'World';
var_dump($_SESSION); // MUTATED STATE

// AN XML STRING FOR TEST DATA
$xml = <<<EOD
<?xml version="1.0"?>
<families>
  <parent>
    <child index="1" value="Category 1">Child One</child>
  </parent>
</families>
EOD;

// STORE THE SimpleXMLElement OBJECT IN THE SESSION
$_SESSION['obj'] = SimpleXML_Load_String($xml);
up
-9
Vextor
14 years ago
It seems that the garbage engine can't delete the expired session related to the itself. If there is only one session, it won't expire even if it has expired the gc_maxlifetime set.

It will be necessary another client connecting, starting a different session, and the garbage collector of this new session will be able to clean the other expired sessions.

I tested this in Windows with file sessions.

官方地址:https://www.php.net/manual/en/ref.session.php

北京半月雨文化科技有限公司.版权所有 京ICP备12026184号-3