[], 'last_upload' => 0]; if (filesize($path) > 1048576) throw new RuntimeException('Metadata exceeds its 1 MiB limit.'); $raw = @file_get_contents($path); if ($raw === false) throw new RuntimeException('Cannot read file metadata.'); try { $store = json_decode($raw, true, 32, JSON_THROW_ON_ERROR); } catch (JsonException $ex) { throw new RuntimeException('Malformed file metadata; no changes were made.'); } if (!is_array($store) || !isset($store['items'], $store['last_upload']) || !is_array($store['items']) || !is_int($store['last_upload']) || count($store['items']) > FILES_MAX_COUNT) { throw new RuntimeException('Invalid file metadata structure; no changes were made.'); } foreach ($store['items'] as $key => $item) { if (!preg_match('/^[a-f0-9]{32}$/D', (string)$key) || !is_array($item) || !isset($item['name'], $item['size'], $item['time']) || !is_string($item['name']) || files_name($item['name']) !== $item['name'] || !is_int($item['size']) || $item['size'] < 0 || $item['size'] > FILES_MAX_BYTES || !is_int($item['time'])) { throw new RuntimeException('Invalid file metadata entry; no changes were made.'); } } return $store; } function files_write(array $store): void { $json = json_encode($store, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n"; if (strlen($json) > 1048576) throw new RuntimeException('Metadata limit reached.'); $temp = @tempnam(__DIR__ . '/data', 'save-'); if ($temp === false) throw new RuntimeException('Cannot create temporary metadata file.'); try { if (file_put_contents($temp, $json) !== strlen($json) || !chmod($temp, 0640) || !rename($temp, __DIR__ . '/data/store.json')) { throw new RuntimeException('Cannot save file metadata. Check permissions and free space.'); } } finally { if (is_file($temp)) @unlink($temp); } }