&next= * * 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();