Files
dasposchi-de/core/helpers.php
Claude 3c97192386 Initiales CMS: Deutschsprachiges Blog-System mit Admin-Bereich
Vollständiges, schlankes PHP/SQLite-CMS für IT-, KI- und Gaming-Inhalte:

- Core: DB-Singleton, Auth mit Passwort-Hashing, Session-Cookies,
  CSRF-Schutz, Login-Rate-Limit, Bild-Upload mit serverseitiger Validierung
- Admin: Dashboard, Artikel/Seiten-Verwaltung mit Quill WYSIWYG-Editor,
  Kategorien, Navigation (Drag & Drop), Medienbibliothek, Profil
- Frontend: Responsive Dark-Theme, Artikel-Grid, Kategorie-Filter,
  Archiv, Paginierung, SEO-Meta-Tags
- Sicherheit: Prepared Statements, HTML-Sanitizer, .htaccess-Schutz
  für sensible Verzeichnisse, PHP-Ausführungsschutz im Upload-Ordner
- Installation: install.php erstellt DB-Schema und Admin-Account

https://claude.ai/code/session_01Xsg4j2t4S9goMuWVpF3ezG
2026-04-05 20:59:52 +00:00

108 lines
3.0 KiB
PHP

<?php
/**
* Hilfsfunktionen
*/
function e(string $str): string
{
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
function slugify(string $str): string
{
$replacements = [
'ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'ß' => 'ss',
'Ä' => 'ae', 'Ö' => 'oe', 'Ü' => 'ue',
];
$str = str_replace(array_keys($replacements), array_values($replacements), $str);
$str = mb_strtolower($str, 'UTF-8');
$str = preg_replace('/[^a-z0-9\s-]/', '', $str);
$str = preg_replace('/[\s-]+/', '-', $str);
return trim($str, '-');
}
function redirect(string $url): never
{
header('Location: ' . $url);
exit;
}
function flash(string $type, string $message): void
{
$_SESSION['flash'][] = ['type' => $type, 'message' => $message];
}
function flash_display(): string
{
if (empty($_SESSION['flash'])) {
return '';
}
$html = '';
foreach ($_SESSION['flash'] as $msg) {
$cls = e($msg['type']);
$text = e($msg['message']);
$html .= "<div class=\"flash flash-{$cls}\">{$text}</div>";
}
$_SESSION['flash'] = [];
return $html;
}
function paginate(int $total, int $page, int $perPage): array
{
$totalPages = max(1, (int) ceil($total / $perPage));
$page = max(1, min($page, $totalPages));
$offset = ($page - 1) * $perPage;
return [
'offset' => $offset,
'limit' => $perPage,
'total_pages' => $totalPages,
'current_page' => $page,
'total' => $total,
];
}
function format_date(string $datetime): string
{
$months = [
1 => 'Januar', 2 => 'Februar', 3 => 'März', 4 => 'April',
5 => 'Mai', 6 => 'Juni', 7 => 'Juli', 8 => 'August',
9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Dezember',
];
$ts = strtotime($datetime);
if ($ts === false) {
return $datetime;
}
$day = (int) date('j', $ts);
$month = $months[(int) date('n', $ts)];
$year = date('Y', $ts);
return "{$day}. {$month} {$year}";
}
function excerpt(string $html, int $length = 200): string
{
$text = strip_tags($html);
if (mb_strlen($text) <= $length) {
return $text;
}
$truncated = mb_substr($text, 0, $length);
$lastSpace = mb_strrpos($truncated, ' ');
if ($lastSpace !== false) {
$truncated = mb_substr($truncated, 0, $lastSpace);
}
return $truncated . '…';
}
function sanitize_html(string $html): string
{
$allowed = '<p><br><strong><b><em><i><u><ul><ol><li><h2><h3><h4><a><img><blockquote><pre><code><hr><table><thead><tbody><tr><th><td>';
$html = strip_tags($html, $allowed);
// Event-Handler und javascript:-URLs entfernen
$html = preg_replace('/\bon\w+\s*=\s*["\'][^"\']*["\']/i', '', $html);
$html = preg_replace('/\bon\w+\s*=\s*\S+/i', '', $html);
$html = preg_replace('/href\s*=\s*["\']?\s*javascript\s*:[^"\'>\s]*/i', 'href="#"', $html);
$html = preg_replace('/src\s*=\s*["\']?\s*javascript\s*:[^"\'>\s]*/i', 'src=""', $html);
return $html;
}