1. When requesting the S3 bucket, I encountered a rate limiting issue: Please reduce your request rate, which caused the request to fail. See Figure 1.

2. The final implementation code is as follows:
$name = $themeId . '/assets.zip';
$zip = new ZipStream($name);
$zip->addFile('apps/internal/back-top/assets/app.9ce8af2.js', '0000000000000');
$res = Storage::disk(config('theme_asset.filesystem.disk'))->put(
$name,
$zip->finish(),
config('theme_asset.filesystem.options')
);
3. Open the corresponding S3 CDN address in the browser: https://xxx.cloudfastin.com/static/xxx/98cb73f9-e61a-40b1-a27a-3beb99015e5e/assets.zip . The file can be downloaded, confirming that the file was uploaded to S3 successfully. See Figure 2.

3. Decompressing the downloaded file failed, with the prompt: This file is not a compressed file and cannot be opened. See Figure 3.

4. I used the putStream method and set the output stream in the ZipStream object options. After downloading, decompression succeeded. See Figure 4.

$name = $themeId . '/assets.zip';
$tmp = tempnam(sys_get_temp_dir(), 'zip_stream');
$stream = fopen($tmp, 'w+');
$options = new Archive();
//$options->setContentType('application/x-zip-compressed');
$options->setOutputStream($stream);
$zip = new ZipStream($name, $options);
$zip = new ZipStream($name);
$zip->addFile('apps/internal/back-top/assets/app.9ce8af2.js', '0000000000000');
$zip->finish();
$res = Storage::disk(config('theme_asset.filesystem.disk'))->putStream(
$name,
$stream,
config('theme_asset.filesystem.options')
);
fclose($stream);
5. However, if the path contains a backslash, for example, a file with the path css\app.6156ec.css will have its path changed to css_app.6156ec.css. See Figure 5.

6. I needed to replace the path of the file css\app.6156ec.css with css/app.6156ec.css. After uploading to S3 and downloading, decompression showed a normal directory structure. See Figure 6.

$zip->addFile(str_replace('\\', '/', 'css\\app.6156ec.css'), $file->getContents());
