SELECT * FROM в MySQLi

Мой сайт довольно обширен, и я недавно сделал переход на PHP5 (назовите меня поздним цветком).

Все мои запросы MySQL были построены следующим образом:

"SELECT * FROM tablename WHERE field1 = 'value' && field2 = 'value2'"; 

Это сделало его очень простым, простым и дружелюбным.

Теперь я пытаюсь переключиться на mysqli по очевидным соображениям безопасности, и мне трудно понять, как реализовать те же запросы SELECT * FROM когда bind_param требует определенных аргументов.

Является ли это утверждение ушедшим в прошлое?

Если это так, как мне обрабатывать запрос с использованием тонны столбцов? Мне действительно нужно каждый раз набирать их?

 "SELECT * FROM tablename WHERE field1 = 'value' && field2 = 'value2'"; 

становится

 "SELECT * FROM tablename WHERE field1 = ? && field2 = ?"; 

который передается в $mysqli::prepare :

 $stmt = $mysqli->prepare( "SELECT * FROM tablename WHERE field1 = ? && field2 = ?"); $stmt->bind_param( "ss", $value, $value2); // "ss' is a format string, each "s" means string $stmt->execute(); $stmt->bind_result($col1, $col2); // then fetch and close the statement 

Комментарии ОП:

поэтому, если у меня есть 5 параметров, я могу потенциально иметь «sssis» или что-то (в зависимости от типов входов?)

Правильно, один спецификатор типа ? параметр в подготовленном операторе, все они позиционные (первый спецификатор применяется к первому ? который заменяется первым фактическим параметром (который является вторым параметром bind_param )).

mysqli позаботится об ускорении и цитировании (я думаю).

Это было уже месяц назад, но хорошо.

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

Проблема, с которой я пользовалась MySQLi SELECT * – это часть bind_result . Вот где это становится интересным. Я столкнулся с этим сообщением с Джеффри Пути: http://jeff-way.com/2009/05/27/tricky-prepared-statements/ (Эта ссылка больше не активна). Скрипт в основном проходит через результаты и возвращает их как массив – не нужно знать, сколько столбцов есть, и вы все равно можете использовать подготовленные операторы.

В этом случае это выглядит примерно так:

 $stmt = $mysqli->prepare( 'SELECT * FROM tablename WHERE field1 = ? AND field2 = ?'); $stmt->bind_param('ss', $value, $value2); $stmt->execute(); 

Затем используйте фрагмент с сайта:

 $meta = $stmt->result_metadata(); while ($field = $meta->fetch_field()) { $parameters[] = &$row[$field->name]; } call_user_func_array(array($stmt, 'bind_result'), $parameters); while ($stmt->fetch()) { foreach($row as $key => $val) { $x[$key] = $val; } $results[] = $x; } 

И $results теперь содержит всю информацию от SELECT * . До сих пор я нашел это идеальным решением.

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

http://www.php.net/pdo

Bindparam для PDO: http://se.php.net/manual/en/pdostatement.bindparam.php

 $sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = :value1 && field2 = :value2"); $sth->bindParam(':value1', 'foo'); $sth->bindParam(':value2', 'bar'); $sth->execute(); 

или:

 $sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = ? && field2 = ?"); $sth->bindParam(1, 'foo'); $sth->bindParam(2, 'bar'); $sth->execute(); 

или выполнить с параметрами в виде массива:

 $sth = $dbh->prepare("SELECT * FROM tablename WHERE field1 = :value1 && field2 = :value2"); $sth->execute(array(':value1' => 'foo' , ':value2' => 'bar')); 

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

Я также думаю, что вы должны потратить некоторое время на использование некоторых классов из Zend Framwework во время работы с PDO. Проверьте их Zend_Db и более конкретно [Zend_Db_Factory] [2]. Вам не нужно использовать всю фреймворк или конвертировать ваше приложение в шаблон MVC, но использование фреймворка и чтение на нем – это потраченное время.

Вы все еще можете использовать его (mysqli – это еще один способ общения с сервером, сам язык SQL расширяется, а не изменяется). Подготовленные утверждения более безопасны, поскольку – вам не нужно каждый раз сталкиваться с трудностями, связанными с тем, чтобы каждый раз избегать ваших значений. Вы можете оставить их такими, какими они были, если вы хотите, но риск перекодировки sql уменьшается, если вы переключаетесь.

Является ли это утверждение ушедшим в прошлое?

Да. Не используйте SELECT * ; это кошмар для обслуживания. Есть много других потоков на SO о том, почему эта конструкция плоха, и как избежать этого поможет вам лучше писать запросы.

Смотрите также:

  • В чем причина не использовать select *?
  • Проблемы с производительностью при использовании SELECT *?
  • Почему используется '*' для создания плохого представления?

Я искал хороший и полный пример того, как динамически связывать несколько параметров запроса с любыми запросами SELECT, INSERT, UPDATE и DELETE. Алек упоминает в своем ответе способ привязки результата, для меня функция get_result () после выполнения () для запросов SELECT работает отлично, и я могу получить все выбранные результаты в массив ассоциативных массивов.

В любом случае, я создал функцию, в которой я могу динамически связывать любое количество параметров с параметризованным запросом (используя функцию call_user_func_array) и получать результат выполнения запроса. Ниже приведена функция с ее документацией (пожалуйста, прочитайте перед ней перед использованием – особенно важный параметр параметра $ paremetersTypes – Type спецификаций )

  /** * Prepares and executes a parametrized QUERY (SELECT, INSERT, UPDATE, DELETE) * * @param[in] $dbConnection mysqli database connection to be used for query execution * @param[in] $dbQuery parametrized query to be bind parameters for and then execute * @param[in] $isDMQ boolean value, should be set to TRUE for (DELETE, INSERT, UPDATE - Data manipulaiton queries), FALSE for SELECT queries * @param[in] $paremetersTypes String representation for input parametrs' types as per http://php.net/manual/en/mysqli-stmt.bind-param.php * @param[in] $errorOut A variable to be passed by reference where a string representation of an error will be present if a FAUILURE occurs * @param[in] $arrayOfParemetersToBind Parameters to be bind to the parametrized query, parameters need to be specified in an array in the correct order * @return array of feched records associative arrays for SELECT query on SUCCESS, TRUE for INSERT, UPDATE, DELETE queries on SUCCESS, on FAIL sets the error and returns NULL */ function ExecuteMySQLParametrizedQuery($dbConnection, $dbQuery, $isDMQ, $paremetersTypes, &$errorOut, $arrayOfParemetersToBind) { $stmt = $dbConnection->prepare($dbQuery); $outValue = NULL; if ($stmt === FALSE) $errorOut = 'Failed to prepare statement for query: ' . $dbQuery; else if ( call_user_func_array(array($stmt, "bind_param"), array_merge(array($paremetersTypes), $arrayOfParemetersToBind)) === FALSE) $errorOut = 'Failed to bind required parameters to query: ' . $dbQuery . ' , parameters :' . json_encode($arrayOfParemetersToBind); else if (!$stmt->execute()) $errorOut = "Failed to execute query [$dbQuery] , erorr:" . $stmt->error; else { if ($isDMQ) $outValue = TRUE; else { $result = $stmt->get_result(); if ($result === FALSE) $errorOut = 'Failed to obtain result from statement for query ' . $dbQuery; else $outValue = $result->fetch_all(MYSQLI_ASSOC); } } $stmt->close(); return $outValue; } 

Применение:

  $param1 = "128989"; $param2 = "some passcode"; $insertQuery = "INSERT INTO Cards (Serial, UserPin) VALUES (?, ?)"; $rowsInserted = ExecuteMySQLParametrizedQuery($dbConnection, $insertQuery, TRUE, 'ss', $errorOut, array(&$param1, &$param2) ); // Make sure the parameters in an array are passed by reference if ($rowsInserted === NULL) echo 'error ' . $errorOut; else echo "successfully inserted row"; $selectQuery = "SELECT CardID FROM Cards WHERE Serial like ? AND UserPin like ?"; $arrayOfCardIDs = ExecuteMySQLParametrizedQuery($dbConnection, $selectQuery, FALSE, 'ss', $errorOut, array(&$param1, &$param2) ); // Make sure the parameters in an array are passed by reference if ($arrayOfCardIDs === NULL) echo 'error ' . $errorOut; else { echo 'obtained result array of ' . count($arrayOfCardIDs) . 'selected rows'; if (count($arrayOfCardIDs) > 0) echo 'obtained card id = ' . $arrayOfCardIDs[0]['CardID']; } 

вы можете использовать get_result() в инструкции.

http://php.net/manual/en/mysqli-stmt.get-result.php