数据库类中的准备语句

时间:2009-08-14 02:01:59

标签: php mysqli prepared-statement

问题

所以我正在编写我的基于Web的应用程序,它让我觉得“Durr,你的东西对SQL注入很开放等等!重写db类!”

我目前正在重写我的$db课程,我在理解如何实施准备好的陈述方面遇到了很多麻烦。

此前...

我曾经使用过这样的东西:

$db->runQuery("SELECT * FROM someTable WHERE someField = '$var1'");
while ($result = mysql_fetch_array($db->result){
    // ... ugh, tedious
}

在执行select语句时,我总是抓住一个数组,并循环遍历结果。

我理解......

  1. 我应该因为在MySQL中使用未准备好的陈述而被焚烧。
  2. 我必须让mysql知道每个变量的参数类型。 (或者我)?
  3. 我想...

    能够将我的查询和值传递给我的新函数(让我们使用select作为示例)然后返回一个结果供我使用(作为一个assoc。数组值);

    $query  = "SELECT * FROM someTable WHERE someField = ? AND anotherField = ?";
    $params = array($var1, $var2);
    $result = $db->doSelect($query, $params);
    // Then do all sorts of neat stuff with $result - huzzah!
    

    我遇到麻烦...

    了解如何将所有信息整合在一起。

    1. 如何呈现一系列价值观并与我准备好的声明一起使用?
    2. 根据上述声明,如何运行它(execute()?)并让它返回一个数组?
    3. 如果我的问题有点迂回,我很抱歉,但是我试图理解它时会感到疲惫不堪。如果需要更多信息,请告诉我,我会添加。

2 个答案:

答案 0 :(得分:3)

这是我为Prepare / Execute功能集编写的内容。这些当然是更大的DB对象的一部分。

/**
*   Prepares a query to be run, storing the data in $this->preparedTokens
*   Use the following characters to indicate how the data is to be put into SQL statement
*   ? -> escaped and quoted (with single quotes) before inserting
*   ^ -> inserted as is
*   & -> implodes the array escpaping each value
*   @ -> implodes the array (no escaping)
*
*   @param      string      $sql        The SQL statement to prepare
*
*   @return     int         The key of prepare sql query to be passed to $this->Execute()
*/
public function Prepare($sql) {
    $tokens = preg_split('/((?<!\\\)[@&?^])/', $sql, -1, PREG_SPLIT_DELIM_CAPTURE);

    // loop through removing any escaped values
    foreach ($tokens as $key => $val) {
        switch ($val) {
            case '?' :
            case '&' :
            case '@' :
                break;
            default :
                $tokens[$key] = preg_replace('/\\\([@&?^])/', "\\1", $val);
                break;
        } // switch
    } // foreach

    $this->preparedTokens[] = $tokens;
    end($this->preparedTokens);
    return key($this->preparedTokens);
} // function Prepare

/**
*   Creates the SQL placing the data in the appropriate places and then runs the sql
*
*   @param      int         $preparedKey        The key of the prepared sql
*   @param      array       $data               The array of data to put into the query (the count of this array must match that of the prepared query)
*
*   @return     object      false if the $preparedKey does not exist in $this->preparedTokens
*                           false if count of needed values in sql statement does not equal the number of keys in the data array
*                           otherwise, the result of $this->Query()
*/
public function Execute($preparedKey, $data) {
    if (isset($this->preparedTokens[$preparedKey])) {
        $tokens = $this->preparedTokens[$preparedKey];
        $query = '';
        $dataKey = 0;
        $count = 0;

        // count the number of tokens we have
        $validTokens = array('?', '^', '&', '@');
        foreach ($tokens as $val) {
            if (in_array($val, $validTokens)) {
                ++$count;
            } // if
        } // foreach

        // check to ensure we have the same number of tokens as data keys
        if ($count != count($data)) {
            trigger_error('Query Error: The number of values received in execute does not equal the number of values needed for the query', E_USER_ERROR);
            return false;
        } // if

        // loop through the tokens creating the sql statement
        foreach ($tokens as $val) {
            switch ($val) {
                case '?' :
                    $query .= "'" . $this->EscapeString($data[$dataKey++]) . "'";
                    break;
                case '^' :
                    $query .= $data[$dataKey++];
                    break;
                case '&' :
                    $query .= $this->ImplodeEscape($data[$dataKey++]);
                    break;
                case '@' :
                    $query .= implode(',', $data[$dataKey++]);
                    break;
                default :
                    $query .= $val;
                    break;
            } // switch
        } // foreach

        return $this->Query($query);

    } else {
        return false;
    } // if
} // function Execute

/**
*   Runs $this->Prepare() then $this->Execute() for the sql and the data
*   Use the following characters to indicate how the data is to be put into SQL statement
*   ? -> escaped and quoted (with single quotes) before inserting
*   ^ -> inserted as is
*   & -> implodes the array escpaping each value
*   @ -> implodes the array (no escaping)
*
*   @param      string      $sql        The SQL statement to prepare
*   @param      array       $data       The array of data to put into the query (the count of this array must match that of the prepared query)
*
*   @return     object      returns value from $this->Query() if Execute was successful
*                           otherwise it'll be false
*/
public function PrepareExecute($sql, $data) {
    return $this->Execute($this->Prepare($sql), $data);
} // function PrepareExecute

$this->Query()执行MySQL语句,然后根据语句的内容返回不同的值(基于语句的前6个字符,修剪):

  • 如果失败则为false(使用$ this-&gt; GetError()来获取错误消息)
  • 如果INSERT成功,则插入id
  • 如果成功DELETE或UPDATE或REPLACE,则受影响的行数
  • 如果SELECT或任何其他查询类型成功,则查询对象

我不确定这是否是您正在寻找的,但它可能会有所帮助。

忘了提这个,但大多数想法来自Pear :: DB类:http://pear.php.net/package/DB

答案 1 :(得分:1)

看看你是否可以使用以下内容。 如果您需要更详细的实施,请告诉我

call_user_func_array(array($stmt,"bind_result"), $params);