PAR1\n\nPAR2 (see State 2)
- // ------------
- $token = array($this->_pStart());
- $this->_splitText($text, $token);
+ // State 1.4:
PAR1\n\nPAR2 (see State 2)
+ // ------------
+ $token = array($this->_pStart());
+ $this->_splitText($text, $token);
+ } else {
+ // State 1.5: \n
+ // --
+ }
}
} else {
// State 2:
PAR1... (similar to 1.4)
diff --git a/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php b/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php
new file mode 100644
index 0000000000..b21313470e
--- /dev/null
+++ b/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php
@@ -0,0 +1,60 @@
+attrValidator = new HTMLPurifier_AttrValidator();
+ $this->config = $config;
+ $this->context = $context;
+ return parent::prepare($config, $context);
+ }
+
+ public function handleElement(&$token) {
+ if ($token->name !== 'span' || !$token instanceof HTMLPurifier_Token_Start) {
+ return;
+ }
+
+ // We need to validate the attributes now since this doesn't normally
+ // happen until after MakeWellFormed. If all the attributes are removed
+ // the span needs to be removed too.
+ $this->attrValidator->validateToken($token, $this->config, $this->context);
+ $token->armor['ValidateAttributes'] = true;
+
+ if (!empty($token->attr)) {
+ return;
+ }
+
+ $nesting = 0;
+ $spanContentTokens = array();
+ while ($this->forwardUntilEndToken($i, $current, $nesting)) {}
+
+ if ($current instanceof HTMLPurifier_Token_End && $current->name === 'span') {
+ // Mark closing span tag for deletion
+ $current->markForDeletion = true;
+ // Delete open span tag
+ $token = false;
+ }
+ }
+
+ public function handleEnd(&$token) {
+ if ($token->markForDeletion) {
+ $token = false;
+ }
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Injector/SafeObject.php b/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Injector/SafeObject.php
index 3415828685..9e178ce01a 100755
--- a/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Injector/SafeObject.php
+++ b/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Injector/SafeObject.php
@@ -20,6 +20,8 @@ class HTMLPurifier_Injector_SafeObject extends HTMLPurifier_Injector
protected $allowedParam = array(
'wmode' => true,
'movie' => true,
+ 'flashvars' => true,
+ 'src' => true,
);
public function prepare($config, $context) {
@@ -47,7 +49,8 @@ class HTMLPurifier_Injector_SafeObject extends HTMLPurifier_Injector
// We need this fix because YouTube doesn't supply a data
// attribute, which we need if a type is specified. This is
// *very* Flash specific.
- if (!isset($this->objectStack[$i]->attr['data']) && $token->attr['name'] == 'movie') {
+ if (!isset($this->objectStack[$i]->attr['data']) &&
+ ($token->attr['name'] == 'movie' || $token->attr['name'] == 'src')) {
$this->objectStack[$i]->attr['data'] = $token->attr['value'];
}
// Check if the parameter is the correct value but has not
diff --git a/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Lexer/PEARSax3.php b/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Lexer/PEARSax3.php
index 57cffa82ab..1d358c7b6b 100755
--- a/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Lexer/PEARSax3.php
+++ b/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Lexer/PEARSax3.php
@@ -26,13 +26,20 @@ class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer
* Internal accumulator array for SAX parsers.
*/
protected $tokens = array();
+ protected $last_token_was_empty;
+
+ private $parent_handler;
+ private $stack = array();
public function tokenizeHTML($string, $config, $context) {
$this->tokens = array();
+ $this->last_token_was_empty = false;
$string = $this->normalize($string, $config, $context);
+ $this->parent_handler = set_error_handler(array($this, 'muteStrictErrorHandler'));
+
$parser = new XML_HTMLSax3();
$parser->set_object($this);
$parser->set_element_handler('openHandler','closeHandler');
@@ -44,6 +51,8 @@ class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer
$parser->parse($string);
+ restore_error_handler();
+
return $this->tokens;
}
@@ -58,9 +67,11 @@ class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer
}
if ($closed) {
$this->tokens[] = new HTMLPurifier_Token_Empty($name, $attrs);
+ $this->last_token_was_empty = true;
} else {
$this->tokens[] = new HTMLPurifier_Token_Start($name, $attrs);
}
+ $this->stack[] = $name;
return true;
}
@@ -71,10 +82,12 @@ class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer
// HTMLSax3 seems to always send empty tags an extra close tag
// check and ignore if you see it:
// [TESTME] to make sure it doesn't overreach
- if ($this->tokens[count($this->tokens)-1] instanceof HTMLPurifier_Token_Empty) {
+ if ($this->last_token_was_empty) {
+ $this->last_token_was_empty = false;
return true;
}
$this->tokens[] = new HTMLPurifier_Token_End($name);
+ if (!empty($this->stack)) array_pop($this->stack);
return true;
}
@@ -82,6 +95,7 @@ class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer
* Data event handler, interface is defined by PEAR package.
*/
public function dataHandler(&$parser, $data) {
+ $this->last_token_was_empty = false;
$this->tokens[] = new HTMLPurifier_Token_Text($data);
return true;
}
@@ -91,7 +105,18 @@ class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer
*/
public function escapeHandler(&$parser, $data) {
if (strpos($data, '--') === 0) {
- $this->tokens[] = new HTMLPurifier_Token_Comment($data);
+ // remove trailing and leading double-dashes
+ $data = substr($data, 2);
+ if (strlen($data) >= 2 && substr($data, -2) == "--") {
+ $data = substr($data, 0, -2);
+ }
+ if (isset($this->stack[sizeof($this->stack) - 1]) &&
+ $this->stack[sizeof($this->stack) - 1] == "style") {
+ $this->tokens[] = new HTMLPurifier_Token_Text($data);
+ } else {
+ $this->tokens[] = new HTMLPurifier_Token_Comment($data);
+ }
+ $this->last_token_was_empty = false;
}
// CDATA is handled elsewhere, but if it was handled here:
//if (strpos($data, '[CDATA[') === 0) {
@@ -101,6 +126,14 @@ class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer
return true;
}
+ /**
+ * An error handler that mutes strict errors
+ */
+ public function muteStrictErrorHandler($errno, $errstr, $errfile=null, $errline=null, $errcontext=null) {
+ if ($errno == E_STRICT) return;
+ return call_user_func($this->parent_handler, $errno, $errstr, $errfile, $errline, $errcontext);
+ }
+
}
// vim: et sw=4 sts=4
diff --git a/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php b/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php
index feb0c32b45..316b2386ac 100755
--- a/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php
+++ b/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php
@@ -83,6 +83,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
$this->injectors[] = $injector;
}
foreach ($custom_injectors as $injector) {
+ if (!$injector) continue;
if (is_string($injector)) {
$injector = "HTMLPurifier_Injector_$injector";
$injector = new $injector;
@@ -219,6 +220,19 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
$autoclose = false;
}
+ if ($autoclose && $definition->info[$token->name]->wrap) {
+ // check if this is actually a wrap (mmm wraps!)
+ $wrapname = $definition->info[$token->name]->wrap;
+ $wrapdef = $definition->info[$wrapname];
+ $elements = $wrapdef->child->getAllowedElements($config);
+ if (isset($elements[$token->name])) {
+ $newtoken = new HTMLPurifier_Token_Start($wrapname);
+ $this->insertBefore($newtoken);
+ $reprocess = true;
+ continue;
+ }
+ }
+
$carryover = false;
if ($autoclose && $definition->info[$parent->name]->formatting) {
$carryover = true;
diff --git a/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/URIScheme/data.php b/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/URIScheme/data.php
new file mode 100644
index 0000000000..b7f1989cbf
--- /dev/null
+++ b/phpgwapi/inc/htmlpurifier/library/HTMLPurifier/URIScheme/data.php
@@ -0,0 +1,93 @@
+ true,
+ 'image/gif' => true,
+ 'image/png' => true,
+ );
+
+ public function validate(&$uri, $config, $context) {
+ $result = explode(',', $uri->path, 2);
+ $is_base64 = false;
+ $charset = null;
+ $content_type = null;
+ if (count($result) == 2) {
+ list($metadata, $data) = $result;
+ // do some legwork on the metadata
+ $metas = explode(';', $metadata);
+ while(!empty($metas)) {
+ $cur = array_shift($metas);
+ if ($cur == 'base64') {
+ $is_base64 = true;
+ break;
+ }
+ if (substr($cur, 0, 8) == 'charset=') {
+ // doesn't match if there are arbitrary spaces, but
+ // whatever dude
+ if ($charset !== null) continue; // garbage
+ $charset = substr($cur, 8); // not used
+ } else {
+ if ($content_type !== null) continue; // garbage
+ $content_type = $cur;
+ }
+ }
+ } else {
+ $data = $result[0];
+ }
+ if ($content_type !== null && empty($this->allowed_types[$content_type])) {
+ return false;
+ }
+ if ($charset !== null) {
+ // error; we don't allow plaintext stuff
+ $charset = null;
+ }
+ $data = rawurldecode($data);
+ if ($is_base64) {
+ $raw_data = base64_decode($data);
+ } else {
+ $raw_data = $data;
+ }
+ // XXX probably want to refactor this into a general mechanism
+ // for filtering arbitrary content types
+ $file = tempnam("/tmp", "");
+ file_put_contents($file, $raw_data);
+ if (function_exists('exif_imagetype')) {
+ $image_code = exif_imagetype($file);
+ } elseif (function_exists('getimagesize')) {
+ set_error_handler(array($this, 'muteErrorHandler'));
+ $info = getimagesize($file);
+ restore_error_handler();
+ if ($info == false) return false;
+ $image_code = $info[2];
+ } else {
+ trigger_error("could not find exif_imagetype or getimagesize functions", E_USER_ERROR);
+ }
+ $real_content_type = image_type_to_mime_type($image_code);
+ if ($real_content_type != $content_type) {
+ // we're nice guys; if the content type is something else we
+ // support, change it over
+ if (empty($this->allowed_types[$real_content_type])) return false;
+ $content_type = $real_content_type;
+ }
+ // ok, it's kosher, rewrite what we need
+ $uri->userinfo = null;
+ $uri->host = null;
+ $uri->port = null;
+ $uri->fragment = null;
+ $uri->query = null;
+ $uri->path = "$content_type;base64," . base64_encode($raw_data);
+ return true;
+ }
+
+ public function muteErrorHandler($errno, $errstr) {}
+
+}
+