16

I've looked over several other questions that seem (from the titles) the same as this. However, my case is a bit different.

The following works (i.e. I get "success" and my database performs what I expect when running the procedure with the given variables):

$sql = "MyDB.dbo.myProcedure {$var1}, {$var2}, {$var3}";
$result = sqlsrv_query($myConn, $sql);
if (!$result) {
    echo 'Your code is fail.';
}
else {
    echo 'Success!';
}

I want to avoid (or lessen the possibility of) SQL injection by creating the SQL string using parameters. For example:

$sql = "select * from aTable where col1 = ? AND col2 = ?";
$result = sqlsrv_query($myConn, $sql, array($var1, $var2));
//please note. This code WILL work!

But when I do that with a stored procedure it fails. It fails with no errors reported via sqlsrv_errors(), no action taken in database, and $result === false.

To be clear, the following fails:

$sql = "MyDB.dbo.myProcedure ?, ?, ?";
$result = sqlsrv_query($myConn, $sql, array($var1, $var2, $var3));

Likewise a prepare/execute statement created the same way will also fail:

$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.

For completeness, I have confirmed that the stored procedure in question works directly within SQL Management Studio AND if called the way I mentioned above. Likewise, I have confirmed that I can use parameterized queries for any raw query (like an insert, select, update vs a stored procedure).

So, my question is how can I call a stored procedure using the parameterized query vs embedding the variables in the query string?

More importantly, I am actually wanting to use a prepare/execute, so hopefully the answer will allow this to work as well.

2
  • 1
    Have you tried like the example on the manual page? $sql = "EXEC stp_Create_Item @Item_ID = ?, @Item_Name = ?"; php.net/manual/en/function.sqlsrv-prepare.php ... or not the examples but from the User Contributed Notes Commented Jul 22, 2015 at 22:55
  • I read through the user contributed notes on the sqlsrv_query page, but obviously I did not read or notice this example on the page you linked. This apparently is the way to do this. Do you want to add this as an answer, so I can mark it for any future searches? Otherwise I'll do it. Commented Jul 23, 2015 at 14:50

4 Answers 4

21

The user contributions on the php.net have a write up on how to execute a stored procedure using the sqlsrv-prepare.

In case that is removed from the php.net user contributions in the future here is what it had(has) listed:

$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);

Here's the manual's page, http://php.net/manual/en/function.sqlsrv-prepare.php

Sign up to request clarification or add additional context in comments.

2 Comments

Are @item_ID and @Item_Name the variables from the stored procedure in SQL Server?
@Hiebs915 Yes. It doesn't work if you generically use the question mark, so you have to explicitly use the variable name = ?. You still have to supply the variables in the correct order as far as I know. I'm not certain why it works this way, but this is the solution.
12

This is a follow up to the answer by @chris85.

It's worth noting here that once the statement is prepared, you need to execute it:

$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() only returns true/false. If you want to parse the data returned by the stored procedure you can process it just like the result from sqlsrv_query().

If you forget the sqlsrv_execute() you'll get an error saying that the result has to be executed before it can be used.

2 Comments

I think sqlsrv_fetch_array or just sqlsrv_fetch is what it is.
sqlsrv_fetch_rows doesn't exist. search it on google. It doesn't work on php 7.2
3

This is another followup to the answer by @chris85.

I tried the answer, combined with the followup answer by @AndyD273, but got the following error: I get the exception "The formal parameter "@param1" was not declared as an OUTPUT parameter, but the actual parameter passed in requested output"

I solved this by changing all instances of SQLSRV_PARAM_OUT to SQLSRV_PARAM_IN. The documentation for SQLSRV_PARAM_IN says:

Indicates an input parameter when passed to sqlsrv_query() or sqlsrv_prepare().

The updated version of @chris85's answer to prepare the stored procedure parameters now looks like:

$procedure_params = array(
    array(&$myparams['Item_ID'], SQLSRV_PARAM_IN),
    array(&$myparams['Item_Name'], SQLSRV_PARAM_IN)
);

1 Comment

You also could just remove the SQLSRV_PARAM_OUT option, no? According to sqlsrv_query() documentation, under the $direction param: "The default value is SQLSRV_PARAM_IN." (ref: php.net/manual/en/function.sqlsrv-query.php)
0

Make sure you set this or you will always get errors returned if the stored procedure has messages being returned.

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));

}

1 Comment

You don't specify how $param1 and $param2 are set.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.