Initial import of space_profiles module
This commit is contained in:
101
helpers/ProfileHtmlSanitizer.php
Normal file
101
helpers/ProfileHtmlSanitizer.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace humhub\modules\space_profiles\helpers;
|
||||
|
||||
use yii\helpers\HtmlPurifier;
|
||||
|
||||
class ProfileHtmlSanitizer
|
||||
{
|
||||
public static function sanitize(?string $html): string
|
||||
{
|
||||
$value = (string)$html;
|
||||
if ($value === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$styleBlocks = [];
|
||||
if (preg_match_all('#<style\\b[^>]*>(.*?)</style>#is', $value, $matches)) {
|
||||
$styleBlocks = $matches[1] ?? [];
|
||||
}
|
||||
$value = preg_replace('#<style\\b[^>]*>.*?</style>#is', '', $value) ?? '';
|
||||
|
||||
$value = preg_replace('#<script\\b[^>]*>.*?</script>#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<style>\n" . implode("\n", $scopedCss) . "\n</style>";
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user