# ch04 — `$_POST` でフォームデータを受け取る

Source: https://php-school.pages.dev/topics/web/ch04-post-params/
Site: AIと学ぶPHPの学校 (https://php-school.pages.dev)
Lesson: Web アプリ入門
Level: L4

Reference (official): https://www.php.net/manual/ja/reserved.variables.request.php

## 本文

# ch04 — `$_POST` でフォームデータを受け取る

## 概要

GET が「URL に値が乗る通信」だったのに対し、**POST はリクエスト本文 (Body) に値が乗る通信**。`<form method="post">` で送信ボタンを押すと、ブラウザは値を URL ではなく Body に詰めてサーバーに送る。PHP では **`$_POST` 連想配列** から取り出す。使い方は `$_GET` とほぼ同じ。

使い分けの基準はシンプルに **取得 → GET / 送信・更新 → POST**。検索結果のように何度開いても結果が変わらないものは GET、ログインやコメント投稿のように「サーバーに記録させる」操作は POST、と分けるのが Web の作法。GET は履歴やブックマークに URL ごと残るので、パスワード送信に GET を使うのは事故のもと。

POST の Body のフォーマットは `application/x-www-form-urlencoded` (普通のテキストフォーム) と `multipart/form-data` (ファイル添付があるとき) の 2 種類。普段のフォームは前者で、Body に `key=value&key=value` の文字列が乗っているだけ。後者はファイルアップロードを扱う `file-io/ch06` で再登場する。

## 学習目標

- `$_POST` でフォームの **method=post** で送られた値を受け取れる
- GET と POST の **使い分け** (取得 vs 送信) を説明できる
- 採点用に **stdin から query string を `parse_str` で `$_POST` に組み立てる** 書き方を知る

## 所要時間

スライド 5 分 + ドリル 2 問 = **20 分**

## ドリル

| no | 内容 |
|---|---|
| 01 | `message=Hello` を受け取り `"受信: Hello"` を出力 |
| 02 | `name=太郎&email=taro@example.com` を受け取り `"登録: 太郎 / taro@example.com"` を出力 |

## 本物の Web で確認したい場合

POST はブラウザのアドレスバーから送れないので、フォーム送信か curl を使う:

```bash
cd topics/web/ch04-post-params/drill/01-post-message/
php -S localhost:8000 answer.php
```

別ターミナルで:

```bash
curl -X POST -d "message=Hello" http://localhost:8000/
```

## スライド

---
marp: true
theme: dojo
paginate: true
size: 16:9
---

<!--
LLM_CONTEXT:
  Lesson 12 / Chapter 4
  目的: $_POST でフォームから送られた値を受け取る / GET と POST の使い分け
  扱わない: form の HTML 作り方 (ch05) / ルーティング (ch06) / CSRF 対策
  読み上げ時間目安: 4 分半
-->

# `$_POST` でフォームを受け取る

Lesson 12 / Chapter 4

---

## `$_POST` は **本文 (body)** から来る

GET: 値は URL の後ろ (見える)

```
GET /register?name=太郎 HTTP/1.1
```

POST: 値はリクエストの **本文** (URL には乗らない)

```
POST /register HTTP/1.1
Content-Type: application/x-www-form-urlencoded

name=太郎
```

PHP は **本文の中身を `$_POST` 連想配列に分解** して渡してくれる。

---

## GET と POST の使い分け

| 用途 | 推奨 | 理由 |
|---|---|---|
| 検索ページ | **GET** | URL を共有できる / ブックマークできる |
| 一覧の絞り込み | **GET** | 結果ページを再現可能 |
| 新規登録 / 投稿 | **POST** | URL に個人情報が残らない / 履歴・キャッシュに乗らない |
| 削除 / 編集 | **POST** | 副作用がある操作はリロードで重複しないように |

**原則**: 「**取得は GET、副作用 (DB を書き換える) は POST**」。

---

## 受け取り方は `$_GET` と同じ

```php
<?php
$msg = $_POST['message'] ?? '';
echo "受信: {$msg}\n";
```

- `$_POST` は **連想配列** ($_GET と同じ構造)
- 値は **文字列** ($_GET と同じ)
- 欠落時の保険として `??` を使うのも同じ

→ 違うのは「**どっち経由で来たか**」だけ。コード側のアクセス方法は揃っている。

---

## 採点用スタブ: stdin で `$_POST` を埋める

```php
<?php
// 採点用: 標準入力の 1 行 (例 "message=Hello") を $_POST に展開
$query = trim(fgets(STDIN) ?: '');
parse_str($query, $_POST);

$msg = $_POST['message'] ?? '';
echo "受信: {$msg}\n";
```

- `$_GET` のときと同じく `parse_str` で文字列を連想配列に分解
- 違うのは展開先が `$_POST` であること
- 本物の Web では PHP が自動で `$_POST` を埋める

---

## どっちが入っているか確認するには `REQUEST_METHOD`

```php
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $msg = $_POST['message'] ?? '';
    echo "POST 受信: {$msg}\n";
} else {
    echo "GET アクセス (form を表示)\n";
}
```

- 1 つの URL で **GET と POST 両方** を捌くのが Web の典型 (ch06 でやる)
- `REQUEST_METHOD` を見て分岐するのが定石

---

## このチャプターでできるようになること

✅ `$_POST` でフォーム値を受け取れる
✅ GET と POST の使い分けを言える
✅ `parse_str` で stdin の文字列を `$_POST` にも展開できる
✅ `REQUEST_METHOD` で GET / POST を区別できると知っている

→ ドリルへ
