Skip to content
Back to skills

Sota Php

ASecurity

State-of-the-art PHP engineering (supported PHP branches) 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, preload...

  • 22 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 1, 2026
ai-agentsrustgophpshellsqlexpresstestingapidatabasesecurity

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 7 files and shows the line behind each finding

Scanned September 26, 2026

npx -y skills add martinholovsky/SOTA-skills --skill sota-php --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sota Php?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sota Php
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/martinholovsky-sota-php/badge)](https://www.skillsdirectory.com/skills/martinholovsky-sota-php)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sota-php
description: >-
  State-of-the-art PHP engineering (supported PHP branches) 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; verify the supported branches at php.net/supported-versions.php, 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, **WordPress** (`$wpdb->prepare`, `esc_*`, nonces with `current_user_can`, REST `permission_callback`), command execution, XSS and context-aware escaping, template engines, eval-family bans and **dynamic code evaluation** (templates compiled from strings, expression engines, why an in-process sandbox is no boundary); **request-chosen names** (`new $class`, `fetchObject`, `$_SESSION[$k]`, mass assignment); LDAP (`ldap_escape`, the empty-password bind) and XPath (`DOMXPath::quote`); **execution after `header('Location')`** (CWE-698) |
| `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); **escape hatches into raw memory**: FFI and `ffi.enable`; every PHP spelling of disabled TLS verification; SSH host keys (phpseclib, ext-ssh2) |
| `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; app cookies via `setcookie()`; `base_convert` tokens; secrets in stack traces (`#[\SensitiveParameter]`) and `phpinfo()`; **debug mode and the dev server** (`APP_DEBUG`, `APP_ENV`, `php -S`); the **framework application key** (`APP_KEY`, `APP_SECRET`, `decrypt()` that unserializes); **the web server to FPM handoff** (docroot `public/`, `vendor/` outside it, `security.limit_extensions`, `cgi.fix_pathinfo`, nginx `try_files`) |
| `rules/05-composer-tooling.md` | dependencies and CI: composer.lock discipline, `composer audit`, Composer's resolve-time advisory blocking (`policy`, `--no-blocking`), platform reqs, **vetting a new dependency and the insecure defaults of libraries you consume** (Guzzle `timeout`, league/commonmark `html_input`, Parsedown safe mode), PHPStan/Psalm levels and baseline ratcheting, PER-CS, PHPUnit/Pest, CI gates; **raising the PHP floor** (live branch state from php.net, Rector `withPhpSets()` as the conversion gate) |
| `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; **worker mode** (Octane, FrankenPHP, RoadRunner, Swoole): request state that leaks into the next request. **Test *strategy* lives in `sota-testing`; DB depth in `sota-databases`.** |

## Top-10 non-negotiables

1. **Run a supported PHP branch at its latest patch** (per the dated table in `rules/01`,
   8.2 is security-only until 2026-12-31; verify at php.net/supported-versions.php); 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`; Composer's advisory blocking stays on
   (no `--no-blocking`, no `block: false`).** (`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`)

Files in this skill

  • SKILL.md8.4 KB
  • rules/01-language-baseline.md10.4 KB
  • rules/02-injection.md8.4 KB
  • rules/03-files-deserialization-ssrf.md9.5 KB
  • rules/04-sessions-auth-web-hardening.md9 KB
  • rules/05-composer-tooling.md7 KB
  • rules/06-performance-runtime.md8.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.