Files
speedBB/app/Http/Controllers/AssetController.php
T
tracer cbe2479e0d
CI/CD Pipeline / deploy (push) Successful in 30s
CI/CD Pipeline / promote_stable (push) Successful in 2s
Fix asset export to create ZIP file with manifest
2026-05-17 16:51:55 +02:00

128 lines
3.8 KiB
PHP

<?php
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use ZipArchive;
class AssetController extends Controller
{
public function export()
{
$user = auth()->user();
if (!$user || !$user->roles()->where('name', 'ROLE_ADMIN')->exists()) {
abort(403, 'Forbidden');
}
try {
$storagePublic = storage_path('app/public');
if (!is_dir($storagePublic)) {
mkdir($storagePublic, 0775, true);
}
// Create ZIP in memory
$zip = new ZipArchive();
$tempFile = tempnam(sys_get_temp_dir(), 'speedbb_');
if ($zip->open($tempFile, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
return response()->json(['message' => 'Failed to create ZIP'], 500);
}
// Add a manifest file to ensure ZIP is created even if empty
$zip->addFromString('MANIFEST.txt', "SpeedBB Assets Export\nExported: " . date('Y-m-d H:i:s') . "\n");
$this->addDirectoryToZip($zip, $storagePublic, '');
$zip->close();
if (!file_exists($tempFile)) {
return response()->json(['message' => 'ZIP file was not created'], 500);
}
$filename = 'assets-'.date('YmdHis').'.zip';
return response()->file($tempFile, [
'Content-Type' => 'application/zip',
'Content-Disposition' => 'attachment; filename="'.$filename.'"',
])->deleteFileAfterSend(true);
} catch (\Exception $e) {
return response()->json(['message' => 'Export error: '.$e->getMessage()], 500);
}
}
public function import(Request $request): JsonResponse
{
$user = $request->user();
if (!$user || !$user->roles()->where('name', 'ROLE_ADMIN')->exists()) {
return response()->json(['message' => 'Forbidden'], 403);
}
$data = $request->validate([
'file' => ['required', 'file', 'mimes:zip', 'max:104857600'],
]);
$file = $data['file'];
$zip = new ZipArchive();
$zipPath = $file->getPathname();
if ($zip->open($zipPath) !== true) {
return response()->json(['message' => 'Invalid zip file'], 400);
}
$storagePublic = storage_path('app/public');
for ($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
$fileinfo = $zip->statIndex($i);
if ($fileinfo['crc'] == 0) {
continue;
}
$targetPath = $storagePublic.DIRECTORY_SEPARATOR.$filename;
$targetDir = dirname($targetPath);
if (!is_dir($targetDir)) {
mkdir($targetDir, 0775, true);
}
copy('zip://'.$zipPath.'#'.$filename, $targetPath);
}
$zip->close();
return response()->json([
'message' => 'Assets imported successfully',
]);
}
private function addDirectoryToZip(ZipArchive $zip, string $dir, string $zipPath): void
{
if (!is_dir($dir)) {
return;
}
$files = @scandir($dir);
if ($files === false) {
return;
}
foreach ($files as $file) {
if ($file === '.' || $file === '..') {
continue;
}
$path = $dir.DIRECTORY_SEPARATOR.$file;
$newZipPath = $zipPath === '' ? $file : $zipPath.'/'.$file;
if (is_dir($path)) {
$zip->addEmptyDir($newZipPath);
$this->addDirectoryToZip($zip, $path, $newZipPath);
} elseif (is_file($path)) {
$zip->addFile($path, $newZipPath);
}
}
}
}