
本文讲解如何安全地从数据库读取用户权限字段,并基于其值(如 level4="yes")动态包含对应 php 菜单文件,重点解决 sql 字符串拼接导致的列名误解析错误及基础安全加固方法。
本文讲解如何安全地从数据库读取用户权限字段,并基于其值(如 level4="yes")动态包含对应 php 菜单文件,重点解决 sql 字符串拼接导致的列名误解析错误及基础安全加固方法。
在构建多角色权限系统时,常需根据登录用户的权限等级(如普通用户、编辑、管理员)动态渲染不同的导航菜单。常见做法是在用户表中设置多个布尔型权限字段(如 level1, level2, level4),默认为 'no',授权时更新为 'yes'。但初学者在实现条件包含逻辑时,极易因 SQL 字符串拼接不严谨引发致命错误。
你遇到的 Unknown column 'justinw' in 'where clause' 错误,根本原因在于未对 $_SESSION['userid'] 值加引号,导致 SQL 解析器将变量内容(如用户名 "justinw")误认为列名而非字符串字面量。原始代码:
$sql = "SELECT * FROM users WHERE userid =" .$_SESSION['userid']; // ❌ 危险!无引号 + 无转义
当 $_SESSION['userid'] 值为 justinw(非数字)时,生成的 SQL 实际为:
SELECT * FROM users WHERE userid = justinw -- 数据库试图查找名为 "justinw" 的列 → 报错
✅ 正确写法(修复版,但仍需进阶优化):
<?php
// 修复:为字符串值添加单引号
$sql = "SELECT * FROM users WHERE userid = '" . mysqli_real_escape_string($con, $_SESSION['userid']) . "'";
$result = $con->query($sql);
if ($result && $result->num_rows > 0) {
$row = $result->fetch_assoc(); // 单用户查询无需 while 循环
if ($row["level4"] === 'yes') {
include 'asidemenus/admin.php';
}
}
?>⚠️ 重要注意事项:
- 永远不要直接拼接用户输入:即使来自 $_SESSION,也应视为不可信数据。mysqli_real_escape_string() 可防御基础 SQL 注入,但推荐使用预处理语句(更安全、更规范);
- *避免 `SELECT **:仅查询必要字段(如SELECT level4 FROM users`),提升性能与可维护性;
- 会话验证前置:确保 $_SESSION['userid'] 已存在且合法,建议在包含此逻辑前做 isset($_SESSION['userid']) 检查;
- 错误处理增强:生产环境应捕获 $con->query() 异常并记录日志,而非暴露致命错误;
- 权限校验逻辑优化:若菜单项较多,建议统一权限检查函数,避免重复查询。
? 推荐升级方案(预处理语句):
<?php
if (isset($_SESSION['userid'])) {
$stmt = $con->prepare("SELECT level4 FROM users WHERE userid = ?");
$stmt->bind_param("s", $_SESSION['userid']); // "s" 表示字符串类型
$stmt->execute();
$result = $stmt->get_result();
if ($result && $result->num_rows === 1) {
$row = $result->fetch_assoc();
if ($row['level4'] === 'yes') {
include 'asidemenus/admin.php';
}
}
$stmt->close();
}
?>该方案彻底杜绝 SQL 注入风险,语义清晰,是 PHP MySQLi 的最佳实践。记住:权限控制是安全关键点,宁可多写几行健壮代码,也不依赖“暂时能用”的脆弱实现。

















