Index: HTMLPurifier_DefinitionCache_Drupal.php =================================================================== RCS file: /cvs/drupal/contributions/modules/htmlpurifier/HTMLPurifier_DefinitionCache_Drupal.php,v retrieving revision 1.3 diff -u -p -r1.3 HTMLPurifier_DefinitionCache_Drupal.php --- HTMLPurifier_DefinitionCache_Drupal.php 24 Apr 2008 04:13:09 -0000 1.3 +++ HTMLPurifier_DefinitionCache_Drupal.php 14 Jun 2010 03:08:34 -0000 @@ -72,8 +72,10 @@ class HTMLPurifier_DefinitionCache_Drupa } function cleanup($config) { - $res = db_query("SELECT cid FROM {cache} WHERE cid LIKE '%s%%'", 'htmlpurifier:'); - while ($row = db_fetch_object($res)) { + // TODO: This does not work with the pluggable cache system in Drupal 7, + // since it assumes a database cache is being used. + $res = db_query("SELECT cid FROM {cache} WHERE cid LIKE :cid", array(':cid' => 'htmlpurifier:%')); + foreach ($res as $row) { $key = substr($row->cid, 13); // 13 == strlen('htmlpurifier:') if ($this->isOld($key, $config)) { cache_clear_all($row->cid, 'cache'); Index: INSTALL.txt =================================================================== RCS file: /cvs/drupal/contributions/modules/htmlpurifier/INSTALL.txt,v retrieving revision 1.6 diff -u -p -r1.6 INSTALL.txt --- INSTALL.txt 10 Jul 2009 00:46:29 -0000 1.6 +++ INSTALL.txt 14 Jun 2010 03:08:34 -0000 @@ -11,11 +11,11 @@ and it's nice to have dom and iconv. * Extract the "library" folder and place it inside your modules/htmlpurifier directory. -* Go to Administer > Site building > Modules and enable this module +* Go to Administer > Modules and enable this module -* You can now create a new input format or add the HTML Purifier to an - existing input format. It is recommended that you place HTML Purifier as - the last filter in the input format. Reorder the filters if necessary. +* You can now create a new text format or add the HTML Purifier to an + existing text format. It is recommended that you place HTML Purifier as + the last filter in the text format. Reorder the filters if necessary. WARNING: Due to HTML Purifier's caching mechanism, dynamic filters MUST NOT be placed before HTML Purifier. Index: config-form.js =================================================================== RCS file: config-form.js diff -N config-form.js --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ config-form.js 14 Jun 2010 03:08:34 -0000 @@ -0,0 +1,14 @@ +// $Id$ +(function ($) { + +Drupal.behaviors.htmlpurifierConfigForm = { + // Makes all configuration links open in new windows; can save lots of grief! + attach: function (context, settings) { + $(".hp-config a", context).click(function () { + window.open(this.href); + return false; + }); + } +}; + +})(jQuery); Index: htmlpurifier.admin.inc =================================================================== RCS file: htmlpurifier.admin.inc diff -N htmlpurifier.admin.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ htmlpurifier.admin.inc 14 Jun 2010 03:08:34 -0000 @@ -0,0 +1,48 @@ + 'submit', + '#value' => t('Clear cache (Warning: Can result in performance degradation)'), + '#submit' => array('_htmlpurifier_clear_cache') + ); + + $form['htmlpurifier_doublecache'] = array( + '#type' => 'checkbox', + '#title' => t('Allow double caching'), + '#default_value' => FALSE, + '#description' => t('If enabled, HTML Purifier will tell the Filter module that its output is cacheable. This is not usually necessary, because HTML Purifier maintains its own cache, but may be helpful if you have later filters that need to be cached. Note: This applies to all text formats in which the HTML Purifier filters are included.'), + ); + + $form = system_settings_form($form); + $form['#submit'][] = 'htmlpurifier_admin_settings_submit'; + return $form; +} + +/** + * Submit handler for the HTML Purifier settings form. + */ +function htmlpurifier_admin_settings_submit($form, &$form_state) { + // Resave all text formats so that the new cache settings for each format are + // recorded. + // TODO: There should be a better way to do this. + foreach (filter_formats() as $format) { + $format->filters = filter_list_format($format->format); + foreach ($format->filters as &$filter) { + $filter = (array) $filter; + } + filter_format_save($format); + } +} Index: htmlpurifier.info =================================================================== RCS file: /cvs/drupal/contributions/modules/htmlpurifier/htmlpurifier.info,v retrieving revision 1.6 diff -u -p -r1.6 htmlpurifier.info --- htmlpurifier.info 24 Apr 2008 04:13:09 -0000 1.6 +++ htmlpurifier.info 14 Jun 2010 03:08:34 -0000 @@ -1,5 +1,8 @@ ; $Id: htmlpurifier.info,v 1.6 2008/04/24 04:13:09 ezyang Exp $ name = "HTML Purifier" description = "Filter that removes malicious HTML and ensures standards compliant output." -core = 6.x -php = 5.0.5 +core = 7.x +files[] = htmlpurifier.install +files[] = htmlpurifier.module +files[] = htmlpurifier.admin.inc +files[] = HTMLPurifier_DefinitionCache_Drupal.php Index: htmlpurifier.install =================================================================== RCS file: /cvs/drupal/contributions/modules/htmlpurifier/htmlpurifier.install,v retrieving revision 1.13 diff -u -p -r1.13 htmlpurifier.install --- htmlpurifier.install 9 Jun 2010 17:07:14 -0000 1.13 +++ htmlpurifier.install 14 Jun 2010 03:08:34 -0000 @@ -1,7 +1,7 @@ condition('name', 'htmlpurifier%', 'LIKE') + ->execute(); } /** - * Implementation of hook_requirements(). + * Implements hook_requirements(). * * Checks the version of HTML Purifier on install and issues an error if there is a problem */ @@ -208,3 +202,12 @@ function htmlpurifier_update_6200() { } function htmlpurifier_update_6201() {} + +/** + * TODO: Perform the D6->D7 upgrade. + * + * We need to update filter names and settings, in the same way that + * filter_update_7003() and filter_update_7004() do. + */ +// function htmlpurifier_update_7000() { +// } Index: htmlpurifier.module =================================================================== RCS file: /cvs/drupal/contributions/modules/htmlpurifier/htmlpurifier.module,v retrieving revision 1.17 diff -u -p -r1.17 htmlpurifier.module --- htmlpurifier.module 9 Jun 2010 17:07:14 -0000 1.17 +++ htmlpurifier.module 14 Jun 2010 03:08:34 -0000 @@ -11,19 +11,19 @@ // -- HOOK IMPLEMENTATIONS -------------------------------------------------- // /** - * Implementation of hook_flush_caches(). + * Implements hook_flush_caches(). */ function htmlpurifier_flush_caches() { return array('cache_htmlpurifier'); } /** - * Implementation of hook_help(). + * Implements hook_help(). */ function htmlpurifier_help($path, $arg) { $output = NULL; switch ($path) { - case 'admin/modules#htmlpurifier': + case 'admin/help#htmlpurifier': $output = t('Filter that removes malicious HTML and ensures standards compliant output.'); break; } @@ -31,7 +31,23 @@ function htmlpurifier_help($path, $arg) } /** - * Implementation of hook_cron(). + * Implements hook_menu(). + */ +function htmlpurifier_menu() { + $items['admin/config/content/htmlpurifier'] = array( + 'title' => 'HTML Purifier settings', + 'description' => 'Configure overall settings for the HTML Purifier filters, including how they are cached.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('htmlpurifier_admin_settings'), + 'access arguments' => array('administer filters'), + 'file' => 'htmlpurifier.admin.inc', + ); + + return $items; +} + +/** + * Implements hook_cron(). * @note * Checks for updates to the HTML Purifier library. */ @@ -42,59 +58,62 @@ function htmlpurifier_cron() { variable_set('htmlpurifier_version_current', $version); } - /** - * Implementation of hook_filter(). + * Implements hook_filter_info(). */ -function htmlpurifier_filter($op, $delta = 0, $format = -1, $text = '') { - switch ($op) { - case 'list': - return array(0 => t('HTML Purifier'), 1 => t('HTML Purifier (advanced)')); - - case 'no cache': - // Since HTML Purifier implements its own caching layer, having filter - // cache it again is wasteful. Returns FALSE if double caching is permitted. - return !variable_get("htmlpurifier_doublecache", FALSE); - - case 'description': - $common = t( - 'Removes malicious HTML code and ensures that the output '. - 'is standards compliant. Warning: For performance '. - 'reasons, please ensure that there are no highly dynamic filters before HTML Purifier. ' - ); - switch ($delta) { - case 0: - return $common; - case 1: - return $common . t('This version has advanced configuration options, do not enable both at the same time.'); - } - - case 'prepare': - return $text; - - case 'process': - return _htmlpurifier_process($text, $format); +function htmlpurifier_filter_info() { + _htmlpurifier_load(); + $filters['htmlpurifier_basic'] = array( + 'title' => t('HTML Purifier'), + 'description' => t('Removes malicious HTML code and ensures that the ' . + 'output is standards compliant. Warning: For ' . + 'performance reasons, please ensure that there are no highly dynamic ' . + 'filters before HTML Purifier. '), + 'process callback' => '_htmlpurifier_process', + 'settings callback' => '_htmlpurifier_settings', + 'default settings' => array( + 'htmlpurifier_help' => TRUE, + 'htmlpurifier_config' => _htmlpurifier_get_config(), + ), + 'tips callback' => '_htmlpurifier_filter_tips', + // Since HTML Purifier implements its own caching layer, having filter + // cache it again is wasteful. Returns TRUE if double caching is permitted. + 'cache' => variable_get("htmlpurifier_doublecache", FALSE), + ); - case 'settings': - return _htmlpurifier_settings($delta, $format); + $filters['htmlpurifier_advanced'] = array( + 'title' => t('HTML Purifier (advanced)'), + 'description' => $filters['htmlpurifier_basic']['description'] . t('This version has advanced configuration options, do not enable both at the same time.'), + ) + $filters['htmlpurifier_basic']; - default: - return NULL; - } + return $filters; } +// -- INTERNAL FUNCTIONS ---------------------------------------------------- // + /** - * Implementation of hook_filter_tips(). + * Filter tips callback for the HTML Purifier filters. */ -function htmlpurifier_filter_tips($delta, $format, $long = FALSE) { - if (variable_get("htmlpurifier_help_$format", TRUE)) { +function _htmlpurifier_filter_tips($filter, $format, $long = FALSE) { + if (!empty($filter->settings['htmlpurifier_help'])) { return t('HTML tags will be transformed to conform to HTML standards.'); } } - - -// -- INTERNAL FUNCTIONS ---------------------------------------------------- // +/** + * Process callback for the HTML Purifier filters. + * + * Passes data along to the helper function with instructions to always try to + * use this module's custom cache mechanism. + * + * We need this helper function because the filter system passes in $cache as + * fifth parameter to this hook (which corresponds to whether or not the core + * filter system itself will cache the data), but we want to cache it always so + * we need to ignore that parameter. + */ +function _htmlpurifier_process($text, $filter, $format, $langcode, $cache) { + return _htmlpurifier_process_text($text, $filter, $format, $langcode, TRUE); +} /** * Processes HTML according to a format and returns purified HTML. Makes a @@ -102,25 +121,25 @@ function htmlpurifier_filter_tips($delta * * @param string $text * Text to purify - * @param int $format - * Input format corresponding to HTML Purifier's configuration. + * @param object $filter + * The filter object containing settings for the given format. + * @param object $format + * The format object of the text to be filtered. + * @param string $langcode + * The language code of the text to be filtered. * @param boolean $cache * Whether or not to check the cache. - * - * @note - * We ignore $delta because the only difference it makes is in the configuration - * screen. */ -function _htmlpurifier_process($text, $format, $cache = TRUE) { +function _htmlpurifier_process_text($text, $filter, $format, $langcode, $cache = TRUE) { if ($cache) { - $cid = $format . ':' . md5($text); + $cid = $format->format . ':' . $langcode . ':' . hash('sha256', $text); $old = cache_get($cid, 'cache_htmlpurifier'); if ($old) return $old->data; } _htmlpurifier_load(); - $config = _htmlpurifier_get_config($format); + $config = _htmlpurifier_get_config($format->format); $purifier = new HTMLPurifier($config); $ret = $purifier->purify($text); @@ -162,13 +181,14 @@ function _htmlpurifier_load() { } /** - * Returns the HTMLPurifier_Config object corresponding to an input format. + * Returns the HTMLPurifier_Config object corresponding to a text format. * @param int $format - * Input format. + * (Optional) Text format ID. If left empty, the default configuration is + * returned. * @return * Instance of HTMLPurifier_Config. */ -function _htmlpurifier_get_config($format) { +function _htmlpurifier_get_config($format = 0) { $config = HTMLPurifier_Config::createDefault(); @@ -191,10 +211,25 @@ function _htmlpurifier_get_config($forma $config->set('Attr.DefaultTextDir', 'rtl'); } - if ($config_function = _htmlpurifier_config_load($format)) { + if ($format && ($config_function = _htmlpurifier_config_load($format))) { $config_function($config); } else { - $config_data = variable_get("htmlpurifier_config_$format", FALSE); + // We only support one instance of this module's filters (either basic or + // advanced) per text format, so choose the first settings we find. + // TODO: This is awkward, but the most straightforward conversion from the + // D6 version, which also treated this as a per-format setting and + // therefore had the same limitation. + $filters = $format ? filter_list_format($format) : array(); + if (!empty($filters['htmlpurifier_advanced']->status)) { + $config_data = (array) $filters['htmlpurifier_advanced']->settings['htmlpurifier_config']; + } + elseif (!empty($filters['htmlpurifier_basic']->status)) { + $config_data = (array) $filters['htmlpurifier_basic']->settings['htmlpurifier_config']; + } + else { + $config_data = FALSE; + } + // {FALSE, TRUE, FALSE} = {no index, everything is allowed, don't do mq fix} $config->mergeArrayFromForm($config_data, FALSE, TRUE, FALSE); } @@ -213,7 +248,7 @@ function _htmlpurifier_get_config($forma * String function name for format, or FALSE if none. */ function _htmlpurifier_config_load($format) { - $config_file = drupal_get_path('module', 'htmlpurifier') ."/config/$format.php"; + $config_file = drupal_get_path('module', 'htmlpurifier') . "/config/$format.php"; $config_function = "htmlpurifier_config_$format"; if ( !function_exists($config_function) && @@ -226,56 +261,54 @@ function _htmlpurifier_config_load($form /** * Generates a settings form for configuring HTML Purifier. - * @param int $delta - * Whether or not to use advanced form (1) or not (0). - * @param int $format - * Input format being configured. + * + * @param array $form + * The prepopulated form array. + * @param array $form_state + * The form state of the (entire) configuration form. + * @param object $filter + * The filter object containing settings for the given format. $filter->name + * can be either 'htmlpurifier_basic' or 'htmlpurifier_advanced' (the two + * filters defined by this module). + * @param object $format + * The format object being configured. + * @param array $defaults + * The default settings for the filter, as defined in 'default settings' in + * hook_filter_info(). + * * @return * Form API array. */ -function _htmlpurifier_settings($delta, $format) { +function _htmlpurifier_settings($form, &$form_state, $filter, $format, $defaults) { _htmlpurifier_load(); // Dry run, testing for errors: - _htmlpurifier_process('', $format, FALSE); + _htmlpurifier_process_text('', $filter, $format, LANGUAGE_NONE, FALSE); $module_path = drupal_get_path('module', 'htmlpurifier'); - drupal_add_css("$module_path/config-form.css"); - // Makes all configuration links open in new windows; can safe lots of grief! - drupal_add_js('$(function(){$(".hp-config a").click(function(){window.open(this.href);return false;});});', 'inline'); - drupal_add_js(HTMLPurifier_Printer_ConfigForm::getJavaScript(), 'inline'); - - $form = array(); - $form['dashboard'] = array( - '#type' => 'fieldset', - '#title' => t('HTML Purifier Dashboard'), - '#collapsible' => true, - ); - $form['dashboard']["htmlpurifier_clear_cache"] = array( - '#type' => 'submit', - '#value' => t('Clear cache (Warning: Can result in performance degradation)'), - '#submit' => array('_htmlpurifier_clear_cache') + $settings['#attached']['css'][] = "$module_path/config-form.css"; + $settings['#attached']['js'][] = "$module_path/config-form.js"; + // TODO: This is broken. The JavaScript may need to be rewritten, or it may + // need to be added via more standard methods. + $settings['#attached']['js'][] = array( + 'data' => HTMLPurifier_Printer_ConfigForm::getJavaScript(), + 'type' => 'inline', ); - $form['htmlpurifier'] = array( - '#type' => 'fieldset', - '#title' => t('HTML Purifier'), - '#collapsible' => TRUE, - ); - $form['htmlpurifier']["htmlpurifier_help_$format"] = array( + $settings['htmlpurifier_help'] = array( '#type' => 'checkbox', '#title' => t('Display help text'), - '#default_value' => variable_get("htmlpurifier_help_$format", TRUE), + '#default_value' => isset($filter->settings['htmlpurifier_help']) ? $filter->settings['htmlpurifier_help'] : $defaults['htmlpurifier_help'], '#description' => t('If enabled, a short note will be added to the filter tips explaining that HTML will be transformed to conform with HTML standards. You may want to disable this option when the HTML Purifier is used to check the output of another filter like BBCode.'), ); - if ($config_function = _htmlpurifier_config_load($format)) { - $form['htmlpurifier']['notice'] = array( + if ($config_function = _htmlpurifier_config_load($format->format)) { + $settings['notice'] = array( '#type' => 'markup', '#value' => t('
Configuration function !function() is already defined. To edit HTML Purifier\'s configuration, edit the corresponding configuration file, which is usually htmlpurifier/config/!format.php. To restore the web configuration form, delete or rename this file.
', - array('!function' => $config_function, '!format' => $format)), + array('!function' => $config_function, '!format' => $format->format)), ); } else { - if ($delta == 0) { + if ($filter->name == 'htmlpurifier_basic') { $title = t('Configure HTML Purifier'); $allowed = array( 'URI.DisableExternalResources', @@ -293,32 +326,26 @@ function _htmlpurifier_settings($delta, } else { $title = t('Advanced configuration options'); $allowed = TRUE; - $form['htmlpurifier']["htmlpurifier_doublecache"] = array( - '#type' => 'checkbox', - '#title' => t('Allow double caching'), - '#default_value' => variable_get("htmlpurifier_doublecache", FALSE), - '#description' => t('If enabled, HTML Purifier will tell filter that its output is cacheable. This is not usually necessary, because HTML Purifier maintains its own cache, but may be helpful if you have later filters that need to be cached. Warning: this applies to ALL filters, not just this one'), - ); } $intro = - '

'. - $title. - '

'. - t('Please click on a directive name for more information on what it does before enabling or changing anything! Changes will not apply to old entries until you clear the cache (see the dashboard)'). + '

' . + $title . + '

' . + t('Please click on a directive name for more information on what it does before enabling or changing anything! Changes will not apply to old entries until you clear the cache (see the dashboard)') . '
'; - $config = _htmlpurifier_get_config($format); + $config = _htmlpurifier_get_config($format->format); $config_form = new HTMLPurifier_Printer_ConfigForm( - "htmlpurifier_config_$format", 'http://htmlpurifier.org/live/configdoc/plain.html#%s' + 'htmlpurifier_config', 'http://htmlpurifier.org/live/configdoc/plain.html#%s' ); - $form['htmlpurifier']["htmlpurifier_config_$format"] = array( - '#value' => $intro . $config_form->render($config, $allowed, FALSE), + $settings['htmlpurifier_config'] = array( + '#markup' => $intro . $config_form->render($config, $allowed, FALSE), '#after_build' => array('_htmlpurifier_config_hack'), ); } - return $form; + return $settings; } /** @@ -328,11 +355,19 @@ function _htmlpurifier_settings($delta, * @warning * If someone ever gets the smart idea of changing the parameters to * this function, I'm SOL! ;-) + * Also, this function does not work correctly if both filters from this + * module are enabled for the same format, since only one set of submitted + * values will make it through. */ function _htmlpurifier_config_hack($form_element, &$form_state) { - $key = $form_element['#parents'][0]; - if (!empty($form_element['#post']) && isset($form_element['#post'][$key])) { - $form_state['values'][$key] = $form_element['#post'][$key]; + $parents = $form_element['#parents']; + $key = end($parents); + if (isset($form_state['input'][$key])) { + $value = $form_state['input'][$key]; + foreach (array_reverse($parents) as $parent) { + $value = array($parent => $value); + } + $form_state['values'] = array_merge_recursive($form_state['values'], $value); } return $form_element; } @@ -341,7 +376,7 @@ function _htmlpurifier_config_hack($form * Clears the HTML Purifier internal Drupal cache. */ function _htmlpurifier_clear_cache($form, &$form_state) { - drupal_set_message("Cache cleared"); - db_query("DELETE FROM {cache_htmlpurifier}"); - db_query("DELETE FROM {cache} WHERE cid LIKE '%s%%'", 'htmlpurifier:'); + drupal_set_message(t('Cache cleared.')); + cache_clear_all('*', 'cache_htmlpurifier', TRUE); + cache_clear_all('htmlpurifier:', 'cache', TRUE); }