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_ERRMODEをPDO::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";
}