2007-06-28 23:01:27 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* HTML Purifier Phorum Mod. Filter your HTML the Standards-Compliant Way!
|
|
|
|
*
|
|
|
|
* This Phorum mod enables users to post raw HTML into Phorum. But never
|
|
|
|
* fear: with the help of HTML Purifier, this HTML will be beat into
|
|
|
|
* de-XSSed and standards-compliant form, safe for general consumption.
|
|
|
|
* It is not recommended, but possible to run this mod in parallel
|
|
|
|
* with other formatters (in short, please DISABLE the BBcode mod).
|
|
|
|
*
|
|
|
|
* For help migrating from your previous markup language to pure HTML
|
|
|
|
* please check the migrate.bbcode.php file.
|
|
|
|
*
|
2007-06-29 00:48:55 +00:00
|
|
|
* If you'd like to use this with a WYSIWYG editor, make sure that
|
|
|
|
* editor sets $PHORUM['mod_htmlpurifier']['wysiwyg'] to true. Otherwise,
|
|
|
|
* administrators who need to edit other people's comments may be at
|
|
|
|
* risk for some nasty attacks.
|
|
|
|
*
|
2007-06-28 23:01:27 +00:00
|
|
|
* Tested with Phorum 5.1.22. This module will almost definitely need
|
|
|
|
* to be upgraded when Phorum 6 rolls around.
|
|
|
|
*/
|
|
|
|
|
2007-06-29 03:41:21 +00:00
|
|
|
// Note: Cache data is base64 encoded because Phorum insists on flinging
|
|
|
|
// to the user and expecting it to come back unharmed, newlines and
|
|
|
|
// all, which ain't happening. It's slower, it takes up more space, but
|
|
|
|
// at least it won't get mutilated
|
|
|
|
|
2007-06-28 23:01:27 +00:00
|
|
|
if(!defined('PHORUM')) exit;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Purifies a data array
|
|
|
|
*/
|
2007-06-29 00:28:07 +00:00
|
|
|
function phorum_htmlpurifier_format($data)
|
2007-06-28 23:01:27 +00:00
|
|
|
{
|
|
|
|
$PHORUM = $GLOBALS["PHORUM"];
|
|
|
|
|
|
|
|
$purifier =& HTMLPurifier::getInstance();
|
|
|
|
$cache_serial = $PHORUM['mod_htmlpurifier']['body_cache_serial'];
|
|
|
|
|
|
|
|
foreach($data as $message_id => $message){
|
2007-06-29 00:28:07 +00:00
|
|
|
if(isset($message['body'])) {
|
|
|
|
if (isset($message['meta']['htmlpurifier_light'])) {
|
|
|
|
// format hook was called outside of Phorum's normal
|
|
|
|
// functions, do the abridged purification
|
|
|
|
$data[$message_id]['body'] = $purifier->purify($message['body']);
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-28 23:01:27 +00:00
|
|
|
|
|
|
|
if (
|
|
|
|
isset($message['meta']['body_cache']) &&
|
|
|
|
isset($message['meta']['body_cache_serial']) &&
|
|
|
|
$message['meta']['body_cache_serial'] == $cache_serial
|
|
|
|
) {
|
|
|
|
// cached version is present, bail out early
|
2007-06-29 03:41:21 +00:00
|
|
|
$data[$message_id]['body'] = base64_decode($message['meta']['body_cache']);
|
2007-06-28 23:01:27 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// migration might edit this array, that's why it's defined
|
|
|
|
// so early
|
|
|
|
$updated_message = array();
|
|
|
|
|
|
|
|
// create the $body variable
|
|
|
|
if (
|
|
|
|
!isset($message['meta']['body_cache_serial'])
|
|
|
|
) {
|
|
|
|
// perform migration
|
|
|
|
$fake_data = array();
|
|
|
|
$fake_data[$message_id] = $message;
|
|
|
|
$fake_data = phorum_htmlpurifier_migrate($fake_data);
|
|
|
|
$body = $fake_data[$message_id]['body'];
|
2007-06-29 03:41:21 +00:00
|
|
|
$body = str_replace("<phorum break>", '', $body);
|
2007-06-28 23:01:27 +00:00
|
|
|
$updated_message['body'] = $body; // save it in
|
|
|
|
} else {
|
|
|
|
// reverse Phorum's pre-processing
|
|
|
|
$body = $message['body'];
|
|
|
|
// order is important
|
|
|
|
$body = str_replace(array('<','>','&'), array('<','>','&'), $body);
|
|
|
|
$body = str_replace("<phorum break>\n", "\n", $body);
|
|
|
|
}
|
|
|
|
|
|
|
|
$body = $purifier->purify($body);
|
|
|
|
|
|
|
|
// dynamically update the cache
|
|
|
|
// this is inefficient on the first read, but the cache
|
|
|
|
// catches will more than make up for it
|
|
|
|
|
|
|
|
// this should ONLY be called on read, for posting and preview
|
|
|
|
// phorum_htmlpurifier_posting should do the trick
|
|
|
|
$updated_message['meta'] = $message['meta'];
|
2007-06-29 03:41:21 +00:00
|
|
|
$updated_message['meta']['body_cache'] = base64_encode($body);
|
2007-06-28 23:01:27 +00:00
|
|
|
$updated_message['meta']['body_cache_serial'] = $cache_serial;
|
|
|
|
phorum_db_update_message($message_id, $updated_message);
|
|
|
|
|
|
|
|
// must not get overloaded until after we cache it
|
|
|
|
$data[$message_id]['body'] = $body;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate necessary cache and serial entries when a posting action happens
|
|
|
|
*/
|
|
|
|
function phorum_htmlpurifier_posting($message) {
|
|
|
|
$PHORUM = $GLOBALS["PHORUM"];
|
2007-06-29 00:28:07 +00:00
|
|
|
$fake_data = array($message);
|
|
|
|
// this is a temporary attribute
|
|
|
|
$fake_data[0]['meta']['htmlpurifier_light'] = true; // only purify, please
|
|
|
|
list($changed_message) = phorum_hook('format', $fake_data);
|
2007-06-29 03:41:21 +00:00
|
|
|
$message['meta']['body_cache'] = base64_encode($changed_message['body']);
|
2007-06-28 23:01:27 +00:00
|
|
|
$message['meta']['body_cache_serial'] = $PHORUM['mod_htmlpurifier']['body_cache_serial'];
|
|
|
|
return $message;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Overload quoting mechanism to prevent default, mail-style quote from happening
|
|
|
|
*/
|
|
|
|
function phorum_htmlpurifier_quote($array) {
|
|
|
|
$PHORUM = $GLOBALS["PHORUM"];
|
|
|
|
$purifier =& HTMLPurifier::getInstance();
|
|
|
|
$text = $purifier->purify($array[1]);
|
|
|
|
return "<blockquote cite=\"$array[0]\">\n$text\n</blockquote>";
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-06-29 00:28:07 +00:00
|
|
|
* Ensure that our format hook is processed last. Also, loads the library.
|
2007-06-28 23:01:27 +00:00
|
|
|
* @credits <http://secretsauce.phorum.org/snippets/make_bbcode_last_formatter.php.txt>
|
|
|
|
*/
|
|
|
|
function phorum_htmlpurifier_common() {
|
|
|
|
|
2007-06-29 00:28:07 +00:00
|
|
|
require_once (dirname(__FILE__).'/htmlpurifier/HTMLPurifier.auto.php');
|
2007-06-28 23:01:27 +00:00
|
|
|
|
2007-06-29 00:28:07 +00:00
|
|
|
$config_exists = file_exists(dirname(__FILE__) . '/config.php');
|
|
|
|
if ($config_exists || !isset($PHORUM['mod_htmlpurifier']['config'])) {
|
|
|
|
$config = HTMLPurifier_Config::createDefault();
|
|
|
|
include(dirname(__FILE__) . '/config.default.php');
|
|
|
|
if ($config_exists) {
|
|
|
|
include(dirname(__FILE__) . '/config.php');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// used cached version that was constructed from web interface
|
|
|
|
$config = HTMLPurifier_Config::create($PHORUM['mod_htmlpurifier']['config']);
|
|
|
|
}
|
|
|
|
HTMLPurifier::getInstance($config);
|
2007-06-29 00:48:55 +00:00
|
|
|
|
2007-06-29 00:28:07 +00:00
|
|
|
// increment revision.txt if you want to invalidate the cache
|
|
|
|
$GLOBALS['PHORUM']['mod_htmlpurifier']['body_cache_serial'] = $config->getSerial();
|
2007-06-29 00:48:55 +00:00
|
|
|
|
|
|
|
$GLOBALS['PHORUM']['mod_htmlpurifier']['wysiwyg'] = true;
|
|
|
|
|
2007-06-29 00:28:07 +00:00
|
|
|
// load migration
|
|
|
|
if (file_exists(dirname(__FILE__) . '/migrate.php')) {
|
|
|
|
include(dirname(__FILE__) . '/migrate.php');
|
|
|
|
} else {
|
|
|
|
echo '<strong>Error:</strong> No migration path specified for HTML Purifier, please check
|
|
|
|
<tt>modes/htmlpurifier/migrate.bbcode.php</tt> for instructions on
|
|
|
|
how to migrate from your previous markup language.';
|
|
|
|
exit;
|
2007-06-28 23:01:27 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 00:28:07 +00:00
|
|
|
// see if our hooks need to be bubbled to the end
|
|
|
|
phorum_htmlpurifier_bubble_hook('format');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function phorum_htmlpurifier_bubble_hook($hook) {
|
|
|
|
global $PHORUM;
|
|
|
|
$our_idx = null;
|
|
|
|
$last_idx = null;
|
|
|
|
if (!isset($PHORUM['hooks'][$hook]['mods'])) return;
|
|
|
|
foreach ($PHORUM['hooks'][$hook]['mods'] as $idx => $mod) {
|
|
|
|
if ($mod == 'htmlpurifier') $our_idx = $idx;
|
|
|
|
$last_idx = $idx;
|
2007-06-28 23:01:27 +00:00
|
|
|
}
|
2007-06-29 00:28:07 +00:00
|
|
|
list($mod) = array_splice($PHORUM['hooks'][$hook]['mods'], $our_idx, 1);
|
|
|
|
$PHORUM['hooks'][$hook]['mods'][] = $mod;
|
|
|
|
list($func) = array_splice($PHORUM['hooks'][$hook]['funcs'], $our_idx, 1);
|
|
|
|
$PHORUM['hooks'][$hook]['funcs'][] = $func;
|
2007-06-28 23:01:27 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 00:48:55 +00:00
|
|
|
/**
|
|
|
|
* Pre-emptively performs purification if it looks like a WYSIWYG editor
|
|
|
|
* is being used
|
|
|
|
*/
|
|
|
|
function phorum_htmlpurifier_before_editor($message) {
|
|
|
|
if (!empty($GLOBALS['PHORUM']['mod_htmlpurifier']['wysiwyg'])) {
|
|
|
|
if (!empty($message['body'])) {
|
|
|
|
$body = $message['body'];
|
|
|
|
// de-entity-ize contents
|
|
|
|
$body = str_replace(array('<','>','&'), array('<','>','&'), $body);
|
|
|
|
$purifier =& HTMLPurifier::getInstance();
|
|
|
|
$body = $purifier->purify($message['body']);
|
|
|
|
// re-entity-ize contents
|
|
|
|
$body = htmlspecialchars($body, ENT_QUOTES, $GLOBALS['PHORUM']['DATA']['CHARSET']);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $message;
|
|
|
|
}
|
|
|
|
|