aboutsummaryrefslogtreecommitdiffstats
path: root/startpage/render_cards.php
blob: 369a5fd33edb102eecada36451ff67dfcc317232 (plain) (blame)
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; ?>