1: <?php
2:
3: /**
4: * This file contains the uri class.
5: *
6: * @package Core
7: * @subpackage Frontend_URI
8: * @author Murat Purc
9: * @copyright four for business AG <www.4fb.de>
10: * @license http://www.contenido.org/license/LIZENZ.txt
11: * @link http://www.4fb.de
12: * @link http://www.contenido.org
13: */
14:
15: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
16:
17: /**
18: * Frontend URL creation. Works as a wrapper of an UriBuilder instance.
19: *
20: * @package Core
21: * @subpackage Frontend_URI
22: */
23: class cUri {
24:
25: /**
26: * Self instance.
27: *
28: * @var cUri
29: */
30: static private $_instance;
31:
32: /**
33: * UriBuilder instance.
34: *
35: * @var cUriBuilder
36: */
37: private $_oUriBuilder;
38:
39: /**
40: * UriBuilder name.
41: *
42: * @var string
43: */
44: private $_sUriBuilderName;
45:
46: /**
47: * Constructor to create an instance of this class.
48: *
49: * Is not callable from outside.
50: *
51: * Gets the UriBuilder configuration and creates an UriBuilder
52: * instance.
53: */
54: private function __construct() {
55: $this->_sUriBuilderName = cUriBuilderConfig::getUriBuilderName();
56: $this->_oUriBuilder = cUriBuilderFactory::getUriBuilder($this->_sUriBuilderName);
57: }
58:
59: /**
60: * Returns self instance.
61: *
62: * @return cUri
63: */
64: public static function getInstance() {
65: if (self::$_instance == NULL) {
66: self::$_instance = new self();
67: }
68: return self::$_instance;
69: }
70:
71: /**
72: * Creates a URL to frontend page.
73: *
74: * @param mixed $param
75: * Either url or assoziative array containing parameter:
76: * - url: front_content.php?idcat=12&lang=1
77: * - params: array('idcat' => 12, 'lang' => 1)
78: * Required values depend on used UriBuilder, but a must have is 'lang'.
79: * @param bool $bUseAbsolutePath [optional]
80: * Flag to create absolute Urls
81: * @param array $aConfig [optional]
82: * If not set, cUriBuilderConfig::getConfig() will be used by the UriBuilder
83: * @throws cInvalidArgumentException
84: * if the given params do not contain the lang
85: * @return string
86: * The Url build by cUriBuilder
87: */
88: public function build($param, $bUseAbsolutePath = false, array $aConfig = array()) {
89: if (!is_array($param)) {
90: $arr = $this->parse($param);
91: $param = $arr['params'];
92: }
93:
94: // fallback for urls to homepage (/ or front_content.php)
95: if (count($param) == 0 || (!isset($param['idart']) && !isset($param['idartlang']) &&
96: !isset($param['idcat']) && !isset($param['idcatlang']) && !isset($param['idcatart']))) {
97: $param['idcat'] = getEffectiveSetting('navigation', 'idcat-home', 1);
98: }
99:
100: // execute preprocess hook
101: $aHookParams = array(
102: 'param' => $param, 'bUseAbsolutePath' => $bUseAbsolutePath, 'aConfig' => $aConfig
103: );
104: $aResult = cApiCecHook::executeAndReturn('Contenido.Frontend.PreprocessUrlBuilding', $aHookParams);
105: if ($aResult) {
106: $param = (isset($aResult['param'])) ? $aResult['param'] : '';
107: if (isset($aResult['bUseAbsolutePath'])) {
108: $bUseAbsolutePath = (bool) $aResult['bUseAbsolutePath'];
109: }
110: if (isset($aResult['aConfig']) && is_array($aResult['aConfig'])) {
111: $aConfig = $aResult['aConfig'];
112: }
113: }
114:
115: if ($this->_sUriBuilderName == 'custom_path' && !isset($aParams['level'])) {
116: // downwards compatibility to cUriBuilderCustomPath
117: $aParams['level'] = '1';
118: }
119:
120: if (!isset($param['lang'])) {
121: // another downwards compatibility to cUriBuilderCustomPath
122: throw new cInvalidArgumentException('$param[lang] must be set!');
123: }
124:
125: if ($this->_sUriBuilderName == 'custom_path' && count($param) <= 3) {
126: // third downwards compatibility
127: $param['_c_p_'] = '1';
128: }
129:
130: $this->_oUriBuilder->buildUrl($param, $bUseAbsolutePath, $aConfig);
131:
132: $url = $this->_oUriBuilder->getUrl();
133:
134: // execute postprocess hook
135: $result = cApiCecHook::executeAndReturn('Contenido.Frontend.PostprocessUrlBuilding', $url);
136: if ($result) {
137: $url = (string) $result;
138: }
139:
140: return $url;
141: }
142:
143: /**
144: * Creates a URL used to redirect to frontend page.
145: *
146: * @param mixed $param
147: * Either url or assoziative array containing parameter:
148: * - url: front_content.php?idcat=12&lang=1
149: * - params: array('idcat' => 12, 'lang' => 1)
150: * Required values depend on used UriBuilder, but a must have is 'lang'.
151: * @param array $aConfig [optional]
152: * If not set, cUriBuilderConfig::getConfig() will be used by the UriBuilder.
153: * @return string
154: * The redirect Url build by cUriBuilder.
155: */
156: public function buildRedirect($param, array $aConfig = array()) {
157: $url = $this->build($param, true, $aConfig);
158: return str_replace('&', '&', $url);
159: }
160:
161: /**
162: * Splits passed url into its components.
163: *
164: * @param string $sUrl
165: * The Url to strip down.
166: * @return array
167: * Assoziative array created by using parse_url()
168: * having the key 'params' which includes the parameter value pairs.
169: */
170: public function parse($sUrl) {
171: $aUrl = @parse_url($sUrl);
172:
173: if (isset($aUrl['query'])) {
174: $aUrl['query'] = str_replace('&', '&', $aUrl['query']);
175: parse_str($aUrl['query'], $aUrl['params']);
176: }
177:
178: if (!isset($aUrl['params']) || !is_array($aUrl['params'])) {
179: $aUrl['params'] = array();
180: }
181:
182: return $aUrl;
183: }
184:
185: /**
186: * Composes a url using passed components array.
187: *
188: * @param array $aComponents
189: * Assoziative array created by parse_url()
190: * @return string
191: * The composed Url
192: */
193: public function composeByComponents(array $aComponents) {
194: $sUrl = (isset($aComponents['scheme']) ? $aComponents['scheme'] . '://' : '') .
195: (isset($aComponents['user']) ? $aComponents['user'] . ':' : '') .
196: (isset($aComponents['pass']) ? $aComponents['pass'] . '@' : '') .
197: (isset($aComponents['host']) ? $aComponents['host'] : '') .
198: (isset($aComponents['port']) ? ':' . $aComponents['port'] : '') .
199: (isset($aComponents['path']) ? $aComponents['path'] : '') .
200: (isset($aComponents['query']) ? '?' . $aComponents['query'] : '') .
201: (isset($aComponents['fragment']) ? '#' . $aComponents['fragment'] : '');
202: return $sUrl;
203: }
204:
205: /**
206: * Checks, if passed url is an external url while performing
207: * hostname check.
208: *
209: * @param string $sUrl
210: * Url to check.
211: * @return bool
212: * True if url is a external url, otherwise false.
213: */
214: public function isExternalUrl($sUrl) {
215: $aComponents = $this->parse($sUrl);
216: if (!isset($aComponents['host'])) {
217: return false;
218: }
219: if (!$path = $this->_oUriBuilder->getHttpBasePath()) {
220: return false;
221: }
222:
223: $aComponents2 = $this->parse($path);
224: if (!isset($aComponents2['host'])) {
225: return false;
226: }
227:
228: return strtolower($aComponents['host']) !== strtolower($aComponents2['host']);
229: }
230:
231: /**
232: * Checks, if passed url is an identifiable internal url.
233: *
234: * Following urls will be identified as a internal url:
235: *
236: * - "/", "/?idart=123", "/?idcat=123", ...
237: * - "front_content.php", "front_content.php?idart=123", "front_content.php?idcat=123", ...
238: * - "/front_content.php", "/front_content.php?idart=123", "/front_content.php?idcat=123", ...
239: * - The path component of an client HTML base path: e.g. "/cms/", "/cms/?idart=123", "/cms/?idcat=123"
240: * - Also possible: "/cms/front_content.php", "/cms/front_content.php?idart=123", "/cms/front_content.php?idcat=123"
241: *
242: * All of them prefixed with protocol and client host (e.g. http://host/) will also be identified
243: * as a internal Url.
244: *
245: * Other Urls, even internal Urls like /unknown/path/to/some/page.html
246: * will not be identified as internal url event if they are real
247: * working clean URLs.
248: *
249: * @param string $sUrl
250: * Url to check.
251: * @return bool
252: * True if url is identifiable internal url, otherwise false.
253: */
254: public function isIdentifiableFrontContentUrl($sUrl) {
255: if ($this->isExternalUrl($sUrl)) {
256: // detect a external url, return false
257: return false;
258: }
259:
260: $aComponents = $this->parse($sUrl);
261: if (!isset($aComponents['path']) || $aComponents['path'] == '') {
262: return false;
263: }
264:
265: $clientPath = '';
266: if ($httpBasePath = $this->_oUriBuilder->getHttpBasePath()) {
267: $aComponents2 = $this->parse($httpBasePath);
268: if (isset($aComponents2['path'])) {
269: $clientPath = $aComponents2['path'];
270: }
271: }
272:
273: // Use pathinfo to get the path part (dirname) of the url
274: $pathinfo = pathinfo($aComponents['path']);
275: $baseName = $pathinfo['basename'];
276: $path = $pathinfo['dirname'];
277: $path = str_replace('\\', '/', $path);
278: if ($path == '.') {
279: $path = '';
280: }
281:
282: // Remove leading/ending slashes
283: $path = trim($path, '/');
284: $clientPath = trim($clientPath, '/');
285:
286: if (($path == '' && ($baseName == 'front_content.php' || $baseName == ''))) {
287: return true;
288: } elseif (($path == $clientPath && ($baseName == 'front_content.php' || $baseName == ''))) {
289: return true;
290: } elseif ($path == '' && $baseName !== 'front_content.php' && $baseName == $clientPath) {
291: // If url is e.g. "/cms/"
292: return true;
293: } else {
294: return false;
295: }
296: }
297:
298: /**
299: * Returns UriBuilder instance.
300: *
301: * @return cUriBuilder
302: */
303: public function getUriBuilder() {
304: return $this->_oUriBuilder;
305: }
306:
307: }
308: