CompiledCache
in package
The compiled cache: a loaded, converted configuration written as a PHP file, so the next request includes it instead of parsing the document.
Why
PHP is shared-nothing: every request starts with an empty process, and Cooper's own cache lives in process memory. Loading eagerly at startup would otherwise mean parsing every document on every request. A PHP file is the one thing PHP keeps between requests for free -- opcache holds its compiled form, and its constant arrays, in shared memory.
When it is used
Only while still valid. A compiled file records what its load
depended on (Cooper's LoadTrace):
- every file the load read, with modification time and size;
- every filesystem import's expansion -- its root, its pattern, and
the files it matched -- expanded again on every check, so a file
added where
import "parts/*.casc"looks (or removed from there) counts, though the load never read it; - every environment variable the document read (values,
${?NAME}guards, import paths,${COOPER_ENV}), as a salted HMAC of the value, never the value itself.
A load compares all three before using the file; any difference, and the
document is loaded afresh and the file rewritten. Environment values
are read the way Cooper reads them -- .env files, the real
environment, the env option -- so a changed .env counts.
Not compiled at all, and loaded afresh every time, is a load whose
result has nothing to fingerprint: one that called a resolvers
entry (its answer could change any time), one given importSchemes,
or one holding a value PhpExport cannot write. Nor is a load that
read a file modified within the last second: a second edit in the
same second would keep the modification time the file is fingerprinted
by (git's "racy" entries, and the same answer); the next load
compiles it.
What is baked in and not fingerprinted: the answers of consumer
tags and !module(...). The modules mapping and the tag names are
part of the file's name, so a different mapping gets a different file;
a changed tag implementation needs cache:clear (part of any
deploy).
Security
The file holds the configuration as the application sees it --
revealed secrets included -- and is code PHP will run. So it is
written atomically (a temporary file renamed over it, so a request
never includes half a file) with mode 0600 into a directory created
0700, and is never included unless it is owned by this process's
user and writable by nobody else; one that fails the check is ignored
and rewritten. Keep the cache directory out of the web root, out of
version control, and out of backups that are less protected than the
secrets themselves.
Table of Contents
Constants
- FORMAT : mixed = 2
- Bumped whenever the file's layout changes, so an older file is simply invalid.
- PREFIX : mixed = 'cooper-config-'
- Every compiled file's name starts with this; `clear()` removes nothing else.
Methods
- clear() : int
- Removes every compiled file in `$dir` (and any temporary file an interrupted write left behind), and nothing else.
- defaultDirectory() : string
- Where compiled files go by default: `<root>/var/cache/cooper-config` -- `var/` being where Symfony, and PHP projects generally, keep what they generate.
- __construct() : mixed
- forget() : void
- Drops opcache's copy of `$file`, which with `opcache.validate_timestamps=0` would otherwise be served forever.
- hash() : string
- stamp() : array{0: int, 1: int}|null
- trustworthy() : bool
- Owned by this process's user, writable by nobody else: a file anybody else could have written is code nobody vetted.
- version() : string
- writeAtomically() : bool
Constants
FORMAT
Bumped whenever the file's layout changes, so an older file is simply invalid.
public
mixed
FORMAT
= 2
PREFIX
Every compiled file's name starts with this; `clear()` removes nothing else.
private
mixed
PREFIX
= 'cooper-config-'
Methods
clear()
Removes every compiled file in `$dir` (and any temporary file an interrupted write left behind), and nothing else.
public
static clear(string $dir) : int
Parameters
- $dir : string
-
the cache directory
Return values
int —how many compiled files were removed
defaultDirectory()
Where compiled files go by default: `<root>/var/cache/cooper-config` -- `var/` being where Symfony, and PHP projects generally, keep what they generate.
public
static defaultDirectory(string $root) : string
Parameters
- $root : string
-
the project root
Return values
string —the directory
__construct()
private
__construct() : mixed
forget()
Drops opcache's copy of `$file`, which with `opcache.validate_timestamps=0` would otherwise be served forever.
private
static forget(string $file) : void
Parameters
- $file : string
hash()
private
static hash(string $salt, string $name, string $value) : string
Parameters
- $salt : string
- $name : string
- $value : string
Return values
stringstamp()
private
static stamp(string $path) : array{0: int, 1: int}|null
Parameters
- $path : string
Return values
array{0: int, 1: int}|null —modification time and size, or null for a missing path
trustworthy()
Owned by this process's user, writable by nobody else: a file anybody else could have written is code nobody vetted.
private
static trustworthy(string $file) : bool
Parameters
- $file : string
Return values
boolversion()
private
static version(string $package) : string
Parameters
- $package : string
Return values
stringwriteAtomically()
private
static writeAtomically(string $file, string $source) : bool
Parameters
- $file : string
- $source : string