3

過去 3 時間、答えを探していましたが、どうすればよいかわかりません。コードは次のとおりです。

    function get_data($tablename)
    {
        try
        {
            $conn = $this->conn();
            $stmt = $conn->prepare("SELECT * FROM :tablename ORDER BY id");
            $stmt->bindParam(':tablename', $tablename, PDO::PARAM_STR);
            $stmt->execute();
            return $stmt;
        }
        catch (Exception $e)
        {
            echo "ERROR:" . $e->getMessage();
        }
    }  

そして、ここにエラーがあります:

ERROR:SQLSTATE[42000]: 構文エラーまたはアクセス違反: 1064 SQL 構文にエラーがあります。1 行目の ''products' ORDER BY id' 付近で使用する正しい構文については、MySQL サーバーのバージョンに対応するマニュアルを確認してください。

私は何を間違えたのでしょうか? ...

4

2 に答える 2

3

ここに記載されているように(@YourCommonSense に感謝)、パラメーターをテーブル名として使用することはできません。その場合、次の 2 つのいずれかが発生します。

  1. 適切なプリペアド ステートメントを使用すると、プリペアド ステートメント モジュールは例外をスローします (不可能なことを要求したので、当然のことです)。
  2. エミュレートされたプリペアド ステートメントを使用すると、パラメータがやみくもにエスケープされ、一重引用符で囲まれ、置換され、SQL 構文エラーが発生します。これがここで起こったことです。

それが問題です。解決策については:

  • データベースの設計を再評価してください。そのような異なるテーブル間でデータを本当に分割する必要がありますか? そうでない場合は、関連するデータを 1 つのテーブルに結合し、それに応じてクエリを実行します。
  • デザインに満足している (または変更できない) 場合は、次のような醜く安全でないハックが必要になります。

    function get_data($tablename, $acceptable_tablenames = array()) {
      /* $acceptable_tablenames is an array of strings, containing
       *  table names that you'll accept. It's your job to make sure
       *  these are safe; this is a much easier task than arbitrary
       *  sanitization.
       */
      if (array_search($tablename, $acceptable_tablenames, true) === FALSE) {
        throw new Exception("Invalid table name"); /* Improve me! */
      } else {
        /* your try/catch block with PDO stuff in it goes here
         * make sure to actually return the data
         */
      }
    }
    

    として呼び出しますget_data($table, array("my_datatable_1", "my_datatable_2"))。インスピレーションを得るための私の回答の冒頭にリンクされている投稿へのクレジット。

于 2013-06-08T09:25:12.313 に答える
0

PDO は、パラメーターを一重引用符 ( ') でエスケープします。MySql テーブル名はバッククォート (`) でエスケープする必要があります。

提供された例では、tablename パラメーター Products が一重引用符でエスケープされています。これは、インジェクション攻撃を防ぐための PDO エンジンの安全機能です。

の値がアプリケーションのコンテキストで意味があると仮定し$tablenameます (たとえば、現在のユーザーが指定されたテーブル内のすべてのデータを表示できることを検証します)。

次のように動作します。

function get_data($tablename)
{
    try
    {
        $conn = $this->conn();
        $stmt = $conn->prepare("SELECT * FROM `" . str_replace("`","``",$tablename) . "` ORDER BY id;");
        $stmt->execute();
        return $stmt;
    }
    catch (Exception $e)
    {
        echo "ERROR:" . $e->getMessage();
    }
}
于 2013-06-08T08:52:24.203 に答える