Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Подготовленные запросы

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (1): [1]   

> Без описания
IncOness
Отправлено: 22 Октября, 2015 - 17:27:12
Post Id


Гость


Покинул форум
Сообщений всего: 97
Дата рег-ции: Нояб. 2013  


Помог: 0 раз(а)




Нужно ли в подготовленных запросах (prepare statements) использовать кавычки при составлении запроса? Например:
PHP:
скопировать код в буфер обмена
  1. SELECT `id` FROM `users` WHERE `login`='$login'

или
PHP:
скопировать код в буфер обмена
  1. SELECT i` FROM users WHERE login=$login

?

И полностью ли защищают подготовленные запросы от SQL-инъекций?
 
 Top
DeepVarvar Супермодератор
Отправлено: 22 Октября, 2015 - 17:40:22
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




 
 Top
IncOness
Отправлено: 22 Октября, 2015 - 18:19:13
Post Id


Гость


Покинул форум
Сообщений всего: 97
Дата рег-ции: Нояб. 2013  


Помог: 0 раз(а)




DeepVarvar пишет:

Т.е. можно и с кавычками, но нежелательно?
 
 Top
IncOness
Отправлено: 22 Октября, 2015 - 22:27:24
Post Id


Гость


Покинул форум
Сообщений всего: 97
Дата рег-ции: Нояб. 2013  


Помог: 0 раз(а)




Еще такой вопрос: является ли код ниже правильным построением подготовленного запроса, чтобы избежать SQL-инъекций?
PHP:
скопировать код в буфер обмена
  1. if($check_money = $connection->prepare("SELECT `money` FROM `users` WHERE `login`='$_SESSION[login]' LIMIT 1"))
  2. {
  3.     $check_money->execute();
  4.     $res_check_money = $check_money->get_result();
  5.     $row_check_money = $res_check_money->fetch_assoc();
  6. }

Или правильнее как-то так?
PHP:
скопировать код в буфер обмена
  1. if($check_money = $connection->prepare("SELECT `money` FROM `users` WHERE `login`=? LIMIT 1"))
  2. {
  3.     $check_money->bind_param('s', $login);
  4.     $login = $_SESSION['login'];
  5.     $check_money->execute();
  6.     $res_check_money = $check_money->get_result();
  7.     $row_check_money = $res_check_money->fetch_assoc();
  8. }

(Отредактировано автором: 22 Октября, 2015 - 22:28:11)

 
 Top
OrmaJever Модератор
Отправлено: 22 Октября, 2015 - 23:10:05
Post Id



Активный участник


Покинул форум
Сообщений всего: 7540
Дата рег-ции: Янв. 2010  
Откуда: Чернигов


Помог: 299 раз(а)




IncOness пишет:
использовать кавычки

нет не нужно, они для строк они ставятся сами
IncOness пишет:
Или правильнее как-то так?

Да, правильнее именно второй вариант. Суть подготовленных запросов это убрать все значения за пределы запроса. Даже если вы знаете что значение полностью безопастно (сами его генерируете, а не берёте от пользователя), то всёравно лучше вынести его из запроса, такое разделение более правильное.


-----
Если вы хотя бы 3-4 раза не решите всё выкинуть и начать заново - вы явно что-то делаете не так.
 
 Top
IncOness
Отправлено: 22 Октября, 2015 - 23:42:59
Post Id


Гость


Покинул форум
Сообщений всего: 97
Дата рег-ции: Нояб. 2013  


Помог: 0 раз(а)




OrmaJever пишет:
IncOness пишет:
использовать кавычки

нет не нужно, они для строк они ставятся сами
IncOness пишет:
Или правильнее как-то так?

Да, правильнее именно второй вариант. Суть подготовленных запросов это убрать все значения за пределы запроса. Даже если вы знаете что значение полностью безопастно (сами его генерируете, а не берёте от пользователя), то всёравно лучше вынести его из запроса, такое разделение более правильное.

Спасибо за помощь.
 
 Top
DeepVarvar Супермодератор
Отправлено: 23 Октября, 2015 - 09:16:06
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




OrmaJever пишет:
Даже если вы знаете что значение полностью безопастно (сами его генерируете, а не берёте от пользователя), то всёравно лучше вынести его из запроса, такое разделение более правильное
Выносят всегда вот почему.

Даже сама фраза "подготовленный запрос" уже намекает, что запрос подготавливается.
Что значит подготавливается?
Он валидируется синтаксически (только в контексте SQL без учета данных, которых еще и нет).

Так же, в некоторых БД текст запроса даже отправляется на сервер чтобы пройти валидацию там, причем не только синтаксическую, но и на наличие таблиц, полей и прочего.
База может (и скорее всего сделает это) заранее просчитать наилучший вариант обработки запроса.
Тут можно положиться на саму базу, а можно указать ей (и структурно и синтаксически) какие индексы конкретно использовать или в каком порядке выполнять вычисления.

На любом из этапов валидации (подготовки) запроса может что-то пойти не так, и мы сразу узнаем об этом, т.к. процесс будет прерван.
Действительно, зачем пытаться лопатить миллионную таблицу, если в запросе синтаксическая или иная ошибка?

Успешно подготовленный запрос, если это делалось прямо на клиенте (в драйвере), вместе с подставленными данными (эскейпинг которых проходит в драйвере(?)) отправляется наконец в базу для выполнения.
А если подготовка проходила уже в базе, то успешно подготовленный запрос лежит в памяти базы и ждет от нас данные для подстановки.
Т.е. мы отправляем только данные (эскейпинг которых проходит в драйвере(?)) для подстановки.

И тут наконец сам запрос и выполняется.
И во время выполнения уже точно никаких ошибок не возникнет.
И мы можем быть уверены что получим результат.
Даже если мы получим ноль строк -- это результат на основании условий запроса.

Ну да, для инсертов или апдейтов конечно может произойти ошибка во время выполнения.
Например попытка дублировать уникальный ключ. И все такое.
Но это уже мелочи.

З.Ы.: Хренасе я тут расписал ))
 
 Top
Мелкий Супермодератор
Отправлено: 23 Октября, 2015 - 11:18:01
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




DeepVarvar пишет:
База может (и скорее всего сделает это) заранее просчитать наилучший вариант обработки запроса.
Тут можно положиться на саму базу, а можно указать ей (и структурно и синтаксически) какие индексы конкретно использовать или в каком порядке выполнять вычисления.

И вот тут-то начинаются проблемы.
Потому что оптимальный план запроса зависит очень сильно от данных. Банально: табличка на лям записей, запрос where created_at between ? and ? and user_id=?, есть два индекса (не уникальные): по created_at и по user_id.
Ну и какой план будет оптимальным? Да фиг его знает. Может, попросим найти крайне редкий user_id - искать надо по его индексу и отсеять по дате. Может, по узкому диапазону дат будет лучше - возьмём индекс по датам. А вдруг мы запросили огромный диапазон дат и этот юзер занимает практически всю таблицу? seq scan окажется быстрее рандомного доступа по индексам.

Ближе к практике:
В mysql prepared statements завязаны на сессию. При завершении сессии подготовленные выражения забываются. Кэшируется ли сам план запроса - сомневаюсь, но точно не знаю.
В postgresql подготовленные выражения живут в work_mem. Следовательно, новый коннект к бекэнду - подготовленные запросы будут обрабатываться заново. Поскольку профиль короткоживущих запросов от PHP и форковая архитектура postgresql вместе живут отвратно, ставится прокси и этот прокси должен так же уметь подготовленные запросы. За остальные не скажу, а pgBouncer в режиме транзакций в принципе не может работать с подготовленными выражениями. Хотя в режиме сессий вроде умеет, на конкретную сессию. Но это куда печальнее режима транзакций. На моём текущем проекте используется pgBouncer в режиме транзакций и PDO::ATTR_EMULATE_PREPARES => true.
В oracle планы запросов кэшируются и получаются как раз большие костыли с попытками базы понять, когда этот план ещё актуален, а когда его лучше переделать. Подробностей не знаю, лично с ораклом не работал.

DeepVarvar пишет:
Т.е. мы отправляем только данные (эскейпинг которых проходит в драйвере(?)) для подстановки.

Нигде не проходит. Это специальный бинарный протокол для отправки данных. Что-то вроде: база, привет. Помнишь, я говорил о таком-то запросе? Так вот, выполни с параметрами: следующие 8 байт - это параметр 1, потом 200 байт параметра 2.


-----
PostgreSQL DBA
 
 Top
DeepVarvar Супермодератор
Отправлено: 23 Октября, 2015 - 11:46:04
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Мелкий пишет:
Нигде не проходит. Это специальный бинарный протокол
Ааааа, точняк, профукал! Эскейпит только если собирает по старинке строку на месте. А тут бинарщина улетает, конечно.
 
 Top
Страниц (1): [1]
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Вопросы новичков »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB