Blogger Information
Blog 57
fans 3
comment 0
visits 59782
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
PHP基础-会话控制和登录小实战
岂几岂几
Original
886 people have browsed it

会话控制和登录小实战

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...判断来得快

Correcting teacher:天蓬老师天蓬老师

Correction status:qualified

Teacher's comments:第一: 前端的代码只需要html结构就可以不必提交css 第二: 类中的代码注释太少, 特别是每个方法前, 必须要有说明
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!