• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

如何在PHP中使用会话和会话变量

会话处理是 php 中的一个关键概念,它使用户信息能够在网站或应用程序的所有页面中持久保存。在这篇文章中,您将学习 PHP 中会话处理的基础知识。

咱们将首先解释会话如何工作以及它们与 cookie 的关系。然后咱们将看一些演示如何使用会话的代码片段。您将学习如何创建和销毁会话,以及如何更改会话变量。

Cookie 与会话变量

不确定您是否需要 cookie 或会话变量?会话变量是一种将有关用户的数据存储在数据库中并稍后检索它的方法。Cookie 是一种在用户计算机上存储用户数据的方式。会话变量通常用于需要跟踪用户活动的应用程序。Cookie 通常用于需要为单个站点存储有关用户的信息的应用程序。

如何在PHP中使用会话和会话变量  第1张

什么是 PHP 中的会话?

会话是一种在不同网页上持久保存信息的机制,以在用户浏览网站或应用程序时识别用户。您想知道为什么网站需要会话吗?要了解为什么需要会话,咱们必须回头看看 HTTP 协议是如何设计的。

HTTP 协议是无状态协议,这意味着服务器无法在多个请求之间记住特定用户。例如,当您访问一个网页时,服务器只负责提供所请求页面的内容。因此,当您访问同一网站的其他页面时,Web 服务器会分别解释每个请求,就好像它们彼此无关一样。服务器无法知道每个请求都来自同一个用户。

下图简要描述了 HTTP协议。

如何在PHP中使用会话和会话变量  第2张在此模型中,如果您想显示特定于用户的信息,则必须在每个请求中对用户进行身份验证。想象一下,如果您必须在显示您的个人资料信息的每个页面上输入您的用户名和密码!是的,这会很麻烦而且根本不实用,这就是会话出现的地方。

会话允许您在单个站点或应用程序的不同页面之间共享信息,从而有助于维护状态。这让服务器知道所有请求都来自同一用户,从而允许站点显示用户特定的信息和偏好。

带有会话和 Cookie 的登录流程

让咱们快速浏览一个网站的常见登录流程,以了解幕后发生的事情。

  1. 用户打开网站的登录页面。

  2. 提交登录表单后,另一端的服务器通过验证输入的凭据来验证请求。

  3. 如果用户输入的凭据有效,则服务器会创建一个新会话。服务器生成一个唯一的随机数,称为会话 id。它还在服务器上创建一个新文件,用于存储特定于会话的信息。

  4. 接下来,将会话 ID 连同所请求的任何资源一起传回给用户。在幕后,这个会话 id 在响应头中的PHPSESSID cookie 中发送。

  5. 当浏览器收到来自服务器的响应时,它会遇到 PHPSESSID cookie 标头。如果浏览器允许 cookie,它会保存这个 PHPSESSID cookie,其中存储了服务器传递的 session id。

  6. 对于后续请求,  PHPSESSID cookie 被传回服务器。当服务器遇到 PHPSESSIDcookie 时,它将尝试使用该会话 id 初始化会话。它通过在会话初始化期间加载之前创建的会话文件来实现。然后它将 $_SESSION 使用存储在会话文件中的数据初始化超全局数组变量。

这样,用户数据在多个请求中被保留,并且用户在整个会话期间保持登录状态。

下图描述了 HTTP 协议如何处理会话。

如何在PHP中使用会话和会话变量  第3张现在您已经看到了有关会话如何工作的简要介绍,咱们将创建一些实际示例来演示如何创建和操作会话变量。

如何开始会话

在本节中,咱们将讨论如何在 PHP 中启动会话。

每当您要处理会话变量时,您需要确保会话已经启动。有几种方法可以在 PHP 中启动会话。

使用 session_start 功能

这是您最常看到的方法,会话由 session_start 函数启动。

<?php
// start a session
session_start();
 
// manipulate session variables
?>

重要的是 session_start 必须在脚本开始时调用该函数,然后才能将任何输出发送到浏览器。否则,您将遇到臭名昭著的 Headers are already sent 错误。

自动启动会话

如果需要在整个应用程序中使用会话,您还可以选择自动启动会话而不使用该 session_start 功能。

php.ini文件中有一个配置选项,  它允许您为每个请求自动启动会话—— session.auto_start。默认情况下,它设置为 0,您可以将其设置 1 为启用自动启动功能。

session.auto_start = 1

另一方面,如果您无权访问 php.ini 文件,并且您使用的是 Apache Web 服务器,您也可以使用 . htaccess 文件。

php_value session.auto_start 1

如果您在.htaccess文件中添加上述行,则  应该会在您的 PHP 应用程序中自动启动一个会话。

如何获取会话 ID

如前所述,服务器为每个新会话创建一个唯一编号。如果要获取会话 id,可以使用该 session_id 函数,如以下代码段所示。

<?php
session_start();
echo session_id();
?>

那应该给你当前的会话ID。该 session_id 函数的有趣之处在于它还可以接受一个参数——会话 ID。如果你想用你自己的替换系统生成的会话 id,你可以将它提供给 session_id 函数的第一个参数。

<?php
session_id(YOUR_SESSION_ID);
session_start();
?>

需要注意的是,  当您想要使用自定义会话 ID 启动会话时,session_id 必须将函数放在调用之前 。session_start

如何创建会话变量

在本节中,咱们将探讨如何在 PHP 中初始化会话变量。

正如咱们前面所讨论的,一旦会话开始, $_SESSION 超全局数组就会使用相应的会话信息进行初始化。默认情况下,它使用空白数组进行初始化,您可以使用键值对存储更多信息。

让咱们通过以下示例脚本来演示如何初始化会话变量。

<?php
// start a session
session_start();
 
// initialize session variables
$_SESSION['logged_in_user_id'] = '1';
$_SESSION['logged_in_user_name'] = 'Tutsplus';
 
// access session variables
echo $_SESSION['logged_in_user_id'];
echo $_SESSION['logged_in_user_name'];
?>

如您所见,咱们在脚本开头使用该 session_start 函数启动了一个会话。之后,咱们初始化了几个会话变量。最后,咱们使用 $_SESSION 超全局变量访问了这些变量。

当您使用 $_SESSION 超全局将数据存储在会话中时,它最终会存储在服务器上相应的会话文件中,该文件是在会话启动时创建的。这样,会话数据在多个请求之间共享。

正如咱们所讨论的,会话信息在请求之间共享,因此在一个页面上初始化的会话变量也可以从其他页面访问,直到会话过期。通常,会话在浏览器关闭时过期。

如何修改和删除会话变量

您可以修改或删除之前在应用程序中创建的会话变量,方法与常规 PHP 变量相同。

让咱们看看如何修改会话变量。

<?php
session_start();
 
if (!isset($_SESSION['count']))
{
  $_SESSION['count'] = 1;
}
else
{
  ++$_SESSION['count'];
}
 
echo $_SESSION['count'];
?>

在上面的脚本中,咱们 $_SESSION[‘count’] 首先检查了变量是否已设置。如果未设置,咱们将其设置为 1,否则咱们将其递增 1。所以,如果你多次刷新这个页面,你应该会看到计数器每次都加一! 

另一方面,如果您想删除会话变量,可以使用该 unset 函数,如以下代码段所示。

<?php
// start a session
session_start();
 
// initialize a session variable
$_SESSION['logged_in_user_id'] = '1';
 
// unset a session variable
unset($_SESSION['logged_in_user_id']);
?>

因此,您无法再访问该 变量,因为它已被 函数$_SESSION[‘logged_in_user_id’] 删除 。unset这就是您可以更改会话信息的方式。

如何销毁会话

在本节中,咱们将了解如何销毁会话。在上一节中,咱们讨论了 unset 要删除特定会话变量时使用的函数。另一方面,如果您想一次删除所有与会话相关的数据,您可以使用该 session_destroy 功能。

该 session_destroy函数删除存储在当前会话中的所有内容。话虽如此,它不会取消设置与会话关联的全局变量或取消设置会话 cookie。

因此,如果您使用该 session_destroy功能注销用户,则必须取消设置$_SESSION变量并取消设置会话 cookie。因此,完全销毁会话的推荐方法是:

<?php
// start a session
session_start();
 
// destroy everything in this session
 
unset($_SESSION);
if (ini_get("session.use_cookies")) {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"],$params["httponly"]);
}
 
session_destroy();
?>

会话处理程序

到目前为止,咱们已经讨论了如何使用会话变量执行不同的操作。在本节中,咱们将讨论什么是会话处理程序以及如何使用它。

PHP 会话处理程序是一种指示 PHP 如何管理会话的机制。默认会话处理程序是文件系统,这意味着 PHP 将会话存储在磁盘上。基本上,它是服务器上与唯一会话 ID 相关联的一个小文件。它与存储在客户端浏览器上的会话 cookie 中的 id 相同。

PHP 中的默认会话处理程序为您提供了所需的所有功能,但有时您希望以不同的方式存储会话。例如,您可能想要在数据库、redis或其他一些存储中管理会话。在这种情况下,您需要实现一个覆盖默认行为的自定义会话处理程序。

为了理解自定义会话处理程序是如何工作的,咱们将简要讨论如何实现一个数据库会话处理程序来管理mysql数据库中的会话。

如何实现数据库会话处理程序

在 PHP 会话生命周期中,有不同的阶段,例如打开、读取、写入和关闭。此外,还有两个阶段:销毁和垃圾收集。因此,当您实现自定义会话处理程序时,您必须处理每个阶段以正确管理会话数据。

有两种方法可以实现自定义会话处理程序,您可以为会话生命周期中的不同阶段定义回调函数,或者您可以编写一个实现SessionHandlerInterface 接口的类。在这两种情况下,您都需要使用该 session_set_save_handler 函数来初始化您的自定义会话处理程序。在咱们的例子中,咱们将使用 SessionHandlerInterface 接口实现。

在咱们的示例中,咱们将在 Mysql 数据库中存储会话。因此,让咱们使用以下代码段创建一个存储会话数据的表。

CREATE TABLE `sessions` (
  `session_id` varbinary(192) NOT NULL,
  `created` int(11) NOT NULL DEFAULT '0',
  `session_data` longtext COLLATE utf8mb4_unicode_ci,
  PRIMARY KEY (`session_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

接下来,让咱们看看咱们的自定义数据库会话处理程序的外观:

<?php
class MySQLSessionHandler implements SessionHandlerInterface
{
    private $connection;

    public function __construct()
    {
        $this->connection = new mysqli("HOST_NAME","USERNAME","PASSWORD","DATABASENAME");
    }

    public function open($savePath, $sessionName)
    {
        if ($this->connection) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    public function read($sessionId)
    {
        try {
            $stmt = $this->connection->prepare("SELECT session_data FROM sessions WHERE session_id = ?");
            $stmt->bind_param("s", $sessionId);
            $stmt->execute();
            $stmt->bind_result($sessionData);
            $stmt->fetch();
            $stmt->close();

            return $sessionData ? $sessionData : '';
        } catch (Exception $e) {
            return '';
        }
    }

    public function write($sessionId, $sessionData)
    {
        try {
            $stmt = $this->connection->prepare("replace INTO sessions(`session_id`, `created`, `session_data`) VALUES(?, ?, ?)");
            $stmt->bind_param("sis", $sessionId, $time=time(), $sessionData);
            $stmt->execute();
            $stmt->close();

            return TRUE;
        } catch (Exception $e) {
            return FALSE;
        }
    }

    public function destroy($sessionId)
    {
        try {
            $stmt = $this->connection->prepare("DELETE FROM sessions WHERE session_id = ?");
            $stmt->bind_param("s", $sessionId);
            $stmt->execute();
            $stmt->close();

            return TRUE;
        } catch (Exception $e) {
            return FALSE;
        }
    }

    public function gc($maxlifetime)
    {
        $past = time() - $maxlifetime;

        try {
            $stmt = $this->connection->prepare("DELETE FROM sessions WHERE `created` < ?");
            $stmt->bind_param("i", $past);
            $stmt->execute();
            $stmt->close();

            return TRUE;
        } catch (Exception $e) {
            return FALSE;
        }
    }

    public function close()
    {
        return TRUE;
    }
}

咱们的自定义会话处理程序类 MySQLSessionHandler 实现了 SessionHandlerInterface 接口。SessionHandlerInterface 因此,它必须实现接口中声明的方法 。咱们将一一查看这些方法,以了解每种方法的工作原理。

    public function __construct()
    {
        $this->connection = new mysqli("HOST_NAME","USERNAME","PASSWORD","DATABASENAME");
    }

首先,要使用此代码,请确保用方法中的实际值替换 HOST_NAME、 USERNAME和其他占位符 __construct 。

    public function open($savePath, $sessionName)
    {
        if ($this->connection) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

当会话开始时,该 open 方法被调用。TRUE 如果数据库连接成功,则返回 。如果设置数据库连接有任何问题,它会返回 FALSE.

    public function read($sessionId)
    {
        try {
            $stmt = $this->connection->prepare("SELECT session_data FROM sessions WHERE session_id = ?");
            $stmt->bind_param("s", $sessionId);
            $stmt->execute();
            $stmt->bind_result($sessionData);
            $stmt->fetch();
            $stmt->close();

            return $sessionData ? $sessionData : '';
        } catch (Exception $e) {
            return '';
        }
    }

接下来,PHP 调用该 read 方法来读取会话数据。该 read 方法接收会话 ID 作为第一个参数。咱们将检查表中是否有任何可用于此会话 ID 的条目 session_data。如果存在,咱们将返回会话数据;否则,将返回一个空字符串。

   public function write($sessionId, $sessionData)
    {
        try {
            $stmt = $this->connection->prepare("REPLACE INTO sessions(`session_id`, `created`, `session_data`) VALUES(?, ?, ?)");
            $stmt->bind_param("sis", $sessionId, $time=time(), $sessionData);
            $stmt->execute();
            $stmt->close();

            return TRUE;
        } catch (Exception $e) {
            return FALSE;
        }
    }

当 PHP 需要保存或关闭会话时,它会调用该 write 方法。它用于将会话数据写入数据库。咱们使用 REPLACE语法来确保如果一个条目存在,它将是最新的d; 否则,它将被插入。

    public function close()
    {
        return TRUE;
    }

该 close 方法在会话 write 方法被调用之后被调用。它的工作方式类似于类中的析构函数。在咱们的例子中,方法中没有什么特别需要做的 close 。

    public function destroy($sessionId)
    {
        try {
            $stmt = $this->connection->prepare("DELETE FROM sessions WHERE session_id = ?");
            $stmt->bind_param("s", $sessionId);
            $stmt->execute();
            $stmt->close();

            return TRUE;
        } catch (Exception $e) {
            return FALSE;
        }
    }

 当使用or  函数destroy 销毁会话时调用 该 方法。在此方法中,如果会话数据存在,则从数据库中删除它。session_destroysession_regenerate_id

    public function gc($maxlifetime)
    {
        $past = time() - $maxlifetime;

        try {
            $stmt = $this->connection->prepare("DELETE FROM sessions WHERE `created` < ?");
            $stmt->bind_param("i", $past);
            $stmt->execute();
            $stmt->close();

            return TRUE;
        } catch (Exception $e) {
            return FALSE;
        }
    }

当 PHP 定期运行垃圾收集器时, gc 会调用该方法。该 $lifetime 变量保存 php.ini 文件中session.gc_maxlifetime 配置选项 的值。在此方法中,咱们将在垃圾收集过程中删除所有过期的会话。

使用 MySQL 会话处理程序类

现在,让咱们看看如何使用 MySQLSessionHandler 处理程序类。

$objSessionHandler = new MySQLSessionHandler();
session_set_save_handler($objSessionHandler, true);
session_start();
$_SESSION['favoriteWebsite'] = 'www.weixiaolive.com';

如您所见,咱们只需要初始化 MySQLSessionHandler 类并将其传递给 session_set_save_handler 函数以指示 PHP 它需要使用 MySQLSessionHandler 该类进行会话管理。接下来,咱们调用了该 session_start 函数来启动会话。最后,咱们为测试目的初始化了一个会话变量。

如果一切顺利,您应该会在 sessions 表格中看到会话条目,如以下屏幕截图所示。

如何在PHP中使用会话和会话变量  第4张这样,您就创建了一个有效的自定义会话处理程序,用于管理数据库中的会话!

结论

在本文中,咱们探讨了 PHP 中会话处理的基础知识。这是一个关键概念,可让您跨网页保存信息。

在文章的前半部分,咱们讨论了会话的基本概念,随后咱们创建了几个 PHP 示例来演示如何创建和销毁会话以及操作会话变量。


文章目录
  • Cookie 与会话变量
  • 什么是 PHP 中的会话?
    • 带有会话和 Cookie 的登录流程
  • 如何开始会话
    • 使用 session_start 功能
    • 自动启动会话
    • 如何获取会话 ID
  • 如何创建会话变量
  • 如何修改和删除会话变量
  • 如何销毁会话
  • 会话处理程序
    • 如何实现数据库会话处理程序
      • 使用 MySQL 会话处理程序类
  • 结论