# 機能設計書 28-アセットアップロード

## 概要

本ドキュメントは、LEGACY CMSにおけるアセットアップロード機能の設計仕様を定義する。

### 本機能の処理概要

アセットアップロード機能は、画像・動画・音声・ドキュメントなどのファイルをCMSにアップロードするための機能である。アップロードされたファイルはサーバーに保存され、データベースにメタ情報が登録される。

**業務上の目的・背景**：CMSで使用するメディアファイルを効率的にアップロードし、コンテンツ管理に活用する。Flashアップローダー（Uploadify）を使用し、複数ファイルの一括アップロードに対応している。

**機能の利用シーン**：アセット管理画面で「Upload Files」ボタンをクリックすると、アップロードフォームが表示される。ファイルを選択してアップロードを実行すると、指定フォルダ内にファイルが保存される。

**主要な処理内容**：
1. アップロードフォームの表示（uploadAction）
2. ファイル受信・保存処理（receiveAction）
3. ファイルのMIMEタイプ判定
4. 同名ファイルの重複チェック
5. データベースへのメタ情報登録

**関連システム・外部連携**：Uploadify（Flashアップローダー）

**権限による制御**：「fassets」権限と「fassetupload」権限の両方を持つロールのみがアクセス可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 56 | アセットアップロード画面 | 主画面 | ファイルアップロード処理 |

## 機能種別

CRUD操作（Create）/ ファイルアップロード

## 入力仕様

### 入力パラメータ

#### アップロードフォーム表示（uploadAction）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| folder | int | No | アップロード先フォルダID | 数値、デフォルト0 |
| type | string | No | 絞り込みタイプ | image/video/audio等 |
| method | string | No | 呼び出し方法 | 使用コンテキスト識別用 |
| field | string | No | 対象フィールド | エディタ挿入時の対象識別用 |

#### ファイル受信（receiveAction）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| folder | int | Yes | アップロード先フォルダID | 数値 |
| Filedata | file | Yes | アップロードファイル | - |

### 入力データソース

- Flashアップローダー（Uploadify）からのHTTPリクエスト
- $_FILES配列

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 成功レスポンス | string | '1'（成功） |
| 失敗レスポンス | string | '0'（失敗：重複または空） |

### 出力先

- ファイルシステム（アセット保存ディレクトリ）
- データベース（assetsテーブル）
- HTTPレスポンス（成功/失敗フラグ）

## 処理フロー

### 処理シーケンス

```
1. アップロードフォーム表示（uploadAction）
   └─ ACL権限チェック（fassets, fassetupload）
   └─ パラメータをビューに渡す

2. ファイル受信処理（receiveAction）
   └─ ACL権限チェック（fassets, fassetupload）
   └─ レイアウト・ビュー無効化
   └─ $_FILES配列からファイル情報取得
   └─ 同名ファイル重複チェック
   └─ 一時ファイルを保存先へ移動
   └─ MIMEタイプ判定
   └─ ファイルサイズ取得
   └─ データベースINSERT
   └─ '1'または'0'を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{権限チェック}
    B -->|権限なし| C[権限エラー]
    B -->|権限あり| D{$_FILES空?}
    D -->|Yes| E[echo '0']
    D -->|No| F[ファイル情報取得]
    F --> G{同名ファイル存在?}
    G -->|Yes| H[echo '0']
    G -->|No| I[ファイル移動]
    I --> J[MIMEタイプ判定]
    J --> K[ファイルサイズ取得]
    K --> L[DB INSERT]
    L --> M[echo '1']
    M --> N[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-28-01 | 同名ファイル重複禁止 | 同一フォルダ内に同名・同拡張子のファイルは登録不可 | 常時 |
| BR-28-02 | ユニークキー生成 | ファイル名のMD5ハッシュをasset_keyとして設定 | 常時 |
| BR-28-03 | MIMEタイプ判定 | OS依存でfinfo_file（Windows）またはfileコマンド（Unix）を使用 | 常時 |
| BR-28-04 | 一時ファイル名保存 | アップロードファイルは一時ファイル名で保存 | 常時 |

### 計算ロジック

- asset_key: `md5(basename($targetFile))`
- MIMEタイプ取得:
  - Windows: `finfo_file($finfo, $targetFile)`
  - Unix/Linux: `file -i -b {$filepath}` コマンド実行

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 重複チェック | assets | SELECT | 同名ファイル存在確認 |
| アセット登録 | assets | INSERT | アセット情報登録 |

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

#### assets

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | asset_id | WHERE asset_name = ? AND asset_extension = ? AND asset_folder = ? | 重複チェック |
| INSERT | asset_folder | フォルダID | アップロード先フォルダ |
| INSERT | asset_key | MD5ハッシュ | ファイル識別キー |
| INSERT | asset_name | ファイル名（拡張子なし） | 元ファイル名 |
| INSERT | asset_extension | 拡張子 | ファイル拡張子 |
| INSERT | asset_file | 保存ファイル名 | サーバー上のファイル名 |
| INSERT | asset_mime | MIMEタイプ | ファイル種別 |
| INSERT | asset_size | ファイルサイズ | バイト単位 |
| INSERT | asset_user | ログインユーザーID | アップロードユーザー |
| INSERT | asset_date | NOW() | アップロード日時 |
| INSERT | asset_modified | NOW() | 更新日時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 権限エラー | fassets/fassetupload権限なし | 権限エラー画面へ転送 |
| 0 | 重複エラー | 同名ファイルが既に存在 | '0'を返却 |
| 0 | 空ファイル | $_FILESが空 | '0'を返却 |

### リトライ仕様

アップローダーUIで再度ファイル選択・アップロード

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

単一INSERT操作のため、明示的なトランザクション制御は不要

## パフォーマンス要件

- 大容量ファイルのアップロードに対応
- php.iniのupload_max_filesize、post_max_sizeに依存

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

- 管理画面へのアクセスはACLによる権限チェック必須
- FlashセッションID対応（__tknパラメータ）
- MIMEタイプはサーバー側で判定（クライアント情報を信頼しない）
- アップロードファイルは元ファイル名ではなく一時ファイル名で保存

## 備考

- Uploadify（Flash）を使用しているため、PHPSESSIDをURL経由で渡す必要がある
- ファイルの上書きは不可（同名ファイルは登録エラー）

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | assetsテーブル | データベース | INSERT対象カラムの確認 |

**読解のコツ**: asset_fileはサーバー上の実ファイル名、asset_nameは元のファイル名（拡張子なし）を格納する。asset_keyはMD5ハッシュでファイルを一意に識別する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Admin_AssetsController.php | `application/modules/admin/controllers/AssetsController.php` | uploadAction, receiveAction |

**主要処理フロー（uploadAction - フォーム表示）**:
1. **122行目**: 権限チェック（fassets, fassetupload）
2. **124行目**: レイアウト設定
3. **125-128行目**: パラメータ取得・ビュー設定

**主要処理フロー（receiveAction - ファイル受信）**:
1. **431行目**: 権限チェック（fassets, fassetupload）
2. **433-434行目**: レイアウト・ビュー無効化
3. **436行目**: フォルダパラメータ取得
4. **438行目**: レジストリ取得
5. **440行目**: $_FILESの存在チェック
6. **442-447行目**: ファイル情報取得（tmp_name, name, extension）
7. **453-458行目**: 同名ファイル重複チェックSELECT
8. **461行目**: 重複チェック結果判定
9. **463行目**: 重複なしの場合、一時ディレクトリからファイル移動
10. **465-467行目**: 一時ファイルを保存先へ移動
11. **467-472行目**: MIMEタイプ判定（Windows: finfo / Unix: fileコマンド）
12. **474行目**: ファイルサイズ取得
13. **478-489行目**: INSERTデータ配列作成
14. **492行目**: データベースINSERT
15. **494行目**: '1'を出力（成功）
16. **496-504行目**: 重複または空の場合'0'を出力

#### Step 3: 補助処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Admin_AssetsController.php | 同上 | get_mime_type()メソッド（17-26行目） |

**get_mime_type()の処理**:
- Unixシステムで`file -i -b`コマンドを実行
- 出力をパースしてMIMEタイプを取得
- セミコロン区切りの場合は最初の部分を使用

#### Step 4: ビューテンプレートを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | upload.phtml | `application/modules/admin/views/scripts/assets/upload.phtml` | Uploadifyの設定 |

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

```
Admin_AssetsController
    │
    ├─ uploadAction() [フォーム表示]
    │      └─ ACL権限チェック (fassets, fassetupload)
    │
    └─ receiveAction() [ファイル受信]
           ├─ ACL権限チェック (fassets, fassetupload)
           ├─ Zend_Db_Select - 重複チェック
           ├─ move_uploaded_file() - ファイル移動
           ├─ finfo_file() または file コマンド - MIME判定
           └─ Zend_Db_Adapter::insert() - DB登録
```

### データフロー図

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

Uploadify                  receiveAction()
  Filedata        ───▶      - $_FILES取得
  folder                    - 重複チェック           ───▶   assetsテーブル
                            - ファイル移動                  (INSERT)
                            - MIME判定
                            - サイズ取得                    ファイルシステム
                            - DB INSERT               ───▶ (保存ファイル)

                                                           HTTPレスポンス
                                                     ───▶  '1' or '0'
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AssetsController.php | `application/modules/admin/controllers/AssetsController.php` | コントローラー | アップロード処理 |
| Admin.php | `library/CMS/Controller/Action/Admin.php` | 親クラス | 認証・ACL基盤処理 |
| upload.phtml | `application/modules/admin/views/scripts/assets/upload.phtml` | ビュー | アップロードフォーム |
| Uploadify | 外部ライブラリ | JavaScript/Flash | マルチファイルアップロード |
