[Library] ModernPDO

StulE

Новичок
Все мы знаем, насколько неудобно работать с базами данных, вручную писать запросы, следить за безопасностью (sql-инъекции и тд). Мы решили исправить это, создав библиотеку.

Описание:
ModernPDO — это незаменимый инструмент для работы с базами данных. Отличительными особенностями данной библиотеки является простота использования, современный стандарт PHP (8.1), полное покрытие кода тестами, уровень PHPStan'а 9, уровень PSalm'а 1, а также единый стандарт кода.

Доступный функционал:
  • Поддержка CRUD действий.
  • Поддержка сырых/готовых запросов.
  • Поддержка транзакций.
Поддерживаемые базы данных:
  • MySQL/MariaDB
  • PostgreSQL
  • SQLite3
Ссылки:
Репозиторий на GitHub
Страница на Packagist
 

weregod

unserializer
Рекомендую плашки покрытия кода и тестов добавить (github actions для PHP>=8.1 умеет, на более ранних версиях PHP/PHPUnit не смог завести).
 

AmdY

Пью пиво
Команда форума
Ну это же совсем ужасно. https://github.com/StulE-ru/ModernPDO/blob/main/src/Actions/Select.php
У вас куча вещей не экранируется, вы слышали про инъекции, ключевые слова, регистрозависимость, where in, джойны, вложенные запросы и т.д. и т.п.
Будь это 10-15 лет назад - одно дело, но сейчас куча нормальных аналогов в оупенсурсе есть.
 

StulE

Новичок
Ну это же совсем ужасно. https://github.com/StulE-ru/ModernPDO/blob/main/src/Actions/Select.php
У вас куча вещей не экранируется, вы слышали про инъекции, ключевые слова, регистрозависимость, where in, джойны, вложенные запросы и т.д. и т.п.
Будь это 10-15 лет назад - одно дело, но сейчас куча нормальных аналогов в оупенсурсе есть.
Спасибо за комментарий, можно только больше конкретики? Где возникают проблемы из-за отсутствия экранирования, конкретные примеры возможных инъекций, причем тут регистронезависимость, какие ключевые слова и тд? По поводу отсутствия многих фич полностью согласны, они будут добавлены в следующих обновлениях.
 

StulE

Новичок
везде, хоть таблицу назови "table union select bla, bla from table2" хоть столбец
Действительно, если назвать таблицу с пробелами, то будут определенного рода проблемы, но:

Во-первых, экранирование не поможет, пробел - это не спец символ (тык)
Во-вторых, пробелами вы ломаете любую совместимость sql-запроса, так как для MariaDB нужно `table name`, для PosgreSQL "table name" (поиграться можно тут)
В-третьих, пробелы могут появится только в 2х случаях, либо вам захотелось, либо данные пришли от клиента
- Если вам захотелось - это ваши проблемы, всегда можно заменить пробелы на '_' и никаких проблем не будет
- Если данные пришли от клиента - скорее всего у вас проблема в архитектуре, но если так задумано, то обрабатывать придется вам, так как данный случай крайне специфичен для широких масс, и вы по-любому знаете лучше, как обработать ввод пользователя
 

antonio

Moderator
Команда форума
Коллеги пытаются вам объяснить, что конечный пользователь вашего продукта может быть настолько пофигистом, что передаст нефильтрованные данные из _GET, _POST, _COOKIE и т.д. прямиком в методы формирования запроса, что приведет к явной реализации инъекции.
 

StulE

Новичок
Коллеги пытаются вам объяснить, что конечный пользователь вашего продукта может быть настолько пофигистом, что передаст нефильтрованные данные из _GET, _POST, _COOKIE и т.д. прямиком в методы формирования запроса, что приведет к явной реализации инъекции.
Благодарю за разъяснение ситуации.
 

WMix

герр M:)ller
Партнер клуба
Во-первых, экранирование не поможет, пробел - это не спец символ
экранирование помогает
SQL:
CREATE TABLE `hello``'"\/wo rld` (
  `id` int(11) NOT NULL,
  `name` varchar(25) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `hello``'"\/wo rld` (`id`, `name`) VALUES
(1, 'hello'),
(2, 'world');

ALTER TABLE `hello``'"\/wo rld`
  ADD PRIMARY KEY (`id`);

ALTER TABLE `hello``'"\/wo rld`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;


SELECT * FROM `hello``'"\/wo rld`


Во-вторых, пробелами вы ломаете любую совместимость sql-запроса, так как для MariaDB нужно `table name`, для PosgreSQL "table name"
это не мои проблемы, я пользуюсь API
PHP:
// Select examples
$mpdo->select('table_name')->all();
Будь это 10-15 лет назад - одно дело, но сейчас куча нормальных аналогов в оупенсурсе есть.

В-третьих, пробелы могут появится только в 2х случаях, либо вам захотелось, либо данные пришли от клиента
бывает и ситуации, когда поменять не возможно, это решение других людей
 
Последнее редактирование:

StulE

Новичок
> экранирование помогает
SQL:
SELECT * FROM `hello``'"\/wo rld`
Wiki: Экранирование символов — замена в тексте управляющих символов на соответствующие текстовые подстановки.
Из этого следует, что экранирование не защищает от SQL инъекций и если экранировать строку с пробелами, то пробелы останутся.
Ваш запрос работает за счет расширения SQL со стороны MySQL/MariaDB, которое говорит, что названия можно заключать в ``

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

AmdY

Пью пиво
Команда форума
Вместо того чтобы в википедию тыкать, лучше бы доку по PDO почитал.
Ну и попробуй написать запрос как говорил, с вложенными запросами, джойнами, группировкой, c оператором IN в который передаёшь массив из пост запроса. У тебя весь код расчитан на простой запрос с обращением к одной таблице.
 

StulE

Новичок
Описание обновления ModernPDO v3.0.0

  • Убраны create методы в ModernPDO и добавлены Drivers
  • Убрана хардкод установка PDO атрибутов в ModernPDO
  • Добавлена поддержка PDO исключений
  • Переработаны билдеры запросов (добавлен класс Factory)
  • Переписана установка кодировки подключения к MySQL/MariaDB
  • Добавлена плашка code coverage
  • Добавлен класс Escaper для экранирования значений
  • Удалены файлы докера
  • Переписаны интеграционные тесты (для упрощения добавления новых тестов)
  • Переименованы методы Select'а all/one в rows/row
  • Удалены методы Select'а firstBy/lastBy
  • Добавлен трейт Limit для Delete/Select/Update
  • Добавлен трейт OrderBy для Delete/Select/Update
  • Добавлена поддержка joins в Select
  • Добавлена возможность создавать/редактировать/удалять таблицы
  • Добавлена поддержка функций(SUM, COUNT и тд) и условий(IN, BETWEEN и тд) Delete/Select/Update/Insert
  • Добавлена поддержка ключей(Primary, Unique, Foreign) в create/alter table

Новая версия тык
 

Фанат

oncle terrible
Команда форума
PHP:
    private function string(string $string): string
    {
        return mb_substr($this->pdo->quote($string), 1, -1);
    }
Боже, всего несколько лет, как мне перестал сниться в ночных кошмарах этот ужас, и я снова вижу его наяву.
Что это? Зачем это? Какой в этом смысл?

Ну и обработка ошибок, конечно, сделана гениально. Нет ошибки - нет проблемы. Воткнул голову в песок, и хищника как бы и нету. Всё хорошо, всё замечательно, работаем дальше.

Уберите, пожалуйста, все блоки try-catch из кода.
После этого можно будет начинать смотреть на это изделие.
 
Последнее редактирование:

Фанат

oncle terrible
Команда форума
  • Добавлена поддержка PDO исключений
Эх, жалко я только сейчас это увидел. Не стал бы тогда удалять весь яд из предыдущего комментария.
Вы серьёзно считаете, что вот эти try-catch, тупо подавляющие сообщения об ошибках, называются "поддержкой исключений"? И это типа достижение, которым надо гордиться?

Ещё из принципиальных замечаний.

К PDO эта программа не имеет отношения. То что вы сделали - называется Query Builder (и их реально готовых как грязи за баней).

В PDO я могу получить конечный результат в самых разных форматах, например с группировкой по полю, или в виде словаря ключ-значение, или в виде инстанса определенного объекта (хотя эта фича довольно сомнительная).
Но почему-то все самозваные "улучшатели опыта с ПДО" на самом деле ухудшают опыт работы с этой либой, обрезая существующую функциональность до собственных представлений о ней.
 
Последнее редактирование:

StulE

Новичок
Эх, жалко я только сейчас это увидел. Не стал бы тогда удалять весь яд из предыдущего комментария.
Вы серьёзно считаете, что вот эти try-catch тупо подавляющие все сообщения об ошибках называются "поддержкой исключений" и это типа достижение, которым надо гордиться?

Ещё из принципиальных замечаний.

К PDO эта программа не имеет отношения. То что вы сделали - называется Query Builder (и их реально готовых как грязи за баней).

В PDO я могу получить конечный результат в самых разных форматах, например с группировкой по полю, или в виде словаря ключ-значение, или в виде инстанса определенного объекта (хотя эта фича довольно сомнительная).
Но почему-то все самозваные "улучшатели опыта с ПДО" на самом деле ухудшают опыт работы с этой либой, обрезая существующую функциональность до собственных представлений о ней.
> Вы серьёзно считаете, что вот эти try-catch
Не считаю, но так вышло что это тянется с первых версий, где я ставил атрибут на ворнинги, и дабы не ломать идею "либа не кидает исключения", решил обернуть все в try-catch, приму к сведению ваше замечание.

> К PDO эта программа не имеет отношения.
Не совсем, все же частично имеет - тот же query, statement. Другой вопрос что я не хочу сильно привязываться к pdo, чтобы в будущем можно было добавить поддержку бд, для которых нет pdo драйвера. Эту папку я не просто так добавил.
 

Фанат

oncle terrible
Команда форума
Вот поэтому и надо разделить этот класс на два, враппер для ПДО и квери билдер. При этом называть первый ModernPDO будет глупо, поскольку там очень мелкие доделки, а второе - и вовсе некорректно.

И ради бога, уберите этот чудовищный код, процитированный в комментарии выше.
 

StulE

Новичок
Вот поэтому и надо разделить этот класс на два, враппер для ПДО и квери билдер. При этом называть первый ModernPDO будет глупо, поскольку там очень мелкие доделки, а второе - и вовсе некорректно.

И ради бога, уберите этот чудовищный код, процитированный в комментарии выше.
> Вот поэтому и надо разделить этот класс на два, враппер для ПДО и квери билдер.
В будущем и планирую.

> При этом называть первый ModernPDO будет глупо.
Понятное дело, но так исторически сложилось.

> И ради бога, уберите этот чудовищный код, процитированный в комментарии выше.
Мне самому это не понравилось, но как лучше - я не знаю. Потому что вручную - плохо, есть pdo::quote(). А через него добавляются скобки по бокам, и все равно приходится вручную подгонять.
 

Фанат

oncle terrible
Команда форума
Попробуйте все-таки попробовать понять, что делает PDO::quote(), и в результате сообразить, нужна ли она здесь вообще.
Ну или хотя бы попробуйте сформулировать, что именно вы собираетесь без неё делать "вручную" и зачем.
 
Последнее редактирование:

StulE

Новичок
Попробуйте все-таки попробовать понять, что делает PDO::quote(), и в результате сообразить, нужна ли она здесь вообще.
Ну или хотя бы попробуйте сформулировать, что именно вы собираетесь без неё делать "вручную" и зачем.
Задача Escaper'ов - обработать строки, которые нельзя "приготовить" (это названия таблиц, столбцов и тд), потому что, как писали выше, без этой обработки возникают проблемы при передаче строк от пользователя и при передаче строки содержащей пробелы. Escaper'ам нужно экранировать спец. символы (чтобы избежать инъекций), а так же заключать строки содержащие пробелы в кавычки, которые специфичны для разных субд. Вот и выходит что это все надо делать вручную. quote() не особо подходит для этой задачи, так как заключает не в те кавычки и не экранирует нужные кавычки (которые подставляются вручную позже), что есть потенциальная инъекция, но при этом она экранирует спец. символы. В итоге - что использовать quote() неправильно, что не использовать.
 

Фанат

oncle terrible
Команда форума
возникают проблемы
Какие проблемы?
нужно экранировать спец. символы
Какие конкретно символы?
но при этом она экранирует спец. символы.
какие и зачем?

Не пробовали задуматься?

Ваша проблема в том, что вы все это воспринимаете абстрактно. "ну есть какие-то инъекции, которые происходят через какие-то символы, которые экранирует какая-то функция".
При этом вы даже близко не понимаете, что такое инъекция. И для чего нужно это самое экранирование.
А туда же - писать гениальные врапперы для ПДО.

Инъекции получаются не из-за "спецсимволов". А путем выхода за границы грамматического литерала. Если у литерала нет ограничителей, как у числа например, или незакавыченного идентификатора, то вообще лафа - заходи кто хочешь, бери что хочешь.
Если ограничители есть, как у классического мальчика Бобби Тэйблс, но при этом эти ограничители не экранируются, то достаточно всего лишь закрыть литерал самому, и снова гулять свободно.

Отсюда становится понятно назначение экранирования. А оно примитивно до дебилизма: функция экранирования экранирует ограничители литерала. Те самые "не те кавычки". Не какие-то мифические "спецсимволы", а всего лишь те самые кавычки, которые служат границами строки. Тупо чтобы не перепутать с этой самой границей. Ну и заодно и сам экранирующий символ. Вы же сами это и делаете для идентификаторов.
Из чего следует вывод, что отрывать кавычки у quote() - это высшая степень дебилизма. Без кавычек она попросту не имеет смысла, ни малейшего. Вся суть этой функции в том, что она добавляет кавычки, в отличие от дебильной mysql_escape_string.
Еще там правда экранируется нулевой байт, но мне кажется, что современный софт уже не ломается через него. В крайнем случае можно руками.

В итоге всё это означает, что применять quote() для чего-то кроме строк - чуть более, чем бессмысленно. А поскольку строки у вас и так передаются через подготовленные выражения, то эта функция вообще не нужна.
 
Последнее редактирование:
Сверху