If any one is interested, there is a page in the PHP Wikibook about user login systems and sessions:
http://en.wikibooks.org/wiki/PHP_Programming/User_login_systems
Session 会话处理函数
简介
PHP 中的会话支持由一种将特定数据保留用于之后的请求的方法组成。这样可以使用户建立更灵活的应用并提高网站的吸引力。
访问网站的来客会被分配一个唯一的标识符,即所谓的会话 ID。它要么存放在客户端的 cookie,要么经由 URL 传递。
会话支持允许用户注册任意数目的变量并保留给各个请求使用。当来客访问网站时,PHP 会自动(如果 session.auto_start 被设为 1)或在用户请求时(由 session_start() 明确调用或 session_register() 暗中调用)检查请求中是否发送了特定的会话 ID。如果是,则之前保存的环境就被重建。
如果确实启用了 session.auto_start,则不能将对象放入会话中,因为类定义必须在启动会话之前加载以在会话中重建对象。
请求结束后所有注册的变量都会被序列化。已注册但未定义的变量被标记为未定义。在之后的访问中这些变量也未被会话模块定义,除非用户以后定义它们。
有些类型的数据不能被序列化因此也就不能保存在会话中。包括 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 文件中设定。这里只是个简短的概览。
- 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_probability 与 session.gc_divisor 合起来用来管理 gc(garbage collection 垃圾回收)进程启动的概率。默认为 1。详见 session.gc_divisor。
- session.gc_divisor integer
- session.gc_divisor 与 session.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 指定是否在客户端用 cookie 来存放会话 ID。默认为 1(启用)。
- session.use_only_cookies 指定是否在客户端仅仅使用 cookie 来存放会话 ID。。启用此设定可以防止有关通过 URL 传递会话 ID 的攻击。此设定是 PHP 4.3.0 添加的。
- session.cookie_lifetime 以秒数指定了发送到浏览器的 cookie 的生命周期。值为 0 表示“直到关闭浏览器”。默认为 0。参见 session_get_cookie_params() 和 session_set_cookie_params()。
- session.cookie_path 指定了要设定会话 cookie 的路径。默认为 /。参见 session_get_cookie_params() 和 session_set_cookie_params()。
- session.cookie_domain 指定了要设定会话 cookie 的域名。默认为无,表示根据 cookie 规范产生 cookie 的主机名。参见 session_get_cookie_params() 和 session_set_cookie_params()。
- 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_42 和 session.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 指定在使用透明 SID 支持时哪些 HTML
标记会被修改以加入会话 ID。默认为
a=href,area=href,frame=src,input=src,form=fakeentry,fieldset=。
Note: 如果要符合 XHTML,去掉 form 项并在表单字段前后加上 <fieldset> 标记。
track_vars 和 register_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']);
?>
不要用 unset($_SESSION) 取消了整个 $_SESSION 数组,这样将不能再通过 $_SESSION 超全局数组注册变量了。
不能在会话变量中用引用,因为没有可行的方法将引用恢复到另一个变量去。
如果启用了 register_globals,则每个全局变量都能被注册为会话变量。在会话重新启动时,这些变量会被恢复到相应的全局变量中去。因为 PHP 必须知道哪些全局变量被注册为会话变量,用户需要用 session_register() 函数来注册变量。可以简单地通过在 $_SESSION 中设定变量来免去这样做。
在 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,这里用 &。
此外,可以用常量 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 — Return current cache expire
- session_cache_limiter — Get and/or set the current cache limiter
- session_commit — session_write_close 的别名
- session_decode — Decodes session data from a string
- session_destroy — Destroys all data registered to a session
- session_encode — 将当前会话数据编码为一个字符串
- session_get_cookie_params — Get the session cookie parameters
- session_id — Get and/or set the current session id
- session_is_registered — Find out whether a global variable is registered in a session
- session_module_name — Get and/or set the current session module
- session_name — Get and/or set the current session name
- session_regenerate_id — Update the current session id with a newly generated one
- session_register — Register one or more global variables with the current session
- session_save_path — Get and/or set the current session save path
- session_set_cookie_params — Set the session cookie parameters
- session_set_save_handler — Sets user-level session storage functions
- session_start — Initialize session data
- session_unregister — Unregister a global variable from the current session
- session_unset — Free all session variables
- session_write_close — Write session data and end session
Sessions
24-Jun-2009 09:49
08-May-2009 03:18
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.
07-May-2009 08:14
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.
03-Dec-2008 06:51
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.site1.com is stored in /home/site1/www
www.site2.com is stored in /home/site2/www
Using both www.site1.com and www.site2.com 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.site1.com
suPHP_ConfigPath /home/site1/server_config
</VirtualHost>
<VirtualHost 10.10.10.10:8082>
DocumentRoot /home/site2/www
ServerName www.site2.com
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 !
16-Nov-2008 03:03
So after like six hours of debugging I found that echoing the word “dick” some how kills a session. Like story short was testing retrieval from a data base and had used Tom, Dick and Harry as test names. I have found that dick kill my session even if use in just a echo statement ex( echo “dick”;) has anyone else ran into this and if so is there a way around it.
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>
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!!!!
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.
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
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
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.
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
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}
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"
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'])) {...
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());
}
?>
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.
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.
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.
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'] : '');
?>
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.
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.
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.
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
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.';
}
}
?>
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
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.
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>';
}
?>
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();
?>
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.
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
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
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.
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!
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();
?>
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).
10-Nov-2005 10:10
> Note: The arg_separator.output php.ini directive allows to customize the argument seperator. For full XHTML conformance, specify & there.
Exactly the same rule applies to HTML as well, there is abolutely no reason why this should not be set to & 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 = "&"
arg_separator.output = ";"
http://www.w3.org/QA/2005/04/php-session
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"');
?>
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.
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.
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
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
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 location with out looking at the directory where your script is bein execute, thus to say, the session file is not created, or re-read. This of course only occurs if you use <?php reregister_id() ?>. This function is told to open the requested session file, obtain the varibles, regenerate an id for that session, create the new session file and then send the cookie header to the client, of course I did not create this function, so it may not be in that order.
The following code will generate the error that I speak of, and will not successfully generate the new session id, of course like I said above, this only accours on PHP 5 & 5.0.4 under the Windows Environment.
<?php
define("_PATH_TMP", "./tmp");
ini_set('session.save_path', _PATH_TMP);
session_start();
$_SESSION['sid']['obsolete'] = session_id();
session_regenerate_id();
$_SESSION['sid']['replaced'] = session_id();
print_r($_SESSION);
?>
(I know that PHP may use defined constants that include '_' characters at the beggining, if it has not already, but I am taking that chance atm...)
This can simply be resolved by using the following code:
<?php
define("_PATH_TMP", dirname($_SERVER['SCRIPT_FILENAME']) . "/tmp");
ini_set('session.save_path', _PATH_TMP);
session_start();
$_SESSION['sid']['obsolete'] = session_id();
session_regenerate_id();
$_SESSION['sid']['replaced'] = session_id();
print_r($_SESSION);
?>
As you can see it uses the uses the servers environment to assurtain the exact location to the script, then locates the next root directory of it, and then allows you to define the tmp directory.
* Of course, you dont need to use a tmp directory, and this issue only occurse when using subdirectorys, I found that the following works just aswell, but this did not fit my needs!
<?php
define("_PATH_TMP", "./");
ini_set('session.save_path', _PATH_TMP);
session_start();
$_SESSION['sid']['obsolete'] = session_id();
session_regenerate_id();
$_SESSION['sid']['replaced'] = session_id();
print_r($_SESSION);
?>
16-Jun-2005 07:52
Session data is not available to an object's __destruct method as sessions are closed before the object is 'destroyed'.
14-Jun-2005 10:44
Having to use transparent on a system where trans_sid was not compiled, I came up with the folowing ob_start handler:
<?php
function ob_sid_rewrite($buffer){
$replacements = array(
'/<\s*(a|link|script)\s[^>]*(href|src)\s*=\s*"([^"]*)"/',
'/<\s*(a|link|script)\s[^>]*(href|src)\s*=\s*\'([^\'<>]*)\'/',
);
$buffer = preg_replace_callback($replacements, "pa_sid_rewriter", $buffer);
$buffer = preg_replace('/<form\s[^>]*>/',
'\0<input type="hidden" name="' . session_name() . '" value="' . session_id() . '"/>', $buffer);
return $buffer;
}
function pa_sid_rewriter($matches){
$buf = $matches[0];
$url = $matches[3];
$url_orig=$url;
if ($url[0]=='/' || $url[0]=='#' || preg_match('/^[A-Za-z0-9]*:/', $url))
return $buf;
$ses_name = session_name();
if (strstr($url, "$session_name="))
return $buf;
$p = strpos($url, "#");
$ref = false;
if($p){
$ref = substr($url, $p);
$url = substr($url, 0, $p);
}
if (strlen($url)==0)
return $buf;
if (!strstr($url, "?"))
$url.="?";
else
$url.="&";
$url.=session_name() ."=".session_id();
if($ref)
$url.=$ret;
return str_replace($url_orig, $url, $buf);
}
?>
It adds a field to urls and a fake form entry.
You can start the rewrite by doing the folowing at the start of the script:
<?php
function pa_set_trans_sid(){
if ( defined('SID') ){ // use trans sid as its available
ini_set("session.use_cookies", "0");
ini_set("session.use_trans_sid", "true");
ini_set("url_rewriter.tags", "a=href,area=href,script=src,link=href,"
. "frame=src,input=src,form=fakeentry");
}else{
ob_start('ob_sid_rewrite');
}
}
?>
04-Jan-2005 12:09
You can't turn off session.use_trans_sid on an individual script basis until PHP5.
However, if you use ini_set('url_rewriter.tags', ''); at the top of your script this will stop the SID being written to the URL's in PHP4.
Hopefully will save someone else a frustrating couple of hours.
Trev
23-Nov-2004 01:04
If you are trying to share sessions across a cluster of servers, and don't want to use NFS, or a relatively heavy and slow RDBMS, there is an excellent tool called ShareDance that can do it over a simple TCP protocol. ShareDance comes complete with a PHP interface example and works 'out of the box' for me.
http://sharedance.pureftpd.org/
My thanks to Frank Denis for writing this elegant, valuable piece of software.
03-Sep-2004 02:06
Be careful when using the Content-Length header with session.use_trans_sid enabled. Technically, it might not be a bug, but PHP does not update the header when it adds the session ID to links in a page. The result is that only partial content is shown in a browser.
In short: if you use ob_get_length to figure out Content-Length, turn session.use_trans_sid off!
06-Jun-2004 07:10
sessions not sticking and cookies not setting with IE? took me ages to find the problem.
you need a 'compact privacy policy'! it's not hard once you know how!
this was too much for me: http://www.w3.org/TR/P3P/
but http://www.sitepoint.com/article/p3p-cookies-ie6/2 is very easy to apply
and a visit to this site is very worthwhile: http://www.privacycouncil.com/freep3pfix.php
happy PHP to all!
Erich
05-May-2004 03:28
I found a good solution to create a persistent session by storing a persistence flag, ironically, in the session itelf. I start the session (which sends a Set-Cookie with no expiry time), read the flag and then, if the user wants a persistent session, stop and restart the session with the expiry time set using session_set_cookie_params, which then sends a cookie with a good expiry time. This solution has been quickly tested with all major browsers and seems to work.
I have outlined the whole process in my blog: http://aftnn.org/journal/508
20-Nov-2003 04:05
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 ;)
16-Oct-2000 08:16
Regarding session.cache_limiter :
For those of you who - like me - had trouble finding the meaning of the possible values (nocache, public and private), here's the explaination taken from the HTTP 1.1 Specification at
http://www.w3.org/Protocols/rfc2068/rfc2068
"14.9.1 What is Cachable
[snip]
public
Indicates that the response is cachable by any cache, even if it would normally be non-cachable or cachable only within a non-shared cache. (See also Authorization, section 14.8, for additional details.)
private
Indicates that all or part of the response message is intended for a single user and MUST NOT be cached by a shared cache. This allows an origin server to state that the specified parts of the response are intended for only one user and are not a valid response for requests by other users. A private (non-shared) cache may cache the response.
Note: This usage of the word private only controls where the response may be cached, and cannot ensure the privacy of the message content.
no-cache
Indicates that all or part of the response message MUST NOT be cached anywhere. This allows an origin server to prevent caching even by caches that have been configured to return stale responses to client requests.
Note: Most HTTP/1.0 caches will not recognize or obey this directive."
20-Aug-2000 10:11
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).
