Немного о подготавливаемых запросах PHP


В этой небольшой заметке я расскажу о подготавливаемые запросах и том, как их создавать на PHP для расширения MySQLi.

Как обычно вообще новички пишут код для работы с базой данных на языке PHP? Как правило, все начинается с чего-то подобного:

$db = mysql_connect ("localhost","bd_user","passowrd");
@mysql_query("SET NAMES utf8");
@mysql_query("SET CHARACTER SET utf8");
@mysql_query("SET character_set_client = utf8");
@mysql_query("SET character_set_connection = utf8");
@mysql_query("SET character_set_results = utf8");
mysql_select_db ("bd_name",$db);
$result = mysql_query("SELECT * FROM table WHERE id=$id",$db); 
$myrow = mysql_fetch_array($result);
Дальше уже начинающий программист начинает осваивать расширения PHP и знакомится с MYSQLi и/или PDO. И уже начинает писать как-то так

$conn = new mysqli("localhost", " bd_user", " passowrd", " bd_name");
$conn ->set_charset("utf8");
if ($conn->connect_error) die("Ошибка: невозможно подключиться: " . $conn->connect_error);
$query = "INSERT INTO `table` (`name`) 
VALUES ('$name');";
mysqli_query($conn, $query) or die (mysqli_error($conn));
Потом сталкивается с тем, что иногда в данных имеются апострофы и начинает использовать такие конструкции перед вставкой

$txt_esc = $conn->real_escape_string($txt);
Потом узнает об SQL инъекциях и начинает проверять данные перед выполнением запросов. Приводит их к типу int(если числа), убирает подозрительные символы и конструкции и так далее. И, наконец, приходит к подготавливаемым запросам. Такие запросы работают с любыми символами, имеют защиту от инъекций, да и просто удобны. Вот как, например, можно получить информацию (SELECT)

$sql = "SELECT * FROM table WHERE id = ? ";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $id); 
$stmt->execute(); 
$result = $stmt->bind_result();
$rows = $result->fetch_all(MYSQLI_ASSOC);
Или так

function prepared_query($mysqli, $sql, $params, $types = ""){
    $types = $types ?: str_repeat("s", count($params));
    $stmt = $mysqli->prepare($sql);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    return $stmt;
}

function get_file($name){
    global $conn;
    $film = array();
	$sql = "SELECT * FROM files WHERE name = ? LIMIT 1";
	$stmt = prepared_query($conn, $sql, [$name]);
	if ($row = $stmt->get_result()->fetch_assoc()){
		$film = $row;
	}
    return $film;
}
А так вставить строку

function insert_film($name){
    global $conn;
    $stmt = $conn->prepare("INSERT INTO `films` (`name`) VALUES (?)");
    $stmt->bind_param("s", $name);
    if ($stmt->execute()) {
        $id =  $conn->insert_id;
    } 
    $stmt->close();
    return $id;
}
Теперь ложка дегтя. Не всегда подготавливаемые запросы можно использовать и даже в серьезных проектах не везде они встречаются, хотя и обладают рядом существенных достоинств. Почему? Основная причина – их сложно менять динамически.

То есть, например, берем мы запрос поиска с набором параметров, заранее неизвестных и что делать? В случае обычного запроса мы просто меняем переменную, генерируем её сами по полям (AND AND AND) , подставляем и выполняем. А для подготавливаемого так не получится.

В общем, тут как обычно в программировании – для каждой ситуации используется свой инструмент.
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегизаметки, php, mysqli, sql




Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Коллекции Java: введение
Java и MySQL
Apache и Nginx