Conversión de HTML a texto sin formato en PHP para correo electrónico

80

Utilizo TinyMCE para permitir un formato mínimo de texto dentro de mi sitio. A partir del HTML que se produce, me gustaría convertirlo en texto sin formato para correo electrónico. He estado usando una clase llamada html2text , pero realmente carece de soporte UTF-8, entre otras cosas. Sin embargo, me gusta que asigna ciertas etiquetas HTML al formato de texto sin formato, como poner guiones bajos alrededor del texto que anteriormente tenía etiquetas <i> en el HTML.

¿Alguien usa un enfoque similar para convertir HTML a texto sin formato en PHP? Y si es así: ¿Recomiendas alguna clase de terceros que pueda usar? ¿O cuál es la mejor manera de abordar este problema?

Justin Stayton
fuente
Como referencia, wikipedia tiene enlaces a una encuesta que dice que solo alrededor del 3% de las personas usan correo electrónico de solo texto.
Redzarf
8
@Redzarf no se trata de este 3%. Agregar una parte de texto sin formato es una muy buena idea si no desea que su correo electrónico vaya directamente a la carpeta de correo no deseado. Además, este 3% probablemente no tenga en cuenta a los clientes móviles ligeros. Por último, pero no menos importante: 3% es mayor que 0%, lo que debería hacer que lo consideres seriamente.
Ninj
@Ninj Acabo de verificar y la encuesta era de 2002, por lo que las cosas habrán cambiado desde entonces (aunque todavía creo que el 3% probablemente sea correcto). Buen punto sobre el problema del spam: para cualquiera que lea esto más tarde y esté preocupado por el spam, Descubrí que esta herramienta era excelente: port25.com/support/authentication-center/email-verification
Redzarf

Respuestas:

99

Utilice html2text (ejemplo de HTML a texto ), con licencia de Eclipse Public License . Utiliza los métodos DOM de PHP para cargar desde HTML y luego itera sobre el DOM resultante para extraer texto sin formato. Uso:

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

Aunque está incompleto, es de código abierto y las contribuciones son bienvenidas.

Problemas con otras secuencias de comandos de conversión:

  • Dado que html2text (GPL) no es compatible con EPL.
  • El enlace de lkessler (atribución) es incompatible con la mayoría de las licencias de código abierto.
jevon
fuente
1
El primer script anterior se publica bajo la GPL, que no es una licencia "no comercial". Dependiendo del contexto, puede ser indeseable, pero no es "no comercial". El segundo enlace también permite el uso comercial, solo con atribución. Eso tampoco es "no comercial".
Oliver Moran
1
@OliverMoran Tienes razón, he editado la respuesta para reflejar con mayor precisión las limitaciones de su licencia.
jevon
Gracias @jevon, incluí tu trabajo en mi proyecto y funciona muy bien. Desafortunadamente, no ayudó a resolver mi problema de Outlook ( stackoverflow.com/questions/19135443/… ) pero obtengo un resultado limpio de esa manera.
Ninj
Enlace roto. Votar en contra.
Sibidharan
por favor aclare, pero ¿quién detectará si alguien está usando o no bajo GLP o lo que sea?
Miguel
14

La conversión de HTML a texto mediante DOMDocument es una solución viable. Considere HTML2Text, que requiere PHP5:

Con respecto a UTF-8, el artículo de la página "cómo" dice:

El propio soporte de PHP para Unicode es bastante deficiente y no siempre maneja utf-8 correctamente. Aunque el script html2text usa métodos seguros para Unicode (sin necesidad del módulo mbstring), no siempre puede hacer frente al manejo de codificaciones por parte de PHP. PHP realmente no entiende unicode o codificaciones como utf-8, y usa la codificación base del sistema, que tiende a ser de la familia ISO-8859. Como resultado, lo que puede parecerle un carácter válido en su editor de texto, ya sea en utf-8 o en un solo byte, puede ser malinterpretado por PHP. Entonces, aunque crea que está introduciendo un carácter válido en html2text, es posible que no lo esté.

El autor proporciona varios enfoques para resolver esto y afirma que la versión 2 de HTML2Text (usando DOMDocument) tiene soporte UTF-8.

Tenga en cuenta las restricciones para uso comercial.

lkessler
fuente
Markdownify ya no se mantiene; la demostración en línea arroja muchas advertencias y no funciona. La nueva versión de html2text funciona para mi correo electrónico. Un +1 tardío para lkessler.
malcanso
13

Existe la confiable función strip_tags . Aunque no es bonito. Solo desinfectará. Puede combinarlo con un reemplazo de cadena para obtener sus elegantes guiones bajos.


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

?>
pestilencia669
fuente
¡No olvide que las etiquetas de tira también eliminan los anclajes!
Alix Axel
9

Puede usar lynx con las opciones -stdin y -dump para lograrlo:

<?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";
}
nad2000
fuente
8

Puedes probar esta función

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);
}
HoangLong85
fuente
Gracias por esto. Funcionó muy bien para mi uso (conversión de HTML para una fuente RSS) y proporcionó una plantilla simple para agregar dos casos adicionales (& rsquo; y & mdash;).
Alan M.
6

No encontré ninguna de las soluciones existentes adecuada: correos electrónicos HTML simples a archivos de texto sin formato simples.

Abrí este repositorio, espero que ayude a alguien. Licencia MIT, por cierto :)

https://github.com/RobQuistNL/SimpleHtmlToText

Ejemplo:

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

devoluciones:

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


Newlines
Robar
fuente
Marcado como de baja calidad por su extensión y contenido. No se. Tal vez la publicación debería decir algo sobre cómo se puede usar su código para responder al problema, o tal vez debería ser un comentario. Las respuestas más populares parecen mostrar cómo se pueden invocar las soluciones desde el código PHP.
Bill Bell
Lamento escribir esa biblioteca. He añadido un pequeño ejemplo para ti si no quieres hacer clic en el enlace y mirar el ejemplo ..
Rob
2
¡No te arrepientas! :-) Estaba escribiendo como revisor de SO. No es que no quisiera hacer clic en el enlace. Es que las respuestas SO que requieren que uno haga se consideran deficientes. No sé por qué alguien rechazaría tu respuesta por cierto.
Bill Bell
4

Si desea convertir los caracteres especiales HTML y no solo eliminarlos, así como eliminar las cosas y prepararse para el texto sin formato, esta fue la solución que funcionó para mí ...

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 con ENT_QUOTES | ENT_XML1 convierte cosas como &#39; htmlspecialchars_decode convierte cosas como &amp; html_entity_decode convierte cosas como '&lt; y strip_tags elimina cualquier etiqueta HTML sobrante.

Arrendajo
fuente
3

Markdownify convierte HTML a Markdown, un sistema de formato de texto sin formato utilizado en este mismo sitio.

outis
fuente
Una buena elección, excepto por cómo maneja los enlaces. Pero pruebe la demostración en línea si lo está considerando.
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);

salida
cadena 1
cadena 2
cadena 3
cadena 4
cadena 5

Aommy Indy
fuente
1
no agregue solo la respuesta. Por favor agregue texto por qué esta es la respuesta
Himanth
2

Encontré el mismo problema que el OP, y probar algunas soluciones de las respuestas principales anteriores no resultó funcionar para mis escenarios. Vea por qué al final.

En su lugar, encontré este script útil, para evitar confusiones, llamémoslo html2text_roundcube, disponible bajo GPL:

En realidad, es una versión actualizada de un script ya mencionado http://www.chuggnutt.com/html2text.php, actualizado por correo de RoundCube.

Uso:

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

Por qué html2text_roundcuberesultó mejor que los demás:

  • El script http://www.chuggnutt.com/html2text.phpno funcionaba de fábrica para casos con códigos / nombres HTML especiales (p &auml;. Ej. ) O comillas sin emparejar (p <p>25" Monitor</p>. Ej .).

  • Script https://github.com/soundasleep/html2textno tenía la opción de ocultar o agrupar los enlaces al final del texto, haciendo que una página HTML habitual pareciera inflada de enlaces cuando estaba en formato de texto sin formato; personalizar el código para un tratamiento especial de cómo se realiza la transformación no es tan sencillo como simplemente editar una matriz en formato html2text_roundcube.

Chris Dev
fuente
1

Acabo de encontrar una función PHP "strip_tags ()" y está funcionando en mi caso.

Intenté convertir el siguiente 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>

Después de aplicar la función strip_tags (), tengo el siguiente resultado:

&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?
sudip
fuente
3
strip_tags () no manejará un caso en el que tenga varios elementos en varias líneas que html considere 'en línea' y los mostrará en varias líneas. Además, el caso inverso: si tiene varios elementos div en una línea, eliminará las etiquetas y concatenará el contenido. Compartí mi experiencia aquí: stackoverflow.com/questions/1930297/…
Nikola Petkanski
1

Si no desea quitar las etiquetas por completo y mantener el contenido dentro de las etiquetas, puede usar DOMDocumenty extraer del textContentnodo raíz de la siguiente manera:

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!

Una ventaja de este enfoque es que no requiere ningún paquete externo.

supersan
fuente
1

Para textos en utf-8, me funcionó mb_convert_encoding. Para procesar todo independientemente de los errores, asegúrese de utilizar la "@".

El código básico que utilizo es:

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

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

Si desea algo más avanzado, puede analizar iterativamente los nodos, pero encontrará muchos problemas con los espacios en blanco.

He implementado un convertidor basado en lo que digo aquí. Si está interesado, puede descargarlo de git https://github.com/kranemora/html2text

Puede servir de referencia para hacer el tuyo

Puedes usarlo así:

$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);
Fernando Pita
fuente