PHP 公式マニュアルにおける SQL インジェクションと PDO の数値の型指定のサンプルコード

PHP 公式マニュアルの SQL インジェクションのページには数値の扱い方がきちんと明記されている。

アプリケーションが、数値入力を期待している場合、データを is_numeric() で検証するか、 settype() により暗黙の型変換を行うか、 sprintf()により数値表現を使用することを検討してみてください。

サンプルコードも掲載されている。

settype($order, 'integer');
$query  = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";

// フォーマット文字列の%dに注意してください。%sを使用しても意味がありません。
$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;", $offset);

ついでに書いておくと mysql_real_escape_string()sqlite_escape_string() はそれぞれ mysqli_real_escape_stringSQLite3::escapeString に変えてほしいな。

データベースがバインド変数をサポートしていない場合は、 データベースに渡される数値以外のユーザー入力を データベース固有の文字列エスケープ関数 ( mysql_real_escape_string(), sqlite_escape_string() など) でクオートしてください。

数値の型指定の話に戻すと PDO のマニュアルでは数値の型指定が徹底されていないので、今後強化すべきと考える。

PDO のプリペアドステートメントおよびストアドプロシージャのページでは数値の型指定が行われていない。

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

// 行を挿入します
$name = 'one';
$value = 1;
$stmt->execute

prepare メソッドおよび executeページでは文字列を前提とする executeメソッドが使われている。

$sql = 'SELECT name, colour, calories
  FROM fruit
  WHERE calories < :calories AND colour = :colour';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':calories' => 150, ':colour' => 'red'));
$red = $sth->fetchAll();

quote のページでは数値の型指定が入ったサンプルコードが存在しない。

bindValue および bindParam のページでは数値の型指定が入ったコードが記載されている。

$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories, PDO::PARAM_INT);
$sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);