PHP会话管理详解:Session与Cookie的实战应用
Orion K Lv6

PHP会话管理详解:Session与Cookie的实战应用

会话管理是Web开发中的重要概念,它让我们能够在HTTP这个无状态协议中维持用户状态。作为一名PHP开发者,我想分享一些关于Session和Cookie的实用知识和最佳实践。

Cookie基础操作

1. Cookie的基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php
// Cookie基本操作示例
echo "=== Cookie基本操作 ===\n";

// 设置Cookie
function setCookieExample() {
// 基本Cookie设置
setcookie("username", "张三", time() + 3600); // 1小时后过期

// 带路径和域名的Cookie
setcookie("user_preference", "dark_theme", time() + 86400, "/", "example.com");

// 安全Cookie(仅HTTPS)
setcookie("secure_token", "abc123", time() + 3600, "/", "", true, true);
// 参数说明:名称、值、过期时间、路径、域名、仅HTTPS、仅HTTP

echo "Cookie已设置\n";
}

// 读取Cookie
function readCookieExample() {
if (isset($_COOKIE['username'])) {
echo "用户名: " . $_COOKIE['username'] . "\n";
} else {
echo "用户名Cookie不存在\n";
}

// 安全地读取Cookie
$username = $_COOKIE['username'] ?? '游客';
echo "当前用户: $username\n";
}

// 删除Cookie
function deleteCookieExample() {
// 通过设置过期时间为过去时间来删除Cookie
setcookie("username", "", time() - 3600);

// 或者使用null值
setcookie("user_preference", null, time() - 3600, "/", "example.com");

echo "Cookie已删除\n";
}

// Cookie工具类
class CookieManager {
private $defaultExpire;
private $defaultPath;
private $defaultDomain;
private $secure;
private $httpOnly;

public function __construct($expire = 3600, $path = "/", $domain = "", $secure = false, $httpOnly = true) {
$this->defaultExpire = $expire;
$this->defaultPath = $path;
$this->defaultDomain = $domain;
$this->secure = $secure;
$this->httpOnly = $httpOnly;
}

public function set($name, $value, $expire = null, $path = null, $domain = null) {
$expire = $expire ?? time() + $this->defaultExpire;
$path = $path ?? $this->defaultPath;
$domain = $domain ?? $this->defaultDomain;

return setcookie($name, $value, $expire, $path, $domain, $this->secure, $this->httpOnly);
}

public function get($name, $default = null) {
return $_COOKIE[$name] ?? $default;
}

public function has($name) {
return isset($_COOKIE[$name]);
}

public function delete($name, $path = null, $domain = null) {
$path = $path ?? $this->defaultPath;
$domain = $domain ?? $this->defaultDomain;

if ($this->has($name)) {
unset($_COOKIE[$name]);
}

return setcookie($name, "", time() - 3600, $path, $domain);
}

public function getAll() {
return $_COOKIE;
}

public function clear() {
foreach ($_COOKIE as $name => $value) {
$this->delete($name);
}
}
}

// 使用Cookie管理器
$cookieManager = new CookieManager(86400); // 24小时过期

// 模拟设置Cookie(在实际Web环境中使用)
echo "Cookie管理器示例:\n";
echo "设置Cookie: " . ($cookieManager->set("user_id", "123") ? "成功" : "失败") . "\n";
echo "设置Cookie: " . ($cookieManager->set("theme", "dark") ? "成功" : "失败") . "\n";

// 模拟读取Cookie
$_COOKIE['user_id'] = '123'; // 模拟Cookie存在
$_COOKIE['theme'] = 'dark';

echo "用户ID: " . $cookieManager->get("user_id", "未知") . "\n";
echo "主题: " . $cookieManager->get("theme", "默认") . "\n";
echo "语言: " . $cookieManager->get("language", "中文") . "\n";

// 检查Cookie是否存在
echo "user_id存在: " . ($cookieManager->has("user_id") ? "是" : "否") . "\n";
echo "email存在: " . ($cookieManager->has("email") ? "是" : "否") . "\n";
?>

2. Cookie安全性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php
// Cookie安全性示例
class SecureCookieManager {
private $encryptionKey;

public function __construct($encryptionKey) {
$this->encryptionKey = $encryptionKey;
}

// 加密Cookie值
private function encrypt($data) {
$cipher = "AES-256-CBC";
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);

$encrypted = openssl_encrypt($data, $cipher, $this->encryptionKey, 0, $iv);

return base64_encode($iv . $encrypted);
}

// 解密Cookie值
private function decrypt($data) {
$cipher = "AES-256-CBC";
$ivlen = openssl_cipher_iv_length($cipher);

$data = base64_decode($data);
$iv = substr($data, 0, $ivlen);
$encrypted = substr($data, $ivlen);

return openssl_decrypt($encrypted, $cipher, $this->encryptionKey, 0, $iv);
}

// 设置加密Cookie
public function setSecure($name, $value, $expire = null) {
$expire = $expire ?? time() + 3600;
$encryptedValue = $this->encrypt($value);

return setcookie($name, $encryptedValue, $expire, "/", "", true, true);
}

// 读取加密Cookie
public function getSecure($name, $default = null) {
if (!isset($_COOKIE[$name])) {
return $default;
}

try {
return $this->decrypt($_COOKIE[$name]);
} catch (Exception $e) {
return $default;
}
}

// 设置签名Cookie(防篡改)
public function setSigned($name, $value, $expire = null) {
$expire = $expire ?? time() + 3600;
$signature = hash_hmac('sha256', $value, $this->encryptionKey);
$signedValue = $value . '.' . $signature;

return setcookie($name, $signedValue, $expire, "/", "", false, true);
}

// 读取签名Cookie
public function getSigned($name, $default = null) {
if (!isset($_COOKIE[$name])) {
return $default;
}

$parts = explode('.', $_COOKIE[$name]);
if (count($parts) !== 2) {
return $default;
}

list($value, $signature) = $parts;
$expectedSignature = hash_hmac('sha256', $value, $this->encryptionKey);

if (hash_equals($expectedSignature, $signature)) {
return $value;
}

return $default;
}

// Cookie完整性验证
public function validateCookie($name, $expectedValue) {
$actualValue = $this->getSigned($name);
return $actualValue !== null && hash_equals($expectedValue, $actualValue);
}
}

// 使用安全Cookie管理器
$secureKey = "your-secret-key-32-characters-long";
$secureCookies = new SecureCookieManager($secureKey);

echo "\n=== 安全Cookie示例 ===\n";

// 模拟设置和读取加密Cookie
echo "设置加密Cookie\n";
$sensitiveData = "用户敏感信息";
echo "原始数据: $sensitiveData\n";

// 在实际应用中,这些操作会设置HTTP响应头
echo "加密后的值: " . base64_encode("模拟加密数据") . "\n";

// 模拟读取
$_COOKIE['encrypted_data'] = base64_encode("模拟加密数据");
echo "解密后的值: 用户敏感信息\n";

// 签名Cookie示例
echo "\n设置签名Cookie\n";
$userData = "user_id=123&role=admin";
echo "原始数据: $userData\n";

$signature = hash_hmac('sha256', $userData, $secureKey);
echo "签名: $signature\n";
echo "签名验证: " . (hash_equals($signature, hash_hmac('sha256', $userData, $secureKey)) ? "通过" : "失败") . "\n";
?>

Session管理

1. Session基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
<?php
// Session基本操作示例
echo "=== Session基本操作 ===\n";

// 启动Session
session_start();

// 设置Session变量
$_SESSION['username'] = '李四';
$_SESSION['user_id'] = 456;
$_SESSION['login_time'] = time();
$_SESSION['permissions'] = ['read', 'write'];

echo "Session已设置\n";

// 读取Session变量
function readSessionExample() {
if (isset($_SESSION['username'])) {
echo "用户名: " . $_SESSION['username'] . "\n";
echo "用户ID: " . $_SESSION['user_id'] . "\n";
echo "登录时间: " . date('Y-m-d H:i:s', $_SESSION['login_time']) . "\n";
echo "权限: " . implode(', ', $_SESSION['permissions']) . "\n";
} else {
echo "用户未登录\n";
}
}

readSessionExample();

// Session工具类
class SessionManager {
private $sessionName;
private $lifetime;

public function __construct($sessionName = 'PHPSESSID', $lifetime = 3600) {
$this->sessionName = $sessionName;
$this->lifetime = $lifetime;

$this->configureSession();
}

private function configureSession() {
// 设置Session配置
ini_set('session.name', $this->sessionName);
ini_set('session.gc_maxlifetime', $this->lifetime);
ini_set('session.cookie_lifetime', $this->lifetime);
ini_set('session.cookie_httponly', 1);
ini_set('session.use_strict_mode', 1);
ini_set('session.cookie_samesite', 'Strict');

// 在HTTPS环境下启用安全Cookie
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
ini_set('session.cookie_secure', 1);
}
}

public function start() {
if (session_status() === PHP_SESSION_NONE) {
return session_start();
}
return true;
}

public function set($key, $value) {
$this->start();
$_SESSION[$key] = $value;
}

public function get($key, $default = null) {
$this->start();
return $_SESSION[$key] ?? $default;
}

public function has($key) {
$this->start();
return isset($_SESSION[$key]);
}

public function remove($key) {
$this->start();
if (isset($_SESSION[$key])) {
unset($_SESSION[$key]);
return true;
}
return false;
}

public function clear() {
$this->start();
$_SESSION = [];
}

public function destroy() {
$this->start();

// 清空Session数组
$_SESSION = [];

// 删除Session Cookie
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
}

// 销毁Session
return session_destroy();
}

public function regenerateId($deleteOldSession = true) {
$this->start();
return session_regenerate_id($deleteOldSession);
}

public function getId() {
$this->start();
return session_id();
}

public function getAll() {
$this->start();
return $_SESSION;
}

public function isActive() {
return session_status() === PHP_SESSION_ACTIVE;
}

// Flash消息(一次性消息)
public function setFlash($key, $message) {
$this->set("_flash_$key", $message);
}

public function getFlash($key, $default = null) {
$flashKey = "_flash_$key";
$message = $this->get($flashKey, $default);
$this->remove($flashKey);
return $message;
}

public function hasFlash($key) {
return $this->has("_flash_$key");
}
}

// 使用Session管理器
$sessionManager = new SessionManager('MY_APP_SESSION', 7200); // 2小时

echo "\n=== Session管理器示例 ===\n";

// 设置Session数据
$sessionManager->set('user_info', [
'id' => 789,
'name' => '王五',
'email' => 'wangwu@example.com',
'role' => 'user'
]);

$sessionManager->set('cart', [
['id' => 1, 'name' => '商品1', 'price' => 99.99],
['id' => 2, 'name' => '商品2', 'price' => 149.99]
]);

// 读取Session数据
$userInfo = $sessionManager->get('user_info');
if ($userInfo) {
echo "用户信息: " . json_encode($userInfo, JSON_UNESCAPED_UNICODE) . "\n";
}

$cart = $sessionManager->get('cart', []);
echo "购物车商品数量: " . count($cart) . "\n";

// Flash消息示例
$sessionManager->setFlash('success', '操作成功完成!');
$sessionManager->setFlash('error', '发生了一个错误');

echo "成功消息: " . $sessionManager->getFlash('success', '无消息') . "\n";
echo "错误消息: " . $sessionManager->getFlash('error', '无消息') . "\n";
echo "再次获取成功消息: " . $sessionManager->getFlash('success', '无消息') . "\n"; // 应该返回'无消息'

// Session信息
echo "Session ID: " . $sessionManager->getId() . "\n";
echo "Session活跃: " . ($sessionManager->isActive() ? '是' : '否') . "\n";
?>

2. 用户认证系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
<?php
// 用户认证系统
class AuthenticationSystem {
private $sessionManager;
private $users; // 模拟用户数据库

public function __construct($sessionManager) {
$this->sessionManager = $sessionManager;

// 模拟用户数据
$this->users = [
'admin' => [
'id' => 1,
'username' => 'admin',
'password' => password_hash('admin123', PASSWORD_DEFAULT),
'role' => 'admin',
'email' => 'admin@example.com'
],
'user1' => [
'id' => 2,
'username' => 'user1',
'password' => password_hash('user123', PASSWORD_DEFAULT),
'role' => 'user',
'email' => 'user1@example.com'
]
];
}

// 用户登录
public function login($username, $password, $rememberMe = false) {
if (!isset($this->users[$username])) {
return ['success' => false, 'message' => '用户不存在'];
}

$user = $this->users[$username];

if (!password_verify($password, $user['password'])) {
return ['success' => false, 'message' => '密码错误'];
}

// 重新生成Session ID防止会话固定攻击
$this->sessionManager->regenerateId();

// 设置Session数据
$this->sessionManager->set('user_id', $user['id']);
$this->sessionManager->set('username', $user['username']);
$this->sessionManager->set('role', $user['role']);
$this->sessionManager->set('login_time', time());
$this->sessionManager->set('last_activity', time());

// 记住我功能
if ($rememberMe) {
$token = $this->generateRememberToken($user['id']);
$this->sessionManager->set('remember_token', $token);

// 设置长期Cookie
setcookie('remember_token', $token, time() + (30 * 24 * 3600), '/', '', false, true);
}

$this->sessionManager->setFlash('success', '登录成功!');

return ['success' => true, 'message' => '登录成功', 'user' => $user];
}

// 用户登出
public function logout() {
// 清除记住我Cookie
if (isset($_COOKIE['remember_token'])) {
setcookie('remember_token', '', time() - 3600, '/', '', false, true);
}

$this->sessionManager->setFlash('info', '您已成功登出');
$this->sessionManager->destroy();

return ['success' => true, 'message' => '登出成功'];
}

// 检查用户是否已登录
public function isLoggedIn() {
if (!$this->sessionManager->has('user_id')) {
// 检查记住我功能
return $this->checkRememberMe();
}

// 检查Session是否过期
$lastActivity = $this->sessionManager->get('last_activity', 0);
$sessionTimeout = 3600; // 1小时

if (time() - $lastActivity > $sessionTimeout) {
$this->logout();
return false;
}

// 更新最后活动时间
$this->sessionManager->set('last_activity', time());

return true;
}

// 获取当前用户信息
public function getCurrentUser() {
if (!$this->isLoggedIn()) {
return null;
}

return [
'id' => $this->sessionManager->get('user_id'),
'username' => $this->sessionManager->get('username'),
'role' => $this->sessionManager->get('role'),
'login_time' => $this->sessionManager->get('login_time')
];
}

// 检查用户权限
public function hasPermission($requiredRole) {
if (!$this->isLoggedIn()) {
return false;
}

$userRole = $this->sessionManager->get('role');

// 简单的角色权限检查
$roleHierarchy = ['user' => 1, 'admin' => 2];

return ($roleHierarchy[$userRole] ?? 0) >= ($roleHierarchy[$requiredRole] ?? 0);
}

// 生成记住我令牌
private function generateRememberToken($userId) {
return hash('sha256', $userId . time() . random_bytes(16));
}

// 检查记住我功能
private function checkRememberMe() {
if (!isset($_COOKIE['remember_token'])) {
return false;
}

$token = $_COOKIE['remember_token'];

// 在实际应用中,应该从数据库验证令牌
// 这里简化处理
if ($this->sessionManager->get('remember_token') === $token) {
return true;
}

return false;
}

// 更改密码
public function changePassword($oldPassword, $newPassword) {
$currentUser = $this->getCurrentUser();
if (!$currentUser) {
return ['success' => false, 'message' => '用户未登录'];
}

$username = $currentUser['username'];
$user = $this->users[$username];

if (!password_verify($oldPassword, $user['password'])) {
return ['success' => false, 'message' => '原密码错误'];
}

// 更新密码(在实际应用中应该更新数据库)
$this->users[$username]['password'] = password_hash($newPassword, PASSWORD_DEFAULT);

$this->sessionManager->setFlash('success', '密码修改成功');

return ['success' => true, 'message' => '密码修改成功'];
}
}

// 使用认证系统
echo "\n=== 用户认证系统示例 ===\n";

$auth = new AuthenticationSystem($sessionManager);

// 模拟登录
echo "=== 登录测试 ===\n";
$loginResult = $auth->login('admin', 'admin123', true);
echo "登录结果: " . json_encode($loginResult, JSON_UNESCAPED_UNICODE) . "\n";

// 检查登录状态
echo "\n=== 登录状态检查 ===\n";
echo "是否已登录: " . ($auth->isLoggedIn() ? '是' : '否') . "\n";

// 获取当前用户
$currentUser = $auth->getCurrentUser();
if ($currentUser) {
echo "当前用户: " . json_encode($currentUser, JSON_UNESCAPED_UNICODE) . "\n";
}

// 权限检查
echo "\n=== 权限检查 ===\n";
echo "是否有用户权限: " . ($auth->hasPermission('user') ? '是' : '否') . "\n";
echo "是否有管理员权限: " . ($auth->hasPermission('admin') ? '是' : '否') . "\n";

// 修改密码
echo "\n=== 修改密码 ===\n";
$changeResult = $auth->changePassword('admin123', 'newpassword123');
echo "修改密码结果: " . json_encode($changeResult, JSON_UNESCAPED_UNICODE) . "\n";

// 登出
echo "\n=== 登出测试 ===\n";
$logoutResult = $auth->logout();
echo "登出结果: " . json_encode($logoutResult, JSON_UNESCAPED_UNICODE) . "\n";

// 再次检查登录状态
echo "登出后是否已登录: " . ($auth->isLoggedIn() ? '是' : '否') . "\n";
?>

3. 购物车系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
<?php
// 购物车系统
class ShoppingCart {
private $sessionManager;
private $cartKey = 'shopping_cart';

public function __construct($sessionManager) {
$this->sessionManager = $sessionManager;
}

// 添加商品到购物车
public function addItem($productId, $name, $price, $quantity = 1) {
$cart = $this->getCart();

if (isset($cart[$productId])) {
// 如果商品已存在,增加数量
$cart[$productId]['quantity'] += $quantity;
} else {
// 添加新商品
$cart[$productId] = [
'id' => $productId,
'name' => $name,
'price' => $price,
'quantity' => $quantity,
'added_time' => time()
];
}

$this->saveCart($cart);
$this->sessionManager->setFlash('success', "商品 {$name} 已添加到购物车");

return true;
}

// 更新商品数量
public function updateQuantity($productId, $quantity) {
$cart = $this->getCart();

if (!isset($cart[$productId])) {
return false;
}

if ($quantity <= 0) {
return $this->removeItem($productId);
}

$cart[$productId]['quantity'] = $quantity;
$this->saveCart($cart);

return true;
}

// 移除商品
public function removeItem($productId) {
$cart = $this->getCart();

if (isset($cart[$productId])) {
$productName = $cart[$productId]['name'];
unset($cart[$productId]);
$this->saveCart($cart);

$this->sessionManager->setFlash('info', "商品 {$productName} 已从购物车移除");
return true;
}

return false;
}

// 清空购物车
public function clear() {
$this->sessionManager->remove($this->cartKey);
$this->sessionManager->setFlash('info', '购物车已清空');
}

// 获取购物车内容
public function getCart() {
return $this->sessionManager->get($this->cartKey, []);
}

// 获取购物车商品数量
public function getItemCount() {
$cart = $this->getCart();
$count = 0;

foreach ($cart as $item) {
$count += $item['quantity'];
}

return $count;
}

// 获取购物车总价
public function getTotal() {
$cart = $this->getCart();
$total = 0;

foreach ($cart as $item) {
$total += $item['price'] * $item['quantity'];
}

return $total;
}

// 检查商品是否在购物车中
public function hasItem($productId) {
$cart = $this->getCart();
return isset($cart[$productId]);
}

// 获取商品详情
public function getItem($productId) {
$cart = $this->getCart();
return $cart[$productId] ?? null;
}

// 保存购物车
private function saveCart($cart) {
$this->sessionManager->set($this->cartKey, $cart);
}

// 获取购物车摘要
public function getSummary() {
$cart = $this->getCart();

return [
'items' => $cart,
'item_count' => $this->getItemCount(),
'total_price' => $this->getTotal(),
'is_empty' => empty($cart)
];
}

// 应用优惠券
public function applyCoupon($couponCode) {
// 模拟优惠券数据
$coupons = [
'SAVE10' => ['type' => 'percentage', 'value' => 10, 'min_amount' => 100],
'SAVE20' => ['type' => 'fixed', 'value' => 20, 'min_amount' => 50]
];

if (!isset($coupons[$couponCode])) {
return ['success' => false, 'message' => '优惠券不存在'];
}

$coupon = $coupons[$couponCode];
$total = $this->getTotal();

if ($total < $coupon['min_amount']) {
return ['success' => false, 'message' => "最低消费金额为 {$coupon['min_amount']} 元"];
}

$discount = 0;
if ($coupon['type'] === 'percentage') {
$discount = $total * ($coupon['value'] / 100);
} else {
$discount = $coupon['value'];
}

$this->sessionManager->set('applied_coupon', [
'code' => $couponCode,
'discount' => $discount,
'type' => $coupon['type'],
'value' => $coupon['value']
]);

return ['success' => true, 'message' => '优惠券应用成功', 'discount' => $discount];
}

// 获取应用的优惠券
public function getAppliedCoupon() {
return $this->sessionManager->get('applied_coupon');
}

// 移除优惠券
public function removeCoupon() {
$this->sessionManager->remove('applied_coupon');
}

// 获取最终价格(含优惠)
public function getFinalTotal() {
$total = $this->getTotal();
$coupon = $this->getAppliedCoupon();

if ($coupon) {
return max(0, $total - $coupon['discount']);
}

return $total;
}
}

// 使用购物车系统
echo "\n=== 购物车系统示例 ===\n";

$cart = new ShoppingCart($sessionManager);

// 添加商品
echo "=== 添加商品 ===\n";
$cart->addItem(1, 'iPhone 14', 5999.00, 1);
$cart->addItem(2, 'MacBook Pro', 12999.00, 1);
$cart->addItem(3, 'AirPods', 1299.00, 2);

// 显示购物车摘要
$summary = $cart->getSummary();
echo "购物车摘要:\n";
echo "商品数量: " . $summary['item_count'] . "\n";
echo "总价: ¥" . number_format($summary['total_price'], 2) . "\n";

// 显示商品详情
echo "\n购物车商品:\n";
foreach ($summary['items'] as $item) {
echo "- {$item['name']}: ¥{$item['price']} x {$item['quantity']} = ¥" .
number_format($item['price'] * $item['quantity'], 2) . "\n";
}

// 应用优惠券
echo "\n=== 应用优惠券 ===\n";
$couponResult = $cart->applyCoupon('SAVE10');
echo "优惠券结果: " . json_encode($couponResult, JSON_UNESCAPED_UNICODE) . "\n";

if ($couponResult['success']) {
echo "优惠金额: ¥" . number_format($couponResult['discount'], 2) . "\n";
echo "最终价格: ¥" . number_format($cart->getFinalTotal(), 2) . "\n";
}

// 更新商品数量
echo "\n=== 更新商品数量 ===\n";
$cart->updateQuantity(3, 1); // 将AirPods数量改为1
echo "更新后商品数量: " . $cart->getItemCount() . "\n";
echo "更新后总价: ¥" . number_format($cart->getTotal(), 2) . "\n";

// 移除商品
echo "\n=== 移除商品 ===\n";
$cart->removeItem(2); // 移除MacBook Pro
echo "移除后商品数量: " . $cart->getItemCount() . "\n";
echo "移除后总价: ¥" . number_format($cart->getTotal(), 2) . "\n";
?>

最佳实践和安全建议

1. Session安全配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?php
// Session安全配置最佳实践
class SecureSessionConfig {
public static function configure() {
// 防止JavaScript访问Session Cookie
ini_set('session.cookie_httponly', 1);

// 在HTTPS环境下启用安全Cookie
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
ini_set('session.cookie_secure', 1);
}

// 设置SameSite属性防止CSRF攻击
ini_set('session.cookie_samesite', 'Strict');

// 启用严格模式
ini_set('session.use_strict_mode', 1);

// 禁用透明Session ID
ini_set('session.use_trans_sid', 0);

// 设置Session垃圾回收
ini_set('session.gc_probability', 1);
ini_set('session.gc_divisor', 100);
ini_set('session.gc_maxlifetime', 3600);

// 设置Session存储路径(可选)
// session_save_path('/path/to/secure/directory');

// 自定义Session名称
session_name('SECURE_SESSION_ID');
}

// Session劫持防护
public static function validateSession() {
if (!isset($_SESSION['user_agent'])) {
$_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'] ?? '';
}

if (!isset($_SESSION['ip_address'])) {
$_SESSION['ip_address'] = $_SERVER['REMOTE_ADDR'] ?? '';
}

// 验证用户代理
if ($_SESSION['user_agent'] !== ($_SERVER['HTTP_USER_AGENT'] ?? '')) {
session_destroy();
return false;
}

// 验证IP地址(可选,可能影响移动用户)
// if ($_SESSION['ip_address'] !== ($_SERVER['REMOTE_ADDR'] ?? '')) {
// session_destroy();
// return false;
// }

return true;
}

// 定期重新生成Session ID
public static function regenerateSessionId() {
if (!isset($_SESSION['last_regeneration'])) {
$_SESSION['last_regeneration'] = time();
}

// 每30分钟重新生成一次Session ID
if (time() - $_SESSION['last_regeneration'] > 1800) {
session_regenerate_id(true);
$_SESSION['last_regeneration'] = time();
}
}
}

// 应用安全配置
SecureSessionConfig::configure();
session_start();

// 验证Session
if (!SecureSessionConfig::validateSession()) {
echo "Session验证失败,可能存在安全风险\n";
exit;
}

// 定期重新生成Session ID
SecureSessionConfig::regenerateSessionId();

echo "Session安全配置已应用\n";
?>

2. 常见问题和解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<?php
// 常见Session和Cookie问题解决方案
class SessionTroubleshooting {

// 问题1: Session数据丢失
public static function debugSessionLoss() {
echo "=== Session数据丢失调试 ===\n";

// 检查Session状态
echo "Session状态: ";
switch (session_status()) {
case PHP_SESSION_DISABLED:
echo "Session被禁用\n";
break;
case PHP_SESSION_NONE:
echo "Session未启动\n";
break;
case PHP_SESSION_ACTIVE:
echo "Session已激活\n";
break;
}

// 检查Session配置
echo "Session保存路径: " . session_save_path() . "\n";
echo "Session名称: " . session_name() . "\n";
echo "Session ID: " . session_id() . "\n";
echo "Session Cookie参数: " . json_encode(session_get_cookie_params()) . "\n";

// 检查Session文件权限
$savePath = session_save_path();
if ($savePath && is_dir($savePath)) {
echo "Session目录可写: " . (is_writable($savePath) ? '是' : '否') . "\n";
}

// 检查垃圾回收设置
echo "垃圾回收概率: " . ini_get('session.gc_probability') . "/" . ini_get('session.gc_divisor') . "\n";
echo "垃圾回收最大生存时间: " . ini_get('session.gc_maxlifetime') . "秒\n";
}

// 问题2: Cookie无法设置
public static function debugCookieIssues() {
echo "\n=== Cookie问题调试 ===\n";

// 检查headers是否已发送
if (headers_sent($file, $line)) {
echo "Headers已发送,无法设置Cookie\n";
echo "Headers发送位置: $file:$line\n";
} else {
echo "Headers未发送,可以设置Cookie\n";
}

// 检查输出缓冲
echo "输出缓冲级别: " . ob_get_level() . "\n";

// 检查Cookie设置
echo "当前Cookie: " . json_encode($_COOKIE, JSON_UNESCAPED_UNICODE) . "\n";

// 测试Cookie设置
$testResult = setcookie('test_cookie', 'test_value', time() + 3600);
echo "测试Cookie设置: " . ($testResult ? '成功' : '失败') . "\n";
}

// 问题3: Session在子域名间共享
public static function setupCrossDomainSession($domain) {
echo "\n=== 跨域Session设置 ===\n";

// 设置Cookie域名
ini_set('session.cookie_domain', $domain);

// 设置Cookie路径
ini_set('session.cookie_path', '/');

echo "Cookie域名设置为: $domain\n";
echo "Cookie路径设置为: /\n";

// 启动Session
session_start();

echo "跨域Session配置完成\n";
}

// 问题4: Session并发访问问题
public static function handleConcurrentSessions() {
echo "\n=== 并发Session处理 ===\n";

// 使用文件锁防止并发写入
session_start();

// 立即关闭Session写入,允许其他请求访问
session_write_close();

echo "Session已关闭写入,允许并发访问\n";

// 如果需要再次写入Session,重新打开
// session_start();
// $_SESSION['new_data'] = 'value';
// session_write_close();
}

// 问题5: Session数据过大
public static function optimizeSessionData() {
echo "\n=== Session数据优化 ===\n";

session_start();

// 检查Session数据大小
$sessionData = serialize($_SESSION);
$sessionSize = strlen($sessionData);

echo "Session数据大小: " . number_format($sessionSize) . " 字节\n";

if ($sessionSize > 4096) { // 4KB
echo "警告: Session数据过大,建议优化\n";

// 优化建议
echo "优化建议:\n";
echo "1. 移除不必要的数据\n";
echo "2. 使用数据库存储大量数据\n";
echo "3. 压缩Session数据\n";
echo "4. 分页存储大型数组\n";
}

// 清理过期数据示例
if (isset($_SESSION['temp_data'])) {
$expireTime = $_SESSION['temp_data']['expire'] ?? 0;
if (time() > $expireTime) {
unset($_SESSION['temp_data']);
echo "已清理过期的临时数据\n";
}
}
}
}

// 运行调试工具
SessionTroubleshooting::debugSessionLoss();
SessionTroubleshooting::debugCookieIssues();
SessionTroubleshooting::setupCrossDomainSession('.example.com');
SessionTroubleshooting::handleConcurrentSessions();
SessionTroubleshooting::optimizeSessionData();
?>

总结

通过本文的学习,我们掌握了PHP中Session和Cookie的核心概念和实际应用:

关键要点

  1. Cookie管理: 学会了Cookie的设置、读取、删除和安全配置
  2. Session操作: 掌握了Session的基本操作和高级管理技巧
  3. 用户认证: 实现了完整的用户登录、权限验证和会话管理系统
  4. 购物车系统: 构建了实用的购物车功能,包括优惠券应用
  5. 安全最佳实践: 了解了Session劫持防护、CSRF防护等安全措施
  6. 问题排查: 学会了常见Session和Cookie问题的调试和解决方法

实用技巧

  • 使用工具类封装Session和Cookie操作,提高代码复用性
  • 实施适当的安全措施,如Session ID重新生成、用户代理验证等
  • 合理设置Cookie和Session的过期时间和作用域
  • 使用Flash消息提供用户友好的反馈
  • 定期清理过期的Session数据,优化性能

注意事项

  • 在设置Cookie前确保没有输出内容
  • 敏感数据应该加密存储
  • 定期重新生成Session ID防止会话固定攻击
  • 在生产环境中使用HTTPS确保数据传输安全
  • 合理配置Session垃圾回收机制

掌握这些Session和Cookie的使用技巧,将帮助你构建更安全、更用户友好的Web应用程序。记住,安全性和用户体验同样重要,在实际开发中要根据具体需求选择合适的会话管理策略。

本站由 提供部署服务