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 ]; self::$sanitizeStore = [ STORE_FORM => true, STORE_SIP => false, STORE_RECORD => false, STORE_PARENT_RECORD => false, STORE_TABLE_DEFAULT => false, STORE_TABLE_COLUMN_TYPES => false, STORE_CLIENT => true, STORE_TYPO3 => false, STORE_ZERO => false, STORE_SYSTEM => false ]; self::fillSystemStore(); self::fillStoreTypo3($bodytext); self::fillStoreClient(); self::fillStoreSip(); } /** * @throws CodeException * @throws qfq\UserException */ private function fillSystemStore() { try { //TODO: Vernuenftige Fehlermeldung falls nicht auf qfq.ini zugegriffen werden kann. //TODO: sinnvollen Platz fuer qfq.ini bestimmen. In der Installationsdoku erwaehnen. $config = parse_ini_file(__DIR__ . '/../../../' . CONFIG_INI, false); //TODO: auskommentiert weil dann die Unittests nicht mehr laufen. Sollte eigentlich wieder aktiviert werden. // $config['SQLLOG'] = Support::ifRelativePathPrependExtensionPath($config['SQLLOG']); } catch (\Exception $e) { throw new qfq\UserException ("Error read file " . CONFIG_INI . ": " . $e->getMessage(), ERROR_IO_READ_FILE); } 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'; } // 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); if ($pos === false) { // probably: index.php - THERE should be a TYPO3 environment. $config[SYSTEM_PATH_EXT] = dirname($GLOBALS['TYPO3_LOADED_EXT'][EXT_KEY]['ext_localconf.php']); } else { $config[SYSTEM_PATH_EXT] = substr($_SERVER['SCRIPT_FILENAME'], 0, $pos + strlen($relExtDir)); } } } // 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]; } self::setVarArray($config, STORE_SYSTEM, true); } /** * @param array $dataArray * @param $store * @param bool|false $flagOverwrite * @throws UserException * @throws \qfq\CodeException */ public function setVarArray(array $dataArray, $store, $flagOverwrite = false) { // Check valid Storename if (!isset(self::$sanitizeStore)) throw new UserException("Unknown Store: $store", ERROR_UNNOWN_STORE); if ($store === STORE_ZERO) throw new CodeException("setVarArray() for STORE_ZERO is impossible - there are no values.", ERROR_SET_STORE_ZERO); if (!$flagOverwrite && isset(self::$raw[$store]) && count(self::$raw[$store]) > 0) { throw new CodeException("Raw values already been copied to store '$store'. Do this only one time.", ERROR_STORE_VALUE_ALREADY_CODPIED); } self::$raw[$store] = $dataArray; } /** * @param $bodytext * @throws CodeException */ private function fillStoreTypo3($bodytext) { $arr = KeyValueStringParser::parse($bodytext, "=", "\n"); 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"]; if (isset($GLOBALS["TSFE"]->page["uid"])) $arr[TYPO3_TT_CONTENT_UID] = $GLOBALS["TSFE"]->page["uid"]; if (isset($GLOBALS["TSFE"]->id)) $arr[TYPO3_PAGE_ID] = $GLOBALS["TSFE"]->id; if (isset($GLOBALS["TSFE"]->type)) $arr[TYPO3_PAGE_TYPE] = $GLOBALS["TSFE"]->type; self::setVarArray($arr, STORE_TYPO3, true); } /** * @throws CodeException */ private function fillStoreClient() { // copy GET and POST and SERVER Parameter. Priority: SERVER, POST, GET $arr = array_merge($_GET, $_POST, $_SERVER); self::setVarArray($arr, STORE_CLIENT, true); } /** * @throws CodeException * @throws UserException */ private function fillStoreSip() { $sessionName = self::getVar(SYSTEM_SESSION_NAME, STORE_SYSTEM); self::$sip = new Sip($sessionName); $s = self::getVar(CLIENT_SIP, STORE_CLIENT); if ($s !== false) { // if session is given, copy values to store $param = self::$sip->getVarsFromSip($s); $param[SIP_SIP] = $s; $param[SIP_URLPARAM] = self::$sip->getQueryStringFromSip($s); // self::setVarArray(KeyValueStringParser::parse($param, "=", "&"), STORE_SIP); self::setVarArray($param, STORE_SIP, true); } } /** * Cycles through all stores in $useStore. * First match will return the found value. * During cycling: fill cache with requestet value and sanitize raw value. * * @param string $key * @param string $useStores f.e.: 'FSRD' * @param string $sanitizeClass * @param string $foundInStore Returns the name of the store where $key has been found. If $key is not found, return ''. * @return string a) if found: value, b) false * @throws \qfq\CodeException */ public static function getVar($key, $useStores = STORE_USE_DEFAULT, $sanitizeClass = '', &$foundInStore = '') { // no store specifed? if ($useStores === "" || $useStores === null) { $useStores = STORE_USE_DEFAULT; } // no sanitizeClass specified: take last/default if ($sanitizeClass === '' || $sanitizeClass === null) { $sanitizeClass = isset(self::$sanitizeClass[$key]) ? self::$sanitizeClass[$key] : SANITIZE_DEFAULT; } while ($useStores !== false) { $store = substr($useStores, 0, 1); // next store $foundInStore = $store; $useStores = substr($useStores, 1); // shift left remaining stores if (!isset(self::$raw[$store][$key])) { if ($store === STORE_ZERO) { return 0; } else { continue; // no value provided } } $rawVal = isset(self::$raw[$store][$key]) ? self::$raw[$store][$key] : null; if (self::$sanitizeStore[$store] && $sanitizeClass != '') { return \qfq\Sanitize::sanitize($rawVal, $sanitizeClass); } else { return $rawVal; } } $foundInStore = ''; return false; } /** * @param string $bodytext * @param bool|false $phpUnit * @return null|\qfq\Store */ public static function getInstance($bodytext = '', $phpUnit = false) { if ($phpUnit) { if (self::$instance !== null) { self::unsetStore(STORE_TYPO3); self::fillStoreTypo3($bodytext); self::unsetStore(STORE_CLIENT); self::fillStoreClient(); } } // Design Pattern: Singleton if (self::$instance === null) { self::$instance = new self($bodytext); } 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); } return self::$instance; } /** * @param $store */ public static function unsetStore($store) { // Check valid Storename if (!isset(self::$sanitizeStore)) throw new UserException("Unknown Store: $store", ERROR_UNNOWN_STORE); if ($store === STORE_ZERO) throw new CodeException("unsetStore() for STORE_ZERO is impossible - there are no values.", ERROR_SET_STORE_ZERO); if (isset(self::$raw[$store])) { self::$raw[$store] = array(); } } /** * @param $formName * @throws CodeException */ public static function createSipAfterFormLoad($formName) { $recordId = self::getVar(CLIENT_RECORD_ID, STORE_TYPO3 . STORE_CLIENT); if ($recordId === false) { $recordId = 0; } $tmpParam = [SIP_RECORD_ID => $recordId, SIP_FORM => $formName]; // Construct fake urlparam $tmpUrlparam = OnArray::toString($tmpParam); // Create a fake SIP which has never been passed by URL - further processing might expect this to exist. $sip = self::getSipInstance()->queryStringToSip($tmpUrlparam, RETURN_SIP); self::setVar(CLIENT_SIP, $sip, STORE_CLIENT); // Store in SIP Store (cause it's empty until now). $tmpParam[SIP_SIP] = $sip; self::setVarArray($tmpParam, STORE_SIP); } /** * @return null|Sip */ public static function getSipInstance() { return self::$sip; } /** * @param $key * @param $value * @param $store * @param bool|true $overWrite * @throws UserException */ public static function setVar($key, $value, $store, $overWrite = true) { // Check valid Storename if (!isset(self::$sanitizeStore)) throw new UserException("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])) { throw new UserException("Value of '$key' already be set in store '$store'.", ERROR_STORE_KEY_EXIST); } self::$raw[$store][$key] = $value; } /** * @param $store * @return mixed */ public static function getStore($store) { // Check valid Storename if (!isset(self::$sanitizeStore[$store])) throw new UserException("Unknown Store: $store", ERROR_UNNOWN_STORE); if ($store === STORE_ZERO) throw new CodeException("getStore() for STORE_ZERO is impossible - there are no values saved.", ERROR_GET_STORE_ZERO); if (isset(self::$raw[$store])) { return self::$raw[$store]; } return array(); } /** * Fills STORE_TABLE_DEFAULT and STORE_TABLE_COLUMN_TYPES * * @param $tableName * @throws CodeException */ public function fillStoreTableDefaultColumnType($tableName) { $db = new qfq\Database(); $tableDefinition = $db->getTableDefinition($tableName); self::setVarArray(array_column($tableDefinition, 'Default', 'Field'), STORE_TABLE_DEFAULT); self::setVarArray(array_column($tableDefinition, 'Type', 'Field'), STORE_TABLE_COLUMN_TYPES); } }