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

タイトル: $_GET
SEOタイトル: PHP $_GET スーパーグローバル変数完全ガイド(XSS / SQL Injection 対策・$_POST との違い)

この本文には実行可能なタグ等が含まれるため、安全のため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>$_GET</strong> は URL クエリパラメータを受け取る PHP のスーパーグローバル変数 (連想配列)</li><li>アクセス: <code>$_GET["name"]</code>、存在確認は <code>isset($_GET["name"])</code> または <code>$_GET["name"] ?? null</code></li><li><strong>XSS 対策</strong>に <code>htmlspecialchars()</code>、<strong>SQL Injection 対策</strong>に Prepared Statement (PDO)</li><li>$_POST との違い: $_GET は URL に露出 → 検索系・パーマリンク向き、$_POST は本文 → 機密 / 大きいデータ向き</li><li>配列パラメータ <code>?ids[]=1&ids[]=2</code> は <code>$_GET["ids"]</code> が配列になる。Laravel は <code>$request->input("x")</code></li></ul></td></tr></table>
<h2>$_GET の基本</h2>

<p>PHP の<strong>$_GET</strong> は、URL のクエリストリング(<code>?key=value&key2=value2</code>)から渡された値を受け取るための<strong>スーパーグローバル連想配列</strong>です。フォームを <code>method="GET"</code> で送信したとき、または直接 URL にパラメータを付けたときに自動で埋まります。</p>
<p><img alt="PHP $_GET の動作イメージ" src="/uploadImage/20170808180944_5803841.jpg" style="max-width:640px;width:100%;height:auto;border:1px solid #ccc;border-radius:4px"></p>
<h2>基本的な使い方</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
// URL: https://example.com/page.php?name=taro&age=20

// 値の取得
$name = $_GET[&apos;name&apos;]; // &apos;taro&apos;
$age  = $_GET[&apos;age&apos;];  // &apos;20&apos; (文字列であることに注意)

// 未定義キーアクセス警告を回避 (PHP 7+)
$name = $_GET[&apos;name&apos;] ?? &apos;&apos;;

// 存在確認
if (isset($_GET[&apos;name&apos;])) {
    echo &apos;こんにちは &apos; . $name . &apos; さん&apos;;
}

// 全件確認
print_r($_GET);
// Array ( [name] => taro [age] => 20 )</code></pre><p><img alt="GET フォーム送信例" src="/uploadImage/20170808180952_5039940.jpg" style="max-width:640px;width:100%;height:auto;border:1px solid #ccc;border-radius:4px"></p>
<h2>フォームから $_GET に送る</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!-- search.html -->
<form action="/search.php" method="GET">
    <input type="text" name="keyword" placeholder="検索キーワード">
    <select name="category">
        <option value="all">全て</option>
        <option value="news">ニュース</option>
        <option value="blog">ブログ</option>
    </select>
    <button type="submit">検索</button>
</form>

<!-- 送信後の URL: /search.php?keyword=PHP&category=news --></code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
// search.php
$keyword  = $_GET[&apos;keyword&apos;]  ?? &apos;&apos;;
$category = $_GET[&apos;category&apos;] ?? &apos;all&apos;;

echo &apos;キーワード: &apos; . htmlspecialchars($keyword) . &apos;<br>&apos;;
echo &apos;カテゴリ: &apos;  . htmlspecialchars($category);</code></pre>
<h2>セキュリティ: 必ずやること</h2>

<p>$_GET の値は<strong>すべて信用してはいけません</strong>。URL は誰でも書き換えられるため、検証とエスケープを必ず行います。</p>

<h3>XSS 対策(HTML 出力時)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
$name = $_GET[&apos;name&apos;] ?? &apos;&apos;;

// ❌ 危険: そのまま出力 → <script> タグを埋め込まれる可能性
echo &apos;こんにちは &apos; . $name;

// ✅ HTML エスケープ
echo &apos;こんにちは &apos; . htmlspecialchars($name, ENT_QUOTES, &apos;UTF-8&apos;);

// ❌ 古い書き方は ENT_QUOTES 必須
echo htmlspecialchars($name); // &apos; をエスケープしない設定があり危険

// ✅ ショートカット関数を作る
function h(string $s): string {
    return htmlspecialchars($s, ENT_QUOTES | ENT_HTML5, &apos;UTF-8&apos;);
}
echo &apos;こんにちは &apos; . h($name);</code></pre>
<h3>SQL Injection 対策(DB クエリ時)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
// ❌ 絶対やってはいけない: 文字列連結
$id = $_GET[&apos;id&apos;];
$sql = "SELECT * FROM users WHERE id = $id"; // ?id=1 OR 1=1 で全件流出

// ✅ PDO の Prepared Statement
$pdo = new PDO(&apos;mysql:host=localhost;dbname=app&apos;, &apos;user&apos;, &apos;pass&apos;);
$stmt = $pdo->prepare(&apos;SELECT * FROM users WHERE id = :id&apos;);
$stmt->execute([&apos;:id&apos; => $_GET[&apos;id&apos;]]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);

// ✅ mysqli の場合
$mysqli = new mysqli(&apos;localhost&apos;, &apos;user&apos;, &apos;pass&apos;, &apos;app&apos;);
$stmt = $mysqli->prepare(&apos;SELECT * FROM users WHERE id = ?&apos;);
$stmt->bind_param(&apos;i&apos;, $_GET[&apos;id&apos;]); // &apos;i&apos; = integer
$stmt->execute();</code></pre>
<h3>型検証とサニタイズ</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
// filter_input でフィルタリング
$id = filter_input(INPUT_GET, &apos;id&apos;, FILTER_VALIDATE_INT);
if ($id === false || $id === null) {
    die(&apos;id is required and must be int&apos;);
}

// メール形式チェック
$email = filter_input(INPUT_GET, &apos;email&apos;, FILTER_VALIDATE_EMAIL);

// URL 形式チェック
$url = filter_input(INPUT_GET, &apos;url&apos;, FILTER_VALIDATE_URL);

// 文字列のサニタイズ (PHP 8.1+ では SANITIZE_STRING は非推奨)
// → htmlspecialchars / strip_tags を明示的に使う
$name = strip_tags($_GET[&apos;name&apos;] ?? &apos;&apos;);
$name = htmlspecialchars($name, ENT_QUOTES, &apos;UTF-8&apos;);</code></pre>
<h2>$_GET vs $_POST vs $_REQUEST</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>変数</th><th>送信元</th><th>URL に露出</th><th>主な用途</th></tr></thead>
<tbody>
<tr><td>$_GET</td><td>URL クエリ ?key=value</td><td>★ する</td><td>検索 / フィルター / パーマリンク</td></tr>
<tr><td>$_POST</td><td>リクエストボディ (form / JSON)</td><td>しない</td><td>ログイン / 登録 / 機密データ</td></tr>
<tr><td>$_REQUEST</td><td>$_GET + $_POST + $_COOKIE</td><td>—</td><td>非推奨。明示的に GET/POST を使う</td></tr>
<tr><td>$_FILES</td><td>multipart/form-data の添付</td><td>—</td><td>ファイルアップロード</td></tr>
</tbody>
</table>

<p><strong>使い分け</strong>:</p>

<ul>
<li>検索結果ページのように<strong>URL を共有・ブックマーク</strong>させたい → $_GET</li>
<li>パスワード / 個人情報 / 大きいデータ → <strong>必ず $_POST</strong>(URL に出ない)</li>
<li>RESTful API では GET=取得 / POST=作成 / PUT=更新 / DELETE=削除 と動詞を分ける</li>
</ul>

<h2>URL エンコーディング</h2>

<p>URL に直接書けない文字(日本語 / スペース / & / # など)は<strong>URL エンコード</strong>します。$_GET はデコード済みの値を返します。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
// 送信側で URL を作る
$keyword = &apos;東京 PHP & MySQL&apos;;
$url = &apos;/search.php?keyword=&apos; . urlencode($keyword);
// /search.php?keyword=%E6%9D%B1%E4%BA%AC+PHP+%26+MySQL

// 受信側 ($_GET) は自動デコード
$keyword = $_GET[&apos;keyword&apos;]; // &apos;東京 PHP & MySQL&apos;

// 複数パラメータをまとめる
$params = [&apos;name&apos; => &apos;太郎&apos;, &apos;age&apos; => 25, &apos;city&apos; => &apos;東京&apos;];
$url = &apos;/page.php?&apos; . http_build_query($params);
// /page.php?name=%E5%A4%AA%E9%83%8E&age=25&city=%E6%9D%B1%E4%BA%AC</code></pre>
<h2>配列パラメータ</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
// URL: /page.php?ids[]=1&ids[]=2&ids[]=3
print_r($_GET[&apos;ids&apos;]);
// Array ( [0] => 1 [1] => 2 [2] => 3 )

// URL: /page.php?user[name]=taro&user[age]=20
print_r($_GET[&apos;user&apos;]);
// Array ( [name] => taro [age] => 20 )

// チェックボックスを配列で受け取る
// <input type="checkbox" name="tags[]" value="php">
// <input type="checkbox" name="tags[]" value="js">
$tags = $_GET[&apos;tags&apos;] ?? [];
foreach ($tags as $tag) {
    echo h($tag) . &apos; &apos;;
}</code></pre>
<h2>Laravel での同等処理</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
// Laravel Controller
public function search(Request $request)
{
    // GET ?keyword=PHP
    $keyword = $request->input(&apos;keyword&apos;); // 推奨
    $keyword = $request->query(&apos;keyword&apos;); // GET のみに限定
    $keyword = $request->get(&apos;keyword&apos;);   // input のエイリアス

    // 配列
    $ids = $request->input(&apos;ids&apos;, []); // [1, 2, 3]

    // バリデーション
    $validated = $request->validate([
        &apos;keyword&apos; => &apos;required|string|max:100&apos;,
        &apos;page&apos;    => &apos;integer|min:1&apos;,
    ]);

    return view(&apos;search&apos;, $validated);
}</code></pre>
<h2>$_GET の長さ制限</h2>

<ul>
<li>URL 全体の長さは<strong>ブラウザ / サーバが個別に制限</strong>。実務上の上限は <strong>2,000 バイト前後</strong></li>
<li>Apache: <code>LimitRequestLine</code> 既定 8190 バイト</li>
<li>Nginx: <code>large_client_header_buffers</code> 既定 8K</li>
<li>長くなる場合は <strong>$_POST に変更</strong>するか、ID を渡してサーバ側で展開</li>
</ul>

<h2>FAQ</h2>

<p><strong>Q: $_GET の値はすべて文字列?</strong><br />
A: はい。数字も文字列として届きます。整数比較したいときは <code>(int)$_GET["age"]</code> でキャストするか <code>filter_input(INPUT_GET, "age", FILTER_VALIDATE_INT)</code>。</p>

<p><strong>Q: GET でログインフォームを作るのは?</strong><br />
A: <strong>絶対 NG</strong>。URL にパスワードが残り、履歴・アクセスログに出ます。ログインは必ず POST + HTTPS。</p>

<p><strong>Q: $_GET と <code>filter_input</code> どちらを使う?</strong><br />
A: 単純な取得は $_GET、型検証・サニタイズを兼ねたいなら filter_input。バリデーション込みなら Laravel の Request 推奨。</p>