Intereting Posts
PHP Check MySQL Последняя строка strtotime () считается вредным? PHP + MySQL Queue Исправления проблем с использованием PHPUnit и Zend Framework Как вы убедитесь, что две строки, выбранные случайным образом, отличаются друг от друга? Регулярное выражение для поиска и замены @ упоминает как твиттер Настройка простого тестирования A / B с помощью PHP Добавление url () прерывает реализацию hook_mail PHP 5.4 PDO не удалось подключиться к MySQL 4.1+, используя старую небезопасную аутентификацию Переопределить URL внешнего продукта на кнопку «Добавить в корзину» Как загрузить загруженные файлы после отправки формы через uploadify? PHP Удалить ключ из ассоциативного массива Разрешения для файлов; Должен ли мой контент в www-папке принадлежать www-data? Игнорировать первую переменную в ссылке с использованием постоянных ссылок HTACCESS Как получить текущее местоположение пользователя с помощью Google Geocode API и PHP

Подготовленные операторы MySQL с переменным переменным

Как бы вы написали подготовленный оператор MySQL в PHP, который каждый раз принимает различное количество аргументов? Пример такого запроса:

SELECT `age`, `name` FROM `people` WHERE id IN (12, 45, 65, 33) 

Параметр IN будет иметь различное количество id каждый раз при его запуске.

У меня есть два возможных решения, но я хочу посмотреть, есть ли лучший способ.

Возможное решение 1 Сделайте оператор, принимающий 100 переменных, и заполните остальные фиктивные значения, которые гарантированно не будут в таблице; сделать несколько вызовов более чем 100 значений.

Возможное решение 2 Не используйте подготовленное заявление; строит и запускает проверку запросов для возможных инъекционных атак.

Я могу придумать пару решений.

Одним из решений может быть создание временной таблицы. Сделайте вставку в таблицу для каждого параметра, который у вас был бы в разделе in. Затем сделайте простое соединение с вашей временной таблицей.

Другой способ – сделать что-то подобное.

 $dbh=new PDO($dbConnect, $dbUser, $dbPass); $parms=array(12, 45, 65, 33); $parmcount=count($parms); // = 4 $inclause=implode(',',array_fill(0,$parmcount,'?')); // = ?,?,?,? $sql='SELECT age, name FROM people WHERE id IN (%s)'; $preparesql=sprintf($sql,$inclause); // = example statement used in the question $st=$dbh->prepare($preparesql); $st->execute($parms); 

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


Чтобы сделать @orrd счастливым здесь, это краткая версия.

 $dbh=new PDO($dbConnect, $dbUser, $dbPass); $parms=array(12, 45, 65, 33); $st=$dbh->prepare(sprintf('SELECT age, name FROM people WHERE id IN (%s)', implode(',',array_fill(0,count($parms),'?')))); $st->execute($parms); 

Существует также функция FIND_IN_SET , второй параметр которой представляет собой строку значений, разделенных запятыми:

 SELECT age, name FROM people WHERE FIND_IN_SET(id, '12,45,65,33') 

Положительные sql-обертки поддерживают привязку к значениям массива. т.е.

 $sql = "... WHERE id IN (?)"; $values = array(1, 2, 3, 4); $result = $dbw -> prepare ($sql, $values) -> execute (); 

Я получил свой ответ от: http://bugs.php.net/bug.php?id=43568
это мое рабочее решение для моей проблемы. Теперь я могу динамически использовать столько параметров, сколько хочу. Они будут того же числа, что и у меня в массиве, или как в этом случае я передаю идентификаторы из последнего запроса (который нашел все идентификаторы, где email = 'johndoe@gmail.com'), в динамический запрос, чтобы получить все информацию о каждом из этих идентификаторов, сколько бы я ни нуждался.

 <?php $NumofIds = 2; //this is the number of ids i got from the last query $parameters=implode(',',array_fill(0,$NumofIds,'?')); // = ?,? the same number of ?'s as ids we are looking for<br /> $paramtype=implode('',array_fill(0,$NumofIds,'i')); // = ii<br/> //make the array to build the bind_param function<br/> $idAr[] = $paramtype; //'ii' or how ever many ?'s we have<br/> while($statement->fetch()){ //this is my last query i am getting the id out of<br/> $idAr[] = $id; } //now this array looks like this array:<br/> //$idAr = array('ii', 128, 237); $query = "SELECT id,studentid,book_title,date FROM contracts WHERE studentid IN ($parameters)"; $statement = $db->prepare($query); //build the bind_param function call_user_func_array (array($statement, "bind_param"), $idAr); //here is what we used to do before making it dynamic //statement->bind_param($paramtype,$v1,$v2); $statement->execute(); ?> 

Пожалуйста, возьмите № 2 со стола. Подготовленные утверждения – это единственный способ защитить себя от SQL-инъекции.

Однако вы можете создать динамический набор переменных привязки. т.е. не составлять 100, если вам нужно 7 (или 103).

Если вы используете только целые значения в своем предложении IN , нет ничего, что бы противоречило динамическому построению вашего запроса без использования параметров SQL.

 function convertToInt(&$value, $key) { $value = intval($value); } $ids = array('12', '45', '65', '33'); array_walk($ids, 'convertToInt'); $sql = 'SELECT age, name FROM people WHERE id IN (' . implode(', ', $ids) . ')'; // $sql will contain SELECT age, name FROM people WHERE id IN (12, 45, 65, 33) 

Но, несомненно, решение здесь – более общий подход к этой проблеме.

Сегодня у меня была подобная проблема, и я нашел эту тему. Глядя на ответы и поиск по Google, я нашел довольно подходящее решение.

Хотя, моя проблема немного сложнее. Потому что у меня есть фиксированные значения привязки и динамические тоже .

Это решение.

 $params = array() $all_ids = $this->get_all_ids(); for($i = 0; $i <= sizeof($all_ids) - 1; $i++){ array_push($params, $all_ids[$i]['id']); } $clause = implode(',', array_fill(0, count($params), '?')); // output ?, ?, ? $total_i = implode('', array_fill(0, count($params), 'i')); // output iiii $types = "ss" . $total_i; // will reproduce : ssiiii ..etc // %% it's necessary because of sprintf function $query = $db->prepare(sprintf("SELECT * FROM clients WHERE name LIKE CONCAT('%%', ?, '%%') AND IFNULL(description, '') LIKE CONCAT('%%', ?, '%%') AND id IN (%s)", $clause)); $thearray = array($name, $description); $merge = array_merge($thearray, $params); // output: "John", "Cool guy!", 1, 2, 3, 4 // We need to pass variables instead of values by reference // So we need a function to that call_user_func_array('mysqli_stmt_bind_param', array_merge (array($query, $types), $this->makeValuesReferenced($merge))); 

И функция makeValuesreferenced :

 public function makeValuesReferenced($arr){ $refs = array(); foreach($arr as $key => $value) $refs[$key] = &$arr[$key]; return $refs; } 

Ссылки для получения этого «ноу-хау»: https://bugs.php.net/bug.php?id=49946 , PHP добавляет один массив в другой (а не array_push или +) , [PHP]: ошибка -> слишком мало аргументы в sprintf (); , http://no2.php.net/manual/en/mysqli-stmt.bind-param.php#89171 , передать справочную проблему с PHP 5.3.1