initial import
This commit is contained in:
+196
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
/*
|
||||
* Shared handling for the Racket installation zip and its binary parts.
|
||||
*/
|
||||
|
||||
define('RACKET_ZIP_FILE', __DIR__ . '/config/racket.zip');
|
||||
define('RACKET_ZIP_DATA_DIR', __DIR__ . '/data');
|
||||
define('RACKET_ZIP_PART_PREFIX', 'racket-part-');
|
||||
define('RACKET_ZIP_MANIFEST_FILE', RACKET_ZIP_DATA_DIR . '/racket-parts.json');
|
||||
|
||||
function racket_zip_binary_chunk_bytes_for_base64_kib($kib)
|
||||
{
|
||||
return intdiv(((int)$kib) * 1024, 4) * 3;
|
||||
}
|
||||
|
||||
function racket_zip_part_name($nr)
|
||||
{
|
||||
return RACKET_ZIP_PART_PREFIX . sprintf('%06d', $nr);
|
||||
}
|
||||
|
||||
function racket_zip_part_file($partNumber)
|
||||
{
|
||||
return RACKET_ZIP_DATA_DIR . '/' . RACKET_ZIP_PART_PREFIX . $partNumber;
|
||||
}
|
||||
|
||||
function racket_zip_ensure_data_dir()
|
||||
{
|
||||
if (!is_dir(RACKET_ZIP_DATA_DIR)) {
|
||||
if (!mkdir(RACKET_ZIP_DATA_DIR, 0755, true)) {
|
||||
throw new RuntimeException('Kan data directory niet maken: ' . RACKET_ZIP_DATA_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_writable(RACKET_ZIP_DATA_DIR)) {
|
||||
throw new RuntimeException('Data directory is niet schrijfbaar: ' . RACKET_ZIP_DATA_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
function racket_zip_remove_old_parts()
|
||||
{
|
||||
foreach (glob(RACKET_ZIP_DATA_DIR . '/' . RACKET_ZIP_PART_PREFIX . '*') ?: array() as $file) {
|
||||
if (is_file($file)) {
|
||||
@unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_file(RACKET_ZIP_MANIFEST_FILE)) {
|
||||
@unlink(RACKET_ZIP_MANIFEST_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
function split_racket_zip_parts($maxBase64Kib)
|
||||
{
|
||||
$maxBase64Bytes = (int)$maxBase64Kib * 1024;
|
||||
$binaryChunkBytes = racket_zip_binary_chunk_bytes_for_base64_kib($maxBase64Kib);
|
||||
|
||||
if ($binaryChunkBytes < 3) {
|
||||
throw new RuntimeException('Ongeldige racket.zip base64 chunk-instelling.');
|
||||
}
|
||||
|
||||
if (!is_file(RACKET_ZIP_FILE) || !is_readable(RACKET_ZIP_FILE)) {
|
||||
throw new RuntimeException('racket.zip ontbreekt of is niet leesbaar: ' . RACKET_ZIP_FILE);
|
||||
}
|
||||
|
||||
racket_zip_ensure_data_dir();
|
||||
racket_zip_remove_old_parts();
|
||||
|
||||
$in = fopen(RACKET_ZIP_FILE, 'rb');
|
||||
|
||||
if ($in === false) {
|
||||
throw new RuntimeException('Kan racket.zip niet openen.');
|
||||
}
|
||||
|
||||
$parts = array();
|
||||
$nr = 1;
|
||||
$totalBinaryBytes = 0;
|
||||
|
||||
while (!feof($in)) {
|
||||
$buf = fread($in, $binaryChunkBytes);
|
||||
|
||||
if ($buf === false) {
|
||||
fclose($in);
|
||||
throw new RuntimeException('Fout bij lezen van racket.zip.');
|
||||
}
|
||||
|
||||
if ($buf === '') {
|
||||
break;
|
||||
}
|
||||
|
||||
$name = racket_zip_part_name($nr);
|
||||
$file = RACKET_ZIP_DATA_DIR . '/' . $name;
|
||||
|
||||
if (file_put_contents($file, $buf, LOCK_EX) === false) {
|
||||
fclose($in);
|
||||
throw new RuntimeException('Kan part niet schrijven: ' . $file);
|
||||
}
|
||||
|
||||
$n = sprintf('%06d', $nr);
|
||||
$binaryBytes = strlen($buf);
|
||||
|
||||
$parts[] = array(
|
||||
'number' => $n,
|
||||
'name' => $name,
|
||||
'file' => $file,
|
||||
'size' => $binaryBytes,
|
||||
);
|
||||
|
||||
$totalBinaryBytes += $binaryBytes;
|
||||
$nr++;
|
||||
}
|
||||
|
||||
fclose($in);
|
||||
|
||||
if (count($parts) === 0) {
|
||||
throw new RuntimeException('racket.zip lijkt leeg te zijn.');
|
||||
}
|
||||
|
||||
$manifest = array(
|
||||
'source_file' => RACKET_ZIP_FILE,
|
||||
'source_bytes' => filesize(RACKET_ZIP_FILE),
|
||||
'source_mtime' => filemtime(RACKET_ZIP_FILE),
|
||||
'source_sha256' => hash_file('sha256', RACKET_ZIP_FILE),
|
||||
'max_base64_kib' => (int)$maxBase64Kib,
|
||||
'max_base64_bytes' => $maxBase64Bytes,
|
||||
'binary_chunk_bytes' => $binaryChunkBytes,
|
||||
'part_count' => count($parts),
|
||||
'total_binary_bytes' => $totalBinaryBytes,
|
||||
'parts' => $parts,
|
||||
'created_at' => gmdate('c'),
|
||||
);
|
||||
|
||||
if (file_put_contents(
|
||||
RACKET_ZIP_MANIFEST_FILE,
|
||||
json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n",
|
||||
LOCK_EX
|
||||
) === false) {
|
||||
throw new RuntimeException('Kan racket.zip manifest niet schrijven: ' . RACKET_ZIP_MANIFEST_FILE);
|
||||
}
|
||||
|
||||
return $manifest;
|
||||
}
|
||||
|
||||
function load_racket_zip_parts_manifest()
|
||||
{
|
||||
if (!is_file(RACKET_ZIP_MANIFEST_FILE) || !is_readable(RACKET_ZIP_MANIFEST_FILE)) {
|
||||
throw new RuntimeException('racket.zip parts-manifest ontbreekt: ' . RACKET_ZIP_MANIFEST_FILE);
|
||||
}
|
||||
|
||||
$raw = file_get_contents(RACKET_ZIP_MANIFEST_FILE);
|
||||
|
||||
if ($raw === false) {
|
||||
throw new RuntimeException('Kan racket.zip parts-manifest niet lezen: ' . RACKET_ZIP_MANIFEST_FILE);
|
||||
}
|
||||
|
||||
$manifest = json_decode($raw, true);
|
||||
|
||||
if (!is_array($manifest)) {
|
||||
throw new RuntimeException('racket.zip parts-manifest is geen geldige JSON: ' . RACKET_ZIP_MANIFEST_FILE);
|
||||
}
|
||||
|
||||
return $manifest;
|
||||
}
|
||||
|
||||
function racket_zip_parts_current($manifest, $maxBase64Kib)
|
||||
{
|
||||
if (!is_array($manifest)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((int)($manifest['max_base64_kib'] ?? 0) !== (int)$maxBase64Kib) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_file(RACKET_ZIP_FILE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((int)($manifest['source_bytes'] ?? -1) !== (int)filesize(RACKET_ZIP_FILE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((int)($manifest['source_mtime'] ?? -1) !== (int)filemtime(RACKET_ZIP_FILE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (($manifest['parts'] ?? array()) as $part) {
|
||||
$number = (string)($part['number'] ?? '');
|
||||
$file = racket_zip_part_file($number);
|
||||
|
||||
if (!preg_match('/^[0-9]{6}$/', $number) || !is_file($file) || !is_readable($file)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return count($manifest['parts'] ?? array()) > 0;
|
||||
}
|
||||
Reference in New Issue
Block a user