session_start

(PHP 4, PHP 5, PHP 7, PHP 8)

session_start启动新的会话或恢复现有会话

描述

session_start(array $options = []): bool

session_start() 基于通过 GET 或 POST 请求传递的会话标识符,或通过 Cookie 传递的会话标识符,创建会话或恢复当前会话。

当调用 session_start() 或会话自动启动时,PHP 将调用打开和读取会话保存处理程序。这些处理程序可以是默认情况下提供的内置保存处理程序,也可以是 PHP 扩展提供的处理程序(如 SQLite 或 Memcached);或者可以是通过 session_set_save_handler() 定义的自定义处理程序。读取回调将检索任何现有的会话数据(以特殊的序列化格式存储),并被反序列化,并在读取回调将保存的会话数据返回给 PHP 会话处理时自动填充 $_SESSION 超级全局变量。

要使用命名会话,请在调用 session_start() 之前调用 session_name()

session.use_trans_sid 启用时,session_start() 函数将为 URL 重写注册一个内部输出处理程序。

如果用户使用 ob_gzhandler 或类似的函数与 ob_start() 一起使用,则函数顺序对于正确的输出很重要。例如,ob_gzhandler 必须在启动会话之前注册。

参数

options

如果提供,这是一个关联数组,其中包含的选项将覆盖当前设置的 会话配置指令。键不应包含 session. 前缀。

除了正常的配置指令集之外,还可以提供 read_and_close 选项。如果设置为 true,这将导致会话在读取后立即关闭,从而避免在会话数据不会更改的情况下进行不必要的锁定。

返回值

如果成功启动会话,此函数返回 true,否则返回 false

变更日志

版本 描述
7.1.0 session_start() 现在返回 false,并且在启动会话失败时不再初始化 $_SESSION

示例

一个基本的会话示例

示例 #1 page1.php

<?php
// page1.php

session_start();

echo
'欢迎来到页面 #1';

$_SESSION['favcolor'] = '绿色';
$_SESSION['animal'] = '猫';
$_SESSION['time'] = time();

// 如果接受了会话 Cookie,则有效
echo '<br /><a href="page2.php">页面 2</a>';

// 或者,如果需要,可以传递会话 ID
echo '<br /><a href="page2.php?' . SID . '">页面 2</a>';
?>

在查看 page1.php 之后,第二个页面 page2.php 将神奇地包含会话数据。阅读 会话参考,以获取有关 传播会话 ID 的信息,例如,它解释了常量 SID 是什么意思。

示例 #2 page2.php

<?php
// page2.php

session_start();

echo
'欢迎来到页面 #2<br />';

echo
$_SESSION['favcolor']; // 绿色
echo $_SESSION['animal']; // 猫
echo date('Y m d H:i:s', $_SESSION['time']);

// 您可能想在这里使用 SID,就像我们在 page1.php 中所做的那样
echo '<br /><a href="page1.php">页面 1</a>';
?>

session_start() 提供选项

示例 #3 覆盖 Cookie 的生命周期

<?php
// 这会发送一个持续一整天的持久 Cookie。
session_start([
'cookie_lifetime' => 86400,
]);
?>

示例 #4 读取会话并关闭它

<?php
// 如果我们知道我们不需要更改会话中的任何内容,
// 我们可以直接读取并关闭,以避免
// 锁定会话文件并阻塞其他页面
session_start([
'cookie_lifetime' => 86400,
'read_and_close' => true,
]);

注释

注意:

要使用基于 Cookie 的会话,必须在向浏览器输出任何内容之前调用 session_start()

注意:

建议使用 zlib.output_compression 而不是 ob_gzhandler()

注意:

此函数根据配置发送多个 HTTP 标头。请参阅 session_cache_limiter() 以自定义这些标头。

另请参阅

添加注释

用户贡献的注释 41 个注释

33
linblow at hotmail dot fr
13 年前
如果您想用类来处理会话,我写了这个小程序

<?php

/*
使用静态方法 getInstance 获取对象。
*/

class Session
{
const
SESSION_STARTED = TRUE;
const
SESSION_NOT_STARTED = FALSE;

// 会话状态
private $sessionState = self::SESSION_NOT_STARTED;

// 类唯一的实例
private static $instance;


private function
__construct() {}


/**
* 返回 'Session' 的唯一实例。
* 如果会话未初始化,则会自动初始化。
*
* @return object
**/

public static function getInstance()
{
if ( !isset(
self::$instance))
{
self::$instance = new self;
}

self::$instance->startSession();

return
self::$instance;
}


/**
* (重新)启动会话。
*
* @return bool 如果会话已初始化,则返回 TRUE,否则返回 FALSE。
**/

public function startSession()
{
if (
$this->sessionState == self::SESSION_NOT_STARTED )
{
$this->sessionState = session_start();
}

return
$this->sessionState;
}


/**
* 将数据存储在会话中。
* 示例:$instance->foo = 'bar';
*
* @param name 数据的名称。
* @param value 您的数据。
* @return void
**/

public function __set( $name , $value )
{
$_SESSION[$name] = $value;
}


/**
* 从会话中获取数据。
* 示例:echo $instance->foo;
*
* @param name 要获取的数据的名称。
* @return mixed 存储在会话中的数据。
**/

public function __get( $name )
{
if ( isset(
$_SESSION[$name]))
{
return
$_SESSION[$name];
}
}


public function
__isset( $name )
{
return isset(
$_SESSION[$name]);
}


public function
__unset( $name )
{
unset(
$_SESSION[$name] );
}


/**
* 销毁当前会话。
*
* @return bool 如果会话已删除,则返回 TRUE,否则返回 FALSE。
**/

public function destroy()
{
if (
$this->sessionState == self::SESSION_STARTED )
{
$this->sessionState = !session_destroy();
unset(
$_SESSION );

return !
$this->sessionState;
}

return
FALSE;
}
}

/*
示例:
*/

// 获取实例
$data = Session::getInstance();

// 将数据存储在会话中
$data->nickname = 'Someone';
$data->age = 18;

// 显示数据
printf( '<p>My name is %s and I\'m %d years old.</p>' , $data->nickname , $data->age );

/*
它将显示:

Array
(
[nickname] => Someone
[age] => 18
)
*/

printf( '<pre>%s</pre>' , print_r( $_SESSION , TRUE ));

// TRUE
var_dump( isset( $data->nickname ));

// 销毁会话
$data->destroy();

// FALSE
var_dump( isset( $data->nickname ));

?>

我更喜欢使用这个类而不是直接使用数组 $_SESSION。
16
ohcc at 163 dot com
10 years ago
如果 php ini 文件中的指令 session.use_trans_sid 设置为 0,常量 SID 将始终为 ''(空字符串)。

因此,请记住在 php 脚本中使用 SID 之前,将 session.use_trans_sid 设置为 1 并重新启动服务器。
20
aaronw at catalyst dot net dot nz
9 years ago
正如其他人所指出的,PHP 的会话处理程序是阻塞的。当你的一个脚本调用 session_start() 时,任何其他也使用相同会话 ID 调用 session_start() 的脚本都将休眠,直到第一个脚本关闭会话。

一个常见的解决方法是每次你想更新会话时都调用 session_start() 和 session_write_close()。

这样做的缺点是,每次你调用 session_start() 时,PHP 都会将会话 cookie 的副本打印到 HTTP 响应头中。如果多次这样做(可能在长时间运行的脚本中),响应头可能会变得太大,导致 Web 服务器和浏览器崩溃或拒绝你的响应,因为它格式错误。

此错误已报告给 PHP 总部,但他们将其标记为“不会修复”,因为他们说你不应该像这样在一个脚本中打开和关闭会话。 https://bugs.php.net/bug.php?id=31455

作为解决方法,我编写了一个函数,它使用 headers_list() 和 header_remove() 来清除重复的 cookie。有趣的是,即使在 PHP 发送重复的会话 cookie 的请求中,headers_list() 也只列出一个会话 cookie 的副本。尽管如此,调用 header_remove() 会删除所有重复的副本。

<?php
/**
* 每次你调用 session_start() 时,PHP 都会在响应头中添加另一个
* 相同的会话 cookie。如果多次这样做,
* 你的响应头可能会变得太大而导致 Web 服务器窒息。
*
* 此方法清除重复的会话 cookie。你可以
* 在每次调用 session_start() 之后调用它,或者在
* 发送你的头之前调用它。
*/
function clear_duplicate_cookies() {
// 如果头已发送,我们无能为力
if (headers_sent()) {
return;
}

$cookies = array();
foreach (
headers_list() as $header) {
// 识别 cookie 头
if (strpos($header, 'Set-Cookie:') === 0) {
$cookies[] = $header;
}
}
// 删除所有 cookie 头,包括重复的
header_remove('Set-Cookie');

// 恢复每个 cookie 的一个副本
foreach(array_unique($cookies) as $cookie) {
header($cookie, false);
}
}
?>
10
marco dot agnoli at me dot com
7 years ago
我最近有一个有趣的观察

似乎 `session_start()` 即使会话没有正确创建,也可以返回 `true`。在我的情况下,磁盘存储已满,因此无法将会话数据写入磁盘。我有一些逻辑导致在会话未写入磁盘时出现无限循环。

为了检查会话是否真的已保存到磁盘,我使用了

```
<?php

function safe_session_start() {
# 尝试启动会话
if (!@\session_start()) return false;

#
# 检查是否需要执行
# 写入测试。
#
if (!isset($_SESSION['__validated'])) {
$_SESSION['__validated'] = 1;

# 尝试将会话写入磁盘
@\session_write_close();

# 从内存中取消设置变量。
# 此步骤可能是不必要的
unset($_SESSION['__validated']);

# 重新启动会话
@\session_start();

# 检查变量值是否保留
if (!isset($_SESSION['__validated'])) {
# 会话未写入磁盘
return false;
}
}

return
true;
}

if (!
safe_session_start()) {
# 会话可能没有写入磁盘...
# 按照相应方式处理错误。
}

?>
```

我花了好一阵子才弄明白这一点。

也许它对某人有帮助!
1
bwz
1 年前
请注意阻止会话的另一个问题:如果您要调用需要使用同一会话访问您网站的外部程序(或使用外部服务)。

例如,我将页面打印为 PDF。我可以直接将网页另存为 HTML 文件。但 HTML 中的图像也是私有的,需要当前用户会话才能查看。

发生的情况是,此程序可能会无限期挂起(或超时),因为 session_start 等待父 PHP 进程释放锁。并且 session_start 不服从 max_execution_time(如该错误中所述:https://bugs.php.net/bug.php?id=72345),因此这将有效地杀死服务器,因为每个请求都会永远挂起。

如果您使用外部 HTTP 服务,情况也是如此。

<?php
$pdf
= file_get_contents('http://pdf.website.tld/?url=http://website.tld/print.php');
?>

该服务将等待网站主机释放锁,但它无法释放,因为它正在等待 PDF 服务完成…

一个不错的解决方案是在 session_start 后立即调用 session_write_close 来释放锁,当您需要写入会话时,执行相同的操作,但如上所述,它有自己的问题。使用自定义会话处理程序可能是最好的解决方案。
11
bachtel at [googles email service]dotcom
7 years ago
如果您通过 session_set_save_handler() 使用自定义会话处理程序,那么在 PHP 7.1 中调用 session_start() 时,您可能会看到类似这样的错误。
session_start(): 无法读取会话数据:用户(路径:/var/lib/php/session)在…

截至撰写本文时,这似乎发生在 PHP 7.1 中,而在 PHP7.0 中看起来一切正常。

也很难追踪,因为如果此 ID 的会话已存在(可能由早期版本的 PHP 创建),它就不会触发此问题,因为 $session_data 不会为 null。

修复很简单... 您只需要在读取函数期间检查“null”

<?php

function read($id)
{
//... 从数据库、磁盘、memcache 等中提取数据
$session_data = getSessionDataFromSomewhere($id);

// 检查 $session_data 是否为 null,然后再返回(关键)
if(is_null($session_data))
{
$session_data = ''; // 使用空字符串而不是 null!
}

return
$session_data;
}

?>
9
emre@yazici
15 年前
PHP 手册专门指出了这种常见的错误。

根据会话处理程序的不同,并非所有字符都可以在会话 ID 中使用。例如,文件会话处理程序仅允许使用 a-z A-Z 0-9、(逗号)和 -(减号)范围内的字符!

有关详细信息,请参见 session_id() 手册页。
11
dave1010 at gmail dot com
13 年前
PHP 会锁定会话文件,直到它关闭。如果您有两个脚本使用同一个会话(即来自同一个用户),那么第二个脚本将无法完成其对 session_start() 的调用,直到第一个脚本完成执行。

如果您有运行时间超过一秒的脚本,并且用户可能一次进行多个请求,那么在完成写入会话数据后,值得调用 session_write_close()。

<?php
// 会话上会放置一个锁,因此其他脚本必须等待
session_start();

// 对 $_SESSION 执行所有写入操作
$_SESSION['a'] = 1;

// $_SESSION 仍然可以读取,但写入不会更新会话。
// 锁定已删除,其他脚本现在可以读取会话
session_write_close();

do_something_slow();
?>

http://konrness.com/php5/how-to-prevent-blocking-php-requests/ 了解到这一点。
8
elitescripts2000 at yahoo dot com
10 years ago
关于 AJAX 应用程序中会话的 3 个简单但至关重要的内容。

<?php
// 会话开始

// 如果使用整个域,包括一个点非常重要
// (.yourdomain.com)
// 设置会话始终运行的根路径非常重要
// (/members) 将确保会话不会受到干扰
// 带有路径的会话,例如 (/admin) ... 这样您就可以登录
// 作为 /admin 和 /members... 不要执行 unset($_SESSION)
// 优选 $_SESSION=array();,session_unset(); session_destroy();

session_set_cookie_params(0, '/members', '.yourdomain.com', 0, 1);
session_start();
$_SESSION = array();
session_unset();
session_destroy();

session_set_cookie_params(0, '/members', '.yourdomain.com', 0, 1);
session_start();

$_SESSION['whatever'] = 'youwhat';

// 会话销毁

// 为确保安全,请清除 $_SESSION 数组
// 接下来,大多数人没有做的是删除会话 cookie!
// 删除 cookie 很容易,方法是将其过期时间设置为当前时间之前很久。
// 删除 cookie 的唯一方法是确保所有参数都与要删除的 cookie 相匹配
// cookie - 使用 session_get_cookie_params() 可以很容易地获得这些参数
// 最后,按照此顺序使用 session_unset(); 和 session_destroy(); 以确保
// Chrome、IE、Firefox 和其他浏览器正确销毁会话。
$_SESSION = array();
if (
ini_get('session.use_cookies'))
{
$p = session_get_cookie_params();
setcookie(session_name(), '', time() - 31536000, $p['path'], $p['domain'], $p['secure'], $p['httponly']);
}
session_unset();
session_destroy();

// AJAX 和会话。
// 例如... 您启动了一个基于会话的 PHP 页面,该页面随后调用一个 AJAX(XMLHTTP),该 AJAX 使用
// 同一会话进行身份验证,以轮询和输出数据,例如。但是,您注意到当您
// 尝试启动轮询 AJAX 调用时,它总是挂起,并且似乎挂在 session_start() 上。
// 这是因为会话是在第一个页面中打开的,它调用 AJAX 轮询示例,并且
// 尝试打开相同的会话(用于身份验证)并执行 AJAX 调用,您必须调用
// session_write_close(); 这意味着您已完成对 $_SESSION 变量的写入,该变量实际上
// 表示必须使用 session_write_close(); 关闭的文件....
// 然后,您可以调用 AJAX 轮询代码来重新打开相同的会话并执行其轮询...
// 通常,$_SESSION 会在脚本关闭或完成执行时自动关闭
// 因此,如果您需要在打开会话后保持 PHP 页面运行,只需在完成时将其关闭即可
// 写入 $_SESSION,以便 AJAX 轮询页面可以在单独的网页中使用同一会话进行身份验证
// ...

session_write_close();

?>

希望这能帮助某人处理他们的会话…
谢谢。
3
ben dot morin at spaboom dot com
17 年前
skinsupport dot com 上的 James 提出一个很好的观点(警告),关于来自浏览器的额外请求。favicon.ico 的请求,根据处理方式的不同,可能会对您的会话产生意想不到的结果。

例如,假设您有 ErrorDocument 404 /signin.php,没有 favicon.ico 文件,并且您网站中所有用户登录的页面,如果他们尚未登录,也会重定向到 /signin.php。

如果 signin.php 进行了任何清理或重新分配 session_id(所有好的 signin.php 页面都应该这样做),那么来自浏览器对 favicon.ico 的额外请求可能会破坏由实际请求设置的会话。

感谢 James 指出这一点,我对此进行了粗略浏览,没有看到它与我的问题有什么关系。也要感谢 Firefox Live HTTP Headers 扩展,因为它显示了额外的请求。

如果您的会话 cookie 没有发送,或者会话数据不是您期望的,不要在这上面浪费几天甚至几小时。至少,消除这种情况,看看是否有其他请求可能是故障原因。
4
James
18 年前
要避免 PHP 从 4.3.3 开始提交的通知,当您两次启动会话时,请先检查 session_id()。

if (session_id() == "")
session_start();
10
someOne_01 at somewhere dot com
11 年前
当您有一个执行时间很长的导入脚本时,浏览器似乎会锁定,您无法再访问网站。这是因为一个请求正在读取和锁定会话文件以防止损坏。

您可以:
- 使用不同的会话处理程序,使用 session_set_save_handler()
- 在导入脚本中使用 session_write_close(),只要您不再需要会话(最好的时机是在执行长时间的部分之前),您就可以在需要时随意调用 session_start(),并且可以根据导入脚本的要求更改会话变量。

示例
<?php
session_start
(); // 初始化/打开会话
$_SESSION['count'] = 0; // 在会话中存储一些东西
session_write_close(); // 现在关闭它,
# 从这里开始,其他脚本都可以运行(并且看起来像多任务处理)
for($i=0; $i<=100; $i++){ // 执行 100 次循环
session_start(); // 再次打开会话以编辑变量
$_SESSION['count'] += 1; // 更改变量
session_write_close(); // 现在再次关闭会话!
sleep(2); // 每个循环休眠两秒钟,或执行一个繁重的任务
}
?>
3
匿名
3 年前
小心使用 “read_and_close” 选项。与默认的 PHP 行为不同,它不会更新会话文件的最后修改时间,当你没有关闭会话时(或当你显式使用 session_write_close 时)。
旧的会话文件(对我来说,超过 24 分钟的旧文件)会偶尔被垃圾收集器清除(对我来说,每小时 09 分和 39 分)。
因此,即使页面定期向服务器发送只读取和关闭会话的请求,会话也可能会消失。
3
[email protected]
5 年前
以下代码展示了 PHP 会话的工作原理。my_session_start() 函数几乎与 session_start() 做同样的事情。

<?php
error_reporting
(E_ALL);
ini_set('display_errors', true);
ini_set('session.save_path', __DIR__);

my_session_start();

echo
'<p>session id: '.my_session_id().'</p>';

echo
'<code><pre>';
var_dump($_SESSION);
echo
'</pre></code>';

$now = date('H:i:s');
if (isset(
$_SESSION['last_visit_time'])) {
echo
'<p>Last Visit Time: '.$_SESSION['last_visit_time'].'</p>';
}
echo
'<p>Current Time: '.$now.'</p>';

$_SESSION['last_visit_time'] = $now;

function
my_session_start() {
global
$phpsessid, $sessfile;

if (!isset(
$_COOKIE['PHPSESSID']) || empty($_COOKIE['PHPSESSID'])) {
$phpsessid = my_base32_encode(my_random_bytes(16));
setcookie('PHPSESSID', $phpsessid, ini_get('session.cookie_lifetime'), ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure'), ini_get('session.cookie_httponly'));
} else {
$phpsessid = substr(preg_replace('/[^a-z0-9]/', '', $_COOKIE['PHPSESSID']), 0, 26);
}

$sessfile = ini_get('session.save_path').'/sess_'.$phpsessid;
if (
is_file($sessfile)) {
$_SESSION = unserialize(file_get_contents($sessfile));
} else {
$_SESSION = array();
}
register_shutdown_function('my_session_save');
}

function
my_session_save() {
global
$sessfile;

file_put_contents($sessfile, serialize($_SESSION));
}

function
my_session_id() {
global
$phpsessid;
return
$phpsessid;
}

function
my_random_bytes($length) {
if (
function_exists('random_bytes')) {
return
random_bytes($length);
}
$randomString = '';
for (
$i = 0; $i < $length; $i++) {
$randomString .= chr(rand(0, 255));
}
return
$randomString;
}

function
my_base32_encode($input) {
$BASE32_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
$output = '';
$v = 0;
$vbits = 0;
for (
$i = 0, $j = strlen($input); $i < $j; $i++) {
$v <<= 8;
$v += ord($input[$i]);
$vbits += 8;
while (
$vbits >= 5) {
$vbits -= 5;
$output .= $BASE32_ALPHABET[$v >> $vbits];
$v &= ((1 << $vbits) - 1);
}
}
if (
$vbits > 0) {
$v <<= (5 - $vbits);
$output .= $BASE32_ALPHABET[$v];
}
return
$output;
}
5
[email protected]
14 年前
不幸的是,在我绞尽脑汁试图弄清楚为什么我的应用程序在除 IE(Internet Explorer)之外的所有浏览器中都运行良好(我在 Opera、Chrome、Firefox、Safari 中测试了它) - 当使用 DNS CNAME 记录(比如与 DNS A 记录不同的虚名,即服务器的主机名)时,会话无法正常工作。

如果你在 CNAME 上存储一个会话变量
vanity.example.com,而服务器的主机名为 hosname.example.com
然后尝试从另一个页面调用该变量,它将找不到它,因为 CNAME 的原因(我认为它在主机名下存储了该变量,然后在尝试读取它时,它仍在 CNAME 下寻找),同一个应用程序在直接访问主机名时可以正常工作。请记住,我是在内部网络上测试的。
3
[email protected]
7 years ago
X 维持者 ... 对不起,这样很烦人,请删除此重复内容,因为是在一个疯狂的 “session” 中提交的,我在浏览器标签之间搞乱了东西 ... 再次抱歉,alessio
https://php.net/manual/en/function.session-start.php#121310
3
[email protected]
19 年前
如果你使用 JavaScript 的 window.open 打开一个弹出窗口(请不要使用商业弹出窗口!),IE 可能会阻止会话 cookie。
一个简单的解决方法是使用 GET 值在打开新窗口时传递会话 ID。请注意,我不会为此使用 SID,因为它不总是可用。

----page.php----
// 你必须在此处启动一个会话
window.open('popup.php?sid=<?php echo session_id(); ?>', '700x500', 'toolbar=no, status=no, scrollbars=yes, location=no, menubar=no, directories=no, width=700, height=500');

----popup.php----
<?php
session_id
(strip_tags($_GET['sid']));
session_start();
// 然后继续使用你的会话变量
?>
3
andy_isherwood at hotmail dot com
15 年前
使用 `session_start` 创建的会话仅对首次创建该会话的页面所在目录树中的页面可用。

例如,如果首次创建会话的页面为 `/dir1/dir2/index.php`,用户随后访问 `dir2` 上面的任何页面(例如 `/dir1/index.php`),`session_start` 将创建新的会话,而不是使用现有的会话。
2
ilnomedellaccount at gmail dot com
11 年前
关于 `session_start()`、自定义处理程序和数据库外键约束的说明,我认为可能有一些用处...

我们知道,如果希望将会话保存到数据库表(而不是默认存储位置),可以参考 `session_set_save_handler(...)` 将它们保存到数据库表。请注意,`session_set_save_handler` 必须(显然)在 `session_start()` 之前调用,但让我直接进入主题...

首次调用 `session_start()` 时,如果会话尚不存在,PHP 将生成新的会话,但在脚本执行完成之前不会调用写入处理程序。

因此,此时会话存在于服务器进程内存中,但在脚本结束之前不会在数据库中显示为一行。

这似乎很合理,因为它避免了一些不必要的数据库访问和资源使用,即使在我们还没有用有意义的和确定的数据填充会话之前。但这也有一些副作用。

在我的情况下,脚本调用了 `session_start()` 以确保会话启动,然后使用 `session_id()` 来填充数据库中的另一个表,该表对“会话”表具有外键约束。这失败了,因为此时数据库中还没有会话!

我知道我可以通过在必要时手动调用写入处理程序来强制在数据库中创建该行,但我不知道这是否是最佳方法。

一旦我找到“优雅”的解决方案,或者完全不同的方法,我将发布一些可工作的示例代码。

在此期间...玩得开心!
2
schlang
15 年前
如果你将会话存储在数据库中,请始终确保数据库列的类型足够大以容纳你的会话值。
1
chris at ocproducts dot com
7 years ago
启动会话可能会覆盖你自己的自定义缓存控制标头,这可能会导致点击后退按钮无法返回到先前的 POST 请求(至少在 Chrome 中是这样)。
在我的系统上,它设置了 `no-store`,这比 `no-cache` 更加严格,并且是导致后退按钮无法正常工作的原因。

如果你仔细控制自己的缓存标头,则需要调用
`session_cache_limiter('');`

...来阻止它更改你的缓存控制标头。
1
fabmlk at hotmail dot com
8 年前
如果你需要在同一个脚本中打开多个不同的会话,并且仍然让 PHP 为你生成会话 ID,这里有一个我想到的简单函数(假设使用 PHP 默认会话处理程序)

<?php
/**
* 切换到或透明地创建名为 $name 的会话。
* 它可以轻松扩展以管理不同的会话生存期。
*/
function session_switch($name = "PHPSESSID") {
static
$created_sessions = array();

if (
session_id() != '') { // 如果当前打开了会话,关闭它
session_write_close();
}
session_name($name);
if (isset(
$_COOKIE[$name])) { // 如果特定的会话已经存在,与 $created_sessions 合并
$created_sessions[$name] = $_COOKIE[$name];
}
if (isset(
$created_sessions[$name])) { // 如果是现有会话,模拟它
session_id($created_sessions[$name]);
session_start();
} else {
// 创建新的会话
session_start();
$_SESSION = array(); // 在复制会话文件之前清空内容
// 用新的 ID 和当前的 $_SESSION 内容复制最后一个会话文件
// 如果这是第一个创建的会话,则没有要复制的内容,并将 true 作为参数传递将负责“创建”仅一个会话文件
session_regenerate_id(empty($created_sessions));
$created_sessions[$name] = session_id();
}
}

session_switch("SESSION1");
$_SESSION["key"] = "value1"; // 特定于会话 1
session_switch("SESSION2");
$_SESSION["key"] = "value2"; // 特定于会话 2
session_switch("SESSION1");
// 返回到会话 1
// ...
?>

使用此函数时,`session_start()` 不应该再单独调用(可以替换为不带参数的 `session_switch()` 调用)。
还要记住,`session_start()` 在每次调用时都会设置一个 Set-Cookie HTTP 标头,因此如果你在会话之间进行回显,请使用输出缓冲区包装。

注意:处理多个会话可能很少是一个好主意,因此如果你认为自己有很好的用途,请三思而后行。
就我个人而言,它在我必须维护的一些遗留代码的快速修复中发挥了作用。
0
theking2(at)king.ma
2 个月前
我通常使用以下代码来启动新的会话

<?php
session_start
( [
'name' => DEBUG ? 'SessionId' : '__Secure-SessionId',
'cookie_lifetime' => 0,
'cookie_path' => '/',
'cookie_secure' => true,
'cookie_httponly' => true,
'cookie_samesite' => 'Strict',
'sid_length' => 96,
'sid_bits_per_character' => 5,
'use_strict_mode' => true,
'referer_check' => $_SERVER['HTTP_HOST'],
] );
?>

这将创建一个会话,在会话 cookie 名称中具有更高的熵,需要安全的会话,确保 roque 引用没有机会访问我的登录页面,以及其他事项。

根据 MDN[1],前缀 `__Secure-` 必须为安全会话设置。

[1](https://mdn.org.cn/en-US/docs/Web/HTTP/Headers/Set-Cookie)
0
polygon dot co dot in at gmail dot com
2 年前
网站容易受到会话攻击,如果在使用会话时没有采取适当的措施。

有一些工具,如“Apache Benchmark”(ab)等,可以对网站进行负载测试,以进行负载/性能测试。

以下代码为每个请求启动会话。

<?php
session_start
();

$username = $_POST['username'];
$password = $_POST['password'];

if(
isValidUser($username, $password)) {

Suserdetails = getUserDetails($username);

$_SESSION['user_id'] = Suserdetails['user_id'];
$_SESSION['username'] = Suserdetails['username'];
$_SESSION['firstname'] = Suserdetails['firstname'];

header('Location: dashboard.php');
}
?>

当使用 ab 等工具时,这将为每个请求生成会话文件,而不管 PHPSESSID cookie 值如何,从而导致 inode 问题。

应该在正确身份验证后启动会话。

<?php

$username
= $_POST['username'];
$password = $_POST['password'];

if(
isValidUser($username, $password)) {

Suserdetails = getUserDetails($username);

session_start();

$_SESSION['user_id'] = Suserdetails['user_id'];
$_SESSION['username'] = Suserdetails['username'];
$_SESSION['firstname'] = Suserdetails['firstname'];

header('Location: dashboard.php');
}
?>

除了登录之外的脚本首先会验证会话,这需要会话。

<?php

if(session_status()!=PHP_SESSION_NONE) header('Location: login.php');

session_start();

if(!isset(
$_SESSION['user_id'])) header('Location: login.php');

代码逻辑如下....
}
?>

此示例适用于基于文件的会话。
有关其他会话模式,请检查函数 session_set_save_handler。
0
axew3 at axew3 dot com
7 years ago
我需要轻松地计算页面在网站上重新加载的次数,以便在计数器为 0 时添加一个警告弹出窗口。
session_start();
if(isset($_SESSION['count'])){
$count = $_SESSION['count'];
$count++;
$count = $_SESSION['count'] = $count;
} else {
$count = $_SESSION['count'] = 0;
}
echo $count;

//session_destroy();
0
info at nospam dot mmfilm dot sk
14 年前
对于那些在使用 UTF-8 编码文件时遇到问题的人

我遇到了一个错误,因为 BOM,尽管我已经将 Dreamweaver 设置为“另存为”不带 BOM。似乎 DW 不会在现有文件中更改此设置。在创建不带 BOM 的新文件后,一切正常。

我还建议使用 http://people.w3.org/rishida/utils/bomtester/index.php - 一个远程检查 BOM 是否存在的实用程序。
0
Charlie at NOSPAM dot example dot com
14 年前
请注意,根据脚本结束来关闭会话实际上会序列化并发会话请求。并发后台“数据检索”(例如 AJAX 或 amfphp/Flex 等应用程序)期望并行检索数据,很容易陷入这个陷阱。

在昂贵的操作之后才进行 session_write_close 也会有问题。

为了最大程度地减少影响,请尽早调用 session_write_close(又名 session_commit)(例如,在不引入竞争条件的情况下),或者避免序列化瓶颈。
-1
axew3 at axew3 dot com
7 years ago
我只需要轻松地计算页面在网站上重新加载的次数,以便在计数器为 0 时添加一个警告弹出窗口。

session_start();
if(isset($_SESSION['count'])){
$count = $_SESSION['count'];
$count++;
$count = $_SESSION['count'] = $count;
} else {
$count = $_SESSION['count'] = 0;
}
echo $count;

//session_destroy();
-2
anon at ymous dot com
13 年前
我正在尝试获取由浏览器调用创建的会话,以便在命令行 cli->curl php 调用中使用它(在本例中,对同一服务器和 php.ini 的调用),用于一组灵活的媒体导入例程。

但是,cli->curl 调用始终会启动一个新会话,尽管我已经将 PHPSESSID=validID 作为 curl 调用的 url 的第一个参数。

我能够通过在调用 session_start() 之前在通过 curl 调用的脚本中调用 session_id($_GET['PHPSESSID']) 来解决它。
-3
sanjuro at 1up-games dot com
12 年前
SID 的问题是,如果在某些情况下你没有启动会话,它会返回一个常规的未定义常量通知,而不是为透明集成输出一个空字符串。因此,你可能想先使用 defined() 测试常量。
-4
info.at.merchandisinginteractive.sk
14 年前
一个方便的脚本,用于检查当前目录开始的所有目录中的所有文件是否存在 uft-8 字节顺序标记 (BOM)。从这里其他人的工作中组合而来...

<?php
function fopen_utf8 ($filename) {
$file = @fopen($filename, "r");
$bom = fread($file, 3);
if (
$bom != b"\xEF\xBB\xBF")
{
return
false;
}
else
{
return
true;
}
}

function
file_array($path, $exclude = ".|..|design", $recursive = true) {
$path = rtrim($path, "/") . "/";
$folder_handle = opendir($path);
$exclude_array = explode("|", $exclude);
$result = array();
while(
false !== ($filename = readdir($folder_handle))) {
if(!
in_array(strtolower($filename), $exclude_array)) {
if(
is_dir($path . $filename . "/")) {
// 需要包含完整的“路径”,否则它将是一个无限循环
if($recursive) $result[] = file_array($path . $filename . "/", $exclude, true);
} else {
if (
fopen_utf8($path . $filename) )
{
//$result[] = $filename;
echo ($path . $filename . "<br>");
}
}
}
}
return
$result;
}

$files = file_array(".");
?>
-3
dstuff at brainsware dot org
15 年前
看起来名称中的空格也不起作用 - 每次都会生成一个新的会话 ID
-4
m dot kuiphuis at hccnet dot nl
21 年前
[编辑注:有关此的更多信息
http://www.zvon.org/tmRFC/RFC882/Output/chapter5.html ]

我在 Linux 上使用基于名称的虚拟主机,使用 Apache 和 PHP 4.3.2。
每次我刷新(通过在 Internet Explorer 中按 F5)时,我都会注意到我得到一个新的 session_id。同时使用 Netscape 浏览同一个网站没有出现这个问题。一开始我以为是 PHP 的问题(在我用 Netscape 测试之前),但在网上搜索了很多资料后,我找到了问题所在。
由于我使用的是基于名称的虚拟主机来测试我的服务器,并且我们为不同的客户拥有不同的网上商店,所以我使用了 webshop_customername.servername.nl 作为域名。
域名中的 _ 似乎是问题所在。当域名中存在特殊字符(例如 _)时,Internet Explorer 就会拒绝在客户端设置 cookie。有关此问题的更多信息:http://support.microsoft.com/default.aspx?scid=kb;EN-US;316112
愚蠢的是,此信息与 asp 相关(yuk:o)
-5
leandroico---at---gmail---dot---com
17 年前
标签:session_start 标头输出错误 include_once require_once php 标签换行

与 *session_start()* 在 include 文件中调用相关的输出标头错误。

如果你在 include 文件中启动会话,则必须注意 php 结束标签之后是否有不需要的字符。

让我们举个例子
> page.php
<?php
include_once 'i_have_php_end_tag.inc.php';
include_once
'init_session.inc.php';

echo
"该死!为什么我会遇到这些输出标头错误?";
?>

> i_have_php_end_tag.inc.php
<?php
$_JUST_A_GLOBAL_VAR
= '是的,一个全局变量,确实';
?>

> init_session.inc.php
<?php
session_start
();
$_SESSION['blabla'] = 123;
?>

有了所有这些东西,我们会得到一个错误,类似于
"... 无法发送会话缓存限制器 - 标头已发送(输出从 ... 开始)",对吧?

要解决这个问题,我们必须忽略 include 文件发送的所有输出。为了确保这一点,我们需要使用 *ob_start()* 和 *ob_end_clean()* 这两个函数来抑制输出。因此,我们要做的就是将 *page.php* 更改为此

<?php
ob_start
();
include_once
'i_have_php_end_tag.inc.php';
include_once
'init_session.inc.php';
ob_end_clean();

echo
"哇!好的!消灭你们这些讨厌的输出!!!";
?>
-7
tom at bitworks dot de
7 years ago
简单的 session_start() 不足以让你的会话保持活动状态。
由于文件系统挂载参数,atime 通常不会更新。atime 将不会更新,而是会提供 mtime。

这种行为可能会导致会话过早死亡,你的用户可能会被踢出登录系统。

要保持会话活动状态,有必要在每个请求中向会话文件写入一些内容,例如

"$_SESSION['time'] = time();"

这将保持你的会话活动状态,即使客户端实际上只是在网站上点击。
-4
james at skinsupport dot com
18 年前
需要注意的一点是,这让我困扰了三天

重要的是要注意,Firefox(至少)会自动向服务器发出两个调用。一个用于页面,一个用于 favicon.ico。

如果你在页面存在时将会话变量(就像我一样)设置为特定值,而在页面不存在时设置为其他值,那么如果 favicon.ico 不存在,则不存在页面的值将覆盖存在页面的值。

我怀疑你们中很少有人会这样做,但如果你这样做,这是你需要解决的问题,否则你会在三天内秃头的!
-5
jphansen at uga dot edu
16 年前
我刚刚写道,session_start() 函数一旦被调用,就会清除你的查询字符串变量。我想澄清一下,它只会在你 $_SESSION[] 中定义了相同下标的变量时才会这样做。
-10
erm[at]the[dash]erm[dot]com
19 年前
如果你像我一样疯狂,想从命令行启动一个会话,以便其他脚本可以访问相同的信息。

我不知道这有多可靠。我能想到的最明显的用途是设置 pid。

// temp.php

#!/usr/bin/php -q
<?php

session_id
("temp");
session_start();

if (
$_SESSION) {
print_r ($_SESSION);
}

$_SESSION['test'] = "this is a test if sessions are usable inside scripts";

?>

// Temp 2

#!/usr/bin/php -q
<?php

session_id
("temp");
session_start();

print_r ($_SESSION);

?>
-10
ivijan dot stefan at gmail dot com
7 years ago
如何修复 session_start 错误?

有时当你在项目中创建插件、附加组件或某些组件时,你需要检查会话是否已启动,如果没有,你需要启动它,而不会出现 session_start() 错误。

这是我经过测试的解决方案,目前在 +9000 个域名和我的一个插件中都有效,也适用于一些自定义工作。

<?php
if (strnatcmp(phpversion(),'5.4.0') >= 0)
{
if (
session_status() == PHP_SESSION_NONE) {
session_start();
}
}
else
{
if(
session_id() == '') {
session_start();
}
}
?>

随意使用它,不要担心,要开心。;)
-10
hbertini at sapo dot pt
19 年前
当在 .php 文件中使用会话变量时,该文件由不同服务器上的框架(.html 或其他文件类型)引用时的解决方法。

在这种情况下,IE6 或更高版本会静默拒绝尝试创建的会话 cookie(无论是隐式还是通过调用 session_start() 函数显式创建)。

结果,你的会话变量将返回一个空值。

根据 MS 的知识库,解决方法是在头部添加一条信息,表明你的远程 .php 页面不会滥用已授予的权限。

将此头部放置在将创建/更新你想要的会话变量的 .php 文件中

<?php header('P3P: CP="CAO PSA OUR"'); ?>

此致,
Hugo
-17
Nathan
5 年前
顺便说一句,你可以使用

if (!isset($_SESSION)) {
// 我们热爱每位用户
session_start();
// 然后刷新以使更改生效
header("location: ../../");
} elseif ($_SESSION["user] == "123ABC - abcmouse.com") {
/* 我们不喜欢这个用户,所以让我们把他们踢出
会话 */
session_destroy();
// 然后刷新以使更改生效
header("location: ../../");
}
To Top