Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/php/build
/tools/composer.lock
/tools/vendor
/docs/agent-proposal/
24 changes: 18 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,20 @@ Source for the prebuilt Docker images `jakubboucek/lamp-devstack-php` and `jakub

The project is maintained primarily to serve the maintainer's own development workflow and is published because others found it useful. Its feature set is intentionally opinionated: components and extensions are included only when the maintainer actually needs them, and deliberately omitted otherwise. Any apparent imbalance in the package scope is a design choice, not an oversight. Suggestions and critical feedback on the scope are welcome — but never add new components or extensions on your own initiative; always consult the maintainer first.

## Documentation

Keep tracked documentation focused on the current project and configuration formats.
Store implementation plans, investigation notes and measurement snapshots in the
ignored `docs/agent-proposal/` directory. Record one-off validation results in commit
messages or PR descriptions. The extension inventory declaration format is described
in [docs/extension-inventory.md](docs/extension-inventory.md).

## Build commands

All build scripts follow the same four-phase pattern (pull → build → test → push), each phase skippable via ENV flags: `NO_PULL=1`, `NO_BUILD=1`, `NO_TEST=1`, `NO_PUSH=1`, `NO_ASSETS=1`.

```bash
./build-php.sh # build all current PHP versions (8.2–8.5, apache + cli variants)
./build-php.sh # build all current PHP versions (8.2–8.5 + 8.6 RC, apache + cli variants)
./php/build-php-8.5.sh # build a single PHP version (apache + debug variants)
./php/build-php-8.5-cli.sh # build a single CLI variant
./php/legacy/build-php-legacy.sh # legacy PHP versions (many disabled — Debian repos shut down)
Expand All @@ -27,14 +35,17 @@ Common examples: `NO_PUSH=1 ./build-php.sh` (local build only), `NO_PULL=1 NO_BU
## Tests

```bash
./test-php.sh # run test suite inside every current PHP image (8.2–8.5, apache + cli)
./test-php.sh # test every tag listed at the top of the script (base, cli, debug)
./test-php.sh 8.6-rc-debug # test a single tag
```

Tests live in `tools/tests/` (Nette Tester, one `*Test.php` per PHP extension in `tools/tests/Extensions/`). To run in a single image:
Prepare dependencies with `composer -d tools install` before running tests or build
checks. Build scripts run the same suite before pushing, unless `NO_TEST=1`.

```bash
docker run --rm -it -v "$(pwd)":/app -w /app jakubboucek/lamp-devstack-php:8.5 composer -d tools/ test
```
Tests live in `tools/tests/` (Nette Tester, one `*Test.php` per PHP extension in
`tools/tests/Extensions/`). The script passes the full image reference through
`IMAGE_NAME`, runs without an interactive terminal, and returns a nonzero status
if any container fails while continuing through the remaining tags.

`tools/compute-minimal-ext-deps.php` is a build helper: run inside an image to compute the minimal runtime package list (`apt-mark` command) that replaces `-dev` packages in Dockerfiles — use it when changing extension deps.

Expand All @@ -58,6 +69,7 @@ docker run --rm -it -v "$(pwd)":/app -w /app jakubboucek/lamp-devstack-php:8.5 c
- PHP: the `-rc` suffix is hard-coded in the script, combined with the pre-release label (e.g. alpha/RC name) which can be read programmatically from the PHP binary itself.
- MariaDB: RC builds have no additional sub-versions. Based on upstream's observed release mechanism, when a release channel goes stable the patch version is bumped to `2` and the `-rc` suffix is dropped.
- During a PHP RC phase, components without upstream support for the new version (typically Xdebug → the `-debug` variant, PIE, individual extensions) are temporarily left out or commented in the Dockerfiles. They are re-enabled as soon as a *functional* upstream version exists — a working dev/beta/dev-master is enough, don't wait for a final release. Track the remaining work in a GitHub issue cross-linked with the version's PR.
- For PHP 8.6 build prerequisites, see [build-notes.md](build-notes.md#php-86-rc); the RC-to-stable checklist is maintained in [#100](https://github.com/jakubboucek/docker-lamp-devstack/issues/100).
- All images are `linux/amd64` only. Building for ARM would require hardware the maintainer doesn't have (and renting a VPS for it is not planned); this will change only if the maintainer's own environment moves to ARM.

## Defaults baked into images
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ of base images designed to cover most standard development workflows — with no
- unsupported versions of **MariaDB** 12.2, 12.1, 12.0, 11.7, 11.6, 11.5, 11.3, 11.2, 11.1, 11.0, 10.10, 10.9, 10.8, 10.7,
10.5, 10.4 and 10.3 (unmaintained)
- current version of **Apache** 2.4 (in non-CLI images)
- current version of **Xdebug** 3.5 (in debug images)
- **Xdebug** 3.5 in stable debug images; 3.6 alpha in PHP 8.6 RC debug images
- current version of [**SPX Profiler**](https://github.com/NoiseByNorthwest/php-spx) (in debug images)
- extra PHP extensions:
[`bmath`](https://www.php.net/manual/en/book.bc.php),
Expand Down Expand Up @@ -161,9 +161,10 @@ All PHP images also have alternative CLI variants, use `-cli` tag suffix, exampl
The pre-release of PHP 8.6 images have the `-rc` suffix, example:
- `jakubboucek/lamp-devstack-php:8.6-rc`
- `jakubboucek/lamp-devstack-php:8.6-rc-cli`
- `jakubboucek/lamp-devstack-php:8.6-rc-debug`

> Note: The 8.6 pre-release images don't contain the `memcached` extension yet and have no `-debug` variant —
> upstream support (PIE, Xdebug) for PHP 8.6 is not available yet.
> The 8.6 pre-release images include `memcached` from its development branch, installed with PIE 1.5 or newer.
> The `-debug` variant includes Xdebug 3.6 alpha and SPX from its `v0.5` development branch.

### Using MariaDB
MariaDB server starts at the same time as the web server.
Expand Down
9 changes: 9 additions & 0 deletions build-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ To build only specific PHP version run only the target script on [`php` folder](

To build older PHP versions run [`php/legacy/build-php-legacy.sh`](php/legacy/build-php-legacy.sh).

### PHP 8.6 RC

PHP 8.6 builds require PIE 1.5 or newer. When reusing assets with `NO_PULL=1`,
run `./prepare-assets.sh` first if the cached `php/build/pie.phar` is older.
Build the Apache image before debug; the debug Dockerfile uses the bundled frontend
and the locally built base. Package selectors and SPX compatibility flags are defined
and explained in the Dockerfiles. The [stable-transition checklist](https://github.com/jakubboucek/docker-lamp-devstack/issues/100)
is maintained in #100.

## MariaDB
Run [`build-mariadb.sh`](build-mariadb.sh) script to build all of MariaDB versions.

Expand Down
220 changes: 220 additions & 0 deletions docs/extension-inventory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
# Extension inventory declaration

`tools/tests/expected-extensions.neon` declares the expected PHP extensions for each
image profile. `tools/tests/ExtensionsTest.php` checks this declaration as part of
Nette Tester. Current build scripts invoke the suite before publishing images.

Prepare tooling with `composer -d tools install`, then use `./test-php.sh` or
`./test-php.sh 8.6-rc-debug`. Dependencies are installed on the host and mounted
read-only into containers; they are not added to published images. Composer resolves
for PHP 8.1 via `config.platform.php`. NEON 3.4.8 is pinned: its declared upper bound
is 8.5, but its runtime behavior has also been verified for this project on PHP 8.6.

The runner passes `IMAGE_NAME` with the full image reference. The test reads the
actual PHP version, derives base/CLI/debug from the tag, and checks that numeric tags
match the runtime major/minor and pre-release status. Numeric tags may include patch
versions and RC release labels; aliases `latest`, `debug`, `cli`, and major tags such
as `8-cli` also work. Exact exceptions use the canonical minor profile (e.g.
`8.6-rc-debug`), independent of the patch tag used to launch the container.

Every pre-release runtime (alpha, beta, RC or dev) receives the `rc` flag. Unknown
future PHP versions use the same rules without registration; unrecognized tag
suffixes and missing image identity are errors. The functional extension tests retain
their skips, but the inventory test never skips missing extensions.

## Structure

- `common`: extensions expected in every supported profile.
- `rules`: a list of conditions (`when`) and extension lists to `add` or `remove`.
All matching rules apply. Conflicting additions/removals between matching rules are
errors; rule order does not resolve conflicts.
- `exceptions`: a map keyed by exact profile, applied after ordinary rules. Each entry
has `add` and/or `remove`, a `reason`, and a human-readable `removeWhen` note for retiring it.
Use `{}` when no exceptions are needed. Quote numeric-looking keys such as `'8.5'`.

Extension names are compared case-insensitively (`SPX` becomes `spx`, `Zend OPcache`
becomes `zend opcache`). Missing and unexpected extensions both fail the check;
`remove` means the extension must be absent, not optional.

## Conditions

A plain condition list means AND. Explicit `all` (AND) and `any` (OR) accept lists
of conditions and may be nested. For example, PHP 8.6 or later with debug or CLI:

```neon
when:
- '>=8.6'
- any: [+debug, +cli]
```

PHP 8.6 or later in any non-CLI variant:

```neon
when:
- '>=8.6'
- -cli
```

Version operators are `=`, `!=`, `>`, `>=`, `<`, and `<=`. They compare PHP minor
series: `=8.4` includes every 8.4.x, `>8.4` starts at 8.5, and `<8` means below 8.0.
Pre-release status is a flag and does not affect numeric version comparisons.

`+flag` requires a flag; `-flag` excludes it. Flags are `debug`, `cli`, `rc`, and
synthetic `base` (neither debug nor CLI):

| Profile | Flags |
| --- | --- |
| `8.5` | base |
| `8.5-debug` | debug |
| `8.5-cli` | cli |
| `8.6-rc` | base, rc |
| `8.6-rc-debug` | debug, rc |

Thus `-debug` also matches CLI, while `+base` includes RC base images. Unknown flags
and unsupported combinations such as CLI plus debug are errors.

Unquoted conditions are allowed when NEON parses them as strings. Operators containing
`=` require quotes because NEON otherwise interprets them as mappings or syntax errors.
Validate recursively: accept string leaves, nonempty lists with consecutive integer
keys starting at zero, and maps containing exactly one `all` or `any` key with a
nonempty condition list. Reject other maps, non-string leaves and empty logical nodes.
Never reconstruct a comparator from a parsed mapping: numeric conversion may have
already changed a version such as `8.10` to `8.1`.

The configuration validator checks every rule, including inactive rules, and rejects
unknown fields, duplicate extension names and malformed exception entries. String
conditions also work directly in `when`. An exception cannot resolve a conflict between
ordinary matching rules: fix the conflicting rules first.

A failure reports the runtime PHP version, canonical profile and sorted missing and
unexpected modules. Build scripts honor `NO_TEST=1` as an explicit bypass; otherwise
a failing suite prevents that build script from reaching its push phase. This does
not make a multi-version release atomic. The suite inspects CLI-loaded modules in
each image; HTTP/Apache behavior remains a separate concern.

## Exceptions

An exception targets one canonical minor profile, including its variant and release
status. It has no `when`: the map key selects the profile. For example,
`8.6-rc-debug` matches all patch tags for that RC debug profile, but not `8.6-rc`,
`8.6-rc-cli`, or stable `8.6-debug`. A quoted key `'8.5'` targets only the stable
8.5 base variant. Wildcards and version expressions are not supported as keys.

Each exception needs at least one of `add` or `remove`, plus two nonempty strings:

- `reason` explains why the normal expectations do not apply.
- `removeWhen` tells the maintainer when to delete the exception. It is **human-readable
documentation**, not an evaluated condition, date, or automatic expiration mechanism.
Even a string such as `'>=8.7'` would only be text here. Delete the entry manually
once its stated condition is satisfied.

The following complete miniature configuration is illustrative; it does not describe
an actual missing extension in our current images:

```neon
exceptions:
8.6-rc-debug:
remove: [spx]
reason: The profiler cannot currently be built for this RC.
removeWhen: Delete after a compatible profiler is installed and verified.

rules:
- when: +debug
add: [xdebug, spx]

common: [core, json]
```

The debug rule first adds both profilers. For `8.6-rc-debug`, the exception then
removes `spx`: the final expected set is `core`, `json`, `xdebug`. A loaded `spx`
would fail as unexpected, reminding the maintainer to retire the exception after
restoring it. Other debug profiles still require both profilers.

Exceptions apply last even when their section appears first in the file. An `add`
can restore an extension removed by an ordinary rule; a `remove` can exclude one
from `common` or a matching rule. A single exception cannot both add and remove the
same extension. Conflicting ordinary rules fail before exceptions are applied.
Use `exceptions: []` or `exceptions: {}` when there are no exceptions; both decode
to an empty PHP array.

## Examples

These independent snippets illustrate the rule language, not changes to the current
extension policy. When trying a snippet on its own, supply any omitted top-level
sections (`common`, `rules`, `exceptions`) with empty lists/maps.

### Version range, alternative variants, and stable releases only

```neon
rules:
- when:
- '>=8.4'
- '<8.7'
- -rc
- any: [+debug, +cli]
add: [intl]
```

Every outer list item must match. This adds `intl` for stable PHP 8.4, 8.5 and 8.6
in either debug or CLI variants. It excludes base variants, every pre-release,
PHP 8.3 and PHP 8.7+. All patch versions of each matching minor series are included.

### Alternatives with their own combined conditions

```neon
rules:
- when:
any:
- all: ['>=8.6', +debug]
- all: ['=8.4', +cli, -rc]
add: [sockets]
```

This adds `sockets` if either branch matches: debug PHP 8.6 or later (including RC),
or stable CLI PHP 8.4. It does not match CLI PHP 8.6 or debug PHP 8.5. Each inner
`all` applies only to its own branch; the second branch's `-rc` does not restrict
the first branch.

### Removing a common extension, then restoring it for one exact profile

```neon
exceptions:
8.6-rc:
add: [intl]
reason: This specific RC base profile retains intl for compatibility.
removeWhen: Delete when this profile adopts the general base-image policy.

rules:
- when: ['>=8.6', +base]
remove: [intl]

common: [core, intl]
```

The rule removes `intl` from base PHP 8.6 and later, both stable and RC. The exception
restores it only for `8.6-rc`. Consequently, stable `8.6` and `8.7-rc` require only
`core`, while `8.6-rc` requires both extensions. CLI and debug variants also retain
both because they never match `+base`. Removing an expectation does not make the
extension optional: it must be absent unless subsequently restored by the exception.

### Accumulating matching rules without relying on their order

```neon
rules:
- when: +debug
add: [xdebug, spx]
- when: ['>=8.5']
add: [lexbor, uri]
- when: ['>=8.6', -cli, '!=8.7']
add: [intl]
```

For `8.6-rc-debug`, all three rules match and their additions are combined with
`common`. For `8.7-debug`, only the first two match. For `8.8-cli`, only the second
matches; `-cli` excludes it from the third. For base `8.8`, the second and third
match. None of these rules excludes RC unless `-rc` is explicitly present.

Repeated additions across matching rules are combined into one expected extension.
However, adding `remove: [spx]` to the third rule would create a conflict for
`8.6-rc-debug`, because the first rule adds `spx`. Moving either rule earlier or later
would not resolve it; use non-overlapping conditions or a justified exact exception.
8 changes: 4 additions & 4 deletions php/Dockerfile-8.6
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ ARG EXTENSION_DEV_DEPS=" \
libgmp-dev \
libicu-dev \
libjpeg62-turbo-dev \
# libmemcached-dev \
libonig-dev \
libmemcached-dev \
libpng-dev \
libsodium-dev \
libssl-dev \
Expand All @@ -50,8 +50,8 @@ ARG EXTENSION_RUNTIME_DEPS=" \
libicu76 \
libjpeg62-turbo \
liblzma5 \
# libmemcached11t64 \
libonig5 \
libmemcached11t64 \
libpng16-16t64 \
librav1e0.7 \
libsharpyuv0 \
Expand All @@ -69,6 +69,7 @@ ARG EXTENSION_RUNTIME_DEPS=" \
zlib1g \
"

# PHP 8.6 API compatibility fixes are currently available in memcached dev-master only.
# OS binaries install && update critical binaries
RUN set -eux; \
apt-get update; \
Expand Down Expand Up @@ -104,8 +105,7 @@ RUN set -eux; \
sysvshm \
xsl \
zip; \
# Memcached disabled: PIE does not support PHP 8.6 yet (requires PHP <= 8.5)
# pie install php-memcached/php-memcached; \
pie install php-memcached/php-memcached:dev-master; \
a2enmod \
expires \
headers \
Expand Down
8 changes: 4 additions & 4 deletions php/Dockerfile-8.6-cli
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ ARG EXTENSION_DEV_DEPS=" \
libgmp-dev \
libicu-dev \
libjpeg62-turbo-dev \
# libmemcached-dev \
libonig-dev \
libmemcached-dev \
libpng-dev \
libsodium-dev \
libssl-dev \
Expand All @@ -50,8 +50,8 @@ ARG EXTENSION_RUNTIME_DEPS=" \
libicu76 \
libjpeg62-turbo \
liblzma5 \
# libmemcached11t64 \
libonig5 \
libmemcached11t64 \
libpng16-16t64 \
librav1e0.7 \
libsharpyuv0 \
Expand All @@ -69,6 +69,7 @@ ARG EXTENSION_RUNTIME_DEPS=" \
zlib1g \
"

# PHP 8.6 API compatibility fixes are currently available in memcached dev-master only.
# OS binaries install && update critical binaries
RUN set -eux; \
apt-get update; \
Expand Down Expand Up @@ -104,8 +105,7 @@ RUN set -eux; \
sysvshm \
xsl \
zip; \
# Memcached disabled: PIE does not support PHP 8.6 yet (requires PHP <= 8.5)
# pie install php-memcached/php-memcached; \
pie install php-memcached/php-memcached:dev-master; \
apt-mark manual ${EXTENSION_RUNTIME_DEPS}; \
apt-get purge -y --auto-remove ${EXTENSION_DEV_DEPS}; \
apt-get clean -y && \
Expand Down
Loading