diff options
Diffstat (limited to 'gaming/runescape/_lib.php')
| -rw-r--r-- | gaming/runescape/_lib.php | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/gaming/runescape/_lib.php b/gaming/runescape/_lib.php new file mode 100644 index 0000000..c8fbbab --- /dev/null +++ b/gaming/runescape/_lib.php @@ -0,0 +1,182 @@ +<?php +// Shared read-only helpers for the /gaming/runescape/ page. +// Data is edited via /admin.php?section=runescape; this file just renders it. + +function runescape_valid_url_or_path(string $url): bool { + if ($url === '') return false; + if ($url[0] === '/') return !str_starts_with($url, '//') && !str_contains($url, "\0"); + $scheme = strtolower(parse_url($url, PHP_URL_SCHEME) ?? ''); + if (in_array($scheme, ['http', 'https', 'gemini', 'gopher'], true)) return filter_var($url, FILTER_VALIDATE_URL) !== false; + return false; +} + +function runescape_data(?string $path = null): array { + $path = $path ?? (__DIR__ . '/data.json'); + $empty = [ + 'welcome' => [], + 'screenshots' => [], + 'eras' => [], + 'links_section' => ['title' => 'Server Lists', 'disclaimer' => '', 'items' => []], + ]; + if (!is_file($path)) { + return $empty; + } + $raw = file_get_contents($path); + if ($raw === false || trim($raw) === '') { + return $empty; + } + $data = json_decode($raw, true); + if (!is_array($data)) { + return $empty; + } + $welcome = []; + foreach (($data['welcome'] ?? []) as $line) { + $line = trim((string)$line); + if ($line !== '') $welcome[] = $line; + } + $screenshots = []; + foreach (($data['screenshots'] ?? []) as $shot) { + if (!is_array($shot)) continue; + $filename = trim((string)($shot['filename'] ?? '')); + if ($filename === '' || str_contains($filename, '..') || str_contains($filename, '/')) continue; + $screenshots[] = [ + 'filename' => $filename, + 'caption' => (string)($shot['caption'] ?? ''), + ]; + } + $eras = []; + foreach (($data['eras'] ?? []) as $era) { + if (!is_array($era)) continue; + $title = trim((string)($era['title'] ?? '')); + if ($title === '') continue; + $servers = []; + foreach (($era['servers'] ?? []) as $srv) { + if (!is_array($srv)) continue; + $name = trim((string)($srv['name'] ?? '')); + if ($name === '') continue; + $url = trim((string)($srv['url'] ?? '')); + if ($url !== '' && !runescape_valid_url_or_path($url)) $url = ''; + $highlights = []; + foreach (($srv['highlights'] ?? []) as $hl) { + $hl = trim((string)$hl); + if ($hl !== '') $highlights[] = $hl; + } + $links = []; + foreach (($srv['links'] ?? []) as $lk) { + if (!is_array($lk)) continue; + $label = trim((string)($lk['label'] ?? '')); + $lurl = trim((string)($lk['url'] ?? '')); + if ($label === '' || $lurl === '' || !runescape_valid_url_or_path($lurl)) continue; + $links[] = ['label' => $label, 'url' => $lurl]; + } + $srvImage = trim((string)($srv['image'] ?? '')); + if ($srvImage !== '' && str_contains($srvImage, '..')) $srvImage = ''; + $servers[] = [ + 'id' => (string)($srv['id'] ?? ''), + 'name' => $name, + 'url' => $url, + 'featured' => !empty($srv['featured']), + 'desc' => (string)($srv['desc'] ?? ''), + 'highlights' => $highlights, + 'links' => $links, + 'image' => $srvImage, + ]; + } + $eraImage = trim((string)($era['image'] ?? '')); + if ($eraImage !== '' && str_contains($eraImage, '..')) $eraImage = ''; + $eras[] = [ + 'id' => (string)($era['id'] ?? ''), + 'title' => $title, + 'subtitle' => (string)($era['subtitle'] ?? ''), + 'image' => $eraImage, + 'servers' => $servers, + ]; + } + $linksSection = ['title' => 'Server Lists', 'disclaimer' => '', 'items' => []]; + if (is_array($data['links_section'] ?? null)) { + $ls = $data['links_section']; + $linksSection['title'] = trim((string)($ls['title'] ?? '')) ?: 'Server Lists'; + $linksSection['disclaimer'] = (string)($ls['disclaimer'] ?? ''); + foreach (($ls['items'] ?? []) as $item) { + if (!is_array($item)) continue; + $label = trim((string)($item['label'] ?? '')); + $lurl = trim((string)($item['url'] ?? '')); + if ($label === '' || $lurl === '' || !runescape_valid_url_or_path($lurl)) continue; + $linksSection['items'][] = ['label' => $label, 'url' => $lurl, 'desc' => (string)($item['desc'] ?? '')]; + } + } + return ['welcome' => $welcome, 'screenshots' => $screenshots, 'eras' => $eras, 'links_section' => $linksSection]; +} + +function runescape_screenshot_src(string $filename): string { + $filename = trim($filename); + if ($filename === '' || str_contains($filename, '..') || str_contains($filename, '/')) return ''; + return '/gaming/runescape/images/' . rawurlencode($filename); +} + +/** Public URL for an era/server image (uploaded filename, site path, or absolute URL). */ +function runescape_image_src(string $image): string { + $image = trim($image); + if ($image === '') return ''; + if (str_starts_with($image, 'http://') || str_starts_with($image, 'https://') || str_starts_with($image, '/')) { + return $image; + } + if (str_contains($image, '..') || str_contains($image, "\0")) return ''; + return '/gaming/runescape/images/' . rawurlencode(basename($image)); +} + +/** Render the Welcome list — lines like "::Label::" become bold headings, everything else is a bullet. */ +function runescape_render_welcome(array $lines): void { + $he = fn($s) => htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); + $inList = false; + foreach ($lines as $line) { + if (preg_match('/^::(.+)::$/', trim($line), $m)) { + if ($inList) { echo '</ul>'; $inList = false; } + echo '<p class="machine-title machine-title--sub">' . $he(trim($m[1])) . '</p>'; + continue; + } + if (!$inList) { echo '<ul class="contact-list">'; $inList = true; } + echo '<li>' . $he($line) . '</li>'; + } + if ($inList) echo '</ul>'; +} + +/** Render one server card (used inside an era section). */ +function runescape_render_server(array $srv): void { + $he = fn($s) => htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); + $cardClass = $srv['featured'] ? 'machine machine--notes' : 'machine'; + $img = runescape_image_src((string)($srv['image'] ?? '')); + ?> + <div class="<?= $cardClass ?>"> + <div class="<?= $img !== '' ? 'machine-row' : '' ?>"> + <?php if ($img !== ''): ?> + <img class="machine-thumb" src="<?= $he($img) ?>" alt="<?= $he($srv['name']) ?>" loading="lazy" decoding="async"> + <?php endif; ?> + <div class="machine-info<?= $img !== '' ? ' machine-facts' : '' ?>"> + <div class="machine-title"> + <?php if ($srv['url'] !== ''): ?> + <a href="<?= $he($srv['url']) ?>" target="_blank" rel="noopener noreferrer"><?= $he($srv['name']) ?></a> + <?php else: ?> + <?= $he($srv['name']) ?> + <?php endif; ?> + </div> + <?php if ($srv['desc'] !== ''): ?> + <?= nl2br($he($srv['desc'])) ?> + <?php endif; ?> + <?php if ($srv['highlights']): ?> + <ul class="contact-list"> + <?php foreach ($srv['highlights'] as $hl): ?><li><?= $he($hl) ?></li><?php endforeach; ?> + </ul> + <?php endif; ?> + <?php if ($srv['links']): ?> + <p> + <?php foreach ($srv['links'] as $i => $lk): ?> + <?= $i > 0 ? ' · ' : '' ?><a href="<?= $he($lk['url']) ?>" target="_blank" rel="noopener noreferrer"><?= $he($lk['label']) ?></a> + <?php endforeach; ?> + </p> + <?php endif; ?> + </div> + </div> + </div> + <?php +} |
