:-: 一、http 协议


:-: 二、COOKIE

# 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_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


:-: 五、COOKIE实战

创建数据库表

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
$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
// 为简化程序, 使用了一个中间层(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
// 请求派发器: 前端控制器
// 功能就是获取到用户的请求, 并调用不同的脚本进行处理和响应

// 连接数据库
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
	// 防止用户重复登录
	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
// 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
// 必须在用户已经登录的情况下再退出
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实战

首页文件:index.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
// 只需要在该脚本中打开会话即可, 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
	// 防止用户重复登录
	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
// 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
// 必须在用户已经登录的情况下再退出
if (isset($_SESSION['name'])) {
	session_destroy();
	echo '<script>alert("退出成功");location.assign("index.php");</script>';
} else {
	// 要求用户先登录
	echo '<script>alert("请先登录");location.assign("login.php");</script>';
}