8.

PHP エスケープ文字 (シングル/ダブルクォート) 完全ガイド

編集
この記事の要点
  • ダブルクォートでは \n / \r / \t / \\ / \$ / \" / \xNN / \u{NNNN} (PHP 7+) が使える
  • シングルクォート\\\' の 2 つだけ。\nそのまま文字列リテラルになる
  • HTML 出力時は htmlspecialchars($str, ENT_QUOTES, "UTF-8") で XSS 対策
  • SQL は addslashes連結禁止PDO::prepare + Prepared Statement で SQL Injection 防御
  • PHP コードを文字列に埋めるなら <?php / ?><?php 化、または heredoc/nowdoc を使う

ダブルクォート vs シングルクォートの違い

エスケープシングル '...'ダブル "..."意味
\nそのまま \n改行 (LF)Line Feed (0x0A)
\rそのまま \rキャリッジリターンCR (0x0D)
\tそのまま \t水平タブ0x09
\vそのまま垂直タブ0x0B
\fそのまま改ページ0x0C
\0そのままヌル文字0x00
\\バックスラッシュバックスラッシュ両方OK
\'シングルクォートそのまま \'-
\"そのまま \"ダブルクォート-
\$そのまま \$$ 記号(変数展開抑止)-
\xNNそのまま16進文字 (例 \x41 → A)-
\NNNそのまま8進文字-
\u{NNNN}そのままUnicode (PHP 7+)例 \u{1F600} → 😀

具体例

// シングルクォート: \n はそのまま文字
echo 'Hello\nWorld';
// → Hello\nWorld (改行されない)

// ダブルクォート: \n は改行
echo "Hello\nWorld";
// → Hello
//   World

// 変数展開
$name = 'Taro';
echo 'Hello, $name';       // Hello, $name (展開されない)
echo "Hello, $name";       // Hello, Taro
echo "Hello, \$name";      // Hello, $name (\$ でエスケープ)

// 配列・オブジェクト展開
$arr = ['name' => 'Taro'];
echo "Hello, {$arr['name']}";   // Hello, Taro
echo "Hello, $arr[name]";       // Hello, Taro (簡易記法、キーはクォートなし)

// Unicode (PHP 7+)
echo "\u{1F600}";   // 😀
echo "\u{3042}";    // あ

// 16進文字
echo "\x41\x42\x43";   // ABC

heredoc と nowdoc

複数行の文字列リテラルは heredoc / nowdoc がベター:

$name = 'Taro';

// heredoc - ダブルクォートと同じ動作(変数展開あり)
$html = <<<HTML
<div>
  Hello, $name
</div>
HTML;

// nowdoc - シングルクォートと同じ動作(変数展開なし)
$raw = <<<'TEXT'
Path: C:\Users\$name
\nは改行しません
TEXT;

// インデント付き heredoc (PHP 7.3+)
function getHtml(): string {
    return <<<HTML
        <div>
            <p>$name</p>
        </div>
        HTML;
    // 終端タグのインデント分が全行から削除される
}

HTML エスケープ (XSS 対策)

ユーザー入力をそのまま HTML に出すと XSS。必ず htmlspecialchars():

// ❌ XSS 脆弱
echo "<p>Hello, $name</p>";
// $name = "<script>alert(1)</script>" だと実行される

// ✅ htmlspecialchars で対策
echo "<p>Hello, " . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . "</p>";

// 第2引数のフラグ
// ENT_QUOTES    - シングル+ダブル両方をエスケープ(推奨)
// ENT_HTML5     - HTML5 仕様(XHTML は ENT_XHTML)
// ENT_SUBSTITUTE - 不正バイト列を U+FFFD に置換
// ENT_DISALLOWED - 文書型で許可されない文字を置換

// 推奨フォーム
function h($s): string {
    return htmlspecialchars($s ?? '', ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE, 'UTF-8');
}
echo "<p>" . h($name) . "</p>";

// htmlentities - htmlspecialchars + 全文字エンティティ化(重い、通常不要)
echo htmlentities('é', ENT_QUOTES, 'UTF-8');   // é
文字エスケープ後
&&amp;
<<
>>
"&quot;
'&#039; (ENT_QUOTES)

SQL Injection 対策 (PDO Prepared Statement)

絶対に文字列連結で SQL を組まないのが鉄則:

// ❌ SQL Injection 脆弱
$id = $_GET['id'];   // "1 OR 1=1"
$pdo->query("SELECT * FROM users WHERE id = $id");

// ❌ addslashes だけでは不十分(マルチバイト攻撃に弱い)
$id = addslashes($_GET['id']);
$pdo->query("SELECT * FROM users WHERE id = '$id'");

// ✅ Prepared Statement で安全
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$_GET['id']]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);

// ✅ 名前付きバインド
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute([':email' => $email]);

// LIKE 句のワイルドカードエスケープ
$keyword = str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $keyword);
$stmt = $pdo->prepare("SELECT * FROM logs WHERE msg LIKE ? ESCAPE '\\\\'");
$stmt->execute(["%{$keyword}%"]);

JSON / URL エスケープ

// JSON
$arr = ['name' => 'Taro', 'msg' => 'Hello "World"'];
echo json_encode($arr);                  // {"name":"Taro","msg":"Hello \"World\""}
echo json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);

// URL
$keyword = 'php 入門';
$url = 'https://example.com/search?q=' . urlencode($keyword);
// → ?q=php+%E5%85%A5%E9%96%80

// rawurlencode - スペースを + ではなく %20 に
$path = 'docs/' . rawurlencode($filename);

// パラメータ全部
$params = ['q' => $keyword, 'page' => 2];
$url = 'https://example.com/search?' . http_build_query($params);

非推奨: addslashes / stripslashes / Magic Quotes

古い記事で出てくる addslashes 系はもう使わないでください:

// ❌ 非推奨(古い解説に出てくる)
$safe = addslashes($input);    // ' " \ \0 にバックスラッシュ追加
$orig = stripslashes($safe);

// ❌ Magic Quotes は PHP 5.4 で廃止
get_magic_quotes_gpc();   // 常に false (PHP 5.4+)、PHP 8 で関数自体削除

// ✅ 現代の対策
// SQL    → PDO Prepared Statement
// HTML   → htmlspecialchars
// JSON   → json_encode
// シェル → escapeshellarg / escapeshellcmd

PHP コードを文字列に埋めたいとき

// nowdoc が最強(変数展開もエスケープも不要)
$snippet = <<<'PHP'
<?php
$name = $_POST['name'] ?? '';
echo htmlspecialchars($name);
PHP;

// HTML として出すなら全てエスケープ
echo '<pre>' . htmlspecialchars($snippet, ENT_QUOTES, 'UTF-8') . '</pre>';

FAQ

Q: シングルとダブル、どちらを使うべき?
A: 変数展開・エスケープシーケンスが要らないならシングル(わずかに高速)。展開したいときだけダブル。

Q: 全角スペースもエスケープ必要?
A: 不要。HTML エスケープ対象は & / < / > / " / ' のみ。

Q: str_replace で自前エスケープを書くのは?
A: 危険。順序・抜けが起きやすい。必ず標準関数 htmlspecialchars / json_encode / PDO::prepare を使ってください。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 基本事項
  2. HTMLへの埋め込み
  3. 変数
  4. 可変変数
  5. 定数
  6. データ型
  7. キャスト
  8. エスケープ文字
  9. 配列
  10. 演算子
  11. 代入の際の注意点
  12. 条件分岐
  13. 繰り返し処理
  14. クラスとインスタンス
  15. コンストラクタ
  16. 関数
  17. スーパーグローバル変数
  18. スコープ
  19. staticについて
  20. yieldについて
  21. ファイルのアップロード方法
  22. DB接続方法
  23. SQL実行方法
  24. カプセル化の具体例
  25. 継承の構文
  26. オーバーライド
  27. ポリモーフィズム(多様性)の具体例
  28. 抽象クラス・メソッドの構文と具体例
  29. GET通信
  30. try catchで全てのエラーを拾う方法

最近更新/作成されたページ