| Server IP : 208.122.213.31 / Your IP : 216.73.216.45 Web Server : Apache System : Linux msd6191.mjhst.com 4.18.0-553.137.1.el8_10.x86_64 #1 SMP Wed Jun 24 11:40:24 UTC 2026 x86_64 User : WHMCS_MIA_382 ( 1001) PHP Version : 7.4.33 Disable Function : NONE MySQL : ON | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/httpd/html/baberankings.com/wp-content/plugins/w3-total-cache/ |
Upload File : |
<?php
/**
* File: Util_WpmuBlogmap.php
*
* @package W3TC
*/
namespace W3TC;
/**
* Class Util_WpmuBlogmap
*
* phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged
* phpcs:disable WordPress.WP.AlternativeFunctions
*/
class Util_WpmuBlogmap {
/**
* Content of files by filename
*
* @var array
* @static
*/
private static $content_by_filename = array();
/**
* RT9-180 sub-C: per-IP rate limit for first-frontend blog
* discovery to bound enumeration-driven amplification of
* filesystem writes.
*
* The dedup at {@see self::register_new_item()} already bounds
* the write to once per blog URL ever. This rate limit
* additionally bounds how fast a single source IP can trigger
* discoveries across multiple subsite URLs (multisite-
* enumeration scenario). Legitimate-user threshold: a real
* visitor does not visit 5 brand-new subsites within 60 seconds
* from one IP. A synthetic monitor probing all subsites at once
* sees a slight delay on the 6th+ URL — recoverable on the next
* window — not a denial.
*
* @since 2.10.0
*
* @var string
*/
const RATE_LIMIT_TRANSIENT_PREFIX = 'w3tc_blogmap_register_rate_';
/**
* Maximum first-frontend registrations from one IP per window.
*
* @since 2.10.0
*
* @var int
*/
const RATE_LIMIT_MAX_PER_WINDOW = 5;
/**
* Rate-limit window in seconds.
*
* @since 2.10.0
*
* @var int
*/
const RATE_LIMIT_WINDOW_SECONDS = 60;
/**
* Generates a unique blog map filename based on the blog's home URL.
*
* This method determines the appropriate blog map file path and name by hashing the blog's home URL. The file path structure
* varies depending on whether `W3TC_BLOG_LEVELS` is defined. If defined, the file path includes subdirectories based on the
* hashed URL to prevent file collisions in multi-site environments.
*
* @param string $blog_home_url The home URL of the blog (e.g., 'https://example.com').
*
* @return string The full file path and name for the blog map file.
*/
public static function blogmap_filename_by_home_url( $blog_home_url ) {
if ( ! defined( 'W3TC_BLOG_LEVELS' ) ) {
return W3TC_CACHE_BLOGMAP_FILENAME;
} else {
$filename = dirname( W3TC_CACHE_BLOGMAP_FILENAME ) . '/' . basename( W3TC_CACHE_BLOGMAP_FILENAME, '.json' ) . '/';
$s = md5( $blog_home_url );
for ( $n = 0; $n < W3TC_BLOG_LEVELS; $n++ ) {
$filename .= substr( $s, $n, 1 ) . '/';
}
return $filename . basename( W3TC_CACHE_BLOGMAP_FILENAME );
}
}
/**
* Retrieves data for the current blog based on its host and URL structure.
*
* This method attempts to identify the current blog in a WordPress multisite network using either a subdomain or subdirectory-based
* configuration. If the blog is not found, it registers the blog's host or URL to be added to the blog map.
*
* @return array|null The blog data if found, or null if the blog is not registered.
*
* @throws Exception If errors occur during environment or data retrieval.
*
* @details
* - **Subdomain Configuration**: Tries to retrieve blog data using the host.
* - **Subdirectory Configuration**: Iteratively checks parent directories in the URL path.
* - **Global Registration**: Sets `$GLOBALS['w3tc_blogmap_register_new_item']` to register the blog if it cannot be found in the map.
*/
public static function get_current_blog_data() {
$host = Util_Environment::host();
// subdomain.
if ( Util_Environment::is_wpmu_subdomain() ) {
$blog_data = self::try_get_current_blog_data( $host );
if ( is_null( $blog_data ) ) {
$GLOBALS['w3tc_blogmap_register_new_item'] = $host;
}
return $blog_data;
} else {
// try subdir blog.
$w3tc_url = $host . ( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '' ); // phpcs:ignore
$pos = strpos( $w3tc_url, '?' );
if ( false !== $pos ) {
$w3tc_url = substr( $w3tc_url, 0, $pos );
}
$w3tc_url = rtrim( $w3tc_url, '/' );
$start_url = $w3tc_url;
for ( ;; ) {
$blog_data = self::try_get_current_blog_data( $w3tc_url );
if ( ! is_null( $blog_data ) ) {
return $blog_data;
}
$pos = strrpos( $w3tc_url, '/' );
if ( false === $pos ) {
break;
}
$w3tc_url = rtrim( substr( $w3tc_url, 0, $pos ), '/' );
}
$GLOBALS['w3tc_blogmap_register_new_item'] = $start_url;
return null;
}
}
/**
* Attempts to retrieve blog data for a given URL from the blog map.
*
* This method checks if the blog data corresponding to the provided URL exists in the cached data or retrieves it from the
* appropriate file. If the blog data is found, it returns the relevant information; otherwise, it returns `null`.
*
* @param string $w3tc_url The home URL of the blog to look up.
*
* @return array|null The blog data if found, or null if the blog is not registered.
*
* @throws Exception If file reading or decoding errors occur.
*
* @details
* - **File Caching**: The method uses `self::$content_by_filename` to cache previously read blog map files, reducing redundant
* file operations.
* - **File Retrieval**: If the data is not cached, it attempts to read the file using the filename generated from
* `blogmap_filename_by_home_url`.
* - **JSON Decoding**: Reads and decodes JSON data from the file if it exists. Invalid or malformed JSON will result in `null`.
* - **Blog Match**: Checks if the URL exists in the retrieved blog map data. Returns the associated data if a match is found.
*/
public static function try_get_current_blog_data( $w3tc_url ) {
$filename = self::blogmap_filename_by_home_url( $w3tc_url );
if ( isset( self::$content_by_filename[ $filename ] ) ) {
$blog_data = self::$content_by_filename[ $filename ];
} else {
$blog_data = null;
if ( file_exists( $filename ) ) {
$w3tc_data = file_get_contents( $filename );
$blog_data = @json_decode( $w3tc_data, true );
if ( is_array( $blog_data ) ) {
self::$content_by_filename[ $filename ] = $blog_data;
}
}
}
if ( isset( $blog_data[ $w3tc_url ] ) ) {
return $blog_data[ $w3tc_url ];
}
return null;
}
/**
* Registers a new blog in the blog map.
*
* This method adds the current blog to the blog map file if it is not already registered. The blog map associates blog URLs with their
* unique identifiers, supporting both subdomain and subdirectory WordPress multisite installations.
*
* @param object $w3tc_config The configuration object containing settings for the current operation. Specifically, the `common.force_master`
* setting is used to determine the blog type.
*
* @return bool Returns `true` if the blog was successfully registered, or `false` if the blog was already registered or an error occurred.
*
* @details
* - **Multisite Handling**: - Detects whether the multisite is using subdomains or subdirectories to determine the home URL of
* the blog to register.
* - **Validation**: - Ensures that the URL and blog data conform to expected formats and sanitizes the input.
* - **File Operations**: - Reads the existing blog map file if it exists. If the file doesn’t exist, it initializes a new empty map.
* - Uses `file_put_contents_atomic` for safe and atomic file writes.
* - **Caching**: - Clears the cached file content in `self::$content_by_filename` to ensure consistency.
* - **Error Handling**: - Catches exceptions during file operations and returns `false` in case of errors.
*
* @throws \Exception If file operations fail and are not caught by internal error handling.
*/
public static function register_new_item( $w3tc_config ) {
if ( ! isset( $GLOBALS['current_blog'] ) ) {
return false;
}
// Find blog_home_url.
if ( Util_Environment::is_wpmu_subdomain() ) {
$blog_home_url = $GLOBALS['w3tc_blogmap_register_new_item'];
} else {
$home_url = rtrim( get_home_url(), '/' );
if ( 'http://' === substr( $home_url, 0, 7 ) ) {
$home_url = substr( $home_url, 7 );
} elseif ( 'https://' === substr( $home_url, 0, 8 ) ) {
$home_url = substr( $home_url, 8 );
}
if ( substr( $GLOBALS['w3tc_blogmap_register_new_item'], 0, strlen( $home_url ) ) === $home_url ) {
$blog_home_url = $home_url;
} else {
$blog_home_url = $GLOBALS['w3tc_blogmap_register_new_item'];
}
}
// Write contents.
$filename = self::blogmap_filename_by_home_url( $blog_home_url );
if ( ! @file_exists( $filename ) ) {
$blog_ids = array();
} else {
$w3tc_data = @file_get_contents( $filename );
$blog_ids = @json_decode( $w3tc_data, true );
if ( ! is_array( $blog_ids ) ) {
$blog_ids = array();
}
}
if ( isset( $blog_ids[ $blog_home_url ] ) ) {
return false;
}
/**
* RT9-180 sub-C: per-IP rate-limit gate. The per-URL dedup
* above already bounds writes to once per blog URL ever; this
* additional gate caps enumeration-driven amplification from
* a single source IP. On rate-limit we return false — same
* return type as the dedup short-circuit — so the caller in
* Generic_Plugin::init() sees `$do_redirect = false` and the
* request continues with master config. The blog URL will
* register on a subsequent visit once the rate-limit window
* has cleared.
*
* @since 2.10.0
*/
if ( ! self::_rate_limit_allows_write() ) {
return false;
}
$w3tc_data = $w3tc_config->get_boolean( 'common.force_master' ) ? 'm' : 'c';
$blog_home_url = preg_replace( '/[^a-zA-Z0-9\+\.%~!:()\/\-\_]/', '', $blog_home_url );
$blog_ids[ $blog_home_url ] = $w3tc_data . $GLOBALS['current_blog']->blog_id;
$w3tc_data = json_encode( $blog_ids );
try {
Util_File::file_put_contents_atomic( $filename, $w3tc_data );
} catch ( \Exception $ex ) {
return false;
}
/**
* Increment the per-IP counter only on a successful write.
* Dedup short-circuits and write failures don't count against
* the rate limit — legitimate writes are what we throttle.
*/
self::_rate_limit_record_write();
unset( self::$content_by_filename[ $filename ] );
unset( $GLOBALS['w3tc_blogmap_register_new_item'] );
return true;
}
/**
* Compute the per-IP rate-limit transient key.
*
* The raw IP is salted with `wp_salt('nonce')` and hashed so the
* persisted transient does not contain the client IP literal
* (defense against transient-table dumps revealing the visitor
* IP set). Returns empty string when no IP is detected (e.g.
* CLI / WP-Cron without REMOTE_ADDR) — the caller treats empty
* as "no rate limit applies" so legitimate non-HTTP contexts
* are never throttled.
*
* @since 2.10.0
*
* @return string Transient key, or '' when no IP available.
*/
private static function _ip_throttle_key() {
$ip = isset( $_SERVER['REMOTE_ADDR'] )
? (string) \wp_unslash( $_SERVER['REMOTE_ADDR'] ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- IP used only as a transient key segment after wp_unslash.
: '';
if ( '' === $ip ) {
return '';
}
if ( false === \filter_var( $ip, FILTER_VALIDATE_IP ) ) {
return '';
}
$salt = \function_exists( 'wp_salt' ) ? \wp_salt( 'nonce' ) : '';
return self::RATE_LIMIT_TRANSIENT_PREFIX
. \substr( \hash( 'sha256', $ip . '|' . $salt ), 0, 16 );
}
/**
* True when the current request's IP has not yet exhausted its
* registration quota within the active window. Permits writes
* when no IP can be derived (CLI, edge cases) so legitimate
* non-HTTP contexts are never blocked.
*
* @since 2.10.0
*
* @return bool
*/
private static function _rate_limit_allows_write() {
$w3tc_key = self::_ip_throttle_key();
if ( '' === $w3tc_key ) {
return true;
}
$w3tc_count = \get_transient( $w3tc_key );
if ( false === $w3tc_count || ! \is_numeric( $w3tc_count ) ) {
$w3tc_count = 0;
}
return (int) $w3tc_count < self::RATE_LIMIT_MAX_PER_WINDOW;
}
/**
* Increment the per-IP counter after a successful write. No-op
* when no IP can be derived (matching the permissive policy in
* {@see self::_rate_limit_allows_write()}).
*
* @since 2.10.0
*
* @return void
*/
private static function _rate_limit_record_write() {
$w3tc_key = self::_ip_throttle_key();
if ( '' === $w3tc_key ) {
return;
}
$w3tc_count = \get_transient( $w3tc_key );
if ( false === $w3tc_count || ! \is_numeric( $w3tc_count ) ) {
$w3tc_count = 0;
}
\set_transient( $w3tc_key, ( (int) $w3tc_count ) + 1, self::RATE_LIMIT_WINDOW_SECONDS );
}
}