wppaste
WordPress

ParagonIE_Sodium_Compat::use_fallback( string $sodium_func_name = '' ): bool

Source
wp-includes/sodium_compat/src/Compat.php:4491

Checks whether ParagonIE_Sodium_Compat should hand off to the native libsodium extension instead of its bundled PHP implementation. It looks for the legacy PECL "libsodium" extension on PHP 5.3 or later, and forces the PHP fallback when the class's internal disableFallbackForUnitTests flag is set. Because it is protected, it is only ever called from inside the other ParagonIE_Sodium_Compat methods that WordPress relies on for signing, hashing and encryption. Passing a $sodium_func_name narrows the check further, confirming that specific function actually exists under the old \Sodium\ namespace before it is trusted.

Should we use the libsodium core function instead? This is always a good idea, if it's available. (Unless we're in the middle of running our unit test suite.)

Description

If ext/libsodium is available, use it. Return TRUE.
Otherwise, we have to use the code provided herein. Return FALSE.

Compatibility

WordPress
core
PHP
7.4–8.6-dev
  • 6.7.7
  • 6.8.8
  • 6.9.7
  • 7.0.4
  • 7.1.0

Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.

Parameters

$sodium_func_namestringoptional
Default: ''

Return value

bool

Code examples

Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.

Check whether WordPress is using the native libsodium extension or the PHP fallback

Reflection is needed because use_fallback() is a protected method on ParagonIE_Sodium_Compat.

$reflection = new ReflectionMethod( 'ParagonIE_Sodium_Compat', 'use_fallback' );
$reflection->setAccessible( true );

$uses_native = $reflection->invoke( null );

printf(
	'WordPress will use the native libsodium extension: %s',
	esc_html( $uses_native ? 'yes' : 'no' )
);

In real plugin code you would not call use_fallback() at all; just call a public method like crypto_box() and let it decide internally.

Check whether a specific legacy Sodium function is callable

Passing a function name makes use_fallback() also confirm that exact \Sodium\ function exists before returning true.

$reflection = new ReflectionMethod( 'ParagonIE_Sodium_Compat', 'use_fallback' );
$reflection->setAccessible( true );

$function_name = 'crypto_box_seal';
$is_callable   = $reflection->invoke( null, $function_name );

printf(
	'\\Sodium\\%s() is callable on this server: %s',
	esc_html( $function_name ),
	esc_html( $is_callable ? 'yes' : 'no' )
);

On almost every current PHP install this prints "no", since PHP 7.2+ ships sodium as ext-sodium rather than the old PECL libsodium extension.

Common problems and fixes · 4

Why does use_fallback() always return false even though sodium works fine on my server?

The source checks extension_loaded('libsodium'), which is the name of the old PECL extension, not PHP's built-in sodium extension that ships from PHP 7.2 onward. On modern PHP that check is false, so use_fallback() always reports no native extension and the pure-PHP compat code runs instead. - This is expected and does not mean encryption is broken. - The public crypto_* methods still work correctly either way, just via the bundled PHP implementation.

Why can't I call ParagonIE_Sodium_Compat::use_fallback() from my own plugin code?

It is declared protected, so PHP only allows it to be called from inside the class itself or a subclass, which is why the internal crypto_* methods listed as callers can use it but external code gets a fatal error. - Call one of the public methods (crypto_box(), crypto_auth(), etc.) instead; they call use_fallback() for you. - If you truly need the raw result for debugging, use ReflectionMethod::setAccessible(true) as shown above.

Why does the result change when I run my code inside PHPUnit but not in production?

The source short-circuits to false whenever the static property self::$disableFallbackForUnitTests is set, which the sodium_compat test suite toggles to force the PHP implementation and get consistent, reproducible test results regardless of what extensions the test runner has installed.

Does the $sodium_func_name argument make the check stricter or looser?

Stricter. With no argument, use_fallback() only confirms the extension is loaded and unit-test overrides are off. Pass a function name and it additionally runs is_callable() against that exact \Sodium\ prefixed function, so a missing individual function still forces the PHP fallback even if the extension itself loaded.

Alternatives and related functions

ParagonIE_Sodium_Compat::crypto_box
When you actually need to perform authenticated public-key encryption, call this directly since it already invokes use_fallback() internally to pick the right implementation.
ParagonIE_Sodium_Compat::crypto_auth
When you just need to generate or verify a message authentication code, use this public method instead of probing use_fallback() yourself.
ParagonIE_Sodium_Compat::bin2hex
When you only need libsodium's constant-time binary-to-hex conversion, call this method directly rather than checking which backend will handle it.

Performance profile

How much work a call to ParagonIE_Sodium_Compat::use_fallback() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.

Cost class
Trivial

Touches nothing outside its own arguments.

Scaling
Constant

No loop in the body: the same number of instructions runs whatever you pass in.

Instructions
7–21

Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 24.

Plugin surface
None

Nothing here hands control to plugin code.

Called by
50

50 places in core call this, so the cost is paid more often than your own code shows.

What one call costs · 4 distinct outcomes

One number would be a lie: the work depends on which branch runs. These are every distinct cost ParagonIE_Sodium_Compat::use_fallback() can have, taken from its control-flow graph on PHP 8.5.

WhenInstructionsCalls it makes
$res !== null7–11none
$res === null12–17extension_loaded()
$res !== null && $res !== false && !empty($sodium_func_name)15is_callable()
$res === null && $res !== false && !empty($sodium_func_name)20–21extension_loaded(), is_callable()

Across PHP versions

Compiles the same on PHP 7.4, 8.1, 8.2, 8.3, 8.4, 8.5 and 8.6-dev: 24 instructions, 7–21 executed per call, 5 branches. The work does not change between versions.

An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.

Used by · 50

Show all 50

Source code

    protected static function use_fallback($sodium_func_name = '')    {        static $res = null;        if ($res === null) {            $res = extension_loaded('libsodium') && PHP_VERSION_ID >= 50300;        }        if ($res === false) {            // No libsodium installed            return false;        }        if (self::$disableFallbackForUnitTests) {            // Don't fallback. Use the PHP implementation.            return false;        }        if (!empty($sodium_func_name)) {            return is_callable('\\Sodium\\' . $sodium_func_name);        }        return true;    }

Changelog

Unchanged from 6.7.7 through 7.1.0.

  1. 6.7.7
  2. 6.8.8
  3. 6.9.7
  4. 7.0.4
  5. 7.1.0

Signature, return type and hooks compared across 5 parsed releases.

About this page

Parsed data
Generated from the wordpress-develop 7.1.0 tag, from src/wp-includes/sodium_compat/src/Compat.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.
Corrections
Something wrong on this page? Report it and it gets fixed in the next regeneration.