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

タイトル: $_POST
SEOタイトル: PHP $_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>$_POST</strong> は <code><form method="post"></code> から送信されたデータが入る連想配列型のスーパーグローバル変数</li><li><code>$_POST["name"]</code> でアクセス。<strong>未定義キー</strong>には <code>isset()</code> または <code>?? null</code> で防御</li><li>XSS / SQL Injection / CSRF を必ず対策。<strong>htmlspecialchars</strong> / <strong>PDO Prepared</strong> / <strong>CSRF Token</strong> が三種の神器</li><li>JSON / multipart は <code>$_POST</code> に入らない場合がある → <code>php://input</code> や <code>$_FILES</code> で取得</li><li>Laravel では <code>$request->input("name")</code> や <code>$request->validated()</code> が定石</li></ul></td></tr></table>
<h2>$_POST とは</h2>

<p>PHP の<strong>スーパーグローバル変数</strong>の 1 つで、HTTP POST リクエストで送信された値が<strong>連想配列</strong>として格納されています。スーパーグローバルなので、<strong>関数の中でも <code>global</code> 宣言不要</strong>でアクセスできます。</p>

<h2>HTML フォームと $_POST の対応</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!-- form.html -->
<form method="post" action="/register.php">
    <input type="text"     name="username">
    <input type="email"    name="email">
    <input type="password" name="password">
    <input type="checkbox" name="agree" value="1">
    <select name="role">
        <option value="user">一般</option>
        <option value="admin">管理者</option>
    </select>
    <button type="submit">登録</button>
</form></code></pre><p><img alt="POST フォームの例" src="/uploadImage/20170809014116_2945120.jpg" style="max-width:640px;width:100%;height:auto;border:1px solid #ccc;border-radius:4px"></p>
<p>↑ HTML フォーム例(上記のような POST フォームを想定)。送信先 <code>register.php</code> での受け取り:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
// register.php
var_dump($_POST);
/*
array(5) {
  ["username"] => string(4) "Taro"
  ["email"]    => string(13) "taro@test.com"
  ["password"] => string(8) "secret12"
  ["agree"]    => string(1) "1"
  ["role"]     => string(4) "user"
}
*/

$username = $_POST[&apos;username&apos;];
$email    = $_POST[&apos;email&apos;];</code></pre><p><img alt="$_POST で取得した値の確認" src="/uploadImage/20170809014405_4709410.jpg" style="max-width:640px;width:100%;height:auto;border:1px solid #ccc;border-radius:4px"></p>
<p>↑ 受信側 PHP で <code>$_POST</code> の中身を確認したイメージ。<code>var_dump</code> や <code>print_r</code> で連想配列の内容が見えます。</p>

<h2>未定義キー対策</h2>

<p>checkbox が未チェック / select が未選択だと、そのキー自体が <code>$_POST</code> に<strong>存在しない</strong>。直接アクセスすると Warning:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// ❌ Warning: Undefined array key "agree"
$agree = $_POST[&apos;agree&apos;];

// ✅ isset で防御
$agree = isset($_POST[&apos;agree&apos;]) ? $_POST[&apos;agree&apos;] : &apos;0&apos;;

// ✅ Null Coalescing (PHP 7+)
$agree = $_POST[&apos;agree&apos;] ?? &apos;0&apos;;

// ✅ filter_input
$agree = filter_input(INPUT_POST, &apos;agree&apos;, FILTER_VALIDATE_INT);

// 推奨: バリデーション関数にまとめる
function postInput(string $key, string $default = &apos;&apos;): string {
    return isset($_POST[$key]) ? trim((string)$_POST[$key]) : $default;
}
$username = postInput(&apos;username&apos;);</code></pre>
<h2>セキュリティ対策の三種の神器</h2>

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

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

// ✅ htmlspecialchars で対策
echo &apos;<p>&apos; . htmlspecialchars($comment, ENT_QUOTES, &apos;UTF-8&apos;) . &apos;</p>&apos;;</code></pre>
<h3>2. SQL Injection 対策</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// ❌ SQL Injection 脆弱
$email = $_POST[&apos;email&apos;];
$pdo->query("SELECT * FROM users WHERE email = &apos;$email&apos;");

// ✅ PDO Prepared Statement
$stmt = $pdo->prepare(&apos;SELECT * FROM users WHERE email = ?&apos;);
$stmt->execute([$_POST[&apos;email&apos;]]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);

// ✅ 名前付きバインド
$stmt = $pdo->prepare(&apos;INSERT INTO users (name, email) VALUES (:n, :e)&apos;);
$stmt->execute([
    &apos;:n&apos; => $_POST[&apos;username&apos;],
    &apos;:e&apos; => $_POST[&apos;email&apos;],
]);</code></pre>
<h3>3. CSRF 対策</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">session_start();

// トークン生成(フォーム表示時)
if (empty($_SESSION[&apos;csrf_token&apos;])) {
    $_SESSION[&apos;csrf_token&apos;] = bin2hex(random_bytes(32));
}
$token = $_SESSION[&apos;csrf_token&apos;];

// HTML 側
// <input type="hidden" name="_token" value="<?= $token ?>">

// 受信時に検証
if (!hash_equals($_SESSION[&apos;csrf_token&apos;] ?? &apos;&apos;, $_POST[&apos;_token&apos;] ?? &apos;&apos;)) {
    http_response_code(419);
    die(&apos;CSRF token mismatch&apos;);
}</code></pre>
<h2>$_POST に入らないケース</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#fff3e0"><th>ケース</th><th>取得方法</th></tr></thead>
<tbody>
<tr><td>JSON ボディ(<code>Content-Type: application/json</code>)</td><td><code>json_decode(file_get_contents("php://input"), true)</code></td></tr>
<tr><td>ファイルアップロード(<code>multipart/form-data</code>)</td><td><code>$_FILES</code></td></tr>
<tr><td>PUT / DELETE / PATCH リクエスト</td><td><code>php://input</code> から自前パース</td></tr>
<tr><td>カスタム Content-Type</td><td><code>php://input</code></td></tr>
<tr><td><code>post_max_size</code> 超過</td><td>空になる + warning。php.ini で <code>post_max_size</code> 拡大</td></tr>
</tbody>
</table>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// JSON 受信
$raw  = file_get_contents(&apos;php://input&apos;);
$data = json_decode($raw, true);
if (!is_array($data)) {
    http_response_code(400);
    die(&apos;Invalid JSON&apos;);
}
$username = $data[&apos;username&apos;] ?? &apos;&apos;;

// ファイルアップロード
if ($_FILES[&apos;avatar&apos;][&apos;error&apos;] === UPLOAD_ERR_OK) {
    move_uploaded_file(
        $_FILES[&apos;avatar&apos;][&apos;tmp_name&apos;],
        __DIR__ . &apos;/uploads/&apos; . basename($_FILES[&apos;avatar&apos;][&apos;name&apos;])
    );
}</code></pre>
<h2>$_POST vs $_GET 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>用途</th></tr></thead>
<tbody>
<tr><td><code>$_GET</code></td><td>URL クエリ文字列 (<code>?key=val</code>)</td><td>検索・ページング・冪等な参照</td></tr>
<tr><td><code>$_POST</code></td><td>POST ボディ (<code>application/x-www-form-urlencoded</code>)</td><td>登録・更新・削除</td></tr>
<tr><td><code>$_REQUEST</code></td><td>GET + POST + COOKIE 混合</td><td>★ 非推奨。意図不明になる</td></tr>
<tr><td><code>$_FILES</code></td><td>multipart アップロード</td><td>ファイル受信</td></tr>
<tr><td><code>$_COOKIE</code></td><td>クッキー</td><td>セッション識別等</td></tr>
<tr><td><code>$_SERVER</code></td><td>サーバ環境変数</td><td>REMOTE_ADDR 等</td></tr>
</tbody>
</table>

<h2>filter_input でバリデーション</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 整数
$age = filter_input(INPUT_POST, &apos;age&apos;, FILTER_VALIDATE_INT, [
    &apos;options&apos; => [&apos;min_range&apos; => 0, &apos;max_range&apos; => 150]
]);
if ($age === false) {
    die(&apos;年齢が不正&apos;);
}

// メール
$email = filter_input(INPUT_POST, &apos;email&apos;, FILTER_VALIDATE_EMAIL);
if ($email === false) {
    die(&apos;メール形式不正&apos;);
}

// URL
$url = filter_input(INPUT_POST, &apos;url&apos;, FILTER_VALIDATE_URL);

// 配列も一括フィルタ
$data = filter_input_array(INPUT_POST, [
    &apos;name&apos;  => FILTER_DEFAULT,
    &apos;age&apos;   => FILTER_VALIDATE_INT,
    &apos;email&apos; => FILTER_VALIDATE_EMAIL,
]);</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">use Illuminate\Http\Request;

public function store(Request $request)
{
    // 個別取得
    $name = $request->input(&apos;name&apos;);
    $age  = $request->input(&apos;age&apos;, 0);      // デフォルト値

    // 一括取得
    $all = $request->all();
    $sub = $request->only([&apos;name&apos;, &apos;email&apos;]);
    $exc = $request->except([&apos;password&apos;]);

    // バリデーション
    $validated = $request->validate([
        &apos;name&apos;     => &apos;required|string|max:100&apos;,
        &apos;email&apos;    => &apos;required|email|unique:users&apos;,
        &apos;password&apos; => &apos;required|min:8|confirmed&apos;,
    ]);

    User::create($validated);
}

// FormRequest クラスでバリデーション分離(推奨)
class StoreUserRequest extends FormRequest {
    public function rules(): array {
        return [
            &apos;name&apos;  => &apos;required|string|max:100&apos;,
            &apos;email&apos; => &apos;required|email|unique:users&apos;,
        ];
    }
}</code></pre>
<h2>FAQ</h2>

<p><strong>Q: <code>$_POST</code> が空になる</strong><br />
A: <code>enctype="multipart/form-data"</code> でもキー名が一致していれば入ります。<code>post_max_size</code> 超過 / <code>Content-Type</code> 違い / <code>php://input</code> を既に読んだ後だと空になることも。</p>

<p><strong>Q: 配列キーで送信したい</strong><br />
A: <code><input name="items[]"></code> や <code><input name="user[name]"></code> で <code>$_POST["items"]</code> や <code>$_POST["user"]["name"]</code> として受け取れます。</p>

<p><strong>Q: 受信した値の型は?</strong><br />
A: 基本<strong>すべて文字列</strong>。数値も <code>"123"</code> として入る。型変換は自前で <code>(int)$_POST["age"]</code> 等。</p>

<p><strong>Q: Magic Quotes でクォートに <code>\</code> が付く</strong><br />
A: PHP 5.4 で廃止済み。古い環境なら <code>stripslashes()</code> で除去。</p>