Skip to content

PHP 8.2 loses security support on 31 December 2026

PHP 8.2 stops receiving security fixes at the end of this year, and Laravel 13 already requires PHP 8.3. Here is a sequencing plan for getting a large legacy application off it without stopping feature work.

Laravel, Legacy systems, Security

A finance director asks why a reporting change that sounds trivial is going to take six weeks. The honest answer is usually not about the reporting change. It is that the application runs on a PHP version the team is nervous about touching, the package that generates the spreadsheets was abandoned in 2021, and nobody wants to be the person who runs composer update on a Friday.

That situation now has a date attached to it.

The dates

PHP 8.1 reached end of life on 31 December 2025. No further security fixes from the PHP project, regardless of severity. PHP 8.2 is in its security-only window and reaches end of life on 31 December 2026, which is a little over three months away as I write this.

The framework side has moved too. Laravel 13 was released on 17 March 2026 and requires PHP 8.3 as a minimum. The support table from that release is worth having in front of you:

If you are on Laravel 11, you are already past the security window. If you are on Laravel 12, bug fixes stopped last month and you have until February 2027 on security.

One caveat before anyone panics. If your servers run PHP from Debian, Ubuntu or RHEL packages rather than from source or from a third party repository, the distribution vendor backports security fixes for the version they shipped, on their own timeline. That buys you time. It does not buy you Laravel 13, and it does not buy you packages that have already dropped support for older runtimes.

Why the version number is not really the problem

Upgrading PHP itself is rarely the hard part. On a well-kept codebase, moving from 8.2 to 8.3 is an afternoon. The hard part is everything that is pinned behind it.

Run this on your worst application:

composer why-not php 8.3

The output is your actual project plan. It is usually not one package. It is one package that constrains three others, plus a fork of something you made in 2019 with a ^7.4 constraint in its own composer.json, plus a private package on a Satis server that nobody has published to since the developer who built it left.

This is the part that surprises people who have only done the arithmetic on the PHP version. The runtime is a single number. The dependency graph is a negotiation.

It is also the part that has quietly become a governance issue rather than an engineering preference. The OWASP Top 10 was revised in 2025, and what was A06:2021 Vulnerable and Outdated Components has been expanded into A03:2025 Software Supply Chain Failures, covering dependencies, build systems and distribution infrastructure. OWASP note that this category has the fewest occurrences in their collected data but the highest average exploit and impact scores from the associated CVEs. Rare and expensive, in other words. If you sell to enterprise or public sector buyers in the UK, expect this to appear in security questionnaires before it appears in an incident report.

Runtime first, framework second

Here is the sequencing that makes this tractable, and it comes straight out of that support table.

Laravel 12 supports PHP 8.2 through 8.5. So if you are on Laravel 12 and PHP 8.2, you can move the runtime to 8.3 without changing a single line of framework code. That is one variable at a time. When something breaks, you know which change caused it.

Do the same in the other direction if you are further back. Get to the newest Laravel release your current PHP version supports, then move PHP, then move Laravel again. Two small upgrades with a working deploy in between are worth far more than one large one, because each gives you a point you can stop at if the business needs the team elsewhere for a fortnight.

The failure mode to avoid is the branch where someone bumps PHP, Laravel, the database driver and Node in the same pull request, and then spends three weeks bisecting a test suite that was already flaky.

Find the deprecations before they find you

PHP tells you what is going to break, if you let it. Most applications throw away that signal because deprecation notices are noisy in development and suppressed in production.

Laravel has a dedicated channel for this. In config/logging.php:

'deprecations' => [
    'channel' => 'deprecations',
    'trace' => true,
],

'channels' => [
    'deprecations' => [
        'driver' => 'daily',
        'path' => storage_path('logs/deprecations.log'),
        'level' => 'debug',
        'days' => 30,
    ],
    // ...
],

Make sure error_reporting in your production php.ini includes E_DEPRECATED, turn this on, and leave it for a fortnight. You will get a file listing every deprecated call path that real traffic actually exercises, with stack traces. That list is materially different from what static analysis finds, because it is weighted by what your users do. A deprecation in a code path that runs four hundred times a day is a different priority from one in an admin screen last opened in 2023.

Run both. PHPStan configured against the target PHP version will find the things that never execute in your sample period. Rector with the relevant PHP set will mechanically fix a good proportion of what it finds, though you should read every diff rather than trusting it wholesale.

The code nobody understands

Every application of a certain age has a region that people route around. Pricing rules, a VAT edge case, an overnight reconciliation job. There are no tests, the original author has gone, and the behaviour is the specification.

Fowler's term for the tests you write here is characterisation tests. You are not asserting what the code should do. You are asserting what it currently does, including the parts that are probably bugs, so that you can tell whether an upgrade changed anything. Capture the inputs from a week of production, record the outputs, assert that they still match after the upgrade. Ugly, and the right thing to do.

The same logic applies to a dependency that will not move. Wrap it in an interface of your own, get your application talking to the interface, then replace what is behind it. That is the strangler fig pattern at package scale rather than system scale, and it works for the same reason: small replacements carry small risk, and you get value from each one before the next begins.

What it costs

Be honest with whoever signs off the budget. This work produces no features. Nobody in the business will notice it happened, except that the next three things they ask for will be cheaper.

The most common way it fails is being treated as a project with a start and an end. It is not. Laravel ships a major version roughly every year, PHP drops a version every year, and you will be having this conversation again in 2027 for PHP 8.3. The teams that find upgrades cheap are the ones that spend a predictable slice of capacity on them continuously, so the gap never grows past one version.

Paid extended support for end of life PHP exists and is a legitimate bridge if you have a hard commercial reason to delay. Price it as rent, not as a fix, and put a date on when the rent stops.

What to check this week

Four things, none of which need a budget approval:

  1. Run php -v on every machine that runs your code. Web servers, queue workers, the cron box, the container image, the one EC2 instance that does the nightly export. They are not always the same version.

  2. Run composer why-not php 8.3 and keep the output. That is your scope.

  3. Turn on the deprecations log channel in production and look at it in two weeks.

  4. Check which Laravel version you are on against the table above, and note the date your security support ends.

If the answers to those four are worse than you expected, that is useful information, and it is better to have it in September than in January.

Keep reading
Modernise

Move the charity's CRM over a weekend, and be able to move it back

A CRM migration is not like other software changes: the data has to exist in exactly one place, which forces a short, sharp cutover rather than a gradual one. This explains, for trustees with no technical background, why a weekend window and a rehearsed rollback plan are the two things worth insisting on.

Legacy systems, Architecture, Testing

Tell us what is slowing you down

A short conversation, let's get to know each other. If we are not the right people we will say so.

Start a conversation