diff --git a/cli/drivers/Typo3ValetDriver.php b/cli/drivers/Typo3ValetDriver.php index ca934cf..108f4ce 100644 --- a/cli/drivers/Typo3ValetDriver.php +++ b/cli/drivers/Typo3ValetDriver.php @@ -24,15 +24,17 @@ class Typo3ValetDriver extends ValetDriver | Forbidden URI Patterns |-------------------------------------------------------------------------- | - | All of these patterns won't be publicly available from your web server. - | Instead, the server will throw a 403 forbidden response, if you try - | to access these files via the HTTP layer. Use regex syntax here. + | All of these patterns won't be accessible from your web server. Instead, + | the server will throw a 403 forbidden response, if you try to access + | these files via the HTTP layer. Use regex syntax here and escape @. | */ protected $forbiddenUriPatterns = [ '_(recycler|temp)_/', '^/(typo3conf/ext|typo3/sysext|typo3/ext)/[^/]+/(Resources/Private|Tests)/', - '\.(htaccess|gitkeep|gitignore)', + '^/typo3/.+\.map$', + '^/typo3temp/var/', + '\.(htaccess|gitkeep|gitignore)$', ]; /** @@ -62,18 +64,44 @@ public function serves($sitePath, $siteName, $uri) */ public function isStaticFile($sitePath, $siteName, $uri) { - $uri = $this->isVersionNumberInFilename($sitePath . $this->documentRoot . $uri, $uri); - - if (file_exists($filePath = $sitePath . $this->documentRoot . $uri) - && ! is_dir($filePath) - && pathinfo($filePath)['extension'] !== 'php') + // May the file contains a cache busting version string like filename.12345678.css + // If that is the case, the file cannot be found on disk, so remove the version + // identifier before retrying below. + if (!$this->isActualFile($filePath = $sitePath . $this->documentRoot . $uri)) { - $this->authorizeAccess($uri); - return $filePath; + $uri = preg_replace("@^(.+)\.(\d+)\.(js|css|png|jpg|gif|gzip)$@", "$1.$3", $uri); } + + // Now that any possible version string is cleared from the filename, the resulting + // URI should be a valid file on disc. So assemble the absolut file name with the + // same schema as above and if it exists, authorize access and return its path. + if ($this->isActualFile($filePath = $sitePath . $this->documentRoot . $uri)) + { + return $this->isAccessAuthorized($uri) ? $filePath : false; + } + + // This file cannot be found in the current project and thus cannot be served. return false; } + /** + * Determines if the given URI is blacklisted so that access is prevented. + * + * @param string $uri + * @return boolean + */ + private function isAccessAuthorized($uri) + { + foreach ($this->forbiddenUriPatterns as $forbiddenUriPattern) + { + if (preg_match("@$forbiddenUriPattern@", $uri)) + { + return false; + } + } + return true; + } + /** * Get the fully resolved path to the application's front controller. * This can be the currently requested PHP script, a folder that @@ -86,12 +114,14 @@ public function isStaticFile($sitePath, $siteName, $uri) */ public function frontControllerPath($sitePath, $siteName, $uri) { - $this->directLoginToInstallTool($uri); - $this->authorizeAccess($uri); - $uri = rtrim($uri, '/'); - $absoluteFilePath = $sitePath . $this->documentRoot . $uri; + // without modifying the URI, redirect if necessary + $this->handleRedirectBackendShorthandUris($uri); - if (file_exists($absoluteFilePath)) + // from now on, remove trailing / for convenience for all the following join operations + $uri = rtrim($uri, '/'); + + // try to find the responsible script file for the requested folder / script URI + if (file_exists($absoluteFilePath = $sitePath . $this->documentRoot . $uri)) { if (is_dir($absoluteFilePath)) { @@ -107,7 +137,7 @@ public function frontControllerPath($sitePath, $siteName, $uri) return $absoluteFilePath . '/index.html'; } } - else if (pathinfo($absoluteFilePath)['extension'] === 'php') + else if (pathinfo($absoluteFilePath, PATHINFO_EXTENSION) === 'php') { // this file can be served directly return $this->serveScript($sitePath, $siteName, $uri); @@ -118,6 +148,28 @@ public function frontControllerPath($sitePath, $siteName, $uri) return $this->serveScript($sitePath, $siteName, '/index.php'); } + /** + * Direct access to installtool via domain.dev/typo3/install/ will be redirected to + * sysext install script. domain.dev/typo3 will be redirected to /typo3/, because + * the generated JavaScript URIs on the login screen would be broken on /typo3. + * + * @param string $uri + */ + private function handleRedirectBackendShorthandUris($uri) + { + if (rtrim($uri, '/') === '/typo3/install') + { + header('Location: /typo3/sysext/install/Start/Install.php'); + die(); + } + + if ($uri === '/typo3') + { + header('Location: /typo3/'); + die(); + } + } + /** * Configures the $_SERVER globals for serving the script at * the specified URI and returns it absolute file path. @@ -125,72 +177,21 @@ public function frontControllerPath($sitePath, $siteName, $uri) * @param string $sitePath * @param string $siteName * @param string $uri + * @param string $script * @return string */ private function serveScript($sitePath, $siteName, $uri) { - $absoluteDocumentRoot = $sitePath . $this->documentRoot; - $absoluteFilePath = $absoluteDocumentRoot . $uri; + $docroot = $sitePath . $this->documentRoot; + $abspath = $docroot . $uri; $_SERVER['SERVER_NAME'] = $siteName . '.dev'; - $_SERVER['DOCUMENT_ROOT'] = $absoluteDocumentRoot; + $_SERVER['DOCUMENT_ROOT'] = $docroot; $_SERVER['DOCUMENT_URI'] = $uri; - $_SERVER['SCRIPT_FILENAME'] = $absoluteFilePath; + $_SERVER['SCRIPT_FILENAME'] = $abspath; $_SERVER['SCRIPT_NAME'] = $uri; $_SERVER['PHP_SELF'] = $uri; - return $absoluteFilePath; - } - - /** - * Interrupts execution with a 403 FORBIDDEN if the requested URI is on - * the global blacklist of system files that should not be served. - * - * @param string $uri - */ - private function authorizeAccess($uri) - { - foreach ($this->forbiddenUriPatterns as $forbiddenUri) - { - if (preg_match("@$forbiddenUri@", $uri)) - { - header('HTTP/1.0 403 Forbidden'); - die("You are forbidden to see $uri!"); - } - } - } - - - /** - * Rule for versioned static files, configured through: - * - $GLOBALS['TYPO3_CONF_VARS']['BE']['versionNumberInFilename'] - * - $GLOBALS['TYPO3_CONF_VARS']['FE']['versionNumberInFilename'] - * - * @param string $filePath - * @param string $uri - * @return string $uri - */ - private function isVersionNumberInFilename($filePath, $uri) { - if ( ! file_exists($filePath) && - preg_match("/^(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$/", $uri) - ) { - return preg_replace("/^(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$/", "$1.$3", $uri); - } - - return $uri; - } - - /** - * Direct access to installtool via domain.dev/typo3/install/ - * Will be redirected to the sysext install script - * - * @param string $uri - */ - private function directLoginToInstallTool($uri) { - if (preg_match("/^\/typo3\/install$/", rtrim($uri))) - { - header('Location: /typo3/sysext/install/Start/Install.php'); - die(); - } + return $abspath; } }