Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( e7ebe1...04b51b )
by Sebastian
19s queued 14s
created

Helper::whereExpression()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 22
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 17
c 1
b 0
f 0
dl 0
loc 22
rs 9.3888
cc 5
nc 6
nop 2
1
<?php
2
3
/**
4
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
5
 *
6
 * This file is part of the Kitodo and TYPO3 projects.
7
 *
8
 * @license GNU General Public License version 3 or later.
9
 * For the full copyright and license information, please read the
10
 * LICENSE.txt file that was distributed with this source code.
11
 */
12
13
namespace Kitodo\Dlf\Common;
14
15
use TYPO3\CMS\Core\Database\ConnectionPool;
16
use TYPO3\CMS\Core\Utility\GeneralUtility;
17
18
/**
19
 * Helper class for the 'dlf' extension
20
 *
21
 * @author Sebastian Meyer <[email protected]>
22
 * @author Henrik Lochmann <[email protected]>
23
 * @package TYPO3
24
 * @subpackage dlf
25
 * @access public
26
 */
27
class Helper
28
{
29
    /**
30
     * The extension key
31
     *
32
     * @var string
33
     * @access public
34
     */
35
    public static $extKey = 'dlf';
36
37
    /**
38
     * The locallang array for flash messages
39
     *
40
     * @var array
41
     * @access protected
42
     */
43
    protected static $messages = [];
44
45
    /**
46
     * Generates a flash message and adds it to a message queue.
47
     *
48
     * @access public
49
     *
50
     * @param string $message: The body of the message
51
     * @param string $title: The title of the message
52
     * @param int $severity: The message's severity
53
     * @param bool $session: Should the message be saved in the user's session?
54
     * @param string $queue: The queue's unique identifier
55
     *
56
     * @return \TYPO3\CMS\Core\Messaging\FlashMessageQueue The queue the message was added to
57
     */
58
    public static function addMessage($message, $title, $severity, $session = false, $queue = 'kitodo.default.flashMessages')
59
    {
60
        $flashMessageService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
61
        $flashMessageQueue = $flashMessageService->getMessageQueueByIdentifier($queue);
62
        $flashMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
63
            \TYPO3\CMS\Core\Messaging\FlashMessage::class,
64
            $message,
65
            $title,
66
            $severity,
67
            $session
68
        );
69
        $flashMessageQueue->enqueue($flashMessage);
70
        return $flashMessageQueue;
71
    }
72
73
    /**
74
     * Check if given identifier is a valid identifier of the German National Library
75
     *
76
     * @access public
77
     *
78
     * @param string $id: The identifier to check
79
     * @param string $type: What type is the identifier supposed to be?
80
     *                      Possible values: PPN, IDN, PND, ZDB, SWD, GKD
81
     *
82
     * @return bool Is $id a valid GNL identifier of the given $type?
83
     */
84
    public static function checkIdentifier($id, $type)
85
    {
86
        $digits = substr($id, 0, 8);
87
        $checksum = 0;
88
        for ($i = 0, $j = strlen($digits); $i < $j; $i++) {
89
            $checksum += (9 - $i) * intval(substr($digits, $i, 1));
90
        }
91
        $checksum = (11 - ($checksum % 11)) % 11;
92
        switch (strtoupper($type)) {
93
            case 'PPN':
94
            case 'IDN':
95
            case 'PND':
96
                if ($checksum == 10) {
97
                    $checksum = 'X';
98
                }
99
                if (!preg_match('/[0-9]{8}[0-9X]{1}/i', $id)) {
100
                    return false;
101
                } elseif (strtoupper(substr($id, -1, 1)) != $checksum) {
102
                    return false;
103
                }
104
                break;
105
            case 'ZDB':
106
                if ($checksum == 10) {
107
                    $checksum = 'X';
108
                }
109
                if (!preg_match('/[0-9]{8}-[0-9X]{1}/i', $id)) {
110
                    return false;
111
                } elseif (strtoupper(substr($id, -1, 1)) != $checksum) {
112
                    return false;
113
                }
114
                break;
115
            case 'SWD':
116
                $checksum = 11 - $checksum;
117
                if (!preg_match('/[0-9]{8}-[0-9]{1}/i', $id)) {
118
                    return false;
119
                } elseif ($checksum == 10) {
120
                    return self::checkIdentifier(($digits + 1) . substr($id, -2, 2), 'SWD');
121
                } elseif (substr($id, -1, 1) != $checksum) {
122
                    return false;
123
                }
124
                break;
125
            case 'GKD':
126
                $checksum = 11 - $checksum;
127
                if ($checksum == 10) {
128
                    $checksum = 'X';
129
                }
130
                if (!preg_match('/[0-9]{8}-[0-9X]{1}/i', $id)) {
131
                    return false;
132
                } elseif (strtoupper(substr($id, -1, 1)) != $checksum) {
133
                    return false;
134
                }
135
                break;
136
        }
137
        return true;
138
    }
139
140
    /**
141
     * Decrypt encrypted value with given control hash
142
     *
143
     * @access public
144
     *
145
     * @param string $encrypted: The encrypted value to decrypt
146
     * @param string $hash: The control hash for decrypting
147
     *
148
     * @return mixed The decrypted value or null on error
149
     */
150
    public static function decrypt($encrypted, $hash)
151
    {
152
        if (
153
            empty($encrypted)
154
            || empty($hash)
155
        ) {
156
            self::devLog('Invalid parameters given for decryption', DEVLOG_SEVERITY_ERROR);
157
            return;
158
        }
159
        if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
160
            self::devLog('No encryption key set in TYPO3 configuration', DEVLOG_SEVERITY_ERROR);
161
            return;
162
        }
163
        $iv = substr(md5($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']), 0, openssl_cipher_iv_length('BF-CFB'));
164
        $decrypted = openssl_decrypt($encrypted, 'BF-CFB', substr($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'], 0, 56), 0, $iv);
165
        $salt = substr($hash, 0, 10);
166
        $hashed = $salt . substr(sha1($salt . $decrypted), -10);
167
        if ($hashed !== $hash) {
168
            self::devLog('Invalid hash "' . $hash . '" given for decryption', DEVLOG_SEVERITY_WARNING);
169
            return;
170
        }
171
        return $decrypted;
172
    }
173
174
    /**
175
     * Add a message to the TYPO3 developer log
176
     *
177
     * @access public
178
     *
179
     * @param string $message: The message to log
180
     * @param int $severity: The severity of the message
181
     *                       0 is info, 1 is notice, 2 is warning, 3 is fatal error, -1 is "OK" message
182
     *
183
     * @return void
184
     */
185
    public static function devLog($message, $severity = 0)
186
    {
187
        if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['devLog'])) {
188
            $stacktrace = debug_backtrace(0, 2);
189
            // Set some defaults.
190
            $caller = 'Kitodo\Dlf\Default\UnknownClass::unknownMethod';
191
            $args = [];
192
            $data = [];
193
            if (!empty($stacktrace[1])) {
194
                $caller = $stacktrace[1]['class'] . $stacktrace[1]['type'] . $stacktrace[1]['function'];
195
                foreach ($stacktrace[1]['args'] as $arg) {
196
                    if (is_bool($arg)) {
197
                        $args[] = ($arg ? 'true' : 'false');
198
                    } elseif (is_scalar($arg)) {
199
                        $args[] = (string) $arg;
200
                    } elseif (is_null($arg)) {
201
                        $args[] = 'null';
202
                    } elseif (is_array($arg)) {
203
                        $args[] = '[data]';
204
                        $data[] = $arg;
205
                    } elseif (is_object($arg)) {
206
                        $args[] = '[' . get_class($arg) . ']';
207
                        $data[] = $arg;
208
                    }
209
                }
210
            }
211
            $arguments = '(' . implode(', ', $args) . ')';
212
            $additionalData = (empty($data) ? false : $data);
213
            /** @scrutinizer ignore-deprecated */ \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[' . $caller . $arguments . '] ' . $message, self::$extKey, $severity, $additionalData);
214
        }
215
    }
216
217
    /**
218
     * Encrypt the given string
219
     *
220
     * @access public
221
     *
222
     * @param string $string: The string to encrypt
223
     *
224
     * @return array Array with encrypted string and control hash
225
     */
226
    public static function encrypt($string)
227
    {
228
        if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
229
            self::devLog('No encryption key set in TYPO3 configuration', DEVLOG_SEVERITY_ERROR);
230
            return;
231
        }
232
        $iv = substr(md5($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']), 0, openssl_cipher_iv_length('BF-CFB'));
233
        $encrypted = openssl_encrypt($string, 'BF-CFB', substr($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'], 0, 56), 0, $iv);
234
        $salt = substr(md5(uniqid(rand(), true)), 0, 10);
235
        $hash = $salt . substr(sha1($salt . $string), -10);
236
        return ['encrypted' => $encrypted, 'hash' => $hash];
237
    }
238
239
    /**
240
     * Get the unqualified name of a class
241
     *
242
     * @access public
243
     *
244
     * @param string $qualifiedClassname: The qualified class name from get_class()
245
     *
246
     * @return string The unqualified class name
247
     */
248
    public static function getUnqualifiedClassName($qualifiedClassname)
249
    {
250
        $nameParts = explode('\\', $qualifiedClassname);
251
        return end($nameParts);
252
    }
253
254
    /**
255
     * Clean up a string to use in an URL.
256
     *
257
     * @access public
258
     *
259
     * @param string $string: The string to clean up
260
     *
261
     * @return string The cleaned up string
262
     */
263
    public static function getCleanString($string)
264
    {
265
        // Convert to lowercase.
266
        $string = strtolower($string);
267
        // Remove non-alphanumeric characters.
268
        $string = preg_replace('/[^a-z0-9_\s-]/', '', $string);
269
        // Remove multiple dashes or whitespaces.
270
        $string = preg_replace('/[\s-]+/', ' ', $string);
271
        // Convert whitespaces and underscore to dash.
272
        $string = preg_replace('/[\s_]/', '-', $string);
273
        return $string;
274
    }
275
276
    /**
277
     * Get the registered hook objects for a class
278
     *
279
     * @access public
280
     *
281
     * @param string $scriptRelPath: The path to the class file
282
     *
283
     * @return array Array of hook objects for the class
284
     */
285
    public static function getHookObjects($scriptRelPath)
286
    {
287
        $hookObjects = [];
288
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::$extKey . '/' . $scriptRelPath]['hookClass'])) {
289
            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::$extKey . '/' . $scriptRelPath]['hookClass'] as $classRef) {
290
                $hookObjects[] = &\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($classRef);
291
            }
292
        }
293
        return $hookObjects;
294
    }
295
296
    /**
297
     * Get the "index_name" for an UID
298
     *
299
     * @access public
300
     *
301
     * @param int $uid: The UID of the record
302
     * @param string $table: Get the "index_name" from this table
303
     * @param int $pid: Get the "index_name" from this page
304
     *
305
     * @return string "index_name" for the given UID
306
     */
307
    public static function getIndexNameFromUid($uid, $table, $pid = -1)
308
    {
309
        // Sanitize input.
310
        $uid = max(intval($uid), 0);
311
        if (
312
            !$uid
313
            || !in_array($table, ['tx_dlf_collections', 'tx_dlf_libraries', 'tx_dlf_metadata', 'tx_dlf_structures', 'tx_dlf_solrcores'])
314
        ) {
315
            self::devLog('Invalid UID "' . $uid . '" or table "' . $table . '"', DEVLOG_SEVERITY_ERROR);
316
            return '';
317
        }
318
319
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
320
            ->getQueryBuilderForTable($table);
321
322
        $where = '';
323
        // Should we check for a specific PID, too?
324
        if ($pid !== -1) {
325
            $pid = max(intval($pid), 0);
326
            $where = $queryBuilder->expr()->eq($table . '.pid', $pid);
327
        }
328
329
        // Get index_name from database.
330
        $result = $queryBuilder
331
            ->select($table . '.index_name AS index_name')
332
            ->from($table)
333
            ->where(
334
                $queryBuilder->expr()->eq($table . '.uid', $uid),
335
                $where,
336
                self::whereExpression($table)
337
            )
338
            ->setMaxResults(1)
339
            ->execute();
340
341
        if ($resArray = $result->fetch()) {
342
            return $resArray['index_name'];
343
        } else {
344
            self::devLog('No "index_name" with UID ' . $uid . ' and PID ' . $pid . ' found in table "' . $table . '"', DEVLOG_SEVERITY_WARNING);
345
            return '';
346
        }
347
    }
348
349
    /**
350
     * Get language name from ISO code
351
     *
352
     * @access public
353
     *
354
     * @param string $code: ISO 639-1 or ISO 639-2/B language code
355
     *
356
     * @return string Localized full name of language or unchanged input
357
     */
358
    public static function getLanguageName($code)
359
    {
360
        // Analyze code and set appropriate ISO table.
361
        $isoCode = strtolower(trim($code));
362
        if (preg_match('/^[a-z]{3}$/', $isoCode)) {
363
            $file = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath(self::$extKey) . 'Resources/Private/Data/iso-639-2b.xml';
364
        } elseif (preg_match('/^[a-z]{2}$/', $isoCode)) {
365
            $file = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath(self::$extKey) . 'Resources/Private/Data/iso-639-1.xml';
366
        } else {
367
            // No ISO code, return unchanged.
368
            return $code;
369
        }
370
        // Load ISO table and get localized full name of language.
371
        if (\TYPO3_MODE === 'FE') {
372
            $iso639 = $GLOBALS['TSFE']->readLLfile($file);
373
            if (!empty($iso639['default'][$isoCode])) {
374
                $lang = $GLOBALS['TSFE']->getLLL($isoCode, $iso639);
375
            }
376
        } elseif (\TYPO3_MODE === 'BE') {
377
            $iso639 = $GLOBALS['LANG']->includeLLFile($file, false, true);
378
            if (!empty($iso639['default'][$isoCode])) {
379
                $lang = $GLOBALS['LANG']->getLLL($isoCode, $iso639);
380
            }
381
        } else {
382
            self::devLog('Unexpected TYPO3_MODE "' . \TYPO3_MODE . '"', DEVLOG_SEVERITY_ERROR);
383
            return $code;
384
        }
385
        if (!empty($lang)) {
386
            return $lang;
387
        } else {
388
            self::devLog('Language code "' . $code . '" not found in ISO-639 table', DEVLOG_SEVERITY_NOTICE);
389
            return $code;
390
        }
391
    }
392
393
    /**
394
     * Wrapper function for getting localized messages in frontend and backend
395
     *
396
     * @access public
397
     *
398
     * @param string $key: The locallang key to translate
399
     * @param bool $hsc: Should the result be htmlspecialchar()'ed?
400
     * @param string $default: Default return value if no translation is available
401
     *
402
     * @return string The translated string or the given key on failure
403
     */
404
    public static function getMessage($key, $hsc = false, $default = '')
405
    {
406
        // Set initial output to default value.
407
        $translated = (string) $default;
408
        // Load common messages file.
409
        if (empty(self::$messages)) {
410
            $file = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath(self::$extKey, 'Resources/Private/Language/FlashMessages.xml');
411
            if (\TYPO3_MODE === 'FE') {
412
                self::$messages = $GLOBALS['TSFE']->readLLfile($file);
413
            } elseif (\TYPO3_MODE === 'BE') {
414
                self::$messages = $GLOBALS['LANG']->includeLLFile($file, false, true);
415
            } else {
416
                self::devLog('Unexpected TYPO3_MODE "' . \TYPO3_MODE . '"', DEVLOG_SEVERITY_ERROR);
417
            }
418
        }
419
        // Get translation.
420
        if (!empty(self::$messages['default'][$key])) {
421
            if (\TYPO3_MODE === 'FE') {
422
                $translated = $GLOBALS['TSFE']->getLLL($key, self::$messages);
423
            } elseif (\TYPO3_MODE === 'BE') {
424
                $translated = $GLOBALS['LANG']->getLLL($key, self::$messages);
425
            } else {
426
                self::devLog('Unexpected TYPO3_MODE "' . \TYPO3_MODE . '"', DEVLOG_SEVERITY_ERROR);
427
            }
428
        }
429
        // Escape HTML characters if applicable.
430
        if ($hsc) {
431
            $translated = htmlspecialchars($translated);
432
        }
433
        return $translated;
434
    }
435
436
    /**
437
     * Get the UID for a given "index_name"
438
     *
439
     * @access public
440
     *
441
     * @param int $index_name: The index_name of the record
442
     * @param string $table: Get the "index_name" from this table
443
     * @param int $pid: Get the "index_name" from this page
444
     *
445
     * @return string "uid" for the given index_name
446
     */
447
    public static function getUidFromIndexName($index_name, $table, $pid = -1)
448
    {
449
        if (
450
            !$index_name
451
            || !in_array($table, ['tx_dlf_collections', 'tx_dlf_libraries', 'tx_dlf_metadata', 'tx_dlf_structures', 'tx_dlf_solrcores'])
452
        ) {
453
            self::devLog('Invalid UID ' . $index_name . ' or table "' . $table . '"', DEVLOG_SEVERITY_ERROR);
454
            return '';
455
        }
456
457
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
458
            ->getQueryBuilderForTable($table);
459
460
        $where = '';
461
        // Should we check for a specific PID, too?
462
        if ($pid !== -1) {
463
            $pid = max(intval($pid), 0);
464
            $where = $queryBuilder->expr()->eq($table . '.pid', $pid);
465
        }
466
        // Get index_name from database.
467
        $result = $queryBuilder
468
            ->select($table . '.uid AS uid')
469
            ->from($table)
470
            ->where(
471
                $queryBuilder->expr()->eq($table . '.index_name', $queryBuilder->expr()->literal($index_name)),
472
                $where,
473
                self::whereExpression($table)
474
            )
475
            ->setMaxResults(1)
476
            ->execute();
477
478
        $allResults = $result->fetchAll();
479
480
        if (count($allResults) == 1) {
481
            return $allResults[0]['uid'];
482
        } else {
483
            self::devLog('No UID for given index_name "' . $index_name . '" and PID ' . $pid . ' found in table "' . $table . '"', DEVLOG_SEVERITY_WARNING);
484
            return '';
485
        }
486
    }
487
488
    /**
489
     * Get the URN of an object
490
     * @see http://www.persistent-identifier.de/?link=316
491
     *
492
     * @access public
493
     *
494
     * @param string $base: The namespace and base URN
495
     * @param string $id: The object's identifier
496
     *
497
     * @return string Uniform Resource Name as string
498
     */
499
    public static function getURN($base, $id)
500
    {
501
        $concordance = [
502
            '0' => 1,
503
            '1' => 2,
504
            '2' => 3,
505
            '3' => 4,
506
            '4' => 5,
507
            '5' => 6,
508
            '6' => 7,
509
            '7' => 8,
510
            '8' => 9,
511
            '9' => 41,
512
            'a' => 18,
513
            'b' => 14,
514
            'c' => 19,
515
            'd' => 15,
516
            'e' => 16,
517
            'f' => 21,
518
            'g' => 22,
519
            'h' => 23,
520
            'i' => 24,
521
            'j' => 25,
522
            'k' => 42,
523
            'l' => 26,
524
            'm' => 27,
525
            'n' => 13,
526
            'o' => 28,
527
            'p' => 29,
528
            'q' => 31,
529
            'r' => 12,
530
            's' => 32,
531
            't' => 33,
532
            'u' => 11,
533
            'v' => 34,
534
            'w' => 35,
535
            'x' => 36,
536
            'y' => 37,
537
            'z' => 38,
538
            '-' => 39,
539
            ':' => 17,
540
        ];
541
        $urn = strtolower($base . $id);
542
        if (preg_match('/[^a-z0-9:-]/', $urn)) {
543
            self::devLog('Invalid chars in given parameters', DEVLOG_SEVERITY_WARNING);
544
            return '';
545
        }
546
        $digits = '';
547
        for ($i = 0, $j = strlen($urn); $i < $j; $i++) {
548
            $digits .= $concordance[substr($urn, $i, 1)];
549
        }
550
        $checksum = 0;
551
        for ($i = 0, $j = strlen($digits); $i < $j; $i++) {
552
            $checksum += ($i + 1) * intval(substr($digits, $i, 1));
553
        }
554
        $checksum = substr(intval($checksum / intval(substr($digits, -1, 1))), -1, 1);
555
        return $base . $id . $checksum;
556
    }
557
558
    /**
559
     * Check if given ID is a valid Pica Production Number (PPN)
560
     *
561
     * @access public
562
     *
563
     * @param string $id: The identifier to check
564
     *
565
     * @return bool Is $id a valid PPN?
566
     */
567
    public static function isPPN($id)
568
    {
569
        return self::checkIdentifier($id, 'PPN');
570
    }
571
572
    /**
573
     * Load value from user's session.
574
     *
575
     * @access public
576
     *
577
     * @param string $key: Session data key for retrieval
578
     *
579
     * @return mixed Session value for given key or null on failure
580
     */
581
    public static function loadFromSession($key)
582
    {
583
        // Cast to string for security reasons.
584
        $key = (string) $key;
585
        if (!$key) {
586
            self::devLog('Invalid key "' . $key . '" for session data retrieval', DEVLOG_SEVERITY_WARNING);
587
            return;
588
        }
589
        // Get the session data.
590
        if (\TYPO3_MODE === 'FE') {
591
            return $GLOBALS['TSFE']->fe_user->getKey('ses', $key);
592
        } elseif (\TYPO3_MODE === 'BE') {
593
            return $GLOBALS['BE_USER']->getSessionData($key);
594
        } else {
595
            self::devLog('Unexpected TYPO3_MODE "' . \TYPO3_MODE . '"', DEVLOG_SEVERITY_ERROR);
596
            return;
597
        }
598
    }
599
600
    /**
601
     * Merges two arrays recursively and actually returns the modified array.
602
     * @see \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule()
603
     *
604
     * @access public
605
     *
606
     * @param array $original: Original array
607
     * @param array $overrule: Overrule array, overruling the original array
608
     * @param bool $addKeys: If set to false, keys that are not found in $original will not be set
609
     * @param bool $includeEmptyValues: If set, values from $overrule will overrule if they are empty
610
     * @param bool $enableUnsetFeature: If set, special value "__UNSET" can be used in the overrule array to unset keys in the original array
611
     *
612
     * @return array Merged array
613
     */
614
    public static function mergeRecursiveWithOverrule(array $original, array $overrule, $addKeys = true, $includeEmptyValues = true, $enableUnsetFeature = true)
615
    {
616
        \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($original, $overrule, $addKeys, $includeEmptyValues, $enableUnsetFeature);
617
        return $original;
618
    }
619
620
    /**
621
     * Process a data and/or command map with TYPO3 core engine as admin.
622
     *
623
     * @access public
624
     *
625
     * @param array $data: Data map
626
     * @param array $cmd: Command map
627
     * @param bool $reverseOrder: Should the data map be reversed?
628
     * @param bool $cmdFirst: Should the command map be processed first?
629
     *
630
     * @return array Array of substituted "NEW..." identifiers and their actual UIDs.
631
     */
632
    public static function processDBasAdmin(array $data = [], array $cmd = [], $reverseOrder = false, $cmdFirst = false)
633
    {
634
        if (
635
            \TYPO3_MODE === 'BE'
636
            && $GLOBALS['BE_USER']->isAdmin()
637
        ) {
638
            // Instantiate TYPO3 core engine.
639
            $dataHandler = GeneralUtility::makeInstance(\TYPO3\CMS\Core\DataHandling\DataHandler::class);
640
            // We do not use workspaces and have to bypass restrictions in DataHandler.
641
            $dataHandler->bypassWorkspaceRestrictions = true;
642
            // Load data and command arrays.
643
            $dataHandler->start($data, $cmd);
644
            // Process command map first if default order is reversed.
645
            if (
646
                !empty($cmd)
647
                && $cmdFirst
648
            ) {
649
                $dataHandler->process_cmdmap();
650
            }
651
            // Process data map.
652
            if (!empty($data)) {
653
                $dataHandler->reverseOrder = $reverseOrder;
654
                $dataHandler->process_datamap();
655
            }
656
            // Process command map if processing order is not reversed.
657
            if (
658
                !empty($cmd)
659
                && !$cmdFirst
660
            ) {
661
                $dataHandler->process_cmdmap();
662
            }
663
            return $dataHandler->substNEWwithIDs;
664
        } else {
665
            self::devLog('Current backend user has no admin privileges', DEVLOG_SEVERITY_ERROR);
666
            return [];
667
        }
668
    }
669
670
    /**
671
     * Fetches and renders all available flash messages from the queue.
672
     *
673
     * @access public
674
     *
675
     * @param string $queue: The queue's unique identifier
676
     *
677
     * @return string All flash messages in the queue rendered as HTML.
678
     */
679
    public static function renderFlashMessages($queue = 'kitodo.default.flashMessages')
680
    {
681
        $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
682
        $flashMessageQueue = $flashMessageService->getMessageQueueByIdentifier($queue);
683
        $flashMessages = $flashMessageQueue->getAllMessagesAndFlush();
684
        $content = GeneralUtility::makeInstance(\Kitodo\Dlf\Common\KitodoFlashMessageRenderer::class)
685
            ->render($flashMessages);
686
        return $content;
687
    }
688
689
    /**
690
     * Save given value to user's session.
691
     *
692
     * @access public
693
     *
694
     * @param mixed $value: Value to save
695
     * @param string $key: Session data key for saving
696
     *
697
     * @return bool true on success, false on failure
698
     */
699
    public static function saveToSession($value, $key)
700
    {
701
        // Cast to string for security reasons.
702
        $key = (string) $key;
703
        if (!$key) {
704
            self::devLog('Invalid key "' . $key . '" for session data saving', DEVLOG_SEVERITY_WARNING);
705
            return false;
706
        }
707
        // Save value in session data.
708
        if (\TYPO3_MODE === 'FE') {
709
            $GLOBALS['TSFE']->fe_user->setKey('ses', $key, $value);
710
            $GLOBALS['TSFE']->fe_user->storeSessionData();
711
            return true;
712
        } elseif (\TYPO3_MODE === 'BE') {
713
            $GLOBALS['BE_USER']->setAndSaveSessionData($key, $value);
714
            return true;
715
        } else {
716
            self::devLog('Unexpected TYPO3_MODE "' . \TYPO3_MODE . '"', DEVLOG_SEVERITY_ERROR);
717
            return false;
718
        }
719
    }
720
721
    /**
722
     * This translates an internal "index_name"
723
     *
724
     * @access public
725
     *
726
     * @param string $index_name: The internal "index_name" to translate
727
     * @param string $table: Get the translation from this table
728
     * @param string $pid: Get the translation from this page
729
     *
730
     * @return string Localized label for $index_name
731
     */
732
    public static function translate($index_name, $table, $pid)
733
    {
734
        // Load labels into static variable for future use.
735
        static $labels = [];
736
        // Sanitize input.
737
        $pid = max(intval($pid), 0);
738
        if (!$pid) {
739
            self::devLog('Invalid PID ' . $pid . ' for translation', DEVLOG_SEVERITY_WARNING);
740
            return $index_name;
741
        }
742
        // Check if "index_name" is an UID.
743
        if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($index_name)) {
744
            $index_name = self::getIndexNameFromUid($index_name, $table, $pid);
745
        }
746
        /* $labels already contains the translated content element, but with the index_name of the translated content element itself
747
         * and not with the $index_name of the original that we receive here. So we have to determine the index_name of the
748
         * associated translated content element. E.g. $labels['title0'] != $index_name = title. */
749
750
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
751
            ->getQueryBuilderForTable($table);
752
753
        // First fetch the uid of the received index_name
754
        $result = $queryBuilder
755
            ->select(
756
                $table . '.uid AS uid',
757
                $table . '.l18n_parent AS l18n_parent'
758
            )
759
            ->from($table)
760
            ->where(
761
                $queryBuilder->expr()->eq($table . '.pid', $pid),
762
                $queryBuilder->expr()->eq($table . '.index_name', $queryBuilder->expr()->literal($index_name)),
763
                self::whereExpression($table, true)
764
            )
765
            ->setMaxResults(1)
766
            ->execute();
767
768
        $allResults = $result->fetchAll();
769
770
        if (count($allResults) == 1) {
771
            // Now we use the uid of the l18_parent to fetch the index_name of the translated content element.
772
            $resArray = $allResults[0];
773
774
            $result = $queryBuilder
775
                ->select($table . '.index_name AS index_name')
776
                ->from($table)
777
                ->where(
778
                    $queryBuilder->expr()->eq($table . '.pid', $pid),
779
                    $queryBuilder->expr()->eq($table . '.uid', $resArray['l18n_parent']),
780
                    $queryBuilder->expr()->eq($table . '.sys_language_uid', intval($GLOBALS['TSFE']->sys_language_content)),
781
                    self::whereExpression($table, true)
782
                )
783
                ->setMaxResults(1)
784
                ->execute();
785
786
            $allResults = $result->fetchAll();
787
788
            if (count($allResults) == 1) {
789
                // If there is an translated content element, overwrite the received $index_name.
790
                $index_name = $allResults[0]['index_name'];
791
            }
792
        }
793
794
        // Check if we already got a translation.
795
        if (empty($labels[$table][$pid][$GLOBALS['TSFE']->sys_language_content][$index_name])) {
796
            // Check if this table is allowed for translation.
797
            if (in_array($table, ['tx_dlf_collections', 'tx_dlf_libraries', 'tx_dlf_metadata', 'tx_dlf_structures'])) {
798
                $additionalWhere = $queryBuilder->expr()->in($table . '.sys_language_uid', [-1, 0]);
799
                if ($GLOBALS['TSFE']->sys_language_content > 0) {
800
                    $additionalWhere = $queryBuilder->expr()->andX(
801
                        $queryBuilder->expr()->orX(
802
                            $queryBuilder->expr()->in($table . '.sys_language_uid', [-1, 0]),
803
                            $queryBuilder->expr()->eq($table . '.sys_language_uid', intval($GLOBALS['TSFE']->sys_language_content))
804
                        ),
805
                        $queryBuilder->expr()->eq($table . '.l18n_parent', 0)
806
                    );
807
                }
808
809
                // Get labels from database.
810
                $result = $queryBuilder
811
                    ->select('*')
812
                    ->from($table)
813
                    ->where(
814
                        $queryBuilder->expr()->eq($table . '.pid', $pid),
815
                        $additionalWhere,
816
                        self::whereExpression($table, true)
817
                    )
818
                    ->setMaxResults(10000)
819
                    ->execute();
820
821
                if ($result->rowCount() > 0) {
822
                    while ($resArray = $result->fetch()) {
823
                        // Overlay localized labels if available.
824
                        if ($GLOBALS['TSFE']->sys_language_content > 0) {
825
                            $resArray = $GLOBALS['TSFE']->sys_page->getRecordOverlay($table, $resArray, $GLOBALS['TSFE']->sys_language_content, $GLOBALS['TSFE']->sys_language_contentOL);
826
                        }
827
                        if ($resArray) {
828
                            $labels[$table][$pid][$GLOBALS['TSFE']->sys_language_content][$resArray['index_name']] = $resArray['label'];
829
                        }
830
                    }
831
                } else {
832
                    self::devLog('No translation with PID ' . $pid . ' available in table "' . $table . '" or translation not accessible', DEVLOG_SEVERITY_NOTICE);
833
                }
834
            } else {
835
                self::devLog('No translations available for table "' . $table . '"', DEVLOG_SEVERITY_WARNING);
836
            }
837
        }
838
839
        if (!empty($labels[$table][$pid][$GLOBALS['TSFE']->sys_language_content][$index_name])) {
840
            return $labels[$table][$pid][$GLOBALS['TSFE']->sys_language_content][$index_name];
841
        } else {
842
            return $index_name;
843
        }
844
    }
845
846
    /**
847
     * This returns the additional WHERE expression of a table based on its TCA configuration
848
     *
849
     * @access public
850
     *
851
     * @param string $table: Table name as defined in TCA
852
     * @param bool $showHidden: Ignore the hidden flag?
853
     *
854
     * @return string Additional WHERE expression
855
     */
856
    public static function whereExpression($table, $showHidden = false)
857
    {
858
        if (\TYPO3_MODE === 'FE') {
859
            // Should we ignore the record's hidden flag?
860
            $ignoreHide = 0;
861
            if ($showHidden) {
862
                $ignoreHide = 1;
863
            }
864
            $expression = $GLOBALS['TSFE']->sys_page->enableFields($table, $ignoreHide);
865
            if (!empty($expression)) {
866
                return substr($expression, 5);
867
            } else {
868
                return '';
869
            }
870
        } elseif (\TYPO3_MODE === 'BE') {
871
            return GeneralUtility::makeInstance(ConnectionPool::class)
872
                ->getQueryBuilderForTable($table)
873
                ->expr()
874
                ->eq($table . '.' . $GLOBALS['TCA'][$table]['ctrl']['delete'], 0);
875
        } else {
876
            self::devLog('Unexpected TYPO3_MODE "' . \TYPO3_MODE . '"', DEVLOG_SEVERITY_ERROR);
877
            return '1=-1';
878
        }
879
    }
880
881
    /**
882
     * Prevent instantiation by hiding the constructor
883
     *
884
     * @access private
885
     */
886
    private function __construct()
887
    {
888
        // This is a static class, thus no instances should be created.
889
    }
890
}
891