Repository navigation
Conversation
Opcache is always compiled into PHP 8.5, so docker-php-ext-install opcache fails (cp: cannot stat 'modules/*'). The ;-chained RUN hid the failure, and the image still loads Zend OPcache, so dropping the step changes nothing in the image.
curl -O without -f saved an HTTP error page as wp-cli.phar, so a failed download produced an image with a broken wp.
The pecl install steps were chained with ;, so when pecl.php.net was down a build still succeeded, just without memcached, redis, apcu and the rest, and PHP then warned about the missing libraries on every start. For the 8.1 to 8.5 images (the ones CI builds and publishes): - Install imagick, memcached, redis, apcu, mcrypt and timezonedb with PIE 1.5.2 (checked against its SHA-256) from Packagist/GitHub. Versions are pinned to what the current images ship; timezonedb stays unpinned because it only exists to ship newer tz data than PHP bundles. The resolved commits are printed to the build log. - Build imap (8.4, 8.5) and gmagick (8.1 to 8.4), which aren't on Packagist, from SHA-256-pinned GitHub tarballs of their pecl releases. - Run the extension step under set -eu so any failing step fails the build. - Add a final check that fails the build on PHP startup warnings or errors, a failing php-fpm -t, wp or composer, or a module missing from the expected list. - 8.3 and 8.5 now get the imagick 3.8.1 release instead of an unversioned git master build. Extensions are still enabled with docker-php-ext-enable and the existing ini lines, so conf.d is unchanged.
The PHP Dockerfiles read an optional github_token BuildKit secret and hand it to PIE, so its GitHub downloads are authenticated instead of anonymous.
There was a problem hiding this comment.
🟢 Approval recommended
No unresolved issues were identified, and the linked verification workflow completed successfully.
No open issues 🎉
What changed in this PR
This PR moves the five CI-published PHP images off PECL and adds build-time checks to prevent publishing images with missing extensions or broken tooling.
Changes:
- Uses checksum-verified PIE and source archives, pins most extension versions, and makes installation failures fatal.
- Adds checks for PHP startup diagnostics, expected modules, PHP-FPM configuration, WP-CLI, and Composer, then removes logs created by validation.
- Passes the GitHub token through BuildKit secrets for extension downloads.
| File | Description |
|---|---|
php/8.5/Dockerfile |
Migrates extensions, removes the shared OPcache build, and adds validation. |
php/8.4/Dockerfile |
Migrates extensions, builds IMAP and gmagick from verified sources, and adds validation. |
php/8.3/Dockerfile |
Replaces Imagick master with a pinned release, migrates other extensions, and adds validation. |
php/8.2/Dockerfile |
Migrates extensions to PIE and verified sources and adds validation. |
php/8.1/Dockerfile |
Migrates extensions to PIE and verified sources and adds validation. |
.github/workflows/test_and_publish.yml |
Supplies the optional BuildKit secret to both PHP build steps. |
Review effort: Balanced
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Install the PECL extensions of the PHP 8.1, 8.2, 8.3, 8.4 and 8.5 images (the ones CI builds and publishes) with PIE, the PHP Foundation's replacement for
pecl, and make the build fail when any extension doesn't install or load, when php-fpm's config is broken, or whenwp/composerdon't run. The workflow now passes the job'sGITHUB_TOKENto these builds as a BuildKit secret.This PR edits
.github/workflows/test_and_publish.yml(twosecrets:lines on the PHP build steps, last commit). Nothing else in CI changes.Why
pecl installsteps are chained with;, so a build during the outage still "succeeds", just without memcached, redis, apcu and the rest, and PHP then logsUnable to load dynamic libraryon every start. CI only builds the images, so a tag run during such an outage would publish broken images.Imagick/imagickmaster, with no version (php --ri imagickreports@PACKAGE_VERSION@). They now get the same 3.8.1 release as the other versions.Commits
fix(php): stop installing opcache as a shared extension on 8.5. Opcache is always compiled into PHP 8.5, sodocker-php-ext-install opcachehas failed in every 8.5 build (cp: cannot stat 'modules/*'); the;chain hid it. Zend OPcache is still loaded, and the current 8.5 image has nodocker-php-ext-opcache.inieither, so the image doesn't change. This comes first because the next commits make that failure fatal.fix(php): fail the build when the wp-cli download fails.curl -Owithout-fsaved an HTTP error page aswp-cli.phar; nowcurl -fsSLo /usr/local/bin/wp.build(php): install extensions with PIE and fail the build on errors. The main change, described below.ci: pass the GitHub token to the PHP image builds. Addssecrets: github_token=${{ secrets.GITHUB_TOKEN }}to both PHPdocker/build-push-actionsteps (PR build and tag build).Each commit builds on its own.
What changed
Same structure in all five Dockerfiles:
RUNstarts withset -eu, so every step in it (PIE, the source builds,docker-php-ext-install,apt-get purge) fails the build instead of being skipped./root/.pieand its Composer cache) in the same layer.pecl install timezonedbdid.PIE installed phpredis/phpredis 6.3.0 <sha>), so every build records what went into it.--skip-enable-extension. Extensions are enabled exactly as before, withdocker-php-ext-enableand the existingmemcached.ini/gmagick.ini/imap.inilines.conf.dis byte-identical to the current images, so anything relying on those file names keeps working.php/pecl-mail-imaptag 1.0.3 (with Kerberos and SSL, as the pecl prompts were answered) andvitoc/gmagickat the commit 2.0.6RC1 was released from (the repo has no tags). Both tarballs are checked against a SHA-256, and their source files are identical to the pecl.tgzreleases.RUNnear the end fails the build, with aBuild check failed: …line explaining why, when:php -v/php -mprint any startup warning, error or notice (for exampleUnable to load dynamic library);php-fpm -tfails;wp --allow-root --versionorcomposer --versionfails;php -m, on purpose: it also catches PHP dropping a module from core (as imap left core in 8.4), not only a failed extension install.Deprecated: the images'php.inimasksE_DEPRECATED, and 8.4/8.5 already emit two masked startup deprecations (session.sid_length,session.sid_bits_per_character).php-fpm -tcreates/var/log/php/access.loganderror.log, and on 8.1 to 8.4 the New Relic agent creates/var/log/newrelic/php_agent.log, all owned by root. The check deletes them in the sameRUN: left in the image, the root-ownederror.logwould stop php-fpm from starting as www-data./var/log/phpand/var/log/newrelicstay empty, as in the current images.GITHUB_TOKENas the optionalgithub_tokenBuildKit secret, and the Dockerfile turns it intoCOMPOSER_AUTHfor PIE beforeset -x, so it is never traced or written to a layer. Without the secret (a localdocker build), PIE downloads anonymously, which also works.Per version:
RUNRUN,docker-php-ext-install opcacheVerification
secrets: github_token=${{ secrets.GITHUB_TOKEN }}, plusload, no push) for 8.1 to 8.5, then a comparison of each new image with the publishedeasyengine/php8.X:v4.13.3(8.1 also with v4.13.0, which core pins). For every versionphp -m, the fullconf.dcontents (file names and bodies) and the/var/log/phpand/var/log/newreliclistings are identical,php -vshows no startup warnings, andphp-fpm -tpasses as www-data. Extension versions are identical apart from imagick on 8.3/8.5 (@PACKAGE_VERSION@→3.8.1); 8.1 vs v4.13.0 additionally differs only in newrelic (12.11 → 12.12) and timezonedb (2026.4 → 2026.5), both newer. A separate job in the same run proves thesecrets:input reachesRUN --mount=type=secret,id=github_token. Each build log lists the PIE-installed commits, e.g.PIE installed phpredis/phpredis 6.3.0 df4fab2de7fc327c54c94a13af2b9542e4fbd720.php-fpm -tas root, which created a root-owned/var/log/php/error.logthat then stopped php-fpm from starting as www-data. The check now deletes the logs it creates (see above).--pull --no-cachebuilds of all five versions with the image smoke test (php -v/php-fpm -v= theFROMversion,php-fpm -t, php-fpm serving the ping and a PHP page through nginx, FPM loads the same extensions as the CLI,php -mequal to v4.13.3,wp/composerwork): PASS for 8.1, 8.2, 8.3, 8.4 and 8.5.php --riof imagick, gmagick, imap, memcached, redis, apcu, mcrypt and timezonedb is identical (configure options such as imap Kerberos/SSL and memcached SASL/session match) apart from apcu's build date and the imagick version on 8.3/8.5; the installed Debian package list is identical (8.3/8.5: only the leftovergitentry is gone); in the compared trees (/usr/local/bin, the extension directory,/usr/local/etcand/tmp) the only file difference is that pecl's/tmp/pearcache is gone.Build check failed: PHP printed these startup warnings or errors:followed by theUnable to load dynamic libraryline; removing an enabled extension's ini fails it withBuild check failed: PHP module redis is missing; a broken php-fpm pool config fails it atphp-fpm -t; apie installof a version that doesn't exist fails the extensionRUN(Could not install package: phpredis/phpredis).Deviations from the current (v4.13.3) images
@PACKAGE_VERSION@) to the 3.8.1 release. Master is 4 commits ahead of 3.8.1, so these two images lose: a memory leak fix inImagick::polynomialImage()(Fix memory leak in polynomialImage() Imagick/imagick#790), error propagation fromMagickEvaluateImages()(#792) andDrawSetStrokeDashArray()(#784), and a build fix for PHP 8.6 (#795). #795 only matters for PHP 8.6; the leak and the two swallowed errors come back on 8.3/8.5 until imagick tags a release with those fixes. A pinned release is still preferable to an unversioned master build that changes on every rebuild./tmp/peardownload cache is no longer left in the images, and 8.3/8.5 lose the leftovergitdpkg entry (removed package, config only).pecl listinside a container no longer lists the extensions, since pecl didn't install them.What stays on pecl, and why
php/5.6,7.0,7.2,7.3,7.4,8.0andphp/stablestill usepecl install. CI doesn't build them (they aren't in thephpmatrix), so their published images don't change, and PIE needs PHP 8.1 or later anyway.Risks and rollback
FROMlines, so new imagick/memcached/redis/apcu/mcrypt releases need a manual bump (previously every build took whatever pecl served). mcrypt 1.0.9 declares PHP ≤ 8.6.0, so a future 8.6 image will need a newer mcrypt; PIE enforces that and fails loudly./archive/tarballs (imap, gmagick) have changed bytes before. If that happens, the SHA-256 check fails the build and the pin needs updating; it can't produce a different image silently.The following build tools are missing: libtoolizeon every install. It's harmless (phpize ships its own libtool scripts, and all extensions build and load);libtoolisn't installed to keep the image contents unchanged.RUN --mount=type=secretline needs BuildKit, which CI (buildx) and Docker 23+ use by default; only a build forced onto the legacy builder (DOCKER_BUILDKIT=0) fails.Could not authenticate against github.com; removing the twosecrets:lines brings back anonymous downloads, which work too.pecl installsteps. Already published tags are unaffected.