本文详解 `db::query()` 返回数组导致 `$user_id` 赋值错误的问题,指出直接取 `[0]['id']` 前未校验查询结果是否为空的风险,并提供安全、简洁的两种解决方案:显式结果校验与单语句子查询插入。
在你提供的 actlogin.php 代码中,问题根源并非 $token 变量本身,而是对 DB::query() 返回值的误用。DB::query() 在执行 SELECT 时始终返回一个二维数组(即使只有一行一列),例如:
$result = DB::query('SELECT id FROM users WHERE username=:username', [':username' => $username]);
// $result 形如: [['id' => 123]] 或 [](查无结果时为空数组)而你在代码中这样写:
$user_id = DB::query('SELECT id FROM users WHERE username=:username', array(':username'=>$username))[0]['id'];这存在双重风险:
✅ 正确做法:先检查查询结果,再安全提取 ID
// ✅ 推荐:显式校验 + 安全取值
$userRows = DB::query('SELECT id FROM users WHERE username=:username', [':username' => $username]);
if (!empty($userRows)) {
$user_id = (int)$userRows[0]['id']; // 强制转为整型,防注入隐患
} else {
die('User not found — cannot generate token.');
}
// 执行插入(此时 $user_id 是有效整数)
DB::query('INSERT INTO login_tokens (token, user_id) VALUES (:token, :user_id)', [
':token' => $token,
':user_id' => $user_id
]);? 更优方案:用 INSERT ... SELECT 一条语句完成,彻底规避 PHP 层数据传递风险
// ✅ 最佳实践:原子化操作,无需中间变量
DB::query('INSERT INTO login_tokens (token, user_id)
SELECT :token, id
FROM users
WHERE username = :username', [
':tok
en' => $token,
':username' => $username // 注意:原答案中的 :usename 是笔误,应为 :username
]);该写法优势显著:
⚠️ 额外注意事项:
通过以上修正,你的登录令牌插入逻辑将变得可靠、高效且符合现代 PHP 最佳实践。