PHP
downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

session_cache_expire> <session_pgsql_status
Last updated: Sun, 25 Nov 2007

view this page in

Session 会话处理函数

简介

PHP 中的会话支持由一种将特定数据保留用于之后的请求的方法组成。这样可以使用户建立更灵活的应用并提高网站的吸引力。

访问网站的来客会被分配一个唯一的标识符,即所谓的会话 ID。它要么存放在客户端的 cookie,要么经由 URL 传递。

会话支持允许用户注册任意数目的变量并保留给各个请求使用。当来客访问网站时,PHP 会自动(如果 session.auto_start 被设为 1)或在用户请求时(由 session_start() 明确调用或 session_register() 暗中调用)检查请求中是否发送了特定的会话 ID。如果是,则之前保存的环境就被重建。

Caution

如果确实启用了 session.auto_start,则不能将对象放入会话中,因为类定义必须在启动会话之前加载以在会话中重建对象。

请求结束后所有注册的变量都会被序列化。已注册但未定义的变量被标记为未定义。在之后的访问中这些变量也未被会话模块定义,除非用户以后定义它们。

Warning

有些类型的数据不能被序列化因此也就不能保存在会话中。包括 resource 变量或者有循环引用的对象(即某对象将一个指向自己的引用传递给另一个对象)。

Note: 会话处理是 PHP 4.0 添加的。

Note: 注意在使用会话时除非用 session_register() 函数注册了一个变量或者将一个新的键添加到了 $_SESSION 超全局数组中去,否则会话的记录不会被创建。不管会话是否用 session_start() 函数启动都是如此。

会话和安全

外部连接:» Session fixation

会话模块不能保证存放在会话中的信息只能被创建该会话的用户看到。根据其存放的数据,还需要采取更多措施来主动保护会话的完整性。

评估会话中携带的数据并实施附加保护措施――这通常要付出代价,降低用户的方便程度。例如,如果要保护用户免于受简单的社交策略侵害(注:指在 URL 中显示的会话 ID 会被别人在电脑屏幕上看到,或被别的网站通过 HTTP Referer 得到等),则应该启用 session.use_only_cookies。此情形下,客户端必须无条件启用 cookie,否则会话就不工作。

有几种途径会将现有的会话 ID 泄露给第三方。泄露出的会话 ID 使第三方能够访问所有与指定 ID 相关联的资源。第一,URL 携带会话 ID。如果连接到外部站点,包含有会话 ID 的 URL 可能会被存在外部站点的 Referer 日志中。第二,较主动的攻击者可能会侦听网段的数据包。如果未加密,会话 ID 会以明文方式在网络中流过。对此的解决方式是在服务器上实施 SSL 并强制用户使用。

需求

要编译本扩展模块无需外部库文件。

Note: 作为可选项,可以使用共享内存分配(mm),由 Ralf S. Engelschall 开发用于会话存储。必须下载 » mm 并安装。此选项在 Windows 平台下不可用。注意 mm 的会话存储模块不能保证到同一个会话的并发访问被正确地锁定。可能用基于共享内存的文件系统(例如 Solaris/Linux 中的 tmpfs,或 BSD 中的 /dev/md)来将会话存放到文件中更为恰当,因为这样会正确锁定。会话数据存放在内存中则 Web 服务器重启动会删除之。

安装

会话的支持在 PHP 默认为激活。如果不想在 PHP 中加入会话支持,应在配置时指定 --disable-session 选项。要为会话存储使用共享内存分配(mm),配置 PHP 时指定 --with-mm[=DIR]

PHP 的 Windows 版本已经内置该扩展模块的支持。无需加载任何附加扩展库即可使用这些函数。

Note: 默认情况下,所有与特定会话相关的数据都被存储在由 INI 选项 session.save_path 指定的目录下的一个文件中。对每个会话会建立一个文件(不论是否有数据与该会话相关)。这是由于每打开一个会话即建立一个文件,不论是否有数据写入到该文件中。注意由于和文件系统协同工作的限制,此行为有个副作用,有可能造成用户定制的会话处理器(例如用数据库)丢失了未存储数据的会话。

运行时配置

这些函数的行为受 php.ini 的影响。

会话配置选项
名称 默认值 可修改范围 更新纪录
session.save_path "" PHP_INI_ALL  
session.name "PHPSESSID" PHP_INI_ALL  
session.save_handler "files" PHP_INI_ALL  
session.auto_start "0" PHP_INI_ALL  
session.gc_probability "1" PHP_INI_ALL  
session.gc_divisor "100" PHP_INI_ALL 自 PHP 4.3.2 起可用。
session.gc_maxlifetime "1440" PHP_INI_ALL  
session.serialize_handler "php" PHP_INI_ALL  
session.cookie_lifetime "0" PHP_INI_ALL  
session.cookie_path "/" PHP_INI_ALL  
session.cookie_domain "" PHP_INI_ALL  
session.cookie_secure "" PHP_INI_ALL 自 PHP 4.0.4 起可用。
session.use_cookies "1" PHP_INI_ALL  
session.use_only_cookies "1" PHP_INI_ALL 自 PHP 4.3.0 起可用。
session.referer_check "" PHP_INI_ALL  
session.entropy_file "" PHP_INI_ALL  
session.entropy_length "0" PHP_INI_ALL  
session.cache_limiter "nocache" PHP_INI_ALL  
session.cache_expire "180" PHP_INI_ALL  
session.use_trans_sid "0" PHP_INI_ALL 在 PHP <= 4.2.3 是 PHP_INI_ALL,在 PHP < 5 是 PHP_INI_PERDIR。自 PHP 4.0.3 起可用。
session.bug_compat_42 "1" PHP_INI_ALL 自 PHP 4.3.0 起可用。
session.bug_compat_warn "1" PHP_INI_ALL 自 PHP 4.3.0 起可用。
session.hash_function "0" PHP_INI_ALL 自 PHP 5.0.0 起可用。
session.hash_bits_per_character "4" PHP_INI_ALL 自 PHP 5.0.0 起可用。
url_rewriter.tags "a=href,area=href,frame=src,form=,fieldset=" PHP_INI_ALL 自 PHP 4.0.4 起可用。
有关 PHP_INI_* 常量进一步的细节与定义参见php.ini 配置选项

会话管理系统支持许多配置选项,可以在自己的 php.ini 文件中设定。这里只是个简短的概览。

session.save_handler string
session.save_handler 定义了来存储和获取与会话关联的数据的处理器的名字。默认为 files。参见 session_set_save_handler()
session.save_path string
session.save_path 定义了传递给存储处理器的参数。如果选择了默认的 files 文件处理器,则此值是创建文件的路径。默认为 /tmp。参见 session_save_path()

此指令还有一个可选的 N 参数来决定会话文件分布的目录深度。例如,设定为 '5;/tmp' 将使创建的会话文件和路径类似于 /tmp/4/b/1/e/3/sess_4b1e384ad74619bd212e236e52a5a174If。要使用 N 参数,必须在使用前先创建好这些目录。在 ext/session 目录下有个小的 shell 脚本名叫 mod_files.sh 可以用来做这件事。此外注意如果使用了 N 参数并且 N 大于 0,那么将不会执行自动垃圾回收,更多信息见 php.ini。另外如果用了 N 参数,要确保将 session.save_path 的值用双引号 "quotes" 括起来,因为分隔符分号( ;)在 php.ini 中也是注释符号。

Warning

如果将此设定为一个全局可读的目录,例如 /tmp(默认值),服务器上的其他用户有可能通过该目录的文件列表破解会话。

Note: 在 PHP 4.3.6 之前,Windows 用户必须修改此选项以使用 PHP 的会话函数。必须指定一个合法路径,例如:c:/temp

session.name string
session.name 指定会话名以用做 cookie 的名字。只能由字母数字组成,默认为 PHPSESSID。参见 session_name()
session.auto_start boolean
session.auto_start 指定会话模块是否在请求开始时自动启动一个会话。默认为 0(不启动)。
session.serialize_handler string
session.serialize_handler 定义用来序列化/解序列化的处理器名字。当前支持 PHP 内部格式(名为 php)和 WDDX(名为 wddx)。如果 PHP 编译时加入了 WDDX 支持,则只能用 WDDX。默认为 php
session.gc_probability integer
session.gc_probabilitysession.gc_divisor 合起来用来管理 gc(garbage collection 垃圾回收)进程启动的概率。默认为 1。详见 session.gc_divisor
session.gc_divisor integer
session.gc_divisorsession.gc_probability 合起来定义了在每个会话初始化时启动 gc(garbage collection 垃圾回收)进程的概率。此概率用 gc_probability/gc_divisor 计算得来。例如 1/100 意味着在每个请求中有 1% 的概率启动 gc 进程。session.gc_divisor 默认为 100
session.gc_maxlifetime integer
session.gc_maxlifetime 指定过了多少秒之后数据就会被视为“垃圾”并被清除。

Note: 如果不同的脚本具有不同的 session.gc_maxlifetime 数值但是共享了同一个地方存储会话数据,则具有最小数值的脚本会清理数据。此情况下,与 session.save_path 一起使用本指令。

Note: 如果使用默认的基于文件的会话处理器,则文件系统必须保持跟踪访问时间(atime)。Windows FAT 文件系统不行,因此如果必须使用 FAT 文件系统或者其他不能跟踪 atime 的文件系统,那就不得不想别的办法来处理会话数据的垃圾回收。自 PHP 4.2.3 起用 mtime(修改时间)来代替了 atime。因此对于不能跟踪 atime 的文件系统也没问题了。

session.referer_check string
session.referer_check 包含有用来检查每个 HTTP Referer 的子串。如果客户端发送了 Referer 信息但是在其中并未找到该子串,则嵌入的会话 ID 会被标记为无效。默认为空字符串。
session.entropy_file string
session.entropy_file 给出了一个到外部资源(文件)的路径,该资源将在会话 ID 创建进程中被用作附加的熵值资源。例如在许多 Unix 系统下都可以用 /dev/random/dev/urandom
session.entropy_length integer
session.entropy_length 指定了从上面的文件中读取的字节数。默认为 0(禁用)。
session.use_cookies boolean
session.use_cookies 指定是否在客户端用 cookie 来存放会话 ID。默认为 1(启用)。
session.use_only_cookies boolean
session.use_only_cookies 指定是否在客户端仅仅使用 cookie 来存放会话 ID。。启用此设定可以防止有关通过 URL 传递会话 ID 的攻击。此设定是 PHP 4.3.0 添加的。
session.cookie_lifetime integer
session.cookie_lifetime 以秒数指定了发送到浏览器的 cookie 的生命周期。值为 0 表示“直到关闭浏览器”。默认为 0。参见 session_get_cookie_params()session_set_cookie_params()
session.cookie_path string
session.cookie_path 指定了要设定会话 cookie 的路径。默认为 /。参见 session_get_cookie_params()session_set_cookie_params()
session.cookie_domain string
session.cookie_domain 指定了要设定会话 cookie 的域名。默认为无,表示根据 cookie 规范产生 cookie 的主机名。参见 session_get_cookie_params()session_set_cookie_params()
session.cookie_secure boolean
session.cookie_secure 指定是否仅通过安全连接发送 cookie。默认为 off。此设定是 PHP 4.0.4 添加的。参见 session_get_cookie_params()session_set_cookie_params()
session.cache_limiter string
session.cache_limiter 指定会话页面所使用的缓冲控制方法(none/nocache/private/private_no_expire/public)。默认为 nocache。参见 session_cache_limiter()
session.cache_expire integer
session.cache_expire 以分钟数指定缓冲的会话页面的存活期,此设定对 nocache 缓冲控制方法无效。默认为 180。参见 session_cache_expire()
session.use_trans_sid boolean
session.use_trans_sid 指定是否启用透明 SID 支持。默认为 0(禁用)。

Note: 对于 PHP 4.1.2 或以下版本,可以通过加入 --enable-trans-sid 配置选项去编译来启用,从 PHP 4.2.0 起,trans-sid 特性总是被编译。 基于 URL 的会话管理比基于 cookie 的会话管理有更多安全风险。例如用户有可能通过 email 将一个包含有效的会话 ID 的 URL 发给他的朋友,或者用户总是有可能在收藏夹中存有一个包含会话 ID 的 URL 来以同样的会话 ID 去访问站点。

session.bug_compat_42 boolean
PHP 4.2.3 以及更低版本有一个未公开的特性/错误,它允许用户在 register_globals 被禁用的情况下在全局范围内初始化一个会话变量。PHP 4.3.0 及更高版本会在使用此特性时并且启用了 session.bug_compat_warn 时发出警告。此特性/错误可以通过关闭此选项而禁用。
session.bug_compat_warn boolean
PHP 4.2.3 以及更低版本有一个未公开的特性/错误,它允许用户在 register_globals 被禁用的情况下在全局范围内初始化一个会话变量。PHP 4.3.0 及更高版本会在使用此特性时并且同时启用了 session.bug_compat_42session.bug_compat_warn 时发出警告。
session.hash_function integer
session.hash_function 允许用户指定生成会话 ID 的散列算法。'0' 表示 MD5(128 位),'1' 表示 SHA-1(160 位)。

Note: 这是 PHP 5 引进的。

session.hash_bits_per_character integer
session.hash_bits_per_character 允许用户定义将二进制散列数据转换为可读的格式时每个字符存放多少个比特。可能值为 '4'(0-9,a-f),'5'(0-9,a-v),以及 '6'(0-9,a-z,A-Z,"-",",")。

Note: 这是 PHP 5 引进的。

url_rewriter.tags string
url_rewriter.tags 指定在使用透明 SID 支持时哪些 HTML 标记会被修改以加入会话 ID。默认为 a=href,area=href,frame=src,input=src,form=fakeentry,fieldset=

Note: 如果要符合 XHTML,去掉 form 项并在表单字段前后加上 <fieldset> 标记。

track_varsregister_globals 配置选项影响到会话变量是怎样存储和恢复的。

Note: 自 PHP 4.0.3 起,track_vars 总是打开的。

资源类型

本扩展模块未定义任何资源类型。

预定义常量

以下常量由本扩展模块定义,因此只有在本扩展模块被编译到 PHP 中,或者在运行时被动态加载后才有效。

SID (string)
包含着会话名以及会话 ID 的常量,格式为 "name=ID",或者如果会话 ID 已经在适当的会话 cookie 中设定时则为空字符串。

范例

Note: 自 PHP 4.1.0 起,$_SESSION 如同 $_POST$_GET$_REQUEST 等一样成为全局数组。与 $HTTP_SESSION_VARS 不同,$_SESSION 总是具有全局范围。因此不要对 $_SESSION 使用 global 关键字。注意本文档已被改为在所有地方都使用 $_SESSION。如果倾向后者,可以将 $HTTP_SESSION_VARS 都替换成 $_SESSION。此外注意必须在使用 $_SESSION 之前先用 session_start() 启动会话。
$_SESSION 关联数组中的键名具有和 PHP 中普通变量名相同的规则,即不能以数字开头,必须以字母或下划线开头。更多细节见本手册中变量一章。

如果 register_globals 被禁用,则只有全局关联数组 $_SESSION 中的成员可以被注册为会话变量。被恢复的会话变量也只存在于 $_SESSION 数组中。

为提高安全性和代码的可读性,建议使用 $_SESSION(或在 PHP 4.0.6 或更低版本中用 $HTTP_SESSION_VARS)。使用了 $_SESSION,就没有必要使用 session_register()session_unregister()session_is_registered() 函数。访问会话变量就和其它变量一样。

Example#1 用 $_SESSION 注册变量

<?php
session_start
();
// Use $HTTP_SESSION_VARS with PHP 4.0.6 or less
if (!isset($_SESSION['count'])) {
    
$_SESSION['count'] = 0;
} else {
    
$_SESSION['count']++;
}
?>

Example#2 用 $_SESSION 取消注册变量并且禁用了 register_globals

<?php
session_start
();
// Use $HTTP_SESSION_VARS with PHP 4.0.6 or less
unset($_SESSION['count']);
?>

Caution

不要用 unset($_SESSION) 取消了整个 $_SESSION 数组,这样将不能再通过 $_SESSION 超全局数组注册变量了。

Warning

不能在会话变量中用引用,因为没有可行的方法将引用恢复到另一个变量去。

如果启用了 register_globals,则每个全局变量都能被注册为会话变量。在会话重新启动时,这些变量会被恢复到相应的全局变量中去。因为 PHP 必须知道哪些全局变量被注册为会话变量,用户需要用 session_register() 函数来注册变量。可以简单地通过在 $_SESSION 中设定变量来免去这样做。

Caution

在 PHP 4.3 之前,如果使用了 $_SESSION 并且仅用了 register_globals,则不要使用 session_register()session_is_registered()session_unregister()。出于安全及性能原因,建议禁用 register_globals

如果启用了 register_globals,则全局变量和 $_SESSION 中的条目自动指向之前注册的同一个会话实例。不过如果变量是用 $_SESSION 注册的,则全局变量自下一个请求起才可用。

在 PHP 4.2.3 和之前版本中有个缺陷。如果用 session_register() 注册了一个新的会话变量,则在全局变量范围中的条目和 $_SESSION 中的条目在下一个 session_start() 之前没有引用到同一个值。即如果修改一个新注册的全局变量,不会在 $_SESSION 条目中反应出来。这在 PHP 4.3 中已被修正。

传递会话 ID

有两种方法传递一个会话 ID:

  • cookie
  • URL 参数

会话模块支持这两种方法。cookie 更优化,但由于不总是可用,也提供替代的方法。第二种方法直接将会话 ID 嵌入到 URL 中间去。

PHP 可以透明地转换连接。除非是使用 PHP 4.2 或更新版本,需要手工在编译 PHP 时激活。在 Unix 下,用 --enable-trans-sid 配置选项。如果此配置选项和运行时选项 session.use_trans_sid 都被激活,相对 URI 将被自动修改为包含会话 ID。

Note: php.ini 指令 arg_separator.output 允许定制参数分隔符。为完全符合 XHTML,这里用 &amp;。

此外,可以用常量 SID,在会话启动时被定义。如果客户端没有发送适当的会话 cookie 的话,则 SID 的格式为 session_name=session_id,否则就为一个空字符串。因此可以无条件将其嵌入到 URL 中去。

下面例子演示了怎样注册一个变量,以及怎样用 SID 正确连接到另一个页面。

Example#3 对单一用户进行页面点击计数

<?php
if (!session_is_registered('count')) {
    
session_register('count');
    
$count 1;
} else {
    
$count++;
}
?>

<p>
Hello visitor, you have seen this page <?php echo $count?> times.
</p>

<p>
To continue, <a href="nextpage.php?<?php echo strip_tags(SID); ?>">click
here</a>.
</p>

strip_tags() 来输出 SID 以避免 XSS 相关的攻击。

如果编译 PHP 时指定了 --enable-trans-sid,就不需要像上例那样输出 SID 了。

Note: 非相对的 URL 被假定为指向外部站点,因此没有附加 SID,因为这可能是个安全隐患将 SID 泄露给不同的服务器。

定制会话处理器

要实现数据库存储或其它储存方法,需要用 session_set_save_handler() 来创建一组用户级别的存储函数。

Table of Contents



session_cache_expire> <session_pgsql_status
Last updated: Sun, 25 Nov 2007
 
add a note add a note User Contributed Notes
Sessions
hinom - iMasters
05-Jun-2008 12:00
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>
paul at shirron dot net
05-May-2008 10:19
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!!!!
Vextor
05-Apr-2008 12:24
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.
session a emailaddress d cjb d net
29-Mar-2008 03:33
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
Csar
07-Mar-2008 11:38
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
Niko
24-Feb-2008 06:07
to anonymousleaf at gmail dot com:

you can get the same result by using this much simplier function call:

<?php
session_start
();
session_regenerate_id();
?>
at the top of the file.
Anonymous
19-Dec-2007 03:10
Hey people,

   This caused a minimal amount of discomfort, but however was quickly solved when I peeked in the php.ini and saw that the entire 'session.save_path' was commented out!  This must have been from the version change from 5.0 to 5.2, and sessions naturally began to work correctly when I removed the comment token and filled in the value like so (using Apache):

session.save_path = "c:\Windows\Temp"

Maybe this will serve as a starting point and save some time for some of you out there who start from a fresh php.ini.

--Matthew
carl /a/ suchideas /o/ com
01-Oct-2007 12:45
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}
jsnell at e-normous dot com
30-Aug-2007 04:58
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"
Nigel Barlass
28-Jun-2007 09:07
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'])) {...
legolas558 d0t users dot sf dot net
01-May-2007 11:45
To clear out a possible doubt of other readers which have read this part of "Eric dot Deplagne at nerim dot net" note:

--------
In fact, two other variables (at least) play a role in session duration, and will explain that the session might last more than expected. The gc erasing your data is a probabilistic thing. Each time a session is opened, the probability the gc is started is session.gc_probability/session.gc_divisor. session.gc_probability defaults to 1 and session.gc_divisor defaults to 100, which makes a 1% probability.

This is to have sessions long enough. I'm unsure about having sessions lasting exactly the time we want them to.
--------

The gc erasing of the sessions is NOT a probabilistic thing, they are erased ONLY when they are older than the number of seconds specified in "session.gc_maxlifetime" ini setting.

The probabilistic fact is that old sessions will not be erased if the garbage collector is not run frenquently enough, but anyway it is your choice to have a higher or lower "session.gc_probability" on "session.gc_divisor" ratio.

So, talking from the server side point of view, a session can last more than the specified amount of time but not less. And if the client respects the cookies duration (in case of cookie-based sessions) those invalid sessions will not last more than expected.

You finally might want to add a timestamp inside the session and validate its age through it to radically solve the problem, if necessary. Example:

<?php

session_start
();

if (!isset(
$_SESSION['generated']))
   
$_SESSION['generated'] = time();
else {
// if the session is not allowed to live more, regenerate it
   
if (time() - $_SESSION['generated'] > ini_get('session.gc_maxlifetime'))
       
$_SESSION = array('generated' => time());
}
?>
g_s_b
27-Apr-2007 11:37
If you try to use your own session handling functions (eg. for saving session data to DB) make sure session.auto_start directive is 0.

The manual warns about not being able to put objects in your sessions with auto_start=1: I guess that for the same reason your customized handling functions are ignored is sessions start automatically.

Hope this saves somebody a few minutes.
skysama at googles_mail dot com
18-Apr-2007 02:56
If your session are not retrieving correctly make sure that session.cookie_secure is to set to 'Off' if you are NOT going through https. Everytime you navigate the site your session data will not be retrieved and your sessionid will change. It may be obvious but I spent two days trying to figuring this out. Hope it helps someone.
Edemilson Lima <pulstar at gmail dot com>
17-Apr-2007 09:17
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.
Marcin Wiazowski
04-Apr-2007 04:11
'session.cookie_domain' should be set to empty string for all local domain names, not only for 'localhost' (but should not be empty for local IP addresses):

<?php
ini_set
('session.cookie_domain', (strpos($_SERVER['HTTP_HOST'],'.') !== false) ? $_SERVER['HTTP_HOST'] : '');
?>
Marce!
22-Dec-2006 04:20
Be careful when using use_trans_sid and javascript together. When adding a form dynamically with javascript, you usually need to put it in quotes and use addslashes() for your html code.
This will nicely put slashes into the code for your form and the javascript will work perfectly. Or so you would think. PHP does recognise the form, even with the slashes added. So it will neatly insert a hidden variable to your form, with the name of your session variable and the value of the session ID. This hidden variable isn't slashed though, and it may break your javascript code.

The only solution I came up with, is to manually add the hidden variable, before applying the addslashes() function. It will then be shown correctly, and PHP will not insert the hidden value. Of course you may get both a cookie and the variable, depending on your settings, but it does work.
robin at amiance dot com
27-Nov-2006 02:19
If you want the simplest way there is to log a session out after 30 minutes (or any other period of inactivity) simply add a second line after session_start(), like this:

<?php
session_start
();
setcookie("PHPSESSID",$_COOKIE['PHPSESSID'],time()+1800);
?>

Where 1800 is the time in seconds before the session should expire. PHPSESSID is the default session ID. This way, every time a user loads a page they get their session extended.
nhap24
09-Sep-2006 08:03
I spent about 8 hours debugging a problem with sessions and redirecting, and I finally found the problem, which after looking back, should have been the first thing I tried.

I use sessions to prevent hotlinking, so if someone hotlinks my file, I will redirect them to a different page by re-writing the header information.  When I redirected, I sent path information in the GET data about the file they were trying to access.  Long story short, when I redirected with a forward-slash "/" AFTER the .php, the page would create a different session ID than the rest of my domain was using.  This happened despite the fact that the cookie path was set to "/" (which should have captured any path on my domain). 

The issue was even harder to figure out, because the page with the wrong session ID was NOT creating a second cookie.  The only cookie was the one with the proper ID, but the broken page did not use this cookie (where then, did it get this ID from?).

To fix the problem, I simply removed the forward-slash from the GET data (base64_encoding works nicely).

I imagine this is an issue with my browser parsing the url, but I tried both Opera and Firefox (IE doesn't load anymore :/) and both browsers showed the same problem.

I looked into hidden header data, failure to write the cookie, trans_ses_id (even though it was set to false), HTTP_HOST, everything, but in the end it was just a stupid forward-slash that had done me in.
greenthumb at 4point-webdesign dot de
02-Sep-2006 02:56
Similar to the use of captcha images you can easely track and advise user who don't accept cookies, especially no session cookies without redirecting them.

so here's the deal:

if the main script (which outputs the html) doesn't have a value in it's session which says that a session is running successfully a different value is saved in the session and an image is included in the html which checks wether the session-check value is set or not.

If it's set the image-script sets a confirming value which will verify the session to be running correctly and output a transparent 1*1px gif.

If the value is not set the image outputs an advising image which tells to allow cookies.

You can also wrap the image with a link who refers the user  to a page addressing the cookie issue. If the 1px trans is generated the user will hardly find the link, but if the error-image is generated he will surely be able to click it.

pros:
- works
- no rerouting, you can see the result on the first page opened by the user
- no javascript

cons:
- bad accessebility (if you give the image an alt-text any blind user will read it at least on the first call, but you cold also write this into the alt text... so maybe there are no cons)

i hope this'll help
rehevkor5 at fastmail dot fm
26-May-2006 02:34
If you have a value specified for session.referer_check you may run into difficulty when someone accesses your site and attempts to log in with a mis-capitalized URL.  The logon will fail because any calls to session_start() will result in the existing session being trashed and a new one being created.  This becomes a bigger problem when the logon is followed by a header("Location: ...") redirect, because the session_start() at the top of the page will fail.

Because session_start() always returns true, it's not obvious how to detect when the referer check fails.  To detect it, I have come up with a method which compares the intended session id with the session id after session_start() is run.  If they are different, the user is redirected to the proper location.  This example uses a technique to avoid session id fixation, as well.

<?php
ini_set
('session.referer_check', 'www.yourdomain.edu/ltr/');
ini_set('session.use_only_cookies', 1);
session_name('yourapp'.str_replace('.', '', $_SERVER['REMOTE_ADDR']));
session_start();
if(
$_GET['badreferer'])
    echo
'You tried accessing the site with a bad URL. Try logging on again.';
if(
isUserAuthed($name, $pass))
{
   
$old_sessid = session_id(); //save current session id so we can delete it later
   
if( !session_regenerate_id() ) //get a new session id (must do this before destroying the old session)
       
die("Couldn't regenerate your session id.");
               
   
$new_sessid = session_id(); //save new session id so we can get back to it
               
   
session_id($old_sessid);
    unset(
$old_sessid);
   
session_destroy(); //destroy the session they got before they logged in
               
   
session_id($new_sessid);
   
session_start(); //start the new session
               
   
$_SESSION = array(); //not really necessary any more, but still a good idea
               
   
if(session_id() != $new_sessid)
    {
       
/*If this is true, then the session_start() failed to work properly. If session_start() failed to work properly, the most likely cause is that the referer url is different from that set in fuxebox.ini on session.referer_check. The most common cause of this is URL capitalization problems. Therefore, we relocate them to the proper URL, and set a flag to display an error because we can't use pushError() if the session isn't valid. */
                   
       
$good_url = ini_get('session.referer_check');
       
header('Location: http://'.$good_url.'?badreferer=1');
        exit;
    } else {
        unset(
$new_sessid);
       
//Set session variables here
       
$_SESSION['isloggedin'] = 1;
       
        echo
'You have been logged in.';
    }

}
?>
php AT coryforsyth [removeme] d0t com
09-May-2006 10:14
I just finished a marathon debugging session with sessions, and I wanted to share what I learned with the rest of the PHP community because this has been a problem I've battled on several projects before finally solving it today.

I am using sessions to register a user's ID, and every so often, for no apparent reason, the session would seem to expire and my logged-in user would get kicked out.

This is the code I am using to validate a user:
<?php
session_start
();

$auth = false;

if (isset(
$_SESSION['user_id'])) {
  
$user = new User($_SESSION['user_id']);
  
$auth = true;
else {
  
$login = $_REQUEST['login'];
  
$password = $_REQUEST['password'];
  
$login = clean($login);
  
$password = clean($password);
  
// clean() is my own function to escape quotes and so on
  
$user = checkLogin($login,$password);
   if (!
is_null($user)) {
       
$auth = true;
   }
}

if (!
$auth) {
   die(
"you must log in.");
}

// etc etc ... //
?>

I was scratching my head as to why, on about 10% of the times I sent a user to a new page (a PHP page that didn't have any of the sessions stuff--no session_start() and no mention of any session variables), when they came back the session variables were all empty.

I came upon a clue when I used ini_set to change the session.save_path location.  My idea was that maybe the session files in /tmp were being deleted by other users on the system or something.  So I added this line before session_start():
<?php
ini_set
('session.save_path',"/path/to/unique/dir/");
?>
I knew no one else was saving their sessions there, so I started logging in to my page and at the same time checking for the creation of new sess_* files.  I noticed that sometimes, especially when I had problems, a second session file (that was empty) would appear.

What I realized was that the URL was changing from www.coryforsyth.com to coryforsyth.com.  When the presence of the WWW changed, PHP thought it was a different session and created an empty one that caused my script to log me out.  If I went to the location bar of my browser and added/removed the WWW (to the way it had been before), all was well and I was still logged in.

An incredibly thorny problem. I hope this post helps someone else fix it, or even better prevent it.  I changed my hosting preferences to automatically add a WWW to my domain if it wasn't typed that way.

thanks,
Cory Forsyth
brady at volchok dot com
18-Apr-2006 03:15
Session locking (concurrency) notes:

As mentioned several times throughout this section on Sessions, the default PHP session model locks a session until the page has finished loading. So if you have two or three frames that load, and each one uses sessions, they will load one at a time. This is so that only one PHP execution context has write access to the session at any one time.

Some people work around this by calling session_write_close() as soon as they've finished writing any data to the $_SESSION - they can continue to read data even after they've called it. The disadvantage to session_write_close() is that your code still will lock on that first call to session_start() on any session'ed page, and that you have to sprinkle session_write_close() everywhere you use sessions, as soon as you can. This is still a very good method, but if your Session access follows some particular patterns, you may have another way which requires less modification of your code.

The idea is that if your session code <b>mostly</b> reads from sessions, and rarely writes to them, then you can allow concurrent access. To prevent completely corrupted session data, we will lock the session's backing store (tmp files usually) while we write to them. This means the session is only locked for the brief instant that we are writing to the backing store. However, this means that if you have two pages loading simultaneously, and both modify the session, the <i>Last One Wins</i>. Whichever one loads first will get its data overwritten by the one that loads second. If this is okay with you, you may continue - otherwise, use the session_write_close method, above.

If you have complicated bits of code that depend on some state in the session, and some state in a database or text file, or something else - again, you may not want to use this method. When you have two simultaneous pages running, you might find that one page runs halfway through, modifying your text file, then the second one runs all the way through, further modifying your text file, then the first one finishes - and your data might be mangled, or completely lost.

So if you're prepared to debug potentially very, very nasty race conditions, and your access patterns for your sessions is read-mostly and write-rarely (and not write-dearly), then you can try the following system.

Copy the example from session_set_save_handler() into your include file, above where you start your sessions. Modify the session write() method:

<?php
function write($id, $sess_data)
{
  global
$sess_save_path, $sess_session_name;

 
$sess_file = "$sess_save_path/sess_$id";
  if (
$fp = @fopen($sess_file, "w")) {
  
flock($fp,LOCK_EX);
  
$results=fwrite($fp, $sess_data);
  
flock($fp,LOCK_UN);
   return(
$results);
  } else {
   return(
false);
  }

}
?>

You will probably also want to add a GC (Garbage Collection) method for the sessions, as well.

And of course, take this advice with a grain of salt - We currently have it running on our testing server, and it seems to work OK there, but people have reported terrible problems with the Shared Memory session handler, and this method may be as unsafe as that.

You can also consider implementing your own locks for scary concurrency-sensitive bits of your code.
Cosmo
01-Apr-2006 08:47
Fairly new to PHP, I've been looking to alter session timeouts on a shared host where I don't have direct access to configure php.ini.  There doesn't appear to be any easy way to find out how to do this in this manual (nor from a quick web search).

The code below seems to work OK to set session timeout.     a timeout of 30 secs is used for convenient testing.  gc settings must come before session_start().

The garbage collection is made 100% by setting probability and divisor to the same value - if I have correctly understood what these functions do.
 
(on the first pass of the file, there is no session file - that's established only when the script ends for the first time.  Keep reloading to test).

Comments welcome.

<?php
  ini_set
('session.gc_maxlifetime',30);
 
ini_set('session.gc_probability',1);
 
ini_set('session.gc_divisor',1);
   
session_start();
   
// check to see what's happening
$filepath = ini_get('session.save_path').'/sess_'.session_id();
   
if(
file_exists($filepath))
{
   
$filetime = filemtime ($filepath);
   
$timediff = mktime() - $filetime;
    echo
'session established '.$timediff.' seconds ago<br><br>';
}
?>
crown2gain at yahoo dot com
02-Mar-2006 02:19
I just spent a lot of time trying to figure out why my session variables were not available after I seemed to have set them(could echo after setting).  I use the same script for several different functions, so the user may reload the page for other purposes.  Someone else posted the use of session_write_close();  before a Location redirect.  This also worked in put this after I set the session variables the variables are available when the page reloads for another function.

<?php
$_SESSION
['guid'] = $guid;
$_SESSION['userdata'] = $response;
session_write_close();
?>
a l bell at hutchison dot com dot au
01-Mar-2006 07:17
Please Note;

Internet explorer users beware.

When using session_start() to begin a session this session will remain open until the page has finished loading or it is explicitly terminated.

You can lose the session however if the the page contains a reference to <img src=""> with name and id references (which may be used if the image is referencing a dynamic image, called by javascript)  This seems to casue IE6 to refresh the page session id and hence loose the session.

This took hours for me to diagnose when users were getting unexpectedly logged out of my site due to this "" in the img src.
kintar at infinities-within dot net
01-Mar-2006 01:10
Important note that it just took me the better part of two hours to figure out:  Even if you're using session_write_close(), calling exit after a redirect will eat your session variables.  I had the following:

Source of register.php:
<?PHP

// Some files included here

// Process our posted form data
$result = processPost();

if (
$result)
{
 
redirect('success.php');
}
else
{
 
redirect('failure.php');
}

exit;
?>

processPost() was setting a couple of session variables, including an error message, but neither results page was seeing those variables.  I removed the exit call from the register page, and all works fine.

/bonks self
hans at nieser dot net
14-Feb-2006 11:15
FreeBSD users, instead of modifying the PHP5 port Makefile, you can either install the session extension using the www/php5-session port, or you can install several extensions at once (you can pick them from a menu) using the lang/php5-extensions port. Same goes for PHP4
just_somedood at yahoo dot com
02-Feb-2006 01:31
If you're running FreeBSD, and installed php5 (have not checked 4) from the ports, and are getting errors saying the session functions are undefined, try running phpinfo().  You'll probably see that the '--disable-all' configure command was used.  To fix, edit the /usr/ports/lang/php5/Makefile, and remove the '--disable-all' line.  In that directory, run a 'make deinstall', if you installed already.  Next, run 'make install' while still in that same directory.  It should work fine after that.
jerry dot walsh at gmail dot com
24-Jan-2006 10:56
If you're using sharedance to distributed php sessions across a group of machines beware of the following:

On a freebsd 6.x system I have observed a huge performance hit caused by dns/host file lookups.

To ensure maximum performance using sharedance you should set the 'SESSION_HANDLER_HOST' constant to an IP rather than a hostname.

When i did this my requests per second jumped from 55 to 389 requests per second!
jazfresh at hotmail dot com
20-Dec-2005 10:55
The vanilla implementation of session will blindly spew back the value of the session_id that the user sends it after URL decoding it. This can be used as an attack vector, by including strings like "%0D%0ALocation:%20http://someothersite.com/%0D%0A" in the cookie. Never trust user input, always cleanse it. If you only expect alphanumerics in the session hash, reject any session_id that doesn't contain it.

<?php
if(!preg_match('#^[[:alnum:]]+$#', $_COOKIE['session_id'])) {
  unset(
$_COOKIE['session_id']);
}
session_start();
?>
Bram
20-Nov-2005 12:39
[editors note]
It should be noted that it's highly recommended to store sessions for each virtual host in seperate directories or in a database.
[/editors note]

I just noticed that it's possible to access the same session through multiple apache virtual hosts.
So keep this in mind when using sessions for anything sensitive, and make sure to encrypt the data (using the mcrypt functions for example, when available).
Lachlan Hunt
10-Nov-2005 10:10
> Note:  The arg_separator.output  php.ini directive allows to customize the argument seperator. For full XHTML conformance, specify &amp; there.

Exactly the same rule applies to HTML as well, there is abolutely no reason why this should not be set to &amp; by default.  The only difference is that in XHTML, XML error handling defines that it's a well formedness error.  For HTML, error handling was not so well defined nor sanely implemented and tag soup parsers just accept it, but that doesn't make it right.

arg_separator.output *MUST* be set to either of these if you're outputting either HTML or XML:

arg_separator.output = "&amp;"
arg_separator.output = ";"

http://www.w3.org/QA/2005/04/php-session
christopher dot klein at ecw dot de
24-Oct-2005 02:26
If you have trouble with Internet Explorer 6 and non-working sessions (all session-data is lost after clicking on a link), please look user-hints for setcookie().
You have to add the following line after session_start() to get sessions working:

<?php
 
// Initalize session
 
session_start();
 
// Send modified header
 
header('P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"');
?>
akoma at t3 dot rim dot or dot jp
19-Sep-2005 06:50
If your are using UTF-8, make sure your source
code editor to do not put the BOM mark
(unicode sign) at the top of your source code. so
it is sent before session_start() causing "headers
already sent" message on httpd error log.
fasteddie at byu dot edu not_this_part
17-Aug-2005 11:43
I hope this helps someone:
---PHP SESSIONS NOT WORKING---
My sessions wouldnt ever load from disk. The sessions would start just fine, and a session file would be created and written to disk. (BTW, I'm on a win XP box, Apache 2.0.54, PHP version 5.0.4.) However, next time I loaded the page, the old session would not be used. Instead, a NEW session was created. For me, this happened no matter what computer I was using, whether it was the server (localhost) or a client (remote). A new session was created EVERY TIME I loaded the page.. it was annoying. After a few hours of googling, I gave up and decided to mess around in the php.ini file. I changed this line:
session.cookie_path = /
to this:
session.cookie_path =

Now, php sessions are loaded properly.

I havent tried many things but I think maybe it is because windows needs backslashes (\) instead of forward slashes (/), and if you just leave it blank, it turns out ok.
artistan at cableone dot net
09-Aug-2005 01:29
I rewrote adodb's session management class to work across servers with database managed sessions.  Take a look at http://phplens.com/lens/lensforum/msgs.php?id=13428
Christian Boltz <php-manual at cboltz dot de>
28-Jul-2005 07:33
Another note about session.bug_compat_42 and bug_compat_warn.

[full error message:
    "Your script possibly relies on a session side-effect which existed
    until PHP 4.2.3. Please be advised that the session extension does
    not consider global variables as a source of data, unless
    register_globals is enabled. You can disable this functionality and
    this warning by setting session.bug_compat_42 or
    session.bug_compat_warn to off, respectively."
]

The following short script causes the bug_compat_42 warning to appear.

<?php
  session_start
();
 
$_SESSION['var'] = NULL;
 
$var = "foo";
?>

It took me an hour to find out this :-(  - so I post it here to avoid
that more people need such a long time.

Conclusion and test results:

You'll get this warning if $_SESSION['var'] contains NULL and you assign
anything (except NULL) to the global variable $var.

The warning will _not_ appear:
- if $_SESSION['var'] contains anything else   - or -
- if you don't use a global variable named $var
d43m0n at shaw dot ca
19-Jul-2005 04:19
Hello,

I posted earlyer about a issue/bug with Windows servers handling sessions. If you did not read it, it was based on the fact that if you can use ini_set to re-define the session.save_path to a relitive location. PHP will instead use it as the exact