Почему я не должен использовать функции mysql_ * в PHP?

Каковы технические причины, почему не следует использовать mysql_* функции? (например. mysql_query(), mysql_connect() или же mysql_real_escape_string())?

Почему я должен использовать что-то еще, даже если они работают на моем сайте?

Если они не работают на моем сайте, почему я получаю такие ошибки, как

Предупреждение: mysql_connect (): нет такого файла или каталога

2306

Решение

Расширение MySQL:

  • Не находится в стадии активной разработки
  • Является официально осуждается по состоянию на PHP 5.5 (выпущен в июне 2013 года).
  • Был удален полностью начиная с PHP 7.0 (выпущено в декабре 2015 г.)
    • Это означает, что с 31 декабря 2018 г. он не будет существовать ни в одной поддерживаемой версии PHP. В настоящее время он получает только безопасность Обновления.
  • Отсутствует интерфейс OO
  • Не поддерживает:
    • Неблокирующие, асинхронные запросы
    • Подготовленные заявления или параметризованные запросы
    • Хранимые процедуры
    • Несколько заявлений
    • операции
    • «Новый» метод аутентификации по паролю (включен по умолчанию в MySQL 5.6; требуется в 5.7)
    • Все функциональные возможности в MySQL 5.1

Поскольку он устарел, его использование делает ваш код менее надежным в будущем.

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

Увидеть сравнение расширений SQL.

1924

Другие решения

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_* функция:

  • Не в стадии активной разработки
  • Удалено с PHP 7
  • Отсутствует интерфейс OO
  • Не поддерживает неблокирующие, асинхронные запросы
  • Не поддерживает подготовленные заявления или параметризованные запросы
  • Не поддерживает хранимые процедуры
  • Не поддерживает несколько утверждений
  • Не поддерживает операции
  • Не поддерживает все функции в MySQL 5.1

Выше цитата из ответа Квентина

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

Увидеть сравнение расширений SQL.


Подавление предупреждений об устаревании

Пока код конвертируется в MySQLi/PDO, E_DEPRECATED ошибки могут быть подавлены настройкой error_reporting в php.ini исключить E_DEPRECATED:

error_reporting = E_ALL ^ E_DEPRECATED

Обратите внимание, что это также будет скрывать другие предупреждения об устаревании, что, однако, может быть для вещей, отличных от MySQL. (из руководства по PHP)

Статья PDO против MySQLi: что использовать? от Деян Марьянович поможет вам выбрать.

И лучший способ PDOи сейчас я пишу простую PDO руководство.


Простое и краткое руководство по PDO


В. Первый вопрос, который у меня возник, был: что такое «PDO»?

А. «PDO — объекты данных PHP — это уровень доступа к базе данных, обеспечивающий единый метод доступа к нескольким базам данных ».

альтернативный текст


Подключение к MySQL

С mysql_* функция или мы можем сказать это по-старому (устарело в PHP 5.5 и выше)

$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);

С PDO: Все, что вам нужно сделать, это создать новый PDO объект. Конструктор принимает параметры для указания источника базы данных PDOКонструктор в основном принимает четыре параметра, которые DSN (имя источника данных) и опционально username, password,

Здесь я думаю, что вы знакомы со всеми, кроме DSN; это новое в PDO, DSN в основном это строка опций, которые говорят PDO какой драйвер использовать, и детали подключения. Для дальнейшего ознакомления, проверьте PDO MySQL DSN.

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');

Замечания: Вы также можете использовать charset=UTF-8, но иногда это вызывает ошибку, поэтому лучше использовать utf8,

Если есть какая-либо ошибка соединения, он выдаст PDOException объект, который можно поймать для обработки Exception в дальнейшем.

Хорошо для чтения: Соединения и Управление соединениями ¶

Вы также можете передать несколько параметров драйвера в виде массива к четвертому параметру. Я рекомендую передать параметр, который ставит PDO в режим исключения. Потому что некоторые PDO драйверы не поддерживают нативно подготовленные операторы, поэтому PDO выполняет эмуляцию приготовления. Это также позволяет вам вручную включить эту эмуляцию. Чтобы использовать собственные подготовленные операторы на стороне сервера, вы должны явно установить его false,

Другой — отключить эмуляцию подготовки, которая включена в MySQL драйвер по умолчанию, но подготовка эмуляции должна быть отключена для использования PDO безопасно.

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

Это возможно только в том случае, если вы используете старую версию MySQL который я не рекомендовал.

Ниже приведен пример того, как вы можете сделать это:

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password',
array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

Можем ли мы установить атрибуты после построения PDO?

да, мы также можем установить некоторые атрибуты после построения PDO с setAttribute метод:

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Обработка ошибок


Обработка ошибок намного проще в PDO чем mysql_*,

Обычная практика при использовании mysql_* является:

//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));

OR die() это не хороший способ справиться с ошибкой, так как мы не можем справиться с вещью в die, Он просто внезапно завершит выполнение сценария, а затем отобразит ошибку на экране, которую вы обычно НЕ хотите показывать своим конечным пользователям, и позволит кровавым хакерам обнаружить вашу схему. Альтернативно, возвращаемые значения mysql_* функции часто могут использоваться в сочетании с mysql_error () обрабатывать ошибки.

PDO предлагает лучшее решение: исключения. Все, что мы делаем с PDO должны быть завернуты в trycatch блок. Мы можем заставить 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 может быть пойман и обработан изящно, если вы решите это сделать.

Хорошо для чтения:

Подобно:

$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

И вы можете обернуть его в trycatchкак показано ниже:

try {
//Connect as appropriate as above
$db->query('hi'); //Invalid query!
}
catch (PDOException $ex) {
echo "An Error occured!"; //User friendly message/message you want to show to user
some_logging_function($ex->getMessage());
}

Вы не должны справляться с trycatch прямо сейчас. Вы можете поймать его в любое удобное время, но я настоятельно рекомендую вам использовать trycatch, Также может иметь смысл поймать его за пределами функции, которая вызывает PDO материал:

function data_fun($db) {
$stmt = $db->query("SELECT * FROM table");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

//Then later
try {
data_fun($db);
}
catch(PDOException $ex) {
//Here you can handle error and show message/perform action you want.
}

Кроме того, вы можете справиться с or die() или мы можем сказать, как mysql_*, но это будет действительно разнообразно. Вы можете скрыть опасные сообщения об ошибках в производстве, повернув display_errors off и просто читать ваш журнал ошибок.

Теперь, после прочтения всего вышесказанного, вы, вероятно, подумаете: что за черт, когда я просто хочу начать просто SELECT, INSERT, UPDATE, или же DELETE заявления? Не волнуйтесь, здесь мы идем:


Выбор данных

PDO выбрать изображение

Так что вы делаете в mysql_* является:

<?php
$result = mysql_query('SELECT * from table') or die(mysql_error());

$num_rows = mysql_num_rows($result);

while($row = mysql_fetch_assoc($result)) {
echo $row['field1'];
}

Сейчас в PDOВы можете сделать это следующим образом:

<?php
$stmt = $db->query('SELECT * FROM table');

while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['field1'];
}

Или же

<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

//Use $results

Заметка: Если вы используете метод, как показано ниже (query()), этот метод возвращает PDOStatement объект. Поэтому, если вы хотите получить результат, используйте его, как указано выше.

<?php
foreach($db->query('SELECT * FROM table') as $row) {
echo $row['field1'];
}

В данных PDO это получается через ->fetch()метод вашего оператора. Перед вызовом fetch лучше всего сообщить PDO, как вы хотите получать данные. В следующем разделе я объясняю это.

Режимы выборки

Обратите внимание на использование PDO::FETCH_ASSOC в fetch() а также fetchAll() код выше. Это говорит PDO вернуть строки в виде ассоциативного массива с именами полей в качестве ключей. Есть также много других режимов извлечения, которые я объясню один за другим.

Прежде всего, я объясню, как выбрать режим выборки:

 $stmt->fetch(PDO::FETCH_ASSOC)

Выше я использовал fetch(), Вы также можете использовать:

  • PDOStatement::fetchAll() — Возвращает массив, содержащий все строки набора результатов
  • PDOStatement::fetchColumn() — Возвращает один столбец из следующей строки набора результатов
  • PDOStatement::fetchObject() — Выбирает следующую строку и возвращает ее как объект.
  • PDOStatement::setFetchMode() — Установите режим выборки по умолчанию для этого оператора

Теперь я пришел к режиму выборки:

  • PDO::FETCH_ASSOC: возвращает массив, проиндексированный по имени столбца, как возвращено в вашем наборе результатов
  • PDO::FETCH_BOTH (по умолчанию): возвращает массив, проиндексированный как по имени столбца, так и по номеру столбца с 0 индексами, как возвращено в вашем наборе результатов

Есть еще больше вариантов! Читайте о них все в PDOStatement Получить документацию..

Получение количества строк:

Вместо того, чтобы использовать mysql_num_rows чтобы получить количество возвращаемых строк, вы можете получить PDOStatement и делать rowCount(), лайк:

<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';

Получение последнего введенного идентификатора

<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();

Вставить и обновить или удалить заявления

Вставьте и обновите изображение PDO

Чем мы занимаемся mysql_* функция:

<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);

И в pdo то же самое можно сделать:

<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;

В приведенном выше запросе PDO::exec выполнить оператор SQL и возвращает количество затронутых строк.

Вставка и удаление будут рассмотрены позже.

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


Подготовленные заявления

Q. Что такое подготовленное заявление и зачем оно мне?
A. Подготовленный оператор — это предварительно скомпилированный оператор SQL, который можно выполнить несколько раз, отправив только данные на сервер.

Типичный рабочий процесс использования подготовленного оператора выглядит следующим образом (цитируется из википедии три 3 очка):

  1. Подготовить: Шаблон выписки создается приложением и отправляется в систему управления базами данных (СУБД). Некоторые значения не указываются, называются параметрами, заполнителями или переменными связывания (помечены ? ниже):

    INSERT INTO PRODUCT (name, price) VALUES (?, ?)

  2. СУБД анализирует, компилирует и выполняет оптимизацию запросов по шаблону оператора и сохраняет результат без его выполнения.

  3. казнитьПозже приложение предоставляет (или связывает) значения для параметров, и СУБД выполняет оператор (возможно, возвращая результат). Приложение может выполнить инструкцию столько раз, сколько захочет, с разными значениями. В этом примере он может предоставить «Хлеб» для первого параметра и 1.00 для второго параметра.

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

Q. Итак, как называются заполнители и как их использовать?
A. Именованные заполнители. Используйте описательные имена, начинающиеся с двоеточия, вместо вопросительных знаков. Нас не волнует позиция / порядок значений в названии местозаполнителя:

 $stmt->bindParam(':bla', $bla);

bindParam(parameter,variable,data_type,length,driver_options)

Вы также можете связать с использованием массива execute:

<?php
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

Еще одна приятная особенность для OOP Друзья в том, что именованные заполнители имеют возможность вставлять объекты непосредственно в вашу базу данных, предполагая, что свойства соответствуют именованным полям. Например:

class person {
public $name;
public $add;
function __construct($a,$b) {
$this->name = $a;
$this->add = $b;
}

}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);

Q. Итак, что же такое безымянные заполнители и как их использовать?
A. Давайте приведем пример:

<?php
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();

а также

$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));

В приведенном выше, вы можете увидеть те, ? вместо имени, как в названии местозаполнителя. Теперь в первом примере мы присваиваем переменные различным заполнителям ($stmt->bindValue(1, $name, PDO::PARAM_STR);). Затем мы присваиваем значения этим заполнителям и выполняем инструкцию. Во втором примере первый элемент массива переходит к первому ? и второй ко второму ?,

НОТА: В неназванные заполнители мы должны позаботиться о правильном порядке элементов в массиве, который мы передаем PDOStatement::execute() метод.


SELECT, INSERT, UPDATE, DELETE подготовленные запросы

  1. SELECT:

    $stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
    $stmt->execute(array(':name' => $name, ':id' => $id));
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
  2. INSERT:

    $stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
    $stmt->execute(array(':field1' => $field1, ':field2' => $field2));
    $affected_rows = $stmt->rowCount();
    
  3. DELETE:

    $stmt = $db->prepare("DELETE FROM table WHERE id=:id");
    $stmt->bindValue(':id', $id, PDO::PARAM_STR);
    $stmt->execute();
    $affected_rows = $stmt->rowCount();
    
  4. UPDATE:

    $stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
    $stmt->execute(array($name, $id));
    $affected_rows = $stmt->rowCount();
    

НОТА:

тем не мение PDO и / или MySQLi не совсем безопасны. Проверьте ответ Достаточно ли подготовленных операторов PDO для предотвращения внедрения SQL? от ircmaxell. Также я цитирую некоторую часть из его ответа:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES GBK');
$stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1");
$stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));
1200

Сначала давайте начнем со стандартного комментария, который мы даем всем:

Пожалуйста, не используйте mysql_* функции в новом коде. Они больше не поддерживаются и официально устарели. Увидеть красная коробка? Узнать о готовые заявления вместо этого и использовать PDO или же MySQLiЭта статья поможет вам решить, какой. Если вы выбираете PDO, вот хороший урок.

Давайте рассмотрим это, предложение за предложением, и объясним:

  • Они больше не поддерживаются и официально устарели

    Это означает, что сообщество PHP постепенно отказывается от поддержки этих очень старых функций. Они, вероятно, не существуют в будущей (недавней) версии PHP! Дальнейшее использование этих функций может нарушить ваш код в (не очень) будущем.

    NEW! — ext / mysql сейчас официально объявлен устаревшим с версии PHP 5.5!

    Новее! внутр / MySQL был удален в PHP 7.

  • Вместо этого вы должны узнать о готовых утверждениях

    mysql_* расширение не поддерживает готовые заявления, что является (среди прочего) очень эффективной контрмерой против SQL-инъекция. Он исправил очень серьезную уязвимость в MySQL-зависимых приложениях, которая позволяет злоумышленникам получить доступ к вашему сценарию и выполнить любой возможный запрос в вашей базе данных.

    Для получения дополнительной информации см. Как я могу предотвратить внедрение SQL в PHP?

  • Видишь красную коробку?

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

  • Используйте либо PDO, либо MySQLi

    Есть лучшие, более надежные и хорошо продуманные альтернативы, PDO — объект базы данных PHP, который предлагает полный ООП подход к взаимодействию с базой данных, и MySQLi, что является специфическим улучшением MySQL.

285

Простота использования

Аналитические и синтетические причины уже упоминались. Для новичков есть более существенный стимул прекратить использование устаревших функций mysql_.

Современные API баз данных просто Полегче использовать.

Это в основном связанные параметры который может упростить код. И с отличные учебники (как видно выше) переход к PDO не слишком сложно.

Перезапись большей кодовой базы за один раз, однако, требует времени. Raison d’être для этой промежуточной альтернативы:

Эквивалентные функции pdo_ * вместо mysql_ *

С помощью <pdo_mysql.php> Вы можете переключиться со старых функций mysql_ с помощью минимальное усилие. Добавляет pdo_ функциональные обертки, которые заменяют их mysql_ двойники.

  1. Просто include_once("pdo_mysql.php"); в каждом скрипте вызова, который должен взаимодействовать с базой данных.

  2. Удалить 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()
    • и так далее…
  3. Ваш код будет работать одинаково и в основном будет выглядеть так же:

    include_once("pdo_mysql.php");
    
    pdo_connect("localhost", "usrABC", "pw1234567");
    pdo_select_db("test");
    
    $result = pdo_query("SELECT title, html FROM pages");
    
    while ($row = pdo_fetch_assoc($result)) {
    print "$row[title] - $row[html]";
    }
    

И вуаля.
Ваш код с помощью PDO.
Теперь пришло время на самом деле использовать Это.

Связанные параметры могут быть просты в использовании

Вам просто нужен менее громоздкий API.

pdo_query() добавляет очень легкую поддержку для связанных параметров. Преобразовать старый код просто:

Переместите ваши переменные из строки SQL.

  • Добавьте их в качестве параметров функции, разделенных запятыми, в pdo_query(),
  • Поместите вопросительные знаки ? в качестве заполнителей, где переменные были раньше.
  • Избавляться от ' одинарные кавычки, которые ранее заключены в строковые значения / переменные.

Преимущество становится более очевидным для более длинного кода.

Часто строковые переменные не просто интерполируются в SQL, а объединяются с экранированием вызовов между ними.

pdo_query("SELECT id, links, html, title, user, date FROM articles
WHERE title='" . pdo_real_escape_string($title) . "' OR id='".
pdo_real_escape_string($title) . "' AND user <> '" .
pdo_real_escape_string($root) . "' ORDER BY date")

С ? заполнители подали заявку, вам не нужно беспокоиться об этом:

pdo_query("SELECT id, links, html, title, user, date FROM articles
WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root)

Помните, что pdo_ * все еще позволяет либо.
Просто не экранируйте переменную а также привязать его в том же запросе.

  • Функция заполнителя обеспечивается настоящим PDO за ним.
  • Таким образом, также допускается :named списки заполнителей позже.

Что еще более важно вы можете безопасно передавать переменные $ _REQUEST [] за любым запросом. Когда подано <form> поля соответствуют структуре базы данных, она еще короче:

pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);

Так много простоты. Но давайте вернемся к еще нескольким советам по переписыванию и техническим причинам, по которым вы можете избавиться от mysql_ и сбежать.

Исправить или удалить любую oldschool sanitize() функция

Как только вы преобразовали все mysql_ звонки в pdo_query со связанными параметрами, удалите все лишние pdo_real_escape_string звонки.

В частности, вы должны исправить любые sanitize или же clean или же filterThis или же clean_data функции, заявленные датированными уроками в той или иной форме:

function sanitize($str) {
return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}

Самая вопиющая ошибка здесь — отсутствие документации. Что еще более важно, порядок фильтрации был в неправильном порядке.

  • Правильный порядок был бы: не рекомендуется stripslashes как внутренний вызов, то trimпотом strip_tags, htmlentities для выходного контекста, и только в конце _escape_string так как его применение должно предшествовать промежуточному анализу SQL.

  • Но в качестве первого шага просто избавиться от _real_escape_string вызов.

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

  • Обработка строк / значений делегируется PDO и его параметризованным операторам.

  • Если было какое-либо упоминание о stripslashes() в вашей функции дезинфекции это может указывать на более высокий уровень контроля.

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

    Оригинальная реализация в PHP2 / FI представила это явно с помощью просто «кавычки будут автоматически экранированы, что упростит передачу данных формы непосредственно в запросы msql«. Это было случайно безопасно для использования с Msql, так как это поддерживает только ASCII.
    Затем PHP3 / Zend заново ввел magic_quotes для MySQL и неправильно его документировал. Но изначально это было просто удобная функция, не предназначено для безопасности.

Чем отличаются готовые заявления

Когда вы скремблируете строковые переменные в запросы 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 ().

Однако лучше начать с упрощения. Например, общий результат выборки:

$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {

Может быть заменено только итерацией foreach:

foreach ($result as $row) {

Или, что еще лучше, прямой и полный поиск массивов:

$result->fetchAll();

В большинстве случаев вы получите более полезные предупреждения, чем обычно предоставляют PDO или mysql_ после неудачных запросов.

Другие опции

Так что это, надеюсь, визуализировал некоторые практическое причины и достойный путь mysql_.

Просто переключаюсь на не совсем порезать это. pdo_query() это также просто интерфейс на него.

Если вы не введете привязку параметров или не сможете использовать что-то еще из более приятного API, это бессмысленный переход. Я надеюсь, что это изображено достаточно просто, чтобы не способствовать разочарованию новичков. (Образование обычно работает лучше, чем запрет.)

Несмотря на то, что он соответствует категории «самая простая вещь, которая может быть возможна», он также все еще является очень экспериментальным кодом. Я просто написал это на выходных. Однако существует множество альтернатив. Просто Google для PHP база данных абстракция и просмотр немного. Для таких задач всегда было и будет много отличных библиотек.

Если вы хотите еще больше упростить взаимодействие с базой данных, такие как Париж / Idiorm стоит попробовать. Точно так же, как никто не использует более мягкий DOM в JavaScript, вам не нужно сейчас присматривать за сырым интерфейсом базы данных.

205

mysql_ функции:

  1. устарели — они больше не поддерживаются
  2. не позволяют легко переходить на другую базу данных
  3. не поддерживает подготовленные заявления, следовательно
  4. поощрять программистов использовать конкатенацию для построения запросов, что приводит к уязвимостям внедрения SQL
136

Говоря о технический Причин здесь всего несколько, крайне специфичных и редко используемых. Скорее всего, вы никогда не будете использовать их в своей жизни.
Может быть, я слишком невежественен, но у меня никогда не было возможности использовать такие вещи, как

  • неблокирующие, асинхронные запросы
  • хранимые процедуры, возвращающие несколько результирующих наборов
  • Шифрование (SSL)
  • компрессия

Если они вам нужны — это, без сомнения, технические причины для перехода от расширения mysql к чему-то более стильному и современному.

Тем не менее, есть также некоторые нетехнические проблемы, которые могут сделать ваш опыт немного сложнее

  • Дальнейшее использование этих функций в современных версиях PHP вызовет уведомления устаревшего уровня. Их просто можно отключить.
  • в отдаленном будущем они могут быть удалены из сборки PHP по умолчанию. Не так уж и страшно, так как mydsql ext будет перемещен в PECL, и каждый хостер будет рад скомпилировать с ним PHP, так как они не хотят терять клиентов, чьи сайты работали десятилетиями.
  • сильное сопротивление со стороны сообщества Stackoverflow. Каждый раз, когда вы упоминаете эти честные функции, вам говорят, что они находятся под строгим табу.
  • Будучи обычным пользователем PHP, скорее всего, ваша идея использовать эти функции подвержена ошибкам и ошибочна. Просто из-за всех этих многочисленных учебников и пособий, которые научат вас неправильному пути. Не сами функции — я должен это подчеркнуть — а то, как они используются.

Эта последняя проблема является проблемой.
Но, на мой взгляд, предлагаемое решение тоже не лучше.
По-моему слишком идеалистично мечта, чтобы все эти пользователи PHP научились правильно обрабатывать запросы SQL. Скорее всего, они просто изменили бы mysql_ * на mysqli_ * механически, оставив подход тот же. Тем более, что mysqli делает использование готовых заявлений невероятно болезненным и хлопотным.
Не говоря уже о том, что родные готовые заявления недостаточно для защиты от SQL-инъекций, и ни mysqli, ни PDO не предлагают решения.

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

Кроме того, есть несколько ложных или несущественных причин, таких как

  • Не поддерживает хранимые процедуры (мы использовали mysql_query("CALL my_proc"); на века)
  • Не поддерживает транзакции (как указано выше)
  • Не поддерживает множественные заявления (кому они нужны?)
  • Не в активном развитии (и что? Это влияет вы любым практическим способом?)
  • Отсутствует интерфейс OO (для его создания требуется несколько часов)
  • Не поддерживает подготовленные операторы или параметризованные запросы

Последний интересный момент. Хотя mysql ext не поддерживает родные подготовленные заявления, они не требуются для безопасности. Мы можем легко подделать подготовленные операторы, используя заполнители, обработанные вручную (как это делает PDO):

function paraQuery()
{
$args  = func_get_args();
$query = array_shift($args);
$query = str_replace("%s","'%s'",$query);

foreach ($args as $key => $val)
{
$args[$key] = mysql_real_escape_string($val);
}

$query  = vsprintf($query, $args);
$result = mysql_query($query);
if (!$result)
{
throw new Exception(mysql_error()." [$query]");
}
return $result;
}

$query  = "SELECT * FROM table where a=%s AND b LIKE %s LIMIT %d";
$result = paraQuery($query, $a, "%$b%", $limit);

вуаля, все параметризовано и безопасно.

Но хорошо, если вам не нравится красный прямоугольник в руководстве, возникает проблема выбора: mysqli или PDO?

Ну, ответ будет следующим:

  • Если вы понимаете необходимость использования уровень абстракции базы данных и ищет API для его создания, MySQLi Это очень хороший выбор, так как он действительно поддерживает многие специфичные для MySQL функции.
  • Если, как и подавляющее большинство PHP-пользователей, вы используете необработанные вызовы API прямо в коде приложения (что по сути неверно) — PDO — единственный выбор, так как это расширение претендует на то, чтобы быть не просто API, а скорее полу-DAL, все еще неполным, но предлагает много важных функций, две из которых делают PDO критически отличным от mysqli:

    • в отличие от mysqli, PDO может связывать заполнители по значению, что делает динамически построенные запросы выполнимыми без нескольких экранов довольно грязного кода.
    • в отличие от mysqli, PDO всегда может вернуть результат запроса в простом обычном массиве, тогда как mysqli может сделать это только при установке mysqlnd.

Итак, если вы обычный пользователь PHP и хотите сэкономить массу головной боли при использовании встроенных подготовленных операторов, PDO — опять же — единственный выбор.
Тем не менее, PDO тоже не серебряная пуля и имеет свои трудности.
Итак, я написал решения для всех распространенных ошибок и сложных случаев в PDO tag вики

Тем не менее, все, кто говорит о расширениях, всегда пропускают 2 важных факта о Mysqli и PDO:

  1. Подготовленное заявление не серебряная пуля. Существуют динамические идентификаторы, которые не могут быть связаны с использованием подготовленных операторов. Существуют динамические запросы с неизвестным количеством параметров, что затрудняет построение запросов.

  2. Ни mysqli_ *, ни функции PDO не должны были появиться в коде приложения.
    Там должно быть слой абстракции между ними и кодом приложения, который будет выполнять всю грязную работу по связыванию, зацикливанию, обработке ошибок и т. д. внутри, делая код приложения СУХИМЫМ и чистым. Особенно для сложных случаев, таких как динамическое построение запросов.

Так что просто переключиться на PDO или mysqli недостаточно. Нужно использовать ORM, или построитель запросов, или любой другой класс абстракции базы данных, вместо того, чтобы вызывать необработанные функции API в их коде.
И наоборот — если у вас есть уровень абстракции между кодом приложения и MySQL API — на самом деле не имеет значения, какой двигатель используется. Вы можете использовать mysql ext до тех пор, пока он не устареет, а затем легко переписать ваш класс абстракции на другой движок, имея весь код приложения без изменений.

Вот несколько примеров, основанных на моем класс safemysql чтобы показать, каким должен быть такой класс абстракции:

$city_ids = array(1,2,3);
$cities   = $db->getCol("SELECT name FROM cities WHERE is IN(?a)", $city_ids);

Сравните эту единственную строку с количество кода, которое вам нужно с PDO.
Тогда сравните с сумасшедшее количество кода Вы будете нуждаться в готовых заявлениях Mysqli.
Обратите внимание, что обработка ошибок, профилирование, ведение журнала запросов уже встроены и работают.

$insert = array('name' => 'John', 'surname' => "O'Hara");
$db->query("INSERT INTO users SET ?u", $insert);

Сравните это с обычными вставками PDO, когда каждое имя поля повторяется шесть-десять раз — во всех этих многочисленных именованных заполнителях, привязках и определениях запросов.

Другой пример:

$data = $db->getAll("SELECT * FROM goods ORDER BY ?n", $_GET['order']);

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

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

99

Причин много, но, возможно, самая важная из них заключается в том, что эти функции поощряют небезопасные методы программирования, поскольку они не поддерживают подготовленные операторы. Подготовленные операторы помогают предотвратить атаки с использованием SQL-инъекций.

Когда используешь mysql_* функции, вы должны помнить, чтобы запустить пользовательские параметры через mysql_real_escape_string(), Если вы забыли только в одном месте или вам удалось избежать только части ввода, ваша база данных может подвергнуться атаке.

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

88

Потому что (среди прочих причин) гораздо сложнее обеспечить очистку входных данных. Если вы используете параметризованные запросы, как в случае с PDO или mysqli, вы можете полностью избежать риска.

Как пример, кто-то может использовать "enhzflep); drop table users" как имя пользователя. Старые функции позволят выполнять несколько операторов за запрос, поэтому что-то вроде этого мерзкого баггера может удалить всю таблицу.

Если бы кто-то использовал PDO mysqli, имя пользователя в конечном итоге было бы "enhzflep); drop table users",

Увидеть bobby-tables.com.

71
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector