专栏首页学院君的专栏在 PHP 中使用和管理 Session

在 PHP 中使用和管理 Session

与 Cookie 一样,Session 技术也是用于解决 HTTP 协议无状态的问题,不过,与 Cookie 数据保存在客户端不同,Session 数据存储在服务端,然后通过分配一个全局唯一的 ID 与特定用户关联(通常在用户认证通过后分配),但 Session 又与 Cookie 紧密关联,因为这个 Session ID 通常会存储到 Cookie 中,在其生命周期内,用户发起请求时就会带上它,这样服务端通过解析存储在 Cookie 中的 Session ID 就能识别特定的客户端用户,并返回与之关联的 Session 数据,比如前面提到的电商网站中的购物车数据。

注:虽然 Session ID 也可以包含在 URL 请求参数(查询字符串)中,但是维护成本太高,不如直接存储到 Cookie 中方便,所以渐渐废弃,现在基本上都是通过 Cookie 存储,并以此建立服务端与客户端的关联和用户认证状态的维护。

2、Session 运行原理和配置浅析

Session 技术的一个主要用途就是用户认证,其基本实现原理是在用户登录成功后为其生成一个全局唯一的 Session ID,并且将必要的用户会话数据存储到服务端对应的 Session 数据中(后续可通过 Session ID 查询),然后通过 Set-Cookie 响应头将 Session ID 发送到客户端,并存储到客户端 Cookie,过期时间与服务端维护的 Session 有效期一致(默认是 3 小时),在 Session 有效期内,所有客户端请求都会自动通过 Cookie 请求头带上这个 Session ID,服务端解析到这个 Session ID 并且查询对应 Session 数据存在,则表明该客户端用户是一个已认证用户,进而返回对应的用户信息该客户端,让客户端可以标识对应用户的登录状态。

注:除了用户认证之外,Session 还有一些其他的使用场景,比如验证码校验、存储一些其他的用户状态信息(比如限定访问频率、禁止重复提交表单等)。

另外,在服务端,Session 数据默认存储在文件中,这是通过 php.inisession.save_handler 配置项配置的:

你还可以通过 session.save_path 指定存储 Session 数据文件的路径(默认是 /tmp,该配置仅在 session.save_handlers 值为 files 时有效),另外,在上述代码中,还可以看到与 Cookie 相关的配置:

当我们基于 Cookie 存储 Session ID 时,会通过这个配置项设置对应的 Cookie 属性,通过下面两个配置可以看到默认就是基于 Cookie 保存 Session ID,并且只使用 Cookie 保存(1 表示 true):

并且这个存储在 Cookie 中的 Session ID 对应名称是 PHPSESSID

session.name => PHPSESSID => PHPSESSID

最后,Session 功能默认是关闭的,如果要使用 Session 需要主动开启,Session 默认的有效期是 3 个小时(通过 cache_expire 配置项配置,单位为分钟),3 小时后自动销毁:

当然,以上配置在运行时都是支持动态设置的。

3、Session 的基本使用

我们以用户认证为例,演示下如何在 PHP 中使用 Session。

基本增删改查演示

首先我们来简单看下如何启用并设置/读取 Session 数据,在 php_learning/http 目录下新建 session.php

<?php
session_save_path('./session');
session_start();
if (isset($_SESSION['name'])) {
    echo $_SESSION['name'];
    exit();
}
$_SESSION['name'] = '学院君';

我们调用 PHP 内置的 session_save_path 函数设置 Session 存储目录为当前目录下的 session 子目录中,然后调用 session_start 函数启动 Session(这一行代码最为关键,不能省略,否则无法使用 Session 保存和读取数据)。

接下来,我们就可以通过 PHP 超全局变量 _SESSION 读取和设置 Session 数据了,和之前的其他超全局变量一样,_SESSION 也是一个关联数组,通过关联数组的方式更新或者新增 Session 数据即可,如果要删除某个 Session 数据,使用 unset 函数即可:

unset($_SESSION['name']);

我们在浏览器中访问 http://localhost:9000/session.php,首次访问没有任何输出,因为 Session 中还没有数据,但是再次刷新就可以看到 Session 中的数据被打印出来:

此时看 http/session 目录下,已经包含生成的 Session 数据文件了:

并且在浏览器中,也可因看到 Cookie 中包含了对应的 PHPSESSID Cookie:

这个就是服务端自动生成并发送到客户端 Cookie 的 Session ID,这些逻辑都有 PHP 底层自动维护,我们不必关心。

4、实现简单的用户登录功能

接下来,我们来基于 Session 在 PHP 代码中实现简单的用户认证。

登录页面

首先将 http/form.html 重命名为 form.php,并加入错误提示(如果有的话),将表单提交链接调整为 login.php

<!DOCTYPE html>
<html>
...
<body>
<div class="container col-4">
    <h1 class="text-center">登录表单</h1>
    <?php if (!empty($error)): ?>
        <div class="alert alert-danger" role="alert">
            <?= $error ?>
        </div>
    <?php endif; ?>
    <form method="post" action="login.php">
        <!-- name form input -->
        <div class="form-group">
            <label for="name">用户名</label>
            <input type="text" class="form-control" name="name" id="name">
        </div>
        <div class="form-group">
            <label for="password">密码</label>
            <input type="password" class="form-control" id="password" name="password">
        </div>
        <button type="submit" class="btn btn-primary">登录</button>
    </form>
</div>
</body>
</html>

用户登录处理

然后我们在 http 目录下新建一个 login.php 编写用户登录处理代码:

<?php
session_save_path('./session');
session_start();

// 模拟数据库数据
$data = [
    [
        'id'  => 1,
        'name' => '测试账号',
        'password' => '123456'
    ],
    [
        'id'  => 2,
        'name' => '学院君',
        'password' => '123456'
    ]
];

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $name = $_POST['name'];
    $password = $_POST['password'];
    if (empty($name) || empty($password)) {
        $error = '用户名/密码不能为空,请重试';
    } else {
        // 简单模拟用户名和密码是否匹配
        $user = array_filter($data, function ($item) use ($name, $password) {
            if ($item['name'] == $name && $item['password'] == $password) {
                return true;
            }
            return false;
        });
        if (!empty($user)) {
            $_SESSION['user'] = array_shift($user);
            header('Location: /user.php');
        } else {
            $error = '用户名/密码不正确,请重试';
        }
    }
}

include_once 'form.php';

开头两行代码还是 Session 初始化设置和启动,然后通过数组模拟数据库用户数据,接下来,如果是 GET 请求,直接通过 include_once 'form.php' 渲染登录表单页面,如果是 POST 请求,则通过 _POST 读取表单输入,如果用户名密码为空或者在「数据库」中不存在,则返回对应的错误提示信息,让用户重新输入并提交表单,否则在 _SESSION['user'] 中设置对应的用户信息,并将用户重定向到 user.php 页面显示登录用户信息。

显示用户信息

最后,我们在 http 下新建 user.php,然后在其中编写登录用户信息展示代码:

<?php
session_save_path('./session');
session_start();

if (isset($_SESSION['user'])) {
    header('Content-Type: application/json');
    $user = $_SESSION['user'];
    echo json_encode($user);
} else {
    header('HTTP/1.1 401 Unauthorized');
    echo '登录后才能访问: <a href="login.php">立即登录</a>';
}

开始还是要初始化和启动 Session(这块代码可以独立出去,然后通过 require 引入,从而方便代码复用),这里为了简化业务逻辑,直接返回包含用户信息的 JSON 数据,如果用户 Session 数据为空,表示该用户尚未登录,返回 401 响应,并提示用户点击登录链接登录。

注:这里,读取 Cookie 中的 Session ID 并与服务端对应的 Session 数据映射由 PHP 系统底层完成,上层业务开发人员不需要关心其细节。

测试用户登录功能

现在,我们访问 http://localhost:9000/user.php,会提示我们需要登录:

点击登录链接,即可进入登录页面,如果输入的登录账号和密码不正确,会提示重新输入:

如果登录成功,则会跳转到 http://localhost:9000/user.php 返回登录用户信息:

感兴趣的同学可以自行实现对应的用户退出逻辑(清除保存用户登录信息的 Session 即可)。

小结

至此,我们就完成了 PHP 中 Web 开发(HTTP 编程)相关的所有基础知识的介绍,包括服务器、请求处理、HTTP响应、Cookie 和 Session,再结合之间的 PHP 基础知识、面向对象编程、数据库操作,我们就已经可以开发出常见的 Web 应用了,从下篇教程开始,我们将结合上述基础知识编写一个简单 PHP Web 框架(MVC 模式),有了这个过渡,相信大家再去看 Laravel 的设计和实现就更加得心应手了。

本文分享自微信公众号 - 学院君的后花园(geekacademy),作者:学院君

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-08-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 基于 gorilla/sessions 在 Go 语言中管理 Session

    Go 语言官方提供的 http 包虽然对 HTTP 编程提供了丰富的 API,但是没有提供官方的 Session 实现。如果在 Web 应用中使用到了 Sess...

    学院君
  • 通过 PHP 原生代码实现 HTTP 路由器

    上篇教程学院君给大家演示了如何基于 Symfony 的 HTTP Foundation 组件封装 HTTP 请求和响应类,今天,我们在此基础上编写简单的 HTT...

    学院君
  • 在博客后台为内容模块实现增删改查功能

    作为 PHP 博客实战项目的终结篇,我们将在后台管理系统为专辑、文章、消息模块添加增删改查功能,来完成内容生产和消费的闭环。

    学院君
  • 基于ZooKeeper的分布式Session实现

    用户1263954
  • 探索式测试,到底应该如何开展?

    对于探索式测试的具体执行层面,我们会采用一种称之为Session-Based Testing management(简称SBTM)的方法来进行测试。关于SBTM...

    测试小兵
  • Cookie禁用了,Session还能用吗?详解

    Cookie与 Session,一般认为是两个独立的东西,Session采用的是在服务器端保持状态的方案,而Cookie采用的是在客户端保持状态的方案。但为什么...

    joshua317
  • 什么是Session共享及实现的方法

    image.png 当网站业务规模和访问量的逐步增大,原本由单台服务器、单个域名组成的网站架构可能已经无法满足发展需要 此时会购买更多的服务器,并且以频道化的...

    dys
  • 状态管理-Session

    qubianzhong
  • Infor ERP LN Correct Purchase Order (History) Amount – tdcor0019m000

    自从用了ERP LN之后,发现很多Session从Menu里面拿掉了,所以不少有用的Session明明存在,却不能很容易找到。上次是财务的Rebuild Ope...

    崔文远TroyCui
  • 微服务架构下分布式Session管理

    一、应用架构变迁下的Session管理 1.1 单体架构 1.2 分布式架构 1.3 微服务架构 二、微服务架构下分布...

    yuanyi928

扫码关注云+社区

领取腾讯云代金券