HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/PvdBoogaard/indoorski.nl/backup/oude-site/cms/api/class.urls.php
<?php

/**
 * This file contains the iwp_urls class
 *
 * @version $Id$
 * 
 *
 * @package IWP
 * @subpackage IWP_API
 */

/**
 * IWP URLs Class
 * This is the class that handles all the functions related to URLs within the application
 *
 * @package IWP
 * @subpackage IWP_API
 */

class iwp_urls extends iwp_base {

	/**
	 * This is the current matched static page name. It is the 'key' for the matched URL regex in the static_urls.ini file.
	 * @var string CurrentStaticPage
	 */
	private $CurrentStaticPage = '';

	/**
	 * This is the current matched module page name. It is the 'key' for the matched URL regex in a module's uriPatterns.ini file.
	 * @var string CurrentModulePage
	 */
	private $CurrentModulePage = '';

	/**
	 * This is the name of the current module that has a match for the current page request
	 * @var string CurrentModule
	 */
	private $CurrentModule = '';

	/**
	 * This is an array with the matched segments from the URL. These segments are determined by $MatchURI
	 * @var array CurrentSegmentMatches
	 * @see $MatchURI
	 */
	private $CurrentSegmentMatches = array();

	/**
	 * This the the current URL used to access this page. It has had the application path and query string removed.
	 * @var string CurrentURL
	 */
	private $CurrentURL = '';

	/**
	 * This is an array that will contain all the static urls from the static_urls.ini file.
	 * @var array StaticUrls
	 */
	private $StaticUrls = array();

	/**
	 * This is a multidimensional associative array for all the module's URLs
	 * @var array ModuleUrls
	 */
	private $ModuleUrls = array();

	/**
	 * An array of predefined regular expressions to match in URLs. This can be added to via a module for its own urls.
	 * @var array MatchURI
	 */
	private $MatchURI = array(
			'From' => array(
				'{contenttype}',
				'{idnumber}',
				'{searchterm}',
				'{slash}',
				'{optionalslash}',
				'{name}',
				'{catparents}',
				'{archive_year}',
				'{archive_month}',
				'{archive_day}',
			),
			'To' => array(
				'(?P<contenttype>[a-zA-Z0-9\-_]*)', // {contenttype}
				'(?P<idnumber>[0-9]*)', // {idnumber}
				'(?P<searchterm>[^/]+)', // {searchterm}
				'/',  // {slash}
				'[/]{0,1}',// {optionalslash}
				'(?P<name>[^/]*)', // {name}
				'(?P<parents>(?P<parent>[^/]*/)*)', // {catparents}
				'(?P<archive_year>([0-9][0-9][0-9][0-9])?)', // {archive_year}
				'(?P<archive_month>([0-9][0-9])?)', // {archive_month}
				'(?P<archive_day>([0-9][0-9])?)', // {archive_day}

			),
		);

	/**
	 * Instance
	 * This static variable holds the current instance of this object being loaded.
	 * So using the getInstance function anywhere will return the very same instance.
	 *
	 * @var object Instance
	 */
	public static $Instance;

	/**
	 * getInstance
	 * This is a static function that sets up the class instance and stores it to the static variable. It will then return that instantiation in the future.
	 *
	 * @return iwp_urls Returns the instantiated object
	 **/
	public static function getInstance(){
		if(!isset(self::$Instance)){
			self::$Instance = new self();
		}
		return self::$Instance;
	}

	/**
	 * Initializes the class by loading the static_urls.ini file into the $StaticUrls member variable.
	 * @return void
	 */
	public function __construct(){
		if(file_exists(IWP_BASE_PATH . '/language/static_urls.ini')){
			$this->StaticUrls = parse_ini_file(IWP_BASE_PATH . '/language/static_urls.ini');
		}
	}

	public function GetRssPageURL(){
		return $this->GetStaticUrl('rsspage');
	}

	/**
	 * Loops through all the modules and loads each one's URI Matches (named regular expressions) to add to the $MatchURI member variable
	 * @return void
	 */
	public function LoadModuleMatches(){
		$modules = iwp_modules::getInstance();
		foreach($modules->ModuleList() as $moduleName){
			$array = call_user_func(array('iwp_module_' .$moduleName, 'getUriMatches'));
			if(!is_array($array) || sizeof($array) < 1){
				continue;
			}
			if(is_array($array['From']) && is_array($array['To']) && sizeof($array['To']) > 0 && sizeof($array['From']) > 0){
				foreach($array['From'] as $k=>$val){
					if(!in_array($val, $this->MatchURI['From'])){
						$this->MatchURI['From'][] = $val;
						$this->MatchURI['To'][] = $array['To'][$k];
					}
				}
			}
		}
	}

	/**
	 * Loops through all the loaded modules and collects their uriPatterns.ini files into a large associative array in $this->ModuleUrls
	 *
	 * @param boolean $force If set to true, it will re-read all the files even if they've already been loaded before.
	 *
	 * @return void
	 */

	public function LoadModuleURIs($force = false){
		if(is_array($this->ModuleUrls) && sizeof($this->ModuleUrls) > 0 && !$force){
			return;
		}
		$modules = iwp_modules::getInstance();
		foreach($modules->ModuleList() as $moduleName){
			$iniFile = IWP_MODULES_PATH . '/'.$moduleName.'/uriPatterns.ini';
			if(file_exists($iniFile)){
				$this->ModuleUrls[$moduleName] = parse_ini_file($iniFile);
			}
		}
	}

	/**
	 * Returns an array of all the module URLs for a specified module
	 *
	 * @param string $module The name of the module to get the variables for.
	 *
	 * @return array An array of module URLs for a specified module
	 */
	public function GetModuleUrls($module=null){
		if($module !== null && isset($this->ModuleUrls[$module])){
			return $this->ModuleUrls[$module];
		}
		return $this->ModuleUrls;
	}

	/**
	 * This function returns the URL for the Error 404 page
	 *
	 * @return string The URL to the 404 page.
	 */
	public function Error404URL(){
		return $this->StaticUrls['error404'];
	}

	/**
	 * This function takes in the UserID and name and returns the User's profile page.
	 *
	 * @return string The URL to a speicified User's profile page
	 */
	public function ViewAuthorProfileURL($userid=null, $name=null){
		if(is_null($name) && is_null($userid)) {
			return $this->Error404URL();
		}

		if(is_null($name) && iwp_IsId($userid)) {
			$userData = iwp_user::getInstance()->GetUserDataById($userid);

			if(!is_array($userData) || sizeof($userData) < 1){
				return $this->Error404URL();
			}

			$name = trim($userData['firstname'] .' '. $userData['lastname']);

		}elseif(!iwp_IsId($userid)){
			return $this->Error404URL();
		}

		$name = $this->CleanURL(trim($name));
		$url = $this->StaticUrls['viewauthor'];
		$url = str_replace('{name}', $name, $url);
		$url = str_replace('{idnumber}', $userid, $url);
		$url = $this->ForceSlash($url);

		return '/'.$url;
	}

	public function UpdateCategoryURL($categoryId, $newURL){
		if($this->db->FetchOne('select count(urlid) from ' . IWP_TABLE_URLS . ' where `associd`=' . (int)$categoryId . ' AND `assoctype`="categories" AND urlpath="' . $this->db->Quote($newURL) . '"') < 1){
			$UpdateData = array();
			$UpdateData['assoctype'] = 'redirect';
			$UpdateData['redirecttype'] = 'categories';
			$this->db->UpdateQuery(IWP_TABLE_URLS, $UpdateData, '`associd`=' . (int)$categoryId . ' AND `assoctype`="categories"');

			$InsertData = array();
			$InsertData['assoctype'] = 'categories';
			$InsertData['associd'] = (int)$categoryId;
			$InsertData['urlpath'] = $newURL;
			$this->db->InsertQuery(IWP_TABLE_URLS, $InsertData);
		}
	}

	public function CategoryNameForURL($categoryName) {
		$categoryName = iwp_strtolower($categoryName);
		$categoryName = preg_replace('#["' . preg_quote("~`!@^&*()_+{}|:?><,./;'[]\\", "#") .  "]#", "", $categoryName);
		$categoryName = str_replace(array('$', '%', '#', '+', '/') , "", $categoryName);
		$categoryName = preg_replace("# +#", " ", $categoryName);
		$categoryName = str_replace(" ", "-", trim($categoryName));
		return $categoryName;
	}

	public function GetParentCategoriesURL($parentid, $categoryClass=null) {
		if(is_null($categoryClass) || !is_object($categoryClass)){
			$categoryClass = iwp_admin_categories::getInstance();
		}

		if ($parentid == 0){
			return '';
		}else{
			$name = $this->CategoryNameForURL($categoryClass->catsById[$parentid]['name']);
			return $this->GetParentCategoriesURL($categoryClass->parentsById[$parentid], $categoryClass) . $name . '/';
		}
	}

	public function GenerateCategoryURL($name, $catid, $parentid, $categoryClass=null) {
		if(is_null($categoryClass) || !is_object($categoryClass)){
			$categoryClass = iwp_admin_categories::getInstance();
		}

		$categoryClass->getCategoryInformation();
		$categoryName = $this->CategoryNameForURL($name);
		$parentCategories = '';

		if($parentid > 0){
			$parentCategories = $this->GetParentCategoriesURL($parentid, $categoryClass);
		}

		$increment = 0;
		$newURL = '/' . $this->lang->Get('urlCategory') . '/' . $parentCategories . $categoryName .'.html';

		if($catid > 0){
			$sql = "select count(urlid) from " . IWP_TABLE_URLS . ' where `urlpath`="%s" AND NOT(assoctype="categories" AND associd=' . $catid . ')';
		}else{
			$sql = "select count(urlid) from " . IWP_TABLE_URLS . ' where `urlpath`="%s"';
		}

		$count = $this->db->FetchOne(sprintf($sql, $newURL));

		while($count > 0){
			++$increment;
			if($increment < 20){
				$newURL = '/' . $this->lang->Get('urlCategory') . '/' . $parentCategories . $categoryName . '-' . $increment .'.html';
				$count = $this->db->FetchOne(sprintf($sql, $newURL));
			}else{
				$newURL = '/' . $this->lang->Get('urlCategory') . '/' . $parentCategories . $categoryName . '-' . rand(1000,200000) . '.html';
				$count = $this->db->FetchOne(sprintf($sql, $newURL));
			}
		}

		return $newURL;
	}

	/**
	 * Takes in a category ID and name and outputs its URL
	 *
	 * @return string The URL of the specified URL
	 */
	public function ViewCategoryURL($catid=null){

		if(is_null($catid) || (int)$catid < 1) {
			return $this->Error404URL();
		}

		$catid = intval($catid);

		if (isset(iwp_categories::$categoryNameURLCache[$catid])) {
			return iwp_categories::$categoryNameURLCache[$catid]['url'];
		}

		$url = $this->db->FetchOne('select urlpath from ' . IWP_TABLE_URLS . ' where associd=' . $catid . ' AND assoctype="categories"');

		return $url;
	}

	/**
	 * Cleans a string ready to be entered into a URL by replacing spaces, casting to lowercase and urlencoding.
	 *
	 * @param string $str The string to clean for use in a URL
	 *
	 * @return string The cleaned string ready for a URL
	 */
	public function CleanURL($str, $FixSpaces=true){
		if($FixSpaces){
			$str = $this->ReplaceSpaces($str);
		}
		$str = iwp_strtolower($str);
		$str = urlencode($str);
		$str = str_replace(array('%5C', '%2F', '%2B'), array('%255C', '%252F' , '%252B'), $str);
		return $str;
	}

	/**
	 * This is the reverse of the CleanURL() function, it takes a URL string and returns it to a normal string with spaces and not urlencoded
	 *
	 * @param string $str The string to be returned to normal
	 */
	public function ReverseCleanURL($str){
		$str = str_replace("-", " ", $str);
		$str = urldecode($str);
		$str = str_replace("%2d", "-", $str);
		return $str;
	}

	/**
	 * This function will create a unique URL for a piece of content. If a URL is already taken, it adds a number to the end of the string.
	 *
	 * @param integer $id The ID number of the content item to create the URL for
	 * @param iwp_content $contentInstance This should be an instance of the content item, if it is null it is created
	 * @param iwp_contenttype $contentTypeInstance This should be an instance of the content type, if it is null it is created
	 *
	 * @return string The unique URL for the piece of content ready to be used and/or saved to the database
	 */
	public function GetUniqueContentUrl($id, $contentInstance=null, $contentTypeInstance=null){
		if(!iwp_IsId($id)) {
			return '';
		}
		if(!is_object($contentTypeInstance)){
			$contentTypeInstance = iwp_contenttypes::getInstance();
		}

		$urlpath = $contentTypeInstance->GetUrlForContentItem($contentInstance,$id);
		$count = 1;
		$maxOut = 100;

		while($this->db->FetchOne('select count(*) from '. IWP_TABLE_URLS .' where urlpath="'.$this->db->Quote($urlpath).'"') > 0){
			--$maxOut;
			++$count;
			if($maxOut < 1){
				break;
			}
			$urlpath = $contentTypeInstance->GetUrlForContentItem($contentInstance,$id,'-'.$count);
			if(empty($urlpath)){
				return '';
			}
		}

		return $urlpath;
	}

	/**
	 * This is a generic function to get a URL for categories, content or users.
	 *
	 * @param string $type The type of URL to get; categories, content or users
	 * @param integer $id The ID for the item to get the URL for
	 * @param array $data An array with any additional data needed to retrieve the URL
	 *
	 * @return string The URL for the requested category, content or user.
	 */
	public function GetUrl($type, $id, $data){
		$url = '';
		if($type == 'categories'){
			$url = $this->ViewCategoryURL($data['categoryid']);
		}elseif($type == 'content'){
			if(!iwp_IsId($id)) {
				return iwp_config::Get('siteURL') .'/';
			}

			$query = 'select * from ' . IWP_TABLE_URLS .' where assoctype="'.$this->db->Quote($type).'" AND associd='.$id;
			$urlData = $this->db->FetchQuery($query);
			if(!is_array($urlData) || sizeof($urlData) < 1 || is_null($urlData['urlpath'])){
				// lets try to generate the url
				$contentType = iwp_contenttypes::getInstance();

				if($contentType->GetId() != $data['typeid']){
					$contentType->Load($data['typeid']);
				}
				$maxOut = 500;

				$Insert = array();
				$Insert['urlpath']		= $this->GetUniqueContentUrl($id, null, $contentType);
				$Insert['assoctype']	= 'content';
				$Insert['associd']		= $id;

				if(!$this->valid->IsBlank($Insert['urlpath'])){
					$this->db->InsertQuery(IWP_TABLE_URLS, $Insert);
				}

				$url = $Insert['urlpath'];

			}else{
				$url = $urlData['urlpath'];
			}
		}elseif($type == 'users'){
			$name = trim($data['firstname'] . ' ' . $data['lastname']);
			$url = $this->ViewAuthorProfileURL($id, $name);
		}

		return $url;
	}

	/**
	 * Returns a string with the base application path
	 *
	 * @param boolean $leadingSlash If set to true (default) it will ensure there is a leading slash on the return string
	 * @param boolean $trailingSlash If set to true (default) it will ensure there is a trailing slash on the return string
	 *
	 * @return string The URL path to the application without the domain
	 */
	public function GetURLPrepend($leadingSlash=true,$trailingSlash=true){
		return $this->ForceSlash(iwp_config::Get('appPath'), $leadingSlash, $trailingSlash);
	}

	/**
	 * Takes in a string and prepares it for use in a URL by replacing spaces with dashes
	 *
	 * @param string $str The string to have the spaces and single quotes replaced
	 *
	 * @return string The cleaned string with spaces replaced
	 */

	public function ReplaceSpaces($str){
		$str = str_replace("-", "%2d", $str);
		$str = str_replace(" ", "-", $str);
		$str = str_replace("'", "%27",$str);
		return $str;
	}


	/**
	 * Takes in a string and prepares it for use in a URL by replacing spaces with dashes
	 *
	 * @param string $str The string to have the spaces and single quotes replaced
	 *
	 * @return string The cleaned string with spaces replaced
	 */

	public function ReplaceSpacesOnly($str){
		$str = str_replace(" ", "-", $str);
		return $str;
	}

	/**
	 * Takes in a string and prepares it for use in a URL by removing bad characters
	 *
	 * @param string $str The string to have the bad characters removed
	 * @param boolean $removeSpaces Whether or not to replace the spaces in the string as well
	 *
	 * @return string The cleaned string with bad characters removed
	 */
	public function RemoveBadCharacters($str, $removeSpaces=true){
		$badChars = array('"', "'", "}", "{", "<", ">", "\\", "=", "+", "*", "^", "&", "$", ".", "/", "%", "#", "@", "!","`", "~", "[", "]", "|", ":", ";", ",", "?");
		$str = str_replace($badChars, "", $str);
		if($removeSpaces){
			$str = $this->ReplaceSpacesOnly($str);
		}
		return $str;
	}

	/**
	 * The getter function for the $CurrentStaticPage member variable
	 *
	 * @return string The current static page that matched the current URL
	 *
	 * @see $CurrentStaticPage
	 */
	public function GetCurrentStaticPage(){
		return $this->CurrentStaticPage;
	}

	/**
	 * The getter function for the $CurrentModulePage member variable
	 *
	 * @return string The current module page that matched the current URL
	 *
	 * @see $CurrentModulePage
	 */
	public function GetCurrentModulePage(){
		return $this->CurrentModulePage;
	}

	/**
	 * The getter function for the $CurrentModule member variable
	 *
	 * @return string The current module that had a page match the current URL
	 *
	 * @see $CurrentModule
	 */
	public function GetCurrentModule(){
		return $this->CurrentModule;
	}

	/**
	 * Checks if a URL passed in matches one of the defined static URLs. If there is a match, it sets the $CurrentStaticPage member variable and returns true.
	 *
	 * @param string $url The URL to search for a match. If null, the function will use the member variable $currentURL.
	 *
	 * @return boolean True if there was a match, false otherwise
	 *
	 * @see $StaticUrls
	 * @see ForceSlash()
	 * @see SetCurrentStaticPage()
	 * @see SetCurrentMatches()
	 */
	public function IsStaticURL($url=null){
		if($url === null){
			$url = $this->GetCurrentURL();
		}

		$appPath = $this->ForceSlash(iwp_config::Get('appPath'), true, false);

		$url = CleanPath($url);
		// this ensures it has a leading slash but not a trailing one
		$url = $this->ForceSlash($url, true, false);

		// this is a quicker check for any urls that aren't regexes
		if(in_array($url, $this->StaticUrls)){
			$key = array_search($url, $this->StaticUrls);
			if(in_string('_alias', $key)) {
				$key = substr($key, 0, strpos($key, '_alias'));
			}
			$this->SetCurrentStaticPage($key);
			return true;
		}

		foreach($this->StaticUrls as $key=>$value){
			$regexValue = $this->TokensToRegex($value);

			if(preg_match('#^'.$regexValue.'[/]{0,1}$#ism', $url, $matches)){
				if(in_string('_alias', $key)) {
					$key = substr($key, 0, strpos($key, '_alias'));
				}

				$this->SetCurrentStaticPage($key);
				$this->SetCurrentMatches($matches);
				return true;
			}
		}

		// nothing was found!
		return false;
	}

	/**
	 * Checks to see if a passed in URL matches any of the modules defined URLs.
	 *
	 * @param string $url The URL to search for a match. If null, the function will use the member variable $currentURL.
	 *
	 * @return boolean True if there was a match, false otherwise
	 *
	 * @see LoadModuleMatches()
	 * @see LoadModuleURIs()
	 * @see ForceSlash()
	 * @see SetCurrentModulePage()
	 * @see SetCurrentMatches()
	 */
	public function IsModuleURL($url=null){
		if($url === null){
			$url = $this->GetCurrentURL();
		}

		$url = CleanPath($url);

		// this ensures it has a leading slash but not a trailing one
		$url = $this->ForceSlash($url, true, false);

		$this->LoadModuleMatches();

		if(!is_array($this->ModuleUrls) || sizeof($this->ModuleUrls) < 1){
			$this->LoadModuleURIs();
		}

		// this is a quicker check for any urls that aren't regexes
		foreach($this->ModuleUrls as $modulename=>$array){
			if(in_array($url, $array)){
				$this->SetCurrentModulePage(array_search($url, $array), $modulename);
				return true;
			}
		}

		foreach($this->ModuleUrls as $modulename=>$uris){
			foreach($uris as $key=>$value){
				$regexValue = $this->TokensToRegex($value);
				if(preg_match('#^'.$regexValue.'[/]{0,1}$#i', $url, $matches)){
					$this->SetCurrentModulePage($key, $modulename);
					$this->SetCurrentMatches($matches);
					return true;
				}
			}
		}

		// nothing was found!
		return false;
	}

	/**
	 * This is the setter for the $CurrentStaticPage member variable
	 *
	 * @param string $key The name of the current matched static page
	 *
	 * @return void
	 */
	private function SetCurrentStaticPage($key){
		$this->CurrentStaticPage = $key;
	}

	/**
	 * This is the setter for the $CurrentModulePage and $CurrentModule member variables
	 *
	 * @param string $key The name of the current matched module page
	 * @param string $module The name of the module that owns the matched page
	 *
	 * @return void
	 */
	private function SetCurrentModulePage($key,$module){
		$this->CurrentModulePage = $key;
		$this->CurrentModule = $module;
	}

	/**
	 * This is the setter for the $CurrentSegmentMatches member variable. It holds all matched segments in the URL.
	 *
	 * @param array $matches The array of matched segments
	 *
	 * @return void
	 */
	private function SetCurrentMatches($matches){
		$this->CurrentSegmentMatches = $matches;
	}

	/**
	 * The getter function for the $CurrentSegmentMatches member variable. It holds all matched segments in the URL.
	 *
	 * @return array The array of matched segments
	 */
	public function GetCurrentMatches(){
		return $this->CurrentSegmentMatches;
	}

	/**
	 * The setter function for the member variable $CurrentURL
	 *
	 * @param string $url The URL to set the CurrentURL to
	 *
	 * @return void
	 */
	public function SetCurrentURL($url){
		$this->CurrentURL = $url;
	}

	/**
	 * The getter function for the member variable $CurrentURL
	 *
	 * @return string The value of the current set URL
	 */
	public function GetCurrentURL(){
		return $this->CurrentURL;
	}

	/**
	 * Replaces placeholder tokens in a URL string with their associated regex patterns
	 *
	 * @param string $value The string to have the tokens replaced
	 *
	 * @return string A regular expression string ready for use in a regular expression function
	 */
	private function TokensToRegex($value){
		$value = str_replace($this->MatchURI['From'], $this->MatchURI['To'], $value);
		return $value;
	}

	/**
	 * This function takes a key/name of a static URL and retrieves the value from a list. It uses the values passed in to replace the tokens and returns the resulting string.
	 *
	 * @param string $name The name/key of the static URL to retrieve
	 * @param array $values An array of values to replace tokens with
	 *
	 * @return string A URL string ready for use with the tokens replaced
	 */
	public function GetStaticUrl($name, $values=null){
		$url = $this->StaticUrls[$name];
		if(is_array($values)){
			foreach($values as $key=>$value){
				$url = str_replace('{preslash}{'.$key.'}', '/' . $this->CleanURL($value), $url);
				$url = str_replace('{optionalslash}{'.$key.'}', '/' . $this->CleanURL($value), $url);
				$url = str_replace('{'.$key.'}{postslash}', $this->CleanURL($value) . '/', $url);
				$url = str_replace('{'.$key.'}', $this->CleanURL($value), $url);
			}
		}
		$url = preg_replace('#\{[a-zA-Z_]*\}#i', '', $url);
		$url = str_replace('//', '/', $url);
		$url = str_replace('//', '/', $url);
		return $this->GetURLPrepend(). $this->RemoveLeadingSlash($url);
	}

	/**
	 * This function takes in a string (usually a URL or path) and ensures there is or isn't leading and trailing slashes
	 *
	 * @param string $url The URL/path to check the slashes on
	 * @param boolean $leading True will ensure there IS a leading slash, false will ensure there isn't one.
	 * @param boolean $trailing True will ensure there IS a trailing slash, false will ensure there isn't one.
	 *
	 * @return string The URL/path with the slashes confirmed
	 */

	public function ForceSlash($url,$leading=false,$trailing=false){
		if($leading){
			if(substr($url,0,1) != '/'){
				$url = '/' . $url;
			}
		}else{
			if(substr($url,0,1) == '/'){
				$url = substr($url,1);
			}
		}

		if($trailing){
			if(substr($url,-1) != '/'){
				$url = $url . '/';
			}
		}else{
			if(substr($url,-1) == '/'){
				$url = substr($url,0, -1);
			}
		}
		return $url;
	}

	/**
	 * Checks to see if there is a leading slash and removes it if there is
	 *
	 * @param string $url The URL or path to ensure there is no leading slash
	 *
	 * @return string The URL or path without a leading slash.
	 */
	function RemoveLeadingSlash($url){

		if(substr($url,0,1) == '/'){
			$url = substr($url,1);
		}

		return $url;
	}

	/**
	 * Checks to see if there is a leading slash and removes it if there is
	 *
	 * @param string $url The URL or path to ensure there is no leading slash
	 *
	 * @return string The URL or path without a leading slash.
	 */
	function ConfirmLeadingSlash($url){

		if(substr($url,0,1) != '/'){
			$url = '/' . $url;
		}

		return $url;
	}


	/**
	 * TODO: Allow modules to enter URLs into the iwp_urls table
	 */
	public function RegisterModuleURL($moduleId, $url){

	}

}