@oldpath
, but should actually be placed in the shared
+ libraries API at @newpath
. You should move the folder
+ such that @somefile
exists (you will need to create an
+ htmlpurifier
folder to hold the library
+ folder). For future updates, you can simply replace the
+ htmlpurifier folder with the htmlpurifier-x.y.z folder that a
+ new HTML Purifier tarball unzips to (you'll be reminded in an
+ update notification).",
+ array(
+ '@oldpath' => dirname(__FILE__) . '/library',
+ '@newpath' => libraries_get_path('htmlpurifier') . '/library',
+ '@somefile' => libraries_get_path('htmlpurifier') . '/library/HTMLPurifier.auto.php',
+ )),
+ );
+ }
+
+ if ($phase=='runtime') {
+ $current = variable_get('htmlpurifier_version_current', FALSE);
+ if (!$current) {
+ $current = htmlpurifier_check_version();
+ }
+ $ours = variable_get('htmlpurifier_version_ours', FALSE);
+ if (!$ours || version_compare($ours, $req_version, '<')) {
+ // Can't use _htmlpurifier_load(), since it assumes a later
+ // version
+ require_once "$library_path/library/HTMLPurifier.auto.php";
+ if (defined('HTMLPurifier::VERSION')) {
+ $version = HTMLPurifier::VERSION;
+ } else {
+ $purifier = new HTMLPurifier;
+ $version = $purifier->version;
+ }
+ variable_set('htmlpurifier_version_ours', $version);
+ if (version_compare($version, $req_version, '<')) {
+
+ $requirements['htmlpurifier_library'] = array (
+ 'title' => $t('HTML Purifier library'),
+ 'severity' => REQUIREMENT_ERROR,
+ 'description' => $t("HTML Purifier @old is not compatible
+ with this module: HTML Purifier @required or later is required.
+ If the required version is a dev version, you will need to
+ check
+ code out of Git or
+ download a nightly
+ to use this module.", array('@old' => $version, '@required' => $req_version)
+ ),
+ );
+
+ return $requirements;
+ }
+ }
+
+ if (!$current) {
+ $requirements['htmlpurifier_check'] = array(
+ 'title' => $t('HTML Purifier Library'),
+ 'value' => $ours,
+ 'description' => $t('Unable to check for the latest version of the
+ HTML Purifier library. You will need to check manually at
+ htmlpurifier.org to find out if
+ the version you are using is out of date.'),
+ 'severity' => REQUIREMENT_WARNING,
+ );
+ }
+ elseif (!$ours || version_compare($current, $ours, '>')) {
+ // Update our version number if it can't be found, or there's a
+ // mismatch. This won't do anything if _htmlpurifier_load() has
+ // already been called. An equivalent formulation would be
+ // to always call _htmlpurifier_load() before retrieving the
+ // variable, but this has the benefit of not always loading
+ // HTML Purifier!
+ _htmlpurifier_load();
+ $ours = variable_get('htmlpurifier_version_ours', FALSE);
+ }
+ if ($current && $ours && version_compare($current, $ours, '>')) {
+ $description = $t('Your HTML Purifier library is out of date. The
+ latest version is %version, which you can download from htmlpurifier.org. ',
+ array('%version' => $current));
+ if ($using_libraries) {
+ $how_to_update = $t('To update, replace
+ %path
with the new directory the downloaded archive
+ extracts into. ',
+ array('%path' => libraries_get_path('htmlpurifier')));
+ } else {
+ $how_to_update = $t('To update, replace
+ %path/library/
with the library/
+ directory from the downloaded archive. ',
+ array('%path' => dirname(__FILE__)));
+ }
+ $warning = $t('If you do not perform this operation correctly,
+ your Drupal installation will stop working. Ensure that
+ %path/library/HTMLPurifier.auto.php
exists after
+ the upgrade.',
+ array('%path' => $library_path));
+ $requirements['htmlpurifier_version'] = array(
+ 'title' => $t('HTML Purifier Library'),
+ 'value' => $ours,
+ 'description' => $description . $how_to_update . $warning,
+ 'severity' => REQUIREMENT_WARNING,
+ );
+ }
+ if (count($requirements) == 0) {
+ $requirements['htmlpurifier'] = array(
+ 'severity' => REQUIREMENT_OK,
+ 'title' => $t('HTML Purifier Library'),
+ 'value' => $ours,
+ );
+ }
+ }
+
+ return $requirements;
+}
+
+// -- Update functions ------------------------------------------------------ //
+
+function htmlpurifier_update_6200() {
+ // Migrate any old-style filter variables to new style.
+ $formats = filter_formats();
+ foreach ($formats as $format => $info) {
+ $filters = filter_list_format($format);
+ if (!isset($filters['htmlpurifier/0'])) continue;
+ $config_data = array(
+ 'URI.DisableExternalResources' => variable_get("htmlpurifier_externalresources_$format", TRUE),
+ 'Attr.EnableID' => variable_get("htmlpurifier_enableattrid_$format", FALSE),
+ 'AutoFormat.Linkify' => variable_get("htmlpurifier_linkify_$format", TRUE),
+ 'AutoFormat.AutoParagraph' => variable_get("htmlpurifier_autoparagraph_$format", TRUE),
+ 'Null_HTML.Allowed' => !variable_get("htmlpurifier_allowedhtml_enabled_$format", FALSE),
+ 'HTML.Allowed' => variable_get("htmlpurifier_allowedhtml_$format", ''),
+ 'Filter.YouTube' => variable_get("htmlpurifier_preserveyoutube_$format", FALSE),
+ );
+ if (defined('HTMLPurifier::VERSION') && version_compare(HTMLPurifier::VERSION, '3.1.0-dev', '>=')) {
+ $config_data['HTML.ForbiddenElements'] = variable_get("htmlpurifier_forbiddenelements_$format", '');
+ $config_data['HTML.ForbiddenAttributes'] = variable_get("htmlpurifier_forbiddenattributes_$format", '');
+ }
+ variable_set("htmlpurifier_config_$format", $config_data);
+ }
+
+ return array();
+}
+
+function htmlpurifier_update_6201() {}
diff --git a/sites/all/modules/htmlpurifier/htmlpurifier.module b/sites/all/modules/htmlpurifier/htmlpurifier.module
new file mode 100644
index 0000000..837279f
--- /dev/null
+++ b/sites/all/modules/htmlpurifier/htmlpurifier.module
@@ -0,0 +1,523 @@
+code == 200) {
+ $version = trim($result->data);
+ variable_set('htmlpurifier_version_check_failed', FALSE);
+ variable_set('htmlpurifier_version_current', $version);
+ return $version;
+ }
+ else {
+ variable_set('htmlpurifier_version_check_failed', TRUE);
+ // Delete any previously known "latest" version so that people can be
+ // alerted if a problem appears on a previously working site.
+ variable_del('htmlpurifier_version_current');
+ }
+ }
+}
+
+/**
+ * Implementation of hook_filter().
+ */
+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);
+
+ case 'settings':
+ return _htmlpurifier_settings($delta, $format);
+
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * Implementation of hook_filter_tips().
+ */
+function htmlpurifier_filter_tips($delta, $format, $long = FALSE) {
+ if (variable_get("htmlpurifier_help_$format", TRUE)) {
+ return t('HTML tags will be transformed to conform to HTML standards.');
+ }
+}
+
+/**
+ * Implementation of hook_nodeapi().
+ */
+function htmlpurifier_nodeapi(&$node, $op, $a3, $a4) {
+ if ($op == 'view') {
+
+ // Should we load CSS cache data from teaser or body?
+ if ($a3 == TRUE) {
+ _htmlpurifier_add_css( $node->content['teaser']['#value'], $node->nid );
+ }
+ else {
+ _htmlpurifier_add_css( $node->content['body']['#value'], $node->nid );
+ }
+ }
+ // @todo: Deal with CCK fields - probably needs to go in op alter?
+}
+
+/**
+ * Helper function for hook_nodeapi
+ * Finds extracted style blocks based on a cache link left by hook_filter
+ * Aggregates the extracted style blocks and adds them to the document head
+ * Also removes the cache link left in hook_filter to the CSS cache
+ *
+ * @param string &$field
+ * Field to process, this should be the actual field value
+ * ex. $node->content['body']['#value']
+ *
+ * @param int $nid
+ * Node ID of the node to which these stylesheets belong
+ * Since filters don't know their node context, we have to use a token
+ * to generate the stylesheet scope, and replace it in hook_nodeapi
+ */
+function _htmlpurifier_add_css( &$field, $nid ) {
+
+ // Some basic validation to assure we really got a rendered field
+ if (!is_string($field)) {
+ return;
+ }
+
+ $cache_matches = array();
+ $cache_match = preg_match('##', $field, $cache_matches);
+
+ // If there's an HTML Purifier Cache #, we need to load CSSTidy blocks
+ if ($cache_match == 1) {
+ $cid = 'css:' . $cache_matches[1];
+ $old = cache_get($cid, 'cache_htmlpurifier');
+
+ // We should always have some cached style blocks to load, but if we don't, just bail
+ if ($old) {
+ $styles = array();
+ $style_rendered = '';
+ foreach($old->data as $i => $style) {
+
+ // Replace Node ID tokens if necessary, otherwise use cached CSSTidy blocks
+ // NOTE: This token is forgeable, but we expect that if the user
+ // is able to invoke this transformation, it will be relatively
+ // harmless.
+ if (strpos($style, '[%HTMLPURIFIER:NID%]') !== FALSE) {
+ $styles[$i] = str_replace('[%HTMLPURIFIER:NID%]', (int) $nid, $style);
+ }
+ else {
+ $styles[$i] = $style;
+ }
+
+ // Save any CSSTidy blocks we find to be rendered in the document head
+ if (!empty($style)) {
+ $style_rendered .= $styles[$i] . "\n";
+ }
+ }
+
+ // Add the rendered stylesheet to the document header
+ if ($style_rendered != '') {
+ drupal_set_html_head('');
+ }
+
+ // Remove the HTML Purifier cache key from the field argument
+ $field = str_replace($cache_matches[0], '', $field);
+
+ // If we had to update CSSTidy blocks, cache the results
+ if ($old->data != $styles) {
+ cache_set($cid, $styles, 'cache_htmlpurifier', CACHE_PERMANENT);
+ }
+ }
+ }
+}
+
+
+
+// -- INTERNAL FUNCTIONS ---------------------------------------------------- //
+
+/**
+ * Processes HTML according to a format and returns purified HTML. Makes a
+ * cache pass if possible.
+ *
+ * @param string $text
+ * Text to purify
+ * @param int $format
+ * Input format corresponding to HTML Purifier's configuration.
+ * @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) {
+
+ if ($cache) {
+ $cid = $format . ':' . md5($text);
+ $old = cache_get($cid, 'cache_htmlpurifier');
+ if ($old) return $old->data;
+ }
+
+ _htmlpurifier_load();
+ $config = _htmlpurifier_get_config($format);
+
+ // If ExtractStyleBlocks is enabled, we'll need to do a bit more for CSSTidy
+ $config_extractstyleblocks = $config->get('Filter.ExtractStyleBlocks');
+
+ // Maybe this works if CSSTidy is at root? CSSTidy could be other places though
+ if ($config_extractstyleblocks == true) {
+ _htmlpurifier_load_csstidy();
+ }
+
+ $purifier = new HTMLPurifier($config);
+ $ret = $purifier->purify($text);
+
+ // If using Filter.ExtractStyleBlocks we need to handle the CSSTidy output
+ if ($config_extractstyleblocks == true) {
+
+ // We're only going to bother if we're caching! - no caching? no style blocks!
+ if ($cache) {
+
+ // Get style blocks, cache them, and help hook_nodeapi find the cache
+ $styles = $purifier->context->get('StyleBlocks');
+ cache_set('css:' . $cid, $styles, 'cache_htmlpurifier', CACHE_PERMANENT);
+ $ret = '' . $ret;
+ }
+ }
+
+ if ($cache) cache_set($cid, $ret, 'cache_htmlpurifier', CACHE_PERMANENT);
+
+ return $ret;
+}
+
+/**
+ * Loads the HTML Purifier library, and performs global initialization.
+ */
+function _htmlpurifier_load() {
+ static $done = false;
+ if ($done) {
+ return;
+ }
+ $done = true;
+ $module_path = drupal_get_path('module', 'htmlpurifier');
+ $library_path = $module_path;
+ if (function_exists('libraries_get_path')) {
+ $library_path = libraries_get_path('htmlpurifier');
+ // This may happen if the user has HTML Purifier installed under the
+ // old configuration, but also installed libraries and forgot to
+ // move it over. There is code for emitting errors in
+ // htmlpurifier.install when this is the case.
+ if (!file_exists("$library_path/library/HTMLPurifier.auto.php")) {
+ $library_path = $module_path;
+ }
+ }
+
+ if (version_compare(phpversion(), '5') < 0) {
+ // If your version of PHP is too old, you're going to fail anyway
+ // when you attempt to include the HTML Purifier library, so we
+ // might as well try to give a useful error message.
+ echo 'Your version of PHP is too old to run HTML Purifier, needs PHP 5 or later';
+ exit;
+ }
+
+ require_once "$library_path/library/HTMLPurifier.auto.php";
+ require_once "$module_path/HTMLPurifier_DefinitionCache_Drupal.php";
+
+ $factory = HTMLPurifier_DefinitionCacheFactory::instance();
+ $factory->register('Drupal', 'HTMLPurifier_DefinitionCache_Drupal');
+
+ // Register the version as a variable:
+ variable_set('htmlpurifier_version_ours', HTMLPurifier::VERSION);
+}
+
+/**
+ * Returns the HTMLPurifier_Config object corresponding to an input format.
+ * @param int $format
+ * Input format.
+ * @return
+ * Instance of HTMLPurifier_Config.
+ */
+function _htmlpurifier_get_config($format) {
+
+ $config = HTMLPurifier_Config::createDefault();
+
+ $config->set('AutoFormat.AutoParagraph', TRUE);
+ $config->set('AutoFormat.Linkify', TRUE);
+ $config->set('HTML.Doctype', 'XHTML 1.0 Transitional'); // Probably
+ $config->set('Core.AggressivelyFixLt', TRUE);
+ $config->set('Cache.DefinitionImpl', 'Drupal');
+
+ // Filter HTML doesn't allow external images, so neither will we...
+ // for now. This can be configured off.
+ $config->set('URI.DisableExternalResources', TRUE);
+
+ if (!empty($_SERVER['SERVER_NAME'])) {
+ // SERVER_NAME is more reliable than HTTP_HOST
+ $config->set('URI.Host', $_SERVER['SERVER_NAME']);
+ }
+
+ if (defined('LANGUAGE_RTL') && $GLOBALS['language']->direction === LANGUAGE_RTL) {
+ $config->set('Attr.DefaultTextDir', 'rtl');
+ }
+
+ if ($config_function = _htmlpurifier_config_load($format)) {
+ $config_function($config);
+ } else {
+ $config_data = variable_get("htmlpurifier_config_$format", FALSE);
+ if (!empty($config_data['Filter.ExtractStyleBlocks'])) {
+ if (!_htmlpurifier_load_csstidy()) {
+ $config_data['Filter.ExtractStyleBlocks'] = '0';
+ drupal_set_message("Could not enable ExtractStyleBlocks because CSSTidy was not installed. You can download CSSTidy module from http://drupal.org/project/csstidy", 'error', FALSE);
+ }
+ }
+ // {FALSE, TRUE, FALSE} = {no index, everything is allowed, don't do mq fix}
+ $config->mergeArrayFromForm($config_data, FALSE, TRUE, FALSE);
+ }
+
+ return $config;
+
+}
+
+function _htmlpurifier_load_csstidY() {
+ // If CSSTidy module is installed, it should have a copy we can use
+ $csstidy_path = drupal_get_path('module', 'csstidy') .'/csstidy';
+
+ // Some future-proofing for library path
+ if (function_exists('libraries_get_path')) {
+ $csstidy_library = libraries_get_path('csstidy');
+ if (file_exists("$csstidy_library/class.csstidy.php")) {
+ $csstidy_path = $csstidy_library;
+ }
+ }
+
+ // Load CSSTidy if we can find it
+ if (file_exists("$csstidy_path/class.csstidy.php")) {
+ require_once "$csstidy_path/class.csstidy.php";
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Returns the name of the configuration function for $format, or FALSE if none
+ * exists. Function name will be htmlpurifier_config_N.
+ *
+ * @param int $format
+ * Integer format to check function for.
+ * @return
+ * 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_function = "htmlpurifier_config_$format";
+ if (
+ !function_exists($config_function) &&
+ file_exists($config_file)
+ ) {
+ include_once $config_file;
+ }
+ return function_exists($config_function) ? $config_function : FALSE;
+}
+
+/**
+ * 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.
+ * @return
+ * Form API array.
+ */
+function _htmlpurifier_settings($delta, $format) {
+ _htmlpurifier_load();
+
+ // Dry run, testing for errors:
+ _htmlpurifier_process('', $format, 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']["enter_hack"] = array(
+ // hack to make normal form submission when !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.Filter.ExtractStyleBlocks.Scope
; this means that users can add CSS that affects all of your Drupal theme and not just their content block. It is recommended to set this to #node-[%HTMLPURIFIER:NID%]
(including brackets) which will automatically ensure that CSS directives only apply to their node.", 'warning', FALSE);
+ } elseif (!isset($config_data['Filter.ExtractStyleBlocks.Scope']) || $config_data['Filter.ExtractStyleBlocks.Scope'] !== '#node-[%HTMLPURIFIER:NID%]') {
+ drupal_set_message("You have enabled Filter.ExtractStyleBlocks.Scope, but you did not set it to #node-[%HTMLPURIFIER:NID%]
; CSS may not work unless you have special theme support.", 'warning', FALSE);
+ }
+ }
+ }
+ return $form_element;
+}
+
+/**
+ * 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:');
+}
diff --git a/sites/all/modules/htmlpurifier/translations/uk.po b/sites/all/modules/htmlpurifier/translations/uk.po
new file mode 100644
index 0000000..8dda98a
--- /dev/null
+++ b/sites/all/modules/htmlpurifier/translations/uk.po
@@ -0,0 +1,81 @@
+# $Id: uk.po,v 1.1.2.2 2009/09/16 17:31:54 podarok Exp $
+#
+# Ukrainian translation of Drupal (general)
+# Copyright YEAR NAME !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.!function()
вже зазначена. Для правки параметрів HTML Чистильщика, змінюйте вкладений файл налаштувань, що зазвичай є htmlpurifier/config/!format.php
. Для відновлення параметрів форми налаштування, стріть або перейменуйте цей файл.