topic: db (PDO / SQL / マルチDB) / ch09 — SQL インジェクション / プリペアド vs 連結 / 演習 01

📝 ドリル 01 — 連結をプレースホルダに直す

問題

starter.php はわざと 文字列連結 で SQL を組み立てている。これだと ' (シングルクォート) を含む名前を入れた瞬間に SQL 構文エラーで落ちる。

ターゲット名:

O'Brien

users テーブルに O'Brien (id=1) が登録されている。標準入力からこの名前を受け取り、

1: O'Brien

と出力するように プレースホルダ + prepare/execute で書き直してほしい。

期待される出力

1: O'Brien

採点

php scripts/grade.php topics/11-db/ch09-sql-injection/drill/01-bad-concat/

ヒント

  • $pdo->prepare("SELECT id, name FROM users WHERE name = ?")? がプレースホルダ
  • $stmt->execute([$name]) で値を渡す
  • 連結 ("... WHERE name = '$name'") は禁止
  • PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION にする習慣を付けておく

テストケース

標準入力

O'Brien

期待される出力

1: O'Brien

📄 starter.php(雛形)

このコードから書き始めてください。

<?php

$pdo = new PDO('sqlite:' . getenv('DOJO_DB_PATH'));
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$name = trim(fgets(STDIN));

// ❌ わざと脆弱な書き方: 文字列連結で SQL を組み立てている
// 入力に ' (シングルクォート) が含まれると SQL 構文が壊れる
$sql = "SELECT id, name FROM users WHERE name = '$name'";
$stmt = $pdo->query($sql);

// TODO: 上の連結方式をやめて、$pdo->prepare(...) + execute([$name]) に書き換える
//       期待される出力: "1: O'Brien"

foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
    echo "{$row['id']}: {$row['name']}\n";
}
✅ 解答例を見る(自分で解いてから)
<?php

$pdo = new PDO('sqlite:' . getenv('DOJO_DB_PATH'));
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$name = trim(fgets(STDIN));

$stmt = $pdo->prepare("SELECT id, name FROM users WHERE name = ?");
$stmt->execute([$name]);

foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
    echo "{$row['id']}: {$row['name']}\n";
}