'UniFi Voucher System', 'logo_url' => '', 'favicon_url' => '', 'public_access' => '1', 'smtp_enabled' => '1', 'sms_enabled' => '1', 'm365_enabled' => '1', 'oidc_enabled' => '0', 'oidc_name' => 'Keycloak', 'default_expire_minutes' => '480', 'default_max_uses' => '2', 'max_uses_limit' => '10', 'instruction_header' => 'So verbinden Sie sich', 'instruction_text' => 'WLAN „Gast-WiFi" wählen, Code eingeben und bestätigen. Bei Fragen hilft der Empfang gerne weiter.', 'last_cron_sync' => '2026-09-22 14:35:00', 'session_driver' => 'db', 'captcha_mode' => 'math', 'enforce_2fa_admins' => '1', 'user_daily_voucher_limit' => '25', 'webhook_enabled' => '1', 'webhook_url' => 'https://hooks.slack.com/services/T024/B0197/XYZ', 'twilio_sid' => 'AC8f2c1d94e77b40a2', 'twilio_from' => '+4915112345678', 'trusted_proxy' => '10.0.0.1, 172.18.0.1', 'cleanup_expired_days' => '90', 'cleanup_audit_days' => '365', 'cleanup_login_days' => '30', 'last_cleanup' => '2026-09-22 03:00:00', ]; public function __construct() { // Screenshot-Varianten: ?brand=custom|gradient|nopanel $brand = $_GET['brand'] ?? ''; if ($brand === 'custom') { $this->settings = array_merge($this->settings, [ 'app_title' => 'Hotel Seeblick', 'login_brand_name' => 'Hotel Seeblick', 'login_logo_url' => '/demo-assets/logo.svg', 'login_claim_title' => 'Willkommen im Hotel Seeblick.', 'login_claim_text' => 'Gäste-WLAN für Zimmer, Tagungsräume und Restaurant – Zugangscodes direkt an der Rezeption erstellen.', 'login_features' => "Code direkt beim Check-in ausdrucken\nTagungsgäste per E-Mail versorgen\nAuswertung je Haus und Etage", 'login_footer' => '© 2026 Hotel Seeblick GmbH · Datenschutz · Impressum', 'login_bg_image' => '/demo-assets/background.svg', 'login_bg_overlay' => '45', 'brand_accent' => '#0f766e', 'brand_accent_dark' => '#2dd4bf', 'brand_gradient_from' => '#0f766e', 'brand_gradient_to' => '#0ea5e9', ]); } elseif ($brand === 'nopanel') { $this->settings = array_merge($this->settings, [ 'login_panel_enabled' => '0', 'login_brand_name' => 'Stadtwerke Nordheim', ]); } } public static function getInstance() { return self::$instance ??= new self(); } public function getConnection() { return null; } public function getSetting($key, $default = null) { return $this->settings[$key] ?? $default; } public function setSetting($key, $value) { $this->settings[$key] = $value; } public function execute($sql, $params = []) { return 1; } public function query($sql, $params = []) { return new DemoStmt(); } public function fetchOne($sql, $params = []) { $r = $this->fetchAll($sql, $params); return $r[0] ?? false; } public function fetchAll($sql, $params = []) { $s = preg_replace('/\s+/', ' ', strtolower($sql)); if (str_contains($s, 'from kiosks')) { return [ ['id'=>1,'site_id'=>1,'template_id'=>1,'name'=>'Empfang Erdgeschoss','token'=>'a1b2c3d4e5f60718293a4b5c6d7e8f90', 'headline'=>'Willkommen im Hotel Seeblick','subline'=>'Tippen Sie auf den Knopf – Ihr WLAN-Code erscheint sofort.', 'logo_url'=>'/demo-assets/logo.svg','background_url'=>'/demo-assets/background.svg', 'bg_overlay'=>55,'accent_color'=>'#0f766e','card_style'=>'dark', 'is_active'=>1,'daily_limit'=>150,'cooldown_seconds'=>15,'display_seconds'=>90,'last_used_at'=>null, 'site_name'=>'Hauptstandort Nord','site_active'=>1,'template_name'=>'Tagesgast', 'tpl_max_uses'=>2,'tpl_expire_minutes'=>480,'qos_rate_max_down'=>20000,'qos_rate_max_up'=>5000,'qos_usage_quota'=>0, 'total_vouchers'=>412,'today_vouchers'=>23,'created_at'=>'2026-06-01 10:00:00'], ['id'=>2,'site_id'=>2,'template_id'=>null,'name'=>'Tagungsraum West','token'=>'0f1e2d3c4b5a69788796a5b4c3d2e1f0', 'headline'=>'','subline'=>'','logo_url'=>null,'background_url'=>null,'bg_overlay'=>45, 'accent_color'=>null,'card_style'=>'light', 'is_active'=>1,'daily_limit'=>0,'cooldown_seconds'=>30,'display_seconds'=>60, 'last_used_at'=>null,'site_name'=>'Campus West','site_active'=>1,'template_name'=>null, 'tpl_max_uses'=>0,'tpl_expire_minutes'=>0,'qos_rate_max_down'=>0,'qos_rate_max_up'=>0,'qos_usage_quota'=>0, 'total_vouchers'=>87,'today_vouchers'=>4,'created_at'=>'2026-07-12 09:30:00'], ]; } if (str_contains($s, 'count(*) as count from sites')) return [['count'=>4]]; if (str_contains($s, 'count(*) as count from users')) return [['count'=>12]]; if (str_contains($s, 'count(*) as count from vouchers where date(created_at)=curdate()')) return [['count'=>18]]; if (str_contains($s, 'count(*) as count from vouchers where date(created_at)=')) { $day = $params[0] ?? ''; $map = [6,9,5,12,8,4,7,14,11,16,9,6,13,18]; $idx = abs((int)((strtotime($day) - strtotime('today')) / 86400)); return [['count' => $map[13 - min($idx, 13)]]]; } if (str_contains($s, 'from vouchers where site_id=?') && str_contains($s, 'count(*) as total')) { $per = [1=>['total'=>128,'valid'=>74,'used'=>39,'expired'=>15], 2=>['total'=>63,'valid'=>41,'used'=>18,'expired'=>4], 3=>['total'=>22,'valid'=>14,'used'=>6,'expired'=>2], 4=>['total'=>0,'valid'=>0,'used'=>0,'expired'=>0]]; return [$per[(int)($params[0] ?? 1)] ?? $per[4]]; } if (str_contains($s, 'count(*) as total') && str_contains($s, 'from vouchers')) { return [['total'=>213,'valid'=>129,'used'=>63,'expired'=>21]]; } if (str_contains($s, 'from sites')) { return [ ['id'=>1,'name'=>'Hauptstandort Nord','site_id'=>'default','unifi_controller_url'=>'https://unifi.example.com:8443','unifi_username'=>'voucher-api','unifi_password'=>'x','is_active'=>1,'use_ssl'=>1,'created_at'=>'2026-01-12 09:00:00'], ['id'=>2,'name'=>'Campus West','site_id'=>'campus-west','unifi_controller_url'=>'https://unifi.example.com:8443','unifi_username'=>'voucher-api','unifi_password'=>'x','is_active'=>1,'use_ssl'=>1,'created_at'=>'2026-02-03 11:30:00'], ['id'=>3,'name'=>'Showroom Berlin','site_id'=>'showroom','unifi_controller_url'=>'https://unifi-b.example.com:8443','unifi_username'=>'voucher-api','unifi_password'=>'x','is_active'=>1,'use_ssl'=>1,'created_at'=>'2026-04-21 15:10:00'], ['id'=>4,'name'=>'Lager Süd','site_id'=>'lager','unifi_controller_url'=>'https://unifi-s.example.com:8443','unifi_username'=>'voucher-api','unifi_password'=>'x','is_active'=>1,'use_ssl'=>0,'created_at'=>'2026-06-08 08:45:00'], ]; } if (str_contains($s, 'count(v.id) as voucher_count') || str_contains($s, 'from users u left join vouchers')) { return [ ['name'=>'Marie Sander','email'=>'marie.sander@example.com','voucher_count'=>48,'c'=>48], ['name'=>'Jonas Weber','email'=>'j.weber@example.com','voucher_count'=>31,'c'=>31], ['name'=>'Alina Brandt','email'=>'alina.brandt@example.com','voucher_count'=>27,'c'=>27], ['name'=>'Tim Kurz','email'=>'tim.kurz@example.com','voucher_count'=>19,'c'=>19], ['name'=>'Sara Vogt','email'=>'sara.vogt@example.com','voucher_count'=>12,'c'=>12], ]; } if (str_contains($s, 'from vouchers')) { if (str_contains($s, 'group by date')) { $out = []; $vals = [6,9,5,12,8,4,7,14,11,16,9,6,13,18]; foreach ($vals as $i => $c) { $out[] = ['date'=>date('d.m', strtotime('-'.(13-$i).' days')), 'count'=>$c]; } return $out; } $codes = [['H7K2-M9QF',1,'Hauptstandort Nord','valid'],['P3RT-8ZXC',2,'Campus West','used'], ['QW4E-7TYU',1,'Hauptstandort Nord','valid'],['LM2N-5BVD',3,'Showroom Berlin','expired'], ['ZX9C-3PLO',2,'Campus West','valid'],['FG6H-1JKL',1,'Hauptstandort Nord','used']]; $names = ['Besuch Agentur Nordlicht','Workshop Raum 2','Empfang Tagesgast','Messe-Stand','Handwerker Haustechnik','Bewerbungsgespräch']; $out = []; foreach ($codes as $i => [$c,$sid,$sname,$st]) { $out[] = ['id'=>$i+1,'voucher_code'=>$c,'site_id'=>$sid,'site_name'=>$sname,'user_name'=>'Marie Sander', 'status'=>$st,'created_at'=>date('Y-m-d H:i:s', strtotime("-{$i} hours")), 'voucher_name'=>$names[$i],'unifi_voucher_id'=>'65f1a'.$i, 'expires_at'=>date('Y-m-d H:i:s', strtotime('+'.(8-$i).' hours')), 'max_uses'=>[2,5,1,3,2,1][$i],'used_count'=>[2,1,0,3,0,1][$i],'expire_minutes'=>480]; } return $out; } if (str_contains($s, 'from users')) { return [ ['id'=>1,'name'=>'Marie Sander','email'=>'marie.sander@example.com','is_admin'=>1,'is_active'=>1,'created_at'=>'2026-01-10 09:00:00','last_login'=>'2026-09-22 08:12:00','totp_enabled'=>1,'auth_source'=>'local','voucher_count'=>48,'password_hash'=>'x'], ['id'=>2,'name'=>'Jonas Weber','email'=>'j.weber@example.com','is_admin'=>0,'is_active'=>1,'created_at'=>'2026-03-02 13:20:00','last_login'=>'2026-09-21 17:40:00','totp_enabled'=>0,'auth_source'=>'m365','voucher_count'=>31,'password_hash'=>''], ['id'=>3,'name'=>'Alina Brandt','email'=>'alina.brandt@example.com','is_admin'=>0,'is_active'=>1,'created_at'=>'2026-05-18 10:05:00','last_login'=>'2026-09-20 09:31:00','totp_enabled'=>1,'auth_source'=>'local','voucher_count'=>27,'password_hash'=>'x'], ]; } if (str_contains($s, 'from api_keys')) { return [ ['id'=>1,'name'=>'Buchungssystem','key_prefix'=>'3f9a2c','scope'=>'write','rate_limit'=>60,'is_active'=>1,'last_used_at'=>'2026-09-22 09:12:00','creator'=>'Marie Sander','created_at'=>'2026-06-01 10:00:00'], ['id'=>2,'name'=>'Terminal Foyer','key_prefix'=>'b71e04','scope'=>'read','rate_limit'=>0,'is_active'=>1,'last_used_at'=>'2026-09-21 17:40:00','creator'=>'Marie Sander','created_at'=>'2026-07-14 16:20:00'], ['id'=>3,'name'=>'Altes Kassensystem','key_prefix'=>'c0d5f8','scope'=>'write','rate_limit'=>30,'is_active'=>0,'last_used_at'=>null,'creator'=>'Jonas Weber','created_at'=>'2026-02-09 08:05:00'], ]; } if (str_contains($s, 'from audit_log')) { if (str_contains($s, 'count(')) return [['total'=>1284,'c'=>1284,'count'=>1284]]; if (str_contains($s, 'distinct action')) { return [['action'=>'voucher_created'],['action'=>'user_login'],['action'=>'settings_saved'],['action'=>'user_created'],['action'=>'template_updated']]; } $rows = [['2026-09-22 14:32:00','Marie Sander','voucher_created','Hauptstandort Nord · H7K2-M9QF','192.168.10.42'], ['2026-09-22 13:58:00','Jonas Weber','user_login','Microsoft 365','83.112.4.17'], ['2026-09-22 11:04:00','Marie Sander','settings_saved','Tab: E-Mail (SMTP)','192.168.10.42'], ['2026-09-21 17:40:00','Alina Brandt','user_created','tim.kurz@example.com','192.168.10.88'], ['2026-09-21 09:12:00','Marie Sander','template_updated','Tagesgast','192.168.10.42'], ['2026-09-20 16:03:00','Jonas Weber','voucher_bulk','5 Vouchers · Campus West','83.112.4.17']]; $out = []; foreach ($rows as $i => [$d,$u,$a,$det,$ip]) { $out[] = ['id'=>$i+1,'created_at'=>$d,'user_name'=>$u,'user_email'=>'demo@example.com','action'=>$a,'details'=>$det,'ip_address'=>$ip,'entity_type'=>'voucher','entity_id'=>$i+1]; } return $out; } if (str_contains($s, 'templates')) { return [ ['id'=>1,'name'=>'Tagesgast','description'=>'Standardprofil für Besucher am Empfang','max_uses'=>2,'expire_minutes'=>480,'qos_rate_max_down'=>20000,'qos_rate_max_up'=>5000,'qos_usage_quota'=>0,'is_active'=>1,'is_default'=>1,'created_at'=>'2026-01-15 10:00:00'], ['id'=>2,'name'=>'Konferenz','description'=>'Mehrtägige Veranstaltungen','max_uses'=>5,'expire_minutes'=>4320,'qos_rate_max_down'=>50000,'qos_rate_max_up'=>10000,'qos_usage_quota'=>0,'is_active'=>1,'is_default'=>0,'created_at'=>'2026-02-20 11:30:00'], ['id'=>3,'name'=>'Handwerker','description'=>'Kurzzugang für Dienstleister','max_uses'=>1,'expire_minutes'=>240,'qos_rate_max_down'=>10000,'qos_rate_max_up'=>2000,'qos_usage_quota'=>1024,'is_active'=>1,'is_default'=>0,'created_at'=>'2026-03-08 09:15:00'], ]; } return []; } } class DemoStmt { public function fetch($m = null) { return false; } public function fetchAll($m = null) { return []; } public function rowCount() { return 1; } public function execute($p = []) { return true; } }