Skip to content

Instantly share code, notes, and snippets.

@brunogasparetto
Created January 23, 2019 11:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brunogasparetto/63f42e44388f13153b57e4c02df33f27 to your computer and use it in GitHub Desktop.
Save brunogasparetto/63f42e44388f13153b57e4c02df33f27 to your computer and use it in GitHub Desktop.
Exemplo de uma configuração mais restrita ao HTML Purifier para tratar HTML inserido dentro do framework Bootstrap
<?php
/**
* Adiciona as classes indicadas a um elemento HTML
*/
class TagClassTransform extends HTMLPurifier_TagTransform
{
/**
* @var array
*/
protected $classes = [];
/**
* @param string[]|string $classes Classes a inserir no elemento
*/
public function __construct($classes)
{
if (is_string($classes)) {
$classes = explode(' ', $classes);
}
$this->classes = array_unique(array_map('trim', $classes));
}
/**
* Executa a transformação
*
* @param HTMLPurifier_Token_Tag $tag
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return HTMLPurifier_Token_Tag
*/
public function transform($tag, $config, $context)
{
if (empty($this->classes) || $tag instanceof HTMLPurifier_Token_End) {
return $tag;
}
$new_tag = clone $tag;
if (empty($new_tag->attr['class'])) {
$new_tag->attr['class'] = '';
}
$new_tag->attr['class'] = $this->appendClasses($new_tag->attr['class']);
return $new_tag;
}
/**
* Concatena as classes da instância à string de classes já definidas
*
* @param string $classes
* @return string
*/
protected function appendClasses($classes = '')
{
return implode(
' ',
array_unique(
array_merge(
array_map('trim', explode(' ', $classes)),
$this->classes
)
)
);
}
}
/**
* Transforma o atributo border em uma classe css
*/
class TableBorderAttrTransform extends HTMLPurifier_AttrTransform
{
/**
* @var array
*/
protected $classes = ['table-bordered'];
/**
* @param array $attr
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
public function transform($attr, $config, $context)
{
if (!isset($attr['border']) || $context->get('CurrentToken')->name !== 'table') {
return $attr;
}
// A intenção é trocar o atributo, então já podemos removê-lo
unset($attr['border']);
if (empty($attr['class'])) {
$attr['class'] = '';
}
$attr['class'] = $this->appendClasses($attr['class']);
return $attr;
}
/**
* Concatena as classes da instância à string de classes já definidas
*
* @param string $classes
* @return string
*/
protected function appendClasses($classes = '')
{
return implode(
' ',
array_unique(
array_merge(
array_map('trim', explode(' ', $classes)),
$this->classes
)
)
);
}
}
/**
* Cerca a nossa tabela com uma div que possui a classe CSS table-responsive
*/
class TableResponsiveWrapperInjector extends HTMLPurifier_Injector
{
public $name = 'TableResponsiveWrapper';
public $needed = [
'table',
'div' => ['class'],
];
/**
* @param HTMLPurifier_Token_Start $token
*/
public function handleElement(&$token)
{
if (!$token->is_tag || $token->name !== 'table') {
return;
}
$table = clone $token;
$token = [
new HTMLPurifier_Token_Start('div', ['class' => 'table-responsive']),
$table,
];
}
/**
* @param HTMLPurifier_Token_End $token
*/
public function handleEnd(&$token)
{
if (!$token->is_tag || $token->name !== 'table') {
return;
}
$table = clone $token;
$token = [
$table,
new HTMLPurifier_Token_End('div'),
];
}
}
// ------------------------------------------
// E agora as configurações do HTML Purifier
$cssPropriedadesPermitidas = [
'color',
'background-color',
'font-size',
'font-weight',
'text-align',
'text-decoration',
];
$classesPermitidas = [
'img-responsive',
'table',
'table-responsive',
'table-bordered',
'table-condensed',
];
$elementosProibidos = [
'script',
'style'
];
$atributosProibidos = [
'*@width',
'*@height',
'table@border',
'table@cellpadding',
'table@cellspacing',
];
$config = HTMLPurifier_Config::createDefault();
$config->set('AutoFormat.RemoveEmpty', true);
$config->set('AutoFormat.RemoveEmpty.RemoveNbsp', true);
$config->set('AutoFormat.RemoveSpansWithoutAttributes', true);
$config->set('CSS.AllowedProperties', $CssPropriedadesPermitidas);
$config->set('Attr.AllowedClasses', $classesPermitidas);
$config->set('HTML.ForbiddenElements', $elementosProibidos);
$config->set('HTML.ForbiddenAttributes', $atributosProibidos);
$config->set('Output.Newline', "\n");
$config->set('HTML.TidyLevel', 'heavy');
$htmlDefinition = $config->getHTMLDefinition();
$htmlDefinition->info_tag_transform['table'] = new TagClassTransform('table table-condensed');
$htmlDefinition->info_tag_transform['img'] = new TagClassTransform('img-responsive');
$htmlDefinition->info_attr_transform_pre[] = new TableBorderAttrTransform();
$htmlDefinition->info_injector[] = new TableResponsiveWrapperInjector();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment