php pdo class mysql
Php pdo class mysql
A PHP MySQL PDO class similar to the Python MySQLdb, which supports iterator and parameter binding when using «WHERE IN» statement.
Copy the files under src/ to your program
Preventing SQL Injection Attacks
Safety: Use parameter binding method
Unsafety: Split joint SQL string
id | name | color |
---|---|---|
1 | apple | red |
2 | banana | yellow |
3 | watermelon | green |
4 | pear | yellow |
5 | strawberry | red |
Fetching with Bindings (ANTI-SQL-INJECTION):
WHERE IN (needs named placeholder):
Delete / Update / Insert
These operations will return the number of affected result set. (integer)
Get Last Insert ID
Get the number of queries since the object initialization
Use iterator when you want to read thousands of data from the database for statistical or full update of Elastic Search or Solr indexes.
Iterator is a traversable object that does not read all the data queried from MySQL into memory.
So you can safely use foreach to handle millions of MySQL result sets without worrying about excessive memory usage.
About
A PHP MySQL PDO class similar to the the Python MySQLdb, which supports iterator and parameter binding when using «WHERE IN» statement.
Почему стоит пользоваться PDO для работы с базой данных
Перевод статьи Why you Should be using PHP’s PDO for Database Access.
Множество PHP-разработчиков привыкли использовать для работы с базами данных расширения mysql и mysqli. Но с версии 5.1 в PHP существует более удобный способ — PHP Data Objects. Этот класс, сокращенно именуемый PDO, предоставляет методы для работы с объектами и prepared statements, которые заметно повысят вашу продуктивность!
Введение в PDO
«PDO – PHP Data Objects – это прослойка, которая предлагает универсальный способ работы с несколькими базами данных.»
Поддержка СУБД
Подключение
Способы подключения к разным СУБД могут незначительно отличаться. Ниже приведены примеры подключения к наиболее популярным из них. Можно заметить, что первые три имеют идентичный синтаксис, в отличие от SQLite.
Пожалуйста, обратите внимание на блок try/catch – всегда стоит оборачивать в него все свои PDO-операции и использовать механизм исключений (об этом чуть дальше).
$DBH расшифровывается как «database handle» и будет использоваться на протяжении всей статьи.
Закрыть любое подключение можно путем переопределения его переменной в null.
Больше информации по теме отличительных опций разных СУБД и методах подключения к ним можно найти на php.net.
Исключения и PDO
PDO умеет выбрасывать исключения при ошибках, поэтому все должно находиться в блоке try/catch. Сразу после создания подключения, PDO можно перевести в любой из трех режимов ошибок:
Но стоит заметить, что ошибка при попытке соединения будет всегда вызывать исключение.
PDO::ERRMODE_SILENT
Это режим по умолчанию. Примерно то же самое вы, скорее всего, используете для отлавливания ошибок в расширениях mysql и mysqli. Следующие два режима больше подходят для DRY программирования.
PDO::ERRMODE_WARNING
Этот режим вызовет стандартный Warning и позволит скрипту продолжить выполнение. Удобен при отладке.
PDO::ERRMODE_EXCEPTION
В большинстве ситуаций этот тип контроля выполнения скрипта предпочтителен. Он выбрасывает исключение, что позволяет вам ловко обрабатывать ошибки и скрывать щепетильную информацию. Как, например, тут:
В SQL-выражении есть синтаксическая ошибка, которая вызовет исключение. Мы можем записать детали ошибки в лог-файл и человеческим языком намекнуть пользователю, что что-то случилось.
Insert и Update
Вставка новых и обновление существующих данных являются одними из наиболее частых операций с БД. В случае с PDO этот процесс обычно состоит из двух шагов. (В следующей секции все относится как к UPDATE, так и INSERT)
Тривиальный пример вставки новых данных:
Вообще-то можно сделать то же самое одним методом exec(), но двухшаговый способ дает все преимущества prepared statements. Они помогают в защите от SQL-инъекций, поэтому имеет смысл их использовать даже при однократном запросе.
Prepared Statements
Использование prepared statements укрепляет защиту от SQL-инъекций.
Prepared statement — это заранее скомпилированное SQL-выражение, которое может быть многократно выполнено путем отправки серверу лишь различных наборов данных. Дополнительным преимуществом является невозможность провести SQL-инъекцию через данные, используемые в placeholder’ах.
Ниже находятся три примера prepared statements.
Первый пример здесь лишь для сравнения, его стоит избегать. Разница между безымянными и именными placeholder’ами в том, как вы будете передавать данные в prepared statements.
Безымянные placeholder’ы
Здесь два шага. На первом мы назначаем всем placeholder’ам переменные (строки 2-4). Затем назначаем этим переменным значения и выполняем запрос. Чтобы послать новый набор данных, просто измените значения переменных и выполните запрос еще раз.
Если в вашем SQL-выражении много параметров, то назначать каждому по переменной весьма неудобно. В таких случаях можно хранить данные в массиве и передавать его:
Именные placeholder’ы
Здесь тоже можно передавать массив, но он должен быть ассоциативным. В роли ключей должны выступать, как можно догадаться, имена placeholder’ов.
Одним из удобств использования именных placeholder’ов является возможность вставки объектов напрямую в базу данных, если названия свойств совпадают с именами параметров. Вставку данных, к примеру, вы можете выполнить так:
Преобразование объекта в массив при execute() приводит к тому, что свойства считаются ключами массива.
Выборка данных
FETCH_ASSOC
При этом формате создается ассоциативный массив с названиями столбцов в виде индексов. Он должен быть знаком тем, кто использует расширения mysql/mysqli.
Цикл while() переберет весь результат запроса.
FETCH_OBJ
Данный тип получения данных создает экземпляр класса std для каждой строки.
FETCH_CLASS
При использовании fetch_class данные заносятся в экземпляры указанного класса. При этом значения назначаются свойствам объекта ДО вызова конструктора. Если свойства с именами, соответствующими названиям столбцов, не существуют, они будут созданы автоматически (с областью видимости public).
Если ваши данные нуждаются в обязательной обработке сразу после их получения из базы данных, ее можно реализовать в конструкторе класса.
Для примера возьмем ситуацию, когда вам нужно скрыть часть адреса проживания человека.
При создании объекта все латинские буквы в нижнем регистре должны замениться на x. Проверим:
Если в базе данных адрес выглядит как ’5 Rosebud’, то на выходе получится ’5 Rxxxxxx’.
Конечно, иногда будет требоваться, чтобы конструктор вызывался ПЕРЕД присваиванием значений. PDO такое тоже позволяет.
Теперь, когда вы дополнили предыдущий пример дополнительной опцией (PDO::FETCH_PROPS_LATE), адрес видоизменяться не будет, так как после записи значений ничего не происходит.
Наконец, при необходимости можно передавать конструктору аргументы прямо при создании объекта:
Можно даже передавать разные аргументы каждому объекту:
Другие полезные методы
Хотя эта статья не может (и не пытается) охватить все аспекты работы с PDO (это огромный модуль!), оставить без упоминания следующие несколько функций нельзя.
Функции MySQL (PDO_MYSQL)
Введение
PDO_MYSQL по умолчанию использует эмулированную подготовку.
При запуске PHP до версии 7.1.16 или PHP 7.2 до 7.2.4, установите плагин пароля по умолчанию MySQL 8 Server в mysql_native_password, иначе вы увидите ошибки, похожие на The server requested authentication method unknown to the client [caching_sha2_password], даже когда caching_sha2_password не используется.
Осторожно: Некоторые типы MySQL таблиц (механизмы хранения, движков) не поддерживают транзакции. При написании кода с использованием транзакций применительно к таблицам, которые их не поддерживают, MySQL будет считать, что транзакция была начата успешно. Кроме того, выполнение любого DDL-запроса завершит все открытые транзакции, а также выполнит весь стек не завершённых запросов.
Драйвер MySQL не поддерживает должным образом PDO::PARAM_INPUT_OUTPUT через PDOStatement::bindParam() ; хотя параметр можно использовать, он не обновляется (т.е. фактический вывод игнорируется).
Установка
Обычно установочные пакеты Unix имеют в своём составе бинарные пакеты PHP. Несмотря на то, что эти бинарные пакеты обычно собраны с поддержкой модуля MySQL, может понадобиться установка библиотек модулей отдельно. Проверьте свой дистрибутив на наличие нужных библиотек через пакетный менеджер.
К примеру, на Ubuntu установка пакета php5-mysql устанавливает модули ext/mysql, ext/mysqli, и PDO_MYSQL. На CentOS пакет php-mysql также устанавливает эти три модуля.
Также вы всегда можете скомпилировать необходимые модули самостоятельно. Сборка PHP из исходных кодов позволит вам собрать именно те модули MySQL, которые вам нужны, а также выбрать нужную клиентскую библиотеку для каждого модуля.
Предопределённые константы
Перечисленные ниже константы определены данным драйвером и будут доступны только в случае, если PHP был собран с поддержкой этого модуля, или данный модуль был динамически загружен во время выполнения. Вдобавок, эти зависимые от драйвера константы должны быть использованы только совместно с этим драйвером. Использование атрибутов, специфичных для некоторого драйвера с другим драйвером может вызвать неожиданное поведение. Если ваш код выполняется с несколькими драйверами, то можно использовать функцию PDO::getAttribute() для получения атрибута PDO::ATTR_DRIVER_NAME для проверки драйвера.
Пример #1 Буферизация запросов в MySQL
PDO::MYSQL_ATTR_LOCAL_INFILE ( int )
Обратите внимание, что эта константа может быть использована только в массиве driver_options при создании дескриптора новой базы данных.
PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY ( string )
Позволяет ограничить загрузку LOCAL DATA файлами, расположенными в указанном каталоге.
Обратите внимание, что эта константа может использоваться только в массиве driver_options при создании нового дескриптора базы данных.
PDO::MYSQL_ATTR_INIT_COMMAND ( int )
Команда, которую необходимо выполнить при подключении к MySQL-серверу. Также будет автоматически выполнена при переподключении.
Обратите внимание, что эта константа может быть использована только в массиве driver_options при создании дескриптора новой базы данных.
PDO::MYSQL_ATTR_READ_DEFAULT_FILE ( int )
PDO::MYSQL_ATTR_READ_DEFAULT_GROUP ( int )
PDO::MYSQL_ATTR_MAX_BUFFER_SIZE ( int )
Максимальный размер буфера. По умолчанию равен 1 Мб. Эта константа не поддерживается при компиляции вместе с mysqlnd.
PDO::MYSQL_ATTR_DIRECT_QUERY ( int )
Выполнять прямые запросы, не использовать подготовленные конструкции.
PDO::MYSQL_ATTR_FOUND_ROWS ( int )
Возвращает количество найденных (совпавших) строк, а не количество изменённых строк.
PDO::MYSQL_ATTR_IGNORE_SPACE ( int )
Разрешает пробелы после имён функций. Делает все имена функций зарезервированными словами.
PDO::MYSQL_ATTR_COMPRESS ( int )
Включить сжатие сетевого соединения.
PDO::MYSQL_ATTR_SSL_CA ( int )
Путь к файлу сертификата SSL.
PDO::MYSQL_ATTR_SSL_CAPATH ( int )
Путь к директории, которая содержит SSL-сертификаты доверенных центров (CA), хранящиеся в формате PEM.
PDO::MYSQL_ATTR_SSL_CERT ( int )
Путь к файлу с SSL-сертификатом.
PDO::MYSQL_ATTR_SSL_CIPHER ( int )
Список из одного или более допустимых шифров для использования в SSL-шифровании в формате, который понимает OpenSSL. Например: DHE-RSA-AES256-SHA:AES128-SHA
PDO::MYSQL_ATTR_SSL_KEY ( int )
Путь к файлу с ключом SSL.
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT ( int )
Предоставляет способ отключения проверки SSL-сертификата сервера.
Существует, начиная с PHP 7.0.18 и PHP 7.1.4.
PDO::MYSQL_ATTR_MULTI_STATEMENTS ( int )
Обратите внимание, что эта константа может быть использована только в массиве driver_options при создании нового дескриптора БД.
Настройка во время выполнения
Имя | По умолчанию | Место изменения |
---|---|---|
pdo_mysql.default_socket | «/tmp/mysql.sock» | PHP_INI_SYSTEM |
pdo_mysql.debug | NULL | PHP_INI_SYSTEM |
Для подробного описания констант PHP_INI_*, обратитесь к разделу Где могут быть установлены параметры конфигурации.
Краткое разъяснение конфигурационных директив.
Устанавливает сокет домена UNIX. Эту опцию необходимо указать во время компиляции, если сокет домена найден во время конфигурирования. Эта настройка только для Unix.
Разрешает отладку для PDO_MYSQL. Эта настройка доступна только, если PDO_MYSQL скомпилирован с «mysqlnd» и в режиме отладки PDO.
Содержание
User Contributed Notes 8 notes
There is an important undocumented attribute which disables certificate CN verification available after
5.6.22 (not sure), 7.0.18 (verified) and 7.1.15 (not sure)
possible values: true, false
default value: true
After spending hours trying to track down why we were getting this error on a new server, after the same code ran fine on other servers, we found the problem to be an old MySQL _client_ library running on our web server, and a latest-version MySQL _server_ running on the database server’s box.
Upgraded the MySQL client on the web server to the current revision and the problem went away.
To use «PDO::MYSQL_ATTR_USE_BUFFERED_QUERY» you should call
PDO::setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
It will not work when passed into PDO::prepare()
I have been getting the error below when performing multiple queries within a single page.
Setting the attribute below did not seem to work for me.
So building on previous example i am initilizing my stmt variable on every query and a fetch all into an array. Seems to be working for me.
Error:
PDO Error 1.1: Array ( [0] => xxx[1] => yyy[2] => Lost connection to MySQL server during query )
Today’s PHP snapshot now has SSL support for PDO. Follow the directions here ( http://dev.mysql.com/doc/refman/5.0/en/secure-create-certs.html ) to set up MySQL and then use the following connection options:
This one can be a royal pain to deal with. Never stack statements to be executed in one go. Nobody ever mentions this possibility in all the posts I’ve seen dealing with this error.
This example is a Zend Framework example but the theory is the same.
If you have the error ‘could not find driver’ and won’t able to install driver for newer linux(Fedora, Redhat, CentOS) with latest PHP7/MariaDB10/Apache2.4 get this package installed and get every things smooth.
First download latest version of epel and remi for your distribution. This links is for Fedora 26:
Know you can use remi repository to gest php-pdo and php-mysql.
Restart the Apache
systemctl stop httpd
systemctl start httpd
Класс PDO
(PHP 5 >= 5.1.0, PHP 7, PHP 8, PECL pdo >= 0.1.0)
Введение
Представляет соединение между PHP и сервером базы данных.
Обзор классов
Содержание
User Contributed Notes 9 notes
«And storing username/password inside class is not a very good idea for production code.»
Good idea is to store database connection settings in *.ini files but you have to restrict access to them. For example this way:
my_setting.ini:
[database]
driver = mysql
host = localhost
;port = 3306
schema = db_schema
username = user
password = secret
I personnaly create a new instance of PDO like this :
$dbDatas = parse_ini_file( DB_FILE );
$dbOptions = [
\PDO::ATTR_DEFAULT_FECTH_MODE => \PDO::FETCH_OBJ,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
];
PDO and Dependency Injection
Dependency injection is good for testing. But for anyone wanting various data mapper objects to have a database connection, dependency injection can make other model code very messy because database objects have to be instantiated all over the place and given to the data mapper objects.
The code below is a good way to maintain dependency injection while keeping clean and minimal model code.
Starting with PHP 5.4 you are unable to use persistent connections when you have your own database class derived from the native PDO class. If your code uses this combination, you will encounter segmentation faults during the cleanup of the PHP process.
You can still use _either_ a derived PDO class _or_ persistent connections.
For more information, please see this bug report: https://bugs.php.net/bug.php?id=63176
Keep in mind, you MUST NOT use ‘root’ user in your applications, unless your application designed to do a database maintenance.
And storing username/password inside class is not a very good idea for production code. You would need to edit the actual working code to change settings, which is bad.
Here is an singleton PDO example:
[db_options]
PDO::MYSQL_ATTR_INIT_COMMAND=set names utf8
p0vidl0.info
Кодинг, админинг и прочие развлечения
PHP PDO — работаем с базами данных правильно
Термин PDO является сокращением понятия PHP Data Objects. Как можно судить по названию, эта технология позволяет работать с содержимым базы данных через объекты.
Почему не myqli или mysql?
Чаще всего, в отношении новых технологий, встает вопрос их преимуществ перед старыми-добрыми и проверенными инструментами, а также, перевода на них текущих и старых проектов.
Объектная ориентированность PDO
PHP развивается очень активно и стремится стать одним из лучших инструментов для быстрой разработки веб приложений как массового, так и корпоративного уровня.
Говоря о PHP, будем подразумевать современный объектно-ориентированный PHP, позволяющий писать универсальный код, удобный для тестирования и повторного использования.
Использование PDO позволяет вынести работу с базой данных на объектно-ориентированный уровень и улучшить переносимость кода. На самом деле, использование PDO не так сложно, как можно было бы подумать.
Абстракция
Представим, что мы уже продолжительное время разрабатываем приложение, с использованием MySQL. И вот, в один прекрасный момент, появляется необходимость заменить MySQL на PostgreSQL.
Как минимум, нам придется заменить все вызовы mysqli_connect() (mysql_connect()) на pg_connect() и, по аналогии, другие функции, используемые для запроса и обработки данных.
При использовании PDO, мы ограничимся изменением нескольких параметров в файлах конфигурации.
Связывание параметров
Использование связанных параметров предоставляет большую гибкость в составлении запросов и позволяет улучшить защиту от SQL инъекций.
Получение данных в виде объектов
Те, кто уже использует ORM (object-relational mapping — объектно-реляционное отображение данных), например, Doctrine, знают удобство представления данных из таблиц БД в виде объектов. PDO позволяет получать данные в виде объектов и без использования ORM.
Расширение mysql больше не поддерживается
Поддержка расширения mysql окончательно удалена из нового PHP 7. Если вы планируете переносить проект на новую версию PHP, уже сейчас следует использовать в нем, как минимум, mysqli. Конечно же, лучше начинать использовать PDO, если вы еще не сделали этого.
Мне кажется, что этих причин достаточно для склонения весов в сторону использования PDO. Тем более, не нужно ничего дополнительно устанавливать.
Проверяем наличие PDO в системе
Версии PHP 5.5 и выше, чаще всего, уже содержать расширение для работы с PDO. Для проверки достаточно выполнить в консоли простую команду:
Теперь откроем его в любом браузере и найдем нужные данные поиском по строке PDO.
Знакомимся с PDO
Процесс работы с PDO не слишком отличается от традиционного. В общем случае, процесс использования PDO выглядит так:
Подключение к базе данных
Для подключения к базе данных нужно создать новый объект PDO и передать ему имя источника данных, так же известного как DSN.
В общем случае, DSN состоит из имени драйвера, отделенного двоеточием от строки подключения, специфичной для каждого драйвера PDO.
Для MySQL, подключение выполняется так:
В данном случае, DSN содержит имя драйвера mysql, указание хоста (возможен формат host=ИМЯ_ХОСТА:ПОРТ), имя базы данных, кодировка, имя пользователя MySQL и его пароль.
Запросы
В отличие от mysqli_query(), в PDO есть два типа запросов:
Первым делом, рассмотрим второй вариант.
Выполнение запросов
Рассмотрим пример выполнения запроса на примере insert.
Конечно же, данный запрос возвращает количество затронутых строк и увидеть его можно следующим образом.
Получение результатов запроса
Для PDO, код будет проще и лаконичнее.
Режимы получения данных
Как и в mysqli, PDO позволяет получать данные в разных режимах. Для определения режима, класс PDO содержит соответствующие константы.
Примечание: это не полный список, все возможные константы и варианты их комбинации доступны в документации.
Пример получения ассоциативного массива:
Примечание: Рекомендуется всегда указывать режим выборки, так как режим PDO::FETCH_BOTH потребует вдвое больше памяти — фактически, будут созданы два массива, ассоциативный и обычный.
Теперь выберем данные и отобразим данные при помощи методов класса:
Подготовленные запросы и связывание параметров
Пример использования подготовленных запросов в PHP PDO:
Теперь нужно передать недостающий параметр и выполнить запрос:
Преимущества использования связанных параметров
Возможно, после рассмотрения механизма работы подготовленных запросов и связанных параметров, преимущества их использования стали очевидными.
PDO предоставляет удобную возможность экранирования пользовательских данных, например, такой код больше не нужен:
Вместо этого, теперь целесообразно делать так:
Можно, даже, еще укоротить код, используя нумерованные параметры вместо именованных:
В тоже время, использование подготовленных запросов позволяет улучшить производительность при многократном использовании запроса по одному шаблону. Пример выборки пяти случайных пользователей из базы данных:
Связанные значения и оператор IN
НЕ корректный код:
Этот код не будет работать потому, что параметр в шаблоне представлен скалярным значением (например, целое число или строка).
Правильным подходом будет создание специальной строки:
Типизированные связанные параметры
Рассмотренные выше примеры были намеренно упрощены и не содержали указания типов параметров. Однако, в реальном коде лучше использовать указание типов.
Заключение
PHP развивается, программисты не должны отставать. Использование расширения PDO позволяет писать более краткий, лаконичный, быстрый и безопасный код. Почему бы не начать использовать его уже сейчас?