Не используйте addslashes()
. Это неадекватный способ избежать значений, и в нем есть ошибки безопасности.
Двойные кавычки в стандартном SQL предназначены для идентификаторов с разделителями. Используйте одинарные кавычки для строковых литералов.
Режим MySQL по умолчанию позволяет использовать взаимозаменяемые одинарные и двойные кавычки, а также обратные кавычки для идентификаторов с разделителями. Но я рекомендую привыкнуть использовать только одинарные кавычки для строк, потому что это делает ваш код SQL более переносимым для других поставщиков РСУБД, а также более понятным для любого, кто читает ваш код.
Вы должны использовать параметры запроса, как подсказывает @Mike B. Это легко и гораздо безопаснее, чем интерполировать переменные в выражения SQL.
Вы можете использовать bindParam()
или предоставить $values
ассоциативный массив для функции execute()
. Делать оба излишне.
Обратите внимание, что массив, который вы передаете методу execute()
, не обязательно должен содержать символ :
, предшествующий имени заполнителя:
$stmt = $pdo->prepare("SELECT * FROM MyTable WHERE myfield = :myfield");
// both of the following would work:
$stmt->execute( array(":myfield" => $value ) );
$stmt->execute( array("myfield" => $value ) );
Также для поддержки параметров как в предложении SET
, так и в предложении WHERE
, я бы посоветовал вам различать поля при указании имен заполнителей параметров. Таким образом, если вы ссылаетесь на одно и то же поле в обоих пунктах (одно для поиска старого значения, а другое для установки нового значения), вы не будете конфликтовать.
Возможно ":set$field"
в предложении SET
и ":where$field"
в предложении WHERE
.
обновление: Я проверил следующий код. Во-первых, я использую простые массивы, а не CachingIterator, который вы использовали. Мне не нужно использовать метод hasNext()
, так как я использую join()
.
$settings = array("myfield" => "value");
$conditions = array("id" => 1);
$sql = "UPDATE $table SET \n";
Далее приведена демонстрация использования array_map()
и join()
вместо циклов. Я использую PHP 5.3.0, поэтому я могу использовать встроенные функции закрытия. Если вы используете более раннюю версию PHP, вам придется объявить функции раньше и использовать их в качестве обратных вызовов.
$sql .= join(",",
array_map(
function($field) { return "$field = :set$field"; },
array_keys($settings)
)
);
if ($conditions)
{
$sql .= " WHERE "
. join(" AND ",
array_map(
function($field) { return "$field = :where$field"; },
array_keys($conditions)
)
);
}
$stmt = $db->prepare($sql);
Я не мог заставить bindParam()
работать, он всегда добавляет значение «1» вместо фактических значений в моем массиве. Итак, вот код для подготовки ассоциативного массива и передачи его в execute()
:
$params = array();
foreach ($settings as $field=>$value) {
$params[":set$field"] = $value;
}
foreach ($conditions as $field=>$value) {
$params[":where$field"] = $value;
}
$stmt->execute($params);