Files
speedBB/app/Http/Controllers/UploadController.php
tracer 41387be802
All checks were successful
CI/CD Pipeline / deploy (push) Successful in 24s
CI/CD Pipeline / promote_stable (push) Successful in 2s
prepare public symlink
2026-02-26 19:08:37 +01:00

130 lines
4.1 KiB
PHP

<?php
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use RuntimeException;
class UploadController extends Controller
{
public function storeAvatar(Request $request): JsonResponse
{
$user = $request->user();
if (!$user) {
return response()->json(['message' => 'Unauthorized'], 401);
}
$this->ensurePublicStorageReady();
$data = $request->validate([
'file' => [
'required',
'image',
'mimes:jpg,jpeg,png,gif,webp',
'max:2048',
'dimensions:max_width=150,max_height=150',
],
]);
if ($user->avatar_path) {
Storage::disk('public')->delete($user->avatar_path);
}
$path = $data['file']->store('avatars', 'public');
$user->avatar_path = $path;
$user->save();
return response()->json([
'path' => $path,
'url' => Storage::url($path),
]);
}
public function storeLogo(Request $request): JsonResponse
{
$user = $request->user();
if (!$user || !$user->roles()->where('name', 'ROLE_ADMIN')->exists()) {
return response()->json(['message' => 'Forbidden'], 403);
}
$this->ensurePublicStorageReady();
$data = $request->validate([
'file' => ['required', 'file', 'mimes:jpg,jpeg,png,gif,webp,svg,ico', 'max:5120'],
]);
$path = $data['file']->store('logos', 'public');
return response()->json([
'path' => $path,
'url' => Storage::url($path),
]);
}
public function storeFavicon(Request $request): JsonResponse
{
$user = $request->user();
if (!$user || !$user->roles()->where('name', 'ROLE_ADMIN')->exists()) {
return response()->json(['message' => 'Forbidden'], 403);
}
$this->ensurePublicStorageReady();
$data = $request->validate([
'file' => ['required', 'file', 'mimes:png,ico', 'max:2048'],
]);
$path = $data['file']->store('favicons', 'public');
return response()->json([
'path' => $path,
'url' => Storage::url($path),
]);
}
private function ensurePublicStorageReady(): void
{
$storagePublic = storage_path('app/public');
$publicStorage = public_path('storage');
if (file_exists($storagePublic) && !is_dir($storagePublic)) {
@rename($storagePublic, $storagePublic.'.bak.'.date('Ymd_His'));
}
if (!is_dir($storagePublic) && !@mkdir($storagePublic, 0775, true) && !is_dir($storagePublic)) {
throw new RuntimeException('Failed to create storage/app/public directory.');
}
if (is_link($publicStorage)) {
$target = readlink($publicStorage);
$resolved = $target !== false ? realpath(dirname($publicStorage).DIRECTORY_SEPARATOR.$target) : false;
$expected = realpath($storagePublic);
if ($resolved === $expected) {
$this->ensureUploadSubdirs($storagePublic);
return;
}
@unlink($publicStorage);
} elseif (is_dir($publicStorage)) {
File::copyDirectory($publicStorage, $storagePublic);
File::deleteDirectory($publicStorage);
} elseif (file_exists($publicStorage)) {
@rename($publicStorage, $publicStorage.'.bak.'.date('Ymd_His'));
}
if (!@symlink($storagePublic, $publicStorage) && !is_link($publicStorage)) {
throw new RuntimeException('Failed to create public/storage symlink.');
}
$this->ensureUploadSubdirs($storagePublic);
}
private function ensureUploadSubdirs(string $storagePublic): void
{
foreach (['avatars', 'favicons', 'logos', 'rank-badges'] as $dir) {
$path = $storagePublic.DIRECTORY_SEPARATOR.$dir;
if (!is_dir($path)) {
@mkdir($path, 0775, true);
}
}
}
}