За последние 24 часа нас посетили 17454 программиста и 1947 роботов. Сейчас ищут 1138 программистов ...

Функ. зеркальная к strip_tags или выборочное удаление тегов

Тема в разделе "Прочие вопросы по PHP", создана пользователем Dimazan, 28 ноя 2012.

  1. Dimazan

    Dimazan Активный пользователь

    С нами с:
    28 ноя 2012
    Сообщения:
    12
    Симпатии:
    0
    Здравствуйте!
    Подскажите, есть ли функция удаляющая указанные теги?
    То есть strip_tags удаляет все теги кроме указанных, а можно ли оставлять все кроме указанных?
    К примеру нужно удалить все ссылки (<a..>Сам текст оставить</a>), выделение жирным шрифтом (аналогично <a>) и горизонтальные разделители (<hr> и <hr />).
    Как это грамотно сделать?
    Встречал мнение, что сделать это грамотно, без косяков, со строкой невозможно (то есть надо строить DOM-дерево а потом удалять из него). Предполагаю, что из-за возможных камментов в тексте HTML (<!-- -->).
    В моем, частном случае, вся страница загнана в одну строку. И можно сделать в два этапа - удалить камменты, а потом удалить ненужные теги.

    Спасибо всем.
     
  2. artem-Kuzmin

    artem-Kuzmin Активный пользователь

    С нами с:
    16 фев 2012
    Сообщения:
    809
    Симпатии:
    0
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    регуляркой по моему все очень даже хорошо удаляется)
     
  3. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.129
    Симпатии:
    1.249
    Адрес:
    там-сям
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    считается, что регулярка не предназначена для обработки структур с неопределенно большой степенью вложенности элементов. не раз такое утверждение встречал. хотя сам регулярно, простите за каламбур, применяю регулярку для html.

    в данном случае я бы поискал в ХОРОШИХ книгах регулярку для HTML, взял preg_replace_callback и в калбэке решал что делать с тегом.
     
  4. Gold Dragon

    Gold Dragon Активный пользователь

    С нами с:
    30 сен 2012
    Сообщения:
    306
    Симпатии:
    2
    Адрес:
    Тамбов
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    если это HTML, то не проще ли всё делать через DOMDocument

    Добавлено спустя 1 минуту 30 секунд:
    Re: Функ. зеркальная к strip_tags или выборочное удаление тегов
    без тестов это просто слова :) может и быстрее, а может и медленнее
     
  5. Dimazan

    Dimazan Активный пользователь

    С нами с:
    28 ноя 2012
    Сообщения:
    12
    Симпатии:
    0
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Тут еще проблема - через DOM я могу удалить узел (со всем его содержимым), а мне надо его "развоплотить".
    То есть: <тег ....>Текст</тег> => Текст.
    Где "Текст", в общем случае, может содержать в себе теги которые не должны потеряться. А значит надо вытаскивать содержимое узла, удалять его и возвращать содержимое (куда-то...).
    Да и что-то мне подсказывает, что построение DOM-дерева, манипуляции с ним и его выгрузка будут сильно медленнее str_replace.
     
  6. Gold Dragon

    Gold Dragon Активный пользователь

    С нами с:
    30 сен 2012
    Сообщения:
    306
    Симпатии:
    2
    Адрес:
    Тамбов
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    опять же слова.. нужны тесты.

    А вообще, слишком размытое задание... Идея то первоначальная какая? Не вырезать же тэги ради того, чтобы их вырезать
     
  7. Dimazan

    Dimazan Активный пользователь

    С нами с:
    28 ноя 2012
    Сообщения:
    12
    Симпатии:
    0
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Идея - при получении письма в HTML формате оно содержит все заголовки полноценной страницы (доктайп, хиад, боди и т.д.) и стили (но стили сами по себе не зло, а зло когда они начинают переопределять стили для body и других тегов). И вот для нормального отображения письма в веб интерфейсе надо все это удалять. То есть можно и не удалять, забить, браузеры нормально переваривают повторные заголовки страницы, но это получается как-то не аккуратненько. А вот стили для тегов (не для классов или id) надо прибивать безжалостно.

    Тесты... Я напишу функцию без использования DOM и выложу ее. Если кто напишет это через DOM сможем сравнить скорость работы.
     
  8. sobachnik

    sobachnik Старожил

    С нами с:
    20 апр 2007
    Сообщения:
    3.380
    Симпатии:
    13
    Адрес:
    Дмитров, МО
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Загружай эти письма в iframe и не будут они ломать верстку твоей страницы
     
  9. Dimazan

    Dimazan Активный пользователь

    С нами с:
    28 ноя 2012
    Сообщения:
    12
    Симпатии:
    0
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Можно и так, но есть одно НО - пользователь может захотеть ответить на это письмо и тогда мне надо будет загрузить его в редактор и отдать ему на редактирование, а потом сформировать из него валидное письмо. Так что заголовки все равно придется убирать. Так для чего городить iframe если все равно это делать?
     
  10. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    попробуйте phpQuery
     
  11. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.129
    Симпатии:
    1.249
    Адрес:
    там-сям
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    я не специалист по регуляркам, скорее потребитель. меня такими фразами на работу не развести ))

    утверждают, что регулярка просто не справится с некоторыми тяжелыми случаями, а не то, что она тормозная.
     
  12. Dimazan

    Dimazan Активный пользователь

    С нами с:
    28 ноя 2012
    Сообщения:
    12
    Симпатии:
    0
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Вот и первый результат:
    Код (Text):
    1. function zdm_strip_this_tags($html_str, $tag, $strip_comments = false) {
    2.     // $html_str - строка или массив с HTML кодом
    3.     // Если массив, то собираем в строку
    4.     if (is_array($html_str)) $html_str = implode('',rtrim($html_str,"\r\n"));
    5.     // Удаляем комментарии
    6.     $free_comm = true;
    7.     if ($strip_comments)
    8.         while ($free_comm) {
    9.             $start_pos = strpos($html_str, '<!--');
    10.             $end_pos = strpos($html_str, '-->');
    11.             if (!$end_pos) $end_pos = strlen($html_str) - 1; // Если нет тега закрывающего каммент, то удаляем все до конца строки
    12.             if ($start_pos AND $end_pos) {
    13.                 $html_str = substr_replace($html_str, '', $start_pos, ($end_pos - $start_pos + 1));
    14.             } else {
    15.                 $free_comm = false;
    16.             }
    17.         }
    18.     // $tag это массив строк или одна строка (тег), если это не массив, то надо его сделать массивом
    19.     if (!is_array($tag)) $tag[] = $tag;
    20.     // Переводим теги в нижний регистр
    21.     for ($tag_num=0;$tag_num<count($tag);$tag_num++) $tag[$tag_num] = strtolower($tag[$tag_num]);
    22.     // Собственно ищем теги
    23.     $res_html_str = ''; // Сюда будем собирать то, что получится
    24.     // Разбиваем строку на массив при помощи '<'
    25.     $html_str = explode('<',$html_str);
    26.     // Проходим по этому массиву и проверяем с чего начинаются строки
    27.     for ($str_num=0;$str_num<count($html_str);$str_num++) {
    28.         $mybe_tag = explode(' ', ltrim($html_str[$str_num]));
    29.         $mybe_tag = explode('>', $mybe_tag[0]);
    30.         if (in_array(strtolower(ltrim($mybe_tag[0], '/')), $tag)) {
    31.             $end_pos = strpos($html_str[$str_num], '>');
    32.             if ($end_pos) {
    33.                 $temp_str = explode('>', $html_str[$str_num], 2);
    34.                 $res_html_str .= $temp_str[1];
    35.             }
    36.         } else {
    37.             $res_html_str .= "<".$html_str[$str_num];
    38.         }
    39.     }
    40.     $res_html_str = substr_replace($res_html_str, '', 0, 1);
    41.     return $res_html_str;
    42. }
    В действии можно попробовать вот тут: http://dimazan.ru/stt/

    В процессе пришло понимание, что не только камменты надо удалять "от" и "до" (из-за их бесполезности) но и скрипты (из-за опасности да и бессмысленности оставления тела скрипта без окаймляющих тегов). Но это в будущем.

    Буду рад конструктивным замечаниям и предложениям.
     
  13. artem-Kuzmin

    artem-Kuzmin Активный пользователь

    С нами с:
    16 фев 2012
    Сообщения:
    809
    Симпатии:
    0
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Та ну))если норм написать уверен все съест..
    И регулярка ясное дело резче любого дума будет
     
  14. Gold Dragon

    Gold Dragon Активный пользователь

    С нами с:
    30 сен 2012
    Сообщения:
    306
    Симпатии:
    2
    Адрес:
    Тамбов
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    скорее всего только регулярка поможет. Код письма просто может быть не валидным и всё управление через DOM не поможет

    Добавлено спустя 2 минуты 10 секунд:
    Re: Функ. зеркальная к strip_tags или выборочное удаление тегов
    у них задачи разные.. Регулярка в большей степени просто "найти", а DOM это уже полноценное управление доступом к элементам
     
  15. artem-Kuzmin

    artem-Kuzmin Активный пользователь

    С нами с:
    16 фев 2012
    Сообщения:
    809
    Симпатии:
    0
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Это я понимаю) но в его случае ему не нужно ни какое управление типа(добавить атрибут, поменять значение атрибута), а нужно просто удалить теги.
    Пользовал phpQuery и еще один класс забыл название более медленный, да удобно), но если пользуешься регулярками я иими довольно часто пользуюсь мне они удобней будут этих библиотек это дело вкуса)) хотя запись find(селектор) красиво)
     
  16. stopkran

    stopkran Активный пользователь

    С нами с:
    10 июл 2011
    Сообщения:
    56
    Симпатии:
    0
    Адрес:
    Иркутск
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Если надо зеркальное, примени зеркальную логику:

    1) замени легальные тэги (которые нужно оставить) - например, замени в них открывающую скобку на ... пару неожиданных символов (с кодом до 5);

    2) примени strip_tags;

    3) замени комбинацию секретных символов обратно на открывающую скобку.
     
  17. Dimazan

    Dimazan Активный пользователь

    С нами с:
    28 ноя 2012
    Сообщения:
    12
    Симпатии:
    0
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Для реализации этого пункта надо либо составить словарь всех тегов и исключить из него не нужные, либо просканировать текст и выбрать все теги кроме не нужных. Потом надо пройтись по всему тексту еще раз заменяя "легальные" теги на что-то другое.
    А в п.3 пройтись по тексту еще раз (возвращая легальные теги в нормальное состояние).

    А придумать более сложный алгоритм слабо? :)
    Да и не выход это так как все равно не решает вопроса с тегом <script> (см. предыдущие посты).
     
  18. stopkran

    stopkran Активный пользователь

    С нами с:
    10 июл 2011
    Сообщения:
    56
    Симпатии:
    0
    Адрес:
    Иркутск
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Да, предложенный способ оставляет содержимое элементов (в частности, script). В моей CMS это нормально работает, потому и посоветовал такой вариант. Cодержимое элементов я тоже в некоторых случаях удаляю, но только через DOM - регулярки в этом случае всегда можно затупить злонамеренной логикой (на всякую хитрую регулярку найдётся ...).
     
  19. Dimazan

    Dimazan Активный пользователь

    С нами с:
    28 ноя 2012
    Сообщения:
    12
    Симпатии:
    0
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Нет никаких регулярок! См. код функции выше. Это, правда, не последний вариант, но вполне себе рабочий.
    А построение DOM мне не нравится (применительно к данной задаче) так как это очень тормозной процесс.
     
  20. stopkran

    stopkran Активный пользователь

    С нами с:
    10 июл 2011
    Сообщения:
    56
    Симпатии:
    0
    Адрес:
    Иркутск
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Запись данных - в принципе тормозной процесс (по сравнению с выводом). И появление внутри него доп. тормозов не намного всё замедлит (не настолько заметно DOM его напряжёт). Важнее другое: разбор DOM на сервере опасен из-за синтаксических ошибок (где-то выше писали об этом). Есть опасность и в explode('<'...): от пользователя, например, может прийти текст с угловыми скобками без тэгов. Любой вариант можно использовать, если учитывать сопутствующие проблемы.
     
  21. Dimazan

    Dimazan Активный пользователь

    С нами с:
    28 ноя 2012
    Сообщения:
    12
    Симпатии:
    0
    Re: Функ. зеркальная к strip_tags или выборочное удаление те

    Чем сложнее механизм, тем проще его сломать.
    Сломать поиск/замену по строке, в этом смысле, очень сложно. Точнее я о таком даже не слыхал.