如何修复PDO调用SQL Server存储过程报'@P1'附近语法错误
报错原因
报错根源是T-SQL存储过程的调用语法写错了:
SQL Server里调用存储过程时,不能用括号包裹参数列表——带括号传参是标量值函数的调用语法,不是存储过程的。你的代码里写EXEC sp_login(?, ?),PDO预处理阶段会把问号占位符替换成驱动自动生成的命名参数@P1、@P2,最终传给SQL Server的语句变成EXEC sp_login(@P1, @P2),数据库解析到这个不符合存储过程调用规则的写法,就会抛出@P1附近存在语法错误的提示。
另外你的现有代码还有两个明显的安全/逻辑问题:
- 把用户提交的明文密码直接存在
$_SESSION里,存在会话泄露后密码被盗的风险 - 跳转头
header发送后没有终止代码执行,存在逻辑被绕过的可能
修复方法
- 首先修正存储过程调用的SQL语句,两种合法写法选一个即可:
- 按位置传参(最简单,直接去掉参数外的括号):
$sql = "EXEC sp_login ?, ?";- 显式指定参数名(兼容性最好,推荐使用,注意参数名要和你存储过程定义的形参名完全一致):
// 假设sp_login的两个形参分别是@utilizador、@password,按你实际定义调整 $sql = "EXEC sp_login @utilizador = ?, @password = ?"; - 调整逻辑,不要把明文密码存入SESSION,header跳转后加exit终止执行,修正后的核心代码如下:
session_start(); // 直接从POST取参数做校验,不需要提前写入SESSION $utilizador = $_POST['utilizador'] ?? null; $password = $_POST['password'] ?? null; if (isset($utilizador) && isset($password)){ require 'ligacao_bd.php'; $pdo = Conexao::getConnection(); $sql = "EXEC sp_login @utilizador = ?, @password = ?"; $statement = $pdo->prepare($sql); $statement->bindParam(1, $utilizador, PDO::PARAM_STR); $statement->bindParam(2, $password, PDO::PARAM_STR); $statement->execute(); $resultado = $statement->fetch(PDO::FETCH_ASSOC); if ($resultado) { // 校验通过后仅把必要的用户标识存入SESSION即可,不要存明文密码 $_SESSION["utilizador"] = $utilizador; header("location: utilizadores.php"); exit; // 必须加终止语句,避免后续代码继续执行 }else{ echo "NO PERMISSIONS"; } }
额外建议:不要在数据库里明文存储用户密码,存储过程里做校验时,应该用加盐哈希后的值做比对,避免数据拖库后所有用户密码泄露。
内容的提问来源于stack exchange,提问作者Antonio Jose
相关产品推荐
相关产品推荐

