@Daaeev

Как экранировать весь контент, кроме определённых тегов?

Есть строка
<script>alert(123)</script> <h1>something</h1> <blockquote>something</blockquote>


Всё что мне надо сделать - это функцию, которая будет экранировать тег script и другие, кроме blockquote и пары других тегов (b, u, h1...).

Задача вроде не сложная, подумал я и сделал вот такую штукенцию:
/*
       Обработчик текста. Функция экранирует весь контент, кроме определённых тегов ($tagsLetters)
    */
    public static function contentProcessing(string $str)
    {
        $tagsLetters = ['blockquote', 'b', 'i', 'u', 's', 'code', 'h1'];

        $result = '';
        $openAndCloseTags = []; // openTag => closeTag
        
        // Получил открывающий и закрывающий теги
        foreach ($tagsLetters as $tag) {
            $openTag = '<' . $tag . '>';
            $closeTag = '</' . $tag . '>';
        
            $openAndCloseTags[$openTag] = $closeTag;
        }
        
        // Заменил закрывающие теги на сгенерированным разделитель типа: '-?#14#&-'
        $replacedCloseTagsString = $str;
        $replaceString = '-?#' . rand(10, 20) . '#&-';
        
        foreach ($openAndCloseTags as $openTag => $closeTag) {
            $replacedCloseTagsString = str_replace($closeTag, $replaceString, $replacedCloseTagsString);
        }
        
        // Разбил главную строку по сгенерированным разделителям ($replacedCloseTagsString)
        $exploadedByReplacedCloseTag = explode($replaceString, $replacedCloseTagsString);
        
        // Получил общее количество тегов в строке, которое нужно экранировать (нужно при результирующей обработке)
        $countOfNotEncodeTags = 0;
        foreach ($exploadedByReplacedCloseTag as $string) {
            foreach($openAndCloseTags as $openTag => $closeTag) {
                if (is_numeric(strpos($string, $openTag))) {
                    $countOfNotEncodeTags++;
                }
            }
        }

        // Если нет тегов, которые НЕ нужно экранировать, то возвращаем экранированный основной контент
        if ($countOfNotEncodeTags == 0) {
            return htmlspecialchars($str);
        }
        
        // Обработал $exploadedByReplacedCloseTag, получив результирующую строку
        $iter = 0;
        foreach ($exploadedByReplacedCloseTag as $string) {
            foreach ($openAndCloseTags as $openTag => $closeTag) {
        
                // Если есть указанный тег в строке, то разбиваем её по нему и соединяем, экранирую нужный контент
                if (is_numeric(strpos($string, $openTag))) {
                    $explodeContent = explode($openTag, $string);
                    $result .= htmlspecialchars($explodeContent[0]) . $openTag . htmlspecialchars($explodeContent[1]) . $closeTag;
                }
                
                // Если тегов больше не осталось и остался контент, то добавляем его в результирующею строку
                if ($iter == ($countOfNotEncodeTags - 1)) {
                    $result .= htmlspecialchars($exploadedByReplacedCloseTag[$iter + 1]);
                    break 2;
                }
            }
        
            $iter++;
        }
        
        return $result;
    }

Функция рабочая(есть недостатки - не работает со вложенными тегами, но это не сильно мешает), и я поражаюсь как я вообще смог додуматься до такого!
У меня возникает вопрос - у кого-нибудь есть идеи, как решить задачу более красивым, может быть, производительным методом?
Если что, мне хватит объяснений просто на словах...
  • Вопрос задан
  • 81 просмотр
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы