@bruandet I have the same problem on all my websites. This is my analysis, which may help you reproduce and fix the error:
◉ Error Message
PHP Fatal error: Uncaught UnexpectedValueException: DirectoryIterator::__construct(/var/www/.../wp-content/session): Failed to open directory: No such file or directory in /var/www/.../wp-content/plugins/ninjafirewall/lib/class-helpers.php:29
◉ The Problem
The NFWSESSION_DIR constant is defined inconsistently in two different files:
1. In ninjafirewall.php (line 71) (incorrect):
define('NFWSESSION_DIR', NFW_LOG_DIR .'/session');
Since NFW_LOG_DIR = WP_CONTENT_DIR, this resolves to:
wp-content/session ❌
2. In lib/firewall.php (line 89) (correct):
define('NFWSESSION_DIR', "{$nfw_['log_dir']}/session" );
Since $nfw_['log_dir'] = wp-content/nfwlog, this resolves to:
wp-content/nfwlog/session ✅
3. Additional inconsistency in lib/class-nfw-session.php (line 46):
self::$session_dir = NFW_LOG_DIR .'/sessions'; // Note: 'sessions' with 's'
This fallback would resolve to:
wp-content/sessions (yet another different path!)
◉ How the Bug Manifests
- When the firewall is active: The
firewall.php script runs first and correctly defines NFWSESSION_DIR as wp-content/nfwlog/session. Session files are created in the correct location.
- When the cron job runs: The garbage collector (
nfwgccron) is triggered via WP-CLI or WordPress cron. In this context, ninjafirewall.php loads first (without the firewall), and defines NFWSESSION_DIR incorrectly as wp-content/session.
- The crash: The garbage collector in
lib/utils.php (line 633) calls:
$list = NinjaFirewall_helpers::nfw_glob( NFWSESSION_DIR, '^sess_', true, true );
This attempts to iterate over wp-content/session/ which doesn’t exist, causing the DirectoryIterator to throw an UnexpectedValueException.
◉ Fix
Primary Fix (ninjafirewall.php, line 71)
Change:
define('NFWSESSION_DIR', NFW_LOG_DIR .'/session');
To:
define('NFWSESSION_DIR', NFW_LOG_DIR .'/nfwlog/session');
Secondary Fix (lib/class-nfw-session.php, line 46)
For consistency, also change:
self::$session_dir = NFW_LOG_DIR .'/sessions';
To:
self::$session_dir = NFW_LOG_DIR .'/nfwlog/session';
Defensive Fix (lib/class-helpers.php, line 27)
As an additional safeguard, add a directory existence check in the nfw_glob() function:
public static function nfw_glob( $directory, $regex, $pathname = false, $sortname = true ) {
$list = [];
// Add this check to prevent crashes if directory doesn't exist
if ( ! is_dir( $directory ) ) {
return $list;
}
foreach ( new DirectoryIterator( $directory ) as $finfo ) {
// ... rest of the function
}
}
The same defensive check should be added to the nfw_glob_recursive() function in the same file.
◉ Steps to Reproduce
- Install NinjaFirewall 4.8.1
- Enable the firewall (this creates sessions in the correct directory)
- Wait for the garbage collector cron to run, or trigger it manually via WP-CLI:
wp cron event run nfwgccron
- Observe the fatal error in the PHP error log