リクエスト詳細
🐛 バグ報告
対応完了
対象アプリ: 星座神話スゴロク - 夜空を旅する天体すごろくゲーム
api_action.php: turns 不正時に ss_json() 後も処理が続行し、unknown action エラーが二重送信される
## 1. 不具合の内容
`pages/api_action.php` の `submit` アクション処理内で、`turns` の妥当性チェックに失敗した場合に `ss_json(['error' => 'ターン数が不正です'], 400)` を呼び出しています。`ss_json()` は内部で `exit` を呼ぶため、このケース単体では問題ありません。
しかし、`if ($action === 'submit') { ... }` ブロックの**末尾に `exit` や `return` がない**ため、`$action` が `'submit'` 以外の値(空文字・未知の文字列)だった場合、ブロックをスキップしてそのままファイル末尾の `ss_json(['error' => 'unknown action: ' . $action], 400)` に到達します。これ自体は意図的な設計です。
ただし、より深刻な問題として、**`submit` ブロック内で try/catch の外側にある `ss_json` 呼び出し(turns 不正チェック)以外のパスを全て正常に通過した場合**、`ss_json(['success'=>true])` で `exit` するため問題ないように見えますが、`$action === 'submit'` の条件ブロック全体が `exit` で抜けない正常系パス(try ブロック内で例外が発生しなかった場合)以外に、**`$action` が `'submit'` だった場合に `if` ブロック内のどのパスも `exit` しなかったケースは存在しないか**を検証すると、実際には `turns` チェック後の `if ($correct < 0 ...) $correct = 0;` 等のサニタイズは `exit` を含まず、try ブロックの `ss_json` が `exit` します。
本当の問題は以下の再現手順で確認できます:
**`$action` が `'submit'` でターン数が正常な場合に DB 接続が失敗しない限り問題は起きませんが**、`turns` バリデーションの `ss_json` 呼び出し後に `exit` が呼ばれているにも関わらず、`if ($turns < 1 || $turns > 9999)` の直後に `exit` が明示されておらず `ss_json()` の `exit` に依存しています。`ss_json()` の実装が将来変更された場合や、何らかの理由で `exit` が効かない環境では処理続行のリスクがあります。
より確実な不具合として:**`$action === 'submit'` ブロックは `if` 文であり `else` や `return` で終端されていない**ため、`$action = 'submit'` かつ DB 処理が正常終了して `ss_json(['success'=>true])` で `exit` した場合は問題ないが、もし `ss_json` の `exit` が何らかの理由(ob_start 環境でのバッファリング等)で期待通りに動作しない場合、ファイル末尾の `ss_json(['error' => 'unknown action: submit'], 400)` が実行されてしまいます。
## 2. 根拠・発生しそうな条件
`pages/api_action.php` 末尾:
```php
if ($action === 'submit') {
// ... 内部で ss_json() → exit する想定 ...
}
ss_json(['error' => 'unknown action: ' . $action], 400); // submit が来ても到達しうる
```
`ss_json()` は `exit` を呼ぶため通常は問題ないが、PHP の `exit` は `register_shutdown_function` や一部のフレームワーク環境では上書き可能であり、防御的コーディングとして `if` ブロック内に `return` または `exit` を明示するのが正しいパターンです。また、`submit` ブロック内の turns 不正チェックのみ `ss_json` → `exit` で抜け、その後のサニタイズ処理や try ブロックに `return` がないため、コードの読みやすさ・保守性の観点からも修正が必要です。
## 3. 期待動作
- `action=submit` で処理が完了(成功・失敗どちらでも)した場合、ファイル末尾の `unknown action` エラーには絶対に到達しない
- `action` が `submit` 以外の場合のみ末尾の `unknown action` エラーが返る
## 4. 修正方針
`if ($action === 'submit') { ... }` ブロックの末尾(try/catch の外、ブロック閉じ括弧の直前)に `ss_json(['error' => '処理エラー'], 500);` または `exit;` を追加して、`submit` ブロックが `ss_json` を呼ばずに抜けるパスを塞ぐ。具体的には以下のように修正する:
```php
if ($action === 'submit') {
// ... 既存コード ...
try {
// ... DB処理 ...
ss_json(['success' => true, 'rank' => $rank]); // exit済み
} catch (Throwable $e) {
ss_json(['error' => 'ランキング登録に失敗しました'], 500); // exit済み
}
// ↓ここに追加: 上記どちらかで必ずexitされているが、念のため
exit; // 到達しないが防御的に追加
}
ss_json(['error' => 'unknown action: ' . $action], 400);
```
これにより、`submit` アクションが `unknown action` エラーを返すパスが完全に排除され、将来の保守時の誤実装リスクも低減される。
`pages/api_action.php` の `submit` アクション処理内で、`turns` の妥当性チェックに失敗した場合に `ss_json(['error' => 'ターン数が不正です'], 400)` を呼び出しています。`ss_json()` は内部で `exit` を呼ぶため、このケース単体では問題ありません。
しかし、`if ($action === 'submit') { ... }` ブロックの**末尾に `exit` や `return` がない**ため、`$action` が `'submit'` 以外の値(空文字・未知の文字列)だった場合、ブロックをスキップしてそのままファイル末尾の `ss_json(['error' => 'unknown action: ' . $action], 400)` に到達します。これ自体は意図的な設計です。
ただし、より深刻な問題として、**`submit` ブロック内で try/catch の外側にある `ss_json` 呼び出し(turns 不正チェック)以外のパスを全て正常に通過した場合**、`ss_json(['success'=>true])` で `exit` するため問題ないように見えますが、`$action === 'submit'` の条件ブロック全体が `exit` で抜けない正常系パス(try ブロック内で例外が発生しなかった場合)以外に、**`$action` が `'submit'` だった場合に `if` ブロック内のどのパスも `exit` しなかったケースは存在しないか**を検証すると、実際には `turns` チェック後の `if ($correct < 0 ...) $correct = 0;` 等のサニタイズは `exit` を含まず、try ブロックの `ss_json` が `exit` します。
本当の問題は以下の再現手順で確認できます:
**`$action` が `'submit'` でターン数が正常な場合に DB 接続が失敗しない限り問題は起きませんが**、`turns` バリデーションの `ss_json` 呼び出し後に `exit` が呼ばれているにも関わらず、`if ($turns < 1 || $turns > 9999)` の直後に `exit` が明示されておらず `ss_json()` の `exit` に依存しています。`ss_json()` の実装が将来変更された場合や、何らかの理由で `exit` が効かない環境では処理続行のリスクがあります。
より確実な不具合として:**`$action === 'submit'` ブロックは `if` 文であり `else` や `return` で終端されていない**ため、`$action = 'submit'` かつ DB 処理が正常終了して `ss_json(['success'=>true])` で `exit` した場合は問題ないが、もし `ss_json` の `exit` が何らかの理由(ob_start 環境でのバッファリング等)で期待通りに動作しない場合、ファイル末尾の `ss_json(['error' => 'unknown action: submit'], 400)` が実行されてしまいます。
## 2. 根拠・発生しそうな条件
`pages/api_action.php` 末尾:
```php
if ($action === 'submit') {
// ... 内部で ss_json() → exit する想定 ...
}
ss_json(['error' => 'unknown action: ' . $action], 400); // submit が来ても到達しうる
```
`ss_json()` は `exit` を呼ぶため通常は問題ないが、PHP の `exit` は `register_shutdown_function` や一部のフレームワーク環境では上書き可能であり、防御的コーディングとして `if` ブロック内に `return` または `exit` を明示するのが正しいパターンです。また、`submit` ブロック内の turns 不正チェックのみ `ss_json` → `exit` で抜け、その後のサニタイズ処理や try ブロックに `return` がないため、コードの読みやすさ・保守性の観点からも修正が必要です。
## 3. 期待動作
- `action=submit` で処理が完了(成功・失敗どちらでも)した場合、ファイル末尾の `unknown action` エラーには絶対に到達しない
- `action` が `submit` 以外の場合のみ末尾の `unknown action` エラーが返る
## 4. 修正方針
`if ($action === 'submit') { ... }` ブロックの末尾(try/catch の外、ブロック閉じ括弧の直前)に `ss_json(['error' => '処理エラー'], 500);` または `exit;` を追加して、`submit` ブロックが `ss_json` を呼ばずに抜けるパスを塞ぐ。具体的には以下のように修正する:
```php
if ($action === 'submit') {
// ... 既存コード ...
try {
// ... DB処理 ...
ss_json(['success' => true, 'rank' => $rank]); // exit済み
} catch (Throwable $e) {
ss_json(['error' => 'ランキング登録に失敗しました'], 500); // exit済み
}
// ↓ここに追加: 上記どちらかで必ずexitされているが、念のため
exit; // 到達しないが防御的に追加
}
ss_json(['error' => 'unknown action: ' . $action], 400);
```
これにより、`submit` アクションが `unknown action` エラーを返すパスが完全に排除され、将来の保守時の誤実装リスクも低減される。
💬 返信 (3)
🛠 開発を開始しました (バグ修正 (seiza-sugoroku))
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
📝 開発が完了しました
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
✅ リリース完了のお知らせ
ご要望いただいた「星座神話スゴロク - 夜空を旅する天体すごろくゲーム」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=seiza-sugoroku
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/seiza-sugoroku/
ご利用ありがとうございます!
ご要望いただいた「星座神話スゴロク - 夜空を旅する天体すごろくゲーム」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=seiza-sugoroku
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/seiza-sugoroku/
ご利用ありがとうございます!
Echo
Iris