Почему PDO лучше избегать запросов и запросов MySQL, чем 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 (или указать мне в сторону чего-то на предмет, написанный на простом английском языке), и как вы его используете?

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

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

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

В качестве примера, без 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, eg // execute the query, passing in the parameters to replace $statement->execute(array(':comparison' => $comparison)); // fetch results as array $results = $statement->fetchAll(); 

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

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

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

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

Я не очень хорошо знаком с PDO, но существует различие между «подготовленными операторами» и экранированными строками. Escaping – это удаление запрещенных строк символов из запроса, но подготовленные операторы сообщают базе данных, какой запрос ожидать .

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

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

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

 'SELECT * FROM transactions WHERE username=$username' 

Когда он получает эту строку, она должна проанализировать ее и решить, что «это SELECT с WHERE ».

Перемещение деталей

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

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

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

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

Удержание деталей прямо

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

С подготовленным заявлением вы можете дать ему правильное ожидание. Вы можете сообщить базе данных «Я собираюсь отправить вам SELECT , и это будет ограничено строками WHERE username = строка, которую я собираюсь вам дать. Вот и все: в запросе нет других частей запроса Вы готовы? ОК, вот строка, которая сравнивается с именем пользователя. "

С учетом этого, база данных не будет обманута: она будет возвращать только строки, где столбец username содержит фактическую строку «billysmith OR 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(); ?> 

Обратите внимание, что в приведенном выше примере первый параметр, калории, должен быть целым числом (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 

против

 SELECT * FROM user WHERE name = ? 

Наконец, PDO позволяет вам переносить ваше приложение на другой db, не изменяя ваши вызовы данных 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, чем mysql_real_escape_string?

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

Единственная проблема с побегом в том, что все ошибаются, считая это своего рода «защитой».
Все говорят: «Я избежал моих переменных» со значением «Я защитил свой запрос».
Хотя побег в одиночку не имеет никакого отношения к защите вообще.

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

Итак, ответ:

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