Using regular expressions to manipulate valid HTML is not advisable because regex is "DOM-unaware" meaning that it doesn't know if it is actually modifying a tag or just text that seems like a tag. Also, unless expressly told to replace only once, it will happily modify multiple matching strings (effectively damaging your content). Finally, using DomDocument is a superior technique because it will intelligently/reliably parse and modify a class attribute regardless of the position of the attribute in the tag and regardless of the character used to quote the value (single or double quotes).
Code: (PHP Demo)
$new_class = "new_class_attr";
$body = JFactory::getApplication()->getBody();
$dom = new DOMDocument;
$dom->loadHTML($body, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$bodytag = $dom->getElementsByTagName('body')->item(0);
if ($bodytag->hasAttribute("class")) {
$new_class = $bodytag->getAttribute("class") . " " . $new_class;
}
$bodytag->setAttribute("class", $new_class);
JFactory::getApplication()->setBody($dom->saveHTML());
And just in case anyone mistakes my endorsement of DOMDocument for fear of regular expressions, here is how I would code it up using refined regex calls.
Code: (PHP Demo) (First Regex Demo) (Second Regex Demo)
$new_class = "new_class_attr";
$body = JFactory::getApplication()->getBody();
$body = preg_replace('~<body[^>]*class *= *["\']\K~', "$new_class ", $body, 1, $count); // add to existing class attribute
if (!$count) {
$body = preg_replace('~<body\K~', " class=\"$new_class\"", $body, 1); // create class with attribute
}
JFactory::getApplication()->setBody($body);
But, again, I don't recommend regex for this job because it will be less stable... Imagine if you had an attribute (and didn't realize it) like specialclass" or specialclass
data-class` or data-class
. So look, let's not go down the tit-for-tat rabbit hole of creating a body string that will break the pattern then adjust the pattern to suit the vulnerability -- just use a DOM parser.