fix #4303 【メール】マルチチェックボックスの各選択肢が自動でspanタグで囲まれる問題を解決#4316
fix #4303 【メール】マルチチェックボックスの各選択肢が自動でspanタグで囲まれる問題を解決#4316ryuring merged 3 commits intobaserproject:5.2.xfrom
Conversation
・入力画面にヘルプも追加しています。
There was a problem hiding this comment.
Pull request overview
このプルリクエストは、baserCMS のメールフォーム機能において、マルチチェックボックスの各選択肢が自動的に span タグで囲まれる問題(Issue #4303)を解決することを目的としています。ユーザーがカスタムのラッピング要素(例:div タグやクラス付き要素)を指定できるよう、templateVars.tag オプションのサポートを追加しています。
Changes:
- MailformHelper.php に
templateVars.tagオプションの処理ロジックを追加 - 管理画面のメールフィールドフォームに、
templateVars.tagオプションの使用方法を説明するヘルプテキストを追加
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| plugins/bc-mail/src/View/Helper/MailformHelper.php | マルチチェックボックスで templateVars.tag オプションが指定された場合の処理ロジックを追加。有効なタグ名(div, span, p, li, dt, dd, label)のバリデーションを実装 |
| plugins/bc-admin-third/templates/plugin/BcMail/Admin/element/MailFields/form.php | オプション欄にヘルプアイコンとヘルプテキストを追加。placeholder、empty、templateVars.tag の3つのオプションの使用方法を記載 |
| if (!empty($attributes['templateVars.tag'])) { | ||
| // 取得した値が有効なタグか確認 | ||
| $validTags = ['div', 'span', 'p', 'li', 'dt', 'dd', 'label']; | ||
| foreach ($validTags as $validTag) { | ||
| // templateVars.tagが有効なタグ名から始まっている場合、$attributes['templateVars']['tag'] にセット | ||
| if (str_starts_with($attributes['templateVars.tag'], $validTag)) { | ||
| $attributes['templateVars']['tag'] = $attributes['templateVars.tag']; | ||
| break; | ||
| } | ||
| } | ||
| // inputタグに出力されないようにunset | ||
| unset($attributes['templateVars.tag']); | ||
| } |
There was a problem hiding this comment.
セキュリティ上の懸念:$attributes['templateVars.tag'] の値がそのままHTMLに出力される可能性があります。ユーザーが div onclick="alert('XSS')" のような悪意のある入力を行った場合、XSS脆弱性につながる可能性があります。
タグ名と属性を分離し、属性値を適切にエスケープする処理を追加することを推奨します。または、属性の指定を許可せず、タグ名のみを受け入れるように仕様を変更することも検討してください。
| foreach ($validTags as $validTag) { | ||
| // templateVars.tagが有効なタグ名から始まっている場合、$attributes['templateVars']['tag'] にセット | ||
| if (str_starts_with($attributes['templateVars.tag'], $validTag)) { | ||
| $attributes['templateVars']['tag'] = $attributes['templateVars.tag']; | ||
| break; | ||
| } | ||
| } |
There was a problem hiding this comment.
有効なタグに一致しない場合の処理が不完全です。ループ内でbreakが実行されなかった場合(つまり、有効なタグが見つからなかった場合)、$attributes['templateVars']['tag'] はデフォルトの 'span' のままになりますが、無効な入力に対する明示的な処理やログ記録がありません。
無効な値が入力された場合は、警告ログを記録するか、デフォルト値を使用していることをユーザーに通知することを検討してください。
| <dt>empty</dt> | ||
| <dd>セレクトボックスの何も選択していないときの表示は、次の形式のように | 区切りで入力します。「empty|何も選択していないときのメッセージ」</dd> | ||
| <dt>templateVars.tag</dt> | ||
| <dd>マルチチェックボックスでそれぞれのインプットタグをラッピングする要素を指定します。例)templateVars.tag|div class="checkbox"(div class="checkbox"で囲む)<br>※デフォルトはspanタグでラッピングされます。</dd> |
There was a problem hiding this comment.
ヘルプテキストの例に誤解を招く可能性があります。「div class="checkbox"」という例は、クラス属性を含むタグを指定できることを示唆していますが、実際のコード実装ではこれが適切に処理されていません(セキュリティとロジックの問題については他のコメントを参照)。
実装が修正されるまで、ヘルプテキストの例を単純なタグ名のみに変更することを推奨します。例:「templateVars.tag|div」
| <dd>マルチチェックボックスでそれぞれのインプットタグをラッピングする要素を指定します。例)templateVars.tag|div class="checkbox"(div class="checkbox"で囲む)<br>※デフォルトはspanタグでラッピングされます。</dd> | |
| <dd>マルチチェックボックスでそれぞれのインプットタグをラッピングする要素を指定します。例)templateVars.tag|div(divタグで囲む)<br>※デフォルトはspanタグでラッピングされます。</dd> |
| if (!empty($attributes['templateVars.tag'])) { | ||
| // 取得した値が有効なタグか確認 | ||
| $validTags = ['div', 'span', 'p', 'li', 'dt', 'dd', 'label']; | ||
| foreach ($validTags as $validTag) { | ||
| // templateVars.tagが有効なタグ名から始まっている場合、$attributes['templateVars']['tag'] にセット | ||
| if (str_starts_with($attributes['templateVars.tag'], $validTag)) { | ||
| $attributes['templateVars']['tag'] = $attributes['templateVars.tag']; | ||
| break; | ||
| } | ||
| } | ||
| // inputタグに出力されないようにunset | ||
| unset($attributes['templateVars.tag']); | ||
| } |
There was a problem hiding this comment.
新しく追加された templateVars.tag オプション処理機能に対するユニットテストが不足しています。以下のテストケースを追加することを推奨します:
- 有効なタグ名(例:'div', 'span', 'p')が正しく処理されることを確認
- タグ名とクラス属性を含む入力(例:'div class="checkbox"')の処理を確認
- 無効なタグ名が入力された場合のデフォルト動作を確認
templateVars.tagが指定されていない場合のデフォルト動作を確認
MailformHelperTest.php に testControlWithTemplateVarsTag のようなテストメソッドを追加してください。
| foreach ($validTags as $validTag) { | ||
| // templateVars.tagが有効なタグ名から始まっている場合、$attributes['templateVars']['tag'] にセット | ||
| if (str_starts_with($attributes['templateVars.tag'], $validTag)) { | ||
| $attributes['templateVars']['tag'] = $attributes['templateVars.tag']; |
There was a problem hiding this comment.
行185の代入が不適切です。$attributes['templateVars']['tag'] に $attributes['templateVars.tag'] をそのまま代入していますが、これでは検証の意味がありません。代わりに、検証されたタグ名(例:$validTag)またはクラスを含む全体の文字列を適切に処理する必要があります。
例えば、ユーザーが templateVars.tag|div class="checkbox" と入力した場合、div class="checkbox" 全体を代入するのではなく、タグ名とクラスを分離して処理することを検討してください。
| foreach ($validTags as $validTag) { | |
| // templateVars.tagが有効なタグ名から始まっている場合、$attributes['templateVars']['tag'] にセット | |
| if (str_starts_with($attributes['templateVars.tag'], $validTag)) { | |
| $attributes['templateVars']['tag'] = $attributes['templateVars.tag']; | |
| $rawTemplateTag = $attributes['templateVars.tag']; | |
| foreach ($validTags as $validTag) { | |
| // templateVars.tagが有効なタグ名から始まっている場合、タグ名とクラス属性を分離して処理 | |
| if (str_starts_with($rawTemplateTag, $validTag)) { | |
| // 検証済みのタグ名のみをtemplateVars['tag']にセット | |
| $attributes['templateVars']['tag'] = $validTag; | |
| // 先頭のタグ名以降の文字列を取得(例: ' class="checkbox"') | |
| $rest = trim(substr($rawTemplateTag, strlen($validTag))); | |
| if ($rest !== '') { | |
| // class属性が指定されている場合は抽出して$attributes['class']にマージ | |
| if (preg_match('/class\s*=\s*([\'"])(.*?)\1/i', $rest, $classMatches)) { | |
| $newClass = $classMatches[2]; | |
| if ($newClass !== '') { | |
| if (!empty($attributes['class'])) { | |
| if (is_array($attributes['class'])) { | |
| $existingClass = implode(' ', $attributes['class']); | |
| } else { | |
| $existingClass = (string)$attributes['class']; | |
| } | |
| $attributes['class'] = trim($existingClass . ' ' . $newClass); | |
| } else { | |
| $attributes['class'] = $newClass; | |
| } | |
| } | |
| } | |
| } |
There was a problem hiding this comment.
ラッピング要素付与するはずの属性がinputタグに付与されてしまうため、
Copilotの指摘は間違っています。(CopilotがCakePHPの仕様を正しく理解できていない)
出力するべき要素(ラッピング要素に指定した属性を付与)
<div class="checkbox">
<input type="checkbox" name="agree[]" value="同意します。" id="agree-同意します。" class="" required="required">
<label for="agree-同意します。" class="">同意します。</label>
</div>
Copilotの指摘のように タグと付与属性を分けた場合の出力(ラッピング要素ではなく、inputタグに属性が付与されてしまい、全く意味をなさない)
<div class="">
<input type="checkbox" name="agree[]" value="同意します。" id="agree-同意します。" class="checkbox" required="required">
<label for="agree-同意します。" class="">同意します。</label>
</div>
There was a problem hiding this comment.
ヘルプテキストの例に誤解を招く可能性があります。「div class="checkbox"」という例は、クラス属性を含むタグを指定できることを示唆していますが、実際のコード実装ではこれが適切に処理されていません
これも全く的外れの指摘のため、完全に無視して構いません。
ラッピング要素にclassやdata属性を付与できるのもcakePHPの仕様です。
セキュリティ上懸念のある、on属性などを除外しておけば、問題ありません、
| $attributes['empty'] = false; | ||
| $attributes['templateVars']['tag'] = 'span'; | ||
| // オプションでtemplateVars.tagが指定されていた場合の対応 | ||
| if (!empty($attributes['templateVars.tag'])) { |
|
設定名を |
|
@katokaisya ありがとうございます! |
* ブログ記事編集画面からブログタグ追加時の挙動調整 * 各プラグインの依存パッケージを更新 * basercms-5.2.2 をリリース * baser-core の composer.json のバージョン番号を更新 * monorepo-builderによる変更を反映 * fix #4302 【メール】フィールド登録画面にて郵便番号登録すると正規表現チェックしか選べなくなる問題を解決 * Copilot レビュー対応 * Jwt を 7.0.2 にアップデート (#4315) * fix #4308 【アップローダー】「.docx」「.xlsx」だと公開期間の指定が効いていない (#4310) * 固定ページ・ブログ記事 afterAddイベント追加 (#4312) * ヘルプを調整 * Bump symfony/process from 6.4.31 to 6.4.33 (#4307) Bumps [symfony/process](https://github.com/symfony/process) from 6.4.31 to 6.4.33. - [Release notes](https://github.com/symfony/process/releases) - [Changelog](https://github.com/symfony/process/blob/8.1/CHANGELOG.md) - [Commits](symfony/process@v6.4.31...v6.4.33) --- updated-dependencies: - dependency-name: symfony/process dependency-version: 6.4.33 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump phpunit/phpunit from 10.5.31 to 10.5.62 (#4317) Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 10.5.31 to 10.5.62. - [Release notes](https://github.com/sebastianbergmann/phpunit/releases) - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.5.62/ChangeLog-10.5.md) - [Commits](sebastianbergmann/phpunit@10.5.31...10.5.62) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-version: 10.5.62 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump webpack from 5.102.1 to 5.104.1 (#4309) Bumps [webpack](https://github.com/webpack/webpack) from 5.102.1 to 5.104.1. - [Release notes](https://github.com/webpack/webpack/releases) - [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md) - [Commits](webpack/webpack@v5.102.1...v5.104.1) --- updated-dependencies: - dependency-name: webpack dependency-version: 5.104.1 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump axios from 1.13.0 to 1.13.5 (#4313) Bumps [axios](https://github.com/axios/axios) from 1.13.0 to 1.13.5. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](axios/axios@v1.13.0...v1.13.5) --- updated-dependencies: - dependency-name: axios dependency-version: 1.13.5 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: Claude Code の worktree ディレクトリを .gitignore に追加 * 開発版へのアップデートの際、バージョン番号に -dev が入っていてもアップデートができるように調整 * アップデートの際、開発版をダウンロードする際にダウンロードボタンをクリックできない問題を改善 * バージョン番号を開発版に更新 * baser-coreが必要とするコアプラグインのバージョン番号を開発版に更新 * 【メール】管理者宛メール本文にユーザーのIPアドレスを表示する fix #4321 メールフォームが脅迫等に悪用された際に通報しやすくするため、 管理者宛メールの末尾にフォーム送信者のIPアドレスを表示する。 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix #4319 【メール】Cache-Controlヘッダ (no-cache no-store must-revalidate)が出力されない件を修正 (#4327) * fix #4319 【メール】Cache-Controlヘッダ (no-cache no-store must-revalidate)が出力されない件を修正 * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix #4299 ユーザーが存在するユーザーグループを削除できないようにする (#4329) - UserGroupsService::delete() で所属ユーザーの存在確認を追加 - ユーザーが所属している場合は BcException をスローして削除を拒否 - API/管理画面コントローラーにエラーハンドリングを追加 - ユニットテストと統合テストを追加 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix #4326 管理画面のオプション部分などのアコーディオンの開閉を記録・復元する機能を追加 * fix #4333 【システム】 存在しないフォントを指定してる箇所があり404になっている件を修正 (#4335) * fix BlogPostsControllerTest.php の UnitTestエラーを修正 (#4336) * fix #4303 【メール】マルチチェックボックスの各選択肢が自動でspanタグで囲まれる問題を解決 (#4316) 設定名を checkboxWrapTag とする * fix #4276 キャッシュクリアのキャンセル時にツールバーの背景が白くなる問題を修正 onclick の return false により defaultPrevented が true になるケース(confirm ダイアログでキャンセル)を e.isDefaultPrevented() で検出し、active クラスの付与をスキップするよう修正 Co-authored-by: terao <> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: momofff <ryosuke.momoi@gmail.com> Co-authored-by: kato <kato@e-catchup.jp> Co-authored-by: ryuring <egashira@catchup.co.jp> Co-authored-by: fuchigam1 <contact@materializing.net> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: sakaguchi <sakaguchi@catchup.co.jp> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: kawaseryoma <161787083+kawaseryoma@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: 加藤 朗 <kato.kaisya@gmail.com> Co-authored-by: tera <52107087+teratai3@users.noreply.github.com>
* ブログ記事編集画面からブログタグ追加時の挙動調整 * fix #4302 【メール】フィールド登録画面にて郵便番号登録すると正規表現チェックしか選べなくなる問題を解決 * Copilot レビュー対応 * containsScript調整 * Jwt を 7.0.2 にアップデート (#4315) * fix #4308 【アップローダー】「.docx」「.xlsx」だと公開期間の指定が効いていない (#4310) * 固定ページ・ブログ記事 afterAddイベント追加 (#4312) * ヘルプを調整 * Bump symfony/process from 6.4.31 to 6.4.33 (#4307) Bumps [symfony/process](https://github.com/symfony/process) from 6.4.31 to 6.4.33. - [Release notes](https://github.com/symfony/process/releases) - [Changelog](https://github.com/symfony/process/blob/8.1/CHANGELOG.md) - [Commits](symfony/process@v6.4.31...v6.4.33) --- updated-dependencies: - dependency-name: symfony/process dependency-version: 6.4.33 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump phpunit/phpunit from 10.5.31 to 10.5.62 (#4317) Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 10.5.31 to 10.5.62. - [Release notes](https://github.com/sebastianbergmann/phpunit/releases) - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.5.62/ChangeLog-10.5.md) - [Commits](sebastianbergmann/phpunit@10.5.31...10.5.62) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-version: 10.5.62 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump webpack from 5.102.1 to 5.104.1 (#4309) Bumps [webpack](https://github.com/webpack/webpack) from 5.102.1 to 5.104.1. - [Release notes](https://github.com/webpack/webpack/releases) - [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md) - [Commits](webpack/webpack@v5.102.1...v5.104.1) --- updated-dependencies: - dependency-name: webpack dependency-version: 5.104.1 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump axios from 1.13.0 to 1.13.5 (#4313) Bumps [axios](https://github.com/axios/axios) from 1.13.0 to 1.13.5. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](axios/axios@v1.13.0...v1.13.5) --- updated-dependencies: - dependency-name: axios dependency-version: 1.13.5 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: Claude Code の worktree ディレクトリを .gitignore に追加 * containsScript の修正と baser-core/composer.json への htmlpurifier 追加 - html_entity_decode に ENT_QUOTES, UTF-8 を明示(
 等の数値文字参照を確実に復号) - javascript: スキーム検出の正規表現に formaction / codebase / data 属性を追加 (<object codebase="javascript:..."> / <button formaction="javascript:..."> に対応) - HTMLPurifier のキャッシュ設定を修正(Cache.DefinitionImpl: null を削除、DefinitionRev を追加) - plugins/baser-core/composer.json に ezyang/htmlpurifier ^4.19 を追加(monorepo 対応) - object / formaction ベクターのテストケースを追加 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * 開発版へのアップデートの際、バージョン番号に -dev が入っていてもアップデートができるように調整 * アップデートの際、開発版をダウンロードする際にダウンロードボタンをクリックできない問題を改善 * バージョン番号を開発版に更新 * baser-coreが必要とするコアプラグインのバージョン番号を開発版に更新 * 【メール】管理者宛メール本文にユーザーのIPアドレスを表示する fix #4321 メールフォームが脅迫等に悪用された際に通報しやすくするため、 管理者宛メールの末尾にフォーム送信者のIPアドレスを表示する。 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix #4319 【メール】Cache-Controlヘッダ (no-cache no-store must-revalidate)が出力されない件を修正 (#4327) * fix #4319 【メール】Cache-Controlヘッダ (no-cache no-store must-revalidate)が出力されない件を修正 * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * containsScript調整 * fix #4299 ユーザーが存在するユーザーグループを削除できないようにする (#4329) - UserGroupsService::delete() で所属ユーザーの存在確認を追加 - ユーザーが所属している場合は BcException をスローして削除を拒否 - API/管理画面コントローラーにエラーハンドリングを追加 - ユニットテストと統合テストを追加 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix #4326 管理画面のオプション部分などのアコーディオンの開閉を記録・復元する機能を追加 * fix #4333 【システム】 存在しないフォントを指定してる箇所があり404になっている件を修正 (#4335) * fix BlogPostsControllerTest.php の UnitTestエラーを修正 (#4336) * fix #4303 【メール】マルチチェックボックスの各選択肢が自動でspanタグで囲まれる問題を解決 (#4316) 設定名を checkboxWrapTag とする * fix #4276 キャッシュクリアのキャンセル時にツールバーの背景が白くなる問題を修正 onclick の return false により defaultPrevented が true になるケース(confirm ダイアログでキャンセル)を e.isDefaultPrevented() で検出し、active クラスの付与をスキップするよう修正 Co-authored-by: terao <> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: kato <kato@e-catchup.jp> Co-authored-by: ryuring <egashira@catchup.co.jp> Co-authored-by: fuchigam1 <contact@materializing.net> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: sakaguchi <sakaguchi@catchup.co.jp> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: kawaseryoma <161787083+kawaseryoma@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: 加藤 朗 <kato.kaisya@gmail.com> Co-authored-by: tera <52107087+teratai3@users.noreply.github.com>
・入力画面にヘルプも追加しています。
