J'ai examiné plusieurs autres questions qui semblent (d'après les titres) identiques à celles-ci. Cependant, mon cas est un peu différent.
Les travaux suivants (c'est-à-dire que j'obtiens "succès" et ma base de données exécute ce que j'attends lors de l'exécution de la procédure avec les variables données):
$sql = "MyDB.dbo.myProcedure {$var1}, {$var2}, {$var3}";
$result = sqlsrv_query($myConn, $sql);
if (!$result) {
echo 'Your code is fail.';
}
else {
echo 'Success!';
}
Je souhaite éviter (ou réduire la possibilité de) l'injection SQL en créant la chaîne SQL à l'aide de paramètres. Par exemple:
$sql = "select * from aTable where col1 = ? AND col2 = ?";
$result = sqlsrv_query($myConn, $sql, array($var1, $var2));
//please note. This code WILL work!
Mais quand je le fais avec une procédure stockée, cela échoue. Il échoue sans aucune erreur signalée via sqlsrv_errors (), aucune action prise dans la base de données et $result === false
.
Pour être clair, ce qui suit échoue:
$sql = "MyDB.dbo.myProcedure ?, ?, ?";
$result = sqlsrv_query($myConn, $sql, array($var1, $var2, $var3));
De même, une instruction prepare/execute créée de la même manière échouera également:
$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.
Pour être complet, j'ai confirmé que la procédure stockée en question fonctionne directement dans SQL Management Studio ET si elle est appelée comme je l'ai mentionné ci-dessus. De même, j'ai confirmé que je peux utiliser des requêtes paramétrées pour toute requête brute (comme une insertion, sélection, mise à jour vs une procédure stockée).
Donc, ma question est de savoir comment puis-je appeler une procédure stockée à l'aide de la requête paramétrée par rapport à l'incorporation des variables dans la chaîne de requête?
Plus important encore, je souhaite réellement utiliser une préparation/exécution, donc j'espère que la réponse permettra que cela fonctionne également.
Les contributions des utilisateurs sur le php.net ont une écriture sur la façon d'exécuter une procédure stockée en utilisant sqlsrv-prepare.
Au cas où cela serait supprimé des contributions des utilisateurs de php.Net à l'avenir, voici ce qu'il avait (a) répertorié:
$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);
Voici la page du manuel, http://php.net/manual/en/function.sqlsrv-prepare.php
Ceci fait suite à la réponse de @ chris85.
Il convient de noter ici qu'une fois la déclaration préparée, vous devez l'exécuter:
$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()
renvoie uniquement vrai/faux. Si vous souhaitez analyser les données renvoyées par la procédure stockée, vous pouvez les traiter comme le résultat de sqlsrv_query()
.
Si vous oubliez la sqlsrv_execute()
vous obtiendrez une erreur indiquant que le résultat doit être exécuté avant de pouvoir être utilisé.
Assurez-vous de le définir ou vous obtiendrez toujours des erreurs renvoyées si la procédure stockée contient des messages renvoyés.
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));
}