$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(); ?> <?= e(SEITEN_TITEL) ?>
SOFTWARE

Verfügbare Werkzeuge

Hier ist noch nichts eingetragen.
Ein Ordner erscheint automatisch, sobald er eine Datei tool.json enthält.

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.