Запросы к БД через PDO

Опубликовано: 01 Окт 2017

Взято тут.

В MODX предусмотрены 2 основных способа работы с базой данных — через xPDO и через PDO. По первому способу информации достаточно много. Как правило, разработчики работают с БД именно через xPDO. Но бывают такие случаи, когда нужно использовать PDO. Например, быстро добавить какое-нибудь значение в свою таблицу или написать сложный запрос. В этом случае разработчик должен понимать, что он делает, потому что в связи между таблицами, в отличие от xPDO, не работают и могут возникнуть проблемы со ссылочной целостностью.

При работе с xPDO используются классы и схемы, в которых указаны типы данных, их связи. Поэтому, если вы хотите обратиться к пользовательским классам, вам предварительно нужно загрузить модель данных и только потом строить запросы. А в случае с PDO, вы можете написать обычный SQL-запрос и отправить его на сервер.

Основные методы PDO — xPDO::query($sql), xPDO::exec($sql) и xPDO::prepare()/PDOStatement::execute(). По ним и пробежимся.

xPDO::exec($sql)

Этот метод запускает SQL запрос на выполнение и возвращает количество строк, задействованных в ходе его выполнения. Данные в SQL запросе должны быть правильно экранированы.

// Удаляем все неактивные записи из произвольной таблицы
$sql = "DELETE FROM myTable WHERE active = 0";
$count = $modx->exec($sql);
// Получим количество удаленных записей
print("Удалено $count записей.");

Важно запомнить, что этот метод возвращает только количество строк. Т.е. оператор SELECT в данном случае используется, как если бы запрос был SELECT COUNT(*).

$sql = "SELECT * FROM modx_users WHERE sudo = 1";
$count = $modx->exec($sql);
// Получим количество администраторов с правами SUDO
print("Количество пользователей с неограниченными правами - $count.");

Если нужно получить результат выборки, то нужно использовать методы, о которых я расскажу дальше.

xPDO::query($sql)

Этот метод выполняет SQL запрос и возвращает результирующий набор в виде объекта PDOStatement. Опять же, данные должны быть уже подготовлены и экранированы. Иначе можно пропустить SQL инъекцию.

PDO::query() возвращает объект PDOStatement или FALSE, если запрос выполнить не удалось.

$sql = "SELECT * FROM modx_users WHERE active = 1";
// Вариант 1.
$statement = $modx->query($sql);
$users = $statement->fetchAll(PDO::FETCH_ASSOC);
foreach ($users as $user) {
    print $user['username'] .'<br/>';
}
// Вариант 2. Если не нужно зачитывать данные в массив
foreach ($modx->query($sql) as $user) {
    print $user['username'] .'<br/>';
}

Узнать количество записей, задействованных в последнем запросе, можно с помощью специального метода PDOStatement::rowCount().

$count = $statement->rowCount();

Если в запросе используются переменные или запрос планируется использовать несколько раз, то для этих случаев подойдут подготовленные выражения (prepared statements).

xPDO::prepare($sql) и PDOStatement::execute()

Смысл подготовленных выражений заключается в том, что заранее подготавливается шаблон SQL запроса, который при запуске настраивается с помощью специальных плейсхолдеров. Преимущества подготовленного запроса:

  • Не нужно подготавливать запрос каждый раз. Немного повышает производительность системы.
  • Запрос не нужно экранировать, драйвер БД может делает это автоматически — что значительно снижает риск получить SQL инъекцию.

PDO поддерживает 2 вида плейсхолдеров — позиционные (?), для которых важен порядок передаваемых переменных, и именованные (:name), для которых порядок не важен.

// 1. Позиционный плейсхолдер
$sql = 'SELECT name FROM modx_users WHERE email = ?';
// Подготавливаем шаблон SQL запроса
$statement = $modx->prepare($sql);
// Выполняем запрос подставляя данные
$result = $statement->execute(array($_GET['email']));

// 2. Именованный плейсхолдер
$sql = 'SELECT name FROM modx_users WHERE email = :email';
// Подготавливаем шаблон SQL запроса
$statement = $modx->prepare($sql);
// Выполняем запрос подставляя данные
$result = $statement->execute(array('email'=>$_GET['email']));

При таком подходе невозможно подсунуть SQL инъекцию, даже если подставлять необработанные данные (см. пример). Кроме того, подготовив один раз запрос, можно несколько раз выполнить метод execute() подставляя разные значения.

Ещё передать данные в подготовленный запрос можно используя специальные методы PDOStatement::bindParam() и PDOStatement::bindValue(). Подробнее про них можно прочитать в официальной документации.

Важно понимать, что работая с БД через PDO ответственность за корректность SQL запроса, ссылочную целостность данных и безопасность ложится целиком на программиста. Поэтому я советую использовать возможности xPDO.

Комментарии (0)


Оставить комментарий




Разрешённые теги: <b><i><br>Добавить новый комментарий: