в сыром виде ДО какого-либо экранирования кавычек $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; } }