# 機能設計書 63-入力検証

## 概要

本ドキュメントは、LEGACY CMSにおける入力検証機能の設計を記述する。本機能はZend_Filter_Inputコンポーネントを使用して、フォーム入力値のバリデーションとフィルタリングを実現する。

### 本機能の処理概要

本機能は、ユーザーが入力したフォームデータをサーバーサイドで検証し、不正な入力値を拒否または修正する。フィルタリングによる入力値のサニタイズと、バリデーションによる入力値の妥当性チェックを組み合わせて、システムのセキュリティとデータ整合性を担保する。

**業務上の目的・背景**：CMSにおいて、ユーザー入力はSQLインジェクション、XSS、不正データ登録などのセキュリティリスクの入口となる。本機能により、サーバーサイドで厳格な入力検証を行い、信頼できるデータのみをシステムに受け入れることで、セキュリティと品質を確保する。

**機能の利用シーン**：
- ログインフォームでのユーザー名・パスワード検証
- 記事・ページ・イベント作成・編集フォームでのタイトル・内容検証
- ユーザー登録・編集フォームでのメールアドレス・パスワード検証
- カテゴリ・ロール作成フォームでの名称検証
- お問い合わせフォームでの入力値検証
- アセットアップロードフォームでのファイル情報検証

**主要な処理内容**：
1. バリデーションルール（$validators）とフィルタルール（$filters）を定義
2. Zend_Filter_Inputオブジェクトを生成してPOSTデータを渡す
3. isValid()で検証を実行
4. 検証成功時は入力値を取得して処理を継続
5. 検証失敗時はgetMessages()でエラーメッセージを取得して表示

**関連システム・外部連携**：Zend_Filter_Input、Zend_Validate_*、Zend_Filter_*コンポーネントと連携してバリデーションを実現する。

**権限による制御**：入力検証自体には権限制御はないが、フォームを含む画面へのアクセスは各機能の権限チェックに依存する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | お問い合わせ画面 | 主画面 | フォーム入力値のバリデーション |
| 5 | ログイン画面 | 参照画面 | ログインフォームのバリデーション |
| 7 | ユーザー登録画面 | 参照画面 | 登録フォームのバリデーション |
| 27 | パスワード変更画面 | 主画面 | パスワード変更フォームのバリデーション |
| 33 | 管理者ログイン画面 | 参照画面 | ログインフォームのバリデーション |
| 34 | 管理者パスワード変更画面 | 主画面 | パスワード変更フォームのバリデーション |
| 36 | 記事編集画面 | 参照画面 | 記事フォームのバリデーション |
| 37 | 記事新規作成画面 | 参照画面 | 記事フォームのバリデーション |
| 40 | 記事カテゴリ新規作成画面 | 主画面 | カテゴリフォームのバリデーション |
| 42 | ユーザー編集画面 | 主画面 | ユーザーフォームのバリデーション |
| 43 | ユーザー新規作成画面 | 主画面 | ユーザーフォームのバリデーション |
| 46 | ロール新規作成画面 | 参照画面 | ロールフォームのバリデーション |
| 49 | イベント編集画面 | 参照画面 | イベントフォームのバリデーション |
| 50 | イベント新規作成画面 | 参照画面 | イベントフォームのバリデーション |
| 54 | イベントカテゴリ新規作成画面 | 参照画面 | カテゴリフォームのバリデーション |
| 55 | イベントカテゴリ編集画面 | 参照画面 | カテゴリフォームのバリデーション |
| 58 | 会場新規作成画面 | 主画面 | 会場フォームのバリデーション |
| 59 | 会場編集画面 | 主画面 | 会場フォームのバリデーション |
| 61 | ページ編集画面 | 参照画面 | ページフォームのバリデーション |
| 62 | ページ新規作成画面 | 参照画面 | ページフォームのバリデーション |
| 65 | メール編集画面 | 参照画面 | メールフォームのバリデーション |
| 68 | グループ新規作成画面 | 参照画面 | グループフォームのバリデーション |
| 74 | 設定詳細画面 | 参照画面 | 設定フォームのバリデーション |
| 76 | アップロード画面 | 参照画面 | アップロードフォームのバリデーション |
| 78 | アセットプロパティ画面 | 参照画面 | プロパティフォームのバリデーション |
| 80 | フォルダ新規作成画面 | 参照画面 | フォルダフォームのバリデーション |
| 81 | フォルダプロパティ画面 | 参照画面 | プロパティフォームのバリデーション |
| 88 | ローテーター編集画面 | 参照画面 | ローテーターフォームのバリデーション |
| 89 | スライド編集画面 | 参照画面 | スライドフォームのバリデーション |
| 90 | スライド新規作成画面 | 参照画面 | スライドフォームのバリデーション |

## 機能種別

バリデーション / データサニタイズ

## 入力仕様

### 入力パラメータ

入力パラメータはフォームごとに異なる。代表的なパターンを以下に示す。

#### 記事編集フォーム

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| title | string | Yes | 記事タイトル | NotEmpty |
| category | int | Yes | カテゴリID | NotEmpty |
| introduction | string | Yes | ティーザー | NotEmpty |
| content | string | No | 本文 | allowEmpty |
| comments | string | No | コメント許可 | allowEmpty |
| moderate | string | No | モデレーション | allowEmpty |
| sticky | string | No | スティッキー | allowEmpty |

#### ユーザー編集フォーム

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| first | string | Yes | 名 | NotEmpty |
| last | string | Yes | 姓 | NotEmpty |
| alias | string | Yes | エイリアス | NotEmpty, Alnum, Db_NoRecordExists |
| email | string | Yes | メールアドレス | NotEmpty, EmailAddress, Db_NoRecordExists |
| role | int | Yes | ロールID | NotEmpty, Digits |
| country | string | Yes | 国 | NotEmpty |

### 入力データソース

- $_POST（PHPグローバル変数）からのフォームデータ
- Zend_Controller_Request経由のパラメータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| isValid | boolean | 検証結果（true:成功、false:失敗） |
| messages | array | エラーメッセージの連想配列（フィールド名 => メッセージ配列） |
| 入力値 | mixed | フィルタ適用後の入力値（$input->fieldname形式でアクセス） |

### 出力先

- 検証成功時: データベース更新処理へ
- 検証失敗時: エラーメッセージをビューに渡して再表示

## 処理フロー

### 処理シーケンス

```
1. フィルタルールの定義
   └─ $filters配列でフィールドごとのフィルタを指定

2. バリデーションルールの定義
   └─ $validators配列でフィールドごとのバリデータを指定

3. Zend_Filter_Inputの生成
   └─ new Zend_Filter_Input($filters, $validators, $_POST, $options)

4. 検証の実行
   └─ $input->isValid() を呼び出し

5. 結果に応じた分岐
   ├─ [成功] 入力値を取得してDB更新
   └─ [失敗] エラーメッセージを取得して表示

6. エラーメッセージの表示
   └─ $input->getMessages() で取得したメッセージをビューに渡す
```

### フローチャート

```mermaid
flowchart TD
    A[フォーム送信] --> B[フィルタ/バリデータ定義]
    B --> C[Zend_Filter_Input生成]
    C --> D[isValid実行]
    D --> E{検証成功?}
    E -->|Yes| F[入力値を取得]
    F --> G[DB更新処理]
    G --> H[成功メッセージ表示]
    E -->|No| I[getMessages実行]
    I --> J[エラーメッセージをビューに渡す]
    J --> K[フォーム再表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-63-01 | 必須フィールド | presence='required'指定フィールドは空を許可しない | フォーム送信時 |
| BR-63-02 | 空許可フィールド | allowEmpty=true指定フィールドは空値を許可 | フォーム送信時 |
| BR-63-03 | 一意性チェック | Db_NoRecordExists使用フィールドはDB内で重複不可 | メール、エイリアス等 |
| BR-63-04 | 除外条件付き一意性 | exclude指定で自レコードを除外して一意性チェック | 編集時 |
| BR-63-05 | チェーン中断 | breakChainOnFailure=true指定で最初のエラーで検証中断 | 特定フィールド |
| BR-63-06 | カスタムメッセージ | messages配列でエラーメッセージをカスタマイズ | 全フィールド |

### 計算ロジック

バリデーションの計算ロジックはZend_Validateの各クラスに委譲される:

1. NotEmpty: 空文字列、null、空配列などを検出
2. EmailAddress: RFC準拠のメールアドレス形式をチェック
3. Alnum: 英数字（オプションで空白許可）をチェック
4. Digits: 数字のみをチェック
5. Regex: 正規表現パターンにマッチするかチェック
6. Db_NoRecordExists: 指定テーブル・カラムに同値が存在しないかチェック

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一意性チェック | users | SELECT | メールアドレス・エイリアスの重複確認 |
| 一意性チェック | articles_categories | SELECT | カテゴリ名の重複確認 |
| 一意性チェック | users_roles | SELECT | ロール名の重複確認 |

### テーブル別操作詳細

#### Zend_Validate_Db_NoRecordExists による一意性チェック

| 操作 | 項目（カラム名） | 取得条件 | 備考 |
|-----|-----------------|---------|------|
| SELECT | COUNT(*) | WHERE field = value | 存在チェック |
| SELECT | COUNT(*) | WHERE field = value AND exclude_field != exclude_value | 編集時の除外条件付き |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| IS_EMPTY | NotEmpty | 必須フィールドが空 | "xxx is required"メッセージ表示 |
| INVALID | EmailAddress | メールアドレス形式不正 | "Invalid E-mail Address"メッセージ表示 |
| NOT_ALNUM | Alnum | 英数字以外を含む | "Invalid xxx"メッセージ表示 |
| NOT_DIGITS | Digits | 数字以外を含む | "Invalid xxx"メッセージ表示 |
| NOT_MATCH | Regex | 正規表現にマッチしない | "Invalid xxx"メッセージ表示 |
| ERROR_RECORD_FOUND | Db_NoRecordExists | 重複レコードが存在 | "xxx in use"/"xxx already exists"メッセージ表示 |

### リトライ仕様

本機能ではリトライは不要。検証失敗時はフォームを再表示してユーザーに修正を促す。

## トランザクション仕様

入力検証自体はトランザクションを使用しない。検証後のDB更新処理は各機能のトランザクション仕様に従う。

## パフォーマンス要件

- Db_NoRecordExistsバリデータは毎回DBクエリを発行するため、大量の一意性チェックがある場合は注意が必要
- 通常のフォーム送信では問題ないレベルのパフォーマンス

## セキュリティ考慮事項

- サーバーサイドでのバリデーションにより、クライアントサイドのバイパスを防止
- HTMLエンティティエンコードはビュー側で$this->escape()を使用
- SQLインジェクションはZend_Db_Selectのプレースホルダ機能で防止
- フィルタ（StringTrim, StringToLower等）による入力値の正規化

## 備考

- 本機能はZend_Filter_Inputを標準的な方法で使用
- カスタムメッセージはmessages配列で各バリデータに対応するメッセージを設定
- Messages Viewヘルパーでエラーメッセージを整形して表示

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: 基本的な入力検証パターンを理解する

まず、最も基本的な入力検証の実装パターンを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ArticlesController.php | `application/modules/admin/controllers/ArticlesController.php` | saveAction()での入力検証パターン |

**読解のコツ**: $filters、$validators、Zend_Filter_Inputの3要素に注目する。messagesの設定方法とisValid()後の分岐処理を理解する。

**主要処理フロー**:
1. **134-158行目**: バリデータ定義
   ```php
   $validators = array(
       'title' => array(
           'presence' => 'required',
           'NotEmpty',
           'messages' => array(array( Zend_Validate_NotEmpty::IS_EMPTY => "Title is required"))
       ),
   ```
2. **160行目**: Zend_Filter_Input生成
   ```php
   $input = new Zend_Filter_Input($filters, $validators, $_POST, $options);
   ```
3. **162行目**: 検証実行
   ```php
   if ($input->isValid()) :
   ```
4. **182-187行目**: エラーメッセージ取得
   ```php
   $this->messages = $input->getMessages();
   $this->_helper->messages->render($this->messages);
   ```

#### Step 2: 高度なバリデーション設定を理解する

複数のバリデータとDB一意性チェックを含む高度な設定を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | UsersController.php | `application/modules/admin/controllers/UsersController.php` | saveAction()での高度なバリデーション |

**主要処理フロー**:
- **362-409行目**: バリデータ定義（複数バリデータ、DB一意性チェック、除外条件）
  ```php
  'alias' => array(
      'presence' => 'required',
      'NotEmpty',
      new Zend_Validate_Alnum(true),
      new Zend_Validate_Db_NoRecordExists(array(
          'table' => 'users',
          'field' => 'user_alias',
          'exclude' => array('field' => 'user_id','value' => $id)
      )),
      'messages' => array(...)
  ),
  ```
- **386行目**: breakChainOnFailure使用
  ```php
  'breakChainOnFailure' => true
  ```

#### Step 3: 新規作成時のバリデーションを理解する

新規作成時の一意性チェック（除外条件なし）を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | UsersController.php | `application/modules/admin/controllers/UsersController.php` | newAction()での新規作成バリデーション |

**主要処理フロー**:
- **609-652行目**: 新規作成用バリデータ定義
  ```php
  'email' => array(
      ...
      new Zend_Validate_Db_NoRecordExists('users','user_email'),
      ...
  ),
  ```
- **654行目**: 検証実行
  ```php
  $input = new Zend_Filter_Input($filters, $validators, $_POST, $options);
  ```

#### Step 4: カテゴリ作成時のバリデーションを理解する

シンプルなカテゴリ作成時のバリデーションを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ArticlesController.php | `application/modules/admin/controllers/ArticlesController.php` | categorynewAction()でのカテゴリ作成バリデーション |

**主要処理フロー**:
- **477-485行目**: カテゴリ名バリデータ
  ```php
  $validators = array(
      'categorytitle' => array(
          'presence' => 'required',
          'NotEmpty',
          new Zend_Validate_Alnum(true),
          new Zend_Validate_Db_NoRecordExists('articles_categories','acat_title'),
          'messages' => array(...)
      )
  );
  ```

#### Step 5: フィルタの使用例を理解する

入力値のフィルタリング（サニタイズ）を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | UsersController.php | `application/modules/admin/controllers/UsersController.php` | newAction()でのフィルタ使用 |

**主要処理フロー**:
- **605-607行目**: フィルタ定義
  ```php
  $filters = array(
      'email' => array('StringTrim', 'StringToLower')
  );
  ```

#### Step 6: エラーメッセージ表示ヘルパーを理解する

エラーメッセージの表示処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | Messages.php | `application/helpers/Messages.php` | メッセージ表示ヘルパー |

**主要処理フロー**:
- render()メソッドでエラーメッセージ配列をHTML整形して出力

### プログラム呼び出し階層図

```
Controller::xxxAction()
    │
    ├─ $filters = array(...)  [フィルタルール定義]
    │
    ├─ $validators = array(...)  [バリデータルール定義]
    │      ├─ 'presence' => 'required'
    │      ├─ 'NotEmpty'
    │      ├─ new Zend_Validate_Alnum(true)
    │      ├─ new Zend_Validate_EmailAddress()
    │      ├─ new Zend_Validate_Db_NoRecordExists(...)
    │      ├─ new Zend_Validate_Regex(...)
    │      ├─ 'messages' => array(...)
    │      └─ 'breakChainOnFailure' => true
    │
    ├─ new Zend_Filter_Input($filters, $validators, $_POST, $options)
    │
    └─ $input->isValid()
           │
           ├─ [true] $input->fieldname でフィルタ済み値を取得
           │         └─ DB更新処理
           │
           └─ [false] $input->getMessages()
                      └─ $this->_helper->messages->render($messages)
                             └─ HTMLエラーメッセージ出力
```

### データフロー図

```
[入力]                    [処理]                              [出力]

$_POST ────────────────┐
                       │
$filters ──────────────┼──▶ Zend_Filter_Input
                       │         │
$validators ───────────┘         │
                                 ▼
                           ┌─────────────┐
                           │  isValid()  │
                           └─────────────┘
                                 │
                    ┌────────────┴────────────┐
                    ▼                         ▼
              [成功: true]              [失敗: false]
                    │                         │
                    ▼                         ▼
           $input->fieldname           $input->getMessages()
           (フィルタ済み値)            (エラーメッセージ配列)
                    │                         │
                    ▼                         ▼
              DB更新処理              HTMLエラー表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ArticlesController.php | `application/modules/admin/controllers/ArticlesController.php` | ソース | 記事管理コントローラー、基本的なバリデーション例 |
| UsersController.php | `application/modules/admin/controllers/UsersController.php` | ソース | ユーザー管理コントローラー、高度なバリデーション例 |
| EventsController.php | `application/modules/admin/controllers/EventsController.php` | ソース | イベント管理コントローラー |
| PagesController.php | `application/modules/admin/controllers/PagesController.php` | ソース | ページ管理コントローラー |
| AssetsController.php | `application/modules/admin/controllers/AssetsController.php` | ソース | アセット管理コントローラー |
| MailController.php | `application/modules/admin/controllers/MailController.php` | ソース | メール管理コントローラー |
| RotatorsController.php | `application/modules/admin/controllers/RotatorsController.php` | ソース | ローテーター管理コントローラー |
| SettingsController.php | `application/modules/admin/controllers/SettingsController.php` | ソース | 設定管理コントローラー |
| AuthController.php (admin) | `application/modules/admin/controllers/AuthController.php` | ソース | 管理者認証コントローラー |
| AuthController.php (default) | `application/modules/default/controllers/AuthController.php` | ソース | ユーザー認証コントローラー |
| Messages.php | `application/helpers/Messages.php` | ソース | エラーメッセージ表示ヘルパー |
