Store.php 13.3 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/Database.php');
21
22
23
24
25
26
27
28
29
30
31


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

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

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

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

Carsten  Rose's avatar
Carsten Rose committed
48
49
50
51
52
53
54
55
56
57
    /**
     * @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
     */
58
    private static $raw = array();
Carsten  Rose's avatar
Carsten Rose committed
59
60

    /**
Carsten  Rose's avatar
Carsten Rose committed
61
     * @var array Default sanitize classes.
Carsten  Rose's avatar
Carsten Rose committed
62
     */
Carsten  Rose's avatar
Carsten Rose committed
63
    private static $sanitizeClass = array();
Carsten  Rose's avatar
Carsten Rose committed
64
65

    /**
Carsten  Rose's avatar
Carsten Rose committed
66
67
     * $sanitizeClass['S'] = false
     * $sanitizeClass['C'] = true
Carsten  Rose's avatar
Carsten Rose committed
68
69
     * ...
     *
Carsten  Rose's avatar
Carsten Rose committed
70
     * @var array each entry with true/false - depending if store needs to be sanitized.
Carsten  Rose's avatar
Carsten Rose committed
71
     */
Carsten  Rose's avatar
Carsten Rose committed
72
    private static $sanitizeStore = array();
73
74

    /**
75
     * @param string $bodytext
76
     */
77
78
    private function __construct($bodytext = '') {

Carsten  Rose's avatar
Carsten Rose committed
79
80
81
82
83
84
85
86
87
88
89
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
122
123
124
125
126
127
128
        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,

//            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
129

130
131
        ];

Carsten  Rose's avatar
Carsten Rose committed
132
        self::$sanitizeStore = [
133
134
135
136
            STORE_FORM => true,
            STORE_SIP => false,
            STORE_RECORD => false,
            STORE_PARENT_RECORD => false,
137
138
            STORE_TABLE_DEFAULT => false,
            STORE_TABLE_COLUMN_TYPES => false,
139
140
            STORE_CLIENT => true,
            STORE_TYPO3 => false,
141
            STORE_ZERO => false,
142
143
144
            STORE_SYSTEM => false
        ];

145
        self::fillSystemStore();
146
        self::fillStoreTypo3($bodytext);
147
        self::fillStoreClient();
148
        self::fillStoreSip();
149
    }
150

151
152
    /**
     * @throws CodeException
153
     * @throws qfq\UserException
154
155
     */
    private function fillSystemStore() {
156
        try {
157
158
            //TODO: Vernuenftige Fehlermeldung falls nicht auf qfq.ini zugegriffen werden kann.
            //TODO: sinnvollen Platz fuer qfq.ini bestimmen. In der Installationsdoku erwaehnen.
159
            $config = parse_ini_file(__DIR__ . '/../../../' . CONFIG_INI, false);
160
        } catch (\Exception $e) {
161
            throw new qfq\UserException ("Error read file " . CONFIG_INI . ": " . $e->getMessage(), ERROR_IO_READ_FILE);
162
        }
163
164
165
166
167

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

168
        self::setVarArray($config, STORE_SYSTEM, true);
169
170
    }

171
172
173
174
175
    /**
     * @param array $dataArray
     * @param $store
     * @throws CodeException
     */
176
    public function setVarArray(array $dataArray, $store, $flagOverwrite = false) {
Carsten  Rose's avatar
Carsten Rose committed
177
        // Check valid Storename
Carsten  Rose's avatar
Carsten Rose committed
178
        if (!isset(self::$sanitizeStore))
Carsten  Rose's avatar
Carsten Rose committed
179
180
181
            throw new UserException("Unknown Store: $store", ERROR_UNNOWN_STORE);


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

185
        if ($flagOverwrite && isset(self::$raw[$store]) && count(self::$raw[$store]) > 0) {
186
            throw new CodeException("Raw values already been copied to store '$store'. Do this only one time.", ERROR_STORE_VALUE_ALREADY_CODPIED);
187
        }
188

189
190
        self::$raw[$store] = $dataArray;
    }
191

192
193
194
195
    /**
     * @param $bodytext
     * @throws CodeException
     */
196
197
    private function fillStoreTypo3($bodytext) {

198
        $arr = KeyValueStringParser::parse($bodytext, "=", "\n");
199
200
201
202
203
204
205
206
207

        if (isset($GLOBALS["TSFE"]->fe_user->user["username"]))
            $arr[TYPO3_FE_USER] = $GLOBALS["TSFE"]->fe_user->user["username"];

        if (isset($GLOBALS["TSFE"]->fe_user->user["uid"]))
            $arr[TYPO3_FE_USER_UID] = $GLOBALS["TSFE"]->fe_user->user["uid"];

        if (isset($GLOBALS["TSFE"]->fe_user->user["usergroup"]))
            $arr[TYPO3_FE_USER_GROUP] = $GLOBALS["TSFE"]->fe_user->user["usergroup"];
208

209
        self::setVarArray($arr, STORE_TYPO3, true);
210
    }
211

212
213
214
215
    /**
     * @throws CodeException
     */
    private function fillStoreClient() {
216
217
        // copy GET and POST and SERVER Parameter. Priority: SERVER, POST, GET
        $arr = array_merge($_GET, $_POST, $_SERVER);
218

219
        self::setVarArray($arr, STORE_CLIENT, true);
220
    }
221

Carsten  Rose's avatar
Carsten Rose committed
222
223
    /**
     * @throws CodeException
224
     * @throws UserException
Carsten  Rose's avatar
Carsten Rose committed
225
     */
226
    private function fillStoreSip() {
Carsten  Rose's avatar
Carsten Rose committed
227

228
        $sessionName = self::getVar(SYSTEM_SESSIONNAME, STORE_SYSTEM);
229
        self::$sip = new Sip($sessionName);
230

231
232
233
234
        $s = self::getVar(CLIENT_SIP, STORE_CLIENT);
        if ($s !== false) {
            // if session is given, copy values to store
            $param = self::$sip->getVarsFromSip($s);
235
236
            $param[SIP_SIP] = $s;
            $param[SIP_URLPARAM] = self::$sip->getQueryStringFromSip($s);
237

238
//            self::setVarArray(KeyValueStringParser::parse($param, "=", "&"), STORE_SIP);
239
            self::setVarArray($param, STORE_SIP, true);
240
241
242
        }
    }

243
    /**
244
     * Cycles through all stores in $useStore.
245
     * First match will return the found value.
Carsten  Rose's avatar
Carsten Rose committed
246
     * During cycling: fill cache with requestet value and sanitize raw value.
247
     *
248
     * @param string $key
249
     * @param string $useStores f.e.: 'FSRD'
Carsten  Rose's avatar
Carsten Rose committed
250
     * @param string $sanitizeClass
251
252
     * @return string a) if found: value, b) false
     */
Carsten  Rose's avatar
Carsten Rose committed
253
    public static function getVar($key, $useStores = STORE_USE_DEFAULT, $sanitizeClass = '') {
254
255

        // no store specifed?
256
        if ($useStores === "" || $useStores === null) {
257
            $useStores = STORE_USE_DEFAULT;
258
259
        }

Carsten  Rose's avatar
Carsten Rose committed
260
261
262
        // no sanitizeClass specified: take last/default
        if ($sanitizeClass === '') {
            $sanitizeClass = isset(self::$sanitizeClass[$key]) ? self::$sanitizeClass[$key] : SANITIZE_DEFAULT;
263
264
        }

265
266
267
268
269
        while ($useStores !== false) {

            $store = substr($useStores, 0, 1); // next store
            $useStores = substr($useStores, 1); // shift left remaining stores

270
            if (!isset(self::$raw[$store][$key])) {
271
                if ($store === STORE_ZERO) {
Carsten  Rose's avatar
Carsten Rose committed
272
273
274
275
                    return 0;
                } else {
                    continue; // no value provided
                }
276
277
            }

278
            $rawVal = isset(self::$raw[$store][$key]) ? self::$raw[$store][$key] : null;
279

Carsten  Rose's avatar
Carsten Rose committed
280
281
            if (self::$sanitizeStore[$store] && $sanitizeClass != '') {
                return \qfq\Sanitize::sanitize($rawVal, $sanitizeClass);
282
283
            } else {
                return $rawVal;
284
            }
285
        }
286

287
        return false;
288
    }
289

290
291
    /**
     * @param string $bodytext
292
     * @param bool|false $phpUnit
293
     * @return null|\qfq\Store
294
     */
295
    public static function getInstance($bodytext = '', $phpUnit = false) {
296

297
        if ($phpUnit) {
298
299
300
301
302
303
304
            if (self::$instance !== null) {

                self::unsetStore(STORE_TYPO3);
                self::fillStoreTypo3($bodytext);

                self::unsetStore(STORE_CLIENT);
                self::fillStoreClient();
305
306
307
308
309
310
311
312
313
            }
        }

        // Design Pattern: Singleton
        if (self::$instance === null) {
            self::$instance = new self($bodytext);
        }

        return self::$instance;
314
    }
315

316
317
318
319
    /**
     * @param $store
     */
    public static function unsetStore($store) {
Carsten  Rose's avatar
Carsten Rose committed
320
        // Check valid Storename
Carsten  Rose's avatar
Carsten Rose committed
321
        if (!isset(self::$sanitizeStore))
Carsten  Rose's avatar
Carsten Rose committed
322
323
            throw new UserException("Unknown Store: $store", ERROR_UNNOWN_STORE);

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

327
328
329
330
331
        if (isset(self::$raw[$store])) {
            self::$raw[$store] = array();
        }
    }

332
333
334
335
    /**
     * @param $formName
     * @throws CodeException
     */
336
337
    public
    static function createSipAfterFormLoad($formName) {
338
        $recordId = self::getVar(CLIENT_RECORD_ID, STORE_TYPO3 . STORE_CLIENT);
339
340
341
342
343
344
345
        if ($recordId === false) {
            $recordId = 0;
        }

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

        // Construct fake urlparam
346
        $tmpUrlparam = OnArray::toString($tmpParam);
347
348

        // Create a fake SIP which has never been passed by URL - further processing might expect this to exist.
349
        $sip = self::getSipInstance()->queryStringToSip($tmpUrlparam, RETURN_SIP);
350
        self::setVar(CLIENT_SIP, $sip, STORE_CLIENT);
351
352
353
354
355

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

356
357
358
    }

    /**
359
     * @return null|Sip
360
     */
361
    public static function getSipInstance() {
362
363
        return self::$sip;
    }
364
365
366
367
368

    /**
     * @param $key
     * @param $value
     * @param $store
Carsten  Rose's avatar
Carsten Rose committed
369
370
     * @param bool|true $overWrite
     * @throws UserException
371
     */
Carsten  Rose's avatar
Carsten Rose committed
372
373
    public static function setVar($key, $value, $store, $overWrite = true) {
        // Check valid Storename
Carsten  Rose's avatar
Carsten Rose committed
374
        if (!isset(self::$sanitizeStore))
Carsten  Rose's avatar
Carsten Rose committed
375
376
            throw new UserException("Unknown Store: $store", ERROR_UNNOWN_STORE);

377
        if ($store === STORE_ZERO)
Carsten  Rose's avatar
Carsten Rose committed
378
379
380
            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])) {
381
            throw new UserException("Value of '$key' already be set in store '$store'.", ERROR_STORE_KEY_EXIST);
Carsten  Rose's avatar
Carsten Rose committed
382
        }
383
384

        self::$raw[$store][$key] = $value;
385
386
387
388
389
390
391
    }

    /**
     * @param $store
     * @return mixed
     */
    public static function getStore($store) {
Carsten  Rose's avatar
Carsten Rose committed
392
        // Check valid Storename
Carsten  Rose's avatar
Carsten Rose committed
393
        if (!isset(self::$sanitizeStore[$store]))
Carsten  Rose's avatar
Carsten Rose committed
394
395
            throw new UserException("Unknown Store: $store", ERROR_UNNOWN_STORE);

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

399
400
401
402
403
        if (isset(self::$raw[$store])) {
            return self::$raw[$store];
        }
        return array();
    }
404

Carsten  Rose's avatar
Carsten Rose committed
405

406
    /**
Carsten  Rose's avatar
Carsten Rose committed
407
408
     * Fills STORE_TABLE_DEFAULT and STORE_TABLE_COLUMN_TYPES
     *
409
410
411
     * @param $tableName
     * @throws CodeException
     */
412
    public function fillStoreTableDefaultColumnType($tableName) {
413
414
415
416
        $db = new qfq\Database();

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

417
418
419
        self::setVarArray(array_column($tableDefinition, 'Default', 'Field'), STORE_TABLE_DEFAULT);
        self::setVarArray(array_column($tableDefinition, 'Type', 'Field'), STORE_TABLE_COLUMN_TYPES);
    }
420
421
422
423
424
}