本文目录导读:

在PHP项目中实现用户自定义过期时间,常见有以下几种方案,我按推荐程度排序介绍:
基于数据库字段(最常用)
实现方式
// 用户表增加过期字段
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50),
email VARCHAR(100),
expire_at DATETIME, -- 过期时间
is_active TINYINT DEFAULT 1
);
// 创建用户时设置过期时间
function createUserWithExpire($username, $email, $expireDays = 30) {
$expireAt = date('Y-m-d H:i:s', strtotime("+{$expireDays} days"));
$sql = "INSERT INTO users (username, email, expire_at)
VALUES (?, ?, ?)";
// 使用PDO或mysqli执行
}
// 验证用户是否过期
function checkUserExpired($userId) {
$sql = "SELECT expire_at FROM users WHERE id = ?";
$user = $db->fetchOne($sql, [$userId]);
if (!$user) return true;
return strtotime($user['expire_at']) < time();
}
// 每次请求时检查
function authMiddleware() {
if (checkUserExpired($_SESSION['user_id'])) {
// 用户已过期,跳转到过期页面或禁止访问
header('Location: /expired.php');
exit;
}
}
使用Session + 数据库(临时过期更灵活)
// 登录时设置session过期
session_start();
function loginWithCustomExpire($userId, $expireMinutes = 30) {
// 数据库记录
$sql = "UPDATE users SET session_expire_at = ? WHERE id = ?";
$expireAt = date('Y-m-d H:i:s', time() + $expireMinutes * 60);
// Session设置
$_SESSION['user_id'] = $userId;
$_SESSION['expire_at'] = $expireAt;
$_SESSION['login_time'] = time();
}
// 中间件检查
function checkSessionExpired() {
if (!isset($_SESSION['expire_at'])) {
return false;
}
if (strtotime($_SESSION['expire_at']) < time()) {
// 过期,销毁session
session_destroy();
return true;
}
// 可选:每次访问更新过期时间(滑动过期)
$slidingExpire = true;
if ($slidingExpire) {
$_SESSION['expire_at'] = date('Y-m-d H:i:s',
time() + 30 * 60); // 再延长30分钟
}
return false;
}
基于JWT Token(适合API接口)
// 使用 firebase/php-jwt 库
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class CustomJWT {
private $secretKey;
public function __construct($secretKey) {
$this->secretKey = $secretKey;
}
// 生成带自定义过期时间的Token
public function generateToken($userId, $expireHours = 24) {
$payload = [
'iss' => 'your-app', // 签发者
'iat' => time(), // 签发时间
'exp' => time() + $expireHours * 3600, // 过期时间
'user_id' => $userId,
'custom_data' => [
'role' => 'premium',
'max_requests' => 1000
]
];
return JWT::encode($payload, $this->secretKey, 'HS256');
}
// 验证Token
public function validateToken($token) {
try {
$decoded = JWT::decode($token, new Key($this->secretKey, 'HS256'));
// 检查自定义过期条件
if ($decoded->custom_data->max_requests < 0) {
return false; // 请求次数用完也算过期
}
return (array)$decoded;
} catch (\Exception $e) {
// Token过期或无效
return false;
}
}
}
// 使用示例
$jwt = new CustomJWT('your-secret-key-here');
$token = $jwt->generateToken(123, 48); // 48小时过期
Redis缓存实现(高性能场景)
class RedisExpireManager {
private $redis;
public function __construct($redis) {
$this->redis = $redis;
}
// 设置用户自定义过期
public function setUserExpire($userId, $ttlSeconds) {
$key = "user:{$userId}:expire";
// 存储过期时间戳
$this->redis->setex($key, $ttlSeconds, time() + $ttlSeconds);
// 也可以构建用户会话
$sessionKey = "user:{$userId}:session";
$sessionData = json_encode([
'user_id' => $userId,
'expire_at' => time() + $ttlSeconds,
'last_activity' => time()
]);
$this->redis->setex($sessionKey, $ttlSeconds, $sessionData);
}
// 检查是否过期
public function isExpired($userId) {
$key = "user:{$userId}:expire";
$expireAt = $this->redis->get($key);
if (!$expireAt) return true; // 不存在视为过期
return $expireAt < time();
}
// 更新过期时间(滑动窗口)
public function refreshExpire($userId, $additionalSeconds = 3600) {
$key = "user:{$userId}:expire";
if ($this->redis->exists($key)) {
// 重新设置过期时间
$this->redis->expire($key, $additionalSeconds);
}
}
}
完整项目集成示例
<?php
// UserAuth.php - 用户认证类
class UserAuth {
private $db;
private $expireStrategies = [];
public function __construct($db) {
$this->db = $db;
}
// 注册过期策略
public function addExpireStrategy($name, callable $checker) {
$this->expireStrategies[$name] = $checker;
}
// 用户登录
public function login($username, $password, $expireConfig = []) {
// 验证用户...
// 设置过期
$expireConfig = array_merge([
'type' => 'fixed', // fixed, sliding, hybrid
'duration' => 3600, // 1小时
'max_idle' => 1800 // 最大空闲时间
], $expireConfig);
// 存储过期配置
$_SESSION['expire_config'] = $expireConfig;
$_SESSION['login_time'] = time();
$_SESSION['last_activity'] = time();
$_SESSION['user_id'] = $userId;
return true;
}
// 检查过期
public function checkExpired() {
if (!isset($_SESSION['expire_config'])) {
return false;
}
$config = $_SESSION['expire_config'];
$now = time();
switch ($config['type']) {
case 'fixed':
// 固定过期时间
return ($_SESSION['login_time'] + $config['duration']) < $now;
case 'sliding':
// 滑动过期:基于最后活动时间
$isExpired = ($_SESSION['last_activity'] + $config['duration']) < $now;
if (!$isExpired) {
$_SESSION['last_activity'] = $now; // 更新活动时间
}
return $isExpired;
case 'hybrid':
// 混合模式:总时长+空闲超时
$totalExpired = ($_SESSION['login_time'] + $config['duration']) < $now;
$idleExpired = ($_SESSION['last_activity'] + $config['max_idle']) < $now;
if (!$idleExpired) {
$_SESSION['last_activity'] = $now;
}
return $totalExpired || $idleExpired;
}
return false;
}
// 用户自定义过期查询
public function getUserCustomExpire($userId) {
// 从数据库获取用户的个性化过期设置
$sql = "SELECT expire_type, expire_value, expire_unit
FROM user_expire_config
WHERE user_id = ?";
$config = $this->db->fetchOne($sql, [$userId]);
if (!$config) {
// 默认过期设置
return [
'type' => 'fixed',
'value' => 24,
'unit' => 'hours'
];
}
// 根据配置计算过期时间
switch ($config['unit']) {
case 'minutes':
$expireSeconds = $config['expire_value'] * 60;
break;
case 'hours':
$expireSeconds = $config['expire_value'] * 3600;
break;
case 'days':
$expireSeconds = $config['expire_value'] * 86400;
break;
case 'custom':
// 自定义逻辑
$expireSeconds = $this->calculateCustomExpire($config);
break;
}
return [
'type' => $config['expire_type'],
'duration' => $expireSeconds
];
}
private function calculateCustomExpire($config) {
// 复杂的自定义过期逻辑
// 周末不过期、特定时间段过期等
$now = new DateTime();
$weekDay = $now->format('N');
if ($weekDay >= 6) { // 周末
return 86400 * 2; // 2天
}
return 3600; // 工作日1小时
}
}
// 使用示例
$auth = new UserAuth($db);
// 注册自定义过期检查策略
$auth->addExpireStrategy('weekend_free', function($userId) {
$now = new DateTime();
return $now->format('N') < 6; // 非周末返回false(不过期)
});
$auth->addExpireStrategy('usage_limit', function($userId) {
// 检查API调用次数
return getApiUsage($userId) > 1000;
});
// 用户登录时设置自定义过期
$expireConfig = $auth->getUserCustomExpire($userId);
$auth->login($username, $password, $expireConfig);
推荐方案选择
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 简单网站 | 数据库字段 | 实现简单,易于维护 |
| REST API | JWT Token | 无状态,适合分布式 |
| 高并发 | Redis | 性能好,支持过期通知 |
| 复杂权限 | 数据库+自定义策略 | 灵活可扩展 |
选择哪种方案取决于你的项目规模、并发量和业务复杂度,对于大多数中小型项目,数据库字段方案就足够了。