Я вижу, что многие люди говорят, что вы всегда должны использовать подготовленные инструкции для запросов к базе данных. Однако в документах PHP говорится:
Каждое подготовленное заявление занимает серверные ресурсы. Заявления должны быть немедленно закрыты сразу после использования. Если это не сделано явно, оператор будет закрыт, когда дескриптор оператора будет освобожден PHP.
Использование подготовленного оператора не всегда является наиболее эффективным способом выполнения инструкции. Подготовленный оператор, выполненный только один раз, вызывает больше круглых поездок клиент-сервер, чем незаготовленный оператор.
С http://php.net/manual/en/mysqli.quickstart.prepared-statements.php
Учитывая вышеизложенное, если вы только собираетесь использовать запрос один раз, не лучше ли использовать подготовленные заявления?
Разница считается незначительной.
Тем не менее, нужно отличить подготовленные заявления от общей идеи подготовленного заявления.
Первый – это просто форма запросов, поддерживаемых большинством СУБД, объясненных здесь . Его использование может быть поставлено под сомнение.
Последнее представляет собой общее представление о замене фактических данных заполнителем, что подразумевает дальнейшую обработку замещенных данных. Он широко используется в программировании, примером является известная функция printf()
. И этот последний подход должен быть ВСЕГДА использоваться для запуска запроса к базе данных , независимо от того, поддерживаются ли он родными подготовленными операциями или нет. Потому как:
Таким образом, даже если вы считаете, что не используете собственные подготовленные операторы (это вполне нормально), вы всегда должны создавать свои запросы, используя заполнители вместо фактических данных. Для этого вы можете использовать PDO , который работает точно так же, как описано выше – по умолчанию он просто подражает подготавливает , означает, что обычный SQL-запрос создается из подготовленного запроса и данных, а затем выполняется против базы данных.
Однако PDO не поддерживает многие важные типы данных, такие как идентификатор или массив, поэтому он не позволяет всегда использовать заполнители и, таким образом, делает инъекцию вполне возможной. К счастью, safeMysql имеет заполнители для каждого типа данных и позволяет безопасно запускать запросы.
Если вы не можете сравнить это и доказать, что у них есть измеримое сопротивление производительности, как в чем-то более чем на 10-15% медленнее, нет никаких оснований суетиться по этому поводу. Даже тогда, это небольшая цена, чтобы заплатить за почти полную уверенность в целостности данных, предполагая, что вы используете только заполнители.
Подготовленные утверждения, даже если они используются только один раз, легко внедряются правильно и очень сложно ошибиться, если вы дисциплинированы, чтобы никогда не использовать строчную интерполяцию для ввода данных.
Любой, кто считает себя профессиональным программистом, должен будет периодически проверять свое приложение, чтобы убедиться, что в нем нет ошибок SQL-инъекций. Если не очевидно, что что-то ускользнуло, нельзя полагать, что его избегают, поэтому вы должны исследовать.
Заполнители также уменьшают вероятность ошибочного смешивания столбцов и связанных с ними значений. Функция названных параметров PDO отлично справляется с этим.
Подготовка инструкции дает план запроса, подходящий для переменных. Затем он остается доступным для многократного использования.
Есть связанные с ними мутации, кстати. Рассмотрим это утверждение:
select * from posts order by post_date limit 10 offset ?;
Если вы подготовите это, вы не получите сканирования индекса. Потому что для всех, кто знает планировщик, вам нужны последние пару строк, и не может быть и речи о том, чтобы проходить миллионы сообщений один за другим, когда вы проходите через индекс.
Если вы запустите это напрямую с параметром, вы получите индексный сканер для небольших смещений, а индексный прогон не будет превышать порог по той же причине, что и подготовленный оператор не использовал индекс.
В этом свете, учитывая, что большинство приложений запускают запросы только один раз, вы обычно можете придерживаться эмулируемых подготавливаний. См., В частности, PDO::ATTR_EMULATE_PREPARES
.
SQL-инъекция является причиной того, что подготовленные заявления являются предпочтительным способом. Если ваш запрос является постоянным, тогда нет оснований для использования подготовленных операторов. Если вы уверены, что ваш запрос будет безопасным, даже если вы построите его путем конкатенации строк, тогда можно пропустить подготовленные инструкции.
Константы в порядке.
$sql = "SELECT * FROM foobar";
Если нет никакой вероятности, что переменная $ id будет содержать любой другой тип данных, чем int, тогда это нормально.
$sql = "SELECT * FROM users WHERE id=".$id;
Обычно легко избежать того, что данные, содержащиеся в переменной, являются правильным типом, поэтому подготовленные операторы являются более безопасным способом построения запроса.