From 985d4d80118a0418bc4cc7e216fb71556453c91e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:58:48 +0000 Subject: [PATCH 1/4] Initial plan From 022aee38adb3bc2568229a4f469e06d4719f2b06 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:14:44 +0000 Subject: [PATCH 2/4] Fix umlaut encoding issue in user display names Co-authored-by: thorsten <45284+thorsten@users.noreply.github.com> --- .../Administration/UserController.php | 4 ++-- .../Frontend/RegistrationController.php | 2 +- .../Controller/Frontend/UserController.php | 2 +- phpmyfaq/src/phpMyFAQ/User/UserData.php | 5 +++++ tests/phpMyFAQ/User/UserDataTest.php | 22 +++++++++++++++++++ 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/phpmyfaq/src/phpMyFAQ/Controller/Administration/UserController.php b/phpmyfaq/src/phpMyFAQ/Controller/Administration/UserController.php index 4ece8eec17..f925cd29a3 100644 --- a/phpmyfaq/src/phpMyFAQ/Controller/Administration/UserController.php +++ b/phpmyfaq/src/phpMyFAQ/Controller/Administration/UserController.php @@ -296,7 +296,7 @@ public function addUser(Request $request): JsonResponse $errorMessage = []; $userName = Filter::filterVar($data->userName, FILTER_SANITIZE_SPECIAL_CHARS); - $userRealName = Filter::filterVar($data->realName, FILTER_SANITIZE_SPECIAL_CHARS); + $userRealName = trim(strip_tags((string) $data->realName)); $userEmail = Filter::filterVar($data->email, FILTER_VALIDATE_EMAIL); $automaticPassword = Filter::filterVar($data->automaticPassword, FILTER_VALIDATE_BOOLEAN); $userPassword = Filter::filterVar($data->password, FILTER_SANITIZE_SPECIAL_CHARS); @@ -366,7 +366,7 @@ public function editUser(Request $request): JsonResponse return $this->json(['error' => Translation::get('ad_user_error_noId')], Response::HTTP_BAD_REQUEST); } else { $userData = []; - $userData['display_name'] = Filter::filterVar($data->display_name, FILTER_SANITIZE_SPECIAL_CHARS); + $userData['display_name'] = trim(strip_tags((string) $data->display_name)); $userData['email'] = Filter::filterVar($data->email, FILTER_VALIDATE_EMAIL); $userData['last_modified'] = Filter::filterVar($data->last_modified, FILTER_SANITIZE_SPECIAL_CHARS); $userStatus = Filter::filterVar($data->user_status, FILTER_SANITIZE_SPECIAL_CHARS, 'active'); diff --git a/phpmyfaq/src/phpMyFAQ/Controller/Frontend/RegistrationController.php b/phpmyfaq/src/phpMyFAQ/Controller/Frontend/RegistrationController.php index 7de1bb966a..4ec793e20a 100644 --- a/phpmyfaq/src/phpMyFAQ/Controller/Frontend/RegistrationController.php +++ b/phpmyfaq/src/phpMyFAQ/Controller/Frontend/RegistrationController.php @@ -39,7 +39,7 @@ public function create(Request $request): JsonResponse $data = json_decode($request->getContent(), false, 512, JSON_THROW_ON_ERROR); - $fullName = trim((string) Filter::filterVar($data->realname, FILTER_SANITIZE_SPECIAL_CHARS)); + $fullName = trim(strip_tags((string) $data->realname)); $userName = trim((string) Filter::filterVar($data->name, FILTER_SANITIZE_SPECIAL_CHARS)); $email = trim((string) Filter::filterVar($data->email, FILTER_VALIDATE_EMAIL)); $isVisible = Filter::filterVar($data->isVisible, FILTER_SANITIZE_SPECIAL_CHARS) ?? false; diff --git a/phpmyfaq/src/phpMyFAQ/Controller/Frontend/UserController.php b/phpmyfaq/src/phpMyFAQ/Controller/Frontend/UserController.php index 0c7a2730dd..311929bc0f 100644 --- a/phpmyfaq/src/phpMyFAQ/Controller/Frontend/UserController.php +++ b/phpmyfaq/src/phpMyFAQ/Controller/Frontend/UserController.php @@ -54,7 +54,7 @@ public function updateData(Request $request): JsonResponse } $userId = Filter::filterVar($data->userid, FILTER_VALIDATE_INT); - $userName = trim((string) Filter::filterVar($data->name, FILTER_SANITIZE_SPECIAL_CHARS)); + $userName = trim(strip_tags((string) $data->name)); $email = Filter::filterVar($data->email, FILTER_VALIDATE_EMAIL); $isVisible = Filter::filterVar($data->{'is_visible'}, FILTER_SANITIZE_SPECIAL_CHARS); $password = trim((string) Filter::filterVar($data->faqpassword, FILTER_SANITIZE_SPECIAL_CHARS)); diff --git a/phpmyfaq/src/phpMyFAQ/User/UserData.php b/phpmyfaq/src/phpMyFAQ/User/UserData.php index 8e00004aa4..5d2907afe0 100644 --- a/phpmyfaq/src/phpMyFAQ/User/UserData.php +++ b/phpmyfaq/src/phpMyFAQ/User/UserData.php @@ -77,6 +77,11 @@ public function get(mixed $field): mixed $array = $this->configuration->getDb()->fetchArray($res); + // Decode HTML entities in display_name for backward compatibility + if (isset($array['display_name'])) { + $array['display_name'] = htmlspecialchars_decode($array['display_name'], ENT_QUOTES); + } + return $singleReturn && $field != '*' ? $array[$field] : $array; } diff --git a/tests/phpMyFAQ/User/UserDataTest.php b/tests/phpMyFAQ/User/UserDataTest.php index 86d74da732..9642a01da9 100644 --- a/tests/phpMyFAQ/User/UserDataTest.php +++ b/tests/phpMyFAQ/User/UserDataTest.php @@ -118,4 +118,26 @@ public function testEmailExistsReturnsFalseForEmptyEmail(): void $result = $this->userData->emailExists(''); $this->assertFalse($result); } + + public function testGetDecodesHtmlEntitiesInDisplayName(): void + { + $this->database->method('query')->willReturn(true); + $this->database->method('numRows')->willReturn(1); + $this->database->method('fetchArray')->willReturn(['display_name' => 'Jürgen']); + + $this->userData->load(1); + $result = $this->userData->get('display_name'); + $this->assertEquals('Jürgen', $result); + } + + public function testGetPreservesPlainUtf8InDisplayName(): void + { + $this->database->method('query')->willReturn(true); + $this->database->method('numRows')->willReturn(1); + $this->database->method('fetchArray')->willReturn(['display_name' => 'Jürgen']); + + $this->userData->load(1); + $result = $this->userData->get('display_name'); + $this->assertEquals('Jürgen', $result); + } } From efacee4a2af0129bd585f85b2dded118babad89d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:18:05 +0000 Subject: [PATCH 3/4] Use html_entity_decode instead of htmlspecialchars_decode for named entities Co-authored-by: thorsten <45284+thorsten@users.noreply.github.com> --- phpmyfaq/src/phpMyFAQ/User/UserData.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpmyfaq/src/phpMyFAQ/User/UserData.php b/phpmyfaq/src/phpMyFAQ/User/UserData.php index 5d2907afe0..450b4cc5c3 100644 --- a/phpmyfaq/src/phpMyFAQ/User/UserData.php +++ b/phpmyfaq/src/phpMyFAQ/User/UserData.php @@ -79,7 +79,7 @@ public function get(mixed $field): mixed // Decode HTML entities in display_name for backward compatibility if (isset($array['display_name'])) { - $array['display_name'] = htmlspecialchars_decode($array['display_name'], ENT_QUOTES); + $array['display_name'] = html_entity_decode($array['display_name'], ENT_QUOTES | ENT_HTML5, 'UTF-8'); } return $singleReturn && $field != '*' ? $array[$field] : $array; From 67fea358fe176b689925ef96e508a606c052f7f7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:19:51 +0000 Subject: [PATCH 4/4] Add ENT_SUBSTITUTE flag for safer HTML entity decoding Co-authored-by: thorsten <45284+thorsten@users.noreply.github.com> --- phpmyfaq/src/phpMyFAQ/User/UserData.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/phpmyfaq/src/phpMyFAQ/User/UserData.php b/phpmyfaq/src/phpMyFAQ/User/UserData.php index 450b4cc5c3..a3349627d7 100644 --- a/phpmyfaq/src/phpMyFAQ/User/UserData.php +++ b/phpmyfaq/src/phpMyFAQ/User/UserData.php @@ -79,7 +79,11 @@ public function get(mixed $field): mixed // Decode HTML entities in display_name for backward compatibility if (isset($array['display_name'])) { - $array['display_name'] = html_entity_decode($array['display_name'], ENT_QUOTES | ENT_HTML5, 'UTF-8'); + $array['display_name'] = html_entity_decode( + $array['display_name'], + ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE, + 'UTF-8' + ); } return $singleReturn && $field != '*' ? $array[$field] : $array;