Files
usbcheck.it/src/functions.php
2025-11-25 22:07:05 +01:00

276 lines
7.6 KiB
PHP

<?php
$GLOBALS['page_header_scripts'] = $GLOBALS['page_header_scripts'] ?? [];
$GLOBALS['page_footer_scripts'] = $GLOBALS['page_footer_scripts'] ?? [];
$GLOBALS['page_styles'] = $GLOBALS['page_styles'] ?? [];
function app_primary_domain(): string
{
return defined('APP_DOMAIN_PRIMARY') ? APP_DOMAIN_PRIMARY : 'usbcheck.it';
}
function app_primary_url(): string
{
$url = defined('APP_URL_PRIMARY') ? APP_URL_PRIMARY : 'https://usbcheck.it';
return rtrim($url, '/');
}
function app_fakecheck_domain(): string
{
return defined('APP_DOMAIN_FAKECHECK') ? APP_DOMAIN_FAKECHECK : 'ismyusbfake.com';
}
function app_fakecheck_url(): string
{
$url = defined('APP_URL_FAKECHECK') ? APP_URL_FAKECHECK : 'https://ismyusbfake.com';
return rtrim($url, '/');
}
/**
* Script registrieren
*
* @param string $src Pfad zur Datei, z. B. '/assets/js/auth.js'
* @param string $pos 'header' oder 'footer'
* @param bool $defer standard true
* @param bool $async standard false
* @param string $type z. B. 'module'
* @param string|null $version null = nutze ASSET_VERSION (falls definiert),
* '' = kein ?v=,
* 'xyz'= erzwinge diese Version
*/
function tpl_add_script(
string $src,
string $pos = 'footer',
bool $defer = true,
bool $async = false,
string $type = '',
?string $version = null
): void {
// Standard-Verhalten: falls Version nicht explizit gesetzt → globale ASSET_VERSION verwenden
if ($version === null && defined('ASSET_VERSION')) {
$version = ASSET_VERSION;
}
$data = [
'src' => $src,
'defer' => $defer,
'async' => $async,
'type' => $type,
'version' => $version, // kann null, '' oder string sein
];
if ($pos === 'header') {
$GLOBALS['page_header_scripts'][] = $data;
} else {
$GLOBALS['page_footer_scripts'][] = $data;
}
}
/**
* CSS registrieren
*
* @param string $href Pfad zur CSS
* @param string $pos 'header' oder 'footer'
* @param string|null $version gleiche Logik wie bei Scripts
*/
function tpl_add_style(string $href, string $pos = 'header', ?string $version = null): void
{
if ($version === null && defined('ASSET_VERSION')) {
$version = ASSET_VERSION;
}
$GLOBALS['page_styles'][] = [
'href' => $href,
'pos' => $pos,
'version' => $version,
];
}
/**
* Templating Loader
*
* Beispiel:
* tpl('header'); // structure/header.php
* tpl('hero', 'landing', 'main'); // landing/main/hero.php
* tpl('faq', 'landing', 'fakecheck'); // landing/fakecheck/faq.php
*/
function tpl(string $file, string $type = 'structure', string $site = 'main'): void
{
$base = __DIR__ . '/../partials/';
// VALIDIERUNG: Nur einfache Check, kein Path-Traversal
if (preg_match('/[^a-zA-Z0-9_\-]/', $file)) {
echo "<!-- tpl(): Ungültiger Template-Name -->";
return;
}
if (preg_match('/[^a-zA-Z0-9_\-]/', $type)) {
echo "<!-- tpl(): Ungültiger Type -->";
return;
}
if (preg_match('/[^a-zA-Z0-9_\-]/', $site)) {
echo "<!-- tpl(): Ungültiger Site -->";
return;
}
if ($type === 'landing') {
$path = $base . "landing/$site/$file.php";
} else {
$path = $base . "structure/$file.php";
}
extract($GLOBALS, EXTR_SKIP);
if (file_exists($path)) {
include $path;
} else {
echo "<!-- tpl(): Datei nicht gefunden: $path -->";
}
}
/**
* Flash-Meldung setzen (wird genau einmal nach Redirect angezeigt).
*
* @param string $type z.B. 'success', 'error', 'info', 'warning'
* @param string $message Die Meldung für den Nutzer
* @param string|null $context Optionaler Kontext (z.B. 'login', 'register')
*/
function flash_set(string $type, string $message, ?string $context = null): void
{
if (session_status() !== PHP_SESSION_ACTIVE) {
@session_start();
}
$_SESSION['flash'] = [
'type' => $type,
'message' => $message,
'context' => $context,
];
}
/**
* Flash-Meldung holen und direkt löschen (Einmal-Anzeige).
*
* @return array|null ['type' => 'success|error|info|warning', 'message' => '...', 'context' => '...']
*/
function flash_get(): ?array
{
if (session_status() !== PHP_SESSION_ACTIVE) {
@session_start();
}
if (empty($_SESSION['flash']) || !is_array($_SESSION['flash'])) {
return null;
}
$flash = $_SESSION['flash'];
unset($_SESSION['flash']);
$flash['type'] = $flash['type'] ?? 'info';
$flash['message'] = $flash['message'] ?? '';
$flash['context'] = $flash['context'] ?? null;
return $flash;
}
/**
* Interne Helper-Funktion: traversiert ein Array mit "dot notation"-Segmenten.
*
* @param array $data
* @param string $key z.B. 'pages.landing.meta.title'
* @return mixed|null
*/
function _i18n_traverse_array(array $data, string $key)
{
$segments = explode('.', $key);
$node = $data;
foreach ($segments as $seg) {
if (!is_array($node) || !array_key_exists($seg, $node)) {
return null;
}
$node = $node[$seg];
}
return $node;
}
/**
* Zentrale Funktion zum Laden eines i18n-Strings mit Fallback.
*
* - greift zuerst auf $GLOBALS['i18n']['current'] zu
* - dann auf $GLOBALS['i18n']['fallback']
* - unterstützt Platzhalter {key} und {{key}}
* - eingebaute Platzhalter:
* {year}
* {{primary_domain}}
* {{primary_url}}
*
* @param string $path z.B. 'pages.login.meta.title'
* @param mixed $default Fallback, falls nichts gefunden wird
* @param array $replacements ['name' => 'Lars']
*
* @return string
*/
function i18n_get(string $path, $default = null, array $replacements = []): string
{
if (!isset($GLOBALS['i18n']) || !is_array($GLOBALS['i18n'])) {
return $default !== null ? (string)$default : '';
}
$current = $GLOBALS['i18n']['current'] ?? [];
$fallback = $GLOBALS['i18n']['fallback'] ?? [];
// zuerst in der aktiven Sprache suchen
$value = _i18n_traverse_array($current, $path);
// wenn dort nichts → Fallback-Sprache
if ($value === null && !empty($fallback)) {
$value = _i18n_traverse_array($fallback, $path);
}
if (!is_string($value)) {
return $default !== null ? (string)$default : '';
}
$text = $value;
// eingebaute Platzhalter
$builtIn = [
'{year}' => date('Y'),
'{{primary_domain}}' => function_exists('app_primary_domain') ? app_primary_domain() : '',
'{{primary_url}}' => function_exists('app_primary_url') ? app_primary_url() : '',
];
foreach ($builtIn as $ph => $val) {
$text = str_replace($ph, $val, $text);
}
// zusätzliche Platzhalter aus $replacements
foreach ($replacements as $key => $val) {
$val = (string)$val;
// Variante {key}
$text = str_replace('{' . $key . '}', $val, $text);
// Variante {{key}}
$text = str_replace('{{' . $key . '}}', $val, $text);
}
return $text;
}
/**
* Convenience-Wrapper für i18n_get, etwas "kürzer" zu tippen
* und vom bisherigen Code kompatibel genutzt.
*
* Beispiel:
* i18n_get_fmt('fake_ui.log_capacity_probe_result', 'Fallback', ['size' => '2 GB']);
*/
function i18n_get_fmt(string $path, $default = '', array $vars = []): string
{
// Falls $default explizit null ist → leere String als Basis
$def = $default ?? '';
return i18n_get($path, $def, $vars);
}