/** * Retrieves field list to check for modification * * @param string $tableName * @return array */ protected function getFieldList($tableName) { if ($tableName == 'pages_language_overlay') { $fieldList = TX_REALURL_SEGTITLEFIELDLIST_PLO; } else { if (isset($this->config['pagePath']['segTitleFieldList'])) { $fieldList = $this->config['pagePath']['segTitleFieldList']; } else { $fieldList = TX_REALURL_SEGTITLEFIELDLIST_DEFAULT; } } $fieldList .= ',hidden'; return array_unique($this->apiWrapper->trimExplode(',', $fieldList, true)); }
/** * Parse speaking URL and translate it to parameters understood by TYPO3 * Function is called from tslib_fe * The overall format of a speaking URL is these five parts [TYPO3_SITE_URL] / [pre-var] / [page-identification] / [post-vars] / [file.ext] * - "TYPO3_SITE_URL" is fixed value from the environment, * - "pre-var" is any number of segments separated by "/" mapping to GETvars AND with a known lenght, * - "page-identification" identifies the page id in TYPO3 possibly with multiple segments separated by "/" BUT with an UNKNOWN length, * - "post-vars" is sets of segments offering the same features as "pre-var" * - "file.ext" is any filename that might apply * * @param array $params Params for hook * @return void Setting internal variables. */ public function decodeSpURL($params) { $this->devLog('Entering decodeSpURL'); // Setting parent object reference (which is $GLOBALS['TSFE']) $this->pObj =& $params['pObj']; // Initializing config / request URL $this->setConfig(); $this->adjustConfigurationByHost('decode'); $this->adjustRootPageId(); // If there has been a redirect (basically; we arrived here otherwise than via "index.php" in the URL) this can happend either due to a CGI-script or because of reWrite rule. Earlier we used $GLOBALS['HTTP_SERVER_VARS']['REDIRECT_URL'] to check but... if ($this->pObj->siteScript && substr($this->pObj->siteScript, 0, 9) != 'index.php' && substr($this->pObj->siteScript, 0, 1) != '?') { // Getting the path which is above the current site url // For instance "first/second/third/index.html?¶m1=value1¶m2=value2" // should be the result of the URL // "http://localhost/typo3/dev/dummy_1/first/second/third/index.html?¶m1=value1¶m2=value2" // Note: sometimes in fcgi installations it is absolute, so we have to make it // relative to work properly. $speakingURIpath = $this->pObj->siteScript[0] == '/' ? substr($this->pObj->siteScript, 1) : $this->pObj->siteScript; // Call hooks if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']['decodeSpURL_preProc'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']['decodeSpURL_preProc'] as $userFunc) { $hookParams = array('pObj' => &$this, 'params' => $params, 'URL' => &$speakingURIpath); $this->apiWrapper->callUserFunction($userFunc, $hookParams, $this); } } // Append missing slash if configured for if ($this->extConf['init']['appendMissingSlash']) { $regexp = '~^([^\\?]*[^/])(\\?.*)?$~'; if (substr($speakingURIpath, -1, 1) == '?') { $speakingURIpath = substr($speakingURIpath, 0, -1); } if (preg_match($regexp, $speakingURIpath)) { // Only process if a slash is missing: $options = $this->apiWrapper->trimExplode(',', $this->extConf['init']['appendMissingSlash'], true); if (in_array('ifNotFile', $options)) { if (!preg_match('/\\/[^\\/\\?]+\\.[^\\/]+(\\?.*)?$/', '/' . $speakingURIpath)) { $speakingURIpath = preg_replace($regexp, '\\1/\\2', $speakingURIpath); $this->appendedSlash = true; } } else { $speakingURIpath = preg_replace($regexp, '\\1/\\2', $speakingURIpath); $this->appendedSlash = true; } if ($this->appendedSlash && count($options) > 0) { foreach ($options as $option) { $matches = array(); if (preg_match('/^redirect(\\[(30[1237])\\])?$/', $option, $matches)) { $code = count($matches) > 1 ? $matches[2] : 301; $status = 'HTTP/1.1 ' . $code . ' TYPO3 RealURL redirect M' . __LINE__; // Check path segment to be relative for the current site. // parse_url() does not work with relative URLs, so we use it to test if (!@parse_url($speakingURIpath, PHP_URL_HOST)) { @ob_end_clean(); header($status); header('Location: ' . $this->apiWrapper->locationHeaderUrl($speakingURIpath)); exit; } } } } } } // If the URL is a single script like "123.1.html" it might be an "old" simulateStaticDocument request. If this is the case and support for this is configured, do NOT try and resolve it as a Speaking URL $fI = $this->apiWrapper->split_fileref($speakingURIpath); if (!$this->apiWrapper->testInt($this->pObj->id) && $fI['path'] == '' && $this->extConf['fileName']['defaultToHTMLsuffixOnPrev'] && $this->extConf['init']['respectSimulateStaticURLs']) { // If page ID does not exist yet and page is on the root level and both // respectSimulateStaticURLs and defaultToHTMLsuffixOnPrev are set, than // ignore respectSimulateStaticURLs and attempt to resolve page id. // See http://bugs.typo3.org/view.php?id=1530 /** @noinspection PhpUndefinedMethodInspection */ $GLOBALS['TT']->setTSlogMessage('decodeSpURL: ignoring respectSimulateStaticURLs due defaultToHTMLsuffixOnPrev for the root level page!)', 2); $this->extConf['init']['respectSimulateStaticURLs'] = false; } if (!$this->extConf['init']['respectSimulateStaticURLs'] || $fI['path']) { $this->devLog('RealURL powered decoding (TM) starting!'); // Parse path $uParts = @parse_url($speakingURIpath); if (!is_array($uParts)) { $this->decodeSpURL_throw404('Current URL is invalid'); } $speakingURIpath = $this->speakingURIpath_procValue = $uParts['path']; // Redirecting if needed (exits if so). $this->decodeSpURL_checkRedirects($speakingURIpath); // Looking for cached information $cachedInfo = $this->decodeSpURL_decodeCache($speakingURIpath); // If no cached info was found, create it if (!is_array($cachedInfo)) { // Decode URL $cachedInfo = $this->decodeSpURL_doDecode($speakingURIpath, $this->extConf['init']['enableCHashCache']); // Storing cached information $this->decodeSpURL_decodeCache($speakingURIpath, $cachedInfo); } // Re-create QUERY_STRING from Get vars for use with typoLink() $_SERVER['QUERY_STRING'] = $this->decodeSpURL_createQueryString($cachedInfo['GET_VARS']); // Jump-admin if configured $this->decodeSpURL_jumpAdmin_goBackend($cachedInfo['id']); // Setting info in TSFE $this->pObj->mergingWithGetVars($cachedInfo['GET_VARS']); $this->pObj->id = $cachedInfo['id']; if ($this->mimeType) { header('Content-type: ' . $this->mimeType); $this->mimeType = null; } } } }
/** * Search for a title in a certain PID * * @param int $searchPid Page id in which to search subpages matching title * @param string $title Title to search for * @return array First entry is uid, second entry is the row selected, including information about the page as a mount point. * @see findPageBySegment() */ protected function findPageBySegmentAndPid($searchPid, $title) { // List of "pages" fields to traverse for a "directory title" in the speaking URL (only from RootLine!!) $segTitleFieldList = $this->conf['segTitleFieldList'] ? $this->conf['segTitleFieldList'] : TX_REALURL_SEGTITLEFIELDLIST_DEFAULT; $selList = $this->apiWrapper->uniqueList('uid,pid,doktype,mount_pid,mount_pid_ol,tx_realurl_exclude,' . $segTitleFieldList); $segTitleFieldArray = $this->apiWrapper->trimExplode(',', $segTitleFieldList, 1); // page select object - used to analyse mount points. $pageRepository = $this->apiWrapper->getPageRepository(); // Build an array with encoded values from the segTitleFieldArray of the subpages // First we find field values from the default language // Pages are selected in menu order and if duplicate titles are found the first takes precedence! $titles = array(); // array(title => uid); $exclude = array(); $uidTrack = array(); /** @noinspection PhpUndefinedMethodInspection */ $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery($selList, 'pages', 'pid=' . intval($searchPid) . ' AND deleted=0 AND doktype<>255', '', 'sorting'); /** @noinspection PhpUndefinedMethodInspection */ while (false != ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result))) { // Mount points $mount_info = $pageRepository->getMountPointInfo($row['uid'], $row); if (is_array($mount_info)) { // There is a valid mount point. if ($mount_info['overlay']) { // Overlay mode: Substitute WHOLE record /** @noinspection PhpUndefinedMethodInspection */ $result2 = $GLOBALS['TYPO3_DB']->exec_SELECTquery($selList, 'pages', 'uid=' . intval($mount_info['mount_pid']) . ' AND deleted=0 AND doktype<>255'); /** @noinspection PhpUndefinedMethodInspection */ $mp_row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result2); if (is_array($mp_row)) { $row = $mp_row; } else { unset($row); // If the mount point could not be fetched, unset the row } } $row['_IS_MOUNTPOINT'] = $mount_info; } // Collect titles from selected row if (is_array($row)) { if ($row['tx_realurl_exclude']) { // segment is excluded $exclude[] = $row; } // Process titles. Note that excluded segments are also searched // otherwise they will never be found $uidTrack[$row['uid']] = $row; foreach ($segTitleFieldArray as $fieldName) { if ($row[$fieldName]) { $encodedTitle = $this->encodeTitle($row[$fieldName]); if (!isset($titles[$fieldName][$encodedTitle])) { $titles[$fieldName][$encodedTitle] = $row['uid']; } } } } } /** @noinspection PhpUndefinedMethodInspection */ $GLOBALS['TYPO3_DB']->sql_free_result($result); // We have to search the language overlay too, if: a) the language isn't the default (0), b) if it's not set (-1) $uidTrackKeys = array_keys($uidTrack); $language = $this->pObj->getDetectedLanguage(); if ($language != 0) { foreach ($uidTrackKeys as $l_id) { /** @noinspection PhpUndefinedMethodInspection */ $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(TX_REALURL_SEGTITLEFIELDLIST_PLO, 'pages_language_overlay', 'pid=' . intval($l_id) . ' AND deleted=0' . ($language > 0 ? ' AND sys_language_uid=' . $language : '')); /** @noinspection PhpUndefinedMethodInspection */ while (false != ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result))) { foreach ($segTitleFieldArray as $fieldName) { if ($row[$fieldName]) { $encodedTitle = $this->encodeTitle($row[$fieldName]); if (!isset($titles[$fieldName][$encodedTitle])) { $titles[$fieldName][$encodedTitle] = $l_id; } } } } /** @noinspection PhpUndefinedMethodInspection */ $GLOBALS['TYPO3_DB']->sql_free_result($result); } } // Merge titles $segTitleFieldArray = array_reverse($segTitleFieldArray); // To observe the priority order... $allTitles = array(); foreach ($segTitleFieldArray as $fieldName) { if (is_array($titles[$fieldName])) { $allTitles = $this->apiWrapper->array_merge($allTitles, $titles[$fieldName]); } } // Return $encodedTitle = $this->encodeTitle($title); $possibleMatch = array(); if (isset($allTitles[$encodedTitle])) { if (!$uidTrack[$allTitles[$encodedTitle]]['tx_realurl_exclude']) { return array($allTitles[$encodedTitle], $uidTrack[$allTitles[$encodedTitle]], false, array()); } $possibleMatch = $uidTrack[$allTitles[$encodedTitle]]; } return array(false, false, $exclude, $possibleMatch); }