]*>(.*?)#is', $value, $matches)) { $styleBlocks = $matches[1] ?? []; } $value = preg_replace('#]*>.*?#is', '', $value) ?? ''; $value = preg_replace('#]*>.*?#is', '', $value) ?? ''; $value = preg_replace("/\\son[a-z]+\\s*=\\s*(\"[^\"]*\"|'[^']*'|[^\\s>]+)/i", '', $value) ?? ''; $value = preg_replace('/javascript\\s*:/i', '', $value) ?? ''; $value = preg_replace('/expression\\s*\\(/i', '', $value) ?? ''; $purified = HtmlPurifier::process($value, [ 'HTML.Allowed' => 'div,p,br,span,strong,em,b,i,u,ul,ol,li,h1,h2,h3,h4,h5,h6,a[href|title|target],img[src|alt|title|width|height],blockquote,hr,table,thead,tbody,tr,th,td,code,pre', 'Attr.EnableID' => false, 'CSS.Trusted' => false, 'URI.AllowedSchemes' => [ 'http' => true, 'https' => true, 'mailto' => true, ], ]); $scopedCss = []; foreach ($styleBlocks as $styleBlock) { $css = self::scopeCss((string)$styleBlock); if (trim($css) !== '') { $scopedCss[] = $css; } } if (empty($scopedCss)) { return $purified; } return $purified . "\n"; } private static function scopeCss(string $css): string { $css = preg_replace('/@import\\s+[^;]+;/i', '', $css) ?? ''; $css = preg_replace('/javascript\\s*:/i', '', $css) ?? ''; $css = preg_replace('/expression\\s*\\(/i', '', $css) ?? ''; $chunks = explode('}', $css); $scoped = []; foreach ($chunks as $chunk) { if (trim($chunk) === '' || strpos($chunk, '{') === false) { continue; } [$selectors, $body] = explode('{', $chunk, 2); $selectors = trim($selectors); if ($selectors === '') { continue; } if (strpos($selectors, '@') === 0) { $scoped[] = $selectors . '{' . $body . '}'; continue; } $selectorParts = array_filter(array_map('trim', explode(',', $selectors))); $scopedSelectors = []; foreach ($selectorParts as $selector) { $selector = str_replace(':root', '.rescue-profile-scope', $selector); if (preg_match('/^(html|body)\\b/i', $selector)) { $selector = preg_replace('/^(html|body)\\b/i', '.rescue-profile-scope', $selector) ?? '.rescue-profile-scope'; } if (strpos($selector, '.rescue-profile-scope') !== 0) { $selector = '.rescue-profile-scope ' . $selector; } $scopedSelectors[] = $selector; } if (!empty($scopedSelectors)) { $scoped[] = implode(', ', $scopedSelectors) . '{' . $body . '}'; } } return implode("\\n", $scoped); } }