Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Directory Lister Laravel Package

phlak/directory-lister

PHLAK DirectoryLister is a lightweight, standalone PHP directory listing tool that turns folders into browsable indexes. It offers sorting, search, breadcrumbs, file icons, and customizable templates with no database required.

View on GitHub
Deep Wiki
Context7

Getting Started

Directory Lister is a standalone PHP application, not a Laravel package — there is no service provider, facade, or php artisan vendor:publish workflow, and the composer package (phlak/directory-lister) simply ships the app. Treat it as a small self-hosted service you mount next to (or behind) your Laravel app, not as a library you compose into it.

Minimal path to a working listing:

  1. Pin the version before anything else. As of 5.8.0 the project ships fixes for two real vulnerabilities (hidden-file filtering bypass via ./.. path segments, and direct-linked content reachable through query-string parameters, plus a HIDE_VCS_FILES typo that made the setting a no-op). Treat <5.8.0 as not deployable; put phlak/directory-lister: 5.8.0 (or a ^5.8 constraint) in your deploy manifest.
  2. Decide the deployment shape. Two viable options:
    • Standalone subdirectory (recommended): drop the release into public/files/_lister/ (or a sibling docroot), point its files/ directory at the folder you want to expose, and leave Laravel untouched.
    • Separate subdomain (e.g. files.example.com): best when you want HTTP basic auth or nginx auth_request in front of it, sharing the Laravel session cookie via session.domain.
  3. Install: composer create-project phlak/directory-lister in a scratch dir, or download the release zip. Copy it to your target path; never leave config/, vendor/, or the app source reachable from the web.
  4. Symlink the content: ln -s /var/www/app/storage/app/public/downloads files (and php artisan storage:link on the Laravel side). The lister only sees what is inside its files/ directory.
  5. Edit config/app.php: set view (theme), sort_order, date_format, timezone, hide_dot_files, hide_vcs_files, enable_search, enable_download_zip, zip_compress, direct_links, and — if you need it — the auth block with a password_hash() value.
  6. Open the URL. That is the whole install.

Where to look first: config/app.php (every behavior is here), the themes/ directory (copy one, rename it, set view), and — since 5.8.0 — the docs/ folder inside the repo, which is now the source of truth for the documentation (the website is generated from it). Reading docs/ at your pinned tag is the only reliable way to get config semantics for your version. Your first real use case is almost always "let clients/vendors browse a folder of exports, invoices, or release artifacts without me building a CRUD screen."

Implementation Patterns

Subdirectory mount with Laravel-owned auth. Put the lister at public/downloads/ and protect the path with a Laravel route/middleware or an nginx auth_request that hits a signed Laravel endpoint. This keeps Directory Lister's own password auth out of the picture and reuses your existing guards and policies.

Subdomain with shared session. Serve on files.example.com, set Laravel's SESSION_DOMAIN=.example.com, and gate the vhost with the same cookie. Simpler than middleware, and lets you scale the lister independently.

Deploy-time config templating. Since config is a PHP array, keep a config/app.php.tpl in your repo and render it in your deploy script (envsubst, Ansible template, or a small PHP script) so timezone, date_format, auth, and feature flags differ per environment. Do not hand-edit on the server. This also gives you a single place to force zip_downloads/zip_compress to real booleans (see gotchas).

Theme as the extension point. Copy themes/<default> to themes/company, replace the logo/CSS, and adjust the header/footer templates. This is the sanctioned way to brand it; avoid patching app source, or your next upgrade will hurt.

Use DIRECT_LINKS for stable, shareable deep URLs (new in 5.8.0). Directories matching the pattern are linkable directly instead of only being reachable by browsing parents, and 5.8.0 also centralized directory URL generation and tightened path-segment encoding. Practical use: set direct_links to your client/vendor slug pattern (/^client-[a-z0-9-]+$/) and hand out https://files.example.com/?dir=client-acme in emails, invoices, or a Laravel-generated link — users no longer need the parent listing to exist or be browsable. Pair it with the auth layer, since a direct link is only as private as the gate in front of it.

README as landing content. 5.8.0 decoupled README rendering from hide_dot_files, so a README.md/README in a directory renders even when hidden-file filtering is on. Drop a short README per client folder ("these are your Q3 exports, contact X") and the listing becomes self-documenting without any Laravel code.

Pair it with object storage for big files. For large artifact sets, mount an S3/Spaces bucket via rclone/s3fs at files/, or front the lister with a CDN and let enable_download_zip handle bundling small groups. Turn zip off for multi-GB trees.

Operational pattern for sharing. Generate a per-client symlink (files/client-a -> /storage/clients/a/exports) and hand out the URL. Cheap multi-tenancy without touching the app — and with 5.8.0's canonical-path checks, ..-style URL tampering no longer escapes the intended boundary.

Gotchas and Tips

  • It is not a Laravel package. No service provider, no Blade views registered with your app, no config merge. Any "integration" is filesystem layout, symlinks, and reverse-proxy auth. Plan accordingly.
  • Upgrade to 5.8.0 if you are on anything older. The hidden-file bypass via non-canonical paths (./, ../ segments) means hide_dot_files/hide_vcs_files were advisory on hostile input, and the direct-link query-string hole leaked content from outside the linked path. Both are fixed in 5.8.0 — but they are fixes, not hardening you can defer.
  • Boolean config values must be real booleans. In <5.8.0, ZIP_DOWNLOADS=false and ZIP_COMPRESS=false were interpreted as enabled — the opposite of intent, which is exactly the kind of bug that turns "zip is off for the 40 GB tree" into an OOM incident. Fixed in 5.8.0, but audit your config template for quoted strings ('false') which are truthy in PHP, and keep the values as true/false literals.
  • HIDE_VCS_FILES was silently ignored before 5.8.0 due to a variable typo. If you had a .git directory or .svn inside files/, assume it was listed. Re-check any listing that ever exposed a deploy checkout, and prefer keeping VCS metadata outside files/ entirely.
  • Directory traversal is your problem. The lister only enforces its own files/ boundary; a bad symlink or a misconfigured docroot exposing config/ is a full disclosure bug. Keep config/ and vendor/ outside the webroot where possible.
  • Auth is single-password, not user management. It stores a password_hash() value; there are no roles, sessions, or audit trail. For anything with more than one audience, put Laravel auth or HTTP basic auth in front.
  • trusted_proxies matters. If ip_blacklist/ip_whitelist behave oddly behind a load balancer, set trusted proxies so the client IP is the real one, not the balancer's.
  • Large directories are slow. Every request rescans the tree; there is no built-in cache. Keep listings under a few thousand entries per folder, or put a CDN/edge cache in front with a short TTL.
  • Zip downloads need ZipArchive and enough memory_limit/max_execution_time. 5.8.0 fixed incomplete archives in some compression paths — if you built tooling that "verifies" archives by size, re-baseline it, and re-run any previously produced bundles you still ship.
  • file_types is extension-driven. Preview handlers won't fire for misnamed files (e.g. .bin containing a PDF). Check the mapping before blaming the theme.
  • Hiding is not access control. hide_dot_files and hide_vcs_files are display filters; files placed inside files/ are still reachable by direct URL. Never park .env, .git, or credentials inside the listing root.
  • URL encoding changed in 5.8.0. Directory URLs are now generated centrally with consistent per-segment encoding. If you scrape or hand-construct listing URLs (or bookmark them for clients), retest names with spaces, +, #, and non-ASCII — old links may not match byte-for-byte.
  • Upgrades can rename config keys. Diff the shipped config/app.php against yours on every minor/major bump, and read the tag's docs/ folder — the docs now move with the code, so they can change without a website changelog entry. Pin the version in your deploy manifest.
  • Debugging blank pages: check the PHP error log first, then confirm files/ exists and is readable by the PHP user. A missing files/ dir is the single most common cause of an empty listing.
  • Extension points are themes and translations, nothing more. There is no event/hook system to speak of — if you need per-request logic, wrap the URL in Laravel and redirect/deny before the lister is reached.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package