
Free script · MIT · reads files only
Find everyPHP versionyour repos pin
One run lists where your repositories set a PHP version, from Dockerfiles and compose files to CI and composer.json, and what PHP2Shell means for each. It runs on your machine and sends nothing anywhere.
PHP2Shell data as of 23 Oct 2026
Run it
01
Download it
curl -fsSLO https://arvion.ai/tools/php-pins.sh02
Read it
It's one file of shell and awk, MIT licensed. Open it in your browser to read it before you run it. Its source, tests and issues are on GitHub.
03
Check the download
- macOS
shasum -a 256 php-pins.sh- Linux
sha256sum php-pins.sh
It should print:
7f5489c507720d5fbd29cfdddc7dfdaedaa476718e5952a4d14725a10138e800
04
Run it on your repositories
sh php-pins.sh ~/code/shop ~/code/apiEvery repository in a folder at once:
sh php-pins.sh ~/code/*/
What it prints
Each pin gets one line: what to do, where it is, what it says, and why. The worst come first. These rows are from a run on a test repository with 29 pins.
$ sh php-pins.sh shop
shop
EOL Dockerfile:3 php:8.1-fpm-alpine PHP 8.1 is past end of life and gets no official fix. This tag is no longer rebuilt. Move to 8.2 or newer.
UPDATE docker/Dockerfile.prod:1 php:8.3.35-apache Pinned below the fix. Change to 8.3.36 or newer.
UPDATE compose.yaml:7 php:8.4-fpm@sha256:... Pinned by digest, so it never changes. Re-pin to a build from after 21 Oct 2026.
REBUILD compose.yaml:3 wordpress:php8.3-apache This tag has carried PHP 8.3.36 since 21 Oct 2026. Pull and rebuild.
CHECK .github/workflows/ci.yml:8 php-version 8.3 The runner may have an older PHP 8.3. Print php -v in the job; 8.3.36 has the fix.
OK .php-version:1 8.4.27 Has the fix (8.4.27 or newer).
NOTE composer.json:5 require php ^7.4 || ^8.0 The code still declares support for PHP 7.4, which is past end of life.
- EOL
- The branch is past end of life and gets no official fix. Move to a supported branch.
- UPDATE
- Pinned to a version, digest, OS variant or WordPress release that doesn't have the fix. Change the pin.
- REBUILD
- The tag already carries the fixed PHP. Pull and rebuild, or the old image keeps running.
- CHECK
- The file can't say which PHP runs: a third-party image, a CI runner, DDEV or your host. Run php -v there.
- OK
- Pinned to a release with the fix.
- NOTE
- Composer settings. They install no PHP, but say which versions your code supports or targets.
What it reads
- Dockerfiles: FROM lines with ARG defaults filled in, ENV PHP_VERSION, and PHP installed with apt or apk
- Compose, Kubernetes, GitLab CI and other YAML: image, container and docker:// references
- GitHub, Forgejo and Gitea workflows: setup-php's php-version and matrix lists
- composer.json: require.php and config.platform.php
- devcontainer.json, .php-version, .tool-versions and mise.toml
- DDEV, Lando, Laravel Sail, Platform.sh and Upsun settings
What it never does
- It makes no network connection.
- It runs nothing it finds and changes no file.
- It skips .git, vendor and node_modules, and files over 1 MB.
- It needs nothing installed: the sh and awk on macOS and Linux are enough.
Checking one site instead? Use the PHP version check. One file? The PHP2Shell check reads php -v output, compose files and Dockerfiles. Every branch's dates are on PHP end of life.
Questions
Does the script send my code anywhere?
No. It reads files under the folders you name and prints to your terminal. It makes no network connection, runs nothing it finds and writes no files. It's one file of shell and awk, so you can read all of it before you run it.
Which files does it read?
Dockerfiles, YAML files (compose, CI, Kubernetes, DDEV, Lando, Platform.sh), devcontainer.json, composer.json, .php-version, .tool-versions and mise.toml. It skips .git, vendor and node_modules, and any file over 1 MB. A note repeated across many composer.json files prints once, with a count.
Why does a floating tag say REBUILD?
The official php and wordpress images on a supported branch were rebuilt with the fixed PHP on 21 October 2026. A server that pulled the tag before then keeps running the old image until you pull it again and rebuild.
Why do some composer.json lines show as notes?
require.php is the range of PHP versions your code says it supports, and config.platform.php is the version Composer resolves packages for. Neither installs PHP, so they're notes, unless they name a branch that's past end of life.
Does it work on macOS?
Yes, with the sh and awk that macOS ships. It also runs on Linux, including Alpine and BusyBox. We test it with dash, bash, zsh and BusyBox sh, and with BWK awk (the one on macOS), gawk, mawk and BusyBox awk.
If a pin says OK, is the server safe?
Not on its own. The script reads what your files say. Linux distributions backport fixes without changing the version number, and a server can run something other than what a file pins. php -v on the server and your vendor's security notice are the final word.
Sources
- PHP: Security advisory, 21 October 2026
- PHP: Supported versions
- Docker Hub: php image tags
- Docker Hub: wordpress image tags
- docker-library/php: branches and variants it builds
- arvion-ai/php-pins: the script's source, tests and issues
The poster shows the PHP logo by Colin Viebrock, licensed CC BY-SA 4.0, painted into the artwork. PHP is not affiliated with Arvion.