<?php
/** $Source: /home/egotec/repository/EGOTEC/error.php,v $
 * Unterstützung für sprechende Urls.
 *
 * @ingroup view
 * @author dg
 * $Id$
 */
$GLOBALS['stats']['db_select'] = 0;
$GLOBALS['stats']['db_cache'] = 0;

require_once 'bin/conf/local.php';

// Securimage Klassen müssen definiert sein, bevor die Session gestartet wird
require_once $GLOBALS['egotec_conf']['bin_dir'] . 'captcha/CaptchaObject.php';
require_once $GLOBALS['egotec_conf']['bin_dir'] . 'captcha/StorageAdapter/AdapterInterface.php';

// HTTPS über Reverse Proxy erkennen
if (
	isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
	&& strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https'
) {
	$_SERVER['HTTPS'] = 'on';
	$_SERVER['REQUEST_SCHEME'] = 'https';
}

if (isset($_SERVER['HTTP_REFERER']) && strpos(basename($_SERVER['HTTP_REFERER']), 'edit.php') === 0) {
	$GLOBALS['frontend_admin'] = true;
}

require_once 'base/error_handler.php';
require_once 'base/session.php';
require_once 'base/global.php';
require_once 'base/handler.php';
require_once 'base/protect.php';
require_once 'base/Ego_Queue.php';
require_once 'base/Site.php';
require_once 'base/Page.php';

// Flag setzen, dass die URL Rewrite Engine genutzt wird
$GLOBALS['egotec_conf']['rewrite_engine'] = 'url';

// Der zu prüfende Host muss immer klein geschrieben sein, da diese in der Regel so definiert werden
$_SERVER['HTTP_HOST'] = mb_strtolower($_SERVER['HTTP_X_FORWARDED_HOST']?$_SERVER['HTTP_X_FORWARDED_HOST']:$_SERVER['HTTP_HOST']);

// Domain ermitteln
$domain = $_SERVER['HTTP_HOST'];

$_REQUEST['_url'] = Ego_System::secureURL($_REQUEST['_url']);
$_SERVER['REQUEST_URI'] = Ego_System::secureURL($_SERVER['REQUEST_URI']);

// URL aus dem REQUEST _url ermitteln
$dir = trim($_REQUEST['_url'], '/');
$last_dir = substr($_REQUEST['_url'], -1);

// Zugehöriger canonical Wert
$canonical = -1;

// Suffix aus der URL ermitteln
$_SERVER['REQUEST_SUFFIX'] = strrchr($dir, '.');
$url_suffix = true;
if (empty($_SERVER['REQUEST_SUFFIX'])) {
	$_SERVER['REQUEST_SUFFIX'] = '.html'; // Standard Suffix
	$url_suffix = false;
}

// Aufruf über index.php erkennen
$is_index = $_REQUEST['id'] && strtok(basename($_SERVER['REQUEST_URI']), '?') == 'index.php';

if ($is_index) {
	if ($_REQUEST['canonical']) {
		// Bei einer Weiterleitung auf die sprechende URL werden diese Parameter verworfen
		unset($_REQUEST['preview'], $_REQUEST['nonactive'], $_REQUEST['showdeleted']);
	} elseif ($_SESSION['auth_id']) {
		// Ist man angemeldet, darf man auch inaktive Seiten sehen
		$_REQUEST['preview'] = $_REQUEST['nonactive'] = 1;
	}
}

// Eine Vorschau und das Login nicht zwischenspeichern
if (
	$_REQUEST['preview']
	|| $_REQUEST['doauth']
	|| (isset($_COOKIE[EGOTEC_PERSIST]) && !isset($_SESSION['auth_id']))
) {
	$GLOBALS['no_cache'] = true;
}

// Statistiken für Awstats aufzeichenn
if (!$GLOBALS['egotec_conf']['no_log'] && function_exists('stats_shutdown')) {
	Ego_Queue::add('stats_shutdown');
}

// Wenn ein Suffix existiert, wird dieses von der URL entfernt
if (!empty($_SERVER['REQUEST_SUFFIX']) && $url_suffix) {
	$dir = substr($dir, 0, -strlen($_SERVER['REQUEST_SUFFIX']));
}

// Leerzeichen werden immer durch + ersetzt
if ($GLOBALS['egotec_conf']['rewrite']['space'] != ' ') {
	$dir = str_replace(' ', '+', $dir);
}

// Frontend Administration aktivieren
if ($GLOBALS['frontend_admin']) {
	$_REQUEST['no301'] = true; // Keine 301 Weiterleitungen
	$GLOBALS['no_cache'] = true; // Ohne HTML Cache

	$not_found = false;

	// Site Objekt erzeugen
	try {
		$site = new Site(
			$_REQUEST['site'],
			$_REQUEST['lang'],
			$_REQUEST['skin'],
			!$_REQUEST['nonactive']
		);
	} catch (Site_Exception $e) {
		// ignorieren
	}
} else {
	$not_found = true;
	$move_permanently = false;
	$canonical_order = '(canonical = 0), canonical ASC';

	if (!$is_index) {
		// Mediapool URL erkennen
		if (
			(($pos = strpos($dir, '/_/')) !== false && $offset = 3)
			|| (($pos = strpos($dir, '_/')) === 0 && $offset = 2)
		) {
			$_REQUEST['pool'] = substr($dir, $pos + $offset);
			$dir = substr($dir, 0, $pos);

			if ($url_suffix) {
				// Mediapool Dateien ohne Dateiendung berücksichtigen
				$_REQUEST['pool'] .= $_SERVER['REQUEST_SUFFIX'];
			}
		}

		// Die URL in der Datenbank suchen
		$db = new_db_connection(array(
			'table' => 'egotec_url',
			'where' => "domain = :domain AND dir = :dir",
			'order' => $canonical_order,
			'limit' => 1,
			'bind' => array(
				'domain' => $domain,
				'dir' => $dir
			)
		));

		// Fallback für Rewrite1 Migration: kodierte URL suchen
		if (!$db->numRecords()) {
			$db = new_db_connection(array(
				'table' => 'egotec_url',
				'where' => "domain = :domain AND dir = :dir",
				'order' => $canonical_order,
				'limit' => 1,
				'bind' => array(
					'domain' => $domain,
					'dir' => str_replace(array('%2F', '%2B'), array('/', '+'), urlencode($dir))
				)
			));
		}

		// Fallback für unterschiedliche Groß-/Kleinschreibungen
		if (!$db->numRecords()) {
			$db = new_db_connection(array(
				'table' => 'egotec_url',
				'where' => "domain = :domain AND LOWER(dir) = :dir",
				'order' => $canonical_order,
				'limit' => 1,
				'bind' => array(
					'domain' => $domain,
					'dir' => mb_strtolower($dir)
				)
			));

			if ($db->numRecords()) {
				// Kann die URL mit einer anderen Groß-/Kleinschreibung zugeordnet werden, muss auf die richtige URL weitergeleitet werden
				$move_permanently = true;
			} elseif (preg_match('/^([^\/]+\/)?([^\/]+\/)?(\d+)(\/|$)/', $dir, $matches)) {
				// Fallback für kurze URLs mit ID und falschem Prefix bei virtuellen Hosts mit Pfad oder keinem virtuellen Host
				$virtual_hosts = Ego_System::getVirtualHosts();
				$found = false;

				if (!empty($matches[1]) || !empty($matches[2])) {
					// 1. Nach einem virtuellen Host mit Pfad suchen
					foreach ($virtual_hosts as $domain_path => $virtual_host) {
						if ($domain_path == ($domain . '/' . rtrim($matches[1] ?: $matches[2], '/'))) {
							$found = true;

							$db = new_db_connection([
								'table' => 'egotec_url',
								'where' => "site = :site AND lang = :lang AND domain = :domain AND (dir LIKE :dir1 OR dir LIKE :dir2)",
								'order' => $canonical_order,
								'limit' => 1,
								'bind' => [
									'site' => $virtual_host['site'],
									'lang' => $virtual_host['lang'],
									'domain' => $domain,
									'dir1' => rtrim($matches[0], '/') . '/%',
									'dir2' => '%/' . rtrim($matches[3], '/') . '/%'
								]
							]);

							if ($db->numRecords()) {
								// Kann die URL mit einer ID zugeordnet werden, muss auf die richtige URL weitergeleitet werden
								$move_permanently = true;
							}

							break;
						}
					}

					// 2. Nach einem Mandant ohne virtuellen Host suchen
					if (!$found) {
						[$matches_site, $matches_lang] = explode('-', rtrim($matches[1] ?: $matches[2], '/'), 2);
						foreach (Ego_System::getAllSites('', '', false, 'content') as $_site) {
							if ($_site->name == $matches_site) {
								$found = true;

								if (empty($matches_lang)) {
									$matches_lang = $_site->site['default_language'];
								}

								$db = new_db_connection([
									'table' => 'egotec_url',
									'where' => $matches_lang
										? "site = :site AND lang = :lang AND domain = :domain AND (dir LIKE :dir1 OR dir LIKE :dir2)"
										: "site = :site AND domain = :domain AND (dir LIKE :dir1 OR dir LIKE :dir2)",
									'order' => $canonical_order,
									'limit' => 1,
									'bind' => array_merge([
										'site' => $_site->name,
										'domain' => $domain,
										'dir1' => rtrim($matches[0], '/') . '/%',
										'dir2' => '%/' . rtrim($matches[3], '/') . '/%'
									], $matches_lang ? ['lang' => $matches_lang] : [])
								]);

								if ($db->numRecords()) {
									// Kann die URL mit einer ID zugeordnet werden, muss auf die richtige URL weitergeleitet werden
									$move_permanently = true;
								}

								break;
							}
						}
					}
				}

				// 3. Nach einem normalen Pfad mit ID suchen
				if (!$found) {
					$db = new_db_connection(array(
						'table' => 'egotec_url',
						'where' => "domain = :domain AND dir LIKE :dir",
						'order' => $canonical_order,
						'limit' => 1,
						'bind' => array(
							'domain' => $domain,
							'dir' => rtrim($matches[0], '/') . '/%'
						)
					));

					if ($db->numRecords()) {
						// Kann die URL mit einer ID zugeordnet werden, muss auf die richtige URL weitergeleitet werden
						$move_permanently = true;
					} else {
						$host_lang = $virtual_hosts[$domain] ? $virtual_hosts[$domain]['lang'] : '';

						$db = new_db_connection(array(
							'table' => 'egotec_url',
							'where' => $host_lang
								? "domain = :domain AND lang = :lang AND dir LIKE :dir"
								: "domain = :domain AND dir LIKE :dir",
							'order' => $canonical_order,
							'limit' => 1,
							'bind' => array_merge(array(
								'domain' => $domain,
								'dir' => '%/' . rtrim($matches[3], '/') . '/%'
							), $host_lang ? array('lang' => $host_lang) : array())
						));

						if ($db->numRecords()) {
							// Kann die URL mit einer ID zugeordnet werden, muss auf die richtige URL weitergeleitet werden
							$move_permanently = true;
						}
					}
				}
			}
		}
	}

	if (isset($db) && $db->nextRecord()) {
		// URL wurde gefunden
		$request = Ego_System::getRequest($_GET);

		$_REQUEST['site'] = $db->Record['site'];
		$_REQUEST['lang'] = $db->Record['lang'];
		$_REQUEST['id'] = $db->Record['id'];
		$_REQUEST['path'] = $db->Record['path'];
		$canonical = $db->Record['canonical'];
		$GLOBALS['current_path'] = array_filter(explode(',', $_REQUEST['path']), function($value) {
			return $value !== '';
		});

		// Site Objekt erzeugen
		try {
			$site = new Site(
				$_REQUEST['site'],
				$_REQUEST['lang'],
				$_REQUEST['skin'],
				!$_REQUEST['nonactive']
			);
		} catch (Site_Exception $e) {
			switch ($e->getCode()) {
				case Site_Exception::LANG_DOESNT_EXIST:
					// Wechsel auf die Standardsprache
					$site = new Site(
						$_REQUEST['site'],
						'',
						$_REQUEST['skin'],
						!$_REQUEST['nonactive']
					);
					break;
				case Site_Exception::SITE_DOESNT_EXIST:
					$_REQUEST['site'] = $GLOBALS['egotec_conf']['default_site'];
					$site = new Site($GLOBALS['egotec_conf']['default_site']);
					$site->displayCachedErrorPage();
					$_SERVER['REQUEST_SUFFIX'] = '.html'; // Fehlerseite immer als .html ausgeben
					$_REQUEST['id'] = $site->site['error_id'] ?: $site->rootId;
			}
			$_REQUEST['lang'] = $site->language;
			$move_permanently = true;
		}

		if (empty($GLOBALS['frontend_admin'])) {
			// Dark Site
			if (
				(
					$site->site['darksite']
					|| isset($_POST['default'])
				)
				&& Ego_System::checkLicence($GLOBALS['egotec_conf']['lib_dir'] . 'darksite')
			) {
				if (isset($_POST['default']) && $_POST['default'] == 1) { // Von Dark Site zu Standard
					// Mandanten finden, der den aktuellen Mandanten als Dark Site verwendet
					$target_site = $_SESSION['darksite_source_site']
						? new Site($_SESSION['darksite_source_site'])
						: (function() use ($site) {
							foreach (Ego_System::getAllSites('', '', false, 'content') as $_site) {
								if ($_site->site['darksite'] === $site->name) {
									return $_site;
								}
							}

							return null;
						})();

					$_SESSION['ignore_darksite'] = time();

					unset($_POST['default']);
					require_once 'base/get_url.php';
					Ego_System::redirect($target_site->getRoot(['auth_or' => '1=1']));
				} else if (
					$site->site['darksite']
					&& (
						empty($_POST['default'])
						|| $_POST['default'] == 0
					)
				) { // Von Standard zu Dark Site
					$darksite = null;

					try {
						$darksite = new Site($site->site['darksite'], $_REQUEST['lang']);
					} catch (Site_Exception $e) {
						if ($e->getCode() == Site_Exception::LANG_DOESNT_EXIST) {
							try {
								$darksite = new Site($site->site['darksite'], '');
							} catch (Site_Exception $e) {
								egotec_warning_log("Eingestelle Dark Site für Mandant \"{$site->site['title']}\" existiert nicht.");
							}
						} else if ($e->getCode() == Site_Exception::SITE_DOESNT_EXIST) {
							egotec_warning_log("Eingestelle Dark Site für Mandant \"{$site->site['title']}\" existiert nicht.");
						}
					}
					if ($darksite) {
						if (empty($_SESSION['ignore_darksite']) || (isset($_POST['default']) && $_POST['default'] == 0)) {
							$_SESSION['darksite_source_site'] = $site->name;

							require_once 'base/get_url.php';
							Ego_System::redirect($darksite->getRoot(['auth_or' => '1=1']), 307);
						}
					}
				}
			}
		}

		// Zu verwendende Konfiguration ermitteln
		$conf = $site->getRewriteConf();

		if (
			(
				$conf['suffix'] == 'none' // Wenn URLs ohne Endung erzeugt werden sollen,
				|| (
					$conf['suffix'] == 'custom' // oder URLs mit einer individuellen Endung,
					&& $conf['suffix_custom'] != '/'
					&& $_SERVER['REQUEST_SUFFIX'] != '.' . ltrim($conf['suffix_custom'], '.')
				)
			)
			&& $url_suffix // es eine Endung gibt,
			&& $_SERVER['REQUEST_SUFFIX'] == '.html' // und die Endung ".html" ist,
		) {
			// weiterleiten auf die vorgesehene URL
			$move_permanently = true;
		}

		// Standard Suffix erkennen und als .html behandeln
		if (
			$conf['suffix'] == 'custom'
			&& $conf['suffix_custom'] != '/'
			&& $_SERVER['REQUEST_SUFFIX'] == '.' . ltrim($conf['suffix_custom'], '.')
		) {
			$_SERVER['REQUEST_SUFFIX'] = '.html';
		}
		$default_suffix = $_SERVER['REQUEST_SUFFIX'];
		if ($default_suffix == '.html') {
			switch ($conf['suffix']) {
				// Keine Endung
				case 'none':
					$default_suffix = '';
					break;
				// Individuelle Endung
				case 'custom':
					$default_suffix = '.' . ltrim(trim($conf['suffix_custom'], ' .') != ''
						? $conf['suffix_custom']
						: $_SERVER['REQUEST_SUFFIX'], '.');
					if ($default_suffix == './') {
						$default_suffix = '/';
					}
			}
		}

		// Duplicate Content für URLs verhindern, die auf "/" enden, ohne dass die URLs auf "/" enden sollen (und umgekehrt)
		if (
			$_REQUEST['id'] != $site->rootId
			&& (
				($default_suffix == '/' && $last_dir != '/')
				|| ($default_suffix != '/' && $last_dir == '/')
			)
		) {
			$move_permanently = true;
		}

		if (
			!( // Alternative URLs nicht weiterleiten (nur "canonical=2")
				$db->Record['canonical'] == 2
				&& (
					$site->admin['rewrite']['no_redirect']
					|| (Ego_System::isDevMode() && empty($GLOBALS['egotec_conf']['dev']['redirect_secondary_urls']))
					|| (
						// Alternative URLs auf die Startseite mit speziellen Endungen nicht weiterleiten
						$_SERVER['REQUEST_SUFFIX'] != '.html'
						&& $_REQUEST['id'] == $site->rootId
					)
				)
			)
			&& (
				$db->Record['canonical'] != 1
				|| $move_permanently
			)
		) {
			// Es handelt sich um eine alte URL oder einen Permalink, diese per 301 auf die erste kanonische URL weiterleiten
			$db->select(array(
				'table' => 'egotec_url',
				'where' => 'site = :site AND lang = :lang AND id = :id AND canonical = :canonical',
				'order' => $canonical_order,
				'limit' => 1,
				'bind' => array(
					'site' => $_REQUEST['site'],
					'lang' => $_REQUEST['lang'],
					'id' => $_REQUEST['id'],
					// Ausnahme: Ein Permalink auf die Startseite mit einem speziellen Suffix leitet immer auf die erste alternative URL weiter
					'canonical' => $db->Record['canonical'] == 3 && $_REQUEST['id'] == $site->rootId && $_SERVER['REQUEST_SUFFIX'] != '.html'
						? 2 : 1
				)
			));
			if ($db->nextRecord()) {
				// Eine kanonische URL wurde gefunden
				$redirect_url = Ego_System::getProtocol()
					. $db->Record['domain']
					. ($db->Record['dir'] !== '' ? '/' . $db->Record['dir'] . $default_suffix : '');
				$current_url = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
				if ($redirect_url != $current_url) {
					// Nur weiterleiten, wenn die neue URL nicht die aktuelle URL ist
					Ego_System::redirect($redirect_url . (!empty($request) ? '?' . http_build_query($request) : ''), 301);
				}
			}
		} else {
			// Die URL ist gültig
			$not_found = false;
		}
	} else {
		if ($is_index) {
			// Aufrufe über index.php direkt weiterreichen
		} else {
			// Versuchen auf die Fehlerseite des Mandanten der Domain zu wechseln
			$virtual_hosts = $virtual_hosts ?? Ego_System::getVirtualHosts();
			$site_lang_found = false;

			// Prüfen, ob der erste Bestandteil des Pfades zu einem virtuellen Host gehört
			if (
				mb_strlen($domain_path = explode('/', $dir)[0]) > 0
				&& isset($virtual_hosts[$domain . '/' . $domain_path])
			) {
				$_REQUEST['site'] = $virtual_hosts[$domain . '/' . $domain_path]['site'];
				$_REQUEST['lang'] = $virtual_hosts[$domain . '/' . $domain_path]['lang'];
				$site_lang_found = true;
			}

			if (!$site_lang_found) {
				// Prüfen, ob der erste Bestandteil des Pfades eine Sprache ist
				$domain_lang = '';
				if (mb_strlen($lang = explode('/', $dir)[0]) == 2) {
					// Sprache für die Fehlerseite annehmen
					$domain_lang = "$domain/$lang";
					$url_lang = $_REQUEST['lang'] = $lang;
				}
				if ($domain_lang && isset($virtual_hosts[$domain_lang])) {
					$_REQUEST['site'] = $virtual_hosts[$domain_lang]['site'];
					$_REQUEST['lang'] = $virtual_hosts[$domain_lang]['lang'];
					unset($url_lang);
				} elseif (!$domain_lang && isset($virtual_hosts[$domain])) {
					$_REQUEST['site'] = $virtual_hosts[$domain]['site'];
					$_REQUEST['lang'] = $virtual_hosts[$domain]['lang'];
					unset($url_lang);
				} elseif ($domain_lang && isset($virtual_hosts[$domain])) {
					$_REQUEST['site'] = $virtual_hosts[$domain]['site'];
				} else {
					// Versuchen den Mandanten/Sprache über die URL ohne virtuellen Host zu ermitteln
					$base_dir = explode('-', explode('/', $dir)[0])[0];
					$site_found = false;

					// Abzufragende Sprache ermitteln
					$default_lang = $url_lang ?? $_REQUEST['lang'];
					if (!$default_lang) {
						// Ist keine Sprache bekannt, versuchen die Standardsprache des potenziellen Mandanten zu ermitteln
						if (Ego_System::file_exists($site_conf = $GLOBALS['egotec_conf']['site_dir'] . $base_dir . '/conf.ini')) {
							$ini = parse_ini_file($site_conf, true);
							$default_lang = $ini['default_language'];
						}
						if (!$default_lang) {
							$default_lang = 'de';
						}
					}

					if ($base_dir) {
						// Herausfinden, auf welchen Mandanten die URL zeigen sollte
						$db->select(array(
							'table' => 'egotec_url',
							'where' => "site = :site AND lang = :lang AND domain = :domain AND canonical > 0",
							'order'	=> $canonical_order,
							'limit' => 1,
							'bind' => array(
								'site' => $base_dir,
								'lang' => $default_lang,
								'domain' => $domain
							)
						));
						if ($db->nextRecord()) {
							$_REQUEST['site'] = $db->Record['site'];
							if (!$url_lang) {
								$_REQUEST['lang'] = $db->Record['lang'];
							}
							$site_found = true;
						}
					}

					if (!$site_found) {
						// Wenn die Domain ein virtueller Host ist,
						$virtual_hosts = $virtual_hosts ?? Ego_System::getVirtualHosts();
						if (isset($virtual_hosts[$domain])) {
							// dann diesen verwenden
							$_REQUEST['site'] = $virtual_hosts[$domain]['site'];
							if (!$url_lang) {
								$_REQUEST['lang'] = $virtual_hosts[$domain]['lang'];
							}
							$site_found = true;
						} else {
							// ansonsten den Mandanten über den ersten Treffer mit der Domain herausfinden
							$db->select(array(
								'table' => 'egotec_url',
								'where' => "lang = :lang AND domain = :domain AND canonical > 0",
								'order'	=> $canonical_order,
								'limit' => 1,
								'bind' => array(
									'lang' => $default_lang,
									'domain' => $domain
								)
							));
							if ($db->nextRecord()) {
								$_REQUEST['site'] = $db->Record['site'];
								if (!$url_lang) {
									$_REQUEST['lang'] = $db->Record['lang'];
								}
								$site_found = true;
							} else {
								// 2. Versuch: Suche nur nach Domain
								$db->select(array(
									'table' => 'egotec_url',
									'where' => "domain = :domain AND canonical > 0",
									'order'	=> $canonical_order,
									'limit' => 1,
									'bind' => array(
										'domain' => $domain
									)
								));
								if ($db->nextRecord()) {
									$_REQUEST['site'] = $db->Record['site'];
									if (!$url_lang) {
										$_REQUEST['lang'] = $db->Record['lang'];
									}
									$site_found = true;
								} else {
									// ansonsten den Standard Mandanten verwenden
									$_REQUEST['site'] = $GLOBALS['egotec_conf']['default_site'];
									unset($_REQUEST['lang']);
									$site_found = true;
								}
							}
						}
					}

					// Auf die Fehlerseite des Standard Mandanten wechseln
					if (!$site_found) {
						$_REQUEST['site'] = $GLOBALS['egotec_conf']['default_site'];
					}
				}
			}
		}

		// Site Objekt erzeugen
		try {
			$site = new Site(
				$_REQUEST['site'],
				$_REQUEST['lang'],
				$_REQUEST['skin'],
				!$_REQUEST['nonactive']
			);
		} catch (Site_Exception $e) {
			switch ($e->getCode()) {
				case Site_Exception::LANG_DOESNT_EXIST:
					// Wechsel auf die Standardsprache
					$site = new Site(
						$_REQUEST['site'],
						'',
						$_REQUEST['skin'],
						!$_REQUEST['nonactive']
					);
					break;
				case Site_Exception::SITE_DOESNT_EXIST:
					$_REQUEST['site'] = $GLOBALS['egotec_conf']['default_site'];
					$site = new Site($GLOBALS['egotec_conf']['default_site']);
					$site->displayCachedErrorPage();
					$_SERVER['REQUEST_SUFFIX'] = '.html'; // Fehlerseite immer als .html ausgeben
					$_REQUEST['id'] = $site->site['error_id'] ?: $site->rootId;
			}

			// Die Sprache des neuen Site Objekts verwenden
			$_REQUEST['lang'] = $site->language;
			unset($url_lang);
		}
	}
}

// Ein "/" in der Endung ist nicht erlaubt
if (strpos($_SERVER['REQUEST_SUFFIX'], '/') !== false) {
	$not_found = true;
	unset($_REQUEST['id']);
}

if (!$not_found) {
	$flag['gzip'] = $_SERVER['REQUEST_SUFFIX']=='.html' && $_SERVER['HTTP_ACCEPT_ENCODING'] && (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')!==false);

	// Der ETag Schlüssel muss die Informationen zu "site", "lang", "id" und "skin" enthalten
	$request = Ego_System::getRequest();
	$request['site'] = $_REQUEST['site'];
	$request['lang'] = $_REQUEST['lang'];
	$request['id'] = $_REQUEST['id'];
	$request['skin'] = $_REQUEST['skin'];

	// Ausgabe aus der Cache
	$output_cache_file = 'url' . ($GLOBALS['frontend_admin'] ? '_frontend' : '') . '.' . md5(serialize([$request, $_SERVER['REQUEST_SUFFIX']]));
	$etag = $output_cache_file . '.' . $site->getCacheLastChanged();

	$info = $site->getCacheEntry($output_cache_file . '.info');
	if (is_array($info['stats'])) {
		$stats = array_merge($info['stats'], $stats);
	}
	x_egocms_header();

	// Entspricht Etag If-None-Match, dann 304 an den Browser schicken
	if (
		$info
		&& !$_SESSION['auth_id'] // Benutzer ist nicht authentifiziert
		&& isset($_SERVER['HTTP_IF_NONE_MATCH'])
		&& $_SERVER['HTTP_IF_NONE_MATCH'] == '"' . $etag . '"'
	) {
		$stats['cache'] = 1;
		$stats['size'] = 0;
		Ego_System::header('Cache-Control: private');
		Ego_System::header(304);
		exit;
	}

	if (
		!$_SESSION['auth_id'] // Benutzer ist nicht authentifiziert
		&& $info
		&& ($s = $site->getCacheEntry($output_cache_file))
	) { // Cache ausgeben
		$stats = array_merge($info['stats'], $stats);
		$stats['cache'] = 1;
		if ($info['headers']) {
			foreach ($info['headers'] as $key => $value) {
				if (!empty($value)) {
					Ego_System::header($key . ':' . $value);
				}
			}
		}
		Ego_System::header('X-Cache: CMS');

		if (
			($site->site['type'] == 'media'
				&& in_array($info['type'], array('multimedia/file', 'multimedia/image')))
			|| $_REQUEST['pool']
		) {
			readfile_chunked($s);
		} else {
			if ($flag['gzip']) {
				Ego_System::header('Content-Encoding: gzip');
				$stats['gzip'] = 1;
				$stats['size'] = $stats['gzipout'];
			} else {
				$s = gzdecode($s);
			}
			echo $s;
		}
		exit;
	}
}

// URL Generierung einbinden
require_once 'base/get_url.php';

// Autoload für PageExtensions
require_once 'base/autoload.php';

if (is_object($site)) {
	// Bestimmte URLs erzeugen eine dynamische Ausgabe
	require_once 'base/output.php';

	if (empty($_REQUEST['id'])) {
		$site->displayCachedErrorPage();
		$_SERVER['REQUEST_SUFFIX'] = '.html'; // Fehlerseite immer als .html ausgeben
		$_REQUEST['id'] = $site->site['error_id'] ?: $site->rootId;
	}

	// Alternative URLs für die Startseite nicht weiterleiten
	if ($site->rootId == $_REQUEST['id'] && $canonical > 1) {
		$_REQUEST['no301'] = true;
	}

	// Aufrufe über index.php?id=ID sind nur für angemeldete Benutzer erlaubt
	if ($is_index) {
		if ($_SESSION['auth_id'] || Ego_System::isLocalRequest()) {
			$not_found = false;
			$_REQUEST['no301'] = true;
		} else {
			$site->displayCachedErrorPage();
			$_SERVER['REQUEST_SUFFIX'] = '.html'; // Fehlerseite immer als .html ausgeben
			$_REQUEST['id'] = $site->site['error_id'] ?: $site->rootId;
		}
	}
}

// Template Ausgabe generieren
require_once 'base/page_prepend.php';

/**
 * In der Vorschau muss die XSS-Protection aufgehoben werden, damit ausführbarer Code,
 * das sich im Request Content befindet und gleichzeitig auch in der Ausgabe, ausgeführt werden kann.
 */
if (
	$_SERVER['REQUEST_METHOD'] == 'POST'
	&& !empty($_REQUEST['preview'])
	&& !$auth->isNobody() // Für die Vorschau muss man angemeldet sein
) {
	Ego_System::header('X-XSS-Protection: 0');
}

if ($not_found) {
	// Für die Fehlerseite keine Cache verwenden
	$GLOBALS['no_cache'] = true;
	$site->displayCachedErrorPage();
	$_SERVER['REQUEST_SUFFIX'] = '.html'; // Fehlerseite immer als .html ausgeben
}

// Weiterleitung auf die sprechende URL dieser Seite
if ($is_index && $_REQUEST['canonical']) {
	unset($_REQUEST['canonical']);
	Ego_System::redirect($page->getUrl());
}

// Komprimiert ausgeben
$gzip = $_SERVER['REQUEST_SUFFIX'] == '.html'
	&& $_SERVER['HTTP_ACCEPT_ENCODING']
	&& strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false;

// Statistik aufzeichnen
$stats['gzipin'] = strlen($s);
$stats['size'] = $stats['gzipin'];
if ($page) {
	$stats['id'] = $page->field['id'];
	$stats['name'] = $page->field['name'];
	$stats['site'] = $site->name;
	$stats['lang'] = $site->language;
}

if (!$_SESSION['auth_id']) {
	Ego_System::header('ETag: "' . $etag . '"');
}
if (
	($page->field['cache']&3) == 0
	|| $GLOBALS['no_cache']
	|| (
		$_SESSION['auth_id']
		&& $_SERVER['REQUEST_SUFFIX'] == '.html'
	)
) {
	// Keiner darf cachen
	Ego_System::noCache();
} else {
	// Jemand darf cachen
	$t = $page->getSite()->getCacheExpire();
	Ego_System::header('Expires: ' . gmdate('D, d M Y H:i:s', time()+$t) . ' GMT');
	if ($page->field['cache']&2 && $auth->isNobody()) {
		// Proxy und/oder Browser darf cachen
		Ego_System::header('Cache-Control: public');
	} else {
		// Nur Browser darf cachen
		Ego_System::header('Cache-Control: private');
	}
}

Ego_System::header('Last-Modified: ' . gmdate('D, d M Y H:i:s', strtotime($page->field['c_date'])) . ' GMT');
x_egocms_header();

if (
	($page->field['cache']&4) && $GLOBALS['auth']->isNobody()
	&& strlen($s) < 32000000
	&& !$GLOBALS['no_cache']
	&& ((int)$stats['start']-1) >= $site->getCacheLastChanged()
) { // Seite wird in den Cache geschrieben
	$s_gz = gzencode($s);
	$site->setCacheEntry($output_cache_file, $s_gz);
	$stats['gzipout'] = strlen($s_gz);
	$info = array(
		'headers' => $GLOBALS['egotec']['response_headers'],
		'stats' => $GLOBALS['stats'],
		'type' => $page->field['type']
	);
	$site->setCacheEntry($output_cache_file . '.info', $info);
	if ($gzip) {
		Ego_System::header('Content-Encoding: gzip');
		$stats['gzip'] = 1;
		$stats['size'] = $stats['gzipout'];
		$s = $s_gz;
	}
} elseif ($gzip) {
	Ego_System::header('Content-Encoding: gzip');
	$s = gzencode($s);
	$stats['gzipout'] = strlen($s);
	$stats['size'] = $stats['gzipout'];
}
if ($_SERVER['REQUEST_METHOD'] != 'HEAD') {
	// Die Fehlerseite wird in Cache geschrieben, um diese bei weiteren Aufrufen wiederverwenden zu können
	if (http_response_code() == 404 && empty($_SESSION['auth_id'])) { // Nur für nicht angemeldete Benutzer
		$site->setCacheEntry('error_page' . ($gzip ? '.gz' : ''), $s);
	}

	echo $s;
}
flush();

/**
 * send stats as header for testing
 */
function x_egocms_header() {
	if (!Ego_System::isDevMode()) return; // Only inside dev mode.
	Ego_System::header('X-stats_size: ' . $GLOBALS['stats']['size']);
	Ego_System::header('X-stats_db_select: ' . $GLOBALS['stats']['db_select']);
	Ego_System::header('X-stats_db_cache: ' . $GLOBALS['stats']['db_cache']);
	Ego_System::header('X-stats_gzipin: ' . $GLOBALS['stats']['gzipin']);
	Ego_System::header('X-stats_gzipout: ' . $GLOBALS['stats']['gzipout']);
	Ego_System::header('X-stats_duration: ' . $GLOBALS['stats']['duration']);
}
