Compare commits

..
Author SHA1 Message Date
Bruno Eckhardt b2b4ac2124 new endpoint for workreports and moved reports to schoolreports 2026-05-19 15:13:53 +02:00
Bruno Eckhardt f7fd4ed183 request saves 2026-05-19 10:37:45 +02:00
Bruno Eckhardt a73b2ec13f fixes and new api entpoints for lessons and reports 2026-05-19 10:10:43 +02:00
Bruno Eckhardt dce0a0caed htaccess 2026-05-19 07:17:17 +02:00
Bruno Eckhardt 3d8c4291be fix error msg 2026-05-11 14:16:41 +02:00
Bruno Eckhardt a0afeabb27 maybe hotfix 2026-05-11 13:18:05 +02:00
Bruno Eckhardt 96c27a8722 changes 2026-05-11 13:14:16 +02:00
Bruno Eckhardt 4478f7e82f error logging 2026-05-11 13:09:04 +02:00
Bruno Eckhardt c1f3c3ea4e new function get berufsschulberichte 2026-05-11 12:54:37 +02:00
Bruno Eckhardt 2a8564d3bf caching for api 2026-05-11 12:53:15 +02:00
9 changed files with 748 additions and 141 deletions

No files matched your search

+14
View File
@@ -3,3 +3,17 @@ RewriteEngine On
RewriteRule ^(Commands|config_backups|controller|modules)($|/.*) - [F,L,NC] RewriteRule ^(Commands|config_backups|controller|modules)($|/.*) - [F,L,NC]
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
# -----------------------------------
# .php entfernen
# -----------------------------------
# browser requestet datei.php -> 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]
+38 -8
View File
@@ -1,7 +1,8 @@
<?php <?php
include_once '../controller/DatabaseController.php'; include_once( __DIR__ . '/../../controller/DatabaseController.php');
include_once '../controller/DataController.php'; include_once( __DIR__ . '/../../controller/DataController.php');
include_once __DIR__ . '/../modules/Mail.php'; include_once( __DIR__ . '/../../controller/ApiController.php');
include_once(__DIR__ . '/../../modules/Mail.php');
header("Content-Type: application/json"); header("Content-Type: application/json");
header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Origin: *");
@@ -13,9 +14,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
exit(); exit();
} }
$validTokens = [ $validTokens = DatabaseShow(
"15a437d128c918633e57dc7d18118a073b807644f21731ed5a7ebcf3eca9e242", "API_Credentials",
]; "TOKEN"
);
$validTokens = array_column($validTokens, 'TOKEN');
$headers = getallheaders(); $headers = getallheaders();
$token = $headers['Authorization'] ?? $headers['authorization'] ?? $_SERVER['HTTP_AUTHORIZATION'] ?? ''; $token = $headers['Authorization'] ?? $headers['authorization'] ?? $_SERVER['HTTP_AUTHORIZATION'] ?? '';
@@ -28,18 +32,37 @@ if (!in_array($token, $validTokens)) {
"debug_received_token" => $token, "debug_received_token" => $token,
"debug_all_headers" => $headers "debug_all_headers" => $headers
]); ]);
DatabaseInsert(
"API_LOGS",
"CLIENT_IP, TOKEN, API, FUNKTION, JSON",
(new getSpecificData())->getClientIP(),
$token,
(new getSpecificData())->getRequestURL(),
$function,
$error
);
errorMail( errorMail(
"API Login failed", "API Login failed",
$error, $error,
true, true,
); );
echo $error;
echo json_encode(
[
"error" => "Unauthorized",
"Contact" => "bruno.eckhardt07@gmail.com",
]
);
exit; exit;
} }
$data = null;
if (in_array($token, $validTokens)) { if (in_array($token, $validTokens)) {
DatabaseInsert( DatabaseInsert(
"API", "API_LOGS",
"CLIENT_IP, TOKEN, API, FUNKTION", "CLIENT_IP, TOKEN, API, FUNKTION",
(new getSpecificData())->getClientIP(), (new getSpecificData())->getClientIP(),
$token, $token,
@@ -60,6 +83,13 @@ if (in_array($token, $validTokens)) {
"MINUTEN" "MINUTEN"
); );
} }
if ($function === "Berichte") {
$data = DatabaseShowWithFK(
"Berufsschulberichte",
$Berufsschulberichte,
);
}
echo json_encode( echo json_encode(
[ [
@@ -1,6 +1,6 @@
<?php <?php
include_once '../controller/DatabaseController.php'; include_once( __DIR__ . '/../../controller/DatabaseController.php' );
include_once '../controller/DataController.php'; include_once( __DIR__ . '/../../controller/DataController.php' );
header("Content-Type: application/json"); header("Content-Type: application/json");
header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Origin: *");
@@ -110,4 +110,4 @@ DatabaseInsert(
$json $json
); );
echo $json; echo $json;
+37
View File
@@ -0,0 +1,37 @@
<?php
include_once(__DIR__ . '/../../controller/DatabaseController.php');
include_once(__DIR__ . '/../../controller/DataController.php');
include_once(__DIR__ . '/../../controller/ApiController.php');
header('Content-Type: application/json');
$api = (new ApiController());
if ($api->urlAuth($_GET['token']) == true ) {
if (isset($_GET['day'])) {
$day = $_GET['day'];
$data = DatabaseShowWithFK(
"Stundenplan",
$Stundenplan,
"ZEITEN, $day",
"$day IS NOT NULL AND $day != '' AND $day != '(NULL)' ORDER BY ZEITEN ASC"
);
} else {
$data = DatabaseShowWithFK(
"Stundenplan",
$Stundenplan,
"ZEITEN, MO, DI, MO, DO, FR",
);
}
echo $api->jsonSuccess($data);
$api->requestSave();
}
/**
* http://localhost:9000/api/v2/lessons.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3
* http://localhost:9000/api/v2/lessons.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3&day=FR
*/
+37
View File
@@ -0,0 +1,37 @@
<?php
include_once(__DIR__ . '/../../controller/DatabaseController.php');
include_once(__DIR__ . '/../../controller/DataController.php');
include_once(__DIR__ . '/../../controller/ApiController.php');
header('Content-Type: application/json');
$api = (new ApiController());
if ($api->urlAuth($_GET['token']) == true ) {
if (isset($_GET['date'])) {
$date = $_GET['date'];
$data = DatabaseShowWithFK(
"Berufsschulberichte",
$Berufsschulberichte,
"*",
"DATUM = ?",
$date
);
} else {
$data = DatabaseShowWithFK(
"Berufsschulberichte",
$Berufsschulberichte,
);
}
echo $api->jsonSuccess($data);
$api->requestSave();
}
/**
* http://localhost:9000/api/v2/schoolReports.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3
* http://localhost:9000/api/v2/schoolReports.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3&date=2025-09-09
*/
+36
View File
@@ -0,0 +1,36 @@
<?php
include_once(__DIR__ . '/../../controller/DatabaseController.php');
include_once(__DIR__ . '/../../controller/DataController.php');
include_once(__DIR__ . '/../../controller/ApiController.php');
header('Content-Type: application/json');
$api = (new ApiController());
if ($api->urlAuth($_GET['token']) == true ) {
if (isset($_GET['date'])) {
$date = $_GET['date'];
$data = DatabaseShow(
"Firmenberichte",
"DATUM, PROZESS_1, PROZESS_2, PROZESS_3, PROZESS_4, BEGINN, ENDE_PUBLIC",
"DATUM = ?",
$date
);
} else {
$data = DatabaseShow(
"Firmenberichte",
"DATUM, PROZESS_1, PROZESS_2, PROZESS_3, PROZESS_4, BEGINN, ENDE_PUBLIC",
);
}
echo $api->jsonSuccess($data);
$api->requestSave();
}
/**
* http://localhost:9000/api/v2/workReports.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3
* http://localhost:9000/api/v2/workReports.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3&date=2025-09-09
*/
+102
View File
@@ -0,0 +1,102 @@
<?php
class ApiController {
/**
* method for pretty jsonsuccess output
*
* @param array $data
* @return string
*/
public function jsonSuccess($data) {
return json_encode(
[
'status' => 'success',
'data' => $data,
],
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
);
}
/**
* method for pretty jsonerror output
*
* @param array $error
* @return string
*/
public function jsonError ($error) {
echo json_encode(
[
'status' => 'failed',
'data' => 'none',
'error' => $error
],
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
);
}
/**
* get authentication key out database
*
* @return array
*/
private function getAuthKey () {
$validTokens = DatabaseShow(
"API_Credentials",
"TOKEN"
);
return array_column($validTokens, 'TOKEN');
}
/**
* url authentication method via token and optional parameter function
*
* @param string $token
* @param string $function
* @return void
*/
public function urlAuth ($token, $function = '') {
$validTokens = $this->getAuthKey();
if (!in_array($token, $validTokens)) {
http_response_code(401);
$error = json_encode([
"error" => "Unauthorized",
"debug_received_token" => $token,
]);
echo $this->jsonError($error);
DatabaseInsert(
"API_LOGS",
"CLIENT_IP, TOKEN, API, FUNKTION, JSON",
(new getSpecificData())->getClientIP(),
$token,
(new getSpecificData())->getRequestURL(),
$function,
$error
);
errorMail(
"API Login failed",
$error,
true,
);
return false;
}
return true;
}
public function requestSave($function = '') {
DatabaseInsert(
"API_LOGS",
"CLIENT_IP, TOKEN, API, FUNKTION, JSON",
(new getSpecificData())->getClientIP(),
$_GET['token'],
(new getSpecificData())->getRequestURL(),
$function,
'{"status": "success"}',
);
}
}
+44 -18
View File
@@ -147,10 +147,37 @@ function DatabaseUpdate($table, $set, $where, ...$values) {
return true; 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) { function DatabaseShowWithFK($table, $fkMap = [], $columns = "*", $where = "", ...$values) {
include_once 'DatabaseConnect.php'; include_once 'DatabaseConnect.php';
$conn = db_connect(); $conn = db_connect();
$cache = [];
$select = is_array($columns) ? implode(", ", $columns) : $columns; $select = is_array($columns) ? implode(", ", $columns) : $columns;
$sql = "SELECT $select FROM `$table`"; $sql = "SELECT $select FROM `$table`";
@@ -161,33 +188,32 @@ function DatabaseShowWithFK($table, $fkMap = [], $columns = "*", $where = "", ..
$stmt = $conn->prepare($sql); $stmt = $conn->prepare($sql);
if (!$stmt) die("Fehler beim Prepare: " . $conn->error); if (!$stmt) die("Fehler beim Prepare: " . $conn->error);
if (!$stmt->execute($values)) die("Fehler beim Execute: " . $stmt->error); if (!empty($values)) {
$stmt->execute($values);
} else {
$stmt->execute();
}
$result = $stmt->get_result(); $result = $stmt->get_result();
if (!$result) die("Fehler beim get_result: " . $stmt->error); if (!$result) die("Fehler beim get_result: " . $conn->error);
$columnsResult = [];
while ($fieldinfo = $result->fetch_field()) {
$columnsResult[] = $fieldinfo->name;
}
$rows = $result->fetch_all(MYSQLI_ASSOC); $rows = $result->fetch_all(MYSQLI_ASSOC);
foreach ($rows as &$row) { foreach ($rows as &$row) {
foreach ($fkMap as $fkColumn => $fkInfo) { foreach ($fkMap as $fkColumn => $fkInfo) {
if (isset($row[$fkColumn]) && $row[$fkColumn] !== null) {
$fkStmt = $conn->prepare(
"SELECT {$fkInfo['value']} FROM `{$fkInfo['table']}` WHERE {$fkInfo['key']} = ?"
);
if (!$fkStmt) die("Fehler beim Prepare FK: " . $conn->error);
$fkStmt->bind_param("i", $row[$fkColumn]); if (!isset($row[$fkColumn]) || $row[$fkColumn] === null) {
$fkStmt->execute(); continue;
$fkResult = $fkStmt->get_result();
$fkRow = $fkResult->fetch_assoc();
$row[$fkColumn] = $fkRow ? $fkRow[$fkInfo['value']] : null;
} }
$row[$fkColumn] = getFKValue(
$conn,
$fkInfo['table'],
$fkInfo['key'],
$fkInfo['value'],
$row[$fkColumn],
$cache
);
} }
} }
+437 -112
View File
@@ -1,29 +1,69 @@
<?php <?php
// API Tester Service - Als Modul für index.php // ======================================================
// Dieser Service dient zum manuellen Testen der API-Endpunkte. // API TESTER
// Modul für index.php
// ======================================================
// Basis-Verzeichnisse scannen (Pfad relativ zur index.php) // API Basis-Verzeichnis
$apiDir = __DIR__ . '/../api/'; $apiDir = realpath(__DIR__ . '/../api');
$apiFiles = glob($apiDir . '*.php');
// Alle PHP APIs rekursiv finden
$apiOptions = []; $apiOptions = [];
foreach ($apiFiles as $file) {
$apiOptions[] = 'api/' . basename($file); if ($apiDir !== false) {
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$apiDir,
RecursiveDirectoryIterator::SKIP_DOTS
)
);
foreach ($iterator as $file) {
if (!$file->isFile()) {
continue;
}
if ($file->getExtension() !== 'php') {
continue;
}
// relativen Pfad erzeugen
$relativePath = str_replace(
$apiDir . DIRECTORY_SEPARATOR,
'',
$file->getPathname()
);
// Windows kompatibel
$relativePath = str_replace('\\', '/', $relativePath);
$apiOptions[] = 'api/' . $relativePath;
}
} }
// Token aus deiner get.php entnommen // sortieren
sort($apiOptions);
// Standard Token
$defaultToken = "15a437d128c918633e57dc7d18118a073b807644f21731ed5a7ebcf3eca9e242"; $defaultToken = "15a437d128c918633e57dc7d18118a073b807644f21731ed5a7ebcf3eca9e242";
?> ?>
<style> <style>
/* Spezifische Styles für den API Tester innerhalb des Content-Bereichs */ /* ======================================================
API TESTER STYLES
====================================================== */
.api-tester-container { .api-tester-container {
width: 100%; width: 100%;
max-width: 900px; max-width: 1000px;
margin: 0 auto; margin: 0 auto;
background-color: var(--card-bg); background-color: var(--card-bg);
padding: 25px; padding: 25px;
border-radius: 10px; border-radius: 12px;
border: 1px solid var(--card-border); border: 1px solid var(--card-border);
box-sizing: border-box;
} }
.api-tester-container h2 { .api-tester-container h2 {
@@ -31,83 +71,8 @@ $defaultToken = "15a437d128c918633e57dc7d18118a073b807644f21731ed5a7ebcf3eca9e24
margin-bottom: 20px; margin-bottom: 20px;
color: var(--btn-bg); color: var(--btn-bg);
border-bottom: 1px solid var(--card-border); border-bottom: 1px solid var(--card-border);
padding-bottom: 10px; padding-bottom: 12px;
display: block; display: block;
/* style.css h2 hat flex, wir wollen hier einfaches block */
}
.tester-form-group {
margin-bottom: 15px;
}
.tester-form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
font-size: 0.9rem;
}
.tester-input {
width: 100%;
padding: 10px;
background-color: var(--input-bg);
border: 1px solid var(--input-border);
color: var(--input-text);
border-radius: 5px;
box-sizing: border-box;
}
.tester-btn-send {
background-color: var(--btn-bg);
color: white;
padding: 12px 20px;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
width: 100%;
margin-top: 10px;
}
.tester-btn-send:hover {
opacity: 0.9;
}
#tester-response-container {
margin-top: 25px;
background-color: var(--input-bg);
padding: 15px;
border-radius: 8px;
border: 1px solid var(--card-border);
min-height: 80px;
overflow-x: auto;
}
#tester-output-content {
white-space: pre-wrap;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 0.85rem;
margin: 0;
color: var(--text);
}
.tester-badge {
display: inline-block;
padding: 3px 8px;
border-radius: 4px;
font-size: 0.8rem;
font-weight: bold;
margin-bottom: 10px;
}
.tester-status-200 {
background-color: var(--status-bg);
color: var(--status-text);
}
.tester-status-error {
background-color: #dc3545;
color: white;
} }
.tester-grid { .tester-grid {
@@ -116,140 +81,500 @@ $defaultToken = "15a437d128c918633e57dc7d18118a073b807644f21731ed5a7ebcf3eca9e24
gap: 15px; gap: 15px;
} }
@media (max-width: 600px) { .tester-form-group {
.tester-grid { margin-bottom: 16px;
grid-template-columns: 1fr; }
}
.tester-form-group label {
display: block;
margin-bottom: 6px;
font-weight: bold;
font-size: 0.9rem;
}
.tester-input,
.tester-textarea,
select {
width: 100%;
padding: 10px;
background-color: var(--input-bg);
border: 1px solid var(--input-border);
color: var(--input-text);
border-radius: 6px;
box-sizing: border-box;
font-size: 0.9rem;
}
.tester-textarea {
min-height: 120px;
resize: vertical;
font-family: Consolas, monospace;
}
.tester-btn-send {
width: 100%;
background-color: var(--btn-bg);
color: white;
border: none;
border-radius: 8px;
padding: 13px;
font-weight: bold;
cursor: pointer;
transition: 0.2s;
margin-top: 5px;
}
.tester-btn-send:hover {
opacity: 0.9;
transform: translateY(-1px);
}
#tester-response-container {
margin-top: 25px;
background-color: var(--input-bg);
border: 1px solid var(--card-border);
border-radius: 10px;
padding: 15px;
min-height: 100px;
overflow-x: auto;
}
#tester-output-content {
white-space: pre-wrap;
font-family: Consolas, monospace;
font-size: 0.85rem;
margin: 0;
color: var(--text);
}
.tester-badge {
display: inline-block;
padding: 5px 10px;
border-radius: 5px;
font-size: 0.8rem;
font-weight: bold;
margin-bottom: 12px;
}
.tester-status-200 {
background-color: #198754;
color: white;
}
.tester-status-error {
background-color: #dc3545;
color: white;
}
.tester-status-warning {
background-color: #ffc107;
color: black;
} }
.hidden { .hidden {
display: none !important; display: none !important;
} }
.tester-row {
display: flex;
gap: 10px;
align-items: center;
}
.tester-checkbox {
display: flex;
align-items: center;
gap: 6px;
white-space: nowrap;
margin-top: 8px;
}
.tester-small-btn {
background: transparent;
border: 1px solid var(--input-border);
color: var(--text);
padding: 6px 10px;
border-radius: 6px;
cursor: pointer;
}
.tester-small-btn:hover {
background: rgba(255, 255, 255, 0.05);
}
.tester-response-info {
margin-bottom: 12px;
font-size: 0.85rem;
opacity: 0.8;
}
@media (max-width: 700px) {
.tester-grid {
grid-template-columns: 1fr;
}
.tester-row {
flex-direction: column;
align-items: stretch;
}
}
</style> </style>
<div class="api-tester-container"> <div class="api-tester-container">
<h2>🛠️ API Tester</h2> <h2>🛠️ API Tester</h2>
<!-- API Auswahl -->
<div class="tester-form-group"> <div class="tester-form-group">
<label for="endpoint">API Endpunkt</label> <label for="endpoint">API Endpunkt</label>
<select id="endpoint" class="tester-input" onchange="checkEndpoint()"> <select id="endpoint" class="tester-input" onchange="checkEndpoint()">
<?php foreach ($apiOptions as $opt): ?> <?php foreach ($apiOptions as $opt): ?>
<option value="<?= $opt ?>"><?= $opt ?></option>
<option value="<?= htmlspecialchars($opt) ?>">
<?= htmlspecialchars($opt) ?>
</option>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
</div> </div>
<!-- Methode + Function -->
<div class="tester-grid"> <div class="tester-grid">
<div class="tester-form-group"> <div class="tester-form-group">
<label for="method">HTTP Methode</label> <label for="method">HTTP Methode</label>
<select id="method" class="tester-input"> <select id="method" class="tester-input">
<option value="GET">GET</option> <option value="GET">GET</option>
<option value="POST">POST</option> <option value="POST">POST</option>
<option value="PUT">PUT</option>
<option value="DELETE">DELETE</option>
<option value="PATCH">PATCH</option>
<option value="OPTIONS">OPTIONS</option> <option value="OPTIONS">OPTIONS</option>
</select> </select>
</div> </div>
<div class="tester-form-group" id="function-group"> <div class="tester-form-group" id="function-group">
<label for="function-header">Function Header</label> <label for="function-header">Function Header</label>
<input type="text" id="function-header" class="tester-input" placeholder="z.B. IPs, Ueberstunden"> <input type="text" id="function-header" class="tester-input" placeholder="z.B. IPs, Ueberstunden">
</div> </div>
</div> </div>
<!-- Token -->
<div class="tester-form-group"> <div class="tester-form-group">
<label for="token">Authorization Token</label> <label for="token">Authorization Token</label>
<input type="text" id="token" class="tester-input" value="<?= $defaultToken ?>">
<div class="tester-row">
<input type="text" id="token" class="tester-input" value="<?= htmlspecialchars($defaultToken) ?>">
<label class="tester-checkbox">
<input type="checkbox" id="send-token" checked>
Mitsenden
</label>
</div>
</div> </div>
<!-- Eigene Header -->
<div class="tester-form-group">
<label for="custom-headers">
Zusätzliche Header (JSON)
</label>
<textarea id="custom-headers" class="tester-textarea" placeholder='{
"X-Test": "123",
"Client": "Frontend"
}'></textarea>
</div>
<!-- JSON Body -->
<div class="tester-form-group" id="json-body-group">
<label for="json-body">
JSON Body
</label>
<textarea id="json-body" class="tester-textarea" placeholder='{
"test": true
}'></textarea>
</div>
<!-- Datei Upload -->
<div class="tester-form-group hidden" id="file-group"> <div class="tester-form-group hidden" id="file-group">
<label for="files">Dateien (files)</label>
<label for="files">Dateien Upload</label>
<input type="file" id="files" class="tester-input" multiple> <input type="file" id="files" class="tester-input" multiple>
</div> </div>
<button class="tester-btn-send" onclick="sendApiRequest()">Anfrage senden 🚀</button> <!-- Buttons -->
<div class="tester-grid">
<button class="tester-btn-send" onclick="sendApiRequest()">
Anfrage senden 🚀
</button>
<button class="tester-btn-send" onclick="clearResponse()">
Ausgabe leeren 🧹
</button>
</div>
<!-- Ausgabe -->
<div id="tester-response-container"> <div id="tester-response-container">
<div style="text-align: center; color: #888; padding: 10px;">Bereit für Anfragen.</div>
<div style="text-align:center; opacity:0.7; padding:15px;">
Bereit für Anfragen.
</div>
</div> </div>
</div> </div>
<script> <script>
// ======================================================
// CHECK ENDPOINT
// ======================================================
function checkEndpoint() { function checkEndpoint() {
const endpoint = document.getElementById('endpoint').value; const endpoint = document.getElementById('endpoint').value;
const fileGroup = document.getElementById('file-group'); const fileGroup = document.getElementById('file-group');
const functionGroup = document.getElementById('function-group'); const functionGroup = document.getElementById('function-group');
const jsonBodyGroup = document.getElementById('json-body-group');
const methodSelect = document.getElementById('method'); const methodSelect = document.getElementById('method');
// Standard: alles ausblenden // reset
fileGroup.classList.add('hidden'); fileGroup.classList.add('hidden');
functionGroup.classList.remove('hidden'); functionGroup.classList.remove('hidden');
jsonBodyGroup.classList.remove('hidden');
// upload api
if (endpoint.includes('upload.php')) {
if (endpoint === 'api/upload.php') {
// Nur bei exakt api/upload.php Dateien anzeigen
fileGroup.classList.remove('hidden'); fileGroup.classList.remove('hidden');
functionGroup.classList.add('hidden'); jsonBodyGroup.classList.add('hidden');
methodSelect.value = 'POST'; methodSelect.value = 'POST';
} }
if (endpoint === 'api/get.php') { // get api
if (endpoint.includes('get.php')) {
methodSelect.value = 'GET'; methodSelect.value = 'GET';
} }
} }
// ======================================================
// CLEAR RESPONSE
// ======================================================
function clearResponse() {
document.getElementById('tester-response-container').innerHTML = `
<div style="text-align:center; opacity:0.7; padding:15px;">
Ausgabe geleert.
</div>
`;
}
// ======================================================
// SEND REQUEST
// ======================================================
async function sendApiRequest() { async function sendApiRequest() {
const endpoint = document.getElementById('endpoint').value; const endpoint = document.getElementById('endpoint').value;
const method = document.getElementById('method').value; const method = document.getElementById('method').value;
const token = document.getElementById('token').value; const token = document.getElementById('token').value;
const functionHeader = document.getElementById('function-header').value; const functionHeader = document.getElementById('function-header').value;
const customHeadersInput = document.getElementById('custom-headers').value;
const jsonBodyInput = document.getElementById('json-body').value;
const fileInput = document.getElementById('files'); const fileInput = document.getElementById('files');
const sendToken = document.getElementById('send-token').checked;
const responseContainer = document.getElementById('tester-response-container'); const responseContainer = document.getElementById('tester-response-container');
responseContainer.innerHTML = '<div style="text-align: center; padding: 10px;">Lade...</div>'; responseContainer.innerHTML = `
<div style="text-align:center; padding:15px;">
Anfrage läuft...
</div>
`;
let headers = { let headers = {};
'Authorization': token
};
if (endpoint.includes('get.php') && functionHeader) { // Token
if (sendToken && token.trim() !== '') {
headers['Authorization'] = token;
}
// Function Header
if (functionHeader.trim() !== '') {
headers['Function'] = functionHeader; headers['Function'] = functionHeader;
} }
// Custom Headers
if (customHeadersInput.trim() !== '') {
try {
const customHeaders = JSON.parse(customHeadersInput);
headers = {
...headers,
...customHeaders
};
} catch (e) {
responseContainer.innerHTML = `
<div style="color:#dc3545; padding:15px;">
Fehlerhafte Header JSON Struktur.
</div>
`;
return;
}
}
let options = { let options = {
method: method, method: method,
headers: headers headers: headers
}; };
// Upload
if (endpoint.includes('upload.php') && fileInput.files.length > 0) { if (endpoint.includes('upload.php') && fileInput.files.length > 0) {
const formData = new FormData(); const formData = new FormData();
for (let i = 0; i < fileInput.files.length; i++) { for (let i = 0; i < fileInput.files.length; i++) {
formData.append('files[]', fileInput.files[i]); formData.append('files[]', fileInput.files[i]);
} }
options.body = formData; options.body = formData;
} else {
// JSON Body
if (
['POST', 'PUT', 'PATCH', 'DELETE']
.includes(method) &&
jsonBodyInput.trim() !== ''
) {
try {
JSON.parse(jsonBodyInput);
headers['Content-Type'] = 'application/json';
options.body = jsonBodyInput;
} catch (e) {
responseContainer.innerHTML = `
<div style="color:#dc3545; padding:15px;">
Fehlerhafte JSON Body Struktur.
</div>
`;
return;
}
}
} }
const startedAt = performance.now();
try { try {
const response = await fetch(endpoint, options); const response = await fetch(endpoint, options);
const duration = (performance.now() - startedAt).toFixed(0);
const status = response.status; const status = response.status;
const rawText = await response.text(); const rawText = await response.text();
let resultText = rawText; let resultText = rawText;
// JSON hübsch formatieren
try { try {
const json = JSON.parse(rawText); const json = JSON.parse(rawText);
resultText = JSON.stringify(json, null, 2); resultText = JSON.stringify(json, null, 2);
} catch (e) {} } catch (e) {}
const badgeClass = status >= 200 && status < 300 ? 'tester-status-200' : 'tester-status-error'; let badgeClass = 'tester-status-error';
if (status >= 200 && status < 300) {
badgeClass = 'tester-status-200';
} else if (status >= 300 && status < 400) {
badgeClass = 'tester-status-warning';
}
responseContainer.innerHTML = ` responseContainer.innerHTML = `
<div class="tester-badge ${badgeClass}">Status: ${status}</div> <div class="tester-badge ${badgeClass}">
<pre id="tester-output-content"></pre> Status: ${status}
`; </div>
<div class="tester-response-info">
⏱️ ${duration} ms
</div>
<button
class="tester-small-btn"
onclick="copyResponse()"
>
Antwort kopieren
</button>
<pre id="tester-output-content"></pre>
`;
document.getElementById('tester-output-content').textContent = resultText; document.getElementById('tester-output-content').textContent = resultText;
} catch (error) { } catch (error) {
responseContainer.innerHTML = `<div style="color:#dc3545; padding: 10px;">Fehler: ${error.message}</div>`;
responseContainer.innerHTML = `
<div style="color:#dc3545; padding:15px;">
Fehler: ${error.message}
</div>
`;
} }
} }
// Initial check // ======================================================
// COPY RESPONSE
// ======================================================
function copyResponse() {
const content = document.getElementById('tester-output-content');
if (!content) {
return;
}
navigator.clipboard.writeText(content.textContent);
alert('Antwort kopiert.');
}
// Initial
checkEndpoint(); checkEndpoint();
</script> </script>