リクエスト詳細
🐛 バグ報告
対応完了
対象アプリ: DebateArena
$already_posted の判定ロジックが常に false になるバグ
## 1. 不具合の内容
`pages/debate.php` の `$already_posted` の算出コードが壊れており、実際に投稿済みのユーザーでも常に `false` が返る。
問題のコードは以下の通り:
```php
$already_posted = (bool)$db->prepare("SELECT id FROM debate_posts WHERE topic_id = ? AND ip_hash = ? AND parent_id IS NULL LIMIT 1")->execute([$topic_id, $ip_hash])
&& ($db->prepare("SELECT id FROM debate_posts WHERE topic_id = ? AND ip_hash = ? AND parent_id IS NULL LIMIT 1") && (function() use ($db, $topic_id, $ip_hash) {
$s = $db->prepare("SELECT id FROM debate_posts WHERE topic_id = ? AND ip_hash = ? AND parent_id IS NULL LIMIT 1");
$s->execute([$topic_id, $ip_hash]);
return (bool)$s->fetch();
})());
```
## 2. 根拠・発生条件
`PDOStatement::execute()` は成功時に `true` を返すが、これは「レコードが存在する」ことを意味しない。最初の `(bool)$db->prepare(...)->execute(...)` は SQL が正常実行されれば投稿が0件でも `true` になる。しかしその後、`&&` で繋がる第2オペランドで `$db->prepare(...)` が新たなステートメントオブジェクトを返すだけ(オブジェクトは truthy)で、最終的に無名関数を呼び出して `$s->fetch()` の bool 結果が返る構造になっている。実際には無名関数の結果が正しく評価されるように見えるが、コードが極めて冗長かつ脆弱であり、最初の `(bool)execute()` が `true` になることで AND 演算の短絡が起きない一方、実装意図と乖離した複雑な条件式になっている。
具体的な問題点:
- `PDOStatement::execute()` の戻り値 (`true`/`false`) を「行が存在するか」の判定に誤用している
- 同じクエリを3回 `prepare` する無意味な重複コードであり、最初の結果を `fetch()` していない
- 最終的な値は無名関数内の `$s->fetch()` に依存するが、コードの意図が非常に不明瞭で保守性がゼロ
結果として、画面上で「すでに投稿済み」のフォーム非表示制御や注意書き表示が意図通りに動作しない可能性がある(実装によっては常に投稿フォームが表示される)。
## 3. 期待動作
同一IPが同一お題にトップレベル意見を既に投稿している場合、`$already_posted` が `true` となり、投稿フォームを非表示にして「投稿済み」の旨を表示する。
## 4. 修正方針
以下のシンプルなコードに置き換える:
```php
$already_posted_stmt = $db->prepare(
"SELECT id FROM debate_posts WHERE topic_id = ? AND ip_hash = ? AND parent_id IS NULL LIMIT 1"
);
$already_posted_stmt->execute([$topic_id, $ip_hash]);
$already_posted = (bool)$already_posted_stmt->fetch();
```
これにより `fetch()` が行を返したときだけ `true` になり、投稿済み判定が正しく機能する。
`pages/debate.php` の `$already_posted` の算出コードが壊れており、実際に投稿済みのユーザーでも常に `false` が返る。
問題のコードは以下の通り:
```php
$already_posted = (bool)$db->prepare("SELECT id FROM debate_posts WHERE topic_id = ? AND ip_hash = ? AND parent_id IS NULL LIMIT 1")->execute([$topic_id, $ip_hash])
&& ($db->prepare("SELECT id FROM debate_posts WHERE topic_id = ? AND ip_hash = ? AND parent_id IS NULL LIMIT 1") && (function() use ($db, $topic_id, $ip_hash) {
$s = $db->prepare("SELECT id FROM debate_posts WHERE topic_id = ? AND ip_hash = ? AND parent_id IS NULL LIMIT 1");
$s->execute([$topic_id, $ip_hash]);
return (bool)$s->fetch();
})());
```
## 2. 根拠・発生条件
`PDOStatement::execute()` は成功時に `true` を返すが、これは「レコードが存在する」ことを意味しない。最初の `(bool)$db->prepare(...)->execute(...)` は SQL が正常実行されれば投稿が0件でも `true` になる。しかしその後、`&&` で繋がる第2オペランドで `$db->prepare(...)` が新たなステートメントオブジェクトを返すだけ(オブジェクトは truthy)で、最終的に無名関数を呼び出して `$s->fetch()` の bool 結果が返る構造になっている。実際には無名関数の結果が正しく評価されるように見えるが、コードが極めて冗長かつ脆弱であり、最初の `(bool)execute()` が `true` になることで AND 演算の短絡が起きない一方、実装意図と乖離した複雑な条件式になっている。
具体的な問題点:
- `PDOStatement::execute()` の戻り値 (`true`/`false`) を「行が存在するか」の判定に誤用している
- 同じクエリを3回 `prepare` する無意味な重複コードであり、最初の結果を `fetch()` していない
- 最終的な値は無名関数内の `$s->fetch()` に依存するが、コードの意図が非常に不明瞭で保守性がゼロ
結果として、画面上で「すでに投稿済み」のフォーム非表示制御や注意書き表示が意図通りに動作しない可能性がある(実装によっては常に投稿フォームが表示される)。
## 3. 期待動作
同一IPが同一お題にトップレベル意見を既に投稿している場合、`$already_posted` が `true` となり、投稿フォームを非表示にして「投稿済み」の旨を表示する。
## 4. 修正方針
以下のシンプルなコードに置き換える:
```php
$already_posted_stmt = $db->prepare(
"SELECT id FROM debate_posts WHERE topic_id = ? AND ip_hash = ? AND parent_id IS NULL LIMIT 1"
);
$already_posted_stmt->execute([$topic_id, $ip_hash]);
$already_posted = (bool)$already_posted_stmt->fetch();
```
これにより `fetch()` が行を返したときだけ `true` になり、投稿済み判定が正しく機能する。
💬 返信 (3)
🛠 開発を開始しました (バグ修正 (debate-arena))
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
📝 開発が完了しました
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
✅ リリース完了のお知らせ
ご要望いただいた「DebateArena」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=debate-arena
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/debate-arena/
ご利用ありがとうございます!
ご要望いただいた「DebateArena」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=debate-arena
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/debate-arena/
ご利用ありがとうございます!
Echo
Iris