mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-05-22 05:15:29 +09:00
Allow customizing the allowed class list, editor components, and widgets
This commit is contained in:
parent
ea161223b9
commit
14f6db25b3
1 changed files with 71 additions and 18 deletions
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Rhymix\Framework\Filters;
|
namespace Rhymix\Framework\Filters;
|
||||||
|
|
||||||
|
use Rhymix\Framework\Config;
|
||||||
use Rhymix\Framework\Security;
|
use Rhymix\Framework\Security;
|
||||||
use Rhymix\Framework\Storage;
|
use Rhymix\Framework\Storage;
|
||||||
|
|
||||||
|
|
@ -11,9 +12,9 @@ use Rhymix\Framework\Storage;
|
||||||
class HTMLFilter
|
class HTMLFilter
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* HTMLPurifier instance is cached here.
|
* HTMLPurifier instances are cached here.
|
||||||
*/
|
*/
|
||||||
protected static $_htmlpurifier;
|
protected static $_instances = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pre-processing and post-processing filters are stored here.
|
* Pre-processing and post-processing filters are stored here.
|
||||||
|
|
@ -69,18 +70,26 @@ class HTMLFilter
|
||||||
* Filter HTML content to block XSS attacks.
|
* Filter HTML content to block XSS attacks.
|
||||||
*
|
*
|
||||||
* @param string $input
|
* @param string $input
|
||||||
|
* @param bool $allow_editor_components (optional)
|
||||||
|
* @param bool $allow_widgets (optional)
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function clean($input)
|
public static function clean($input, $allow_editor_components = true, $allow_widgets = false)
|
||||||
{
|
{
|
||||||
foreach (self::$_preproc as $callback)
|
foreach (self::$_preproc as $callback)
|
||||||
{
|
{
|
||||||
$input = $callback($input);
|
$input = $callback($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
$input = self::_preprocess($input);
|
$allowed_classes = Config::get('mediafilter.classes') ?: array();
|
||||||
$output = self::getHTMLPurifier()->purify($input);
|
if ($allow_widgets)
|
||||||
$output = self::_postprocess($output);
|
{
|
||||||
|
$allowed_classes[] = 'zbxe_widget_output';
|
||||||
|
}
|
||||||
|
|
||||||
|
$input = self::_preprocess($input, $allow_editor_components, $allow_widgets);
|
||||||
|
$output = self::getHTMLPurifier($allowed_classes)->purify($input);
|
||||||
|
$output = self::_postprocess($output, $allow_editor_components, $allow_widgets);
|
||||||
|
|
||||||
foreach (self::$_postproc as $callback)
|
foreach (self::$_postproc as $callback)
|
||||||
{
|
{
|
||||||
|
|
@ -93,18 +102,24 @@ class HTMLFilter
|
||||||
/**
|
/**
|
||||||
* Get an instance of HTMLPurifier.
|
* Get an instance of HTMLPurifier.
|
||||||
*
|
*
|
||||||
|
* @param array $allowed_classes (optional)
|
||||||
* @return object
|
* @return object
|
||||||
*/
|
*/
|
||||||
public static function getHTMLPurifier()
|
public static function getHTMLPurifier($allowed_classes = array())
|
||||||
{
|
{
|
||||||
|
// Keep separate instances for different sets of allowed classes.
|
||||||
|
$allowed_classes = array_unique($allowed_classes);
|
||||||
|
sort($allowed_classes);
|
||||||
|
$key = sha1(serialize($allowed_classes));
|
||||||
|
|
||||||
// Create an instance with reasonable defaults.
|
// Create an instance with reasonable defaults.
|
||||||
if (self::$_htmlpurifier === null)
|
if (!isset(self::$_instances[$key]))
|
||||||
{
|
{
|
||||||
// Get the default configuration.
|
// Get the default configuration.
|
||||||
$config = \HTMLPurifier_Config::createDefault();
|
$config = \HTMLPurifier_Config::createDefault();
|
||||||
|
|
||||||
// Customize the default configuration.
|
// Customize the default configuration.
|
||||||
$config->set('Attr.AllowedClasses', array());
|
$config->set('Attr.AllowedClasses', $allowed_classes);
|
||||||
$config->set('Attr.AllowedFrameTargets', array('_blank'));
|
$config->set('Attr.AllowedFrameTargets', array('_blank'));
|
||||||
$config->set('Attr.DefaultImageAlt', '');
|
$config->set('Attr.DefaultImageAlt', '');
|
||||||
$config->set('Attr.EnableID', true);
|
$config->set('Attr.EnableID', true);
|
||||||
|
|
@ -144,11 +159,11 @@ class HTMLFilter
|
||||||
self::_supportCSS3($config);
|
self::_supportCSS3($config);
|
||||||
|
|
||||||
// Cache our instance of HTMLPurifier.
|
// Cache our instance of HTMLPurifier.
|
||||||
self::$_htmlpurifier = new \HTMLPurifier($config);
|
self::$_instances[$key] = new \HTMLPurifier($config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the cached instance.
|
// Return the cached instance.
|
||||||
return self::$_htmlpurifier;
|
return self::$_instances[$key];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -379,12 +394,17 @@ class HTMLFilter
|
||||||
* Rhymix-specific preprocessing method.
|
* Rhymix-specific preprocessing method.
|
||||||
*
|
*
|
||||||
* @param string $content
|
* @param string $content
|
||||||
|
* @param bool $allow_editor_components (optional)
|
||||||
|
* @param bool $allow_widgets (optional)
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected static function _preprocess($content)
|
protected static function _preprocess($content, $allow_editor_components = true, $allow_widgets = false)
|
||||||
{
|
{
|
||||||
// Encode widget and editor component properties so that they are not removed by HTMLPurifier.
|
// Encode widget and editor component properties so that they are not removed by HTMLPurifier.
|
||||||
$content = self::_encodeWidgetsAndEditorComponents($content);
|
if ($allow_editor_components || $allow_widgets)
|
||||||
|
{
|
||||||
|
$content = self::_encodeWidgetsAndEditorComponents($content, $allow_editor_components, $allow_widgets);
|
||||||
|
}
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -392,9 +412,11 @@ class HTMLFilter
|
||||||
* Rhymix-specific postprocessing method.
|
* Rhymix-specific postprocessing method.
|
||||||
*
|
*
|
||||||
* @param string $content
|
* @param string $content
|
||||||
|
* @param bool $allow_editor_components (optional)
|
||||||
|
* @param bool $allow_widgets (optional)
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected static function _postprocess($content)
|
protected static function _postprocess($content, $allow_editor_components = true, $allow_widgets = false)
|
||||||
{
|
{
|
||||||
// Define acts to allow and deny.
|
// Define acts to allow and deny.
|
||||||
$allow_acts = array('procFileDownload');
|
$allow_acts = array('procFileDownload');
|
||||||
|
|
@ -436,7 +458,7 @@ class HTMLFilter
|
||||||
}, $content);
|
}, $content);
|
||||||
|
|
||||||
// Restore widget and editor component properties.
|
// Restore widget and editor component properties.
|
||||||
$content = self::_decodeWidgetsAndEditorComponents($content);
|
$content = self::_decodeWidgetsAndEditorComponents($content, $allow_editor_components, $allow_widgets);
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -444,11 +466,27 @@ class HTMLFilter
|
||||||
* Encode widgets and editor components before processing.
|
* Encode widgets and editor components before processing.
|
||||||
*
|
*
|
||||||
* @param string $content
|
* @param string $content
|
||||||
|
* @param bool $allow_editor_components (optional)
|
||||||
|
* @param bool $allow_widgets (optional)
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected static function _encodeWidgetsAndEditorComponents($content)
|
protected static function _encodeWidgetsAndEditorComponents($content, $allow_editor_components = true, $allow_widgets = false)
|
||||||
{
|
{
|
||||||
return preg_replace_callback('!<(div|img)([^>]*)(editor_component="[^"]+"|class="zbxe_widget_output")([^>]*)>!i', function($match) {
|
$regexp = array();
|
||||||
|
if ($allow_editor_components)
|
||||||
|
{
|
||||||
|
$regexp[] = 'editor_component="[^"]+"';
|
||||||
|
}
|
||||||
|
if ($allow_widgets)
|
||||||
|
{
|
||||||
|
$regexp[] = 'class="zbxe_widget_output"';
|
||||||
|
}
|
||||||
|
if (!count($regexp))
|
||||||
|
{
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return preg_replace_callback('!<(div|img)([^>]*)(' . implode('|', $regexp) . ')([^>]*)>!i', function($match) {
|
||||||
$tag = strtolower($match[1]);
|
$tag = strtolower($match[1]);
|
||||||
$attrs = array();
|
$attrs = array();
|
||||||
$html = preg_replace_callback('!([a-zA-Z0-9_-]+)="([^"]+)"!', function($attr) use($tag, &$attrs) {
|
$html = preg_replace_callback('!([a-zA-Z0-9_-]+)="([^"]+)"!', function($attr) use($tag, &$attrs) {
|
||||||
|
|
@ -477,10 +515,25 @@ class HTMLFilter
|
||||||
* Decode widgets and editor components after processing.
|
* Decode widgets and editor components after processing.
|
||||||
*
|
*
|
||||||
* @param string $content
|
* @param string $content
|
||||||
|
* @param bool $allow_editor_components (optional)
|
||||||
|
* @param bool $allow_widgets (optional)
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected static function _decodeWidgetsAndEditorComponents($content)
|
protected static function _decodeWidgetsAndEditorComponents($content, $allow_editor_components = true, $allow_widgets = false)
|
||||||
{
|
{
|
||||||
|
if (!$allow_editor_components)
|
||||||
|
{
|
||||||
|
$content = preg_replace('!(<(?:div|img)[^>]*)\s(editor_component="(?:[^"]+)")!i', '$1', $content);
|
||||||
|
}
|
||||||
|
if (!$allow_widgets)
|
||||||
|
{
|
||||||
|
$content = preg_replace('!(<(?:div|img)[^>]*)\s(widget="(?:[^"]+)")!i', '$1blocked-$2', $content);
|
||||||
|
}
|
||||||
|
if (!$allow_editor_components && !$allow_widgets)
|
||||||
|
{
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
return preg_replace_callback('!<(div|img)([^>]*)(\srx_encoded_properties="([^"]+)")!i', function($match) {
|
return preg_replace_callback('!<(div|img)([^>]*)(\srx_encoded_properties="([^"]+)")!i', function($match) {
|
||||||
$attrs = array();
|
$attrs = array();
|
||||||
$decoded_properties = Security::decrypt($match[4]);
|
$decoded_properties = Security::decrypt($match[4]);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue