ВЫБЕРИТЕ *ИЗ в MySQLi


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

Все мои запросы MySQL до этого были построены как таковые:

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

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

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

Является ли это утверждение частью прошлое?

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

 23
Author: GEOCHET, 2009-04-15

7 answers

"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 позаботится о побеге и цитировании (я думаю).

 33
Author: tpdi, 2014-05-29 06:22:46

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

Я могу ошибаться, но по вашему вопросу у меня такое чувство, что 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 *. До сих пор я считал, что это идеальное решение.

 51
Author: Alec, 2012-09-01 23:39:11

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

Http://www.php.net/pdo

Параметр привязки для 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, но использование фреймворка и его изучение - это хорошо потраченное время.

 6
Author: olle, 2009-04-15 11:31:33

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

 2
Author: soulmerge, 2009-04-15 07:33:48

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

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

См. также:

 2
Author: kquinn, 2017-05-23 12:18:02

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

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

     /**
     * 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'];
    }
 0
Author: mbuster, 2017-05-23 12:03:05

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

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

 0
Author: Sugumar Venkatesan, 2017-09-27 07:05:32