Преобразование HTML в обычный текст в PHP для электронной почты

Я использую TinyMCE, чтобы обеспечить минимальное форматирование текста на моем сайте. Из созданного HTML я хотел бы преобразовать его в простой текст для электронной почты. Я использовал класс под названием html2text, но ему действительно не хватает поддержки UTF-8, в том числе другие вещи. Однако мне нравится, что он сопоставляет определенные теги HTML с форматированием обычного текста - например, подчеркивание текста, который ранее имел теги ‹i› в HTML.

Кто-нибудь использует аналогичный подход к преобразованию HTML в обычный текст в PHP? И если да: вы рекомендуете какие-либо сторонние классы, которые я могу использовать? Или как лучше всего решить эту проблему?


person Justin Stayton    schedule 10.12.2009    source источник
comment
См. Также HTML в обычный текст (для электронной почты)   -  person outis    schedule 27.04.2011
comment
html2text содержит опасные уязвимости выполнения кода.   -  person Tgr    schedule 28.11.2011
comment
Для справки, википедия ссылается на опрос, в котором говорится только о 3% людей используют только текстовую электронную почту.   -  person Redzarf    schedule 13.08.2013
comment
@Redzarf дело не в этих 3%. Добавление текстовой части - действительно хорошая идея, если вы не хотите, чтобы ваша электронная почта попадала прямо в папку для спама. К тому же эти 3%, вероятно, не учитывают легких мобильных клиентов. И последнее, но не менее важное: 3% больше, чем 0%, что должно заставить вас серьезно задуматься.   -  person Ninj    schedule 02.10.2013
comment
@Ninj Я только что проверил, и опрос проводился в 2002 году, так что с тех пор все изменится (хотя я все еще думаю, что 3%, вероятно, правильные.) Хороший момент по поводу проблемы со спамом - для всех, кто читает это позже и обеспокоен спамом, Я обнаружил, что это отличный инструмент: port25.com/support/authentication-center / email-verify   -  person Redzarf    schedule 02.10.2013
comment
Это также удобно для преобразования электронных писем HTML в обычный текст для других контекстов (например, для хранения сообщения в базе данных или вывода на печать в виде чистого текста и т. Д.), Поэтому то, что я не читаю свою электронную почту как простой текст, не означает, что мне может не понадобиться текстовая копия для других целей   -  person Anthony    schedule 25.03.2015
comment
добавление текстовой части в дополнение к html также дает вам еще одну возможность с помощью SpamAssassin: wiki.apache.org/ spamassassin / Правила / MIME_HTML_ONLY   -  person Wes    schedule 12.10.2017
comment
вот простое решение htmlspecialchars (trim (strip_tags ($ htmlString))); $ htmlString будет заменен вашим html-текстом   -  person Abhijeet kumar sharma    schedule 22.08.2018


Ответы (14)


Используйте html2text (пример HTML на text), под лицензией Eclipse Public License. Он использует методы DOM PHP для загрузки из HTML, а затем выполняет итерацию по полученному DOM для извлечения простого текста. Использование:

// when installed using the Composer package
$text = Html2Text\Html2Text::convert($html);

// usage when installed using html2text.php
require('html2text.php');
$text = convert_html_to_text($html);

Несмотря на то, что он неполный, он имеет открытый исходный код, и предложения приветствуются.

Проблемы с другими скриптами конвертации:

  • Поскольку html2text (GPL) не совместим с EPL.
  • Ссылка lkessler (указание авторства) несовместима с большинством лицензий с открытым исходным кодом.
person jevon    schedule 02.04.2010
comment
Первый сценарий выше выпущен под лицензией GPL, которая не является некоммерческой лицензией. В зависимости от контекста это может быть нежелательно, но не является некоммерческим. Вторая ссылка также допускает коммерческое использование - только с указанием авторства. Это тоже не некоммерческое. - person Oliver Moran; 20.05.2013
comment
@OliverMoran Вы правы, я отредактировал ответ, чтобы точнее отразить их лицензионные ограничения. - person jevon; 21.05.2013
comment
Спасибо @jevon, я включил вашу работу в свой проект, и она отлично работает! К сожалению, это не помогло решить мою проблему с Outlook (stackoverflow.com/questions/19135443/), но таким образом я получаю чистый результат. - person Ninj; 02.10.2013
comment
Ссылка не работает. Голосование против. - person Sibidharan; 14.10.2016
comment
пожалуйста, поясните, но кто будет определять, использует ли кто-то GLP или что-то еще? - person Miguel; 30.03.2017
comment
Это имеет некоторые проблемы в PHP 7 - person Brian Leishman; 11.04.2017
comment
Я не видел convert_html_to_text() функции, хотя мне удалось заставить Html2Text (самая первая ссылка) работать без особых проблем. - person Alexis Wilke; 30.07.2017

вот еще одно решение:

$cleaner_input = strip_tags($text);

Чтобы узнать о других вариантах функций очистки, см .:

https://github.com/ttodua/useful-php-scripts/blob/master/filter-php-variable-sanitize.php

person T.Todua    schedule 25.06.2013
comment
Лучшая версия $ClearText = preg_replace( "/\n\s+/", "\n", rtrim(html_entity_decode(strip_tags($HTMLText))) ); - person mAsT3RpEE; 27.01.2014
comment
это так просто, и нет необходимости в другой библиотеке. тоже работает очень хорошо .......... :) - person mili; 27.11.2018

Преобразование HTML в текст с помощью DOMDocument является жизнеспособным решением. Рассмотрим HTML2Text, для которого требуется PHP5:

Что касается UTF-8, в описании на странице с практическими рекомендациями говорится:

Собственная поддержка Unicode в PHP довольно слабая, и он не всегда правильно обрабатывает utf-8. Хотя сценарий html2text использует методы, безопасные для юникода (без использования модуля mbstring), он не всегда может справиться с собственной обработкой кодировок PHP. PHP на самом деле не понимает Unicode или кодировки, такие как utf-8, и использует базовую кодировку системы, которая, как правило, принадлежит к семейству ISO-8859. В результате то, что вам может показаться допустимым символом в вашем текстовом редакторе, в формате utf-8 или однобайтовом, вполне может быть неправильно истолковано PHP. Таким образом, даже если вы думаете, что вводите действительный символ в html2text, возможно, это не так.

Автор предлагает несколько подходов к решению этой проблемы и заявляет, что версия 2 HTML2Text (с использованием DOMDocument) поддерживает UTF-8.

Обратите внимание на ограничения для коммерческого использования.

person lkessler    schedule 17.03.2010
comment
Markdownify больше не поддерживается; онлайн-демонстрация выдает много предупреждений и не работает. Новая версия html2text работает с моей электронной почтой. Поздний +1 к lkessler. - person malcanso; 24.09.2013

Есть надежная функция strip_tags. Хотя это некрасиво. Это только продезинфицирует. Вы можете комбинировать это с заменой строки, чтобы получить свои причудливые подчеркивания.


<?php
// to strip all tags and wrap italics with underscore
strip_tags(str_replace(array("<i>", "</i>"), array("_", "_"), $text));

// to preserve anchors...
str_replace("|a", "<a", strip_tags(str_replace("<a", "|a", $text)));

?>
person pestilence669    schedule 10.12.2009
comment
Не забывайте, что метки-полоски также удаляют якоря! - person Alix Axel; 11.12.2009

Для этого вы можете использовать lynx с параметрами -stdin и -dump:

<?php
$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array("file", "/tmp/htmp2txt.log", "a") // stderr is a file to write to
);

$process = proc_open('lynx -stdin -dump 2>&1', $descriptorspec, $pipes, '/tmp', NULL);

if (is_resource($process)) {
    // $pipes now looks like this:
    // 0 => writeable handle connected to child stdin
    // 1 => readable handle connected to child stdout
    // Any error output will be appended to htmp2txt.log

    $stdin = $pipes[0];
    fwrite($stdin,  <<<'EOT'
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
 <title>TEST</title>
</head>
<body>
<h1><span>Lorem Ipsum</span></h1>

<h4>"Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."</h4>
<h5>"There is no one who loves pain itself, who seeks after it and wants to have it, simply because it is pain..."</h5>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque et sapien ut erat porttitor suscipit id nec dui. Nam rhoncus mauris ac dui tristique bibendum. Aliquam molestie placerat gravida. Duis vitae tortor gravida libero semper cursus eu ut tortor. Nunc id orci orci. Suspendisse potenti. Phasellus vehicula leo sed erat rutrum sed blandit purus convallis.
</p>
<p>
Aliquam feugiat, neque a tempus rhoncus, neque dolor vulputate eros, non pellentesque elit lacus ut nunc. Pellentesque vel purus libero, ultrices condimentum lorem. Nam dictum faucibus mollis. Praesent adipiscing nunc sed dui ultricies molestie. Quisque facilisis purus quis felis molestie ut accumsan felis ultricies. Curabitur euismod est id est pretium accumsan. Praesent a mi in dolor feugiat vehicula quis at elit. Mauris lacus mauris, laoreet non molestie nec, adipiscing a nulla. Nullam rutrum, libero id pellentesque tempus, erat nibh ornare dolor, id accumsan est risus at leo. In convallis felis at eros condimentum adipiscing aliquam nisi faucibus. Integer arcu ligula, porttitor in fermentum vitae, lacinia nec dui.
</p>
</body>
</html>
EOT
    );
    fclose($stdin);

    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    // It is important that you close any pipes before calling
    // proc_close in order to avoid a deadlock
    $return_value = proc_close($process);

    echo "command returned $return_value\n";
}
person nad2000    schedule 08.03.2012

Вы можете протестировать эту функцию

function html2text($Document) {
    $Rules = array ('@<script[^>]*?>.*?</script>@si',
                    '@<[\/\!]*?[^<>]*?>@si',
                    '@([\r\n])[\s]+@',
                    '@&(quot|#34);@i',
                    '@&(amp|#38);@i',
                    '@&(lt|#60);@i',
                    '@&(gt|#62);@i',
                    '@&(nbsp|#160);@i',
                    '@&(iexcl|#161);@i',
                    '@&(cent|#162);@i',
                    '@&(pound|#163);@i',
                    '@&(copy|#169);@i',
                    '@&(reg|#174);@i',
                    '@&#(d+);@e'
             );
    $Replace = array ('',
                      '',
                      '',
                      '',
                      '&',
                      '<',
                      '>',
                      ' ',
                      chr(161),
                      chr(162),
                      chr(163),
                      chr(169),
                      chr(174),
                      'chr()'
                );
  return preg_replace($Rules, $Replace, $Document);
}
person HoangLong85    schedule 13.12.2013
comment
Спасибо за это. Отлично сработал для моего использования (преобразование HTML в RSS-канал) и предоставил простой шаблон для добавления двух дополнительных случаев (и). - person Alan M.; 09.01.2014

Я не нашел подходящего ни одного из существующих решений - простых HTML-писем для простых текстовых файлов.

Я открыл этот репозиторий, надеюсь, это кому-то поможет. Лицензия MIT, кстати :)

https://github.com/RobQuistNL/SimpleHtmlToText

Пример:

$myHtml = '<b>This is HTML</b><h1>Header</h1><br/><br/>Newlines';
echo (new Parser())->parseString($myHtml);

возвращает:

**This is HTML**
### Header ###


Newlines
person Rob    schedule 21.11.2016
comment
Отмечено как низкое качество по длине и содержанию. Я не знаю. Может быть, сообщение должно сказать что-то о том, как ваш код может быть использован для решения проблемы, или, может быть, это должен быть комментарий. Наиболее популярные ответы, кажется, показывают, как решения могут быть вызваны из кода PHP. - person Bill Bell; 21.11.2016
comment
Прошу прощения за написание этой библиотеки. Я добавил вам небольшой пример, если вы не хотите нажимать на ссылку и смотреть на пример. - person Rob; 21.11.2016
comment
Не сожалей! :-) Я писал как рецензент SO. Дело не в том, что я не хотел переходить по ссылке. Это те ответы SO, которые требуют, чтобы кто-то сделал, что считается некачественным. Я не знаю, почему кто-то, кстати, проголосовал против вашего ответа. - person Bill Bell; 22.11.2016

public function plainText($text)
{
    $text = strip_tags($text, '<br><p><li>');
    $text = preg_replace ('/<[^>]*>/', PHP_EOL, $text);

    return $text;
}

$text = "string 1<br>string 2<br/><ul><li>string 3</li><li>string 4</li></ul><p>string 5</p>";

echo planText($text);

вывод
строка 1
строка 2
строка 3
строка 4
строка 5

person Aommy Indy    schedule 11.08.2017
comment
не добавляйте просто ответ. Пожалуйста, добавьте текст, почему это ответ - person Himanth; 11.08.2017

Если вы хотите преобразовать специальные символы HTML, а не просто удалить их, а также разделить все и подготовиться к простому тексту, это решение, которое сработало для меня ...

function htmlToPlainText($str){
    $str = str_replace('&nbsp;', ' ', $str);
    $str = html_entity_decode($str, ENT_QUOTES | ENT_COMPAT , 'UTF-8');
    $str = html_entity_decode($str, ENT_HTML5, 'UTF-8');
    $str = html_entity_decode($str);
    $str = htmlspecialchars_decode($str);
    $str = strip_tags($str);

    return $str;
}

$string = '<p>this is (&nbsp;) a test</p>
<div>Yes this is! &amp; does it get "processed"? </div>'

htmlToPlainText($string);
// "this is ( ) a test. Yes this is! & does it get processed?"`

html_entity_decode с ENT_QUOTES | ENT_XML1 преобразует такие вещи, как &#39; htmlspecialchars_decode, преобразует такие вещи, как &amp; html_entity_decode, преобразует такие вещи, как '&lt;, а strip_tags удаляет любые оставшиеся HTML-теги.

person Jay    schedule 15.05.2018

Markdownify преобразует HTML в Markdown, систему форматирования простого текста, используемую на этом самом сайте.

person outis    schedule 28.12.2011
comment
Хороший выбор, за исключением того, как он обрабатывает ссылки. Но попробуйте онлайн-демонстрацию, если вы ее рассматриваете. - person Redzarf; 13.08.2013

Я столкнулся с той же проблемой, что и OP, и попытка некоторых решений из приведенных выше ответов не сработала для моих сценариев. Посмотрим, почему в конце.

Вместо этого я нашел этот полезный сценарий, во избежание путаницы назовем его html2text_roundcube, доступный под GPL:

Фактически это обновленная версия уже упомянутого скрипта - http://www.chuggnutt.com/html2text.php - обновленная по почте RoundCube.

Использование:

$h2t = new \Html2Text\Html2Text('Hello, &quot;<b>world</b>&quot;');
echo $h2t->getText(); // prints Hello, "WORLD"

Почему html2text_roundcube оказался лучше остальных:

  • Скрипт http://www.chuggnutt.com/html2text.php не работал "из коробки" для случаев со специальными кодами / именами HTML (например, &auml;) или непарными кавычками (например, <p>25" Monitor</p>).

  • В сценарии https://github.com/soundasleep/html2text не было возможности скрыть или сгруппировать ссылки в конце текста, из-за чего обычная HTML-страница выглядела раздутой ссылками в текстовом формате; настройка кода для специальной обработки того, как выполняется преобразование, не так проста, как простое редактирование массива в html2text_roundcube.

person Chris Dev    schedule 24.11.2016

Для текстов в utf-8 у меня сработало mb_convert_encoding. Чтобы обработать все, независимо от ошибок, убедитесь, что вы используете символ «@».

Я использую следующий базовый код:

$dom = new DOMDocument();
@$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));

$body = $dom->getElementsByTagName('body')->item(0);
echo $body->textContent;

Если вам нужно что-то более продвинутое, вы можете итеративно анализировать узлы, но вы столкнетесь со многими проблемами с пробелами.

Я реализовал преобразователь, основанный на том, что я здесь говорю. Если вам интересно, вы можете скачать его с git https://github.com/kranemora/html2text

Это может послужить справкой, чтобы сделать ваш

Вы можете использовать это так:

$html = <<<EOF
<p>Welcome to <strong>html2text<strong></p>
<p>It's <em>works</em> for you?</p>
EOF;

$html2Text = new \kranemora\Html2Text\Html2Text;
$text = $html2Text->convert($html);
person Fernando Pita    schedule 03.09.2019

Я только что нашел функцию PHP "strip_tags ()" и ее работу в моем случае.

Я попытался преобразовать следующий HTML:

<p><span style="font-family: 'Verdana','sans-serif'; color: black; font-size: 7.5pt;">&nbsp;</span>Many  practitioners are optimistic that the eyeglass and contact lens  industry will recover from the recent economic storm. Did your practice  feel its affects?&nbsp; Statistics show revenue notably declined in 2008 and  2009. But interestingly enough, those that monitor these trends state  that despite the industry's lackluster performance during this time,  revenue has grown at an average annual rate&nbsp;of 2.2% over the last five  years, to $9.0 billion in 2010.&nbsp; So despite the downturn, how were we  able to manage growth as an industry?</p>

После применения функции strip_tags () я получил следующий результат:

&amp;nbsp;Many  practitioners are optimistic that the eyeglass and contact lens  industry will recover from the recent economic storm. Did your practice  feel its affects?&amp;nbsp; Statistics show revenue notably declined in 2008 and  2009. But interestingly enough, those that monitor these trends state  that despite the industry&#039;s lackluster performance during this time,  revenue has grown at an average annual rate&amp;nbsp;of 2.2% over the last five  years, to $9.0 billion in 2010.&amp;nbsp; So despite the downturn, how were we  able to manage growth as an industry?
person sudip    schedule 16.05.2012
comment
strip_tags () не будет обрабатывать случай, когда у вас есть несколько элементов в нескольких строках, которые рассматриваются html как «встроенные», и будет отображать их в нескольких строках. Также обратный случай - если у вас есть несколько элементов div в одной строке, он удалит теги и объединит содержимое. Я поделился своим опытом здесь: stackoverflow.com/questions/1930297/ - person Nikola Petkanski; 24.09.2012

Если вы не хотите полностью удалять теги и сохранять содержимое внутри тегов, вы можете использовать DOMDocument и извлечь textContent корневого узла следующим образом:

function html2text($html) {
    $dom = new DOMDocument();
    $dom->loadHTML("<body>" . strip_tags($html, '<b><a><i><div><span><p>') . "</body>");
    $xpath = new DOMXPath($dom);
    $node = $xpath->query('body')->item(0);
    return $node->textContent; // text
}

$p = 'this is <b>test</b>. <p>how are <i>you?</i>. <a href="#">I\'m fine!</a></p>';
print html2text($p);
// this is test. how are you?. I'm fine!

Одним из преимуществ этого подхода является то, что он не требует никаких внешних пакетов.

person supersan    schedule 02.04.2018