博客列表 >PHP基础-会话控制和登录小实战

PHP基础-会话控制和登录小实战

岂几岂几
岂几岂几原创
2020年05月12日 01:39:55885浏览

会话控制和登录小实战

1. 会话控制

  • HTTP 是基于无连接的网络协议, 每一次访问, 对于服务器来说, 都是全新的

  • 有两个地方可以实现多次请求之间共享数据:

    1. 保存到浏览器中的叫: cookie;

    2. 保存到服务器中的叫: session;


COOKIE操作

  • 创建COOKIE: 使用setcookie()函数.

    • 使用语法:

      1. bool setcookie (
      2. string $名字
      3. [, string $值]
      4. [, int $过期时间 = 0]
      5. [, string $路径]
      6. [, string $域名]
      7. [, bool $安全 = false]
      8. [, bool $http只读 = false]
      9. );
    • 参数含义:

      1. $名字 必需。规定 cookie 的名称。
      2. $值 可选。规定 cookie 的值。
      3. $有效期 可选。规定 cookie 的有效期。要记住,是time() + 有效期秒数. 值为0则表示永久有效。值为负数则表示跟session生命周期一样。
      4. $路径 可选。规定 cookie 的服务器路径。
      5. $域名 可选。规定 cookie 的域名。
      6. $安全 可选。规定是否通过安全的 HTTPS 连接来传输 cookie。
      7. $http安读 可选。如果true,那么js就无法读取改cookie,增加安全性。
    • 举例:

      1. setcookie('loginuser', 'zhangsan', time() + 60 * 60 * 24, '/');
      2. setcookie('manager', 'admin', time() + 60 * 20, '/admin');
  • 获取COOKIE的值: 通过操作超全局数组$_COOKIE实现. 假设COOKIE键名为$cookieName, 则获取其值: $_COOKIE[$cookieName].

  • 修改COOKIE的值:

    • 方法1: 跟取值类似. 假设COOKIE键名为$cookieName, 则修改其值: $_COOKIE[$cookieName] = 新值.

    • 方法2: 相当于使用setcookie()函数再”覆盖创建”一次同键名的COOKIE.

  • 删除COOKIE: 就是用setcookie()给被销毁的cookie设置一个比当前时间早的时间,如:time() - 1;

一个特殊的COOKIE: PHPSESSID

3. SESSION

SESSION操作

  • 在PHP中session的操作就是操作$_SESSION超全局数组。

  • 开始操作前要启用session:session_start().

  • 将数据保存到SESSION中: $_SESSION['key1'] = "value1".

  • 删除单个session数据:用unset。删除全部session数据:session_destroy().

4. 登录小实战

  • 创建库表
  1. DROP DATABASE IF EXISTS `phpedu`;
  2. CREATE DATABASE `phpedu` /*!40100 DEFAULT CHARACTER SET utf8 */;
  3. USE `phpedu`;
  4. DROP TABLE IF EXISTS `users`;
  5. CREATE TABLE `users` (
  6. `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  7. `username` varchar(50) NOT NULL,
  8. `password` varchar(50) NOT NULL,
  9. `realname` varchar(50) NOT NULL,
  10. `sex` int(1) NOT NULL DEFAULT '0',
  11. `in_use` int(1) NOT NULL DEFAULT '1',
  12. `create_time` int(11) NOT NULL,
  13. `update_time` int(11) NOT NULL,
  14. PRIMARY KEY (`id`)
  15. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  • 创建初始数据

  • 页面文件(php/html)

    • 首页(index.php)

      1. <!DOCTYPE html>
      2. <html lang="en">
      3. <head>
      4. <meta charset="UTF-8">
      5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
      6. <title>登录小实战</title>
      7. <style>
      8. @import 'css/global.css';
      9. @import 'css/index.css';
      10. </style>
      11. </head>
      12. <?php
      13. require('UserStorage.php');
      14. // $userStorage = new UserStorage(1);
      15. $userStorage = new UserStorage(2);
      16. ?>
      17. <body>
      18. <!-- <header> -->
      19. <nav class="top-bar">
      20. <span>LOGO</span>
      21. <?php if ($userStorage->isLogin()) : ?>
      22. <div class="user-info">
      23. <span>你好, <?php echo $userStorage->getUserInfo()['realname'] ?? '没登录' ?></span>
      24. <a href="doBusiness.php?action=logout">注销</a>
      25. </div>
      26. <?php else : ?>
      27. <div class="user-opra">
      28. <a href="login.html">登录</a>
      29. <a href="register.html">注册</a>
      30. </div>
      31. <?php endif; ?>
      32. </nav>
      33. <!-- </header> -->
      34. </body>
      35. </html>
    • 注册页(register.html)

      1. <!DOCTYPE html>
      2. <html lang="en">
      3. <head>
      4. <meta charset="UTF-8">
      5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
      6. <title>用户注册</title>
      7. <style>
      8. @import 'css/global.css';
      9. @import 'css/register.css';
      10. </style>
      11. </head>
      12. <body>
      13. <form action="doBusiness.php?action=register" method="post">
      14. <section class="register-box">
      15. <div class="register-title">
      16. <span>注册新用户</span>
      17. </div>
      18. <div class="register-content">
      19. <div class="register-item">
      20. <label for="username">用户名:</label>
      21. <input type="text" name="username" id="username" autofocus required>
      22. </div>
      23. <div class="register-item">
      24. <label for="password">密码:</label>
      25. <input type="password" name="password" id="password" required>
      26. </div>
      27. <div class="register-item">
      28. <label for="repassword">确认密码:</label>
      29. <input type="password" name="repassword" id="repassword" required>
      30. </div>
      31. <div class="register-item">
      32. <label for="realname">姓名</label>
      33. <input type="text" name="realname" id="realname" required>
      34. </div>
      35. <div class="register-item">
      36. <label for="sex_2">性别</label>
      37. <div class="radio-item"><input type="radio" name="sex" id="sex_0" value="0"><label
      38. for="sex_0"></label>
      39. </div>
      40. <div class="radio-item"><input type="radio" name="sex" id="sex_1" value="1"><label
      41. for="sex_1"></label>
      42. </div>
      43. <div class="radio-item"><input type="radio" name="sex" id="sex_2" value="2" checked><label
      44. for="sex_2">保密</label></div>
      45. </div>
      46. <div class="register-item">
      47. <button type="submit">提交</button>
      48. </div>
      49. </div>
      50. <div class="goto-login">
      51. <a href="login.html">已有账号, 去登录 >></a>
      52. </div>
      53. </section>
      54. </form>
      55. </body>
      56. </html>
    • 登录页(login.html)

      1. <!DOCTYPE html>
      2. <html lang="en">
      3. <head>
      4. <meta charset="UTF-8" />
      5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      6. <title>用户登陆</title>
      7. <style>
      8. @import "css/global.css";
      9. @import "css/login.css";
      10. </style>
      11. </head>
      12. <body>
      13. <form action="doBusiness.php?action=login" method="post">
      14. <section class="login-box">
      15. <div class="login-title">
      16. <span>用户登录</span>
      17. </div>
      18. <div class="login-content">
      19. <div class="login-item">
      20. <label for="username">用户名:</label>
      21. <input type="text" name="username" id="username" required autofocus />
      22. </div>
      23. <div class="login-item">
      24. <label for="password">密码:</label>
      25. <input type="password" name="password" id="password" />
      26. </div>
      27. <div class="login-item">
      28. <button type="submit">登陆</button>
      29. </div>
      30. </div>
      31. <div class="goto-register">
      32. <a href="register.html">还没有账号?赶紧去注册一个吧 >></a>
      33. </div>
      34. </section>
      35. </form>
      36. </body>
      37. </html>
  • css文件

    • global.css

      1. * {
      2. padding: 0;
      3. margin: 0;
      4. box-sizing: border-box;
      5. }
      6. html {
      7. font-family: Helvetica, Geneva, Verdana, Arial;
      8. }
      9. body {
      10. width: 100vw;
      11. height: 100vh;
      12. }
    • index.css

      1. .top-bar {
      2. height: 60px;
      3. width: 100vw;
      4. background-color: #ccc;
      5. padding: 0 20px;
      6. display: flex;
      7. flex-flow: row nowrap;
      8. justify-content: space-between;
      9. align-items: center;
      10. }
      11. .top-bar>:first-child {
      12. font-size: 30px;
      13. }
      14. .top-bar>:last-child>a {
      15. color: #333;
      16. text-decoration: none;
      17. margin-left: 20px;
      18. }
      19. .top-bar>:last-child>a:hover {
      20. color: red;
      21. }
    • register.css

  1. body {
  2. display: table-cell;
  3. vertical-align: middle;
  4. background: #fafafa;
  5. }
  6. .register-box {
  7. border: 1px solid #ddd;
  8. width: 340px;
  9. height: 340px;
  10. margin: 0 auto;
  11. background: white;
  12. padding: 10px;
  13. }
  14. .register-box>.register-title {
  15. height: 40px;
  16. line-height: 30px;
  17. padding: 0 20px;
  18. font-size: 20px;
  19. border-bottom: 1px solid #ddd;
  20. color: #999;
  21. }
  22. .register-box>.register-content {
  23. display: flex;
  24. flex-flow: column nowrap;
  25. justify-content: start;
  26. align-items: start;
  27. padding: 10px;
  28. }
  29. .register-box>.register-content>.register-item {
  30. height: 40px;
  31. line-height: 40px;
  32. }
  33. .register-box>.register-content>.register-item>label:first-of-type {
  34. display: inline-block;
  35. width: 80px;
  36. color: #999;
  37. text-align: justify;
  38. }
  39. .register-box>.register-content>.register-item input {
  40. border: 1px solid #ddd;
  41. height: 32px;
  42. border-radius: 5px;
  43. width: 200px;
  44. }
  45. .register-box>.register-content>.register-item:nth-last-child(2) {
  46. display: flex;
  47. flex-flow: row wrap;
  48. justify-content: left;
  49. align-content: center;
  50. }
  51. .register-box>.register-content>.register-item:nth-last-child(2) input {
  52. width: 30px;
  53. vertical-align: middle;
  54. color: #999;
  55. height: unset;
  56. }
  57. .register-box>.register-content>.register-item:nth-last-child(2) input:hover {
  58. cursor: pointer;
  59. }
  60. .register-box>.register-content>.register-item:nth-last-child(2) label {
  61. color: #999;
  62. }
  63. .register-box>.register-content>.register-item:nth-last-child(2) label:hover {
  64. cursor: pointer;
  65. }
  66. button {
  67. border: none;
  68. height: 30px;
  69. width: 280px;
  70. }
  71. button:hover {
  72. background-color: #ccc;
  73. cursor: pointer;
  74. color: orangered;
  75. }
  76. .goto-login {
  77. margin-top: 40px;
  78. text-align: center;
  79. }
  80. .goto-login>a {
  81. color: orangered;
  82. text-decoration: none;
  83. }
  84. .goto-login>a:hover {
  85. cursor: pointer;
  86. color: darkgreen;
  87. }
  1. - login.css
  1. body {
  2. display: table-cell;
  3. vertical-align: middle;
  4. background-color: #fafafa;
  5. }
  6. .login-box {
  7. width: 340px;
  8. height: 220px;
  9. background-color: #fff;
  10. margin: 0 auto;
  11. padding: 10px;
  12. }
  13. .login-box > .login-title {
  14. height: 40px;
  15. line-height: 30px;
  16. font-size: 1.5rem;
  17. text-align: center;
  18. color: #aaa;
  19. border-bottom: 1px solid #ddd;
  20. }
  21. .login-box > .login-content {
  22. display: flex;
  23. flex-flow: column nowrap;
  24. padding: 10px;
  25. justify-content: start;
  26. align-items: flex-start;
  27. color: #aaa;
  28. }
  29. .login-box > .login-content > .login-item {
  30. height: 40px;
  31. line-height: 40px;
  32. vertical-align: middle;
  33. width: 100%;
  34. }
  35. .login-box > .login-content > .login-item > label {
  36. display: inline-block;
  37. width: 80px;
  38. text-align-last: justify;
  39. }
  40. .login-box > .login-content > .login-item > input {
  41. height: 32px;
  42. border: 1px solid #aaa;
  43. border-radius: 5px;
  44. width: 200px;
  45. }
  46. .login-box > .login-content > .login-item > button {
  47. border: none;
  48. height: 30px;
  49. line-height: 30px;
  50. width: 100%;
  51. margin-top: 30px;
  52. color: #333;
  53. }
  54. .login-box > .login-content > .login-item > button:hover {
  55. background-color: #aaa;
  56. cursor: pointer;
  57. color: orangered;
  58. }
  59. .goto-register {
  60. margin-top: 50px;
  61. text-align: center;
  62. }
  63. .goto-register>a {
  64. color: orangered;
  65. text-decoration: none;
  66. }
  67. .goto-register>a:hover {
  68. cursor: pointer;
  69. color: darkgreen;
  70. }
  • PHP脚本

    • 请求分发类doBusiness.php
  1. <?php
  2. require('../../out.php');
  3. require('UserStorage.php');
  4. require('UserLogin.php');
  5. // $userStorage = new UserStorage(1);
  6. $userStorage = new UserStorage(2);
  7. try {
  8. $pdo = new PDO('mysql:host=localhost;dbname=phpedu;charset=utf8;port=3306', 'root', 'root');
  9. } catch (Exception $ex) {
  10. echobr('系统内部错误');
  11. die;
  12. }
  13. // 处理用户表相关操作
  14. $action = $_GET['action'];
  15. $userLogin = new UserLogin($pdo, $userStorage);
  16. switch ($action) {
  17. case 'register':
  18. $userLogin->doRegister();
  19. break;
  20. case 'login':
  21. $userLogin->doLogin();
  22. break;
  23. case 'logout':
  24. $userLogin->doLogout();
  25. break;
  26. default:
  27. echo "<script>alert('无法处理的请求');window.location = '/0508/index.php';</script>";
  28. }
  1. - 会话管理类UserStorage.php
  1. <?php
  2. class UserStorage
  3. {
  4. /* 1=cookie; 2=session */
  5. public $storageType = 1;
  6. public function __construct(int $storageType)
  7. {
  8. try {
  9. if ($storageType !== 1 && $storageType !== 2) {
  10. throw new Exception("无效的存储类型");
  11. }
  12. $this->storageType = $storageType;
  13. } catch (Exception $e) {
  14. echobr($e->getMessage());
  15. die;
  16. }
  17. }
  18. public function getUserInfo()
  19. {
  20. if (!$this->isLogin()) {
  21. return [];
  22. }
  23. if ($this->storageType === 1) {
  24. return unserialize($_COOKIE['loginUser']);
  25. }
  26. session_start();
  27. return unserialize($_SESSION['loginUser']);
  28. }
  29. public function rmUserInfo()
  30. {
  31. if ($this->storageType === 1) {
  32. setcookie('loginUser', null, time() - 3600 * 24, '/');
  33. } else {
  34. session_start();
  35. unset($_SESSION['loginUser']);
  36. }
  37. }
  38. public function saveUserInfo($userStr)
  39. {
  40. if ($this->storageType === 1) {
  41. $this->saveUserInfo2Cookie($userStr);
  42. } else {
  43. $this->saveUserInfo2Session($userStr);
  44. }
  45. }
  46. public function saveUserInfo2Cookie($userStr)
  47. {
  48. setcookie('loginUser', $userStr, time() + 3600 * 24, '/');
  49. }
  50. public function saveUserInfo2Session($userStr)
  51. {
  52. session_start();
  53. $_SESSION['loginUser'] = $userStr;
  54. }
  55. public function isLogin()
  56. {
  57. if ($this->storageType === 1) {
  58. return $this->isLoginInCookie();
  59. }
  60. return $this->isLoginInSession();
  61. }
  62. public function isLoginInCookie()
  63. {
  64. if (isset($_COOKIE['loginUser']) && !empty($_COOKIE['loginUser'])) {
  65. return true;
  66. }
  67. return false;
  68. }
  69. public function isLoginInSession()
  70. {
  71. session_start();
  72. if (isset($_SESSION['loginUser']) && !empty($_SESSION['loginUser'])) {
  73. return true;
  74. }
  75. return false;
  76. }
  77. }
  1. - 登录相关操作类:UserLogin.php
  1. <?php
  2. require_once('UserStorage.php');
  3. class UserLogin
  4. {
  5. private $pdo;
  6. private $userStorage;
  7. public function __construct(PDO $pdo, UserStorage $userStorage)
  8. {
  9. $this->pdo = $pdo;
  10. $this->userStorage = $userStorage;
  11. }
  12. public function doRegister()
  13. {
  14. /* 解构post请求中的变量 */
  15. extract($_POST);
  16. // 数据验证
  17. if (strlen($username) < 3 || strlen($username) > 20) {
  18. echobr("<script>alert('用户名长度需在6-20位之间');window.history.go(-1);</script>");
  19. exit;
  20. }
  21. if (strlen($password) < 6 || strlen($password) > 15) {
  22. echobr("<script>alert('密码长度需在6-15位之间');window.history.go(-1);</script>");
  23. exit;
  24. }
  25. if ($password !== $repassword) {
  26. echobr("<script>alert('两次输入的密码不一致');window.history.go(-1);</script>");
  27. exit;
  28. }
  29. // 用户名验证
  30. $sql = 'SELECT * FROM `users` WHERE `username` = :username';
  31. $stmt = $this->pdo->prepare($sql);
  32. $stmt->execute(['username' => $username]);
  33. if ($stmt->rowCount() > 0) {
  34. echobr("<script>alert('用户名已被使用');window.history.go(-1);</script>");
  35. exit;
  36. }
  37. // 保存新用户
  38. $sql = 'INSERT `users` SET `username` = :username, `password` = :pswd, `realname` = :realname, `sex` = :sex, `update_time` = :update_time, `create_time` = :create_time';
  39. $stmt = $this->pdo->prepare($sql);
  40. $stmt->execute(['username' => $username, 'pswd' => md5($password), 'realname' => $realname, 'sex' => $sex, 'update_time' => time(), 'create_time' => time()]);
  41. dumpbr($stmt->debugDumpParams());
  42. if ($stmt->rowCount() === 1) {
  43. echobr("<script>alert('注册成功');window.location='/0508/login/index.php'</script>");
  44. } else {
  45. echobr($stmt->errorInfo());
  46. // echobr("<script>alert('注册失败, 请重试');window.history.go(-1);</script>");
  47. echobr("<script>alert('注册失败, 请重试');</script>");
  48. }
  49. }
  50. public function doLogin()
  51. {
  52. // 解构参数
  53. extract($_POST);
  54. // 判断是不是已登陆
  55. if ($this->userStorage->isLogin()) {
  56. echobr("<script>alert('请不要重复登陆');window.location='/0508/login/index.php'</script>");
  57. exit;
  58. }
  59. // 查询用户信息
  60. $sql = "SELECT * FROM `users` WHERE `username` = :username";
  61. $stmt = $this->pdo->prepare($sql);
  62. $stmt->execute(['username' => $username]);
  63. if ($stmt->rowCount() < 1) {
  64. echobr("<script>alert('用户名不存在');window.history.go(-1);</script>");
  65. exit;
  66. }
  67. $user = $stmt->fetch(PDO::FETCH_ASSOC);
  68. if (md5($password) !== $user['password']) {
  69. echobr("<script>alert('密码不正确');window.history.go(-1);</script>");
  70. exit;
  71. }
  72. // 去掉密码
  73. unset($user['password']);
  74. $userStr = serialize($user);
  75. // 存到cookie或session中
  76. $this->userStorage->saveUserInfo($userStr);
  77. // 跳转回首页
  78. echobr("<script>alert('登陆成功');window.location='/0508/login/index.php'</script>");
  79. }
  80. public function doLogout()
  81. {
  82. $this->userStorage->rmUserInfo();
  83. echobr("<script>alert('注销成功');window.location='/0508/login/index.php';</script>");
  84. }
  85. }

运行效果:

  • 首页

  • 注册页

  • 登录页

  • 登陆成功

  • 注销成功

学习心得

  • cookie和session个人把它们看成是在不同的请求之间共享数据的两个池子, 一个放在客户端(浏览器), 一个放在服务器端. 可以把一些不太敏感的数据放到cookie中, 可以减少服务器的性能消耗. 而一些比较敏感的数据, 类似用户积分等, 放在session中似乎更安全一些.

  • 登录小实战, 似乎是自己抽象能力不够强, 都是把所有的业务逻辑”按流程”写完后, 才封装整理成相应的操作类. 而数据库操作类, 感觉不封装反而使用起来更灵活一些. 属性过滤器的用法较简单, 但是因为过滤器的种类太多, 相关参数也很杂, 对于初学者, 使用它还没有使用if...else...判断来得快

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议