diff --git a/public/.htaccess b/public/.htaccess index 3aec5e27e..b6fdd07cc 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -14,7 +14,13 @@ RewriteCond %{REQUEST_URI} (.+)/$ RewriteRule ^ %1 [L,R=301] + # Serve storage files directly if they exist + RewriteCond %{REQUEST_URI} ^/storage/(.*)$ + RewriteCond %{REQUEST_FILENAME} -f + RewriteRule ^storage/(.*)$ storage/$1 [L] + # Send Requests To Front Controller... + # Files that exist are served directly (including storage symlink) RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L] diff --git a/routes/web.php b/routes/web.php index 1ede40075..4a1ee1dfb 100644 --- a/routes/web.php +++ b/routes/web.php @@ -61,6 +61,36 @@ Route::group(['middleware' => ['web', 'auth']], function () { Route::get('cart', Cart::class)->name('cart'); +// Serve storage files if symlink doesn't work or web server doesn't serve them directly +// This route only handles requests that reach Laravel (if .htaccess doesn't serve them) +Route::get('/storage/{path}', function ($path) { + // Sanitize the path to prevent directory traversal + $path = str_replace('..', '', $path); + $path = ltrim($path, '/'); + + $filePath = storage_path('app/public/' . $path); + + // Ensure the file exists and is within the public storage directory + if (!file_exists($filePath) || !is_file($filePath)) { + abort(404, 'File not found'); + } + + // Verify the file is actually within the storage/app/public directory + $realPath = realpath($filePath); + $publicPath = realpath(storage_path('app/public')); + + if (!$realPath || strpos($realPath, $publicPath) !== 0) { + abort(403, 'Access denied'); + } + + $mimeType = mime_content_type($filePath) ?: 'application/octet-stream'; + + return response()->file($filePath, [ + 'Content-Type' => $mimeType, + 'Cache-Control' => 'public, max-age=31536000', + ]); +})->where('path', '.*')->name('storage.serve'); + Route::group(['prefix' => 'products'], function () { Route::get('/{category:slug}', Products\Index::class)->name('category.show')/* ->where('category', '[A-Za-z0-9_/-]+') */; Route::get('/{category:slug}/{product:slug}', Products\Show::class)->name('products.show')/* ->where('category', '[A-Za-z0-9_/-]+') */;