Engineering

What to check before rewriting a legacy PHP system

A checklist of what to find out before you commit to rewriting a legacy PHP system, and the cases where repairing it in stages is the better choice.

Lal Chand, founder · · 6 min read

A legacy PHP system that nobody understands is an uncomfortable thing to own. It runs the business, it’s hard to change and the developer who wrote it has moved on. The usual reaction is to propose a rewrite. Sometimes that’s right. More often it’s the most expensive of several options, and it’s chosen before anyone has looked properly at what is there.

This is what we’d check first, in roughly the order we’d check it.

1. Can you run it, and can you deploy it?

Start with the boring questions. Can a developer get the system running on a laptop from the repository alone? Is there a repository? Do you know where the production code lives, and does it match what is in version control?

On older systems the production server is the only copy of the truth. Files edited directly on the host, a config file with credentials that exist nowhere else, a cron job set up by hand. Getting the code into version control and into a repeatable deployment is the first job whatever you decide next, because every other choice depends on it.

2. What PHP version is it on, and what depends on that?

PHP releases follow a published schedule: two years of active support, then two more years where only security fixes arrive. After that a version is end of life and gets no fixes at all. If your system runs on an end-of-life version, you’re exposed to problems nobody will patch, and the hosting provider may eventually stop offering that version.

Check the version, then check what stops you upgrading it. Removed functions, changed error handling, stricter type behaviour and abandoned libraries are the usual obstacles. Some systems move up a version or two with modest effort. Others are tied to an extension or a library with no maintained successor. That distinction decides a lot of the cost.

3. Read the data model first

The database is the part of the system that matters most and changes least. The code is an opinion about it. Look at the tables, the relationships, the columns with unclear meanings and the places where rules live in the data instead of the code.

If the data model is sound and the code is messy, you have a good case for repairing in stages. If the data model itself is wrong, say a booking that can’t have more than one traveller, then no amount of tidy code fixes the real problem, and you’re looking at a migration whatever you choose.

4. Find out what is actually in use

Old systems accumulate features. Some are essential, some were used twice in 2019 and some were never finished. A rewrite that reproduces everything costs far more than one that reproduces what people use.

Ask the people who use the system, not only the owner. Look at access logs, database tables that are still being written to, and reports someone opens every month. Write a list of features in three groups: used daily, used occasionally, apparently dead. Take the dead group out of scope.

5. Find the rules nobody wrote down

This is the hidden cost of a rewrite. The old system contains years of edge-case handling: a rounding rule for one currency, a special case for a supplier, a check added after an incident. Nobody documented them, and a new system won’t have them unless someone finds them.

Techniques that help:

  • Read the code around conditionals that look arbitrary. Each one has a reason.
  • Read old support emails and bug reports.
  • Run the old and new systems side by side on the same input and compare outputs.
  • Write tests that capture what the old system does now, even where that behaviour looks odd. These are often called characterisation tests, and they give you a safety net for either repair or rewrite.

6. Check security, honestly

Look for the usual signs. Database queries built by joining strings. Passwords stored without proper hashing. File upload code that trusts the file name. Admin pages with no access control. Secrets committed in the repository. Dependencies that haven’t been updated in years.

A practical security review is part of our System Audit. It won’t find everything, and it will tell you whether the problems are fixable in place. Many are: parameterised queries and a password hash upgrade are targeted fixes, and neither needs a rewrite.

7. What does the business need that this can’t do?

A rewrite should solve a problem the current system can’t. Ask what that problem is. If the answer is "the code is ugly", that’s a maintenance cost, and probably not a reason to spend months rebuilding. If the answer is "we need a multi-currency model and the data structure can’t represent it", or "we need to open the system to partners and it has no API", that’s a structural limit, and a stronger case.

Write the requirement as a sentence the owner agrees with. If you can’t, you aren’t ready to commit.

8. Can you replace it in pieces?

The strangler pattern is the usual alternative to a full rewrite. You put a layer in front of the old system, build new features or replacement modules alongside it, and move traffic across one piece at a time. The old system shrinks until it can be switched off.

It’s slower to describe and often faster to deliver, because the business keeps running throughout and each step is small enough to test and reverse. It doesn’t suit every system. If the old code is so entangled that nothing can be separated, the pieces approach struggles. Finding that out in a short audit is cheaper than finding it halfway through.

9. What is the cost of waiting, and what is the cost of the rewrite?

Put rough numbers on both. Include the cost of running two systems during the transition, the time of your own staff for testing and the period when new features stop because everyone is busy with the migration. Be honest about the risk that a rewrite takes twice as long as planned, because that’s a common outcome.

A rewrite isn’t a bad idea. It’s a decision with a large cost that deserves evidence. If the audit says the data model is sound, the version can be upgraded and the security issues are fixable, repairing and replacing in stages is usually the better route. If it says the foundations can’t support what the business now needs, rewrite, and you’ll go in knowing why.

Our legacy modernisation service starts with the audit for exactly this reason. For the documentation you should expect at the end, see what a proper software handover contains.

Sources and further reading

Questions about this topic

Should I always rewrite an old PHP system?

No. A rewrite discards years of unrecorded edge-case handling and costs a lot. Repair in stages when the data model is sound and the problems are fixable. Rewrite when the structure can’t support what the business now needs.

How do I know if my PHP version is a problem?

Check it against the official supported versions page. Each branch gets two years of active support and two more of security fixes only. After that it’s end of life and receives no fixes.

What is a characterisation test?

A test that records what the existing system actually does for a given input, including odd behaviour. It doesn’t judge whether the behaviour is right. It lets you change the system and see at once whether you altered something you didn’t mean to.

Can I move to a new system without stopping the business?

Often yes, by replacing the system in pieces behind a front layer and moving one function at a time. Running old and new side by side on the same data also helps confirm the new one matches.

What does a legacy audit cost and how long does it take?

Our System Audit takes about a week and is priced at USD 600 to 1,200. You receive a written report that ranks what is sound, fragile and expensive, and what each fix would cost.

Start a conversation

Tell us what the system has to do.

Describe the problem in a paragraph and we’ll tell you honestly whether we’re the right people for it, and roughly what it costs before you spend anything.