Почему PDO лучше для экранирования запросов MySQL / querystrings, чем mysql real escape string?

мне сказали, что мне лучше использовать PDO для MySQL escaping, а не mysql_real_escape_string.

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

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

может ли кто-нибудь объяснить мне на "простом английском", что такое PDO (или указать мне в направлении чего-то на тему, написанную на простом английском языке), и как вы пойдете использовать его?

6 ответов


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

классы PDO направлены на инкапсуляцию всех функций, необходимых для взаимодействия с базой данных. Они делают это, определяя "методы" (OO parlor для функций) и "свойства" (OO parlor для переменных). Вы бы использовали их как полная замена для всех "стандартных" функций, которые вы используете сейчас для общения с базой данных.

так вместо вызова серии функций " mysql_doSomething ()", сохраняя их результаты в ваших собственных переменных, вы бы "инстанцировали" объект из класса PDO ("class" = абстрактное определение, "object" = конкретный, полезный экземпляр класса) и вызывали методы на этом объекте, чтобы сделать то же самое.

в качестве примера, без PDO, вы бы сделали что-то вроде этого:

// Get a db connection
$connection = mysql_connect('someHost/someDB', 'userName', 'password');
// Prepare a query
$query = "SELECT * FROM someTable WHERE something = " . mysql_real_escape_string($comparison) . "'";
// Issue a query
$db_result = mysql_query($query);
// Fetch the results
$results = array();
while ($row = mysql_fetch_array($db_result)) {
  $results[] = $row;
}

в то время как это было бы эквивалентно использованию PDO:

// Instantiate new PDO object (will create connection on the fly)
$db = new PDO('mysql:dbname=someDB;host=someHost');
// Prepare a query (will escape on the fly)
$statement = $db->prepare('SELECT * FROM someTable WHERE something = :comparison');
// $statement is now a PDOStatement object, with its own methods to use it, e.g.
// execute the query, passing in the parameters to replace
$statement->execute(array(':comparison' => $comparison));
// fetch results as array
$results = $statement->fetchAll();

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

Если вам нужно поговорить с базой данных PostgreSQL, вы только измените mysql:to pgsql: в инстанцирование вызов new PDO(). С помощью старого метода вам придется пройти весь свой код, заменив все функции "mysql_doSomething ()" на их аналог "pg_doSomthing ()" (всегда проверяя потенциальные различия в обработке параметров). Тот же это относится ко многим другим поддерживаемым ядрам баз данных.

Итак, чтобы вернуться к вашему вопросу, PDO в основном просто дает вам другой способ достичь того же самого, предлагая некоторые ярлыки/улучшения/преимущества. Например, экранирование произойдет автоматически надлежащим образом, необходимым для используемого компонента database engine. Также замена параметров (предотвращает SQL-инъекции, не показанные в Примере) намного проще, что делает ее менее подверженной ошибкам.

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


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

запрос имеет несколько частей

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

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

'SELECT * FROM transactions WHERE username=$username'

когда он получает эту строку, он должен разобрать его и решить "это SELECT С WHERE".

смешивание деталей вверх!--19-->

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

'SELECT * FROM transactions WHERE username=billysmith OR 1=1'

...который вернется все транзакции для всех пользователей, потому что 1 всегда равен 1. Упс, тебя взломали!

посмотреть, что случилось? база данных не знала, какие части ожидать в вашем запросе, поэтому он просто разобрал строки. Не удивительно, что WHERE у OR, С двумя условиями, которые могли бы удовлетворить его.

держать части прямо

если бы он только знал чего ожидать, а именно, a SELECT чей WHERE было только одно условие, злонамеренный пользователь не мог обмануть его.

С подготовленным заявлением вы можете дать ему правильное ожидание. Вы можете сказать базе данных "я собираюсь отправить вам SELECT, и он будет ограничен строками WHERE username = a веревка, которую я собираюсь тебе дать. Это все - в запросе нет других частей. Вы готовы? Хорошо, вот строка Для сравнения с именем пользователя."

С этим ожиданием база данных не будет обманута: она будет возвращать только строки, где username столбец содержит фактическую строку ' billysmith или 1=1.- Если ни у кого нет такого имени, он ничего не вернет.

другие преимущества подготовленных заявлений

В дополнение к повышенной безопасности , подготовленные заявления имеют пару преимуществ скорости:

  • они могут быть повторно использованы с различными параметрами, что должно быть быстрее, чем создание нового запроса с нуля, потому что база данных уже знает в основном, что вы собираетесь попросить. Он уже построил свой "план запроса".
  • некоторые базы данных (Postgres-одна, я думаю) начнут составлять план запроса, как только они получат подготовленный оператор-прежде чем вы фактически отправите параметры для использования с он. Таким образом, вы можете увидеть ускорение даже при первом запросе.

для другого объяснения см. ответ Тео здесь.


В отличие от mysql_real_escape_string, PDO позволяет применять тип данных.

<?php
/* Execute a prepared statement by binding PHP variables */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories, PDO::PARAM_INT);
$sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);
$sth->execute();
?>

обратите внимание, что в приведенном выше примере первый параметр, calories, должен быть целым числом (PDO::PARAM_INT).

во-вторых, для меня параметризованные запросы PDO легче читать. Я бы лучше прочитал:

SELECT name FROM user WHERE id = ? AND admin = ? 

чем

SELECT name FROM user WHERE id = mysql_real_escape_string($id) AND admin = mysql_real_escape_string($admin);

в-третьих, вам не обязательно правильно указывать параметры. PDO позаботится об этом. Например, mysql_real_query_string:

SELECT * FROM user WHERE name = 'mysql_real_escape_string($name)' //note quotes around param

vs

SELECT * FROM user WHERE name = ?

наконец, PDO позволяет переносить приложение в другую БД без изменения вызовов данных PHP.


представьте, что вы пишете что-то вроде:

$query = 'SELECT * FROM table WHERE id = ' . mysql_real_escape_string($id);

это не спасет вас от инъекций, потому что $id может быть 1 OR 1=1 и вы получите все записи из таблицы. вам нужно будет привести $id к правильному типу данных (int в этом случае)

pdo имеет еще одно преимущество, и это взаимозаменяемость бэкэндов базы данных.


в дополнение к предотвращению SQL-инъекции PDO позволяет подготовить запрос один раз и выполнить его несколько раз. Если ваш запрос выполняется несколько раз (например, в цикле), этот метод должен быть более эффективным (я говорю "должен быть", потому что похоже, что это не всегда так в старых версиях MySQL). Метод prepare/bind также больше соответствует другим языкам, с которыми я работал.


почему PDO лучше для избежания запросов MySQL / querystrings, чем mysql_real_escape_string?

просто потому, что "побег в одиночку" не имеет смысла.
Более того, это разные несравнимые вопросы.

единственная проблема с побегом-это все это неправильно, предполагая, что это своего рода "защита".
Все говорят: "Я избежал своих переменных "со значением"я защитил свой запрос".
В то время как побег в одиночку не имеет ничего общего с защитой вообще.

защита может быть грубо достигнута в случае я сбежал и процитировал свои данные, но это не применимо везде, например, для идентификаторов (а также PDO, кстати).

Итак, ответ:

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