Encode HTML special characters in lang texts via lang_secure()#519
Encode HTML special characters in lang texts via lang_secure()#519darknoon29 merged 4 commits intodevelopfrom
Conversation
…(), fix help.php, add tests Co-authored-by: darknoon29 <13015521+darknoon29@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Enables HTML-escaping of language strings by activating the existing lang_secure() mechanism, while cleaning up translation files so UI output is no longer malformed/double-encoded and line breaks are handled consistently.
Changes:
- Enabled
$lang = lang_secure($lang);so all non-help lang strings are safely HTML-escaped (including newline →<br>conversion). - Cleaned up many lang files to remove pre-encoded entities / inline HTML like
<br>and decorative<a>wrappers to prevent double-encoding. - Adjusted tooltip help rendering to preserve intentional HTML in
help_*strings; added unit tests forlang_print()/lang_secure().
Reviewed changes
Copilot reviewed 51 out of 51 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| includes/help.php | Decodes entities for help_* values before tooltip HTML generation to preserve intentional HTML after lang_secure(). |
| lang/lang_main.php | Enables lang_secure() globally for loaded language arrays. |
| tests/unit/LangTest.php | Adds unit tests for HTML escaping and newline handling in lang_print() / lang_secure(). |
| lang/pt_BR/lang_statistic.php | Replaces <br> with \n to align with lang_print() newline handling. |
| lang/pt_BR/lang_login.php | Replaces <br> with \n to avoid escaped <br> rendering. |
| lang/pt_BR/lang_install.php | Removes embedded <a> markup / replaces <br> with \n to avoid escaped HTML in installer strings. |
| lang/pt_BR/lang_admin.php | Removes decorative <a> wrappers and relies on safe text rendering via lang_secure(). |
| lang/pt/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/it_IT/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/it_CH/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/it/lang_statistic.php | Replaces <br> with \n to align with lang_print() newline handling. |
| lang/it/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/it/lang_install.php | Removes embedded <a> markup / replaces <br> with \n to avoid escaped HTML. |
| lang/it/lang_admin.php | Removes decorative <a> wrappers and relies on safe text rendering via lang_secure(). |
| lang/hr_HR/lang_statistic.php | Replaces <br> with \n to align with lang_print() newline handling. |
| lang/hr_HR/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/hr_HR/lang_install.php | Replaces <br> with \n to avoid escaped HTML. |
| lang/hr_HR/lang_admin.php | Removes decorative <a> wrappers and relies on safe text rendering via lang_secure(). |
| lang/hr/lang_statistic.php | Replaces <br> with \n to align with lang_print() newline handling. |
| lang/hr/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/hr/lang_install.php | Replaces <br> with \n to avoid escaped HTML. |
| lang/hr/lang_admin.php | Removes decorative <a> wrappers and relies on safe text rendering via lang_secure(). |
| lang/fr/lang_statistic.php | Replaces <br> with \n to align with lang_print() newline handling. |
| lang/fr/lang_profile.php | Normalizes pre-encoded entities so lang_secure() doesn’t double-encode. |
| lang/fr/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/fr/lang_install.php | Replaces <br> with \n to avoid escaped HTML. |
| lang/fr/lang_home.php | Normalizes pre-encoded & to & to prevent double-encoding under lang_secure(). |
| lang/fr/lang_help.php | Normalizes entity usage in help strings while keeping intentional HTML (help-specific handling is in includes/help.php). |
| lang/es/lang_statistic.php | Replaces <br> with \n to align with lang_print() newline handling. |
| lang/es/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/es/lang_install.php | Removes embedded <a> markup / replaces <br> with \n to avoid escaped HTML. |
| lang/es/lang_admin.php | Removes decorative <a> wrappers and relies on safe text rendering via lang_secure(). |
| lang/en_US/lang_statistic.php | Replaces <br> with \n to align with lang_print() newline handling. |
| lang/en_US/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/en_US/lang_install.php | Removes embedded <a> markup / replaces <br> with \n to avoid escaped HTML. |
| lang/en_US/lang_admin.php | Removes decorative <a> wrappers and relies on safe text rendering via lang_secure(). |
| lang/en/lang_statistic.php | Replaces <br> with \n to align with lang_print() newline handling. |
| lang/en/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/en/lang_install.php | Removes embedded <a> markup / replaces <br> with \n to avoid escaped HTML. |
| lang/en/lang_home.php | Normalizes pre-encoded & to & to prevent double-encoding under lang_secure(). |
| lang/en/lang_help.php | Normalizes entity usage in help strings while keeping intentional HTML (help-specific handling is in includes/help.php). |
| lang/en/lang_admin.php | Removes decorative <a> wrappers and relies on safe text rendering via lang_secure(). |
| lang/de/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/bs_BA/lang_statistic.php | Replaces <br> with \n to align with lang_print() newline handling. |
| lang/bs_BA/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/bs_BA/lang_install.php | Replaces <br> with \n to avoid escaped HTML. |
| lang/bs_BA/lang_admin.php | Removes decorative <a> wrappers and relies on safe text rendering via lang_secure(). |
| lang/bs/lang_statistic.php | Replaces <br> with \n to align with lang_print() newline handling. |
| lang/bs/lang_login.php | Replaces <br> with \n for consistent line breaks under lang_secure(). |
| lang/bs/lang_install.php | Replaces <br> with \n to avoid escaped HTML. |
| lang/bs/lang_admin.php | Removes decorative <a> wrappers and relies on safe text rendering via lang_secure(). |
| public function testLangPrintEncodesSingleQuote(): void | ||
| { | ||
| $result = lang_print("L'ancien mot de passe"); | ||
| $this->assertEquals('L'ancien mot de passe', $result); | ||
| } |
There was a problem hiding this comment.
No change needed here. The concern was that ' might be wrong, but htmlspecialchars() with ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE does produce ' — that's the HTML5 named entity for single quotes. The ' encoding only occurs without the ENT_HTML5 flag. The test is already asserting the correct actual output and all 9 Lang tests pass on PHP 8.3.
| $lang['ADMIN_PARAMS_DURATION_SPYREPORTS'] = "Spy reports storage <a>[1-999 days or number]</a>"; | ||
| $lang['ADMIN_PARAMS_DURATION_SPYREPORTS'] = "Spy reports storage [1-999 days or number]"; | ||
| $lang['ADMIN_PARAMS_MAX_SPYREPORTS'] = "Spy reports storage / planet [1-50]"; | ||
| $lang['ADMIN_PARAMS_DURATION_SPYREPORTS'] = "Spy reports storage [1-999 days or number]"; |
| $lang['ADMIN_DISPLAY_STATS_GVIEW'] = "Número de galáxias por linha[1-100]"; | ||
| $lang['ADMIN_DISPLAY_STATS_SVIEW'] = "Número de sistemas por linha [1-100]"; |
There was a problem hiding this comment.
This was already fixed in 624eb9b — lines 34 and 35 in lang/pt_BR/lang_admin.php now read "linha [1-100]" with the space.
|
@copilot apply changes based on the comments in this thread |
…in pt_BR lang Co-authored-by: darknoon29 <13015521+darknoon29@users.noreply.github.com>
Done in 624eb9b:
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|


Lang strings containing special HTML characters (e.g.
&,<,>,",') were echoed raw into HTML, producing malformed output. Thelang_secure()function existed for this purpose but was disabled pending a lang file cleanup.Changes
Lang file cleanup (48 files, all languages)
$langvalues (&→&,’→',"→") to prevent double-encoding oncelang_secure()is active<br>tags in regular strings with\n—lang_print()already converts\n→<br>after encoding<a>wrapper tags from admin/install strings (French reference has plain text)help_*keys left untouched — they contain intentional HTML for tooltip renderingincludes/help.phpAdded
html_entity_decode()before embedding a lang value into the tooltip HTML table. This reverseslang_secure()encoding for help strings so their intentional HTML (<font>,<br>,<i>) is preserved through thehtmlentities()/html_entity_decode()round-trip used byToolTip_Helper.lang/lang_main.phpRemoved the TODO comment and enabled the existing
lang_secure()call:Tests
Added
tests/unit/LangTest.phpcoveringlang_print()andlang_secure()for&,<,>,",', newline→<br>conversion, and non-HTML mode.Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://api.github.com/repos/PHPMailer/PHPMailer/zipball/ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/components/jquery/zipball/8edc7785239bb8c2ad2b83302b856a1d61de60e7/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/iamceege/tooltipster/zipball/0daaeffdc7da578f4048c4cf9ad2f37a474144f0/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/90f41072d220e5c40df6e8635f5dafba2d9d4d04/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a7de5df2e094f9a80b40a522391a7e6022df5f6/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/environment/zipball/24a711b5c916efc6d6e62aa65aa2ec98fef77f68/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/exporter/zipball/016951ae10980765e4e7aee491eb288c64e505b7/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b015312f28dd75b75d3422ca37dff2cd1a565e8d/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/phpunit/zipball/47283cfd98d553edcb1353591f4e255dc1bb61f0/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/type/zipball/e549163b9760b8f71f191651d22acf32d56d6d4d/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4/usr/bin/php8.3 /usr/bin/php8.3 -n -c /tmp/M4nnRg /usr/bin/composer install --no-interaction(http block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.