{
"event": "PreToolUse",
"tool_name": "Edit",
"tool_input": {
"file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Framework\/Controller.php",
"old_string": " protected function jsonError(string $message, int $status = 500): void\n {\n $this->json(['success' => false, 'error' => $message], $status);\n }\n}",
"new_string": " protected function jsonError(string $message, int $status = 500): void\n {\n $this->json(['success' => false, 'error' => $message], $status);\n }\n\n \/**\n * Return 404 Not Found response and exit.\n * Automatically detects JSON requests.\n *\/\n protected function notFound(string $message = 'Nicht gefunden'): never\n {\n http_response_code(404);\n if ($this->isJsonRequest()) {\n $this->json(['error' => $message], 404);\n } else {\n echo \"404 - {$message}\";\n }\n exit;\n }\n\n \/**\n * Decode JSON string to array with safe defaults.\n *\n * @return array<mixed>\n *\/\n protected function decodeJson(?string $json): array\n {\n if ($json === null || $json === '') {\n return [];\n }\n\n $decoded = json_decode($json, true);\n\n return is_array($decoded) ? $decoded : [];\n }\n\n \/**\n * Get input value from GET or POST.\n *\/\n protected function getInput(string $key, mixed $default = null): mixed\n {\n return $_GET[$key] ?? $_POST[$key] ?? $default;\n }\n\n \/**\n * Get trimmed string input.\n *\/\n protected function getString(string $key, string $default = ''): string\n {\n $value = $this->getInput($key, $default);\n\n return is_string($value) ? trim($value) : $default;\n }\n\n \/**\n * Get integer input.\n *\/\n protected function getInt(string $key, int $default = 0): int\n {\n return (int) ($this->getInput($key, $default));\n }\n\n \/**\n * Get current page number from request.\n *\/\n protected function getPage(): int\n {\n return max(1, $this->getInt('page', 1));\n }\n\n \/**\n * Get limit with bounds.\n *\/\n protected function getLimit(int $max = 50, int $default = 10): int\n {\n return min($max, max(1, $this->getInt('limit', $default)));\n }\n\n \/**\n * Calculate offset from page and limit.\n *\/\n protected function getOffset(int $limit): int\n {\n return ($this->getPage() - 1) * $limit;\n }\n}"
}
}
{
"tool_response": {
"filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Framework\/Controller.php",
"oldString": " protected function jsonError(string $message, int $status = 500): void\n {\n $this->json(['success' => false, 'error' => $message], $status);\n }\n}",
"newString": " protected function jsonError(string $message, int $status = 500): void\n {\n $this->json(['success' => false, 'error' => $message], $status);\n }\n\n \/**\n * Return 404 Not Found response and exit.\n * Automatically detects JSON requests.\n *\/\n protected function notFound(string $message = 'Nicht gefunden'): never\n {\n http_response_code(404);\n if ($this->isJsonRequest()) {\n $this->json(['error' => $message], 404);\n } else {\n echo \"404 - {$message}\";\n }\n exit;\n }\n\n \/**\n * Decode JSON string to array with safe defaults.\n *\n * @return array<mixed>\n *\/\n protected function decodeJson(?string $json): array\n {\n if ($json === null || $json === '') {\n return [];\n }\n\n $decoded = json_decode($json, true);\n\n return is_array($decoded) ? $decoded : [];\n }\n\n \/**\n * Get input value from GET or POST.\n *\/\n protected function getInput(string $key, mixed $default = null): mixed\n {\n return $_GET[$key] ?? $_POST[$key] ?? $default;\n }\n\n \/**\n * Get trimmed string input.\n *\/\n protected function getString(string $key, string $default = ''): string\n {\n $value = $this->getInput($key, $default);\n\n return is_string($value) ? trim($value) : $default;\n }\n\n \/**\n * Get integer input.\n *\/\n protected function getInt(string $key, int $default = 0): int\n {\n return (int) ($this->getInput($key, $default));\n }\n\n \/**\n * Get current page number from request.\n *\/\n protected function getPage(): int\n {\n return max(1, $this->getInt('page', 1));\n }\n\n \/**\n * Get limit with bounds.\n *\/\n protected function getLimit(int $max = 50, int $default = 10): int\n {\n return min($max, max(1, $this->getInt('limit', $default)));\n }\n\n \/**\n * Calculate offset from page and limit.\n *\/\n protected function getOffset(int $limit): int\n {\n return ($this->getPage() - 1) * $limit;\n }\n}",
"originalFile": "<?php\n\nnamespace Framework;\n\nabstract class Controller\n{\n protected function csrfToken(): string\n {\n return CsrfService::getToken();\n }\n\n protected function csrfField(): string\n {\n return CsrfService::getTokenField();\n }\n\n protected function validateCsrf(): bool\n {\n $token = $_POST['_csrf_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? null;\n\n return CsrfService::validateToken($token);\n }\n\n protected function requireCsrf(): void\n {\n if (!$this->validateCsrf()) {\n http_response_code(403);\n if ($this->isJsonRequest()) {\n $this->json(['error' => 'CSRF token invalid'], 403);\n } else {\n echo 'CSRF token invalid';\n }\n exit;\n }\n }\n\n private function isJsonRequest(): bool\n {\n $accept = $_SERVER['HTTP_ACCEPT'] ?? '';\n $contentType = $_SERVER['CONTENT_TYPE'] ?? '';\n\n return str_contains($accept, 'application\/json') || str_contains($contentType, 'application\/json');\n }\n\n protected function view(string $name, array $data = []): void\n {\n $data['csrfField'] = $this->csrfField();\n $data['csrfToken'] = $this->csrfToken();\n extract($data);\n $file = VIEW_PATH . '\/' . str_replace('.', '\/', $name) . '.php';\n\n if (file_exists($file)) {\n require $file;\n } else {\n throw new \\Exception(\"View not found: {$name}\");\n }\n }\n\n protected function json(mixed $data, int $status = 200): void\n {\n http_response_code($status);\n header('Content-Type: application\/json');\n echo json_encode($data, JSON_UNESCAPED_UNICODE);\n }\n\n protected function redirect(string $url): void\n {\n header(\"Location: {$url}\");\n exit;\n }\n\n \/**\n * @return array<string, mixed>\n *\/\n protected function getJsonInput(): array\n {\n $input = file_get_contents('php:\/\/input');\n if ($input === false || $input === '') {\n return [];\n }\n\n $decoded = json_decode($input, true);\n if (!is_array($decoded)) {\n return [];\n }\n\n return $decoded;\n }\n\n protected function jsonError(string $message, int $status = 500): void\n {\n $this->json(['success' => false, 'error' => $message], $status);\n }\n}\n",
"structuredPatch": [
{
"oldStart": 91,
"oldLines": 4,
"newStart": 91,
"newLines": 85,
"lines": [
" {",
" $this->json(['success' => false, 'error' => $message], $status);",
" }",
"+",
"+ \/**",
"+ * Return 404 Not Found response and exit.",
"+ * Automatically detects JSON requests.",
"+ *\/",
"+ protected function notFound(string $message = 'Nicht gefunden'): never",
"+ {",
"+ http_response_code(404);",
"+ if ($this->isJsonRequest()) {",
"+ $this->json(['error' => $message], 404);",
"+ } else {",
"+ echo \"404 - {$message}\";",
"+ }",
"+ exit;",
"+ }",
"+",
"+ \/**",
"+ * Decode JSON string to array with safe defaults.",
"+ *",
"+ * @return array<mixed>",
"+ *\/",
"+ protected function decodeJson(?string $json): array",
"+ {",
"+ if ($json === null || $json === '') {",
"+ return [];",
"+ }",
"+",
"+ $decoded = json_decode($json, true);",
"+",
"+ return is_array($decoded) ? $decoded : [];",
"+ }",
"+",
"+ \/**",
"+ * Get input value from GET or POST.",
"+ *\/",
"+ protected function getInput(string $key, mixed $default = null): mixed",
"+ {",
"+ return $_GET[$key] ?? $_POST[$key] ?? $default;",
"+ }",
"+",
"+ \/**",
"+ * Get trimmed string input.",
"+ *\/",
"+ protected function getString(string $key, string $default = ''): string",
"+ {",
"+ $value = $this->getInput($key, $default);",
"+",
"+ return is_string($value) ? trim($value) : $default;",
"+ }",
"+",
"+ \/**",
"+ * Get integer input.",
"+ *\/",
"+ protected function getInt(string $key, int $default = 0): int",
"+ {",
"+ return (int) ($this->getInput($key, $default));",
"+ }",
"+",
"+ \/**",
"+ * Get current page number from request.",
"+ *\/",
"+ protected function getPage(): int",
"+ {",
"+ return max(1, $this->getInt('page', 1));",
"+ }",
"+",
"+ \/**",
"+ * Get limit with bounds.",
"+ *\/",
"+ protected function getLimit(int $max = 50, int $default = 10): int",
"+ {",
"+ return min($max, max(1, $this->getInt('limit', $default)));",
"+ }",
"+",
"+ \/**",
"+ * Calculate offset from page and limit.",
"+ *\/",
"+ protected function getOffset(int $limit): int",
"+ {",
"+ return ($this->getPage() - 1) * $limit;",
"+ }",
" }"
]
}
],
"userModified": false,
"replaceAll": false
}
}