Каковы технические причины, почему не следует использовать mysql_*
функции? (например. mysql_query()
, mysql_connect()
или же mysql_real_escape_string()
)?
Почему я должен использовать что-то еще, даже если они работают на моем сайте?
Если они не работают на моем сайте, почему я получаю такие ошибки, как
Предупреждение: mysql_connect (): нет такого файла или каталога
Расширение MySQL:
Поскольку он устарел, его использование делает ваш код менее надежным в будущем.
Отсутствие поддержки подготовленных операторов особенно важно, поскольку они предоставляют более понятный и менее подверженный ошибкам метод экранирования и цитирования внешних данных, чем ручной экранирование с помощью отдельного вызова функции.
Увидеть сравнение расширений SQL.
PHP предлагает три разных API для подключения к MySQL. Эти mysql
(удалено с PHP 7), mysqli
, а также PDO
расширения.
mysql_*
Раньше функции были очень популярны, но их использование больше не поощряется. Команда разработчиков документации обсуждает ситуацию с безопасностью базы данных, и обучение пользователей отойти от широко используемого расширения ext / mysql является частью этого (проверьте php.internals: устарел ext / mysql).
И более поздняя команда разработчиков PHP приняла решение генерировать E_DEPRECATED
ошибки при подключении пользователей к MySQL через mysql_connect()
, mysql_pconnect()
или неявная функциональность подключения, встроенная в ext/mysql
,
ext/mysql
было официально устарел с PHP 5.5 и был удалено с PHP 7.
Видишь красную коробку?
Когда вы идете на любой mysql_*
На странице руководства функции вы видите красную рамку, объясняющую, что ее больше не следует использовать.
Отойдя от ext/mysql
речь идет не только о безопасности, но и о доступе ко всем функциям базы данных MySQL.
ext/mysql
был построен для MySQL 3.23 и только с тех пор получил очень мало дополнений, сохраняя совместимость с этой старой версией, что усложняет поддержку кода. Отсутствуют функции, которые не поддерживаются ext/mysql
включают: (из руководства по PHP).
Причина не использовать mysql_*
функция:
Выше цитата из ответа Квентина
Отсутствие поддержки подготовленных операторов особенно важно, поскольку они обеспечивают более четкий и менее подверженный ошибкам метод экранирования и цитирования внешних данных, чем ручной экранирование с помощью отдельного вызова функции.
Увидеть сравнение расширений SQL.
Подавление предупреждений об устаревании
Пока код конвертируется в MySQLi
/PDO
, E_DEPRECATED
ошибки могут быть подавлены настройкой error_reporting
в php.ini исключить E_DEPRECATED:
error_reporting = E_ALL ^ E_DEPRECATED
Обратите внимание, что это также будет скрывать другие предупреждения об устаревании, что, однако, может быть для вещей, отличных от MySQL. (из руководства по PHP)
Статья PDO против MySQLi: что использовать? от Деян Марьянович поможет вам выбрать.
И лучший способ PDO
и сейчас я пишу простую PDO
руководство.
А. «PDO — объекты данных PHP — это уровень доступа к базе данных, обеспечивающий единый метод доступа к нескольким базам данных ».
С 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
заявления? Не волнуйтесь, здесь мы идем:
Так что вы делаете в 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();
Чем мы занимаемся 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 очка):
Подготовить: Шаблон выписки создается приложением и отправляется в систему управления базами данных (СУБД). Некоторые значения не указываются, называются параметрами, заполнителями или переменными связывания (помечены ?
ниже):
INSERT INTO PRODUCT (name, price) VALUES (?, ?)
СУБД анализирует, компилирует и выполняет оптимизацию запросов по шаблону оператора и сохраняет результат без его выполнения.
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
подготовленные запросы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);
INSERT
:
$stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
$stmt->execute(array(':field1' => $field1, ':field2' => $field2));
$affected_rows = $stmt->rowCount();
DELETE
:
$stmt = $db->prepare("DELETE FROM table WHERE id=:id");
$stmt->bindValue(':id', $id, PDO::PARAM_STR);
$stmt->execute();
$affected_rows = $stmt->rowCount();
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!
Вместо этого вы должны узнать о готовых утверждениях
mysql_*
расширение не поддерживает готовые заявления, что является (среди прочего) очень эффективной контрмерой против SQL-инъекция. Он исправил очень серьезную уязвимость в MySQL-зависимых приложениях, которая позволяет злоумышленникам получить доступ к вашему сценарию и выполнить любой возможный запрос в вашей базе данных.
Для получения дополнительной информации см. Как я могу предотвратить внедрение SQL в PHP?
Видишь красную коробку?
Когда вы идете в любой mysql
На странице руководства функции вы видите красную рамку, объясняющую, что ее больше не следует использовать.
Используйте либо PDO, либо MySQLi
Есть лучшие, более надежные и хорошо продуманные альтернативы, PDO — объект базы данных PHP, который предлагает полный ООП подход к взаимодействию с базой данных, и MySQLi, что является специфическим улучшением MySQL.
Аналитические и синтетические причины уже упоминались. Для новичков есть более существенный стимул прекратить использование устаревших функций mysql_.
Современные API баз данных просто Полегче использовать.
Это в основном связанные параметры который может упростить код. И с отличные учебники (как видно выше) переход к PDO не слишком сложно.
Перезапись большей кодовой базы за один раз, однако, требует времени. Raison d’être для этой промежуточной альтернативы:
С помощью <pdo_mysql.php> Вы можете переключиться со старых функций mysql_ с помощью минимальное усилие. Добавляет pdo_
функциональные обертки, которые заменяют их mysql_
двойники.
Просто include_once(
"pdo_mysql.php"
);
в каждом скрипте вызова, который должен взаимодействовать с базой данных.
Удалить префикс функции везде и заменить его на mysql_
pdo_
.
mysql_
connect()
становится pdo_
connect()
mysql_
query()
становится pdo_
query()
mysql_
num_rows()
становится pdo_
num_rows()
mysql_
insert_id()
становится pdo_
insert_id()
mysql_
fetch_array()
становится pdo_
fetch_array()
mysql_
fetch_assoc()
становится pdo_
fetch_assoc()
mysql_
real_escape_string()
становится pdo_
real_escape_string()
Ваш код будет работать одинаково и в основном будет выглядеть так же:
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_ * все еще позволяет либо.
Просто не экранируйте переменную а также привязать его в том же запросе.
:named
списки заполнителей позже.Что еще более важно вы можете безопасно передавать переменные $ _REQUEST [] за любым запросом. Когда подано <form>
поля соответствуют структуре базы данных, она еще короче:
pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);
Так много простоты. Но давайте вернемся к еще нескольким советам по переписыванию и техническим причинам, по которым вы можете избавиться от и сбежать.mysql_
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
. Который однако лучше всего зафиксировано централизованно, не строка за строкой.
Используйте один из изменение пользовательского пространства подходы. Затем удалите stripslashes()
в sanitize
функция.
Историческая справка о 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_*
Функции-обертки создают удобный для программирования 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, вам не нужно сейчас присматривать за сырым интерфейсом базы данных.
mysql_
функции:
Говоря о технический Причин здесь всего несколько, крайне специфичных и редко используемых. Скорее всего, вы никогда не будете использовать их в своей жизни.
Может быть, я слишком невежественен, но у меня никогда не было возможности использовать такие вещи, как
Если они вам нужны — это, без сомнения, технические причины для перехода от расширения mysql к чему-то более стильному и современному.
Тем не менее, есть также некоторые нетехнические проблемы, которые могут сделать ваш опыт немного сложнее
Эта последняя проблема является проблемой.
Но, на мой взгляд, предлагаемое решение тоже не лучше.
По-моему слишком идеалистично мечта, чтобы все эти пользователи PHP научились правильно обрабатывать запросы SQL. Скорее всего, они просто изменили бы mysql_ * на mysqli_ * механически, оставив подход тот же. Тем более, что mysqli делает использование готовых заявлений невероятно болезненным и хлопотным.
Не говоря уже о том, что родные готовые заявления недостаточно для защиты от SQL-инъекций, и ни mysqli, ни PDO не предлагают решения.
Таким образом, вместо того, чтобы бороться с этим честным продолжением, я предпочел бы бороться с неправильными методами и обучать людей правильными способами.
Кроме того, есть несколько ложных или несущественных причин, таких как
mysql_query("CALL my_proc");
на века)Последний интересный момент. Хотя 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?
Ну, ответ будет следующим:
Если, как и подавляющее большинство PHP-пользователей, вы используете необработанные вызовы API прямо в коде приложения (что по сути неверно) — PDO — единственный выбор, так как это расширение претендует на то, чтобы быть не просто API, а скорее полу-DAL, все еще неполным, но предлагает много важных функций, две из которых делают PDO критически отличным от mysqli:
Итак, если вы обычный пользователь PHP и хотите сэкономить массу головной боли при использовании встроенных подготовленных операторов, PDO — опять же — единственный выбор.
Тем не менее, PDO тоже не серебряная пуля и имеет свои трудности.
Итак, я написал решения для всех распространенных ошибок и сложных случаев в PDO tag вики
Тем не менее, все, кто говорит о расширениях, всегда пропускают 2 важных факта о Mysqli и PDO:
Подготовленное заявление не серебряная пуля. Существуют динамические идентификаторы, которые не могут быть связаны с использованием подготовленных операторов. Существуют динамические запросы с неизвестным количеством параметров, что затрудняет построение запросов.
Ни 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, чтобы справиться с таким практическим случаем.
И это будет слишком многословно и, скорее всего, небезопасно.
Итак, еще раз — это должен быть не просто необработанный драйвер, а класс абстракции, полезный не только для глупых примеров из руководства для начинающих, но и для решения любых реальных проблем.
Причин много, но, возможно, самая важная из них заключается в том, что эти функции поощряют небезопасные методы программирования, поскольку они не поддерживают подготовленные операторы. Подготовленные операторы помогают предотвратить атаки с использованием SQL-инъекций.
Когда используешь mysql_*
функции, вы должны помнить, чтобы запустить пользовательские параметры через mysql_real_escape_string()
, Если вы забыли только в одном месте или вам удалось избежать только части ввода, ваша база данных может подвергнуться атаке.
Используя подготовленные заявления в PDO
или же mysqli
сделаю так, чтобы эти виды программных ошибок были более сложными.
Потому что (среди прочих причин) гораздо сложнее обеспечить очистку входных данных. Если вы используете параметризованные запросы, как в случае с PDO или mysqli, вы можете полностью избежать риска.
Как пример, кто-то может использовать "enhzflep); drop table users"
как имя пользователя. Старые функции позволят выполнять несколько операторов за запрос, поэтому что-то вроде этого мерзкого баггера может удалить всю таблицу.
Если бы кто-то использовал PDO mysqli, имя пользователя в конечном итоге было бы "enhzflep); drop table users"
,
Увидеть bobby-tables.com.