Files
www-data 475765e31f Move rendering into private templates
Add an explicit template renderer with HTML views and partials for the app, bootstrap, package, and catalog pages. Move shared reporting setup into config/reporting.php and relocate stylesheet assets under css/.
2026-05-26 12:50:26 +02:00

154 lines
3.6 KiB
PHP

<?php
/*
* rktpkgs.php
*
* Maakt een volledige HTML-index van de Racket package catalogus.
*
* Bron:
* https://pkgs.racket-lang.org/pkgs-all
*
* Output:
* Alleen HTML.
*
* Package-links:
* /package?name=<pkg-name>&next=<id>
*
* Regels:
* - Geen filterveld.
* - Geen git-adressen tonen.
* - Geen package-details tonen.
* - Geen package-downloads implementeren in dit script.
* - De package-naam zelf is de link.
* - Eén next-id per gegenereerde HTML-pagina.
*
* .htaccess:
*
* Options -MultiViews
* RewriteEngine On
* RewriteRule ^racket-pkg-index$ rktpkgs.php [L,QSA]
*/
require_once __DIR__ . '/config/reporting.php';
require_once __DIR__ . '/private/nexttoken.php';
require_once __DIR__ . '/private/lib/catalog-http.php';
require_once __DIR__ . '/private/lib/racket-data.php';
require_once __DIR__ . '/private/Template.php';
$TOKENS = new NextTokenStore(__DIR__ . '/data/racket-sandbox.sqlite');
@set_time_limit(180);
ignore_user_abort(false);
define('CATALOG_PKGS_ALL', 'https://pkgs.racket-lang.org/pkgs-all');
define('CACHE_DIR', __DIR__ . '/data');
define('CACHE_FILE', CACHE_DIR . '/pkgs-all.rktd');
define('CACHE_META_FILE', CACHE_DIR . '/pkgs-all.meta.json');
define('CACHE_TTL', 3600);
/*
* Eén next-id voor alle package-links op deze pagina.
*/
$NEXT_ID = $TOKENS->create();
function h($s)
{
return htmlspecialchars((string)$s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
function current_scheme()
{
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
return strtolower(trim(explode(',', $_SERVER['HTTP_X_FORWARDED_PROTO'])[0]));
}
return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
}
function current_host()
{
return $_SERVER['HTTP_HOST'] ?? 'localhost';
}
function make_url($path, $query = array())
{
global $NEXT_ID;
$query['next'] = $NEXT_ID;
return current_scheme() . '://' . current_host() . $path . '?' . http_build_query($query);
}
function html_response($html, $status = 200)
{
http_response_code($status);
header('Content-Type: text/html; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
echo $html;
exit;
}
function fail_html($message, $status = 500)
{
html_response(
RacketSandboxTemplate::renderFile('protocol-error.html', array(
'title' => 'Error',
'message' => $message,
)),
$status
);
}
function get_pkgs_all_text()
{
try {
return catalog_http_fetch_cached(
CATALOG_PKGS_ALL,
CACHE_FILE,
CACHE_META_FILE,
CACHE_TTL,
'rktsndbx-rktpkgs/1.0',
180
);
} catch (Throwable $e) {
fail_html($e->getMessage());
}
}
function serve_index()
{
global $NEXT_ID;
$text = get_pkgs_all_text();
$names = rktd_extract_top_level_package_names($text);
if (count($names) === 0) {
fail_html('Geen package-namen gevonden in pkgs-all.');
}
$rows = '';
foreach ($names as $i => $name) {
$url = make_url('/package', array('name' => $name));
$rows .= RacketSandboxTemplate::renderFile('partials/package-index-row.html', array(
'id' => $name,
'index' => (string)($i + 1),
'url' => $url,
'name' => $name,
)) . "\n";
}
html_response(RacketSandboxTemplate::renderFile('racket-pkg-index.html', array(
'package_count' => (string)count($names),
'next_id' => $NEXT_ID,
'package_rows_html' => $rows,
)));
}
$TOKENS->check_valid_next('html');
serve_index();