/** * Implement normalization according to OpenID 2.0 specification * See http://openid.net/specs/openid-authentication-2_0.html#normalization * * @param string $openIDIdentifier OpenID identifier to normalize * @return string Normalized OpenID identifier * @throws Exception */ protected function normalizeOpenID($openIDIdentifier) { if (empty($openIDIdentifier)) { throw new Exception('Empty OpenID Identifier given.', 1381922460); } // Strip everything with and behind the fragment delimiter character "#" if (strpos($openIDIdentifier, '#') !== FALSE) { $openIDIdentifier = preg_replace('/#.*$/', '', $openIDIdentifier); } // A URI with a missing scheme is normalized to a http URI if (!preg_match('#^https?://#', $openIDIdentifier)) { $escapedIdentifier = $this->databaseConnection->quoteStr($openIDIdentifier, $this->authenticationInformation['db_user']['table']); $condition = 'tx_openid_openid IN (' . '\'http://' . $escapedIdentifier . '\',' . '\'http://' . $escapedIdentifier . '/\',' . '\'https://' . $escapedIdentifier . '\',' . '\'https://' . $escapedIdentifier . '/\'' . ')'; $row = $this->databaseConnection->exec_SELECTgetSingleRow('tx_openid_openid', $this->authenticationInformation['db_user']['table'], $condition); if (is_array($row)) { $openIDIdentifier = $row['tx_openid_openid']; } else { // This only happens when the OpenID provider will select the final OpenID identity // In this case we require a valid URL as we cannot guess the scheme // So we throw an Exception and do not start the OpenID handshake at all throw new Exception('Trying to authenticate with OpenID but identifier is neither found in a user record nor it is a valid URL.', 1381922465); } } // An empty path component is normalized to a slash // (e.g. "http://domain.org" -> "http://domain.org/") if (preg_match('#^https?://[^/]+$#', $openIDIdentifier)) { $openIDIdentifier .= '/'; } return $openIDIdentifier; }
/** * Find an extension by title, author name or extension key * This is the function used by the TER search. It is using a * scoring for the matches to sort the extension with an * exact key match on top * * @param string $searchString The string to search for extensions * @return mixed */ public function findByTitleOrAuthorNameOrExtensionKey($searchString) { $quotedSearchString = $this->databaseConnection->escapeStrForLike($this->databaseConnection->quoteStr($searchString, 'tx_extensionmanager_domain_model_extension'), 'tx_extensionmanager_domain_model_extension'); $quotedSearchStringForLike = '\'%' . $quotedSearchString . '%\''; $quotedSearchString = '\'' . $quotedSearchString . '\''; $select = 'tx_extensionmanager_domain_model_extension.*, ( (extension_key like ' . $quotedSearchString . ') * 8 + (extension_key like ' . $quotedSearchStringForLike . ') * 4 + (title like ' . $quotedSearchStringForLike . ') * 2 + (author_name like ' . $quotedSearchStringForLike . ') ) as position'; $from = 'tx_extensionmanager_domain_model_extension'; $where = '( extension_key = ' . $quotedSearchString . ' OR extension_key LIKE ' . $quotedSearchStringForLike . ' OR title LIKE ' . $quotedSearchStringForLike . ' OR description LIKE ' . $quotedSearchStringForLike . ' OR author_name LIKE ' . $quotedSearchStringForLike . ' ) AND current_version=1 AND review_state >= 0 HAVING position > 0'; $order = 'position desc'; $result = $this->databaseConnection->exec_SELECTgetRows($select, $from, $where, '', $order); return $this->dataMapper->map('TYPO3\\CMS\\Extensionmanager\\Domain\\Model\\Extension', $result); }
/** * @test */ public function addDataThrowsExceptionIfDatabaseFetchingReturnsInvalidRowResultData() { $input = ['tableName' => 'tt_content', 'command' => 'edit', 'vanillaUid' => 10]; $this->dbProphecy->quoteStr(Argument::cetera())->willReturn($input['tableName']); $this->dbProphecy->exec_SELECTgetSingleRow(Argument::cetera())->willReturn('invalid result data'); $this->setExpectedException(\UnexpectedValueException::class, '', 1437656323); $this->subject->addData($input); }
/** * @test */ public function addDataSetsParentPageRowOnParentIfCommandIsEdit() { $input = ['tableName' => 'tt_content', 'command' => 'edit', 'vanillaUid' => 123, 'databaseRow' => ['uid' => 123, 'pid' => 321]]; $parentPageRow = ['uid' => 321, 'pid' => 456]; $this->dbProphecy->quoteStr(Argument::cetera())->willReturnArgument(0); $this->dbProphecy->exec_SELECTgetSingleRow('*', 'pages', 'uid=321')->willReturn($parentPageRow); $result = $this->subject->addData($input); $this->assertSame($parentPageRow, $result['parentPageRow']); }
/** * Search for users and returns usernames as result * * @param string $sword search string * @return array Array of usernames */ public function search($sword) { $result = array(); if (!$this->is_init) { $this->init(); } if (!$this->validateName($this->field)) { return $result; } /** @see https://buzz.typo3.org/teams/security/article/correct-usage-of-typo3-database-api/ */ $sword = '"' . $this->databaseHandle->escapeStrForLike($this->databaseHandle->quoteStr($sword, 'fe_users'), 'fe_users') . '%"'; $res = $this->databaseHandle->exec_SELECTquery($this->field, 'fe_users', 'disable=0 AND deleted=0 AND ' . $this->field . ' LIKE ' . $sword . ' AND pid=' . $this->pid . ' AND FIND_IN_SET(' . $this->group_id . ', usergroup)', '', $this->field . ' ASC', '8'); while (list($item) = $this->databaseHandle->sql_fetch_row($res)) { array_push($result, $item); } return $result; }
/** * Find an extension by title, author name or extension key * This is the function used by the TER search. It is using a * scoring for the matches to sort the extension with an * exact key match on top * * @param string $searchString The string to search for extensions * @return mixed */ public function findByTitleOrAuthorNameOrExtensionKey($searchString) { $quotedSearchString = $this->databaseConnection->escapeStrForLike($this->databaseConnection->quoteStr($searchString, 'tx_extensionmanager_domain_model_extension'), 'tx_extensionmanager_domain_model_extension'); $quotedSearchStringForLike = '\'%' . $quotedSearchString . '%\''; $quotedSearchString = '\'' . $quotedSearchString . '\''; $select = self::TABLE_NAME . '.*, ' . 'CASE ' . 'WHEN extension_key = ' . $quotedSearchString . ' THEN 16 ' . 'WHEN extension_key LIKE ' . $quotedSearchStringForLike . ' THEN 8 ' . 'WHEN title LIKE ' . $quotedSearchStringForLike . ' THEN 4 ' . 'WHEN description LIKE ' . $quotedSearchStringForLike . ' THEN 2 ' . 'WHEN author_name LIKE ' . $quotedSearchStringForLike . ' THEN 1 ' . 'END AS position'; $where = '( extension_key = ' . $quotedSearchString . ' OR extension_key LIKE ' . $quotedSearchStringForLike . ' OR title LIKE ' . $quotedSearchStringForLike . ' OR description LIKE ' . $quotedSearchStringForLike . ' OR author_name LIKE ' . $quotedSearchStringForLike . ' ) AND current_version = 1 AND review_state >= 0'; $order = 'position DESC'; $result = $this->databaseConnection->exec_SELECTgetRows($select, self::TABLE_NAME, $where, '', $order); return $this->dataMapper->map(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension::class, $result); }
/** * Will expand the parameters configuration to individual values. This follows a certain syntax of the value of each parameter. * Syntax of values: * - Basically: If the value is wrapped in [...] it will be expanded according to the following syntax, otherwise the value is taken literally * - Configuration is splitted by "|" and the parts are processed individually and finally added together * - For each configuration part: * - "[int]-[int]" = Integer range, will be expanded to all values in between, values included, starting from low to high (max. 1000). Example "1-34" or "-40--30" * - "_TABLE:[TCA table name];[_PID:[optional page id, default is current page]];[_ENABLELANG:1]" = Look up of table records from PID, filtering out deleted records. Example "_TABLE:tt_content; _PID:123" * _ENABLELANG:1 picks only original records without their language overlays * - Default: Literal value * * @param array Array with key (GET var name) and values (value of GET var which is configuration for expansion) * @param integer Current page ID * @return array Array with key (GET var name) with the value being an array of all possible values for that key. */ function expandParameters($paramArray, $pid) { global $TCA; // Traverse parameter names: foreach ($paramArray as $p => $v) { $v = trim($v); // If value is encapsulated in square brackets it means there are some ranges of values to find, otherwise the value is literal if (substr($v, 0, 1) === '[' && substr($v, -1) === ']') { // So, find the value inside brackets and reset the paramArray value as an array. $v = substr($v, 1, -1); $paramArray[$p] = array(); // Explode parts and traverse them: $parts = explode('|', $v); foreach ($parts as $pV) { // Look for integer range: (fx. 1-34 or -40--30 // reads minus 40 to minus 30) if (preg_match('/^(-?[0-9]+)\\s*-\\s*(-?[0-9]+)$/', trim($pV), $reg)) { // Integer range: // Swap if first is larger than last: if ($reg[1] > $reg[2]) { $temp = $reg[2]; $reg[2] = $reg[1]; $reg[1] = $temp; } // Traverse range, add values: $runAwayBrake = 1000; // Limit to size of range! for ($a = $reg[1]; $a <= $reg[2]; $a++) { $paramArray[$p][] = $a; $runAwayBrake--; if ($runAwayBrake <= 0) { break; } } } elseif (substr(trim($pV), 0, 7) == '_TABLE:') { // Parse parameters: $subparts = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(';', $pV); $subpartParams = array(); foreach ($subparts as $spV) { list($pKey, $pVal) = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(':', $spV); $subpartParams[$pKey] = $pVal; } // Table exists: if (isset($TCA[$subpartParams['_TABLE']])) { $lookUpPid = isset($subpartParams['_PID']) ? intval($subpartParams['_PID']) : $pid; $pidField = isset($subpartParams['_PIDFIELD']) ? trim($subpartParams['_PIDFIELD']) : 'pid'; $where = isset($subpartParams['_WHERE']) ? $subpartParams['_WHERE'] : ''; $addTable = isset($subpartParams['_ADDTABLE']) ? $subpartParams['_ADDTABLE'] : ''; $fieldName = $subpartParams['_FIELD'] ? $subpartParams['_FIELD'] : 'uid'; if ($fieldName === 'uid' || $TCA[$subpartParams['_TABLE']]['columns'][$fieldName]) { $andWhereLanguage = ''; $transOrigPointerField = $TCA[$subpartParams['_TABLE']]['ctrl']['transOrigPointerField']; if ($subpartParams['_ENABLELANG'] && $transOrigPointerField) { $andWhereLanguage = ' AND ' . $this->db->quoteStr($transOrigPointerField, $subpartParams['_TABLE']) . ' <= 0 '; } $where = $this->db->quoteStr($pidField, $subpartParams['_TABLE']) . '=' . intval($lookUpPid) . ' ' . $andWhereLanguage . $where; $rows = $this->db->exec_SELECTgetRows($fieldName, $subpartParams['_TABLE'] . $addTable, $where . \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause($subpartParams['_TABLE']), '', '', '', $fieldName); if (is_array($rows)) { $paramArray[$p] = array_merge($paramArray[$p], array_keys($rows)); } } } } else { // Just add value: $paramArray[$p][] = $pV; } // Hook for processing own expandParameters place holder if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['crawler/class.tx_crawler_lib.php']['expandParameters'])) { $_params = array('pObj' => &$this, 'paramArray' => &$paramArray, 'currentKey' => $p, 'currentValue' => $pV, 'pid' => $pid); foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['crawler/class.tx_crawler_lib.php']['expandParameters'] as $key => $_funcRef) { \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($_funcRef, $_params, $this); } } } // Make unique set of values and sort array by key: $paramArray[$p] = array_unique($paramArray[$p]); ksort($paramArray); } else { // Set the literal value as only value in array: $paramArray[$p] = array($v); } } return $paramArray; }
/** * Returns true if a specified database table contains record rows: the existence of a table ashould have been checked before using Tx_PtExtbase_Div::dbTableExists()! * * @param string database table name to check * @param string database name of the table to check * @param DatabaseConnection database object of type \TYPO3\CMS\Core\Database\DatabaseConnection to use (e.g. $GLOBALS['TYPO3_DB'] to use TYPO3 default database) * @return boolean TRUE if specified table contains record rows, FALSE if not * @throws \PunktDe\PtExtbase\Exception\Exception if the SHOW TABLE STATUS query fails/returns false */ public static function dbTableHasRecords($table, $dbName, DatabaseConnection $dbObj) { $tableHasRecords = false; $query = 'SHOW TABLE STATUS FROM ' . $dbObj->quoteStr($dbName, $table) . ' LIKE "' . $dbObj->quoteStr($table, $table) . '"'; // exec query using TYPO3 DB API $res = $dbObj->sql_query($query); if ($res == false) { throw new \PunktDe\PtExtbase\Exception\Exception('Query failed', 1, $dbObj->sql_error()); } $a_row = $dbObj->sql_fetch_assoc($res); $dbObj->sql_free_result($res); // check number of table rows if ($a_row['Rows'] > 0) { $tableHasRecords = true; } return $tableHasRecords; }
/** * @test * @dataProvider quoteStrQuotesCorrectlyDataProvider * * @param string $string String to quote * @param string $expectedResult Quoted string we expect * * @return void */ public function quoteStrQuotesDoubleQuotesCorrectly($string, $expectedResult) { $quotedString = $this->subject->quoteStr($string, $this->testTable); $this->assertSame($expectedResult, $quotedString); }