0

パラメーターを PDO 準備済みステートメントにバインドしようとすると、非常にイライラする結果が得られます。

結果は次 のエラーです。SQL 構文にエラーがあります。1 行目の「items」付近で使用する正しい構文については、MySQL サーバーのバージョンに対応するマニュアルを確認してください。

このエラーは、テーブル 'items' が一重引用符で囲まれてはならないときに引用されていることを明確に示しています。以下に少しテストをまとめました。ご覧のとおり、最初からステートメントでパラメーターを引用符で囲んでいません。これは、おそらくほとんどの人が最初に推測することです。$params を null に設定し、ステートメント内の ':table' を 'items' に置き換えて bindParams 関数をバイパスすると、それは完全に正常に動作します。

<?php

echo 'started test...';

//connect to database

try {
    $dbHandle = new PDO('mysql:dbname=mydatabase;host=mysql.mywebsite.com', 'myuser', 'mypass');   
} catch (PDOException $e) {
    echo 'Database connection failed: ' . $e->getMessage();    
}

//print out the contents of table 'items'

print_r(query("SELECT * FROM :table", array("table" => "items"), $dbHandle));

//the query() function used above

function query($query_str, $params = null, $dbHandle) {

    $stmt_obj = $dbHandle->prepare($query_str);

    if($params != null) {           
        bindParams($stmt_obj, $params);
    }

    $stmt_obj->execute();

    //debug stuff
    echo '<pre>';   
    echo 'ERROR: ';
    $error = $stmt_obj->errorInfo();        
    echo $error[2].'<br /><br />';
    echo 'DEBUG DUMP:<br />';
    $stmt_obj->debugDumpParams();
    echo '</pre>';

    if (preg_match("/SELECT/i", $query_str)) {
        $result = array();      
        while ($row = $stmt_obj->fetch(PDO::FETCH_ASSOC)) {         
            array_push($result, $row);
        }
        unset($stmt_obj);
        return $result;
    }   

}

function bindParams($stmt, $params) {   
    if(is_object($stmt) && ($stmt instanceof PDOStatement))
    {           
        foreach($params as $key => $value)
        {            
            if(is_int($value)) {
                $param = PDO::PARAM_INT; 
            } elseif(is_bool($value)) {
                $param = PDO::PARAM_BOOL;
            } elseif(is_null($value)) {
                $param = PDO::PARAM_NULL;
            } elseif(is_string($value)) {
                $param = PDO::PARAM_STR;
            } else {
                $param = FALSE;
            }
            if($param) {                                                        
                $stmt->bindValue(":$key", $value, $param);                  
            }
        }
    }

誰も私を悲惨な状況から解放し、私が見逃していることを本当に明白に指摘してくれる人はいますか?

4

1 に答える 1

1

準備済みステートメントの記号は、識別子ではなく値のプレースホルダーにすぎないため、動的な列またはテーブル名を使用して準備済みステートメントを作成することはできません。すべてのデータベース参照は、準備時に解決する必要があります。これが真実ではなかったとしても、PDO/MySQL は:tableプレースホルダーがリテラルか識別子かをどのように知るのでしょうか? それらには異なる引用ルールがあります。

この制限は、すべてのデータベース システムとすべての API の準備済みステートメントに共通です。これは確かに PDO のバグではありません。

于 2012-01-07T05:33:23.923 に答える