# PHPの処理起点とファイル構成 解説
## 対象：社内Web開発初心者向け（PHP / HTML）

---

## 1. submitボタンを押したとき、何が起きているか

`$_SERVER['REQUEST_METHOD']` が処理を「開始」するわけではありません。
PHPファイルは **常に1行目から順番に実行** されます。
`$_SERVER` はその途中で「読む」だけです。

### 処理の流れ

```
① ブラウザ
   submitボタンを押す
       ↓
② ブラウザ → サーバー
   HTTPリクエストを送信（GET または POST）
       ↓
③ Apache（XAMPPのWebサーバー）
   リクエストを受け取り、対象の .php ファイルを実行開始
       ↓
④ PHP
   ファイルを【1行目から順番に】実行する
   このとき $_SERVER は PHP が自動で用意済み
       ↓
⑤ if ($_SERVER['REQUEST_METHOD'] === 'POST') に到達
   → 値を「読んで」分岐するだけ。ここが起点ではない
```

### C# との対比

| PHP | C# WebForms 相当 |
|-----|-----------------|
| PHPファイルが1行目から実行される | `Page_Load()` が呼ばれる |
| `if ($method === 'POST')` で手動分岐 | `if (!IsPostBack)` で分岐 |
| イベントハンドラは存在しない | `Button1_Click()` などのイベントがある |

> **PHPにはボタンに紐づくイベントハンドラがありません。**
> `$_SERVER` の値を `if` で読んで自分で分岐するのがPHPの流儀です。

---

## 2. 「操作の検知」手段

PHPはサーバー側言語なので「画面操作でリアルタイムにイベント発生」という概念がありません。
操作を検知する方法は以下の2系統です。

---

### ① PHP側（サーバーへのリクエスト単位で検知）

ページ全体の再読み込みを伴います。フォームのsubmit等が該当します。

```php
// フォームのsubmit方法の判定
$_SERVER['REQUEST_METHOD'] === 'POST'  // POSTで来た（登録・更新・削除）
$_SERVER['REQUEST_METHOD'] === 'GET'   // GETで来た（検索・表示）

// 特定のボタンが押されたかを hidden 項目で判定
$_POST['action'] === 'delete'          // 削除ボタン
$_POST['action'] === 'restore'         // 復活ボタン

// GETパラメータで状態を判定
$_GET['searched'] === '1'              // 検索ボタンが押された後か
```

---

### ② JavaScript側（画面上のリアルタイム操作を検知）

ページ再読み込みなしに動作します。PHPと組み合わせて使います。

```javascript
// ボタンクリック
document.getElementById('btn').addEventListener('click', () => { ... });

// セレクトボックスの選択変更
document.getElementById('view_kbn').addEventListener('change', () => { ... });

// フォーム送信前の確認ダイアログ（今回のコードでも使われている）
onsubmit="return confirm('削除します。よろしいですか？')"
```

#### JavaScriptで検知した結果をPHPに渡すパターン（Ajax）

```
① 画面でJSイベント発生（クリック等）
       ↓
② JS が fetch() で PHP にリクエスト送信（画面遷移なし）
       ↓
③ PHP が処理してJSONを返す
       ↓
④ JS がレスポンスを受け取って画面の一部だけ更新
```

> **初学者の学習順序としては**、フォームsubmit → 画面遷移のシンプルな構成を
> 完全に理解してから、Ajaxへ進むことを推奨します。

---

## 3. PHPファイルの構成順序（ベストプラクティス）

### 鉄則：「HTMLを1文字も出力する前に、すべての処理を終わらせる」

```php
<?php
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【ロジック層】HTML出力より必ず前に書く
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// ① 型宣言（必ずファイル先頭の1行目）
declare(strict_types=1);

// ② 外部ファイル読み込み（設定・関数の準備）
require_once __DIR__ . '/../config/app.php';
require_once __DIR__ . '/../common/auth.php';
require_once __DIR__ . '/../common/functions.php';

// ③ 認証チェック（未ログインなら redirect → ここで処理が止まる）
requireLogin();

// ④ DB接続（以降のロジックで使うため早めに確保）
$pdo = getTenantDb();

// ⑤ 変数の初期化（入力値受け取り・デフォルト設定）
$tokuiManage = get_string('tokui_manage');
$error       = '';
$rows        = [];

// ⑥ POST処理（更新・削除・登録）← 処理後に redirect() で終わる
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // ...
    redirect('/master/tokui_list.php?message=' . urlencode('削除しました。'));
    // ↑ redirect() の内部で exit() が呼ばれ、以降は実行されない
}

// ⑦ GET処理（画面表示用データの取得）
if ($searched === '1') {
    // SELECT ... DB検索
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【ビュー層】ここからHTML出力開始
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
?>
<!doctype html>
<html lang="ja">
...
```

---

### なぜこの順序が鉄則なのか

`redirect()` の内部では PHP の `header()` 関数を使っています。

```php
function redirect($url) {
    header('Location: ' . $url);  // HTTPレスポンスヘッダーを送信
    exit();                        // 以降の処理をすべて止める
}
```

`header()` は **HTMLを1文字でも出力した後には呼べません**。
これはHTTPの仕様上、ヘッダーはボディ（HTML）より先に送る必要があるためです。

```php
// ✅ 正しい順序
// まだ何も出力していない状態
header('Location: /list.php');  // OK → リダイレクトできる

// ❌ アウト（エラーになる）
echo '<html>...';               // HTML出力してしまった
header('Location: /list.php');  // エラー: "Cannot modify header information"
```

#### C# との対比

| PHP | C# ASP.NET |
|-----|-----------|
| HTML出力前に `header()` 必須 | `Response.Redirect()` も出力前が必須（同じ制約） |
| `?>` の前にすべてのロジックを書く | `Page_Load()` 内にすべてのロジックを書く |

---

### POST処理を GET処理より先に書く理由

```php
// ⑥ POST処理を先に書く
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 処理 → redirect() → ここで終了（exitされる）
}

// ⑦ POST で来た場合、ここには到達しない
// GET で来た場合のみ、ここが実行される
if ($searched === '1') {
    // 検索処理
}
```

POSTの場合は `redirect()` 内部の `exit()` で処理が止まるため、
GET用の検索処理には到達しません。
この前後関係を利用することで `else` を書かずにすっきり記述できます。

---

## 4. まとめ：PHPファイルの構成テンプレート

```
【ロジック層：HTMLを出力する前にすべて完了させる】

  declare(strict_types=1)          ← ファイル先頭に固定
       ↓
  require_once 群                  ← 設定・関数の読み込み
       ↓
  requireLogin()                   ← 認証（通らなければここで終了）
       ↓
  DB接続・変数の初期化              ← $pdo / $error / $rows = ...
       ↓
  POST処理                         ← 更新・登録・削除（redirect で脱出）
  if (REQUEST_METHOD === 'POST') { ... redirect(); }
       ↓
  GET処理（表示用データ取得）       ← SELECT など
  if ($searched === '1') { ... }
       ↓
【ビュー層：ここから先はHTML出力のみ】

  ?>
  <!doctype html>
  <html> ... </html>
```

---

## 5. よくある誤りと対策

| 誤り | 問題 | 対策 |
|------|------|------|
| HTML出力後に `redirect()` を呼ぶ | `header()` エラーが発生する | ロジックを `?>` より前に移動する |
| POST後に `redirect()` せずそのまま表示 | F5で処理が再実行される | 必ず `redirect()`（PRGパターン） |
| `$_POST` をそのままSQLに埋め込む | SQLインジェクションが発生する | `bindValue()` でパラメータ化 |
| `$_POST` をそのままHTMLに出力する | XSSが発生する | `h()`（`htmlspecialchars()`）でエスケープ |
| `==` で比較する | 型変換により予期しない動作になる | `===` で厳格比較 |
