3

I need some help with my PHP as I have a hard time of getting rid of the style type="text/css" tag. I want to remove the style tag to replace it with the empty string.

When I try this:

if (strpos($inbox_message, '<style type="text/css">') !== false) {
    echo (preg_replace('/<style[^>]*>(([^<]|[<[^\/]|<\/[^s]|<\/s[^t])*)<\/style>/i','',$inbox_message));
}

It will still showing the style tag in the html page.

Here is what it is showing:

<style type="text/css"> body {position: relative; font-family: Segoe UI; font-size: 12px; } .pageHeader {color: #9C9C9C; font-size: 160%; padding: 0px 0px 6px 0px} .pageHeaderLogo {padding-right: 15px;} .pageHeaderTitle{border-left: 1px solid #CCCCCC; padding: 5px;} .pageFooter {width: 100%; background-color: #f2f2f2; font-size: 12px; font-family: Segoe UI; padding:4px 4px 4px 4px; } .pageFooterLogo {text-align:right; width:100%} .padCells { padding: 0px 6px 0px 0px; } .preHeader {display: none !important; visibility:hidden; opacity:0; color:transparent; height:0; width:0; }</style>

Can you please show me an example how I could use preg_replace to find the style type=text/css tag so I can be able to remove them?

Thank you.

EDIT: Sorry I realised that I only need to remove the body in the style tags as I want to keep the other tags in the style.

/*GENERAL*/
    table{width:100%}
    body{background-color:#ebebeb; width: 100%; margin:0; padding:0; -webkit-font-smoothing: antialiased;font-family: "Segoe UI",SegoeUI,"Helvetica Neue",Helvetica,sans serif; -webkit-text-size-adjust: 100%;}
    div.ms-article-container #emailbodyouter .emailbodyinner section{margin:0}
    div.ms-article-container #emailbodyouter .emailbodyinner table div {margin:0}
    div.content-article #emailbodyouter .emailbodyinner section{margin:0}
    div.content-article #emailbodyouter .emailbodyinner table div {margin:0}
chris oojer
  • 301
  • 1
  • 10
  • `preg_replace` doesn't replace in place, you need to assign its output to the variable i.e. `$inbox_message = preg_replace('/ – Nick Mar 27 '20 at 22:33
  • Thank you, but it will remove all html tags in the page so it show as empty. I want to remove the tags between ``. Any idea? – chris oojer Mar 27 '20 at 22:36
  • Do you want to also remove the style tag itself? – lbrandao Mar 27 '20 at 22:39
  • @fromvega yes please. I want to remove it because it will change the body style so i want to remove it – chris oojer Mar 27 '20 at 22:40
  • I could use something like this `$inbox_message = str_replace(' – chris oojer Mar 27 '20 at 22:40
  • @chrisoojer your problem is your regex is too greedy and it will match from the first ``, removing everything in between – Nick Mar 27 '20 at 22:41
  • ` .preHeader {display: none !important; visibility:hidden; opacity:0; color:transparent; height:0; width:0; }', '', $inbox_message);` but the style will be random so i want to use preg_match or preg_replace to remove the style tag itself that come with `style type=text/css` – chris oojer Mar 27 '20 at 22:41

1 Answers1

7

Literal answer:

$inbox_message = preg_replace('#<style type="text/css">.*?</style>#s', '', $inbox_message);

You don't need to check whether it exists or not — if not, preg_replace will not do anything. You don't need to worry about what's inside the tag — the non-greedy quantifier takes care of it (as long as you don't by any chance have a nested <style> tag, which would be kind of extraordinary). And you don't need to worry about escaping slashes, if you choose another delimiter.

Non-literal answer: Beware Zalgo.

$doc = new DOMDocument();
$doc->loadHTML($inbox_message);
$xpath = new DOMXpath($doc);
$styles = $xpath->query('//style[@type="text/css"]');
if ($styles) {
  foreach ($styles as $style) {
    $style->parentNode->removeChild($style);
  }
}
$inbox_message = $doc->saveHTML();

EDIT after the question changed: Since there is no CSS parser by default, we end up having to use regexp anyway. Something like this should be okay. Zalgo method:

$inbox_message = preg_replace_callback('#<style type="text/css">.*?</style>#s', function($match) {
  return preg_replace('#body\s*{(?:[^"}]|"[^"]*")*}#', '', $match[0]);
}, $inbox_message);

Anti-Zalgo method:

$doc = new DOMDocument();
$doc->loadHTML($inbox_message);
$xpath = new DOMXpath($doc);
$styles = $xpath->query('//style[@type="text/css"]');
if ($styles) {
  foreach ($styles as $style) {
    $style->textContent = preg_replace('#body\s*{(?:[^"}]|"[^"]*")*}#', '', $style->textContent);
  }
}
$inbox_message = $doc->saveHTML();
Amadan
  • 191,408
  • 23
  • 240
  • 301
  • This is what I am looking for exactly as it is working great thanks – chris oojer Mar 27 '20 at 22:43
  • The `if ($styles)` would seem to be redundant as the `foreach` will do nothing if it's empty – Nick Mar 27 '20 at 22:44
  • @Nick Yeah, probably being too defensive. `query` can return `FALSE`, but only if my query is malformed or the context is wrong (yet I believe the query is fine and I don't use the context)... :P – Amadan Mar 27 '20 at 22:46
  • That's a fair point. Anyway, you get my vote for doing it the right way! – Nick Mar 27 '20 at 22:47
  • @Amadan Sorry to say that I only need to remove the `body {` so how I can do that using your code? – chris oojer Mar 27 '20 at 22:58
  • @Amadan I only need to remove this `body{background-color:#ebebeb; width: 100%; margin:0; padding:0; -webkit-font-smoothing: antialiased;font-family: "Segoe UI",SegoeUI,"Helvetica Neue",Helvetica,sans serif; -webkit-text-size-adjust: 100%;}` as it show on the bottom of the page – chris oojer Mar 27 '20 at 22:58
  • What do you mean, “show on the bottom of the page”? Styles aren’t shown, they’re applied. And after running my code, there shouldn’t be a style to apply any more (and certainly not show). What exactly are you asking? And, there was no talk about “body” in your question..? – Amadan Mar 27 '20 at 23:02