<?php
/**
* @version $Id: uri.class.php 2413 2021-08-21 17:36:26Z IOS $
* @package Elxis
* @subpackage URI
* @copyright Copyright (c) 2006-2021 Elxis CMS (https://www.elxis.org). All rights reserved.
* @license Elxis Public License ( https://www.elxis.org/elxis-public-license.html )
* @author Elxis Team ( https://www.elxis.org )
* @description Elxis CMS is free software. Read the license for copyright notices and details
*/
defined('_ELXIS_') or die ('Direct access to this location is not allowed');
class elxisUri {
private $sef = 0;
private $site_url = ''; //site's URL
private $site_aurl = ''; //site's administration URL
private $admindir = 'estia';
private $site_lang = 'en'; //site's default language
private $site_frontpage = 'content:/'; //site's frontpage (default route)
private $site_ssl = false; //site's ssl switch
private $site_url_ssl = '';
private $site_url_ssl_force = '';
private $ssl = false;
private $uri_string = ''; //requested URI (frontend or backend)
private $uri_string_real = ''; //the full real requested URI
private $uri_string_elxis; //elxis formatted requested URI
private $has_slash = false; //url (not counting query string) has slash at the end?
private $query_string = ''; //query string from uri_string
private $uri_lang = ''; //requested language (empty for default)
private $route = ''; //URI first segment (can be empty, file, or directory)
private $component = 'content'; //component routed from the first segment of the URI
private $segments = array(); //Parsed URI segments without the route/component and the query string
private $routes = array();
private $page_routes = array();
private $reverse_routes = array();
private $apc = 0;
/*********************/
/* MAGIC CONSTRUCTOR */
/*********************/
public function __construct() {
$elxis = eFactory::getElxis();
$this->apc = (int)$elxis->getConfig('APC');
$this->sef = (int)$elxis->getConfig('SEF');
$this->site_url = $elxis->getConfig('URL');
$this->site_frontpage = $elxis->getConfig('DEFAULT_ROUTE');
if (($this->site_frontpage == '') || ($this->site_frontpage == '/') || ($this->site_frontpage == 'content')) {
$this->site_frontpage = 'content:/';
}
if (defined('ELXIS_ADMIN')) {
$this->admindir = ELXIS_ADIR;
$this->site_aurl = $elxis->getConfig('URL').'/'.ELXIS_ADIR;
} else {
$this->admindir = 'estia';
$this->site_aurl = $elxis->getConfig('URL').'/estia';
}
$this->site_lang = $elxis->getConfig('LANG');
if ($elxis->getConfig('SSL') == 2) {
$this->site_ssl = true;
} elseif ($elxis->getConfig('SSL') == 1) {
$this->site_ssl = defined('ELXIS_ADMIN') ? true : false;
}
$this->ssl = $this->detectSSL();
$this->site_url_ssl = $this->secureURL($this->site_url, false);
$this->site_url_ssl_force = $this->secureURL($this->site_url, true);
$this->loadRoutes();
$this->uri_string = $this->getURI();
$extra = (defined('ELXIS_ADMIN')) ? '/'.ELXIS_ADIR.'/' : '/';
if (ELXIS_INNER == 1) {
$extra .= 'inner.php/';
} else if ($this->sef == 0) {
$extra .= (ELXIS_INNER == 1) ? 'inner.php/' : 'index.php/';
}
$this->uri_string_real = $this->site_url_ssl.$extra.$this->uri_string;
$this->parseURI();
$this->makeElxisUri();
}
/***************************************/
/* CHECK IF PAGE WAS REQUESTED VIA SSL */
/***************************************/
public function detectSSL() {
if (isset($_SERVER['HTTPS'])) {
if (($_SERVER['HTTPS'] == 'on') || ($_SERVER['HTTPS'] == 1)) { return true; }
}
if (isset($_SERVER['SERVER_PORT']) && ($_SERVER['SERVER_PORT'] == 443)) { return true; }
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && (strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https')) { return true; }
return false;
}
/*********************/
/* GET REQUESTED URI */
/*********************/
private function getURI() {
$parsed = defined('ELXIS_ADMIN') ? parse_url($this->site_url.'/'.ELXIS_ADIR) : parse_url($this->site_url);
$path = '';
if (isset($parsed['path']) && ($parsed['path'] != '')) { $path = ltrim($parsed['path'], '/'); }
unset($parsed);
$pat = '\/\/|\-\-|\*|\<|\>|\`|\'|\"|\(|\)|\`|\:|[^a-z0-9]0x[0-9a-f][0-9a-f]|\x01|\x02|\x03|\x04|\x05|\x06|\x07|\x08|\x0e|\x0f|\x10|\x11|\x12|\x13|\x14|\x15|\x16|\x17|\x18|\x19|\x1a|\x1b|\x1c|\x1d|\x1e|\x1f';
if (isset($_SERVER['REQUEST_URI'])) {
$uri = ltrim(filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL), '/');
if ($uri == '') { //php 5.2 bug or frontpage, retry to make sure value is ok
$uri = ltrim($_SERVER['REQUEST_URI'], '/');
}
if (preg_match('~'.$pat.'~', strtolower($uri))) {
exitPage::make('security', 'URI-0001', 'Bad URL!');
}
return $this->replacerURI($uri, $path, '');
}
if (isset($_SERVER['QUERY_STRING'])) {
$query_str = filter_input(INPUT_SERVER, 'QUERY_STRING', FILTER_SANITIZE_URL);
} else if (@getenv('QUERY_STRING')) {
$query_str = filter_input(INPUT_ENV, 'QUERY_STRING', FILTER_SANITIZE_URL);
} else {
$query_str = '';
}
if ($query_str != '') { $query_str = '?'.$query_str; }
if (isset($_SERVER['PATH_INFO'])) {
$uri = ltrim(filter_input(INPUT_SERVER, 'PATH_INFO', FILTER_SANITIZE_URL), '/');
if (preg_match('~'.$pat.'~', strtolower($uri.$query_str))) {
exitPage::make('security', 'URI-0002', 'Bad URL!');
}
return $this->replacerURI($uri, $path, $query_str);
} elseif (@getenv('PATH_INFO')) {
$uri = ltrim(filter_input(INPUT_ENV, 'PATH_INFO', FILTER_SANITIZE_URL), '/');
if (preg_match('~'.$pat.'~', strtolower($uri.$query_str))) {
exitPage::make('security', 'URI-0003', 'Bad URL!');
}
return $this->replacerURI($uri, $path, $query_str);
}
if (isset($_SERVER['PHP_SELF'])) {
$uri = ltrim(filter_input(INPUT_SERVER, 'PHP_SELF', FILTER_SANITIZE_URL), '/');
if (preg_match('~'.$pat.'~', strtolower($uri.$query_str))) {
exitPage::make('security', 'URI-0004', 'Bad URL!');
}
return $this->replacerURI($uri, $path, $query_str);
} elseif (@getenv('PHP_SELF')) {
$uri = ltrim(filter_input(INPUT_ENV, 'PHP_SELF', FILTER_SANITIZE_URL), '/');
if (preg_match('~'.$pat.'~', strtolower($uri.$query_str))) {
exitPage::make('security', 'URI-0005', 'Bad URL!');
}
return $this->replacerURI($uri, $path, $query_str);
} else {
return $this->replacerURI('', $path, $query_str);
}
}
/***************************/
/* GET RELATIVE URI STRING */
/***************************/
private function replacerURI($uri, $path='', $query_str='') {
if ($uri != '') {
if ($path != '') {
$uri = preg_replace('#^('.$path.')#i', '', $uri);
$uri = ltrim($uri, '/');
}
$uri = preg_replace('#^('.ELXIS_SELF.')#i', '', $uri);
$uri = ltrim($uri, '/');
}
return $this->filter_uri(urldecode($uri.$query_str));
}
/***********************************************/
/* REMOVE MALICIOUS CHARACTERS FROM URI STRING */
/***********************************************/
private function filter_uri($uri_string) {
$chars = array('"', '<', '>', '$', '(', ')', '`', '^', '|', '\\', ':', '\x');
$replacements = array('', '', '', '', '', '', '', '', '', '', '', '');
$uri_string = str_replace($chars, $replacements, $uri_string);
return $uri_string;
}
/********************/
/* PARSE URI STRING */
/********************/
private function parseURI() {
$sLink = preg_split('/[\?]/', $this->uri_string, 2);
if (isset($sLink[1])) {
$this->query_string = $sLink[1];
}
if (isset($sLink[0])) {
$this->has_slash = (preg_match('#(\/)$#', $sLink[0])) ? true : false;
$parts = preg_split('#[\/]#', $sLink[0], -1, PREG_SPLIT_NO_EMPTY);
} else {
$this->has_slash = false;
$parts = array();
}
if ($parts && (count($parts) > 0)) {
if (strlen($parts[0]) < 3) {
if (file_exists(ELXIS_PATH.'/language/'.$parts[0].'/'.$parts[0].'.php') && ($parts[0] == strtolower($parts[0]))) {
$this->uri_lang = $parts[0];
if ($this->uri_lang == $this->site_lang) { $this->uri_lang = ''; }
array_shift($parts);
} else {
exitPage::make('fatallang', 'URI-0006', 'Invalid request. Requested language does not exist!');
}
}
}
if (!$parts || (count($parts) == 0)) {
$this->has_slash = false;
if (defined('ELXIS_ADMIN')) {
if ($this->query_string != '') {
$this->uri_string = 'cpanel/?'.$this->query_string;
} else {
$this->uri_string = 'cpanel';
}
//$this->uri_string = 'cpanel';
//$this->query_string = '';
$fp = 'cpanel';
} else {
$this->uri_string = $this->site_frontpage;
$this->query_string = '';
$fp = str_replace(':', '/', $this->site_frontpage);
}
$parts2 = preg_split('/[\/]/', $fp, -1, PREG_SPLIT_NO_EMPTY);
} else {
$parts2 = $parts;
}
unset($parts);
$rt = $parts2[0];
if (isset($this->routes[$rt])) {
$this->route = $rt;
$this->component = $this->routes[$rt];
array_shift($parts2);
} elseif ((count($parts2) == 1) && isset($this->page_routes[$rt])) {
$this->route = '';
$this->component = $this->page_routes[$rt];
} elseif (!preg_match('#\.#', $rt) && file_exists(ELXIS_PATH.'/components/com_'.$rt.'/'.$rt.'.php')) {
$this->route = $rt;
$this->component = $rt;
array_shift($parts2);
} else {
//We could query the db to find out if the first segment is a category or item seotitle, if not -> page not found
$this->route = '';
$this->component = defined('ELXIS_ADMIN') ? 'cpanel' : 'content';
}
$this->segments = $parts2;
if (!file_exists(ELXIS_PATH.'/components/com_'.$this->component.'/'.$this->component.'.php')) {
exitPage::make('fatal', 'URI-0007', 'Invalid request! The page requests a component which does not exist.');
}
}
/******************************************************************/
/* MAKE ELXIS FORMATTED URI STRING (NO LANGUAGE, NO QUERY STRING) */
/******************************************************************/
private function makeElxisUri() {
$elxis_uri = '';
if (($this->component != '') && ($this->component != 'frontpage') && ($this->component != 'cpanel') && ($this->component != 'content')) {
$elxis_uri .= $this->component.':';
}
if ($this->segments) {
$elxis_uri .= implode('/', $this->segments);
}
if ($this->has_slash && ($elxis_uri != '')) { $elxis_uri .= '/'; }
$this->uri_string_elxis = $elxis_uri;
}
/* PUBLIC GETTERS */
/**********************************/
/* GET ELXIS FORMATTED URI STRING */
/**********************************/
public function getElxisUri($with_lang=false, $with_query_string=false) {
$elxis_uri = '';
if (($with_lang === true) && ($this->uri_lang != '')) {
$elxis_uri .= ($this->uri_string_elxis != '') ? $this->uri_lang.':'.$this->uri_string_elxis : $this->uri_lang;
} else {
$elxis_uri .= $this->uri_string_elxis;
}
if (($with_query_string === true) && ($this->query_string != '')) {
$elxis_uri .= '?'.$this->query_string;
}
return $elxis_uri;
}
public function isDir() {
return $this->has_slash;
}
public function getUriString() {
return $this->uri_string;
}
public function getRealUriString() {
return $this->uri_string_real;
}
public function getUriLang() {
return $this->uri_lang;
}
public function getQueryString() {
return $this->query_string;
}
public function getRoute() {
return $this->route;
}
public function getComponent() {
return $this->component;
}
public function getSegments() {
return $this->segments;
}
public function secureBase($force=false) {
return ($force) ? $this->site_url_ssl_force : $this->site_url_ssl;
}
/********************************/
/* GET THE SSL VERSION OF A URL */
/********************************/
public function secureURL($url='', $force=false) {
if ($this->site_ssl) {
if ($this->ssl || $force) {
return preg_replace('@^(http\:)@i', 'https:', $url);
}
}
return $url;
}
/**********************/
/* LOAD CUSTOM ROUTES */
/**********************/
private function loadRoutes() {
$elxis = eFactory::getElxis();
if ($this->apc == 1) {
$routes = elxisAPC::fetch('routes', 'system');
if (($routes !== false) && is_array($routes)) {
if (isset($routes['routes'])) { $this->routes = $routes['routes']; }
if (isset($routes['reverse_routes'])) { $this->reverse_routes = $routes['reverse_routes']; }
if (isset($routes['page_routes'])) { $this->page_routes = $routes['page_routes']; }
return;
}
}
if ($elxis->getConfig('REPO_PATH') == '') {
$repo_path = ELXIS_PATH.'/repository';
} else {
$repo_path = $elxis->getConfig('REPO_PATH');
}
if (file_exists($repo_path.'/other/routes.php')) {
include($repo_path.'/other/routes.php');
if (isset($routes) && (count($routes) > 0)) {
$this->routes = $routes;
$this->reverse_routes = array_flip($routes);
}
if (isset($page_routes)) { $this->page_routes = $page_routes; }
}
$db = eFactory::getDB();
$sql = "SELECT ".$db->quoteId('component').", ".$db->quoteId('route')." FROM ".$db->quoteId('#__components')."\n"
."\n WHERE ".$db->quoteId('route')." IS NOT NULL";
$stmt = $db->prepare($sql);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($rows) {
foreach ($rows as $row) {
$r = trim($row['route']);
if ($r == '') { continue; }
$c = str_replace('com_', '', $row['component']);
$this->routes[$r] = $c;
$this->reverse_routes[$c] = $r;
}
}
if ($this->apc == 1) {
$routes = array(
'routes' => $this->routes,
'reverse_routes' => $this->reverse_routes,
'page_routes' => $this->page_routes
);
elxisAPC::store('routes', 'system', $routes, 7200);
}
}
/**************************************/
/* GENERATE URL FROM ELXIS URI STRING */
/**************************************/
public function makeURL($elxis_uri='', $file='', $forcessl=false, $xhtml=true, $isadmin=false) {
if ($isadmin) {
$url = ($forcessl) ? $this->site_url_ssl_force.'/'.$this->admindir.'/' : $this->site_aurl.'/';
} else {
$url = ($forcessl) ? $this->site_url_ssl_force.'/' : $this->site_url.'/';
}
if (!$this->sef) {
$url .= ($file == '') ? 'index.php/' : $file.'/';
} else if (($file != '') && ($file != 'index.php')) {
$url .= $file.'/';
}
if ($elxis_uri == '') {
if ($this->uri_lang != '') { $url .= $this->uri_lang.'/'; }
return $url;
}
$parts = preg_split('#\:#', $elxis_uri, -1, PREG_SPLIT_NO_EMPTY);
$comp = '';
$str = '';
if (strlen($parts[0]) < 3) { //language
if ($parts[0] != $this->site_lang) { $url .= $parts[0].'/'; }
array_shift($parts);
} elseif ($this->uri_lang != '') {
$url .= $this->uri_lang.'/';
}
$c = count($parts);
$stdcomp = $isadmin ? 'cpanel' : 'content';
if ($c == 2) {
$comp = $parts[0];
if ($comp != $stdcomp) {
if (isset($this->reverse_routes[$comp])) {
$url .= $this->reverse_routes[$comp];
} else {
$url .= $comp;
}
if (substr($parts[1], 0, 1) != '/') { $url .= '/'; }
}
$url .= ($xhtml === true) ? str_replace('&', '&', $parts[1]) : $parts[1];
$url = preg_replace('#\/\/$#', '/', $url);
} elseif ($c == 1) {
$comp = $parts[0];
if ($comp != $stdcomp) {
if (isset($this->reverse_routes[$comp])) {
$url .= $this->reverse_routes[$comp];
} else {
$url .= ($xhtml === true) ? str_replace('&', '&', $comp) : $comp;
}
}
} else { //error
return $url;
}
return $url;
}
/*****************************************************************/
/* GENERATE ADMIN URL FROM ELXIS URI STRING (ALL SSL IF ENABLED) */
/*****************************************************************/
public function makeAURL($elxis_uri='', $file='', $forcessl=false, $xhtml=true) {
return $this->makeURL($elxis_uri, $file, $this->site_ssl, $xhtml, true);
}
/****************************************************/
/* GENERATE SECURE URL (simpler method for makeURL) */
/****************************************************/
public function makeSecureURL($elxis_uri='', $file='', $xhtml=true) {
return $this->makeURL($elxis_uri, $file, true, $xhtml);
}
/**********************************************************/
/* GENERATE SECURE ADMIN URL (simpler method for makeURL) */
/**********************************************************/
public function makeSecureAURL($elxis_uri='', $file='', $xhtml=true) {
return $this->makeURL($elxis_uri, $file, true, $xhtml, true);
}
}
?>