本文详解“only variables should be passed by reference”错误成因,指出bind_param()要求传入变量而非函数返回值,并提供修复方案;同时强调弃用sha-1,推荐使用php原生password_hash()/password_verify()实现安全密码存储与验证。
本文详解“only variables should be passed by reference”错误成因,指出bind_param()要求传入变量而非函数返回值,并提供修复方案;同时强调弃用sha-1,推荐使用php原生password_hash()/password_verify()实现安全密码存储与验证。
在使用MySQLi预处理语句(Prepared Statement)时,bind_param()方法要求所有参数必须是可被引用的变量(lvalue),而不能是表达式、字面量或函数调用结果(如sha1($_POST['l_pass']))。该限制源于PHP底层对引用传递的语法要求——只有变量才能被取地址并传递给内部函数。
上述报错代码第44行:
$query->bind_param("ss", $_POST['l_user'], sha1($_POST['l_pass'])); // ❌ 错误:函数调用不可传引用
sha1($_POST['l_pass']) 是一个临时计算结果,不是变量,因此无法满足bind_param()的引用约束。
✅ 正确做法是先计算哈希值并赋给一个变量,再绑定该变量:
立即学习“PHP免费学习笔记(深入)”;
if (isset($_POST['l_login'])) { $query = $con->prepare("SELECT id FROM librarian WHERE username = ? AND password = ?"); $username = $_POST['l_user']; $password_hash = sha1($_POST['l_pass']); // ✅ 先赋值为变量 $query->bind_param("ss", $username, $password_hash); $query->execute(); $result = $query->get_result(); if ($result->num_rows !== 1) { echo error_without_field("Invalid username/password combination"); } else { // 登录成功逻辑 $row = $result->fetch_assoc(); $_SESSION['librarian_id'] = $row['id']; header("Location: dashboard.php"); exit; }}
⚠️ 重要安全提醒:
sha1() 已被密码学界彻底废弃——自2005年起即存在实用碰撞攻击,2017年Google更公开演示了SHA-1碰撞(SHAttered攻击)。绝不可用于密码哈希。现代PHP应使用内置的、自适应的、带盐的密码哈希方案:
? 推荐方案(PHP 5.5+):
// 注册时:生成强哈希(自动加盐、支持算法升级)$hash = password_hash($_POST['l_pass'], PASSWORD_ARGON2ID, [ 'memory_cost' => 65536, // 64MB 内存 'time_cost' => 4, 'threads' => 3]);// 登录时:安全比对(自动处理盐与算法)if (password_verify($_POST['l_pass'], $stored_hash)) { // 密码正确}
若环境不支持Argon2(如PHP < 7.2),退而使用PASSWORD_DEFAULT(当前为bcrypt):
$hash = password_hash($_POST['l_pass'], PASSWORD_DEFAULT);// 验证方式不变:password_verify($input, $hash) → 始终安全
? 总结: