我已经查看了其他几个(从标题中)与此相同的问题。但是,我的情况有点不同。
以下工作(即我得到"成功"我的数据库执行我在使用给定变量运行程序时的预期):
$sql = "MyDB.dbo.myProcedure {$var1}, {$var2}, {$var3}";
$result = sqlsrv_query($myConn, $sql);
if (!$result) {
echo 'Your code is fail.';
}
else {
echo 'Success!';
}
我想通过使用参数创建SQL字符串来避免(或减少)SQL注入的可能性。例如:
$sql = "select * from aTable where col1 = ? AND col2 = ?";
$result = sqlsrv_query($myConn, $sql, array($var1, $var2));
//please note. This code WILL work!
但是当我使用存储过程执行此操作时,它会失败。它失败,没有通过sqlsrv_errors()报告错误,数据库中没有采取任何操作,$result === false
。
要明确,以下内容失败:
$sql = "MyDB.dbo.myProcedure ?, ?, ?";
$result = sqlsrv_query($myConn, $sql, array($var1, $var2, $var3));
同样,以相同方式创建的prepare / execute语句也将失败:
$sql = "MyDB.dbo.myProcedure ?, ?, ?";
$stmt = sqlsrv_prepare($myConn, $sql, array(&$var1, &$var2, &$var3));
foreach($someArray as $key => $var3) {
if(sqlsrv_execute($stmt) === false) {
echo 'mucho fail.';
}
}
//this code also fails.
为了完整起见,我已经确认有问题的存储过程直接在SQL Management Studio中工作,如果按照我上面提到的方式调用的话。同样,我已经确认我可以对任何原始查询使用参数化查询(如插入,选择,更新与存储过程)。
所以,我的问题是如何使用参数化查询调用存储过程vs在查询字符串中嵌入变量?
更重要的是,我实际上想要使用准备/执行,所以希望答案能够让它也能正常工作。
答案 0 :(得分:12)
php.net上的用户贡献记录了如何使用sqlsrv-prepare执行存储过程。
如果从php.net中删除用户以后的贡献,这里有它已经列出的内容:
$procedure_params = array(
array(&$myparams['Item_ID'], SQLSRV_PARAM_OUT),
array(&$myparams['Item_Name'], SQLSRV_PARAM_OUT)
);
// EXEC the procedure, {call stp_Create_Item (@Item_ID = ?, @Item_Name = ?)} seems to fail with various errors in my experiments
$sql = "EXEC stp_Create_Item @Item_ID = ?, @Item_Name = ?";
$stmt = sqlsrv_prepare($conn, $sql, $procedure_params);
答案 1 :(得分:9)
这是@ chris85答案的后续内容。
值得注意的是,一旦准备好声明,你需要执行它:
$sql = "EXEC stp_Create_Item @Item_ID = ?, @Item_Name = ?";
$stmt = sqlsrv_prepare($conn, $sql, $procedure_params);
if (!sqlsrv_execute($stmt)) {
echo "Your code is fail!";
die;
}
while($row = sqlsrv_fetch_array($stmt)){
//Stuff
}
sqlsrv_execute()
仅返回true / false。如果要解析存储过程返回的数据,则可以像sqlsrv_query()
的结果一样处理它。
如果您忘记sqlsrv_execute()
,您将收到错误消息,说明在使用结果之前必须执行该结果。
答案 2 :(得分:0)
请确保您设置了此选项,否则如果存储过程中有返回的消息,则始终会返回错误。
sqlsrv_configure('WarningsReturnAsErrors',0);
//Full working code below
$sql = "{call NameOfDatabase.NameOfOwner.StoredProcedureName(?,?)}";
$params = array($param1, $param2);
if ($stmt = sqlsrv_prepare($conn, $sql, $params)) {
echo "Statement prepared.<br><br>\n";
} else {
echo "Statement could not be prepared.\n";
die(print_r(sqlsrv_errors(), true));
}
if( sqlsrv_execute( $stmt ) === false ) {
die( print_r( sqlsrv_errors(), true));
}else{
print_r(sqlsrv_fetch_array($stmt));
}