File: /home/owzicwjp/public_html/ufd.360digitcrm.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();
}