diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index c3c8d1066..84651f653 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -10,6 +10,7 @@ use BookStack\Entities\Queries\TopFavourites; use BookStack\Entities\Repos\BookRepo; use BookStack\Entities\Repos\BookshelfRepo; use BookStack\Entities\Tools\PageContent; +use BookStack\Uploads\FaviconHandler; use BookStack\Util\SimpleListOptions; use Illuminate\Http\Request; @@ -127,4 +128,15 @@ class HomeController extends Controller { return response()->view('errors.404', [], 404); } + + /** + * Serve the application favicon. + * Ensures a 'favicon.ico' file exists at the web root location (if writable) to be served + * directly by the webserver in the future. + */ + public function favicon(FaviconHandler $favicons) + { + $favicons->restoreOriginalIfNotExists(); + return response()->file($favicons->getPath()); + } } diff --git a/app/Uploads/FaviconHandler.php b/app/Uploads/FaviconHandler.php index 2e756c587..3dc702ea6 100644 --- a/app/Uploads/FaviconHandler.php +++ b/app/Uploads/FaviconHandler.php @@ -7,9 +7,12 @@ use Intervention\Image\ImageManager; class FaviconHandler { + protected string $path; + public function __construct( protected ImageManager $imageTool ) { + $this->path = public_path('favicon.ico'); } /** @@ -17,8 +20,7 @@ class FaviconHandler */ public function saveForUploadedImage(UploadedFile $file): void { - $targetPath = public_path('favicon.ico'); - if (!is_writeable($targetPath)) { + if (!is_writeable($this->path)) { return; } @@ -28,7 +30,7 @@ class FaviconHandler $bmpData = $image->encode('png'); $icoData = $this->pngToIco($bmpData, 32, 32); - file_put_contents($targetPath, $icoData); + file_put_contents($this->path, $icoData); } /** @@ -36,13 +38,30 @@ class FaviconHandler */ public function restoreOriginal(): void { - $targetPath = public_path('favicon.ico'); $original = public_path('icon.ico'); - if (!is_writeable($targetPath)) { + if (!is_writeable($this->path)) { return; } - copy($original, $targetPath); + copy($original, $this->path); + } + + /** + * Restore the original favicon image if no favicon image is already in use. + */ + public function restoreOriginalIfNotExists(): void + { + if (!file_exists($this->path)) { + $this->restoreOriginal(); + } + } + + /** + * Get the path to the favicon file. + */ + public function getPath(): string + { + return $this->path; } /** diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index 41655ccba..000000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/routes/web.php b/routes/web.php index 95b4ae535..937dc0c6c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -40,6 +40,7 @@ use Illuminate\View\Middleware\ShareErrorsFromSession; Route::get('/status', [StatusController::class, 'show']); Route::get('/robots.txt', [HomeController::class, 'robots']); +Route::get('/favicon.ico', [HomeController::class, 'favicon']); // Authenticated routes... Route::middleware('auth')->group(function () {