Konwersja HTML do zwykłego tekstu w PHP na potrzeby poczty e-mail

80

Używam TinyMCE, aby umożliwić minimalne formatowanie tekstu w mojej witrynie. Z utworzonego kodu HTML chciałbym przekonwertować go na zwykły tekst do wiadomości e-mail. Używałem klasy o nazwie html2text , ale naprawdę brakuje jej między innymi obsługi UTF-8. Jednak podoba mi się to, że mapuje pewne znaczniki HTML na formatowanie zwykłego tekstu - na przykład umieszczanie podkreśleń wokół tekstu, który wcześniej miał znaczniki <i> w HTML.

Czy ktoś stosuje podobne podejście do konwersji HTML na zwykły tekst w PHP? A jeśli tak: czy polecacie jakieś zajęcia osób trzecich, z których mogę skorzystać? Albo jak najlepiej rozwiązać ten problem?

Justin Stayton
źródło
Dla porównania, wikipedia odsyła do ankiety, która mówi, że tylko około 3% osób korzysta z poczty tekstowej.
Redzarf
8
@Redzarf nie chodzi o te 3%. Dodanie zwykłego tekstu jest naprawdę dobrym pomysłem, jeśli nie chcesz, aby Twój e-mail trafiał bezpośrednio do folderu spamu. Ponadto te 3% prawdopodobnie nie bierze pod uwagę lekkich klientów mobilnych. Last but not least: 3% to więcej niż 0%, co powinno sprawić, że potraktujesz to poważnie.
Ninj
@Ninj Właśnie sprawdziłem, a ankieta pochodzi z 2002 roku, więc od tego czasu wszystko się zmieni (chociaż nadal uważam, że 3% prawdopodobnie ma rację). Okazało się, że to narzędzie jest doskonałe: port25.com/support/authentication-center/email-verification
Redzarf

Odpowiedzi:

99

Użyj html2text (przykład HTML do tekstu ), na licencji Eclipse Public License . Używa metod DOM PHP do ładowania z HTML, a następnie iteruje po wynikowym DOM, aby wyodrębnić zwykły tekst. Stosowanie:

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

Chociaż jest niekompletny, ma otwarty kod źródłowy i mile widziany jest wkład.

Problemy z innymi skryptami konwersji:

  • Ponieważ html2text (GPL) nie jest kompatybilny z EPL.
  • Link (atrybucja) lkesslera jest niekompatybilny z większością licencji open source.
jevon
źródło
1
Pierwszy powyższy skrypt został wydany na warunkach licencji GPL, która nie jest licencją „niekomercyjną”. W zależności od kontekstu może to być niepożądane, ale nie jest „niekomercyjne”. Drugi link umożliwia również wykorzystanie komercyjne - tylko z przypisaniem. To też nie jest „niekomercyjne”.
Oliver Moran
1
@OliverMoran Masz rację, zredagowałem odpowiedź, aby dokładniej odzwierciedlić ograniczenia licencji.
jevon
Dziękuję @jevon, włączyłem Twoją pracę do mojego projektu i działa świetnie! Niestety, nie pomogło to rozwiązać mojego problemu z Outlookiem ( stackoverflow.com/questions/19135443/… ), ale w ten sposób otrzymuję czysty wynik.
Ninj
Link uszkodzony. Głosowanie przeciw.
Sibidharan
proszę wyjaśnić, ale kto wykryje, czy ktoś używa, czy nie, zgodnie z DPL lub czymkolwiek?
Miguel
21

oto inne rozwiązanie:

$cleaner_input = strip_tags($text);

Aby zapoznać się z innymi odmianami funkcji odkażania, zobacz:

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

T.Todua
źródło
13
Lepsza wersja$ClearText = preg_replace( "/\n\s+/", "\n", rtrim(html_entity_decode(strip_tags($HTMLText))) );
mAsT3RpEE
1
to jest takie proste i nie potrzebujesz innej biblioteki. również działa bardzo dobrze .......... :)
mili
14

Konwersja z HTML do tekstu za pomocą DOMDocument to realne rozwiązanie. Rozważ HTML2Text, który wymaga PHP5:

W odniesieniu do UTF-8, opis na stronie „Howto” stwierdza:

Wsparcie PHP dla Unicode jest dość słabe i nie zawsze obsługuje poprawnie utf-8. Chociaż skrypt html2text korzysta z metod bezpiecznych dla formatu Unicode (bez konieczności stosowania modułu mbstring), nie zawsze radzi sobie z obsługą kodowania w PHP. PHP tak naprawdę nie rozumie unicode ani kodowań, takich jak utf-8, i używa podstawowego kodowania systemu, który zwykle należy do rodziny ISO-8859. W rezultacie to, co może wyglądać jak prawidłowy znak w edytorze tekstu, w formacie utf-8 lub jednobajtowym, może zostać źle zinterpretowane przez PHP. Więc nawet jeśli myślisz, że wprowadzasz prawidłowy znak do html2text, możesz nie być.

Autor podaje kilka podejść do rozwiązania tego problemu i stwierdza, że ​​wersja 2 HTML2Text (używająca DOMDocument) obsługuje UTF-8.

Zwróć uwagę na ograniczenia dotyczące użytku komercyjnego.

lkessler
źródło
Markdownify nie jest już utrzymywane; demo online generuje wiele ostrzeżeń i nie działa. Nowa wersja html2text działa z moim e-mailem. Późne +1 do lkesslera.
malcanso
13

Jest sprawdzona funkcja strip_tags . Ale to nie jest ładne. To tylko odkaża. Możesz połączyć to z wymianą ciągu, aby uzyskać fantazyjne podkreślenia.


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

?>
Zaraza 669
źródło
Nie zapominaj, że paski tagi również usuwają kotwice!
Alix Axel
9

Aby to osiągnąć, możesz użyć lynx z opcjami -stdin i -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";
}
nad2000
źródło
8

Możesz przetestować tę funkcję

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
źródło
Dzięki za to. Działał świetnie dla mojego użytku (konwertowanie kodu HTML na potrzeby źródła RSS) i zapewniał prosty szablon do dodawania dwóch dodatkowych przypadków (& rsquo; i & mdash;).
Alan M.
6

Nie znalazłem żadnego z istniejących rozwiązań - proste e-maile w formacie HTML do zwykłych plików tekstowych.

Otworzyłem to repozytorium, mam nadzieję, że to komuś pomoże. Nawiasem mówiąc, licencja MIT :)

https://github.com/RobQuistNL/SimpleHtmlToText

Przykład:

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

zwroty:

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


Newlines
Obrabować
źródło
Oznaczone jako niskiej jakości ze względu na długość i treść. Nie wiem. Może post powinien zawierać informacje o tym, jak można wykorzystać kod do rozwiązania problemu, a może powinien to być komentarz. Najpopularniejsze odpowiedzi zdają się wskazywać, w jaki sposób można wywoływać rozwiązania z poziomu kodu PHP.
Bill Bell
Przepraszam za napisanie tej biblioteki. Dodałem dla ciebie mały przykład, jeśli nie chcesz klikać linku i spojrzeć na przykład.
Rob
2
Nie przepraszaj! :-) Pisałem jako recenzent SO. Nie chodzi o to, że nie chciałem kliknąć linku. Chodzi o to, że odpowiedzi SO, które wymagają tego, są uważane za poniżej standardu. Nie wiem, dlaczego ktokolwiek miałby przypadkowo głosować w dół na twoją odpowiedź.
Bill Bell
4

Jeśli chcesz przekonwertować znaki specjalne HTML, a nie tylko je usunąć, a także usunąć rzeczy i przygotować się na zwykły tekst, to rozwiązanie zadziałało dla mnie ...

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 z / ENT_QUOTES | ENT_XML1 konwertuje rzeczy takie &#39; jak &amp; htmlspecialchars_decode konwertuje rzeczy takie jak html_entity_decode konwertuje rzeczy takie jak, '&lt; a strip_tags usuwa wszelkie pozostałe tagi HTML.

Sójka
źródło
3

Markdownify konwertuje HTML do Markdown, systemu formatowania zwykłego tekstu używanego w tej witrynie.

poza
źródło
Dobry wybór, poza tym, jak obsługuje linki. Ale wypróbuj demo online, jeśli się nad tym zastanawiasz.
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);


ciąg wyjściowy 1
ciąg 2
ciąg 3
ciąg 4
ciąg 5

Aommy Indy
źródło
1
nie dodawaj tylko odpowiedz. Dodaj tekst, dlaczego tak brzmi odpowiedź
Himanth
2

Natknąłem się na ten sam problem, co w przypadku OP, i wypróbowanie niektórych rozwiązań z powyższych najlepszych odpowiedzi nie sprawdziło się w moich scenariuszach. Zobacz, dlaczego na końcu.

Zamiast tego znalazłem ten pomocny skrypt, aby uniknąć nieporozumień, nazwijmy go html2text_roundcube, dostępny na GPL:

W rzeczywistości jest to zaktualizowana wersja wspomnianego już skryptu - http://www.chuggnutt.com/html2text.php - zaktualizowana pocztą RoundCube.

Stosowanie:

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

Dlaczego html2text_roundcubeokazał się lepszy od innych:

  • Skrypt http://www.chuggnutt.com/html2text.phpnie działał od razu w przypadku przypadków ze specjalnymi kodami / nazwami HTML (np. &auml;) Lub niesparowanymi cudzysłowami (np <p>25" Monitor</p>.).

  • Skrypt https://github.com/soundasleep/html2textnie miał opcji ukrywania lub grupowania linków na końcu tekstu, przez co zwykła strona HTML wyglądała na rozdętą linkami w formacie zwykłego tekstu; dostosowywanie kodu do specjalnego traktowania sposobu przeprowadzania transformacji nie jest tak proste, jak zwykła edycja tablicy w programie html2text_roundcube.

Chris Dev
źródło
1

Właśnie znalazłem funkcję PHP "strip_tags ()" i działa ona w moim przypadku.

Próbowałem przekonwertować następujący 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>

Po zastosowaniu funkcji strip_tags () otrzymałem następujący wynik:

&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
źródło
3
strip_tags () nie obsłuży przypadku, w którym masz wiele elementów w kilku wierszach, które są traktowane przez html jako „inline” i wyświetlą je w wielu wierszach. Również odwrotny przypadek - jeśli masz wiele elementów div w jednym wierszu, usunie tagi i połączy zawartość. Tutaj podzieliłem się swoim doświadczeniem: stackoverflow.com/questions/1930297/…
Nikola Petkanski
1

Jeśli nie chcesz całkowicie usuwać tagów i zachować zawartość wewnątrz tagów, możesz użyć DOMDocumenti wyodrębnić textContentwęzeł główny w następujący sposób:

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!

Jedną z zalet tego podejścia jest to, że nie wymaga żadnych zewnętrznych pakietów.

supersan
źródło
1

W przypadku tekstów w utf-8 działało dla mnie mb_convert_encoding. Aby przetworzyć wszystko bez względu na błędy, użyj znaku „@”.

Podstawowy kod, którego używam to:

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

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

Jeśli chcesz czegoś bardziej zaawansowanego, możesz iteracyjnie analizować węzły, ale napotkasz wiele problemów z białymi znakami.

Zaimplementowałem konwerter na podstawie tego, co tu mówię. Jeśli jesteś zainteresowany, możesz go pobrać z git https://github.com/kranemora/html2text

Może służyć jako odniesienie do twojego

Możesz go używać w ten sposób:

$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
źródło