0

私はこのPDOラッパーを持っています

private function cleanup($bind) {
    if(!is_array($bind)) {
        if(!empty($bind))
            $bind = array($bind);
        else
            $bind = array();
    }
    return $bind;
}

public function run($sql, $bind="") {
    $this->sql = trim($sql);
    $this->bind = $this->cleanup($bind);
    $this->error = "";
    array_push($this->qs, $sql);

    try {
        $pdostmt = $this->prepare($this->sql);
        if($pdostmt->execute($this->bind) !== false) {
            if(preg_match("/^(" . implode("|", array("select", "describe", "pragma")) . ") /i", $this->sql))
                return $pdostmt->fetchAll(PDO::FETCH_ASSOC);
            elseif(preg_match("/^(" . implode("|", array("delete", "insert", "update")) . ") /i", $this->sql))
                return $pdostmt->rowCount();
        }
    } catch (PDOException $e) {
        $this->error = $e->getMessage();
        $this->debug();
        return false;
    }
}

数年前に使い始めてから問題はありませんでしたが、文字列がエスケープされていないため、エラーメッセージが表示されます。たぶん、私はこのようなシナリオで働いたことがない.

問題を引き起こしているSQL文は次のとおりです

$db->run("SELECT region_id FROM region WHERE name = '$name'");

$nameホークスベイはどこですか。私は PDO が文字列をエスケープするという印象を受けていましたが、間違っていたようです。この問題を解決する方法はありますか?

4

2 に答える 2

3

この質問に至った2つの誤った仮定があります

  1. エスケープは、クエリを正しいものにするものです。
  2. PDO は、「魔法の」方法でこの「エスケープ」を行い、何をエスケープするかを何らかの形で知っています。

残念ながら、どちらの仮定も間違っています。

実際のところ、エスケープは SQL 文字列にのみ必要です。PDO、準備済みステートメント、安全性などとは関係ありません。文字列リテラルをクエリに入れる場合は、特殊文字をエスケープする必要があります。
しかし、そうでない場合は、逃げるのは良くありません。

PDOに関しては、「エスケープ」するのではなく、クエリでプレースホルダーを処理する必要があります。これが全体の仕組みです。プレースホルダーを使用して、対応する値を適切にフォーマットするように PDO に指示しています。このようなフォーマットには、エスケープだけでなく、さらに多くのさまざまな手段が含まれます。

だから、それはこのようなものでなければなりません

$db->run("SELECT region_id FROM region WHERE name = :name", array(':name' => $name));

このように、PDO は $name を文字列として扱い、それに応じてフォーマットします。

「クリーンアップ」機能が適切に機能するかどうか、およびなぜ使用されるのかはわかりませんが。

于 2013-08-03T12:49:35.667 に答える