A small, runnable reference for the web vulnerabilities that show up most often in PHP code. Every topic has three files:
vulnerable.php— the smallest reproduction of the flaw.fixed.php— the minimal change that fixes it.README.md— what the attack does, why the fix works, and the rules of thumb that fall out of it.
The goal is the kind of code you can read end-to-end in a minute and then apply to your own app.
| Topic | What it covers |
|---|---|
| SQL injection | String interpolation in queries vs. prepared statements |
| XSS | Raw output of user input vs. htmlspecialchars at the boundary |
| CSRF | Unauthenticated state-changing POSTs vs. session-bound tokens |
| Password hashing | md5 vs. password_hash / password_verify / password_needs_rehash |
| Error disclosure | display_errors in production vs. log-only with a generic 500 |
| Cookie flags | Default cookies vs. Secure / HttpOnly / SameSite |
| Session hijacking | Static session IDs vs. regenerated IDs with hardened cookies |
| File uploads | Trusted client filename/MIME vs. content sniffing + safe storage |
| Directory listing | Options +Indexes vs. -Indexes |
Pick a topic and open its README — each one stands on its own.
.
├── examples/ one folder per topic, each with vulnerable.php + fixed.php + README
├── src/ small shared helpers used by the examples (db, csrf, escaping)
├── db/ SQL schema for the demo database
├── docker/ Dockerfile for the lab web server
├── tests/ PHPUnit tests that exercise the underlying behaviors
├── docker-compose.yml runs PHP + MariaDB so the examples actually work
├── composer.json autoload + phpunit
└── .github/workflows/ CI: lint + tests on PHP 8.1, 8.2, 8.3
You need Docker.
docker compose upThat brings up Apache + PHP 8.3 on http://localhost:8080 and MariaDB on localhost:3306. The schema in db/schema.sql is loaded on first boot.
Open any example in the browser:
http://localhost:8080/examples/sql-injection/vulnerable.phphttp://localhost:8080/examples/sql-injection/fixed.php
…and the same pattern for every other topic.
composer install
composer testThe tests don't need the lab; they use SQLite in-memory and pure-PHP helpers, so they run anywhere PHP 8.1+ is installed. CI runs them on every push.
They are vulnerable on purpose. Don't deploy them anywhere a real user can reach them, and don't lift the patterns out of context — the surrounding lab assumes localhost, throwaway data, and an audience that's trying to break things.
See CONTRIBUTING.md. New topics are welcome; the bar is that the vulnerable file is genuinely vulnerable and the fix is the smallest thing that closes it.
MIT.