2017-04-12 14 views
1

Im new to databaseと私はMySQLを使用してデータベースにアクセスするたくさんのPHPコードを書いています。通常のmysqlを準備済みの文に変換する

私はSQLインジェクション攻撃を考慮しませんでしたので、mysqlプリペアドステートメントを使用するにはすべてのPHPコードを書き直さなければなりません。

準備されたSQL文を使用する方法のビデオを見た後、ただ1つのSQLコマンドを実行するためには、たくさんの "準備された"文が必要です。私の既存のコードには、いろいろなSQLステートメントがたくさんあります。準備された各ステートメントコマンドのすべての必要な準備をパックして解凍するために、すべてのコードを変更するのは悪夢です。

準備された文の6行または7行に正規SQLの1行を回すのを防ぐために使用できるラッパーがありますか?例えば

は、SQL

SELECT * from users where userid=10 

のこの行ラインを行うために使用する他のSQL文がたくさんある場合は特に、あまりにも、それは現在、非常に複雑になり、準備されたSQL文のより多くの行を必要とします。

テンプレートSQL文字列に加え、コマンドを実行し、結果をMYSQLステートメントのさまざまなタイプのラッパーの1行だけで返すパラメータを受け入れることができる、ある種の行ラッパーがありますかコードはずっと混乱しにくく見栄えが悪くなる傾向があります。

$users=WrapAndExecute($db,"SELECT * from users where userid=?","s",$userid); 

$data=WrapAndExecute($db,"UPDATE table SET username=?,city=?","ss",$name,$city); 

$result=WrapAndExecute($db,"DELETE from table where id=?","s",$userid); 

$result=WrapAndExecute($db,"INSERT into ? (name,address) VALUES(?,?)","ss","users",$name,$address); 

例えば

上記のこれらの線のそれぞれは、準備された文のテンプレートを作成してバインドを行い、それを実行し、定期的なMYSQL文があろうと、結果を返します。これにより、既存のコードに与える影響は最小限に抑えられます。

誰かがこれを行う方法を知っているか、またはこれを行うための簡単なPHPライブラリまたはクラスが既に存在する場合、私はそれをインポートして使用することができますか?それはそれで何のPHP変数を持っていない場合は、プリペアドステートメントにクエリを変更する必要はありません

おかげ

+0

私は何を求めているのか分かりませんが、疑問のあるところでは、[PDO :: prepare](https://secure.php.net/manual/en/pdo.prepare.php)PHPドキュメントがあります。 – Artemis

+0

申し訳ありませんが、十分な情報を提供しませんでした。元の投稿を更新しました。ご意見ありがとうございます。 – Programmer2

+1

_準備済みのSQL文の数多くの行が必要です。そして、それほど読んでいない/理解している/維持するのは簡単です...私は何らかの良い/優れたコードを持つために少し汗をかくことがない理由**を見ていません^^ – OldPadawan

答えて

2

。式が一定であれば、SQLインジェクションから安全です。あなたはその変数の値限り、PHPの変数を含むクエリを変更する必要はありません

$sql = "SELECT * from users where userid=10"; // Safe! 
$stmt = $pdo->query($sql); 
$data = $stmt->fetchAll(); 

は、あなたのコード内で指定された定数です。外部ソースから価値が得られない場合は安全です。

$uid = 10; 
$sql = "SELECT * from users where userid=$uid"; // Safe! 
$stmt = $pdo->query($sql); 
$data = $stmt->fetchAll(); 

あなたは限り、あなたはそれがSQLインジェクションを危険にさらすしないことを保証するために値をフィルタリングすることができますよう、PHPの変数を含むクエリを変更する必要はありません。これを行う簡単かつ簡単な方法は、整数にキャストすることです(整数であることが想定される場合)。

あなたはユーザー入力に由来している可能性があり、「信頼できない」の値を、使用して、またはファイルを読み込み、あるいはデータベースから読んでいる例を残し
$uid = (int) $_GET['uid']; 
$sql = "SELECT * from users where userid=$uid"; // Safe! 
$stmt = $pdo->query($sql); 
$data = $stmt->fetchAll(); 

。そのような場合、パラメータは自分を守る最も信頼できる方法です。例サブセットにおいて

$sql = "SELECT * from users where userid=?"; // Safe! 

// two lines instead of the one line query() 
$stmt = $pdo->prepare($sql); 
$stmt->execute([$_GET['uid']]); 

$data = $stmt->fetchAll(); 

あなたが通常使用するよりも、あなたがコードのつの追加行が必要になります。それは非常に簡単です。

あなたの泣き言をやめる! ;-)


mysqliで準備されたステートメントについてのコメントをお寄せください。

変数をバインドする方法は、PDOよりも使いにくいです。私はそれが混乱し、不要だ、bind_result()と彼らの例に彼らがものを好きではありません

$sql = "SELECT * from users where userid=?"; // Safe! 

$stmt = $mysqli->prepare($sql); 
$stmt->bind_param('i', $_GET['uid']); 
$stmt->execute(); 
$result = $stmt->get_result(); 

$data = $result->fetch_all(); 

:私はここにmysqliのと簡単な方法だhttp://php.net/manual/en/mysqli.prepare.php

で与えられた例は好きではありません。ちょうどget_result()を使用してください。したがって、mysqliではPDOよりもコード行が2行多く必要になります。

私は、PDOの​​機能の便利さをエミュレートするmysqliのクエリラッパーを作成しました。可変引数型の配列をbind_param()にマッピングするのはPITAです。

は、PHPでのPDO拡張を見てみましょうhttps://stackoverflow.com/a/15933696/20860https://stackoverflow.com/a/7383439/20860

+0

ビル、それはありがたいですが、あなたはまたデータのタイプを教えてはいけません。例えば、 "ssddd"パラメータ1は文字列です。parameter2もまた文字列ですparmater 3は小数です(d) – Programmer2

+1

いいえ、MySQLの場合はありません。これは、他のブランドのSQLデータベースの他のPDOドライバで必要となるかもしれませんが、MySQLの場合、 'bindParam()'ナンセンスをスキップして、パラメータ値の配列を 'execute()'に渡すことができます。これははるかに簡単です。 –

+0

私はSQLの "prepared statements"チュートリアルで、プレゼンターが通常のPHPの行を1行だけ実行するために6行または7行の余分なPHP文を使用しているのを見ましたが、私はそれが狂ったようだったので、私のコードは7倍大きくなりますすべてを追加するには複雑です!しかし、それは本当にそのようではないようです – Programmer2

-1

への私の答えで解決策を参照してください - http://php.net/manual/en/intro.pdo.php:それは準備された文への注射のおかげに対して確保します。また、さまざまなデータベース(MySQL、MSSQLなど)に接続することもできます。

次に、独自のラッパーを構築して、それをきれいに保つことができます。例えば次のように独自のラッパーは次のようになります。 (以下の例では、オブジェクトとしてユーザーの行を返します)

// connect to DB 
$GLOBALS['default_db'] = new DB('localhost','db_name','username','password') ; 

// Get users and output results 
$query = new DBQuery('SELECT * FROM users WHERE userid = ?',array(10)) ; 
var_dump($query -> results()) ; 
var_dump($query -> num_rows()) ; 

// DB connection 
class DB { 

    public $connection; 

    public function __construct($host , $dbname , $username , $password) { 
     $this->connection = new \PDO('mysql:host=' . $host . ';dbname=' . $dbname , $username , $password); 
    } 

} 

// Wrapper 
class DBQuery { 

    private $num_rows = 0; 
    private $results = array(); 

    public function __construct($query , $params = null , $class_name = null , DB $db = null) { 

     if (is_null($db)) { 
      $db = $GLOBALS['default_db']; 
     } 

     $statement = $db->connection->prepare($query); 
     $statement->execute($params); 

     $errors = $statement->errorInfo(); 
     if ($errors[2]) { 
      throw new \Exception($errors[2]); 
     } 

     $fetch_style = ($class_name ? \PDO::FETCH_CLASS : \PDO::FETCH_OBJ); 
     $this->results = $class_name ? $statement->fetchAll($fetch_style , $class_name) : $statement->fetchAll($fetch_style); 
     $this->num_rows += $statement->rowCount(); 

     while ($statement->nextrowset()) { 
      $this->results = array_merge($this->results,$class_name ? $statement->fetchAll($fetch_style , $class_name) : $statement->fetchAll($fetch_style)); 
      $this->num_rows += $statement->rowCount(); 
     } 
    } 

    public function num_rows() { 
     return $this->num_rows; 
    } 

    public function results() { 
     return $this->results; 
    } 

} 
+0

ありがとうsammyaglam – Programmer2

+0

np :)あなたはラッパーが役立つことを願っています。 – sammysaglam

+0

私は残念なことに、私はmysqliを使用して、あなたが書いたコードがmysqliで動作することを確認していないことを認識します – Programmer2

-1

主要な要件は、あなたの現在のコードベースへの影響を最小限に抑えながら、これを実装することができることのようですので、それは希望あなたが現在クエリを実行するためにどのインタフェースを使用しているか教えてくれた場合に役立ちました。あなたはPDOを使用することもできますが

すでにPDOを使用していない場合は、作業の非常に多くを意味
  • PDOの例外は、あなたが手続きを使用していると仮定すると、恐ろしい

ですmysqli(およびmysqli_prepare()を使用しないようにしなければならない理由があります)、それは何かを書くことが難しくありません(テストされていません):

function wrapAndExecute() 
{ 
    $args=func_get_args(); 
    $db=array_shift($args); 
    $stmt=array_shift($args); 
    $stmt_parts=explode('?', $stmt); 
    if (count($args)+1!=count($stmt_parts)) { 
     trigger_error("Argument count does not match placeholder count"); 
     return false; 
    } 
    $real_statement=array_shift($stmt_parts); 
    foreach ($args as $k=>$val) { 
     if (isnull($val)) { 
     $val='NULL'; 
     } else if (!is_numeric($val)) { 
     $val="'" . mysqli_real_escape_string($db, $val) . "'"; 
     } 
     $real_statement.=$val . array_shift($stmt_parts); 
    } 
    return mysqli_query($db, $real_statement); 
} 

これは、IS [NOT] NULLもうまく処理できないことに注意してください。ステートメントやブーリアンでは(しかし、これらは修正するのは簡単です)。

+0

ありがとう! – Programmer2

+0

pdoの例外についてご意見を少しお寄せください。私は本当に困惑している –

0

私は同じボートにいましたが、私はsuch a wrapperと書いています。これは機能ではなくクラスであることを除けば、あなたが望むように正確に動作します。

$user = $sdb->getRow("SELECT * from users where userid=?s", $userid); 
$sdb->query("UPDATE table SET username=?s, city=?s", $name, $city); 
$sdb->query("DELETE from table where id=?s", $userid); 
$sdb->query("INSERT into ?n (name,address) VALUES(?s,?s)","users", $name, $address); 

上記は、どこかにあなたのブートストラップファイルに限り、あなたが持っているように、作業コードある

$db = mysqli_connect(...); 
... 
require 'safemysql.class.php'; 
$sdb = new SafeMySQL('mysqli' => $db); 

他のいずれの方法でもそのような何かをすることができなかったことに注意してください。

今日私が書いていたのであれば、このクラスはPDOにはすでに多くの機能が組み込まれているので、私はPDOを使用していました。

+0

ありがとう!私はクラスを使用していないので、私はそれが働くことができないので、暗号化を放棄することを決めた – Programmer2

関連する問題