144 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| declare(strict_types=1);
 | |
| 
 | |
| /* ========= Session & Bootstrap ========= */
 | |
| $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
 | |
| session_set_cookie_params([
 | |
|   'lifetime'=>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();
 | |
| }
 |