Есть ли способ, которым я могу поместить эти операторы bindParam в один оператор?
$q = $dbc -> prepare("INSERT INTO accounts (username, email, password) VALUES (:username, :email, :password)"); $q -> bindParam(':username', $_POST['username']); $q -> bindParam(':email', $_POST['email']); $q -> bindParam(':password', $_POST['password']); $q -> execute();
Я использовал mysqli, подготовленный до того, где это было возможно, я переключился на PDO для поддержки assoc_array. На веб-сайте php.net для PDO он показывает их по отдельным строкам, и во всех примерах я видел, что он находится на отдельных строках.
Является ли это возможным?
Пример 2 на странице execute
– это то, что вы хотите:
$sth->execute(array(':calories' => $calories, ':colour' => $colour));
Вы можете посмотреть и на другие примеры. С параметрами вопросительных знаков это будет:
$q = $dbc -> prepare("INSERT INTO accounts (username, email, password) VALUES (?, ?, ?)"); $q->execute(array($_POST['username'], $_POST['email'], $_POST['password']));
Если это единственные столбцы, вы можете просто написать:
$q = $dbc -> prepare("INSERT INTO accounts VALUES (?, ?, ?)"); $q->execute(array($_POST['username'], $_POST['email'], $_POST['password']));
Вспомогательная функция – это функция, которая помогает избежать написания множества повторяющихся кодов каждый раз, когда вы хотите запустить запрос.
Это называется «программированием», и на этом сайте почти нет его, по крайней мере, под тегом «PHP».
Хотя многие люди полагают, что программирование означает копирование / склеивание фрагментов кода из ручных примеров, это несколько другое. Хотя это трудно понять, но действительно стоит того, особенно если вы посвящаете себя веб-разработке.
Как вы можете видеть, никакой принятый ответ не оказал вам реальной помощи, так как вам все равно нужно написать что-то вроде
$sth->execute(array(':username' => $_POST['username'], ':email' => $_POST['email'] ':password' => $_POST['password']);
столько раз, сколько полей в вашей таблице, что не сильно отличается от вашего первоначального подхода, все равно заставляет вас писать каждое имя поля в четыре раза.
Но, будучи программистом, вы можете использовать возможности программирования. Например, петля – один из операторов программирования краеугольного камня.
Каждый раз, когда вы видите повторения, вы знаете, что должен быть цикл.
например, вы можете настроить список полей, называя их только один раз. И пусть программа сделает все остальное.
Скажем, такая функция, как эта
function pdoSet($fields, &$values, $source = array()) { $set = ''; $values = array(); if (!$source) $source = &$_POST; foreach ($fields as $field) { if (isset($source[$field])) { $set.="`$field`=:$field, "; $values[$field] = $source[$field]; } } return substr($set, 0, -2); }
получая массив имен полей, он может создавать для вас как инструкцию insert, так и массив данных. Программный. Таким образом, ваш код станет не более чем этими тремя короткими строками:
$fields = array('username', 'email', 'password'); $stmt = $dbh->prepare("INSERT INTO accounts SET ".pdoSet($fields,$values)); $stmt->execute($values);
Ваше общее чувство совершенно верно, что целью кодирования является сохранение ввода текста … но его решение не помогает бит BindParams. Я не мог найти ничего об этом в Интернете, так что вот что-то, что я, наконец, просто убедил работать – надеюсь, что это кому-то полезно!
//First, a function to add the colon for each field value. function PrepareString($array){ //takes array (title,author); //and returns the middle bit of pdo update query :title,:author etc foreach($array as $k =>$v){ $array[$k]=':'.$v; } return implode(', ', $array); }
Затем…
function PdoInsert($table_name,$array){ $db = new PDO(); //however you create your own pdo //get $fields and $vals for statement $fields_vals=array_keys($array); $fields=implode(',',$fields_vals); $vals=PrepareString($fields_vals); $sql = "INSERT INTO $table_name($fields) VALUES ($vals)"; $qwe=$db->prepare($sql); foreach ($array as $k =>$v ){ //add the colon to the key $y=':'.$k; //god knows why it doesn't like $qwe->bindParam($y,$v,PDO::PARAM_STR); // but it really doesn't! So we refer back to $array. //add checks for different binding types here
(см. PDO :: PARAM_INT важно в bindParam? )
$qwe->bindParam($y,$array[$k],PDO::PARAM_STR); } if ($qwe->execute()==true){ return $db->lastInsertId(); } else { return $db->errorCode(); } }
Затем вы можете вставлять что угодно, делая
PdoInsert('MyTableName',array('field1'=>$value1,'field2'=>$value2...));
Раньше санировали ваши ценности, конечно.
+1 Мэтью Флашен за принятый ответ, но я покажу вам еще один совет. Если вы используете параметры SQL с именами так же, как и записи в $ _POST, вы можете воспользоваться тем фактом, что $ _POST уже является массивом:
$q->execute($_POST);
Имена параметров SQL имеют префикс двоеточия (:), но ключи в массиве $ _POST не являются. Но современные версии PDO учитывают это – вам больше не нужно использовать префиксы двоеточия в ключах в массиве, который вы передаете для выполнения ().
Но вы должны быть осторожны, чтобы каждый мог добавить дополнительные параметры в любой веб-запрос, и вы должны получить только подмножество параметров $ _POST, которые соответствуют параметрам в вашем запросе.
$q = $dbc -> prepare("INSERT INTO accounts (username, email, password) VALUES (:username, :email, :password)"); $params = array_intersect_key($_POST, array("username"=>1,"email"=>1,"password"=>1)); $q->execute($params);
Лично я предпочитаю использовать функцию обертки для всех pdo, что значительно упрощает необходимый код.
Например, чтобы запускать связанные запросы (ну, все мои запросы), я делаю это:
$iterable_resultset = query("INSERT INTO accounts (username, email, password) VALUES (:username, :email, :password)", array(':username'=>'bob', ':email'=>'bob@example.com', ':password'=>'bobpassword'));
Обратите внимание, что не только sql просто строка, но это фактически многократно используемая строка, так как вы можете просто передать sql в виде строки и изменить массив переменных, которые нужно передать, если вы хотите выполнить аналогичную вставку сразу после этого ( не применимо к этой ситуации, но применимо к другим случаям использования sql).
Код, который я использую для создания этой функции-обертки, приведен ниже:
/** * Run bound queries on the database. * * Use: query('select all from players limit :count', array('count'=>10)); * Or: query('select all from players limit :count', array('count'=>array(10, PDO::PARAM_INT))); * * Note that it returns foreachable resultset object unless an array is specifically requested. **/ function query($sql, $bindings=array(), $return_resultset=true) { DatabaseConnection::getInstance(); // Gets a singleton database connection $statement = DatabaseConnection::$pdo->prepare($sql); // Get your pdo instance, in this case I use a static singleton instance. You may want to do something simpler. foreach ($bindings as $binding => $value) { if (is_array($value)) { $first = reset($value); $last = end($value); // Cast the bindings when something to cast to was sent in. $statement->bindParam($binding, $first, $last); } else { $statement->bindValue($binding, $value); } } $statement->execute(); if ($return_resultset) { return $statement; // Returns a foreachable resultset } else { // Otherwise returns all the data an associative array. return $statement->fetchAll(PDO::FETCH_ASSOC); } } // Wrapper to explicitly & simply get a multi-dimensional array. function query_array($sql_query, $bindings=array()) { return query($sql_query, $bindings, false); // Set return_resultset to false to return the array. }
Как отмечено в комментариях, вы хотите использовать свой собственный метод для настройки соединения с базой данных и получения инициализированного pdo, но в целом он позволяет сократить ваш SQL-код до одной строки.