# ch02 — `session_start()` と `$_SESSION` の基本

Source: https://php-school.pages.dev/topics/session-cookie/ch02-session-basic/
Site: AIと学ぶPHPの学校 (https://php-school.pages.dev)
Lesson: セッション・Cookie・ログイン
Level: L4

Reference (official): https://www.php.net/manual/ja/book.session.php

## 本文

# ch02 — `session_start()` と `$_SESSION` の基本

## 概要

Session を使う入り口は **`session_start()`** 関数。これを呼んだ瞬間、PHP は「クライアントから来た Cookie に `PHPSESSID` があればそれを使い、無ければ新規発行する」「対応する Session ファイルがあれば読み込み、無ければ新規作成する」をまとめて面倒見てくれる。利用者は呼ぶだけで、後は **`$_SESSION` 連想配列** に値を入れたり取ったりすればよい。

`$_SESSION['name'] = '太郎'` と書いて画面を閉じても、次に同じブラウザで開けば `'太郎'` のまま読める。値が **サーバー側のファイル** (`/tmp/sess_<sessionId>` 等) に書かれていて、ブラウザ側には ID しか残らない構造だから。本物のデータはサーバー管理下、という安全な設計。

採点ランナーは **CLI で動く** ので、Cookie 経由の ID 同期はそのまま再現できない。代わりに `ini_set('session.use_cookies', '0')` で Cookie 機構を切り、`session_id('固定ID')` で ID を直接指定する **採点用スタブ** が冒頭に入っている。これで 1 プロセス内でも `session_start` を擬似的に呼べる、と理解する。

## 学習目標

- `session_start()` で Session を開始できる
- `$_SESSION['key'] = value` で値を保存し、`$_SESSION['key']` で取り出せる
- CLI 採点用の **session スタブ** (use_cookies=0 / 固定 session_id) を理解して使える

## 所要時間

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

## ドリル

| no | 内容 |
|---|---|
| 01 | `$_SESSION['name']` に `'太郎'` を保存して echo |
| 02 | 同一プロセス内で `$_SESSION['count']` を 3 回 increment して最終値を出力 |

## 本物のセッション動作で確認したい場合

```bash
cd topics/session-cookie/ch02-session-basic/drill/01-set-and-get/
php -S localhost:8000 answer.php
```

ブラウザで `http://localhost:8000/` を開く。リロードすると Session が保持されていることを開発者ツール (Application → Cookies) で `PHPSESSID` として確認できる。

## スライド

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

<!--
LLM_CONTEXT:
  Lesson 13 / Chapter 2
  目的: session_start() / $_SESSION への代入と取得
  扱わない: setcookie (ch03) / login (ch04) / CSRF (ch05) / regenerate_id (ch06)
  読み上げ時間目安: 4 分半〜5 分
-->

# `session_start()` と `$_SESSION`

Lesson 13 / Chapter 2

---

## 最小の Session 操作

```php
<?php
session_start();                   // 1. Session を開始する
$_SESSION['name'] = '太郎';        // 2. 連想配列に書き込む
echo $_SESSION['name'];            // 3. 読み出す
```

- `session_start()` を **最初に呼ぶ** のが鉄則 (ヘッダ送信より前)
- `$_SESSION` はただの連想配列。読み書きの作法は `$_GET` / `$_POST` と同じ
- リクエストをまたいでも、同じブラウザなら `$_SESSION['name']` が **残り続ける**

---

## `$_SESSION` は連想配列 (array-assoc トピックと同じ)

```php
<?php
session_start();
$_SESSION['user'] = [
    'id'   => 42,
    'name' => '太郎',
    'role' => 'admin',
];

echo $_SESSION['user']['name'];   // 太郎
```

- ネストした配列・オブジェクトもそのまま入る
- PHP が裏側でシリアライズして保存してくれるので、利用側は気にしなくて良い

→ ただし「**何を入れるか**」は自分で決める。何でも詰めると Session が肥大化する。

---

## CLI 採点用スタブ: cookie を切る

`session_start()` は **本来** ブラウザ + Web サーバーが前提。CLI で素直に呼ぶと:

```
PHP Warning: session_start(): Cannot send session cookie - headers already sent
```

CLI で安定動作させるために、**Cookie 経路を切る** スタブを冒頭に置く:

```php
<?php
// 採点用スタブ: header() / cookie 関連の警告を抑止
ini_set('session.use_cookies', '0');
ini_set('session.use_only_cookies', '0');
session_id('TESTSESSIONID');  // 固定 ID で Session を擬似化
@session_start();
```

- `use_cookies=0` で Cookie 自動発行を止める
- `session_id()` で **固定 ID** を渡し、毎回同じ Session を引けるようにする
- 本物の Web では PHP が自動で ID を発行するので、このスタブは不要

---

## 同一プロセス内でも `$_SESSION` は使える

採点ランナーは **1 リクエストぶんしか実行しない**。それでも `$_SESSION` を使う意味は:

```php
<?php
// 採点用スタブ ...

$_SESSION['count'] = 0;
for ($i = 0; $i < 3; $i++) {
    $_SESSION['count']++;
}
echo $_SESSION['count'];   // 3
```

「**プロセス内で**」読み書きできるので、ログイン → マイページのような **2 リクエスト分のシナリオを 1 スクリプトで擬似化** できる (ch04 で使う)。

---

## 「無ければ初期化」のお作法

```php
<?php
session_start();

// ✅ 初回アクセスでも落ちない
if (!isset($_SESSION['count'])) {
    $_SESSION['count'] = 0;
}
$_SESSION['count']++;
echo $_SESSION['count'];
```

または `??` で:

```php
$_SESSION['count'] = ($_SESSION['count'] ?? 0) + 1;
```

- 初回アクセス時は `$_SESSION` は空 → そのまま `++` すると警告
- `isset` か `??` で必ず初期値を用意する

---

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

✅ `session_start()` で Session を開始できる
✅ `$_SESSION['key'] = value` で値を保存・取得できる
✅ CLI 採点用スタブ (use_cookies=0 + 固定 session_id) を理解している
✅ 「無ければ初期化」を `isset` または `??` で書ける

→ ドリルへ
