<>
Login
E-Commerce Code Viewer /ecom_shop
PHP · HTML · CSS Nur Leseansicht
Code-Vorschau Wähle links eine Datei aus
Klick auf Dateinamen → Code anzeigen

./shop/app/Controllers/AddProductController.php

<?php
/**
 * AddProductController
 */

class AddProductController {
    
    public function index() {
        $title = 'Home';
        require_once APP_ROOT . '/app/Views/addproduct.php';
    }
    public function store() {
        // file_put_contents('log.txt', print_r($_FILES, true)  . "\n", FILE_APPEND);









$zielOrdner = dirname(__DIR__, 2) . '/public/uploads/';
if (!is_dir($zielOrdner)) {
    mkdir($zielOrdner, 0755, true); // Ordner erstellen, falls er nicht existiert
}
$erfolgreichGespeichert = []; // Hier sammeln wir die Pfade der fertigen Bilder
$fehlerMeldungen = [];        // Hier sammeln wir Fehler

// Prüfen, ob das Array 'images' ankam
if (isset($_FILES['images'])) {
    
    // Zählen, wie viele Bilder im Array stecken
    $anzahlBilder = count($_FILES['images']['name']);
    
    $erlaubteTypen = [
        'image/jpeg' => 'jpg',
        'image/png'  => 'png',
        'image/gif'  => 'gif',
        'image/webp' => 'webp'
    ];

    // Schleife durch alle hochgeladenen Bilder
    for ($i = 0; $i < $anzahlBilder; $i++) {
        
        $temporaererPfad = $_FILES['images']['tmp_name'][$i];
        $originalName    = $_FILES['images']['name'][$i];
        $fehlerCode      = $_FILES['images']['error'][$i];

        // 1. Prüfen, ob die Datei überhaupt hochgeladen wurde (z.B. bei leeren Feldern)
        if ($fehlerCode === UPLOAD_ERR_NO_FILE) {
            continue; // Überspringen
        }

        // 2. Gab es einen generellen Übertragungsfehler?
        if ($fehlerCode !== UPLOAD_ERR_OK) {
            $fehlerMeldungen[] = "Fehler bei '$originalName' (Code: $fehlerCode).";
            continue; // Zum nächsten Bild springen
        }

        // 3. SICHERHEITS-CHECK: Ist es wirklich ein Bild?
        $bildInfo = getimagesize($temporaererPfad);
        if ($bildInfo === false) {
            $fehlerMeldungen[] = "'$originalName' ist kein gültiges Bild und wurde blockiert!";
            continue;
        }

        // 4. MIME-Type überprüfen (Nur bestimmte Formate erlauben)
        $echterMimeType = $bildInfo['mime'];
        if (!array_key_exists($echterMimeType, $erlaubteTypen)) {
            $fehlerMeldungen[] = "'$originalName' hat ein falsches Format (Nur JPG, PNG, GIF, WebP).";
            continue;
        }

        // 5. Neuen, sicheren Dateinamen generieren
        $sichereEndung = $erlaubteTypen[$echterMimeType];
        // uniqid() generiert einen einmaligen Namen, das $i sorgt dafür, dass 
        // Bilder in der gleichen Millisekunde keine Konflikte machen.
        $neuerDateiname = uniqid('img_') . '_' . $i . '.' . $sichereEndung;
        
        $endgueltigerPfad = $zielOrdner . $neuerDateiname;

        // 6. Datei verschieben
        if (move_uploaded_file($temporaererPfad, $endgueltigerPfad)) {
            // Wenn erfolgreich, merken wir uns den Pfad
            $erfolgreichGespeichert[] =['image_url'=> $endgueltigerPfad,'is_main_image'=> $i === 0 ? true : false, 'sort_order' => $i];
        } else {
            $fehlerMeldungen[] = "'$originalName' konnte nicht auf dem Server gespeichert werden.";
        }
    }

file_put_contents('logtest.txt', "Erfolgreich: " . print_r($erfolgreichGespeichert, true)  . "\n", FILE_APPEND);


    if(isset($_POST)){
    file_put_contents('logpost.txt', print_r($_POST, true)  . "\n", FILE_APPEND);
    $name = $_POST['name'] ?? '';
    $description = $_POST['description'] ?? '';
    $price = $_POST['price'] ?? 0;
    $sku =  strtoupper(bin2hex(random_bytes(4)));
    $productModel = new ProductModel();
    $productModel->addProduct($name, $sku, $price, $description, $erfolgreichGespeichert);
}
    // ---------------------------------------------------------
    // ZUSAMMENFASSUNG ZURÜCK AN JAVASCRIPT SENDEN (als JSON)
    // ---------------------------------------------------------
    //header('Content-Type: application/json');
    echo json_encode([
        'status' => count($fehlerMeldungen) === 0 ? 'success' : 'partial',
        'gespeichert' => $erfolgreichGespeichert,
        'fehler' => $fehlerMeldungen
    ]);

} else {
    echo json_encode(['status' => 'error', 'message' => 'Keine Bilder empfangen.']);
}




















        // $name = $_POST['name'];
        // $price = $_POST['price'];
        // $description = $_POST['description'];
        // $image = $_FILES['image']['name'];
        // $target = "uploads/" . basename($image);

        // Move the uploaded file to the target directory
        // if (move_uploaded_file($_FILES['image']['tmp_name'], $target)) {
        //     // File upload successful, now save product details to the database
        //     $db = new Database();
        //     $db->query("INSERT INTO products (name, price, description, image) VALUES (:name, :price, :description, :image)");
        //     $db->bind(':name', $name);
        //     $db->bind(':price', $price);
        //     $db->bind(':description', $description);
        //     $db->bind(':image', $image);
        //     if ($db->execute()) {
        //         header('Location: ' . URL_ROOT . '/products');
        //         exit();
        //     } else {
        //         echo "Error saving product to database.";
        //     }
        // } else {
        //     echo "Error uploading image.";
        // }
    }
}
?>

./shop/app/Controllers/AuthController.php

<?php

class AuthController
{
    public function login()
    {
        $model = new LoginModel();
       $AuthStatus= $model->authenticate($_POST['email'], $_POST['password']);
       if ($AuthStatus) {
            // Erfolg
            $_SESSION['user'] = $AuthStatus;
            header('Location: ' . APP_URL . 'home');
            exit;
        } else{
            $login_Msg = 'Ungültige Zugangsdaten';

        }

        // Fehler
        $error = 'Ungültige Zugangsdaten';
        require APP_ROOT . '/app/Views/login.php';
    }

    public function logout()
    {
        session_start();
        session_destroy();
        header('Location: ' . APP_URL . 'login');
        exit;
    }
    public function register (){
        $vorname = htmlentities($_POST['vorname']);
        $nachname = htmlentities($_POST['nachname']);
        $email =filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
        $adresse = htmlentities($_POST['adresse']);
        $geburtsdatum = htmlentities($_POST['geburtsdatum']);
        $password = htmlentities($_POST['password']);
        $password_confirm = htmlentities($_POST['password_confirm']);
        // Validierung
        if (empty($vorname) || empty($nachname) || empty($email) || empty($adresse) || empty($geburtsdatum) || empty($password) || empty($password_confirm)) {
            $error = 'Alle Felder müssen ausgefüllt sein!';
            $title = 'Registrierung';
            require_once APP_ROOT . '/app/Views/register.php';
            return;
        }
        if($password !== $password_confirm){
            $error = 'Die Passwörter stimmen nicht überein!';
            $title = 'Registrierung';
            require_once APP_ROOT . '/app/Views/register.php';
            return;
        }
        $model = new RegisterModel();
        $registerStatus = $model->register($vorname, $nachname, $email, $adresse, $geburtsdatum, $password);
        if ($registerStatus) {
            $success = 'Registrierung erfolgreich! Du kannst dich jetzt anmelden.';
            require_once APP_ROOT . '/app/Views/register.php';
        } else {
            $error = 'Registrierung fehlgeschlagen. Bitte versuche es erneut.';
            require_once APP_ROOT . '/app/Views/register.php';
        }


    }
}
?>

./shop/app/Controllers/HomeController.php

<?php
/**
 * Home Controller
 */

class HomeController {
    
    public function index() {
        $title = 'Home';
        require_once APP_ROOT . '/app/Views/home.php';
    }
}
?>

./shop/app/Controllers/LoginController.php

<?php
class LoginController {
    
    public function index() {
        $title = 'Login';
        require_once APP_ROOT . '/app/Views/login.php';
    }
}

./shop/app/Controllers/ProductController.php

<?php
class ProductController {
    public function index() {
        $id = $_GET['params']['id'] ?? null;
        if (!$id) {
            echo "Produkt ID fehlt";
            return;
        }

        $productModel = new ProductModel();
        $product = $productModel->getProductById($id);

        if (!$product || empty($product)) {
            echo "Produkt nicht gefunden";
            return;
            exit;
        }

        // Extrahiere die Produktdaten
        extract($product[0]);

        // Lade Produktbilder
        $imagesData = $productModel->getProductImages($id);
        $images = [];
        if ($imagesData) {
            foreach ($imagesData as $img) {
                $images[] = $img['image_path'];
            }
        }

        // Lade die View
        require_once APP_ROOT . '/app/Views/products.php';
    }
}

./shop/app/Controllers/RegisterController.php

<?php

class RegisterController {
    public function index() {
        $title = 'Registrierung';
        require_once APP_ROOT . '/app/Views/register.php';
    }
    
    public function store() {
        // POST-Anfrage verarbeiten
        $vorname = trim($_POST['vorname'] ?? '');
        $nachname = trim($_POST['nachname'] ?? '');
        $email = trim($_POST['email'] ?? '');
        $adresse = trim($_POST['adresse'] ?? '');
        $geburtsdatum = trim($_POST['geburtsdatum'] ?? '');
        $password = trim($_POST['password'] ?? '');
        $password_confirm = trim($_POST['password_confirm'] ?? '');
        
        // Validierung
        if (empty($vorname) || empty($nachname) || empty($email) || empty($adresse) || empty($geburtsdatum) || empty($password) || empty($password_confirm)) {
            $error = 'Alle Felder müssen ausgefüllt sein!';
            $title = 'Registrierung';
            require_once APP_ROOT . '/app/Views/register.php';
            return;
        }
        
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $error = 'Bitte gib eine gültige E-Mail Adresse ein!';
            $title = 'Registrierung';
            require_once APP_ROOT . '/app/Views/register.php';
            return;
        }
        
        if (strlen($password) < 6) {
            $error = 'Das Passwort muss mindestens 6 Zeichen lang sein!';
            $title = 'Registrierung';
            require_once APP_ROOT . '/app/Views/register.php';
            return;
        }
        
        if ($password !== $password_confirm) {
            $error = 'Die Passwörter stimmen nicht überein!';
            $title = 'Registrierung';
            require_once APP_ROOT . '/app/Views/register.php';
            return;
        }
        
        // Geburtsdatum validieren
        $dob = DateTime::createFromFormat('Y-m-d', $geburtsdatum);
        if (!$dob || $dob > new DateTime()) {
            $error = 'Bitte gib ein gültiges Geburtsdatum ein!';
            $title = 'Registrierung';
            require_once APP_ROOT . '/app/Views/register.php';
            return;
        }
        
        // TODO: Prüfe ob Email bereits existiert
        // TODO: Speichere neuen Benutzer in der Datenbank mit gehashtem Passwort
        // password_hash($password, PASSWORD_BCRYPT)
        
        $success = 'Registrierung erfolgreich! Du kannst dich jetzt anmelden.';
        $_POST = []; // Clear form
        $title = 'Registrierung';
        require_once APP_ROOT . '/app/Views/register.php';
    }
}

./shop/app/Controllers/TestController.php

<?php
/**
 * test Controller
 */

class TestController {
    
    public function index() {
        $title = 'test';
       // echo "Test funktioniert!";
        require_once APP_ROOT . '/app/Views/test.php';
    }
}
?>

./shop/app/Controllers/cartController.php

<?php
$_SESSION['cart_items'] ;
//=[['product_id'=>13,'count'=>1],['product_id'=>14,'cout'=>2]];
class CartController{
    public $products=[];
   public function getCart_items(){
    header('Content-Type: application/json');
    $cart_itemes=$_SESSION['cart_items'] ?? [];
  //  echo json_encode($cart_itemes); 
  $model=new ProductModel();
    foreach($cart_itemes as $key => $item){
        $cart_itemes[$key]+=$model->getProductForcart($item['product_id']);


        
       
    }
    echo json_encode($cart_itemes);
//    file_put_contents('TEST.txt', print_r($cart_itemes));
   }
   public function addToCart($product_id){
    $cart_itemes=$_SESSION['cart_items'] ?? [];
    if(isset($cart_itemes[$product_id])){
        $cart_itemes[$product_id]++;
    }else{
        $cart_itemes[$product_id]=1;
    }
    $_SESSION['cart_items']=$cart_itemes;
   } 



    public function update(){
     $input = json_decode(file_get_contents('php://input'), true);
     $product_id = $input['product_id'] ?? null;
     $quantity = $input['quantity'] ?? null;
    
     if ($product_id !== null && $quantity !== null) {
          $cart_itemes=$_SESSION['cart_items'] ?? [];
          $found = false;
          foreach ($cart_itemes as $key => $item) {
              if (isset($item['product_id']) && $item['product_id'] == $product_id) {
                  $found = true;
                  if ($quantity > 0) {
                      $cart_itemes[$key]['count'] = (int)$quantity;
                  } else {
                      unset($cart_itemes[$key]);
                  }
                  break;
              }
          }
          // reindex numeric keys
          $cart_itemes = array_values($cart_itemes);
          $_SESSION['cart_items'] = $cart_itemes;
          if ($found) {
              echo json_encode(['status' => 'success', 'cart' => $cart_itemes]);
          } else {
              echo json_encode(['status' => 'error', 'message' => 'Product not in cart']);
          }
     } else {
          echo json_encode(['status' => 'error', 'message' => 'Invalid input']);
     }
    }
}

./shop/app/Models/DbModel.php

<?php
require_once dirname(__DIR__) . '/../config/config.php';

class DbModel{
    private $host = DB_HOST;
    private $db_name = DB_NAME;
    private $username = DB_USER;
    private $password =  DB_PASS;
    public $conn;
    public $sql;
    public $dat=[];
    public $fehler;


public function __construct(){
  try {
            $this->conn = new PDO(
                "mysql:host={$this->host};dbname={$this->db_name};charset=utf8",
                $this->username,
                $this->password,
                [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
            );
        } catch (PDOException $e) {
            die("Datenbankverbindung fehlgeschlagen: " . $e->getMessage());
        }
    
}

//select funktion
 public function select ($table, $spalten=["*"], $where = [], $fehler = "Fehler bei SELECT") {
// $where =[spalte => bedinung]
        $dat=[];
         $sql = "select ";
         $spalten_last=end($spalten);
         reset($spalten);
    foreach($spalten as $e){
            if ($e == $spalten_last) {
                $sql .= " " . $e . " ";
           }else{
            $sql .= " " . $e . ",";
        }}
            $sql .= " from " . $table;
            if (!empty($where)) {
                $sql.=" where";
                $lastkey=array_key_last($where);
                foreach ($where as $key => $value) {
                    if ($lastkey!=$key){
                    $sql.= " ".$key ."= :$key and";
                    $dat[$key]=$value;
                }else{
                     $sql.= " ".$key ."= :$key ";
                    $dat[$key]=$value;
                }
                }
        }
        
    

// Klasseneigenschaften setzen und ausführen
        $this->sql = $sql;
        $this->dat = $dat;
        $this->fehler = $fehler;

        return $this->execute();
    }
    #select funktion Ende

#isert funktion Anfang

/**
     * Insert in Tabelle
     * @param string $table
     * @param array $inhalt ['spalte' => 'wert']
     * @param string $fehler
     * @return mixed lastInsertId oder bool
     */
    public function insert($table, $inhalt, $fehler = "fehler von insert"){
        $this->fehler = $fehler;
        $this->dat = [];

        $this->sql= "insert into $table (";
        foreach ($inhalt as $key => $value) {
        $this->sql.="$key ,";
        $this->dat[$key]=$value;
    }
$this->sql =rtrim($this->sql,",");
$this->sql.=") Values (";
foreach($inhalt as $key=>$value){
    $this->sql.= " :$key ,";
}
$this->sql =rtrim($this->sql,",");
$this->sql.=" )";


return $this->execute();

}
#insert funktion Ende

    /**
     * Update-Funktion
     * @param string $table Tabelle
     * @param array $inhalt ['spalte' => 'wert']
     * @param array $where  ['spalte' => 'wert']
     * @param string $fehler Fehlertext
     * @return int Anzahl betroffener Zeilen
     */
    public function update($table, $inhalt, $where = [], $fehler = "Fehler bei UPDATE"){
        $this->fehler = $fehler;
        $this->dat = [];
        $this->sql = "UPDATE $table SET ";
        // Set-Teil
        foreach ($inhalt as $key => $value) {
            $this->sql .= "$key = :u_$key ,";
            $this->dat["u_$key"] = $value;
        }
        $this->sql = rtrim($this->sql, ",");
        // Where-Teil
        if (!empty($where)) {
            $this->sql .= " WHERE ";
            $lastkey = array_key_last($where);
            foreach ($where as $key => $value) {
                if ($lastkey != $key) {
                    $this->sql .= "$key = :w_$key AND ";
                } else {
                    $this->sql .= "$key = :w_$key ";
                }
                $this->dat["w_$key"] = $value;
            }
        }

        return $this->execute();
    }

    /**
     * Delete-Funktion
     * @param string $table Tabelle
     * @param array $where ['spalte' => 'wert']
     * @param string $fehler Fehlertext
     * @return int Anzahl betroffener Zeilen
     */
    public function delete($table, $where = [], $fehler = "Fehler bei DELETE"){
        $this->fehler = $fehler;
        $this->dat = [];
        $this->sql = "DELETE FROM $table";
        if (!empty($where)) {
            $this->sql .= " WHERE ";
            $lastkey = array_key_last($where);
            foreach ($where as $key => $value) {
                if ($lastkey != $key) {
                    $this->sql .= "$key = :$key AND ";
                } else {
                    $this->sql .= "$key = :$key ";
                }
                $this->dat[$key] = $value;
            }
        }

        return $this->execute();
    }
    public function rawquery($sql, $dat = [], $fehler = "Fehler bei Query"){
        $this->fehler = $fehler;
        $this->dat = $dat;
        $this->sql = $sql;

        return $this->execute();
    }

/**
     * Führt die vorbereitete SQL-Anweisung aus und liefert je nach Typ sinnvolle Rückgabe zurück:
     * - SELECT: Array von Arrays
     * - INSERT: lastInsertId()
     * - UPDATE/DELETE: Anzahl betroffener Zeilen (rowCount)
     */
    private function execute()
    {
        try {
            $stmt = $this->conn->prepare($this->sql);
            $stmt->execute($this->dat);

            $sqlTrim = ltrim($this->sql);
            $verb = strtolower(strtok($sqlTrim, " "));

            if ($verb === 'select') {
                return $stmt->fetchAll(PDO::FETCH_ASSOC);
            }

            if ($verb === 'insert') {
                return $this->conn->lastInsertId();
            }

            if (in_array($verb, ['update', 'delete'])) {
                return $stmt->rowCount();
            }

            // Standardmäßig die Anzahl der betroffenen Zeilen zurückgeben
            return $stmt->rowCount();
        } catch (PDOException $e) {
            die("$this->fehler: " . $e->getMessage());
        }
    }

}


 


 


 

./shop/app/Models/LoginModel.php

<?php

class LoginModel {
    private $db;

    public function __construct() {
        $this->db = new DbModel();
    }

    public function authenticate($email, $password) {
        $users = $this->db->select('users', ['id',"company_id","email","password"], ['email' => $email]);
        $user = $users[0] ?? null;

        if ($user && password_verify($password, $user['password'])) {
            return $user;
        } else {
            return false;
        }
        
    }
}

./shop/app/Models/ProductModel.php

<?php
class ProductModel extends DbModel{
    public function __construct() {
        parent::__construct();
    }

    public function addProduct($name,$sku, $price, $description, array $images ) {
      $lastinsertid= $this->insert('products', [
            'sku' => $sku,
            'name' => $name,
            'price' => $price,
            'description' => $description,
            
        ]);
        //bessern
        foreach($images as $image){
            $this->addProductImage($lastinsertid,$image['sort_order'],$image['image_url'],$image['is_main_image']);
        }

    }
    public function addProductImage($productId,$sort_order, $imagePath,$isMainImage = false) {
        $this->insert('product_images', [
            'product_id' => $productId,
            'image_url' => $imagePath,
            'is_main_image' => $isMainImage ,
            'sort_order' => $sort_order +1
        ]);
    }
    public function getProductById($id) {
        $product_array= $this->select('products', ['*'], ['id' => $id]);
       
            return $product_array;
        
    }
    public function getProductForcart($id) {
        $product= $this->select('products', ['name','price','stock'], ['id' => $id]);
        if(!empty($product)){
        $product_images=$this->getProductImages($id,['image_url'],['is_main_image' => 1]);
           
            $product['images']=$product_images ?? [];
            return $product;
        }
    }

    public function getProductImages($productId,$columns=['*'],$where=[]){ 
        return $this->select('product_images', $columns, array_merge(['product_id' => $productId],$where));
    }
    
}

./shop/app/Models/RegisterModel.php

<?php
class registerModel {
    private $db;

    public function __construct() {
        $this->db = new DbModel();
    }

    public function register($vorname, $nachname, $email, $adresse, $geburtsdatum, $password) {
        // Überprüfen, ob die E-Mail bereits existiert
        $existingUser = $this->db->select('users', ['id'], ['email' => $email]);
        if (!empty($existingUser)) {
            return false; // E-Mail bereits registriert
        }

        // Passwort hashen
        $hashedPassword = password_hash($password, PASSWORD_DEFAULT);

        // Benutzer in der Datenbank speichern
        $this->db->insert('users', [
            'vorname' => $vorname,
            'nachname' => $nachname,
            'email' => $email,
            'adresse' => $adresse,
            'geburtsdatum' => $geburtsdatum,
            'password' => $hashedPassword
        ]);

        return true; // Registrierung erfolgreich
    }
}

./shop/app/Router.php

<?php
/**
 * Router Class - Object-Oriented Routing
 */

class Router {
    private $routes = [];

    public function get($path, $handler) {
        $this->addRoute('GET', $path, $handler);
    }

    public function post($path, $handler) {
        $this->addRoute('POST', $path, $handler);
    }
     public function put($path, $handler) {
        $this->addRoute('PUT', $path, $handler);
    }

    private function addRoute($method, $path, $handler) {
        $this->routes[] = [
            'method' => $method,
            'path' => $path,
            'handler' => $handler
        ];
    }

    public function dispatch() {
        $requestMethod = $_SERVER['REQUEST_METHOD'];

        if (!empty($_GET['url'])) {
            $requestUri = trim($_GET['url'], '/');
        } else {
            $requestUri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
            $basePath = str_replace('/index.php', '', $_SERVER['SCRIPT_NAME']);
            $requestUri = str_replace($basePath, '', $requestUri);
            $requestUri = trim($requestUri, '/');
        }

        $urlSegments = explode('/', $requestUri);

        foreach ($this->routes as $route) {
            $routePath = trim($route['path'], '/');
            $routeSegments = explode('/', $routePath);

            if ($route['method'] === $requestMethod && $this->matchRoute($routeSegments, $urlSegments)) {
                $this->callHandler($route['handler'], $urlSegments, $routeSegments);
                return;
            }
        }

        // Default route
        $this->callHandler('HomeController@index');
    }

    private function matchRoute($routeSegments, $urlSegments) {
        if (count($routeSegments) !== count($urlSegments)) {
            return false;
        }
        
        foreach ($routeSegments as $i => $segment) {
            if ($segment[0] === ':') continue; // Dynamischer Parameter
            if ($segment !== $urlSegments[$i]) return false;
        }
        
        return true;
    }

    private function callHandler($handler, $urlSegments = [], $routeSegments = []) {
        // Parameter speichern in $_GET['params']
        $_GET['params'] = [];
        foreach ($routeSegments as $i => $segment) {
            if ($segment[0] === ':') {
                $paramName = substr($segment, 1);
                $_GET['params'][$paramName] = $urlSegments[$i];
            }
        }
        
        list($controllerName, $methodName) = explode('@', $handler);
        $controllerFile = APP_ROOT . '/app/Controllers/' . $controllerName . '.php';

        if (file_exists($controllerFile)) {
            require_once $controllerFile;

            if (class_exists($controllerName)) {
                $controller = new $controllerName();

                if (method_exists($controller, $methodName)) {
                    $controller->$methodName();
                } else {
                    echo "Method $methodName not found in $controllerName";
                }
            } else {
                echo "Class $controllerName not found";
            }
        } else {
            echo "Controller $controllerName not found";
        }
    }
}
?>

./shop/app/Views/addproduct.php

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Neues Produkt anlegen</title>
    <style>
        /* --- CSS STYLING --- */
        :root {
            --primary-color: #4A90E2;
            --background: #f4f7f6;
            --surface: #ffffff;
            --text: #333333;
            --border: #e0e0e0;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: var(--background);
            color: var(--text);
            padding: 2rem;
            margin: 0;
            display: flex;
            justify-content: center;
        }

        .container {
            background: var(--surface);
            padding: 2rem;
            border-radius: 10px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.05);
            width: 100%;
            max-width: 600px;
        }

        h2 {
            margin-top: 0;
            border-bottom: 2px solid var(--border);
            padding-bottom: 10px;
        }

        .form-group {
            margin-bottom: 1.5rem;
        }

        label {
            display: block;
            font-weight: bold;
            margin-bottom: 0.5rem;
            font-size: 0.9rem;
        }

        input[type="text"],
        input[type="number"],
        textarea {
            width: 100%;
            padding: 10px;
            border: 1px solid var(--border);
            border-radius: 5px;
            box-sizing: border-box;
            font-family: inherit;
        }

        textarea {
            resize: vertical;
            min-height: 100px;
        }

        .row {
            display: flex;
            gap: 1rem;
        }

        .row .form-group {
            flex: 1;
        }

        .checkbox-group {
            display: flex;
            align-items: center;
            gap: 10px;
            cursor: pointer;
        }

        input[type="checkbox"] {
            width: 18px;
            height: 18px;
            cursor: pointer;
        }

        /* --- NEU: Styling für Upload und Drag & Drop --- */
        .file-upload-wrapper {
            position: relative;
            border: 2px dashed var(--primary-color);
            border-radius: 8px;
            padding: 20px;
            text-align: center;
            background: #f9fbfd;
            transition: background 0.3s;
        }

        .file-upload-wrapper:hover {
            background: #f1f5f9;
        }

        input[type="file"] {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            opacity: 0; /* Versteckt das hässliche Standard-Feld, aber hält es anklickbar */
            cursor: pointer;
        }

        .upload-text {
            color: var(--primary-color);
            font-weight: bold;
        }

        #imagePreview {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin-top: 15px;
        }

        /* Styling für die einzelnen Bild-Kacheln */
        .preview-item {
            position: relative;
            width: 90px;
            height: 90px;
            border-radius: 5px;
            overflow: hidden;
            border: 1px solid var(--border);
            cursor: grab; /* Zeigt an, dass man es greifen kann */
            background: #fff;
        }

        .preview-item:active {
            cursor: grabbing;
        }

        .preview-item img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            pointer-events: none; /* Wichtig für Drag & Drop, damit das Bild nicht stört */
        }

        /* Das rote X zum Löschen eines Bildes */
        .remove-btn {
            position: absolute;
            top: 2px;
            right: 2px;
            background: rgba(255, 0, 0, 0.8);
            color: white;
            border: none;
            border-radius: 50%;
            width: 20px;
            height: 20px;
            font-size: 12px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .remove-btn:hover {
            background: red;
        }

        /* Highlight-Effekt beim Drüberziehen */
        .preview-item.drag-over {
            border: 2px dashed var(--primary-color);
            opacity: 0.5;
        }

        button[type="submit"] {
            background-color: var(--primary-color);
            color: white;
            border: none;
            padding: 12px 20px;
            font-size: 1rem;
            border-radius: 5px;
            cursor: pointer;
            width: 100%;
            font-weight: bold;
            transition: background 0.3s;
            margin-top: 1rem;
        }

        button[type="submit"]:hover {
            background-color: #357ABD;
        }

        #output {
            margin-top: 2rem;
            padding: 1rem;
            background: #2d2d2d;
            color: #4ae26a;
            border-radius: 5px;
            font-family: monospace;
            display: none;
            white-space: pre-wrap;
        }
    </style>
</head>
<body>

    <div class="container">
        <h2>Neues Produkt anlegen</h2>
        
        <form id="productForm">
            
            <div class="row">
                <div class="form-group">
                    <label for="name">Produktname *</label>
                    <input type="text" id="name" name="name" required placeholder="z.B. Premium T-Shirt">
                </div>
                <!-- <div class="form-group">
                    <label for="sku">Artikelnummer (SKU) *</label>
                    <input type="text" id="sku" name="sku" required placeholder="z.B. TS-001-RED">
                </div> -->
            </div>

            <div class="form-group">
                <label for="description">Beschreibung</label>
                <textarea id="description" name="description" placeholder="Beschreibe dein Produkt..."></textarea>
            </div>

            <div class="row">
                <div class="form-group">
                    <label for="price">Preis (€) *</label>
                    <input type="number" id="price" name="price" step="0.01" min="0" required placeholder="19.99">
                </div>
                <div class="form-group">
                    <label for="stock">Lagerbestand *</label>
                    <input type="number" id="stock" name="stock" step="1" min="0" required placeholder="50">
                </div>
            </div>

            <div class="form-group">
                <label>Produktbilder (Zuerst Hauptbild, Drag & Drop zum Sortieren)</label>
                <div class="file-upload-wrapper">
                    <span class="upload-text">Bilder hierher ziehen oder klicken zum Auswählen</span>
                    <input type="file" id="images" name="images" accept="image/png, image/jpeg, image/webp" multiple>
                </div>
                <div id="imagePreview"></div>
            </div>

            <div class="form-group">
                <label class="checkbox-group">
                    <input type="checkbox" id="isActive" name="isActive" checked>
                    Produkt sofort im Shop aktivieren
                </label>
            </div>

            <button type="submit">Produkt speichern</button>
        </form>

        <div id="output"></div>
    </div>

    <script>
        /* --- JAVASCRIPT LOGIK --- */
        
        const form = document.getElementById('productForm');
        const imageInput = document.getElementById('images');
        const previewContainer = document.getElementById('imagePreview');
        const outputBox = document.getElementById('output');

        // Unser eigener Speicher für die Bilder (da wir das input-Feld nicht sortieren können)
        let selectedFiles = [];
        let dragStartIndex; // Merkt sich, welches Bild gerade gezogen wird

        // 1. Bilder auswählen und zum Array hinzufügen
        imageInput.addEventListener('change', function() {
            const files = Array.from(this.files);
            
            files.forEach(file => {
                if(file.type.startsWith('image/')) {
                    selectedFiles.push(file); // Ins eigene Array schieben
                }
            });

            // Das Input-Feld wieder leeren, damit man das gleiche Bild nochmal anklicken könnte
            this.value = ''; 
            
            // Vorschau neu zeichnen
            renderPreview();
        });

        // 2. Funktion zum Zeichnen der Vorschau-Bilder
        function renderPreview() {
            previewContainer.innerHTML = ''; // Alles leeren

            selectedFiles.forEach((file, index) => {
                // Den Container (die Kachel) für ein Bild bauen
                const item = document.createElement('div');
                item.classList.add('preview-item');
                item.setAttribute('draggable', 'true'); // Wichtig für Drag & Drop
                item.setAttribute('data-index', index);

                // Das Bild erzeugen
                const img = document.createElement('img');
                img.src = URL.createObjectURL(file);
                img.onload = () => URL.revokeObjectURL(img.src); // Speicherplatz freigeben

                // Den Löschen-Button bauen
                const removeBtn = document.createElement('button');
                removeBtn.classList.add('remove-btn');
                removeBtn.innerHTML = '✖';
                removeBtn.type = 'button'; // Wichtig, sonst schickt der Button das Formular ab
                removeBtn.onclick = () => {
                    selectedFiles.splice(index, 1); // Bild aus Array löschen
                    renderPreview(); // Neu zeichnen
                };

                // Drag & Drop Events anfügen
                item.addEventListener('dragstart', dragStart);
                item.addEventListener('dragover', dragOver);
                item.addEventListener('drop', dragDrop);
                item.addEventListener('dragenter', dragEnter);
                item.addEventListener('dragleave', dragLeave);

                item.appendChild(img);
                item.appendChild(removeBtn);
                previewContainer.appendChild(item);
            });
        }

        // --- DRAG & DROP LOGIK ---
        function dragStart(e) {
            dragStartIndex = +this.getAttribute('data-index');
        }

        function dragOver(e) {
            e.preventDefault(); // Zwingend notwendig, um das "Drop" Event zu erlauben
        }

        function dragEnter(e) {
            this.classList.add('drag-over'); // Zeigt visuell, wo das Bild landen würde
        }

        function dragLeave(e) {
            this.classList.remove('drag-over');
        }

        function dragDrop(e) {
            this.classList.remove('drag-over');
            const dragEndIndex = +this.getAttribute('data-index');

            // Elemente im Array vertauschen (Das gezogene Bild an die neue Position setzen)
            const itemToMove = selectedFiles.splice(dragStartIndex, 1)[0];
            selectedFiles.splice(dragEndIndex, 0, itemToMove);

            // Ansicht aktualisieren
            renderPreview();
        }

        // 3. Formular absenden (Jetzt übernehmen wir die volle Kontrolle)
        form.addEventListener('submit', function(event) {
            // Wir MÜSSEN das Standard-Absenden blockieren, da wir unser eigenes `selectedFiles` Array haben
            event.preventDefault(); 

            // FormData sammelt alle Text-Inputs automatisch
            const formData = new FormData(form);
            
            // Da das Standard-Feld für Bilder leer ist (wir haben es oben geleert), 
            // fügen wir jetzt unsere mühsam sortierten Bilder manuell hinzu!
            selectedFiles.forEach((file, index) => {
                // Fügt die Dateien als Array "images[]" an das Backend an
                formData.append('images[]', file);
            });

            // --- HIER KOMMT DIE ECHTE BACKEND ANBINDUNG HIN ---
            
            fetch('<?php echo APP_URL; ?>addproduct', {
                method: 'POST',
                body: formData
            }).then(response => {
                // Erfolgreich gespeichert!
                response.json().then(data => {
                    alert(data.status); // Zeigt die Erfolgsmeldung vom Backend
                    // Hier könntest du auch die Seite neu laden oder zum Produkt-Listing weiterleiten
                });
            });
           

            // --- SIMULATION FÜR DICH ZUR ANSICHT ---
            const resultData = {
                name: formData.get('name'),
                sku: formData.get('sku'),
                price: formData.get('price'),
                // Zeigt dir, dass die Dateien in der korrekten, neuen Reihenfolge vorliegen:
                uploadedFiles: selectedFiles.map((f, i) => `Position ${i+1}: ${f.name}`)
            };

            // outputBox.style.display = 'block';
            // outputBox.textContent = "Senden simuliert! Die sortierten Bilder werden jetzt so ans PHP-Backend übergeben:\n\n" + JSON.stringify(resultData, null, 4);
        });
    </script>

</body>
</html>

./shop/app/Views/header.php

<nav class="navbar">

    <!-- LOGO -->
    <div class="logo">
        WEB<span>SHOP</span>
    </div>

    <!-- MENÜ -->
    <ul class="nav-links" id="menu">
        <li><a href="#">Startseite</a></li>
        <li><a href="#">Produkte</a></li>
        <li><a href="#">Kollektionen</a></li>
        <li><a href="#">Über uns</a></li>
        <li><a href="#">Kontakt</a></li>
    </ul>

    <!-- RECHTS -->
    <div class="right-side">

        <!-- WARENKORB -->
        <button class="cart-btn" id="openCart">

            <div class="cart-count">2</div>

            <!-- SVG -->
            <svg 
                fill="none" 
                stroke-width="2" 
                stroke-linecap="round" 
                stroke-linejoin="round" 
                viewBox="0 0 24 24">

                <circle cx="9" cy="21" r="1"></circle>
                <circle cx="20" cy="21" r="1"></circle>

                <path d="M1 1h4l2.68 13.39
                         a2 2 0 0 0 2 1.61h9.72
                         a2 2 0 0 0 2-1.61L23 6H6"></path>

            </svg>

        </button>

        <!-- HAMBURGER -->
        <div class="hamburger" id="hamburger">
            <span></span>
            <span></span>
            <span></span>
        </div>

    </div>

</nav>



    <!-- OVERLAY -->
    <div class="cart-overlay" id="cartOverlay"></div>

   

    <!-- SIDEBAR -->
    <aside class="cart-sidebar" id="cartSidebar">

        <!-- HEADER -->
        <div class="cart-header">

            <h2>Warenkorb</h2>

            <button class="close-cart" id="closeCart">
                ✕
            </button>

        </div>

        <!-- PRODUKTE -->
        <div class="cart-items" id="cart-Items">

            <!-- ITEM -->
            <div class="cart-item">

                <img src="https://picsum.photos/100" alt="Produkt">

                <div class="item-info">
                    <h3>Premium Hoodie</h3>
                    <p>79,99 €</p>

                    <div class="quantity">
                        <button>-</button>
                        <span>1</span>
                        <button>+</button>
                    </div>
                </div>

            </div>

            <!-- ITEM -->
            <div class="cart-item" >

                <img src="https://picsum.photos/101" alt="Produkt">

                <div class="item-info">
                    <h3>Sneaker Pro</h3>
                    <p>129,99 €</p>

                    <div class="quantity">
                        <button>-</button>
                        <span>2</span>
                        <button>+</button>
                    </div>
                </div>

            </div>

        </div>

        <!-- FOOTER -->
        <div class="cart-footer">

            <div class="cart-total">
                <span>Gesamt</span>
                <strong id="full_price">339,97 €</strong>
            </div>

            <button class="checkout-btn">
                Zur Kasse
            </button>

        </div>

    </aside>

    

./shop/app/Views/home.php

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php echo isset($title) ? $title : 'MVC Application'; ?></title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        .container {
            background: white;
            padding: 50px;
            border-radius: 10px;
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
            text-align: center;
            max-width: 600px;
        }
        h1 {
            color: #333;
            margin-bottom: 20px;
        }
        p {
            color: #666;
            line-height: 1.6;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Willkommen zur MVC-Anwendung</h1>
        <p>Ihre MVC-Struktur wurde erfolgreich aufgesetzt!</p>
        <p style="margin-top: 30px; font-size: 14px; color: #999;">
            Ordnerstruktur: app/ (Models, Views, Controllers) | config/ | public/
        </p>
    </div>
</body>
</html>

./shop/app/Views/login.php

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background: #f0f4f8;
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            margin: 0;
        }
        .login-box {
            width: 360px;
            padding: 30px 40px;
            background: #fff;
            box-shadow: 0 8px 25px rgba(0,0,0,0.1);
            border-radius: 10px;
        }
        .login-box h1 {
            font-size: 24px;
            margin-bottom: 20px;
            text-align: center;
            color: #333;
        }
        .input-group {
            margin-bottom: 18px;
        }
        .input-group label {
            display: block;
            margin-bottom: 6px;
            color: #555;
            font-size: 14px;
        }
        .input-group input {
            width: 100%;
            padding: 10px;
            border: 1px solid #ccd6dd;
            border-radius: 6px;
            font-size: 14px;
            box-sizing: border-box;
        }
        .login-action {
            margin-top: 20px;
            text-align: center;
        }
        .login-action button {
            width: 100%;
            padding: 11px;
            background: #4d84ff;
            color: white;
            border: none;
            border-radius: 6px;
            font-size: 15px;
            cursor: pointer;
        }
        .login-action button:hover {
            background: #3f6ee6;
        }
    </style>
</head>
<body>
    <div class="login-box">
        <h1>Login</h1>
        <form method="post" action="./login">
            <div class="input-group">
                <label for="username">Benutzername</label>
                <input type="email" id="email" name="email" required autofocus>
            </div>
            <div class="input-group">
                <label for="password">Passwort</label>
                <input type="password" id="password" name="password" required>
            </div>
            <div class="login-action">
                <button type="submit">Anmelden</button>
            </div>
            <div><?php echo $login_Msg ?? "" ?> </div>
        </form>
    </div>
</body>
</html>

./shop/app/Views/products.php

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php echo htmlspecialchars($name ?? 'Produkt'); ?> - Shop</title>
    
    </style>
    <link rel="stylesheet" href="<?= APP_URL ?>/styles/header.css">
</head>
<body>
    
<?php require_once  APP_ROOT . '/app/Views/header.php'; ?>
<script src="<?= APP_URL ?>/scripts/header.js"></script>
</body>
</html>

./shop/app/Views/register.php

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Registrierung</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        
        .container {
            background: white;
            padding: 40px;
            border-radius: 10px;
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
            width: 100%;
            max-width: 550px;
        }
        
        .form-row {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
        }
        
        h1 {
            text-align: center;
            color: #333;
            margin-bottom: 30px;
            font-size: 28px;
        }
        
        .form-group {
            margin-bottom: 20px;
        }
        
        label {
            display: block;
            margin-bottom: 8px;
            color: #555;
            font-weight: bold;
        }
        
        input {
            width: 100%;
            padding: 12px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 14px;
            transition: border-color 0.3s;
        }
        
        input:focus {
            outline: none;
            border-color: #667eea;
            box-shadow: 0 0 5px rgba(102, 126, 234, 0.1);
        }
        
        .btn-register {
            width: 100%;
            padding: 12px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            border-radius: 5px;
            font-size: 16px;
            font-weight: bold;
            cursor: pointer;
            transition: transform 0.2s;
            margin-top: 10px;
        }
        
        .btn-register:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }
        
        .login-link {
            text-align: center;
            margin-top: 20px;
            color: #666;
        }
        
        .login-link a {
            color: #667eea;
            text-decoration: none;
            font-weight: bold;
        }
        
        .login-link a:hover {
            text-decoration: underline;
        }
        
        .error {
            background-color: #fee;
            color: #c33;
            padding: 12px;
            border-radius: 5px;
            margin-bottom: 20px;
            border-left: 4px solid #c33;
        }
        
        .success {
            background-color: #efe;
            color: #3c3;
            padding: 12px;
            border-radius: 5px;
            margin-bottom: 20px;
            border-left: 4px solid #3c3;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Registrierung</h1>
        
        <?php if (isset($error) && !empty($error)): ?>
            <div class="error"><?php echo htmlspecialchars($error); ?></div>
        <?php endif; ?>
        
        <?php if (isset($success) && !empty($success)): ?>
            <div class="success"><?php echo htmlspecialchars($success); ?></div>
        <?php endif; ?>
        
        <form method="POST" action="<?php echo APP_URL; ?>register">
            <div class="form-row">
                <div class="form-group">
                    <label for="vorname">Vorname:</label>
                    <input 
                        type="text" 
                        id="vorname" 
                        name="vorname" 
                        required 
                        placeholder="Max"
                        value="<?php echo isset($_POST['vorname']) ? htmlspecialchars($_POST['vorname']) : ''; ?>"
                    >
                </div>
                
                <div class="form-group">
                    <label for="nachname">Nachname:</label>
                    <input 
                        type="text" 
                        id="nachname" 
                        name="nachname" 
                        required 
                        placeholder="Mustermann"
                        value="<?php echo isset($_POST['nachname']) ? htmlspecialchars($_POST['nachname']) : ''; ?>"
                    >
                </div>
            </div>
            
            <div class="form-group">
                <label for="email">E-Mail Adresse:</label>
                <input 
                    type="email" 
                    id="email" 
                    name="email" 
                    required 
                    placeholder="deine@email.de"
                    value="<?php echo isset($_POST['email']) ? htmlspecialchars($_POST['email']) : ''; ?>"
                >
            </div>
            
            <div class="form-group">
                <label for="adresse">Adresse:</label>
                <input 
                    type="text" 
                    id="adresse" 
                    name="adresse" 
                    required 
                    placeholder="Musterstraße 123, 12345 Musterstadt"
                    value="<?php echo isset($_POST['adresse']) ? htmlspecialchars($_POST['adresse']) : ''; ?>"
                >
            </div>
            
            <div class="form-group">
                <label for="geburtsdatum">Geburtsdatum:</label>
                <input 
                    type="date" 
                    id="geburtsdatum" 
                    name="geburtsdatum" 
                    required
                    value="<?php echo isset($_POST['geburtsdatum']) ? htmlspecialchars($_POST['geburtsdatum']) : ''; ?>"
                >
            </div>
            
            <div class="form-row">
                <div class="form-group">
                    <label for="password">Passwort:</label>
                    <input 
                        type="password" 
                        id="password" 
                        name="password" 
                        required 
                        placeholder="Mindestens 6 Zeichen"
                        minlength="6"
                    >
                </div>
                
                <div class="form-group">
                    <label for="password_confirm">Passwort wiederholen:</label>
                    <input 
                        type="password" 
                        id="password_confirm" 
                        name="password_confirm" 
                        required 
                        placeholder="Passwort bestätigen"
                        minlength="6"
                    >
                </div>
            </div>
            
            <button type="submit" class="btn-register">Registrieren</button>
        </form>
        
        <div class="login-link">
            Bereits registriert? <a href="<?php echo APP_URL; ?>login">Hier anmelden</a>
        </div>
    </div>
</body>
</html>

./shop/app/Views/test.php

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php echo isset($title) ? $title : 'MVC Application'; ?></title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        .container {
            background: white;
            padding: 50px;
            border-radius: 10px;
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
            text-align: center;
            max-width: 600px;
        }
        h1 {
            color: #333;
            margin-bottom: 20px;
        }
        p {
            color: #666;
            line-height: 1.6;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Willkommen zur MVC-Anwendung</h1>
        <p>Ihre MVC-Struktur wurde erfolgreich aufgesetzt!</p>
        <p style="margin-top: 30px; font-size: 14px; color: #999;">
            Ordnerstruktur: app/ (Models, Views, Controllers) | config/ | public/
        </p>
    </div>
</body>
</html>

./shop/config/autoload.php

<?php
/**
 * Autoload Configuration
 */

// Autoload Models
function autoloadModel($class) {
    $modelFile = APP_ROOT . '/app/Models/' . $class . '.php';
    if (file_exists($modelFile)) {
        require_once $modelFile;
    }
}
spl_autoload_register('autoloadModel');

// Autoload Controllers
function autoloadController($class) {
    $controllerFile = APP_ROOT . '/app/Controllers/' . $class . '.php';
    if (file_exists($controllerFile)) {
        require_once $controllerFile;
    }
}
spl_autoload_register('autoloadController');
?>

./shop/public/index.php

<?php

/**
 * MVC Application - Main Entry Point
 * Located in public folder (Document Root)
 */

define('APP_ROOT', dirname(__FILE__) . '/..');
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443 ? 'https://' : 'http://';
define('APP_URL', $scheme . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['SCRIPT_NAME']), '\\/') . '/');

// Start session
session_start();

// Autoload classes
require_once APP_ROOT . '/config/autoload.php';

// Include Router
require_once APP_ROOT . '/app/Router.php';

// Create Router instance
$router = new Router();

// Define routes
$router->get('/home', 'HomeController@index');
$router->get('/login', 'LoginController@index');
$router->post('/login', 'AuthController@login');
$router->get('/test', 'TestController@index');
$router->get('/logout', 'AuthController@logout');
$router->get('/register', 'RegisterController@index');
$router->post('/register', 'AuthController@register');
$router->get('/addproduct', 'AddProductController@index');
$router->post('/addproduct', 'AddProductController@store');
$router->get('/products/:id', 'ProductController@index');
$router->get('/cart', 'CartController@getCart_items');
$router->put('/cart', 'CartController@update');

// Dispatch the route
$router->dispatch();
?>

./shop/public/scripts/header.js

const baseUrl = window.location.origin +"/shop/public"; // Dynamisch die Basis-URL ermitteln

const hamburger = document.getElementById("hamburger");
const menu = document.getElementById("menu");

hamburger.addEventListener("click", () => {
    menu.classList.toggle("active");
    getCartItems();
});
// warenkorb
const openCart = document.getElementById("openCart");
const closeCart = document.getElementById("closeCart");

const cartSidebar = document.getElementById("cartSidebar");
const cartOverlay = document.getElementById("cartOverlay");
const fullPriceElement = document.getElementById("full_price");
let delayTimer;

/* ÖFFNEN */

openCart.addEventListener("click", () => {

    cartSidebar.classList.add("active");
    cartOverlay.classList.add("active");

});

/* SCHLIESSEN */

closeCart.addEventListener("click", () => {

    cartSidebar.classList.remove("active");
    cartOverlay.classList.remove("active");

});

/* OVERLAY */

cartOverlay.addEventListener("click", () => {

    cartSidebar.classList.remove("active");
    cartOverlay.classList.remove("active");

});

// cart inhalt
function getCartItems() {
    fetch(baseUrl+'/cart')
        .then(response => response.json())
        .then(data => {
            const cartItemsContainer = document.getElementById('cart-Items');
            cartItemsContainer.innerHTML = ''; 
            console.log(data);
            data.forEach(item => {
                const cartItem = document.createElement('div');
                cartItem.classList.add('cart-item');
                const product = item[0] || {};
                const imageUrl = item.images && item.images[0] ? item.images[0].image_url : '';
                const quantity = item.count ?? item.quantity ?? 0;
                const id = item.id ?? item.product_id ?? '';
                cartItem.innerHTML = `
                    <img src="${imageUrl.replace(/\\/g, '/')}" alt="${product.name || ''}">
                    <div class="cart-item-details"> 
                        <h4>${product.name || 'Unknown product'}</h4>
                        <p>Price: $${product.price || '0.00'}</p>
                         <div class="quantity">
                        <button onclick='removeQuantity()'>-</button>
                        <span>${quantity}</span>
                        <button onclick=addQuantity()>+</button>
                        <input type="hidden" value="${id}">
                    </div>
                    </div>
                `;
                cartItemsContainer.appendChild(cartItem);
            });
            console.log(data);
        })
        .catch(error => console.error('Error fetching cart items:', error));
}
window.onload = getCartItems;


function addQuantity() {
    event.target.previousElementSibling.textContent = parseInt(event.target.previousElementSibling.textContent) + 1;
    let id = event.target.nextElementSibling.value;
    let quantity = parseInt(event.target.previousElementSibling.textContent);
    delyupdate(() => updateCart(id, quantity));
  

}
function removeQuantity() {
    const quantityElement = event.target.nextElementSibling;
    const currentQuantity = parseInt(quantityElement.textContent);  
    if (currentQuantity > 0) {
        quantityElement.textContent = currentQuantity - 1;
            let id = event.target.parentElement.querySelector('input[type="hidden"]').value;
            let  quantity = parseInt(event.target.nextElementSibling.textContent);
            delyupdate(() => updateCart(id, quantity));
  

    }   
}

function delyupdate(functionName) {
    if (delayTimer) {
        clearTimeout(delayTimer);
    }
   delayTimer=  setTimeout(() => {
        functionName();
    }, 1000);
}

function updateCart(id, quantity) {
    fetch(baseUrl+'/cart', {
        method: 'put',
        headers: {
            'Content-Type': 'application/json'

        },
        body: JSON.stringify({ product_id : id, quantity: quantity })
    })
    .then(response => response.json())
    .then(data => {
        console.log('Cart updated:', data); })
    .catch(error => console.error('Error updating cart:', error));
}

cartSidebar.addEventListener('click', function(event) {
  
    cartSidebar.querySelectorAll('.cart-item').forEach(item => {
        const priceElement = item.querySelector('.cart-item-details p');
        const priceText = priceElement.textContent.replace('Price: $', '').trim();
        console.log(priceText);
       // const priceMatch = priceText.match(/Price: \$(\d+(\.\d{2})?)/);
      
            const price = priceText;
            const quantityElement = item.querySelector('.quantity span');
            const quantity = parseInt(quantityElement.textContent);
            const totalPrice = (price * quantity).toFixed(2);
           // priceElement.textContent = `Price: $${totalPrice}`;
            fullPriceElement.textContent = `Total: $${totalPrice}`;
    });

});

./shop/public/styles/header.css


*{
    margin:0;
    padding:0;
    box-sizing:border-box;
    font-family:Inter, Arial, sans-serif;
}

body{
    background:#f5f7fb;
    min-height:100vh;
}

/* =========================
   NAVBAR
========================= */

.navbar{
    width:100%;
    height:85px;
    background:#ffffff;
    display:flex;
    align-items:center;
    justify-content:space-between;
    padding:0 50px;
    border-bottom:1px solid #e8edf3;
    position:sticky;
    top:0;
    z-index:999;
}

/* =========================
   LOGO
========================= */

.logo{
    font-size:28px;
    font-weight:800;
    color:#111827;
    letter-spacing:-1px;
}

.logo span{
    color:#2563eb;
}

/* =========================
   MENÜ
========================= */

.nav-links{
    display:flex;
    list-style:none;
    gap:40px;
}

.nav-links a{
    text-decoration:none;
    color:#374151;
    font-size:16px;
    font-weight:500;
    position:relative;
    transition:0.3s;
}

.nav-links a::after{
    content:"";
    position:absolute;
    left:0;
    bottom:-8px;
    width:0%;
    height:2px;
    background:#2563eb;
    transition:0.3s;
}

.nav-links a:hover{
    color:#111827;
}

.nav-links a:hover::after{
    width:100%;
}

/* =========================
   RECHTE SEITE
========================= */

.right-side{
    display:flex;
    align-items:center;
    gap:18px;
}

/* =========================
   WARENKORB BUTTON
========================= */

.cart-btn{
    position:relative;
    width:56px;
    height:56px;
    border:none;
    border-radius:18px;
    background:#111827;
    display:flex;
    align-items:center;
    justify-content:center;
    cursor:pointer;
    transition:0.3s;
    box-shadow:
        0 10px 25px rgba(17,24,39,0.15);
}

.cart-btn:hover{
    transform:translateY(-2px);
    background:#2563eb;
}

.cart-btn svg{
    width:24px;
    height:24px;
    stroke:white;
}

/* BADGE */

.cart-count{
    position:absolute;
    top:-5px;
    right:-5px;
    width:24px;
    height:24px;
    border-radius:50%;
    background:#2563eb;
    color:white;
    font-size:12px;
    font-weight:700;
    display:flex;
    align-items:center;
    justify-content:center;
    border:3px solid white;
}

/* =========================
   HAMBURGER
========================= */

.hamburger{
    width:48px;
    height:48px;
    border-radius:14px;
    background:#f3f4f6;
    display:none;
    flex-direction:column;
    justify-content:center;
    align-items:center;
    gap:5px;
    cursor:pointer;
    transition:0.3s;
}

.hamburger:hover{
    background:#e5e7eb;
}

.hamburger span{
    width:22px;
    height:2px;
    background:#111827;
    border-radius:10px;
    transition:0.3s;
}

/* =========================
   MOBILE
========================= */

@media(max-width:950px){

    .navbar{
        padding:0 20px;
    }

    .hamburger{
        display:flex;
    }

    .nav-links{
        position:absolute;
        top:85px;
        left:0;
        width:100%;
        background:white;
        flex-direction:column;
        align-items:center;
        gap:30px;
        padding:40px 0;
        border-bottom:1px solid #e5e7eb;
        display:none;
    }

    .nav-links.active{
        display:flex;
    }

}







/* warenkorb */



*{
    margin:0;
    padding:0;
    box-sizing:border-box;
    font-family:Inter, Arial, sans-serif;
}

body{
    background:#f4f7fb;
    min-height:100vh;
}

/* =========================
   BUTTON
========================= */

.cart-button{
    position:fixed;
    top:30px;
    right:30px;

    width:64px;
    height:64px;

    border:none;
    border-radius:20px;

    background:#111827;
    color:white;

    display:flex;
    align-items:center;
    justify-content:center;

    cursor:pointer;

    box-shadow:
        0 10px 30px rgba(0,0,0,0.15);

    transition:0.3s;
}

.cart-button:hover{
    transform:translateY(-3px);
    background:#2563eb;
}

.cart-button svg{
    width:28px;
    height:28px;
}

/* BADGE */

.cart-count{
    position:absolute;
    top:-5px;
    right:-5px;

    width:24px;
    height:24px;

    border-radius:50%;

    background:#2563eb;
    color:white;

    display:flex;
    align-items:center;
    justify-content:center;

    font-size:12px;
    font-weight:700;

    border:3px solid white;
}

/* =========================
   OVERLAY
========================= */

.cart-overlay{
    position:fixed;
    inset:0;

    background:rgba(0,0,0,0.45);

    opacity:0;
    visibility:hidden;

    transition:0.3s;

    z-index:998;
}

.cart-overlay.active{
    opacity:1;
    visibility:visible;
}

/* =========================
   SIDEBAR
========================= */

.cart-sidebar{
    position:fixed;
    top:0;
    right:-450px;

    width:420px;
    max-width:100%;

    height:100vh;

    background:white;

    z-index:999;

    display:flex;
    flex-direction:column;

    transition:0.35s ease;

    box-shadow:
        -10px 0 40px rgba(0,0,0,0.12);
}

.cart-sidebar.active{
    right:0;
}

/* =========================
   HEADER
========================= */

.cart-header{
    padding:25px;

    display:flex;
    justify-content:space-between;
    align-items:center;

    border-bottom:1px solid #e5e7eb;
}

.cart-header h2{
    font-size:24px;
    color:#111827;
}

.close-cart{
    width:42px;
    height:42px;

    border:none;
    border-radius:12px;

    background:#f3f4f6;

    cursor:pointer;

    font-size:18px;

    transition:0.3s;
}

.close-cart:hover{
    background:#e5e7eb;
}

/* =========================
   ITEMS
========================= */

.cart-items{
    flex:1;
    overflow-y:auto;
    padding:25px;
}

.cart-item{
    display:flex;
    gap:18px;

    margin-bottom:25px;
}

.cart-item img{
    width:95px;
    height:95px;

    object-fit:cover;

    border-radius:16px;
}

.item-info{
    flex:1;
}

.item-info h3{
    font-size:18px;
    margin-bottom:8px;
    color:#111827;
}

.item-info p{
    color:#2563eb;
    font-weight:700;
    margin-bottom:15px;
}

/* =========================
   QUANTITY
========================= */

.quantity{
    display:flex;
    align-items:center;
    gap:12px;
}

.quantity button{
    width:34px;
    height:34px;

    border:none;
    border-radius:10px;

    background:#f3f4f6;

    cursor:pointer;

    font-size:18px;

    transition:0.3s;
}

.quantity button:hover{
    background:#e5e7eb;
}

/* =========================
   FOOTER
========================= */

.cart-footer{
    padding:25px;
    border-top:1px solid #e5e7eb;
}

.cart-total{
    display:flex;
    justify-content:space-between;

    margin-bottom:20px;

    font-size:18px;
}

.cart-total strong{
    color:#111827;
}

/* CHECKOUT */

.checkout-btn{
    width:100%;
    height:58px;

    border:none;
    border-radius:16px;

    background:#111827;
    color:white;

    font-size:17px;
    font-weight:600;

    cursor:pointer;

    transition:0.3s;
}

.checkout-btn:hover{
    background:#2563eb;
}