public static function normaliseURL($url, array &$components = []){

		$url = filter_var(trim($url), FILTER_SANITIZE_URL);
		$components = @parse_url($url);

		if(!$components || !isset($components['host'])){

			return '';
		}

		// Scheme

		if(!preg_match('/https*/i', $components['scheme'])){

			switch($components['port']){

				case 443:

					$components['scheme'] = 'https';

				break;

				case 80:
				default:

					$components['scheme'] = 'http';

				break;
			}
		}

		// Remove default ports

		if(!empty($components['port'])){

			if($components['scheme'] == 'http' && $components['port'] == 80){

				unset($components['port']);
			}
			elseif($components['scheme'] == 'https' &&
				$components['port'] == 443){

				unset($components['port']);
			}
		}

		// Remove trailing dot from FQDN

		if(substr($components['host'], -1) == '.'){

			$components['host'] = substr($components['host'], 0, -1);
		}

		// Reconstruct URL

		$normalised =
			strtolower("{$components['scheme']}://{$components['host']}/");

		if(isset($components['port'])){

			$normalised = substr($normalised, 0, -1) . ":{$components['port']}/";
		}

		if(isset($components['path'])){

			// Clean path

			$components['path'] =
				str_replace(['\\', '/./'], '/', $components['path']);
			$components['path'] =
				preg_replace('/[\/]+/', '/', $components['path']);

			$normalised .= ltrim($components['path'], '/');
		}

		if(isset($components['query'])){

			$normalised .= "?{$components['query']}";
		}

		if(isset($components['fragment'])){

			$normalised .= "#{$components['fragment']}";
		}

		return $normalised;
	}