diff --git a/Classes/Configuration/ConfigurationReader.php b/Classes/Configuration/ConfigurationReader.php index 06ae4c01..3e28d199 100644 --- a/Classes/Configuration/ConfigurationReader.php +++ b/Classes/Configuration/ConfigurationReader.php @@ -87,6 +87,7 @@ class ConfigurationReader { 'fileName/defaultToHTMLsuffixOnPrev' => FALSE, 'init/appendMissingSlash' => 'ifNotFile,redirect[301]', 'init/emptySegmentValue' => '', + 'init/recalculateChashIfMissing' => false, 'pagePath/spaceCharacter' => '-', // undocumented & deprecated! ); diff --git a/Classes/Decoder/UrlDecoder.php b/Classes/Decoder/UrlDecoder.php index 964c2b32..314a6132 100644 --- a/Classes/Decoder/UrlDecoder.php +++ b/Classes/Decoder/UrlDecoder.php @@ -33,6 +33,7 @@ use DmitryDulepov\Realurl\Cache\UrlCacheEntry; use DmitryDulepov\Realurl\Configuration\ConfigurationReader; use DmitryDulepov\Realurl\EncodeDecoderBase; +use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\MathUtility; @@ -40,12 +41,13 @@ use TYPO3\CMS\Frontend\Page\PageRepository; /** - * This class contains URL decoder for the RealURL. + * This class contains URL decoder for the RealURL. It is singleton because the + * same instance must run in two different hooks. * * @package DmitryDulepov\Realurl\Decoder * @author Dmitry Dulepov */ -class UrlDecoder extends EncodeDecoderBase { +class UrlDecoder extends EncodeDecoderBase implements SingletonInterface { /** @var bool */ protected $appendedSlash = FALSE; @@ -53,6 +55,9 @@ class UrlDecoder extends EncodeDecoderBase { /** @var TypoScriptFrontendController */ protected $caller; + /** @var UrlCacheEntry */ + protected $createdCacheEntry = null; + /** @var int */ protected $detectedLanguageId = 0; @@ -142,6 +147,35 @@ public function decodeUrl(array $params) { } } + /** + * Stores decoded record to the URL cache. This function is called after + * TSFE validates cHash. This way we avoid storing URLs with wrong cHash + * in the cache that would always lead to a 404 until URL cache is cleared. + * + * Currently this function uses 'configArrayPostProc' because this hook + * is closest to the TypoScriptFrontendController::makeCacheHash(). If + * execution comes here, than cHash is validated (assuming that + * $TYPO3_CONF_VARS['FE']['pageNotFoundOnCHashError'] is true). However + * it may not be the best place. Another place could be + * TypoScriptFrontendController::hook_eofe(), which runs after the content + * is generated. Advantage is that the URL to the current page could be + * already generated by the encoding process, which is guaranteed to make + * the URL correctly. On the other hand, if content generation fails for + * some reason, we will not have entries in any case and the next call + * to this URL will have to make costly decoding again. To avoid the + * problem, we do it in the earlier hook. Later, when expiration of URL + * entries is implemented, we could set expiration time for this record + * and the encoder will unexpire it if it generates the same URL. The + * advantage of this is that there will be a proper redirect and no + * duplicate content due to possibly different encoded URL. + */ + public function storeCacheRecord() { + // If it is still not there (could have been added by other process!), than store it + if ($this->createdCacheEntry && !$this->isExpiredPath && !$this->getFromUrlCache($this->speakingUri)) { + $this->putToUrlCache($this->createdCacheEntry); + } + } + /** * Calculates and adds cHash to the entry. This function is only called * if we had to decode the entry, which was not in the cache. Even if we @@ -154,13 +188,15 @@ public function decodeUrl(array $params) { */ protected function calculateChash(UrlCacheEntry $cacheEntry) { $requestVariables = $cacheEntry->getRequestVariables(); - $cacheHashCalculator = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\CacheHashCalculator'); - /* @var \TYPO3\CMS\Frontend\Page\CacheHashCalculator $cacheHashCalculator */ - $cHashParameters = $cacheHashCalculator->getRelevantParameters(GeneralUtility::implodeArrayForUrl('', $requestVariables)); + if (!isset($requestVariables['cHash']) && $this->configuration->get('init/recalculateChashIfMissing')) { + $cacheHashCalculator = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\CacheHashCalculator'); + /* @var \TYPO3\CMS\Frontend\Page\CacheHashCalculator $cacheHashCalculator */ + $cHashParameters = $cacheHashCalculator->getRelevantParameters(GeneralUtility::implodeArrayForUrl('', $requestVariables)); - if (count($cHashParameters) > 0) { - $requestVariables['cHash'] = $cacheHashCalculator->calculateCacheHash($cHashParameters); - $cacheEntry->setRequestVariables($requestVariables); + if (count($cHashParameters) > 0) { + $requestVariables['cHash'] = $cacheHashCalculator->calculateCacheHash($cHashParameters); + $cacheEntry->setRequestVariables($requestVariables); + } } } @@ -1224,10 +1260,7 @@ protected function runDecoding() { } $this->setRequestVariables($cacheEntry); - // If it is still not there (could have been added by other process!), than update - if (!$this->isExpiredPath && !$this->getFromUrlCache($this->speakingUri)) { - $this->putToUrlCache($cacheEntry); - } + $this->createdCacheEntry = $cacheEntry; } /** diff --git a/composer.json b/composer.json index a265afcc..0d51840a 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "type": "typo3-cms-extension", "description": "Speaking URLs for TYPO3", "homepage": "https://github.com/dmitryd/typo3-realurl", - "version": "2.0.14", + "version": "2.0.15", "license": "LGPL-3.0+", "conflict": { "bednee/cooluri": ">0.0.1", diff --git a/ext_emconf.php b/ext_emconf.php index f203cd8d..c65a1dcb 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -12,7 +12,7 @@ 'title' => 'Speaking URLs for TYPO3', 'description' => 'Makes TYPO3 URLs search engine friendly. Donations are welcome to dmitry.dulepov@gmail.com. They help to support the extension!', 'category' => 'services', - 'version' => '2.0.14', + 'version' => '2.0.15', 'state' => 'stable', 'uploadfolder' => 0, 'createDirs' => '', diff --git a/ext_localconf.php b/ext_localconf.php index c46628fc..0ff0d028 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -38,6 +38,7 @@ function includeRealurlConfiguration() { $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['linkData-PostProc']['realurl'] = 'DmitryDulepov\\Realurl\\Encoder\\UrlEncoder->encodeUrl'; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['typoLink_PostProc']['realurl'] = 'DmitryDulepov\\Realurl\\Encoder\\UrlEncoder->postProcessEncodedUrl'; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkAlternativeIdMethods-PostProc']['realurl'] = 'DmitryDulepov\\Realurl\\Decoder\\UrlDecoder->decodeUrl'; +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['configArrayPostProc']['realurl'] = 'DmitryDulepov\\Realurl\\Decoder\\UrlDecoder->storeCacheRecord'; includeRealurlConfiguration();