chmod( $root, 0700 ) ) { throw new \RuntimeException( 'Cannot protect Snapshot storage.' ); } return $root; } private static function directory(): string { $path = self::root() . '/' . get_current_user_id(); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir -- Create private directories with mode 0700 immediately; WP_Filesystem_Direct::mkdir applies permissions only after creation. if ( is_link( $path ) || ( ! is_dir( $path ) && ! mkdir( $path, 0700 ) ) ) { throw new \RuntimeException( 'Cannot open private Snapshot storage.' ); } return $path; } private static function read( string $file ): array { if ( ! is_file( $file ) || is_link( $file ) ) { return []; } $json = file_get_contents( $file, false, null, 0, Environment::MAX_JSON + 1 ); if ( false === $json || strlen( $json ) > Environment::MAX_JSON ) { throw new \RuntimeException( 'Snapshot metadata is unreadable.' ); } $value = json_decode( $json, true, 64 ); if ( ! is_array( $value ) ) { throw new \RuntimeException( 'Snapshot metadata is invalid.' ); } return $value; } private static function write( string $file, array $value ): void { $json = wp_json_encode( $value ); if ( ! $json || strlen( $json ) > Environment::MAX_JSON ) { throw new \RuntimeException( 'Snapshot metadata exceeds its size limit.' ); } $tmp = $file . '.' . bin2hex( random_bytes( 8 ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.rename_rename -- Atomic same-directory replacement preserves the completed Snapshot on failure; WP_Filesystem::move deletes the destination first. if ( false === file_put_contents( $tmp, $json, LOCK_EX ) || ! Filesystem::local()->chmod( $tmp, 0600 ) || ! rename( $tmp, $file ) ) { Filesystem::local()->delete( $tmp, false, 'f' ); throw new \RuntimeException( 'Could not save Snapshot metadata.' ); } } private static function lock( string $directory ) { $file = $directory . '/lock'; if ( is_link( $file ) ) { throw new \RuntimeException( 'Invalid Snapshot lock.' ); } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- Native stream handles are required by flock for nonblocking worker locks. $lock = fopen( $file, 'c' ); if ( ! $lock ) { throw new \RuntimeException( 'Could not lock Snapshot storage.' ); } Filesystem::local()->chmod( $file, 0600 ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Native stream handles are required by flock for nonblocking worker locks. if ( ! flock( $lock, LOCK_EX | LOCK_NB ) ) { fclose( $lock ); throw new \RuntimeException( 'Snapshot is being updated. Please wait for it to finish.' ); } return $lock; } public static function settings(): array { self::authorize(); return self::read( self::directory() . '/settings.json' ) ?: [ 'privateContent' => false, 'users' => [], 'credentials' => [] ]; } public static function inventory(): array { self::authorize(); $directory = self::directory(); $latest = self::read( $directory . '/latest.json' ); $saved = $latest ? self::read( $directory . '/' . $latest['revision'] . '/manifest.json' ) : []; return $saved['inventory'] ?? Environment::inventory(); } public static function end( string $id ): void { self::authorize(); if ( ! preg_match( '/^[a-f0-9]{48}$/D', $id ) ) { return; } $transfer = get_transient( 'smooth_sandbox_transfer_snapshot_' . $id ); if ( is_array( $transfer ) && $transfer['owner'] === get_current_user_id() ) { delete_transient( 'smooth_sandbox_transfer_snapshot_' . $id ); } } private static function normalize( array $input ): array { if ( ! is_bool( $input['privateContent'] ?? false ) || ! is_array( $input['users'] ?? [] ) || ! is_array( $input['credentials'] ?? [] ) || count( $input['users'] ?? [] ) > 100 || count( $input['credentials'] ?? [] ) > 500 ) { throw new \RuntimeException( 'Invalid Snapshot settings.' ); } $users = []; $seen = []; foreach ( $input['users'] ?? [] as $row ) { $id = $row['id'] ?? 0; $password = $row['password'] ?? ''; if ( ! is_int( $id ) || $id < 1 || isset( $seen[ $id ] ) || ! current_user_can( 'edit_user', $id ) || ! ( $user = get_userdata( $id ) ) || ! is_string( $password ) || strlen( $password ) < 16 || strlen( $password ) > 128 || wp_check_password( $password, $user->user_pass, $id ) ) { throw new \RuntimeException( 'Choose valid users with unique, new sandbox passwords of 16–128 characters.' ); } $seen[ $id ] = true; $users[] = [ 'id' => $id, 'password' => $password ]; } foreach ( $input['credentials'] ?? [] as $id ) { if ( ! is_string( $id ) || ! preg_match( '/^[a-f0-9]{64}$/D', $id ) ) { throw new \RuntimeException( 'Invalid credential selection.' ); } } return [ 'privateContent' => $input['privateContent'] ?? false, 'users' => $users, 'credentials' => array_values( array_unique( $input['credentials'] ?? [] ) ) ]; } public static function save( array $input ): array { self::authorize(); $directory = self::directory(); $lock = self::lock( $directory ); try { $settings = self::normalize( $input ); // Validate value-bound credential choices before persisting them. $selection = $settings; $selection['users'] = array_column( $settings['users'], 'id' ); $selection['plugins'] = Environment::inventory()['plugins']; $items = Environment::credential_inventory( $selection ); if ( array_diff( $settings['credentials'], array_column( $items, 'id' ) ) ) { throw new \RuntimeException( 'Some credentials changed. Refresh keys and select them again.' ); } self::write( $directory . '/settings.json', $settings ); $latest = self::read( $directory . '/latest.json' ); if ( ! $latest || ! hash_equals( $latest['settingsHash'], hash( 'sha256', wp_json_encode( $settings ) ) ) ) { try { self::queue_locked( $directory ); } catch ( \Throwable $error ) { throw new \RuntimeException( 'Settings saved, but Snapshot could not be queued. Try queueing it again.', 0, $error ); } } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Native stream handles are required by flock for nonblocking worker locks. } finally { flock( $lock, LOCK_UN ); fclose( $lock ); } return self::status(); } public static function status(): array { self::authorize(); $directory = self::directory(); $state = self::read( $directory . '/state.json' ); $latest = self::read( $directory . '/latest.json' ); if ( ( $state['status'] ?? '' ) === 'queued' && ( $state['queuedAt'] ?? 0 ) < time() - 60 && ! wp_next_scheduled( self::HOOK, [ get_current_user_id(), $state['job'] ] ) ) { try { $queue_lock = self::lock( $directory ); $state = self::read( $directory . '/state.json' ); if ( ( $state['status'] ?? '' ) === 'queued' ) { $state['status'] = 'failed'; $state['error'] = 'The queued job was removed or could not start. Queue an update to retry.'; self::write( $directory . '/state.json', $state ); } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Native stream handles are required by flock for nonblocking worker locks. flock( $queue_lock, LOCK_UN ); fclose( $queue_lock ); } catch ( \Throwable $ignored ) { /* The worker is starting. */ } } if ( ( $state['status'] ?? '' ) === 'running' ) { // A worker owns the OS lock. A released lock with 'running' means it died. // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- Native stream handles are required by flock for nonblocking worker locks. $probe = fopen( $directory . '/lock', 'c' ); if ( $probe && flock( $probe, LOCK_EX | LOCK_NB ) ) { $state = self::read( $directory . '/state.json' ); if ( ( $state['status'] ?? '' ) === 'running' ) { $state['status'] = 'failed'; $state['error'] = 'Snapshot generation was interrupted. Queue an update to retry.'; self::write( $directory . '/state.json', $state ); } flock( $probe, LOCK_UN ); } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Native stream handles are required by flock for nonblocking worker locks. if ( $probe ) { fclose( $probe ); } } $settings = self::settings(); $stale = $latest && ! hash_equals( $latest['settingsHash'], hash( 'sha256', wp_json_encode( $settings ) ) ); return [ 'status' => $state['status'] ?? 'idle', 'queuedAt' => $state['queuedAt'] ?? null, 'startedAt' => $state['startedAt'] ?? null, 'finishedAt' => $state['finishedAt'] ?? null, 'progress' => $state['progress'] ?? null, 'error' => $state['error'] ?? '', 'latest' => $latest['summary'] ?? null, 'settingsChanged' => (bool) $stale, 'cronDisabled' => defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ]; } public static function queue(): array { self::authorize(); $directory = self::directory(); $lock = self::lock( $directory ); try { self::queue_locked( $directory ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Native stream handles are required by flock for nonblocking worker locks. } finally { flock( $lock, LOCK_UN ); fclose( $lock ); } return self::status(); } /** Caller holds the owner's lock, including when settings are being saved. */ private static function queue_locked( string $directory ): void { $state = self::read( $directory . '/state.json' ); if ( ( $state['status'] ?? '' ) === 'queued' ) { return; } $job = bin2hex( random_bytes( 16 ) ); $event = wp_schedule_single_event( time() + 1, self::HOOK, [ get_current_user_id(), $job ], true ); if ( is_wp_error( $event ) || ! $event ) { throw new \RuntimeException( 'WordPress could not queue Snapshot generation.' ); } self::write( $directory . '/state.json', [ 'status' => 'queued', 'job' => $job, 'queuedAt' => time() ] ); } public static function remove(): array { self::authorize(); $directory = self::directory(); $lock = self::lock( $directory ); try { $state = self::read( $directory . '/state.json' ); if ( in_array( $state['status'] ?? '', [ 'queued', 'running' ], true ) ) { throw new \RuntimeException( 'Wait for Snapshot generation to finish before deleting it.' ); } // Revisions contain only flat blobs and a manifest. Never follow links // or remove the owner's saved settings or shared lock file. foreach ( new \DirectoryIterator( $directory ) as $entry ) { if ( ! preg_match( '/^[a-f0-9]{32}$/D', $entry->getFilename() ) ) { continue; } $path = $entry->getPathname(); if ( $entry->isDir() && ! $entry->isLink() ) { foreach ( new \DirectoryIterator( $path ) as $file ) { if ( $file->isDot() ) { continue; } if ( ! Filesystem::local()->delete( $file->getPathname(), false, 'f' ) ) { throw new \RuntimeException( 'Could not delete all Snapshot files. Check storage permissions and retry.' ); } } if ( ! Filesystem::local()->rmdir( $path ) ) { throw new \RuntimeException( 'Could not delete the Snapshot revision. Check storage permissions and retry.' ); } } elseif ( ! Filesystem::local()->delete( $path, false, 'f' ) ) { throw new \RuntimeException( 'Could not delete the Snapshot file. Check storage permissions and retry.' ); } } foreach ( [ 'state.json', 'latest.json' ] as $name ) { $file = $directory . '/' . $name; if ( ( file_exists( $file ) || is_link( $file ) ) && ! Filesystem::local()->delete( $file, false, 'f' ) ) { throw new \RuntimeException( 'Could not delete Snapshot metadata. Check storage permissions and retry.' ); } } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Native stream handles are required by flock for nonblocking worker locks. } finally { flock( $lock, LOCK_UN ); fclose( $lock ); } return self::status(); } public static function run( int $owner, string $job ): void { $previous_user = get_current_user_id(); wp_set_current_user( $owner ); $lock = null; $export = null; $directory = ''; $state = []; $stage = ''; $published = false; try { self::authorize(); $directory = self::directory(); $lock = self::lock( $directory ); $state = self::read( $directory . '/state.json' ); if ( ( $state['status'] ?? '' ) !== 'queued' || ( $state['job'] ?? '' ) !== $job ) { return; } $state['status'] = 'running'; $state['startedAt'] = time(); self::write( $directory . '/state.json', $state ); $last_progress = 0; $progress = static function ( string $phase, int $done, int $total, string $unit ) use ( &$state, $directory, &$last_progress ): void { $now = microtime( true ); if ( ( $state['progress']['phase'] ?? '' ) === $phase && $done !== $total && $now - $last_progress < 0.5 ) { return; } $state['progress'] = [ 'phase' => $phase, 'processed' => $done, 'total' => $total, 'unit' => $unit, 'updatedAt' => time() ]; self::write( $directory . '/state.json', $state ); $last_progress = $now; }; $progress( 'preparing', 0, 0, '' ); $settings = self::normalize( self::settings() ); $inventory = Environment::inventory(); $versions = Runtime_Versions::get(); $selection = $settings + [ 'wp' => in_array( $inventory['wp'], $versions['wordpress'], true ) ? $inventory['wp'] : Runtime_Versions::newest( $versions['wordpress'] ), 'php' => $versions['php'][0], 'theme' => $inventory['theme'], 'plugins' => $inventory['plugins'], 'sandboxPassword' => wp_generate_password( 32, false ) ]; $export = Environment::build( $selection, true, true, $progress ); $packages = Packages::prefer_repository( $export, $progress ); SQLite_Snapshot::build( $export, $progress ); $latest = self::read( $directory . '/latest.json' ); $old = $latest ? self::read( $directory . '/' . $latest['revision'] . '/manifest.json' ) : []; $old_files = array_column( $old['manifest']['files'] ?? [], null, 'path' ); $revision = bin2hex( random_bytes( 16 ) ); $stage = $directory . '/' . $revision; // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir -- Create private directories with mode 0700 immediately; WP_Filesystem_Direct::mkdir applies permissions only after creation. if ( ! mkdir( $stage, 0700 ) ) { throw new \RuntimeException( 'Could not create a Snapshot revision.' ); } $stats = [ 'reused' => 0, 'changed' => 0, 'added' => 0, 'deleted' => 0, 'databaseFiles' => 0 ]; $compressed = 0; $blobs = []; foreach ( $export['manifest']['files'] as $index => $file ) { $progress( 'compressing', $index, count( $export['manifest']['files'] ), 'files' ); $path = $file['path']; $database = str_starts_with( $path, 'database/' ); $destination = $stage . '/' . $index . '.gz'; $old_index = $old['blobs'][ $path ] ?? null; $reuse = ! $database && ( $old['compressionLevel'] ?? 6 ) === self::COMPRESSION && isset( $old_files[ $path ] ) && $old_files[ $path ] === $file && null !== $old_index; $source = $reuse ? $directory . '/' . $latest['revision'] . '/' . $old_index . '.gz' : ''; if ( $reuse && is_file( $source ) && ! is_link( $source ) && ( @link( $source, $destination ) || copy( $source, $destination ) ) ) { $stats['reused']++; } else { $bytes = file_get_contents( $export['paths'][ $path ], false, null, 0, 20971521 ); if ( false === $bytes || strlen( $bytes ) !== $file['bytes'] || ! hash_equals( $file['sha256'], hash( 'sha256', $bytes ) ) ) { throw new \RuntimeException( 'A source file changed while preparing Snapshot. Queue an update to retry.' ); } $gzip = gzencode( $bytes, self::COMPRESSION ); if ( false === $gzip || false === file_put_contents( $destination, $gzip ) ) { throw new \RuntimeException( 'Could not write a Snapshot file. Check free disk space.' ); } if ( $database ) { $stats['databaseFiles']++; } else { $stats[ isset( $old_files[ $path ] ) ? 'changed' : 'added' ]++; } unset( $bytes, $gzip ); } Filesystem::local()->chmod( $destination, 0600 ); $compressed += filesize( $destination ); $blobs[ $path ] = $index; } foreach ( $old_files as $path => $file ) { if ( ! str_starts_with( $path, 'database/' ) && ! isset( $blobs[ $path ] ) ) { $stats['deleted']++; } } $summary = [ 'revision' => $revision, 'createdAt' => time(), 'bytes' => array_sum( array_column( $export['manifest']['files'], 'bytes' ) ), 'compressedBytes' => $compressed, 'files' => count( $blobs ), 'databaseMode' => $export['manifest']['database']['format'] === 2 ? 'sqlite' : 'json', 'databaseRows' => array_sum( array_column( $export['manifest']['database']['tables'], 'rows' ) ), 'packages' => $packages, 'changes' => $stats ]; $summary['compression'] = 'gzip-' . self::COMPRESSION; $progress( 'publishing', 0, 0, '' ); self::write( $stage . '/manifest.json', [ 'format' => self::FORMAT, 'compressionLevel' => self::COMPRESSION, 'manifest' => $export['manifest'], 'mediaReport' => $export['mediaReport'], 'inventory' => $inventory, 'blobs' => $blobs ] ); // Retention starts when a revision is superseded, not when it was built. // A transfer authorized just before this update still has 30 minutes. if ( $latest && is_dir( $directory . '/' . $latest['revision'] ) && ! Filesystem::local()->touch( $directory . '/' . $latest['revision'] ) ) { throw new \RuntimeException( 'Could not retain the previous Snapshot for active transfers.' ); } self::write( $directory . '/latest.json', [ 'revision' => $revision, 'settingsHash' => hash( 'sha256', wp_json_encode( $settings ) ), 'summary' => $summary ] ); $published = true; $state['status'] = 'ready'; $state['finishedAt'] = time(); unset( $state['error'] ); self::write( $directory . '/state.json', $state ); self::prune( $directory, $revision ); } catch ( \Throwable $error ) { if ( $lock && $directory && ( $state['job'] ?? '' ) === $job ) { $state['status'] = 'failed'; $state['error'] = $error->getMessage(); self::write( $directory . '/state.json', $state ); } } finally { if ( $stage && ! $published && is_dir( $stage ) ) { foreach ( glob( $stage . '/*' ) ?: [] as $file ) { if ( is_file( $file ) && ! is_link( $file ) ) { Filesystem::local()->delete( $file, false, 'f' ); } } Filesystem::local()->rmdir( $stage ); } if ( $export ) { Database::remove_files( $export['databaseDirectory'] ); } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Native stream handles are required by flock for nonblocking worker locks. if ( $lock ) { flock( $lock, LOCK_UN ); fclose( $lock ); } wp_set_current_user( $previous_user ); } } private static function prune( string $directory, string $keep ): void { foreach ( glob( $directory . '/*', GLOB_ONLYDIR ) ?: [] as $path ) { if ( basename( $path ) === $keep || ! preg_match( '/^[a-f0-9]{32}$/D', basename( $path ) ) || is_link( $path ) || filemtime( $path ) > time() - HOUR_IN_SECONDS ) { continue; } foreach ( glob( $path . '/*' ) ?: [] as $file ) { if ( is_file( $file ) && ! is_link( $file ) ) { Filesystem::local()->delete( $file, false, 'f' ); } } Filesystem::local()->rmdir( $path ); } } public static function prepare( array $selection ): array { self::authorize(); $directory = self::directory(); $status = self::status(); if ( ! $status['latest'] || $status['settingsChanged'] ) { throw new \RuntimeException( 'Create an up-to-date Snapshot in Settings before launching Sandbox.' ); } $revision = $status['latest']['revision']; $saved = self::read( $directory . '/' . $revision . '/manifest.json' ); if ( ! $saved || $saved['format'] !== self::FORMAT ) { throw new \RuntimeException( 'Snapshot is unavailable. Queue an update in Settings.' ); } $manifest = $saved['manifest']; $versions = Runtime_Versions::get(); // Associative JSON decoding turns an empty object into an empty array. $manifest['database']['excluded'] = (object) $manifest['database']['excluded']; // Version 1.0.1 stored an extra counter rejected by the receiver's // strict protocol. Adapt existing revisions at launch without rebuilding. if ( isset( $manifest['omitted']['runtime_files'] ) ) { $manifest['omitted']['package_files'] += $manifest['omitted']['runtime_files']; unset( $manifest['omitted']['runtime_files'] ); } foreach ( [ 'wp' => 'wordpress', 'php' => 'php' ] as $key => $catalogue ) { if ( ! is_string( $selection[ $key ] ?? null ) || ! in_array( $selection[ $key ], $versions[ $catalogue ], true ) ) { throw new \RuntimeException( 'Choose supported WordPress and PHP versions.' ); } $manifest[ $key ] = $selection[ $key ]; } $plugins = array_column( $manifest['plugins'], null, 'file' ); $requirements = array_column( $saved['inventory']['plugins'], 'requiresPHP', 'file' ); if ( ! is_array( $selection['plugins'] ?? null ) || count( $selection['plugins'] ) > 200 ) { throw new \RuntimeException( 'Invalid plugin selection.' ); } $chosen = []; $prefixes = []; foreach ( $selection['plugins'] as $choice ) { $file = $choice['file'] ?? ''; if ( ! is_string( $file ) || ! isset( $plugins[ $file ] ) ) { throw new \RuntimeException( 'A selected plugin is absent from Snapshot. Update Snapshot in Settings.' ); } if ( $requirements[ $file ] && version_compare( $manifest['php'], $requirements[ $file ], '<' ) ) { throw new \RuntimeException( 'A selected plugin requires a newer PHP version.' ); } $chosen[ $file ] = $plugins[ $file ]; $prefixes[] = 'plugins/' . ( '.' === dirname( $file ) ? $file : dirname( $file ) . '/' ); } $theme = $selection['theme'] ?? ''; $themes = array_column( $saved['inventory']['themes'], null, 'slug' ); if ( ! is_string( $theme ) || ! isset( $themes[ $theme ] ) ) { throw new \RuntimeException( 'The selected theme is absent from Snapshot. Update Snapshot in Settings.' ); } $slugs = array_unique( [ $theme, $themes[ $theme ]['template'] ] ); foreach ( $slugs as $slug ) { if ( ! isset( $themes[ $slug ] ) ) { throw new \RuntimeException( 'Snapshot is missing the parent theme.' ); } $prefixes[] = 'themes/' . $slug . '/'; } $manifest['plugins'] = array_values( $chosen ); $manifest['theme'] = $theme; $manifest['themes'] = array_values( array_filter( $manifest['themes'], static fn( $item ) => in_array( $item['slug'], $slugs, true ) ) ); $manifest['files'] = array_values( array_filter( $manifest['files'], static function ( $file ) use ( $prefixes ) { if ( ! preg_match( '#^(plugins|themes)/#', $file['path'] ) ) { return true; } foreach ( $prefixes as $prefix ) { if ( str_ends_with( $prefix, '/' ) ? str_starts_with( $file['path'], $prefix ) : $file['path'] === $prefix ) { return true; } } return false; } ) ); foreach ( $manifest['users'] as $user ) { if ( ! current_user_can( 'edit_user', $user['id'] ) ) { throw new \RuntimeException( 'Access to a Snapshot user has changed. Update Snapshot.' ); } } $id = bin2hex( random_bytes( 24 ) ); if ( ! set_transient( 'smooth_sandbox_transfer_snapshot_' . $id, [ 'owner' => get_current_user_id(), 'revision' => $revision, 'paths' => array_column( $manifest['files'], 'path' ) ], 30 * MINUTE_IN_SECONDS ) ) { throw new \RuntimeException( 'Could not authorize Snapshot transfer.' ); } return [ 'manifest' => $manifest, 'mediaReport' => $saved['mediaReport'], 'id' => $id, 'snapshot' => $status['latest'] ]; } public static function stream( string $id ): void { self::authorize(); if ( ! preg_match( '/^[a-f0-9]{48}$/D', $id ) ) { throw new \RuntimeException( 'Invalid Snapshot transfer.' ); } $transfer = get_transient( 'smooth_sandbox_transfer_snapshot_' . $id ); if ( ! is_array( $transfer ) || $transfer['owner'] !== get_current_user_id() ) { throw new \RuntimeException( 'Snapshot transfer expired or access was denied.' ); } $directory = self::directory() . '/' . $transfer['revision']; $saved = self::read( $directory . '/manifest.json' ); $files = []; foreach ( $transfer['paths'] as $path ) { if ( ! isset( $saved['blobs'][ $path ] ) ) { throw new \RuntimeException( 'Snapshot is incomplete. Queue an update.' ); } $file = $directory . '/' . $saved['blobs'][ $path ] . '.gz'; if ( is_link( $file ) || ! is_readable( $file ) ) { throw new \RuntimeException( 'Snapshot files are unavailable. Queue an update.' ); } $files[] = $file; } nocache_headers(); header( 'Content-Type: application/octet-stream' ); header( 'X-Content-Type-Options: nosniff' ); header( 'X-Accel-Buffering: no' ); while ( ob_get_level() ) { ob_end_clean(); } echo "SSNP1\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Authenticated application/octet-stream framing requires unchanged binary bytes, not HTML escaping. Stream authorized private gzip files directly to the binary response without buffering the entire transfer. foreach ( $files as $file ) { echo pack( 'N', filesize( $file ) ); readfile( $file ); if ( connection_aborted() ) { break; } } delete_transient( 'smooth_sandbox_transfer_snapshot_' . $id ); exit; } }