# :-: 一、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依賴管理工具