2

问题

所以我正在编写我的基于 Web 的应用程序,我突然意识到“杜尔,你的东西对 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知道每个变量是什么类型的参数。(或者我)?

我想...

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

$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()?)并让它返回一个数组?

如果我的问题有点迂回,我很抱歉,但是我因为试图理解它而感到疲倦。如果需要更多信息,请告诉我,我会添加。

4

2 回答 2

3

这是我为准备/执行功能集编写的内容。这些当然是更大的数据库对象的一部分。

/**
*   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->GetError() 获取错误消息)
  • 如果INSERT成功,则插入id
  • 如果成功 DELETE 或 UPDATE 或 REPLACE,则受影响的行数
  • 如果成功 SELECT 或任何其他查询类型,则查询对象

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

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

于 2009-08-14T02:09:04.390 回答
2

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

call_user_func_array(array($stmt,"bind_result"), $params);
于 2009-08-18T07:42:38.127 回答