Skip to content

Commit c7d825e

Browse files
committed
Merge branch '5.x' into advisory-fix-1
# Conflicts: # CHANGELOG.md
2 parents 8e854ea + ecad338 commit c7d825e

14 files changed

Lines changed: 2202 additions & 2155 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@
22

33
## Unreleased
44

5+
- The control panel is now translated into Greek. ([#18458](https://github.com/craftcms/cms/pull/18458))
6+
- The `PDO::MYSQL_ATTR_MULTI_STATEMENTS` attribute is now set to `false` by default for database connections.
7+
- Fixed a bug where `searchindex` and `searchindexqueue` rows weren’t being deleted when an element was deleted for a site. ([#18394](https://github.com/craftcms/cms/issues/18394))
8+
- Fixed a bug where multi-select condition rules weren’t applying their “has a value” and “is empty” operators correctly. ([#18470](https://github.com/craftcms/cms/pull/18470))
59
- Fixed an unintended change in behavior where `craft\helpers\App::parseEnv()` was returning `null` instad of an empty string, when an environment variable name was passed in, which was set to an empty string.
10+
- Fixed a bug where drafts within “My Drafts” widgets weren’t getting hyperlinked. ([#18456](https://github.com/craftcms/cms/issues/18456))
11+
- Fixed a bug where nested entries were getting assigned new IDs if they were edited multiple times for the same owner element draft. ([#18461](https://github.com/craftcms/cms/issues/18461))
12+
- Fixed a bug where the “New Tab” button within field layout designers could be positioned incorrectly. ([#18450](https://github.com/craftcms/cms/issues/18450))
613
- Fixed a [high-severity](https://github.com/craftcms/cms/security/policy#severity--remediation) RCE vulnerability. ([GHSA-2fph-6v5w-89hh](https://github.com/craftcms/cms/security/advisories/GHSA-2fph-6v5w-89hh))
14+
- Fixed a [low-severity](https://github.com/craftcms/cms/security/policy#severity--remediation) path traversal vulnerability. (GHSA-472v-j2g4-g9h2)
715

816
## 5.9.12 - 2026-02-18
917

@@ -380,9 +388,9 @@
380388
- Fixed a bug where verification emails weren’t getting sent when a user without the “Administrate users” permission changed a user account’s email address.
381389
- Fixed a bug where MP3 files weren’t always being properly recognized. ([#18243](https://github.com/craftcms/cms/issues/18243))
382390
- Fixed a bug where deeply-nested slideouts could cause visual glitches in Chromium-based browsers. ([#18255](https://github.com/craftcms/cms/issues/18255))
383-
- Fixed [low-severity](https://github.com/craftcms/cms/security/policy#severity--remediation) XSS vulnerabilities. (GHSA-6j87-m5qx-9fqp, GHSA-3jh3-prx3-w6wc)
384-
- Fixed [moderate-severity](https://github.com/craftcms/cms/security/policy#severity--remediation) SSRF vulnerabilities. (GHSA-gp2f-7wcm-5fhx, GHSA-v2gc-rm6g-wrw9)
385-
- Fixed a [moderate-severity](https://github.com/craftcms/cms/security/policy#severity--remediation) TOCTOU vulnerability. (GHSA-6fx5-5cw5-4897)
391+
- Fixed [low-severity](https://github.com/craftcms/cms/security/policy#severity--remediation) XSS vulnerabilities. ([GHSA-6j87-m5qx-9fqp](https://github.com/craftcms/cms/security/advisories/GHSA-6j87-m5qx-9fqp), [GHSA-3jh3-prx3-w6wc](https://github.com/craftcms/cms/security/advisories/GHSA-3jh3-prx3-w6wc))
392+
- Fixed [moderate-severity](https://github.com/craftcms/cms/security/policy#severity--remediation) SSRF vulnerabilities. ([GHSA-gp2f-7wcm-5fhx](https://github.com/craftcms/cms/security/advisories/GHSA-gp2f-7wcm-5fhx), [GHSA-v2gc-rm6g-wrw9](https://github.com/craftcms/cms/security/advisories/GHSA-v2gc-rm6g-wrw9))
393+
- Fixed a [moderate-severity](https://github.com/craftcms/cms/security/policy#severity--remediation) TOCTOU vulnerability. ([GHSA-6fx5-5cw5-4897](https://github.com/craftcms/cms/security/advisories/GHSA-6fx5-5cw5-4897))
386394

387395
## 5.8.22 - 2026-01-09
388396

crowdin.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ files:
99
type: php
1010
excluded_target_languages:
1111
- cy
12-
- el
1312
- hr
1413
- id
1514
- ky

src/base/conditions/BaseMultiSelectConditionRule.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ protected function paramValue(?callable $normalizeValue = null): string|array|nu
181181
*/
182182
protected function matchValue(array|string|null $value): bool
183183
{
184+
if (in_array($this->operator, [self::OPERATOR_EMPTY, self::OPERATOR_NOT_EMPTY])) {
185+
return match ($this->operator) {
186+
self::OPERATOR_EMPTY => empty($value),
187+
self::OPERATOR_NOT_EMPTY => !empty($value),
188+
};
189+
}
190+
184191
if (!$this->_values) {
185192
return true;
186193
}
@@ -194,8 +201,6 @@ protected function matchValue(array|string|null $value): bool
194201
return match ($this->operator) {
195202
self::OPERATOR_IN => !empty(array_intersect($value, $this->_values)),
196203
self::OPERATOR_NOT_IN => empty(array_intersect($value, $this->_values)),
197-
self::OPERATOR_NOT_EMPTY => !empty($value),
198-
self::OPERATOR_EMPTY => empty($value),
199204
default => throw new InvalidConfigException("Invalid operator: $this->operator"),
200205
};
201206
}

src/helpers/App.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
use craft\web\User as WebUser;
3838
use craft\web\View;
3939
use HTMLPurifier_Encoder;
40+
use PDO;
4041
use ReflectionClass;
4142
use ReflectionFunction;
4243
use ReflectionNamedType;
@@ -1046,7 +1047,10 @@ public static function dbConfig(?DbConfig $dbConfig = null): array
10461047
'commandMap' => [
10471048
$driver => Command::class,
10481049
],
1049-
'attributes' => $dbConfig->attributes,
1050+
'attributes' => [
1051+
PDO::MYSQL_ATTR_MULTI_STATEMENTS => false,
1052+
...$dbConfig->attributes,
1053+
],
10501054
'enableSchemaCache' => !static::devMode(),
10511055
];
10521056

@@ -1263,16 +1267,13 @@ public static function webRequestConfig(): array
12631267
'enableCsrfValidation' => $generalConfig->enableCsrfProtection,
12641268
'enableCsrfCookie' => $generalConfig->enableCsrfCookie,
12651269
'csrfParam' => $generalConfig->csrfTokenName,
1270+
'trustedHosts' => $generalConfig->trustedHosts,
12661271
'parsers' => [
12671272
'application/json' => JsonParser::class,
12681273
],
12691274
'isCpRequest' => static::normalizeBooleanValue(static::env('CRAFT_CP')),
12701275
];
12711276

1272-
if ($generalConfig->trustedHosts !== null) {
1273-
$config['trustedHosts'] = $generalConfig->trustedHosts;
1274-
}
1275-
12761277
if ($generalConfig->secureHeaders !== null) {
12771278
$config['secureHeaders'] = $generalConfig->secureHeaders;
12781279
}

src/helpers/Assets.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,10 @@ public static function downloadFile(BaseFsInterface $fs, string $uriPath, string
890890
*/
891891
public static function iconUrl(string $extension): string
892892
{
893+
if (!preg_match('/^\w+$/', $extension)) {
894+
throw new InvalidArgumentException("$extension isn’t a valid file extension.");
895+
}
896+
893897
return UrlHelper::actionUrl('assets/icon', [
894898
'extension' => $extension,
895899
]);
@@ -905,6 +909,10 @@ public static function iconUrl(string $extension): string
905909
*/
906910
public static function iconPath(string $extension): string
907911
{
912+
if (!preg_match('/^\w+$/', $extension)) {
913+
throw new InvalidArgumentException("$extension isn’t a valid file extension.");
914+
}
915+
908916
$path = sprintf('%s%s%s.svg', Craft::$app->getPath()->getAssetsIconsPath(), DIRECTORY_SEPARATOR, strtolower($extension));
909917

910918
if (file_exists($path)) {

src/i18n/I18N.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ private function _defineAppLocales(): void
187187
'da' => true,
188188
'de' => true,
189189
'de-CH' => true,
190+
'el' => true,
190191
'en' => true,
191192
'en-GB' => true,
192193
'es' => true,

src/services/Elements.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,7 @@ public function updateCanonicalElement(ElementInterface $element, array $newAttr
15031503
$newAttributes += [
15041504
'id' => $canonical->id,
15051505
'uid' => $canonical->uid,
1506+
'canonicalId' => $canonical->getCanonicalId(),
15061507
'root' => $canonical->root,
15071508
'lft' => $canonical->lft,
15081509
'rgt' => $canonical->rgt,
@@ -4265,14 +4266,15 @@ private function _saveElementInternal(
42654266
if (!$element->propagating) {
42664267
// Delete the rows that don't need to be there anymore
42674268
if (!$isNewElement) {
4268-
Db::deleteIfExists(
4269-
Table::ELEMENTS_SITES,
4270-
[
4271-
'and',
4272-
['elementId' => $element->id],
4273-
['not', ['siteId' => array_keys($supportedSites)]],
4274-
]
4275-
);
4269+
$deleteCondition = [
4270+
'and',
4271+
['elementId' => $element->id],
4272+
['not', ['siteId' => array_keys($supportedSites)]],
4273+
];
4274+
4275+
Db::deleteIfExists(Table::ELEMENTS_SITES, $deleteCondition);
4276+
Db::deleteIfExists(Table::SEARCHINDEX, $deleteCondition);
4277+
Db::deleteIfExists(Table::SEARCHINDEXQUEUE, $deleteCondition);
42764278
}
42774279

42784280
// Invalidate any caches involving this element

src/services/Search.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -581,20 +581,20 @@ public function deleteOrphanedIndexes(): void
581581
{
582582
$db = Craft::$app->getDb();
583583
$searchIndexTable = Table::SEARCHINDEX;
584-
$elementsTable = Table::ELEMENTS;
584+
$elementsSitesTable = Table::ELEMENTS_SITES;
585585

586586
if ($db->getIsMysql()) {
587587
$sql = <<<SQL
588588
DELETE s.* FROM $searchIndexTable s
589-
LEFT JOIN $elementsTable e ON e.id = s.elementId
590-
WHERE e.id IS NULL
589+
LEFT JOIN $elementsSitesTable es ON es.elementId = s.elementId AND es.siteId = s.siteId
590+
WHERE es.elementId IS NULL
591591
SQL;
592592
} else {
593593
$sql = <<<SQL
594594
DELETE FROM $searchIndexTable s
595595
WHERE NOT EXISTS (
596-
SELECT * FROM $elementsTable
597-
WHERE id = s."elementId"
596+
SELECT * FROM $elementsSitesTable
597+
WHERE "elementId" = s."elementId" AND "siteId" = s."siteId"
598598
)
599599
SQL;
600600
}
@@ -610,20 +610,20 @@ public function deleteOrphanedIndexJobs(): void
610610
{
611611
$db = Craft::$app->getDb();
612612
$searchIndexQueueTable = Table::SEARCHINDEXQUEUE;
613-
$elementsTable = Table::ELEMENTS;
613+
$elementsSitesTable = Table::ELEMENTS_SITES;
614614

615615
if ($db->getIsMysql()) {
616616
$sql = <<<SQL
617617
DELETE q.* FROM $searchIndexQueueTable q
618-
LEFT JOIN $elementsTable e ON e.id = q.elementId
619-
WHERE e.id IS NULL
618+
LEFT JOIN $elementsSitesTable es ON es.elementId = q.elementId AND es.siteId = q.siteId
619+
WHERE es.elementId IS NULL
620620
SQL;
621621
} else {
622622
$sql = <<<SQL
623623
DELETE FROM $searchIndexQueueTable q
624624
WHERE NOT EXISTS (
625-
SELECT * FROM $elementsTable
626-
WHERE id = q."elementId"
625+
SELECT * FROM $elementsSitesTable
626+
WHERE "elementId" = q."elementId" AND "siteId" = q."siteId"
627627
)
628628
SQL;
629629
}

0 commit comments

Comments
 (0)