댓글 6 / 19
보상 + 1 보상 포인트
BUG 待修复

PS: 已通过修改 /app/views/htm/message.htm 实现目标效果,不知有无未知问题。
보상 + 2 보상 포인트
可以接受
找到根因了。這不是 CSRF 驗證失敗,而是一個被 誤包裝成 CSRF 錯誤 的 PHP TypeError。
真正的出錯位置
app/Utils/HttpLink.php:26-28 的 httpUrlPath():
$len = strrpos($php_self, '//');
false === $len and $len = strrpos($php_self, '/');
$path = substr($php_self, 0, $len); // ← 當 $len === false 時,strict_types 下拋 TypeError當 $php_self(來自 IpHelper::scriptName() → $_SERVER['PHP_SELF']/SCRIPT_NAME)不含 / 或為空字串 時,兩個 strrpos 都回傳 false,$len = false,於是 substr('', 0, false) 在 declare(strict_types=1) 下拋出: substr(): Argument #3 ($length) must be of type ?int, false given
觸發鏈路
POST /admin/store/signin
→ StoreController::signin() (StoreController.php:309)
→ MarketClient::getCommonParams() (MarketClient.php:847, 組裝 'app_url')
→ HttpLink::httpUrlPath() (HttpLink.php:28) ← TypeError為什麼會顯示「CSRF verification error」
關鍵在 CsrfMiddleware 是最內層的 meta 中間件:
- 路由 meta 依序 merge 成
requiresAdminSignIn→requiresUserPerm→requiresCsrf(Router.php:82array_merge($groupMeta, $meta))。 - MetaDispatcher 依此順序組建 stack,所以執行鏈是
AdminSignIn → UserPerm → Csrf → 控制器,Csrf 離控制器最近。 CsrfMiddleware::process()的 try 包住了$handler->handle($request)(CsrfMiddleware.php:55),因此下游控制器的任何 Throwable 都會被它捕獲並包裝成'CSRF verification error: ' . $e->getMessage()(CsrfMiddleware.php:63)。
也就是說:CSRF token 本身校驗通過,真正炸掉的是控制器內 httpUrlPath() 的 substr。這也解釋了為何「用戶名密碼正確仍報錯」——請求根本沒發到 wellcms.com。
修復方案(建議)
- 修
HttpLink::httpUrlPath()(真正根因):另外可考慮讓$len = strrpos($php_self, '//'); if (false === $len) { $len = strrpos($php_self, '/'); } $path = false === $len ? '' : substr($php_self, 0, $len);IpHelper::scriptName()空值時回退到REQUEST_URI解析。 - (可選)改善
CsrfMiddleware的誤導性包裝:只有 CSRF 校驗本身的邏輯失敗才用該訊息,下游異常應重新拋出(if (\DEBUG >= 2) throw $e;目前只對 DEBUG 生效)。
app/Utils/HttpLink.php 相應代碼後,確實順利登入插件商店。먼저 로그인하세요
토론에 참여하시겠습니까? 먼저 계정에 로그인하세요.
