Каковы технические причины, почему не следует использовать mysql_*
функции? (например mysql_query()
, mysql_connect()
или mysql_real_escape_string()
)?
Почему я должен использовать что-то еще, даже если они работают на моем сайте?
Если они не работают на моем сайте, почему я получаю такие ошибки, как
Предупреждение: mysql_connect (): нет такого файла или каталога
Ответы:
Расширение MySQL:
Поскольку он устарел, его использование делает ваш код менее надежным в будущем.
Отсутствие поддержки подготовленных операторов особенно важно, поскольку они предоставляют более понятный и менее подверженный ошибкам метод экранирования и цитирования внешних данных, чем ручной экранирование с помощью отдельного вызова функции.
Смотрите сравнение расширений SQL .
источник
PHP предлагает три разных API для подключения к MySQL. Это
mysql
(удалены с PHP 7)mysqli
иPDO
расширения.Эти
mysql_*
функции используются очень популярны, но их использование не рекомендуется больше. Команда разработчиков документации обсуждает ситуацию с безопасностью базы данных, и частью этого является обучение пользователей отходить от обычно используемого расширения ext / mysql (проверьте php.internals: устарел ext / mysql ).И более поздняя команда разработчиков PHP приняла решение генерировать
E_DEPRECATED
ошибки, когда пользователи подключаются к MySQL, будь то черезmysql_connect()
,mysql_pconnect()
или встроенные функции неявного подключенияext/mysql
.ext/mysql
был официально устаревшим PHP 5.5 и был удален в PHP 7 .Видишь красную коробку?
Когда вы заходите на
mysql_*
страницу руководства по любым функциям, вы видите красную рамку, объясняющую, что она больше не должна использоваться.Почему
Отойдя от
ext/mysql
не только безопасности, но и доступа ко всем функциям базы данных MySQL.ext/mysql
был построен для MySQL 3.23 и с тех пор получил лишь очень мало дополнений, сохраняя при этом совместимость с этой старой версией, что делает код немного сложнее поддерживать. К отсутствующим функциям, которые не поддерживаются,ext/mysql
относятся: ( из руководства по PHP ).Причина не использовать
mysql_*
функцию :Выше цитата из ответа Квентина
Отсутствие поддержки подготовленных операторов особенно важно, поскольку они предоставляют более понятный и менее подверженный ошибкам метод экранирования и цитирования внешних данных, чем ручной экранирование с помощью отдельного вызова функции.
Смотрите сравнение расширений SQL .
Подавление предупреждений об устаревании
Пока код преобразуется в
MySQLi
/PDO
,E_DEPRECATED
ошибки можно подавить, установивerror_reporting
в php.ini исключениеE_DEPRECATED:
Обратите внимание, что это также скрывает другие предупреждения об устаревании , которые, однако, могут относиться к вещам, отличным от MySQL. ( из руководства по PHP )
Статья PDO против MySQLi: что использовать? от Деяна Марьянович поможет вам выбрать.
И лучший способ
PDO
, и я сейчас пишу простойPDO
учебник.Простой и краткий учебник по PDO
В. Первый вопрос, который у меня возник, был: что такое «PDO»?
A. « PDO - PHP Data Objects - это уровень доступа к базе данных, обеспечивающий единый метод доступа к нескольким базам данных».
Подключение к MySQL
С помощью
mysql_*
функции или мы можем сказать это по-старому (устарело в PHP 5.5 и выше)С
PDO
: Все, что вам нужно сделать, это создать новыйPDO
объект. Конструктор принимает параметры для указания конструктора источника базы данных, вPDO
основном принимает четыре параметраDSN
(имя источника данных) и, необязательноusername
,password
.Здесь я думаю, что вы знакомы со всеми, кроме
DSN
; это новое вPDO
. ADSN
- это в основном строка опций, которые указывают,PDO
какой драйвер использовать, и сведения о соединении. Для дальнейшего ознакомления проверьте PDO MySQL DSN .Примечание: вы также можете использовать
charset=UTF-8
, но иногда это вызывает ошибку, поэтому лучше использоватьutf8
.Если есть какая-либо ошибка соединения, он бросит
PDOException
объект, который может быть перехвачен для обработкиException
дальнейшей .Хорошее чтение : Соединения и Управление соединениями ¶
Вы также можете передать несколько параметров драйвера в виде массива к четвертому параметру. Я рекомендую передать параметр, который переводит
PDO
в режим исключения. Поскольку некоторыеPDO
драйверы не поддерживают встроенные подготовленные операторы,PDO
выполняется эмуляция подготовки. Это также позволяет вам вручную включить эту эмуляцию. Чтобы использовать встроенные операторы, подготовленные на стороне сервера, вы должны явно установить ихfalse
.Другой вариант - отключить эмуляцию подготовки, которая
MySQL
по умолчанию включена в драйвере, но дляPDO
безопасного использования эмуляцию подготовки следует отключить .Позже я объясню, почему подготовка эмуляции должна быть отключена. Чтобы найти причину, пожалуйста, проверьте этот пост .
Это возможно только в том случае, если вы используете старую версию,
MySQL
которую я не рекомендую.Ниже приведен пример того, как вы можете это сделать:
Можем ли мы установить атрибуты после построения PDO?
Да , мы также можем установить некоторые атрибуты после построения PDO с помощью
setAttribute
метода:Обработка ошибок
Обработка ошибок намного проще,
PDO
чемmysql_*
.Обычная практика при использовании
mysql_*
:OR die()
не очень хороший способ справиться с ошибкой, так как мы не можем справиться с этимdie
. Он просто внезапно завершит выполнение сценария, а затем отобразит ошибку на экране, которую вы обычно НЕ хотите показывать своим конечным пользователям, и позволит кровавым хакерам обнаружить вашу схему. Альтернативно, возвращаемые значенияmysql_*
функций часто можно использовать вместе с mysql_error (). для обработки ошибок.PDO
предлагает лучшее решение: исключения. Все , что мы делаем сPDO
должны быть завернуты вtry
-catch
блок. Мы можем принудительноPDO
включить один из трех режимов ошибок, установив атрибут режима ошибок. Три режима обработки ошибок приведены ниже.PDO::ERRMODE_SILENT
, Он просто устанавливает коды ошибок и действует почти так же, как и в случае,mysql_*
когда вы должны проверить каждый результат, а затем посмотреть,$db->errorInfo();
чтобы получить подробности об ошибке.PDO::ERRMODE_WARNING
ПоднятьE_WARNING
. (Предупреждения во время выполнения (нефатальные ошибки). Выполнение сценария не прекращается.)PDO::ERRMODE_EXCEPTION
: Бросить исключения. Это представляет ошибку, выдвинутую PDO. Вы не должны бросатьPDOException
из своего собственного кода. Посмотрите Исключения для получения дополнительной информации об исключениях в PHP. Это действует так же, какor die(mysql_error());
, когда он не пойман. Но в отличие от этогоor die()
, выPDOException
можете изящно поймать и обработать его, если вы решите это сделать.Хорошо читать :
Подобно:
И вы можете обернуть его
try
-catch
как показано ниже:Вы не должны справляться с
try
-catch
прямо сейчас. Вы можете поймать его в любое удобное время, но я настоятельно рекомендую вам использоватьtry
-catch
. Также может иметь смысл поймать его вне функции, вызывающейPDO
материал:Кроме того, вы можете справиться
or die()
или мы можем сказать, какmysql_*
, но это будет действительно различным. Вы можете скрыть опасные сообщения об ошибках в производственном процессе, включивdisplay_errors off
и просто прочитав журнал ошибок.Теперь, после прочтения всех вещей выше, вы, вероятно , думаете: что это такое , когда я просто хочу , чтобы начать опираясь простым
SELECT
,INSERT
,UPDATE
, илиDELETE
заявление? Не волнуйтесь, здесь мы идем:Выбор данных
Итак, что вы делаете в
mysql_*
это:Теперь
PDO
вы можете сделать это следующим образом:Или
Примечание . Если вы используете метод, подобный приведенному ниже (
query()
), этот метод возвращаетPDOStatement
объект. Поэтому, если вы хотите получить результат, используйте его, как указано выше.В данных PDO он получается с помощью
->fetch()
метода вашего дескриптора оператора. Перед вызовом fetch лучшим подходом будет сообщить PDO, как вы хотите получать данные. В следующем разделе я объясняю это.Режимы выборки
Обратите внимание на использование
PDO::FETCH_ASSOC
вfetch()
иfetchAll()
код выше. Это говоритPDO
о необходимости возвращать строки в виде ассоциативного массива с именами полей в качестве ключей. Есть также много других режимов извлечения, которые я объясню один за другим.Прежде всего, я объясню, как выбрать режим выборки:
В вышеупомянутом, я использовал
fetch()
. Вы также можете использовать:PDOStatement::fetchAll()
- возвращает массив, содержащий все строки набора результатовPDOStatement::fetchColumn()
- возвращает один столбец из следующей строки набора результатовPDOStatement::fetchObject()
- Выбирает следующую строку и возвращает ее как объект.PDOStatement::setFetchMode()
- Установите режим выборки по умолчанию для этого оператораТеперь я пришел к режиму выборки:
PDO::FETCH_ASSOC
: возвращает массив, проиндексированный по имени столбца, как возвращено в вашем наборе результатовPDO::FETCH_BOTH
(по умолчанию): возвращает массив, проиндексированный как по имени столбца, так и по номеру столбца с 0 индексами, как возвращено в вашем наборе результатовЕсть еще больше вариантов! Читайте о них все в
PDOStatement
документации Fetch. ,Получение количества строк :
Вместо того
mysql_num_rows
чтобы использовать количество возвращаемых строк, вы можете получитьPDOStatement
и сделатьrowCount()
, например:Получение последнего введенного идентификатора
Вставить и обновить или удалить заявления
Что мы делаем в
mysql_*
функции:И в pdo то же самое можно сделать:
В приведенном выше запросе
PDO::exec
выполните оператор SQL и верните количество затронутых строк.Вставка и удаление будут рассмотрены позже.
Вышеуказанный метод полезен только тогда, когда вы не используете переменную в запросе. Но когда вам нужно использовать переменную в запросе, никогда не пытайтесь делать то же самое, что и выше, и там готовый оператор или параметризованный оператор .
Подготовленные заявления
В. Что такое подготовленное утверждение и зачем оно мне?
A. Подготовленный оператор - это предварительно скомпилированный оператор SQL, который можно выполнить несколько раз, отправив только данные на сервер.
Типичный рабочий процесс использования подготовленного оператора выглядит следующим образом ( цитируется из Википедии три 3 пункта ):
Подготовка : шаблон выписки создается приложением и отправляется в систему управления базами данных (СУБД). Некоторые значения остаются неопределенными, они называются параметрами, заполнителями или переменными связывания (помечены
?
ниже):INSERT INTO PRODUCT (name, price) VALUES (?, ?)
СУБД анализирует, компилирует и выполняет оптимизацию запросов по шаблону оператора и сохраняет результат, не выполняя его.
1.00
для второго параметра.Вы можете использовать подготовленный оператор, включив заполнители в ваш SQL. В основном есть три без заполнителей (не пытайтесь сделать это с переменной выше одной), один с неназванными заполнителями и один с именованными заполнителями.
Q. Так что теперь, как называются заполнители и как их использовать?
А. Именованные заполнители. Используйте описательные имена, начинающиеся с двоеточия, вместо вопросительных знаков. Нас не волнует позиция / порядок значений в названии местозаполнителя:
bindParam(parameter,variable,data_type,length,driver_options)
Вы также можете связать, используя массив execute:
Еще одна приятная особенность для
OOP
друзей заключается в том, что именованные заполнители имеют возможность вставлять объекты непосредственно в вашу базу данных, при условии, что свойства соответствуют именованным полям. Например:В. Итак, что же такое безымянные заполнители и как их использовать?
А. Давайте приведем пример:
а также
Выше вы можете увидеть их
?
вместо имени, как в заполнителе имен. Теперь в первом примере мы присваиваем переменные различным заполнителям ($stmt->bindValue(1, $name, PDO::PARAM_STR);
). Затем мы присваиваем значения этим заполнителям и выполняем инструкцию. Во втором примере первый элемент массива переходит к первому,?
а второй - ко второму?
.ПРИМЕЧАНИЕ . В безымянных заполнителях мы должны позаботиться о правильном порядке элементов в массиве, который мы передаем
PDOStatement::execute()
методу.SELECT
,INSERT
,UPDATE
,DELETE
Подготовлены запросыSELECT
:INSERT
:DELETE
:UPDATE
:НОТА:
Однако
PDO
и / илиMySQLi
не являются полностью безопасными. Проверьте ответ Достаточно ли подготовленных операторов PDO для предотвращения внедрения SQL? по ircmaxell . Также я цитирую некоторую часть из его ответа:источник
IN (...) construct
.function throwEx() { throw new Exception("You did selected not existng db"); } mysql_select_db("nonexistdb") or throwEx();
Это работает для создания исключений.Doesn't support non-blocking, asynchronous queries
указываете в качестве причины, чтобы не использовать mysql_ - вы должны также указать это в качестве причины, чтобы не использовать PDO, потому что PDO также не поддерживает это. (но MySQLi это поддерживает)Во-первых, давайте начнем со стандартного комментария, который мы даем всем:
Давайте рассмотрим это, предложение за предложением, и объясним:
Они больше не поддерживаются и официально устарели
Это означает, что сообщество PHP постепенно отказывается от поддержки этих очень старых функций. Они, вероятно, не существуют в будущей (недавней) версии PHP! Дальнейшее использование этих функций может нарушить ваш код в (не очень) будущем.
NEW! - ext / mysql официально объявлен устаревшим с PHP 5.5!
Новее! ext / mysql был удален в PHP 7 .
Вместо этого вы должны узнать о готовых утверждениях
mysql_*
расширение не поддерживает подготовленные операторы , что является (среди прочего) очень эффективной контрмерой против SQL-инъекции . Он исправил очень серьезную уязвимость в MySQL-зависимых приложениях, которая позволяет злоумышленникам получить доступ к вашему сценарию и выполнить любой возможный запрос к вашей базе данных.Для получения дополнительной информации см. Как я могу предотвратить внедрение SQL в PHP?
Видишь красную коробку?
Когда вы переходите на
mysql
страницу руководства по любым функциям, вы видите красное поле, объясняющее, что его больше не следует использовать.Используйте либо PDO, либо MySQLi
Существуют лучшие, более надежные и хорошо построенные альтернативы: PDO - объект базы данных PHP , который предлагает полный подход ООП к взаимодействию с базой данных, и MySQLi , который является специфическим улучшением для MySQL.
источник
IN (...) construct
.Простота использования
Аналитические и синтетические причины уже упоминались. Для новичков есть более существенный стимул прекратить использование устаревших функций mysql_.
Современные API баз данных проще в использовании.
В основном это связанные параметры, которые могут упростить код. И с отличными учебниками (как видно выше) переход на PDO не слишком труден.
Переписывание большей кодовой базы за один раз, однако, требует времени. Raison d'être для этой промежуточной альтернативы:
Эквивалентные функции pdo_ * вместо
mysql_ *Используя < pdo_mysql.php >, вы можете переключаться со старых функций mysql_ с минимальными усилиями . Он добавляет
pdo_
функции-обертки, которые заменяют ихmysql_
аналоги.Просто в каждом скрипте вызова, который должен взаимодействовать с базой данных.
include_once(
"pdo_mysql.php"
);
Удалите
префикс функции везде и замените его наmysql_
pdo_
.mysql_
connect()
становитсяpdo_
connect()
mysql_
query()
становитсяpdo_
query()
mysql_
num_rows()
становитсяpdo_
num_rows()
mysql_
insert_id()
становитсяpdo_
insert_id()
mysql_
fetch_array()
становитсяpdo_
fetch_array()
mysql_
fetch_assoc()
становитсяpdo_
fetch_assoc()
mysql_
real_escape_string()
становитсяpdo_
real_escape_string()
Ваш код будет работать одинаково и в основном будет выглядеть одинаково:
И вуаля.
Ваш код использует PDO.
Теперь пришло время на самом деле использовать это.
Связанные параметры могут быть просты в использовании
Вам просто нужен менее громоздкий API.
pdo_query()
добавляет очень легкую поддержку для связанных параметров. Преобразовать старый код просто:Переместите свои переменные из строки SQL.
pdo_query()
.?
качестве заполнителей там, где переменные были раньше.'
одинарных кавычек, которые ранее заключены в строковые значения / переменные.Преимущество становится более очевидным для более длинного кода.
Часто строковые переменные не просто интерполируются в SQL, а объединяются с экранированием вызовов между ними.
При использовании
?
заполнителей вам не нужно беспокоиться об этом:Помните, что pdo_ * все еще позволяет либо .
Просто не экранируйте переменную и связывайте ее в одном запросе.
:named
списки заполнителей позже.Более того, вы можете безопасно передавать переменные $ _REQUEST [] за любым запросом. Когда отправленные
<form>
поля соответствуют структуре базы данных, она становится еще короче:Так много простоты. Но давайте вернемся к еще нескольким советам по переписыванию и техническим причинам того, почему вы можете избавиться от
побега.mysql_
Исправить или удалить любую oldschool
sanitize()
функциюПосле преобразования всех
вызовов вmysql_
pdo_query
связанные параметры удалите все лишниеpdo_real_escape_string
вызовы.В частности, вы должны исправить любые
sanitize
илиclean
илиfilterThis
илиclean_data
функции, как объявлено датированными учебниками в одной или другой форме:Самая вопиющая ошибка здесь - отсутствие документации. Что еще важнее, порядок фильтрации был в неправильном порядке.
Правильный порядок был бы: не рекомендуется
stripslashes
как самый внутренний вызов, затемtrim
, впоследствииstrip_tags
,htmlentities
для выходного контекста и только в последнем случае,_escape_string
поскольку его приложение должно непосредственно предшествовать промежуточному анализу SQL.Но в качестве первого шага просто избавьтесь от
_real_escape_string
звонка.Возможно, вам придется оставить остальную часть вашей
sanitize()
функции на данный момент, если ваша база данных и поток приложений ожидают HTML-контекстно-безопасные строки. Добавьте комментарий, что отныне он применяет только HTML.Обработка строк / значений делегируется PDO и его параметризованным операторам.
Если
stripslashes()
в вашей функции дезинфекции было упомянуто какое-либо упоминание , это может указывать на более высокий уровень надзора.Обычно это было для того, чтобы отменить урон (двойное спасение) от устаревших
magic_quotes
. Что, однако, лучше всего исправить по центру , а не строка за строкой.Используйте один из подходов к изменению пользовательского пространства . Затем удалите
stripslashes()
вsanitize
функции.Чем отличаются готовые заявления
Когда вы скремблируете строковые переменные в запросы SQL, вам не просто становится сложнее следовать. MySQL также постарается снова разделить код и данные.
Инъекции SQL просто происходят, когда данные переходят в код контекст . Сервер базы данных не может позже определить, где PHP изначально склеивал переменные между предложениями запроса.
С помощью связанных параметров вы разделяете значения SQL-кода и SQL-контекста в вашем PHP-коде. Но он не зацикливается снова (за исключением PDO :: EMULATE_PREPARES). Ваша база данных получает неизменные команды SQL и значения переменных 1: 1.
Хотя в этом ответе подчеркивается, что вам следует позаботиться о читабельности преимуществ отбрасывания
. Иногда это также дает преимущество в производительности (повторяющиеся вставки с просто отличающимися значениями) из-за этого видимого и технического разделения данных и кода.mysql_
Остерегайтесь того, что привязка параметров не является волшебным универсальным решением против всех SQL-инъекций. Он обрабатывает наиболее распространенное использование для данных / значений. Но он не может указать имя столбца / идентификаторы таблицы, помочь с построением динамического предложения или просто списком значений массива.
Использование гибридного PDO
Эти
pdo_*
функции-обертки создают удобный для программирования API-интерфейс. (Это в значительной степени то, чтоMYSQLI
могло бы быть, если бы не смещение сигнатуры уникальной функции). Они также чаще всего выставляют настоящий PDO.Перезапись не должна останавливаться на использовании новых имен функций pdo_. Вы можете по одному переходить каждый pdo_query () в простой вызов $ pdo-> prepare () -> execute ().
Однако лучше начать с упрощения. Например, общий результат выборки:
Может быть заменен только итерацией foreach:
Или, что еще лучше, прямой и полный поиск массивов:
В большинстве случаев вы получите более полезные предупреждения, чем обычно выдают PDO или mysql_ после неудачных запросов.
Другие опции
Таким образом, мы надеемся, что это наглядно продемонстрировало некоторые практические причины и достойный путь к снижению
.mysql_
Просто переключаюсь на п.д.о.не совсем порезать это.
pdo_query()
это также просто интерфейс на него.Если вы не введете привязку параметров или не сможете использовать что-то еще из более приятного API, это бессмысленный переход. Я надеюсь, что это изображено достаточно просто, чтобы не способствовать разочарованию новичков. (Образование обычно работает лучше, чем запрет.)
Несмотря на то, что он подходит для категории «самая простая вещь, которая может быть возможна», он также все еще очень экспериментальный код. Я только написал это в выходные. Однако существует множество альтернатив. Просто Google для PHP абстракции базы данных и просматривать немного. Для таких задач всегда было и будет много отличных библиотек.
Если вы хотите еще больше упростить взаимодействие с базой данных, стоит попробовать такие картографы, как Paris / Idiorm . Точно так же, как никто не использует более мягкий DOM в JavaScript, вам не нужно сейчас присматривать за сырым интерфейсом базы данных.
источник
pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);
функцией - то есть:pdo_query("INSERT INTO users VALUES (?, ?, ?), $_POST); $_POST = array( 'username' => 'lawl', 'password' => '123', 'is_admin' => 'true');
pdo_real_escape_string()
<- Это даже реальная функция, я не могу найти документацию для нее? Пожалуйста, опубликуйте источник для этого.Эти
mysql_
функции:источник
mysqli_
mysql_*
функции являются оболочками в функцию mysqlnd для новых версий PHP. Таким образом, даже если старая клиентская библиотека больше не поддерживается, mysqlnd сохраняется :)Говоря о технических причинах, их всего несколько, крайне специфичных и редко используемых. Скорее всего, вы никогда не будете использовать их в своей жизни.
Может быть, я слишком невежественен, но у меня никогда не было возможности использовать такие вещи, как
Если они вам нужны - это, без сомнения, технические причины для перехода от расширения mysql к чему-то более стильному и современному.
Тем не менее, есть также некоторые нетехнические проблемы, которые могут сделать ваш опыт немного сложнее
Эта последняя проблема является проблемой.
Но, на мой взгляд, предлагаемое решение тоже не лучше.
Мне кажется слишком идеалистической мечтой, что все эти пользователи PHP научатся правильно обрабатывать запросы SQL. Скорее всего, они просто изменили бы mysql_ * на mysqli_ * механически, оставив подход тот же . Тем более, что mysqli делает использование готовых заявлений невероятно болезненным и хлопотным.
Не говоря уже о том, что собственных подготовленных операторов недостаточно для защиты от SQL-инъекций, и ни mysqli, ни PDO не предлагают решения.
Таким образом, вместо того, чтобы бороться с этим честным продолжением, я предпочел бы бороться с неправильными методами и обучать людей правильными способами.
Кроме того, есть несколько ложных или несущественных причин, таких как
mysql_query("CALL my_proc");
целую вечность)Последний интересный момент. Хотя mysql ext не поддерживает нативно подготовленные операторы, они не требуются для безопасности. Мы можем легко подделать подготовленные операторы, используя заполнители, обработанные вручную (как это делает PDO):
Вуаля , все параметризовано и безопасно.
Но хорошо, если вам не нравится красная рамка в руководстве, возникает проблема выбора: mysqli или PDO?
Ну, ответ будет следующим:
Если, как и подавляющее большинство PHP-пользователей, вы используете необработанные вызовы API прямо в коде приложения (что, по сути, является неправильной практикой), PDO - единственный выбор , поскольку это расширение претендует на то, чтобы быть не просто API, а скорее полу-DAL, все еще неполный, но предлагает много важных функций, с двумя из них отличает PDO от mysqli:
Итак, если вы обычный пользователь PHP и хотите сэкономить массу головной боли при использовании встроенных подготовленных операторов, PDO - опять же - единственный выбор.
Тем не менее, PDO тоже не серебряная пуля и имеет свои трудности.
Итак, я написал решения для всех распространенных ошибок и сложных случаев в теге PDO вики
Тем не менее, все, кто говорит о расширениях, всегда упускают два важных факта о Mysqli и PDO:
Подготовленное заявление не является серебряной пулей . Существуют динамические идентификаторы, которые нельзя связать с помощью подготовленных операторов. Существуют динамические запросы с неизвестным количеством параметров, что затрудняет построение запросов.
Ни mysqli_ *, ни функции PDO не должны были появиться в коде приложения. Между ними и кодом приложения
должен быть уровень абстракции , который будет выполнять всю грязную работу по связыванию, зацикливанию, обработке ошибок и т. Д. Внутри, делая код приложения СУХИМЫМ и чистым. Особенно для сложных случаев, таких как динамическое построение запросов.
Таким образом, просто переключиться на PDO или MySQL не достаточно. Нужно использовать ORM, или построитель запросов, или любой другой класс абстракции базы данных вместо вызова сырых функций API в их коде.
И наоборот - если у вас есть уровень абстракции между кодом приложения и MySQL API - на самом деле не имеет значения, какой движок используется. Вы можете использовать mysql ext до тех пор, пока он не устареет, а затем легко переписать свой класс абстракции на другой движок, оставив весь код приложения без изменений.
Вот несколько примеров, основанных на моем классе safemysql, чтобы показать, каким должен быть такой класс абстракции:
Сравните эту единственную строку с количеством кода, который вам понадобится в PDO .
Затем сравните с сумасшедшим количеством кода, который вам понадобится, с необработанными инструкциями, написанными на Mysqli. Обратите внимание, что обработка ошибок, профилирование, ведение журнала запросов уже встроены и работают.
Сравните это с обычными вставками PDO, когда каждое имя поля повторяется шесть-десять раз - во всех этих многочисленных именованных заполнителях, привязках и определениях запросов.
Другой пример:
Вы вряд ли найдете пример для PDO, чтобы справиться с таким практическим случаем.
И это будет слишком многословно и, скорее всего, небезопасно.
Итак, еще раз - это должен быть не только необработанный драйвер, но и класс абстракции, полезный не только для глупых примеров из руководства для начинающих, но и для решения любых реальных проблем.
источник
mysql_*
делает уязвимости очень легко найти. Поскольку PHP используется многими начинающими пользователями,mysql_*
на практике он активно вреден, даже если теоретически его можно использовать без помех.everything is parameterized and safe
- это может быть параметризовано, но ваша функция не использует реально подготовленные операторы.Not under active development
только для этого макияжа «0,01%»? Если вы что-то создадите с помощью этой функции ожидания, обновите свою версию mysql через год и в результате получите нерабочую систему, я уверен, что неожиданно много людей неожиданно набрали эти 0,01%. Я бы сказал , чтоdeprecated
иnot under active development
тесно связаны между собой . Вы можете сказать, что для этого нет «достойной причины», но факт в том, что когда предлагается выбор между вариантами,no active development
это почти так же плохо, какdeprecated
я бы сказал?Причин много, но, возможно, самая важная из них заключается в том, что эти функции поощряют небезопасные методы программирования, поскольку они не поддерживают подготовленные операторы. Подготовленные операторы помогают предотвратить атаки с использованием SQL-инъекций.
При использовании
mysql_*
функций, вы должны помнить, чтобы запустить пользовательские параметры черезmysql_real_escape_string()
. Если вы забыли только в одном месте или вам удалось избежать только части ввода, ваша база данных может подвергнуться атаке.Использование подготовленных операторов
PDO
илиmysqli
сделает так, чтобы такого рода программные ошибки были более сложными.источник
Потому что (среди прочих причин) гораздо сложнее обеспечить очистку входных данных. Если вы используете параметризованные запросы, как в случае с PDO или mysqli, вы можете полностью избежать риска.
Как пример, кто-то может использовать
"enhzflep); drop table users"
в качестве имени пользователя. Старые функции позволят выполнять несколько операторов за запрос, поэтому что-то вроде этого мерзкого баггера может удалить всю таблицу.Если бы кто-то использовал PDO mysqli, имя пользователя в конечном итоге оказалось бы
"enhzflep); drop table users"
.Смотрите bobby-tables.com .
источник
The old functions will allow executing of multiple statements per query
- нет, они не будут. Этот тип внедрения невозможен в ext / mysql - единственный способ, которым этот тип внедрения возможен в PHP и MySQL, - это использование MySQLi иmysqli_multi_query()
функции. Внедрение типа, которое возможно с ext / mysql и неэкранированными строками, - это что-то вроде' OR '1' = '1
извлечения данных из базы данных, которая не должна была быть доступной. В определенных ситуациях возможно вводить подзапросы, однако все еще невозможно изменить базу данных таким способом.Этот ответ написан, чтобы показать, насколько тривиально обходить плохо написанный код проверки пользователя PHP, как (и с помощью чего) эти атаки работают и как заменить старые функции MySQL защищенным подготовленным оператором - и, в основном, почему пользователи StackOverflow (вероятно, с большим количеством представителей) лают на новых пользователей, задающих вопросы, чтобы улучшить их код.
Прежде всего, пожалуйста, не стесняйтесь создавать эту тестовую базу данных MySQL (я назвал мой Prep):
После этого мы можем перейти к нашему PHP-коду.
Предположим, что следующий скрипт является процессом проверки для администратора на веб-сайте (упрощенный, но работающий, если вы копируете и используете его для тестирования):
На первый взгляд кажется вполне законным.
Пользователь должен ввести логин и пароль, верно?
Молодец, не входи в следующее:
и представить его.
Вывод следующий:
Супер! Работая как положено, теперь давайте попробуем ввести действительное имя пользователя и пароль:
Удивительно! Привет пятерки со всех сторон, код правильно проверен админом. Идеально!
Ну не совсем. Допустим, пользователь умный маленький человек. Допустим, человек - это я.
Введите в следующем:
И вывод:
Поздравляю, вы только что разрешили мне войти в раздел ваших сверхзащищенных администраторов, указав ложное имя пользователя и ложный пароль. Серьезно, если вы мне не верите, создайте базу данных с помощью предоставленного мною кода и запустите этот PHP-код, который на первый взгляд действительно ДЕЙСТВИТЕЛЬНО проверяет имя пользователя и пароль.
Итак, в ответ, это то, почему вы кричали.
Итак, давайте посмотрим, что пошло не так, и почему я только что попал в вашу пещеру супер-админ-только-летучая мышь. Я сделал предположение и предположил, что вы не были осторожны со своими данными и просто передали их напрямую в базу данных. Я сконструировал вход таким образом, чтобы он ИЗМЕНИЛ запрос, который вы на самом деле выполняли. Итак, что это должно было быть, и чем это закончилось?
Это запрос, но когда мы заменяем переменные фактическими данными, которые мы использовали, мы получаем следующее:
Посмотрите, как я создал свой «пароль», чтобы он сначала закрывал одинарную кавычку вокруг пароля, а затем вводил совершенно новое сравнение? Затем для безопасности я добавил еще одну «строку», чтобы одинарная кавычка закрывалась, как и ожидалось, в исходном коде.
Однако речь идет не о людях, которые кричат на вас, а о том, как сделать ваш код более безопасным.
Итак, что пошло не так, и как мы можем это исправить?
Это классическая атака SQL-инъекций. Один из самых простых в этом отношении. По шкале векторов атаки это малыш атакует танк - и выигрывает.
Итак, как мы можем защитить ваш священный раздел администратора и сделать его красивым и безопасным? Первое, что нужно сделать, это перестать использовать тех, кто действительно стар и устарел
mysql_*
функции. Я знаю, что вы следовали учебному пособию, которое вы нашли в Интернете, и оно работает, но оно старое, оно устарело, и за несколько минут я только что преодолел его, не потратив ни капельки пота.Теперь у вас есть лучшие варианты использования mysqli_ или PDO . Я лично большой поклонник PDO, поэтому я буду использовать PDO в оставшейся части этого ответа. Есть «за» и «против», но лично я считаю, что «за» намного перевешивают «против». Он переносим между несколькими ядрами баз данных - используете ли вы MySQL или Oracle или просто что-то кровавое - просто изменив строку подключения, он обладает всеми интересными функциями, которые мы хотим использовать, и он приятен и чист. Мне нравится чистый.
Теперь давайте снова посмотрим на этот код, на этот раз написанный с использованием объекта PDO:
Основные отличия в том, что больше нет
mysql_*
функций. Все это делается через объект PDO, во-вторых, он использует подготовленный оператор. Теперь, какое предварительное утверждение вы спрашиваете? Это способ сообщить базе данных перед запуском запроса, какой запрос мы собираемся запустить. В этом случае мы говорим базе данных: «Привет, я собираюсь запустить оператор select, требующий идентификатора, идентификатора пользователя и передачи от пользователей таблицы, где идентификатор пользователя является переменной, а передача также является переменной».Затем в операторе execute мы передаем базе данных массив со всеми переменными, которые он теперь ожидает.
Результаты фантастические. Давайте снова попробуем эти комбинации имени пользователя и пароля:
Пользователь не был подтвержден. Потрясающие.
Как насчет:
О, я просто немного взволнован, это сработало: проверка прошла. У нас есть проверенный админ!
Теперь, давайте попробуем данные, которые умный парень введет, чтобы попытаться обойти нашу маленькую систему проверки:
На этот раз мы получаем следующее:
Вот почему на вас кричат при публикации вопросов, потому что люди видят, что ваш код можно обойти даже без попыток. Пожалуйста, используйте этот вопрос и ответ, чтобы улучшить свой код, сделать его более безопасным и использовать текущие функции.
Наконец, это не означает, что это ИДЕАЛЬНЫЙ код. Есть еще много вещей, которые вы могли бы сделать, чтобы улучшить его, например, использовать хешированные пароли, обеспечить, чтобы при хранении конфиденциальной информации в базе данных вы не хранили ее в виде простого текста, имели несколько уровней проверки - но на самом деле, если вы просто измените свой старый склонный к инъекциям код на это, вы будете ХОРОШО на пути к написанию хорошего кода - и тот факт, что вы продвинулись так далеко и все еще читаете, дает мне чувство надежды, что вы не только реализуете этот тип кода при написании ваших веб-сайтов и приложений, но вы можете выйти и исследовать те другие вещи, которые я только что упомянул - и многое другое. Напишите лучший код, который вы можете, а не самый простой код, который едва работает.
источник
mysql_*
сам по себе не небезопасен, но он продвигает небезопасный код с помощью плохих учебников и отсутствия надлежащего API подготовки операторов.Расширение MySQL является старейшим из трех и было оригинальным способом, который разработчики использовали для связи с MySQL. Это расширение в настоящее время считается устаревшим в пользу двух других альтернатив из-за улучшений, сделанных в более новых выпусках как PHP, так и MySQL.
MySQLi - это «улучшенное» расширение для работы с базами данных MySQL. Он использует преимущества функций, доступных в более новых версиях сервера MySQL, предоставляет разработчикам как функционально-ориентированный, так и объектно-ориентированный интерфейс и делает несколько других изящных вещей.
PDO предлагает API, который объединяет большинство функций, которые ранее были распространены на основные расширения доступа к базе данных, то есть MySQL, PostgreSQL, SQLite, MSSQL и т. Д. Интерфейс предоставляет высокоуровневые объекты для программиста для работы с соединениями с базой данных, запросами и наборы результатов и низкоуровневые драйверы осуществляют связь и обработку ресурсов с сервером базы данных. В PDO идет много дискуссий и работы, и он считается подходящим методом работы с базами данных в современном профессиональном коде.
источник
Я считаю, что приведенные выше ответы действительно длинные, поэтому подведем итог:
Источник: MySQLi обзор
Как объяснялось в ответах выше, альтернативами mysql являются mysqli и PDO (объекты данных PHP).
И MySQLi, и PDO были введены в PHP 5.0, тогда как MySQL был представлен до PHP 3.0. Следует отметить, что MySQL включен в PHP5.x, хотя и не рекомендуется в более поздних версиях.
источник
Можно определить почти все
mysql_*
функции, используя mysqli или PDO. Просто включите их поверх старого PHP-приложения, и оно будет работать на PHP7. Мое решение здесь .источник
Функции , которые , как похожи на это
mysql_connect()
,mysql_query()
типе , являются предыдущими версиями PHP есть (PHP 4) функция и сейчас не используются.Они заменяются
mysqli_connect()
, такmysqli_query()
же в последнем PHP5.Это причина ошибки.
источник
MySQL устарел в PHP 5.5.0 и удален в PHP 7.0.0. Для большого и старого приложения это трудно найти и заменить каждую функцию.
Мы можем использовать функции MySQL, создавая функцию-обертку для каждого ниже выполняемого кода. кликните сюда
источник
Функции mysql_ * устарели ( начиная с PHP 5.5 ), учитывая тот факт, что были разработаны более совершенные функции и структуры кода. Тот факт, что функция устарела, означает, что больше не нужно прилагать усилий для ее улучшения с точки зрения производительности и безопасности, что означает , что она менее надежна в будущем .
Если вам нужно больше причин:
источник