redirect zu /datei RewriteCond %{THE_REQUEST} \s/+(.+?)\.php[\s?] [NC] RewriteRule ^ /%1 [R=301,L] # /datei -> datei.php RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{DOCUMENT_ROOT}/$1.php -f RewriteRule ^(.+)$ $1.php [L] HTACCESS; $files[$projectName . '.code-workspace'] = <<prepare($sql); if (!$stmt) { die("Fehler beim Prepare: " . $conn->error); } if (!$stmt->execute()) { die("Fehler beim Execute: " . $stmt->error); } return true; } function DatabaseShowTables() { include_once(__DIR__ . '/../database/databaseConnect.php'); $conn = db_connect(); $tablesResult = $conn->query("SHOW TABLES"); if (!$tablesResult) { die("Fehler beim Laden der Tabellen: " . $conn->error); } $tables = []; while ($tableRow = $tablesResult->fetch_array()) { $tables[] = $tableRow[0]; } return $tables; } function DatabaseShowTableStructure($table) { include_once(__DIR__ . '/../database/databaseConnect.php'); $conn = db_connect(); $stmt = $conn->prepare("SHOW COLUMNS FROM `$table`"); if (!$stmt) { die("Fehler beim Prepare: " . $conn->error); } if (!$stmt->execute()) { die("Fehler beim Execute: " . $stmt->error); } $result = $stmt->get_result(); $columns = []; while ($column = $result->fetch_assoc()) { $columns[] = [ "Field" => $column["Field"], "Type" => $column["Type"], "Null" => $column["Null"], "Key" => $column["Key"], "Default" => $column["Default"], "Extra" => $column["Extra"] ]; } return $columns; } function DatabaseShow($table, $columns = "*", $where = "", ...$values) { include_once(__DIR__ . '/../database/databaseConnect.php'); $conn = db_connect(); $sql = "SELECT $columns FROM `$table`"; if (!empty($where)) { $sql .= " WHERE $where"; } $stmt = $conn->prepare($sql); if (!$stmt) { die("Fehler beim Prepare: " . $conn->error); } if (!$stmt->execute($values)) { die("Fehler beim Execute: " . $stmt->error); } $result = $stmt->get_result(); return $result->fetch_all(MYSQLI_ASSOC); } function DatabaseInsert($table, $columns, ...$values) { include_once(__DIR__ . '/../database/databaseConnect.php'); $conn = db_connect(); $placeholders = rtrim(str_repeat("?,", count($values)), ","); $sql = "INSERT INTO `$table` ($columns) VALUES ($placeholders)"; $stmt = $conn->prepare($sql); if (!$stmt) { die("Fehler beim Prepare: " . $conn->error); } if (!$stmt->execute($values)) { die("Fehler beim Execute: " . $stmt->error); } return true; } function DatabaseDelete($table, $where, ...$values) { include_once(__DIR__ . '/../database/databaseConnect.php'); $conn = db_connect(); $sql = "DELETE FROM `$table` WHERE $where"; $stmt = $conn->prepare($sql); if (!$stmt) { die("Fehler beim Prepare: " . $conn->error); } if (!$stmt->execute($values)) { die("Fehler beim Execute: " . $stmt->error); } return true; } function DatabaseUpdate($table, $set, $where, ...$values) { include_once(__DIR__ . '/../database/databaseConnect.php'); $conn = db_connect(); $sql = "UPDATE `$table` SET $set WHERE $where"; $stmt = $conn->prepare($sql); if (!$stmt) { die("Fehler beim Prepare: " . $conn->error); } if (!$stmt->execute($values)) { die("Fehler beim Execute: " . $stmt->error); } return true; } function getFKValue($conn, $table, $key, $value, $id, &$cache) { if ($id === null) return null; $cacheKey = $table . "_" . $id; if (isset($cache[$cacheKey])) { return $cache[$cacheKey]; } $stmt = $conn->prepare("SELECT `$value` FROM `$table` WHERE `$key` = ? LIMIT 1"); if (!$stmt) { die("FK Prepare Fehler: " . $conn->error); } $stmt->bind_param("i", $id); $stmt->execute(); $result = $stmt->get_result()->fetch_assoc(); $valueResult = $result[$value] ?? null; $cache[$cacheKey] = $valueResult; return $valueResult; } function DatabaseShowWithFK($table, $fkMap = [], $columns = "*", $where = "", ...$values) { include_once(__DIR__ . '/../database/databaseConnect.php'); $conn = db_connect(); $cache = []; $select = is_array($columns) ? implode(", ", $columns) : $columns; $sql = "SELECT $select FROM `$table`"; if (!empty($where)) { $sql .= " WHERE $where"; } $stmt = $conn->prepare($sql); if (!$stmt) die("Fehler beim Prepare: " . $conn->error); if (!empty($values)) { $stmt->execute($values); } else { $stmt->execute(); } $result = $stmt->get_result(); if (!$result) die("Fehler beim get_result: " . $conn->error); $rows = $result->fetch_all(MYSQLI_ASSOC); foreach ($rows as &$row) { foreach ($fkMap as $fkColumn => $fkInfo) { if (!isset($row[$fkColumn]) || $row[$fkColumn] === null) { continue; } $row[$fkColumn] = getFKValue( $conn, $fkInfo['table'], $fkInfo['key'], $fkInfo['value'], $row[$fkColumn], $cache ); } } return [ "rows" => $rows ]; } PHP; // --- CONFIG: env.ini --- $files['WEBROOT/src/config/env.ini'] = <<set_charset("utf8mb4"); return $conn; } catch (Exception $e) { return null; } } PHP; // -- CLASSES -- $files['WEBROOT/src/MVC/Classes/Api.php'] = <<<'PHP' $statusCode === 200 ? 'success' : 'error', 'data' => $data, ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE ); exit; } } PHP; $files['WEBROOT/src/MVC/Classes/Client.php'] = <<<'PHP' country ?? 'UNKNOWN'; } public static function userAgent() { return $_SERVER['HTTP_USER_AGENT'] ?? 'UNKNOWN'; } } PHP; $files['WEBROOT/src/MVC/Classes/Cookie.php'] = <<<'PHP' view = new View(__DIR__ . '/../View'); } protected function render($template, $data = []) { foreach ($data as $key => $value) { $this->view->assign($key, $value); } return $this->view->render($template); } protected function json($data, $status = 200) { header('Content-Type: application/json'); http_response_code($status); echo json_encode($data); exit; } } PHP; $files['WEBROOT/src/MVC/Core/Model.php'] = <<<'PHP' $value) { $sets[] = "$column = ?"; $values[] = $value; } $setString = implode(", ", $sets); return \DatabaseUpdate(static::$table, $setString, $where, ...array_merge($values, $whereParams)); } public static function delete($where, ...$params) { return \DatabaseDelete(static::$table, $where, ...$params); } public static function query($sql, ...$params) { $conn = self::getConnection(); if (empty($params)) { return $conn->query($sql); } $stmt = $conn->prepare($sql); $types = str_repeat('s', count($params)); $stmt->bind_param($types, ...$params); $stmt->execute(); return $stmt->get_result(); } } PHP; $files['WEBROOT/src/MVC/Core/View.php'] = <<<'PHP' viewPath = $viewPath; } public function assign($key, $value) { $this->data[$key] = $value; } public function render($template) { extract($this->data); $file = $this->viewPath . '/' . $template . '.php'; if (file_exists($file)) { ob_start(); include $file; return ob_get_clean(); } return "View $template not found at $file"; } } PHP; $files['WEBROOT/src/MVC/Core/Router.php'] = <<<'PHP' routes[$service] = [ 'controller' => $controller, 'method' => $method, 'middlewares' => $middlewares ]; } public function dispatch($service) { if (!isset($this->routes[$service])) { throw new \Exception("Service '$service' not found."); } $route = $this->routes[$service]; // Run Middlewares foreach ($route['middlewares'] as $middleware) { $this->runMiddleware($middleware); } $controllerClass = $route['controller']; $method = $route['method']; if (!class_exists($controllerClass)) { throw new \Exception("Controller class '$controllerClass' not found."); } $controller = new $controllerClass(); if (!method_exists($controller, $method)) { throw new \Exception("Method '$method' not found in controller '$controllerClass'."); } return $controller->$method(); } protected function runMiddleware($middleware) { if ($middleware === 'admin') { if (!isset($_SESSION['is_admin']) || $_SESSION['is_admin'] !== true) { die("Access Denied: Admin rights required."); } } if ($middleware === 'auth') { if (empty($_SESSION['user_logged_in'])) { header('Location: ?service=login'); exit; } } } } PHP; $files['WEBROOT/src/MVC/Layout/Layout.php'] = <<<'PHP' template = $template; } public function setBlock($name, $content) { $this->blocks[$name] = $content; } public function getBlock($name) { return $this->blocks[$name] ?? ''; } public function render() { $layoutFile = __DIR__ . '/Templates/' . $this->template . '.php'; if (file_exists($layoutFile)) { ob_start(); include $layoutFile; return ob_get_clean(); } return "Layout template nicht gefunden."; } } PHP; $files['WEBROOT/src/MVC/autoloader.php'] = <<<'PHP' <?= $this->getBlock('title') ?>
getBlock('header_actions') ?>
getBlock('content') ?>
HTML; // --- CONTROLLERS --- $files['WEBROOT/src/MVC/Controller/ApiController.php'] = <<<'PHP' 'DummyData', ]); } } PHP; $files['WEBROOT/src/MVC/Controller/HomeController.php'] = <<<'PHP' render('home'); } public function toggle_theme() { $_SESSION['theme'] = ($_SESSION['theme'] ?? 'light') === 'dark' ? 'light' : 'dark'; return $this->json( [ 'success' => true ] ); } } PHP; $files['WEBROOT/src/MVC/Controller/AuthController.php'] = <<<'PHP' 'password123', 'user' => 'user123' ]; if (isset($users[$username]) && $users[$username] === $password) { $_SESSION['user_logged_in'] = true; $_SESSION['username'] = $username; header('Location: ?service=home'); exit; } else { return $this->render('login', ['error' => 'Ungültige Anmeldedaten']); } } return $this->render('login'); } public function logout() { session_destroy(); header('Location: ?service=login'); exit; } } PHP; $files['WEBROOT/src/MVC/Controller/DocsController.php'] = <<<'PHP' render('docs', [ 'title' => '📚 System-Dokumentation' ]); } } PHP; $files['WEBROOT/src/MVC/Controller/TestController.php'] = <<<'PHP' render( 'test1', [ 'msg' => 'Service 1 ist bereit!' ] ); } public function service2() { return $this->render( 'test2', [ 'data' => [ 'Layout' => 'Header + Sidebar', 'Theme' => 'Auto-Toggle' ] ] ); } } PHP; // --- API --- $files['WEBROOT/api/v1/get.php'] = <<<'PHP' get()); } catch (\Exception $e) { echo ($e->getMessage()); } PHP; // --- VIEWS --- $files['WEBROOT/src/MVC/View/home.php'] = "

Dashboard

Willkommen in deinem neuen MVC-System mit integriertem Header.

"; $files['WEBROOT/src/MVC/View/test1.php'] = "

Service 1

"; $files['WEBROOT/src/MVC/View/test2.php'] = "

System Check

"; $files['WEBROOT/src/MVC/View/docs.php'] = <<<'HTML'

🏛️ Framework Architektur & Dokumentation

1. Einführung

Dieses Framework basiert auf dem Model-View-Controller (MVC) Entwurfsmuster und nutzt einen Front Controller (index.php). Alle Anfragen werden zentral verarbeitet, was globale Middleware (wie Authentifizierung) und ein einheitliches Layout ermöglicht.

2. Datei-Referenz (Deep Dive)

Framework Core

  • Router.php: Verwaltet die Routen. Unterstützt Middlewares. Das Dispatching erfolgt über den service Parameter in der URL.
  • Controller.php: Basisklasse für alle Controller. Bietet render() für Views und json() für API-Responses.
  • Model.php: Abstrakte Basis für Datenbank-Entitäten. Kapselt die databaseMethods.php in ein objektorientiertes Interface.
  • View.php: Behandelt das Extrahieren von Daten in HTML-Templates.

Konfiguration

  • env.ini: Speichert Datenbank-Zugangsdaten für dev und live Umgebungen.
  • autoloader.php: Registriert einen PSR-4 ähnlichen Autoloader für den MVC\ Namespace.

3. API-System

APIs liegen im Verzeichnis WEBROOT/api/v1/. Sie nutzen die ApiController-Klasse.

// Beispiel: WEBROOT/api/v1/get.php
use MVC\Classes\Api;
use MVC\Controller\ApiController;

Api::jsonResponse((new ApiController())->get());
        

4. Datenbank & Models

Das Framework nutzt mysqli mit Prepared Statements für maximale Sicherheit.

databaseMethods.php (Die Power-Tools)

  • DatabaseShow($table, $columns, $where, ...$values)
  • DatabaseInsert($table, $columns, ...$values)
  • DatabaseUpdate($table, $set, $where, ...$values)
  • DatabaseDelete($table, $where, ...$values)

5. Helper Klassen (MVC\Classes)

  • Request: Zugriff auf method(), queryParams(), headers().
  • Client: Ermittelt ip(), userAgent(), country().
  • Cookie: Interface zum set(), read(), Delete() von Cookies.

6. CLI-Generatoren

php create_module.php [Name] - Erstellt Controller & View.

php create_model.php [Tabelle] [Spalten] - Erstellt ein Model.

7. Best Practices

Naming: Controller immer mit Controller-Suffix. Models im Singular.

Security: Nutze ['auth'] Middleware konsequent für alle internen Seiten.

HTML; $files['WEBROOT/src/MVC/View/login.php'] = <<<'HTML' HTML; // --- ENTRY POINT --- $files['WEBROOT/index.php'] = <<<'PHP' add('home', \MVC\Controller\HomeController::class, 'index'); $router->add('toggle_theme', \MVC\Controller\HomeController::class, 'toggle_theme'); $router->add('docs', \MVC\Controller\DocsController::class, 'index'); $router->add('test1', \MVC\Controller\TestController::class, 'service1', ['auth']); $router->add('test2', \MVC\Controller\TestController::class, 'service2', ['auth']); $router->add('login', \MVC\Controller\AuthController::class, 'login'); $router->add('logout', \MVC\Controller\AuthController::class, 'logout'); $layout = new \MVC\Layout\Layout('main'); $layout->setBlock('title', 'MVC Starter'); $layout->setBlock('header_title', '🚀 MVC Dashboard'); $headerActions = ''; if (isset($_SESSION['user_logged_in'])) { $headerActions = '👤 ' . htmlspecialchars($_SESSION['username']) . '' . '🚪 Logout ' . $headerActions; } else { $headerActions = '🔑 Login ' . $headerActions; } $layout->setBlock('header_actions', $headerActions); // Sidebar Block ob_start(); $navItems = [ 'home' => ['label' => '🏠 Home', 'auth' => false], 'test1' => ['label' => '🛠️ Test 1', 'auth' => true], 'test2' => ['label' => '📊 Test 2', 'auth' => true], 'docs' => ['label' => '📚 Dokumentation', 'auth' => false], ]; ?> setBlock('sidebar', ob_get_clean()); $layout->setBlock('content', $router->dispatch($service)); echo $layout->render(); } catch (\Throwable $e) { http_response_code(500); echo "

Error

" . htmlspecialchars($e->getMessage()) . "

"; if (ini_get('display_errors')) echo "
" . htmlspecialchars($e->getTraceAsString()) . "
"; } PHP; // --- GENERATOR: create_model.php --- $files['create_model.php'] = <<<'PHP' */ if (php_sapi_name() !== 'cli') { die("Dieses Script muss über die CLI ausgeführt werden.\n"); } $tableName = $argv[1] ?? null; $columnsInput = $argv[2] ?? null; // Interaktive Abfrage, falls Argumente fehlen if (!$tableName) { echo "Tabellenname eingeben (z.B. Benutzer): "; $handle = fopen("php://stdin", "r"); $tableName = trim(fgets($handle)); fclose($handle); } if (!$columnsInput) { echo "Spalten kommagetrennt eingeben (z.B. NAME,EMAIL,ROLLE): "; $handle = fopen("php://stdin", "r"); $columnsInput = trim(fgets($handle)); fclose($handle); } if (!$tableName) die("Fehler: Kein Tabellenname angegeben.\n"); // Namen formatieren $className = str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($tableName)))); $modelFile = __DIR__ . "/WEBROOT/src/MVC/Model/{$className}.php"; // Spalten aufbereiten $columns = array_map('trim', explode(',', $columnsInput)); $columnList = implode("', '", $columns); // Model-Inhalt generieren $content = << */ if (php_sapi_name() !== 'cli') { die("Dieses Script kann nur über die Kommandozeile ausgeführt werden.\n"); } $name = $argv[1] ?? null; if (!$name) { echo "Bitte gib einen Namen für das Modul an (z.B. mein_projekt): "; $handle = fopen("php://stdin", "r"); $name = trim(fgets($handle)); fclose($handle); } if (!$name) { die("Fehler: Kein Name angegeben.\n"); } // Namen formatieren $key = strtolower(str_replace(' ', '_', $name)); $className = str_replace(' ', '', ucwords(str_replace('_', ' ', $key))); $controllerFile = __DIR__ . "/WEBROOT/src/MVC/Controller/{$className}Controller.php"; $viewFile = __DIR__ . "/WEBROOT/src/MVC/View/{$key}.php"; // 1. Controller erstellen $controllerContent = <<render('{$key}', [ 'title' => '{$className} Modul', 'message' => 'Willkommen in deinem neuen Modul {$className}!' ]); } } PHPCTRL; if (!file_exists($controllerFile)) { file_put_contents($controllerFile, $controllerContent); echo "✅ Controller erstellt: WEBROOT/src/MVC/Controller/{$className}Controller.php\n"; } else { echo "⚠️ Controller existiert bereits.\n"; } // 2. View erstellen $viewContent = <<

Hier kannst du nun dein Projekt aufbauen.

HTML; if (!file_exists($viewFile)) { file_put_contents($viewFile, $viewContent); echo "✅ View erstellt: WEBROOT/src/MVC/View/{$key}.php\n"; } else { echo "⚠️ View existiert bereits.\n"; } // 3. Anleitung ausgeben echo "\n--- NÄCHSTE SCHRITTE ---\n"; echo " Registriere das Modul in WEBROOT/index.php beim Router:\n"; echo " \$router->add('{$key}', \\MVC\\Controller\\{$className}Controller::class, '{$key}', ['auth']);\n"; echo " (Lösche ['auth'] wenn kein Login erforderlich ist)\n\n"; echo "------------------------\n"; PHP; // 3. Dateien schreiben foreach ($files as $file => $content) { $path = $baseDir . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $file); file_put_contents($path, $content); echo "📄 Datei erstellt: $file\n"; } echo "\n✨ Projekt '$projectName' wurde initialisiert!\n"; echo "1. Richte deine Datenbankverbindung in WEBROOT/src/config/env.ini ein.\n"; echo "2. Starten: php server.php\n"; echo "3. Öffnen: http://localhost:8000\n";