1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
<?php
if (realpath(__FILE__) === realpath($_SERVER['SCRIPT_FILENAME'] ?? '')) { http_response_code(404); exit; }
function startpage_valid_card_url(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) ?? '');
return in_array($scheme, ['http', 'https', 'gemini', 'gopher'], true) && filter_var($url, FILTER_VALIDATE_URL) !== false;
}
function startpage_valid_card_asset(string $ref): bool {
if ($ref === '' || str_contains($ref, "\0")) return false;
if (startpage_valid_card_url($ref)) return true;
return !str_contains($ref, '..') && preg_match('/^[A-Za-z0-9][A-Za-z0-9._\/-]*$/', $ref);
}
function startpage_card_data(): array {
$file = __DIR__ . '/cards.txt';
$raw = is_file($file) ? file_get_contents($file) : '';
$cards = [];
$cur = null;
foreach (explode("\n", str_replace("\r\n", "\n", (string)$raw)) as $line) {
$line = trim($line);
if ($line === '') continue;
if ($line[0] === '#') {
if ($cur !== null) $cards[] = $cur;
$parts = array_map('trim', explode('|', ltrim($line, '#'), 3));
$title = $parts[0] ?? '';
$image = $parts[1] ?? '';
$alt = $parts[2] ?? 'Visual';
if ($title === '' || !startpage_valid_card_asset($image)) { $cur = null; continue; }
$cur = ['title' => $title, 'image' => $image, 'alt' => $alt !== '' ? $alt : 'Visual', 'links' => []];
continue;
}
if ($cur === null) continue;
$parts = array_map('trim', explode('|', $line, 2));
$label = $parts[0] ?? '';
$url = $parts[1] ?? '';
if ($label !== '' && startpage_valid_card_url($url)) $cur['links'][] = ['label' => $label, 'url' => $url];
}
if ($cur !== null) $cards[] = $cur;
$all = array_values(array_filter($cards, fn($card) => $card['links'] !== []));
return $all;
}
function startpage_seasonal_sports_image(string $image): string {
// Sports card logo follows the local season: Belleville Senators (AHL)
// October–April, Belleville Kodiaks (OSL Sr B lacrosse) May–September.
if ($image !== 'belleville.png') return $image;
$month = (int)date('n');
return ($month >= 5 && $month <= 9) ? 'kodiaks.png' : 'belleville.png';
}
$allCardData = startpage_card_data();
foreach ($allCardData as &$card) {
$card['image'] = startpage_seasonal_sports_image($card['image']);
}
unset($card);
?>
<?php foreach ($allCardData as $card): ?>
<article class="card" data-title="<?= htmlspecialchars($card['title'], ENT_QUOTES, 'UTF-8') ?>" data-labels="<?= htmlspecialchars(implode(' ', array_column($card['links'], 'label')), ENT_QUOTES, 'UTF-8') ?>">
<div class="card-titlebar">
<span class="card-dots" aria-hidden="true"><span></span><span></span><span></span></span>
<span class="card-title"><?= htmlspecialchars($card['title'], ENT_QUOTES, 'UTF-8') ?></span>
</div>
<div class="card-body">
<div class="thumb"><img src="<?= htmlspecialchars($card['image'], ENT_QUOTES, 'UTF-8') ?>" alt="<?= htmlspecialchars($card['alt'], ENT_QUOTES, 'UTF-8') ?>" loading="lazy" decoding="async" /></div>
<div class="card-links">
<?php foreach ($card['links'] as $link): ?>
<a href="<?= htmlspecialchars($link['url'], ENT_QUOTES, 'UTF-8') ?>" title="<?= htmlspecialchars($link['label'] . ' — ' . $link['url'], ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars($link['label'], ENT_QUOTES, 'UTF-8') ?></a>
<?php endforeach; ?>
</div>
</div>
</article>
<?php endforeach; ?>
|