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.
Passed
Pull Request — master (#329)
by Sebastian
03:28
created

Helper::loadFromSession()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 4
nop 1
dl 0
loc 15
rs 9.9
c 0
b 0
f 0
1
<?php
2
namespace Kitodo\Dlf\Common;
3
4
/**
5
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
6
 *
7
 * This file is part of the Kitodo and TYPO3 projects.
8
 *
9
 * @license GNU General Public License version 3 or later.
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 */
13
14
/**
15
 * Helper class for the 'dlf' extension
16
 *
17
 * @author Sebastian Meyer <[email protected]>
18
 * @author Henrik Lochmann <[email protected]>
19
 * @package TYPO3
20
 * @subpackage dlf
21
 * @access public
22
 */
23
class Helper {
24
    /**
25
     * The extension key
26
     *
27
     * @var string
28
     * @access public
29
     */
30
    public static $extKey = 'dlf';
31
32
    /**
33
     * The locallang array for flash messages
34
     *
35
     * @var array
36
     * @access protected
37
     */
38
    protected static $messages = [];
39
40
    /**
41
     * Generates a flash message and adds it to a message queue.
42
     *
43
     * @access public
44
     *
45
     * @param string $message: The body of the message
46
     * @param string $title: The title of the message
47
     * @param integer $severity: The message's severity
48
     * @param boolean $session: Should the message be saved in the user's session?
49
     * @param string $queue: The queue's unique identifier
50
     *
51
     * @return \TYPO3\CMS\Core\Messaging\FlashMessageQueue The queue the message was added to
52
     */
53
    public static function addMessage($message, $title, $severity, $session = FALSE, $queue = 'kitodo.default.flashMessages') {
54
        $flashMessageService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
55
        $flashMessageQueue = $flashMessageService->getMessageQueueByIdentifier($queue);
56
        $flashMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
57
            \TYPO3\CMS\Core\Messaging\FlashMessage::class,
58
            $message,
59
            $title,
60
            $severity,
61
            $session
62
        );
63
        $flashMessageQueue->enqueue($flashMessage);
64
        return $flashMessageQueue;
65
    }
66
67
    /**
68
     * Check if given identifier is a valid identifier of the German National Library
69
     *
70
     * @access public
71
     *
72
     * @param string $id: The identifier to check
73
     * @param string $type: What type is the identifier supposed to be?
74
     *                      Possible values: PPN, IDN, PND, ZDB, SWD, GKD
75
     *
76
     * @return boolean Is $id a valid GNL identifier of the given $type?
77
     */
78
    public static function checkIdentifier($id, $type) {
79
        $digits = substr($id, 0, 8);
80
        $checksum = 0;
81
        for ($i = 0, $j = strlen($digits); $i < $j; $i++) {
82
            $checksum += (9 - $i) * intval(substr($digits, $i, 1));
83
        }
84
        $checksum = (11 - ($checksum % 11)) % 11;
85
        switch (strtoupper($type)) {
86
            case 'PPN':
87
            case 'IDN':
88
            case 'PND':
89
                if ($checksum == 10) {
90
                    $checksum = 'X';
91
                }
92
                if (!preg_match('/[0-9]{8}[0-9X]{1}/i', $id)) {
93
                    return FALSE;
94
                } elseif (strtoupper(substr($id, -1, 1)) != $checksum) {
95
                    return FALSE;
96
                }
97
                break;
98
            case 'ZDB':
99
                if ($checksum == 10) {
100
                    $checksum = 'X';
101
                }
102
                if (!preg_match('/[0-9]{8}-[0-9X]{1}/i', $id)) {
103
                    return FALSE;
104
                } elseif (strtoupper(substr($id, -1, 1)) != $checksum) {
105
                    return FALSE;
106
                }
107
                break;
108
            case 'SWD':
109
                $checksum = 11 - $checksum;
110
                if (!preg_match('/[0-9]{8}-[0-9]{1}/i', $id)) {
111
                    return FALSE;
112
                } elseif ($checksum == 10) {
113
                    return self::checkIdentifier(($digits + 1).substr($id, -2, 2), 'SWD');
114
                } elseif (substr($id, -1, 1) != $checksum) {
115
                    return FALSE;
116
                }
117
                break;
118
            case 'GKD':
119
                $checksum = 11 - $checksum;
120
                if ($checksum == 10) {
121
                    $checksum = 'X';
122
                }
123
                if (!preg_match('/[0-9]{8}-[0-9X]{1}/i', $id)) {
124
                    return FALSE;
125
                } elseif (strtoupper(substr($id, -1, 1)) != $checksum) {
126
                    return FALSE;
127
                }
128
                break;
129
        }
130
        return TRUE;
131
    }
132
133
    /**
134
     * Decrypt encrypted value with given control hash
135
     *
136
     * @access public
137
     *
138
     * @param string $encrypted: The encrypted value to decrypt
139
     * @param string $hash: The control hash for decrypting
140
     *
141
     * @return mixed The decrypted value or NULL on error
142
     */
143
    public static function decrypt($encrypted, $hash) {
144
        $decrypted = NULL;
0 ignored issues
show
Unused Code introduced by
The assignment to $decrypted is dead and can be removed.
Loading history...
145
        if (empty($encrypted)
146
            || empty($hash)) {
147
            self::devLog('Invalid parameters given for decryption', DEVLOG_SEVERITY_ERROR);
148
            return;
149
        }
150
        if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
151
            self::devLog('No encryption key set in TYPO3 configuration', DEVLOG_SEVERITY_ERROR);
152
            return;
153
        }
154
        $iv = substr(md5($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']), 0, openssl_cipher_iv_length('BF-CFB'));
155
        $decrypted = openssl_decrypt($encrypted, 'BF-CFB', substr($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'], 0, 56), 0, $iv);
156
        $salt = substr($hash, 0, 10);
157
        $hashed = $salt.substr(sha1($salt.$decrypted), -10);
158
        if ($hashed !== $hash) {
159
            self::devLog('Invalid hash "'.$hash.'" given for decryption', DEVLOG_SEVERITY_WARNING);
160
            return;
161
        }
162
        return $decrypted;
163
    }
164
165
    /**
166
     * Add a message to the TYPO3 developer log
167
     *
168
     * @access public
169
     *
170
     * @param string $message: The message to log
171
     * @param integer $severity: The severity of the message
172
     *                           0 is info, 1 is notice, 2 is warning, 3 is fatal error, -1 is "OK" message
173
     *
174
     * @return void
175
     */
176
    public static function devLog($message, $severity = 0) {
177
        if (TYPO3_DLOG) {
178
            $stacktrace = debug_backtrace(0, 2);
179
            // Set some defaults.
180
            $caller = 'Kitodo\Dlf\Default\UnknownClass::unknownMethod';
181
            $args = [];
182
            $data = [];
183
            if (!empty($stacktrace[1])) {
184
                $caller = $stacktrace[1]['class'].$stacktrace[1]['type'].$stacktrace[1]['function'];
185
                foreach ($stacktrace[1]['args'] as $arg) {
186
                    if (is_bool($arg)) {
187
                        $args[] = ($arg ? 'TRUE' : 'FALSE');
188
                    } elseif (is_scalar($arg)) {
189
                        $args[] = (string) $arg;
190
                    } elseif (is_null($arg)) {
191
                        $args[] = 'NULL';
192
                    } elseif (is_array($arg)) {
193
                        $args[] = '[data]';
194
                        $data[] = $arg;
195
                    } elseif (is_object($arg)) {
196
                        $args[] = '['.get_class($arg).']';
197
                        $data[] = $arg;
198
                    }
199
                }
200
            }
201
            $arguments = '('.implode(', ', $args).')';
202
            $additionalData = (empty($data) ? FALSE : $data);
203
            \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('['.$caller.$arguments.'] '.$message, self::$extKey, $severity, $additionalData);
204
        }
205
    }
206
207
    /**
208
     * Encrypt the given string
209
     *
210
     * @access public
211
     *
212
     * @param string $string: The string to encrypt
213
     *
214
     * @return array Array with encrypted string and control hash
215
     */
216
    public static function encrypt($string) {
217
        if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
218
            self::devLog('No encryption key set in TYPO3 configuration', DEVLOG_SEVERITY_ERROR);
219
            return;
220
        }
221
        $iv = substr(md5($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']), 0, openssl_cipher_iv_length('BF-CFB'));
222
        $encrypted = openssl_encrypt($string, 'BF-CFB', substr($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'], 0, 56), 0, $iv);
223
        $salt = substr(md5(uniqid(rand(), TRUE)), 0, 10);
224
        $hash = $salt.substr(sha1($salt.$string), -10);
225
        return ['encrypted' => $encrypted, 'hash' => $hash];
226
    }
227
228
    /**
229
     * Get a backend user object (even in frontend mode)
230
     *
231
     * @access public
232
     *
233
     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication Instance of \TYPO3\CMS\Core\Authentication\BackendUserAuthentication or NULL on failure
234
     */
235
    public static function getBeUser() {
236
        if (TYPO3_MODE === 'FE'
237
            || TYPO3_MODE === 'BE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'BE' is always true.
Loading history...
238
            // Initialize backend session with CLI user's rights.
239
            $userObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class);
240
            $userObj->dontSetCookie = TRUE;
241
            $userObj->start();
242
            $userObj->setBeUserByName('_cli_dlf');
243
            $userObj->backendCheckLogin();
244
            return $userObj;
245
        } else {
246
            self::devLog('Unexpected TYPO3_MODE "'.TYPO3_MODE.'"', DEVLOG_SEVERITY_ERROR);
247
            return;
248
        }
249
    }
250
251
    /**
252
     * Clean up a string to use in an URL.
253
     *
254
     * @access public
255
     *
256
     * @param string $string: The string to clean up
257
     *
258
     * @return string The cleaned up string
259
     */
260
    public static function getCleanString($string) {
261
        // Convert to lowercase.
262
        $string = strtolower($string);
263
        // Remove non-alphanumeric characters.
264
        $string = preg_replace('/[^a-z0-9_\s-]/', '', $string);
265
        // Remove multiple dashes or whitespaces.
266
        $string = preg_replace('/[\s-]+/', ' ', $string);
267
        // Convert whitespaces and underscore to dash.
268
        $string = preg_replace('/[\s_]/', '-', $string);
269
        return $string;
270
    }
271
272
    /**
273
     * Get the current frontend user object
274
     *
275
     * @access public
276
     *
277
     * @return \TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication Instance of \TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication or NULL on failure
278
     */
279
    public static function getFeUser() {
280
        if (TYPO3_MODE === 'FE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'FE' is always false.
Loading history...
281
            // Check if a user is currently logged in.
282
            if (!empty($GLOBALS['TSFE']->loginUser)) {
283
                return $GLOBALS['TSFE']->fe_user;
284
            } elseif (\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('eID') !== NULL) {
285
                return \TYPO3\CMS\Frontend\Utility\EidUtility::initFeUser();
286
            }
287
        } else {
288
            self::devLog('Unexpected TYPO3_MODE "'.TYPO3_MODE.'"', DEVLOG_SEVERITY_ERROR);
289
        }
290
        return;
291
    }
292
293
    /**
294
     * Get the registered hook objects for a class
295
     *
296
     * @access public
297
     *
298
     * @param string $scriptRelPath: The path to the class file
299
     *
300
     * @return array Array of hook objects for the class
301
     */
302
    public static function getHookObjects($scriptRelPath) {
303
        $hookObjects = [];
304
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::$extKey.'/'.$scriptRelPath]['hookClass'])) {
305
            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::$extKey.'/'.$scriptRelPath]['hookClass'] as $classRef) {
306
                $hookObjects[] = &\TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classRef);
307
            }
308
        }
309
        return $hookObjects;
310
    }
311
312
    /**
313
     * Get the "index_name" for an UID
314
     *
315
     * @access public
316
     *
317
     * @param integer $uid: The UID of the record
318
     * @param string $table: Get the "index_name" from this table
319
     * @param integer $pid: Get the "index_name" from this page
320
     *
321
     * @return string "index_name" for the given UID
322
     */
323
    public static function getIndexNameFromUid($uid, $table, $pid = -1) {
324
        // Sanitize input.
325
        $uid = max(intval($uid), 0);
326
        if (!$uid
327
            || !in_array($table, ['tx_dlf_collections', 'tx_dlf_libraries', 'tx_dlf_metadata', 'tx_dlf_structures', 'tx_dlf_solrcores'])) {
328
            self::devLog('Invalid UID "'.$uid.'" or table "'.$table.'"', DEVLOG_SEVERITY_ERROR);
329
            return '';
330
        }
331
        $where = '';
332
        // Should we check for a specific PID, too?
333
        if ($pid !== -1) {
334
            $pid = max(intval($pid), 0);
335
            $where = ' AND '.$table.'.pid='.$pid;
336
        }
337
        // Get index_name from database.
338
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
339
            $table.'.index_name AS index_name',
340
            $table,
341
            $table.'.uid='.$uid
342
                .$where
343
                .self::whereClause($table),
344
            '',
345
            '',
346
            '1'
347
        );
348
        if ($GLOBALS['TYPO3_DB']->sql_num_rows($result) > 0) {
349
            $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
350
            return $resArray['index_name'];
351
        } else {
352
            self::devLog('No "index_name" with UID '.$uid.' and PID '.$pid.' found in table "'.$table.'"', DEVLOG_SEVERITY_WARNING);
353
            return '';
354
        }
355
    }
356
357
    /**
358
     * Get language name from ISO code
359
     *
360
     * @access public
361
     *
362
     * @param string $code: ISO 639-1 or ISO 639-2/B language code
363
     *
364
     * @return string Localized full name of language or unchanged input
365
     */
366
    public static function getLanguageName($code) {
367
        // Analyze code and set appropriate ISO table.
368
        $isoCode = strtolower(trim($code));
369
        if (preg_match('/^[a-z]{3}$/', $isoCode)) {
370
            $file = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath(self::$extKey).'Resources/Private/ISO-639/iso-639-2b.xml';
371
        } elseif (preg_match('/^[a-z]{2}$/', $isoCode)) {
372
            $file = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath(self::$extKey).'Resources/Private/ISO-639/iso-639-1.xml';
373
        } else {
374
            // No ISO code, return unchanged.
375
            return $code;
376
        }
377
        // Load ISO table and get localized full name of language.
378
        if (TYPO3_MODE === 'FE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'FE' is always false.
Loading history...
379
            $iso639 = $GLOBALS['TSFE']->readLLfile($file);
380
            if (!empty($iso639['default'][$isoCode])) {
381
                $lang = $GLOBALS['TSFE']->getLLL($isoCode, $iso639);
382
            }
383
        } elseif (TYPO3_MODE === 'BE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'BE' is always true.
Loading history...
384
            $iso639 = $GLOBALS['LANG']->includeLLFile($file, FALSE, TRUE);
385
            if (!empty($iso639['default'][$isoCode])) {
386
                $lang = $GLOBALS['LANG']->getLLL($isoCode, $iso639, FALSE);
387
            }
388
        } else {
389
            self::devLog('Unexpected TYPO3_MODE "'.TYPO3_MODE.'"', DEVLOG_SEVERITY_ERROR);
390
            return $code;
391
        }
392
        if (!empty($lang)) {
393
            return $lang;
394
        } else {
395
            self::devLog('Language code "'.$code.'" not found in ISO-639 table', DEVLOG_SEVERITY_NOTICE);
396
            return $code;
397
        }
398
    }
399
400
    /**
401
     * Wrapper function for getting localized messages in frontend and backend
402
     *
403
     * @access public
404
     *
405
     * @param string $key: The locallang key to translate
406
     * @param boolean $hsc: Should the result be htmlspecialchar()'ed?
407
     * @param string $default: Default return value if no translation is available
408
     *
409
     * @return string The translated string or the given key on failure
410
     */
411
    public static function getMessage($key, $hsc = FALSE, $default = '') {
412
        // Set initial output to default value.
413
        $translated = (string) $default;
414
        // Load common messages file.
415
        if (empty(self::$messages)) {
416
            $file = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath(self::$extKey, 'Resources/Private/Language/FlashMessages.xml');
417
            if (TYPO3_MODE === 'FE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'FE' is always false.
Loading history...
418
                self::$messages = $GLOBALS['TSFE']->readLLfile($file);
419
            } elseif (TYPO3_MODE === 'BE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'BE' is always true.
Loading history...
420
                self::$messages = $GLOBALS['LANG']->includeLLFile($file, FALSE, TRUE);
421
            } else {
422
                self::devLog('Unexpected TYPO3_MODE "'.TYPO3_MODE.'"', DEVLOG_SEVERITY_ERROR);
423
            }
424
        }
425
        // Get translation.
426
        if (!empty(self::$messages['default'][$key])) {
427
            if (TYPO3_MODE === 'FE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'FE' is always false.
Loading history...
428
                $translated = $GLOBALS['TSFE']->getLLL($key, self::$messages);
429
            } elseif (TYPO3_MODE === 'BE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'BE' is always true.
Loading history...
430
                $translated = $GLOBALS['LANG']->getLLL($key, self::$messages, FALSE);
431
            } else {
432
                self::devLog('Unexpected TYPO3_MODE "'.TYPO3_MODE.'"', DEVLOG_SEVERITY_ERROR);
433
            }
434
        }
435
        // Escape HTML characters if applicable.
436
        if ($hsc) {
437
            $translated = htmlspecialchars($translated);
438
        }
439
        return $translated;
440
    }
441
442
    /**
443
     * Get the UID for a given "index_name"
444
     *
445
     * @access public
446
     *
447
     * @param integer $index_name: The index_name of the record
448
     * @param string $table: Get the "index_name" from this table
449
     * @param integer $pid: Get the "index_name" from this page
450
     *
451
     * @return string "uid" for the given index_name
452
     */
453
    public static function getUidFromIndexName($index_name, $table, $pid = -1) {
454
        if (!$index_name
455
            || !in_array($table, ['tx_dlf_collections', 'tx_dlf_libraries', 'tx_dlf_metadata', 'tx_dlf_structures', 'tx_dlf_solrcores'])) {
456
            self::devLog('Invalid UID '.$index_name.' or table "'.$table.'"', DEVLOG_SEVERITY_ERROR);
457
            return '';
458
        }
459
        $where = '';
460
        // Should we check for a specific PID, too?
461
        if ($pid !== -1) {
462
            $pid = max(intval($pid), 0);
463
            $where = ' AND '.$table.'.pid='.$pid;
464
        }
465
        // Get index_name from database.
466
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
467
            $table.'.uid AS uid',
468
            $table,
469
            $table.'.index_name="'.$index_name.'"'
470
                .$where
471
                .self::whereClause($table),
472
            '',
473
            '',
474
            '1'
475
        );
476
        if ($GLOBALS['TYPO3_DB']->sql_num_rows($result) > 0) {
477
            $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
478
            return $resArray['uid'];
479
        } else {
480
            self::devLog('No UID for given index_name "'.$index_name.'" and PID '.$pid.' found in table "'.$table.'"', DEVLOG_SEVERITY_WARNING);
481
            return '';
482
        }
483
    }
484
485
    /**
486
     * Get the URN of an object
487
     * @see http://www.persistent-identifier.de/?link=316
488
     *
489
     * @access public
490
     *
491
     * @param string $base: The namespace and base URN
492
     * @param string $id: The object's identifier
493
     *
494
     * @return string Uniform Resource Name as string
495
     */
496
    public static function getURN($base, $id) {
497
        $concordance = [
498
            '0' => 1,
499
            '1' => 2,
500
            '2' => 3,
501
            '3' => 4,
502
            '4' => 5,
503
            '5' => 6,
504
            '6' => 7,
505
            '7' => 8,
506
            '8' => 9,
507
            '9' => 41,
508
            'a' => 18,
509
            'b' => 14,
510
            'c' => 19,
511
            'd' => 15,
512
            'e' => 16,
513
            'f' => 21,
514
            'g' => 22,
515
            'h' => 23,
516
            'i' => 24,
517
            'j' => 25,
518
            'k' => 42,
519
            'l' => 26,
520
            'm' => 27,
521
            'n' => 13,
522
            'o' => 28,
523
            'p' => 29,
524
            'q' => 31,
525
            'r' => 12,
526
            's' => 32,
527
            't' => 33,
528
            'u' => 11,
529
            'v' => 34,
530
            'w' => 35,
531
            'x' => 36,
532
            'y' => 37,
533
            'z' => 38,
534
            '-' => 39,
535
            ':' => 17,
536
        ];
537
        $urn = strtolower($base.$id);
538
        if (preg_match('/[^a-z0-9:-]/', $urn)) {
539
            self::devLog('Invalid chars in given parameters', DEVLOG_SEVERITY_WARNING);
540
            return '';
541
        }
542
        $digits = '';
543
        for ($i = 0, $j = strlen($urn); $i < $j; $i++) {
544
            $digits .= $concordance[substr($urn, $i, 1)];
545
        }
546
        $checksum = 0;
547
        for ($i = 0, $j = strlen($digits); $i < $j; $i++) {
548
            $checksum += ($i + 1) * intval(substr($digits, $i, 1));
549
        }
550
        $checksum = substr(intval($checksum / intval(substr($digits, -1, 1))), -1, 1);
551
        return $base.$id.$checksum;
552
    }
553
554
    /**
555
     * Check if given ID is a valid Pica Production Number (PPN)
556
     *
557
     * @access public
558
     *
559
     * @param string $id: The identifier to check
560
     *
561
     * @return boolean Is $id a valid PPN?
562
     */
563
    public static function isPPN($id) {
564
        return self::checkIdentifier($id, 'PPN');
565
    }
566
567
    /**
568
     * Load value from user's session.
569
     *
570
     * @access public
571
     *
572
     * @param string $key: Session data key for retrieval
573
     *
574
     * @return mixed Session value for given key or NULL on failure
575
     */
576
    public static function loadFromSession($key) {
577
        // Cast to string for security reasons.
578
        $key = (string) $key;
579
        if (!$key) {
580
            self::devLog('Invalid key "'.$key.'" for session data retrieval', DEVLOG_SEVERITY_WARNING);
581
            return;
582
        }
583
        // Get the session data.
584
        if (TYPO3_MODE === 'FE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'FE' is always false.
Loading history...
585
            return $GLOBALS['TSFE']->fe_user->getKey('ses', $key);
586
        } elseif (TYPO3_MODE === 'BE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'BE' is always true.
Loading history...
587
            return $GLOBALS['BE_USER']->getSessionData($key);
588
        } else {
589
            self::devLog('Unexpected TYPO3_MODE "'.TYPO3_MODE.'"', DEVLOG_SEVERITY_ERROR);
590
            return;
591
        }
592
    }
593
594
    /**
595
     * Process a data and/or command map with TYPO3 core engine.
596
     *
597
     * @access public
598
     *
599
     * @param array $data: Data map
600
     * @param array $cmd: Command map
601
     * @param boolean $reverseOrder: Should the command map be processed first?
602
     * @param boolean $be_user: Use current backend user's rights for processing?
603
     *
604
     * @return array Array of substituted "NEW..." identifiers and their actual UIDs.
605
     */
606
    public static function processDB(array $data = [], array $cmd = [], $reverseOrder = FALSE, $be_user = FALSE) {
607
        // Instantiate TYPO3 core engine.
608
        $tce = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\DataHandling\DataHandler::class);
609
        // Set some configuration variables.
610
        $tce->stripslashes_values = FALSE;
611
        // Get backend user for processing.
612
        if ($be_user
613
            && isset($GLOBALS['BE_USER'])) {
614
            $user = $GLOBALS['BE_USER'];
615
        } else {
616
            $user = self::getBeUser();
617
        }
618
        // Load data and command arrays.
619
        $tce->start($data, $cmd, $user);
620
        // Process command map first if default order is reversed.
621
        if ($cmd
0 ignored issues
show
Bug Best Practice introduced by
The expression $cmd of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
622
            && $reverseOrder) {
623
            $tce->process_cmdmap();
624
        }
625
        // Process data map.
626
        if ($data) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $data of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
627
            $tce->process_datamap();
628
        }
629
        // Process command map if processing order is not reversed.
630
        if ($cmd
0 ignored issues
show
Bug Best Practice introduced by
The expression $cmd of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
631
            && !$reverseOrder) {
632
            $tce->process_cmdmap();
633
        }
634
        return $tce->substNEWwithIDs;
635
    }
636
637
    /**
638
     * Process a data and/or command map with TYPO3 core engine as admin.
639
     *
640
     * @access public
641
     *
642
     * @param array $data: Data map
643
     * @param array $cmd: Command map
644
     * @param boolean $reverseOrder: Should the command map be processed first?
645
     *
646
     * @return array Array of substituted "NEW..." identifiers and their actual UIDs.
647
     */
648
    public static function processDBasAdmin(array $data = [], array $cmd = [], $reverseOrder = FALSE) {
649
        if (TYPO3_MODE === 'BE'
650
            && $GLOBALS['BE_USER']->isAdmin()) {
651
            return self::processDB($data, $cmd, $reverseOrder, TRUE);
652
        } else {
653
            self::devLog('Current backend user has no admin privileges', DEVLOG_SEVERITY_ERROR);
654
            return [];
655
        }
656
    }
657
658
    /**
659
     * Fetches and renders all available flash messages from the queue.
660
     *
661
     * @access public
662
     *
663
     * @param string $queue: The queue's unique identifier
664
     *
665
     * @return string All flash messages in the queue rendered as HTML.
666
     */
667
    public static function renderFlashMessages($queue = 'kitodo.default.flashMessages') {
668
        $flashMessageService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
669
        $flashMessageQueue = $flashMessageService->getMessageQueueByIdentifier($queue);
670
        // \TYPO3\CMS\Core\Messaging\FlashMessage::getMessageAsMarkup() uses htmlspecialchars()
671
        // on all messages, but we have messages with HTML tags. Therefore we copy the official
672
        // implementation and remove the htmlspecialchars() call on the message body.
673
        $content = '';
674
        $flashMessages = $flashMessageQueue->getAllMessagesAndFlush();
675
        if (!empty($flashMessages)) {
676
            $content .= '<div class="typo3-messages">';
677
            foreach ($flashMessages as $flashMessage) {
678
                $messageTitle = $flashMessage->getTitle();
679
                $markup = [];
680
                $markup[] = '<div class="alert '.htmlspecialchars($flashMessage->getClass()).'">';
681
                $markup[] = '    <div class="media">';
682
                $markup[] = '        <div class="media-left">';
683
                $markup[] = '            <span class="fa-stack fa-lg">';
684
                $markup[] = '                <i class="fa fa-circle fa-stack-2x"></i>';
685
                $markup[] = '                <i class="fa fa-'.htmlspecialchars($flashMessage->getIconName()).' fa-stack-1x"></i>';
686
                $markup[] = '            </span>';
687
                $markup[] = '        </div>';
688
                $markup[] = '        <div class="media-body">';
689
                if (!empty($messageTitle)) {
690
                    $markup[] = '            <h4 class="alert-title">'.htmlspecialchars($messageTitle).'</h4>';
691
                }
692
                $markup[] = '            <p class="alert-message">'.$flashMessage->getMessage().'</p>'; // Removed htmlspecialchars() here.
693
                $markup[] = '        </div>';
694
                $markup[] = '    </div>';
695
                $markup[] = '</div>';
696
                $content .= implode('', $markup);
697
            }
698
            $content .= '</div>';
699
        }
700
        return $content;
701
    }
702
703
    /**
704
     * Save given value to user's session.
705
     *
706
     * @access public
707
     *
708
     * @param mixed $value: Value to save
709
     * @param string $key: Session data key for saving
710
     *
711
     * @return boolean TRUE on success, FALSE on failure
712
     */
713
    public static function saveToSession($value, $key) {
714
        // Cast to string for security reasons.
715
        $key = (string) $key;
716
        if (!$key) {
717
            self::devLog('Invalid key "'.$key.'" for session data saving', DEVLOG_SEVERITY_WARNING);
718
            return FALSE;
719
        }
720
        // Save value in session data.
721
        if (TYPO3_MODE === 'FE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'FE' is always false.
Loading history...
722
            $GLOBALS['TSFE']->fe_user->setKey('ses', $key, $value);
723
            $GLOBALS['TSFE']->fe_user->storeSessionData();
724
            return TRUE;
725
        } elseif (TYPO3_MODE === 'BE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'BE' is always true.
Loading history...
726
            $GLOBALS['BE_USER']->setAndSaveSessionData($key, $value);
727
            return TRUE;
728
        } else {
729
            self::devLog('Unexpected TYPO3_MODE "'.TYPO3_MODE.'"', DEVLOG_SEVERITY_ERROR);
730
            return FALSE;
731
        }
732
    }
733
734
    /**
735
     * This translates an internal "index_name"
736
     *
737
     * @access public
738
     *
739
     * @param string $index_name: The internal "index_name" to translate
740
     * @param string $table: Get the translation from this table
741
     * @param string $pid: Get the translation from this page
742
     *
743
     * @return string Localized label for $index_name
744
     */
745
    public static function translate($index_name, $table, $pid) {
746
        // Load labels into static variable for future use.
747
        static $labels = [];
748
        // Sanitize input.
749
        $pid = max(intval($pid), 0);
750
        if (!$pid) {
751
            self::devLog('Invalid PID '.$pid.' for translation', DEVLOG_SEVERITY_WARNING);
752
            return $index_name;
753
        }
754
        // Check if "index_name" is an UID.
755
        if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($index_name)) {
756
            $index_name = self::getIndexNameFromUid($index_name, $table, $pid);
757
        }
758
        /* $labels already contains the translated content element, but with the index_name of the translated content element itself
759
         * and not with the $index_name of the original that we receive here. So we have to determine the index_name of the
760
         * associated translated content element. E.g. $labels['title0'] != $index_name = title. */
761
        // First fetch the uid of the received index_name
762
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
763
            'uid, l18n_parent',
764
            $table,
765
            'pid='.$pid
766
                .' AND index_name="'.$index_name.'"'
767
                .self::whereClause($table, TRUE),
768
            '',
769
            '',
770
            ''
771
        );
772
        if ($GLOBALS['TYPO3_DB']->sql_num_rows($result) > 0) {
773
            // Now we use the uid of the l18_parent to fetch the index_name of the translated content element.
774
            $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
775
            $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
776
                'index_name',
777
                $table,
778
                'pid='.$pid
779
                    .' AND uid='.$resArray['l18n_parent']
780
                    .' AND sys_language_uid='.intval($GLOBALS['TSFE']->sys_language_content)
781
                    .self::whereClause($table, TRUE),
782
                '',
783
                '',
784
                ''
785
            );
786
            if ($GLOBALS['TYPO3_DB']->sql_num_rows($result) > 0) {
787
                // If there is an translated content element, overwrite the received $index_name.
788
                $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
789
                $index_name = $resArray['index_name'];
790
            }
791
        }
792
        // Check if we already got a translation.
793
        if (empty($labels[$table][$pid][$GLOBALS['TSFE']->sys_language_content][$index_name])) {
794
            // Check if this table is allowed for translation.
795
            if (in_array($table, ['tx_dlf_collections', 'tx_dlf_libraries', 'tx_dlf_metadata', 'tx_dlf_structures'])) {
796
                $additionalWhere = ' AND sys_language_uid IN (-1,0)';
797
                if ($GLOBALS['TSFE']->sys_language_content > 0) {
798
                    $additionalWhere = ' AND (sys_language_uid IN (-1,0) OR (sys_language_uid='.intval($GLOBALS['TSFE']->sys_language_content).' AND l18n_parent=0))';
799
                }
800
                // Get labels from database.
801
                $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
802
                    '*',
803
                    $table,
804
                    'pid='.$pid
805
                        .$additionalWhere
806
                        .self::whereClause($table, TRUE),
807
                    '',
808
                    '',
809
                    ''
810
                );
811
                if ($GLOBALS['TYPO3_DB']->sql_num_rows($result) > 0) {
812
                    while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
813
                        // Overlay localized labels if available.
814
                        if ($GLOBALS['TSFE']->sys_language_content > 0) {
815
                            $resArray = $GLOBALS['TSFE']->sys_page->getRecordOverlay($table, $resArray, $GLOBALS['TSFE']->sys_language_content, $GLOBALS['TSFE']->sys_language_contentOL);
816
                        }
817
                        if ($resArray) {
818
                            $labels[$table][$pid][$GLOBALS['TSFE']->sys_language_content][$resArray['index_name']] = $resArray['label'];
819
                        }
820
                    }
821
                } else {
822
                    self::devLog('No translation with PID '.$pid.' available in table "'.$table.'" or translation not accessible', DEVLOG_SEVERITY_NOTICE);
823
                }
824
            } else {
825
                self::devLog('No translations available for table "'.$table.'"', DEVLOG_SEVERITY_WARNING);
826
            }
827
        }
828
        if (!empty($labels[$table][$pid][$GLOBALS['TSFE']->sys_language_content][$index_name])) {
829
            return $labels[$table][$pid][$GLOBALS['TSFE']->sys_language_content][$index_name];
830
        } else {
831
            return $index_name;
832
        }
833
    }
834
835
    /**
836
     * This returns the additional WHERE clause of a table based on its TCA configuration
837
     *
838
     * @access public
839
     *
840
     * @param string $table: Table name as defined in TCA
841
     * @param boolean $showHidden: Ignore the hidden flag?
842
     *
843
     * @return string Additional WHERE clause
844
     */
845
    public static function whereClause($table, $showHidden = FALSE) {
846
        if (TYPO3_MODE === 'FE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'FE' is always false.
Loading history...
847
            // Table "tx_dlf_formats" always has PID 0.
848
            if ($table == 'tx_dlf_formats') {
849
                return \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause($table);
850
            }
851
            // Should we ignore the record's hidden flag?
852
            $ignoreHide = -1;
853
            if ($showHidden) {
854
                $ignoreHide = 1;
855
            }
856
            // $GLOBALS['TSFE']->sys_page is not always available in frontend.
857
            if (is_object($GLOBALS['TSFE']->sys_page)) {
858
                return $GLOBALS['TSFE']->sys_page->enableFields($table, $ignoreHide);
859
            } else {
860
                $pageRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Page\PageRepository::class);
861
                $GLOBALS['TSFE']->includeTCA();
862
                return $pageRepository->enableFields($table, $ignoreHide);
863
            }
864
        } elseif (TYPO3_MODE === 'BE') {
0 ignored issues
show
introduced by
The condition Kitodo\Dlf\Common\TYPO3_MODE === 'BE' is always true.
Loading history...
865
            return \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause($table);
866
        } else {
867
            self::devLog('Unexpected TYPO3_MODE "'.TYPO3_MODE.'"', DEVLOG_SEVERITY_ERROR);
868
            return ' AND 1=-1';
869
        }
870
    }
871
872
    /**
873
     * This is a static class, thus no instances should be created
874
     *
875
     * @access private
876
     */
877
    private function __construct() {}
878
}
879