Skip to content

PHP 5.6 to PHP 8.5 migration, without the rewrite

Ten years of PHP releases separate PHP 5.6 from PHP 8.5. We migrate legacy applications across that gap incrementally: mysql_* to PDO, mcrypt to OpenSSL, removed functions replaced and dead frameworks retired, while the application keeps running.

  • No big-bang rewrite
  • Behaviour locked in by tests
  • Fixed price, phase by phase

Why a PHP 5.6 application can’t wait

PHP 5.6 stopped receiving security fixes at the end of 2018, and PHP 7.0 a few weeks later. Applications this old usually still work, which is why they get left alone. But they run on an unpatched runtime, often on an operating system that is out of support too, and they can only be hosted on servers that still offer a PHP version nobody else uses.

The longer it waits, the fewer hosts, developers and libraries can support it. Usually the first sign of a problem is a failed security questionnaire, a hosting migration that can’t go ahead, or a developer leaving who was the only one who knew the code.

What has to change between PHP 5.6 and PHP 8.5

Ten years of PHP releases lie between them. The changes that cause the most work:

  • The mysql_* extension was removed in PHP 7.0. Every database call moves to PDO or mysqli. It’s also the best chance to replace string-built SQL with prepared statements, which closes SQL injection holes.
  • mcrypt was removed in PHP 7.2. Encryption moves to OpenSSL or libsodium. Data already encrypted with mcrypt has to stay readable, so it needs a migration plan rather than a find-and-replace.
  • Removed functions and syntax: ereg*, split(), each(), create_function(), __autoload(), the /e modifier for preg_replace() and PHP 4-style constructors.
  • Fatal errors became exceptions in PHP 7, and many warnings became TypeError exceptions in PHP 8. Error handling and logging need rethinking.
  • Old frameworks and libraries. CodeIgniter 2, Zend Framework 1, Laravel 4 and Symfony 2 don’t run on modern PHP. Many old apps also have no Composer, with libraries copied straight into the repository.

How we migrate PHP 5.6 to PHP 8.5 without a rewrite

A full rewrite looks attractive and almost always overruns. We keep the application running and change it in place:

  1. Get it under control. Version control, a repeatable local environment in Docker and Composer for dependencies, if they aren’t there already.
  2. Record current behaviour. HTTP-level characterisation tests on the pages and journeys that matter, so we can prove the migrated application behaves the same.
  3. Replace removed extensions behind small adapters. Database and encryption calls go through one thin layer, so the switch to PDO and OpenSSL happens in one place.
  4. Automate the mechanical changes. Rector applies upgrade rules from PHP 5.3 through to 8.5. PHPStan finds what Rector can’t.
  5. Strangle the old framework, if needed. Where a dead framework has to go, new routes run on a modern framework next to the old code and take over page by page.
  6. Release in stages. Staging first, then production with a rollback plan.

Cost and timescale

PHP 5.6 migrations vary more than any other upgrade we do. Code size counts for less than how much raw SQL, encryption and framework code the application has. That’s why every migration starts with the fixed-price £350 audit. It gives you a phased plan and effort estimate, and the upgrade is then quoted at a fixed price, phase by phase, so you approve each stage before it starts.

Frequently asked questions

Should we rewrite instead of upgrading?
Rarely. A rewrite has to rediscover years of business rules hidden in the old code, and the old system keeps changing while you build the new one. Migrating in place keeps the knowledge in the code and delivers value much sooner. Where part of an application really does need replacing, we do it page by page.
Do you upgrade to PHP 7.4 first, then to PHP 8?
Often, yes, as an intermediate step: once the removed extensions are replaced, PHP 7.4 accepts most PHP 5.6 code with small changes, and it makes a stable base for the larger PHP 8 changes. Whether it goes to production depends on the application and its timeline.
Our application has no tests. Is that a problem?
It is normal for applications this old. We write characterisation tests first: they record what the application does today on the paths that matter, without needing to understand every line. These tests are what make the migration safe.
What happens to data encrypted with mcrypt?
It stays readable. We decrypt it with a compatible library such as phpseclib, then re-encrypt it with OpenSSL or libsodium, either in one migration or as records are read. The audit identifies where encrypted data lives.