Place Holder for missing Images
This commit is contained in:
145
admin.php
145
admin.php
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
// admin.php - Multi-User Login, Google Authenticator 2FA & News Verwaltung
|
||||
// admin.php - Multi-User Login, Google Authenticator 2FA, Cropper, News Verwaltung & AES-256 VERSCHLÜSSELUNG
|
||||
session_start();
|
||||
|
||||
// Fehleranzeige (für Live-Betrieb auf 0 setzen)
|
||||
// Fehleranzeige (für Live-Betrieb auf 0 setzen - oder anlassen, wenn du Schmerzen magst)
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
@@ -13,6 +13,7 @@ error_reporting(E_ALL);
|
||||
class MiniTOTP {
|
||||
public static function verify($secret, $code) {
|
||||
$time = floor(time() / 30);
|
||||
// Prüft aktuelles, vorheriges und nächstes Zeitfenster (Toleranz)
|
||||
for ($i = -1; $i <= 1; $i++) {
|
||||
if (self::getCode($secret, $time + $i) === $code) return true;
|
||||
}
|
||||
@@ -156,43 +157,41 @@ if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
|
||||
// ============================================================================
|
||||
$message = "";
|
||||
|
||||
// --- NEU: Bild-Upload Funktion ---
|
||||
// --- BILD-UPLOAD FUNKTION (mit Base64 Crop-Unterstützung) ---
|
||||
function handleImageUpload() {
|
||||
if (isset($_FILES['image_file']) && $_FILES['image_file']['error'] === UPLOAD_ERR_OK) {
|
||||
if (!empty($_POST['cropped_image_data'])) {
|
||||
$data = $_POST['cropped_image_data'];
|
||||
list($type, $data) = explode(';', $data);
|
||||
list(, $data) = explode(',', $data);
|
||||
$data = base64_decode($data);
|
||||
|
||||
$year = date('Y');
|
||||
// Ordnerstruktur: img/news/YYYY (wird automatisch erstellt, falls nicht vorhanden)
|
||||
$upload_dir = __DIR__ . '/img/news/' . $year;
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
mkdir($upload_dir, 0777, true); // Erstellt den Ordner, wenn er fehlt
|
||||
}
|
||||
|
||||
$ext = strtolower(pathinfo($_FILES['image_file']['name'], PATHINFO_EXTENSION));
|
||||
$allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
$filename = date('Ymd') . '_' . rand(10000, 99999) . '.jpg';
|
||||
$target_file = $upload_dir . '/' . $filename;
|
||||
|
||||
if (in_array($ext, $allowed)) {
|
||||
// Format: YYYYMMDD_randomnummer.format
|
||||
$filename = date('Ymd') . '_' . rand(10000, 99999) . '.' . $ext;
|
||||
$target_file = $upload_dir . '/' . $filename;
|
||||
|
||||
if (move_uploaded_file($_FILES['image_file']['tmp_name'], $target_file)) {
|
||||
// Gib den relativen Pfad für die Datenbank zurück
|
||||
return 'img/news/' . $year . '/' . $filename;
|
||||
}
|
||||
if (file_put_contents($target_file, $data)) {
|
||||
return 'img/news/' . $year . '/' . $filename;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Aktion: News aktualisieren (EDIT)
|
||||
// --- AKTION: NEWS AKTUALISIEREN (EDIT) ---
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_news'])) {
|
||||
$final_image_path = $_POST['existing_image']; // Standard: Altes Bild behalten
|
||||
$final_image_path = $_POST['existing_image'];
|
||||
|
||||
$uploaded_img = handleImageUpload();
|
||||
if ($uploaded_img) {
|
||||
$final_image_path = $uploaded_img; // Neues Upload-Bild nutzen
|
||||
} elseif (isset($_POST['image_url'])) {
|
||||
// Link korrigieren, falls manuell etwas eingetragen wurde
|
||||
$final_image_path = $uploaded_img;
|
||||
} elseif (isset($_POST['image_url']) && !empty($_POST['image_url'])) {
|
||||
$final_image_path = str_replace(['http://new.sg07-stleon.de/', 'https://new.sg07-stleon.de/', 'new.sg07-stleon.de/', 'new.sg07-stleon.de\\'], '', trim($_POST['image_url']));
|
||||
} elseif (isset($_POST['placeholder_image']) && !empty($_POST['placeholder_image'])) {
|
||||
$final_image_path = $_POST['placeholder_image'];
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("UPDATE news SET date=?, department=?, title=?, content=?, full_text=?, image=?, link=? WHERE id=?");
|
||||
@@ -201,15 +200,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_news'])) {
|
||||
}
|
||||
}
|
||||
|
||||
// Aktion: News speichern (NEU ERSTELLEN)
|
||||
// --- AKTION: NEWS SPEICHERN (NEU) ---
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_news'])) {
|
||||
$final_image_path = '';
|
||||
|
||||
$uploaded_img = handleImageUpload();
|
||||
if ($uploaded_img) {
|
||||
$final_image_path = $uploaded_img;
|
||||
} else {
|
||||
$final_image_path = str_replace(['http://new.sg07-stleon.de/', 'https://new.sg07-stleon.de/', 'new.sg07-stleon.de/', 'new.sg07-stleon.de\\'], '', trim($_POST['image_url'] ?? ''));
|
||||
} elseif (isset($_POST['image_url']) && !empty($_POST['image_url'])) {
|
||||
$final_image_path = str_replace(['http://new.sg07-stleon.de/', 'https://new.sg07-stleon.de/', 'new.sg07-stleon.de/', 'new.sg07-stleon.de\\'], '', trim($_POST['image_url']));
|
||||
} elseif (isset($_POST['placeholder_image']) && !empty($_POST['placeholder_image'])) {
|
||||
$final_image_path = $_POST['placeholder_image'];
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("INSERT INTO news (date, department, title, content, full_text, image, link) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||
@@ -218,7 +219,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_news'])) {
|
||||
}
|
||||
}
|
||||
|
||||
// Aktion: News löschen
|
||||
// --- AKTION: NEWS LÖSCHEN ---
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_news'])) {
|
||||
$stmt = $db->prepare("DELETE FROM news WHERE id = ?");
|
||||
if ($stmt->execute([$_POST['delete_id']])) {
|
||||
@@ -226,7 +227,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_news'])) {
|
||||
}
|
||||
}
|
||||
|
||||
// Aktion: Neuen Benutzer anlegen
|
||||
// --- AKTION: NEUEN BENUTZER ANLEGEN ---
|
||||
$new_user_qr = "";
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_user'])) {
|
||||
$new_user = trim($_POST['new_username']);
|
||||
@@ -243,17 +244,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_user'])) {
|
||||
}
|
||||
}
|
||||
|
||||
// Edit-Modus prüfen (Ist ein Klick auf "Ändern" erfolgt?)
|
||||
// Edit-Modus prüfen
|
||||
$is_edit = false;
|
||||
$edit_news = null;
|
||||
if (isset($_GET['edit_id'])) {
|
||||
$stmt = $db->prepare("SELECT * FROM news WHERE id = ?");
|
||||
$stmt->execute([$_GET['edit_id']]);
|
||||
$edit_news = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if ($edit_news) $is_edit = true;
|
||||
if ($edit_news) {
|
||||
$is_edit = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Alle bestehenden News abrufen, um sie aufzulisten
|
||||
// Alle bestehenden News abrufen für die Übersichtstabelle
|
||||
$existing_news = $db->query("SELECT id, date, department, title FROM news ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
@@ -261,6 +264,9 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Admin Dashboard | SG 07 St. Leon</title>
|
||||
<!-- Cropper.js für Bildzuschnitt -->
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js"></script>
|
||||
<style>
|
||||
body { font-family: 'Segoe UI', sans-serif; background: #f4f4f4; padding: 40px 20px; margin: 0; }
|
||||
.container { max-width: 1000px; background: white; padding: 40px; border-radius: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.05); margin: 0 auto; }
|
||||
@@ -277,12 +283,12 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
||||
.sidebar-box { background: #fafafa; padding: 20px; border-radius: 8px; border: 1px solid #ddd; }
|
||||
.qr-box { background: #fff3cd; color: #856404; padding: 20px; border-radius: 8px; text-align: center; margin-bottom: 20px; border: 1px solid #ffeeba;}
|
||||
|
||||
/* Tabelle für News Verwaltung */
|
||||
.news-table { width: 100%; border-collapse: collapse; margin-top: 20px; font-size: 0.95rem; }
|
||||
.news-table th { background: #f4f4f4; padding: 12px; text-align: left; border-bottom: 2px solid #ddd; color: #333; }
|
||||
.news-table td { padding: 12px; border-bottom: 1px solid #eee; vertical-align: middle; }
|
||||
.news-table tr:hover { background: #fafafa; }
|
||||
.edit-btn { background: #2196F3; color: white; padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; text-decoration: none; font-size: 0.9rem; }
|
||||
.social-btn { background: #E1306C; color: white; padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; font-size: 0.9rem; margin-right: 5px; }
|
||||
.delete-btn { background: #d32f2f; color: white; padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; margin: 0; width: auto; font-size: 0.9rem; }
|
||||
|
||||
@media(max-width: 768px) { .grid-2 { grid-template-columns: 1fr; } }
|
||||
@@ -305,7 +311,7 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
||||
<!-- News Eintragen / Ändern -->
|
||||
<div>
|
||||
<h2 style="color: #333; margin-bottom: 10px;"><?= $is_edit ? 'News bearbeiten' : 'News veröffentlichen' ?></h2>
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<form method="POST" id="newsForm" enctype="multipart/form-data">
|
||||
<?php if($is_edit): ?>
|
||||
<input type="hidden" name="news_id" value="<?= $edit_news['id'] ?>">
|
||||
<input type="hidden" name="existing_image" value="<?= htmlspecialchars($edit_news['image']) ?>">
|
||||
@@ -322,8 +328,15 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
||||
<label>Kompletter Artikel (Popup)</label>
|
||||
<textarea name="full_text" rows="8" required><?= $is_edit ? htmlspecialchars($edit_news['full_text']) : '' ?></textarea>
|
||||
|
||||
<label>Bild hochladen (wird gespeichert unter /img/news/Jahr/...)</label>
|
||||
<input type="file" name="image_file" accept="image/*" style="background: white;">
|
||||
<label>Bild hochladen & zuschneiden</label>
|
||||
<input type="file" id="image_file_input" accept="image/*" style="background: white; margin-bottom: 10px;">
|
||||
|
||||
<!-- Cropper Container -->
|
||||
<div id="cropper_container" style="display:none; margin-bottom: 15px; max-height: 400px; overflow: hidden; border: 1px dashed #ccc;">
|
||||
<img id="image_to_crop" src="" style="max-width: 100%; display: block;">
|
||||
</div>
|
||||
<input type="hidden" name="cropped_image_data" id="cropped_image_data">
|
||||
|
||||
<?php if($is_edit && $edit_news['image']): ?>
|
||||
<p style="font-size: 0.85rem; color: #666; margin-top: -10px; margin-bottom: 10px;">Aktuelles Bild: <b><?= htmlspecialchars($edit_news['image']) ?></b></p>
|
||||
<?php endif; ?>
|
||||
@@ -331,6 +344,14 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
||||
<label>ODER Bild-Link (URL)</label>
|
||||
<input type="text" name="image_url" placeholder="https://..." value="<?= $is_edit ? htmlspecialchars($edit_news['image']) : '' ?>">
|
||||
|
||||
<label>ODER Platzhalter-Bild verwenden</label>
|
||||
<select name="placeholder_image" style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-family: inherit; margin-bottom: 15px; background: white;">
|
||||
<option value="">-- Kein Platzhalter (Leeres Bild) --</option>
|
||||
<option value="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' fill='%23f4f4f4'/%3E%3Ccircle cx='50' cy='50' r='35' fill='%23d32f2f'/%3E%3Ctext x='50' y='57' font-size='20' fill='white' text-anchor='middle' font-weight='bold'%3ESG 07%3C/text%3E%3C/svg%3E">Neutral (SG 07 Logo)</option>
|
||||
<option value="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' fill='%23e3f2fd'/%3E%3Ccircle cx='50' cy='50' r='35' fill='%232196f3'/%3E%3Ctext x='50' y='60' font-size='30' fill='white' text-anchor='middle' font-weight='bold' font-family='serif'%3Ei%3C/text%3E%3C/svg%3E">Info (Blaues i)</option>
|
||||
<option value="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' fill='%23fff3e0'/%3E%3Cpath d='M50 20 L85 80 L15 80 Z' fill='%23ff9800'/%3E%3Ctext x='50' y='70' font-size='30' fill='white' text-anchor='middle' font-weight='bold'%3E!%3C/text%3E%3C/svg%3E">Wichtig (Warnung)</option>
|
||||
</select>
|
||||
|
||||
<label>Weiterführender Link (Optional)</label>
|
||||
<input type="text" name="link" value="<?= $is_edit ? htmlspecialchars($edit_news['link']) : '' ?>">
|
||||
|
||||
@@ -361,17 +382,16 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- News Liste zum Löschen -->
|
||||
<!-- News Liste zum Löschen / Posten / Ändern -->
|
||||
<div style="margin-top: 50px; border-top: 2px solid #eee; padding-top: 30px;">
|
||||
<h2 style="color: #333; margin-bottom: 10px;">Bestehende News verwalten</h2>
|
||||
<p style="color: #666; font-size: 0.95rem;">Hier kannst du fehlerhafte oder veraltete News endgültig von der Website entfernen.</p>
|
||||
|
||||
<table class="news-table">
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<th>Abteilung</th>
|
||||
<th>Titel</th>
|
||||
<th style="width: 100px; text-align: right;">Aktion</th>
|
||||
<th style="width: 250px; text-align: right;">Aktion</th>
|
||||
</tr>
|
||||
<?php foreach($existing_news as $news_item): ?>
|
||||
<tr>
|
||||
@@ -379,6 +399,7 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
||||
<td><span style="background: #eee; padding: 2px 8px; border-radius: 4px; font-size: 0.85rem;"><?= htmlspecialchars($news_item['department']) ?></span></td>
|
||||
<td><strong><?= htmlspecialchars($news_item['title']) ?></strong></td>
|
||||
<td style="text-align: right; display: flex; justify-content: flex-end; gap: 5px;">
|
||||
<button type="button" class="social-btn" onclick="copySocialMediaText('<?= htmlspecialchars(addslashes($news_item['title'])) ?>', '<?= htmlspecialchars(addslashes($news_item['department'])) ?>')">📲 Posten</button>
|
||||
<a href="?edit_id=<?= $news_item['id'] ?>" class="edit-btn">Ändern</a>
|
||||
<form method="POST" style="margin: 0;" onsubmit="return confirm('Möchtest du diese News wirklich unwiderruflich löschen?');">
|
||||
<input type="hidden" name="delete_id" value="<?= $news_item['id'] ?>">
|
||||
@@ -389,11 +410,59 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
||||
<?php endforeach; ?>
|
||||
<?php if(empty($existing_news)): ?>
|
||||
<tr>
|
||||
<td colspan="4" style="text-align: center; padding: 20px; color: #888;">Noch keine News in der Datenbank vorhanden.</td>
|
||||
<td colspan="4" style="text-align: center; padding: 20px; color: #888;">Noch keine News vorhanden.</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Javascript für Crop und Social Media -->
|
||||
<script>
|
||||
// CROPPER LOGIK
|
||||
let cropper;
|
||||
document.getElementById('image_file_input').addEventListener('change', function(e) {
|
||||
const file = e.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(event) {
|
||||
document.getElementById('image_to_crop').src = event.target.result;
|
||||
document.getElementById('cropper_container').style.display = 'block';
|
||||
|
||||
if (cropper) cropper.destroy();
|
||||
cropper = new Cropper(document.getElementById('image_to_crop'), {
|
||||
aspectRatio: 4 / 3,
|
||||
viewMode: 1,
|
||||
autoCropArea: 1
|
||||
});
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('newsForm').addEventListener('submit', function(e) {
|
||||
if (cropper) {
|
||||
const canvas = cropper.getCroppedCanvas({ width: 800, height: 600 });
|
||||
if(canvas) {
|
||||
document.getElementById('cropped_image_data').value = canvas.toDataURL('image/jpeg', 0.85);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// SOCIAL MEDIA EXPORT LOGIK
|
||||
function copySocialMediaText(title, department) {
|
||||
const cleanDept = department.replace(/\s+/g, '');
|
||||
const text = `🚨 NEUE NEWS VON DER SG 07 🚨\n\n📢 ${title}\n\nLies jetzt den ganzen Bericht auf unserer Website!\n👉 sg07-stleon.de\n\n#SG07StLeon #Vereinsliebe #${cleanDept} #StLeonRot`;
|
||||
|
||||
const tempInput = document.createElement("textarea");
|
||||
tempInput.value = text;
|
||||
document.body.appendChild(tempInput);
|
||||
tempInput.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(tempInput);
|
||||
|
||||
alert("✅ Der Text für Instagram & Facebook wurde in deine Zwischenablage kopiert!\n\nDu kannst jetzt einfach rüber zu Insta gehen, dein Bild einfügen und beim Text auf 'Einsetzen' drücken.");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
8
gitea_deploy_key
Normal file
8
gitea_deploy_key
Normal file
@@ -0,0 +1,8 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACA9K1g7EYM4GXW56/fwbXLZlWn7rP9AP1Gk8cC16WxTywAAAKjYMmgw2DJo
|
||||
MAAAAAtzc2gtZWQyNTUxOQAAACA9K1g7EYM4GXW56/fwbXLZlWn7rP9AP1Gk8cC16WxTyw
|
||||
AAAEA93szDRUXvB7RSxG1lUz9P/zKbzFIH2zQv1onw3QYyZT0rWDsRgzgZdbnr9/BtctmV
|
||||
afus/0A/UaTxwLXpbFPLAAAAIGhlaWRlbGJlcmctaXRcaGVpbkBIRElULVBGNFBSR0hTAQ
|
||||
IDBAU=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
1
gitea_deploy_key.pub
Normal file
1
gitea_deploy_key.pub
Normal file
@@ -0,0 +1 @@
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID0rWDsRgzgZdbnr9/BtctmVafus/0A/UaTxwLXpbFPL heidelberg-it\hein@HDIT-PF4PRGHS
|
||||
Reference in New Issue
Block a user