Enhance configuration management: Updated README.md with Windows sync instructions, refactored backend configuration files to improve loading logic, and ensured consistent function definitions. Improved error handling in bootstrap.php for better user feedback during application startup.

This commit is contained in:
smueller
2026-05-22 14:07:27 +02:00
parent 96a5977283
commit 8afba16905
15 changed files with 1433 additions and 37 deletions

View File

@@ -147,6 +147,11 @@ HexaHost-Frontend/
cp -r HexaHost-Backend/includes/* HexaHost-Frontend/public/includes/
```
Alternativ (Windows, aus diesem Repo mit `backend/`):
```powershell
.\scripts\sync-backend-to-public.ps1
```
3. **PHP Dependencies installieren**
```bash
cd HexaHost-Frontend/public

View File

@@ -14,4 +14,4 @@
// Lade die neue Konfiguration
require_once __DIR__ . '/mail-config.php';
?>

View File

@@ -195,4 +195,3 @@ function getHexaHostConfig($key = null) {
return $config[$key] ?? null;
}
?>

View File

@@ -553,4 +553,4 @@ function renderAllPackages($productId) {
}
return $html;
}
?>

View File

@@ -3,18 +3,25 @@
* HexaHost.de zentrale Domain- und Umgebungskonfiguration
*/
define('SITE_DOMAIN_PRODUCTION', 'hexahost.de');
define('SITE_DOMAIN_DEVELOPMENT', 'dev.hexahost.de');
if (!defined('SITE_DOMAIN_PRODUCTION')) {
define('SITE_DOMAIN_PRODUCTION', 'hexahost.de');
}
if (!defined('SITE_DOMAIN_DEVELOPMENT')) {
define('SITE_DOMAIN_DEVELOPMENT', 'dev.hexahost.de');
}
/**
* Aktuellen HTTP-Host (ohne Port) ermitteln
*
* @return string
*/
function getSiteHost(): string
function getSiteHost()
{
$host = $_SERVER['HTTP_HOST'] ?? SITE_DOMAIN_PRODUCTION;
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : SITE_DOMAIN_PRODUCTION;
$host = strtolower($host);
if (str_contains($host, ':')) {
if (strpos($host, ':') !== false) {
$host = explode(':', $host, 2)[0];
}
@@ -23,16 +30,20 @@ function getSiteHost(): string
/**
* true, wenn die Seite unter der Dev-Domain läuft
*
* @return bool
*/
function isDevelopmentSite(): bool
function isDevelopmentSite()
{
return getSiteHost() === SITE_DOMAIN_DEVELOPMENT;
}
/**
* Basis-URL der aktuellen Anfrage (Schema + Host)
*
* @return string
*/
function getSiteBaseUrl(): string
function getSiteBaseUrl()
{
$https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| (isset($_SERVER['SERVER_PORT']) && (int) $_SERVER['SERVER_PORT'] === 443);
@@ -45,9 +56,9 @@ function getSiteBaseUrl(): string
/**
* Erlaubte CORS-Origins für AJAX (Kontaktformular)
*
* @return list<string>
* @return array<int, string>
*/
function getAllowedOrigins(): array
function getAllowedOrigins()
{
return [
'https://' . SITE_DOMAIN_PRODUCTION,
@@ -61,8 +72,10 @@ function getAllowedOrigins(): array
/**
* Kanonische Basis-URL für SEO (Produktion immer hexahost.de)
*
* @return string
*/
function getCanonicalBaseUrl(): string
function getCanonicalBaseUrl()
{
return 'https://' . SITE_DOMAIN_PRODUCTION;
}

View File

@@ -7,7 +7,62 @@ $configDir = defined('HEXAHOST_CONFIG_DIR')
? HEXAHOST_CONFIG_DIR
: __DIR__ . '/../config';
require_once $configDir . '/site-config.php';
$siteConfigFile = $configDir . '/site-config.php';
if (is_file($siteConfigFile)) {
require_once $siteConfigFile;
} elseif (!function_exists('getSiteHost')) {
define('SITE_DOMAIN_PRODUCTION', 'hexahost.de');
define('SITE_DOMAIN_DEVELOPMENT', 'dev.hexahost.de');
function getSiteHost()
{
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : SITE_DOMAIN_PRODUCTION;
$host = strtolower($host);
if (strpos($host, ':') !== false) {
$host = explode(':', $host, 2)[0];
}
return $host;
}
function isDevelopmentSite()
{
return getSiteHost() === SITE_DOMAIN_DEVELOPMENT;
}
function getSiteBaseUrl()
{
$https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| (isset($_SERVER['SERVER_PORT']) && (int) $_SERVER['SERVER_PORT'] === 443);
return ($https ? 'https' : 'http') . '://' . getSiteHost();
}
function getAllowedOrigins()
{
return [
'https://' . SITE_DOMAIN_PRODUCTION,
'https://www.' . SITE_DOMAIN_PRODUCTION,
'https://' . SITE_DOMAIN_DEVELOPMENT,
'http://localhost',
'http://127.0.0.1',
'http://localhost:8000',
];
}
function getCanonicalBaseUrl()
{
return 'https://' . SITE_DOMAIN_PRODUCTION;
}
}
// Fehleranzeige auf Dev/localhost für einfacheres Debugging
$hexahostHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
if (
(function_exists('isDevelopmentSite') && isDevelopmentSite())
|| preg_match('/^(localhost|127\.0\.0\.1)(:\d+)?$/', $hexahostHost)
) {
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
}
// Sichere Session-Konfiguration
if (session_status() === PHP_SESSION_NONE) {
@@ -106,4 +161,3 @@ function generateCSRFToken() {
}
return $_SESSION['csrf_token'];
}
?>

View File

@@ -1,39 +1,71 @@
<?php
/**
* HexaHost Bootstrap für Monorepo- und Produktions-Layout
* HexaHost Bootstrap (gleiches Prinzip wie dev-Branch: backend/ zuerst)
*
* Monorepo: public/../backend/{includes,config}
* Produktion: public/{includes,config} (nach Backend-Kopie)
* Priorität (wie Deploy auf dev.hexahost.de):
* 1. ../backend/{includes,config} Monorepo / Dev-Server
* 2. public/{includes,config} Prod nur mit Webroot public/
* 3. Hybrid (includes/config gemischt)
*/
if (!defined('HEXAHOST_BOOTSTRAPPED')) {
$pathCandidates = [
[
'includes' => __DIR__ . '/includes',
'config' => __DIR__ . '/config',
],
[
'includes' => __DIR__ . '/../backend/includes',
'config' => __DIR__ . '/../backend/config',
],
];
function hexahost_path_candidates(): array
{
$backendIncludes = dirname(__DIR__) . '/backend/includes';
$backendConfig = dirname(__DIR__) . '/backend/config';
$publicIncludes = __DIR__ . '/includes';
$publicConfig = __DIR__ . '/config';
return [
['includes' => $backendIncludes, 'config' => $backendConfig],
['includes' => $publicIncludes, 'config' => $publicConfig],
['includes' => $publicIncludes, 'config' => $backendConfig],
['includes' => $backendIncludes, 'config' => $publicConfig],
];
}
function hexahost_is_app_root_valid(string $includesDir, string $configDir): bool
{
$required = [
$includesDir . '/functions.php',
$includesDir . '/header.php',
$includesDir . '/footer.php',
$configDir . '/products-config.php',
];
foreach ($required as $file) {
if (!is_file($file)) {
return false;
}
}
return true;
}
$resolved = false;
foreach ($pathCandidates as $paths) {
if (is_file($paths['includes'] . '/functions.php')) {
define('HEXAHOST_INCLUDES_DIR', $paths['includes']);
define('HEXAHOST_CONFIG_DIR', $paths['config']);
require_once $paths['includes'] . '/functions.php';
$resolved = true;
break;
foreach (hexahost_path_candidates() as $paths) {
if (!hexahost_is_app_root_valid($paths['includes'], $paths['config'])) {
continue;
}
define('HEXAHOST_INCLUDES_DIR', $paths['includes']);
define('HEXAHOST_CONFIG_DIR', $paths['config']);
require_once $paths['includes'] . '/functions.php';
$resolved = true;
break;
}
if (!$resolved) {
http_response_code(500);
header('Content-Type: text/plain; charset=utf-8');
echo 'HexaHost: Anwendung konnte nicht gestartet werden (includes nicht gefunden).';
header('Content-Type: text/html; charset=utf-8');
echo '<!DOCTYPE html><html lang="de"><head><meta charset="utf-8"><title>HexaHost</title></head><body>';
echo '<h1>HexaHost: Seite konnte nicht geladen werden</h1>';
echo '<p>PHP konnte die Anwendungsdateien nicht finden.</p>';
echo '<p><strong>Dev-Branch:</strong> Repository mit Ordner <code>backend/</code> neben <code>public/</code> deployen.</p>';
echo '<p><strong>Produktion:</strong> Vor dem Upload <code>scripts/sync-backend-to-public.ps1</code> ausführen ';
echo 'oder <code>backend/includes</code> und <code>backend/config</code> nach <code>public/</code> kopieren.</p>';
echo '</body></html>';
exit;
}

17
public/config/config.php Normal file
View File

@@ -0,0 +1,17 @@
<?php
/**
* HexaHost.de Konfiguration
*
* HINWEIS: Diese Datei ist veraltet!
*
* Die Konfiguration wurde nach mail-config.php verschoben.
* Bitte verwenden Sie stattdessen:
*
* require_once 'config/mail-config.php';
*
* Diese Datei wird nur aus Kompatibilitätsgründen beibehalten.
*/
// Lade die neue Konfiguration
require_once __DIR__ . '/mail-config.php';

View File

@@ -0,0 +1,197 @@
<?php
/**
* HexaHost.de Mail Configuration
*
* Bitte passen Sie die folgenden SMTP-Einstellungen an Ihre E-Mail-Provider an.
*
* Beispiele für gängige Provider:
*
* Gmail:
* - SMTP_HOST = 'smtp.gmail.com'
* - SMTP_PORT = 587
* - SMTP_USERNAME = 'ihre-email@gmail.com'
* - SMTP_PASSWORD = 'ihr-app-passwort'
*
* Outlook/Hotmail:
* - SMTP_HOST = 'smtp-mail.outlook.com'
* - SMTP_PORT = 587
*
* GMX:
* - SMTP_HOST = 'mail.gmx.net'
* - SMTP_PORT = 587
*
* Web.de:
* - SMTP_HOST = 'smtp.web.de'
* - SMTP_PORT = 587
*
* 1&1:
* - SMTP_HOST = 'smtp.1und1.de'
* - SMTP_PORT = 587
*
* Strato:
* - SMTP_HOST = 'smtp.strato.de'
* - SMTP_PORT = 587
*
* Ionos:
* - SMTP_HOST = 'smtp.ionos.de'
* - SMTP_PORT = 587
*/
// SMTP Server Einstellungen
define('SMTP_HOST', 'smtp.ihre-domain.de'); // Ihr SMTP-Server
define('SMTP_PORT', 587); // SMTP-Port (meist 587 oder 465)
define('SMTP_USERNAME', 'kontakt@ihre-domain.de'); // Ihr SMTP-Benutzername
define('SMTP_PASSWORD', 'ihr-smtp-passwort'); // Ihr SMTP-Passwort
// E-Mail Adressen
define('SMTP_FROM_EMAIL', 'kontakt@hexahost.de'); // Absender-E-Mail (muss zu SMTP_USERNAME passen)
define('SMTP_TO_EMAIL', 'info@hexahost.de'); // Empfänger-E-Mail für Kontaktformular
// Sicherheitseinstellungen
define('ENABLE_CSRF_PROTECTION', true); // CSRF-Schutz aktivieren
define('ENABLE_RATE_LIMITING', true); // Rate-Limiting aktivieren
define('MAX_REQUESTS_PER_HOUR', 10); // Max. Anfragen pro Stunde
// Spam-Schutz Einstellungen
define('ENABLE_SPAM_PROTECTION', true); // Spam-Schutz aktivieren
define('MAX_MESSAGE_LENGTH', 5000); // Max. Nachrichtenlänge
define('MIN_MESSAGE_LENGTH', 10); // Min. Nachrichtenlänge
// Debug-Einstellungen (nur für Entwicklung)
define('DEBUG_MODE', false); // Debug-Modus (true/false)
define('LOG_EMAILS', true); // E-Mails loggen (true/false)
// Zusätzliche Sicherheitsheader
define('ADDITIONAL_HEADERS', [
'X-Mailer' => 'HexaHost.de Contact Form',
'X-Priority' => '3',
'X-MSMail-Priority' => 'Normal',
'Importance' => 'Normal',
'X-Report-Abuse' => 'Please report abuse here: abuse@hexahost.de',
'List-Unsubscribe' => '<mailto:unsubscribe@hexahost.de>',
'Precedence' => 'bulk'
]);
// Erlaubte Domains für E-Mail-Adressen (optional)
define('ALLOWED_EMAIL_DOMAINS', [
// Leer lassen für alle Domains zu erlauben
// 'gmail.com',
// 'outlook.com',
// 'web.de',
// 'gmx.de'
]);
// Blacklist für E-Mail-Adressen (optional)
define('BLACKLISTED_EMAILS', [
// 'spam@example.com',
// 'test@test.com'
]);
// Validierung der Konfiguration
if (!defined('SMTP_HOST') || !defined('SMTP_USERNAME') || !defined('SMTP_PASSWORD')) {
die('SMTP-Konfiguration ist unvollständig. Bitte überprüfen Sie die mail-config.php');
}
// Überprüfung der E-Mail-Adressen
if (!filter_var(SMTP_FROM_EMAIL, FILTER_VALIDATE_EMAIL)) {
die('Ungültige SMTP_FROM_EMAIL Adresse');
}
if (!filter_var(SMTP_TO_EMAIL, FILTER_VALIDATE_EMAIL)) {
die('Ungültige SMTP_TO_EMAIL Adresse');
}
// Logging-Funktion
function logEmail($type, $data) {
if (!LOG_EMAILS) return;
$logFile = __DIR__ . '/../logs/email.log';
$logDir = dirname($logFile);
if (!is_dir($logDir)) {
mkdir($logDir, 0755, true);
}
$timestamp = date('Y-m-d H:i:s');
$logEntry = "[$timestamp] $type: " . json_encode($data) . "\n";
file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);
}
// Hilfsfunktion für E-Mail-Validierung
function isValidEmail($email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return false;
}
// Prüfe Blacklist
if (in_array($email, BLACKLISTED_EMAILS)) {
return false;
}
// Prüfe Domain-Whitelist (falls gesetzt)
if (!empty(ALLOWED_EMAIL_DOMAINS)) {
$domain = substr(strrchr($email, "@"), 1);
if (!in_array($domain, ALLOWED_EMAIL_DOMAINS)) {
return false;
}
}
return true;
}
// CSRF Token generieren (wird in functions.php verwendet)
// Hinweis: Diese Funktion existiert auch in functions.php - hier nur als Fallback
if (!function_exists('generateCSRFToken')) {
function generateCSRFToken() {
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
}
// CSRF Token validieren
if (!function_exists('validateCSRFToken')) {
function validateCSRFToken($token) {
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}
}
/**
* Hilfsfunktion zum Abrufen der Konfiguration als Array
* Kompatibilität mit contact-handler.php
*
* @param string|null $key Optional: einzelner Schlüssel
* @return mixed Konfigurationsarray oder einzelner Wert
*/
function getHexaHostConfig($key = null) {
$config = [
// SMTP Server-Einstellungen
'smtp_host' => SMTP_HOST,
'smtp_port' => SMTP_PORT,
'smtp_username' => SMTP_USERNAME,
'smtp_password' => SMTP_PASSWORD,
'smtp_encryption' => 'tls',
// Absender/Empfänger
'from_email' => SMTP_FROM_EMAIL,
'from_name' => 'HexaHost.de Kontaktformular',
'to_email' => SMTP_TO_EMAIL,
'to_name' => 'HexaHost Support',
// Sicherheit
'max_requests_per_hour' => MAX_REQUESTS_PER_HOUR,
'honeypot_field' => 'website',
// Debug
'debug_mode' => DEBUG_MODE,
'log_errors' => LOG_EMAILS,
];
if ($key === null) {
return $config;
}
return $config[$key] ?? null;
}

View File

@@ -0,0 +1,556 @@
<?php
/**
* HexaHost.de Produkt-Konfiguration
*
* Hier können Sie alle Preise und Produktinformationen zentral verwalten.
* Nach Änderungen: npm run build && npm run deploy
*
* Verwendung in PHP-Seiten:
* require_once 'config/products-config.php';
* $packages = getProductPackages('vpc');
*/
// Temporär ausgeblendete Produkte (einfach IDs aus dieser Liste entfernen, um sie wieder im Shop anzuzeigen)
$HIDDEN_PRODUCTS = ['vpc', 'vps'];
// ============================================================================
// VIRTUAL PRIVATE CONTAINER (VPC)
// ============================================================================
$PRODUCTS['vpc'] = [
'name' => 'Virtual Private Container',
'short_name' => 'VPC',
'description' => 'Effiziente LXC-Container auf Proxmox-Basis',
'min_price' => '4,99',
'hero_highlight' => 'auf Proxmox LXC',
'hero_description' => 'Erleben Sie die Effizienz von Linux-Containern mit der Zuverlässigkeit von Proxmox. Unsere VPC-Lösungen bieten optimale Performance bei minimalem Ressourcenverbrauch.',
'packages_title' => 'VPC Pakete',
'packages_description' => 'Wählen Sie das perfekte Container-Paket für Ihre Anforderungen',
'cta_title' => 'Bereit für Ihren VPC?',
'cta_description' => 'Starten Sie noch heute mit einem Virtual Private Container',
'page_title' => 'Virtual Private Container - Effiziente LXC Container | HexaHost.de',
'page_description' => 'Virtual Private Container auf Proxmox LXC-Basis. Effiziente und preiswerte Container-Lösungen ab 4,99€/Monat bei HexaHost.de',
'packages' => [
'starter' => [
'name' => 'VPC Starter',
'price' => '4,99',
'featured' => false,
'specs' => [
['label' => 'CPU Kerne', 'value' => '1 vCore'],
['label' => 'RAM', 'value' => '1 GB'],
['label' => 'SSD Speicher', 'value' => '20 GB'],
['label' => 'Traffic', 'value' => '1 TB'],
['label' => 'IPv4 Adressen', 'value' => '1'],
],
'features' => [
'Proxmox LXC Container',
'Root-Zugriff',
'SSH-Zugang',
'Backup inklusive',
'24/7 Monitoring',
],
],
'business' => [
'name' => 'VPC Business',
'price' => '9,99',
'featured' => true,
'specs' => [
['label' => 'CPU Kerne', 'value' => '2 vCores'],
['label' => 'RAM', 'value' => '4 GB'],
['label' => 'SSD Speicher', 'value' => '80 GB'],
['label' => 'Traffic', 'value' => '3 TB'],
['label' => 'IPv4 Adressen', 'value' => '1'],
],
'features' => [
'Proxmox LXC Container',
'Root-Zugriff',
'SSH-Zugang',
'Tägliches Backup',
'24/7 Monitoring',
'Snapshot-Funktion',
],
],
'professional' => [
'name' => 'VPC Professional',
'price' => '19,99',
'featured' => false,
'specs' => [
['label' => 'CPU Kerne', 'value' => '4 vCores'],
['label' => 'RAM', 'value' => '8 GB'],
['label' => 'SSD Speicher', 'value' => '160 GB'],
['label' => 'Traffic', 'value' => '5 TB'],
['label' => 'IPv4 Adressen', 'value' => '2'],
],
'features' => [
'Proxmox LXC Container',
'Root-Zugriff',
'SSH-Zugang',
'Stündliches Backup',
'24/7 Monitoring',
'Snapshot-Funktion',
'Priority Support',
],
],
'enterprise' => [
'name' => 'VPC Enterprise',
'price' => '39,99',
'featured' => false,
'specs' => [
['label' => 'CPU Kerne', 'value' => '8 vCores'],
['label' => 'RAM', 'value' => '16 GB'],
['label' => 'SSD Speicher', 'value' => '320 GB'],
['label' => 'Traffic', 'value' => '10 TB'],
['label' => 'IPv4 Adressen', 'value' => '3'],
],
'features' => [
'Proxmox LXC Container',
'Root-Zugriff',
'SSH-Zugang',
'Stündliches Backup',
'24/7 Monitoring',
'Snapshot-Funktion',
'Priority Support',
'Individuelle Konfiguration',
],
],
],
];
// ============================================================================
// VIRTUAL PRIVATE SERVER (VPS)
// ============================================================================
$PRODUCTS['vps'] = [
'name' => 'Virtual Private Server',
'short_name' => 'VPS',
'description' => 'Vollwertige KVM-Virtualisierung mit Root-Zugriff',
'min_price' => '9,99',
'hero_highlight' => 'auf Proxmox KVM',
'hero_description' => 'Maximale Flexibilität und Kontrolle mit vollwertiger KVM-Virtualisierung. Installieren Sie jedes Betriebssystem und genießen Sie vollständigen Root-Zugriff.',
'packages_title' => 'VPS Pakete',
'packages_description' => 'Wählen Sie das perfekte VPS-Paket für Ihre Anforderungen',
'cta_title' => 'Bereit für Ihren VPS?',
'cta_description' => 'Starten Sie noch heute mit einem Virtual Private Server',
'page_title' => 'Virtual Private Server - KVM Virtualisierung | HexaHost.de',
'page_description' => 'Virtual Private Server auf Proxmox KVM-Basis. Vollwertige Virtualisierung mit Root-Zugriff ab 9,99€/Monat bei HexaHost.de',
'packages' => [
'starter' => [
'name' => 'VPS Starter',
'price' => '9,99',
'featured' => false,
'specs' => [
['label' => 'CPU Kerne', 'value' => '1 vCore'],
['label' => 'RAM', 'value' => '2 GB'],
['label' => 'SSD Speicher', 'value' => '40 GB'],
['label' => 'Traffic', 'value' => '2 TB'],
['label' => 'IPv4 Adressen', 'value' => '1'],
],
'features' => [
'Proxmox KVM Virtualisierung',
'Root-Zugriff',
'SSH-Zugang',
'Backup inklusive',
'24/7 Monitoring',
],
],
'business' => [
'name' => 'VPS Business',
'price' => '19,99',
'featured' => true,
'specs' => [
['label' => 'CPU Kerne', 'value' => '2 vCores'],
['label' => 'RAM', 'value' => '4 GB'],
['label' => 'SSD Speicher', 'value' => '80 GB'],
['label' => 'Traffic', 'value' => '4 TB'],
['label' => 'IPv4 Adressen', 'value' => '1'],
],
'features' => [
'Proxmox KVM Virtualisierung',
'Root-Zugriff',
'SSH-Zugang',
'Tägliches Backup',
'24/7 Monitoring',
'Snapshot-Funktion',
],
],
'professional' => [
'name' => 'VPS Professional',
'price' => '39,99',
'featured' => false,
'specs' => [
['label' => 'CPU Kerne', 'value' => '4 vCores'],
['label' => 'RAM', 'value' => '8 GB'],
['label' => 'SSD Speicher', 'value' => '160 GB'],
['label' => 'Traffic', 'value' => '8 TB'],
['label' => 'IPv4 Adressen', 'value' => '2'],
],
'features' => [
'Proxmox KVM Virtualisierung',
'Root-Zugriff',
'SSH-Zugang',
'Stündliches Backup',
'24/7 Monitoring',
'Snapshot-Funktion',
'Priority Support',
],
],
'enterprise' => [
'name' => 'VPS Enterprise',
'price' => '79,99',
'featured' => false,
'specs' => [
['label' => 'CPU Kerne', 'value' => '8 vCores'],
['label' => 'RAM', 'value' => '16 GB'],
['label' => 'SSD Speicher', 'value' => '320 GB'],
['label' => 'Traffic', 'value' => '15 TB'],
['label' => 'IPv4 Adressen', 'value' => '3'],
],
'features' => [
'Proxmox KVM Virtualisierung',
'Root-Zugriff',
'SSH-Zugang',
'Stündliches Backup',
'24/7 Monitoring',
'Snapshot-Funktion',
'Priority Support',
'Individuelle Konfiguration',
],
],
],
];
// ============================================================================
// MAIL GATEWAY
// ============================================================================
$PRODUCTS['mail-gateway'] = [
'name' => 'Mail Gateway',
'short_name' => 'Mail',
'description' => 'Professioneller E-Mail-Schutz für Unternehmen',
'min_price' => '4,99',
'hero_highlight' => 'für Unternehmen',
'hero_description' => 'Professionelle E-Mail-Infrastruktur mit maximalem Schutz vor Spam und Malware. Sichern Sie Ihre geschäftliche Kommunikation mit unseren Mail Gateway Lösungen.',
'packages_title' => 'Mail Gateway Pakete',
'packages_description' => 'Wählen Sie das passende Mail Gateway Paket für Ihr Unternehmen',
'cta_title' => 'Bereit für professionelle E-Mail-Kommunikation?',
'cta_description' => 'Starten Sie noch heute mit unserem Mail Gateway',
'page_title' => 'Mail Gateway - Professionelle E-Mail-Lösungen | HexaHost.de',
'page_description' => 'Professionelle Mail Gateway Lösungen für Unternehmen. Spam-Schutz, E-Mail-Archivierung und sichere E-Mail-Kommunikation bei HexaHost.de',
'packages' => [
'starter' => [
'name' => 'Mail Starter',
'price' => '4,99',
'featured' => false,
'specs' => [
['label' => 'Postfächer', 'value' => '5'],
['label' => 'Speicher/Postfach', 'value' => '5 GB'],
['label' => 'Domains', 'value' => '1'],
['label' => 'E-Mails/Tag', 'value' => '500'],
],
'features' => [
'Spam-Filter',
'Virus-Schutz',
'Webmail',
'IMAP/POP3',
'SSL/TLS Verschlüsselung',
],
],
'business' => [
'name' => 'Mail Business',
'price' => '14,99',
'featured' => true,
'specs' => [
['label' => 'Postfächer', 'value' => '25'],
['label' => 'Speicher/Postfach', 'value' => '10 GB'],
['label' => 'Domains', 'value' => '3'],
['label' => 'E-Mails/Tag', 'value' => '2.000'],
],
'features' => [
'Spam-Filter (erweitert)',
'Virus-Schutz',
'Webmail',
'IMAP/POP3',
'SSL/TLS Verschlüsselung',
],
],
'professional' => [
'name' => 'Mail Professional',
'price' => '29,99',
'featured' => false,
'specs' => [
['label' => 'Postfächer', 'value' => '100'],
['label' => 'Speicher/Postfach', 'value' => '25 GB'],
['label' => 'Domains', 'value' => '10'],
['label' => 'E-Mails/Tag', 'value' => '10.000'],
],
'features' => [
'Spam-Filter (KI-gestützt)',
'Virus-Schutz',
'Webmail',
'IMAP/POP3',
'SSL/TLS Verschlüsselung',
],
],
'enterprise' => [
'name' => 'Mail Enterprise',
'price' => '59,99',
'featured' => false,
'specs' => [
['label' => 'Postfächer', 'value' => 'Unbegrenzt'],
['label' => 'Speicher/Postfach', 'value' => '50 GB'],
['label' => 'Domains', 'value' => 'Unbegrenzt'],
['label' => 'E-Mails/Tag', 'value' => 'Unbegrenzt'],
],
'features' => [
'Spam-Filter (KI-gestützt)',
'Virus-Schutz',
'Webmail',
'IMAP/POP3',
'SSL/TLS Verschlüsselung',
'Dedizierte IP',
'Priority Support',
],
],
],
];
// ============================================================================
// WEBHOSTING
// ============================================================================
$PRODUCTS['webhosting'] = [
'name' => 'Webhosting',
'short_name' => 'Webhosting',
'description' => 'Klassisches Hosting mit PHP, MySQL und SSL. WordPress-ready mit Plesk Webhosting.',
'min_price' => '2,99',
'hero_highlight' => 'Alles für Ihre Website',
'hero_description' => 'Klassisches Webhosting mit allem, was Sie für eine erfolgreiche Website benötigen. PHP, MySQL, SSL-Zertifikate und E-Mail-Postfächer - alles inklusive.',
'packages_title' => 'Webhosting Pakete',
'packages_description' => 'Von der ersten Website bis zum professionellen Online-Shop',
'cta_title' => 'Bereit für Ihr Webhosting?',
'cta_description' => 'Starten Sie noch heute mit professionellem Webhosting',
'page_title' => 'Webhosting - Klassisches Hosting für Websites - WordPress-ready | HexaHost.de',
'page_description' => 'Webhosting mit PHP, MySQL und SSL-Zertifikaten. Klassisches Hosting für Websites - WordPress-ready ab 2,99€/Monat bei HexaHost.de',
'packages' => [
'starter' => [
'name' => 'Webhosting Starter',
'price' => '2,99',
'featured' => false,
'specs' => [
['label' => 'Webspace', 'value' => '10 GB'],
['label' => 'Domains', 'value' => '1'],
['label' => 'Subdomains', 'value' => '5'],
['label' => 'Domain Aliase', 'value' => '2'],
['label' => 'E-Mail-Postfächer', 'value' => '10'],
['label' => 'Datenbanken', 'value' => '2 MySQL'],
['label' => 'Traffic', 'value' => '100 GB'],
],
'features' => [
'Plesk Webhosting',
'PHP 8.4',
'Git, WP Toolkit, Composer',
'SSL-Zertifikat',
'E-Mail-Postfächer',
'MySQL Datenbanken',
],
],
'business' => [
'name' => 'Webhosting Business',
'price' => '7,99',
'featured' => true,
'specs' => [
['label' => 'Webspace', 'value' => '30 GB'],
['label' => 'Domains Inkl.', 'value' => '1'],
['label' => 'Subdomains', 'value' => '10'],
['label' => 'Domain Aliase', 'value' => '2'],
['label' => 'E-Mail-Postfächer', 'value' => '20'],
['label' => 'Datenbanken', 'value' => '5 MySQL'],
['label' => 'Traffic', 'value' => '100 GB'],
],
'features' => [
'Plesk Webhosting',
'PHP 8.4',
'Git, WP Toolkit, Composer',
'SSL-Zertifikat',
'E-Mail-Postfächer',
'MySQL Datenbanken',
'Backup-Service',
],
],
'professional' => [
'name' => 'Webhosting Professional',
'price' => '13,99',
'featured' => false,
'specs' => [
['label' => 'Webspace', 'value' => '50 GB'],
['label' => 'Domains Inkl.', 'value' => '1'],
['label' => 'Subdomains', 'value' => 'unbegrenzt'],
['label' => 'Domain Aliase', 'value' => 'unbegrenzt'],
['label' => 'E-Mail-Postfächer', 'value' => '20'],
['label' => 'Datenbanken', 'value' => '20 MySQL'],
['label' => 'Traffic', 'value' => '100 GB'],
],
'features' => [
'Plesk Webhosting',
'PHP 8.4',
'Git, WP Toolkit, Composer',
'SSL-Zertifikat',
'E-Mail-Postfächer',
'MySQL Datenbanken',
'Backup-Service',
'Priority Support',
],
],
'enterprise' => [
'name' => 'Webhosting Enterprise',
'price' => '19,99',
'featured' => false,
'specs' => [
['label' => 'Webspace', 'value' => '100 GB'],
['label' => 'Domains Inkl.', 'value' => '3'],
['label' => 'Subdomains', 'value' => 'unbegrenzt'],
['label' => 'Domain Aliase', 'value' => 'unbegrenzt'],
['label' => 'E-Mail-Postfächer', 'value' => '100'],
['label' => 'Datenbanken', 'value' => 'Unbegrenzt'],
['label' => 'Traffic', 'value' => '1 TB'],
],
'features' => [
'Plesk Webhosting',
'PHP 8.4',
'Git, WP Toolkit, Composer',
'SSL-Zertifikat',
'E-Mail-Postfächer',
'MySQL Datenbanken',
'Backup-Service',
'Priority Support',
'Individuelle Konfiguration',
],
],
],
];
// ============================================================================
// HILFSFUNKTIONEN
// ============================================================================
/**
* Alle Produkte abrufen
*/
function getAllProducts() {
global $PRODUCTS;
return $PRODUCTS;
}
/**
* Ein Produkt abrufen
*/
function getProduct($productId) {
global $PRODUCTS;
return $PRODUCTS[$productId] ?? null;
}
/**
* Prüft, ob ein Produkt im Shop angezeigt werden soll
*/
function isProductVisible($productId) {
global $HIDDEN_PRODUCTS;
return !in_array($productId, $HIDDEN_PRODUCTS, true);
}
/**
* Alle Pakete eines Produkts abrufen
*/
function getProductPackages($productId) {
global $PRODUCTS;
return $PRODUCTS[$productId]['packages'] ?? [];
}
/**
* Ein bestimmtes Paket abrufen
*/
function getPackage($productId, $packageId) {
global $PRODUCTS;
return $PRODUCTS[$productId]['packages'][$packageId] ?? null;
}
/**
* Preis eines Pakets abrufen
*/
function getPackagePrice($productId, $packageId) {
$package = getPackage($productId, $packageId);
return $package['price'] ?? null;
}
/**
* Minimalen Preis eines Produkts abrufen
*/
function getMinPrice($productId) {
global $PRODUCTS;
return $PRODUCTS[$productId]['min_price'] ?? null;
}
/**
* Preis formatiert ausgeben
*/
function formatPrice($price, $withCurrency = true) {
return $withCurrency ? $price . '€' : $price;
}
/**
* Generiert HTML für eine Paket-Karte
*/
function renderPackageCard($productId, $packageId, $package) {
$featuredClass = $package['featured'] ? ' featured' : '';
$featuredBadge = $package['featured'] ? '<div class="featured-badge">Beliebt</div>' : '';
$specsHtml = '';
foreach ($package['specs'] as $spec) {
$specsHtml .= sprintf(
'<div class="spec-item"><span class="spec-label">%s:</span><span class="spec-value">%s</span></div>',
htmlspecialchars($spec['label']),
htmlspecialchars($spec['value'])
);
}
$featuresHtml = '';
foreach ($package['features'] as $feature) {
$featuresHtml .= sprintf('<div class="feature">✓ %s</div>', htmlspecialchars($feature));
}
return sprintf('
<div class="package-card glass-card%s">
%s
<div class="package-header">
<h3 class="package-name">%s</h3>
<div class="package-price">
<span class="price">%s€</span>
<span class="period">/Monat</span>
</div>
</div>
<div class="package-specs">
%s
</div>
<div class="package-features">
%s
</div>
<a href="contact.php?package=%s-%s" class="btn btn-primary">Jetzt bestellen</a>
</div>',
$featuredClass,
$featuredBadge,
htmlspecialchars($package['name']),
$package['price'],
$specsHtml,
$featuresHtml,
$productId,
$packageId
);
}
/**
* Generiert HTML für alle Pakete eines Produkts
*/
function renderAllPackages($productId) {
$packages = getProductPackages($productId);
$html = '';
foreach ($packages as $packageId => $package) {
$html .= renderPackageCard($productId, $packageId, $package);
}
return $html;
}

View File

@@ -0,0 +1,81 @@
<?php
/**
* HexaHost.de zentrale Domain- und Umgebungskonfiguration
*/
if (!defined('SITE_DOMAIN_PRODUCTION')) {
define('SITE_DOMAIN_PRODUCTION', 'hexahost.de');
}
if (!defined('SITE_DOMAIN_DEVELOPMENT')) {
define('SITE_DOMAIN_DEVELOPMENT', 'dev.hexahost.de');
}
/**
* Aktuellen HTTP-Host (ohne Port) ermitteln
*
* @return string
*/
function getSiteHost()
{
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : SITE_DOMAIN_PRODUCTION;
$host = strtolower($host);
if (strpos($host, ':') !== false) {
$host = explode(':', $host, 2)[0];
}
return $host;
}
/**
* true, wenn die Seite unter der Dev-Domain läuft
*
* @return bool
*/
function isDevelopmentSite()
{
return getSiteHost() === SITE_DOMAIN_DEVELOPMENT;
}
/**
* Basis-URL der aktuellen Anfrage (Schema + Host)
*
* @return string
*/
function getSiteBaseUrl()
{
$https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| (isset($_SERVER['SERVER_PORT']) && (int) $_SERVER['SERVER_PORT'] === 443);
$scheme = $https ? 'https' : 'http';
return $scheme . '://' . getSiteHost();
}
/**
* Erlaubte CORS-Origins für AJAX (Kontaktformular)
*
* @return array<int, string>
*/
function getAllowedOrigins()
{
return [
'https://' . SITE_DOMAIN_PRODUCTION,
'https://www.' . SITE_DOMAIN_PRODUCTION,
'https://' . SITE_DOMAIN_DEVELOPMENT,
'http://localhost',
'http://127.0.0.1',
'http://localhost:8000',
];
}
/**
* Kanonische Basis-URL für SEO (Produktion immer hexahost.de)
*
* @return string
*/
function getCanonicalBaseUrl()
{
return 'https://' . SITE_DOMAIN_PRODUCTION;
}

167
public/includes/footer.php Normal file
View File

@@ -0,0 +1,167 @@
<footer class="footer">
<div class="container">
<div class="footer-content">
<div class="footer-section">
<h4>HexaHost.de</h4>
<p>Zuverlässiges Hosting aus Niederbayern</p>
<div class="footer-location">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/>
<circle cx="12" cy="10" r="3"/>
</svg>
<span>Niederbayern, Deutschland</span>
</div>
</div>
<div class="footer-section">
<h4>Produkte</h4>
<ul>
<li><a href="/vpc">Virtual Private Container</a></li>
<li><a href="/vps">Virtual Private Server</a></li>
<li><a href="/mail-gateway">Mail Gateway</a></li>
<li><a href="/webhosting">Webhosting</a></li>
</ul>
</div>
<div class="footer-section">
<h4>Unternehmen</h4>
<ul>
<li><a href="/about">Über mich</a></li>
<li><a href="/contact">Kontakt</a></li>
<li><a href="/impressum">Impressum</a></li>
<li><a href="/datenschutz">Datenschutz</a></li>
<li><a href="/agb">AGB</a></li>
<li><a href="/widerruf">Widerrufsbelehrung</a></li>
<li><a href="#" id="openCookieSettings" onclick="CookieConsent.resetConsent(); return false;">Cookie-Einstellungen</a></li>
</ul>
</div>
<div class="footer-section">
<h4>Support</h4>
<ul>
<li><a href="https://shop.hexahost.de/clientarea.php">Kunden-Center</a></li>
<li><a href="https://shop.hexahost.de/serverstatus.php">Status</a></li>
<li><a href="https://shop.hexahost.de/supporttickets.php">Support-Ticket</a></li>
<li><a href="#">FAQ</a></li>
</ul>
</div>
</div>
<div class="footer-bottom">
<p>&copy; <?php echo date('Y'); ?> HexaHost.de - Alle Rechte vorbehalten</p>
</div>
</div>
</footer>
<!-- Cookie Consent Banner -->
<div id="cookieConsent" class="cookie-consent" role="dialog" aria-labelledby="cookieConsentTitle" aria-describedby="cookieConsentDesc">
<div class="cookie-consent-container">
<div class="cookie-consent-content">
<div class="cookie-consent-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<circle cx="8" cy="9" r="1" fill="currentColor"/>
<circle cx="15" cy="8" r="1" fill="currentColor"/>
<circle cx="10" cy="14" r="1" fill="currentColor"/>
<circle cx="16" cy="13" r="1" fill="currentColor"/>
<circle cx="13" cy="17" r="1" fill="currentColor"/>
</svg>
</div>
<div class="cookie-consent-text">
<h3 id="cookieConsentTitle">Cookie-Einstellungen</h3>
<p id="cookieConsentDesc">
Wir verwenden Cookies, um Ihnen die bestmögliche Erfahrung auf unserer Website zu bieten.
Technisch notwendige Cookies sind für die Funktionalität erforderlich.
<a href="/datenschutz">Mehr erfahren</a>
</p>
</div>
</div>
<div class="cookie-consent-actions">
<button type="button" id="cookieAcceptAll" class="btn btn-primary">Alle akzeptieren</button>
<button type="button" id="cookieAcceptEssential" class="btn btn-secondary">Nur notwendige</button>
<button type="button" id="cookieSettings" class="btn btn-text">Einstellungen</button>
</div>
</div>
<!-- Erweiterte Cookie-Einstellungen (standardmäßig versteckt) -->
<div id="cookieSettingsPanel" class="cookie-settings-panel" style="display: none;">
<div class="cookie-settings-content">
<h4>Cookie-Einstellungen</h4>
<div class="cookie-option">
<div class="cookie-option-info">
<strong>Notwendige Cookies</strong>
<p>Diese Cookies sind für die Grundfunktionen der Website erforderlich.</p>
</div>
<label class="cookie-toggle disabled">
<input type="checkbox" checked disabled>
<span class="cookie-toggle-slider"></span>
</label>
</div>
<div class="cookie-option">
<div class="cookie-option-info">
<strong>Analyse-Cookies</strong>
<p>Helfen uns zu verstehen, wie Besucher unsere Website nutzen.</p>
</div>
<label class="cookie-toggle">
<input type="checkbox" id="cookieAnalytics">
<span class="cookie-toggle-slider"></span>
</label>
</div>
<div class="cookie-option">
<div class="cookie-option-info">
<strong>Marketing-Cookies</strong>
<p>Werden verwendet, um relevante Werbung anzuzeigen.</p>
</div>
<label class="cookie-toggle">
<input type="checkbox" id="cookieMarketing">
<span class="cookie-toggle-slider"></span>
</label>
</div>
<div class="cookie-settings-actions">
<button type="button" id="cookieSaveSettings" class="btn btn-primary">Einstellungen speichern</button>
<button type="button" id="cookieCloseSettings" class="btn btn-secondary">Abbrechen</button>
</div>
</div>
</div>
</div>
<!-- Google Analytics (GA4) mit Consent Mode -->
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// Standard: keine Analyse/Marketing-Cookies bis zur Einwilligung
gtag('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied'
});
gtag('js', new Date());
gtag('config', 'G-EF0E9VPMTD', {
anonymize_ip: true
});
// Übergibt Consent-Änderungen aus dem eigenen Cookie-Banner an GA
window.addEventListener('cookieConsentUpdated', function (event) {
var payload = event && event.detail ? event.detail : {};
var consent = payload.consent ? payload.consent : payload;
var analyticsGranted = !!(consent && consent.analytics);
var marketingGranted = !!(consent && consent.marketing);
gtag('consent', 'update', {
analytics_storage: analyticsGranted ? 'granted' : 'denied',
ad_storage: marketingGranted ? 'granted' : 'denied',
ad_user_data: marketingGranted ? 'granted' : 'denied',
ad_personalization: marketingGranted ? 'granted' : 'denied'
});
});
</script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-EF0E9VPMTD"></script>
<script src="/assets/js/main.js" defer></script>
<script src="/assets/js/cookie-consent.js" defer></script>
<?php if (isset($additional_scripts)): ?>
<?php foreach ($additional_scripts as $script): ?>
<script src="<?php echo $script; ?>" defer></script>
<?php endforeach; ?>
<?php endif; ?>
</body>
</html>

View File

@@ -0,0 +1,163 @@
<?php
/**
* Helper functions for HexaHost.de
*/
$configDir = defined('HEXAHOST_CONFIG_DIR')
? HEXAHOST_CONFIG_DIR
: __DIR__ . '/../config';
$siteConfigFile = $configDir . '/site-config.php';
if (is_file($siteConfigFile)) {
require_once $siteConfigFile;
} elseif (!function_exists('getSiteHost')) {
define('SITE_DOMAIN_PRODUCTION', 'hexahost.de');
define('SITE_DOMAIN_DEVELOPMENT', 'dev.hexahost.de');
function getSiteHost()
{
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : SITE_DOMAIN_PRODUCTION;
$host = strtolower($host);
if (strpos($host, ':') !== false) {
$host = explode(':', $host, 2)[0];
}
return $host;
}
function isDevelopmentSite()
{
return getSiteHost() === SITE_DOMAIN_DEVELOPMENT;
}
function getSiteBaseUrl()
{
$https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| (isset($_SERVER['SERVER_PORT']) && (int) $_SERVER['SERVER_PORT'] === 443);
return ($https ? 'https' : 'http') . '://' . getSiteHost();
}
function getAllowedOrigins()
{
return [
'https://' . SITE_DOMAIN_PRODUCTION,
'https://www.' . SITE_DOMAIN_PRODUCTION,
'https://' . SITE_DOMAIN_DEVELOPMENT,
'http://localhost',
'http://127.0.0.1',
'http://localhost:8000',
];
}
function getCanonicalBaseUrl()
{
return 'https://' . SITE_DOMAIN_PRODUCTION;
}
}
// Fehleranzeige auf Dev/localhost für einfacheres Debugging
$hexahostHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
if (
(function_exists('isDevelopmentSite') && isDevelopmentSite())
|| preg_match('/^(localhost|127\.0\.0\.1)(:\d+)?$/', $hexahostHost)
) {
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
}
// Sichere Session-Konfiguration
if (session_status() === PHP_SESSION_NONE) {
// Session-Cookie-Sicherheit
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', isset($_SERVER['HTTPS']) ? 1 : 0);
ini_set('session.cookie_samesite', 'Strict');
ini_set('session.use_strict_mode', 1);
ini_set('session.use_only_cookies', 1);
session_start();
// Session-ID regenerieren bei Login/wichtigen Aktionen (Schutz vor Session Fixation)
if (!isset($_SESSION['initiated'])) {
session_regenerate_id(true);
$_SESSION['initiated'] = true;
}
}
// PHP Error Display in Produktion deaktivieren
if (!defined('DEBUG_MODE') || !DEBUG_MODE) {
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
error_reporting(E_ALL);
ini_set('log_errors', 1);
}
/**
* Set page configuration and include header
*
* @param string $title The page title
* @param string $description The page description
* @param string $page The current page identifier
* @param array $scripts Additional scripts to include
*/
function includeHeader($title = '', $description = '', $page = '', $scripts = []) {
global $page_title, $page_description, $current_page, $additional_scripts;
// Set page configuration from parameters
$page_title = !empty($title)
? $title
: 'HexaHost.de - Zuverlässiges Hosting aus Niederbayern';
$page_description = !empty($description)
? $description
: 'HexaHost.de - Zuverlässiges und preiswertes Hosting aus Niederbayern. VPS, VPC, Mail Gateway und Webhosting Lösungen.';
$current_page = $page;
$additional_scripts = $scripts;
if (!isset($canonical_url)) {
$requestPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
$canonical_url = rtrim(getCanonicalBaseUrl(), '/') . $requestPath;
}
include __DIR__ . '/header.php';
}
/**
* Include footer
*/
function includeFooter() {
include __DIR__ . '/footer.php';
}
/**
* Generate breadcrumb navigation
*
* @param array $breadcrumbs Array of breadcrumb items [['title' => 'Home', 'url' => 'index.html'], ...]
*/
function generateBreadcrumbs($breadcrumbs) {
echo '<div class="breadcrumb">';
$last_index = count($breadcrumbs) - 1;
foreach ($breadcrumbs as $index => $item) {
if ($index === $last_index) {
// Last item (current page)
echo '<span>' . htmlspecialchars($item['title']) . '</span>';
} else {
// Link to other pages
echo '<a href="' . htmlspecialchars($item['url']) . '">' . htmlspecialchars($item['title']) . '</a>';
echo '<span>/</span>';
}
}
echo '</div>';
}
/**
* Generate CSRF token for form security
*
* @return string CSRF token
*/
function generateCSRFToken() {
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}

View File

@@ -0,0 +1,89 @@
<!DOCTYPE html>
<?php
$configDir = defined('HEXAHOST_CONFIG_DIR') ? HEXAHOST_CONFIG_DIR : __DIR__ . '/../config';
require_once $configDir . '/products-config.php';
?>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Performance: DNS Prefetch & Preconnect -->
<link rel="dns-prefetch" href="//fonts.googleapis.com">
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link rel="dns-prefetch" href="//cdn.hexahost.de">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preconnect" href="https://cdn.hexahost.de" crossorigin>
<!-- Performance: Preload kritischer Ressourcen -->
<link rel="preload" href="/assets/css/style.css" as="style">
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" as="style">
<title><?php echo isset($page_title) ? htmlspecialchars($page_title) : 'HexaHost.de - Zuverlässiges Hosting aus Niederbayern'; ?></title>
<!-- SEO Meta Tags -->
<meta name="description" content="<?php echo isset($page_description) ? htmlspecialchars($page_description) : 'HexaHost.de - Zuverlässiges und preiswertes Hosting aus Niederbayern. VPS, VPC, Mail Gateway und Webhosting Lösungen.'; ?>">
<meta name="robots" content="index, follow">
<meta name="author" content="HexaHost.de">
<meta name="theme-color" content="#0d0821">
<!-- Open Graph / Social Media -->
<meta property="og:type" content="website">
<meta property="og:site_name" content="HexaHost.de">
<meta property="og:title" content="<?php echo isset($page_title) ? htmlspecialchars($page_title) : 'HexaHost.de'; ?>">
<meta property="og:description" content="<?php echo isset($page_description) ? htmlspecialchars($page_description) : 'Zuverlässiges Hosting aus Niederbayern'; ?>">
<meta property="og:locale" content="de_DE">
<!-- Main Stylesheets -->
<link rel="stylesheet" href="/assets/css/style.css">
<link rel="stylesheet" href="/assets/css/custom.css">
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Russo+One&family=Source+Sans+Pro:wght@300;400;600;700&display=swap" rel="stylesheet">
<!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="apple-touch-icon" href="/favicon.svg">
<!-- Canonical URL (falls gesetzt) -->
<?php if (isset($canonical_url)): ?>
<link rel="canonical" href="<?php echo htmlspecialchars($canonical_url); ?>">
<?php endif; ?>
</head>
<body>
<header class="header">
<nav class="nav">
<div class="nav-container">
<div class="nav-logo">
<a href="/">
<img src="https://cdn.hexahost.de/assets/img/logo/8iFs123BynHQWHI5.png" alt="HexaHost.de Logo" class="logo-image">
</a>
</div>
<ul class="nav-menu">
<li><a href="/" class="nav-link <?php echo ($current_page === 'home') ? 'active' : ''; ?>">Home</a></li>
<li class="nav-dropdown">
<a href="#" class="nav-link <?php echo (in_array($current_page, ['vpc', 'vps', 'mail-gateway', 'webhosting'])) ? 'active' : ''; ?>">Produkte</a>
<ul class="dropdown-menu">
<?php if (isProductVisible('vpc')): ?>
<li><a href="/vpc" class="<?php echo ($current_page === 'vpc') ? 'active' : ''; ?>">Virtual Private Container</a></li>
<?php endif; ?>
<?php if (isProductVisible('vps')): ?>
<li><a href="/vps" class="<?php echo ($current_page === 'vps') ? 'active' : ''; ?>">Virtual Private Server</a></li>
<?php endif; ?>
<li><a href="/mail-gateway" class="<?php echo ($current_page === 'mail-gateway') ? 'active' : ''; ?>">Mail Gateway</a></li>
<li><a href="/webhosting" class="<?php echo ($current_page === 'webhosting') ? 'active' : ''; ?>">Webhosting</a></li>
</ul>
</li>
<li><a href="/it-dienstleistungen" class="nav-link <?php echo ($current_page === 'it-dienstleistungen') ? 'active' : ''; ?>">IT-Dienstleistungen</a></li>
<li><a href="/about" class="nav-link <?php echo ($current_page === 'about') ? 'active' : ''; ?>">Über mich</a></li>
<li><a href="/contact" class="nav-link <?php echo ($current_page === 'contact') ? 'active' : ''; ?>">Kontakt</a></li>
</ul>
<div class="nav-toggle">
<span></span>
<span></span>
<span></span>
</div>
</div>
</nav>
</header>

View File

@@ -0,0 +1,23 @@
# Kopiert Backend-Includes und -Config nach public/ (für Produktions-Deploy)
$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $PSScriptRoot
$includesSrc = Join-Path $root 'backend\includes'
$configSrc = Join-Path $root 'backend\config'
$includesDst = Join-Path $root 'public\includes'
$configDst = Join-Path $root 'public\config'
if (-not (Test-Path $includesSrc)) {
throw "Backend-Includes nicht gefunden: $includesSrc"
}
if (-not (Test-Path $configSrc)) {
throw "Backend-Config nicht gefunden: $configSrc"
}
New-Item -ItemType Directory -Force -Path $includesDst | Out-Null
New-Item -ItemType Directory -Force -Path $configDst | Out-Null
Copy-Item -Path (Join-Path $includesSrc '*') -Destination $includesDst -Recurse -Force
Copy-Item -Path (Join-Path $configSrc '*') -Destination $configDst -Recurse -Force
Write-Host "OK: backend -> public/includes und public/config synchronisiert."