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( '' . 'Error' . '

Error

' . 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 .= '' . '' . h((string)($i + 1)) . '' . '' . h($part['number']) . '' . '' . h((string)$part['size']) . '' . '' . h($part['url']) . '' . '' . "\n"; } $zipSize = (int)($manifest['source_bytes'] ?? 0); $pkg_url = make_url('/racket-pkg-index'); html_response(' Racket bootstrap

Racket bootstrap

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.

' . $rows . '
# partnummer bytes base64 text/plain URL

Reconstructie in de sandbox

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);