为什么PHP角色权限校验函数本地正常但线上服务器无法生效
问题根因
该问题是本地和线上环境的PHP数据库驱动配置差异导致的,核心触发点是权限校验的严格比较逻辑:
你在check_users_permissions方法中使用了===严格全等判断,调用时传入的permissionID为整数类型1:
- 本地环境一般默认使用
mysqlnd驱动,且关闭了ATTR_STRINGIFY_FETCHES配置,从数据库查询返回的permissionID为整数类型,1 === 1判断成立,校验正常通过 - 线上环境如果使用旧版
libmysql驱动,或者开启了ATTR_STRINGIFY_FETCHES配置,数据库返回的数值字段会被自动转换为字符串类型,此时"1" === 1判断不成立,校验直接返回false,导致功能失效
你贴出的SESSION结构中已经能看到返回值同时存在数字索引和关联索引,说明当前PDO查询使用的是默认的PDO::FETCH_BOTH模式,未显式指定返回格式,进一步放大了环境配置差异的影响。
修复方案
方案1(最优,不依赖环境配置)
修改校验逻辑,统一转换数值类型后再比较,同时补全SESSION不存在的异常判断:
public function check_users_permissions($permissionID, $permissionName) { if (empty($_SESSION['permissions'])) { return false; } foreach ($_SESSION['permissions'] as $perm) { if ( isset($perm['permissionID'], $perm['permissionName']) && intval($perm['permissionID']) === intval($permissionID) && $perm['permissionName'] === $permissionName ) { return true; } } return false; }
方案2(统一数据库查询格式)
显式指定PDO查询的返回模式,从源头上统一返回值类型:
- 在PDO初始化代码中添加配置:
// 关闭查询结果数值自动转字符串 $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
- 修改权限查询的fetchAll调用,显式指定返回关联数组,避免冗余索引:
public function get_user_permissions($username) { $row = $this->get_user_hash($username); try { $stmt = $this->_db->prepare("SELECT roleID, permissionID, permissionName FROM roles_permissions WHERE roleID = :userRoleID"); $stmt->execute(array( 'userRoleID' => $row['userRoleID'] )); // 显式指定返回关联数组 return $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { echo '<p>' . $e->getMessage() . '</p>'; } }
快速验证方案
如果要快速定位问题,可临时将校验逻辑中的===改为==做非严格比较,若线上功能恢复即可100%确认是类型差异导致的问题,之后再用上面的稳妥方案改造即可。
内容的提问来源于stack exchange,提问作者AKIN CAN
相关产品推荐
相关产品推荐

