🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# :-: 一、http 协议 * http是无状态的,每个页面完全独立,无法通信 * http无法跟踪当前访问者的,无法提供个性化的定制服务,例如登录,购物车等 * 有必要在多个页面之间存储一些公共变量,保存访问者的信息,就显示非常有必要 ***** # :-: 二、COOKIE * 服务器对用户访问的跟踪手段 * `$_COOKIE`: 超全局变量数组 * `setcookie()`: 设置客户端cookie * 常用操作: 创建/读取/更新/删除 * 浏览器开发者工具,application中查看`COOKIE` ```php # 1、设置 setcookie('id',1); // 可设置过期时间,默认关闭页面自动消除 // 设置user_id变量,在浏览器中一分钟后失效 setcookie('name', '欧阳克', time() + 60); # 2、读取 // 需要刷新二次,才可以获取到cookie,原因是 // 第一次刷新,是将cookie写入到客户端, 即写操作 // 第二次刷新,是将写入到客户端的cookie数据读出来,即读操作 echo 'id = '. $_COOKIE['id']. '<br>'; echo 'name = '. $_COOKIE['name']. '<br>'; // 如果想在一个cookie变量可存储多个值,可以使用数组语法 // 60*60表示1小时, 60*60*24表示1天 setcookie('user[id]', '2', time() + 60 * 60 * 24); setcookie('user[name]', '欧阳克', time() + 60 * 60 * 24); setcookie('user[email]', 'a@oyk.cn', time() + 60 * 60 * 24); if (isset($_COOKIE['user'])) { foreach ($_COOKIE['user'] as $key => $value) { echo "{$key} => {$value} <br>"; } } # 3、更新 if ($_COOKIE['id']) { $_COOKIE['id'] = 800; } echo 'id = '. $_COOKIE['id']; # 4、删除 unset($_COOKIE['username']); // 函数删除 setcookie('username', '', time() - 3600); // 设置一个已经过期的持续时间 ``` ***** # :-: 三、SESSION * `session_start()`: 启动新会话或者重用现有会话 * `session_id()`: 获取/设置当前会话 ID * `session_save_path()`: 读取/设置当前会话的保存路径 * `session_encode()`: 将当前会话数据编码为一个字符串 * `session_decode`: 解码会话数据 * `session_destroy()`: 销毁一个会话中的全部数据,仅清空而已 * `session_unset()`: 释放所有的会话变量 * `session_reset()`: 回滚到上一次的会话 **注意:** 必须先执行`session_start()`开启会话才生效,且之前不能有输出 ```php // 开启一个会话(之前不能有输出) // session_start()自动设置客户端的session_id,或重启启用一个已存在的会话 session_start(); // 刷新页面, 打开application可以查看到COOKIE里有PHPSESSID,适用于根路径 // 查看服务器上的sesscion会话存储的路径位置 // 到该路径下可看到一个sess_为前缀,后跟session_id的文件名 echo session_save_path(); echo '<hr>'; // 1、设置 $_SESSION['id'] = 3; $_SESSION['name'] = '欧阳克'; // 2、读取 echo 'id = '. $_SESSION['id']. '<br>'; echo 'name = '. $_SESSION['name']. '<br>'; // 3、清除 session_unset(); // 会话内容清空,但会话文件'sess_******'仍在 session_destroy(); // 会话内容清空,会话文件删除,但客户端的cookie仍在,即会话仍在,还能重启 // 可以session_destroy()后, 再调用setcookie()清除掉客户端的session_id,就完全清除了会话 setcookie('PHPSESSID','',time()-3600,'/'); ``` ***** # :-: 四、COOKIE与SESSION * 1. cookie与session是php中非常有效的在多页面间跟踪用户的手段 * 2. cookie是将用户信息保存在浏览器端,因为浏览器的限制,容量有限,且并不安全 * 3. session,也叫会话,是将用户信息保存到服务器端,容量更大,并且非常安全 * 4. 其实session也是基于cookie的,将标识用户身份的SESSION_ID保存在客户端 * 5. 所以cookie与session密不可分,尽管在操用session时,cookie似乎感觉不到 ***** # :-: 五、COOKIE实战 * 以用户登陆为例,使用技术有: * 数据库pdo操作 * 请求派发器 * 验证(登陆、未登陆、重复登陆) > 创建数据库表 ```php CREATE TABLE `user` ( `uid` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `phone` varchar(20) NOT NULL DEFAULT '' COMMENT '手机号', `name` varchar(50) NOT NULL DEFAULT '' COMMENT '姓名', `pwd` varchar(32) NOT NULL DEFAULT '' COMMENT '密码', `age` int(3) unsigned NOT NULL DEFAULT '18' COMMENT '年龄', `sex` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '性别,值为1时是男性,值为2时是女性,值为0时是未知', `status` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '1为正常,0为禁止', `last_time` int(11) unsigned DEFAULT '0' COMMENT '最后登录时间', PRIMARY KEY (`uid`) USING BTREE ) ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=utf8 COMMENT='用户--用户信息表'; INSERT INTO `user` VALUES (1, '18011112222', '欧阳克', 'e10adc3949ba59abbe56e057f20f883e', 18, 1, 1, 1561125595); ``` > 创建数据库连接文件:connect.php ```php <?php $db = [ 'type' => 'mysql', 'host' => 'localhost', 'dbname' => 'php', 'username' => 'root', 'password' => 'root' ]; $dsn = "{$db['type']}:host={$db['host']};dbname={$db['dbname']}"; $username = $db['username']; $password = $db['password']; try { $pdo = new PDO($dsn, $username, $password); } catch (PDOException $e) { die('连接失败' . $e->getMessage()); } ``` > 首页文件:index.php > 先展示未登陆功能 ```php <?php // 为简化程序, 使用了一个中间层(dispatch.php): 请求派发器,类似于框架的控制器, 对用户的请求进行集中处理 // 1: 已登录: 显示出用户的登录信息, 显示退出按钮 if (isset($_COOKIE['name']) { echo '用户: ' . $_COOKIE['name'] . '已登录<br>'; echo '<a href="dispatch.php?action=logout">退出</a>'; } else { // 2. 未登录,就跳转到登录页面 echo '<a href="dispatch.php?action=login">请登录</a>'; } ``` > 派发器:dispatch.php ```php <?php // 请求派发器: 前端控制器 // 功能就是获取到用户的请求, 并调用不同的脚本进行处理和响应 // 连接数据库 require __DIR__ . '/connect.php'; // 获取请求参数 $action = isset($_GET['action']) ? $_GET['action'] : 'login'; $action = htmlentities(strtolower(trim($action))); // 请求分发 switch ($action) { // 1. 登录页面 case 'login': // 加载登录表单 include __DIR__ . '/login.php'; break; // 2. 验证登录 case 'check': include __DIR__ . '/check.php'; break; // 3. 退出登录 case 'logout': include __DIR__ . '/logout.php'; break; // 默认操作 default: header('Location: index.php'); echo '<script>location.assign("index.php");</script>'; } ``` > 登陆页面:login.php ```php <?php // 防止用户重复登录 if (isset($_COOKIE['name'])) { echo '<script>alert("不要重复登录");location.assign("index.php");</script>'; } ?> <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户登录</title> </head> <body> <h3>用户登录</h3> <form action="dispatch.php?action=check" method="post" onsubmit="return isEmpty();"> <p> <label for="phone">手机号:</label> <input type="phone" name="phone" id="phone"> </p> <p> <label for="password">密码:</label> <input type="password" name="password" id="password"> </p> <p> <button>提交</button> </p> </form> <script> function isEmpty() { var phone = document.getElementById('phone').value; var password = document.getElementById('password').value; if (phone.length=== 0 || password.length===0) { alert('手机和密码不能为空'); return false; } } </script> </body> </html> ``` > 验证登陆:check.php ```php <?php // 1.判断用户的请求类型是否正确? if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 2.获取表单数据 $phone = $_POST['phone']; $password = sha1($_POST['password']); // 3. 用用户表user.dbf进行验证 $sql = 'SELECT * FROM `user` WHERE `phone` = :phone AND `password` = :password LIMIT 1'; $stmt = $pdo->prepare($sql); $stmt->execute(['phone'=>$phone, 'password'=>$password]); $user = $stmt->fetch(PDO::FETCH_ASSOC); // 4. 判断验证的结果 if (false === $user) { // 验证失败,返回上一下页面 echo '<script>alert("验证失败");history.back();</script>'; die; } // 验证成功,将用户的信息写到cookie setcookie('name', $user['name']); echo '<script>alert("登录成功");location.assign("index.php");</script>'; exit; } else { die('请求类型错误'); } ``` > 退出登陆:logout.php ```php <?php // 必须在用户已经登录的情况下再退出 if (isset($_COOKIE['name'])) { setcookie('name', null, time()-3600); echo '<script>alert("退出成功");location.assign("index.php");</script>'; } else { // 要求用户先登录 echo '<script>alert("请先登录");location.assign("login.php");</script>'; } ``` ***** # :-: 六、SESSION实战 * 数据库继续使用user > 首页文件:index.php ```php <?php //开启会话 session_start(); // 为简化程序, 使用了一个中间层: 请求派发器,类似于框架的控制器, 对用户的请求进行集中处理 // 1: 已登录: 显示出用户的登录信息, 显示退出按钮 if (isset($_SESSION['name']) && $_SESSION['name'] === 'admin') { echo '用户: ' . $_SESSION['name'] . '已登录<br>'; echo '<a href="dispatch.php?action=logout">退出</a>'; } else { // 2. 未登录,就跳转到登录页面 echo '<a href="dispatch.php?action=login">请登录</a>'; } ``` > 派发器:dispatch.php ```php <?php // 只需要在该脚本中打开会话即可, check.php/logout.php/login.php都是由它调用的, 不必重复开启 session_start(); // 连接数据库 require __DIR__ . '/connect.php'; // 获取请求参数 $action = isset($_GET['action']) ? $_GET['action'] : 'login'; $action = htmlentities(strtolower(trim($action))); // 请求分发 switch ($action) { // 1. 登录页面 case 'login': // 加载登录表单 include __DIR__ . '/login.php'; break; // 2. 验证登录 case 'check': include __DIR__ . '/check.php'; break; // 3. 退出登录 case 'logout': include __DIR__ . '/logout.php'; break; // 默认操作 default: header('Location: index.php'); echo '<script>location.assign("index.php");</script>'; } ``` > 登陆页面:login.php ```php <?php // 防止用户重复登录 if (isset($_SESSION['name'])) { echo '<script>alert("不要重复登录");location.assign("index.php");</script>'; } ?> <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户登录</title> </head> <body> <h3>用户登录</h3> <form action="dispatch.php?action=check" method="post" onsubmit="return isEmpty();"> <p> <label for="phone">手机:</label> <input type="phone" name="phone" id="phone"> </p> <p> <label for="password">密码:</label> <input type="password" name="password" id="password"> </p> <p> <button>提交</button> </p> </form> <script> function isEmpty() { var phone = document.getElementById('phone').value; var password = document.getElementById('password').value; if (phone.length=== 0 || password.length===0) { alert('手机和密码不能为空'); return false; } } </script> </body> </html> ``` > 验证登陆:check.php ```php <?php // 1.判断用户的请求类型是否正确? if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 2.获取表单数据 $phone = $_POST['phone']; $password = sha1($_POST['password']); // 3. 用用户表user.dbf进行验证 $sql = 'SELECT * FROM `user` WHERE `phone` = :phone AND `password` = :password LIMIT 1'; $stmt = $pdo->prepare($sql); $stmt->execute(['phone'=>$phone, 'password'=>$password]); $user = $stmt->fetch(PDO::FETCH_ASSOC); // 4. 判断验证的结果 if (false === $user) { // 验证失败,返回上一下页面 echo '<script>alert("验证失败");history.back();</script>'; die; } // 验证成功,将用户的信息写到session $_SESSION['name'] = $user['name']; echo '<script>alert("登录成功");location.assign("index.php");</script>'; exit; } else { die('请求类型错误'); } ``` > 退出登陆:logout.php ```php <?php // 必须在用户已经登录的情况下再退出 if (isset($_SESSION['name'])) { session_destroy(); echo '<script>alert("退出成功");location.assign("index.php");</script>'; } else { // 要求用户先登录 echo '<script>alert("请先登录");location.assign("login.php");</script>'; } ```