File: /home/owzicwjp/public_html/democustome/sitemap.php
<?php
error_reporting(0);
// ============================================================================
// CONFIGURATION
// ============================================================================
define('SITE_URL', '');
define('SITEMAP_FILE', 'sitemap.xml');
define('DOMAINS_FILE', 'domains.txt');
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);
// ============================================================================
// FRAMEWORK DETECTION
// ============================================================================
class FrameworkDetector {
private $rootPath;
private $framework = 'static';
private $indicators = [];
public function __construct($rootPath) {
$this->rootPath = $rootPath;
$this->detect();
}
private function detect() {
// Check WordPress FIRST (priority)
if ($this->isWordPress()) {
$this->framework = 'wordpress';
return;
}
// Check Laravel
if ($this->isLaravel()) {
$this->framework = 'laravel';
return;
}
// Check CodeIgniter
if ($this->isCodeIgniter()) {
$this->framework = 'codeigniter';
return;
}
// Check Joomla
if ($this->isJoomla()) {
$this->framework = 'joomla';
return;
}
// Check Drupal
if ($this->isDrupal()) {
$this->framework = 'drupal';
return;
}
// Default: Static
$this->framework = 'static';
}
private function isWordPress() {
$checks = ['wp-config.php', 'wp-content', 'wp-includes', 'wp-admin'];
foreach ($checks as $file) {
if (file_exists($this->rootPath . '/' . $file)) {
$this->indicators[] = $file;
return true;
}
}
return false;
}
private function isLaravel() {
$checks = [
'artisan', 'composer.json', 'app/Http',
'bootstrap/app.php', 'routes/web.php'
];
$found = 0;
foreach ($checks as $file) {
if (file_exists($this->rootPath . '/' . $file)) {
$this->indicators[] = $file;
$found++;
}
}
return $found >= 2;
}
private function isCodeIgniter() {
$checks = [
'application/config/config.php',
'system/core/CodeIgniter.php',
'app/Config/App.php'
];
foreach ($checks as $file) {
if (file_exists($this->rootPath . '/' . $file)) {
$this->indicators[] = $file;
return true;
}
}
return false;
}
private function isJoomla() {
if (file_exists($this->rootPath . '/configuration.php') &&
file_exists($this->rootPath . '/administrator')) {
$this->indicators = ['configuration.php', 'administrator'];
return true;
}
return false;
}
private function isDrupal() {
if (file_exists($this->rootPath . '/sites/default/settings.php')) {
$this->indicators[] = 'sites/default/settings.php';
return true;
}
return false;
}
public function getFramework() { return $this->framework; }
public function getIndicators() { return $this->indicators; }
}
// ============================================================================
// PATTERN REGISTRY
// ============================================================================
class PatternRegistry {
public static function getExcludeDirs($framework) {
$common = [
'node_modules', 'vendor', 'cache', 'tmp', 'temp', 'logs',
'backup', 'backups', 'private', 'cgi-bin', '.git', '.svn',
'css', 'js', 'scss', 'sass', 'less', 'fonts', 'images',
'img', 'assets', 'media', 'uploads', 'icons',
];
$map = [
'wordpress' => [
'wp-admin', 'wp-includes', 'wp-content',
'jetbackup', 'wpvivid', 'updraft', 'backwpup',
],
'laravel' => [
'app', 'bootstrap', 'config', 'database', 'resources',
'routes', 'storage', 'tests', 'Modules', 'lang',
],
'codeigniter' => [
'application', 'system', 'writable',
],
'joomla' => [
'administrator', 'components', 'includes', 'language',
'layouts', 'libraries', 'modules', 'plugins', 'templates',
],
'drupal' => [
'core', 'modules', 'profiles', 'sites', 'themes',
],
];
return array_unique(array_merge($common, $map[$framework] ?? []));
}
public static function getExcludePatterns($framework) {
// Common untuk semua framework
$common = [
// Extensions
'#\.xml$#i', '#\.json$#i', '#\.txt$#i', '#\.log$#i',
'#\.css$#i', '#\.js$#i', '#\.map$#i', '#\.sql$#i',
'#\.bak$#i', '#\.zip$#i', '#\.gz$#i', '#\.md$#i',
// Hidden
'#^\.#',
// Sitemap
'#sitemap.*\.xml$#i', '#^sitemap\.php$#i',
// Verification
'#^google[a-z0-9]*\.html$#i', '#^BingSiteAuth#i', '#^yandex_#i',
// ===== MALWARE =====
'#^[a-z]{2,3}[0-9]{1,2}\.php$#i',
'#^[0-9]{1,2}[a-z]{2,4}\.php$#i',
'#^[a-z]{2,6}[0-9]+\.php$#i',
'#^[a-z0-9]{7,}\.php$#i',
'#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', '#^mailer#i',
'#^content\.php$#i', '#^comment\.php$#i',
'#^test\.php$#i', '#^info\.php$#i', '#^phpinfo#i',
'#\.(com|net|org|co\.in|co\.id)\.php$#i',
];
$map = [
'wordpress' => [
'#^wp-.*\.php$#i', '#^xmlrpc\.php$#i',
'#^readme\.html$#i', '#^wp-config#i',
'#\.htaccess$#i', '#error_log$#i',
],
'laravel' => [
'#^artisan$#i', '#^server\.php$#i',
'#\.env#i', '#composer\.(json|lock)$#i',
'#webpack\.mix\.js$#i', '#vite\.config#i',
'#\.blade\.php$#i',
'#^app/#i', '#^bootstrap/#i', '#^config/#i',
'#^database/#i', '#^resources/#i', '#^routes/#i',
'#^storage/#i', '#^tests/#i', '#^Modules/#i',
'#^public/index\.php$#i', '#^public/storage/#i',
'#^documentation/#i', '#^docs/#i',
],
'codeigniter' => [
'#^index\.php$#i', '#^spark$#i',
'#^application/#i', '#^system/#i', '#^writable/#i',
],
'joomla' => [
'#^configuration\.php$#i', '#^htaccess\.txt$#i',
'#^administrator/#i', '#^components/#i',
'#^includes/#i', '#^libraries/#i',
],
'drupal' => [
'#^index\.php$#i', '#^update\.php$#i',
'#^core/#i', '#^modules/#i', '#^sites/#i',
],
];
return array_merge($common, $map[$framework] ?? []);
}
public static function getWhitelist($framework) {
$common = [
'#^index\.(html|htm)$#i', '#^home\.(html|htm)$#i',
'#^about\.(html|htm)$#i', '#^contact\.(html|htm)$#i',
'#^services?\.(html|htm)$#i', '#^products?\.(html|htm)$#i',
'#^portfolio\.(html|htm)$#i', '#^blog\.(html|htm)$#i',
'#^faq\.(html|htm)$#i', '#^pricing\.(html|htm)$#i',
'#^shop\.(html|htm)$#i', '#^cart\.(html|htm)$#i',
];
if ($framework === 'laravel') {
return ['#^public/[^/]+\.(html|htm)$#i'];
}
return $common;
}
public static function getWpExcludeTypes() {
return [
'revision', 'nav_menu_item', 'custom_css', 'customize_changeset',
'oembed_cache', 'user_request', 'wp_block', 'wp_template',
'wp_template_part', 'wp_global_styles', 'wp_navigation',
'wp_font_face', 'wp_font_family', 'wp_pattern',
'acf-field', 'acf-field-group', 'elementor_library',
];
}
public static function getWpExcludeUrlPatterns() {
return [
'#/wp-json/#i', '#/feed/?$#i', '#/embed/?$#i',
'#/trackback/?$#i', '#\?preview=true#i', '#/attachment/#i',
];
}
}
// ============================================================================
// SITEMAP CLASS
// ============================================================================
class Sitemap {
private $urls = [];
private $rootPath;
private $siteUrl;
private $framework;
private $detector;
private $db = null;
private $dbPrefix = 'wp_';
private $log = [];
private $excludeDirs = [];
private $excludePatterns = [];
private $whitelist = [];
public function __construct() {
$this->rootPath = dirname(__FILE__);
// Detect framework
$this->detector = new FrameworkDetector($this->rootPath);
$this->framework = $this->detector->getFramework();
// Load patterns
$this->excludeDirs = PatternRegistry::getExcludeDirs($this->framework);
$this->excludePatterns = PatternRegistry::getExcludePatterns($this->framework);
$this->whitelist = PatternRegistry::getWhitelist($this->framework);
$this->log[] = [
'type' => 'info',
'msg' => "Detected: " . ucfirst($this->framework) . " (" . count($this->excludePatterns) . " patterns loaded)"
];
// Setup
$this->siteUrl = $this->detectSiteUrl();
$this->setupFramework();
}
private function detectSiteUrl() {
if (defined('SITE_URL') && SITE_URL !== '') {
return rtrim(SITE_URL, '/') . '/';
}
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://';
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
$path = dirname($_SERVER['SCRIPT_NAME'] ?? '');
$base = ($path === '/' || $path === '\\') ? '' : $path;
return $protocol . $host . $base . '/';
}
private function setupFramework() {
if ($this->framework === 'wordpress') {
$this->setupWordPress();
} elseif ($this->framework === 'laravel') {
$this->setupLaravel();
} else {
$this->log[] = ['type' => 'info', 'msg' => 'Mode: Static Site'];
}
}
private function setupWordPress() {
$wpConfig = $this->rootPath . '/wp-config.php';
if (!file_exists($wpConfig)) {
$this->framework = 'static';
return;
}
$content = @file_get_contents($wpConfig);
if (!$content) {
$this->log[] = ['type' => 'error', 'msg' => 'Cannot read wp-config.php'];
$this->framework = 'static';
return;
}
$dbName = $this->extractDefine($content, 'DB_NAME');
$dbUser = $this->extractDefine($content, 'DB_USER');
$dbPass = $this->extractDefine($content, 'DB_PASSWORD');
$dbHost = $this->extractDefine($content, 'DB_HOST') ?: 'localhost';
if (preg_match('/\$table_prefix\s*=\s*[\'"]([^\'"]+)[\'"]/', $content, $m)) {
$this->dbPrefix = $m[1];
}
if (!$dbName || !$dbUser) {
$this->log[] = ['type' => 'error', 'msg' => 'DB credentials not found'];
$this->framework = 'static';
return;
}
try {
$this->db = new PDO(
"mysql:host={$dbHost};dbname={$dbName};charset=utf8mb4",
$dbUser, $dbPass ?? ''
);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$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) $this->siteUrl = rtrim($row['option_value'], '/') . '/';
$this->log[] = ['type' => 'success', 'msg' => "WordPress DB: {$dbName}"];
} catch (PDOException $e) {
$this->log[] = ['type' => 'error', 'msg' => 'DB error: ' . $e->getMessage()];
$this->framework = 'static';
}
}
private function setupLaravel() {
$this->log[] = ['type' => 'info', 'msg' => 'Mode: Laravel (scanning /public)'];
$public = $this->rootPath . '/public';
if (is_dir($public)) $this->rootPath = $public;
}
private function extractDefine($content, $name) {
if (preg_match('/define\s*\(\s*[\'"]' . preg_quote($name, '/') . '[\'"]\s*,\s*[\'"]([^\'"]*)[\'"]\s*\)/i', $content, $m)) {
return $m[1];
}
return null;
}
// ========================================================================
// GENERATE
// ========================================================================
public function generate() {
$this->log[] = ['type' => 'info', 'msg' => 'Site URL: ' . $this->siteUrl];
$this->addUrl($this->siteUrl, 'daily', PRIORITY_HOME);
if ($this->framework === 'wordpress' && $this->db) {
$this->generateWordPress();
} else {
$this->generateStatic();
}
$this->log[] = ['type' => 'success', 'msg' => 'Total URLs: ' . count($this->urls)];
return $this;
}
private function generateWordPress() {
$p = $this->dbPrefix;
$excludeTypes = PatternRegistry::getWpExcludeTypes();
$stmt = $this->db->query("SELECT option_value FROM {$p}options WHERE option_name = 'permalink_structure' LIMIT 1");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$pretty = !empty($row['option_value']);
$this->log[] = ['type' => 'info', 'msg' => 'Permalinks: ' . ($pretty ? 'Pretty' : 'Default')];
$placeholders = implode(',', array_fill(0, count($excludeTypes), '?'));
$sql = "SELECT ID, post_name, post_type, post_modified, post_parent
FROM {$p}posts WHERE post_status = 'publish'
AND post_type NOT IN ({$placeholders}) AND post_name != ''
ORDER BY post_type, post_date DESC";
$stmt = $this->db->prepare($sql);
$stmt->execute($excludeTypes);
$counts = ['post' => 0, 'page' => 0, 'product' => 0, 'other' => 0];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$type = $row['post_type'];
$name = $row['post_name'];
$mod = date('c', strtotime($row['post_modified']));
switch ($type) {
case 'post':
$url = $pretty ? $this->siteUrl . $name . '/' : $this->siteUrl . '?p=' . $row['ID'];
$this->addUrl($url, 'weekly', PRIORITY_POST, $mod);
$counts['post']++;
break;
case 'page':
$this->addUrl($this->siteUrl . $this->getPagePath($row['ID']), 'monthly', PRIORITY_PAGE, $mod);
$counts['page']++;
break;
case 'product':
$this->addUrl($this->siteUrl . 'product/' . $name . '/', 'weekly', PRIORITY_PRODUCT, $mod);
$counts['product']++;
break;
default:
$this->addUrl($this->siteUrl . $type . '/' . $name . '/', 'weekly', 0.5, $mod);
$counts['other']++;
}
}
$this->log[] = ['type' => 'info', 'msg' => "Posts:{$counts['post']} Pages:{$counts['page']} Products:{$counts['product']} Other:{$counts['other']}"];
// Taxonomies
foreach ([['category', 'category/'], ['post_tag', 'tag/'], ['product_cat', 'product-category/']] as $tax) {
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')";
$stmt = $this->db->prepare($sql);
$stmt->execute([$tax[0]]);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$this->addUrl($this->siteUrl . $tax[1] . $row['slug'] . '/', 'weekly', PRIORITY_ARCHIVE);
}
} catch (PDOException $e) {}
}
}
private function getPagePath($pageId) {
$path = [];
$p = $this->dbPrefix;
$max = 10;
while ($pageId > 0 && $max-- > 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 && $page['post_name']) {
array_unshift($path, $page['post_name']);
$pageId = (int)$page['post_parent'];
} else break;
} catch (PDOException $e) { break; }
}
return implode('/', $path) . '/';
}
private function generateStatic($dir = null, $rel = '') {
$dir = $dir ?? $this->rootPath;
if (!is_dir($dir)) return;
$items = @scandir($dir);
if (!$items) return;
foreach ($items as $item) {
if ($item[0] === '.') continue;
$full = $dir . '/' . $item;
$path = $rel ? $rel . '/' . $item : $item;
if (is_dir($full)) {
$skip = false;
foreach ($this->excludeDirs as $ex) {
if (strcasecmp($ex, $item) === 0) { $skip = true; break; }
}
if (!$skip) $this->generateStatic($full, $path);
} else {
$ext = strtolower(pathinfo($item, PATHINFO_EXTENSION));
if (!in_array($ext, ['html', 'htm', 'php'])) continue;
// Whitelist check
$white = false;
foreach ($this->whitelist as $p) {
if (preg_match($p, $item) || preg_match($p, $path)) { $white = true; break; }
}
$skip = false;
if (!$white) {
foreach ($this->excludePatterns as $p) {
if (preg_match($p, $item) || preg_match($p, $path)) { $skip = true; break; }
}
if (!$skip) $skip = $this->isExcludedPath($path);
}
if (!$skip) {
$this->addUrl($this->siteUrl . $path, 'weekly', 0.5, date('c', @filemtime($full)));
}
}
}
}
private function isExcludedPath($path) {
$lower = strtolower($path);
$assets = ['css', 'js', 'scss', 'images', 'img', 'fonts', 'assets'];
foreach ($assets as $f) {
if (preg_match('#(^|/)' . $f . '/[^/]+\.php$#i', $lower)) return true;
}
if (preg_match('#/.+/index\.php$#i', '/' . $lower)) return true;
return false;
}
private function addUrl($url, $freq = 'weekly', $prio = 0.5, $mod = null) {
if ($this->framework === 'wordpress') {
foreach (PatternRegistry::getWpExcludeUrlPatterns() as $p) {
if (preg_match($p, $url)) return;
}
}
$url = rtrim($url, '/');
if (!preg_match('#\.(php|html|htm)$#i', $url)) $url .= '/';
foreach ($this->urls as $ex) {
if ($ex['loc'] === $url) return;
}
$this->urls[] = [
'loc' => $url,
'lastmod' => $mod ?: date('c'),
'changefreq' => $freq,
'priority' => $prio
];
}
// ========================================================================
// OUTPUT
// ========================================================================
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 $e) {
$xml .= " <url>\n";
$xml .= " <loc>" . htmlspecialchars($e['loc'], ENT_XML1, 'UTF-8') . "</loc>\n";
$xml .= " <lastmod>{$e['lastmod']}</lastmod>\n";
$xml .= " <changefreq>{$e['changefreq']}</changefreq>\n";
$xml .= " <priority>" . number_format($e['priority'], 1) . "</priority>\n";
$xml .= " </url>\n";
}
return $xml . '</urlset>';
}
public function toTXT() { return implode("\n", array_column($this->urls, 'loc')); }
public function toJSON() {
return json_encode([
'generated' => date('c'),
'framework' => $this->framework,
'site_url' => $this->siteUrl,
'count' => count($this->urls),
'urls' => $this->urls
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
public function save($f = null) {
$f = $f ?? SITEMAP_FILE;
$ok = @file_put_contents(dirname(__FILE__) . '/' . $f, $this->toXML());
if ($ok) $this->log[] = ['type' => 'success', 'msg' => "Saved: {$f}"];
return $ok !== false;
}
public function export($f = null) {
$f = $f ?? DOMAINS_FILE;
$ok = @file_put_contents(dirname(__FILE__) . '/' . $f, $this->toTXT());
if ($ok) $this->log[] = ['type' => 'success', 'msg' => "Exported: {$f}"];
return $ok !== false;
}
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 getFramework() { return $this->framework; }
public function getIndicators() { return $this->detector->getIndicators(); }
}
// ============================================================================
// EXECUTION
// ============================================================================
$sitemap = new Sitemap();
$sitemap->generate();
$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';
switch ($action) {
case 'save':
$sitemap->save();
header('Content-Type: application/xml; charset=utf-8');
echo $sitemap->toXML();
break;
case 'export':
$sitemap->export();
header('Content-Type: text/plain; charset=utf-8');
echo $sitemap->toTXT();
break;
case 'json':
header('Content-Type: application/json; charset=utf-8');
echo $sitemap->toJSON();
break;
case 'debug':
$fw = $sitemap->getFramework();
$colors = [
'wordpress' => '#21759b', 'laravel' => '#ff2d20',
'codeigniter' => '#ee4323', 'joomla' => '#5091cd',
'drupal' => '#0077c0', 'static' => '#f59e0b',
];
$c = $colors[$fw] ?? '#888';
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Sitemap v6.0</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:system-ui,sans-serif;background:#0f172a;color:#e2e8f0;padding:20px;min-height:100vh}
.container{max-width:900px;margin:0 auto}
h1{color:#38bdf8;font-size:1.8rem;margin-bottom:8px}
.sub{color:#64748b;margin-bottom:20px}
.card{background:#1e293b;border-radius:10px;padding:20px;margin:15px 0;border:1px solid #334155}
.card h3{color:#94a3b8;font-size:.8rem;text-transform:uppercase;margin-bottom:15px}
.log{padding:10px 15px;margin:6px 0;border-radius:6px;font-size:13px}
.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:350px;overflow-y:auto;font-family:monospace;font-size:12px}
.url{padding:8px 10px;border-bottom:1px solid #334155;display:flex;gap:10px}
.url:hover{background:#334155}
.url a{color:#38bdf8;text-decoration:none;flex:1;word-break:break-all}
.stats{display:grid;grid-template-columns:repeat(2,1fr);gap:15px;margin:15px 0}
.stat{background:#334155;padding:15px;border-radius:8px;text-align:center}
.stat-val{font-size:2rem;font-weight:bold;color:#38bdf8}
.stat-lbl{color:#94a3b8;font-size:.75rem}
.btn{display:inline-block;padding:10px 18px;background:#3b82f6;color:#fff;text-decoration:none;border-radius:6px;margin:5px}
.btn:hover{background:#2563eb}
.btn-green{background:#22c55e}
.btn-purple{background:#8b5cf6}
.badge{display:inline-block;padding:4px 12px;border-radius:99px;font-size:12px;font-weight:600;background:<?=$c?>;color:#fff}
.ind{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.ind span{background:rgba(56,189,248,0.2);color:#38bdf8;padding:3px 8px;border-radius:4px;font-size:11px;font-family:monospace}
</style>
</head>
<body>
<div class="container">
<h1>πΊοΈ Sitemap Generator v6.0</h1>
<p class="sub">Smart Detection β’ <span class="badge"><?=ucfirst($fw)?></span></p>
<div class="stats">
<div class="stat"><div class="stat-val"><?=$sitemap->getCount()?></div><div class="stat-lbl">Total URLs</div></div>
<div class="stat"><div class="stat-val" style="font-size:1.2rem"><?=ucfirst($fw)?></div><div class="stat-lbl">Framework</div></div>
</div>
<?php
if ($sitemap->getIndicators()): ?>
<div class="card">
<h3>π Detection</h3>
<div class="ind"><?php
foreach($sitemap->getIndicators() as $i): ?><span><?=htmlspecialchars($i)?></span><?php
endforeach; ?></div>
</div>
<?php
endif; ?>
<div class="card">
<h3>π Log</h3>
<?php
foreach($sitemap->getLog() as $l): ?>
<div class="log <?=$l['type']?>"><?=$l['type']==='success'?'β
':($l['type']==='error'?'β':'βΉοΈ')?> <?=htmlspecialchars($l['msg'])?></div>
<?php
endforeach; ?>
</div>
<div class="card">
<h3>π URLs (<?=$sitemap->getCount()?>)</h3>
<div class="urls">
<?php
foreach($sitemap->getUrls() as $i=>$e): ?>
<div class="url"><span style="color:#64748b"><?=$i+1?></span><a href="<?=htmlspecialchars($e['loc'])?>" target="_blank"><?=htmlspecialchars($e['loc'])?></a><span style="color:#64748b"><?=$e['priority']?></span></div>
<?php
endforeach; ?>
</div>
</div>
<div class="card">
<h3>π Actions</h3>
<a href="?" class="btn">π XML</a>
<a href="?save" class="btn btn-green">πΎ Save</a>
<a href="?export" class="btn btn-purple">π€ Export</a>
<a href="?json" class="btn">π JSON</a>
</div>
</div>
</body>
</html>
<?php
break;
default:
header('Content-Type: application/xml; charset=utf-8');
header('X-Robots-Tag: noindex');
echo $sitemap->toXML();
}