PHP数据库日期比较问题:令牌认证过期校验失败
排查PHP令牌认证中日期比对失效的问题
嘿,我太懂这种明明逻辑没问题但比对就是不生效的抓狂感了!这种情况90%都是日期类型/格式不匹配或者时区不一致导致的,咱们一步步拆解问题:
首先,先明确核心:存储与读取的日期类型必须统一
你得先搞清楚两个关键信息:
- 数据库里
expires_at字段是什么类型?(是INT存时间戳,还是DATETIME/TIMESTAMP存字符串?) - 你插入令牌时,是用哪种格式写入的过期时间?
场景1:用时间戳存储(最不容易出错的方式)
如果数据库字段设为INT类型,插入和校验都用时间戳就不会有格式纠纷:
// 插入令牌时 $expires_timestamp = time() + 120; // 当前时间+2分钟(120秒) $stmt = $pdo->prepare("INSERT INTO tokens (token, expires_at) VALUES (:token, :expires)"); $stmt->execute(['token' => $your_generated_token, 'expires' => $expires_timestamp]); // 校验令牌时 $stmt = $pdo->prepare("SELECT expires_at FROM tokens WHERE token = :token"); $stmt->execute(['token' => $request_token]); $token_data = $stmt->fetch(PDO::FETCH_ASSOC); if (!$token_data) { // 令牌不存在 } elseif ($token_data['expires_at'] < time()) { // 令牌已过期 } else { // 令牌有效,继续执行逻辑 }
场景2:用DATETIME/TIMESTAMP存储字符串
如果数据库字段是DATETIME,必须保证插入的格式和比对的格式完全一致,还要重点注意时区:
// 先统一时区!这步很容易忽略,避免PHP和数据库时区差导致时间偏差 date_default_timezone_set('Asia/Shanghai'); // 换成你实际使用的时区 // 插入时生成标准datetime字符串 $expires_datetime = date('Y-m-d H:i:s', time() + 120); $stmt = $pdo->prepare("INSERT INTO tokens (token, expires_at) VALUES (:token, :expires)"); $stmt->execute(['token' => $your_generated_token, 'expires' => $expires_datetime]); // 校验时,推荐直接用数据库的当前时间比对(更准确,绕开PHP时区问题) $stmt = $pdo->prepare("SELECT * FROM tokens WHERE token = :token AND expires_at > NOW()"); $stmt->execute(['token' => $request_token]); if ($stmt->rowCount() === 0) { // 令牌不存在或已过期 } else { // 令牌有效 }
最容易踩的隐形坑:时区不一致
如果你的PHP时区和数据库时区不一样(比如PHP用上海时区,数据库用UTC),存的时间会和实际时间有偏差,导致明明没过期却被判过期,或者反过来。
- 检查PHP时区:执行
echo date_default_timezone_get(); - 检查数据库时区:执行SQL语句
SELECT @@global.time_zone, @@session.time_zone; - 统一两者的时区,要么都用UTC,要么都用你的本地时区。
快速排查小技巧
- 直接去数据库里查看
expires_at的值,和当前实际时间对比,确认是不是真的加了2分钟。 - 在PHP里打印出比对的两个值,比如:
看看两者的类型和格式是不是一致——比如一个是字符串一个是整数,那比对肯定会出错。var_dump($token_data['expires_at'], time()); // 如果是时间戳类型 // 或者 var_dump($token_data['expires_at'], date('Y-m-d H:i:s')); // 如果是datetime字符串类型
内容的提问来源于stack exchange,提问作者levaa
相关产品推荐
相关产品推荐

