HEX
Server: LiteSpeed
System: Linux twilight.herosite.pro 4.18.0-553.141.2.lve.el8.x86_64 #1 SMP Wed Jul 8 16:10:02 UTC 2026 x86_64
User: owzicwjp (1120)
PHP: 8.2.32
Disabled: show_source, system, shell_exec, passthru, popen, exec
Upload Files
File: /home/owzicwjp/public_html/talennect.akashdairy.com/sitemap.php
<?php
/**
 * ============================================================================
 * AUTO SITEMAP GENERATOR v5.0 - PERFECT EDITION
 * ============================================================================
 * 
 * Support: WordPress (priority) + Static Site
 * 
 * USAGE:
 *   sitemap.php              β†’ Output XML sitemap
 *   sitemap.php?save         β†’ Save to sitemap.xml
 *   sitemap.php?export       β†’ Export to domains.txt (for indexing script)
 *   sitemap.php?debug        β†’ Debug mode with logs
 * 
 * @version 5.0
 * @author  Auto Generated
 */

error_reporting(0); // Suppress errors in production

// ============================================================================
// CONFIGURATION
// ============================================================================

// Leave empty for auto-detect, or set manually: 'https://example.com'
define('SITE_URL', '');

// Output files
define('SITEMAP_FILE', 'sitemap.xml');
define('DOMAINS_FILE', 'domains.txt');

// Priority settings
define('PRIORITY_HOME', 1.0);
define('PRIORITY_PAGE', 0.8);
define('PRIORITY_POST', 0.6);
define('PRIORITY_PRODUCT', 0.7);
define('PRIORITY_ARCHIVE', 0.4);

// ============================================================================
// WORDPRESS: EXCLUDE POST TYPES (internal system only)
// ============================================================================

$WP_EXCLUDE_TYPES = [
    // WordPress Core Internal
    'revision',
    'nav_menu_item',
    'custom_css',
    'customize_changeset',
    'oembed_cache',
    'user_request',
    
    // WordPress Block Editor Internal
    'wp_block',
    'wp_template',
    'wp_template_part',
    'wp_global_styles',
    'wp_navigation',
    'wp_font_face',        // Font face - HARUS exclude
    'wp_font_family',      // Font family - HARUS exclude
    'wp_pattern',
    
    // Plugin Internal
    'acf-field',
    'acf-field-group',
    'elementor_library',
    'elementor_font',
    'elementor_icons',
];

// ============================================================================
// WORDPRESS: EXCLUDE URL PATTERNS
// ============================================================================

$WP_EXCLUDE_URL_PATTERNS = [
    // WordPress Internal URLs
    '#/wp-json/#i',
    '#/feed/?$#i',
    '#/embed/?$#i',
    '#/trackback/?$#i',
    '#\?preview=true#i',
    '#/attachment/#i',
];

// ============================================================================
// STATIC SITE: EXCLUDE DIRECTORIES
// ============================================================================

$STATIC_EXCLUDE_DIRS = [
    // WordPress Core
    'wp-admin',
    'wp-includes',
    'wp-content',
    
    // Asset Folders
    'css',
    'js',
    'scss',
    'sass',
    'less',
    'fonts',
    'images',
    'img',
    'assets',
    'media',
    'uploads',
    'icons',
    
    // System Folders
    'node_modules',
    'resources',
    'Modules',
    'vendor',
    'cache',
    'tmp',
    'temp',
    'logs',
    'backup',
    'backups',
    'private',
    'cgi-bin',
    '.git',
    '.svn',
    
    // Backup Plugins
    'jetbackup',
    'wpvivid',
    'updraft',
    'backwpup',
    'akeeba',
];

// ============================================================================
// STATIC SITE: EXCLUDE FILE PATTERNS
// ============================================================================

$STATIC_EXCLUDE_FILES = [
    // ----- Non-HTML Extensions -----
    '#\.xml$#i',
    '#\.json$#i',
    '#\.txt$#i',
    '#\.log$#i',
    '#\.css$#i',
    '#\.js$#i',
    '#\.map$#i',
    '#\.sql$#i',
    '#\.bak$#i',
    '#\.zip$#i',
    '#\.gz$#i',
    '#\.tar$#i',
    '#\.rar$#i',
    '#\.md$#i',
    
    // ----- Hidden Files -----
    '#^\.#',
    
    // ----- WordPress Core Files -----
    '#^wp-.*\.php$#i',
    '#^xmlrpc\.php$#i',
    '#^readme\.html$#i',
    '#^license\.txt$#i',
    
    // ----- Config & System -----
    '#^wp-config#i',
    '#^\.htaccess$#i',
    '#^\.htpasswd$#i',
    '#^php\.ini$#i',
    '#error_log$#i',
    
    // ----- Sitemap Files -----
    '#sitemap.*\.xml$#i',
    '#^sitemap\.php$#i',
    
    // ----- Verification Files -----
    '#^google[a-z0-9]*\.html$#i',
    '#^BingSiteAuth\.xml$#i',
    '#^yandex_[a-z0-9]+\.html$#i',
    
    // ===== MALWARE / BACKDOOR PATTERNS =====
    
    // Random 2-6 char filenames (common malware)
    '#^[a-z]{2,3}[0-9]{1,2}\.php$#i',          // ss.php, h87.php, dn8q.php
    '#^[0-9]{1,2}[a-z]{2,4}\.php$#i',          // 3u6o.php
    '#^[a-z]{2,6}[0-9]+\.php$#i',              // hfvse0.php, mp8t.php
    '#^[a-z0-9]{7,}\.php$#i',                  // zfks84enp2.php, cauj5p0y.php
        // ----- Laravel Modules Internal (BasicPayment, dll) -----
    '#^Modules/#i',                          // Blokir SEMUA folder Modules
    '#\.blade\.php$#i',                      // Blokir semua Blade template
    '#database/migrations/#i',               // Blokir migration files
    '#resources/views/#i',                   // Blokir semua views folder
    '#Modules/.*(database|resources|config|routes|Providers|Console)/#i', // general Laravel module junk
        // ===== BARU: Yang masih lolos sekarang =====
    '#/routes/#i',                          // Seluruh folder routes
    '#/public/index\.php$#i',               // Laravel entry point
    '#/public/backend/.*(test|demo|example|clockpicker)/#i',  // Test files backend
    '#/public/backend/clockpicker/#i',      // Khusus clockpicker test

    // ===== BONUS LARAVEL STANDARD (biar aman selamanya) =====
    '#/app/#i',
    '#/bootstrap/#i',
    '#/config/#i',
    '#/database/#i',
    '#/storage/#i',
    '#/tests/#i',
    '#/vendor/#i',
    '#/public/(storage|cache)/#i',          // storage di public kadang kebawa
    '#^app/#i',                    // app/Console, app/Http, app/Models, dll
    '#^bootstrap/#i',
    '#^config/#i',                 // semua config/*.php
    '#^database/#i',               // semua migration
    '#^documentation/#i',          // docs folder
    '#^index\.php$#i',             // root index.php
    '#^server\.php$#i',            // Laravel server.php
    // Known Backdoor Names
    '#fmanager#i',
    '#filemanager#i',
    '#^shell\.php$#i',
    '#^c99\.php$#i',
    '#^r57\.php$#i',
    '#^wso\.php$#i',
    '#^b374k#i',
    '#^alfa#i',
    '#^mini\.php$#i',
    '#^up\.php$#i',
    '#^upload\.php$#i',
    '#^uploader#i',
    '#^mailer#i',
    '#^priv8#i',
    '#^bypass#i',
    
    // Suspicious Generic Names
    '#^content\.php$#i',
    '#^comment\.php$#i',
    '#^great\.php$#i',
    '#^good\.php$#i',
    '#^waff\.php$#i',
    '#^test\.php$#i',
    '#^info\.php$#i',
    '#^phpinfo#i',
    
    // Domain-named PHP (suspicious)
    '#\.(com|net|org|co\.in|co\.id)\.php$#i',
];

// ============================================================================
// STATIC SITE: WHITELIST PATTERNS (always include)
// ============================================================================

$STATIC_WHITELIST = [
    // Main pages
    '#^index\.(html|htm|php)$#i',
    '#^home\.(html|htm|php)$#i',
    '#^default\.(html|htm|php)$#i',
    
    // Common pages
    '#^about\.(html|htm|php)$#i',
    '#^contact\.(html|htm|php)$#i',
    '#^services?\.#i',
    '#^products?\.#i',
    '#^portfolio\.#i',
    '#^gallery\.#i',
    '#^blog\.#i',
    '#^news\.#i',
    '#^faq\.#i',
    '#^pricing\.#i',
    '#^features?\.#i',
    '#^team\.#i',
    '#^careers?\.#i',
    
    // E-commerce
    '#^shop\.#i',
    '#^store\.#i',
    '#^cart\.#i',
    '#^checkout\.#i',
    '#^thankyou\.#i',
    '#^thank-you\.#i',
    
    // Other
    '#^terms\.#i',
    '#^privacy\.#i',
    '#^schema\.#i',
    '#^g33k\.#i',
];

// Allowed extensions
$INCLUDE_EXT = ['html', 'htm', 'php'];

// ============================================================================
// SITEMAP CLASS
// ============================================================================

class Sitemap {
    private $urls = [];
    private $rootPath;
    private $siteUrl;
    private $isWP = false;
    private $db = null;
    private $dbPrefix = 'wp_';
    private $log = [];
    
    public function __construct() {
        $this->rootPath = dirname(__FILE__);
        $this->siteUrl = $this->detectSiteUrl();
        $this->detectWordPress();
    }
    
    /**
     * Detect site URL
     */
    private function detectSiteUrl() {
        if (defined('SITE_URL') && SITE_URL !== '') {
            return rtrim(SITE_URL, '/') . '/';
        }
        
        $protocol = 'http://';
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
            $protocol = 'https://';
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
            $protocol = 'https://';
        }
        
        $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
        $scriptPath = dirname($_SERVER['SCRIPT_NAME'] ?? '');
        $basePath = ($scriptPath === '/' || $scriptPath === '\\') ? '' : $scriptPath;
        
        return $protocol . $host . $basePath . '/';
    }
    
    /**
     * Detect WordPress and connect to database
     */
    private function detectWordPress() {
        $wpConfig = $this->rootPath . '/wp-config.php';
        
        if (!file_exists($wpConfig)) {
            $this->log[] = ['type' => 'info', 'msg' => 'Mode: Static Site (no wp-config.php)'];
            return;
        }
        
        $this->isWP = true;
        $configContent = @file_get_contents($wpConfig);
        
        if (!$configContent) {
            $this->log[] = ['type' => 'error', 'msg' => 'Cannot read wp-config.php'];
            $this->isWP = false;
            return;
        }
        
        // Extract DB credentials
        $dbName = $this->extractWpDefine($configContent, 'DB_NAME');
        $dbUser = $this->extractWpDefine($configContent, 'DB_USER');
        $dbPass = $this->extractWpDefine($configContent, 'DB_PASSWORD');
        $dbHost = $this->extractWpDefine($configContent, 'DB_HOST');
        
        if (!$dbHost) $dbHost = 'localhost';
        
        // Extract table prefix
        if (preg_match('/\$table_prefix\s*=\s*[\'"]([^\'"]+)[\'"]/', $configContent, $matches)) {
            $this->dbPrefix = $matches[1];
        }
        
        $this->log[] = ['type' => 'info', 'msg' => "WordPress detected (prefix: {$this->dbPrefix})"];
        
        if (!$dbName || !$dbUser) {
            $this->log[] = ['type' => 'error', 'msg' => 'Database credentials not found'];
            $this->isWP = false;
            return;
        }
        
        // Connect to database
        try {
            $dsn = "mysql:host={$dbHost};dbname={$dbName};charset=utf8mb4";
            $this->db = new PDO($dsn, $dbUser, $dbPass !== null ? $dbPass : '');
            $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            
            // Get site URL from database
            $stmt = $this->db->query("SELECT option_value FROM {$this->dbPrefix}options WHERE option_name = 'siteurl' LIMIT 1");
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if ($row && !empty($row['option_value'])) {
                $this->siteUrl = rtrim($row['option_value'], '/') . '/';
            }
            
            $this->log[] = ['type' => 'success', 'msg' => "Database connected: {$dbName}"];
            
        } catch (PDOException $e) {
            $this->log[] = ['type' => 'error', 'msg' => 'Database error: ' . $e->getMessage()];
            $this->isWP = false;
            $this->db = null;
        }
    }
    
    /**
     * Extract WordPress define() value
     */
    private function extractWpDefine($content, $name) {
        // Match: define('NAME', 'value') or define("NAME", "value")
        $pattern = '/define\s*\(\s*[\'"]' . preg_quote($name, '/') . '[\'"]\s*,\s*[\'"]([^\'"]*)[\'"]\s*\)/i';
        
        if (preg_match($pattern, $content, $matches)) {
            return $matches[1];
        }
        return null;
    }
    
    /**
     * Generate sitemap
     */
    public function generate() {
        $this->log[] = ['type' => 'info', 'msg' => 'Site URL: ' . $this->siteUrl];
        
        // Add homepage
        $this->addUrl($this->siteUrl, 'daily', PRIORITY_HOME);
        
        // Generate based on site type
        if ($this->isWP && $this->db !== null) {
            $this->generateWordPress();
        } else {
            $this->generateStatic();
        }
        
        $this->log[] = ['type' => 'success', 'msg' => 'Total URLs: ' . count($this->urls)];
        
        return $this;
    }
    
    // ========================================================================
    // WORDPRESS GENERATOR
    // ========================================================================
    
    private function generateWordPress() {
        global $WP_EXCLUDE_TYPES, $WP_EXCLUDE_URL_PATTERNS;
        
        $p = $this->dbPrefix;
        
        // Get permalink structure
        $stmt = $this->db->query("SELECT option_value FROM {$p}options WHERE option_name = 'permalink_structure' LIMIT 1");
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        $prettyPermalinks = !empty($row['option_value']);
        
        $this->log[] = ['type' => 'info', 'msg' => 'Permalinks: ' . ($prettyPermalinks ? 'Pretty URLs' : 'Default')];
        
        // Build exclude types placeholder
        $excludePlaceholders = implode(',', array_fill(0, count($WP_EXCLUDE_TYPES), '?'));
        
        // Query all published posts
        $sql = "SELECT ID, post_name, post_type, post_modified, post_parent 
                FROM {$p}posts 
                WHERE post_status = 'publish' 
                AND post_type NOT IN ({$excludePlaceholders})
                AND post_name != ''
                ORDER BY post_type ASC, post_date DESC";
        
        $stmt = $this->db->prepare($sql);
        $stmt->execute($WP_EXCLUDE_TYPES);
        
        $counts = ['post' => 0, 'page' => 0, 'product' => 0, 'other' => 0];
        
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $postType = $row['post_type'];
            $postName = $row['post_name'];
            $lastmod = date('c', strtotime($row['post_modified']));
            $url = '';
            
            // Build URL based on post type
            switch ($postType) {
                case 'post':
                    $url = $prettyPermalinks 
                        ? $this->siteUrl . $postName . '/'
                        : $this->siteUrl . '?p=' . $row['ID'];
                    $this->addUrl($url, 'weekly', PRIORITY_POST, $lastmod);
                    $counts['post']++;
                    break;
                    
                case 'page':
                    $pagePath = $this->getPagePath($row['ID']);
                    $url = $this->siteUrl . $pagePath;
                    $this->addUrl($url, 'monthly', PRIORITY_PAGE, $lastmod);
                    $counts['page']++;
                    break;
                    
                case 'product':
                    $url = $this->siteUrl . 'product/' . $postName . '/';
                    $this->addUrl($url, 'weekly', PRIORITY_PRODUCT, $lastmod);
                    $counts['product']++;
                    break;
                    
                default:
                    // Custom post types (product_variation, shop_coupon, etc.)
                    $url = $this->siteUrl . $postType . '/' . $postName . '/';
                    $this->addUrl($url, 'weekly', 0.5, $lastmod);
                    $counts['other']++;
                    break;
            }
        }
        
        $this->log[] = ['type' => 'info', 'msg' => "Posts: {$counts['post']}, Pages: {$counts['page']}, Products: {$counts['product']}, Other: {$counts['other']}"];
        
        // Get categories
        $catCount = $this->generateTaxonomy('category', 'category/');
        
        // Get tags
        $tagCount = $this->generateTaxonomy('post_tag', 'tag/');
        
        // Get product categories (WooCommerce)
        $prodCatCount = $this->generateTaxonomy('product_cat', 'product-category/');
        
        if ($catCount || $tagCount || $prodCatCount) {
            $this->log[] = ['type' => 'info', 'msg' => "Categories: {$catCount}, Tags: {$tagCount}, Product Cats: {$prodCatCount}"];
        }
    }
    
    /**
     * Generate taxonomy URLs
     */
    private function generateTaxonomy($taxonomy, $prefix) {
        $p = $this->dbPrefix;
        $count = 0;
        
        try {
            $sql = "SELECT t.slug 
                    FROM {$p}terms t
                    INNER JOIN {$p}term_taxonomy tt ON t.term_id = tt.term_id
                    WHERE tt.taxonomy = ?
                    AND tt.count > 0
                    AND t.slug NOT IN ('uncategorized', 'uncategorised')";
            
            $stmt = $this->db->prepare($sql);
            $stmt->execute([$taxonomy]);
            
            while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                $url = $this->siteUrl . $prefix . $row['slug'] . '/';
                $this->addUrl($url, 'weekly', PRIORITY_ARCHIVE);
                $count++;
            }
        } catch (PDOException $e) {
            // Taxonomy might not exist, ignore
        }
        
        return $count;
    }
    
    /**
     * Get hierarchical page path
     */
    private function getPagePath($pageId) {
        $path = [];
        $p = $this->dbPrefix;
        $maxDepth = 10;
        
        while ($pageId > 0 && $maxDepth-- > 0) {
            try {
                $stmt = $this->db->prepare("SELECT post_name, post_parent FROM {$p}posts WHERE ID = ? LIMIT 1");
                $stmt->execute([$pageId]);
                $page = $stmt->fetch(PDO::FETCH_ASSOC);
                
                if ($page && !empty($page['post_name'])) {
                    array_unshift($path, $page['post_name']);
                    $pageId = (int)$page['post_parent'];
                } else {
                    break;
                }
            } catch (PDOException $e) {
                break;
            }
        }
        
        return implode('/', $path) . '/';
    }
    
    // ========================================================================
    // STATIC SITE GENERATOR
    // ========================================================================
    
    private function generateStatic($dir = null, $relativePath = '') {
        global $STATIC_EXCLUDE_DIRS, $STATIC_EXCLUDE_FILES, $STATIC_WHITELIST, $INCLUDE_EXT;
        
        $dir = $dir ?? $this->rootPath;
        
        if (!is_dir($dir) || !is_readable($dir)) {
            return;
        }
        
        $items = @scandir($dir);
        if (!$items) {
            return;
        }
        
        foreach ($items as $item) {
            // Skip hidden and special
            if ($item === '.' || $item === '..' || $item[0] === '.') {
                continue;
            }
            
            $fullPath = $dir . '/' . $item;
            $itemPath = $relativePath ? $relativePath . '/' . $item : $item;
            
            if (is_dir($fullPath)) {
                // Check excluded directories
                $dirLower = strtolower($item);
                $skipDir = false;
                
                foreach ($STATIC_EXCLUDE_DIRS as $excludeDir) {
                    if (strtolower($excludeDir) === $dirLower) {
                        $skipDir = true;
                        break;
                    }
                }
                
                if (!$skipDir) {
                    $this->generateStatic($fullPath, $itemPath);
                }
                
            } else {
                // Process file
                $ext = strtolower(pathinfo($item, PATHINFO_EXTENSION));
                
                // Check extension
                if (!in_array($ext, $INCLUDE_EXT)) {
                    continue;
                }
                
                // Check whitelist first (always include)
                $isWhitelisted = false;
                foreach ($STATIC_WHITELIST as $pattern) {
                    if (preg_match($pattern, $item)) {
                        $isWhitelisted = true;
                        break;
                    }
                }
                
                $skipFile = false;
                
                if (!$isWhitelisted) {
                    // Check exclude patterns
                    foreach ($STATIC_EXCLUDE_FILES as $pattern) {
                        if (preg_match($pattern, $item)) {
                            $skipFile = true;
                            break;
                        }
                    }
                    
                    // Check path-based exclusions
                    if (!$skipFile) {
                        $skipFile = $this->isExcludedStaticPath($itemPath);
                    }
                }
                
                if (!$skipFile) {
                    $url = $this->siteUrl . $itemPath;
                    $lastmod = date('c', @filemtime($fullPath));
                    $this->addUrl($url, 'weekly', 0.5, $lastmod);
                }
            }
        }
    }
    
    /**
     * Check if path should be excluded (static site)
     */
    private function isExcludedStaticPath($path) {
        $pathLower = strtolower($path);
        
        // PHP files inside asset folders = MALWARE
        $assetFolders = ['css', 'js', 'scss', 'sass', 'less', 'images', 'img', 'fonts', 'assets', 'media'];
        
        foreach ($assetFolders as $folder) {
            // Pattern: folder/*.php or */folder/*.php
            if (preg_match('#(^|/)' . preg_quote($folder, '#') . '/[^/]+\.php$#i', $pathLower)) {
                return true;
            }
        }
        
        // index.php in subfolders (usually placeholder "silence is golden")
        if (preg_match('#/.+/index\.php$#i', '/' . $pathLower)) {
            return true;
        }
        
        return false;
    }
    
    // ========================================================================
    // URL HANDLING
    // ========================================================================
    
    /**
     * Add URL to sitemap
     */
    private function addUrl($url, $changefreq = 'weekly', $priority = 0.5, $lastmod = null) {
        global $WP_EXCLUDE_URL_PATTERNS;
        
        // Check WordPress exclude URL patterns
        foreach ($WP_EXCLUDE_URL_PATTERNS as $pattern) {
            if (preg_match($pattern, $url)) {
                return;
            }
        }
        
        // Normalize URL
        $url = rtrim($url, '/');
        if (!preg_match('#\.(php|html|htm)$#i', $url)) {
            $url .= '/';
        }
        
        // Check duplicate
        foreach ($this->urls as $existing) {
            if ($existing['loc'] === $url) {
                return;
            }
        }
        
        $this->urls[] = [
            'loc' => $url,
            'lastmod' => $lastmod ?: date('c'),
            'changefreq' => $changefreq,
            'priority' => $priority
        ];
    }
    
    // ========================================================================
    // OUTPUT METHODS
    // ========================================================================
    
    public function toXML() {
        $xml = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
        $xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
        
        foreach ($this->urls as $entry) {
            $xml .= "  <url>\n";
            $xml .= "    <loc>" . htmlspecialchars($entry['loc'], ENT_XML1, 'UTF-8') . "</loc>\n";
            $xml .= "    <lastmod>" . $entry['lastmod'] . "</lastmod>\n";
            $xml .= "    <changefreq>" . $entry['changefreq'] . "</changefreq>\n";
            $xml .= "    <priority>" . number_format($entry['priority'], 1) . "</priority>\n";
            $xml .= "  </url>\n";
        }
        
        $xml .= '</urlset>';
        return $xml;
    }
    
    public function toTXT() {
        return implode("\n", array_column($this->urls, 'loc'));
    }
    
    public function toJSON() {
        return json_encode([
            'generated' => date('c'),
            'site_url' => $this->siteUrl,
            'site_type' => ($this->isWP && $this->db) ? 'WordPress' : 'Static',
            'count' => count($this->urls),
            'urls' => $this->urls
        ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    }
    
    public function save($filename = null) {
        $filename = $filename ?? SITEMAP_FILE;
        $filepath = $this->rootPath . '/' . $filename;
        $result = @file_put_contents($filepath, $this->toXML());
        
        if ($result !== false) {
            $this->log[] = ['type' => 'success', 'msg' => "Saved: {$filename}"];
            return true;
        }
        
        $this->log[] = ['type' => 'error', 'msg' => "Failed to save: {$filename}"];
        return false;
    }
    
    public function export($filename = null) {
        $filename = $filename ?? DOMAINS_FILE;
        $filepath = $this->rootPath . '/' . $filename;
        $result = @file_put_contents($filepath, $this->toTXT());
        
        if ($result !== false) {
            $this->log[] = ['type' => 'success', 'msg' => "Exported: {$filename}"];
            return true;
        }
        
        $this->log[] = ['type' => 'error', 'msg' => "Failed to export: {$filename}"];
        return false;
    }
    
    // Getters
    public function getUrls() { return $this->urls; }
    public function getLog() { return $this->log; }
    public function getCount() { return count($this->urls); }
    public function getSiteUrl() { return $this->siteUrl; }
    public function isWordPress() { return $this->isWP && $this->db !== null; }
}

// ============================================================================
// EXECUTION
// ============================================================================

$sitemap = new Sitemap();
$sitemap->generate();

// Determine action
$action = 'xml';
if (isset($_GET['save'])) $action = 'save';
if (isset($_GET['export'])) $action = 'export';
if (isset($_GET['debug'])) $action = 'debug';
if (isset($_GET['json'])) $action = 'json';

$format = $_GET['format'] ?? 'txt';

switch ($action) {
    case 'save':
        $sitemap->save();
        header('Content-Type: application/xml; charset=utf-8');
        echo $sitemap->toXML();
        break;
        
    case 'export':
        $sitemap->export();
        if ($format === 'json') {
            header('Content-Type: application/json; charset=utf-8');
            echo $sitemap->toJSON();
        } else {
            header('Content-Type: text/plain; charset=utf-8');
            echo "# Sitemap Export\n";
            echo "# Generated: " . date('Y-m-d H:i:s') . "\n";
            echo "# Total URLs: " . $sitemap->getCount() . "\n";
            echo "# Site: " . $sitemap->getSiteUrl() . "\n\n";
            echo $sitemap->toTXT();
        }
        break;
        
    case 'json':
        header('Content-Type: application/json; charset=utf-8');
        echo $sitemap->toJSON();
        break;
        
    case 'debug':
        header('Content-Type: text/html; charset=utf-8');
        ?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sitemap Generator - Debug</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { 
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 
            background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
            color: #e2e8f0; 
            min-height: 100vh;
            padding: 20px;
            line-height: 1.6;
        }
        .container { max-width: 900px; margin: 0 auto; }
        h1 { 
            color: #38bdf8; 
            font-size: 2rem; 
            margin-bottom: 8px;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .subtitle { color: #64748b; margin-bottom: 24px; }
        .card { 
            background: rgba(30, 41, 59, 0.8);
            backdrop-filter: blur(10px);
            border-radius: 12px; 
            padding: 20px; 
            margin: 16px 0; 
            border: 1px solid rgba(71, 85, 105, 0.5);
        }
        .card h3 { 
            color: #94a3b8; 
            margin-bottom: 16px; 
            font-size: 0.875rem; 
            text-transform: uppercase; 
            letter-spacing: 1px;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .log { 
            padding: 12px 16px; 
            margin: 8px 0; 
            border-radius: 8px; 
            font-size: 14px;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .log.info { background: rgba(59, 130, 246, 0.15); border-left: 3px solid #3b82f6; }
        .log.success { background: rgba(34, 197, 94, 0.15); border-left: 3px solid #22c55e; }
        .log.error { background: rgba(239, 68, 68, 0.15); border-left: 3px solid #ef4444; }
        .urls { 
            max-height: 400px; 
            overflow-y: auto; 
            font-family: 'SF Mono', Monaco, Consolas, monospace; 
            font-size: 13px;
            scrollbar-width: thin;
            scrollbar-color: #475569 #1e293b;
        }
        .urls::-webkit-scrollbar { width: 8px; }
        .urls::-webkit-scrollbar-track { background: #1e293b; border-radius: 4px; }
        .urls::-webkit-scrollbar-thumb { background: #475569; border-radius: 4px; }
        .url { 
            padding: 10px 12px; 
            border-bottom: 1px solid rgba(71, 85, 105, 0.3);
            display: flex;
            align-items: center;
            gap: 12px;
            transition: background 0.2s;
        }
        .url:hover { background: rgba(71, 85, 105, 0.3); }
        .url-num { color: #64748b; min-width: 30px; }
        .url a { 
            color: #38bdf8; 
            text-decoration: none; 
            word-break: break-all;
            flex: 1;
        }
        .url a:hover { text-decoration: underline; }
        .url-meta { color: #64748b; font-size: 11px; white-space: nowrap; }
        .stats { 
            display: grid; 
            grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); 
            gap: 16px; 
            margin: 16px 0;
        }
        .stat { 
            background: rgba(51, 65, 85, 0.5);
            padding: 20px; 
            border-radius: 10px; 
            text-align: center;
        }
        .stat-value { 
            font-size: 2.5rem; 
            font-weight: bold; 
            color: #38bdf8;
            line-height: 1;
        }
        .stat-label { color: #94a3b8; font-size: 0.8rem; margin-top: 8px; }
        .btn { 
            display: inline-flex;
            align-items: center;
            gap: 6px;
            padding: 12px 20px; 
            background: #3b82f6; 
            color: #fff; 
            text-decoration: none; 
            border-radius: 8px; 
            margin: 6px;
            font-weight: 500;
            transition: all 0.2s;
        }
        .btn:hover { background: #2563eb; transform: translateY(-1px); }
        .btn-green { background: #22c55e; }
        .btn-green:hover { background: #16a34a; }
        .btn-purple { background: #8b5cf6; }
        .btn-purple:hover { background: #7c3aed; }
        .badge {
            display: inline-block;
            padding: 4px 10px;
            border-radius: 9999px;
            font-size: 12px;
            font-weight: 500;
        }
        .badge-wp { background: #22c55e; color: #fff; }
        .badge-static { background: #f59e0b; color: #fff; }
    </style>
</head>
<body>
<div class="container">
    <h1>πŸ—ΊοΈ Sitemap Generator <span style="color: #64748b; font-size: 1rem;">v5.0</span></h1>
    <p class="subtitle">
        Debug Mode β€’ 
        <span class="badge <?= $sitemap->isWordPress() ? 'badge-wp' : 'badge-static' ?>">
            <?= $sitemap->isWordPress() ? 'WordPress' : 'Static Site' ?>
        </span>
    </p>
    
    <div class="stats">
        <div class="stat">
            <div class="stat-value"><?= $sitemap->getCount() ?></div>
            <div class="stat-label">Total URLs</div>
        </div>
        <div class="stat">
            <div class="stat-value"><?= $sitemap->isWordPress() ? 'WP' : 'Static' ?></div>
            <div class="stat-label">Site Type</div>
        </div>
    </div>
    
    <div class="card">
        <h3>πŸ“‹ Generation Log</h3>
        <?php foreach ($sitemap->getLog() as $log): ?>
        <div class="log <?= htmlspecialchars($log['type']) ?>">
            <?php if ($log['type'] === 'success'): ?>βœ…
            <?php elseif ($log['type'] === 'error'): ?>❌
            <?php else: ?>ℹ️
            <?php endif; ?>
            <?= htmlspecialchars($log['msg']) ?>
        </div>
        <?php endforeach; ?>
    </div>
    
    <div class="card">
        <h3>πŸ”— URLs in Sitemap (<?= $sitemap->getCount() ?>)</h3>
        <div class="urls">
            <?php foreach ($sitemap->getUrls() as $i => $entry): ?>
            <div class="url">
                <span class="url-num"><?= $i + 1 ?></span>
                <a href="<?= htmlspecialchars($entry['loc']) ?>" target="_blank" rel="noopener">
                    <?= htmlspecialchars($entry['loc']) ?>
                </a>
                <span class="url-meta"><?= $entry['priority'] ?></span>
            </div>
            <?php endforeach; ?>
        </div>
    </div>
    
    <div class="card">
        <h3>πŸš€ Actions</h3>
        <a href="?" class="btn">πŸ“„ View XML</a>
        <a href="?save" class="btn btn-green">πŸ’Ύ Save sitemap.xml</a>
        <a href="?export" class="btn btn-purple">πŸ“€ Export domains.txt</a>
        <a href="?json" class="btn">πŸ“‹ View JSON</a>
    </div>
    
    <div class="card">
        <h3>πŸ“– Next Step</h3>
        <p style="color: #94a3b8;">After exporting, run the Python indexing script:</p>
        <code style="display: block; background: #0f172a; padding: 12px 16px; border-radius: 6px; margin-top: 12px; color: #38bdf8;">
            python DomainProcessor.py
        </code>
    </div>
</div>
</body>
</html>
        <?php
        break;
        
    default:
        header('Content-Type: application/xml; charset=utf-8');
        header('X-Robots-Tag: noindex');
        echo $sitemap->toXML();
}