Merge remote-tracking branch 'origin/main'

This commit is contained in:
Fabian Schieder 2026-01-23 19:58:00 +01:00
commit 74f6de522b
12 changed files with 363 additions and 245 deletions

View File

@ -1,9 +1,9 @@
AuthType Basic # AuthType Basic
AuthName "Geschützter Bereich" # AuthName "Geschützter Bereich"
AuthUserFile /FSST/Website/.htpasswd # AuthUserFile /FSST/Website/.htpasswd
Require valid-user # Require valid-user
#
# .htpasswd vor Auslieferung schützen # # .htpasswd vor Auslieferung schützen
<Files ".htpasswd"> # <Files ".htpasswd">
Require all denied # Require all denied
</Files> # </Files>

155
README.md
View File

@ -1,156 +1 @@
# Readme File
> ## ![Projekt Logins](https://send.bitwarden.com/#0sol_osHmkGnJrPXARShXA/AzFCC4rVoXqEqjQUEqBt1A)
> ## ![Datenbank Design](https://dbdiagram.io/d/Geizkragen-695e708939fa3db27b5c7599)
> ![user](assets/images/DB_Design_user.png)
> ![products](assets/images/DB_Design_products.png)
```sql
Table categories {
categoryID int [pk]
name varchar(255)
parentCategoryID int
}
Ref: "categories"."parentCategoryID" < "categories"."categoryID"
Table brands {
brandID int [pk]
name varchar(255)
}
Table products {
productID int [pk]
categoryID int
brandID int
model varchar(255)
ean varchar(20)
description text
}
Ref: "products"."categoryID" < "categories"."categoryID"
Ref: "products"."brandID" < "brands"."brandID"
Table shops {
shopID int [pk]
name varchar(255)
website varchar(255)
}
Table offers {
offerID int [pk]
productID int
shopID int
price decimal(10,2)
shippingCost decimal(10,2)
inStock boolean
productURL varchar(500)
lastUpdated timestamp
}
Ref: "offers"."productID" < "products"."productID"
Ref: "offers"."shopID" < "shops"."shopID"
Table attributes {
attributeID int [pk]
name varchar(255)
unit varchar(50)
dataType varchar(20)
}
Table categoryAttributes {
categoryID int
attributeID int
}
Ref: "categoryAttributes"."categoryID" < "categories"."categoryID"
Ref: "categoryAttributes"."attributeID" < "attributes"."attributeID"
Table productAttributes {
productID int
attributeID int
valueString varchar(255)
valueNumber decimal(10,2)
valueBool boolean
}
Ref: "productAttributes"."productID" < "products"."productID"
Ref: "productAttributes"."attributeID" < "attributes"."attributeID"
Table users {
userID int [pk]
email varchar(255)
passwordHash varchar(255)
displayName varchar(255)
isActive boolean
createdAt timestamp
}
Table roles {
roleID int [pk]
name varchar(50)
}
Table userRoles {
userID int
roleID int
}
Ref: "userRoles"."userID" < "users"."userID"
Ref: "userRoles"."roleID" < "roles"."roleID"
Table userFavorites {
userID int
productID int
createdAt timestamp
}
Ref: "userFavorites"."userID" < "users"."userID"
Ref: "userFavorites"."productID" < "products"."productID"
Table priceAlerts {
alertID int [pk]
userID int
productID int
targetPrice decimal(10,2)
isActive boolean
createdAt timestamp
}
Ref: "priceAlerts"."userID" < "users"."userID"
Ref: "priceAlerts"."productID" < "products"."productID"
Table notifications {
notificationID int [pk]
userID int
title varchar(255)
message text
isRead boolean
createdAt timestamp
}
Ref: "notifications"."userID" < "users"."userID"
Table reviews {
reviewID int [pk]
userID int
productID int
rating int
comment text
createdAt timestamp
}
Ref: "reviews"."userID" < "users"."userID"
Ref: "reviews"."productID" < "products"."productID"
Table userSessions {
sessionID varchar(128) [pk]
userID int
expiresAt timestamp
}
Ref: "userSessions"."userID" < "users"."userID"
```

80
assets/css/catbar.css Normal file
View File

@ -0,0 +1,80 @@
.home-nav {
width: 100%;
display: flex;
align-items: center;
background-color: #2d3b50;
padding: 1px 0; /* nur minimal größer als Buttons */
}
/* Inner zentriert */
.home-nav__inner {
flex: 1;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
/* List: 5 gleich große Bereiche */
.home-nav__list {
width: 100%;
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
/* LI nur als Container KEINE Höhe hier */
.home-nav__list li {
flex: 1;
position: relative;
}
/* =============================== */
/* HOME CATEGORY BUTTON */
/* =============================== */
.home-nav__list li button[type="categorybutton"] {
width: 100%;
padding: 8px 0; /* <-- HIER steuerst du die Höhe */
background-color: #2d3b50;
color: #ffffff;
font-weight: bold;
font-size: 0.9rem;
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.2s ease, box-shadow 0.2s ease;
}
/* Hover */
.home-nav__list li button[type="categorybutton"]:hover {
background-color: #3b4f6b;
}
/* Active */
.home-nav__list li button[type="categorybutton"]:active {
background-color: #1f2a3a;
}
/* Fokus sichtbar aber clean */
.home-nav__list li button[type="categorybutton"]:focus-visible {
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.6);
}
/* Trennstriche */
.home-nav__list li:not(:last-child)::after {
content: "";
position: absolute;
right: 0;
top: 0%;
height: 100%;
width: 2px;
background-color: rgba(255, 255, 255, 0.4);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 278 KiB

40
catbar.php Normal file
View File

@ -0,0 +1,40 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="assets/css/catbar.css">
</head>
<nav class="home-nav" aria-label="Homenavigation">
<div class="home-nav__inner container">
<ul class="home-nav__list">
<li class="home-nav__item">
<button type="categorybutton">Kategorie 0</button>
</li>
<li class="home-nav__item">
<button type="categorybutton">Kategorie 1</button>
</li>
<li class="home-nav__item">
<button type="categorybutton">Kategorie 2</button>
</li>
<li class="home-nav__item">
<button type="categorybutton">Kategorie 3</button>
</li>
<li class="home-nav__item">
<button type="categorybutton">Kategorie 4</button>
</li>
</ul>
</div>
</nav>
<?php echo "Test123" ?>

View File

@ -11,7 +11,7 @@
<title>Geizkragen</title> <title>Geizkragen</title>
</head> </head>
<body>
<!--==================== HEADER ====================--> <!--==================== HEADER ====================-->
<header class="header" id="header"> <header class="header" id="header">
<nav class="nav" aria-label="Hauptnavigation"> <nav class="nav" aria-label="Hauptnavigation">
@ -23,15 +23,15 @@
<div class="nav__menu" id="nav-menu"> <div class="nav__menu" id="nav-menu">
<ul class="nav__list"> <ul class="nav__list">
<li class="nav__item"> <li class="nav__item">
<a href="home.php" class="nav__link">Home</a> <a href="index.php" class="nav__link">Home</a>
</li> </li>
<li class="nav__item"> <li class="nav__item">
<a href="wunschliste.php" class="nav__link">Wunschliste</a> <a href="wunschliste.php" class="nav__link">Wunschliste</a>
</li> </li>
</ul> </ul>
<!-- Close button --> <!-- Close button -->
<div class="nav__close" id="nav-close"> <div class="nav__close" id="nav-close">
<i class="ri-close-line"></i> <i class="ri-close-line"></i>
</div> </div>

View File

@ -1,45 +0,0 @@
<?php include "header.php"; ?>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/style.css">
</head>
<nav class="nav" aria-label="Homenavigation">
<div class="nav__inner2 container">
<div class="nav__menu" id="nav-menu">
<ul class="nav__list">
<li class="nav__categories">
<p>Elektronik</p>
</li>
<li class="nav__categories">
<p>Computer</p>
</li>
<li class="nav__categories">
<p>Smartphones</p>
</li>
<li class="nav__categories">
<p>Kopfhörer</p>
</li>
<li class="nav__categories">
<p>Laptop</p>
</li>
</ul>
</div>
</div>
</nav>
<?php echo "Test123" ?>
<?php include "footer.php"; ?>

View File

@ -5,5 +5,6 @@ error_reporting(E_ALL);
<?php include 'header.php'; ?> <?php include 'header.php'; ?>
<?php include 'catbar.php'; ?>
<?php include 'footer.php'; ?> <?php include 'footer.php'; ?>

View File

@ -22,54 +22,81 @@ if (!$conn) {
// 2) POST-Verarbeitung VOR jeglicher Ausgabe // 2) POST-Verarbeitung VOR jeglicher Ausgabe
$loginError = null; $loginError = null;
$loginInfo = null;
if (isset($_GET['registered']) && $_GET['registered'] === '1') {
$loginInfo = 'Registrierung erfolgreich. Du kannst dich jetzt einloggen.';
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$uname = isset($_POST['uname']) ? $_POST['uname'] : ''; $uname = trim(isset($_POST['uname']) ? $_POST['uname'] : '');
$pw = isset($_POST['pw']) ? $_POST['pw'] : ''; $pw = isset($_POST['pw']) ? $_POST['pw'] : '';
// Basic Validierung // Basic Validierung
if ($uname === '' || $pw === '') { if ($uname === '' || $pw === '') {
$loginError = "Bitte Username und Passwort eingeben."; $loginError = "Bitte Username und Passwort eingeben.";
} } else {
else { // Login ist SELECT, mit Prepared Statement (sicher) und ?-Platzhalter
// Login ist SELECT, nicht INSERT $stmt = mysqli_prepare(
$stmt = mysqli_prepare($conn, "SELECT id, pw FROM user WHERE un = ?"); $conn,
mysqli_stmt_bind_param($stmt, "s", $uname); "SELECT userID, displayName, passwordHash FROM users WHERE displayName = ? LIMIT 1"
mysqli_stmt_execute($stmt); );
$result = mysqli_stmt_get_result($stmt);
$user = $result ? mysqli_fetch_assoc($result) : null; if (!$stmt) {
$loginError = "Datenbankfehler.";
} else {
mysqli_stmt_bind_param($stmt, "s", $uname);
mysqli_stmt_execute($stmt);
// Falls du Passwörter gehasht speicherst: password_verify($pw, $user['pw']) $result = mysqli_stmt_get_result($stmt);
// Wenn aktuell Klartext (nicht empfohlen): $pw === $user['pw'] $user = $result ? mysqli_fetch_assoc($result) : null;
if ($user && $pw === $user['pw']) {
$_SESSION['user_id'] = (int)$user['id'];
$_SESSION['username'] = $uname;
mysqli_close($conn); // Passwort prüfen: Eingabe gegen gespeicherten Hash (password_hash/password_verify)
header("Location: index.php"); if ($user && password_verify($pw, $user['passwordHash'])) {
exit; // Optional: Rehash, falls Algorithmus/Cost geändert wurde
if (password_needs_rehash($user['passwordHash'], PASSWORD_DEFAULT)) {
$newHash = password_hash($pw, PASSWORD_DEFAULT);
$upd = mysqli_prepare($conn, "UPDATE users SET passwordHash = ? WHERE userID = ?");
if ($upd) {
$userID = (int)$user['userID'];
mysqli_stmt_bind_param($upd, "si", $newHash, $userID);
mysqli_stmt_execute($upd);
mysqli_stmt_close($upd);
}
}
$_SESSION['user_id'] = (int)$user['userID'];
$_SESSION['displayName'] = $user['displayName'];
mysqli_stmt_close($stmt);
mysqli_close($conn);
header("Location: index.php");
exit;
}
$loginError = "Ungültige Zugangsdaten.";
mysqli_stmt_close($stmt);
} }
$loginError = "Ungültige Zugangsdaten.";
} }
} }
include 'header.php';
?> ?>
<?php include 'header.php'; ?>
<!-- Hinweis: header.php öffnet bereits <!DOCTYPE html>, <html>, <head> und <body>. -->
<link rel="stylesheet" href="assets/css/login.css"> <link rel="stylesheet" href="assets/css/login.css">
<main class="auth" role="main"> <main class="auth" role="main">
<section class="auth__grid" aria-label="Login Bereich"> <section class="auth__grid" aria-label="Login Bereich">
<div class="auth__card"> <div class="auth__card">
<header class="auth__header"> <header class="auth__header">
<h2 class="auth__title">Login</h2> <h2 class="auth__title">Login</h2>
<p class="auth__subtitle">Melde dich an, um deine Wunschliste zu verwalten und Deals schneller zu speichern.</p> <p class="auth__subtitle">Melde dich an, um deine Wunschliste zu verwalten und Deals schneller zu speichern.</p>
</header> </header>
<?php if ($loginInfo): ?>
<p class="auth__alert" role="status"><?php echo htmlspecialchars($loginInfo, ENT_QUOTES, 'UTF-8'); ?></p>
<?php endif; ?>
<?php if ($loginError): ?> <?php if ($loginError): ?>
<p class="auth__alert" role="alert"><?php echo htmlspecialchars($loginError, ENT_QUOTES, 'UTF-8'); ?></p> <p class="auth__alert" role="alert"><?php echo htmlspecialchars($loginError, ENT_QUOTES, 'UTF-8'); ?></p>
<?php endif; ?> <?php endif; ?>
@ -91,11 +118,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
</form> </form>
<div class="auth__links"> <div class="auth__links">
<p class="auth__muted">Neu hier? <a href="other/login.html">Account erstellen</a></p> <p class="auth__muted">Neu hier? <a href="register.php">Account erstellen</a></p>
<p class="auth__muted"><a href="index.php">Zurück zur Startseite</a></p> <p class="auth__muted"><a href="index.php">Zurück zur Startseite</a></p>
</div> </div>
</div> </div>
</section> </section>
</main> </main>
@ -103,5 +129,3 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
mysqli_close($conn); mysqli_close($conn);
include 'footer.php'; include 'footer.php';
?> ?>
<!-- footer.php schließt </body> und </html> -->

1
productpage.php Normal file
View File

@ -0,0 +1 @@
<?php

171
register.php Normal file
View File

@ -0,0 +1,171 @@
<?php
// register.php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
session_start();
// 1) DB-Verbindung (einmal)
$servername = "localhost";
$port = 3306;
$username = "FSST";
$password = "L9wUNZZ9Qkbt";
$db = "FSST";
$conn = mysqli_connect($servername, $username, $password, $db, $port);
if (!$conn) {
http_response_code(500);
die("Datenbankfehler");
}
$errors = [];
$values = [
'email' => '',
'displayName' => ''
];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = trim((string)(isset($_POST['email']) ? $_POST['email'] : ''));
$displayName = trim((string)(isset($_POST['displayName']) ? $_POST['displayName'] : ''));
$pw = (string)(isset($_POST['pw']) ? $_POST['pw'] : '');
$pw2 = (string)(isset($_POST['pw2']) ? $_POST['pw2'] : '');
$values['email'] = $email;
$values['displayName'] = $displayName;
// Validierung
if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Bitte eine gültige E-Mail-Adresse eingeben.';
}
if ($displayName === '' || mb_strlen($displayName) < 3 || mb_strlen($displayName) > 50) {
$errors[] = 'Bitte einen Benutzernamen mit 350 Zeichen eingeben.';
}
if ($pw === '' || mb_strlen($pw) < 8) {
$errors[] = 'Bitte ein Passwort mit mindestens 8 Zeichen wählen.';
}
if ($pw !== $pw2) {
$errors[] = 'Die Passwörter stimmen nicht überein.';
}
// Duplicate-Checks
if (!$errors) {
$stmt = mysqli_prepare($conn, 'SELECT userID FROM users WHERE email = ? LIMIT 1');
if (!$stmt) {
$errors[] = 'Datenbankfehler.';
} else {
mysqli_stmt_bind_param($stmt, 's', $email);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
if ($result && mysqli_fetch_assoc($result)) {
$errors[] = 'Diese E-Mail ist bereits registriert.';
}
mysqli_stmt_close($stmt);
}
}
if (!$errors) {
$stmt = mysqli_prepare($conn, 'SELECT userID FROM users WHERE displayName = ? LIMIT 1');
if (!$stmt) {
$errors[] = 'Datenbankfehler.';
} else {
mysqli_stmt_bind_param($stmt, 's', $displayName);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
if ($result && mysqli_fetch_assoc($result)) {
$errors[] = 'Dieser Benutzername ist bereits vergeben.';
}
mysqli_stmt_close($stmt);
}
}
// Insert
if (!$errors) {
$hash = password_hash($pw, PASSWORD_DEFAULT);
$stmt = mysqli_prepare(
$conn,
'INSERT INTO users (email, passwordHash, displayName, isActive, createdAt) VALUES (?, ?, ?, 1, NOW())'
);
if (!$stmt) {
$errors[] = 'Datenbankfehler.';
} else {
mysqli_stmt_bind_param($stmt, 'sss', $email, $hash, $displayName);
$ok = mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
if ($ok) {
mysqli_close($conn);
header('Location: login.php?registered=1');
exit;
}
$errors[] = 'Registrierung fehlgeschlagen.';
}
}
}
include 'header.php';
?>
<link rel="stylesheet" href="assets/css/login.css">
<main class="auth" role="main">
<section class="auth__grid" aria-label="Registrierung Bereich">
<div class="auth__card">
<header class="auth__header">
<h2 class="auth__title">Registrierung</h2>
<p class="auth__subtitle">Erstelle einen Account, um deine Wunschliste zu verwalten und Deals schneller zu speichern.</p>
</header>
<?php if ($errors): ?>
<div class="auth__alert" role="alert">
<ul>
<?php foreach ($errors as $e): ?>
<li><?php echo htmlspecialchars($e, ENT_QUOTES, 'UTF-8'); ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<form class="auth__form" action="register.php" method="POST" autocomplete="on">
<div class="auth__field">
<label for="email">E-Mail</label>
<input type="email" id="email" name="email" autocomplete="email" required value="<?php echo htmlspecialchars($values['email'], ENT_QUOTES, 'UTF-8'); ?>">
</div>
<div class="auth__field">
<label for="displayName">Username</label>
<input type="text" id="displayName" name="displayName" inputmode="text" autocomplete="username" required value="<?php echo htmlspecialchars($values['displayName'], ENT_QUOTES, 'UTF-8'); ?>">
</div>
<div class="auth__field">
<label for="pw">Passwort</label>
<input type="password" id="pw" name="pw" autocomplete="new-password" required>
</div>
<div class="auth__field">
<label for="pw2">Passwort wiederholen</label>
<input type="password" id="pw2" name="pw2" autocomplete="new-password" required>
</div>
<div class="auth__actions">
<input class="auth__submit" type="submit" value="Registrieren">
</div>
</form>
<div class="auth__links">
<p class="auth__muted">Schon registriert? <a href="login.php">Einloggen</a></p>
<p class="auth__muted"><a href="index.php">Zurück zur Startseite</a></p>
</div>
</div>
</section>
</main>
<?php
mysqli_close($conn);
include 'footer.php';
?>

View File

@ -1,4 +1,5 @@
<?php include 'header.php'; ?> <?php include 'header.php'; ?>
<p>Secret pimmel</p>
<?php include 'footer.php'; ?> <?php include 'footer.php'; ?>