(覚書）コードイグナイター＋Smarty　ファイルアップロードができない

# ファイルアップロード問題解決ガイド

## 🚨 よくある原因と解決法

### 1. フォームの設定ミス（最頻出！）

#### ❌ 間違った書き方
```html
<!-- これだとファイルが送信されない -->
<form method="post" action="...">
    <input type="file" name="upload_file">
    <button type="submit">送信</button>
</form>
```

#### ✅ 正しい書き方
```html
<!-- enctype="multipart/form-data" が必須！ -->
<form method="post" action="..." enctype="multipart/form-data">
    <input type="file" name="upload_file">
    <button type="submit">送信</button>
</form>
```

### 2. CodeIgniterでの正しいファイルアップロード手順

#### コントローラー側の処理
```php
public function upload() {
    // ファイルアップロードライブラリを読み込み
    $this->load->library('upload');
    
    // アップロード設定
    $config = [
        'upload_path' => './uploads/',          // アップロード先
        'allowed_types' => 'gif|jpg|jpeg|png|pdf|doc|docx',
        'max_size' => 5120,                     // 5MB (KB単位)
        'encrypt_name' => TRUE                  // ファイル名暗号化
    ];
    
    // ライブラリを設定で初期化
    $this->upload->initialize($config);
    
    // ファイルがアップロードされているかチェック
    if (empty($_FILES['upload_file']['name'])) {
        echo "ファイルが選択されていません";
        return;
    }
    
    // アップロード実行
    if ($this->upload->do_upload('upload_file')) {
        // 成功時
        $upload_data = $this->upload->data();
        echo "アップロード成功: " . $upload_data['file_name'];
        
        // デバッグ用：アップロード情報を表示
        print_r($upload_data);
        
    } else {
        // 失敗時
        $error = $this->upload->display_errors();
        echo "アップロード失敗: " . $error;
    }
}
```

#### テンプレート(.tpl)側
```html
<!-- Smartyでフォーム作成 -->
<form method="post" action="{site_url('controller/upload')}" enctype="multipart/form-data">
    <div>
        <label for="upload_file">ファイル選択</label>
        <input type="file" id="upload_file" name="upload_file" 
               accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx">
    </div>
    
    <!-- 他のフィールドも含める場合 -->
    <div>
        <label for="title">タイトル</label>
        <input type="text" id="title" name="title" value="{$form_data.title|default:''|escape}">
    </div>
    
    <button type="submit">アップロード</button>
</form>
```

### 3. デバッグ方法

#### コントローラーでデータ確認
```php
public function debug_upload() {
    echo "<h3>POST Data:</h3>";
    print_r($this->input->post());
    
    echo "<h3>FILES Data:</h3>";
    print_r($_FILES);
    
    echo "<h3>Request Method:</h3>";
    echo $this->input->method();
    
    // ファイルが送信されているかチェック
    if (isset($_FILES['upload_file'])) {
        echo "<h3>File Info:</h3>";
        echo "Name: " . $_FILES['upload_file']['name'] . "<br>";
        echo "Size: " . $_FILES['upload_file']['size'] . "<br>";
        echo "Type: " . $_FILES['upload_file']['type'] . "<br>";
        echo "Error: " . $_FILES['upload_file']['error'] . "<br>";
    } else {
        echo "<h3>ファイルデータが送信されていません</h3>";
    }
}
```

### 4. form_update関数について

`form_update`は**CodeIgniterの標準関数ではありません**。以下の可能性があります：

#### 確認すべき場所
```php
// 1. カスタムヘルパー
// application/helpers/my_form_helper.php を確認

// 2. カスタムライブラリ
// application/libraries/ 内を確認

// 3. 既存プロジェクトの関数
// application/core/ 内を確認
```

#### 一般的なカスタム関数の例
```php
// よくあるカスタム関数のパターン
function form_update($action = '', $attributes = array()) {
    // 更新用フォームの開始タグを生成
    if (!isset($attributes['enctype'])) {
        $attributes['enctype'] = 'multipart/form-data';
    }
    return form_open($action, $attributes);
}
```

### 5. 完全な動作例

#### コントローラー（Contact.php）
```php
class Contact extends CI_Controller {
    
    public function __construct() {
        parent::__construct();
        $this->load->helper(['form', 'url']);
        $this->load->library(['upload', 'form_validation', 'smarty']);
    }
    
    public function index() {
        $data = [
            'errors' => [],
            'form_data' => [],
            'success' => false
        ];
        
        if ($this->input->method() === 'post') {
            // デバッグ：送信データ確認
            echo "<pre>";
            echo "POST: "; print_r($this->input->post());
            echo "FILES: "; print_r($_FILES);
            echo "</pre>";
            
            // ファイルアップロード処理
            $upload_result = $this->handle_upload();
            
            if ($upload_result['success']) {
                $data['success'] = true;
                $data['uploaded_file'] = $upload_result['file_name'];
            } else {
                $data['errors']['upload'] = $upload_result['error'];
            }
        }
        
        // Smartyに渡す
        $this->smarty->assign('errors', $data['errors']);
        $this->smarty->assign('form_data', $data['form_data']);
        $this->smarty->assign('success', $data['success']);
        $this->smarty->display('contact/form.tpl');
    }
    
    private function handle_upload() {
        // ファイルが選択されていない場合
        if (empty($_FILES['upload_file']['name'])) {
            return ['success' => true, 'file_name' => null];
        }
        
        // アップロードディレクトリ作成
        $upload_path = './uploads/';
        if (!is_dir($upload_path)) {
            mkdir($upload_path, 0755, true);
        }
        
        // アップロード設定
        $config = [
            'upload_path' => $upload_path,
            'allowed_types' => 'gif|jpg|jpeg|png|pdf|doc|docx',
            'max_size' => 5120,
            'encrypt_name' => TRUE
        ];
        
        $this->upload->initialize($config);
        
        if ($this->upload->do_upload('upload_file')) {
            $upload_data = $this->upload->data();
            return [
                'success' => true,
                'file_name' => $upload_data['file_name'],
                'original_name' => $upload_data['orig_name']
            ];
        } else {
            return [
                'success' => false,
                'error' => strip_tags($this->upload->display_errors())
            ];
        }
    }
}
```

#### テンプレート（form.tpl）
```html
<!DOCTYPE html>
<html>
<head>
    <title>ファイルアップロードテスト</title>
</head>
<body>
    {if $success}
        <div style="color: green;">
            <h3>アップロード成功！</h3>
        </div>
    {/if}
    
    {if isset($errors.upload)}
        <div style="color: red;">
            <h3>エラー: {$errors.upload}</h3>
        </div>
    {/if}
    
    <!-- 重要：enctype="multipart/form-data" を忘れずに！ -->
    <form method="post" action="{site_url('contact')}" enctype="multipart/form-data">
        <div>
            <label for="upload_file">ファイル選択：</label>
            <input type="file" id="upload_file" name="upload_file">
        </div>
        
        <div>
            <label for="title">タイトル：</label>
            <input type="text" id="title" name="title" value="{$form_data.title|default:''|escape}">
        </div>
        
        <div>
            <button type="submit">送信</button>
        </div>
    </form>
    
    <!-- デバッグ用：フォームのenctype確認 -->
    <script>
        console.log('Form enctype:', document.querySelector('form').enctype);
    </script>
</body>
</html>
```

### 6. よくあるエラーと対処法

#### エラー1: 「The upload path does not appear to be valid.」
```php
// 解決法：ディレクトリを作成
$upload_path = './uploads/';
if (!is_dir($upload_path)) {
    mkdir($upload_path, 0755, true);
}
```

#### エラー2: 「The filetype you are attempting to upload is not allowed.」
```php
// 解決法：許可ファイル形式を確認
$config['allowed_types'] = 'gif|jpg|jpeg|png|pdf|doc|docx|txt';
```

#### エラー3: 「The file you are attempting to upload is larger than the permitted size.」
```php
// 解決法：サイズ制限を調整
$config['max_size'] = 10240; // 10MB

// php.iniも確認
// upload_max_filesize = 10M
// post_max_size = 10M
```

### 7. 確認チェックリスト

- [ ] フォームに `enctype="multipart/form-data"` が設定されている
- [ ] `<input type="file" name="upload_file">` のname属性が正しい
- [ ] コントローラーで `$this->load->library('upload')` している
- [ ] アップロード先ディレクトリが存在し、書き込み権限がある
- [ ] `$_FILES['upload_file']` にデータが入っている
- [ ] `do_upload('upload_file')` の引数がinputのname属性と一致

### 8. 緊急対処法（とりあえず動かす）

#### 最小限のテストコード
```php
// 超シンプルなテスト用コントローラー
public function test_upload() {
    echo "<h2>アップロードテスト</h2>";
    
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        echo "<h3>受信データ：</h3>";
        echo "<pre>";
        print_r($_POST);
        print_r($_FILES);
        echo "</pre>";
        
        if (isset($_FILES['test_file']) && $_FILES['test_file']['error'] === 0) {
            $upload_dir = './uploads/';
            if (!is_dir($upload_dir)) mkdir($upload_dir, 0755, true);
            
            $filename = time() . '_' . $_FILES['test_file']['name'];
            if (move_uploaded_file($_FILES['test_file']['tmp_name'], $upload_dir . $filename)) {
                echo "<p style='color:green'>アップロード成功: $filename</p>";
            } else {
                echo "<p style='color:red'>ファイル移動失敗</p>";
            }
        } else {
            echo "<p style='color:red'>ファイルが送信されていません</p>";
        }
    }
    
    echo '<form method="post" enctype="multipart/form-data">
            <input type="file" name="test_file" required>
            <button type="submit">テストアップロード</button>
          </form>';
}
```