Скрипт генерирует HTML-карту сайта для Joomla с правильными ЧПУ-адресами на основе структуры меню и категорий. В отличие от XML-версии, этот скрипт создаёт человекочитаемую страницу со списком всех актуальных статей.
Показывает только опубликованные статьи с доступом для всех пользователей
Строит ссылки на основе структуры меню и иерархии категорий
Отображает дату последнего изменения или публикации статьи
Никакой группировки по категориям — просто список всех статей в алфавитном порядке
Экранирование вывода через htmlspecialchars() для защиты от XSS
Автоматический подсчёт общего количества статей на сайте
Приоритеты построения URL:
| Проверка | Результат |
|---|---|
| SQL-инъекции | ✅ Используются подготовленные запросы Joomla |
| XSS (межсайтовый скриптинг) | ✅ Данные экранируются через htmlspecialchars() |
| Вывод паролей/логинов | ✅ Отсутствует |
| Доступ к файловой системе | ✅ Только чтение базы данных |
| Инъекции в URL | ✅ ЧПУ формируется из БД |
| Обработка ошибок | ✅ Ошибки скрыты |
Основные таблицы Joomla:
Пункты меню для получения ЧПУ
id
alias
link
path
Статьи
id
alias
title
catid
state
Категории
id
alias
parent_id
error_reporting(0))HTML — человекочитаемая страница для пользователей
Без группировки — просто список всех статей по алфавиту
Удобная навигация для посетителей сайта
sitemap.html.php в корне сайта JoomlabuildArticleUrl()https://ваш-сайт.ру/sitemap.html.php<?php
/**
* Sitemap HTML - упрощённая версия
* Только актуальные статьи без группировки по категориям
*/
error_reporting(0);
ini_set('display_errors', 0);
define('_JEXEC', 1);
define('JPATH_BASE', __DIR__);
require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';
use Joomla\CMS\Factory;
$db = Factory::getDbo();
// ============================================
// 1. ПОЛУЧАЕМ ВСЕ ПУНКТЫ МЕНЮ (для определения правильных ЧПУ)
// ============================================
$query = $db->getQuery(true);
$query->select('id, alias, link, path')
->from('#__menu')
->where('published = 1')
->where('client_id = 0');
$db->setQuery($query);
$menuItems = $db->loadObjectList();
// Строим карту: ID статьи => путь из меню
$menuArticleMap = [];
foreach ($menuItems as $item) {
if (strpos($item->link, 'view=article&id=') !== false) {
preg_match('/id=(\d+)/', $item->link, $matches);
if (isset($matches[1])) {
$articleId = (int)$matches[1];
$menuPath = trim($item->path, '/');
if (!empty($menuPath)) {
if (!isset($menuArticleMap[$articleId]) || strlen($menuPath) < strlen($menuArticleMap[$articleId])) {
$menuArticleMap[$articleId] = $menuPath;
}
}
}
}
}
// ============================================
// 2. ФУНКЦИЯ ДЛЯ ПОЛУЧЕНИЯ ПУТИ КАТЕГОРИИ (с родителями)
// ============================================
function getCategoryPath($catId, $db) {
$path = [];
$currentId = (int)$catId;
while ($currentId > 0) {
$query = $db->getQuery(true);
$query->select('id, alias, parent_id')
->from('#__categories')
->where('id = ' . $currentId);
$db->setQuery($query);
$category = $db->loadObject();
if (!$category || empty($category->alias)) {
break;
}
array_unshift($path, $category->alias);
if ($category->parent_id <= 1) {
break;
}
$currentId = $category->parent_id;
}
return implode('/', $path);
}
// ============================================
// 3. ПОЛУЧАЕМ ВСЕ АКТИВНЫЕ СТАТЬИ
// ============================================
$query = $db->getQuery(true);
$query->select('a.id, a.alias, a.title, a.catid, a.modified, a.publish_up, a.created, a.publish_down, a.state, a.access, c.alias AS category_alias')
->from('#__content AS a')
->leftJoin('#__categories AS c ON a.catid = c.id')
->where('a.state = 1')
->where('a.access = 1')
->where('c.published = 1')
->where('c.access = 1')
->order('a.title ASC');
$db->setQuery($query);
$articles = $db->loadObjectList();
// ============================================
// 4. ФИЛЬТРУЕМ СТАТЬИ (проверка дат и т.д.)
// ============================================
$validArticles = [];
foreach ($articles as $article) {
$now = date('Y-m-d H:i:s');
if (isset($article->publish_up) && $article->publish_up && $article->publish_up > $now) continue;
if (isset($article->publish_down) && $article->publish_down && $article->publish_down < $now) continue;
if (empty($article->catid) || empty($article->category_alias)) continue;
$validArticles[] = $article;
}
// ============================================
// 5. ФУНКЦИЯ ДЛЯ ПОСТРОЕНИЯ ПРАВИЛЬНОГО URL
// ============================================
function buildArticleUrl($article, $menuArticleMap, $db) {
// Приоритет 1: если есть путь из меню — используем его
if (isset($menuArticleMap[$article->id])) {
return 'https://www.doctorneiro.ru/' . $menuArticleMap[$article->id];
}
// Приоритет 2: строим из категории
$categoryPath = getCategoryPath($article->catid, $db);
if (!empty($categoryPath) && !empty($article->alias) && $article->alias != 'index.php') {
return 'https://www.doctorneiro.ru/' . $categoryPath . '/' . $article->alias;
}
// Приоритет 3: запасной вариант
return 'https://www.doctorneiro.ru/component/content/article/' . $article->id . '-' . ($article->alias ?: 'article');
}
// ============================================
// 6. ВЫВОД HTML
// ============================================
?>
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Карта сайта - ДокторНейро</title>
<link rel="icon" type="image/svg+xml" sizes="any" href="/favicon.svg">
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 40px auto; padding: 0 20px; background: #f9fafb; }
h1 { color: #0a2463; border-bottom: 2px solid #d4a373; padding-bottom: 10px; }
.stats { background: #eef2f7; padding: 10px 20px; border-radius: 8px; margin-bottom: 20px; }
ul { list-style: none; padding: 0; }
li { padding: 6px 0; border-bottom: 1px solid #e8edf4; }
li a { color: #1a4b8c; text-decoration: none; }
li a:hover { text-decoration: underline; color: #0a2463; }
.date { color: #8a9aa8; font-size: 12px; margin-left: 10px; }
</style>
</head>
<body>
<h1>🗺️ Карта сайта — все актуальные статьи</h1>
<div class="stats">
📄 Всего статей: <strong><?php echo count($validArticles); ?></strong>
</div>
<ul>
<?php foreach ($validArticles as $article):
$fullUrl = buildArticleUrl($article, $menuArticleMap, $db);
$date = $article->modified ?: ($article->publish_up ?: $article->created);
$dateFormatted = date('d.m.Y', strtotime($date));
?>
<li>
<a href="<?php echo $fullUrl; ?>" target="_blank">
<?php echo htmlspecialchars($article->title ?: $article->alias); ?>
</a>
<span class="date">📅 <?php echo $dateFormatted; ?></span>
</li>
<?php endforeach; ?>
</ul>
<p style="margin-top: 30px; font-size: 13px; color: #8a9aa8;">
© <?php echo date('Y'); ?> <a href="https://www.doctorneiro.ru/" style="color:#1a4b8c;">DoctorNeiro.ru</a>
</p>
</body>
</html>
Комментарии
Пока нет комментариев. Будьте первым!