* @license http://www.contenido.org/license/LIZENZ.txt * @link http://www.4fb.de * @link http://www.contenido.org * * {@internal * created 2009-09-29 * modified 2008-12-23, Murat Purc, added functions buildRedirect(), composeByComponents() and * isExternalUrl() and exended flexibility of build() * modified 2008-12-26, Murat Purc, added execution of chains 'Contenido.Frontend.PreprocessUrlBuilding' * and 'Contenido.Frontend.PostprocessUrlBuilding' to build() * modified 2009-01-13, Murat Purc, added new function isIdentifiableFrontContentUrl() for better * identification of internal urls * modified 2009-10-27, Murat Purc, fixed/modified CEC_Hook, see [#CON-256] * modified 2011-05-20, Murat Purc, fixed wrong condition in function parse(), see [#CON-399] * * $Id$: * }} * */ if(!defined('CON_FRAMEWORK')) { die('Illegal call'); } final class Contenido_Url { /** * Self instance. * * @var Contenido_Url */ static private $_instance; /** * UrlBuilder instance. * * @var Contenido_UrlBuilder */ private $_oUrlBuilder; /** * UrlBuilder name. * * @var string */ private $_sUrlBuilderName; /** * Constructor of Contenido_Url. Is not callable from outside. * * Gets the UrlBuilder configuration and creates an UrlBuilder instance. */ private function __construct() { $this->_sUrlBuilderName = Contenido_UrlBuilderConfig::getUrlBuilderName(); $this->_oUrlBuilder = Contenido_UrlBuilderFactory::getUrlBuilder( $this->_sUrlBuilderName ); } /** * Returns self instance * * @return Contenido_Url */ public static function getInstance() { if (self::$_instance == null) { self::$_instance = new Contenido_Url(); } return self::$_instance; } /** * Creates a URL to frontend page. * * @param mixed $param Either url or assoziative array containing parameter: * - url: front_content.php?idcat=12&lang=1 * - params: array('idcat' => 12, 'lang' => 1) * Required values depend on used UrlBuilder, but a must have is 'lang'. * @param boolean $bUseAbsolutePath Flag to create absolute Urls * @param array $aConfig If not set, UrlBuilderConfig::getConfig() will be used by the URLBuilder * @return string The Url build by UrlBuilder */ public function build($param, $bUseAbsolutePath=false, array $aConfig=array()) { if (!is_array($param)) { $arr = $this->parse($param); $param = $arr['params']; } // fallback for urls to homepage (/ or front_content.php) if (count($param) == 0 || (!isset($param['idart']) && !isset($param['idartlang']) && !isset($param['idcat']) && !isset($param['idcatlang']) && !isset($param['idcatart']))) { $param['idcat'] = getEffectiveSetting('navigation', 'idcat-home', 1); } // execute preprocess hook $aHookParams = array( 'param' => $param, 'bUseAbsolutePath' => $bUseAbsolutePath, 'aConfig' => $aConfig ); if ($aResult = CEC_Hook::executeAndReturn('Contenido.Frontend.PreprocessUrlBuilding', $aHookParams)) { $param = (isset($aResult['param'])) ? $aResult['param'] : ''; if (isset($aResult['bUseAbsolutePath'])) { $bUseAbsolutePath = (bool) $aResult['bUseAbsolutePath']; } if (isset($aResult['aConfig']) && is_array($aResult['aConfig'])) { $aConfig = $aResult['aConfig']; } } if ($this->_sUrlBuilderName == 'custom_path' && !isset($aParams['level'])) { // downwards compatibility to Contenido_UrlBuilder_CustomPath $aParams['level'] = '1'; } if (!isset($param['lang'])) { // another downwards compatibility to Contenido_UrlBuilder_CustomPath throw new InvalidArgumentException('$param[lang] must be set!'); } if ($this->_sUrlBuilderName == 'custom_path' && count($param) <= 3) { // third downwards compatibility $param['_c_p_'] = '1'; } $this->_oUrlBuilder->buildUrl($param, $bUseAbsolutePath, $aConfig); $url = $this->_oUrlBuilder->getUrl(); // execute postprocess hook if ($result = CEC_Hook::executeAndReturn('Contenido.Frontend.PostprocessUrlBuilding', $url)) { $url = (string) $result; } return $url; } /** * Creates a URL used to redirect to frontend page. * * @param mixed $param Either url or assoziative array containing parameter: * - url: front_content.php?idcat=12&lang=1 * - params: array('idcat' => 12, 'lang' => 1) * Required values depend on used UrlBuilder, but a must have is 'lang'. * @param array $aConfig If not set, UrlBuilderConfig::getConfig() will be used by the URLBuilder * @return string The redirect Url build by UrlBuilder */ public function buildRedirect($param, array $aConfig=array()) { $url = $this->build($param, true, $aConfig); return str_replace('&', '&', $url); } /** * Splits passed url into its components * * @param string $sUrl The Url to strip down * @return array Assoziative array created by using parse_url() having the key 'params' which * includes the parameter value pairs. */ public function parse($sUrl){ $aUrl = @parse_url($sUrl); if (isset($aUrl['query'])) { $aUrl['query'] = str_replace('&', '&', $aUrl['query']); parse_str($aUrl['query'], $aUrl['params']); } if (!isset($aUrl['params']) || !is_array($aUrl['params'])) { $aUrl['params'] = array(); } return $aUrl; } /** * Composes a url using passed components array * * @param array Assoziative array created by parse_url() * @return string $sUrl The composed Url */ public function composeByComponents(array $aComponents) { $sUrl = (isset($aComponents['scheme']) ? $aComponents['scheme'] . '://' : '') . (isset($aComponents['user']) ? $aComponents['user'] . ':' : '') . (isset($aComponents['pass']) ? $aComponents['pass'] . '@' : '') . (isset($aComponents['host']) ? $aComponents['host'] : '') . (isset($aComponents['port']) ? ':' . $aComponents['port'] : '') . (isset($aComponents['path']) ? $aComponents['path'] : '') . (isset($aComponents['query']) ? '?' . $aComponents['query'] : '') . (isset($aComponents['fragment']) ? '#' . $aComponents['fragment'] : ''); return $sUrl; } /** * Checks, if passed url is an external url while performing hostname check * * @param string $sUrl Url to check * @return bool True if url is a external url, otherwhise false */ public function isExternalUrl($sUrl) { $aComponents = $this->parse($sUrl); if (!isset($aComponents['host'])) { return false; } if (!$path = $this->_oUrlBuilder->getHttpBasePath()) { return false; } $aComponents2 = $this->parse($path); if (!isset($aComponents2['host'])) { return false; } return (strtolower($aComponents['host']) !== strtolower($aComponents2['host'])); } /** * Checks, if passed url is an identifiable internal url. * * Following urls will be identified as a internal url: * - "/", "/?idart=123", "/?idcat=123", ... * - "front_content.php", "front_content.php?idart=123", "front_content.php?idcat=123", ... * - The path component of an client HTML base path: e. g. "/cms/", "/cms/?idart=123", "/cms/?idcat=123" * - Also possible: "/cms/front_content.php", "/cms/front_content.php?idart=123", "/cms/front_content.php?idcat=123" * All of them prefixed with protocol and client host (e. g. http://host/) will also be identified * as a internal Url. * * Other Urls, even internal Urls like /unknown/path/to/some/page.html will not be identified as * internal url event if they are real working clean URLs. * * @param string $sUrl Url to check * @return bool True if url is identifiable internal url, otherwhise false */ public function isIdentifiableFrontContentUrl($sUrl){ if ($this->isExternalUrl($sUrl)) { // detect a external url, return false return false; } $aComponents = $this->parse($sUrl); if (!isset($aComponents['path']) || $aComponents['path'] == '') { return false; } $clientPath = ''; if ($httpBasePath = $this->_oUrlBuilder->getHttpBasePath()) { $aComponents2 = $this->parse($httpBasePath); if (isset($aComponents2['path'])) { $clientPath = $aComponents2['path']; } } $path = $aComponents['path']; if ($path == '/' || strpos($path, 'front_content.php') === 0 || strpos($path, '/front_content.php') > 0 || ($clientPath !== '' && $clientPath == $path)) { return true; } else { return false; } } /** * Returns UrlBuilder instance. * * @return Contenido_UrlBuilder */ public function getUrlBuilder() { return $this->_oUrlBuilder; } }