From f9b5ff59ab233017972a3b2f179deee82eb3cfa0 Mon Sep 17 00:00:00 2001
From: Oliver Bartsch <bo@cedev.de>
Date: Fri, 6 Aug 2021 03:05:37 +0200
Subject: [PATCH] [BUGFIX] Ensure getRecordTitle returns a string
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

BackendUtility::getRecordTitle() should return a string (as
the return type annotation suggest). Especially because the
return value is usually directly passed to htmlspecialchars(),
which again requires a string to be given.

Since BackendUtility::getRecordTitle() was missing some
typecasts, it was possible that e.g. an integer was returned.
This then failed in classes, defining strict mode.

An example for such scenario: Having a table, which
defines the `uid` as `label` field. getRecordTitle is using
getProcessedValue(), which has a guard clause to directly
return the input value, in case the label field is `uid`. This
would then usually (depending on DBMS) return an integer.

This is now fixed by applying type casts to the relevant places.

Resolves: #94726
Releases: master
Change-Id: Ie02837ff5e55f369ff8ddf1f3e5098e636f475bb
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/70243
Tested-by: core-ci <typo3@b13.com>
Tested-by: Benni Mack <benni@typo3.org>
Tested-by: Jochen <rothjochen@gmail.com>
Tested-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Reviewed-by: Jörg Bösche <typo3@joergboesche.de>
Reviewed-by: Jochen <rothjochen@gmail.com>
Reviewed-by: Oliver Bartsch <bo@cedev.de>
---
 .../backend/Classes/Utility/BackendUtility.php  |  8 ++++----
 .../Functional/Utility/BackendUtilityTest.php   | 17 +++++++++++++++--
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/typo3/sysext/backend/Classes/Utility/BackendUtility.php b/typo3/sysext/backend/Classes/Utility/BackendUtility.php
index ba0d3c1d49a0..9e3693e6393e 100644
--- a/typo3/sysext/backend/Classes/Utility/BackendUtility.php
+++ b/typo3/sysext/backend/Classes/Utility/BackendUtility.php
@@ -1426,7 +1426,7 @@ class BackendUtility
                 $recordTitle = self::getProcessedValue(
                     $table,
                     $ctrlLabel,
-                    $row[$ctrlLabel] ?? '',
+                    (string)($row[$ctrlLabel] ?? ''),
                     0,
                     false,
                     false,
@@ -1434,7 +1434,7 @@ class BackendUtility
                     $forceResult
                 ) ?? '';
                 if (!empty($GLOBALS['TCA'][$table]['ctrl']['label_alt'])
-                    && (!empty($GLOBALS['TCA'][$table]['ctrl']['label_alt_force']) || (string)$recordTitle === '')
+                    && (!empty($GLOBALS['TCA'][$table]['ctrl']['label_alt_force']) || $recordTitle === '')
                 ) {
                     $altFields = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['label_alt'], true);
                     $tA = [];
@@ -1442,8 +1442,8 @@ class BackendUtility
                         $tA[] = $recordTitle;
                     }
                     foreach ($altFields as $fN) {
-                        $recordTitle = trim(strip_tags($row[$fN] ?? ''));
-                        if ((string)$recordTitle !== '') {
+                        $recordTitle = trim(strip_tags((string)($row[$fN] ?? '')));
+                        if ($recordTitle !== '') {
                             $recordTitle = self::getProcessedValue($table, $fN, $recordTitle, 0, false, false, $row['uid']);
                             if (!($GLOBALS['TCA'][$table]['ctrl']['label_alt_force'] ?? false)) {
                                 break;
diff --git a/typo3/sysext/backend/Tests/Functional/Utility/BackendUtilityTest.php b/typo3/sysext/backend/Tests/Functional/Utility/BackendUtilityTest.php
index 536044163b94..2ad8063cdc32 100644
--- a/typo3/sysext/backend/Tests/Functional/Utility/BackendUtilityTest.php
+++ b/typo3/sysext/backend/Tests/Functional/Utility/BackendUtilityTest.php
@@ -24,6 +24,7 @@ class BackendUtilityTest extends FunctionalTestCase
     {
         parent::setUp();
         $this->importDataSet('PACKAGE:typo3/testing-framework/Resources/Core/Functional/Fixtures/pages.xml');
+        $this->importDataSet('PACKAGE:typo3/testing-framework/Resources/Core/Functional/Fixtures/tt_content.xml');
         $this->setUpBackendUserFromFixture(1);
         Bootstrap::initializeLanguageObject();
     }
@@ -98,8 +99,6 @@ class BackendUtilityTest extends FunctionalTestCase
             )
         );
 
-        $this->importDataSet('PACKAGE:typo3/testing-framework/Resources/Core/Functional/Fixtures/tt_content.xml');
-
         self::assertEquals(
             'German',
             BackendUtility::getProcessedValue(
@@ -114,6 +113,20 @@ class BackendUtilityTest extends FunctionalTestCase
         );
     }
 
+    /**
+     * @test
+     */
+    public function getRecordTitleForUidLabel(): void
+    {
+        $GLOBALS['TCA']['tt_content']['ctrl']['label'] = 'uid';
+        unset($GLOBALS['TCA']['tt_content']['ctrl']['label_alt']);
+
+        self::assertEquals(
+            '1',
+            BackendUtility::getRecordTitle('tt_content', BackendUtility::getRecord('tt_content', 1))
+        );
+    }
+
     private function getBackendUser(): BackendUserAuthentication
     {
         return $GLOBALS['BE_USER'];
-- 
GitLab