Files
anjuma-dashboard/termin_create.php
T
xBeaTz d97605f801 security: harden application security baseline
- Fixed SQL injection vulnerabilities with prepared statements
- Added column whitelist protection for dynamic termin updates
- Extracted iCloud credentials into protected config file
- Moved sensitive configuration files out of webroot
- Added authentication and admin checks to PVE APIs
- Added CSRF protection to write operations and APIs
- Disabled debug output in production mode
- Added centralized configuration handling
- Protected sensitive directories with access rules
- Added initial project security documentation
2026-07-22 02:23:34 +02:00

251 lines
8.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
date_default_timezone_set("Europe/Berlin");
// Header / Navbar / Zugriffsschutz falls nötig
require_once "config/config.php";
require_once "Data.class.php";
$Data = new Data($pdo);
require_once "config/session.php";
if (!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true) {
header("location: index.php");
exit;
}
if (isset($_POST['submit'])) {
// CSRF check
if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
die("CSRF validation failed");
}
// Required fields
if (
!empty($_POST['inputStartzeit_ts']) &&
!empty($_POST['inputLocation']) &&
!empty($_POST['inputArt'])
) {
$endzeit = !empty($_POST['inputEndzeit_ts']) ? $_POST['inputEndzeit_ts'] : 0;
$gage = $_POST['inputGage'];
if ($gage === '' || $gage === null) {
$gage = 0;
}
$gage = (int)$gage;
$art = $_POST['inputArt'] ?? '';
$validArts = ['Party', 'Club', 'Hochzeit'];
if (!in_array($art, $validArts, true)) {
$art = 'Party';
}
$terminid = $Data->createTermin(
$_POST['inputStartzeit_ts'],
$endzeit,
$_POST['inputLocation'],
$_SESSION['id'],
$gage,
$art
);
$Data->createChanges($terminid, $_SESSION["id"], "create", "", "");
header("Location: termin_show.php?id=" . $terminid);
exit;
}
}
include('navbar.php');
?>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<div class="container mt-4">
<h3 class="mb-4"><i class="bi bi-plus-circle"></i> Neuen Termin erstellen</h3>
<form method="POST" action="termin_create.php" id="createTerminForm">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-bold">Startzeit</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-clock-fill"></i></span>
<input
type="datetime-local"
class="form-control"
id="inputStartzeit"
name="inputStartzeit"
required
>
<input type="hidden" name="inputStartzeit_ts" id="inputStartzeit_ts">
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Endzeit</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-clock-fill"></i></span>
<input
type="datetime-local"
class="form-control"
id="inputEndzeit"
name="inputEndzeit"
>
<input type="hidden" name="inputEndzeit_ts" id="inputEndzeit_ts">
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Location</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-geo-alt"></i></span>
<input
type="text"
class="form-control"
name="inputLocation"
placeholder="Veranstaltungsort"
required
>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Veranstaltungsart</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-calendar-event"></i></span>
<select
class="form-select"
name="inputArt"
required
>
<option value="" selected disabled>Bitte auswählen</option>
<option value="Party">Party (eigene Technik, kompletter Aufbau)</option>
<option value="Club">Club (Technik vor Ort, nur DJ-Setup)</option>
<option value="Hochzeit">Hochzeit (hoher Orga-Aufwand, eigenes Equipment)</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Gage</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-cash-stack"></i></span>
<input
type="number"
class="form-control"
name="inputGage"
placeholder="z. B. 350"
min="0"
step="1"
required
>
</div>
<div class="text-end mt-4">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<button type="submit" name="submit" class="btn btn-primary">
<i class="bi bi-check-circle"></i> Termin speichern
</button>
</div>
</form>
</div>
<div class="modal fade" id="terminConflictModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-danger text-white">
<h5 class="modal-title">Achtung Terminüberschneidung!</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Für dieses Datum existiert bereits mindestens ein Termin:</p>
<div id="terminConflictList" class="border rounded p-2 bg-light"></div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal">Okay</button>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
const startInput = document.getElementById("inputStartzeit");
const endInput = document.getElementById("inputEndzeit");
let conflictShownForDate = null;
startInput.addEventListener("change", async () => {
if (!startInput.value) return;
const selectedDate = startInput.value;
const dateOnly = selectedDate.split("T")[0];
if (conflictShownForDate !== dateOnly) {
const ts = Math.floor(new Date(selectedDate).getTime() / 1000);
const res = await fetch(`check_date.php?ts=${ts}`);
const data = await res.json();
if (Array.isArray(data) && data.length > 0) {
let html = "";
data.forEach(t => {
html += `
<div class="p-2 mb-2 bg-white rounded border">
<strong>Termin #${t.id}</strong><br>
Start: ${new Date(t.startzeit * 1000).toLocaleString()}<br>
Location: ${t.location}
</div>
`;
});
document.getElementById("terminConflictList").innerHTML = html;
const modal = new bootstrap.Modal(document.getElementById("terminConflictModal"));
modal.show();
conflictShownForDate = dateOnly;
}
}
if (startInput.value) {
const startDate = new Date(startInput.value);
startDate.setHours(startDate.getHours() + 8);
const iso = startDate.toISOString().slice(0, 16);
endInput.value = iso;
const hidden = document.getElementById("inputEndzeit_ts");
if (hidden) hidden.value = Math.floor(startDate.getTime() / 1000);
}
});
});
function toTimestampLocal(datetime) {
return datetime ? Math.floor(new Date(datetime).getTime() / 1000) : "";
}
document.getElementById("createTerminForm").addEventListener("submit", function() {
document.getElementById("inputStartzeit_ts").value = toTimestampLocal(document.getElementById("inputStartzeit").value);
document.getElementById("inputEndzeit_ts").value = toTimestampLocal(document.getElementById("inputEndzeit").value);
document.getElementById("inputRealEndzeit_ts").value = toTimestampLocal(document.getElementById("inputRealEndzeit").value);
});
</script>
</create_file>