PDO (Объекты данных PHP) является уровнем абстракции доступа к данным (интерфейс) для PHP. Это работает с большинством систем баз данных.

PDO обеспечивает уровень абстракции доступа к данным, что означает, что, независимо от которой базы данных Вы используете, Вы используете те же функции для издания данных выборки и запросов. PDO не обеспечивает абстракцию базы данных; это не переписывает SQL или эмулирует недостающие возможности. Необходимо использовать полноценный уровень абстракции при необходимости в том средстве.

Источник — https://php.net/manual/en/intro.pdo.php

Соединение

PDO использует DSN для определения соединения с базой данных. Это также имеет много опций соединения, которые могут помочь Вам подстроить свой экземпляр PDO. Некоторые из этих опций стоит установить по умолчанию. Вот пример:

$dsn = "mysql:host=localhost;dbname=test;charset=utf8"; $opt = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); $pdo = new PDO($dsn,'root','', $opt); 

Давайте более тщательно изучим этот код:

  • $dsn содержит драйвер базы данных (mysql), хост (localhost), имя базы данных (тест) и набор символов (utf8). Конечно, эти параметры могут быть заменены переменными также.
  • После $dsn прибывает имя пользователя и пароль.
  • $opt параметр является массивом, содержит параметры конфигурации.

Рекомендуется установить ERRMODE_EXCEPTION поскольку это позволит PDO выдать исключения на ошибках; этот режим является самым надежным способом обработать ошибки PDO.
Установка ATTR_DEFAULT_FETCH_MODE также хорошая идея. Это сохраняет Вас имеющий необходимость включать его с каждой выборкой, делая Ваш код приложения менее чрезмерно увеличенным в размерах.

Существует много плохих примеров вокруг сообщения Вам перенести каждый оператор PDO в try..catch - таким образом я должен сделать отличное примечание:

НЕ используйте try..catch оператор только для обработки сообщения об ошибке. Неперехваченные исключения уже превосходны с этой целью, поскольку они будут рассматривать ошибки PDO просто тем же способом как другие ошибки PHP - так, можно определить поведение, использующее по всему сайту настройки.
Пользовательский обработчик исключений мог быть добавлен позже, но он не требуется. Для новых пользователей особенно, рекомендуется использовать необработанные исключения, поскольку они чрезвычайно информативны, полезны и безопасны.
Подробнее...

Подготовленные операторы

Подготовленные операторы являются одной из главных причин для использования PDO.
Путь, как это работает, объяснен здесь: Как подготовленные операторы могут защитить от атак с использованием кода на SQL? Так, здесь следует правилам использования PDO:

  • Каждый динамический литерал данных должен быть представлен в запросе любым именем (:name) или регулярный заполнитель (?).
  • Каждый запрос должен быть выполнен в 3 (или 4) шаги:
    • prepare() - подготовит запрос и создаст объект оператора.
    • bindValue() / bindParam() - это - дополнительный шаг, поскольку переменные могут быть переданы непосредственно в execute().
    • execute() - на самом деле выполнит запрос.
    • fetch* - возвратит результат запроса в применимой форме.

Некоторые эмпирические правила:

  • Используйте названных заполнителей, только если Вам нужен сложный запрос или если у Вас уже есть ассоциативный массив, какие ключи равны названиям поля таблицы. Иначе регулярные заполнители более просты использовать.
  • Используйте "ленивую" привязку, когда возможный - передающие данные в выполняются, существенно сократит Ваш код.
  • Если Вы не знаете, нужно ли Вам bindValue() или bindParam(), пойдите для первого. bindValue() менее неоднозначно и имеет меньше побочных эффектов.

Так, вот пример:

$id = 1; $stm = $pdo->prepare("SELECT name FROM table WHERE id=?"); $stm->execute(array($id)); $name = $stm->fetchColumn(); 

Получение результатов

PDO имеет некоторые чрезвычайно удобные методы для возврата результата запроса в различных форматах:

  • fetch() - метод выборки общего назначения, подобный mysql_fetch_array().
  • fetchAll() получить все строки без цикла с условием продолжения.
  • fetchColumn() получить единственную скалярную величину, не получая массив сначала.

fetchAll() очень удобная функция, когда Вы делаете себя знакомыми с разделением бизнес-логики от логики представления. Это позволяет Вам получить данные сначала и затем использовать его для отображения:

$stm = $pdo->prepare("SELECT id,name FROM news WHERE dt=curdate()"); $stm->execute(); $data = $stm->fetchAll(); 

Теперь у нас есть все новости в $data массив и мы можем переместиться в часть презентации:

?> <table> <? foreach ($data as $row): ?> <tr> <td> <a href="news.php?<?=$row['id']?>"> <?=htmlspecialchars($row['name'])?> </a> </td> </tr> <? endforeach ?> 

Сложные случаи

Хотя подготовленные операторы являются хорошими вещами в целом, существуют некоторые хорошие советы, приемы и ловушки для знания о. В первую очередь, нужно понять, что заполнители не могут представить произвольную часть запроса, но полный литерал данных только. Ни часть литерала, ни независимо от того, что сложным выражением или ключевым словом синтаксиса можно заменить с подготовленным оператором.

Вот некоторые типичные случаи:

Операторы PDO Prepared и КАК

Подготовьте полный литерал сначала:

$name = "%$name%"; $stm = $pdo->prepare("SELECT * FROM table WHERE name LIKE ?"); $stm->execute(array($name)); $data = $stm->fetchAll(); 

Операторы PDO Prepared и ПРЕДЕЛ

Когда в режиме эмуляции (который идет по умолчанию), PDO заменяет заполнителями с фактическими данными. И с "ленивой" привязкой (использующий массив в execute()), PDO рассматривает каждый параметр как строку. В результате подготовленное LIMIT ?,? запрос становится LIMIT '10', '10' который является недопустимым синтаксисом, который заставляет запрос перестать работать.

Существует два решения:

  • Выключите эмуляцию (поскольку MySQL может уладить всех заполнителей правильно).
  • Свяжите число явно и установку надлежащего типа (PDO:: PARAM_INT) для этой переменной.

Для выключения эмуляции можно выполнить этот код (или установить в массиве options соединения):

$conn->setAttribute( PDO::ATTR_EMULATE_PREPARES, false ); 

Или связывать эти переменные явно с типом параметрического усилителя:

$stm = $pdo->prepare('SELECT * FROM table LIMIT ?, ?'); $stm->bindParam(1, $limit_from,PDO::PARAM_INT); $stm->bindParam(2, $per_page,PDO::PARAM_INT); $stm->execute(); $data = $stm->fetchAll(); 

Операторы PDO Prepared и В

Невозможно занять место, произвольная часть запроса с помощью PDO подготовила операторы. Для таких случаев как IN() оператор, нужно создать ряд ?s вручную и помещенный их в запрос:

$arr = array(1,2,3); $in = str_repeat('?,', count($arr) - 1) . '?'; $sql = "SELECT * FROM table WHERE column IN ($in)"; $stm = $db->prepare($sql); $stm->execute($arr); $data = $stm->fetchAll(); 

Операторы PDO Prepared и идентификаторы.

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

  • Включите идентификатор в обратные галочки.
  • Обратные галочки Escape внутри путем удвоения их.

Код был бы:

$table = "`".str_replace("`","``",$table)."`"; 

После такого форматирования безопасно вставить $table переменная в запрос.

Также важно всегда проверить динамические идентификаторы по списку позволенных значений. Вот краткий пример (от того, Как я могу предотвратить Внедрение SQL в PHP?):

$orders = array("name","price","qty"); //field names $key = array_search($_GET['sort'],$orders); // see if we have such a name $orderby = $orders[$key]; //if not, first one will be set automatically. smart enuf :) $query = "SELECT * FROM `table` ORDER BY $orderby"; //value is safe 

другой пример мог быть найден ниже:

Операторы PDO Prepared и ВСТАВЛЯЮТ/ЗАПРОС НА ОБНОВЛЕНИЕ

(от Вставляют/обновляют функцию помощника, использующую PDO),
Обычный PDO-подготовленный оператор Запроса на вставку состоит из 2-5 килобайтов повторного кода, при этом каждое имя поля повторяется шесть - десять раз. Вместо этого нам нужна компактная функция помощника для обработки переменного количества вставленных полей. Конечно, с поверхностью управляют для этих полей, для разрешения только утвержденных полей в запрос.

Следующий код основан на предположении, что имена полей HTML-формы равны названиям поля таблицы SQL. Это также использует уникальную функцию MySQL разрешения операторов НАБОРА и для ВСТАВКИ и для Запросов на обновление:

function pdoSet($fields, &$values, $source = array()) { $set = ''; $values = array(); if (!$source) $source = &$_POST; foreach ($fields as $field) { if (isset($source[$field])) { $set.="`".str_replace("`","``",$field)."`". "=:$field, "; $values[$field] = $source[$field]; } } return substr($set, 0, -2); } 

Эта функция произведет корректную последовательность для оператора SET,

`field1`=:field1,`field2`=:field2 

быть вставленным в запрос и $values массив для execute().
Может использоваться этот путь:

$allowed = array("name","surname","email"); // allowed fields $sql = "INSERT INTO users SET ".pdoSet($allowed,$values); $stm = $dbh->prepare($sql); $stm->execute($values); 

Или, для более сложного случая:

$allowed = array("name","surname","email","password"); // allowed fields $_POST['password'] = MD5($_POST['login'].$_POST['password']); $sql = "UPDATE users SET ".pdoSet($allowed,$values)." WHERE id = :id"; $stm = $dbh->prepare($sql); $values["id"] = $_POST['id']; $stm->execute($values);