Удалите изображения из HTML так же, как это сделал бы Gmail для писем без включенных изображений

Я пишу простой редактор HTML-дизайна электронной почты на PHP, а также показываю демонстрацию того, как это будет выглядеть.

Я думаю, что было бы также очень полезно показать пользователю, как это будет выглядеть в почтовом клиенте, таком как gmail, с отключенными изображениями.

Какой мой лучший подход к этому? Кто-нибудь знает, как это делается в gmail / hotmail и т. Д.?

Я просто удаляю img -> src а также css background: url с регулярным выражением?

Я хотел бы удалить фоновые части из:background="url" используется в таблицах иbackground-image:url(url); используется встроенный CSS

Я нашел этот вопрос, который имеет такую ​​же идею, хотя я хотел бы на самом деле удалить img и backrgound-images из текста HTML.

Или этот код может быть изменен для работы с фоновыми изображениями?

7 ответов

Решение

Я бы также предложил использовать PHP DOM вместо регулярных выражений, которые часто бывают неточными. Вот пример кода, который вы можете использовать для удаления всех тегов img и всех атрибутов фона из вашей строки:

// ...loading the DOM
$dom = new DOMDocument();
@$dom->loadHTML($string);  // Using @ to hide any parse warning sometimes resulting from markup errors
$dom->preserveWhiteSpace = false;
// Here we strip all the img tags in the document
$images = $dom->getElementsByTagName('img');
$imgs = array();
foreach($images as $img) {
    $imgs[] = $img;
}
foreach($imgs as $img) {
    $img->parentNode->removeChild($img);
}
// This part strips all 'background' attribute in (all) the body tag(s)
$bodies = $dom->getElementsByTagName('body');
$bodybg = array();
foreach($bodies as $bg) {
    $bodybg[] = $bg;
}
foreach($bodybg as $bg) {
    $bg->removeAttribute('background');
}

$str = $dom->saveHTML();

Я выбрал теги тела вместо таблицы, так как <table> сам по себе не имеет background атрибут, он имеет только bgcolor, Чтобы удалить фоновое встроенное свойство css, вы можете использовать PHP CSS Parser sabberworm для анализа CSS, полученного из DOM: попробуйте это

// Selecting all the elements since each one could have a style attribute
$alltags = $dom->getElementsByTagName('*');
$tags = array();
foreach($alltags as $tag) {
    $tags[] = $tag;
} $css = array();
foreach($tags as &$tag) {
    $oParser = new CSSParser("p{".$tag->getAttribute('style')."}");
    $oCss = $oParser->parse();
    foreach($oCss->getAllRuleSets() as $oRuleSet) {
        $oRuleSet->removeRule('background');
        $oRuleSet->removeRule('background-image');
    }
    $css = $oCss->__toString();
    $css = substr_replace($css, '', 0, 3);
    $css = substr_replace($css, '', -2, 2);
    if($css)
        $tag->setAttribute('style', $css);
}

Использование всего этого кода вместе, например, если у вас есть

$string = '<!DOCTYPE html>
<html><body background="http://yo.ur/background/dot/com" etc="an attribute value">
<img src="http://your.pa/th/to/image"><img src="http://anoth.er/path/to/image">
<div style="background-image:url(http://inli.ne/css/background);border: 1px solid black">div content...</div>
<div style="background:url(http://inli.ne/css/background);border: 1px solid black">2nd div content...</div>
</body></html>';

PHP будет выводить

<!DOCTYPE html>
<html><body etc="an attribute value">
<div style="border: 1px solid black;">div content...</div>
<div style="border: 1px solid black;">2nd div content...</div>
</body></html>

Чтобы полностью имитировать поведение gmail или подобных веб-писем, нужно заменить теги и атрибуты background: css соответствующим образом, чтобы они отображали заполнитель, давая понять пользователю, что здесь лежит изображение.

Так как обычно сообщение загружается в iframe, я думаю, что вам лучше всего будет очистить сторону сервера сообщений, удалив все ненужные теги и соответственно заменив изображения при предварительном просмотре.

Я согласен с Михалом в том, что не стоит использовать просто регулярное выражение для проверки вашего HTML, и вам, вероятно, следует пройтись по дереву DOM, чтобы быть в безопасности.

Почему бы вам не взглянуть на washtml Фредерика Мотта, который использовал roundcube, чтобы начать?

Использование регулярных выражений для разбора HTML обычно не рекомендуется.

Я думаю, что лучшим подходом было бы проанализировать серверную часть html и манипулировать ею, чтобы удалить изображения или атрибуты src изображения. Библиотека, с которой я добился успеха - http://simplehtmldom.sourceforge.net/, но я думаю, что вы можете использовать официальные расширения PHP DOM.

Удаление фоновых изображений может быть более сложным. Возможно, вам придется использовать что-то вроде http://www.pelagodesign.com/sidecar/emogrifier/ чтобы применить что-то вроде {background: none} к html-элементам. Однако фоновые изображения CSS не поддерживаются в последних версиях Microsoft Outlook, поэтому я бы рекомендовал вообще не использовать их с самого начала, чтобы сообщения электронной почты были совместимы для большинства почтовых клиентов.

Как упомянуто tkone: возможно, JavaScript / jQuery является ответом.

Это позволит просмотреть все изображения в области предварительного просмотра и изменить источник на изображение-заполнитель. Класс placeholder также устанавливает фоновое изображение для заполнителя.

JQuery

$("#previewArea img").each(function(){
  $(this).attr("src","placeholder.jpg");
  $(this).addClass("hideBG");
});

CSS

.hideBG{
  background: url("placeholder.jpg");
}

Не проверено, но должно работать - в зависимости от ваших настроек и потребностей.

Я задал похожий вопрос (в решении, а не в реальной проблеме): как убрать из строки определенные теги и определенные атрибуты? ( Решение)

Это серверная библиотека, которая очищает (и форматирует) ввод HTML в соответствии с предопределенными настройками. Имейте это удалить любой src атрибуты и все background свойства.

Вы всегда можете сделать это на стороне клиента.

Используя этот гипотетический код, вы должны быть в состоянии сделать что-то вроде этого, притворяясь, что все современные браузеры работают одинаково: (или использовать jQuery или что-то в этом роде)

var email;
var xhr = new XMLHttpRequest();
xhr.open('GET', URL_FOR_EMAIL, true);
xhr.onreadystatechange = function(event){
   if(xhr.readyState === 4 && xhr.status === 200){
        email = HTMLParser(xhr.responseText);
   }
}

var imgs = email.getElementsByTagName('img');
for(var i = 0; i > imgs.length; i++){
    email.removeChild(imgs[i]);
}

// attach the email body to the DOM
// do something with the images

HTMLParser от MDN

function HTMLParser(aHTMLString){
  var html = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html", null),
    body = document.createElementNS("http://www.w3.org/1999/xhtml", "body");
  html.documentElement.appendChild(body);

  body.appendChild(Components.classes["@mozilla.org/feed-unescapehtml;1"]
    .getService(Components.interfaces.nsIScriptableUnescapeHTML)
    .parseFragment(aHTMLString, false, null, body));

  return body;
},

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

Пример: Поменяйте все "img" на "br"

Так что сначала напечатайте отфильтрованный HTML и переверните его с помощью ajax, найдите все br с атрибутом src.

Другие вопросы по тегам