137 lines · 4.4 KB
Raw Download
1
<?php
2
/**
3
 * Front controller / router.
4
 *
5
 * Any request that is not a real file or directory is rewritten here by
6
 * .htaccess. We strip BASE_PATH, parse the path, and dispatch.
7
 */
8
9
require_once __DIR__ . '/includes/db.php';
10
require_once __DIR__ . '/includes/helpers.php';
11
12
// ---- Parse the request path -------------------------------------------------
13
$uri  = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?? '/';
14
$uri  = rawurldecode($uri);
15
16
// Strip the base path prefix if present.
17
$base = BASE_PATH;
18
if ($base !== '' && strpos($uri, $base) === 0) {
19
    $uri = substr($uri, strlen($base));
20
}
21
22
$path  = trim($uri, '/');
23
$parts = $path === '' ? [] : explode('/', $path);
24
25
// ---- Dispatch ---------------------------------------------------------------
26
if (count($parts) === 0) {
27
    render_home();
28
    exit;
29
}
30
31
$slug = strtolower($parts[0]);
32
33
if (!valid_slug($slug)) {
34
    render_404();
35
    exit;
36
}
37
38
// /{slug}/og-{hash}.png — generated social preview card. The hash only busts
39
// crawler caches; the current card is served whatever hash is asked for.
40
if (count($parts) === 2 && preg_match('/^og(?:-([a-f0-9]+))?\.png$/', $parts[1], $m)) {
41
    require __DIR__ . '/includes/og.php';
42
    render_repo_og($slug, $m[1] ?? '');
43
    exit;
44
}
45
46
// /{slug}/{blob|tree|raw|archive}/{path}
47
if (count($parts) >= 2 && in_array($parts[1], ['blob', 'tree', 'raw', 'archive'], true)) {
48
    $view = $parts[1];
49
    $path = implode('/', array_slice($parts, 2)); // repo.php sanitises it
50
    // blob and raw need an actual file path; tree and archive operate on the
51
    // whole repository and so may have an empty path.
52
    if ($path === '' && !in_array($view, ['tree', 'archive'], true)) {
53
        render_404();
54
        exit;
55
    }
56
    require __DIR__ . '/repo.php';
57
    exit;
58
}
59
60
// /{slug}
61
if (count($parts) === 1) {
62
    $view = 'tree';
63
    $path = '';
64
    require __DIR__ . '/repo.php';
65
    exit;
66
}
67
68
render_404();
69
exit;
70
71
72
// ---- Views ------------------------------------------------------------------
73
74
function render_home(): void
75
{
76
    $sort = $_GET['sort'] ?? 'newest';
77
    if (!isset(REPO_SORTS[$sort])) {
78
        $sort = 'newest';
79
    }
80
    $repos = get_repositories($sort);
81
    $page_title = 'Repositories';
82
    $og_description = 'Source code and projects by jefftml.';
83
    require __DIR__ . '/includes/header.php';
84
85
    $sort_labels = [
86
        'newest' => 'Newest first',
87
        'oldest' => 'Oldest first',
88
        'name'   => 'Name (A–Z)',
89
        'slug'   => 'Slug (A–Z)',
90
    ];
91
    ?>
92
    <div class="repo-list-head">
93
        <h1>Repositories</h1>
94
        <?php if (!empty($repos)): ?>
95
            <form method="get" action="<?= e(url('/')) ?>" class="repo-sort">
96
                <label for="repo-sort">Sort</label>
97
                <select name="sort" id="repo-sort" onchange="this.form.submit()">
98
                    <?php foreach ($sort_labels as $key => $label): ?>
99
                        <option value="<?= e($key) ?>"<?= $key === $sort ? ' selected' : '' ?>><?= e($label) ?></option>
100
                    <?php endforeach; ?>
101
                </select>
102
                <noscript><button type="submit" class="btn-secondary">Apply</button></noscript>
103
            </form>
104
        <?php endif; ?>
105
    </div>
106
    <?php if (empty($repos)): ?>
107
        <p class="empty">No repositories yet.</p>
108
    <?php else: ?>
109
        <ul class="repo-list">
110
            <?php foreach ($repos as $r): ?>
111
                <li class="repo-item">
112
                    <a class="repo-name" href="<?= e(url('/' . $r['slug'])) ?>"><?= e($r['name']) ?></a>
113
                    <?php $rLang = repo_language_display($r); ?>
114
                    <?php if ($rLang !== ''): ?>
115
                        <span class="badge"><?= e($rLang) ?></span>
116
                    <?php endif; ?>
117
                    <?php if (!empty($r['description'])): ?>
118
                        <p class="repo-desc"><?= e($r['description']) ?></p>
119
                    <?php endif; ?>
120
                    <p class="muted">/<?= e($r['slug']) ?> &middot; created <?= e(substr($r['created_at'], 0, 10)) ?></p>
121
                </li>
122
            <?php endforeach; ?>
123
        </ul>
124
    <?php endif; ?>
125
    <?php
126
    require __DIR__ . '/includes/footer.php';
127
}
128
129
function render_404(): void
130
{
131
    http_response_code(404);
132
    $page_title = 'Not found';
133
    require __DIR__ . '/includes/header.php';
134
    echo '<h1>404</h1><p class="empty">Nothing here.</p>';
135
    require __DIR__ . '/includes/footer.php';
136
}
137