Support

Documentation

6.Addressing OPcache issues

6.Addressing OPcache issues

Here's the scenario. You try to run Kickstart but you get a PHP error that some files (usually preamble.php) is not found without a message about a broken signature. No matter what you do, you can't get Kickstart to work.

This points to one thing: bad settings for OPcache.

A properly configured OPcache can make your site faster. A misconfigured OPcache will render your site broken, either obviously or –as is most common– subtly but with very strong bad implications. Understanding the OPcache inner workings and configuration is, therefore, of paramount importance to running a site.

The root cause of this problem is that most hosts do not understand how OPcache actually works. OPcache doesn't magically know if a .php file –whether it is included in a PHAR archive, or extracted into a directory such as kicktemp– exists and whether it is the same as what was previously cached. This behaviour is configurable.

The configuration you see suggested on-line for live hosts is not geared towards shared hosting. It is geared towards the CI/CD (Continuous Integration / Continuous Deployment) pipeline use case. In this use case a new virtual machine or container fleet consisting of at least the web server (NginX, Apache, …) and PHP (typically as a PHP-FPM service) is created each time new code is being deployed, i.e. every time any PHP file in the application changes. In this very specific use case you specifically don't want OPcache to waste any time at all checking whether any of the PHP files it serves have changed. By the very definition of this use case, PHP files will never change while the virtual machine / container fleet is running. When a PHP file changes, it's a new deployment, therefore a new virtual machine / container fleet. In this use case the goal is an essentially static OPcache and the only worry is how fast you can warm the cache.

However, we do not and cannot use shared / commercial hosting this way. In the case of shared / commercial hosting we have a long-lived server on which the application, therefore the PHP files it consists of, change over time. Installing or updating the CMS, extracting a backup, installing or updating software running under the CMS, even using file-based caching and log files does create and modify PHP files on the host. OPcache will not work properly in this use case unless it's configured to check whether the cached files still exist, and whether they match what it has already cached (if not, it gets to read them and cache them afresh).

The most pertinent OPcache configuration options are:

  • opcache.validate_timestamps This MUST be enabled (set to 1 or true). This is the toggle switch for this OPcache feature we described.

  • opcache.revalidate_freq This MUST be set to something fairly low. A value between 2 and 5 (measured in seconds) allows OPcache to be effective in speeding up the server without causing issues when the PHP files on the server are created, removed, or modified.

  • opcache.enable_file_override This SHOULD be disabled, as it usually causes problems with temporary files which are created and go away faster than the opcache.revalidate_freq setting.

  • opcache.revalidate_path This MUST be enabled (set to 1 or true). It tells OPcache to resolve files to their real path before caching, which is critical for PHAR archives where multiple distinct paths (such as phar:///path/to/kickstart.php/…) may otherwise collide in the cache.

The default settings in PHP are opcache.validate_timestamps=1, opcache.revalidate_freq=2, opcache.enable_file_override=0, and opcache.revalidate_path=1 which is perfectly fine for both development servers, and for live shared / commercial hosting.

You might wonder why you'd get missing files errors if OPcache is misconfigured. It's because OPcache caches two things: the compiled contents of the files (also known as op-code, hence the name “OPcache”), and the metadata of a file (does it exist, when it was created and last modified, what is its size). The latter is true if opcache.enable_file_override is set to 1.

This means that it's possible and common to misconfigure OPcache in such a way that it "remembers" the compiled contents of files, and file metadata, but is out-of-date with the actual files in your filesystem. The cached executable op-code executes up to the point it needs to include a class file to continue. That file is reported as non-existent even though it's shipped with Kickstart itself, therefore you get an error.

You can temporarily work around that by using a different filename for Kickstart and its kicktemp folder. This creates a new path for loading code files from. However, this will also get out of sync with the filesystem very soon which is why it's a bad workaround.

The correct solution is to work with your host to configure OPcache correctly for the use case of a Joomla or WordPress site:

  • opcache.validate_timestamps=1

  • opcache.revalidate_freq=2

  • opcache.enable_file_override=0

  • opcache.revalidate_path=1

Your host will probably tell you that OPcache can't have anything to do with your problem. They are wrong. They just don't understand how OPcache actually works. We do. It's our job to know that. Moreover, we have seen every person with a similar problem applying those OPcache settings on their server –and making sure to afterwards restart PHP-FPM or the web server itself, depending on how PHP execution is configured– have these problems disappear.

As a side note, misconfigured OPcache is worse than just getting in your way of restoring a backup. It also means that any updates you install in your core CMS and its software is not applied. You may have installed a security update as soon as it was available... but your site kept running the old, vulnerable code exposing you and your site to known and otherwise preventable danger. You may have installed updates to the software you run on the site, but the old code with known bugs still runs and you blame the developer for not addressing your issue even though they already have.

Why opcache.revalidate_path=0 breaks Kickstart

There is a specific OPcache pitfall that deserves special attention: opcache.revalidate_path set to 0.

When opcache.revalidate_path is disabled, OPcache uses the unresolved file path as the cache key. For PHAR archives like Kickstart this is catastrophic. Kickstart's internal files are accessed via phar:// stream wrapper paths, e.g. phar:///home/user/public_html/kickstart.php/src/includes/preamble.php. When OPcache does not resolve these paths properly, the cached entry for a given include path can point to stale or entirely wrong op-code. The first page load works because OPcache has not cached anything yet. Every subsequent request fails with an HTTP 500 Internal Server Error and a PHP error log entry stating that it failed to include a phar://…/preamble.php (or similar) file from the PHAR archive.

The fix is simple: set opcache.revalidate_path=1 and restart PHP-FPM (or the web server). This tells OPcache to resolve each file to its real, canonical path before looking it up in the cache, which is the correct behaviour for any environment serving PHAR archives or using symbolic links.

You may worry about performance. Don't. The additional real-path resolution is a single realpath() call per cached file, and it is only performed once every opcache.revalidate_freq seconds (typically 2). The performance impact on a Joomla or WordPress site is negligible – effectively unmeasurable in real-world use. Both CMS platforms already resolve thousands of file paths on every request; one extra resolution per cached file adds nothing you could notice.