From d1d83d36340e2b3d5b846ab699f5079db119742d Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Sat, 9 Aug 2014 11:38:53 +0200 Subject: [PATCH] Fixed some issues with URLs, added case-insensitive controller cache --- .../install/files/lib/system/WCFACP.class.php | 5 +- .../builder/ControllerCacheBuilder.class.php | 70 +++++++++++++++++++ .../system/request/RequestHandler.class.php | 55 ++++++++++++++- .../files/lib/system/request/Route.class.php | 2 + .../lib/system/request/RouteHandler.class.php | 2 +- 5 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 wcfsetup/install/files/lib/system/cache/builder/ControllerCacheBuilder.class.php diff --git a/wcfsetup/install/files/lib/system/WCFACP.class.php b/wcfsetup/install/files/lib/system/WCFACP.class.php index a05d127b88..22733613e9 100644 --- a/wcfsetup/install/files/lib/system/WCFACP.class.php +++ b/wcfsetup/install/files/lib/system/WCFACP.class.php @@ -85,7 +85,10 @@ class WCFACP extends WCF { $pageURL = $application->getPageURL(); } - $path = $pageURL . 'acp/?Login/' . SID_ARG_2ND . '&url=' . rawurlencode(RouteHandler::getProtocol() . $_SERVER['HTTP_HOST'] . WCF::getSession()->requestURI); + // drop session id + $redirectURI = preg_replace('~[&\?]s=[a-f0-9]{40}(&|$)~', '', WCF::getSession()->requestURI); + + $path = $pageURL . 'acp/?Login/' . SID_ARG_2ND_NOT_ENCODED . '&url=' . rawurlencode(RouteHandler::getProtocol() . $_SERVER['HTTP_HOST'] . $redirectURI); HeaderUtil::redirect($path); exit; diff --git a/wcfsetup/install/files/lib/system/cache/builder/ControllerCacheBuilder.class.php b/wcfsetup/install/files/lib/system/cache/builder/ControllerCacheBuilder.class.php new file mode 100644 index 0000000000..03ee39342c --- /dev/null +++ b/wcfsetup/install/files/lib/system/cache/builder/ControllerCacheBuilder.class.php @@ -0,0 +1,70 @@ + + * @package com.woltlab.wcf + * @subpackage system.cache.builder + * @category Community Framework + */ +class ControllerCacheBuilder extends AbstractCacheBuilder { + /** + * @see \wcf\system\cache\builder\AbstractCacheBuilder::rebuild() + */ + public function rebuild(array $parameters) { + $data = array(); + $isACP = ($parameters['environment'] == 'admin'); + + $packageList = new PackageList(); + $packageList->getConditionBuilder()->add("isApplication = ?", array(1)); + $packageList->readObjects(); + foreach ($packageList as $package) { + $abbreviation = Package::getAbbreviation($package->package); + $path = WCF_DIR . $package->packageDir . 'lib/' . ($isACP ? 'acp/' : ''); + + $data[$abbreviation] = array( + 'action' => $this->getControllers($path, $abbreviation, 'action', $isACP), + 'form' => $this->getControllers($path, $abbreviation, 'form', $isACP), + 'page' => $this->getControllers($path, $abbreviation, 'page', $isACP) + ); + } + + return $data; + } + + /** + * Returns a list of case-insensitive controllers with their fully-qualified namespace grouped by type. + * + * @param string $path + * @param string $abbreviation + * @param string $type + * @param boolean $isACP + * @return array + */ + protected function getControllers($path, $abbreviation, $type, $isACP) { + $controllers = array(); + $path .= $type . '/'; + + foreach(glob($path . '*' . ucfirst($type) . '.class.php') as $file) { + $file = basename($file); + if (preg_match('~^([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(Action|Form|Page)\.class\.php$~', $file, $match)) { + if ($match[1] === 'I') { + continue; + } + + $controller = mb_strtolower($match[1]); + $fqn = '\\' . $abbreviation . '\\' . ($isACP ? 'acp\\' : '') . $type . '\\' . $match[1] . $match[2]; + + $controllers[$controller] = $fqn; + } + } + + return $controllers; + } +} diff --git a/wcfsetup/install/files/lib/system/request/RequestHandler.class.php b/wcfsetup/install/files/lib/system/request/RequestHandler.class.php index 87679b3ad7..5be79cf224 100644 --- a/wcfsetup/install/files/lib/system/request/RequestHandler.class.php +++ b/wcfsetup/install/files/lib/system/request/RequestHandler.class.php @@ -1,6 +1,7 @@ + */ + protected $controllers = null; + /** * true, if current domain mismatch any known domain * @var boolean @@ -62,6 +69,16 @@ class RequestHandler extends SingletonFactory { // when using cli, no rescue mode is provided $this->inRescueMode = false; } + + if (class_exists('wcf\system\WCFACP', false)) { + $this->isACPRequest = true; + } + + if (PACKAGE_ID) { + $this->controllers = ControllerCacheBuilder::getInstance()->getData(array( + 'environment' => ($this->isACPRequest ? 'admin' : 'user') + )); + } } /** @@ -223,10 +240,23 @@ class RequestHandler extends SingletonFactory { * @return array */ protected function getClassData($controller, $pageType, $application) { - $className = $application.'\\'.($this->isACPRequest() ? 'acp\\' : '').$pageType.'\\'.ucfirst($controller).ucfirst($pageType); - if ($application != 'wcf' && !class_exists($className)) { - $className = 'wcf\\'.($this->isACPRequest() ? 'acp\\' : '').$pageType.'\\'.ucfirst($controller).ucfirst($pageType); + $className = false; + + if ($this->controllers !== null) { + $className = $this->lookupController($controller, $pageType, $application); + if ($className === false && $application != 'wcf') { + $className = $this->lookupController($controller, $pageType, 'wcf'); + } + } + + // controller is either unknown or within WCFSetup + if ($className === false) { + $className = $application.'\\'.($this->isACPRequest() ? 'acp\\' : '').$pageType.'\\'.ucfirst($controller).ucfirst($pageType); + if ($application != 'wcf' && !class_exists($className)) { + $className = 'wcf\\'.($this->isACPRequest() ? 'acp\\' : '').$pageType.'\\'.ucfirst($controller).ucfirst($pageType); + } } + if (!class_exists($className)) { return null; } @@ -244,6 +274,25 @@ class RequestHandler extends SingletonFactory { ); } + /** + * Lookups a controller from the list of known controllers using a case-insensitive search. + * + * @param string $controller + * @param string $pageType + * @param string $application + * @return boolean + */ + protected function lookupController($controller, $pageType, $application) { + if (isset($this->controllers[$application]) && isset($this->controllers[$application][$pageType])) { + $ciController = mb_strtolower($controller); + if (isset($this->controllers[$application][$pageType][$ciController])) { + return $this->controllers[$application][$pageType][$ciController]; + } + } + + return false; + } + /** * Returns the active request object. * diff --git a/wcfsetup/install/files/lib/system/request/Route.class.php b/wcfsetup/install/files/lib/system/request/Route.class.php index 85e69e5f92..4559b1cc7a 100644 --- a/wcfsetup/install/files/lib/system/request/Route.class.php +++ b/wcfsetup/install/files/lib/system/request/Route.class.php @@ -314,6 +314,8 @@ class Route { if (!empty($components)) { if (strpos($link, '?') === false) $link .= '?'; + else $link .= '&'; + $link .= http_build_query($components, '', '&'); } diff --git a/wcfsetup/install/files/lib/system/request/RouteHandler.class.php b/wcfsetup/install/files/lib/system/request/RouteHandler.class.php index 14b71041fa..47df34ce82 100644 --- a/wcfsetup/install/files/lib/system/request/RouteHandler.class.php +++ b/wcfsetup/install/files/lib/system/request/RouteHandler.class.php @@ -264,7 +264,7 @@ class RouteHandler extends SingletonFactory { self::$pathInfo = ''; // WCF 2.0: index.php/Foo/Bar/ - if (URL_LEGACY_MODE) { + if (URL_LEGACY_MODE && !RequestHandler::getInstance()->isACPRequest()) { if (isset($_SERVER['PATH_INFO'])) { self::$pathInfo = $_SERVER['PATH_INFO']; } -- 2.20.1