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

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

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

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

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

17 ответов

Решение

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

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

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

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

Смотрите сравнение расширений 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_* функция:

  • Не в стадии активной разработки
  • Удалено с 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"?

A. " PDO - PHP Data Objects - это уровень доступа к базе данных, обеспечивающий единый метод доступа к нескольким базам данных".

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


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

Хорошо читать:

Подобно:

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

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

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());
}

Вы не должны справляться с try - catch прямо сейчас. Вы можете поймать его в любое удобное время, но я настоятельно рекомендую вам использовать try - catch, Также может иметь смысл поймать его за пределами функции, которая вызывает 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 и возвращает количество затронутых строк.

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

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


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

В. Что такое подготовленное утверждение и зачем оно мне?
О. Подготовленный оператор - это предварительно скомпилированный оператор SQL, который можно выполнить несколько раз, отправив только данные на сервер.

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

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

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

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

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

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

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

 $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);

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

<?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 /*"));

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

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

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

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

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

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

    Новее! ext/mysql был удален в PHP 7.

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

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

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

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

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

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

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

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

Аналитические и синтетические причины уже упоминались. Для новичков есть более существенный стимул прекратить использование устаревших функций 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 не совсем так. pdo_query() это также просто интерфейс на него.

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

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

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

mysql_ функции:

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

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

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

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

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

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

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

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

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

Таким образом, просто переключиться на PDO или MySQL не достаточно. Нужно использовать 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, чтобы справиться с таким практическим случаем.
И это будет слишком многословно и, скорее всего, небезопасно.

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

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

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

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

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

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

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

Смотрите http://bobby-tables.com/.

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

Прежде всего, пожалуйста, не стесняйтесь создавать эту тестовую базу данных MySQL (я назвал мой Prep):

mysql> create table users(
    -> id int(2) primary key auto_increment,
    -> userid tinytext,
    -> pass tinytext);
Query OK, 0 rows affected (0.05 sec)

mysql> insert into users values(null, 'Fluffeh', 'mypass');
Query OK, 1 row affected (0.04 sec)

mysql> create user 'prepared'@'localhost' identified by 'example';
Query OK, 0 rows affected (0.01 sec)

mysql> grant all privileges on prep.* to 'prepared'@'localhost' with grant option;
Query OK, 0 rows affected (0.00 sec)

После этого мы можем перейти к нашему PHP-коду.

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

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }

    $database='prep';
    $link=mysql_connect('localhost', 'prepared', 'example');
    mysql_select_db($database) or die( "Unable to select database");

    $sql="select id, userid, pass from users where userid='$user' and pass='$pass'";
    //echo $sql."<br><br>";
    $result=mysql_query($sql);
    $isAdmin=false;
    while ($row = mysql_fetch_assoc($result)) {
        echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
        $isAdmin=true;
        // We have correctly matched the Username and Password
        // Lets give this person full access
    }
    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }
    mysql_close($link);

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

На первый взгляд кажется вполне законным.

Пользователь должен ввести логин и пароль, верно?

Молодец, не входи в следующее:

user: bob
pass: somePass

и представить его.

Вывод следующий:

You could not be verified. Please try again...

Супер! Работая как положено, теперь давайте попробуем ввести действительное имя пользователя и пароль:

user: Fluffeh
pass: mypass

Удивительно! Привет пятерки со всех сторон, код правильно проверен админом. Это идеально!

Ну не совсем. Допустим, пользователь умный маленький человек. Допустим, человек - это я.

Введите в следующем:

user: bob
pass: n' or 1=1 or 'm=m

И вывод:

The check passed. We have a verified admin!

Поздравляю, вы только что разрешили мне войти в раздел ваших сверхзащищенных администраторов, указав ложное имя пользователя и ложный пароль. Серьезно, если вы мне не верите, создайте базу данных с помощью предоставленного мною кода и запустите этот PHP-код, который на первый взгляд ДЕЙСТВИТЕЛЬНО, кажется, довольно хорошо проверяет имя пользователя и пароль.

Итак, в ответ, это то, почему вы кричали на.

Итак, давайте посмотрим, что пошло не так, и почему я только что попал в вашу пещеру супер-админ-только-летучая мышь. Я сделал предположение и предположил, что вы не были осторожны со своими данными и просто передали их напрямую в базу данных. Я сконструировал вход таким образом, чтобы он ИЗМЕНИЛ запрос, который вы на самом деле выполняли. Итак, что это должно было быть, и что это было в итоге?

select id, userid, pass from users where userid='$user' and pass='$pass'

Это запрос, но когда мы заменяем переменные фактическими входными данными, которые мы использовали, мы получаем следующее:

select id, userid, pass from users where userid='bob' and pass='n' or 1=1 or 'm=m'

Посмотрите, как я построил свой "пароль", чтобы он сначала закрывал одинарную кавычку вокруг пароля, а затем вводил совершенно новое сравнение? Затем для безопасности я добавил еще одну "строку", чтобы одинарная кавычка закрывалась, как и ожидалось, в исходном коде.

Однако речь идет не о людях, которые на вас кричат, а о том, как сделать ваш код более безопасным.

Итак, что пошло не так, и как мы можем это исправить?

Это классическая SQL-инъекция. Один из самых простых в этом отношении. По шкале векторов атаки этот малыш атакует танк - и выигрывает.

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

Теперь у вас есть лучшие варианты использования mysqli_ или PDO. Я лично большой поклонник PDO, поэтому я буду использовать PDO в оставшейся части этого ответа. Есть "за" и "против", но лично я считаю, что "за" намного перевешивают "против". Он переносим между несколькими ядрами баз данных - используете ли вы MySQL или Oracle или просто что-то кровавое - просто изменив строку подключения, он обладает всеми интересными функциями, которые мы хотим использовать, и он приятен и чист. Мне нравится чистый.

Теперь давайте снова посмотрим на этот код, на этот раз написанный с использованием объекта PDO:

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }
    $isAdmin=false;

    $database='prep';
    $pdo=new PDO ('mysql:host=localhost;dbname=prep', 'prepared', 'example');
    $sql="select id, userid, pass from users where userid=:user and pass=:password";
    $myPDO = $pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
    if($myPDO->execute(array(':user' => $user, ':password' => $pass)))
    {
        while($row=$myPDO->fetch(PDO::FETCH_ASSOC))
        {
            echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
            $isAdmin=true;
            // We have correctly matched the Username and Password
            // Lets give this person full access
        }
    }

    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

Основные отличия в том, что больше нет mysql_* функции. Все это делается через объект PDO, во-вторых, он использует подготовленный оператор. Теперь, какое предварительное утверждение вы спрашиваете? Это способ сообщить базе данных перед выполнением запроса, что запрос мы собираемся запустить. В этом случае мы говорим базе данных: "Привет, я собираюсь запустить оператор select с запросом id, userid и pass от пользователей таблицы, где userid - это переменная, а pass - также переменная".

Затем в операторе execute мы передаем базе данных массив со всеми переменными, которые он теперь ожидает.

Результаты фантастические. Давайте попробуем эти комбинации имени пользователя и пароля еще раз:

user: bob
pass: somePass

Пользователь не был подтвержден. Потрясающие.

Как насчет:

user: Fluffeh
pass: mypass

О, я просто немного взволнован, это сработало: проверка прошла. У нас есть проверенный админ!

Теперь, давайте попробуем данные, которые введет умный парень, чтобы попытаться обойти нашу маленькую систему проверки:

user: bob
pass: n' or 1=1 or 'm=m

На этот раз мы получаем следующее:

You could not be verified. Please try again...

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

Наконец, это не означает, что это ИДЕАЛЬНЫЙ код. Есть много вещей, которые вы могли бы сделать, чтобы улучшить его, например, использовать хешированные пароли, обеспечить, чтобы при хранении чувствительной информации в базе данных вы не хранили ее в виде простого текста, имели несколько уровней проверки - но на самом деле, если вы просто измените свой старый подверженный инъекциям код на это, вы будете ХОРОШО на пути к написанию хорошего кода - и тот факт, что вы продвинулись так далеко и все еще читаете, дает мне чувство надежды, что вы не только реализуете этот тип кода при написании ваших веб-сайтов и приложений, но вы можете выйти и исследовать те другие вещи, которые я только что упомянул - и многое другое. Напишите лучший код, который вы можете, а не самый простой код, который едва работает.

Расширение MySQL является старейшим из трех и было оригинальным способом, который разработчики использовали для связи с MySQL. Это расширение в настоящее время не рекомендуется в пользу двух других альтернатив из-за улучшений, сделанных в более новых выпусках как PHP, так и MySQL.

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

  • PDO предлагает API, который объединяет большинство функций, которые ранее были распространены на основные расширения доступа к базе данных, то есть MySQL, PostgreSQL, SQLite, MSSQL и т. Д. Интерфейс предоставляет высокоуровневые объекты для программиста для работы с соединениями с базой данных, запросами и наборы результатов и низкоуровневые драйверы осуществляют связь и обработку ресурсов с сервером базы данных. В PDO идет много дискуссий и работы, и он считается подходящим методом работы с базами данных в современном профессиональном коде.

Я считаю, что приведенные выше ответы действительно длинные, поэтому подведем итог:

Расширение mysqli имеет ряд преимуществ, ключевые улучшения по сравнению с расширением mysql:

  • Объектно-ориентированный интерфейс
  • Поддержка подготовленных заявлений
  • Поддержка нескольких заявлений
  • Поддержка транзакций
  • Расширенные возможности отладки
  • Поддержка встроенного сервера

Источник: MySQLi обзор


Как объяснялось в ответах выше, альтернативами mysql являются mysqli и PDO (объекты данных PHP).

  • API поддерживает подготовленные операторы на стороне сервера: поддерживается MYSQLi и PDO
  • API поддерживает подготовленные операторы на стороне клиента: поддерживается только PDO
  • API поддерживает хранимые процедуры: MySQLi и PDO
  • API поддерживает множественные операторы и все функции MySQL 4.1+ - поддерживается MySQLi и в основном также PDO

И MySQLi, и PDO были введены в PHP 5.0, тогда как MySQL был представлен до PHP 3.0. Следует отметить, что MySQL включен в PHP5.x, хотя и не рекомендуется в более поздних версиях.

Можно определить почти все mysql_* функции с использованием MySQL или PDO. Просто включите их поверх старого PHP-приложения, и оно будет работать на PHP7. Мое решение здесь.

<?php

define('MYSQL_LINK', 'dbl');
$GLOBALS[MYSQL_LINK] = null;

function mysql_link($link=null) {
    return ($link === null) ? $GLOBALS[MYSQL_LINK] : $link;
}

function mysql_connect($host, $user, $pass) {
    $GLOBALS[MYSQL_LINK] = mysqli_connect($host, $user, $pass);
    return $GLOBALS[MYSQL_LINK];
}

function mysql_pconnect($host, $user, $pass) {
    return mysql_connect($host, $user, $pass);
}

function mysql_select_db($db, $link=null) {
    $link = mysql_link($link);
    return mysqli_select_db($link, $db);
}

function mysql_close($link=null) {
    $link = mysql_link($link);
    return mysqli_close($link);
}

function mysql_error($link=null) {
    $link = mysql_link($link);
    return mysqli_error($link);
}

function mysql_errno($link=null) {
    $link = mysql_link($link);
    return mysqli_errno($link);
}

function mysql_ping($link=null) {
    $link = mysql_link($link);
    return mysqli_ping($link);
}

function mysql_stat($link=null) {
    $link = mysql_link($link);
    return mysqli_stat($link);
}

function mysql_affected_rows($link=null) {
    $link = mysql_link($link);
    return mysqli_affected_rows($link);
}

function mysql_client_encoding($link=null) {
    $link = mysql_link($link);
    return mysqli_character_set_name($link);
}

function mysql_thread_id($link=null) {
    $link = mysql_link($link);
    return mysqli_thread_id($link);
}

function mysql_escape_string($string) {
    return mysql_real_escape_string($string);
}

function mysql_real_escape_string($string, $link=null) {
    $link = mysql_link($link);
    return mysqli_real_escape_string($link, $string);
}

function mysql_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql);
}

function mysql_unbuffered_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql, MYSQLI_USE_RESULT);
}

function mysql_set_charset($charset, $link=null){
    $link = mysql_link($link);
    return mysqli_set_charset($link, $charset);
}

function mysql_get_host_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_host_info($link);
}

function mysql_get_proto_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_proto_info($link);
}
function mysql_get_server_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_server_info($link);
}

function mysql_info($link=null) {
    $link = mysql_link($link);
    return mysqli_info($link);
}

function mysql_get_client_info() {
    $link = mysql_link();
    return mysqli_get_client_info($link);
}

function mysql_create_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "CREATE DATABASE `$db`");
}

function mysql_drop_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "DROP DATABASE `$db`");
}

function mysql_list_dbs($link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, "SHOW DATABASES");
}

function mysql_list_fields($db, $table, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    $table = str_replace('`', '', mysqli_real_escape_string($link, $table));
    return mysqli_query($link, "SHOW COLUMNS FROM `$db`.`$table`");
}

function mysql_list_tables($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "SHOW TABLES FROM `$db`");
}

function mysql_db_query($db, $sql, $link=null) {
    $link = mysql_link($link);
    mysqli_select_db($link, $db);
    return mysqli_query($link, $sql);
}

function mysql_fetch_row($qlink) {
    return mysqli_fetch_row($qlink);
}

function mysql_fetch_assoc($qlink) {
    return mysqli_fetch_assoc($qlink);
}

function mysql_fetch_array($qlink, $result=MYSQLI_BOTH) {
    return mysqli_fetch_array($qlink, $result);
}

function mysql_fetch_lengths($qlink) {
    return mysqli_fetch_lengths($qlink);
}

function mysql_insert_id($qlink) {
    return mysqli_insert_id($qlink);
}

function mysql_num_rows($qlink) {
    return mysqli_num_rows($qlink);
}

function mysql_num_fields($qlink) {
    return mysqli_num_fields($qlink);
}

function mysql_data_seek($qlink, $row) {
    return mysqli_data_seek($qlink, $row);
}

function mysql_field_seek($qlink, $offset) {
    return mysqli_field_seek($qlink, $offset);
}

function mysql_fetch_object($qlink, $class="stdClass", array $params=null) {
    return ($params === null)
        ? mysqli_fetch_object($qlink, $class)
        : mysqli_fetch_object($qlink, $class, $params);
}

function mysql_db_name($qlink, $row, $field='Database') {
    mysqli_data_seek($qlink, $row);
    $db = mysqli_fetch_assoc($qlink);
    return $db[$field];
}

function mysql_fetch_field($qlink, $offset=null) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    return mysqli_fetch_field($qlink);
}

function mysql_result($qlink, $offset, $field=0) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    $row = mysqli_fetch_array($qlink);
    return (!is_array($row) || !isset($row[$field]))
        ? false
        : $row[$field];
}

function mysql_field_len($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->length : false;
}

function mysql_field_name($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgname) ? $field->name : $field->orgname;
}

function mysql_field_table($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgtable) ? $field->table : $field->orgtable;
}

function mysql_field_type($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->type : false;
}

function mysql_free_result($qlink) {
    try {
        mysqli_free_result($qlink);
    } catch (Exception $e) {
        return false;
    }
    return true;
}

Не используйте mysql, потому что он устарел, используйте Mysqli.

Что означает устаревшее:

Это означает, что не используйте какую-то конкретную функцию / метод / функцию программного обеспечения / конкретную программную практику, это просто означает, что ее не следует использовать, потому что в этом программном обеспечении есть (или будет) лучшая альтернатива, которую следует использовать вместо этого.

При использовании устаревших функций может возникнуть несколько общих проблем:

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

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

Например: это может вызвать проблемы со входом в систему (файлы cookie / сеансы не устанавливаются должным образом) или проблемы с пересылкой (перенаправления 301/302/303).

имейте в виду, что:

-Устаревшее программное обеспечение по-прежнему является частью программного обеспечения.

-Устаревший код - это просто статус (метка) кода.

Ключевые различия между MYSQL и MYSQLI | mysql* | mysqli || ---------------------------------------- | -------- ------------------------------- || старый драйвер базы данных | новый драйвер базы данных || MySQL можно использовать только процедурно | как процедурные, так и объектно-ориентированные || Нет защиты от атаки sql-инъекции | подготовленное заявление защищает от нападок || Устарела в PHP 5.5.0 и была удалена в PHP 7 | В настоящее время используется |

Это старый вопрос сегодня (январь 2019 года), но он все еще может быть полезным. Около 7 лет назад я создал табличное отображение функциональности MySQL / MySQLi / PDO. Может быть полезной ссылкой. Это онлайн здесь и воспроизведено ниже. Не стесняйтесь копировать и вставлять HTML.

На практике я обнаружил, что преобразование процедурных функций MySQL в ООП MySQLi - это путь наименьшего сопротивления. Прекрасно, когда два соединения с БД открыты одновременно, и это дало нам некоторую гибкость при работе с преобразованиями - мы могли преобразовывать сценарии по частям, по одному запросу за раз. Хотя я не мог бы рекомендовать это сегодня, это было целесообразно в то время.

<div class="container">

<h2>Mapping Obsolete MySQL Functions to Current PHP Extensions</h2>
<table>
<tr><th>MySQL Extension</th><th>MySQL<b><i>i</i></b></th><th>PDO</th></tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-affected-rows.php">mysql_affected_rows</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.affected-rows.php">mysqli::$affected_rows</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.rowcount.php">PDOStatement::rowCount</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-client-encoding.php">mysql_client_encoding</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.character-set-name.php">mysqli::character_set_name</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-close.php">mysql_close</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.close.php">mysqli::close</a></td>
    <td>Assign NULL to PDO Object</td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-connect.php">mysql_connect</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.construct.php">mysqli::__construct</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.construct.php">PDO::__construct</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-create-db.php">mysql_create_db</a></td>
    <td>Query: CREATE DATABASE</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-data-seek.php">mysql_data_seek</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-stmt.data-seek.php">mysqli_stmt::data_seek</a></td>
    <td>PDO::FETCH_ORI_ABS (?)</td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-db-name.php">mysql_db_name</a></td>
    <td>Query: SELECT DATABASE()</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-db-query.php">mysql_db_query</a></td>
    <td> </td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-drop-db.php">mysql_drop_db</a></td>
    <td>Query: DROP DATABASE</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-errno.php">mysql_errno</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.errno.php">mysqli::$errno</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.errorcode.php">PDO::errorCode</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-error.php">mysql_error</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.error-list.php">mysqli::$error_list</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.errorinfo.php">PDO::errorInfo</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-escape-string.php">mysql_escape_string</a></td>
    <td> </td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-array.php">mysql_fetch_array</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-array.php">mysqli_result::fetch_array</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetch.php">PDOStatement::fetch</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-assoc.php">mysql_fetch_assoc</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-assoc.php">mysqli_result::fetch_assoc</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetch.php">PDOStatement::fetch</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-field.php">mysql_fetch_field</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-field.php">mysqli_result::fetch_field</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-lengths.php">mysql_fetch_lengths</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.lengths.php">mysqli_result::$lengths</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-object.php">mysql_fetch_object</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-object.php">mysqli_result::fetch_object</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetch.php">PDOStatement::fetch</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-row.php">mysql_fetch_row</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-row.php">mysqli_result::fetch_row</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetch.php">PDOStatement::fetch</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-flags.php">mysql_field_flags</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-fields.php">mysqli_result::fetch_fields</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-len.php">mysql_field_len</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-field-direct.php">mysqli_result::fetch_field_direct</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-name.php">mysql_field_name</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-field-direct.php">mysqli_result::fetch_field_direct</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-seek.php">mysql_field_seek</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.field-seek.php">mysqli_result::field_seek</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetch.php">PDOStatement::fetch</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-table.php">mysql_field_table</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-field-direct.php">mysqli_result::fetch_field_direct</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-type.php">mysql_field_type</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-field-direct.php">mysqli_result::fetch_field_direct</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-free-result.php">mysql_free_result</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.free.php">mysqli_result::free</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.closecursor.php">PDOStatement::closeCursor</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-get-client-info.php">mysql_get_client_info</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.get-client-info.php">mysqli::get_client_info</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.getattribute.php">PDO::getAttribute</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-get-host-info.php">mysql_get_host_info</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.get-host-info.php">mysqli::$host_info</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.getattribute.php">PDO::getAttribute</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-get-proto-info.php">mysql_get_proto_info</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.get-proto-info.php">mysqli::$protocol_version</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-get-server-info.php">mysql_get_server_info</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.get-server-info.php">mysqli::$server_info</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.getattribute.php">PDO::getAttribute</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-info.php">mysql_info</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.info.php">mysqli::$info</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-insert-id.php">mysql_insert_id</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.insert-id.php">mysqli::$insert_id</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.lastinsertid.php">PDO::lastInsertId</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-list-dbs.php">mysql_list_dbs</a></td>
    <td>Query: SHOW DATABASES</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-list-fields.php">mysql_list_fields</a></td>
    <td>Query: SHOW COLUMNS</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-list-processes.php">mysql_list_processes</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.thread-id.php">mysqli::$thread_id</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-list-tables.php">mysql_list_tables</a></td>
    <td>Query: SHOW TABLES</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-num-fields.php">mysql_num_fields</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.field-count.php">mysqli::$field_count</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.columncount.php">PDOStatement::columnCount</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-num-rows.php">mysql_num_rows</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-stmt.num-rows.php">mysqli_stmt::$num_rows</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.rowcount.php">PDOStatement::rowCount</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-pconnect.php">mysql_pconnect</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.construct.php">mysqli::__construct</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.construct.php">PDO::__construct</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-ping.php">mysql_ping</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.ping.php">mysqli::ping</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-query.php">mysql_query</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.query.php">mysqli::query</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.query.php">PDO::query</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-real-escape-string.php">mysql_real_escape_string</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.real-escape-string.php">mysqli::real_escape_string</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.quote.php">PDO::quote</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-result.php">mysql_result</a></td>
    <td>Combination</td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetchcolumn.php">PDOStatement::fetchColumn</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-select-db.php">mysql_select_db</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.send-query.php">mysqli::send_query</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.construct.php">PDO::__construct</a></td></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-set-charset.php">mysql_set_charset</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.character-set-name.php">mysqli::character_set_name</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.construct.php">PDO::__construct</a></td></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-stat.php">mysql_stat</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.stat.php">mysqli::stat</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.getattribute.php">PDO::getAttribute</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-tablename.php">mysql_tablename</a></td>
    <td>Query: SHOW TABLES</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-thread-id.php">mysql_thread_id</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.thread-id.php">mysqli::$thread_id</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-unbuffered-query.php">mysql_unbuffered_query</a></td>
    <td>See <a href="http://www.php.net/manual/en/mysqlinfo.concepts.buffering.php">Buffering Concepts</a></td>
    <td> </td>
    </tr>
</table>

</div><!-- container -->

Функции, которые похожи на это mysql_connect(), mysql_query() Типом являются предыдущие версии PHP, т.е. функции (PHP 4), и теперь они не используются.

Они заменены mysqli_connect(), mysqli_query() аналогично в последней версии PHP5.

Это причина ошибки.

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

Функции mysql_* устарели (начиная с PHP 5.5), учитывая тот факт, что были разработаны более совершенные функции и структуры кода. Тот факт, что функция устарела, означает, что больше не нужно прилагать усилий для ее улучшения с точки зрения производительности и безопасности, что означает, что она менее надежна в будущем.

Если вам нужно больше причин:

  • Функции mysql_* не поддерживают подготовленные операторы.
  • Функции mysql_* не поддерживают привязку параметров.
  • В функциях mysql_* отсутствует функциональность для объектно-ориентированного программирования.
  • список можно продолжить...
Другие вопросы по тегам