= e($tool['name']) ?>
= e($tool['beschreibung']) ?>
Keine Beschreibung hinterlegt.
$maxZeichen) break; $ergebnis .= $wert[$i]; } return $ergebnis; } /** Text säubern: ungültiges UTF-8 und Steuerzeichen raus, Länge begrenzen. */ function sauberText(mixed $wert, int $maxLaenge = MAX_TEXT_LAENGE): string { if (!is_string($wert)) return ''; // Ungültiges UTF-8 komplett verwerfen - sonst könnten kaputte Bytes // die spätere Maskierung unterlaufen. if (preg_match('//u', $wert) !== 1) return ''; // Steuerzeichen byteweise entfernen; bei UTF-8 gefahrlos, weil // Folgebytes immer >= 0x80 sind. $wert = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $wert) ?? ''; $wert = trim($wert); if (textLaenge($wert) > $maxLaenge) { $wert = textKuerzen($wert, $maxLaenge - 1) . '…'; } return $wert; } /** Ausgabe maskieren - wird bei JEDER Ausgabe verwendet. */ function e(string $wert): string { return htmlspecialchars($wert, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8'); } /** Externe Adresse: nur http/https, sonst verworfen. */ function sichereUrl(mixed $wert): string { if (!is_string($wert)) return ''; $wert = trim($wert); if ($wert === '' || textLaenge($wert) > 500) return ''; if (!preg_match('#^https?://#i', $wert)) return ''; if (filter_var($wert, FILTER_VALIDATE_URL) === false) return ''; return $wert; } /** Relativer Pfad innerhalb des Tool-Ordners - kein Ausbruch möglich. */ function sichererEinstieg(mixed $wert, string $ordnerPfad): string { if (!is_string($wert)) return ''; $wert = trim($wert); if ($wert === '' || strlen($wert) > 200) return ''; if (!preg_match('#^[A-Za-z0-9._\-/]+$#', $wert)) return ''; if (str_contains($wert, '..') || str_starts_with($wert, '/')) return ''; $ziel = realpath($ordnerPfad . DIRECTORY_SEPARATOR . $wert); $basis = realpath($ordnerPfad); if ($ziel === false || $basis === false) return ''; if (!str_starts_with($ziel, $basis . DIRECTORY_SEPARATOR)) return ''; if (!is_file($ziel)) return ''; return $wert; } /** Datum nur akzeptieren, wenn es wirklich eines ist. */ function sicheresDatum(mixed $wert): string { if (!is_string($wert)) return ''; $wert = trim($wert); if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $wert)) return ''; [$j, $m, $t] = array_map('intval', explode('-', $wert)); return checkdate($m, $t, $j) ? $wert : ''; } /** Alle Tools einsammeln. */ function toolsLesen(): array { $basis = __DIR__; $eintraege = @scandir($basis); if ($eintraege === false) return []; $tools = []; foreach ($eintraege as $name) { if ($name === '.' || $name === '..') continue; if (str_starts_with($name, '.') || str_starts_with($name, '_')) continue; if (in_array(strtolower($name), GESPERRTE_ORDNER, true)) continue; $ordner = $basis . DIRECTORY_SEPARATOR . $name; if (!is_dir($ordner)) continue; // Symlinks, die aus dem Verzeichnis herausführen, werden ignoriert $echt = realpath($ordner); if ($echt === false || !str_starts_with($echt, $basis . DIRECTORY_SEPARATOR)) continue; $jsonPfad = $echt . DIRECTORY_SEPARATOR . 'tool.json'; if (!is_file($jsonPfad)) continue; if (filesize($jsonPfad) > MAX_JSON_BYTES) continue; $roh = @file_get_contents($jsonPfad, false, null, 0, MAX_JSON_BYTES); if ($roh === false) continue; try { $daten = json_decode($roh, true, 8, JSON_THROW_ON_ERROR); } catch (JsonException) { continue; // defekte Datei wird still übersprungen } if (!is_array($daten)) continue; if (isset($daten['sichtbar']) && $daten['sichtbar'] === false) continue; $anzeigename = sauberText($daten['name'] ?? '', 80) ?: $name; $einstieg = sichererEinstieg($daten['einstieg'] ?? '', $echt); $tags = []; if (isset($daten['tags']) && is_array($daten['tags'])) { foreach (array_slice($daten['tags'], 0, MAX_TAGS) as $tag) { $tag = sauberText($tag, 24); if ($tag !== '') $tags[] = $tag; } } $tools[] = [ 'ordner' => $name, 'name' => $anzeigename, 'beschreibung' => sauberText($daten['beschreibung'] ?? ''), 'einstieg' => $einstieg, 'repository' => sichereUrl($daten['repository'] ?? ''), 'repositoryName'=> sauberText($daten['repositoryName'] ?? '', 30) ?: 'Quellcode', 'version' => sauberText($daten['version'] ?? '', 20), 'lizenz' => sauberText($daten['lizenz'] ?? '', 40), 'stand' => sicheresDatum($daten['stand'] ?? ''), 'tags' => $tags, ]; } usort($tools, fn(array $a, array $b) => strcasecmp($a['name'], $b['name'])); return $tools; } $tools = toolsLesen(); ?>
tool.json enthält.
= e($tool['beschreibung']) ?>
Keine Beschreibung hinterlegt.
Alle Werkzeuge laufen vollständig in deinem Browser. Es werden keine Inhalte, die du darin bearbeitest, an diesen Server übertragen oder dort gespeichert. Näheres in der Datenschutzerklärung.