Prepared statements and stored procedures

Many of the more mature databases support the concept of prepared statements. What are they? You can think of them as a kind of compiled template for the SQL that you want to run, that can be customized using variable parameters. Prepared statements offer two major benefits:

  • The query only needs to be parsed (or prepared) once, but can be executed multiple times with the same or different parameters. When the query is prepared, the database will analyze, compile and optimize it's plan for executing the query. For complex queries this process can take up enough time that it will noticeably slow down your application if you need to repeat the same query many times with different parameters. By using a prepared statement you avoid repeating the analyze/compile/optimize cycle. In short, prepared statements use fewer resources and thus run faster.
  • The parameters to prepared statements don't need to be quoted; the driver handles it for you. If your application exclusively uses prepared statements, you can be sure that no SQL injection will occur. (However, if you're still building up other parts of the query based on untrusted input, you're still at risk).

Prepared statements are so useful that they are the only feature that PDO will emulate for drivers that don't support them. This ensures that you will be able to use the same data access paradigm regardless of the capabilities of the database.

Пример #1 Repeated inserts using prepared statements

This example performs an INSERT query by substituting a name and a value for the named placeholders.

<?php
$stmt 
$dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name'$name);
$stmt->bindParam(':value'$value);

// insert one row
$name 'one';
$value 1;
$stmt->execute();

// insert another row with different values
$name 'two';
$value 2;
$stmt->execute();
?>

Пример #2 Repeated inserts using prepared statements

This example performs an INSERT query by substituting a name and a value for the positional ? placeholders.

<?php
$stmt 
$dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1$name);
$stmt->bindParam(2$value);

// insert one row
$name 'one';
$value 1;
$stmt->execute();

// insert another row with different values
$name 'two';
$value 2;
$stmt->execute();
?>

Пример #3 Fetching data using prepared statements

This example fetches data based on a key value supplied by a form. The user input is automatically quoted, so there is no risk of a SQL injection attack.

<?php
$stmt 
$dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if (
$stmt->execute(array($_GET['name']))) {
  while (
$row $stmt->fetch()) {
    
print_r($row);
  }
}
?>

If the database driver supports it, you may also bind parameters for output as well as input. Output parameters are typically used to retrieve values from stored procedures. Output parameters are slightly more complex to use than input parameters, in that you must know how large a given parameter might be when you bind it. If the value turns out to be larger than the size you suggested, an error is raised.

Пример #4 Calling a stored procedure with an output parameter

<?php
$stmt 
$dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1$return_valuePDO::PARAM_STR4000); 

// call the stored procedure
$stmt->execute();

print 
"procedure returned $return_value\n";
?>

You may also specify parameters that hold values both input and output; the syntax is similar to output parameters. In this next example, the string 'hello' is passed into the stored procedure, and when it returns, hello is replaced with the return value of the procedure.

Пример #5 Calling a stored procedure with an input/output parameter

<?php
$stmt 
$dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value 'hello';
$stmt->bindParam(1$valuePDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT4000); 

// call the stored procedure
$stmt->execute();

print 
"procedure returned $value\n";
?>

Пример #6 Invalid use of placeholder

<?php
$stmt 
$dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute(array($_GET['name']));

// placeholder must be used in the place of the whole value
$stmt $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(array("%$_GET[name]%"));
?>

Коментарии

Note that when using name parameters with bindParam, the name itself, cannot contain a dash '-'. 

example:
<?php
$stmt 
$dbh->prepare ("INSERT INTO user (firstname, surname) VALUES (:f-name, :s-name)");
$stmt -> bindParam(':f-name''John');
$stmt -> bindParam(':s-name''Smith');
$stmt -> execute();
?>

The dashes in 'f-name' and 's-name' should be replaced with an underscore or no dash at all.

See http://bugs.php.net/43130

Adam
2010-04-05 21:38:53
http://php5.kiev.ua/manual/ru/pdo.prepared-statements.html
Insert a multidimensional array into the database through a prepared query:
We have an array to write the form:

$dataArr:
Array
(
    [0] => Array
        (
            [0] => 2020
            [1] => 23
            [2] => 111111
        )
 
    [1] => Array
        (
            [0] => 2020
            [1] => 24
            [2] => 222222222
        )
....

Task: prepare a request and pass through binds
$array = [];
foreach ($dataArr as $k=>$v) {
// $x = 2020, the variable is predetermined in advance, does not change the essence
$array[] = [$x, $k, $v];
}
$sql = ("INSERT INTO `table` (`field`,`field`,`field`) VALUES (?,?,?)");

$db->queryBindInsert($sql,$array);

public function queryBindInsert($sql,$bind) {
        $stmt = $this->pdo->prepare($sql);
 
        if(count($bind)) {
            foreach($bind as $param => $value) {
                $c = 1;
                for ($i=0; $i<count($value); $i++) {
                    $stmt->bindValue($c++, $value[$i]);
                }
                $stmt->execute();
            }
        }
    }
2020-02-06 20:11:09
http://php5.kiev.ua/manual/ru/pdo.prepared-statements.html
it is a good practice not using double quotes in sql strings. This way you can ensure that no variable is injected in query.
a simple query with parameters should be;
'INSERT INTO REGISTRY (name, value) VALUES (?, ?)'
not
"INSERT INTO REGISTRY (name, value) VALUES (?, ?)"
2021-01-28 07:38:41
http://php5.kiev.ua/manual/ru/pdo.prepared-statements.html
Example #5 gives an 1414 wenn tried on MariaDB. Use this function to call a stored procedure with the last parameter as INOUT returning a value like a (uu)id or a count;

<?php
/**
 * call_sp Call the specified stored procedure with the given parameters.
 * The first parameter is the name of the stored procedure.
 * The remaining parameters are the (in) parameters to the stored procedure.
 * the last (out) parameter should be an int like state or number of affected rows.
 *
 * @param  mixed $sp_name The name of the stored procedure to call.
 * @param  mixed $params The parameters to pass to the stored procedure.
 * @return int The number of affected rows.
 */
function call_sp\PDO $dbstring $sp_name, ...$params ): mixed
{
 
$placeholders   array_fill0count$params ), "?" );
 
$placeholders[] = "@new_id";

 
$sql "CALL $sp_name( " implode", "$placeholders ) . " ); SELECT @new_id AS `new_id`";

  try {
   
LOG->debug"calling Stored Procedure", [ "sql" => $sql ] );

   
$stmt $db->prepare$sql );
   
$i    0;
    foreach( 
$params as $param ) {
     
$stmt->bindValue( ++$i$param );
    }
   
$stmt->execute();
   
$new_id $stmt->fetchPDO::FETCH_ASSOC )['new_id'];

    return 
$new_id;

  } catch ( 
\Exception $e ) {
   
LOG->error"Error calling Stored Procedure", [ "sql" => $sql"params" => $params"error" => $e->getMessage() ] );
    throw 
$e;
  }
2024-02-27 13:30:01
http://php5.kiev.ua/manual/ru/pdo.prepared-statements.html

    Поддержать сайт на родительском проекте КГБ