в сыром виде ДО какого-либо экранирования кавычек
$text = preg_replace_callback('/(.*?)<\/code>/s', function(array $matches) use (&$codeBlocks, &$blockCount, $highlighter): string {
$paramLine = isset($matches[1]) ? (string)$matches[1] : '';
$codeBody = isset($matches[2]) ? (string)$matches[2] : '';
// Обрабатываем блок кода в чистом виде
$renderedBlock = $highlighter->highlight($paramLine, $codeBody);
// Исправлено: Маркер сделан алфавитно-цифровым, чтобы htmlspecialchars его не портил
$marker = "DokuCodeBlock" . $blockCount . "X";
$codeBlocks[$marker] = $renderedBlock;
$blockCount++;
return $marker;
}, $text);
// Шаг 2. Безопасность: теперь экранируем ОСТАВШИЙСЯ текст страницы от XSS уязвимостей
$text = htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
// Шаг 3. Парсим заголовки DokuWiki
$text = preg_replace('/======\s*(.*?)\s*======/', '$1
', $text);
$text = preg_replace('/=====\s*(.*?)\s*=====/', '$1
', $text);
$text = preg_replace('/====\s*(.*?)\s*====/', '$1
', $text);
// Шаг 4. Стили форматирования текста
$text = preg_replace('/\*\*(.*?)\*\*/', '$1', $text);
$text = preg_replace('/\/\/(.*?)\/\//', '$1', $text);
$text = preg_replace('/__(.*?)__/', '$1', $text);
// Шаг 5. Парсим ссылки [[page_id]] или [[page_id|Текст]]
$text = preg_replace_callback('/\[\[(.*?)\]\]/', function(array $matches): string {
$innerContent = isset($matches[1]) ? (string)$matches[1] : '';
if (str_contains($innerContent, '|')) {
$parts = explode('|', $innerContent, 2);
$pageId = trim((string)array_shift($parts));
$label = trim((string)array_shift($parts));
} else {
$pageId = trim($innerContent);
$label = $pageId;
}
$pageId = ltrim($pageId, ':');
return '' . htmlspecialchars($label) . '';
}, $text);
// Шаг 6. Парсим медиа-теги изображений {{:картинка.png}}
$text = preg_replace_callback('/\{\{:(.*?)\}\}/', function(array $matches): string {
$innerMedia = isset($matches[1]) ? (string)$matches[1] : '';
if (str_contains($innerMedia, '|')) {
$mediaParts = explode('|', $innerMedia, 2);
$mediaPath = trim((string)array_shift($mediaParts));
} else {
$mediaPath = trim($innerMedia);
}
$realPath = str_replace(':', '/', $mediaPath);
return '
';
}, $text);
// Шаг 7. Делаем автоматические переносы строк для текста страницы
$text = nl2br($text);
// Шаг 8. Финал: возвращаем сохраненные блоки кода обратно на свои места в обход nl2br
foreach ($codeBlocks as $marker => $renderedHtml) {
$text = str_replace($marker, $renderedHtml, $text);
}
return $text;
}
}