hash_equals for anything that arrived in a request

String comparison short-circuits on the first differing byte, which leaks how much of a secret an attacker has guessed.

// timing varies with the length of the common prefix
if ($signature === $expected) { }

// constant time, for equal-length strings
if (hash_equals($expected, $signature)) { }

// the argument order matters for a different reason:
// hash_equals leaks the length of the FIRST argument,
// so the known-good value goes first.

The argument order is the detail that is almost always wrong in code that otherwise gets this right — the function is constant-time with respect to content and not with respect to length, so the expected value belongs first. It applies to signatures, tokens, API keys and anything else compared against a value from a request; it does not apply to a password, which should be going through password_verify instead.