23

我的网站相当广泛,而且我最近才切换到 PHP5(称我为大器晚成者)。

我之前的所有 MySQL 查询都是这样构建的:

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

这使它变得非常容易、简单和友好。

出于明显的安全原因,我现在正尝试切换到 mysqli,并且我很难弄清楚如何在需要特定参数SELECT * FROM时实现相同的查询。bind_param

这种说法是否已成为过去?

如果是,我如何处理涉及大量列的查询?我真的需要每次都打出来吗?

4

7 回答 7

51

我可能是错的,但对于你的问题,我觉得这bind_param()并不是真正的问题。您总是需要定义一些条件,直接在查询字符串本身中,bind_param()用于设置?占位符。这不是一个真正的问题。

我使用 MySQLiSELECT *查询时遇到的问题是其中的bind_result()一部分。这就是有趣的地方。我从 Jeffrey Way 看到了这篇文章: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 *到目前为止,我发现这是一个理想的解决方案。

于 2009-06-08T20:06:58.967 回答
31
"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

OP评论:

所以如果我有 5 个参数,我可能有“sssis”之类的东西(取决于输入的类型?)

对,准备好的语句中的每个?参数都有一个类型说明符,它们都是位置说明符(第一个说明符适用于第一个?,它被第一个实际参数(它是 的第二个参数bind_param)替换)。

于 2009-04-15T07:45:47.507 回答
7

在切换时,切换到 PDO 而不是 mysqli,它可以帮助您编写与数据库无关的代码,并为准备好的语句提供更好的功能。

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'));

如果您希望您的应用程序将来能够在不同的数据库上运行,这对您来说会更容易。

我还认为,在使用 PDO 时,您应该花一些时间来使用 Zend Framwework 中的一些类。查看他们的Zend_Db,更具体地说是 [Zend_Db_Factory][2]。您不必使用所有框架或将应用程序转换为 MVC 模式,但使用框架并阅读它是值得的。

于 2009-04-15T08:31:15.010 回答
2

这种说法是否已成为过去?

是的。不要使用SELECT *; 这是维护的噩梦。SO上有很多其他线程关于为什么这个结构不好,以及如何避免它会帮助你编写更好的查询。

也可以看看:

于 2009-04-15T07:33:14.727 回答
1

你仍然可以使用它(mysqli只是与服务器通信的另一种方式,SQL语言本身是扩展的,没有改变)。不过,准备好的语句更安全——因为您不需要每次都经历正确转义值的麻烦。如果你愿意,你可以让它们保持原样,但如果你切换,SQL 捎带的风险会降低。

于 2009-04-15T07:33:48.907 回答
1

你可以get_result()在语句上使用。

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

于 2017-09-27T07:01:58.027 回答
-1

我正在寻找一个很好且完整的示例,说明如何将多个查询参数动态绑定到任何 SELECT、INSERT、UPDATE 和 DELETE 查询。Alec在他的回答中提到了一种如何绑定结果的方法,对我来说,用于 SELECT 查询的 execute() 函数之后的 get_result() 工作得很好,并且能够将所有选定的结果检索到关联数组的数组中。

无论如何,我最终创建了一个函数,我可以在其中动态地将任意数量的参数绑定到参数化查询(使用 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'];
    }
于 2017-01-23T15:05:26.627 回答