diff --git a/src/.htaccess b/src/.htaccess
new file mode 100644
index 0000000..afb951a
--- /dev/null
+++ b/src/.htaccess
@@ -0,0 +1,5 @@
+Options -Indexes
+AddDefaultCharset UTF-8
+
+RewriteEngine On
+
diff --git a/src/.vscode/sftp.json b/src/.vscode/sftp.json
new file mode 100644
index 0000000..7ac08e6
--- /dev/null
+++ b/src/.vscode/sftp.json
@@ -0,0 +1,12 @@
+{
+ "name": "Mein Webserver",
+ "host": "192.168.178.88",
+ "protocol": "sftp",
+ "port": 22,
+ "username": "root",
+ "password": "934290",
+ "remotePath": "/var/www/html/",
+ "uploadOnSave": true,
+ "useTempFile": false,
+ "openSsh": false
+}
diff --git a/src/admin/bands.php b/src/admin/bands.php
new file mode 100644
index 0000000..418f339
--- /dev/null
+++ b/src/admin/bands.php
@@ -0,0 +1,48 @@
+
+
+
+
+ ';
+
+ // Navigation
+ $output .= '
';
+ $output .= '◀ ';
+ $output .= '
' . $this->monthNames[$currentMonth]['de'] . ' ' . $currentYear . ' ';
+ $output .= '▶ ';
+ $output .= '';
+
+ // Kalender-Grid
+ $output .= '
';
+
+ // Wochentage Header
+ $weekdays = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
+ foreach ($weekdays as $day) {
+ $output .= '
' . $day . '
';
+ }
+
+ // Tage des Monats
+ $firstDay = mktime(0, 0, 0, $currentMonth, 1, $currentYear);
+ $daysInMonth = date('t', $firstDay);
+ $dayOfWeek = date('N', $firstDay) - 1; // 0 = Montag
+
+ // Leere Zellen vor dem ersten Tag
+ for ($i = 0; $i < $dayOfWeek; $i++) {
+ $output .= '
';
+ }
+
+ // Tage mit Videos markieren
+ for ($day = 1; $day <= $daysInMonth; $day++) {
+ $hasVideos = $this->hasVideosForDate($currentYear, $currentMonth, $day);
+ $isSelected = ($selectedDay == $day);
+ $isToday = ($currentYear == date('Y') && $currentMonth == date('n') && $day == date('j'));
+
+ $classes = 'calendar-day';
+ if ($hasVideos) $classes .= ' has-video';
+ if ($isSelected) $classes .= ' selected';
+ if ($isToday) $classes .= ' today';
+
+ $output .= '
';
+ $output .= '' . $day . ' ';
+ if ($hasVideos) {
+ $output .= '📹 ';
+ }
+ $output .= '
';
+ }
+
+ $output .= '
'; // calendar-grid
+
+ // Video-Liste für ausgewählten Tag
+ if ($selectedDay) {
+ $videos = $this->getVideosForDate($currentYear, $currentMonth, $selectedDay);
+ if (!empty($videos)) {
+ $output .= '
';
+ $output .= '
Videos vom ' . sprintf('%02d.%02d.%04d', $selectedDay, $currentMonth, $currentYear) . ' ';
+ $output .= '
';
+
+ foreach ($videos as $video) {
+ $sizeInMb = round($video['filesize'] / (1024 * 1024), 2);
+ $token = hash_hmac('sha256', $video['path'], session_id());
+
+ $output .= '';
+ $output .= '🕐 ' . $video['time'] . ' Uhr ';
+ $output .= '' . $sizeInMb . ' MB ';
+ $output .= '';
+ $output .= '⬇️ Download';
+ $output .= ' ';
+ $output .= ' ';
+ }
+
+ $output .= ' ';
+ $output .= '
';
+ } else {
+ $output .= '
Keine Videos für diesen Tag verfügbar.
';
+ }
+ }
+
+ $output .= '
'; // visual-calendar-container
+
+ return $output;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class GuestbookManager {
+ private $entries = [];
+ private $dbFile = 'guestbook.json';
+
+ public function __construct() {
+ if (file_exists($this->dbFile)) {
+ $this->entries = json_decode(file_get_contents($this->dbFile), true);
+ }
+ }
+
+ public function handleFormSubmission() {
+ if (isset($_POST['guestbook'], $_POST['guest-name'], $_POST['guest-message'])) {
+ $this->addEntry($_POST['guest-name'], $_POST['guest-message']);
+ $this->saveEntries();
+ }
+ }
+
+ private function addEntry($name, $message) {
+ $this->entries[] = [
+ 'name' => $name,
+ 'message' => $message,
+ 'date' => date('Y-m-d H:i:s')
+ ];
+ }
+
+ public function deleteEntry($index) {
+ if (isset($this->entries[$index])) {
+ unset($this->entries[$index]);
+ $this->entries = array_values($this->entries); // Re-indizieren des Arrays
+ $this->saveEntries();
+ return true;
+ }
+ return false;
+ }
+
+
+
+ private function saveEntries() {
+ file_put_contents($this->dbFile, json_encode($this->entries));
+ }
+
+ public function displayForm() {
+ return '
+ ';
+ foreach ($this->entries as $index => $entry) {
+ $output .= "
+
+
{$entry['name']}
+
{$entry['message']}
+
{$entry['date']}";
+ if ($isAdmin) {
+ $output .= "
";
+ }
+
+ }
+ $output .= '
';
+ return $output;
+}
+
+
+}
+
+
+class ContactManager {
+ //private $adminEmail = 'ingo.kohler.zh@gmail.com'; // ← Empfänger
+ private $adminEmail = 'metacube@gmail.com'; // ← Empfänger
+ private $feedbackFile = 'feedbacks.json';
+ private $gmailUser = 'metacube@gmail.com'; // ← DEINE GMAIL-ADRESSE
+ private $gmailAppPassword = 'qggk hsxz fdkq jgxa'; // ← APP-PASSWORT VON GMAIL
+
+ public function displayForm() {
+ return '
+
+
';
+ }
+
+ public function handleSubmission($name, $email, $message) {
+ // Validierung
+ if (empty($name) || empty($email) || empty($message)) {
+ return [
+ 'success' => false,
+ 'message' => 'Alle Felder sind erforderlich'
+ ];
+ }
+
+ if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ return [
+ 'success' => false,
+ 'message' => 'Ungültige E-Mail-Adresse'
+ ];
+ }
+
+ if (strlen($message) < 10) {
+ return [
+ 'success' => false,
+ 'message' => 'Nachricht zu kurz (mindestens 10 Zeichen)'
+ ];
+ }
+
+ // Sanitize
+ $name = htmlspecialchars(trim($name), ENT_QUOTES, 'UTF-8');
+ $email = filter_var(trim($email), FILTER_SANITIZE_EMAIL);
+ $message = htmlspecialchars(trim($message), ENT_QUOTES, 'UTF-8');
+
+ // Feedback speichern
+ $feedback = [
+ 'name' => $name,
+ 'email' => $email,
+ 'message' => $message,
+ 'date' => date('Y-m-d H:i:s'),
+ 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
+ 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown'
+ ];
+
+ $feedbacks = file_exists($this->feedbackFile)
+ ? json_decode(file_get_contents($this->feedbackFile), true)
+ : [];
+
+ if (!is_array($feedbacks)) {
+ $feedbacks = [];
+ }
+
+ $feedbacks[] = $feedback;
+ file_put_contents($this->feedbackFile, json_encode($feedbacks, JSON_PRETTY_PRINT));
+
+ // E-MAIL SENDEN MIT GMAIL SMTP
+ $mailSent = $this->sendEmailViaGmail($name, $email, $message, $feedback['date'], $feedback['ip']);
+
+ if ($mailSent) {
+ return [
+ 'success' => true,
+ 'message' => 'Vielen Dank! Ihre Nachricht wurde gesendet.'
+ ];
+ } else {
+ error_log("Mail-Fehler: Nachricht von {$email} konnte nicht gesendet werden");
+ return [
+ 'success' => false,
+ 'message' => 'Nachricht wurde gespeichert, aber E-Mail konnte nicht gesendet werden.'
+ ];
+ }
+ }
+
+ private function sendEmailViaGmail($name, $email, $message, $date, $ip) {
+ $mail = new PHPMailer(true);
+
+
+ try {
+ // DEBUG-MODUS AKTIVIEREN
+ $mail->SMTPDebug = 2;
+ $mail->Debugoutput = function($str, $level) {
+ error_log("PHPMailer Debug: $str");
+ };
+
+ // SMTP Konfiguration
+ $mail->isSMTP();
+ $mail->Host = 'smtp.gmail.com';
+ $mail->SMTPAuth = true;
+ $mail->Username = $this->gmailUser; // metacube@gmail.com
+ $mail->Password = $this->gmailAppPassword; // qggk hsxz fdkq jgxa
+ $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
+ $mail->Port = 587;
+
+
+
+
+ // Absender & Empfänger
+ $mail->setFrom($this->gmailUser, 'Aurora Livecam');
+ $mail->addAddress($this->adminEmail); // admin@aurora-live-weathercam.com
+ $mail->addReplyTo($email, $name);
+
+ // Inhalt
+ $mail->isHTML(true);
+ $mail->CharSet = 'UTF-8';
+ $mail->Subject = '🔔 Neue Kontaktanfrage von ' . $name;
+ $mail->Body = $this->getEmailTemplate($name, $email, $message, $date, $ip);
+
+ $mail->send();
+ return true;
+ } catch (Exception $e) {
+ error_log("PHPMailer Error: {$mail->ErrorInfo}");
+ return false;
+ }
+ }
+
+ private function getEmailTemplate($name, $email, $message, $date, $ip) {
+ return "
+
+
+
+
+
+
+
+
+
+
+
+
+ 👤 Name:
+ {$name}
+
+
+
+
+
+ 💬 Nachricht:
+
+
+
+ " . nl2br($message) . "
+
+
+
+
+
+
+
+
+
+ ";
+ }
+}
+
+class AdminManager {
+ public function isAdmin() {
+ return isset($_SESSION['admin']) && $_SESSION['admin'] === true;
+ }
+ public function handleLogin($username, $password) {
+ echo "Login-Versuch: Username = $username, Passwort = $password"; // Debugging
+ if ($username === 'admin' && $password === 'sonne4000$$$$Q') {
+ $_SESSION['admin'] = true;
+ return true;
+ }
+ return false;
+ }
+
+ public function handleImageUpload($file) {
+ if (!$this->isAdmin()) {
+ return false; // Nur Admins dürfen Bilder hochladen
+ }
+
+ if (!isset($file['tmp_name']) || empty($file['tmp_name'])) {
+ echo "Keine Datei hochgeladen.";
+ return false;
+ }
+
+ $target_dir = "uploads/";
+ if (!file_exists($target_dir)) {
+ mkdir($target_dir, 0777, true);
+ }
+
+ $target_file = $target_dir . basename($file["name"]);
+ $uploadOk = 1;
+ $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
+
+
+ $check = @getimagesize($file["tmp_name"]);
+ if($check === false) {
+ echo "Die Datei ist kein Bild.";
+ return false;
+ }
+
+
+ if ($file["size"] > 5000000) { // 5MB Limit
+ echo "Die Datei ist zu groß.";
+ return false;
+ }
+
+ // Erlauben Sie nur bestimmte Dateiformate
+ if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
+ && $imageFileType != "gif" ) {
+ echo "Nur JPG, JPEG, PNG & GIF Dateien sind erlaubt.";
+ return false;
+ }
+
+ // Wenn alles in Ordnung ist, versuchen Sie, die Datei hochzuladen
+ if (move_uploaded_file($file["tmp_name"], $target_file)) {
+ echo "Die Datei ". basename( $file["name"]). " wurde hochgeladen.";
+ return true;
+ } else {
+ echo "Es gab einen Fehler beim Hochladen der Datei.";
+ return false;
+ }
+ }
+
+
+ public function displayLoginForm() {
+ return '
+
+
+ Benutzername:
+
+ Passwort:
+
+ Einloggen
+ ';
+ }
+
+ public function displayAdminContent() {
+ $feedbacks = json_decode(file_get_contents('feedbacks.json') ?: '[]', true);
+ $output = '
Admin-Bereich ';
+ foreach ($feedbacks as $feedback) {
+ $output .= "
";
+ $output .= "
{$feedback['name']} ({$feedback['email']}) ";
+ $output .= "
{$feedback['message']}
";
+ $output .= "
{$feedback['date']} ";
+ $output .= "
";
+ }
+ $output .= '
';
+
+ $output .= '
+
Social Media Links verwalten
+
+
+
+ Facebook
+ Instagram
+ TikTok
+
+
+ Aktualisieren
+ ';
+ $output .= '
+
Bild hochladen
+
+
+
+ ';
+ return $output;
+ }
+
+ public function displayGalleryImages() {
+ $output = '
';
+ $files = glob("uploads/*.*");
+ foreach($files as $file) {
+ $filename = basename($file);
+ $extension = pathinfo($file, PATHINFO_EXTENSION);
+
+ // NUR Bilddateien anzeigen, KEINE Videos
+ if (in_array(strtolower($extension), ['jpg', 'jpeg', 'png', 'gif'])) {
+ $output .= '
';
+ }
+ }
+ $output .= '
';
+ return $output;
+}
+
+
+
+
+ public function handleSocialMediaUpdate($platform, $url) {
+ $socialLinks = json_decode(file_get_contents('social_links.json') ?: '{}', true);
+ $socialLinks[$platform] = $url;
+ file_put_contents('social_links.json', json_encode($socialLinks));
+ }
+}
+
+
+
+// Weather Bingo Manager
+//require_once 'weather_bingo.php';
+//$weatherBingo = new WeatherBingo();
+
+
+
+
+
+
+// Neue VideoArchiveManager Klasse
+
+
+class VideoArchiveManager {
+ private $videoDir;
+ private $monthNames;
+
+ public function __construct($videoDir = './videos/') {
+ $this->videoDir = $videoDir;
+ $this->monthNames = [
+ '01' => 'Januar',
+ '02' => 'Februar',
+ '03' => 'März',
+ '04' => 'April',
+ '05' => 'Mai',
+ '06' => 'Juni',
+ '07' => 'Juli',
+ '08' => 'August',
+ '09' => 'September',
+ '10' => 'Oktober',
+ '11' => 'November',
+ '12' => 'Dezember'
+ ];
+ }
+
+ public function getVideosGroupedByDate() {
+ $videos = [];
+
+ foreach (glob($this->videoDir . 'daily_video_*.mp4') as $video) {
+ // Dateinamenformat: daily_video_YYYYMMDD_HHMMSS.mp4
+ if (preg_match('/daily_video_(\d{8})_\d{6}\.mp4/', basename($video), $matches)) {
+ $dateStr = $matches[1]; // YYYYMMDD
+ $year = substr($dateStr, 0, 4);
+ $month = substr($dateStr, 4, 2);
+ $day = substr($dateStr, 6, 2);
+
+ // Gruppiere nach Jahr und Monat
+ $videos[$year][$month][] = [
+ 'path' => $video,
+ 'filename' => basename($video),
+ 'day' => $day,
+ 'filesize' => filesize($video),
+ 'modified' => filemtime($video)
+ ];
+ }
+ }
+
+ // Nach Tag sortieren
+ foreach ($videos as $year => $months) {
+ foreach ($months as $month => $days) {
+ usort($videos[$year][$month], function($a, $b) {
+ return $b['day'] - $a['day']; // Absteigend sortieren (neueste zuerst)
+ });
+ }
+ }
+
+ return $videos;
+ }
+
+ public function getAvailableYearsAndMonths() {
+ $videos = $this->getVideosGroupedByDate();
+ $result = [];
+
+ foreach ($videos as $year => $months) {
+ $result[$year] = array_keys($months);
+ }
+
+ return $result;
+ }
+
+ public function getVideosForYearAndMonth($year, $month) {
+ $videos = $this->getVideosGroupedByDate();
+ return isset($videos[$year][$month]) ? $videos[$year][$month] : [];
+ }
+
+ public function displayCalendarInterface() {
+ $yearsAndMonths = $this->getAvailableYearsAndMonths();
+
+ $output = '
';
+ $output .= '
Video-Archiv ';
+
+ if (empty($yearsAndMonths)) {
+ $output .= '
Keine Videos verfügbar.
';
+ } else {
+ $output .= '
';
+ $output .= '
';
+
+ // Jahr-Auswahl
+ $output .= 'Jahr: ';
+ $output .= '';
+
+ foreach ($yearsAndMonths as $year => $months) {
+ $selected = (isset($_GET['calendar_year']) && $_GET['calendar_year'] == $year) ? 'selected' : '';
+ $output .= "$year ";
+ }
+
+ $output .= ' ';
+
+ // Monats-Auswahl
+ $output .= 'Monat: ';
+ $output .= '';
+
+ // Wenn ein Jahr ausgewählt wurde, zeige die verfügbaren Monate
+ if (isset($_GET['calendar_year']) && isset($yearsAndMonths[$_GET['calendar_year']])) {
+ foreach ($yearsAndMonths[$_GET['calendar_year']] as $month) {
+ $selected = (isset($_GET['calendar_month']) && $_GET['calendar_month'] == $month) ? 'selected' : '';
+ $output .= "{$this->monthNames[$month]} ";
+ }
+ }
+
+ $output .= ' ';
+ $output .= 'Anzeigen ';
+ $output .= ' ';
+ $output .= '';
+
+ // Wenn Jahr und Monat ausgewählt wurden, zeige die Videos
+ if (isset($_GET['calendar_year']) && isset($_GET['calendar_month'])) {
+ $year = $_GET['calendar_year'];
+ $month = $_GET['calendar_month'];
+ $videos = $this->getVideosForYearAndMonth($year, $month);
+
+ if (!empty($videos)) {
+ $output .= '
';
+ $output .= "
Videos für {$this->monthNames[$month]} $year ";
+ $output .= '
';
+ $output .= '
';
+ } else {
+ $output .= "
Keine Videos für {$this->monthNames[$month]} $year gefunden.
";
+ }
+ }
+ }
+
+ $output .= '
';
+ return $output;
+ }
+
+ public function handleSpecificVideoDownload() {
+ if (isset($_GET['download_specific_video']) && isset($_GET['token'])) {
+ $videoPath = $_GET['download_specific_video'];
+ $token = $_GET['token'];
+
+ // Token-Validierung
+ $expectedToken = hash_hmac('sha256', $videoPath, session_id());
+ if (!hash_equals($expectedToken, $token)) {
+ echo "Ungültiger Token. Zugriff verweigert.";
+ exit;
+ }
+
+ // Sicherheitsüberprüfung: Stelle sicher, dass das Video im erlaubten Verzeichnis liegt
+ $videoDir = realpath($this->videoDir);
+ $requestedPath = realpath($videoPath);
+
+ if ($requestedPath && strpos($requestedPath, $videoDir) === 0 && file_exists($requestedPath)) {
+ // Nur MP4-Dateien erlauben
+ $extension = pathinfo($requestedPath, PATHINFO_EXTENSION);
+ if (strtolower($extension) !== 'mp4') {
+ echo "Nur MP4-Dateien können heruntergeladen werden.";
+ exit;
+ }
+
+ header('Content-Description: File Transfer');
+ header('Content-Type: video/mp4');
+ header('Content-Disposition: attachment; filename="'.basename($requestedPath).'"');
+ header('Expires: 0');
+ header('Cache-Control: must-revalidate');
+ header('Pragma: public');
+ header('Content-Length: ' . filesize($requestedPath));
+ readfile($requestedPath);
+ exit;
+ } else {
+ echo "Datei nicht gefunden oder ungültiger Dateipfad.";
+ exit;
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+$webcamManager = new WebcamManager();
+$imageFilesJson = $webcamManager->getImageFiles();
+$guestbookManager = new GuestbookManager();
+$contactManager = new ContactManager();
+$adminManager = new AdminManager();
+
+// Nach den anderen Manager-Instanzen hinzufügen
+$videoArchiveManager = new VideoArchiveManager('./videos/');
+
+// Video-Download-Handler nach dem existierenden Download-Handler hinzufügen
+$videoArchiveManager->handleSpecificVideoDownload();
+
+
+if (isset($_GET['action'])) {
+ switch ($_GET['action']) {
+ case 'snapshot':
+ $webcamManager->captureSnapshot();
+
+ break;
+ case 'sequence':
+ $webcamManager->captureVideoSequence();
+
+ break;
+
+ }
+
+}
+
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'delete_guestbook') {
+ if ($adminManager->isAdmin() && isset($_POST['delete_entry'])) {
+ $index = $_POST['delete_entry'];
+ if ($guestbookManager->deleteEntry($index)) {
+ $_SESSION['message'] = "Eintrag erfolgreich gelöscht.";
+ } else {
+ $_SESSION['error'] = "Fehler beim Löschen des Eintrags.";
+ }
+ // Umleitung zur gleichen Seite, um Neuladen des Formulars zu verhindern
+ header("Location: " . $_SERVER['PHP_SELF'] . "#guestbook");
+ exit();
+ }
+}
+
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ if (isset($_POST['guestbook'])) {
+ $guestbookManager->handleFormSubmission();
+ } elseif (isset($_POST['contact'])) {
+ $result = $contactManager->handleSubmission($_POST['name'], $_POST['email'], $_POST['message']);
+
+ // JSON-Response für AJAX
+ if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
+ strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
+ header('Content-Type: application/json');
+ echo json_encode($result);
+ exit;
+ }
+
+ // Normale Formular-Submission
+ $_SESSION['contact_result'] = $result;
+ header('Location: ' . $_SERVER['PHP_SELF'] . '#kontakt');
+ exit;
+
+ } elseif (isset($_POST['admin-login'])) {
+ $adminManager->handleLogin($_POST['username'], $_POST['password']);
+ } elseif (isset($_POST['update-social-media'])) {
+ $adminManager->handleSocialMediaUpdate($_POST['social-platform'], $_POST['social-url']);
+
+
+ } elseif (isset($_FILES["fileToUpload"]) && $adminManager->isAdmin()) {
+ $adminManager->handleImageUpload($_FILES["fileToUpload"]);
+}}
+?>
+
+
+
+
+
+
+
+
+
+
Aurora Livecam - Einzigartige Live-Webcam und Wetter>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Willkommen bei Aurora Wetter Livecam
+
+
+
+
+
+
+ Erleben Sie faszinierende Ausblicke der Züricher Region - in Echtzeit!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ displayWebcam(); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Videoarchiv Tagesvideos
+
+ displayVisualCalendar();
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+