create(); function path_only() { $p = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH); $p = '/' . trim($p ?: '/', '/'); return $p === '/' ? '/' : $p; } function 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 host_name() { return $_SERVER['HTTP_HOST'] ?? 'localhost'; } function make_url($path, $query = array()) { global $NEXT_ID; $query['next'] = $NEXT_ID; return scheme() . '://' . host_name() . $path . '?' . http_build_query($query); } function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } 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 text_response($text, $status = 200) { http_response_code($status); header('Content-Type: text/plain; charset=us-ascii'); header('Content-Disposition: inline'); header('X-Content-Type-Options: nosniff'); header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'); header('Pragma: no-cache'); echo $text; if ($text === '' || substr($text, -1) !== "\n") { echo "\n"; } exit; } function fail_html($message, $status = 500) { html_response( '' . '
' . h($message) . '', $status ); } function fail_text($message, $status = 500) { text_response("error: " . $message . "\n", $status); } function load_parts() { try { $manifest = load_racket_zip_parts_manifest(); } catch (Throwable $e) { fail_html($e->getMessage() . "\n\nSla de configuratiepagina op om racket.zip in parts te verdelen."); } if (!racket_zip_parts_current($manifest, RACKET_ZIP_MAX_BASE64_KB)) { fail_html( "racket.zip parts ontbreken of passen niet bij de huidige chunk-grootte.\n\n" . "Sla de configuratiepagina op om de parts opnieuw te maken." ); } $parts = array(); foreach (($manifest['parts'] ?? array()) as $part) { $number = (string)($part['number'] ?? ''); $parts[] = array( 'number' => $number, 'name' => (string)($part['name'] ?? racket_zip_part_name((int)$number)), 'size' => (int)($part['size'] ?? 0), 'url' => make_url('/bootstrap-racket-part', array('n' => $number)), ); } $manifest['parts'] = $parts; return $manifest; } function serve_bootstrap() { global $NEXT_ID; $manifest = load_parts(); $parts = $manifest['parts']; $rows = ''; foreach ($parts as $i => $part) { $rows .= '
racket.zip is vooraf via de configuratiepagina gesplitst naar
parts in de map data.
Package index: Racket package index
Bronbestand: config/racket.zip
Bronbestand bytes: ' . h((string)$zipSize) . '
Maximale base64 part-grootte: ' . h((string)RACKET_ZIP_MAX_BASE64_KB) . ' KiB (' . h((string)RACKET_ZIP_MAX_BASE64_BYTES) . ' bytes)
Binaire chunk-grootte: ' . h((string)RACKET_ZIP_BINARY_CHUNK_BYTES) . ' bytes
Aantal parts: ' . h((string)count($parts)) . '
Parts gemaakt op: ' . h((string)($manifest['created_at'] ?? '')) . '
next-id voor alle links op deze pagina: ' . h($NEXT_ID) . '
Elke link hieronder geeft text/plain met de base64-representatie van één binair part. De URL bevat alleen een nummer, geen bestandsnaam en geen extensie.
| # | partnummer | bytes | base64 text/plain URL |
|---|
Decodeer ieder base64-part afzonderlijk naar een binair part. Plak daarna de binaire parts in numerieke volgorde aan elkaar.
base64 -d part-000001.txt > part-000001 base64 -d part-000002.txt > part-000002 base64 -d part-000003.txt > part-000003 # enzovoort cat part-* > racket.zip unzip racket.zip -d /tmp/racket'); } function serve_part() { $n = $_GET['n'] ?? ''; if (!is_string($n) || !preg_match('/^[0-9]{6}$/', $n)) { fail_text('ongeldig partnummer; gebruik bijvoorbeeld n=000001', 400); } $file = racket_zip_part_file($n); if (!is_file($file) || !is_readable($file)) { fail_text('part ontbreekt of is niet leesbaar: ' . $n, 404); } $bin = file_get_contents($file); if ($bin === false) { fail_text('kan part niet lezen: ' . $n, 500); } text_response(base64_encode($bin)); } $path = path_only(); if ($path === '/' || $path === '/index.php') { header('Location: ' . make_url('/bootstrap-racket'), true, 302); exit; } if ($path === '/bootstrap-racket') { $TOKENS->check_valid_next('html'); serve_bootstrap(); } if ($path === '/bootstrap-racket-part') { $TOKENS->check_valid_next('text'); serve_part(); } fail_html('Onbekende route: ' . $path, 404);