HuTor Tech logo HuTor Tech
← All posts

· hutor.tech

How to audit a legacy PHP codebase

How to audit a legacy PHP codebase

An audit answers three questions: what will break, what will cost money, and what can be fixed cheaply. Everything else is opinion. We keep audits to about a week and end them with a document a non-technical owner can act on.

Begin with the facts a machine can gather. PHP and framework versions against their end-of-life dates; the number of files and lines; the largest classes; how much of the code is vendor and how much is yours; whether tests exist and whether they pass. `composer audit` and `npm audit` give you known vulnerabilities in minutes, and an out-of-support PHP version is usually the single most expensive finding in the whole report.

Then look for the shapes that predict trouble:
— SQL built by string concatenation with request data in it;
— passwords hashed with md5 or sha1, or not hashed at all;
— credentials committed to the repository;
— file uploads that trust the client's MIME type;
— one file of several thousand lines that everything else depends on;
— a `vendor` directory edited by hand, so `composer install` would erase the fixes.

Run the application, do not only read it. Enable a query log on a real page and count the queries — the N+1 problem is the most common performance defect in inherited code and the easiest to demonstrate. Watch the slow log. Load the heaviest page with a profiler once; you usually find that a single unindexed column, not the framework, is responsible for the wait.

Check the operational side with the same seriousness as the code: backups (and whether anyone has restored one), deployment (a script or a person with FTP), logs, monitoring, staging. A tidy codebase deployed by hand at midnight is more dangerous than a messy one with a pipeline.

Write the report for the person who pays. Group findings by risk, put a rough cost next to each, and separate "must fix now" from "worth doing while we are in there". Include the two or three quick wins you found — an index, a cache header, an upgrade — so the first invoice already buys something visible.

An audit ends with a plan, not a verdict. Rewriting from scratch is almost always the wrong answer: legacy code is ugly because it encodes years of business rules that nobody wrote down anywhere else.