Parse phpinfo() output into clean, scriptable JSON. Diff two environments.
CI-friendly exit codes. PHP 8.2 stdlib only — no Composer runtime deps, just
DOMDocument + DOMXPath + json_encode.
phpinfo() is still the canonical way to ask "what does this environment
actually look like?" but its HTML dump is hostile to everything you'd
reasonably want to do with it: you can't grep a nested directive with its
section, you can't pipe it into jq, you can't diff two containers that
claim to run the same PHP stack. phpinfo-json fixes that in ~400 lines of
strict PHP.
The typical workflow: a CI job fails because OPcache was disabled on one
runner, or a container ships with a different openssl version than the
dev image, or memory_limit somehow ended up at 128M in production and
nobody knows why. You reach for phpinfo(), get a 200 KB HTML blob, and
then stare at it. This tool turns that blob into:
{
"general": {
"php_version": "8.2.20",
"system": "Linux host 6.1.0 #1 SMP x86_64",
"server_api": "Command Line Interface"
},
"sections": {
"Core": {
"memory_limit": { "local": "256M", "master": "128M" },
"display_errors": { "local": "Off", "master": "On" }
},
"opcache": {
"opcache.enable": { "local": "On", "master": "On" }
}
},
"modules": ["Core", "opcache", "PDO", "json", "curl"]
}Now you can jq '.sections.opcache', grep memory_limit, or feed two
dumps into --diff and get a clean added / removed / changed report.
- Parses phpinfo() HTML via
DOMDocument+DOMXPath— no regex, no SimpleXML, no Composer runtime deps. - Also parses text output (
php -i) so you can feed it raw CLI dumps. - Auto-detects format by looking for
<tabletags. --diffmode: compare two environments, getadded/removed/changedkeys + amodules.added/removeddelta.--section NAMEto extract a single section;--only-modulesto list loaded extensions.--format flatemitssection.key=valuelines forgrep/awk.- No arguments = run
phpinfo()inside the current PHP process via output buffering and dump the result as JSON. Great for DockerfileRUN phpinfo-json > /env.json. - Exit codes:
0success,1parse/IO error,2bad CLI args. - 20+ PHPUnit tests, strict types, PSR-4 autoload, fallback manual autoloader for zero-vendor runtime.
docker build -t phpinfo-json .
# Dump the running container's phpinfo
docker run --rm phpinfo-json | jq '.sections.Core'
# Just the module list
docker run --rm phpinfo-json --only-modules
# Parse a captured file
docker run --rm -v $(pwd):/work phpinfo-json /work/phpinfo.html --format flat
# Diff two containers
docker run --rm -v $(pwd):/work phpinfo-json /work/env-a.html --diff /work/env-b.htmlThe image is a multi-stage Alpine build (alpine:3.19 runtime). PHPUnit
lives in the builder stage only. Final size is under 100 MB.
git clone https://github.com/sen-ltd/phpinfo-json.git
cd phpinfo-json
php bin/phpinfo-json --helpNo composer install is required for the tool to run — the bin script
registers a manual PSR-4 autoloader. Composer is only needed for tests.
# Default: capture phpinfo() inside the current PHP process → JSON
phpinfo-json
# Parse a saved HTML dump
phpinfo-json phpinfo.html
# Parse CLI text output (php -i > info.txt)
phpinfo-json info.txt --input text
# Pipe from stdin
php -i | phpinfo-json -
# One section only
phpinfo-json --section opcache
phpinfo-json --section Core
# Just loaded modules
phpinfo-json --only-modules
# Flat format: section.key=value
phpinfo-json --format flat | grep memory_limit
# Diff two environments
phpinfo-json prod.html --diff staging.html | jq '.changed'phpinfo() HTML has a predictable structure: each section is an <h2> tag
followed by a <table> with rows of <tr><td>key</td><td>value</td></tr>,
or the Directive | Local Value | Master Value three-column form for
INI-style directives. The parser walks <h2> elements in document order,
picks up the next <table> sibling, and extracts rows via XPath.
The tricky bits are handled by design:
- "no value" cells (
<i>no value</i>in HTML, literalno valuein text mode) become the empty string in output. - Multi-line values (like
disable_functionswith\n-separated function names) are preserved with newlines intact. - UTF-8 keys and values work without manual encoding — the DOMDocument
loader is given an
<?xml encoding="UTF-8"?>hint.
Read the article for the full write-up:
Parsing phpinfo() in pure PHP.
composer install
vendor/bin/phpunit
# or inside the docker image:
docker run --rm --entrypoint /app/vendor/bin/phpunit phpinfo-json \
--no-coverage -c /app/phpunit.xmlMIT