EC-CUBE / EC-CUBE/ec-cube2

SC_ClassAutoloader.php における *_Ex ファイルの期待パスと実際パス相違問題

Open
#1,268 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
PHP
Stars
92
Forks
97
Avg merge
4d 2h
Merged PRs (30d)
9

Description

## 概要

EC-CUBE 2系の`SC_ClassAutoloader.php`において、`*_Ex`クラスファイルの期待パスと実際のファイル配置に相違がある問題について調査した結果をまとめる。

## 問題の発端

- 決済プラグインの提供する `data/class_extends/helper_extends/SC_Helper_Purchase_Ex.php` が正常にロードされない環境がある
- `data/class/SC_ClassAutoloader.php`の145行目からの処理で、`*_Ex`ファイルが存在しない場合はエイリアスを作成している
- composerのオートローダーと、このエイリアスはどちらが優先されるか?
- `data/class_extends/helper_extends/SC_Helper_Purchase_Ex.php`の場合はどちらが優先されるか?

## 正常にロードされない環境での暫定対応

`data/app_initial.php` の末尾で、 require_once にて明示的にロードすることで解消可能

```diff
diff --git a/data/app_initial.php b/data/app_initial.php
index 57e4cf3b5..5e9bac2c3 100755
--- a/data/app_initial.php
+++ b/data/app_initial.php
@@ -65,3 +65,6 @@ SC_Helper_HandleError_Ex::load();
// アプリケーション初期化処理
$objInit = new SC_Initial_Ex();
$objInit->init();
+
+require_once(CLASS_EX_REALDIR . 'helper_extends/SC_Helper_Purchase_Ex.php');
+require_once(CLASS_EX_REALDIR . 'helper_extends/SC_Helper_Payment_Ex.php');
```

## オートローダー優先順位

### 登録順序
1. **Composerオートローダー**: `html/define.php:16-20`で最初にロード
2. **EC-CUBEカスタムオートローダー**: `data/app_initial.php:56-61`で後から登録

### 優先順位の決定要因
```php
spl_autoload_register(
function ($class) {
SC_ClassAutoloader_Ex::autoload($class, __DIR__.'/downloads/plugin/');
},
true, true // 第3引数がtrueで先頭に登録
);
```

**結論**: `spl_autoload_register`の第3引数が`true`のため、**EC-CUBEオートローダーがComposerオートローダーより優先される**。

## パス解決の仕組み

### SC_Helper_Purchase_Ex の例

**1. クラス名の分析**
- `SC_Helper_Purchase_Ex` → `['SC', 'Helper', 'Purchase', 'Ex']`
- `$is_ex = true`(末尾が'Ex')
- `$count = 4`
- `$classpath = CLASS_EX_REALDIR` (`data/class_extends/`)

**2. パス構築(47-59行目の条件分岐)**
条件:`($arrClassNamePart[0] === 'SC') && $is_ex === true && $count >= 4`

**3. 詳細条件(54-58行目)**
```php
if ($count === 4 && $arrClassNamePart[2] != 'Index' && $arrClassNamePart[3] === 'Ex') {
$classpath .= strtolower(implode('/', array_slice($arrClassNamePartTemp, 1, -1))).'/';
}
```

**4. 最終パス構築**
- `$arrClassNamePartTemp = ['SC', 'Helper_extends', 'Purchase', 'Ex']`(50行目で変更)
- `array_slice($arrClassNamePartTemp, 1, -1)` → `['Helper_extends', 'Purchase']`
- 最終的な期待パス:`data/class_extends/helper_extends/purchase/SC_Helper_Purchase_Ex.php`

## 期待パスと実際パスの相違

### 1. SC_Helper_*_Ex 系(24ファイル)

**代表例:SC_Helper_Purchase_Ex**
- **オートローダー期待パス**: `data/class_extends/helper_extends/purchase/SC_Helper_Purchase_Ex.php`
- **実際のファイルパス**: `data/class_extends/helper_extends/SC_Helper_Purchase_Ex.php`

**影響を受けるファイル一覧**:
- SC_Helper_Kiyaku_Ex.php
- SC_Helper_Purchase_Ex.php
- SC_Helper_HandleError_Ex.php
- SC_Helper_Category_Ex.php
- SC_Helper_Mailtemplate_Ex.php
- SC_Helper_PageLayout_Ex.php
- SC_Helper_News_Ex.php
- SC_Helper_Customer_Ex.php
- SC_Helper_Holiday_Ex.php
- SC_Helper_Address_Ex.php
- SC_Helper_Payment_Ex.php
- SC_Helper_FileManager_Ex.php
- SC_Helper_FPDI_Ex.php
- SC_Helper_BestProducts_Ex.php
- SC_Helper_Bloc_Ex.php
- SC_Helper_CSV_Ex.php
- SC_Helper_TaxRule_Ex.php
- SC_Helper_Mail_Ex.php
- SC_Helper_Maker_Ex.php
- SC_Helper_Delivery_Ex.php
- SC_Helper_Plugin_Ex.php
- SC_Helper_Session_Ex.php
- SC_Helper_Transform_Ex.php
- SC_Helper_Mobile_Ex.php
- SC_Helper_DB_Ex.php

### 2. SC_Graph_*_Ex 系(4ファイル)

**代表例:SC_Graph_Bar_Ex**
- **オートローダー期待パス**: `data/class_extends/graph_extends/bar/SC_Graph_Bar_Ex.php`
- **実際のファイルパス**: `data/class_extends/graph_extends/SC_Graph_Bar_Ex.php`

**影響を受けるファイル**:
- SC_Graph_Bar_Ex.php
- SC_Graph_Line_Ex.php
- SC_Graph_Pie_Ex.php
- SC_Graph_Base_Ex.php

### 3. SC_Api_*_Ex 系(3ファイル)

**代表例:SC_Api_Abstract_Ex**
- **オートローダー期待パス**: `data/class_extends/api_extends/abstract/SC_Api_Abstract_Ex.php`
- **実際のファイルパス**: `data/class_extends/api_extends/SC_Api_Abstract_Ex.php`

**影響を受けるファイル**:
- SC_Api_Abstract_Ex.php
- SC_Api_Operation_Ex.php
- SC_Api_Utils_Ex.php

### 4. SC_DB_DBFactory_*_Ex 系(2ファイル)

**代表例:SC_DB_DBFactory_MYSQL_Ex**
- **オートローダー期待パス**: `data/class_extends/db_extends/dbfactory/mysql/SC_DB_DBFactory_MYSQL_Ex.php`
- **実際のファイルパス**: `data/class_extends/db_extends/dbfactory/SC_DB_DBFactory_MYSQL_Ex.php`

**影響を受けるファイル**:
- SC_DB_DBFactory_MYSQL_Ex.php
- SC_DB_DBFactory_PGSQL_Ex.php

### 5. SC_SessionFactory_*_Ex 系(2ファイル)

**代表例:SC_SessionFactory_UseRequest_Ex**
- **オートローダー期待パス**: `data/class_extends/sessionfactory_extends/userequest/SC_SessionFactory_UseRequest_Ex.php`
- **実際のファイルパス**: `data/class_extends/sessionfactory_extends/SC_SessionFactory_UseRequest_Ex.php`

**影響を受けるファイル**:
- SC_SessionFactory_UseRequest_Ex.php
- SC_SessionFactory_UseCookie_Ex.php

### 6. Admin系の深い階層(多数)

**代表例:LC_Page_Admin_Order_Multiple_Ex**
- **オートローダー期待パス**: `data/class_extends/page_extends/admin/order/multiple/LC_Page_Admin_Order_Multiple_Ex.php`
- **実際のファイルパス**: `data/class_extends/page_extends/admin/order/LC_Page_Admin_Order_Multiple_Ex.php`

### 7. operations下のファイル(13ファイル)

**代表例:CartModify_Ex**
- **オートローダー期待パス**: `data/class_extends/CartModify/Ex.php` (PEAR形式のパス変換)
- **実際のファイルパス**: `data/class_extends/api_extends/operations/CartModify_Ex.php`

**影響を受けるファイル**:
- CartModify_Ex.php
- CartAdd_Ex.php
- AddrFromZip_Ex.php
- CartCreate_Ex.php
- ItemSearch_Ex.php
- CartGet_Ex.php
- BrowseNodeLookup_Ex.php
- GetVersion_Ex.php
- Default_Ex.php
- CartClear_Ex.php
- ItemLookup_Ex.php

## ファイル存在チェックの実行箇所

### 主要チェック箇所

1. **SC_ClassAutoloader.php:147行目**(エイリアス作成前)
```php
if (!file_exists($classpath) && str_contains($class, '_Ex')) {
class_alias(preg_replace('/_Ex$/', '', $class), $class);
}
```

2. **SC_ClassAutoloader.php:152行目**(メインのファイルロード)
```php
if (file_exists($classpath)) {
include $classpath;
} else {
// include_pathでの検索処理(155-162行目)
}
```

### 実際の動作フロー

期待パスと実際パスに相違がある場合:

1. 152行目の`file_exists($classpath)`が**false**を返す
2. 155-162行目のinclude_path検索が実行される
3. **Composerのclassmapオートローダー**が実際のファイルパスを把握しているため、最終的にファイルがロードされる
4. **147-149行目のエイリアス作成処理は実行されない**(ファイルが存在するため)

ただし、環境によってはエイリアス作成処理が実行され、 `*_Ex` クラスが正常にロードされない場合がある模様

## 影響範囲

### 合計影響ファイル数
**約70個以上**のファイルで期待パスと実際パスに相違があると推定される。

### 正常に動作する理由
1. Composerのclassmapが実際のファイル位置を正確に把握
2. include_path検索によるフォールバック機能
3. spl_autoload_register チェーンによる複数オートローダー連携

## 技術的考察

### 問題の根本原因
- EC-CUBEオートローダーのパス構築ロジックが実際のファイル配置規則と一致していない
- SC_ClassAutoloader.php:49行目のコメント「クラスファイルのディレクトリ命名が変。変な現状に合わせて強引な処理をしてる。」が示す通り、既知の設計問題

### 現在の解決策
- Composer classmapとinclude_path検索によるフォールバック機能で実質的に解決されている
- パフォーマンス上の軽微な影響はあるものの、機能的には問題なし
- 環境によってはエイリアス作成処理が優先されてしまう場合があるので、修正が望ましい

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.