# :-: 一、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>';
}
```
- 序言
- PHP基础
- 认识PHP
- 环境安装
- PHP语法
- 流程控制
- PHP数组
- PHP函数
- PHP类与对象
- PHP命名空间
- PHP7新特性
- PHP方法库
- PHP交互
- 前后端交互
- 项目常规开发流程
- MySQL数据库
- 会话控制
- Ajax分页技术
- 细说函数
- 类与对象
- 对象进阶
- 类与对象进阶
- OOP面向对象
- 设计模式
- 路由与模板引擎
- 异常类
- PHP爬虫
- PHP抓取函数
- PHP匹配函数
- 正则表达式
- PHP字符串函数
- 抓取实战
- PHP接口
- 了解接口
- PHP插件
- PHPSpreadsheet
- ThinkPHP6
- 安装
- 架构
- 数据库
- 数据库操作
- 视图
- 模版
- 模型
- 杂项
- 命令行
- 交互
- 微信小程序
- 介绍
- 配置
- 组件
- 交互
- API
- 其他知识
- 百度小程序
- 介绍
- 配置
- 组件
- 交互
- API
- 其他知识
- Linux
- 服务器上线流程
- 安装svn
- MySQL
- 认识MySQL
- MySQL函数
- 杂项
- composer依赖管理工具