proside/file-manager
Reusable file manager for Laravel 10/11/12 built in Livewire v4: directory tree, grid/list views, uploads, drag & drop, trash with restore, previews, search, multi-disk support and a file picker component. No iframe or external service.
Gestor de ficheiros reutilizável para Laravel 10/11/12 construído integralmente em Livewire v4. Substitui o antigo File Manager em Next.js/React, mantendo paridade funcional e melhorando a arquitetura: sem iframe, sem JWT, sem serviço externo — corre dentro da própria aplicação Laravel e usa a autenticação/sessão existente.
Compatível com Laravel 10.49 e PHP 8.1+. Requer Livewire ^4.0.
apagados) com retenção configurável e expiração automática<x-file-manager::picker>)composer require proside/file-manager
O Service Provider, rotas, componente Livewire e componentes Blade são registados automaticamente (package discovery).
Por omissão usa o disco public. Crie o symlink uma vez:
php artisan storage:link
php artisan vendor:publish --tag=file-manager-config # config/file-manager.php
php artisan vendor:publish --tag=file-manager-views # resources/views/vendor/file-manager
php artisan vendor:publish --tag=file-manager-lang # lang/vendor/file-manager
php artisan vendor:publish --tag=file-manager-assets # public/vendor/file-manager/file-manager.css
O package usa classes utilitárias Tailwind (paleta proximo, equivalente ao antigo proximo).
Se a sua app compila Tailwind, adicione o caminho das vistas do package ao content do
tailwind.config.js para que as classes sejam geradas:
content: [
// ...
'./vendor/proside/file-manager/resources/views/**/*.blade.php',
],
Em app/Console/Kernel.php:
$schedule->command('file-manager:prune-trash')->daily();
Já existe a rota GET /file-manager (configurável). Ou embeba o componente onde quiser:
<div style="height: 80vh">
<livewire:file-manager />
</div>
Substitui o antigo <x-file-manager-modal> com a mesma API de props:
{{-- Um ficheiro --}}
<x-file-manager::picker input-name="gfqueue_image" :value="$queue->image ?? ''" />
{{-- Vários ficheiros --}}
<x-file-manager::picker input-name="imagens[]" :value="$existing" multiple />
{{-- Forçar apenas imagens (ou 'videos') --}}
<x-file-manager::picker input-name="icon" filter="images" />
O ficheiro escolhido fica num <input type="hidden" name="..."> — o submit do formulário
funciona exatamente como antes. Ao escolher, o componente emite o evento Livewire
file-manager-selected ({ paths: [...] }).
O File Manager pode confinar cada utilizador a uma ou mais pastas-raiz próprias.
Define um resolver que devolve a(s) raiz(es) efetiva(s) do utilizador atual
(relativas ao disco), ou null para acesso total:
// config/file-manager.php
'root_resolver' => \App\FileManager\LevelRootResolver::class, // invocável: __invoke(): null|string|array
Regras aplicadas pelo package quando há resolver:
null, '', ou um valor igual à raiz da config → acesso total;"conteudos/optivisao" → o utilizador só vê essa pasta para baixo
(árvore, breadcrumbs, navegação e operações ficam confinadas; aceder acima é
bloqueado por PathGuard); o lixo mostra apenas o que esse utilizador apagou
(via originalPath).['conteudos/a', 'conteudos/b']) → o utilizador vê
várias raízes: cada uma aparece na sidebar com a sua árvore, abre-se na
primeira, e a navegação fica confinada a qualquer uma delas. Caminhos fora da
raiz da config são ignorados (não escalam privilégios). O lixo é partilhado,
filtrado pela origem de qualquer das raízes.Exemplo de resolver (Backoffice Proside — perfil gflevel ligado por gfleveluser,
campo gflevel_ctvdir): ver docs/BACKOFFICE-INTEGRATION.md.
O resolver pode ser um class-string invocável (compatível com config:cache) ou um callable.
config/file-manager.php)| Chave | Omissão | Descrição |
|---|---|---|
disk |
public |
Disco do Filesystem |
root |
conteudos |
Pasta base navegável |
trash |
apagados |
Pasta do lixo |
trash_retention_days |
30 |
Dias até eliminação definitiva |
root_resolver |
null |
Resolver da raiz por utilizador (scoping); null = acesso total |
uploads.max_size |
51200 (KB) |
Tamanho máximo por ficheiro |
uploads.mimes |
null |
Mimes aceites (null = todos) |
media_url |
route |
route (seguro, qualquer disco/nome) / storage (direto, mais rápido) / auto |
route.* |
— | Prefixo, middleware e rota full-page |
Variáveis .env: FILE_MANAGER_DISK, FILE_MANAGER_ROOT, FILE_MANAGER_TRASH,
FILE_MANAGER_TRASH_DAYS, FILE_MANAGER_MAX_UPLOAD, FILE_MANAGER_MEDIA_URL,
FILE_MANAGER_ROUTE, FILE_MANAGER_ROUTE_PREFIX.
| Antigo (Next.js/React) | Novo (Livewire v4) |
|---|---|
FileManagerContext.js (estado global React) |
Propriedades públicas + #[Computed] em FileManager.php |
FileManager.jsx (layout) |
resources/views/livewire/file-manager.blade.php |
Files.jsx (grid/lista) |
partials/grid-item.blade.php, partials/list-item.blade.php |
NavItem.jsx (árvore) |
partials/tree-node.blade.php + tree() computed |
ContextMenu.jsx |
partials/context-menu.blade.php (Alpine) |
Modal.jsx |
partials/modal.blade.php (Alpine) |
ShowFile.jsx (lightbox) |
partials/lightbox.blade.php |
Filters.jsx, BreadCrumbs.js |
toolbar na view principal + breadcrumbs() |
AddFile.jsx (FAB + upload) |
FAB na view + wire:model="uploads" + updatedUploads() |
api/files, api/files/tree |
FileManagerService::listing() / tree() |
api/folders, api/rename, api/move |
createFolder() / rename() / move() |
api/delete, api/delete/cleanup |
trash() + file-manager:prune-trash |
api/upload, image/route.js |
upload() + MediaController (rota file-manager.media) |
verify-token, TokenListener.jsx (JWT) |
eliminado — usa auth/sessão do Laravel |
iframe + postMessage(SELECTED_FILE) |
<x-file-manager::picker> + evento file-manager-selected |
FILE_MANAGER_URL, proxy HTTP, JWT RS256 e chaves .pem.PathGuard contra path traversal.fs direto no public/.Integração no Backoffice Proside: ver docs/BACKOFFICE-INTEGRATION.md.
How can I help you explore Laravel packages today?