Simplify: PHP page dedup, secure UUID, input validation, remove redundant headers
- pages/*.php: 11 files reduced to 1-liners via shared renderPage() helper - Session: UUID generation uses random_bytes() instead of mt_rand() - Session: logout cookie uses same security options as create - API saves: size limits on key (100) and data (500KB) - API sessions: displayName capped at 64 chars - API: removed redundant Content-Type headers (Response::json handles it) - API dashboard: replaced SELECT * with explicit columns Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1 @@
|
||||
<?php
|
||||
/** GeoGraSim — Lehrkraefte-Dashboard */
|
||||
$html = file_get_contents(APP_ROOT . '/dashboard.html');
|
||||
$ctx = '<script>window.__GGS__ = ' . json_encode(['sessionId' => Session::studentId(), 'teacherId' => Session::teacherId(), 'baseUrl' => BASE_URL, 'basePath' => BASE_PATH], JSON_UNESCAPED_UNICODE) . ';</script>';
|
||||
echo str_replace('</body>', $ctx . "\n</body>", $html);
|
||||
<?php renderPage('dashboard.html');
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
<?php
|
||||
/** GeoGraSim — Energiemix-Simulator */
|
||||
$html = file_get_contents(APP_ROOT . '/energiemix.html');
|
||||
$ctx = '<script>window.__GGS__ = ' . json_encode(['sessionId' => Session::studentId(), 'teacherId' => Session::teacherId(), 'baseUrl' => BASE_URL, 'basePath' => BASE_PATH], JSON_UNESCAPED_UNICODE) . ';</script>';
|
||||
echo str_replace('</body>', $ctx . "\n</body>", $html);
|
||||
<?php renderPage('energiemix.html');
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
<?php
|
||||
/** GeoGraSim — Erdbeben-Simulator */
|
||||
$html = file_get_contents(APP_ROOT . '/erdbeben.html');
|
||||
$ctx = '<script>window.__GGS__ = ' . json_encode(['sessionId' => Session::studentId(), 'teacherId' => Session::teacherId(), 'baseUrl' => BASE_URL, 'basePath' => BASE_PATH], JSON_UNESCAPED_UNICODE) . ';</script>';
|
||||
echo str_replace('</body>', $ctx . "\n</body>", $html);
|
||||
<?php renderPage('erdbeben.html');
|
||||
|
||||
+1
-5
@@ -1,5 +1 @@
|
||||
<?php
|
||||
/** GeoGraSim — Flussmanagement-Simulation */
|
||||
$html = file_get_contents(APP_ROOT . '/fluss.html');
|
||||
$ctx = '<script>window.__GGS__ = ' . json_encode(['sessionId' => Session::studentId(), 'teacherId' => Session::teacherId(), 'baseUrl' => BASE_URL, 'basePath' => BASE_PATH], JSON_UNESCAPED_UNICODE) . ';</script>';
|
||||
echo str_replace('</body>', $ctx . "\n</body>", $html);
|
||||
<?php renderPage('fluss.html');
|
||||
|
||||
+1
-18
@@ -1,18 +1 @@
|
||||
<?php
|
||||
/**
|
||||
* GeoGraSim — Klimawächter (3D)
|
||||
*/
|
||||
|
||||
$html = file_get_contents(APP_ROOT . '/game-3d.html');
|
||||
|
||||
$sessionScript = '<script>' . "\n"
|
||||
. 'window.__GGS__ = ' . json_encode([
|
||||
'sessionId' => Session::studentId(),
|
||||
'teacherId' => Session::teacherId(),
|
||||
'baseUrl' => BASE_URL,
|
||||
'basePath' => BASE_PATH,
|
||||
], JSON_UNESCAPED_UNICODE) . ";\n"
|
||||
. '</script>';
|
||||
|
||||
$html = str_replace('</body>', $sessionScript . "\n</body>", $html);
|
||||
echo $html;
|
||||
<?php renderPage('game-3d.html');
|
||||
|
||||
+1
-18
@@ -1,18 +1 @@
|
||||
<?php
|
||||
/**
|
||||
* GeoGraSim — Klimawächter (2D)
|
||||
*/
|
||||
|
||||
$html = file_get_contents(APP_ROOT . '/game.html');
|
||||
|
||||
$sessionScript = '<script>' . "\n"
|
||||
. 'window.__GGS__ = ' . json_encode([
|
||||
'sessionId' => Session::studentId(),
|
||||
'teacherId' => Session::teacherId(),
|
||||
'baseUrl' => BASE_URL,
|
||||
'basePath' => BASE_PATH,
|
||||
], JSON_UNESCAPED_UNICODE) . ";\n"
|
||||
. '</script>';
|
||||
|
||||
$html = str_replace('</body>', $sessionScript . "\n</body>", $html);
|
||||
echo $html;
|
||||
<?php renderPage('game.html');
|
||||
|
||||
+1
-21
@@ -1,21 +1 @@
|
||||
<?php
|
||||
/**
|
||||
* GeoGraSim — Startseite (Landing Page)
|
||||
* Laedt die bestehende index.html und injiziert Session-Kontext.
|
||||
*/
|
||||
|
||||
$html = file_get_contents(APP_ROOT . '/index.html');
|
||||
|
||||
// Session-Kontext vor </body> injizieren
|
||||
$sessionScript = '<script>' . "\n"
|
||||
. 'window.__GGS__ = ' . json_encode([
|
||||
'sessionId' => Session::studentId(),
|
||||
'teacherId' => Session::teacherId(),
|
||||
'baseUrl' => BASE_URL,
|
||||
'basePath' => BASE_PATH,
|
||||
], JSON_UNESCAPED_UNICODE) . ";\n"
|
||||
. '</script>';
|
||||
|
||||
$html = str_replace('</body>', $sessionScript . "\n</body>", $html);
|
||||
|
||||
echo $html;
|
||||
<?php renderPage('index.html');
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
<?php
|
||||
/** GeoGraSim — Lieferketten-Simulator */
|
||||
$html = file_get_contents(APP_ROOT . '/lieferketten.html');
|
||||
$ctx = '<script>window.__GGS__ = ' . json_encode(['sessionId' => Session::studentId(), 'teacherId' => Session::teacherId(), 'baseUrl' => BASE_URL, 'basePath' => BASE_PATH], JSON_UNESCAPED_UNICODE) . ';</script>';
|
||||
echo str_replace('</body>', $ctx . "\n</body>", $html);
|
||||
<?php renderPage('lieferketten.html');
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
<?php
|
||||
/** GeoGraSim — Regenwald-Explorer */
|
||||
$html = file_get_contents(APP_ROOT . '/regenwald.html');
|
||||
$ctx = '<script>window.__GGS__ = ' . json_encode(['sessionId' => Session::studentId(), 'teacherId' => Session::teacherId(), 'baseUrl' => BASE_URL, 'basePath' => BASE_PATH], JSON_UNESCAPED_UNICODE) . ';</script>';
|
||||
echo str_replace('</body>', $ctx . "\n</body>", $html);
|
||||
<?php renderPage('regenwald.html');
|
||||
|
||||
+1
-5
@@ -1,5 +1 @@
|
||||
<?php
|
||||
/** GeoGraSim — Simulationsseite (POE-Workflow) */
|
||||
$html = file_get_contents(APP_ROOT . '/sim.html');
|
||||
$ctx = '<script>window.__GGS__ = ' . json_encode(['sessionId' => Session::studentId(), 'teacherId' => Session::teacherId(), 'baseUrl' => BASE_URL, 'basePath' => BASE_PATH], JSON_UNESCAPED_UNICODE) . ';</script>';
|
||||
echo str_replace('</body>', $ctx . "\n</body>", $html);
|
||||
<?php renderPage('sim.html');
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
<?php
|
||||
/** GeoGraSim — Stilauswahl */
|
||||
$html = file_get_contents(APP_ROOT . '/stilauswahl.html');
|
||||
$ctx = '<script>window.__GGS__ = ' . json_encode(['sessionId' => Session::studentId(), 'teacherId' => Session::teacherId(), 'baseUrl' => BASE_URL, 'basePath' => BASE_PATH], JSON_UNESCAPED_UNICODE) . ';</script>';
|
||||
echo str_replace('</body>', $ctx . "\n</body>", $html);
|
||||
<?php renderPage('stilauswahl.html');
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
* POST /api/assessment {simId, processLog, predictions, results, reflections, duration, completedPhases}
|
||||
*/
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
Response::error('Nur POST erlaubt', 405);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
* GET /api/dashboard?class_id=X
|
||||
*/
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||
Response::error('Nur GET erlaubt', 405);
|
||||
}
|
||||
@@ -18,14 +16,14 @@ $classId = (int)($_GET['class_id'] ?? 0);
|
||||
// Verifizieren dass die Klasse dem Lehrer gehoert
|
||||
if ($classId) {
|
||||
$class = $db->fetchOne(
|
||||
'SELECT * FROM classes WHERE id = ? AND teacher_id = ?',
|
||||
'SELECT id, name, school_year, join_code, created_at FROM classes WHERE id = ? AND teacher_id = ?',
|
||||
[$classId, $teacherId]
|
||||
);
|
||||
if (!$class) Response::error('Klasse nicht gefunden', 404);
|
||||
}
|
||||
|
||||
// Klassen des Lehrers
|
||||
$classes = $db->fetchAll('SELECT * FROM classes WHERE teacher_id = ? ORDER BY created_at DESC', [$teacherId]);
|
||||
$classes = $db->fetchAll('SELECT id, name, school_year, join_code, created_at FROM classes WHERE teacher_id = ? ORDER BY created_at DESC', [$teacherId]);
|
||||
|
||||
if (!$classId && !empty($classes)) {
|
||||
$classId = $classes[0]['id'];
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
<?php
|
||||
/**
|
||||
* API: Spielstaende speichern/laden
|
||||
* GET /api/saves?key=klimawaechter-save → Spielstand laden
|
||||
* POST /api/saves {key, data, version} → Spielstand speichern
|
||||
* GET /api/saves?key=klimawaechter-save
|
||||
* POST /api/saves {key, data, version}
|
||||
*/
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
$db = Database::get();
|
||||
|
||||
if ($method === 'GET') {
|
||||
$sessionId = Session::studentId();
|
||||
if (!$sessionId) {
|
||||
Response::json(['data' => null]);
|
||||
}
|
||||
if (!$sessionId) Response::json(['data' => null]);
|
||||
|
||||
$key = $_GET['key'] ?? '';
|
||||
if (!$key) Response::error('key fehlt');
|
||||
if (!$key || strlen($key) > 100) Response::error('key fehlt oder zu lang');
|
||||
|
||||
$row = $db->fetchOne(
|
||||
'SELECT save_data, save_version FROM game_saves WHERE session_id = ? AND save_key = ?',
|
||||
@@ -31,6 +28,9 @@ if ($method === 'POST') {
|
||||
if (!$body || !isset($body['key']) || !isset($body['data'])) {
|
||||
Response::error('key und data erforderlich');
|
||||
}
|
||||
if (strlen($body['key']) > 100 || strlen($body['data']) > 500000) {
|
||||
Response::error('Payload zu gross', 413);
|
||||
}
|
||||
|
||||
$db->execute(
|
||||
'INSERT INTO game_saves (session_id, save_key, save_data, save_version)
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
* POST /api/sessions {action: "status"}
|
||||
*/
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
Response::error('Nur POST erlaubt', 405);
|
||||
}
|
||||
@@ -26,7 +24,7 @@ if ($action === 'join') {
|
||||
Response::error('Klasse nicht gefunden');
|
||||
}
|
||||
|
||||
$displayName = trim($body['displayName'] ?? '');
|
||||
$displayName = mb_substr(trim($body['displayName'] ?? ''), 0, 64);
|
||||
$uuid = Session::createStudent((int)$class['id'], $displayName);
|
||||
|
||||
Response::ok([
|
||||
|
||||
+13
-7
@@ -22,12 +22,12 @@ class Session {
|
||||
|
||||
/** Neue Schueler-Session erstellen */
|
||||
public static function createStudent(int $classId, string $displayName = ''): string {
|
||||
$uuid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0x0fff) | 0x4000,
|
||||
mt_rand(0, 0x3fff) | 0x8000,
|
||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
|
||||
$uuid = sprintf('%s-%s-%s-%s-%s',
|
||||
bin2hex(random_bytes(4)),
|
||||
bin2hex(random_bytes(2)),
|
||||
bin2hex(random_bytes(2)),
|
||||
bin2hex(random_bytes(2)),
|
||||
bin2hex(random_bytes(6))
|
||||
);
|
||||
|
||||
$db = Database::get();
|
||||
@@ -83,6 +83,12 @@ class Session {
|
||||
public static function logout(): void {
|
||||
self::start();
|
||||
session_destroy();
|
||||
setcookie(self::COOKIE_NAME, '', ['expires' => 1, 'path' => BASE_PATH . '/']);
|
||||
setcookie(self::COOKIE_NAME, '', [
|
||||
'expires' => 1,
|
||||
'path' => BASE_PATH . '/',
|
||||
'samesite' => 'Lax',
|
||||
'secure' => IS_PRODUCTION,
|
||||
'httponly' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,3 +41,15 @@ function injectSessionContext(): void {
|
||||
];
|
||||
echo '<script>window.__GGS__ = ' . json_encode($ctx, JSON_UNESCAPED_UNICODE) . ';</script>' . "\n";
|
||||
}
|
||||
|
||||
/** Seite rendern: HTML laden, Session-Kontext injizieren, ausgeben */
|
||||
function renderPage(string $htmlFile): void {
|
||||
$html = file_get_contents(APP_ROOT . '/' . $htmlFile);
|
||||
$ctx = '<script>window.__GGS__ = ' . json_encode([
|
||||
'sessionId' => Session::studentId(),
|
||||
'teacherId' => Session::teacherId(),
|
||||
'baseUrl' => BASE_URL,
|
||||
'basePath' => BASE_PATH,
|
||||
], JSON_UNESCAPED_UNICODE) . ';</script>';
|
||||
echo str_replace('</body>', $ctx . "\n</body>", $html);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user