State-of-the-art PHP engineering (2026 baseline, PHP 8.3+ floor, 8.5 current) for both writing new PHP and auditing existing PHP code. Covers strict_types and modern idioms (enums, readonly, match, fibers, property hooks), OWASP-grade security (SQL injection, XSS, file uploads, LFI/RFI, unserialize/Phar object injection, sessions, password hashing, sodium, SSRF), framework-neutral web hardening, Composer supply chain and static analysis (PHPStan/Psalm levels, baselines), and runtime performan...
Scanned 9/1/2026
Install to Claude Code
npx -y skills add martinholovsky/SOTA-skills --skill sota-php --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Sota Php?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/martinholovsky-sota-php)More formats (shields.io, HTML) on the badges page.
---
name: sota-php
description: >-
State-of-the-art PHP engineering (2026 baseline, PHP 8.3+ floor, 8.5 current) for both
writing new PHP and auditing existing PHP code. Covers strict_types and modern idioms
(enums, readonly, match, fibers, property hooks), OWASP-grade security (SQL injection,
XSS, file uploads, LFI/RFI, unserialize/Phar object injection, sessions, password
hashing, sodium, SSRF), framework-neutral web hardening, Composer supply chain and
static analysis (PHPStan/Psalm levels, baselines), and runtime performance (OPcache,
preloading, FPM tuning, JIT, N+1). Use whenever the task involves PHP source,
composer.json, php.ini, FPM config, or a PHP framework — building features,
scaffolding projects, reviewing PRs, or hunting bugs and vulnerabilities.
Trigger keywords: PHP, composer, Laravel, Symfony, WordPress, PHPStan, Psalm, PHPUnit,
Pest, PDO, php-fpm, OPcache, strict_types, phar, unserialize, htmlspecialchars.
---
# SOTA PHP (2026)
## Purpose
This skill encodes the 2026 state of the art for PHP: a supported-version baseline
(PHP 8.3+ floor; 8.5 is the latest annual line — verify current, see `rules/01`), `strict_types` everywhere, typed
object-oriented design, security-by-default at every trust boundary, a locked and audited
Composer supply chain, and measured runtime performance. It serves two modes:
- **BUILD** — writing new code or modifying existing code to this standard.
- **AUDIT** — reviewing existing code against this standard and reporting findings.
The detailed rules live in `rules/*.md`. Read SKILL.md fully; load rules files on demand
per the index table below.
## BUILD mode
When creating or modifying PHP code:
1. **Establish context first.** Check `composer.json` (`require.php`, `config.platform`),
`composer.lock`, the framework in use, PHPStan/Psalm config, and CS ruleset. Match the
project's PHP floor — no enums on a project that still supports 8.0. For a *new*
project, scaffold per `rules/05`: PHP ≥ 8.3 floor, committed lockfile, PHPStan at max
level (baseline only for legacy), PER-CS formatting, CI gates from day one.
2. **Default style:** `declare(strict_types=1)` in every file, full parameter/return/
property types, constructor promotion, `readonly` where state shouldn't mutate, enums
over class constants, `match` over `switch`, exceptions over error codes, no `@`
suppression. (`rules/01`)
3. **Security posture is non-optional** even when unrequested: PDO prepared statements,
context-correct output escaping, upload validation by content, no `unserialize()` on
external data, `password_hash`/`sodium`/`random_bytes` for anything secret.
(`rules/02`–`rules/04`)
4. **Framework first.** When a framework is present (e.g. Laravel, Symfony), use its
escaping, CSRF, auth, and validation mechanisms instead of hand-rolling — but verify
raw-escape hatches (`DB::raw`, `|raw`, `html()`) aren't fed user input.
5. **Tests accompany code** (PHPUnit or Pest as the project dictates); static analysis
and CS must pass before code is presented. (`rules/05`)
6. **Performance:** OPcache assumptions belong in deploy config, not code; anything
beyond correct-by-default (eager loading, streaming, generators) requires a profile
first. (`rules/06`)
## AUDIT mode
When reviewing existing PHP code:
1. **Sweep mechanically first.** Run the "Audit checklist" blocks at the end of every
relevant rules file — ordered grep/composer/phpstan commands. Start with
`composer audit --locked` and a grep sweep for `unserialize(`, `eval(`, `shell_exec`,
string-interpolated SQL, and `echo $_`.
2. **Then read for design:** trust-boundary placement, escaping strategy (output-time or
scattered?), session lifecycle, N+1 patterns, lockfile discipline.
3. **Verify every finding** — open the file, trace the data flow. An `unserialize()` of a
value the same app signed with HMAC is not CRITICAL. Note mitigations already present.
4. **Don't report style noise** a fixer would auto-fix; mention once collectively.
### Severity conventions
| Severity | Meaning | Examples |
|---|---|---|
| CRITICAL | Exploitable now, or data loss | SQL built by interpolation from request data, `unserialize($_GET…)`, `include` of user path, `eval` on input, uploads executed as PHP |
| HIGH | Exploitable with preconditions, or prod-breaking | XSS via unescaped output, `md5()` passwords, missing `use_strict_mode`/fixation, SSRF fetch of user URL, `CURLOPT_SSL_VERIFYPEER => false`, world-readable secrets |
| MEDIUM | Correctness/maintenance risk | no lockfile committed, no `composer audit` in CI, loose `==` on security decisions, `rand()` for tokens in non-auth context, N+1 on hot path, no static analysis |
| LOW | Deviation from SOTA, friction | missing `strict_types`, untyped properties, `switch` where `match` fits, dev deps in prod image |
| INFO | Worth knowing | newer-PHP features available after floor bump, tooling consolidation |
### Finding format
```
file:line | rule violated (rules/NN §S) | severity | effort | fix
```
Effort: trivial · small · medium · large. Group by severity, CRITICAL first. Borderline
severities state the deciding assumption; unconfirmed findings are marked "needs
verification", never asserted. End with counts per severity, the sweep commands run, and
explicit "checked and clean" areas.
## Rules index
| File | Read this when... |
|---|---|
| `rules/01-language-baseline.md` | choosing/verifying PHP version floor (support/EOL table); writing any PHP: strict_types, typed properties, enums, readonly, match, fibers, 8.4/8.5 features, comparison pitfalls incl. **`strpos` returning `false` where `0` is a real match**, error handling, deprecations |
| `rules/02-injection.md` | code touching SQL, shell, or HTML output: PDO prepared statements, command execution, XSS and context-aware escaping, template engines, eval-family bans |
| `rules/03-files-deserialization-ssrf.md` | file uploads, include/require paths, stream wrappers (LFI/RFI/`phar://`), `unserialize` and Phar object injection, XXE, server-side URL fetching (SSRF) |
| `rules/04-sessions-auth-web-hardening.md` | login/session/auth code: session cookie flags and fixation, password_hash/argon2id, sodium crypto, CSRF, security headers, production php.ini hardening |
| `rules/05-composer-tooling.md` | dependencies and CI: composer.lock discipline, `composer audit`, platform reqs, PHPStan/Psalm levels and baseline ratcheting, PER-CS, PHPUnit/Pest, CI gates |
| `rules/06-performance-runtime.md` | anything slow or deploy-shaped: OPcache and preloading, JIT reality check, PHP-FPM pool sizing, N+1/caching, autoloader optimization, profiling. **Test *strategy* lives in `sota-testing`; DB depth in `sota-databases`.** |
## Top-10 non-negotiables
1. **Run a supported PHP** (≥ 8.2 today, and 8.2 is security-only until 2026-12-31 —
plan the 8.3+ move now); new code targets 8.3+. (`rules/01`)
2. **`declare(strict_types=1)` in every file; full types on every property, parameter,
and return.** Untyped is legacy, not a style choice. (`rules/01`)
3. **SQL only via prepared statements with bound parameters** (PDO/mysqli, emulation
off); identifiers via allowlist. String-built SQL is CRITICAL, no exceptions for
"internal" values. (`rules/02`)
4. **Escape at output, for the right context** — `htmlspecialchars(…, ENT_QUOTES |
ENT_SUBSTITUTE, 'UTF-8')` or the template engine's auto-escaping; raw-output escape
hatches never receive user input. (`rules/02`)
5. **Never `unserialize()`, `eval()`, or `include`/`require` data you don't fully
control.** External data is JSON. Filter user paths for `phar://` and friends.
(`rules/03`)
6. **Uploads: validate by content, rename randomly, store non-executable** — never trust
client filename or MIME; never let the webserver execute uploads. (`rules/03`)
7. **Passwords via `password_hash()` (bcrypt default, or argon2id) + `password_verify`;
secrets via `random_bytes`/`sodium`; compare with `hash_equals`.** Never md5/sha1/
`rand()`/`uniqid()` for anything secret. (`rules/04`)
8. **Sessions hardened:** `use_strict_mode=1`, cookies `Secure` + `HttpOnly` +
`SameSite`, `session_regenerate_id(true)` on privilege change. (`rules/04`)
9. **`composer.lock` committed; CI runs `composer install` (never `update`) and
`composer audit --locked`; prod installs `--no-dev`.** (`rules/05`)
10. **PHPStan (or Psalm) gates CI at the highest level the project can hold; the
baseline only shrinks. OPcache on in prod; performance claims require a profile.**
(`rules/05`, `rules/06`)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!