最近,我的日志中出现了以下错误:
PHP Warning: session_start(): The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,' in [...] on line [..]
PHP Warning: Unknown: The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,' in Unknown on line 0
PHP Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/lib/php5) in Unknown on line 0
前面这个问题的答案足以让检测和转移这样的场景,这样就不会产生错误,但是我对最优雅的恢复感兴趣;也就是说,以一个有效的新(空)会话结束。
首先,对检测&上一个问题中的导流代码,现在已经是六年前的了:
这些天,会话更有可能通过cookie单独处理。
session.use_only_cookies
标志在我的php.ini是启用的,因为我不记得改变它,我认为这是默认值。在有效的会话id中使用哪些字符,以及这些字符的数量取决于php.ini中的
session.hash_function
和session.hash_bits_per_character
值。我的值分别是0和5,这(除非我搞错了)意味着我自己的会话id应该匹配正则表达式/^[a-v0-9]{26}$/
。用于存储会话的cookie的名称可以在php.ini中使用
session.name
自定义。正确的值总是可以通过session_name()
函数检索到的。
考虑到这些,最优雅的转移方法(可能)是:
function my_session_start() {
if (!isset($_COOKIE[session_name()]) || preg_match('/^[a-v0-9]{26}$/', $_COOKIE[session_name()]) !== 0) {
return session_start(); // since 5.3, returns TRUE on success, FALSE on failure.
}
else {
return false;
}
}
至于恢复(它将取代else
块中的return false;
),对上一个问题的一个回答建议如下:
session_id(uniqid());
session_start();
session_regenerate_id();
然而,我担心的是,这意味着恢复,只有两个赞成,没有评论,是不够的审查。
这个问题的答案表明内部session_start()
函数直接依赖于 $_COOKIE[session_name()]
的值,而不是该值的其他内部表示。是这样吗?如果是这样,具有检测和恢复功能的my_session_start()
函数可以像以下这样简单:
function my_session_start() {
if (isset($_COOKIE[session_name()]) && preg_match('/^[a-v0-9]{26}$/', $_COOKIE[session_name()]) === 0) {
unset($_COOKIE[session_name()]);
}
return session_start();
}
我只看到这种情况发生在$_COOKIE['PHPSESSID'] === ''
。当有人使用Firebug"清除cookie"时,就会发生这种情况。我只想处理这种特殊情况;如果会话ID以其他方式无效,我希望得到警告。处理我的特定用例很简单:
$session_name = session_name();
if (isset($_COOKIE[$session_name]) and empty($_COOKIE[$session_name])) {
// This happens when someone does "clear cookie" in Firebug; it causes session_start()
// to trigger a warning. session_start() relies on $_COOKIE[$session_name], thus:
unset($_COOKIE[$session_name]);
}
session_start();
出于好奇,除了它是一个空字符串之外,你真的需要处理任何场景吗?如果是恶意的(为了触发警告),它只能是其他东西,但是由于您在生产中禁用了display_errors
,因此没有人可以从中获得任何信息。