将HTML转换为PHP中的纯文本格式以用于电子邮件


80

我使用TinyMCE允许在我的网站中使用最少的文本格式。从生成的HTML中,我想将其转换为纯文本格式以发送电子邮件。我一直在使用一个名为html2text的类,但除其他外,它实际上缺少UTF-8支持。但是,我确实这样做,它将某些HTML标记映射为纯文本格式-就像在HTML之前带有<i>标记的文本周围加下划线。

是否有人使用类似的方法将HTML转换为PHP中的纯文本?如果是这样:您是否推荐我可以使用的任何第三方类?或者您如何最好地解决这个问题?



4
html2text具有可怕的代码执行漏洞
Tgr

作为参考,维基百科链接到一项调查,该调查称仅约3%的人使用纯文本电子邮件。
Redzarf

7
@Redzarf与这3%无关。如果您不希望电子邮件直接进入垃圾邮件文件夹,则添加纯文本部分是一个非常好的主意。另外,这3%可能没有考虑到轻量级的移动客户端。最后但并非最不重要的一点:3%大于0%,这应该使您认真考虑。
Ninj

@Ninj我刚刚检查过,调查是从2002年开始的,因此此后情况将有所变化(尽管我仍然认为3%可能是正确的。)有关垃圾邮件问题的要点-对于以后阅读此内容,担心垃圾邮件的任何人,我发现此工具非常出色:port25.com/support/authentication-center/email-verification
Redzarf

Answers:


99

使用html2text(示例HTMLtext),该文件已获得Eclipse Public License的许可。它使用PHP的DOM方法从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);

尽管不完整,但它是开源的,欢迎您提供帮助。

其他转换脚本的问题:


1
上面的第一个脚本是根据GPL发布的,该GPL不是“非商业”许可。根据上下文,这可能是不希望的,但不是“非商业性的”。第二个链接也允许用于商业用途-只需注明出处。那也不是“非商业性的”。
奥利弗·莫兰

1
@OliverMoran是的,我已经编辑了答案,以更准确地反映其许可限制。
jevon 2013年

谢谢@jevon,我将您的工作包括在我的项目中,并且效果很好!不幸的是,这无助于解决我的Outlook问题(stackoverflow.com/questions/19135443/…),但是我以这种方式得到了干净的结果。
Ninj

链接断开。不赞成投票。
西比达拉恩

请澄清一下,但是谁会发现有人在使用或不使用GLP?
米格尔(Miguel)


14

使用DOMDocument将HTML转换为文本是可行的解决方案。考虑HTML2Text,它需要PHP5:

关于UTF-8,“ howto”页面上的内容指出:

PHP自己对unicode的支持非常差,并且不能始终正确处理utf-8。尽管html2text脚本使用unicode-safe方法(不需要mbstring模块),但是它不能总是应付PHP自己的编码处理。PHP并不真正了解unicode或utf-8之类的编码,而是使用系统的基本编码,该编码通常是ISO-8859家族之一。结果,看起来像文本编辑器中的有效字符(utf-8或单字节)的内容可能会被PHP误解。因此,即使您认为自己将有效字符输入到html2text中,也可能不是这样。

作者提供了几种解决方法,并指出HTML2Text版本2(使用DOMDocument)具有UTF-8支持。

注意商业用途的限制。


Markdownify不再维护;在线演示会发出很多警告,并且不起作用。html2text的新版本确实适用于我的电子邮件。晚期+1给lkessler。
malcanso 2013年

13

有值得信赖的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)));

?>

不要忘记,剥离标签也可以删除锚点!
Alix Axel

9

您可以将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";
}

8

您可以测试此功能

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);
}

谢谢你 非常适合我使用(将HTML转换为RSS feed),并提供了一个简单的模板来添加另外两个案例(&rsquo;和&mdash;)。
艾伦·

6

我找不到适合的任何现有解决方案-简单的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

长度和内容标记为低质量。我不知道。帖子可能会说一些有关如何使用代码来回答问题的信息,或者应该是评论。最受欢迎的答案似乎表明如何从PHP代码中调用解决方案。
比尔·贝尔

很抱歉编写该库。我添加了一个小例子你,如果你不想点击的例子中的链接,看看..
罗布

2
不要后悔!:-)我写的是SO审稿人。这并不是我不想单击链接。是因为SO答案要求这样做是不合标准的。我不知道为什么有人会偶然拒绝您的回答。
比尔·贝尔

4

如果您要转换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?"`

带有ENT_QUOTES的html_entity_decode | ENT_XML1转换类似&#39; htmlspecialchars_decode转换类似&amp; html_entity_decode转换像'&lt; ,strip_tags删除所有剩余的HTML标记。


3

Markdownify将HTML转换为Markdown,这是该站点上使用的纯文本格式系统。


一个很好的选择,除了它如何处理链接。但是,如果您正在考虑的话,请尝试在线演示。
Redzarf

3
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


1
不要只添加答案。请添加文本,为什么会这样回答
Himanth '17

2

我遇到了与OP相同的问题,尝试从上面的最高答案中尝试一些解决方案并不能证明适合我的方案。看看为什么最后。

相反,我发现了这个有用的脚本,为避免混淆,我们称之为html2text_roundcubeGPL下可用的脚本:

它实际上是已经提到的脚本的更新版本- 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


1

我刚刚发现一个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?

3
strip_tags()无法处理您在几行上具有多个元素的情况,这些行被html视为“内联”,并将在多行上显示。同样,相反的情况-如果一行上有多个div元素,它将剥离标签并连接内容。我在这里分享我的经验:stackoverflow.com/questions/1930297/...
尼古拉Petkanski

1

对于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);

0

如果您不想完全剥离标签并将内容保留在标签内,则可以使用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!

这种方法的一个优点是它不需要任何外部程序包。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.