PageRenderTime 75ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/typo3conf/ext/realurl/class.tx_realurl.php

https://github.com/moodley/fdummy
PHP | 2787 lines | 1614 code | 289 blank | 884 comment | 400 complexity | b9f1b668f5260e817bfc22b904be50ce MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /***************************************************************
  3. * Copyright notice
  4. *
  5. * (c) 2004 Kasper Skaarhoj (kasper@typo3.com)
  6. * (c) 2005-2010 Dmitry Dulepov (dmitry@typo3.org)
  7. * All rights reserved
  8. *
  9. * This script is part of the Typo3 project. The Typo3 project is
  10. * free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * The GNU General Public License can be found at
  16. * http://www.gnu.org/copyleft/gpl.html.
  17. * A copy is found in the textfile GPL.txt and important notices to the license
  18. * from the author is found in LICENSE.txt distributed with these scripts.
  19. *
  20. *
  21. * This script is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU General Public License for more details.
  25. *
  26. * This copyright notice MUST APPEAR in all copies of the script!
  27. ***************************************************************/
  28. /**
  29. * Class for creating and parsing Speaking Urls
  30. *
  31. * $Id: class.tx_realurl.php 63839 2012-06-25 11:38:02Z dmitry $
  32. *
  33. * @author Kasper Skaarhoj <kasper@typo3.com>
  34. * @author Dmitry Dulepov <dmitry@typo3.org>
  35. */
  36. /**
  37. * [CLASS/FUNCTION INDEX of SCRIPT]
  38. *
  39. *
  40. *
  41. * 107: class tx_realurl
  42. *
  43. * SECTION: Translate parameters to a Speaking URL (t3lib_tstemplate::linkData)
  44. * 152: function tx_realurl()
  45. * 170: function encodeSpURL(&$params, $ref)
  46. * 241: function encodeSpURL_doEncode($inputQuery, $cHashCache = FALSE, $origUrl = '')
  47. * 324: function encodeSpURL_pathFromId(&$paramKeyValues, &$pathParts)
  48. * 353: function encodeSpURL_gettingPostVarSets(&$paramKeyValues, &$pathParts, $postVarSetCfg)
  49. * 390: function encodeSpURL_fileName(&$paramKeyValues)
  50. * 412: function encodeSpURL_setSequence($varSetCfg, &$paramKeyValues, &$pathParts)
  51. * 516: function encodeSpURL_setSingle($keyWord, $keyValues, &$paramKeyValues, &$pathParts)
  52. * 550: function encodeSpURL_encodeCache($urlToEncode, $internalExtras, $setEncodedURL = '')
  53. * 617: function encodeSpURL_cHashCache($newUrl, &$paramKeyValues)
  54. *
  55. * SECTION: Translate a Speaking URL to parameters (tslib_fe)
  56. * 669: function decodeSpURL($params, $ref)
  57. * 759: function decodeSpURL_checkRedirects($speakingURIpath)
  58. * 801: function decodeSpURL_doDecode($speakingURIpath, $cHashCache = FALSE)
  59. * 877: function decodeSpURL_createQueryStringParam($paramArr, $prependString = '')
  60. * 900: function decodeSpURL_createQueryString(&$getVars)
  61. * 925: function decodeSpURL_idFromPath(&$pathParts)
  62. * 966: function decodeSpURL_settingPreVars(&$pathParts, $config)
  63. * 989: function decodeSpURL_settingPostVarSets(&$pathParts, $postVarSetCfg)
  64. * 1054: function decodeSpURL_fixBrackets(&$arr)
  65. * 1080: function decodeSpURL_fileName($fileName)
  66. * 1108: function decodeSpURL_getSequence(&$pathParts, $setupArr)
  67. * 1201: function decodeSpURL_getSingle($keyValues)
  68. * 1217: function decodeSpURL_throw404($msg)
  69. * 1251: function decodeSpURL_jumpAdmin()
  70. * 1275: function decodeSpURL_jumpAdmin_goBackend($pageId)
  71. * 1290: function decodeSpURL_decodeCache($speakingURIpath, $cachedInfo = '')
  72. * 1354: function decodeSpURL_cHashCache($speakingURIpath)
  73. *
  74. * SECTION: Alias-ID look up functions
  75. * 1385: function lookUpTranslation($cfg, $value, $aliasToUid = FALSE)
  76. * 1495: function lookUp_uniqAliasToId($cfg, $aliasValue, $onlyNonExpired = FALSE)
  77. * 1522: function lookUp_idToUniqAlias($cfg, $idValue, $lang, $aliasValue = '')
  78. * 1550: function lookUp_newAlias($cfg, $newAliasValue, $idValue, $lang)
  79. * 1620: function lookUp_cleanAlias($cfg, $newAliasValue)
  80. *
  81. * SECTION: General helper functions (both decode/encode)
  82. * 1665: function setConfig()
  83. * 1699: function getPostVarSetConfig($page_id, $mainCat = 'postVarSets')
  84. * 1721: function pageAliasToID($alias)
  85. * 1744: function rawurlencodeParam($str)
  86. * 1759: function checkCondition($setup, $prevVal, $value)
  87. * 1777: function isBEUserLoggedIn()
  88. *
  89. * SECTION: External Hooks
  90. * 1794: function clearPageCacheMgm($params, $ref)
  91. * 1809: function isString(&$str, $paramName)
  92. * 1834: function findRootPageId($host = '')
  93. *
  94. * TOTAL FUNCTIONS: 41
  95. * (This index is automatically created/updated by the extension "extdeveval")
  96. *
  97. */
  98. /**
  99. * Class for creating and parsing Speaking Urls
  100. * This class interfaces with hooks in TYPO3 inside tslib_fe (for parsing speaking URLs to GET parameters) and in t3lib_tstemplate (for parsing GET parameters into a speaking URL)
  101. *
  102. * @author Kasper Skaarhoj <kasper@typo3.com>
  103. * @author Dmitry Dulepov <dmitry@typo3.org>
  104. * @package TYPO3
  105. * @subpackage tx_realurl
  106. */
  107. class tx_realurl {
  108. // External, static:
  109. var $NA = '-'; // Substitute value for "blank" values
  110. var $maxLookUpLgd = 100; // Max. length of look-up strings. Just a "brake"
  111. var $prefixEnablingSpURL = 'index.php'; // Only work Speaking URL on URLs starting with "index.php"
  112. var $decodeCacheTTL = 1; // TTL for decode cache, default is 1 day.
  113. var $encodeCacheTTL = 1; // TTL for encode cache, default is 1 day.
  114. // Internal:
  115. /** @var tslib_fe */
  116. var $pObj; // tslib_fe / GLOBALS['TSFE'] (for ->decodeSpURL())
  117. var $extConf; // Configuration for extension, from $TYPO3_CONF_VARS['EXTCONF']['realurl']
  118. var $adminJumpSet = FALSE; // Is set true (->encodeSpURL) if AdminJump is active in some way. Is set false again when captured first time!
  119. var $fe_user_prefix_set = FALSE; // Is set true (->encodeSpURL) if there is a frontend user logged in
  120. var $filePart; // Contains the filename when a Speaking URL is decoded.
  121. var $dirParts; // All directory parts of the string
  122. var $orig_paramKeyValues = array(); // Contains the index of GETvars that the URL had when the encoding began.
  123. var $appendedSlash = false; // Set true if slash is appended
  124. var $encodePageId = 0; // Set with the page id during encoding. for internal use only.
  125. var $speakingURIpath_procValue = ''; // For decoding, the path we are processing.
  126. var $disableDecodeCache = FALSE; // If set internally, decode caching is disabled. Used when a 303 header is set in tx_realurl_advanced.
  127. var $decode_editInBackend = FALSE; // If set (in adminjump function) then we will redirect to edit the found page id in the backend.
  128. var $encodeError = FALSE; // If set true encoding failed , probably because the url was outside of root line - and the input url is returned directly.
  129. var $host = ''; // Current host name. Set in setConfig()
  130. /**
  131. * Additional values to use when creating chash cache. This works, for
  132. * example, when using _DOMAINS and cHash for links that do not really
  133. * need a cHash.
  134. *
  135. * @var array
  136. */
  137. protected $additionalParametersForChash;
  138. /**
  139. * Actual host name (configuration key) for the current request. This can
  140. * be different from the $this->host if there are host aliases.
  141. *
  142. * @var string
  143. */
  144. protected $hostConfigured = '';
  145. var $multidomain = false;
  146. var $urlPrepend = array();
  147. var $useMySQLExtendedSyntax = false;
  148. /**
  149. * Holds a uid of the detected language during decoding to limit search of
  150. * titles only to this language. Valid values are:
  151. * -1 - no language detected
  152. * 0 - default language (only if really detected!)
  153. * >0 - a language uid taken from preVars or _DOMAINS (corresponds to uid in sys_languages table)
  154. *
  155. * @var int
  156. */
  157. protected $detectedLanguage = -1;
  158. /**
  159. * Inidicates wwether devLog is enabled
  160. *
  161. * @var true
  162. */
  163. protected $enableDevLog = false;
  164. /**
  165. * Contains a request id. This is to simplify identification of a single
  166. * request when the site is accessed concurently
  167. *
  168. * @var string
  169. */
  170. protected $devLogId;
  171. /**
  172. * Mime type that can be set according to the file extension (decoding only).
  173. *
  174. * @var string
  175. */
  176. protected $mimeType = null;
  177. var $enableStrictMode = false;
  178. var $enableChashDebug = false;
  179. /**
  180. * If non-empty, corresponding URL query parameter will be ignored in preVars
  181. * (note: preVars only!). This is necessary for _DOMAINS feature. This value
  182. * is set to empty in adjustConfigurationByHostEncode().
  183. *
  184. * @see tx_realurl::adjustConfigurationByHostEncode()
  185. * @see tx_realurl::encodeSpURL_doEncode()
  186. * @var string
  187. */
  188. protected $ignoreGETvar;
  189. /**
  190. * Contains URL parameters that were merged into URL. This is necessary
  191. * if cHash has to be recalculated due to bypassed parameters. Used during
  192. * encoding only.
  193. *
  194. * @var array
  195. * @see http://bugs.typo3.org/view.php?id=11219
  196. */
  197. protected $cHashParameters;
  198. /**
  199. * Indicates wether cHash should be rebuilt for the URL. Used during
  200. * encoding only.
  201. *
  202. * @var boolean
  203. * @see http://bugs.typo3.org/view.php?id=11219
  204. */
  205. protected $rebuildCHash;
  206. /************************************
  207. *
  208. * Translate parameters to a Speaking URL (t3lib_tstemplate::linkData)
  209. *
  210. ************************************/
  211. /**
  212. * Creates an instance of this class
  213. *
  214. * @return void
  215. */
  216. public function __construct() {
  217. if (!t3lib_extMgm::isLoaded('dbal') && strpos(get_resource_type($GLOBALS['TYPO3_DB']->link), 'mysql link') !== false) {
  218. $res = $GLOBALS['TYPO3_DB']->sql_query('SELECT @@VERSION');
  219. $rec = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
  220. $GLOBALS['TYPO3_DB']->sql_free_result($res);
  221. $this->useMySQLExtendedSyntax = version_compare($rec[0], '4.1.0', '>');
  222. }
  223. $sysconf = (array)unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['realurl']);
  224. $this->enableStrictMode = (boolean)$sysconf['enableStrictMode'];
  225. $this->enableChashUrlDebug = (boolean)$sysconf['enableChashUrlDebug'];
  226. $this->initDevLog($sysconf);
  227. }
  228. /**
  229. * Initializes devLog support
  230. *
  231. * @param array $sysconf
  232. * @return void
  233. */
  234. protected function initDevLog(array $sysconf) {
  235. $this->enableDevLog = (boolean)$sysconf['enableDevLog'];
  236. if ($this->enableDevLog) {
  237. $this->devLogId = (isset($_SERVER['UNIQUE_ID']) ? $_SERVER['UNIQUE_ID'] : uniqid(''));
  238. }
  239. }
  240. /**
  241. * Translates a URL with query string (GET parameters) into Speaking URL.
  242. * Called from t3lib_tstemplate::linkData
  243. *
  244. * @param array Array of parameters from t3lib_tstemplate::linkData - the function creating all links inside TYPO3
  245. * @return void
  246. */
  247. public function encodeSpURL(&$params) {
  248. $this->devLog('Entering encodeSpURL for ' . $params['LD']['totalURL']);
  249. if ($this->isInWorkspace()) {
  250. $this->devLog('Workspace detected. Not doing anything!');
  251. return;
  252. }
  253. if (!$params['TCEmainHook']) {
  254. // Return directly, if simulateStaticDocuments is set:
  255. if ($GLOBALS['TSFE']->config['config']['simulateStaticDocuments']) {
  256. $GLOBALS['TT']->setTSlogMessage('SimulateStaticDocuments is enabled. RealURL disables itself.', 2);
  257. return;
  258. }
  259. // Return directly, if realurl is not enabled:
  260. if (!$GLOBALS['TSFE']->config['config']['tx_realurl_enable']) {
  261. $GLOBALS['TT']->setTSlogMessage('RealURL is not enabled in TS setup. Finished.');
  262. return;
  263. }
  264. }
  265. // Checking prefix:
  266. $prefix = $GLOBALS['TSFE']->absRefPrefix . $this->prefixEnablingSpURL;
  267. if (substr($params['LD']['totalURL'], 0, strlen($prefix)) != $prefix) {
  268. return;
  269. }
  270. $this->devLog('Starting URL encode');
  271. // Initializing config / request URL:
  272. $this->setConfig();
  273. $adjustedConfiguration = $this->adjustConfigurationByHost('encode', $params);
  274. $this->adjustRootPageId();
  275. $internalExtras = array();
  276. // Init "Admin Jump"; If frontend edit was enabled by the current URL of the page, set it again in the generated URL (and disable caching!)
  277. if (!$params['TCEmainHook']) {
  278. if ($GLOBALS['TSFE']->applicationData['tx_realurl']['adminJumpActive']) {
  279. $GLOBALS['TSFE']->set_no_cache();
  280. $this->adminJumpSet = TRUE;
  281. $internalExtras['adminJump'] = 1;
  282. }
  283. // If there is a frontend user logged in, set fe_user_prefix
  284. if (is_array($GLOBALS['TSFE']->fe_user->user)) {
  285. $this->fe_user_prefix_set = TRUE;
  286. $internalExtras['feLogin'] = 1;
  287. }
  288. }
  289. // Parse current URL into main parts:
  290. $uParts = parse_url($params['LD']['totalURL']);
  291. // Look in memory cache first
  292. $urlData = $this->hostConfigured . ' | ' . $uParts['query'];
  293. $newUrl = $this->encodeSpURL_encodeCache($urlData, $internalExtras);
  294. if (!$newUrl) {
  295. // Encode URL
  296. $newUrl = $this->encodeSpURL_doEncode($uParts['query'], $this->extConf['init']['enableCHashCache'], $params['LD']['totalURL']);
  297. // Set new URL in cache
  298. $this->encodeSpURL_encodeCache($urlData, $internalExtras, $newUrl);
  299. }
  300. unset($urlData);
  301. // Adding any anchor there might be:
  302. if ($uParts['fragment']) {
  303. $newUrl .= '#' . $uParts['fragment'];
  304. }
  305. // Reapply config.absRefPrefix if necessary
  306. if ((!isset($this->extConf['init']['reapplyAbsRefPrefix']) || $this->extConf['init']['reapplyAbsRefPrefix']) && $GLOBALS['TSFE']->absRefPrefix) {
  307. // Prevent // in case of absRefPrefix ending with / and emptyUrlReturnValue=/
  308. if (substr($GLOBALS['TSFE']->absRefPrefix, -1, 1) == '/' && substr($newUrl, 0, 1) == '/') {
  309. $newUrl = substr($newUrl, 1);
  310. }
  311. $newUrl = $GLOBALS['TSFE']->absRefPrefix . $newUrl;
  312. }
  313. // Set prepending of URL (e.g. hostname) which will be processed by typoLink_PostProc hook in tslib_content:
  314. if (isset($adjustedConfiguration['urlPrepend']) && !isset($this->urlPrepend[$newUrl])) {
  315. $urlPrepend = $adjustedConfiguration['urlPrepend'];
  316. if (substr($urlPrepend, -1) == '/') {
  317. $urlPrepend = substr($urlPrepend, 0, -1);
  318. }
  319. $this->urlPrepend[$newUrl] = $urlPrepend;
  320. }
  321. // Call hooks
  322. if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']['encodeSpURL_postProc'])) {
  323. foreach($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']['encodeSpURL_postProc'] as $userFunc) {
  324. $hookParams = array(
  325. 'pObj' => &$this,
  326. 'params' => $params,
  327. 'URL' => &$newUrl,
  328. );
  329. t3lib_div::callUserFunction($userFunc, $hookParams, $this);
  330. }
  331. }
  332. // Setting the encoded URL in the LD key of the params array - that value is passed by reference and thus returned to the linkData function!
  333. $params['LD']['totalURL'] = $newUrl;
  334. }
  335. /**
  336. * Prepends URL generated by RealURL by something (e.g. a host).
  337. * This method gets called by the typoLink_PostProc hook in tslib_content:
  338. *
  339. * @param array $parameters: Array of parameters from typoLink_PostProc hook in tslib_content
  340. * @param object $cObj: Reference to the calling tslib_content instance
  341. * @return void
  342. */
  343. public function encodeSpURL_urlPrepend(&$parameters, &$pObj) {
  344. if (isset($parameters['finalTagParts']['url'])) {
  345. // We must check for absolute URLs here because typolink can force
  346. // absolute URLs for pages with restricted access. It prepends
  347. // current host always. See http://bugs.typo3.org/view.php?id=18200
  348. $testUrl = $parameters['finalTagParts']['url'];
  349. if (preg_match('/^https?:\/\/[^\/]+\//', $testUrl)) {
  350. $testUrl = preg_replace('/https?:\/\/[^\/]+(.+)$/', '\1', $testUrl);
  351. }
  352. if (isset($this->urlPrepend[$testUrl])) {
  353. $urlKey = $url = $testUrl;
  354. // Remove absRefPrefix if necessary
  355. $absRefPrefixLength = strlen($GLOBALS['TSFE']->absRefPrefix);
  356. if ($absRefPrefixLength != 0 && substr($url, 0, $absRefPrefixLength) == $GLOBALS['TSFE']->absRefPrefix) {
  357. $url = substr($url, $absRefPrefixLength);
  358. }
  359. $url = $this->urlPrepend[$urlKey] . ($url{0} != '/' ? '/' : '') . $url;
  360. unset($this->urlPrepend[$testUrl]);
  361. // Adjust the URL:
  362. $parameters['finalTag'] = str_replace(
  363. '"' . htmlspecialchars($parameters['finalTagParts']['url']) . '"',
  364. '"' . htmlspecialchars($url) . '"',
  365. $parameters['finalTag']
  366. );
  367. $parameters['finalTagParts']['url'] = $url;
  368. $pObj->lastTypoLinkUrl = $url;
  369. }
  370. }
  371. }
  372. /**
  373. * Transforms a query string into a speaking URL according to the configuration in ->extConf
  374. *
  375. * @param string Input query string
  376. * @param boolean If set, the cHashCache table is used for "&cHash"
  377. * @param string Original URL
  378. * @return string Output Speaking URL (with as many GET parameters encoded into the URL as possible).
  379. * @see encodeSpURL()
  380. */
  381. protected function encodeSpURL_doEncode($inputQuery, $cHashCache = FALSE, $origUrl = '') {
  382. $this->cHashParameters = array();
  383. $this->rebuildCHash = false;
  384. // Extract all GET parameters into an ARRAY:
  385. $paramKeyValues = array();
  386. $GETparams = explode('&', $inputQuery);
  387. foreach ($GETparams as $paramAndValue) {
  388. list($p, $v) = explode('=', $paramAndValue, 2);
  389. $p = rawurldecode($p);
  390. if ($p != '') {
  391. $paramKeyValues[$p] = rawurldecode($v);
  392. }
  393. }
  394. $this->orig_paramKeyValues = $paramKeyValues;
  395. // Init array in which to collect the "directories" of the URL:
  396. $pathParts = array();
  397. // Pre-vars:
  398. $this->encodeSpURL_setSequence($this->extConf['preVars'], $paramKeyValues, $pathParts);
  399. // Create path from ID value:
  400. $page_id = $this->encodePageId = $paramKeyValues['id'];
  401. $this->encodeError = FALSE;
  402. $this->encodeSpURL_pathFromId($paramKeyValues, $pathParts);
  403. if ($this->encodeError) {
  404. return $origUrl;
  405. }
  406. // Fixed Post-vars:
  407. $fixedPostVarSetCfg = $this->getPostVarSetConfig($page_id, 'fixedPostVars');
  408. if (is_array($fixedPostVarSetCfg)) {
  409. $this->encodeSpURL_setSequence($fixedPostVarSetCfg, $paramKeyValues, $pathParts);
  410. }
  411. // Post var sets:
  412. $postVarSetCfg = $this->getPostVarSetConfig($page_id);
  413. $this->encodeSpURL_gettingPostVarSets($paramKeyValues, $pathParts, $postVarSetCfg);
  414. // Compile Speaking URL path
  415. $pathParts = $this->cleanUpPathParts($pathParts);
  416. // Add filename, if any:
  417. $newUrl = $this->createURLWithFileName($paramKeyValues, $pathParts);
  418. // Fix empty URLs
  419. $newUrl = $this->fixEmptyUrl($newUrl);
  420. // Clear ignored var
  421. if (isset($paramKeyValues[$this->ignoreGETvar])) {
  422. unset($paramKeyValues[$this->ignoreGETvar]);
  423. }
  424. // Store cHash cache:
  425. if ($cHashCache) {
  426. $this->encodeSpURL_cHashCache($newUrl, $paramKeyValues);
  427. }
  428. // Manage remaining GET parameters:
  429. if (count($paramKeyValues)) {
  430. $q = array();
  431. foreach ($paramKeyValues as $k => $v) {
  432. $q[] = $this->rawurlencodeParam($k) . '=' . rawurlencode($v);
  433. }
  434. $newUrl .= '?' . implode('&', $q);
  435. }
  436. // Memory clean up
  437. unset($this->cHashParameters);
  438. // Return new, Speaking URL encoded URL:
  439. return $newUrl;
  440. }
  441. /**
  442. * Creating the TYPO3 Page path into $pathParts from the "id" value in $paramKeyValues
  443. *
  444. * @param array Current URLs GETvar => value pairs in array, being translated into pathParts: Here we take out "id" GET var.
  445. * @param array Numerical array of path-parts, continously being filled. Here, the "page path" is being added by which-ever method is preferred. Passed by reference.
  446. * @return void Unsetting "id" from $paramKeyValues / Setting page path in $pathParts
  447. * @see encodeSpURL_doEncode()
  448. */
  449. protected function encodeSpURL_pathFromId(&$paramKeyValues, &$pathParts) {
  450. // Return immediately if no GET vars remain to be translated:
  451. if (!count($paramKeyValues)) {
  452. return;
  453. }
  454. // Creating page path:
  455. switch ((string)$this->extConf['pagePath']['type']) {
  456. case 'user':
  457. $params = array('paramKeyValues' => &$paramKeyValues, 'pathParts' => &$pathParts, 'pObj' => &$this, 'conf' => $this->extConf['pagePath'], 'mode' => 'encode');
  458. t3lib_div::callUserFunction($this->extConf['pagePath']['userFunc'], $params, $this);
  459. break;
  460. default: // Default: Just passing through the ID/alias of the page:
  461. $pathParts[] = rawurlencode($paramKeyValues['id']);
  462. unset($paramKeyValues['id']);
  463. break;
  464. }
  465. }
  466. /**
  467. * Traversing setup for variables AFTER the page path.
  468. *
  469. * @param array Current URLs GETvar => value pairs in array, being translated into pathParts, continously shortend. Passed by reference.
  470. * @param array Numerical array of path-parts, continously being filled. Passed by reference.
  471. * @param array $postVarSetCfg config
  472. * @return void Removing values from $paramKeyValues / Setting values in $pathParts
  473. * @see encodeSpURL_doEncode(), decodeSpURL_settingPostVarSets()
  474. */
  475. protected function encodeSpURL_gettingPostVarSets(&$paramKeyValues, &$pathParts, $postVarSetCfg) {
  476. // Traverse setup for postVarSets. If any of those matches
  477. if (is_array($postVarSetCfg)) {
  478. foreach ($postVarSetCfg as $keyWord => $cfg) {
  479. switch ((string)$cfg['type']) {
  480. case 'admin':
  481. if ($this->adminJumpSet) {
  482. $pathParts[] = rawurlencode($keyWord);
  483. $this->adminJumpSet = FALSE; // ... this makes sure that any subsequent "admin-jump" activation is set...
  484. }
  485. break;
  486. case 'single':
  487. $this->encodeSpURL_setSingle($keyWord, $cfg['keyValues'], $paramKeyValues, $pathParts);
  488. break;
  489. default:
  490. unset($cfg['type']); // Just to make sure it is NOT set.
  491. foreach ($cfg as $Gcfg) {
  492. if (isset($paramKeyValues[$Gcfg['GETvar']])) {
  493. $pathParts[] = rawurlencode($keyWord);
  494. $pathPartsSize = count($pathParts);
  495. $cHashParameters = $this->cHashParameters;
  496. $this->encodeSpURL_setSequence($cfg, $paramKeyValues, $pathParts);
  497. // If (1) nothing was added or (2) only empty segments added, remove this part completely
  498. if (count($pathParts) == $pathPartsSize) {
  499. array_pop($pathParts);
  500. }
  501. else {
  502. $dropSegment = true;
  503. for ($i = $pathPartsSize; $i < count($pathParts); $i++) {
  504. if ($pathParts[$i] != '') {
  505. $dropSegment = false;
  506. break;
  507. }
  508. }
  509. if ($dropSegment) {
  510. $pathParts = array_slice($pathParts, 0, $pathPartsSize - 1);
  511. // Nothing goes to cHash from this part.
  512. $this->cHashParameters = $cHashParameters;
  513. }
  514. }
  515. break;
  516. }
  517. }
  518. break;
  519. }
  520. }
  521. }
  522. }
  523. /**
  524. * Setting a filename if any filename is configured to match remaining variables.
  525. *
  526. * @param array Current URLs GETvar => value pairs in array, being translated into pathParts, continously shortend. Passed by reference.
  527. * @return string Returns the filename to prepend, if any
  528. * @see encodeSpURL_doEncode(), decodeSpURL_fileName()
  529. */
  530. protected function encodeSpURL_fileName(array &$paramKeyValues) {
  531. // Look if any filename matches the remaining variables:
  532. if (is_array($this->extConf['fileName']['index'])) {
  533. foreach ($this->extConf['fileName']['index'] as $keyWord => $cfg) {
  534. $pathParts = array();
  535. if ($this->encodeSpURL_setSingle($keyWord, $cfg['keyValues'], $paramKeyValues, $pathParts)) {
  536. return $keyWord != '_DEFAULT' ? $keyWord : '';
  537. }
  538. }
  539. }
  540. return '';
  541. }
  542. /**
  543. * Traverses a set of GETvars configured (array of segments)
  544. *
  545. * @param array Array of segment-configurations.
  546. * @param array Current URLs GETvar => value pairs in array, being translated into pathParts, continously shortend. Passed by reference.
  547. * @param array Numerical array of path-parts, continously being filled. Passed by reference.
  548. * @return void Removing values from $paramKeyValues / Setting values in $pathParts
  549. * @see encodeSpURL_doEncode(), encodeSpURL_gettingPostVarSets(), decodeSpURL_getSequence()
  550. */
  551. protected function encodeSpURL_setSequence($varSetCfg, &$paramKeyValues, &$pathParts) {
  552. // Traverse array of segments configuration
  553. $prevVal = '';
  554. if (is_array($varSetCfg)) {
  555. foreach ($varSetCfg as $setup) {
  556. switch ($setup['type']) {
  557. case 'action':
  558. $pathPartVal = '';
  559. // Look for admin jump:
  560. if ($this->adminJumpSet) {
  561. foreach ($setup['index'] as $pKey => $pCfg) {
  562. if ((string)$pCfg['type'] == 'admin') {
  563. $pathPartVal = $pKey;
  564. $this->adminJumpSet = FALSE;
  565. break;
  566. }
  567. }
  568. }
  569. // Look for frontend user login:
  570. if ($this->fe_user_prefix_set) {
  571. foreach ($setup['index'] as $pKey => $pCfg) {
  572. if ((string)$pCfg['type'] == 'feLogin') {
  573. $pathPartVal = $pKey;
  574. $this->fe_user_prefix_set = FALSE;
  575. break;
  576. }
  577. }
  578. }
  579. // If either pathPartVal has been set OR if _DEFAULT type is not bypass, set a value:
  580. if (strlen($pathPartVal) || $setup['index']['_DEFAULT']['type'] != 'bypass') {
  581. // If admin jump did not set $pathPartVal, look for first pass-through (no "type" set):
  582. if (!strlen($pathPartVal)) {
  583. foreach ($setup['index'] as $pKey => $pCfg) {
  584. if (!strlen($pCfg['type'])) {
  585. $pathPartVal = $pKey;
  586. break;
  587. }
  588. }
  589. }
  590. // Setting part of path:
  591. $pathParts[] = rawurlencode(strlen($pathPartVal) ? $pathPartVal : $this->NA);
  592. }
  593. break;
  594. default:
  595. if (!is_array($setup['cond']) || $this->checkCondition($setup['cond'], $prevVal)) {
  596. // Looking if the GET var is found in parameter index
  597. $GETvar = $setup['GETvar'];
  598. if ($GETvar == $this->ignoreGETvar) {
  599. // Do not do anything with this var!
  600. continue;
  601. }
  602. $parameterSet = isset($paramKeyValues[$GETvar]);
  603. $GETvarVal = $parameterSet ? $paramKeyValues[$GETvar] : '';
  604. // Set reverse map:
  605. $revMap = is_array($setup['valueMap']) ? array_flip($setup['valueMap']) : array();
  606. if (isset($revMap[$GETvarVal])) {
  607. $prevVal = $GETvarVal;
  608. $pathParts[] = rawurlencode($revMap[$GETvarVal]);
  609. $this->cHashParameters[$GETvar] = $GETvarVal;
  610. } elseif ($setup['noMatch'] == 'bypass') {
  611. // If no match in reverse value map and "bypass" is set, remove the parameter from the URL
  612. // Must rebuild cHash because we remove a parameter!
  613. $this->rebuildCHash |= $parameterSet;
  614. } elseif ($setup['noMatch'] == 'null') {
  615. // If no match and "null" is set, then set "dummy" value
  616. // Set "dummy" value (?)
  617. $prevVal = '';
  618. $pathParts[] = '';
  619. $this->rebuildCHash |= $parameterSet;
  620. } elseif ($setup['userFunc']) {
  621. $params = array(
  622. 'pObj' => &$this,
  623. 'value' => $GETvarVal,
  624. 'decodeAlias' => false,
  625. 'pathParts' => &$pathParts
  626. );
  627. $prevVal = $GETvarVal;
  628. $GETvarVal = t3lib_div::callUserFunction($setup['userFunc'], $params, $this);
  629. $pathParts[] = rawurlencode($GETvarVal);
  630. $this->cHashParameters[$GETvar] = $prevVal;
  631. } elseif (is_array($setup['lookUpTable'])) {
  632. $prevVal = $GETvarVal;
  633. $GETvarVal = $this->lookUpTranslation($setup['lookUpTable'], $GETvarVal);
  634. $pathParts[] = rawurlencode($GETvarVal);
  635. $this->cHashParameters[$GETvar] = $prevVal;
  636. } elseif (isset($setup['valueDefault'])) {
  637. $prevVal = $setup['valueDefault'];
  638. $pathParts[] = rawurlencode($setup['valueDefault']);
  639. $this->cHashParameters[$GETvar] = $setup['valueMap'][$setup['valueDefault']];
  640. $this->rebuildCHash |= !$parameterSet;
  641. } else {
  642. $prevVal = $GETvarVal;
  643. $pathParts[] = rawurlencode($GETvarVal);
  644. $this->cHashParameters[$GETvar] = $prevVal;
  645. $this->rebuildCHash |= !$parameterSet;
  646. }
  647. // Finally, unset GET var so it doesn't get processed once more:
  648. unset($paramKeyValues[$setup['GETvar']]);
  649. }
  650. break;
  651. }
  652. }
  653. }
  654. }
  655. /**
  656. * Traversing an array of GETvar => value pairs and checking if both variable names AND values are matching any found in $paramKeyValues; If so, the keyword representing those values is set and the GEtvars are unset from $paramkeyValues array
  657. *
  658. * @param string Keyword to set as a representation of the GETvars configured.
  659. * @param array Array of GETvar => values which content in $paramKeyvalues must match exactly in order to be substituted with the keyword, $keyWord
  660. * @param array Current URLs GETvar => value pairs in array, being translated into pathParts, continously shortend. Passed by reference.
  661. * @param array Numerical array of path-parts, continously being filled. Passed by reference.
  662. * @return boolean Return true, if any value from $paramKeyValues was removed.
  663. * @see encodeSpURL_fileName(), encodeSpURL_gettingPostVarSets(), decodeSpURL_getSingle()
  664. */
  665. protected function encodeSpURL_setSingle($keyWord, $keyValues, &$paramKeyValues, &$pathParts) {
  666. if (is_array($keyValues)) {
  667. $allSet = TRUE;
  668. // Check if all GETvars configured are found in $paramKeyValues:
  669. foreach ($keyValues as $getVar => $value) {
  670. if (!isset($paramKeyValues[$getVar]) || strcmp($paramKeyValues[$getVar], $value)) {
  671. $allSet = FALSE;
  672. break;
  673. }
  674. }
  675. // If all is set, unset the GETvars and set the value.
  676. if ($allSet) {
  677. $pathParts[] = rawurlencode($keyWord);
  678. foreach ($keyValues as $getVar => $value) {
  679. $this->cHashParameters[$getVar] = $value;
  680. unset($paramKeyValues[$getVar]);
  681. }
  682. return TRUE;
  683. }
  684. }
  685. return FALSE;
  686. }
  687. /**
  688. * Setting / Getting encoded URL to/from cache (memory cache, but could be extended to database cache)
  689. *
  690. * @param string Host + the original URL with GET parameters - identifying the cached version to find
  691. * @param array Array with extra data to include in encoding. This is flags if adminJump url or feLogin flags are set since these are NOT a part of the URL to encode and therefore are needed for the hash to be true.
  692. * @param string If set, this URL will be cached as the encoded version of $urlToEncode. Otherwise the function will look for and return the cached version of $urlToEncode
  693. * @return mixed If $setEncodedURL is true, this will be STORED as the cached version and the function returns false, otherwise the cached version is returned (string).
  694. * @see encodeSpURL()
  695. */
  696. protected function encodeSpURL_encodeCache($urlData, $internalExtras, $setEncodedURL = '') {
  697. // Create hash string:
  698. $hash = md5($urlData . '///' . serialize($internalExtras));
  699. if (!$setEncodedURL) { // Asking for cached encoded URL:
  700. // First, check memory, otherwise ask database:
  701. if (!isset($GLOBALS['TSFE']->applicationData['tx_realurl']['_CACHE'][$hash]) && $this->extConf['init']['enableUrlEncodeCache']) {
  702. $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('content', 'tx_realurl_urlencodecache',
  703. 'url_hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'tx_realurl_urlencodecache') .
  704. ' AND tstamp>' . strtotime('midnight', time() - 24 * 3600 * $this->encodeCacheTTL));
  705. if (false != ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))) {
  706. $GLOBALS['TSFE']->applicationData['tx_realurl']['_CACHE'][$hash] = $row['content'];
  707. }
  708. $GLOBALS['TYPO3_DB']->sql_free_result($res);
  709. }
  710. return $GLOBALS['TSFE']->applicationData['tx_realurl']['_CACHE'][$hash];
  711. }
  712. else { // Setting encoded URL in cache:
  713. // No caching if FE editing is enabled!
  714. if (!$this->isBEUserLoggedIn()) {
  715. $GLOBALS['TSFE']->applicationData['tx_realurl']['_CACHE'][$hash] = $setEncodedURL;
  716. // If the page id is NOT an integer, it's an alias we have to look up:
  717. if (!self::testInt($this->encodePageId)) {
  718. $this->encodePageId = $this->pageAliasToID($this->encodePageId);
  719. }
  720. if ($this->extConf['init']['enableUrlEncodeCache'] && $this->canCachePageURL($this->encodePageId)) {
  721. $insertFields = array(
  722. 'url_hash' => $hash,
  723. 'origparams' => $urlData,
  724. 'internalExtras' => count($internalExtras) ? serialize($internalExtras) : '',
  725. 'content' => $setEncodedURL,
  726. 'page_id' => $this->encodePageId,
  727. 'tstamp' => time()
  728. );
  729. if ($this->useMySQLExtendedSyntax) {
  730. $query = $GLOBALS['TYPO3_DB']->INSERTquery('tx_realurl_urlencodecache', $insertFields);
  731. $query .= ' ON DUPLICATE KEY UPDATE tstamp=' . $insertFields['tstamp'];
  732. $GLOBALS['TYPO3_DB']->sql_query($query);
  733. } else {
  734. $GLOBALS['TYPO3_DB']->sql_query('START TRANSACTION');
  735. $GLOBALS['TYPO3_DB']->exec_DELETEquery('tx_realurl_urlencodecache', 'url_hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'tx_realurl_urlencodecache'));
  736. $GLOBALS['TYPO3_DB']->exec_INSERTquery('tx_realurl_urlencodecache', $insertFields);
  737. $GLOBALS['TYPO3_DB']->sql_query('COMMIT');
  738. }
  739. }
  740. }
  741. }
  742. return '';
  743. }
  744. /**
  745. * Will store a record in a cachetable holding the value of the "cHash" parameter in a link, if any.
  746. * Background:
  747. * The "cHash" parameter is a hash over the values in the Query String of a URL and it "authenticates" the URL to the frontend so we can safely cache page content with that parameter combination.
  748. * Technically, there is no problem with the "cHash" parameter - it is like any other parameter something we could encode with Speaking URLs. The problem is: a cHash string is not "speaking" (and never will be!)
  749. * So; the only option we are left with if we want to remove the "?cHash=...:" remains in URLs and at the same time do not want to include it in the virtual path is; store it in the database!
  750. * This is what this function does: Stores a record in the database which relates the cHash value to a hash id of the URL. This is done ONLY if the "cHash" parameter is the only one left which would make the URL non-speaking. Otherwise it is left behind.
  751. * Obviously, this whole thing only works if there is a function in the decode part which will look up the cHash again and include it in the GET parameters resolved from the Speaking URL - but there is of course...
  752. *
  753. * @param string Speaking URL path (being hashed to an integer and cHash value related to this.)
  754. * @param array Params array, passed by reference. If "cHash" is the only value left it will be put in the cache table and the value is unset in the array.
  755. * @return void
  756. * @see decodeSpURL_cHashCache()
  757. */
  758. protected function encodeSpURL_cHashCache($newUrl, &$paramKeyValues) {
  759. // If "cHash" is the ONLY parameter left...
  760. // (if there are others our problem is that the cHash probably covers those
  761. // as well and if we include the cHash anyways we might get duplicates for
  762. // the same speaking URL in the cache table!)
  763. if (isset($paramKeyValues['cHash'])) {
  764. if ($this->rebuildCHash) {
  765. $cHashParameters = array_merge($this->cHashParameters, $paramKeyValues);
  766. unset($cHashParameters['cHash']);
  767. $cHashParameters = t3lib_div::cHashParams(t3lib_div::implodeArrayForUrl('', $cHashParameters));
  768. unset($cHashParameters['']);
  769. if (count($cHashParameters) == 1) {
  770. // No cHash needed.
  771. unset($paramKeyValues['cHash']);
  772. }
  773. elseif (count($cHashParameters) > 1) {
  774. if (method_exists('t3lib_div', 'calculateCHash')) {
  775. $paramKeyValues['cHash'] = t3lib_div::calculateCHash($cHashParameters);
  776. }
  777. else {
  778. $paramKeyValues['cHash'] = t3lib_div::shortMD5(serialize($cHashParameters));
  779. }
  780. }
  781. unset($cHashParameters);
  782. }
  783. if (count($paramKeyValues) == 1) {
  784. $stringForHash = $newUrl;
  785. if (count($this->additionalParametersForChash)) {
  786. $stringForHash .= '|' . serialize($this->additionalParametersForChash);
  787. }
  788. $spUrlHash = md5($stringForHash);
  789. $spUrlHashQuoted = $GLOBALS['TYPO3_DB']->fullQuoteStr($spUrlHash, 'tx_realurl_chashcache');
  790. // first, look if a cHash is already there for this SpURL
  791. list($row) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('chash_string',
  792. 'tx_realurl_chashcache', 'spurl_hash=' . $spUrlHashQuoted);
  793. if (!is_array($row)) {
  794. // Nothing found, insert to the cache
  795. $data = array(
  796. 'spurl_hash' => $spUrlHash,
  797. 'spurl_string' => $this->enableChashUrlDebug ? $stringForHash : null,
  798. 'chash_string' => $paramKeyValues['cHash']
  799. );
  800. $GLOBALS['TYPO3_DB']->exec_INSERTquery('tx_realurl_chashcache', $data);
  801. }
  802. else {
  803. // If one found, check if it is different, and if so update:
  804. if ($row['chash_string'] != $paramKeyValues['cHash']) {
  805. // If that chash_string is different from the one we want to
  806. // insert, that might be a bug or mean that encryptionKey was
  807. // changed so cHash values will be different now
  808. // In any case we will just silently update the value:
  809. $data = array(
  810. 'chash_string' => $paramKeyValues['cHash']
  811. );
  812. $GLOBALS['TYPO3_DB']->exec_UPDATEquery('tx_realurl_chashcache',
  813. 'spurl_hash=' . $spUrlHashQuoted, $data);
  814. }
  815. }
  816. // Unset "cHash" (and array should now be empty!)
  817. unset($paramKeyValues['cHash']);
  818. }
  819. }
  820. }
  821. /************************************
  822. *
  823. * Translate a Speaking URL to parameters (tslib_fe)
  824. *
  825. ************************************/
  826. /**
  827. * Parse speaking URL and translate it to parameters understood by TYPO3
  828. * Function is called from tslib_fe
  829. * The overall format of a speaking URL is these five parts [TYPO3_SITE_URL] / [pre-var] / [page-identification] / [post-vars] / [file.ext]
  830. * - "TYPO3_SITE_URL" is fixed value from the environment,
  831. * - "pre-var" is any number of segments separated by "/" mapping to GETvars AND with a known lenght,
  832. * - "page-identification" identifies the page id in TYPO3 possibly with multiple segments separated by "/" BUT with an UNKNOWN length,
  833. * - "post-vars" is sets of segments offering the same features as "pre-var"
  834. * - "file.ext" is any filename that might apply
  835. *
  836. * @param array Params for hook
  837. * @return void Setting internal variables.
  838. */
  839. public function decodeSpURL($params) {
  840. $this->devLog('Entering decodeSpURL');
  841. // Setting parent object reference (which is $GLOBALS['TSFE'])
  842. $this->pObj = &$params['pObj'];
  843. // Initializing config / request URL:
  844. $this->setConfig();
  845. $this->adjustConfigurationByHost('decode');
  846. $this->adjustRootPageId();
  847. // 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...
  848. if ($this->pObj->siteScript && substr($this->pObj->siteScript, 0, 9) != 'index.php' && substr($this->pObj->siteScript, 0, 1) != '?') {
  849. // Getting the path which is above the current site url:
  850. // For instance "first/second/third/index.html?&param1=value1&param2=value2"
  851. // should be the result of the URL
  852. // "http://localhost/typo3/dev/dummy_1/first/second/third/index.html?&param1=value1&param2=value2"
  853. // Note: sometimes in fcgi installations it is absolute, so we have to make it
  854. // relative to work properly.
  855. $speakingURIpath = $this->pObj->siteScript{0} == '/' ? substr($this->pObj->siteScript, 1) : $this->pObj->siteScript;
  856. // Call hooks
  857. if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']['decodeSpURL_preProc'])) {
  858. foreach($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']['decodeSpURL_preProc'] as $userFunc) {
  859. $hookParams = array(
  860. 'pObj' => &$this,
  861. 'params' => $params,
  862. 'URL' => &$speakingURIpath,
  863. );
  864. t3lib_div::callUserFunction($userFunc, $hookParams, $this);
  865. }
  866. }
  867. // Append missing slash if configured for:
  868. if ($this->extConf['init']['appendMissingSlash']) {
  869. $regexp = '~^([^\?]*[^/])(\?.*)?$~';
  870. if (substr($speakingURIpath, -1, 1) == '?') {
  871. $speakingURIpath = substr($speakingURIpath, 0, -1);
  872. }
  873. if (preg_match($regexp, $speakingURIpath)) { // Only process if a slash is missing:
  874. $options = t3lib_div::trimExplode(',', $this->extConf['init']['appendMissingSlash'], true);
  875. if (in_array('ifNotFile', $options)) {
  876. if (!preg_match('/\/[^\/\?]+\.[^\/]+(\?.*)?$/', '/' . $speakingURIpath)) {
  877. $speakingURIpath = preg_replace($regexp, '\1/\2', $speakingURIpath);
  878. $this->appendedSlash = true;
  879. }
  880. }
  881. else {
  882. $speakingURIpath = preg_replace($regexp, '\1/\2', $speakingURIpath);
  883. $this->appendedSlash = true;
  884. }
  885. if ($this->appendedSlash && count($options) > 0) {
  886. foreach ($options as $option) {
  887. $matches = array();
  888. if (preg_match('/^redirect(\[(30[1237])\])?$/', $option, $matches)) {
  889. $code = count($matches) > 1 ? $matches[2] : 301;
  890. $status = 'HTTP/1.0 ' . $code . ' TYPO3 RealURL redirect';
  891. // Check path segment to be relative for the current site.
  892. // parse_url() does not work with relative URLs, so we use it to test
  893. if (!@parse_url($speakingURIpath, PHP_URL_HOST)) {
  894. @ob_end_clean();
  895. header($status);
  896. header('Location: ' . t3lib_div::locationHeaderUrl($speakingURIpath));
  897. exit;
  898. }
  899. }
  900. }
  901. }
  902. }
  903. }
  904. // 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
  905. $fI = t3lib_div::split_fileref($speakingURIpath);
  906. if (!self::testInt($this->pObj->id) && $fI['path'] == '' && $this->extConf['fileName']['defaultToHTMLsuffixOnPrev'] && $this->extConf['init']['respectSimulateStaticURLs']) {
  907. // If page ID does not exist yet and page is on the root level and both
  908. // respectSimulateStaticURLs and defaultToHTMLsuffixOnPrev are set, than
  909. // ignore respectSimulateStaticURLs and attempt to resolve page id.
  910. // See http://bugs.typo3.org/view.php?id=1530
  911. $GLOBALS['TT']->setTSlogMessage('decodeSpURL: ignoring respectSimulateStaticURLs due defaultToHTMLsuffixOnPrev for the root level page!)', 2);
  912. $this->extConf['init']['respectSimulateStaticURLs'] = false;
  913. }
  914. if (!$this->extConf['init']['respectSimulateStaticURLs'] || $fI['path']) {
  915. $this->devLog('RealURL powered decoding (TM) starting!');
  916. // Parse path:
  917. $uParts = @parse_url($speakingURIpath);
  918. if (!is_array($uParts)) {
  919. $this->decodeSpURL_throw404('Current URL is invalid');
  920. }
  921. $speakingURIpath = $this->speakingURIpath_procValue = $uParts['path'];
  922. // Redirecting if needed (exits if so).
  923. $this->decodeSpURL_checkRedirects($speakingURIpath);
  924. // Looking for cached information:
  925. $cachedInfo = $this->decodeSpURL_decodeCache($speakingURIpath);
  926. // If no cached info was found, create it:
  927. if (!is_array($cachedInfo)) {
  928. // Decode URL:
  929. $cachedInfo = $this->decodeSpURL_doDecode($speakingURIpath, $this->extConf['init']['enableCHashCache']);
  930. // Storing cached information:
  931. $this->decodeSpURL_decodeCache($speakingURIpath, $cachedInfo);
  932. }
  933. // Re-create QUERY_STRING from Get vars for use with typoLink()
  934. $_SERVER['QUERY_STRING'] = $this->decodeSpURL_createQueryString($cachedInfo['GET_VARS']);
  935. // Jump-admin if configured:
  936. $this->decodeSpURL_jumpAdmin_goBackend($cachedInfo['id']);
  937. // Setting info in TSFE:
  938. $this->pObj->mergingWithGetVars($cachedInfo['GET_VARS']);
  939. $this->pObj->id = $cachedInfo['id'];
  940. if ($this->mimeType) {
  941. header('Content-type: ' . $this->mimeType);
  942. $this->mimeType = null;
  943. }
  944. }
  945. }
  946. }
  947. /**
  948. * Look for redirect configuration.
  949. * If the input path is found as key in $this->extConf['redirects'] this method redirects to the URL found as value
  950. *
  951. * @param string Path from SpeakingURL.
  952. * @return void
  953. * @see decodeSpURL_doDecode()
  954. */
  955. protected function decodeSpURL_checkRedirects($speakingURIpath) {
  956. $speakingURIpath = strtolower(trim($speakingURIpath));
  957. if (isset($this->extConf['redirects'][$speakingURIpath])) {
  958. $url = $this->extConf['redirects'][$speakingURIpath];
  959. if (preg_match('/^30[1237];/', $url)) {
  960. $redirectCode = intval(substr($url, 0, 3));
  961. $url = substr($url, 4);
  962. header('HTTP/1.0 ' . $redirectCode . ' Redirect');
  963. }
  964. header('Location: ' . t3lib_div::locationHeaderUrl($url));
  965. exit();
  966. }
  967. // Regex redirects:
  968. if (is_array($this->extConf['redirects_regex'])) {
  969. foreach ($this->extConf['redirects_regex'] as $regex => $substString) {
  970. if (preg_match('/' . $regex . '/', $speakingURIpath)) {
  971. $url = @preg_replace('/' . $regex . '/', $substString, $speakingURIpath);
  972. if ($url) {
  973. if (preg_match('/^30[1237];/', $url)) {
  974. $redirectCode = intval(substr($url, 0, 3));
  975. header('HTTP/1.0 ' . $redirectCode . ' Redirect');
  976. $url = substr($url, 4);
  977. }
  978. header('Location: ' . t3lib_div::locationHeaderUrl($url));
  979. exit();
  980. }
  981. }
  982. }
  983. }
  984. // DB defined redirects:
  985. $hash = t3lib_div::md5int($speakingURIpath);
  986. $url = $GLOBALS['TYPO3_DB']->fullQuoteStr($speakingURIpath, 'tx_realurl_redirects');
  987. $domainId = $this->getCurrentDomainId();
  988. list($redirectRow) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
  989. 'destination,has_moved,domain_limit', 'tx_realurl_redirects',
  990. 'url_hash=' . $hash . ' AND url=' . $url . ' AND domain_limit IN (0,' . $domainId . ')',
  991. '', 'domain_limit DESC');
  992. if (is_array($redirectRow)) {
  993. // Update statistics
  994. $fields_values = array(
  995. 'counter' => 'counter+1',
  996. 'tstamp' => time(),
  997. 'last_referer' => t3lib_div::getIndpEnv('HTTP_REFERER')
  998. );
  999. $GLOBALS['TYPO3_DB']->exec_UPDATEquery('tx_realurl_redirects',
  1000. 'url_hash=' . $hash . ' AND url=' . $url . ' AND domain_limit=' . $redirectRow['domain_limit'],
  1001. $fields_values, array('counter'));
  1002. // Redirect
  1003. if ($redirectRow['has_moved']) {
  1004. header('HTTP/1.1 301 Moved Permanently');
  1005. }
  1006. header('Location: ' . t3lib_div::locationHeaderUrl($redirectRow['destination']));
  1007. exit();
  1008. }
  1009. }
  1010. /**
  1011. * Obtains current domain id from sys_domain.
  1012. *
  1013. * @return int
  1014. */
  1015. protected function getCurrentDomainId() {
  1016. list($row) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid',
  1017. 'sys_domain',
  1018. 'domainName=' . $GLOBALS['TYPO3_DB']->fullQuoteStr(t3lib_div::getIndpEnv('HTTP_HOST'), 'sys_domain') .
  1019. ' AND redirectTo=\'\''
  1020. );
  1021. $result = (is_array($row) ? intval($row['uid']) : 0);
  1022. return $result;
  1023. }
  1024. /**
  1025. * Decodes a speaking URL path into an array of GET parameters and a page id.
  1026. *
  1027. * @param string Speaking URL path (after the "root" path of the website!) but without query parameters
  1028. * @param boolean If cHash caching is enabled or not.
  1029. * @return array Array with id and GET parameters.
  1030. * @see decodeSpURL()
  1031. */
  1032. protected function decodeSpURL_doDecode($speakingURIpath, $cHashCache = FALSE) {
  1033. // Cached info:
  1034. $cachedInfo = array();
  1035. // Convert URL to segments
  1036. $pathParts = explode('/', $speakingURIpath);
  1037. array_walk($pathParts, create_function('&$value', '$value = rawurldecode($value);'));
  1038. // Strip/process file name or extension first
  1039. $file_GET_VARS = $this->decodeSpURL_decodeFileName($pathParts);
  1040. // Setting original dir-parts:
  1041. $this->dirParts = $pathParts;
  1042. // Setting "preVars":
  1043. $pre_GET_VARS = $this->decodeSpURL_settingPreVars($pathParts, $this->extConf['preVars']);
  1044. if (isset($this->extConf['pagePath']['languageGetVar'])) {
  1045. $languageGetVar = $this->extConf['pagePath']['languageGetVar'];
  1046. if (isset($pre_GET_VARS[$languageGetVar]) && self::testInt($pre_GET_VARS[$languageGetVar])) {
  1047. // Language from URL
  1048. $this->detectedLanguage = $pre_GET_VARS[$languageGetVar];
  1049. }
  1050. elseif (isset($_GET[$languageGetVar]) && self::testInt($_GET[$languageGetVar])) {
  1051. // This is for _DOMAINS feature
  1052. $this->detectedLanguage = $_GET[$languageGetVar];
  1053. }
  1054. }
  1055. // Setting page id:
  1056. list($cachedInfo['id'], $id_GET_VARS, $cachedInfo['rootpage_id']) = $this->decodeSpURL_idFromPath($pathParts);
  1057. // Fixed Post-vars:
  1058. $fixedPostVarSetCfg = $this->getPostVarSetConfig($cachedInfo['id'], 'fixedPostVars');
  1059. $fixedPost_GET_VARS = $this->decodeSpURL_settingPreVars($pathParts, $fixedPostVarSetCfg);
  1060. // Setting "postVarSets":
  1061. $postVarSetCfg = $this->getPostVarSetConfig($cachedInfo['id']);
  1062. $post_GET_VARS = $this->decodeSpURL_settingPostVarSets($pathParts, $postVarSetCfg, $cachedInfo['id']);
  1063. // Looking for remaining parts:
  1064. if (count($pathParts)) {
  1065. $this->decodeSpURL_throw404('"' . $speakingURIpath . '" could not be found, closest page matching is ' . substr(implode('/', $this->dirParts), 0, -strlen(implode('/', $pathParts))) . '');
  1066. }
  1067. // Merge Get vars together:
  1068. $cachedInfo['GET_VARS'] = array();
  1069. if (is_array($pre_GET_VARS))
  1070. $cachedInfo['GET_VARS'] = t3lib_div::array_merge_recursive_overrule($cachedInfo['GET_VARS'], $pre_GET_VARS);
  1071. if (is_array($id_GET_VARS))
  1072. $cachedInfo['GET_VARS'] = t3lib_div::array_merge_recursive_overrule($cachedInfo['GET_VARS'], $id_GET_VARS);
  1073. if (is_array($fixedPost_GET_VARS))
  1074. $cachedInfo['GET_VARS'] = t3lib_div::array_merge_recursive_overrule($cachedInfo['GET_VARS'], $fixedPost_GET_VARS);
  1075. if (is_array($post_GET_VARS))
  1076. $cachedInfo['GET_VARS'] = t3lib_div::array_merge_recursive_overrule($cachedInfo['GET_VARS'], $post_GET_VARS);
  1077. if (is_array($file_GET_VARS))
  1078. $cachedInfo['GET_VARS'] = t3lib_div::array_merge_recursive_overrule($cachedInfo['GET_VARS'], $file_GET_VARS);
  1079. // cHash handling:
  1080. if ($cHashCache) {
  1081. $cHash_value = $this->decodeSpURL_cHashCache($speakingURIpath);
  1082. if ($cHash_value) {
  1083. $cachedInfo['GET_VARS']['cHash'] = $cHash_value;
  1084. }
  1085. }
  1086. // Return information found:
  1087. return $cachedInfo;
  1088. }
  1089. /**
  1090. * Generates a parameter string from an array recursively
  1091. *
  1092. * @param array Array to generate strings from
  1093. * @param string path to prepend to every parameter
  1094. * @return array Array with parameter strings
  1095. */
  1096. protected function decodeSpURL_createQueryStringParam($paramArr, $prependString = '') {
  1097. if (!is_array($paramArr)) {
  1098. return array($prependString . '=' . $paramArr);
  1099. }
  1100. if (count($paramArr) == 0) {
  1101. return array();
  1102. }
  1103. $paramList = array();
  1104. foreach ($paramArr as $var => $value) {
  1105. $paramList = array_merge($paramList, $this->decodeSpURL_createQueryStringParam($value, $prependString . '[' . $var . ']'));
  1106. }
  1107. return $paramList;
  1108. }
  1109. /**
  1110. * Re-creates QUERY_STRING for use with typoLink()
  1111. *
  1112. * @param array List of Get vars
  1113. * @return string QUERY_STRING value
  1114. */
  1115. protected function decodeSpURL_createQueryString(&$getVars) {
  1116. if (!is_array($getVars)

Large files files are truncated, but you can click here to view the full file