From 660f99287d032c8fdc3cf09fb52f46512b68ede0 Mon Sep 17 00:00:00 2001 From: Steven Wittens Date: Tue, 10 Aug 2004 18:34:29 +0000 Subject: [PATCH] The Input formats - filter patch has landed. I still need to make update instructions for modules and update the hook docs. Here's an overview of the changes: 1) Multiple Input formats: they are complete filter configurations (what filters to use, in what order and with which settings). Input formats are admin-definable, and usage of them is role-dependant. For example, you can set it up so that regular users can only use limited HTML, while admins can free HTML without any tag limitations. The input format can be chosen per content item (nodes, comments, blocks, ...) when you add/edit them. If only a single format is available, there is no choice, and nothing changes with before. The default install (and the upgrade) contains a basic set of formats which should satisfy the average user's needs. 2) Filters have toggles Because now you might want to enable a filter only on some input formats, an explicit toggle is provided by the filter system. Modules do not need to worry about it and filters that still have their own on/off switch should get rid of it. 3) Multiple filters per module This was necessary to accomodate the next change, and it's also a logical extension of the filter system. 4) Embedded PHP is now a filter Thanks to the multiple input formats, I was able to move the 'embedded PHP' feature from block.module, page.module and book.module into a simple filter which executes PHP code. This filter is part of filter.module, and by default there is an input format 'PHP', restricted to the administrator only, which contains this filter. This change means that block.module now passes custom block contents through the filter system. As well as from reducing code duplication and avoiding two type selectors for page/book nodes, you can now combine PHP code with other filters. 5) User-supplied PHP code now requires tags. This is required for teasers to work with PHP code. Because PHP evaluation is now just another step in the filter process, we can't do this. Also, because teasers are generated before filtering, this would result in errors when the teaser generation would cut off a piece of PHP code. Also, regular PHP syntax explicitly includes the tags for PHP files, so it makes sense to use the same convention for embedded PHP in Drupal. 6) Filter caching was added. Benchmarking shows that even for a simple setup (basic html filtering + legacy URL rewriting), filtercache can offer speedups. Unlike the old filtercache, this uses the normal cache table. 7) Filtertips were moved from help into a hook_filter_tips(). This was required to accomodate the fact that there are multiple filters per module, and that filter settings are format dependant. Shoehorning filter tips into _help was ugly and silly. The display of the filter tips is done through the input format selector, so filter_tips_short() no longer exists. 8) A more intelligent linebreak convertor was added, which doesn't stop working if you use block-level tags and which adds

tags. --- database/database.mysql | 31 +- database/database.pgsql | 10 + database/updates.inc | 156 ++++- includes/bootstrap.inc | 13 +- includes/common.inc | 16 +- misc/drupal.css | 7 + modules/aggregator.module | 7 +- modules/aggregator/aggregator.module | 7 +- modules/block.module | 50 +- modules/block/block.module | 50 +- modules/blog.module | 4 +- modules/blog/blog.module | 4 +- modules/blogapi.module | 1 + modules/blogapi/blogapi.module | 1 + modules/book.module | 49 +- modules/book/book.module | 49 +- modules/comment.module | 20 +- modules/comment/comment.module | 20 +- modules/filter.module | 893 ++++++++++++++++++++++----- modules/filter/filter.module | 893 ++++++++++++++++++++++----- modules/forum.module | 2 +- modules/forum/forum.module | 2 +- modules/node.module | 33 +- modules/node/node.module | 33 +- modules/page.module | 51 +- modules/page/page.module | 51 +- modules/statistics.module | 2 +- modules/statistics/statistics.module | 2 +- modules/story.module | 2 +- modules/story/story.module | 2 +- modules/system.module | 2 +- modules/system/system.module | 2 +- 32 files changed, 1909 insertions(+), 556 deletions(-) diff --git a/database/database.mysql b/database/database.mysql index b630c17346..2e91654f2c 100644 --- a/database/database.mysql +++ b/database/database.mysql @@ -135,7 +135,6 @@ CREATE TABLE book ( nid int(10) unsigned NOT NULL default '0', parent int(10) NOT NULL default '0', weight tinyint(3) NOT NULL default '0', - format tinyint(2) default '0', log longtext, PRIMARY KEY (nid), KEY parent (parent) @@ -150,7 +149,7 @@ CREATE TABLE boxes ( title varchar(64) NOT NULL default '', body longtext, info varchar(128) NOT NULL default '', - type tinyint(2) NOT NULL default '0', + format int(4) NOT NULL default '0', PRIMARY KEY (bid), UNIQUE KEY title (title), UNIQUE KEY info (info) @@ -184,6 +183,7 @@ CREATE TABLE comments ( timestamp int(11) NOT NULL default '0', score mediumint(9) NOT NULL default '0', status tinyint(3) unsigned NOT NULL default '0', + format int(4) NOT NULL default '0', thread varchar(255) NOT NULL, users longtext, name varchar(60) default NULL, @@ -207,14 +207,28 @@ CREATE TABLE directory ( PRIMARY KEY (link) ) TYPE=MyISAM; +-- +-- Table structure for table 'filter_formats' +-- + +CREATE TABLE filter_formats ( + format int(4) NOT NULL default '0' auto_increment, + name varchar(255) NOT NULL default '', + roles varchar(255) NOT NULL default '', + cache tinyint(2) NOT NULL default '0', + PRIMARY KEY format (format) +) TYPE=MyISAM; + -- -- Table structure for table 'filters' -- CREATE TABLE filters ( + format int(4) NOT NULL default '0', module varchar(64) NOT NULL default '', + delta tinyint(2) DEFAULT '0' NOT NULL, weight tinyint(2) DEFAULT '0' NOT NULL, - KEY module (module) + INDEX (weight) ) TYPE=MyISAM; -- @@ -330,6 +344,7 @@ CREATE TABLE node ( body longtext NOT NULL, revisions longtext NOT NULL, sticky int(2) NOT NULL default '0', + format int(4) NOT NULL default '0', PRIMARY KEY (nid), KEY node_type (type(4)), KEY node_title_type (title,type(4)), @@ -362,7 +377,6 @@ CREATE TABLE node_access ( CREATE TABLE page ( nid int(10) unsigned NOT NULL default '0', link varchar(128) NOT NULL default '', - format tinyint(2) NOT NULL default '0', description varchar(128) NOT NULL default '', PRIMARY KEY (nid) ) TYPE=MyISAM; @@ -700,3 +714,12 @@ REPLACE blocks SET module = 'user', delta = '1', status = '1'; INSERT INTO sequences (name, id) VALUES ('menu_mid', 1); INSERT INTO node_access VALUES (0, 0, 'all', 1, 0, 0); + +INSERT INTO filter_formats VALUES (1,'Filtered HTML',',1,2,',1); +INSERT INTO filter_formats VALUES (2,'PHP code','',0); +INSERT INTO filter_formats VALUES (3,'Full HTML','',1); +INSERT INTO filters VALUES (1,'filter',0,0); +INSERT INTO filters VALUES (1,'filter',3,1); +INSERT INTO filters VALUES (2,'filter',1,0); +INSERT INTO filters VALUES (3,'filter',3,0); +INSERT INTO variable (name,value) VALUES ('filter_html_1','i:1;'); diff --git a/database/database.pgsql b/database/database.pgsql index 289a2e2752..669889f7f8 100644 --- a/database/database.pgsql +++ b/database/database.pgsql @@ -694,6 +694,16 @@ INSERT INTO permission VALUES (2,'access comments, access content, post comments INSERT INTO blocks(module,delta,status) VALUES('user', '0', '1'); INSERT INTO blocks(module,delta,status) VALUES('user', '1', '1'); +INSERT INTO filter_formats VALUES (1,'Filtered HTML',',1,2,',1); +INSERT INTO filter_formats VALUES (2,'PHP code','',0); +INSERT INTO filter_formats VALUES (3,'Full HTML','',1)); +INSERT INTO filters VALUES (1,'filter',0,0); +INSERT INTO filters VALUES (1,'filter',3,1); +INSERT INTO filters VALUES (2,'filter',1,0); +INSERT INTO filters VALUES (3,'filter',3,0); +INSERT INTO variable (name,value) VALUES ('filter_html_1','i:1;'); + + --- --- Functions --- diff --git a/database/updates.inc b/database/updates.inc index e2faae044e..be5a59b810 100644 --- a/database/updates.inc +++ b/database/updates.inc @@ -69,7 +69,8 @@ "2004-07-30" => "update_95", "2004-08-04" => "update_96", "2004-08-06" => "update_97", - "2004-08-07" => "update_98" + "2004-08-07" => "update_98", + "2004-08-09" => "update_99" ); function update_32() { @@ -1308,6 +1309,159 @@ function update_98() { return array(); } +function update_99() { + // Filter patch - Multiple input formats + $ret = array(); + + /* + ** Load the list of PHP book and page nodes. + */ + $php_nodes = array(); + $res = db_query("SELECT nid FROM {book} WHERE format = 1"); + while ($book = db_fetch_object($res)) { + $php_nodes[] = $book->nid; + } + $res = db_query("SELECT nid FROM {page} WHERE format = 1"); + while ($page = db_fetch_object($res)) { + $php_nodes[] = $page->nid; + } + + /* + ** Apply database changes + */ + if ($GLOBALS['db_type'] == 'mysql') { + // Filters table + $ret[] = update_sql("ALTER TABLE {filters} ADD format int(4) NOT NULL default '0'"); + $ret[] = update_sql("ALTER TABLE {filters} ADD delta tinyint(2) NOT NULL default '0'"); + + // Filter_formats table + $ret[] = update_sql("CREATE TABLE {filter_formats} ( + format int(4) NOT NULL auto_increment, + name varchar(255) NOT NULL default '', + roles varchar(255) NOT NULL default '', + cache tinyint(2) NOT NULL default '1', + PRIMARY KEY (format) + )"); + + // Store formats in nodes, comments and boxes + $ret[] = update_sql("ALTER TABLE {boxes} CHANGE type format int(4) NOT NULL default '0'"); + $ret[] = update_sql("ALTER TABLE {comments} ADD format int(4) NOT NULL default '0'"); + $ret[] = update_sql("ALTER TABLE {node} ADD format int(4) NOT NULL default '0'"); + + // Get rid of the old book/page type info + $ret[] = update_sql("ALTER TABLE {book} DROP format"); + $ret[] = update_sql("ALTER TABLE {page} DROP format"); + } + else if ($GLOBALS['db_type'] == 'pgsql') { + // TODO: add pgsql equivalent. Whoever does this should pay attention that + // the keys/indices for the 'filters' table are correct. There was some + // inconsistency between the MySQL and PGSQL version before. + } + + // Initialize all nodes and comments to the legacy format (see below) + $ret[] = update_sql("UPDATE {node} SET format = 1"); + $ret[] = update_sql("UPDATE {comments} SET format = 1"); + + // Set format to PHP for the old PHP book/page nodes. + if (count($php_nodes)) { + $ret[] = update_sql("UPDATE {node} SET format = 2 WHERE nid IN (". implode(',', $php_nodes) .")"); + } + + // Boxes now use the filtering system as well. + // Type 0 (HTML) maps to Format 3 (Full HTML). + // Type 1 (PHP) maps to Format 2 (PHP). + $ret[] = update_sql("UPDATE {boxes} SET format = 3 - format"); + + /* + ** Update PHP content to use tags. + */ + if ($GLOBALS['db_type'] == 'mysql') { + $ret[] = update_sql("UPDATE {node} SET teaser = CONCAT('rid; + } + $ret[] = update_sql("INSERT INTO {filter_formats} VALUES (2,'PHP code','". implode(',', $php_roles) .",',0)"); + + // This is a 'Full HTML' format which allows all HTML without restrictions. + $ret[] = update_sql("INSERT INTO {filter_formats} VALUES (3,'Full HTML','',1)"); + + // Set the default format to the legacy format + variable_set('filter_default_format', 1); + + // Put the old filters into the legacy format + $ret[] = update_sql("UPDATE {filters} SET format = 1"); + + // Add filter.module's standard filters (these used to be hardcoded). + if (!variable_get('rewrite_old_urls', 0)) { + $ret[] = update_sql("DELETE FROM {filters} WHERE module = 'filter'"); + } + else { + $ret[] = update_sql("UPDATE {filters} SET delta = 2 WHERE module ='filter'"); + } + if ($old_html_filter != 0) { + $ret[] = update_sql("INSERT INTO {filters} (format, module, delta, weight) VALUES (1,'filter',0,0)"); // HTML tag/style filter + } + $ret[] = update_sql("INSERT INTO {filters} (format, module, delta, weight) VALUES (1,'filter',3,1)"); // Linebreak filter + $ret[] = update_sql("INSERT INTO {filters} (format, module, delta, weight) VALUES (2,'filter',1,0)"); // PHP evaluator + $ret[] = update_sql("INSERT INTO {filters} (format, module, delta, weight) VALUES (3,'filter',3,0)"); // Linebreak filter + + // Migrate the settings for all core/contrib filtering modules into the legacy + // format. + $migrate = array('filter_html', // filter.module + 'allowed_html', + 'filter_style', + 'anyfilter_regexps', // anyfilter.module + 'htmlcorrector_smartclose', // htmlcorrector.module + 'htmlcorrector_xhtmlify', + 'htmlcorrector_valueentities', + 'project_filter', // project.module + 'latex_filter_link' // latex.module + ); + + foreach ($migrate as $variable) { + $value = variable_get($variable, NULL); + if ($value != NULL) { + variable_set($variable .'_1', $value); + variable_del($variable); + } + } + + return $ret; +} + + function update_sql($sql) { $edit = $_POST["edit"]; $result = db_query($sql); diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 8241fc41ff..0d1fb15621 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -133,13 +133,22 @@ function cache_set($cid, $data, $expire = 0, $headers = NULL) { * @param $cid * If set, the cache ID to delete. Otherwise, all cache entries that can expire * are deleted. + * + * @param $wildcard + * If set to true, the $cid is treated as a substring to match rather than a + * complete ID. */ -function cache_clear_all($cid = NULL) { +function cache_clear_all($cid = NULL, $wildcard = false) { if (empty($cid)) { db_query("DELETE FROM {cache} WHERE expire <> 0"); } else { - db_query("DELETE FROM {cache} WHERE cid = '%s'", $cid); + if ($wildcard) { + db_query("DELETE FROM {cache} WHERE cid LIKE '%%%s%%'", $cid); + } + else { + db_query("DELETE FROM {cache} WHERE cid = '%s'", $cid); + } } } diff --git a/includes/common.inc b/includes/common.inc index feab010d24..209769c8fd 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -813,7 +813,7 @@ function format_rss_item($title, $link, $description, $args = array()) { $output = "\n"; $output .= ' '. drupal_specialchars(strip_tags($title)) ."\n"; $output .= ' '. drupal_specialchars(strip_tags($link)) ."\n"; - $output .= ' '. drupal_specialchars(check_output($description)) ."\n"; + $output .= ' '. drupal_specialchars($description) ."\n"; foreach ($args as $key => $value) { $output .= ' <'. $key .'>'. drupal_specialchars(strip_tags($value)) ."\n"; } @@ -1770,6 +1770,20 @@ function truncate_utf8($string, $len) { return substr($string, 0, $len); } +/** + * Wrapper around PHP's eval(). Uses output buffering to capture both returned + * and printed text. Unlike eval(), we require code to be surrounded by + * tags (in other words, we evaluate the code as if it were a stand-alone PHP + * file). + * + * @param $code The code to evaluate + */ +function drupal_eval($code) { + ob_start(); + print eval('?>'. $code); + return ob_get_clean(); +} + include_once 'includes/theme.inc'; include_once 'includes/pager.inc'; include_once 'includes/menu.inc'; diff --git a/misc/drupal.css b/misc/drupal.css index 4ca9f0c359..548b122bbd 100644 --- a/misc/drupal.css +++ b/misc/drupal.css @@ -319,6 +319,13 @@ tr.light .form-item, tr.dark .form-item { margin: 0; font-size: 0.8em; } +.tips { + margin-top: 0px; + margin-bottom: 0px; + padding-top: 0px; + padding-bottom: 0px; + font-size: 0.9em; +} #forum .description { font-size: 0.9em; margin: 0.5em; diff --git a/modules/aggregator.module b/modules/aggregator.module index 6a2d535406..7d68ddccba 100644 --- a/modules/aggregator.module +++ b/modules/aggregator.module @@ -470,7 +470,12 @@ function aggregator_parse_feed(&$data, $feed) { // Prepare the item: foreach ($item as $key => $value) { - $item[$key] = filter_default(strtr(trim($value), $tt)); + // TODO: Make handling of aggregated HTML more flexible/configurable. + $value = strtr(trim($value), $tt); + $value = strip_tags($value, '