Как выполнить хранимую процедуру в php с помощью sqlsrv и "?" параметры стиля

Я просмотрел несколько других вопросов, которые кажутся (из названий) такими же, как это. Однако мой случай немного отличается.

Следующие работы (т.е. я получаю "успех", и моя база данных выполняет то, что я ожидаю при запуске процедуры с заданными переменными):

$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 И если называется так, как я упоминал выше. Аналогично, я подтвердил, что я может использовать параметризованные запросы для любого необработанного запроса (например, вставка, выбор, обновление и хранимая процедура).

Итак, мой вопрос заключается в том, как я могу вызвать хранимую процедуру с использованием параметризованного запроса и встраивания переменных в строку запроса?

Что еще более важно, я действительно хочу использовать команду prepare/execute, поэтому, надеюсь, ответ позволит этому и работать.

Ответ 1

Вклад пользователя на 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);

Здесь страница руководства, http://php.net/manual/en/function.sqlsrv-prepare.php

Ответ 2

Это продолжение ответа от @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() вы получите сообщение о том, что результат должен быть выполнен до того, как его можно будет использовать.

Ответ 3

Убедитесь, что вы установили это, иначе вы всегда будете получать ошибки, если хранимая процедура имеет возвращаемые сообщения.

sqlsrv_configure('WarningsReturnAsErrors',0);
$sql = "{call database.owner.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));

}