この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:4
ページ更新者:guest
更新日時:2026-06-11 07:07:02

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

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li><strong>ダブルクォート</strong>では <code>\n</code> / <code>\r</code> / <code>\t</code> / <code>\\</code> / <code>\$</code> / <code>\"</code> / <code>\xNN</code> / <code>\u{NNNN}</code> (PHP 7+) が使える</li><li><strong>シングルクォート</strong>は <code>\\</code> と <code>\&apos;</code> の 2 つだけ。<code>\n</code> は<strong>そのまま文字列リテラル</strong>になる</li><li>HTML 出力時は <code>htmlspecialchars($str, ENT_QUOTES, "UTF-8")</code> で XSS 対策</li><li>SQL は <code>addslashes</code> や<strong>連結禁止</strong>。<code>PDO::prepare</code> + Prepared Statement で SQL Injection 防御</li><li>PHP コードを文字列に埋めるなら <code><?php</code> / <code>?></code> を <code>&lt;?php</code> 化、または heredoc/nowdoc を使う</li></ul></td></tr></table>
<h2>ダブルクォート vs シングルクォートの違い</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>エスケープ</th><th>シングル <code>'...'</code></th><th>ダブル <code>"..."</code></th><th>意味</th></tr></thead>
<tbody>
<tr><td><code>\n</code></td><td>そのまま \n</td><td>改行 (LF)</td><td>Line Feed (0x0A)</td></tr>
<tr><td><code>\r</code></td><td>そのまま \r</td><td>キャリッジリターン</td><td>CR (0x0D)</td></tr>
<tr><td><code>\t</code></td><td>そのまま \t</td><td>水平タブ</td><td>0x09</td></tr>
<tr><td><code>\v</code></td><td>そのまま</td><td>垂直タブ</td><td>0x0B</td></tr>
<tr><td><code>\f</code></td><td>そのまま</td><td>改ページ</td><td>0x0C</td></tr>
<tr><td><code>\0</code></td><td>そのまま</td><td>ヌル文字</td><td>0x00</td></tr>
<tr><td><code>\\</code></td><td>バックスラッシュ</td><td>バックスラッシュ</td><td>両方OK</td></tr>
<tr><td><code>\'</code></td><td>シングルクォート</td><td>そのまま \'</td><td>-</td></tr>
<tr><td><code>\"</code></td><td>そのまま \"</td><td>ダブルクォート</td><td>-</td></tr>
<tr><td><code>\$</code></td><td>そのまま \$</td><td>$ 記号(変数展開抑止)</td><td>-</td></tr>
<tr><td><code>\xNN</code></td><td>そのまま</td><td>16進文字 (例 \x41 → A)</td><td>-</td></tr>
<tr><td><code>\NNN</code></td><td>そのまま</td><td>8進文字</td><td>-</td></tr>
<tr><td><code>\u{NNNN}</code></td><td>そのまま</td><td>Unicode (PHP 7+)</td><td>例 \u{1F600} → 😀</td></tr>
</tbody>
</table>

<h2>具体例</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// シングルクォート: \n はそのまま文字
echo &apos;Hello\nWorld&apos;;
// → Hello\nWorld (改行されない)

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

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

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

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

// 16進文字
echo "\x41\x42\x43";   // ABC</code></pre>
<h2>heredoc と nowdoc</h2>

<p>複数行の文字列リテラルは heredoc / nowdoc がベター:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">$name = &apos;Taro&apos;;

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

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

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

<p>ユーザー入力をそのまま HTML に出すと XSS。必ず <code>htmlspecialchars()</code>:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// ❌ XSS 脆弱
echo "<p>Hello, $name</p>";
// $name = "<script>alert(1)</script>" だと実行される

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

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

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

// htmlentities - htmlspecialchars + 全文字エンティティ化(重い、通常不要)
echo htmlentities(&apos;é&apos;, ENT_QUOTES, &apos;UTF-8&apos;);   // &eacute;</code></pre>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e8f5e9"><th>文字</th><th>エスケープ後</th></tr></thead>
<tbody>
<tr><td><code>&</code></td><td><code>&amp;</code></td></tr>
<tr><td><code><</code></td><td><code>&lt;</code></td></tr>
<tr><td><code>></code></td><td><code>&gt;</code></td></tr>
<tr><td><code>"</code></td><td><code>&quot;</code></td></tr>
<tr><td><code>&apos;</code></td><td><code>&#039;</code> (ENT_QUOTES)</td></tr>
</tbody>
</table>

<h2>SQL Injection 対策 (PDO Prepared Statement)</h2>

<p><strong>絶対に文字列連結で SQL を組まない</strong>のが鉄則:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// ❌ SQL Injection 脆弱
$id = $_GET[&apos;id&apos;];   // "1 OR 1=1"
$pdo->query("SELECT * FROM users WHERE id = $id");

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

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

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

// LIKE 句のワイルドカードエスケープ
$keyword = str_replace([&apos;\\&apos;, &apos;%&apos;, &apos;_&apos;], [&apos;\\\\&apos;, &apos;\\%&apos;, &apos;\\_&apos;], $keyword);
$stmt = $pdo->prepare("SELECT * FROM logs WHERE msg LIKE ? ESCAPE &apos;\\\\&apos;");
$stmt->execute(["%{$keyword}%"]);</code></pre>
<h2>JSON / URL エスケープ</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// JSON
$arr = [&apos;name&apos; => &apos;Taro&apos;, &apos;msg&apos; => &apos;Hello "World"&apos;];
echo json_encode($arr);                  // {"name":"Taro","msg":"Hello \"World\""}
echo json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);

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

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

// パラメータ全部
$params = [&apos;q&apos; => $keyword, &apos;page&apos; => 2];
$url = &apos;https://example.com/search?&apos; . http_build_query($params);</code></pre>
<h2>非推奨: addslashes / stripslashes / Magic Quotes</h2>

<p>古い記事で出てくる <code>addslashes</code> 系は<strong>もう使わない</strong>でください:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// ❌ 非推奨(古い解説に出てくる)
$safe = addslashes($input);    // &apos; " \ \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</code></pre>
<h2>PHP コードを文字列に埋めたいとき</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// nowdoc が最強(変数展開もエスケープも不要)
$snippet = <<<&apos;PHP&apos;
<?php
$name = $_POST[&apos;name&apos;] ?? &apos;&apos;;
echo htmlspecialchars($name);
PHP;

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

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

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

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