0,'path'=>'/','secure'=>$secure,'httponly'=>true,'samesite'=>'Lax', ]); session_name('WLISTSESSID'); session_start(); umask(0022); // neue Dateien: 0644, Ordner: 0755 require_once __DIR__ . '/config/config.php'; /* ===== Debug Toggle (wie item.php) ===== */ if (!empty($app_debug)) { ini_set('display_errors','1'); ini_set('display_startup_errors','1'); ini_set('log_errors','1'); if (!is_dir(__DIR__.'/logs')) { @mkdir(__DIR__.'/logs',0750,true); } ini_set('error_log', __DIR__.'/logs/php-error.log'); error_reporting(E_ALL); } else { ini_set('display_errors','0'); ini_set('display_startup_errors','0'); ini_set('log_errors','1'); if (!is_dir(__DIR__.'/logs')) { @mkdir(__DIR__.'/logs',0750,true); } ini_set('error_log', __DIR__.'/logs/php-error.log'); error_reporting(E_ALL); } /* ============= Helpers ============= */ function fail(string $msg, int $code=400): void { http_response_code($code); // kleine Flash-Message für index.php $_SESSION['flash'] = ['msg'=>$msg,'type'=> ($code>=400?'danger':'success')]; safe_redirect_back(); } function db(): mysqli { global $servername, $username, $password, $db; $conn = new mysqli($servername, $username, $password, $db); if ($conn->connect_error) fail('Interner Fehler (DB)', 500); $conn->set_charset('utf8mb4'); return $conn; } function require_csrf(): void { $t = (string)($_POST['csrf'] ?? ''); if (empty($_SESSION['csrf']) || !hash_equals($_SESSION['csrf'], $t)) { fail('Ungültiges CSRF-Token', 403); } } function e(string $s): string { return htmlspecialchars($s, ENT_QUOTES|ENT_SUBSTITUTE, 'UTF-8'); } function safe_redirect_back(): void { $ref = (string)($_SERVER['HTTP_REFERER'] ?? ''); if ($ref === '' || stripos($ref, 'http') !== 0) { $host = $_SERVER['HTTP_HOST'] ?? ''; $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; header('Location: '.$scheme.'://'.$host.'/', true, 303); } else { header('Location: '.$ref, true, 303); } exit; } /* ============= Controller ============= */ if ($_SERVER['REQUEST_METHOD'] !== 'POST') { fail('Methode nicht erlaubt', 405); } require_csrf(); $wishId = (int)($_POST['wishid'] ?? -1); $pw = (string)($_POST['WishPassword'] ?? ''); $reservedstat = (int)($_POST['reservedstat'] ?? 0); // 0 = setzen, 1 = aufheben if ($wishId <= 0) fail('Ungültige Wunsch-ID', 400); if ($pw === '') fail('Passwort erforderlich', 400); $conn = db(); /* --- qty des Wunsch + bestehende Reservierungen zählen --- */ $qty = 1; $stmt = $conn->prepare('SELECT qty FROM wishes WHERE ID = ?'); $stmt->bind_param('i', $wishId); $stmt->execute(); $res = $stmt->get_result(); if (!$res || !($row = $res->fetch_assoc())) { $stmt->close(); $conn->close(); fail('Wunsch nicht gefunden', 404); } $qty = max(1, (int)$row['qty']); $stmt->close(); /* Existierende Reservierungen zählen */ $cnt = 0; $stmt = $conn->prepare('SELECT COUNT(*) AS c FROM wishes_reservations WHERE wish_id = ?'); $stmt->bind_param('i',$wishId); $stmt->execute(); $res = $stmt->get_result(); if ($res && ($row = $res->fetch_assoc())) $cnt = (int)$row['c']; $stmt->close(); /* --- Operationen --- */ if ($reservedstat === 0) { // setzen if ($cnt >= $qty) { $conn->close(); fail('Für diesen Wunsch sind bereits alle Exemplare reserviert.', 409); } $hash = password_hash($pw, PASSWORD_BCRYPT); $ins = $conn->prepare('INSERT INTO wishes_reservations (wish_id, pass_hash, created_at) VALUES (?, ?, NOW())'); $ins->bind_param('is', $wishId, $hash); if (!$ins->execute()) { $ins->close(); $conn->close(); fail('Reservierung fehlgeschlagen', 500); } $ins->close(); $conn->close(); $_SESSION['flash'] = ['msg'=>'Reservierung eingetragen','type'=>'success']; safe_redirect_back(); } else { // aufheben: passenden Hash suchen und genau einen Eintrag löschen $sel = $conn->prepare('SELECT id, pass_hash FROM wishes_reservations WHERE wish_id = ?'); $sel->bind_param('i',$wishId); $sel->execute(); $res = $sel->get_result(); $deleted = false; while ($row = $res->fetch_assoc()) { $rid = (int)$row['id']; $rhash= (string)$row['pass_hash']; if (password_verify($pw, $rhash)) { $del = $conn->prepare('DELETE FROM wishes_reservations WHERE id = ? LIMIT 1'); $del->bind_param('i', $rid); $deleted = $del->execute(); $del->close(); break; } } $sel->close(); $conn->close(); if ($deleted) { $_SESSION['flash'] = ['msg'=>'Reservierung aufgehoben','type'=>'success']; } else { $_SESSION['flash'] = ['msg'=>'Kein passender Reservierungseintrag gefunden (Passwort korrekt?)','type'=>'warning']; } safe_redirect_back(); }