SOTA PHP (2026)

SkillDatabases & data

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.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the SOTA PHP (2026) skill

What this skill tells your AI

The instructions your AI receives, as published by martinholovsky/sota-skills in skills/sota-php/SKILL.md and read by ahel’s review.

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/02rules/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

SeverityMeaningExamples
CRITICALExploitable now, or data lossSQL built by interpolation from request data, unserialize($_GET…), include of user path, eval on input, uploads executed as PHP
HIGHExploitable with preconditions, or prod-breakingXSS via unescaped output, md5() passwords, missing use_strict_mode/fixation, SSRF fetch of user URL, CURLOPT_SSL_VERIFYPEER => false, world-readable secrets
MEDIUMCorrectness/maintenance riskno 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
LOWDeviation from SOTA, frictionmissing strict_types, untyped properties, switch where match fits, dev deps in prod image
INFOWorth knowingnewer-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

FileRead this when...
rules/01-language-baseline.mdchoosing/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.mdcode 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.mdfile 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.mdlogin/session/auth code: session cookie flags and fixation, password_hash/argon2id, sodium crypto, CSRF, security headers, production php.ini hardening
rules/05-composer-tooling.mddependencies 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.mdanything 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 contexthtmlspecialchars(…, 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)

Signals

GitHub stars
22
Forks
4
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
sota-php
Source
github.com/martinholovsky/sota-skills