В PHP я хочу вставить в базу данных данные, содержащиеся в ассоциативном массиве пар полей/значений.
Пример:
$_fields = array('field1'=>'value1','field2'=>'value2','field3'=>'value3');
Результирующая вставка SQL должна выглядеть следующим образом:
INSERT INTO table (field1,field2,field3) VALUES ('value1','value2','value3');
Я придумал следующий однострочный PHP:
mysql_query("INSERT INTO table (".implode(',',array_keys($_fields)).") VALUES (".implode(',',array_values($_fields)).")");
Он разделяет ключи и значения ассоциативного массива и implodes
для генерации строки, разделенной запятыми. Проблема в том, что он не убегает или не цитирует значения, которые были вставлены в базу данных. Чтобы проиллюстрировать опасность, представьте, если $_fields
содержит следующее:
$_fields = array('field1'=>"naustyvalue); drop table members; --");
Будет создан следующий SQL:
INSERT INTO table (field1) VALUES (naustyvalue); drop table members; --;
К счастью, несколько запросов не поддерживаются, тем не менее, цитаты и экранирование необходимы для предотвращения уязвимостей SQL-инъекций.
Как вы пишете свои вставки Mysql PHP?
Примечание: подготовленные запросы PDO или mysqli в настоящее время не являются для меня опцией, потому что база кода уже использует mysql - изменения планируются, но для преобразования требуется много ресурсов?
Ответ 1
Единственное, что я бы изменил, было бы использовать sprintf для целей удобочитаемости
$sql = sprintf(
'INSERT INTO table (%s) VALUES ("%s")',
implode(',',array_keys($_fields)),
implode('","',array_values($_fields))
);
mysql_query($sql);
и убедитесь, что значения экранированы.
Ответ 2
В этом нет ничего плохого. Я делаю то же самое.
Но убедитесь, что вы mysql_escape()
и укажите значения, которые вы вставляете в запрос, в противном случае вы смотрите на уязвимость SQL-инъекции.
В качестве альтернативы вы можете использовать параметризованные запросы, и в этом случае вы можете практически передать массив сам по себе, а не строить строку запроса.
Ответ 3
Лучшей практикой является использование ORM (Doctrine 2.0), реализация ActiveRecord (Doctrine 1.0, RedBean) или реализация шаблона TableGateway (Zend_Db_Table, Propel). Эти инструменты сделают вашу жизнь намного проще и справятся с большой тягой для вас и помогут защитить вас от инъекций SQL.
Кроме того, нет ничего неправильного в том, что вы делаете, вы просто можете отвлечь его на класс или функцию, чтобы вы могли повторять функциональность в разных местах.
Ответ 4
Используя трюк sprintf, упомянутый Галеном в предыдущем ответе, я придумал следующий код:
$escapedfieldValues = array_map(create_function('$e', 'return mysql_real_escape_string(((get_magic_quotes_gpc()) ? stripslashes($e) : $e));'), array_values($_fields));
$sql = sprintf('INSERT INTO table (%s) VALUES ("%s")', implode(',',array_keys($_fields)), implode('"," ',$escapedfieldValues));
mysql_query($sql);
Он генерирует скрытую и цитированную вставку. Он также управляется независимо от того, включен или нет magic_quotes_gpc
. Код может быть приятнее, если я использовал новый PHP v5.3.0 анонимные функции, но мне нужно, чтобы он запускался на старых установках PHP.
Этот код немного дольше, чем оригинал (и медленнее), но он более безопасен.
Ответ 5
Я использую это, чтобы получить часть VALUES INSERT.
Но это может быть абсурдным способом. Комментарии/предложения приветствуются.
function arrayToSqlValues($array)
{
$sql = "";
foreach($array as $val)
{
//adding value
if($val === NULL)
$sql .= "NULL";
else
/*
useless piece of code see comments
if($val === FALSE)
$sql .= "FALSE";
else
*/
$sql .= "'" . addslashes($val) . "'";
$sql .= ", ";
};
return "VALUES(" . rtrim($sql, " ,") . ")";
}
Ответ 6
Существует проблема с значениями NULL (в принятом ответе), которые преобразуются в пустую строку "". Итак, это исправление, NULL становится NULL без кавычек:
function implode_sql_values($vals)
{
$s = '';
foreach ($vals as $v)
$s .= ','.(($v===NULL)?'NULL':'"'.mysql_real_escape_string($v).'"');
return substr($s, 1);
}
Использование:
implode_sql_values(array_values( array('id'=>1, 'nick'=>'bla', 'fbid'=>NULL) ));
// =='"1","bla",NULL'
Ответ 7
Если вы хотите улучшить свой подход и добавить возможность проверки ввода и санитарии, вы можете сделать это:
function insertarray($table, $arr){
foreach($arr as $k => $v){
$col[] = sanitize($k);
$val[] = "'".sanitize($v)."'";
}
query('INSERT INTO '.sanitize($table).' ('.implode(', ', $col).') VALUES ('.implode(', ', $val).')' );
}