Add safe_html() for XSS-safe WYSIWYG HTML sanitization

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-12-25 23:39:42 +00:00
parent 1322bbf988
commit 1abbac58e7
419 changed files with 39662 additions and 154 deletions

View File

@@ -1182,6 +1182,48 @@ function is_loopback_ip(): bool
return in_array($ip, $loopback_addresses, true);
}
/**
* Sanitize HTML from WYSIWYG editors to prevent XSS attacks
*
* Uses HTMLPurifier to filter potentially malicious HTML while preserving
* safe formatting tags. Suitable for user-generated rich text content.
*
* @param string $html The HTML string to sanitize
* @return string Sanitized HTML safe for display
*/
function safe_html(string $html): string
{
static $purifier = null;
if ($purifier === null) {
require_once base_path('vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php');
$config = HTMLPurifier_Config::createDefault();
// Cache serialized definitions for performance
$cache_dir = storage_path('rsx-tmp/htmlpurifier');
if (!is_dir($cache_dir)) {
mkdir($cache_dir, 0755, true);
}
$config->set('Cache.SerializerPath', $cache_dir);
$config->set('Cache.SerializerPermissions', null); // Disable chmod (Docker compatibility)
// Allow common formatting elements
$config->set('HTML.Allowed', 'p,br,strong,b,em,i,u,s,strike,a[href|title|target],ul,ol,li,blockquote,h1,h2,h3,h4,h5,h6,pre,code,img[src|alt|title|width|height],table,thead,tbody,tr,th,td,div,span');
// Allow class attributes for styling
$config->set('Attr.AllowedClasses', null); // Allow all classes
// Link handling
$config->set('HTML.TargetBlank', true);
$config->set('URI.AllowedSchemes', ['http' => true, 'https' => true, 'mailto' => true]);
$purifier = new HTMLPurifier($config);
}
return $purifier->purify($html);
}
/**
* Generate a hash for a file suitable for build/cache invalidation
*