Web サーバー権限に依存しないコンテンツ管理 — ec-cube2/cli への CLI 導線の追加(4系 EC-CUBE/ec-cube#7072 の 2系版)
- Dominant language
- PHP
- Stars
- 92
- Forks
- 97
- Avg merge
- 4d 2h
- Merged PRs (30d)
- 9
Description
## 概要(Overview)
4系(EC-CUBE/ec-cube)で、デザイン管理などのファイル書き込みを Web サーバー権限から
SSH ログインユーザー権限の CLI へ移す設計を提案しています。
- EC-CUBE/ec-cube#7072 「[4.4] Web サーバー権限に依存しないコンテンツ管理 — CLI 導線と build/cache 分離の実装設計」
2系にも同じ課題があり、かつ **`ec-cube2/cli`(`composer.json` の require に `^1.4.3`)という土台が既にあります**。
**4系で仕様を固めてから 2系を実装する**流れとし、本 issue はその受け皿として作成します。
現時点では 2系側の調査結果と、共有すべき仕様の範囲を整理するものです。
なお、ファイル所有ユーザーと PHP 実行ユーザーの分離という前提は #841 と共通しています。
## 現状の調査結果
### `ec-cube2/cli` の構造
- Symfony Console + DI コンテナ(`config/services.yaml` + `AddConsoleCommandPass`)、65 ファイル
- **`Eccube2\Console\Application::appendConfigPath()` / `prependConfigPath()`** により、
外部から `services.yaml` を読み込ませてコマンドを追加できる拡張機構がある
- `Command` は薄く、処理は `Eccube2\Util\*` へ委譲する構成
- `Eccube2\Init::init()` で 2系本体をブートストラップ
### CLI のカバレッジ比較
| 領域 | 2系 `ec-cube2/cli` | 4系 |
|---|---|---|
| 設定パラメータ | `parameter:get` / `parameter:set`(`data/config/config.php`) | 無い(`.env` は管理画面のみ) |
| キャッシュ削除 | `cache:clear` | `cache:clear`(Symfony 標準) |
| プラグイン | `plugin:*` / `module:*` | `eccube:plugin:*` |
| テンプレート切替 | `template:{pc,mobile,smartphone}:{get,set}` | 無い(管理画面のみ) |
| バックアップ | `backup:create` / `restore` / `list` / `delete` | 無い |
| 管理者アカウント | `member:create` / `set-password` / `enable` / `disable` | 無い |
| 本体アップデート | `zip:download` / `update` / `info` | 無い |
| オーナーズストア | `owners-store:set-key` / `list` | 一部 |
| **ページ / ブロック / CSS / ヘッダーの内容編集** | **無い** | **無い** |
| **ファイル管理** | **無い** | **無い** |
| **権限診断** | **無い** | **無い** |
CLI のカバレッジは 2系のほうが広く、バックアップ・管理者アカウント作成・本体アップデートは
4系に無い機能です。一方で、**両系統で欠けているのは同じ 3 つ**(コンテンツ編集・ファイル管理・権限診断)で、
これが #7072 のスコープと一致します。
### 2系の書き込み経路は集約されている
デザイン管理からのファイル書き込みは `SC_Helper_FileManager_Ex::sfWriteFile()` の 1 本に集約されています。
| 機能 | 呼び出し元 |
|---|---|
| ページ編集(`tpl_data`) | `data/class/pages/admin/design/LC_Page_Admin_Design_MainEdit.php:246` |
| ページの PHP ファイル生成 | `data/class/pages/admin/design/LC_Page_Admin_Design_MainEdit.php:397` |
| CSS 編集 | `data/class/pages/admin/design/LC_Page_Admin_Design_CSS.php:189` |
| ヘッダー / フッター編集 | `data/class/pages/admin/design/LC_Page_Admin_Design_Header.php:169` |
4系は `dumpFile` / `file_put_contents` / `move` が各コントローラに散在しているため、
CLI へ切り出す観点では 2系のほうが構造的に有利です。
(ブロックの保存は `SC_Helper_Bloc_Ex` 経由で別経路のため、別途整理が必要です)
## 期待する内容(Expect) or 要望(Requirement)
### 1. 書き込み先を 3 レーンに分類する(2系版・要精査)
4系 #7072 と同じ考え方を 2系のディレクトリ構成へ適用します。以下は現時点の整理案です。
**レーン W — Web サーバー所有(書き込みが必要)**
| 定数 | パス |
|---|---|
| `CACHE_REALDIR` | `data/cache/` |
| `COMPILE_REALDIR` / `COMPILE_ADMIN_REALDIR` | `data/Smarty/templates_c/{template}/`, `data/Smarty/templates_c/admin/` |
| `LOG_REALFILE` / `PLUGIN_LOG_REALFILE` | `data/logs/site.log`, `data/logs/plugin.log` |
| `IMAGE_SAVE_REALDIR` | `html/upload/save_image/` |
| `PLUGIN_TEMP_REALDIR` | `html/upload/temp_plugin/` |
| `DOWNLOADS_TEMP_PLUGIN_*` | `data/downloads/tmp/...` |
**レーン S — SSH ユーザー所有(Web サーバーは読み取りのみ)**
| 定数 | パス |
|---|---|
| `SMARTY_TEMPLATES_REALDIR` | `data/Smarty/templates/` |
| `USER_REALDIR` | `html/user_data/` |
| `USER_TEMPLATE_REALDIR` | `html/user_data/packages/` |
| `PLUGIN_REALDIR` | `html/user_data/plugins/` |
| `PLUGIN_HTML_REALDIR` | `html/plugin/` |
| `CLASS_EX_REALDIR` | `data/class_extends/` |
| (設定ファイル) | `data/config/config.php` |
| `PLUGIN_UPLOAD_REALDIR` | `data/downloads/plugin/` |
**確認が必要な点**
- `COMPILE_REALDIR` は `data/class/SC_Initial.php:292-301` がリクエスト処理中に `mkdir` します。
Smarty の `compile_check` が有効であればテンプレート更新は自動反映されるため、
4系で必要になる build ディレクトリ分離に相当する対応は 2系では不要になる見込みです(実設定の確認が必要)。
- `PLUGIN_REALDIR` が `html/user_data/plugins/` と公開ディレクトリ配下にある点は、
4系の `app/Plugin`(非公開)と構成が異なるため、レーン分けの検討時に個別の判断が必要です。
- 複数箇所で `umask(0)` が実行されている件(#841)と合わせて整理する必要があります。
### 2. `ec-cube2/cli` へ追加するコマンド
4系 #7072 と同じ仕様に揃えます。
```
design:page:list|show|apply|remove dtb_pagelayout + data/Smarty/templates/**、生成 PHP
design:block:list|show|apply|remove dtb_bloc + テンプレート
design:css:show|apply CSS
design:header:show|apply ヘッダー / フッター
file:list|put|remove html/user_data/**
doctor:permissions 3 レーンの期待値と実際の所有者・権限の差分表示
```
実装は `Application::appendConfigPath()` による拡張機構を利用できるか、
`ec-cube2/cli` 本体へ追加するかを含めて検討します。
### 3. 4系と共有する仕様
**コードの共有は行いません。** `ec-cube2/cli` は PHP 5.3+ / Symfony Console 2.8〜5.4 を対象とし、
4系は PHP 8.2 / Symfony 7.4 を対象とするため互換性がなく、ライセンスも異なります
(`ec-cube2/cli` は LGPL-3.0、本体は GPL-2.0 / 商用デュアル)。
共有するのは **仕様(インターフェース契約)** です。
- コマンド名の体系(`<領域>:<対象>:<動詞>`)
- `apply` を冪等な upsert とする原則(`new` / `edit` に分けない)
- 標準入力の受け口(`--body=-`)
- `--dry-run` の差分表示形式
- `--format=json` の出力スキーマ
- 終了コードの意味(0 = 正常 / 1 = 失敗 / 2 = 完了したが手動操作が必要)
- 権限診断の 3 レーン分類と出力形式
- Web サーバーの実行ユーザー名をコードに固定値で持たず、
Web サーバーが生成するファイル(ログ等)の `fileowner()` から実測する方針
これにより、実装が別であっても**同じ手順書・同じデプロイスクリプト・同じ運用**を両系統で共有できます。
## 進め方
1. 4系 EC-CUBE/ec-cube#7072 の Phase 1〜3 を実装し、仕様を確定させる
2. 確定した仕様に沿って 2系へ実装する(本 issue)
4系のほうが制約が多いため(build / cache ディレクトリの分離、DB レコードとテンプレートファイルの対応、
Doctrine のエンティティプロキシ)、先に 4系で仕様を揉んだほうが 2系の設計が単純になります。
2系側で先行して着手できるものとして、以下があります。
- `Application::appendConfigPath()` が 2系本体側から利用できるかの確認
- 上記レーン分類の精査(特に `PLUGIN_REALDIR` と `umask(0)` の扱い)
## 関連情報 (Ref)
- EC-CUBE/ec-cube#7072 [4.4] Web サーバー権限に依存しないコンテンツ管理 — CLI 導線と build/cache 分離の実装設計
- #841 umask を改善する
- https://doc4.ec-cube.net/permission
- https://qiita.com/nanasess/items/19ef094309f50009c742
- https://zenn.dev/nanasess/articles/choice-hosting-services-of-eccube
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with ec-cube2/cli’s Application::appendConfigPath(), prependConfigPath(), config/services.yaml, and AddConsoleCommandPass to verify how commands can be added. Inspect the listed write paths, SC_Helper_FileManager_Ex::sfWriteFile(), and the referenced design page callers, then compare them with issue #7072. The work is ready when the 2系 command scope, permission lanes, and shared interface contract are confirmed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php, symfony
- Domain
- backend, cli
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100