# Introduction

Directory Lister is the easiest way to expose the contents of any web-accessible folder for browsing and sharing. With a zero configuration, drag-and-drop installation you'll be up and running in less than a minute.

## Features

* **Simple installation** allows you to be up and running in less than a minute.
* **Light and dark themes** to suit your professional needs or personal style.
* **Custom sort ordering** gives you control of the ordering of your files/folders.
* **File search** helps you locate the files you need quickly and efficiently.
* **File hashes** instill confidence when downloading files through verification.
* **Readme rendering** allows exposing the contents of READMEs directly on the page.
* **Zip downloads** for fetching an entire directory of files in a single action.
* **Multi-lingual support** brings Directory Lister to the language of your choice.

## Changelog

A list of changes can be found on the [GitHub Releases](https://github.com/DirectoryLister/DirectoryLister/releases) page.

## Copyright

This project is licensed under the [MIT License](https://github.com/DirectoryLister/DirectoryLister/blob/master/LICENSE).


# Installation

Installation of Directory Lister is fast and requires no configuration.

## Requirements

* Directory Lister requires [PHP](https://www.php.net/) 8.2+
  * The [Zip](https://www.php.net/manual/en/book.zip.php) extension is required for zip downloads
  * The [DOM](https://www.php.net/en/dom) and [Fileinfo](https://www.php.net/manual/en/book.fileinfo.php) extensions are required for README rendering

## Manual Installation

1. [Download Directory Lister](https://www.directorylister.com)
2. Extract the zip/tar archive
3. Copy extracted files/folders to your web server

## Install with Composer

```bash
composer create-project phlak/directory-lister
```


# Upgrade Guide

Upgrading an existing Directory Lister installation is quick and painless.

1. Download the latest version of Directory Lister from <https://www.directorylister.com>
2. Extract the zip/tar archive
3. Copy the extracted files/folders to your existing installation location
   1. If prompted, overwriting all files
4. Clear the application cache by deleting all files in the `app/cache` directory

   ```
    rm --recursive --force app/cache/*
   ```


# Docker

Starting with Directory Lister v5.0 an [official Docker image is provided](https://hub.docker.com/r/directorylister/directorylister) as `directorylister/directorylister`.

## Running with `docker run`

```bash
docker run --detach [--env ENVIRONMENT_VARIABLE=value] \
    --volume <host_path>:/data --publish <host_port>:80 \
    directorylister/directorylister:5
```

{% hint style="warning" %}
Replace `<host_path>` with the path to the directory you'd like to list.

Replace `<host_port>` with the port you would like to expose the application on.
{% endhint %}

{% hint style="info" %}
You may pass one or more environment variables with multiple `--env` flags.

See the [Configuration Reference](/configuration/configuration-reference) for a full list of the available environment variables.
{% endhint %}

## Running with `docker compose`

The following is an example `docker-compose.yaml` file. For more information on `docker compose` and how to use this file see the [Docker Compose documentation](https://docs.docker.com/compose/).

{% code title="docker-compose.yaml" %}

```yaml
services:

  directory-lister:
    image: directorylister/directorylister:<version>
    environment:
      # APP_LANGUAGE: en
      # DISPLAY_READMES: true
      # READMES_FIRST: false
      # ZIP_DOWNLOADS: true
      # TIMEZONE: America/Phoenix
      # See configuration docs for additional variables
    ports:
      - <host_port>:80
    volumes:
      - <host_path>:/data
    restart: unless-stopped
```

{% endcode %}

{% hint style="warning" %}
Replace `<version>` with the version of Directory Lister you'd like to use (e.g. `5.0.5`, `5.0` or `5`)

Replace `<host_path>` with the path to the directory you'd like to list.

Replace `<host_port>` with the port you would like to expose the application on.
{% endhint %}

{% hint style="info" %}
See the [Configuration Reference](/configuration/configuration-reference) for a full list of the available environment variables.
{% endhint %}

### Advanced `docker compose` usage&#x20;

The following is an example `docker-compose.yaml` file showing Directory Lister being run with a Valkey container for caching.

{% code title="docker-compose.yaml" %}

```yaml
services:

  directory-lister:
    image: directorylister/directorylister:<version>
    environment:
      CACHE_DRIVER: redis
      REDIS_HOST: cache
      REDIS_PORT: 6379
      # See configuration docs for additional variables
    ports:
      - <host_port>:80
    volumes:
      - <host_path>:/data
    depends_on: [cache]
    restart: unless-stopped

  cache:
    image: valkey:8
    restart: unless-stopped
```

{% endcode %}

{% hint style="warning" %}
Replace `<version>` with the version of Directory Lister you'd like to use (e.g. `5.0.5`, `5.0` or `5`)

Replace `<host_path>` with the path to the directory you'd like to list.

Replace `<host_port>` with the port you would like to expose the application on.
{% endhint %}


# Configuration Overview

Directory Lister is customizable through configuration. You can configure Directory Lister in a few different ways.

## The `.env` File

{% hint style="success" %}
This is the recommended method of configuring Directory Lister.
{% endhint %}

Most configuration changes are possible via a custom `.env` file. This file defines environment variables and their value. To get started:

1. Copy `.env.example` to `.env`
2. Edit the configuration values in `.env`

Your default `.env` file should look something like this:

{% code title=".env" %}

```bash
APP_DEBUG=false
APP_LANGUAGE=en

# FILES_PATH=

DISPLAY_READMES=true
READMES_FIRST=false
ZIP_DOWNLOADS=true

SORT_ORDER=type
REVERSE_SORT=false
```

{% endcode %}

See the [App Config Reference](/configuration/configuration-reference) for additional configuration options.

## Hiding Files

By default Directory Lister will look for a `.hidden` file in the app root directory (the same place as `index.php`). If found, each line of this file will be used as a [file matching pattern](/configuration/configuration-overview/file-matching-patterns) and every matched file/folder will be hidden from the directory listing.

Each line of the `.hidden` file should contain a single file or path pattern with no end-of-line delimiter. A pattern matching a folder path will cause all files and folders within that folder to be hidden as well as the folder itself.

{% hint style="info" %}
The `.hidden` file does not exist by default and must be created to be used.
{% endhint %}

### Custom JavaScript and CSS <a href="#custom-javascript-and-css" id="custom-javascript-and-css"></a>

Directory Lister allows for including arbitrary CSS and JavaScript into your Directory Listing through a `.customizations.html` file. This is particularly useful for injecting analytics tracking script (e.g. [Google Analytics](https://analytics.google.com), [Matomo Analytics](https://matomo.org/), [Umami Analytics](https://umami.is/), etc.) into the HTML output of your directory listing.

To inject your code into your page create a file named `.customizations.html` in the base project directory (the same folder as `index.php`) and place your analytics tracking script code into this file.

## Icon Configuration

You can control your application icon mapping through the icon config file.

Reference the [Icon Configuration](#icon-configuration) for more information on configuring icons.

## Advanced Configuration

More control can be achieved via the application config files located in `app/config`. Here you have full control over each option and can even write full PHP code if desired. The application configs are broken up into separate files based on their use. Reference the individual config documentation for more information about individual application configuration options.

{% hint style="warning" %}
Take care when upgrading your Directory Lister installation as the files in `app/config` may be overwritten if you copy/paste and replace all files.
{% endhint %}

See the [Configuration Reference](/configuration/configuration-reference) for more information about individual options.


# File Matching Patterns

File matching patterns are used in various configuration options including specifying [hidden files](/configuration/configuration-overview#hiding-files) and [direct links](/configuration/configuration-reference#direct_links). A file matching pattern is a path to a file or folder that may contain one or more of the following special expressions.

{% hint style="warning" %}
File matching patterns are *case sensitive*. This means that `foo.txt` and `Foo.txt` are *not* the same.
{% endhint %}

## Matching Expressions

* `?` matches any single character
* `*` matches zero or more characters excluding `/`
* `**` matches zero or more characters including `/`
* `[abc]` matches a single character from the set (i.e. `a`, `b` or `c`)
* `[a-c]` matches a single character in the range (i.e. `a`, `b` or `c`)
* `[^abc]` matches any character not in the set (i.e. not `a`, `b` or `c`)
* `[^a-c]` matches any character not in the range (i.e. not `a`, `b` or `c`)
* `{foo,bar,baz}` matches any pattern in the set (i.e. `foo`, `bar` or `baz`)

## Assertions

The following assertions can be used to assert that a path is followed by or not followed by another pattern.

* `(=foo)` matches any file name that also contains `foo`
* `(!foo)` matches any file name that does not also contain `foo`

## Examples

**`foo`** Match the literal file or folder `foo` in the root folder

**`foo/bar`** Matches the literal file or folder `bar` in the `foo` folder

**`*.txt`** Matches any file or folder ending with `.txt` in the root folder

**`**/*.txt`** Matches any file or folder ending with `.txt` one or more folders deep (e.g. `foo/bar.txt` or `foo/bar/baz.txt`)

**`**.txt`** Matches any file or folder ending with `.txt` (e.g. `foo.txt`, `foo/bar.txt`, `foo/bar/baz.txt`, etc.)

**`foo/bar/*.txt`** Matches all `.txt` files or folders in the `foo/bar` folder

**`foo/bar/**.txt`** Matches all `.txt` files or folders in the `foo/bar` folder and sub-folders

**`file.{yml,yaml}`** Matches a file or folder named `file.yml` or `file.yaml` in the root folder

**`file.tar(!.{gz,xz})`** Matches a file named `file.tar` or `file.tar.bz` but not `file.tar.gz` or `file.tar.xz`


# Configuration Reference

## Bootstrap Configuration

These configuration options are special configuration options only configurable through environment variables (e.g. through the `.env` file).

{% hint style="info" %}
There are no corresponding configuration options for these values in the `app/config` definitions because they are applied *before* the application container (and configuration) is loaded.
{% endhint %}

### `FILES_PATH`&#x20;

A path (relative or absolute) to the directory in which you would like to list. This may even be a path outside of the application directory. When left unset, the root application directory (i.e. the folder where `index.php` is located) will be listed.

{% tabs %}
{% tab title="Possible Values" %}
An absolute or relative file path (string)
{% endtab %}

{% tab title="Default Value" %}
`<unset>`
{% endtab %}
{% endtabs %}

### `COMPILE_CONTAINER`&#x20;

Whether or not the application container will be compiled. When set to `false` the container will *not* be compiled and cached. If left unset the container will be compiled and cached on first run and the cached container will be reused on subsequent requests. Disabling this comes with a (likely negligible) performance hit. Generally this should not be changed but might be necessary to modify when running Directory Lister on a read-only filesystem.

{% tabs %}
{% tab title="Possible Values" %}
`false` or `<unset>`
{% endtab %}

{% tab title="Default Value" %}
`<unset>`
{% endtab %}
{% endtabs %}

## Runtime Configuration

General application runtime configuration can be controlled through environment variables. This can be accomplished via an `.env` file located in the root of your application. An example file is provided as `.env.example`.

{% hint style="info" %}
Advanced configuration can be accomplished via the app config located at `app/config/app.php`. However, changes to this fill will need to be manually re-applied between upgrades. It is highly recommended to stick to environment variables for controlling app configuration unless absolutely necessary.
{% endhint %}

### `APP_DEBUG`

Enable application debugging and display error messages.

{% hint style="danger" %}
It is recommended that debug remains OFF unless troubleshooting an issue. Leaving this enabled WILL cause leakage of sensitive server information.
{% endhint %}

{% tabs %}
{% tab title="Possible Values" %}
`true` or `false`
{% endtab %}

{% tab title="Default Value" %}
`false`
{% endtab %}
{% endtabs %}

### `APP_LANGUAGE`

The application's interface language.

{% tabs %}
{% tab title="Possible Values" %}
See the [`app/translations`](https://github.com/DirectoryLister/DirectoryLister/tree/master/app/translations) folder for available translations.
{% endtab %}

{% tab title="Default Value" %}
`en` (English)
{% endtab %}
{% endtabs %}

### `DATE_FORMAT`

The format used for rendering dates in the application views.

{% tabs %}
{% tab title="Possible Values" %}
See the [PHP `date` format documentation](https://www.php.net/manual/en/function.date.php#refsect1-function.date-parameters) for possible values.
{% endtab %}

{% tab title="Default Value" %}
`Y-m-d H:i:s`
{% endtab %}
{% endtabs %}

### `DIRECT_LINKS`

Comma separated list of [file matching patterns](/configuration/configuration-overview/file-matching-patterns) to be directly linked. Directly linked files will not be served by Directory Lister but handled by the web server directly.&#x20;

{% hint style="warning" %}
This setting has no effect when [`FILES_PATH`](#files_path) is set or when used in the Docker container.
{% endhint %}

#### Example

To directly link all `.htm`, `.html` *one or more folders deep* and `.php` files *in all folders and sub-folders*.

```
DIRECT_LINKS=**/index.{htm,html},**.php
```

{% tabs %}
{% tab title="Possible Values" %}
A comma separated list of [file matching patterns](/configuration/configuration-overview/file-matching-patterns).
{% endtab %}

{% tab title="Default Value" %}
`null`
{% endtab %}
{% endtabs %}

### `DISPLAY_READMES`

Parse and render `README` files on the page.

{% tabs %}
{% tab title="Possible Values" %}
`true` or `false`
{% endtab %}

{% tab title="Default Value" %}
`true`
{% endtab %}
{% endtabs %}

### `GOOGLE_ANALYTICS_ID`

Your Google analytics tracking ID.

{% hint style="danger" %}
This configuration option has been deprecated and will stop working in a future release. See the [Analytics Script Injection](/configuration/configuration-overview#analytics-script-injection) section for instructions on configuring analytics tracking.
{% endhint %}

{% tabs %}
{% tab title="Possible Values" %}
A string in the format of `UA-123456789-0` or `false` to disable
{% endtab %}

{% tab title="Default Value" %}
`false`
{% endtab %}
{% endtabs %}

### `HIDDEN_FILES_LIST`

File containing hidden file definitions. Will be merged with definitions from the 'hidden\_files' configuration option.

{% hint style="info" %}
See the [Hiding Files](broken://pages/-MRY0IoZxbSmQKztpD6x) page for additional info on hiding files.
{% endhint %}

{% tabs %}
{% tab title="Possible Values" %}
A path (string) to a file
{% endtab %}

{% tab title="Default Value" %}
`.hidden`
{% endtab %}
{% endtabs %}

### `HIDE_APP_FILES`

Hide application specific files/directories (i.e. `index.php` and the `app` folder).

{% tabs %}
{% tab title="Possible Values" %}
`true` or `false`
{% endtab %}

{% tab title="Default Value" %}
`true`
{% endtab %}
{% endtabs %}

### `HIDE_DOT_FILES`

Hide dot files/directories from the listing.

{% tabs %}
{% tab title="Possible Values" %}
`true` or `false`
{% endtab %}

{% tab title="Default Value" %}
`true`
{% endtab %}
{% endtabs %}

### `HIDE_VCS_FILES`

Hide the files Version Control Systems (i.e. Git and Mercurial) use to store their metadata.

{% tabs %}
{% tab title="Possible Values" %}
`true` or `false`
{% endtab %}

{% tab title="Default Value" %}
`true`
{% endtab %}
{% endtabs %}

### `HOME_TEXT`

Text of the `home` link in the navigation breadcrumbs. If undefined or `null` will use the translated form of "home" from your selected language.

{% tabs %}
{% tab title="Possible Values" %}
Any string
{% endtab %}

{% tab title="Default Value" %}
`null`
{% endtab %}
{% endtabs %}

### `MATOMO_ANALYTICS_SITE_ID`

Your Matomo analytics site ID.

{% hint style="danger" %}
This configuration option has been deprecated and will stop working in a future release. See the [Analytics Script Injection](/configuration/configuration-overview#analytics-script-injection) section for instructions on configuring analytics tracking.
{% endhint %}

{% tabs %}
{% tab title="Possible Values" %}
A Matomo analytics site ID (string)
{% endtab %}

{% tab title="Default Value" %}
`false`
{% endtab %}
{% endtabs %}

### `MATOMO_ANALYTICS_URL`

Your Matomo analytics URL.

{% hint style="danger" %}
This configuration option has been deprecated and will stop working in a future release. See the [Analytics Script Injection](/configuration/configuration-overview#analytics-script-injection) section for instructions on configuring analytics tracking.
{% endhint %}

{% tabs %}
{% tab title="Possible Values" %}
A Matomo analytics URL (string)
{% endtab %}

{% tab title="Default Value" %}
`false`
{% endtab %}
{% endtabs %}

### `MAX_HASH_SIZE`

The maximum file size (in bytes) that can be hashed. This helps to prevent timeouts for excessively large files.

{% hint style="warning" %}
The larger a file is the longer it will take to calculate hashes for that file.
{% endhint %}

{% tabs %}
{% tab title="Possible Values" %}
Any positive integer `0` - `9223372036854775807` ([`PHP_INT_MAX`](https://www.php.net/manual/en/reserved.constants.php#constant.php-int-max))
{% endtab %}

{% tab title="Default Value" %}
`1000000000` (1 GB)
{% endtab %}
{% endtabs %}

### `META_DESCRIPTION`

Meta tag description (i.e. `<meta name="description">`) text.

{% tabs %}
{% tab title="Possible Values" %}
Any string
{% endtab %}

{% tab title="Default Value" %}
`Yet another directory listing, powered by Directory Lister.`
{% endtab %}
{% endtabs %}

### `READMES_FIRST`

Show READMEs before the file listing.

{% tabs %}
{% tab title="Possible Values" %}
`true` or `false`
{% endtab %}

{% tab title="Default Value" %}
`false`
{% endtab %}
{% endtabs %}

### `REVERSE_SORT`

When enabled, reverses the order of files (after sorting is applied).

{% tabs %}
{% tab title="Possible Values" %}
`true` or `false`
{% endtab %}

{% tab title="Default Value" %}
`false`
{% endtab %}
{% endtabs %}

### `SITE_TITLE`

The title of your directory listing. This will be displayed in the browser tab/title bar along with the current path.

{% tabs %}
{% tab title="Possible Values" %}
Any string
{% endtab %}

{% tab title="Default Value" %}
`Directory Lister`
{% endtab %}
{% endtabs %}

### `SORT_ORDER`

Sorting order of files and folders. Can be one of several predefined values. Advanced sorting configuration can be achieved by using an anonymous function. See the [`sort_order` configuration option](#sort_order-1) documentation for more information.

{% tabs %}
{% tab title="Possible Values" %}
`type`, `natural`, `name`, `accessed`, `changed`, `modified`, `<anonymous function>`
{% endtab %}

{% tab title="Default Value" %}
`type`
{% endtab %}
{% endtabs %}

### `TIMEZONE`

Time zone used for date formatting.

{% tabs %}
{% tab title="Possible Values" %}
For a list of supported time zones see: <https://www.php.net/manual/en/timezones.php>.
{% endtab %}

{% tab title="Default Value" %}
The server's timezone
{% endtab %}
{% endtabs %}

### `ZIP_DOWNLOADS`

Enable downloading of directories as a zip archive.

{% tabs %}
{% tab title="Possible Values" %}
`true` or `false`
{% endtab %}

{% tab title="Default Value" %}
`true`
{% endtab %}
{% endtabs %}

### &#x20;`ZIP_COMPRESS`

Compress Zip using Deflate. Enabling this option prevents file size estimation and it may prevent zip download resuming when paused.

{% tabs %}
{% tab title="Possible Values" %}
`true` or `false`
{% endtab %}

{% tab title="Default Value" %}
`false`
{% endtab %}
{% endtabs %}

## Cache Configuration

Application cache configuration is also controlled through environment variables. This can be accomplished via an `.env` file located in the root of your application. An example file is provided as `.env.example`.

{% hint style="info" %}
Advanced configuration can be accomplished via the cache config located at `app/config/cache.php`. However, changes to this fill will need to be manually re-applied between upgrades. It is highly recommended to stick to environment variables for controlling cache configuration unless absolutely necessary.
{% endhint %}

### `CACHE_DRIVER`

The application cache driver. Setting this value to `array` will disable the cache across requests. Additional driver-specific options may be required with certain values.

{% tabs %}
{% tab title="Possible Values" %}
`apcu`, `array`, `file`, `memcached`, `redis`, `php-file`, `valkey`
{% endtab %}

{% tab title="Default Value" %}
`file`
{% endtab %}
{% endtabs %}

### `CACHE_LIFETIME`

The app cache lifetime (in seconds). Setting this value to `0` will cache indefinitely.

{% tabs %}
{% tab title="Possible values" %}
Any positive integer
{% endtab %}

{% tab title="Default Value" %}
`60` (one hour)
{% endtab %}
{% endtabs %}

### `CACHE_LOTTERY`

Some cache drivers require manually pruning the cache periodically to remove expired items. This is the percentage chance (out of 100) of a request "winning" the lottery causing the cache to be pruned.

{% tabs %}
{% tab title="Possible Values" %}
Any integer betweeen `1` and `100`
{% endtab %}

{% tab title="Default Value" %}
`2`
{% endtab %}
{% endtabs %}

### `MEMCACHED_HOST`

The Memcached server hostname or IP address.

{% tabs %}
{% tab title="Possible Values" %}
Any string
{% endtab %}

{% tab title="Default Value" %}
`localhost`
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Advanced Memcached configuration is possible via the [`memcached_config` option](#memcached_config) in `app/config/cache.php`
{% endhint %}

### `MEMCACHED_PORT`

The Memcached server port.

{% tabs %}
{% tab title="Possible Values" %}
Any valid port as an integer (`0` to `65353`)
{% endtab %}

{% tab title="Default Value" %}
`11211`
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Advanced Memcached configuration is possible via the [`memcached_config` option](#memcached_config) in `app/config/cache.php`
{% endhint %}

### `REDIS_HOST`

The Redis server hostname or IP address.

{% tabs %}
{% tab title="Possible Values" %}
Any string
{% endtab %}

{% tab title="Default Value" %}
`localhost`
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Advanced Reds configuration is possible via the [`redis_config` option](#redis_config) in `app/config/cache.php`
{% endhint %}

### `REDIS_PORT`

The Redis server port.

{% tabs %}
{% tab title="Possible Values" %}
Any valid port as an integer (`0` to `65353`)
{% endtab %}

{% tab title="Defualt Value" %}
`6379`
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Advanced Reds configuration is possible via the [`redis_config` option](#redis_config) in `app/config/cache.php`
{% endhint %}

### `VIEW_CACHE`

Path to the view cache directory. Set to `false` to disable view caching entirely.

{% tabs %}
{% tab title="Possible Values" %}
A directory path as a string or `false` to disable the view cache entirely
{% endtab %}

{% tab title="Default Value" %}
`app/cache/views`
{% endtab %}
{% endtabs %}

## Icon Configuration

The icon config is located at `app/config/icons.php`. Here is were file types are mapped to their respective icons. The mapping is a PHP array where the array key is the file extension (without a preceding dot) and the array value is the desired [Font Awesome](https://fontawesome.com/icons) class names.

{% code title="icons.php" %}

```php
return [
    'icons' => [
        '7z' => 'fas fa-file-archive',
        'aac' => 'fas fa-music',
        'accdb' => 'fas fa-database',
        'ai' => 'fas fa-image',
        'aif' => 'fas fa-music',
        'apk' => 'fab fa-android',
        'app' => 'fas fa-window',
        'avi' => 'fas fa-video',
        'bak' => 'fas fa-save',
        'bat' => 'fas fa-terminal',
        // etc...
    ],
];
```

{% endcode %}

## Advanced Configuration

Some configuration values do not have a corresponding variable. These values can only be controlled through their entries in the `app/config` files.

#### `hidden_files` <a href="#hidden_files" id="hidden_files"></a>

Array of hidden file definitions. Will be merged with definitions in the file defined in the `hidden_files_list` configuration option. Supports glob patterns (e.g. `*.txt`, `file.{yml,yaml}`, etc.).

{% hint style="info" %}
See the [Hiding Files](https://docs.directorylister.com/configuration/hiding-files) page for additional info on hiding files.
{% endhint %}

{% tabs %}
{% tab title="Possible Values" %}
An array of paths (strings)
{% endtab %}

{% tab title="Default Value" %}
`[]` (an empty array)
{% endtab %}

{% tab title="Example" %}

```php
'hidden_files' => [
    'somefile.txt', // Matches 'somefile.txt' exactly
    'README.*', // Matches files named 'README' with any file extension
    'foo/*', // Matches all files in the 'foo' directory
    'schema.{ya?ml}', // Matches 'schema.yml' or 'schema.yaml'
]
```

{% endtab %}
{% endtabs %}

### `memcached_config`

The Memcached configuration [anonymous function](https://www.php.net/manual/en/functions.anonymous.php) (closure). This option is used when the `cache_driver` configuration option is set to `memcached`. The closure receives a `Memcached` object as it's only parameter. You can use this object to configure the Memcached connection. At a minimum you must connect to one or more Memcached servers via the `addServer()` or `addServers()` methods.

{% hint style="info" %}
Reference the [PHP Memcached documentation](https://secure.php.net/manual/en/book.memcached.php) for Memcached configuration options.
{% endhint %}

{% tabs %}
{% tab title="Possible Values" %}
An anonymous function that receives a `Memcached` object

```php
function (Memcached $memcached): void {
    // Configure the $memcached object
}
```

{% endtab %}

{% tab title="Default Value" %}

```php
DI\value(function (Memcached $memcached, Config $config): void {
    $memcached->addServer(
        $config->get('memcached_host'),
        $config->get('memcached_port')
    );
})
```

This closure adds a single connection to a server at the host defined by [`memcached_host`](broken://pages/-MRY0IoXSIBVorYDYDqP#memcached_host) on the port defined by [`memcached_port`](broken://pages/-MRY0IoXSIBVorYDYDqP#memcached_port).
{% endtab %}

{% tab title="Environment Variables" %}
Uses the `MEMCACHED_HOST` and `MEMCACHED_PORT` variables by default
{% endtab %}
{% endtabs %}

### `redis_config`

The Redis configuration [anonymous function](https://www.php.net/manual/en/functions.anonymous.php) (closure). This option is used when the `cache_driver` configuration option is set to `redis`. The closure receives a `Redis` object as it's only parameter. You can use this object to configure the Redis connection. At a minimum you must connect to one or more Redis servers via the `connect()` or `pconnect()` methods.

{% hint style="info" %}
Reference the [phpredis documentation](https://github.com/phpredis/phpredis#readme) for Redis configuration options.
{% endhint %}

{% tabs %}
{% tab title="Possible Values" %}
An anonymous function that receives a `Redis` object

```php
function (Redis $redis): void {
    // Configure the $redis object
}
```

{% endtab %}

{% tab title="Default Value" %}

```php
DI\value(function (Redis $redis, Config $config): void {
    $redis->pconnect(
        $config->get('redis_host'),
        $config->get('redis_port')
    );
})
```

This closure adds a single connection to a server at the host defined by [`redis_host`](broken://pages/-MRY0IoXSIBVorYDYDqP#redis_host) on the port defined by [`redis_port`](broken://pages/-MRY0IoXSIBVorYDYDqP#redis_port).
{% endtab %}

{% tab title="Environment Variables" %}
Uses the `REDIS_HOST` and `REDIS_PORT` variables by default
{% endtab %}
{% endtabs %}

### `http_cache`

HTTP cache values for controlling browser page cache duration. An array of mime types mapped to their cache duration in seconds.

{% tabs %}
{% tab title="Possible Values" %}
An array of [mime types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) mapped to their cache duration as a seconds (integers).
{% endtab %}

{% tab title="Defualt Value" %}

```php
[
    'application/json' => 300,
    'application/zip' => 300,
]
```

{% endtab %}
{% endtabs %}

### `sort_order`

An [anonymous function](https://www.php.net/manual/en/functions.anonymous.php) can be used to customize the sort order of files and folders in your directory listing. The anonymous function receives two `SplFileInfo` objects as arguments and must return an integer less than, equal to, or greater than zero to represent the first argument being respectively less than, equal to, or greater than the second.

```php
'sort_order' => \DI\value(
    function (SplFileInfo $file1, SplFileInfo $file2): int {
        return strcmp($file1->getRealPath(), $file2->getRealPath());
    })
);
```

{% hint style="warning" %}
The anonymous function must be wrapped in a `\DI\value()` function.
{% endhint %}


# Authentication

Directory Lister does not include any form of authentication out of the box. This is intentional to keep the application focused and easier to maintain. However, there are ways to use external authentication with Directory Lister. The following are some known methods of adding authentication to your application.

## HTTP Basic Authentication

Modern web servers have the ability to restrict access to a directory via a `.htpasswd` file. The way this is configured varies based on the web server in use so you will need to reference the documentation for your web server.

### Apache

* [`mod_auth_basic` documentation](https://httpd.apache.org/docs/2.4/mod/mod_auth_basic.html)
* [`.htpasswd` documentation](https://httpd.apache.org/docs/current/programs/htpasswd.html)&#x20;

### NGINX

* [Basic Authentication documentation](https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/)

## Authelia Proxy Authorization

[Authelia](https://www.authelia.com/), the open-source authentication and authorization server, may be used to add authorization to an instance of Directory Lister behind a reverse proxy.

* [Proxy Authorization documentation](https://www.authelia.com/reference/guides/proxy-authorization/)
* [NGINX integration documentation](https://www.authelia.com/reference/guides/proxy-authorization/)


# Troubleshooting

1. Ensure you have met the minimum [requirements](/installation#requirements) for running Directory Lister
2. Check the [Common Issues](/help-and-support/common-issues) page for a list of common issues and help in solving them
3. Many problems can be solved by clearing the application cache (`rm -rf app/cache/*`)
4. Enable [`debug`](/configuration/configuration-reference#debug) and use [Google](https://www.google.com) to search for any errors shown
5. If you continue having issues start a new discussion on our [Help & Support](https://github.com/DirectoryLister/DirectoryLister/discussions/categories/help-support) board

Please report bugs to the [GitHub Issue Tracker](https://github.com/DirectoryLister/DirectoryLister/issues).


# Common Issues

The following are common issues and some information on why these occur and how to solve them.

## `open_basedir restriction in effect`

### Symptoms

You may see an error like the following:

```
PHP Fatal error:  Uncaught RuntimeException: SplFileInfo::isFile(): open_basedir restriction in effect.
```

### Explanation

Directory Lister has security restrictions in place to to mitigate [directory traversal attacks](https://owasp.org/www-community/attacks/Path_Traversal). Specifically, the [`open_basedir`](https://www.php.net/manual/en/ini.core.php#ini.open-basedir) directive is set to the application root directory. Thus, any attempt to access files outside of the application root will be denied and cause an error similar to the one above. This applies to symbolic links pointing to files outside of the application root as well.

## Configuration changes don't take affect when changed

### Symptoms

Configuration changes made in the `.env` file aren't reflected in your application.

### Explanation

This was an issue with the v3.4.0 release. The issue was promptly resolved with the v3.4.1 bug fix, however, the bug could persist through upgrades if the application cache wasn't cleared. To resolve this issue, first ensure you're running v3.4.1 or later then clear your application cache as per the [Upgrade Guide](/upgrade-guide).

```
rm -rf app/cache/*
```

## `Class 'DOMDocument' not found`

### Symptoms

You may see an error like the following:

```
Fatal error: Uncaught Error: Class 'DOMDocument' not found
```

### Explanation

This error occurs when you're server is missing the PHP [DOM extension](https://www.php.net/en/dom). This extension is required for rendering README files on the page. You will need to install that extension.

#### Ubuntu / Debian

```
sudo apt install php-dom
```

#### Fedora / Redhat

```
sudo yum install php-xml
```

Alternatively you can disable READMEs by setting [`DISPLAY_READMES`](/configuration/configuration-reference#display_readmes) to `false` in your `.env` file.

## `Call to undefined function mime_content_type()`

### Symptoms

You may see an error like the following:

```
Fatal error: Uncaught Error: Call to undefined function mime_content_type()
```

### Explanation

This error occurs when you're server is missing the PHP [fileinfo](https://www.php.net/manual/en/book.fileinfo.php) extension. This extension is required for rendering README files on the page. You will need to install that extension.

#### Ubuntu / Debian

```
sudo apt install php-mime-type
```

#### Fedora / Redhat

```
???
```

Alternatively you can disable READMEs by setting [`DISPLAY_READMES`](/configuration/configuration-reference#display_readmes) to `false` in your `.env` file.


# Development Environment

## Requirements

* [PHP](https://php.net) >= 8.2 with the `zip`, `dom` and `fileinfo` (and optionally `apcu`, `memcached`, `redis`) extensions&#x20;
  * [Composer](https://getcomposer.org) for PHP dependency management
* [NPM](https://www.npmjs.com) for front end asset serving and bundling
* [Docker](https://www.docker.com) and [Docker Compose](https://docs.docker.com/compose/) for running the local development container
* [Git](https://git-scm.com/) for version control

## Instructions

{% hint style="info" %}
These instructions are for setting up a local DEVELOPMENT environment. If you are looking for basic installation instruction see the [Installation](/installation) page instead.
{% endhint %}

1. [Fork the Directory Lister repository to your own account](https://github.com/DirectoryLister/DirectoryLister/fork) (optional)
2. [Clone Directory Lister to a local repository](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository)

   ```
   git clone {{ REPOSITORY_URL }}
   ```
3. Switch to the Directory Lister directory

   ```
   cd /path/to/DirectoryLister
   ```
4. Install and build PHP and JavaScript dependencies

   ```
   composer install
   npm install
   npm run dev
   ```
5. Run the local Docker container

   ```
   docker-compose up -d
   ```
6. Add a host name entry to `/etc/hosts` (optional)

   ```
   127.0.0.1  directory-lister.local
   ```

You should now be able to access your local Directory Lister installation at `http://localhost` (or <http://directory-lister.local> if you added a host name entry)

## Common Development Commands

Many common development actions have been defined in the `Makefile` and can be run with `make` command.

### Clear the application cache

{% tabs %}
{% tab title="Make" %}

```sh
make clear-cache
```

{% endtab %}

{% tab title="Manual" %}

```sh
rm --recursive --force app/cache/*
```

{% endtab %}
{% endtabs %}

### Build dependencies and assets (for production)

{% tabs %}
{% tab title="Make" %}

```sh
make production
```

{% endtab %}

{% tab title="Manual" %}

```sh
composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader
npm install --no-save
npm run build
npm prune --production
```

{% endtab %}
{% endtabs %}

### Clear built assets

{% tabs %}
{% tab title="Make" %}

```sh
make clear-assets
```

{% endtab %}

{% tab title="Manual" %}

```sh
rm --recursive --force app/assets/*
```

{% endtab %}
{% endtabs %}

### Run test suite

{% tabs %}
{% tab title="Make" %}

```sh
make tests
```

{% endtab %}

{% tab title="Composer" %}

```sh
composer exec phpunit
```

{% endtab %}

{% tab title="Manual" %}

```sh
app/vendor/bin/phpunit
```

{% endtab %}
{% endtabs %}

### Check or fix coding standards

{% tabs %}
{% tab title="Make" %}

```sh
make coding-standards
```

{% hint style="info" %}
This will apply coding standard fixes will be automatically.\
\
See the Compor or Manual tab to report coding standard problems *without* modifying files.
{% endhint %}
{% endtab %}

{% tab title="Composer" %}

```sh
composer exec php-cs-fixer fix [--diff] [--dry-run]
```

{% hint style="info" %}
If no flags are present, coding standard fixes will be automatically applied.\
\
To report coding standard problems *without* modifying files use the `--dry-run` flag.\
\
Additionally, to display a diff of the fixes that would be applied, use the `--diff` flag as well.
{% endhint %}
{% endtab %}

{% tab title="Manual" %}

```sh
app/vendor/bin/php-cs-fixer fix [--diff] [--dry-run]
```

{% hint style="info" %}
If no flags are present, coding standard fixes will be automatically applied.\
\
To report coding standard problems *without* modifying files use the `--dry-run` flag.\
\
Additionally, to display a diff of the fixes that would be applied, use the `--diff` flag as well.
{% endhint %}
{% endtab %}
{% endtabs %}

### Perform static analysis

{% tabs %}
{% tab title="Make" %}

```sh
make static-analysis
```

{% endtab %}

{% tab title="Composer" %}

```sh
composer exec phpstan analyze
```

{% endtab %}

{% tab title="Manual" %}

```sh
app/vendor/bin/phpstan analyze
```

{% endtab %}
{% endtabs %}

### Generate code coverage report

{% tabs %}
{% tab title="First Tab" %}

```sh
make coverage
```

{% endtab %}

{% tab title="Composer" %}

```sh
XDEBUG_MODE=coverage composer exec phpunit --coverage-html .coverage
```

{% endtab %}

{% tab title="Untitled" %}

```sh
XDEBUG_MODE=coverage app/vendor/bin/phpunit --coverage-html .coverage
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Code coverage requires a code coverage engine (e.g. xdebug pr pcov) to run.
{% endhint %}


