Store.php 22.7 KB
Newer Older
1
2
3
4
5
6
7
8
<?php
/**
 * Created by PhpStorm.
 * User: crose
 * Date: 1/1/16
 * Time: 6:51 PM
 */

9
namespace qfq;
10

11
use qfq\CodeException;
12
13
use qfq\keyValueStringParser;
use qfq\OnArray;
14
use qfq;
15

16
require_once(__DIR__ . '/../../qfq/helper/KeyValueStringParser.php');
Carsten  Rose's avatar
Carsten Rose committed
17
require_once(__DIR__ . '/../../qfq/helper/Sanitize.php');
18
require_once(__DIR__ . '/../../qfq/Constants.php');
19
require_once(__DIR__ . '/../../qfq/store/Sip.php');
20
//require_once(__DIR__ . '/../../qfq/store/Session.php');
21
require_once(__DIR__ . '/../../qfq/Database.php');
22
23
24
25
26
27
28
29
30
31
32


/*
 * Stores:
 * - SIP
 * - webVar
 * - record
 * - form
 * - formElement
 */

Carsten  Rose's avatar
Carsten Rose committed
33
34
/**
 * Class Store
35
 * @package qfq
Carsten  Rose's avatar
Carsten Rose committed
36
 */
37
38
class Store {

Carsten  Rose's avatar
Carsten Rose committed
39
40
41
    /**
     * @var Store Instance of class Store. There should only be one class 'Store' at a time.
     */
42
43
    private static $instance = null;

Carsten  Rose's avatar
Carsten Rose committed
44
45
46
    /**
     * @var Sip Instance of class SIP
     */
47
48
    private static $sip = null;

49
50
51
    /**
     * @var Session Instance of class Session
     */
52
//    private static $session = null;
53

Carsten  Rose's avatar
Carsten Rose committed
54
55
56
57
58
59
60
61
62
63
    /**
     * @var array Stores all indiviudal stores with the variable raw values
     *
     * $raw['D']['id'] = 0  - Defaultvalues from Tabledefinition
     * ...
     * $raw['S']['r'] = 1234 - record ID from current SIP identifier
     * ...
     * $raw['C']['HTTP_SERVER'] = 'qfq' - Servername
     * $raw['C']['s'] = 'badcaffee1234' - recent SIP
     */
64
    private static $raw = array();
Carsten  Rose's avatar
Carsten Rose committed
65
66

    /**
Carsten  Rose's avatar
Carsten Rose committed
67
     * @var array Default sanitize classes.
Carsten  Rose's avatar
Carsten Rose committed
68
     */
Carsten  Rose's avatar
Carsten Rose committed
69
    private static $sanitizeClass = array();
Carsten  Rose's avatar
Carsten Rose committed
70
71

    /**
Carsten  Rose's avatar
Carsten Rose committed
72
73
     * $sanitizeClass['S'] = false
     * $sanitizeClass['C'] = true
Carsten  Rose's avatar
Carsten Rose committed
74
75
     * ...
     *
Carsten  Rose's avatar
Carsten Rose committed
76
     * @var array each entry with true/false - depending if store needs to be sanitized.
Carsten  Rose's avatar
Carsten Rose committed
77
     */
Carsten  Rose's avatar
Carsten Rose committed
78
    private static $sanitizeStore = array();
79

Carsten  Rose's avatar
Carsten Rose committed
80
    private static $phpUnit = false;
81

82

83
    /**
84
     * @param string $bodytext
85
     */
86
    private function __construct($bodytext = '') {
87

88
//        self::$session = Session::getInstance(self::$phpUnit);
89

Carsten  Rose's avatar
Carsten Rose committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
        self::$sanitizeClass = [
//            TYPO3_DEBUG_LOAD => SANITIZE_ALLOW_DIGIT,
//            TYPO3_DEBUG_SAVE => SANITIZE_ALLOW_DIGIT,
//            TYPO3_FORM => SANITIZE_ALLOW_ALNUMX,
//            TYPO3_FE_USER => SANITIZE_ALLOW_ALNUMX,
//            TYPO3_FE_USER_UID => SANITIZE_ALLOW_DIGIT,
//            TYPO3_FE_USER_GROUP => SANITIZE_ALLOW_ALNUMX,

            CLIENT_SIP => SANITIZE_ALLOW_ALNUMX,
            CLIENT_RECORD_ID => SANITIZE_ALLOW_DIGIT,
            CLIENT_KEY_SEM_ID => SANITIZE_ALLOW_DIGIT,
            CLIENT_KEY_SEM_ID_USER => SANITIZE_ALLOW_DIGIT,
            CLIENT_PAGE_ID => SANITIZE_ALLOW_DIGIT,
            CLIENT_PAGE_TYPE => SANITIZE_ALLOW_DIGIT,
            CLIENT_PAGE_LANGUAGE => SANITIZE_ALLOW_DIGIT,
            CLIENT_FORM => SANITIZE_ALLOW_ALNUMX,

            // Part of $_SERVER. Missing vars must be requested individual with the needed sanitize class.
            CLIENT_SCRIPT_URL => SANITIZE_ALLOW_ALNUMX,
            CLIENT_SCRIPT_URI => SANITIZE_ALLOW_ALNUMX,
            CLIENT_HTTP_HOST => SANITIZE_ALLOW_ALNUMX,
            CLIENT_HTTP_USER_AGENT => SANITIZE_ALLOW_ALNUMX,
            CLIENT_SERVER_NAME => SANITIZE_ALLOW_ALNUMX,
            CLIENT_SERVER_ADDRESS => SANITIZE_ALLOW_ALNUMX,
            CLIENT_SERVER_PORT => SANITIZE_ALLOW_DIGIT,
            CLIENT_REMOTE_ADDRESS => SANITIZE_ALLOW_ALNUMX,
            CLIENT_REQUEST_SCHEME => SANITIZE_ALLOW_ALNUMX,
            CLIENT_SCRIPT_FILENAME => SANITIZE_ALLOW_ALNUMX,
            CLIENT_QUERY_STRING => SANITIZE_ALLOW_ALL,
            CLIENT_REQUEST_URI => SANITIZE_ALLOW_ALL,
            CLIENT_SCRIPT_NAME => SANITIZE_ALLOW_ALNUMX,
            CLIENT_PHP_SELF => SANITIZE_ALLOW_ALNUMX,
122
            CLIENT_UPLOAD_FILENAME => SANITIZE_ALLOW_ALLBUT,
Carsten  Rose's avatar
Carsten Rose committed
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

//            SYSTEM_DBUSER => SANITIZE_ALLOW_ALNUMX,
//            SYSTEM_DBSERVER => SANITIZE_ALLOW_ALNUMX,
//            SYSTEM_DBPW => SANITIZE_ALLOW_ALL,
//            SYSTEM_DB => SANITIZE_ALLOW_ALNUMX,
//            SYSTEM_TESTDB => SANITIZE_ALLOW_ALNUMX,
//            SYSTEM_SESSIONNAME => SANITIZE_ALLOW_ALNUMX,
//            SYSTEM_DBH => SANITIZE_ALLOW_ALL,

//            SYSTEM_SQL_RAW => SANITIZE_ALLOW_ALL,
//            SYSTEM_SQL_FINAL => SANITIZE_ALLOW_ALL,
//            SYSTEM_SQL_COUNT => SANITIZE_ALLOW_DIGIT,
//            SYSTEM_SQL_PARAM_ARRAY => SANITIZE_ALLOW_ALL,

//            SIP_SIP => SANITIZE_ALLOW_ALNUMX,
//            SIP_RECORD_ID => SANITIZE_ALLOW_DIGIT,
//            SIP_FORM => SANITIZE_ALLOW_ALNUMX,
//            SIP_URLPARAM => SANITIZE_ALLOW_ALL
141

142
143
        ];

Carsten  Rose's avatar
Carsten Rose committed
144
        self::$sanitizeStore = [
145
146
147
            STORE_FORM => true,
            STORE_SIP => false,
            STORE_RECORD => false,
148
            STORE_BEFORE => false,
149
            STORE_PARENT_RECORD => false,
150
151
            STORE_TABLE_DEFAULT => false,
            STORE_TABLE_COLUMN_TYPES => false,
152
153
            STORE_CLIENT => true,
            STORE_TYPO3 => false,
154
            STORE_VAR => false,
155
            STORE_ZERO => false,
156
            STORE_EMPTY => false,
157
            STORE_SYSTEM => false,
158
            STORE_EXTRA => false
159
160
        ];

161
        self::fillSystemStore();
162
        self::fillStoreTypo3($bodytext);
163
        self::fillStoreClient();
164
        self::fillStoreSip();
Carsten  Rose's avatar
Carsten Rose committed
165
        self::fillStoreExtra();
166
167


168
    }
169

170
    /**
Carsten  Rose's avatar
Carsten Rose committed
171
172
     * Fills the system store.
     *
173
     * @throws CodeException
174
     * @throws qfq\UserFormException
175
     */
176
    private static function fillSystemStore() {
177
178
179
180
181
182
183
184
185
186
187
188

        // PHPUnit Path to CONFIG_INI
        $configIni = __DIR__ . '/../../../' . CONFIG_INI;
        if (!file_exists($configIni)) {
            // Production Path to CONFIG_INI
            $configIni = __DIR__ . '/../../../../../' . CONFIG_INI;

            if (!file_exists($configIni)) {
                throw new qfq\UserFormException ("Config not found: " . getcwd() . "/" . $configIni, ERROR_IO_READ_FILE);
            }
        }

189
        try {
190
            //TODO: Vernuenftige Fehlermeldung falls nicht auf qfq.ini zugegriffen werden kann.
191
192
//            $config = parse_ini_file(__DIR__ . '/../../../' . CONFIG_INI, false);
            $config = parse_ini_file($configIni, false);
193

194
195
            //TODO: auskommentiert weil dann die Unittests nicht mehr laufen. Sollte eigentlich wieder aktiviert werden.
//            $config['SQLLOG'] = Support::ifRelativePathPrependExtensionPath($config['SQLLOG']);
196

197
        } catch (\Exception $e) {
198
            throw new qfq\UserFormException ("Error read file " . CONFIG_INI . ": " . $e->getMessage(), ERROR_IO_READ_FILE);
199
        }
200

201
        // Adjust config
202
        if (!isset($config['SHOW_DEBUG_INFO']) || $config['SHOW_DEBUG_INFO'] === 'auto') {
203
204
205
            $config['SHOW_DEBUG_INFO'] = (isset($GLOBALS["TSFE"]->beUserLogin) && $GLOBALS["TSFE"]->beUserLogin === true) ? 'yes' : 'no';
        }

206
207
208
209
210
211
212
        // SYSTEM_PATH_EXT: compute only if not already defined.
        if (!isset($config[SYSTEM_PATH_EXT]) || $config[SYSTEM_PATH_EXT] === '' || $config[SYSTEM_PATH_EXT][0] !== '/') {
            $relExtDir = '/typo3conf/ext/' . EXT_KEY;

            // If we are called through AJAX API (e.g. api/save.php), there is no TYPO3 environment.
            if (isset($_SERVER['SCRIPT_FILENAME'])) {
                $pos = strpos($_SERVER['SCRIPT_FILENAME'], $relExtDir);
213
214
                if ($pos === false && isset($GLOBALS['TYPO3_LOADED_EXT'][EXT_KEY]['ext_localconf.php'])) {

215
                    // Typo3 extension: probably index.php
216
                    $config[SYSTEM_PATH_EXT] = dirname($GLOBALS['TYPO3_LOADED_EXT'][EXT_KEY]['ext_localconf.php']);
217
                    $config[SYSTEM_SITE_PATH] = dirname($_SERVER['SCRIPT_FILENAME']);
218
                } else {
219
                    // API
220
                    $config[SYSTEM_PATH_EXT] = substr($_SERVER['SCRIPT_FILENAME'], 0, $pos + strlen($relExtDir));
221
                    $config[SYSTEM_SITE_PATH] = substr($_SERVER['SCRIPT_FILENAME'], 0, $pos);
222
                }
223
224
225
226
            } else {
                // No $_SERVER >>this means phpUnit.
                $config[SYSTEM_SITE_PATH] = getcwd();
                $config[SYSTEM_PATH_EXT] = getcwd();
227
228
229
            }
        }

230
231
232
        // Defaults
        Support::setIfNotSet($config, SYSTEM_DATE_FORMAT, 'yyyy-mm-dd');

233
234
235
236
237
        // make SQL PATH absolute. This is necessary to work in different directories correctly.
        if (isset($config[SYSTEM_SQL_LOG]) && $config[SYSTEM_SQL_LOG][0] !== '/') {
            $config[SYSTEM_SQL_LOG] = $config[SYSTEM_PATH_EXT] . '/' . $config[SYSTEM_SQL_LOG];
        }

238
239
240
241
242
243
244
        // Verify existence
        $names = array('DB_USER', 'DB_SERVER', 'DB_PASSWORD', 'DB_NAME', 'SQL_LOG', 'SQL_LOG_MODE');
        foreach ($names as $name) {
            if (!isset($config[$name])) {
                throw new qfq\UserFormException ("Missing configuration in `config.ini`: $name", ERROR_MISSING_CONFIG_INI_VALUE);
            }
        }
245

246
        self::setVarArray($config, STORE_SYSTEM, true);
247
248
    }

249
    /**
Carsten  Rose's avatar
Carsten Rose committed
250
251
     * Set or overwrite a complete store.
     *
252
253
     * @param array $dataArray
     * @param $store
254
     * @param bool|false $flagOverwrite
255
     * @throws UserFormException
256
     * @throws \qfq\CodeException
257
     */
258
    public static function setVarArray(array $dataArray, $store, $flagOverwrite = false) {
259

Carsten  Rose's avatar
Carsten Rose committed
260
        // Check valid Storename
Carsten  Rose's avatar
Carsten Rose committed
261
        if (!isset(self::$sanitizeStore))
262
            throw new UserFormException("Unknown Store: $store", ERROR_UNNOWN_STORE);
Carsten  Rose's avatar
Carsten Rose committed
263

264
        if ($store === STORE_ZERO)
Carsten  Rose's avatar
Carsten Rose committed
265
            throw new CodeException("setVarArray() for STORE_ZERO is impossible - there are no values.", ERROR_SET_STORE_ZERO);
266

Carsten  Rose's avatar
Carsten Rose committed
267
        if (!$flagOverwrite && isset(self::$raw[$store]) && count(self::$raw[$store]) > 0) {
268
            throw new CodeException("Raw values already been copied to store '$store'. Do this only one time.", ERROR_STORE_VALUE_ALREADY_CODPIED);
269
        }
270

271
272
        self::$raw[$store] = $dataArray;
    }
273

274
    /**
275
276
277
     * Copy the BodyText as well as some T3 specific vars to STORE_TYPO3.
     * Attention: if called through API, there is no T3 environment. The only values which are available are fe_user and fe_user_uid.
     *
278
279
280
     * @param $bodytext
     * @throws CodeException
     */
281
    private static function fillStoreTypo3($bodytext) {
282

283
        // form=, showDebugBodyText=, 10.20..
284
        $arr = KeyValueStringParser::parse($bodytext, "=", "\n");
285

286
        if (isset($GLOBALS["TSFE"])) {
287

288
289
290
            if (isset($GLOBALS["TSFE"]->fe_user->user["username"])) {
                $arr[TYPO3_FE_USER] = $GLOBALS["TSFE"]->fe_user->user["username"];
            }
291

292
293
294
295
            if (isset($GLOBALS["TSFE"]->fe_user->user["uid"])) {
                $feUid = $GLOBALS["TSFE"]->fe_user->user["uid"];
                $arr[TYPO3_FE_USER_UID] = $GLOBALS["TSFE"]->fe_user->user["uid"];
            }
296

297
298
299
            if (isset($GLOBALS["TSFE"]->fe_user->user["usergroup"])) {
                $arr[TYPO3_FE_USER_GROUP] = $GLOBALS["TSFE"]->fe_user->user["usergroup"];
            }
Carsten  Rose's avatar
Carsten Rose committed
300

301
302
303
            if (isset($GLOBALS["TSFE"]->page["uid"])) {
                $arr[TYPO3_TT_CONTENT_UID] = $GLOBALS["TSFE"]->page["uid"];
            }
304

305
306
307
308
309
310
311
            if (isset($GLOBALS["TSFE"]->id)) {
                $arr[TYPO3_PAGE_ID] = $GLOBALS["TSFE"]->id;
            }

            if (isset($GLOBALS["TSFE"]->type)) {
                $arr[TYPO3_PAGE_TYPE] = $GLOBALS["TSFE"]->type;
            }
Carsten  Rose's avatar
Carsten Rose committed
312

313
314
315
            if (isset($GLOBALS["TSFE"]->sys_language_uid)) {
                $arr[TYPO3_PAGE_LANGUAGE] = $GLOBALS["TSFE"]->sys_language_uid;
            }
316

317
        } else {
318

319
            // NO T3 environment (called by API): restore from SESSION
320
321
322
323
            foreach([ SESSION_FE_USER, SESSION_FE_USER_UID, SESSION_FE_USER_GROUP ] as $key) {
                if (isset($_SESSION[SESSION_NAME][$key])) {
                    $arr[$key] = $_SESSION[SESSION_NAME][$key];
                }
324
325
            }
        }
326

327
        self::setVarArray($arr, STORE_TYPO3, true);
328
    }
329

330
    /**
Carsten  Rose's avatar
Carsten Rose committed
331
332
     * Fills the STORE_CLIENT
     *
333
334
     * @throws CodeException
     */
335
    private static function fillStoreClient() {
336
        // copy GET and POST and SERVER Parameter. Priority: SERVER, POST, GET
337
338
339
340
341
342
343
344
345
        $arr = array();
        if (isset($_GET))
            $arr = array_merge($arr, $_GET);

        if (isset($_POST))
            $arr = array_merge($arr, $_POST);

        if (isset($_SERVER))
            $arr = array_merge($arr, $_SERVER);
346

347
        self::setVarArray($arr, STORE_CLIENT, true);
348
    }
349

Carsten  Rose's avatar
Carsten Rose committed
350
    /**
Carsten  Rose's avatar
Carsten Rose committed
351
352
     * Fills the STORE_SIP. Reads therefore specified SIP, decode the values and stores them in STORE_SIP.
     *
Carsten  Rose's avatar
Carsten Rose committed
353
     * @throws CodeException
354
     * @throws UserFormException
Carsten  Rose's avatar
Carsten Rose committed
355
     */
356
    private static function fillStoreSip() {
Carsten  Rose's avatar
Carsten Rose committed
357

358
        self::$sip = new Sip(self::$phpUnit);
359

360
361
362
363
        $s = self::getVar(CLIENT_SIP, STORE_CLIENT);
        if ($s !== false) {
            // if session is given, copy values to store
            $param = self::$sip->getVarsFromSip($s);
364
365
            $param[SIP_SIP] = $s;
            $param[SIP_URLPARAM] = self::$sip->getQueryStringFromSip($s);
366

367
//            self::setVarArray(KeyValueStringParser::parse($param, "=", "&"), STORE_SIP);
368
            self::setVarArray($param, STORE_SIP, true);
369
370
371
        }
    }

372
    /**
373
     * Cycles through all stores in $useStore.
374
     * First match will return the found value.
Carsten  Rose's avatar
Carsten Rose committed
375
     * During cycling: fill cache with requestet value and sanitize raw value.
376
     *
377
     * @param string $key
378
     * @param string $useStores f.e.: 'FSRD'
Carsten  Rose's avatar
Carsten Rose committed
379
     * @param string $sanitizeClass
Carsten  Rose's avatar
Carsten Rose committed
380
     * @param string $foundInStore Returns the name of the store where $key has been found. If $key is not found, return ''.
381
     * @return string a) if found: value, b) false
Carsten  Rose's avatar
Carsten Rose committed
382
     * @throws \qfq\CodeException
383
     */
Carsten  Rose's avatar
Carsten Rose committed
384
    public static function getVar($key, $useStores = STORE_USE_DEFAULT, $sanitizeClass = '', &$foundInStore = '') {
385
386

        // no store specifed?
387
        if ($useStores === "" || $useStores === null) {
388
            $useStores = STORE_USE_DEFAULT;
389
390
        }

391
        // no sanitizeClass specified: take predefined (if exist) or default.
392
        if ($sanitizeClass === '' || $sanitizeClass === null) {
Carsten  Rose's avatar
Carsten Rose committed
393
            $sanitizeClass = isset(self::$sanitizeClass[$key]) ? self::$sanitizeClass[$key] : SANITIZE_DEFAULT;
394
395
        }

396
397
398
        while ($useStores !== false) {

            $store = substr($useStores, 0, 1); // next store
Carsten  Rose's avatar
Carsten Rose committed
399
            $foundInStore = $store;
400
401
            $useStores = substr($useStores, 1); // shift left remaining stores

402
            if (!isset(self::$raw[$store][$key])) {
403
404
405
                switch ($store) {
                    case STORE_ZERO:
                        return 0;
406
407
                    case STORE_EMPTY:
                        return '';
408
409
                    case STORE_VAR:
                        if ($key === VAR_RANDOM) {
410
                            return Support::randomAlphaNum(RANDOM_LENGTH);
411
412
413
414
415
416
417
                        } else {
                            continue 2;  // no value provided, continue with while loop
                        }
                        break;
                    default:
                        continue 2; // no value provided, continue with while loop
                        break;
Carsten  Rose's avatar
Carsten Rose committed
418
                }
419
420
            }

421
            $rawVal = isset(self::$raw[$store][$key]) ? self::$raw[$store][$key] : null;
Carsten  Rose's avatar
Carsten Rose committed
422
            if (self::$sanitizeStore[$store] && $sanitizeClass != '') {
423
424
425
426
427
                if ($sanitizeClass == SANITIZE_ALLOW_PATTERN || $sanitizeClass == SANITIZE_ALLOW_MIN_MAX || $sanitizeClass == SANITIZE_ALLOW_MIN_MAX_DATE) {
                    // We do not have any pattern or min|max values at this point. For those who be affected, they already checked earlier. So set 'no check'
                    $sanitizeClass = SANITIZE_ALLOW_ALL;
                }
                return \qfq\Sanitize::sanitize($rawVal, $sanitizeClass, '', SANATIZE_EMPTY_STRING);
428
429
            } else {
                return $rawVal;
430
            }
431
        }
Carsten  Rose's avatar
Carsten Rose committed
432
        $foundInStore = '';
433
        return false;
434
    }
435

Carsten  Rose's avatar
Carsten Rose committed
436
    /**
Carsten  Rose's avatar
Carsten Rose committed
437
438
     * Fills the STORE_EXTRA.
     *
Carsten  Rose's avatar
Carsten Rose committed
439
440
441
442
     * @throws UserFormException
     * @throws \qfq\CodeException
     */
    private static function fillStoreExtra() {
443

444
        $value = Session::get(STORE_EXTRA);
445

446
        if (!isset($_SESSION[SESSION_NAME][STORE_EXTRA]) || $_SESSION[SESSION_NAME][STORE_EXTRA] === null) {
447
448
449
450
            $value = false;
        }

        if ($value === false) {
Carsten  Rose's avatar
Carsten Rose committed
451
            self::setVarArray(array(), STORE_EXTRA, true);
452
        } else {
453
            self::setVarArray($_SESSION[SESSION_NAME][STORE_EXTRA], STORE_EXTRA, true);
454
        }
Carsten  Rose's avatar
Carsten Rose committed
455
456
    }

457
    /**
Carsten  Rose's avatar
Carsten Rose committed
458
459
     * Returns a pointer to this Class.
     *
460
     * @param string $bodytext
461
     * @param bool|false $phpUnit
462
     * @return null|\qfq\Store
463
     */
464
    public static function getInstance($bodytext = '', $phpUnit = false) {
465

466
        if ($phpUnit) {
467
            if (self::$instance !== null) {
468
                // fake to have a clean environment for the next test.
469
470
471
472
473
                self::unsetStore(STORE_TYPO3);
                self::fillStoreTypo3($bodytext);

                self::unsetStore(STORE_CLIENT);
                self::fillStoreClient();
474
475
476
477
478
            }
        }

        // Design Pattern: Singleton
        if (self::$instance === null) {
479
480
481
            self::$phpUnit = $phpUnit;

            self::$instance = new self($bodytext);
Carsten  Rose's avatar
Carsten Rose committed
482
483
484
485
        } else {
            // Class Store seems to be presistent over multiple QFQ instantiation. Set bodytext again, with every new request (if bodytext is given).
            if ($bodytext !== '')
                self::fillStoreTypo3($bodytext);
486
487
        }

488
489
490
491
492
493
494
        // Disable TYPO3_DEBUG_SHOW_BODY_TEXT=1 if SYSTEM_SHOW_DEBUG_INFO!='yes'
        if (self::getVar(TYPO3_DEBUG_SHOW_BODY_TEXT, STORE_TYPO3) === '1' &&
            self::getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM) !== 'yes'
        ) {
            self::setVar(TYPO3_DEBUG_SHOW_BODY_TEXT, '0', STORE_TYPO3);
        }

495
        return self::$instance;
496
    }
497

498
    /**
Carsten  Rose's avatar
Carsten Rose committed
499
500
     * Deletes a store assigning a new empty array to it.
     *
501
     * @param $store
502
503
     * @throws UserFormException
     * @throws \qfq\CodeException
504
505
     */
    public static function unsetStore($store) {
Carsten  Rose's avatar
Carsten Rose committed
506
        // Check valid Storename
Carsten  Rose's avatar
Carsten Rose committed
507
        if (!isset(self::$sanitizeStore))
508
            throw new UserFormException("Unknown Store: $store", ERROR_UNNOWN_STORE);
Carsten  Rose's avatar
Carsten Rose committed
509

510
        if ($store === STORE_ZERO)
Carsten  Rose's avatar
Carsten Rose committed
511
512
            throw new CodeException("unsetStore() for STORE_ZERO is impossible - there are no values.", ERROR_SET_STORE_ZERO);

513
514
515
        if (isset(self::$raw[$store])) {
            self::$raw[$store] = array();
        }
Carsten  Rose's avatar
Carsten Rose committed
516

517
518
    }

519
    /**
Carsten  Rose's avatar
Carsten Rose committed
520
521
     * Set's a single $key/$value pair $store.
     *
Carsten  Rose's avatar
Carsten Rose committed
522
523
524
     * @param string $key
     * @param string|array $value
     * @param string $store
525
526
527
528
529
530
531
532
533
534
535
536
537
     * @param bool|true $overWrite
     * @throws UserFormException
     * @throws \qfq\CodeException
     */
    public static function setVar($key, $value, $store, $overWrite = true) {
        // Check valid Storename
        if (!isset(self::$sanitizeStore))
            throw new UserFormException("Unknown Store: $store", ERROR_UNNOWN_STORE);

        if ($store === STORE_ZERO)
            throw new CodeException("setVar() for STORE_ZERO is impossible - there are no values.", ERROR_SET_STORE_ZERO);

        if ($overWrite === false && isset(self::$raw[$store][$key])) {
538
            throw new UserFormException("Value of '$key' already set in store '$store'.", ERROR_STORE_KEY_EXIST);
539
540
541
        }

        self::$raw[$store][$key] = $value;
Carsten  Rose's avatar
Carsten Rose committed
542
543
544

        // The STORE_EXTRA saves arrays and is persistent
        if ($store === STORE_EXTRA) {
545

546
            $store = Session::get(STORE_EXTRA);
547
548

            if ($store === false) {
549
                $store = array();
550
551
            }

552
553
            $store[$key] = $value;
            Session::set(STORE_EXTRA, $store);
554

Carsten  Rose's avatar
Carsten Rose committed
555
        }
556
557
    }

558
    /**
Carsten  Rose's avatar
Carsten Rose committed
559
560
     * Create a SIP after a form load. This is necessary on forms without a sip and on forms with r=0 (new record).
     *
561
562
563
     * @param $formName
     * @throws CodeException
     */
564
    public static function createSipAfterFormLoad($formName) {
565

566
        $recordId = self::getVar(CLIENT_RECORD_ID, STORE_TYPO3 . STORE_CLIENT);
567
568
569
570
        if ($recordId === false) {
            $recordId = 0;
        }

571
572
573
574
575
576
        // If there are existing SIP param, keep them by copying to the new SIP Param Array
        $tmpParam = self::getNonSystemSipParam();

        $tmpParam[SIP_RECORD_ID] = $recordId;
        $tmpParam[SIP_FORM] = $formName;

Carsten  Rose's avatar
#2067    
Carsten Rose committed
577
578
579
580
        if ($recordId == 0) {
            // SIPs for 'new records' needs to be uniq per TAB! Therefore add a uniq parameter
            $tmpParam[SIP_MAKE_URLPARAM_UNIQ] = uniqid();
        }
581
582

        // Construct fake urlparam
583
        $tmpUrlparam = OnArray::toString($tmpParam);
584
585

        // Create a fake SIP which has never been passed by URL - further processing might expect this to exist.
586
        $sip = self::getSipInstance()->queryStringToSip($tmpUrlparam, RETURN_SIP);
587
        self::setVar(CLIENT_SIP, $sip, STORE_CLIENT);
588
589
590

        // Store in SIP Store (cause it's empty until now).
        $tmpParam[SIP_SIP] = $sip;
591
        self::setVarArray($tmpParam, STORE_SIP, true);
592

593
594
595
    }

    /**
596
597
598
599
     * Return an array with non system SIP parameter. Take the whole STORE_SIP and search for non system parameter.
     * @return array
     * @throws UserFormException
     * @throws \qfq\CodeException
600
     */
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
    private static function getNonSystemSipParam() {
        $tmpParam = array();

        $sipArray = self::getStore(STORE_SIP);

        foreach ($sipArray as $key => $value) {
            if ($key[0] === '_') {
                continue;
            }
            switch ($key) {
                case SIP_SIP:
                case SIP_RECORD_ID:
                case SIP_FORM;
                case SIP_URLPARAM:
                    continue;
                default:
                    $tmpParam[$key] = $value;
            }
        }

        return $tmpParam;
622
    }
623

624
    /**
Carsten  Rose's avatar
Carsten Rose committed
625
626
     * Returns a complete $store.
     *
627
     * @param $store
628
629
630
     * @return array
     * @throws UserFormException
     * @throws \qfq\CodeException
631
632
     */
    public static function getStore($store) {
Carsten  Rose's avatar
Carsten Rose committed
633
        // Check valid Storename
Carsten  Rose's avatar
Carsten Rose committed
634
        if (!isset(self::$sanitizeStore[$store]))
635
            throw new UserFormException("Unknown Store: $store", ERROR_UNNOWN_STORE);
Carsten  Rose's avatar
Carsten Rose committed
636

637
        if ($store === STORE_ZERO)
Carsten  Rose's avatar
Carsten Rose committed
638
639
            throw new CodeException("getStore() for STORE_ZERO is impossible - there are no values saved.", ERROR_GET_STORE_ZERO);

640
641
642
        if (isset(self::$raw[$store])) {
            return self::$raw[$store];
        }
643

644
645
        return array();
    }
646

647
648
649
650
651
652
653
654
    /**
     * Returns a pointer to this class.
     *
     * @return null|Sip
     */
    public static function getSipInstance() {
        return self::$sip;
    }
Carsten  Rose's avatar
Carsten Rose committed
655

656
    /**
Carsten  Rose's avatar
Carsten Rose committed
657
658
     * Fills STORE_TABLE_DEFAULT and STORE_TABLE_COLUMN_TYPES
     *
659
660
661
     * @param $tableName
     * @throws CodeException
     */
662
    public static function fillStoreTableDefaultColumnType($tableName) {
663
664
665
666
        $db = new qfq\Database();

        $tableDefinition = $db->getTableDefinition($tableName);

Carsten  Rose's avatar
Carsten Rose committed
667
668
        self::setVarArray(array_column($tableDefinition, 'Default', 'Field'), STORE_TABLE_DEFAULT, true);
        self::setVarArray(array_column($tableDefinition, 'Type', 'Field'), STORE_TABLE_COLUMN_TYPES, true);
669
    }
670
671
672
673
674
}