* @since Version 1.0 */ class cUrl { public $_endSlash; public $_showDefault; public $_url; public $_is_cms; public $_default; public $_uri_lang; public $_is_mobile; public $_has_lang; public $_visible = true; public $_redirect_return = false; public $_uri_lang_default = false; public $_ssl = false; public $_sslS = ''; public $_base_key = 'www'; public $_mobile_redirect = false; public $_mobile_key = 'm'; public array $_mobile_key_exclude = ['kam']; // Keys for switching between mobile & desktop views public $_mobile_switch_key = 'sw'; public $_desktop_switch_key = 'dsw'; public $_url_param_sep = ':'; public array $_uri_struct = [ 'params' => false, 'chunks' => false ]; public array $excludeIP = [ '83.241.17.142', '192.168.8.114', '192.168.88.153', '80.232.245.53', ]; public array $excludeActions = [ 'addToCart', ]; public array $excludeDomains = [ 'kam.elixirvault.lv', 'local.elixirvault.lv' ]; public function __construct() { $this->_default = false; $this->_has_lang = false; $this->_endSlash = false; $this->_showDefault = false; $this->_ssl = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443; if ($this->_ssl) { $this->_sslS = 's'; } if (defined('EXCLUDE_WWW_REDIRECT')) { $this->excludeDomains = $this->excludeDomains + (is_array(EXCLUDE_WWW_REDIRECT) ? EXCLUDE_WWW_REDIRECT : array()); } } /** * Function to check user for rights to do sth. * * @author Mareks Keišs * @category Module * @param bool $bCmsSideUrl - is url from cms side * @param bool|string $sAdminFolder - is url from cms side * @param bool $passedURI - is url from cms side * @return bool - true / false */ public function parseUrl(&$bCmsSideUrl = false, $sAdminFolder = false, $passedURI = false) { $red_params = ''; if (!($uri = $passedURI)) { $uri = $_SERVER['REQUEST_URI']; } // Strip params & preserve for redirect set to variable if (count($chunks = explode('?', $uri)) > 1) { $uri = $chunks[0]; $red_params = '?' . $chunks[1]; } // Recreate uri & split into parts if ($red_params) { $uri .= $red_params; } $normalized_uri = preg_replace('/\/+$/', '', $uri); $chunks = explode('?', $normalized_uri); // Handle language in the uri $this->addLanguageToUri($chunks, $sAdminFolder); $bCmsSideUrl = $this->_is_cms; // Get parameter like param:value - erase from url $map = explode('/', $chunks[0]); foreach ($map as $k => $v) { if (strpos($v, $this->_url_param_sep)) { $params = explode($this->_url_param_sep, $v); if (strlen($params[0])) { $_GET[$params[0]] = $params[1]; } unset($map[$k]); } else if (!strlen($v)) { unset($map[$k]); } } // Found a module - analyse / else redirect to index if (!count($map)) { $map[] = 'index'; $this->_visible = false; } // Check backslash at the end & redirect if necessary if (!getV('ajax') && !getV('cron')) { if ( $this->_endSlash && substr($uri, strlen($uri) - 1) != '/' ) { if ($this->_redirect_return) { return $uri . '/' . $red_params; } redirectToUri($uri . '/' . $red_params); } else if ( !$this->_endSlash && substr($uri, -1) == '/' && !is_dir(str_replace('//', '/', __MDIR__ . $uri)) ) { if ($this->_redirect_return) { return substr($uri, 0, strlen($uri) - 1) . $red_params; } redirectToUri(substr($uri, 0, strlen($uri) - 1) . $red_params); } } // Check if mobile request detected - then redirect if ( $this->_mobile_redirect && $_SERVER['REMOTE_ADDR'] != '127.0.0.1' && $_SERVER['SERVER_ADDR'] !== $_SERVER['REMOTE_ADDR'] && !in_array($_SERVER['SERVER_ADDR'], $this->excludeIP) ) { $this->chkIsMobileDeviceRequest(); } else { // Back to base url if ($this->chkIsMobileView()) { redirectToUri($this->getMobileDesktopRedirectUrl(false)); } } // WWW redirect if (!$this->chkIsMobileView()) { if ( $_SERVER['REMOTE_ADDR'] != '127.0.0.1' && $_SERVER['SERVER_ADDR'] !== $_SERVER['REMOTE_ADDR'] && !in_array($_SERVER['SERVER_ADDR'], $this->excludeIP) && (!defined('NO_SSL') || defined('NO_SSL') && !NO_SSL) && !in_array(getV('action'), $this->excludeActions) && !in_array($_SERVER['HTTP_HOST'], $this->excludeDomains) ) { if (isset($_SERVER['HTTP_HOST'])) { // Route all through https $addWWW = (substr($_SERVER['HTTP_HOST'], 0, 3) != 'www' ? 'www.' : ''); //------------------------------------------------------------ // Always use SSL //------------------------------------------------------------ /*if(!$this->_ssl) redirectToUri("https://{$addWWW}{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}"); elseif(isset($_SERVER['HTTP_HOST']) && $addWWW){ redirectToUri("https://{$addWWW}{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}"); }*/ //------------------------------------------------------------ // Key based page SSL usage //------------------------------------------------------------ /* $keyPage = (strpos($uri, 'konts') == 1 || strpos($uri, 'forcehttps') || strpos($uri, 'kpsadmin') == 1 ? true : false); if($keyPage && !$this->_ssl){ redirectToUri("https://{$addWWW}{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}"); }elseif(!$keyPage && $this->_ssl){ redirectToUri("http://{$addWWW}{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}"); }elseif($addWWW){ redirectToUri("http://{$addWWW}{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}"); }*/ } } } $this->_url = '/' . implode('/', $map) . '/'; return true; } /** * Function to check if mobile device sent request * * @author Mareks Keišs * @category Module * @return bool true or false */ const VIEW_MOBILE = 2; const VIEW_DESKTOP = 3; public function chkIsMobileDeviceRequest() { //session_destroy(); $bMobileView = false; if(isset($_SERVER['HTTP_USER_AGENT'])){ $UserAgent = $_SERVER['HTTP_USER_AGENT']; // http://detectmobilebrowsers.com/ $bMobileView = preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i', $UserAgent) || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i', substr($UserAgent, 0, 4)); // Save user agent & check if agent changed if(empty($_SESSION['user_agent'])){ $_SESSION['user_agent'] = $UserAgent; $_SESSION['user_agent_manual_switched_to'] = false; $_SESSION['user_device_is_mobile'] = $bMobileView; } if(getG($this->_mobile_switch_key, false) || getG($this->_desktop_switch_key, false)){ $_SESSION['user_agent_manual_switched_to'] = true; } // Automatic redirect if(!$_SESSION['user_agent_manual_switched_to']){ if($bMobileView){ $this->redirectToMobileUrlAndBack(); }else{ $this->redirectToMobileUrlAndBack(false); } }else{ // Check if page switch accrued by referer if(!empty($_SERVER['HTTP_REFERER'])){ // Distinguish mobile from desktop switch if(getG($this->_mobile_switch_key, false)){ $_SESSION['user_agent_manual_switched_to'] = self::VIEW_MOBILE; redirectToUri($this->getMobileDesktopRedirectUrl()); }else if(getG($this->_desktop_switch_key, false)){ $_SESSION['user_agent_manual_switched_to'] = self::VIEW_DESKTOP; redirectToUri($this->getMobileDesktopRedirectUrl(false)); } } } } return $bMobileView; } /** * Function to add / remove language to the url * * @author Mareks Keišs * @category Module * @param mixed $uriCh - by ref url chunks * @param string $sAdminFolder - admin folder string * @return bool - true / false */ private function addLanguageToUri(&$uriCh, $sAdminFolder){ $params = ''; $uri = ''; if(count($uriCh)){ $uri = preg_replace('/\/+$/', '', $uriCh[0]); } if(count($uriCh)>1){ $params = '?' . $uriCh[1]; } $chunks = array_filter(explode('/', $uri)); // Check passed url for cms indication $this->_is_cms = ($sAdminFolder && current($chunks) == $sAdminFolder) ? true : false; $lang_code = end($chunks); // Check & set language $oLangMod = new sysLanguagesModule(); $vLang = $oLangMod->getLangDataByCode($lang_code, $this->_is_cms); if(strlen($lang_code) == 2 && !!$vLang){ array_pop($chunks); if($vLang['default'] && !$this->_showDefault){ // Redirect & hide default language $uri = "http{$this->_sslS}://{$_SERVER['HTTP_HOST']}/" . implode('/', $chunks) . $params; if($this->_redirect_return) return $uri; redirectToUri($uri); } // Set uri without language $this->_has_lang = true; $this->_uri_lang = $vLang; $this->_uri_lang_default = $vLang['default']; $uriCh[0] = '/' . implode('/', $chunks); }else{ if($vLang = $oLangMod->getDefaultAppLang($this->_is_cms)){ $this->_uri_lang = $vLang; $this->_uri_lang_default = 1; } if($this->_showDefault){ $uri = "http{$this->_sslS}://{$_SERVER['HTTP_HOST']}/" . implode('/', $chunks) . '/' . $this->_uri_lang['lang_code'] . $params; redirectToUri($uri); } } // Save in class varibles $this->_uri_struct['params'] = $params; $this->_uri_struct['chunks'] = $chunks; return true; } /** * Function to redirect & show default language * * @author Mareks Keišs * @category Module * @return bool - true / false */ public function redirectToDefaultLang(){ // Get default language & redirect if($this->_showDefault && !$this->_has_lang && $this->_uri_lang && $this->_uri_struct['chunks']){ } } /** * Function to redirect & hide any language for CMS side * * @author Mareks Keišs * @category Module * @return bool - true / false */ public function redirectToNoLang(){ // Get default language & redirect if($this->_has_lang && $this->_uri_struct['chunks']){ $uri = "http{$this->_sslS}://" . $_SERVER['HTTP_HOST'] . implode('/', $this->_uri_struct['chunks']) . $this->_uri_struct['params']; redirectToUri($uri); } } /** * Function to get language locale code for frontend * * @author Mareks Keišs * @category Module * @return bool - true / false */ public function getAppLangLocale(){ // Get default language & redirect if(isset($this->_uri_lang['lang_locale']) && $this->_uri_lang['lang_locale']){ return $this->_uri_lang['lang_locale']; }else{ return false; } } /** * Function to get language locale code for frontend * * @author Mareks Keišs * @category Module * @return void */ public function redirectToDomain(): void { // Get default language & redirect $code = ''; if (isset($this->_uri_lang['lang_code']) && $this->_uri_lang['lang_code']) { $code = $this->_uri_lang['lang_code']; } redirectToUri('/' . $code); } /** * Function to check if we are in mobile view on desktop view * * @author Mareks Keišs * @category Module * @param string|bool $host - host to check against * @return bool - true / false (returns default TRUE - in case no action / redirect is necessary) */ public function chkIsMobileView($host = false){ $host = ($host ? str_replace(array('http://', 'https://'), '', $host) : $_SERVER['HTTP_HOST']); $vTmp = explode('.', $host); $sSubDomain = array_shift($vTmp); if(!in_array($sSubDomain, $this->_mobile_key_exclude)) return substr($host, 0, strlen("{$this->_mobile_key}.")) == "{$this->_mobile_key}."; return true; } public function chkIsDesktopView($host = false){ $host = ($host ? str_replace(array('http://', 'https://'), "", $host) : $_SERVER['HTTP_HOST']); $vTmp = explode('.', $host); $sSubDomain = array_shift($vTmp); if(!in_array($sSubDomain, $this->_mobile_key_exclude)) return substr($host, 0, strlen("{$this->_base_key}.")) == "{$this->_base_key}."; return true; } /** * Function to redirect current view to mobile view * * @author Mareks Keišs * @category Module */ public function redirectToMobileUrlAndBack($bToMobile = true){ if($bToMobile){ // Check are we already mobile view if(!$this->chkIsMobileView()) redirectToUri($this->getMobileDesktopRedirectUrl()); }else{ if(!$this->chkIsDesktopView()) redirectToUri($this->getMobileDesktopRedirectUrl(false)); } } /** * Function to get device url * * @author Mareks Keišs * @category Module */ public function getMobileDesktopRedirectUrl($bMobile = true, $bManualSwitch = false){ // Match domain preg_match("/(?P[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i", $_SERVER['HTTP_HOST'], $matches); $bManualSwitch = ($bManualSwitch ? ($bMobile ? $this->_mobile_switch_key : $this->_desktop_switch_key) . ":1" : ""); $sRequestUrl = str_replace("{$this->_mobile_switch_key}:1", '', $_SERVER['REQUEST_URI']) . "/{$bManualSwitch}"; $sRequestUrl = preg_replace('/\/+/', '/', $sRequestUrl); if($bMobile){ return "http{$this->_sslS}://{$this->_mobile_key}.{$matches['domain']}{$sRequestUrl}"; }else{ return "http{$this->_sslS}://{$this->_base_key}.{$matches['domain']}{$sRequestUrl}"; } } /** * Function to create current possition full URL * * @author Mareks Keišs * @category Module * @return string URL */ public function getDomainUrl(){ return "http{$this->_sslS}://" . $_SERVER['HTTP_HOST']; } public function getUrl($param = ''){ if(!$param){ return "http{$this->_sslS}://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; }else{ $add = $param; if(is_array($param)){ $add = http_build_query($param); } if($add){ if(count($chunks = explode('?', $_SERVER['REQUEST_URI']))>1){ return "http{$this->_sslS}://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . '?' . $chunks[1] . $add; }else{ return "http{$this->_sslS}://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . '?' . $add; } }else{ return "http{$this->_sslS}://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; } } } /** * Function to get base uri from SERVER REQUEST_URI * * @author Mareks Keišs * @category Module * @return string URL */ public static function getBaseUrl(){ if($url = $_SERVER['REQUEST_URI']){ $chunks = parse_url($url); return $chunks['path']; } } /** * Function to reformat urls based on site settings - remove index page, slashes added / removed if needed * * @author Mareks Keiss * @category Url class * @param null|string $url - url to format * @param bool $base - return url in base structure * @return string - url to be used */ public function rmSlashesIndex(?string $url, bool $base = false): string { // Check if slash at the end needed & add if necessary if (!$base) { if (substr($url, -1) == '/') { if (!$this->_endSlash) { $url = substr($url, 0, strlen($url) - 1); } } else { if ($this->_endSlash) { $url .= '/'; } } } // Remove index page $len = ($this->_endSlash ? 7 : 6); if (substr($url, 0, $len) == ($len == 7 ? '/index/' : '/index')) { $url = substr($url, $len); } if (!$url) { return '/'; } return $url; } }