Commit c1917cf1 authored by Radek Suski's avatar Radek Suski

(+) Implemented AthosHun\HTMLFilter

parent e13f33fb
......@@ -111,6 +111,11 @@ class Autoloader
throw new Exception( "Can't find class {$class} definition" );
}
}
elseif ( isset( $path[ 1 ] ) && isset( $path[ 2 ] ) && file_exists( dirname( __DIR__ . '../' ) . '/ThirdParty/' . $path[ 1 ] . '/' . $path[ 2 ] . '.php' ) ) {
unset( $path[ 0 ] );
$path = implode( '/', $path );
include_once dirname( __DIR__ . '../' ) . '/ThirdParty/' . $path . '.php';
}
elseif ( isset( $this->classes[ $class ] ) ) {
/** @noinspection PhpIncludeInspection */
include_once $this->classes[ $class ];
......
......@@ -205,9 +205,9 @@ class MySQLi
/**
* Creates a "select" SQL query.
*
* @param string $toSelect - table rows to select
* @param string | array $toSelect - table rows to select
* @param string $tables - from which table(s)
* @param string $where - SQL select condition
* @param string | array $where - SQL select condition
* @param null $order
* @param int $limit - maximal number of rows
* @param int $limitStart - start position
......
......@@ -193,9 +193,9 @@ class Image extends File
private function storeImage()
{
$st = preg_replace( '/[^0-9]/', null, microtime( true ) * 10000 );
$this->temp = SPLoader::path( 'tmp.img.' . $st, 'front', false, 'var', false );
if ( !( SPLoader::dirPath( 'tmp.img', 'front', true ) ) ) {
SPFs::mkdir( SPLoader::dirPath( 'tmp.img', 'front', false ) );
$this->temp = \SPLoader::path( 'tmp.img.' . $st, 'front', false, 'var', false );
if ( !( \SPLoader::dirPath( 'tmp.img', 'front', true ) ) ) {
\SPFs::mkdir( \SPLoader::dirPath( 'tmp.img', 'front', false ) );
}
switch ( $this->type ) {
case IMAGETYPE_GIF:
......@@ -203,11 +203,11 @@ class Image extends File
break;
case IMAGETYPE_JPEG:
case IMAGETYPE_JPEG2000:
imagejpeg( $this->image, $this->temp, Sobi::Cfg( 'image.jpeg_quality', 100 ) );
imagejpeg( $this->image, $this->temp, \Sobi::Cfg( 'image.jpeg_quality', 100 ) );
break;
case IMAGETYPE_PNG:
imagealphablending( $this->image, true );
imagepng( $this->image, $this->temp, Sobi::Cfg( 'image.png_compression', 9 ) );
imagepng( $this->image, $this->temp, \Sobi::Cfg( 'image.png_compression', 9 ) );
break;
}
$this->_content = file_get_contents( $this->temp );
......@@ -272,7 +272,7 @@ class Image extends File
$currentImg = $function( $this->_filename );
}
if ( !isset( self::$imgFunctions[ $imgType ] ) || !isset( $currentImg ) ) {
throw new SPException( SPLang::e( 'CREATE_IMAGE_MISSING_HANDLER', $this->_filename, $imgType ) );
throw new Exception( \SPLang::e( 'CREATE_IMAGE_MISSING_HANDLER', $this->_filename, $imgType ) );
}
return $currentImg;
}
......
......@@ -65,7 +65,7 @@ abstract class Framework
}
/**
* @return string
* @return string | array
* @throws Exception
*/
public static function Cfg()
......
......@@ -21,7 +21,10 @@
namespace Sobi\Input;
use AthosHun\HTMLFilter\Configuration;
use AthosHun\HTMLFilter\HTMLFilter;
use Sobi\Error\Exception;
use Sobi\Framework;
defined( 'SOBI' ) || exit( 'Restricted access' );
......@@ -79,7 +82,7 @@ abstract class Input
{
$var = null;
$input = 'request';
switch ( strtolower($request) ) {
switch ( strtolower( $request ) ) {
case 'post':
$input = 'post';
$request = $_POST;
......@@ -196,7 +199,28 @@ abstract class Input
*/
public static function Html( $name, $request = 'request', $default = null )
{
return filter_var( Request::Instance()->{$request}->getHtml( $name, $default ), FILTER_SANITIZE_MAGIC_QUOTES );
static $config = null;
static $filter = null;
if ( !( $config ) ) {
$tags = Framework::Cfg( 'html.allowed_tags_array', [] );
$attributes = Framework::Cfg( 'html.allowed_attributes_array', [] );
$config = new Configuration();
$filter = new HTMLFilter();
if ( count( $tags ) ) {
foreach ( $tags as $tag ) {
$config->allowTag( $tag );
if ( count( $attributes ) ) {
foreach ( $attributes as $attribute ) {
$config->allowAttribute( $tag, $attribute );
}
}
}
}
}
$html = Request::Instance()->{$request}->getHtml( $name, $default );
return filter_var( $filter->filter( $config, $html ), FILTER_SANITIZE_MAGIC_QUOTES );
}
/**
......
<?php
namespace AthosHun\HTMLFilter;
class Configuration
{
private $allowed_tags_with_attributes;
public function __construct()
{
$this->allowed_tags_with_attributes = array();
}
public function allowTag($tag_name)
{
if (!$this->isAllowedTag($tag_name)) {
$this->allowed_tags_with_attributes[(string)$tag_name] = array();
}
return $this;
}
public function allowAttribute(
$tag_name,
$attribute_name,
$attribute_regexp = "/.*/"
) {
$this->allowTag($tag_name);
$tag = (string)$tag_name;
$attr = (string)$attribute_name;
$this->allowed_tags_with_attributes[$tag][$attr] = $attribute_regexp;
return $this;
}
public function isAllowedTag($tag_name)
{
return array_key_exists((string)$tag_name,
$this->allowed_tags_with_attributes);
}
public function isAllowedAttribute(
$tag_name,
$attribute_name,
$attribute_value
) {
if (!$this->isAllowedTag($tag_name)) {
return false;
}
$tag = (string)$tag_name;
$attr = (string)$attribute_name;
$allowed_attributes = $this->allowed_tags_with_attributes[$tag];
if (!array_key_exists($attr, $allowed_attributes)) {
return false;
}
$restriction = $allowed_attributes[$attr];
return 1 === preg_match($restriction, $attribute_value);
}
}
<?php
namespace AthosHun\HTMLFilter;
class HTMLFilter
{
private $config;
private $original_dom;
private $filtered_dom;
private $libxml_used_internal_errors;
public function __construct()
{
}
public function filter(Configuration $config, $html_text)
{
$this->libxml_used_internal_errors = libxml_use_internal_errors(true);
try {
$this->initialize($config, $html_text);
$this->copyAllowedNodes();
$filtered_html = $this->fetchFilteredHTML();
} catch (\Exception $error) {
$this->cleanup();
throw $error;
}
$this->cleanup();
return $filtered_html;
}
private function initialize(Configuration $config, $html_text)
{
$this->config = $config;
$html_text = mb_convert_encoding($html_text, "UTF-8", "UTF-8");
$this->original_dom = $this->createDOMDocument($html_text);
$this->filtered_dom = $this->createDOMDocument("");
}
private function createDOMDocument($html_text)
{
$dom_document = new \DOMDocument("1.0", "UTF-8");
$dom_document->loadHTML(
"<?xml encoding=\"UTF-8\"><html><body>$html_text</body></html>"
);
return $dom_document;
}
private function copyAllowedNodes()
{
$original_body = $this->findBodyNode($this->original_dom);
$filtered_body = $this->findBodyNode($this->filtered_dom);
$this->copyAllowedChildNodes($original_body, $filtered_body);
}
private function findBodyNode(\DOMDocument $dom_document)
{
return $dom_document->getElementsByTagName("body")->item(0);
}
private function copyAllowedChildNodes(
\DOMNode $source,
\DOMNode $destination
) {
if (!$source->hasChildNodes()) {
return;
}
for ($i = 0, $l = $source->childNodes->length; $i != $l; ++$i) {
$node = $source->childNodes->item($i);
if ($this->isAllowedNode($node)) {
$this->copyNode($node, $destination);
} else {
$this->copyAllowedChildNodes($node, $destination);
}
}
}
private function isAllowedNode(\DOMNode $node)
{
return ($node instanceof \DOMText)
|| ($node instanceof \DOMComment)
|| ($this->config->isAllowedTag($node->nodeName));
}
private function copyNode(\DOMNode $node, \DOMNode $destination)
{
if ($node instanceof \DOMText) {
$this->copyTextNode($node, $destination);
} else if ($node instanceof \DOMElement) {
$this->copyDOMElement($node, $destination);
} else if ($node instanceof \DOMComment) {
$this->copyDOMComment($node, $destination);
}
}
private function copyTextNode(\DOMText $text_node, \DOMNode $destination)
{
$destination->appendChild(
$destination->ownerDocument->createTextNode($text_node->data)
);
}
private function copyDOMElement(
\DOMElement $element,
\DOMNode $destination
) {
$copied_element = $destination->ownerDocument
->createElement($element->nodeName);
$destination->appendChild($copied_element);
$this->copyAllowedAttributes($element, $copied_element);
$this->copyAllowedChildNodes($element, $copied_element);
}
private function copyAllowedAttributes(
\DOMElement $source,
\DOMElement $destination
) {
for ($i = 0, $l = $source->attributes->length; $i != $l; ++$i) {
$attribute = $source->attributes->item($i);
if ($this->isAllowedAttribute($attribute)) {
$this->copyAttribute($attribute, $destination);
}
}
}
private function isAllowedAttribute(\DOMAttr $attribute)
{
return $this->config->isAllowedAttribute(
$attribute->ownerElement->nodeName,
$attribute->name,
$attribute->value
);
}
private function copyAttribute(
\DOMAttr $attribute,
\DOMElement $destination
) {
$copied_attribute = $destination->ownerDocument
->createAttribute($attribute->name);
$copied_attribute->value = htmlspecialchars(
$attribute->value,
ENT_QUOTES,
"UTF-8"
);
$destination->appendChild($copied_attribute);
}
private function copyDOMComment(\DOMComment $comment, \DOMNode $destination)
{
$destination->appendChild(
$destination->ownerDocument->createComment($comment->data)
);
}
private function fetchFilteredHTML()
{
$filtered_html = $this->filtered_dom->saveXML(
$this->findBodyNode($this->filtered_dom)
);
return $this->trimBodyTags($filtered_html);
}
private function trimBodyTags($html_text)
{
if ($html_text === "<body/>") {
return "";
}
if (substr($html_text, 0, 6) === "<body>") {
$html_text = substr($html_text, 6);
}
if (substr($html_text, -7, 7) === "</body>") {
$html_text = substr($html_text, 0, strlen($html_text) - 7);
}
return $html_text;
}
private function cleanup()
{
$this->config = null;
$this->original_dom = null;
$this->filtered_dom = null;
libxml_use_internal_errors($this->libxml_used_internal_errors);
}
}
......@@ -46,7 +46,7 @@ abstract class StringUtils
public static function Nid( $txt, $unicode = false, $forceUnicode = false )
{
$txt = trim( str_replace( [ '.', '_' ], '-', $txt ) );
return ( Framework::Cfg( 'sef.unicode' ) && $unicode ) || $forceUnicode ? self::urlSafe( $txt ) : trim( preg_replace( '/(\s|[^A-Za-z0-9\-])+/', '-', \JFactory::getLanguage()->transliterate( $txt ) ), '_-\[\]\(\)' );
return ( Framework::Cfg( 'sef.unicode' ) && $unicode ) || $forceUnicode ? self::UrlSafe( $txt ) : trim( preg_replace( '/(\s|[^A-Za-z0-9\-])+/', '-', \JFactory::getLanguage()->transliterate( $txt ) ), '_-\[\]\(\)' );
}
/**
......
......@@ -31,6 +31,7 @@ Legend:
-------------------
(+) Input::Search implemented
(+) Implemented AthosHun\HTMLFilter
(!) Switching Input::Raw back to vanilla PHP
(!) Autoloader inclusion changed from relative to absolute path. Seems doesn't work on some servers.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment