mysqli_stmt::prepare

mysqli_stmt_prepare

(PHP 5, PHP 7, PHP 8)

mysqli_stmt::prepare -- mysqli_stmt_prepareПодготавливает утверждение SQL к выполнению

Описание

Объектно-ориентированный стиль

public mysqli_stmt::prepare(string $query): bool

Процедурный стиль

mysqli_stmt_prepare(mysqli_stmt $statement, string $query): bool

Подготавливает утверждение к выполнению. Запрос должен состоять из одного оператора SQL.

Шаблон утверждения может содержать ноль или несколько вопросительных знаков (?), меток параметров, также называемых заполнителями. Метки параметров должны быть привязаны к переменным приложения с помощью mysqli_stmt_bind_param() перед выполнением утверждения. строк.

Замечание:

В случае, если длина выражения, которое передаётся в mysqli_stmt_prepare(), больше, чем max_allowed_packet сервера, возвращаемые коды ошибки могут различаться в зависимости от используемого драйвера. А это может быть либо родной MySQL-драйвер (mysqlnd), либо клиентская библиотека MySQL (libmysqlclient). Поведение функции будет следующим:

  • mysqlnd на платформе Linux возвращает код ошибки 1153. Сообщение об ошибке означает размер пакета превышает max_allowed_packet байт.

  • mysqlnd на платформе Windows возвращает код ошибки 2006. Это сообщение об ошибке означает сервер недоступен.

  • libmysqlclient на всех платформах возвращает код ошибки 2006. Это сообщение об ошибке означает сервер недоступен.

Список параметров

stmt

Только для процедурного стиля: объект mysqli_stmt, который вернула функция mysqli_stmt_init().

query

Текст запроса в виде строки. Запрос должен состоять из одного SQL-выражения.

Утверждение SQL может содержать ноль или более меток параметров, представленных знаками вопроса (?) в соответствующих позициях.

Замечание:

Метки параметров запроса можно встраивать только в определённые места в выражении. Например, они допустимы в списке VALUES() выражения INSERT (чтобы задать значения столбцов для строки), или в операциях сравнения предложения WHERE для задания сравниваемого значения. Однако, эти метки недопустимы в качестве идентификаторов (таких как имена столбцов или таблиц).

Возвращаемые значения

Возвращает true в случае успешного выполнения или false в случае возникновения ошибки.

Ошибки

Если уведомления об ошибках mysqli включены (MYSQLI_REPORT_ERROR) и запрошенная операция не удалась, выдаётся предупреждение. Если, кроме того, установлен режим MYSQLI_REPORT_STRICT, вместо этого будет выброшено исключение mysqli_sql_exception.

Примеры

Пример #1 Пример использования mysqli_stmt::prepare()

Объектно-ориентированный стиль

<?php

mysqli_report
(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");

$city = "Amersfoort";

/* Создаём подготовленное утверждение */
$stmt = $mysqli->stmt_init();
$stmt->prepare("SELECT District FROM City WHERE Name=?");

/* Связываем переменные с метками */
$stmt->bind_param("s", $city);

/* Выполняем запрос */
$stmt->execute();

/* Связываем переменные результата */
$stmt->bind_result($district);

/* Получаем значение */
$stmt->fetch();

printf("%s находится в районе %s\n", $city, $district);

Процедурный стиль

<?php

mysqli_report
(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$link = mysqli_connect("localhost", "my_user", "my_password", "world");

$city = "Amersfoort";

/* Создаём подготовленное утверждение */
$stmt = mysqli_stmt_init($link);
mysqli_stmt_prepare($stmt, "SELECT District FROM City WHERE Name=?");

/* Связываем переменные с метками */
mysqli_stmt_bind_param($stmt, "s", $city);

/* Выполняем запрос */
mysqli_stmt_execute($stmt);

/* Связываем переменные результата */
mysqli_stmt_bind_result($stmt, $district);

/* Получаем значение */
mysqli_stmt_fetch($stmt);

printf("%s находится в районе %s\n", $city, $district);

Результат выполнения приведённых примеров:

Amersfoort находится в районе Utrecht

Смотрите также

  • mysqli_stmt_init() - Инициализирует запрос и возвращает объект для использования в mysqli_stmt_prepare
  • mysqli_stmt_execute() - Выполняет подготовленное утверждение
  • mysqli_stmt_fetch() - Связывает результаты подготовленного выражения с переменными
  • mysqli_stmt_bind_param() - Привязка переменных к параметрам подготавливаемого запроса
  • mysqli_stmt_bind_result() - Привязка переменных к подготовленному запросу для размещения результата
  • mysqli_stmt_get_result() - Получает результат из подготовленного запроса в виде объекта mysqli_result
  • mysqli_stmt_close() - Закрывает подготовленный запрос

add a note add a note

User Contributed Notes 9 notes

up
17
logos-php at kith dot org
12 years ago
Note that if you're using a question mark as a placeholder for a string value, you don't surround it with quotation marks in the MySQL query.

For example, do this:

mysqli_stmt_prepare($stmt, "SELECT * FROM foo WHERE foo.Date > ?");

Do not do this:

mysqli_stmt_prepare($stmt, "SELECT * FROM foo WHERE foo.Date > '?'");

If you put quotation marks around a question mark in the query, then PHP doesn't recognize the question mark as a placeholder, and then when you try to use mysqli_stmt_bind_param(), it gives an error to the effect that you have the wrong number of parameters.

The lack of quotation marks around a string placeholder is implicit in the official example on this page, but it's not explicitly stated in the docs, and I had trouble figuring it out, so figured it was worth posting.
up
6
logos-php at kith dot orgpp
12 years ago
Turns out you can't directly use a prepared statement for a query that has a placeholder in an IN() clause.

There are ways around that (such as constructing a string that consists of n question marks separated by commas, then using that set of placeholders in the IN() clause), but you can't just say IN (?).

This is a MySQL restriction rather than a PHP restriction, but it's not really documented in the MySQL docs either, so I figured it was worth mentioning here.

(Btw, turns out someone else had previously posted the info that I put in my previous comment, about not using quotation marks. Sorry for the repeat; not sure how I missed the earlier comment.)
up
2
ndungi at gmail dot com
15 years ago
The `prepare` , `bind_param`, `bind_result`, `fetch` result, `close` stmt cycle can be tedious at times. Here is an object that does all the mysqli mumbo jumbo for you when all you want is a select leaving you to the bare essential `preparedSelect` on a prepared stmt. The method returns the result set as a 2D associative array with the `select`ed columns as keys. I havent done sufficient error-checking and it also may have some bugs. Help debug and improve on it.

I used the bible.sql db from http://www.biblesql.net/sites/biblesql.net/files/bible.mysql.gz.

Baraka tele!

============================

<?php

class DB
{
    public
$connection;
   
   
#establish db connection
   
public function __construct($host="localhost", $user="user", $pass="", $db="bible")
    {
       
$this->connection = new mysqli($host, $user, $pass, $db);
                 
        if(
mysqli_connect_errno())
        {
            echo(
"Database connect Error : "
           
. mysqli_connect_error($mysqli));
        }   
    }
   
   
#store mysqli object
   
public function connect()
    {
        return
$this->connection;
    }

   
#run a prepared query
   
public function runPreparedQuery($query, $params_r)
    {
       
$stmt = $this->connection->prepare($query);
       
$this->bindParameters($stmt, $params_r);

        if (
$stmt->execute()) {
            return
$stmt;
        } else {
            echo(
"Error in $statement: "
                     
. mysqli_error($this->connection));
            return
0;
        }
       
    }

# To run a select statement with bound parameters and bound results.
# Returns an associative array two dimensional array which u can easily 
# manipulate with array functions.

   
public function preparedSelect($query, $bind_params_r)
    {
       
$select = $this->runPreparedQuery($query, $bind_params_r);
       
$fields_r = $this->fetchFields($select);
       
        foreach (
$fields_r as $field) {
           
$bind_result_r[] = &${$field};
        }
       
       
$this->bindResult($select, $bind_result_r);
       
       
$result_r = array();
       
$i = 0;
        while (
$select->fetch()) {
            foreach (
$fields_r as $field) {
               
$result_r[$i][$field] = $$field;
            }
           
$i++;
        }
       
$select->close();
        return
$result_r;   
    }
   
   
   
#takes in array of bind parameters and binds them to result of
    #executed prepared stmt
   
   
private function bindParameters(&$obj, &$bind_params_r)
    {
       
call_user_func_array(array($obj, "bind_param"), $bind_params_r);
    }
   
    private function
bindResult(&$obj, &$bind_result_r)
    {
       
call_user_func_array(array($obj, "bind_result"), $bind_result_r);
    }
   
   
#returns a list of the selected field names
   
   
private function fetchFields($selectStmt)
    {
       
$metadata = $selectStmt->result_metadata();
       
$fields_r = array();
        while (
$field = $metadata->fetch_field()) {
           
$fields_r[] = $field->name;
        }

        return
$fields_r;
    }
}
#end of class

#An example of the DB class in use

$DB = new DB("localhost", "root", "", "bible");
$var = 5;
$query = "SELECT abbr, name from books where id > ?" ;
$bound_params_r = array("i", $var);

$result_r = $DB->preparedSelect($query, $bound_params_r);

#loop thru result array and display result

foreach ($result_r as $result) {
    echo
$result['abbr'] . " : " . $result['name'] . "<br/>" ;
}

?>
up
3
andrey at php dot net
19 years ago
If you select LOBs use the following order of execution or you risk mysqli allocating more memory that actually used

1)prepare()
2)execute()
3)store_result()
4)bind_result()

If you skip 3) or exchange 3) and 4) then mysqli will allocate memory for the maximal length of the column which is 255 for tinyblob, 64k for blob(still ok), 16MByte for MEDIUMBLOB - quite a lot and 4G for LONGBLOB (good if you have so much memory). Queries which use this order a bit slower when there is a LOB but this is the price of not having memory exhaustion in seconds.
up
2
kontakt at arthur minus schiwon dot de
16 years ago
If you wrap the placeholders with quotation marks you will experience warnings like "Number of variables doesn't match number of parameters in prepared statement" (at least with INSERT Statements).
up
0
mhradek AT gmail.com
16 years ago
A particularly helpful adaptation of this function and the call_user_func_array function:

// $params is sent as array($val=>'i', $val=>'d', etc...)

function db_stmt_bind_params($stmt, $params)
{
    $funcArg[] = $stmt;
    foreach($params as $val=>$type)
    {
        $funcArg['type'] .= $type;
        $funcArg[] = $val;
    }
    return call_user_func_array('mysqli_stmt_bind_param', $funcArgs);
}

Thanks to 'sned' for the code.
up
0
st dot john dot johnson at gmail dot com
17 years ago
In reference to what lachlan76 said before, stored procedures CAN be executed through prepared statements as long as you tell the DB to move to the next result before executing again.

Example (Five calls to a stored procedure):

<?php
for ($i=0;$i<5;$i++) {
 
$statement = $mysqli->stmt_init();
 
$statement->prepare("CALL some_procedure( ? )");

 
// Bind, execute, and bind.
 
$statement->bind_param("i", 1);
 
$statement->execute();
 
$statement->bind_result($results);

  while(
$statement->fetch()) {
   
// Do what you want with your results.
 
}

 
$statement->close();

 
// Now move the mysqli connection to a new result.
 
while($mysqli->next_result()) { }
}
?>

If you include the last statement, this code should execute without the nasty "Commands out of sync" error.
up
-1
lukaszNOSPAMPLEASE at epas dot pl
16 years ago
i've got some bad news for you guys if you haven't found out already.
the trick with mysqli_next_result() only prevents having the connection dropped after a stored procedure call.
apparently you can bind parameters for a prepared stored procedure call, but you'll get messed up records from mysqli_stmt_fetch() after mysqli_stmt_bind_result(), at least when the stored procedure itself contains a prepared statement.
a way to avoid data corruption could be specifying the CLIENT_MULTI_STATEMENTS flag in mysqli_real_connect(), if it wasn't disabled entirely (for security reasons, as they say). another option is to use mysqli_multi_query(), but then you can't bind at all.
up
-1
lachlan76 at gmail dot com
18 years ago
Do not try to use a stored procedure through a prepared statement.

Example:

<?php
$statement
= $mysqli->stmt_init();
$statement->prepare("CALL some_procedure()");
?>

If you attempt to do this, it will fail by dropping the connection during the next query.  Use mysqli_multi_query instead.

Example:

<?php
$mysqli
->multi_query("CALL some_procedure()");
do
{
 
$result = $mysqli->store_result();

  
// Do your processing work here 
 
 
$result->free();
} while(
$mysqli->next_result());
?>

This means that you cannot bind parameters or results, however.
To Top