PDO :: prepare () не экранирует специальные символы в SQL

У меня есть входные значения из элемента HTML textarea, который нельзя вставить в таблицу MySQL, потому что он содержит символ апострофа ('), например: 'Adam's garden'. Итак, я использовал функцию PDO :: prepare (), как рекомендовано в документации PHP, но я все еще не могу вставить эти данные в таблицу, но когда я удаляю апостроф, чтобы вместо этого получить 'Adams garden', значение вставляется успешно

Я думал, что функция PDO::prepare() должна заботиться о кавычках и экранировании специальных символов для операторов SQL. В документации PHP сказано использовать PDO::prepare() с привязанными параметрами, но я не привязываю свои переменные php к параметрам запроса. Являются ли связанные параметры абсолютно необходимыми или это просто указано, потому что это обычный способ использования функции PDO::prepare()?

Как еще я могу заключить в кавычки и экранировать специальные символы в моих входных переменных?

РЕДАКТИРОВАТЬ: Я использую конкатенацию строк для выполнения нескольких INSERT SQL. Апостроф находится в поле $evData['Description'] в примере кода ниже.

$evQuery ="INSERT INTO ep_events
        VALUES(NULL, '" .$evData['Title'] ."', '" .$evData['Venue'] ."', '" .$evData['Address'] ."', '" .$evData['Description'] ."')";


$tkQuery ="INSERT INTO ep_tickets VALUES";
foreach ($tkData as $ref =>$tkObj){
    for($i=0; $i<$tkObj['Quantity']; $i++){
        $tkQuery .='(NULL, LAST_INSERT_ID(), "' .$tkObj['Name'] .'", "' .$tkObj['Price'] .'"),';
    }
}

$tkQuery =rtrim($tkQuery, ',');

$query ='START TRANSACTION;' .$evQuery ."; " .$tkQuery .';' .'COMMIT;';
$stm =$db->prepare($query);     
$stm->execute();

Это сегмент документации PHP:

PDO :: quote () помещает кавычки вокруг входной строки (если требуется) и экранирует специальные ›символы внутри входной строки, используя стиль кавычек, соответствующий базовому› драйверу.

Если вы используете эту функцию для построения операторов SQL, настоятельно рекомендуется использовать PDO :: prepare () для подготовки операторов SQL со связанными параметрами вместо использования PDO :: quote () для интерполяции вводимых пользователем данных в оператор SQL. Подготовленные операторы со связанными параметрами не только более переносимы, удобны и невосприимчивы к SQL-инъекции, но и часто выполняются намного быстрее, чем интерполированные запросы, поскольку и серверная, и клиентская стороны могут кэшировать скомпилированную форму запроса. http://www.php.net/manual/en/pdo.quote.php


person okey_on    schedule 25.06.2013    source источник
comment
Вместо того, чтобы цитировать документацию, покажите нам свой код.   -  person hjpotter92    schedule 26.06.2013
comment
Почему нельзя вставить апострофы в базу данных ...?   -  person jeremy    schedule 26.06.2013
comment
возможный дубликат подготовленных операторов PDO   -  person Musa    schedule 26.06.2013


Ответы (2)


PDO::prepare создает только подготовленный оператор. Запрос должен быть правильно параметризован, и вы должны отправить аргументы в execute (или иным образом связать их), чтобы они были правильно экранированы. Например:

$ta = $_REQUEST['textarea'];
$stmt = $pdo->prepare("INSERT INTO t1 VALUES (?)");
$stmt->execute(array($ta));

Что вы, вероятно, делаете

$pdo->prepare("INSERT INTO t1 VALUES ('" . $_REQUEST['ta'] . "')")->execute();

В этом случае ввод не экранируется.

person Explosion Pills    schedule 25.06.2013
comment
Урок здесь в том, что не используйте конкатенацию строк. - person tadman; 26.06.2013
comment
Спасибо @ExplodionPills, ваша демонстрация - это почти то же самое, что и я, без желаемых побегов. @tadman: я использую конкатенацию строк, потому что делаю несколько INSERTS, то есть: VALUES(val1, val2),(val3, val4),... - person okey_on; 26.06.2013
comment
@ExplosionPills, я отредактировал OP и добавил соответствующий фрагмент кода. - person okey_on; 26.06.2013
comment
@okeyxyz вы все еще выполняете конкатенацию строк. Вам нужно буквально использовать ? - person Explosion Pills; 26.06.2013
comment
@ExplosionPills да, я знаю. Это был мой исходный код. Я рассмотрел вашу рекомендацию, и она отлично работает. Спасибо - person okey_on; 26.06.2013

Оператор SQL - это код. Когда вы строите SQL-запрос с конкатенацией (или чем-то еще), вы выполняете генерацию кода. И эта генерация кода имеет те же проблемы, когда вы генерируете php-код (eval ("echo '$variable';");) или HTML-код (<h1><?= $header?></h1>). В сгенерированном коде нет «данных», только сам код.

Есть несколько способов избежать нежелательного поведения.

  1. Упаковка / распаковка: используйте base64_encode / FROM_BASE64 для переменной данных для базы данных, используйте base64_encode / base64_decode для eval и htmlentities для html.

  2. Экранирование: $ PDO :: quote () для переменной данных для базы данных, некоторая функция для eval (например, return '\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $var) . '\'';)

  3. (плохо) Удаление 'опасной' конструкции: (например, `$ v = preg_replace ('/ UNION (?: \ s + ALL)? \ s + SELECT / i', '-', $ a);) для базы данных , strip_tags для HTML.

  4. Отделите данные от кода: подготовьте операторы для базы данных, сгенерируйте функцию и передайте ей данные для eval, используя объектную модель документа для построения HTML.

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

Самый простой способ вставить с подготовленным оператором -

$pdo->prepare('INSERT INTO `table` (`text`) VALUES(?);')->execute(array($text));

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

person sectus    schedule 26.06.2013