| 1 |
<?php
|
| 2 |
// $Id: htmLawed.module,v 1.8.2.2 2008/07/03 01:28:14 patnaik Exp $
|
| 3 |
|
| 4 |
// Drupal 7 htmLawed module
|
| 5 |
// GPL v3 license
|
| 6 |
// Copyright Santosh Patnaik, MD, PhD
|
| 7 |
// Since May 2008
|
| 8 |
|
| 9 |
/*
|
| 10 |
* The module_comment hook is used for 'save' for 'Comment'
|
| 11 |
* Calls _htmLawed_process() to filter data before it is stored
|
| 12 |
* As this is for 'save', we don't care that there will be no filtering if node's content-type-settings are unavailable
|
| 13 |
* Other filtering in htmLawed_node_rss_item(), htmLawed_node_presave(), htmLawed_filter() and htmLawed_nodeapi()
|
| 14 |
*/
|
| 15 |
function htmLawed_comment(&$comment, $op) {
|
| 16 |
$config = 0;
|
| 17 |
if($op == 'insert' or $op == 'update') {
|
| 18 |
$node_format = $comment['format'];
|
| 19 |
$filters = array_keys(filter_list_format($node_format));
|
| 20 |
if(in_array('htmLawed/0', $filters) and !empty($comment['comment'])) {
|
| 21 |
// Check setting
|
| 22 |
$setting = variable_get('htmLawed_format_'. $node_format, 0);
|
| 23 |
if(!is_array($setting)) {
|
| 24 |
return;
|
| 25 |
}
|
| 26 |
$def_setting = isset($setting['htmLawedDef']['Comment']) ? $setting['htmLawedDef']['Comment'] : array('config'=>"'safe'=>1, 'elements'=>'a, em, strong, cite, code, ol, ul, li, dl, dt, dd', 'deny_attribute'=>'id, style'",'spec'=>'');
|
| 27 |
$node_type = db_fetch_object(db_query('SELECT type AS type FROM {node} WHERE nid = %d', $comment['nid']))->type;
|
| 28 |
$setting = isset($setting[$node_type]['Comment']) ? $setting[$node_type]['Comment'] : array();
|
| 29 |
if(!empty($setting['save'])) {
|
| 30 |
$setting = !empty($setting['default']) ? $def_setting : $setting;
|
| 31 |
eval('$config = array('. $setting['config']. ');');
|
| 32 |
// Filter & save this way as hook_comment is unfortunately called AFTER database insertion
|
| 33 |
if(is_array($config)) {
|
| 34 |
// Preserve PHP code
|
| 35 |
$htmLawed_hook_parameter = (in_array('php/0', $filters) && strpos($comment['comment'], '<?') !== FALSE) ? 'save_php' : 0;
|
| 36 |
db_query("UPDATE {comments} SET comment = '%s' WHERE cid = %d", _htmLawed_process($comment['comment'], $config, $setting['spec'], $htmLawed_hook_parameter), $comment['cid']);
|
| 37 |
}
|
| 38 |
}
|
| 39 |
}
|
| 40 |
}
|
| 41 |
}
|
| 42 |
|
| 43 |
/*
|
| 44 |
* Delete settings for extinct input formats
|
| 45 |
* Also see htmLawed_uninstall() in htmLawed.install, and htmLawed_node_type()
|
| 46 |
*/
|
| 47 |
function htmLawed_cron() {
|
| 48 |
$setting_rows = db_query("SELECT name AS name FROM {variable} WHERE name LIKE 'htmLawed_format_%'");
|
| 49 |
while($row = db_fetch_object($setting_rows)) {
|
| 50 |
$format = substr($row->name, 16);
|
| 51 |
if(db_fetch_object(db_query('SELECT COUNT(name) AS count FROM {filter_format} WHERE format = %d', $format))->count < 1) {
|
| 52 |
variable_del('htmLawed_format_'. $format);
|
| 53 |
drupal_set_message(t('Variable %htmLawed_format_num storing specific htmLawed settings for a non-existing text format was deleted from the database.', array('%htmLawed_format_num' => "htmLawed_format_$format")));
|
| 54 |
}
|
| 55 |
}
|
| 56 |
}
|
| 57 |
|
| 58 |
/*
|
| 59 |
* The module_filter hook; for 'show'
|
| 60 |
* Other filtering in htmLawed_node_rss_item(), htmLawed_node_presave(), htmLawed_comment() and htmLawed_nodeapi()
|
| 61 |
*/
|
| 62 |
function htmLawed_filter($op, $delta = 0, $format = -1, $text = '') {
|
| 63 |
switch ($op) {
|
| 64 |
case 'list':
|
| 65 |
return array(0 => t('htmLawed (X)HTML filter/purifier'));
|
| 66 |
case 'no cache':
|
| 67 |
return FALSE;
|
| 68 |
case 'description':
|
| 69 |
return t('Restrict HTML markup as well as make content more secure, and standards- and admin-compliant.');
|
| 70 |
case 'prepare':
|
| 71 |
return $text;
|
| 72 |
case 'process':
|
| 73 |
// htmLawed_help() should use similar logic
|
| 74 |
$setting = variable_get('htmLawed_format_'. $format, 0);
|
| 75 |
if(!is_array($setting)){
|
| 76 |
return $text;
|
| 77 |
}
|
| 78 |
|
| 79 |
$node_id = $node_type = NULL;
|
| 80 |
$for = 'Other';
|
| 81 |
// Comment
|
| 82 |
if(arg(0) == 'comment') {
|
| 83 |
$for = 'Comment';
|
| 84 |
if(arg(1) == 'reply') {
|
| 85 |
$node_id = arg(2);
|
| 86 |
}
|
| 87 |
elseif(arg(1) == 'edit') {
|
| 88 |
$comment_id = arg(2);
|
| 89 |
$node_id = db_fetch_object(db_query('SELECT nid AS nid FROM {comments} WHERE cid = %d', $comment_id))->nid;
|
| 90 |
}
|
| 91 |
}
|
| 92 |
// Body, extra fields because of CCK, etc.
|
| 93 |
elseif(arg(0) == 'node') {
|
| 94 |
$for = 'Body';
|
| 95 |
if(arg(1) == 'add') {
|
| 96 |
$node_type = arg(2);
|
| 97 |
}
|
| 98 |
elseif(is_numeric(arg(1))) {
|
| 99 |
$node_id = arg(1);
|
| 100 |
}
|
| 101 |
}
|
| 102 |
|
| 103 |
// Content-type
|
| 104 |
if($node_id) {
|
| 105 |
$node_type = db_fetch_object(db_query('SELECT type AS type FROM {node} WHERE nid = %d', $node_id))->type;
|
| 106 |
}
|
| 107 |
|
| 108 |
// Right settings
|
| 109 |
$def_setting = isset($setting['htmLawedDef'][$for]) ? $setting['htmLawedDef'][$for] : array('show'=>1, 'config'=>"'safe'=>1, 'elements'=>'a, em, strong, cite, code, ol, ul, li, dl, dt, dd', 'deny_attribute'=>'id, style'",'spec'=>'');
|
| 110 |
if($node_type) {
|
| 111 |
$setting = isset($setting[$node_type][$for]) ? $setting[$node_type][$for] : $def_setting;
|
| 112 |
}
|
| 113 |
else {
|
| 114 |
$setting = $def_setting;
|
| 115 |
}
|
| 116 |
|
| 117 |
if(!empty($setting['show'])) {
|
| 118 |
$config = 0;
|
| 119 |
$setting = !empty($setting['default']) ? $def_setting : $setting;
|
| 120 |
// Filter by calling _htmLawed_process
|
| 121 |
eval('$config = array('. $setting['config']. ');');
|
| 122 |
if(!is_array($config)) {
|
| 123 |
return $text;
|
| 124 |
}
|
| 125 |
return _htmLawed_process($text, $config, $setting['spec']);
|
| 126 |
}
|
| 127 |
|
| 128 |
return $text;
|
| 129 |
break;
|
| 130 |
|
| 131 |
// Shows sub-forms on the pages for configuring input formats; _htmLawed_store_setting() will save the submitted data
|
| 132 |
case 'settings':
|
| 133 |
// Same key as in htmLawed_perm()
|
| 134 |
if(!user_access('administer htmLawed (X)HTML filter/purifier')) {
|
| 135 |
break;
|
| 136 |
}
|
| 137 |
|
| 138 |
// Default & content-type-specific settings to pre-fill sub-forms
|
| 139 |
$content_types = array();
|
| 140 |
$content_types['htmLawedDef'] = t('Default');
|
| 141 |
$content_types += node_get_types('names');
|
| 142 |
|
| 143 |
$help = l(t('(?)'), 'admin/help/htmLawed', array('title'=>t('help')));
|
| 144 |
$subform_count = 0;
|
| 145 |
|
| 146 |
$setting = variable_get('htmLawed_format_'. $format, array());
|
| 147 |
|
| 148 |
$form['htmLawed'] = array(
|
| 149 |
'#type' => 'fieldset',
|
| 150 |
'#title' => t('htmLawed (X)HTML filter/purifier'),
|
| 151 |
'#collapsible' => TRUE,
|
| 152 |
);
|
| 153 |
|
| 154 |
foreach($content_types as $k=>$v) {
|
| 155 |
// Default values
|
| 156 |
if(!isset($setting[$k]) or !is_array($setting[$k])) {
|
| 157 |
foreach(array('Body', 'Comment', 'Other', 'RSS') as $for) {
|
| 158 |
if($for == 'Other' and $k != 'htmLawedDef') {
|
| 159 |
continue;
|
| 160 |
}
|
| 161 |
$val[$for] = array('config'=>"'safe'=>1, 'elements'=>'a, em, strong, cite, code, ol, ul, li, dl, dt, dd". ($for == 'RSS' ? ', br, p' : ''). "', 'deny_attribute'=>'id, style'", 'spec'=>'', 'help'=>'Tags allowed: a, em, strong, cite, code, ol, ul, li, dl, dt, dd'. ($for == 'RSS' ? ', br, p' : ''));
|
| 162 |
if($k != 'htmLawedDef') {
|
| 163 |
if($for != 'RSS') {
|
| 164 |
$val[$for]['save'] = 0;
|
| 165 |
$val[$for]['show'] = 1;
|
| 166 |
}
|
| 167 |
else {
|
| 168 |
$val[$for]['show'] = 0;
|
| 169 |
}
|
| 170 |
$val[$for]['default'] = 1;
|
| 171 |
}
|
| 172 |
elseif($for == 'Other') {
|
| 173 |
$val[$for]['show'] = 1;
|
| 174 |
}
|
| 175 |
}
|
| 176 |
$setting[$k] = $val;
|
| 177 |
}
|
| 178 |
|
| 179 |
$my_k = 'htmLawed_'. $k;
|
| 180 |
|
| 181 |
$form['htmLawed'][$my_k] = array(
|
| 182 |
'#type' => 'fieldset',
|
| 183 |
'#title' => $v,
|
| 184 |
'#collapsible' => TRUE,
|
| 185 |
'#collapsed' => !$subform_count ? FALSE : TRUE,
|
| 186 |
'#description' => !$subform_count ? t('Generic settings; content-type-specific values can be set <a href="!below">further below</a>.', array('!below'=>'#htmLawed_specific_point')). '<a id="htmLawed_default_point"></a> <small>'. "$help</small>" : NULL,
|
| 187 |
);
|
| 188 |
|
| 189 |
foreach(array('Body', 'Comment', 'Other', 'RSS') as $for) {
|
| 190 |
if($for == 'Other' and $k != 'htmLawedDef') {
|
| 191 |
continue;
|
| 192 |
}
|
| 193 |
|
| 194 |
$my_for = $my_k. '_'. $for;
|
| 195 |
|
| 196 |
$form['htmLawed'][$my_k][$my_for] = array(
|
| 197 |
'#type' => 'fieldset',
|
| 198 |
'#title' => t(($for == 'RSS' ? 'Teaser' : $for)),
|
| 199 |
'#collapsible' => TRUE,
|
| 200 |
'#collapsed' => TRUE,
|
| 201 |
'#theme' => 'htmLawed_tabled_subform',
|
| 202 |
);
|
| 203 |
|
| 204 |
if($k != 'htmLawedDef') {
|
| 205 |
$form['htmLawed'][$my_k][$my_for][$my_for. '_guide'] = array(
|
| 206 |
'#type' => 'markup',
|
| 207 |
'#value' => '<p><small>'. t('For content-type %type, ', array('%type'=>$v)). ($for == 'Body' ? t('for main body') : ($for == 'RSS' ? t('for teasers and newsfeed items; the filtering will be additional to any done for <em>Body</em>') : t('for any user comment'))). " $help</small></p>",
|
| 208 |
);
|
| 209 |
$form['htmLawed'][$my_k][$my_for][$my_for. '_show'] = array(
|
| 210 |
'#type' => 'checkbox',
|
| 211 |
'#title' => t('Enable'),
|
| 212 |
'#default_value' => $setting[$k][$for]['show'],
|
| 213 |
'#description' => t('Filter content during page-display'),
|
| 214 |
);
|
| 215 |
if($for != 'RSS') {
|
| 216 |
$form['htmLawed'][$my_k][$my_for][$my_for. '_save'] = array(
|
| 217 |
'#type' => 'checkbox',
|
| 218 |
'#title' => t('Enable for <em>save</em>'),
|
| 219 |
'#default_value' => $setting[$k][$for]['save'],
|
| 220 |
'#description' => t('Filter submitted content before saving'),
|
| 221 |
);
|
| 222 |
}
|
| 223 |
$form['htmLawed'][$my_k][$my_for][$my_for. '_default'] = array(
|
| 224 |
'#type' => 'checkbox',
|
| 225 |
'#title' => t('Use the <a href="!default">Default</a> values', array('!default'=>'#htmLawed_default_point')),
|
| 226 |
'#default_value' => $setting[$k][$for]['default'],
|
| 227 |
'#description' => t('For <em>Config.</em>, <em>Help</em> and <em>Spec.</em>'),
|
| 228 |
);
|
| 229 |
}
|
| 230 |
else {
|
| 231 |
$form['htmLawed'][$my_k][$my_for][$my_for. '_guide'] = array(
|
| 232 |
'#type' => 'markup',
|
| 233 |
'#value' => '<p><small>'. t('Default settings for <em>Config.</em>, <em>Help</em> and <em>Spec.</em> for use with ', array('%type'=>$v)). ($for == 'Body' ? t('main body') : ($for == 'RSS' ? t('teasers and newsfeed items; the filtering will be additional to any done for <em>Body</em>') : ($for == 'Other' ? t('other cases not based on content-type (like a <em>header</em> field seen with the <em>Views</em> module. There are obviously no content-type-specific settings.') : t('any user comment')))). " $help</small></p>",
|
| 234 |
);
|
| 235 |
if($for == 'Other') {
|
| 236 |
$form['htmLawed'][$my_k][$my_for][$my_for. '_show'] = array(
|
| 237 |
'#type' => 'checkbox',
|
| 238 |
'#title' => t('Enable'),
|
| 239 |
'#default_value' => $setting[$k][$for]['show'],
|
| 240 |
'#description' => t('Filter content before showing'),
|
| 241 |
);
|
| 242 |
}
|
| 243 |
}
|
| 244 |
|
| 245 |
$form['htmLawed'][$my_k][$my_for][$my_for. '_config'] = array(
|
| 246 |
'#type' => 'textarea',
|
| 247 |
'#rows' => '3',
|
| 248 |
'#title' => t('Config.'),
|
| 249 |
'#default_value' => $setting[$k][$for]['config'],
|
| 250 |
'#description' => t('Comma-separated, quoted key-value pairs'),
|
| 251 |
);
|
| 252 |
$form['htmLawed'][$my_k][$my_for][$my_for. '_spec'] = array(
|
| 253 |
'#type' => 'textarea',
|
| 254 |
'#rows' => '3',
|
| 255 |
'#title' => t('Spec.'),
|
| 256 |
'#default_value' => $setting[$k][$for]['spec'],
|
| 257 |
'#description' => t('Optional'),
|
| 258 |
);
|
| 259 |
$form['htmLawed'][$my_k][$my_for][$my_for. '_help'] = array(
|
| 260 |
'#type' => 'textarea',
|
| 261 |
'#rows' => '3',
|
| 262 |
'#title' => t('Help'),
|
| 263 |
'#default_value' => $setting[$k][$for]['help'],
|
| 264 |
'#description' => t('Tips for users'),
|
| 265 |
);
|
| 266 |
} // End inner foreach
|
| 267 |
|
| 268 |
if(!$subform_count) {
|
| 269 |
$form['htmLawed']['htmLawed_content_specific_point'] = array(
|
| 270 |
'#type' => 'markup',
|
| 271 |
'#value' => '<div class="description">'. t('Set values per content-type below. Generic default values are set <a href="!above">above</a>.', array('!above'=>'#htmLawed_default_point')). '<a id="htmLawed_specific_point"></a> <small>'. "$help</small></div>",
|
| 272 |
);
|
| 273 |
}
|
| 274 |
++$subform_count;
|
| 275 |
} // End outer foreach
|
| 276 |
|
| 277 |
$form['#submit'][] = '_htmLawed_store_setting'; // Drupal 6 diff.
|
| 278 |
$form['#submit'] = array_reverse($form['#submit']);
|
| 279 |
return $form;
|
| 280 |
break;
|
| 281 |
|
| 282 |
default:
|
| 283 |
return $text;
|
| 284 |
break;
|
| 285 |
}
|
| 286 |
}
|
| 287 |
|
| 288 |
/*
|
| 289 |
* Display tips indicating htmLawed settings (elements allowed, etc.)
|
| 290 |
*/
|
| 291 |
function htmLawed_filter_tips($delta, $format, $long = FALSE) {
|
| 292 |
// Content-type unknown
|
| 293 |
$basic_out = t('Information indicating specific htmLawed (X)HTML filter/purifier settings in effect will be shown where appropriate.');
|
| 294 |
$setting = variable_get('htmLawed_format_'. $format, 0);
|
| 295 |
if(arg(2) == 'filter') { // Drupal 7 diff
|
| 296 |
if($setting) {
|
| 297 |
return $basic_out;
|
| 298 |
}
|
| 299 |
return t('For htmLawed to be active with this text format, it needs to be configured and the configuration <em>saved</em>. <a href="!conf" title="!tip">Configure now?</a>', array('!conf'=>url('admin/settings/filter/'. arg(3). '/configure'), '!tip'=>'proceed to configuration form')); // Drupal 7 diff
|
| 300 |
}
|
| 301 |
if(!$setting) {
|
| 302 |
return $basic_out;
|
| 303 |
}
|
| 304 |
|
| 305 |
if(!$long) {
|
| 306 |
$node_id = $node_type = NULL;
|
| 307 |
$for = 'Other';
|
| 308 |
// Comment
|
| 309 |
if(arg(0) == 'comment') {
|
| 310 |
$for = 'Comment';
|
| 311 |
if(arg(1) == 'reply') {
|
| 312 |
$node_id = arg(2);
|
| 313 |
}
|
| 314 |
elseif(arg(1) == 'edit') {
|
| 315 |
$comment_id = arg(2);
|
| 316 |
$node_id = db_fetch_object(db_query('SELECT nid AS nid FROM {comments} WHERE cid = %d', $comment_id))->nid;
|
| 317 |
}
|
| 318 |
}
|
| 319 |
// Body, extra fields because of CCK, etc.
|
| 320 |
elseif(arg(0) == 'node') {
|
| 321 |
$for = 'Body';
|
| 322 |
if(arg(1) == 'add') {
|
| 323 |
$node_type = arg(2);
|
| 324 |
}
|
| 325 |
elseif(is_numeric(arg(1))) {
|
| 326 |
$node_id = arg(1);
|
| 327 |
}
|
| 328 |
}
|
| 329 |
// Admin configuring an extra field, because of modules like CCK
|
| 330 |
elseif(arg(0) == 'admin' and arg(1) == 'content' and arg(2) == 'types') {
|
| 331 |
$for = 'Body';
|
| 332 |
$node_type = arg(3);
|
| 333 |
}
|
| 334 |
|
| 335 |
// Content-type
|
| 336 |
if($node_id) {
|
| 337 |
$node_type = db_fetch_object(db_query('SELECT type AS type FROM {node} WHERE nid = %d', $node_id))->type;
|
| 338 |
}
|
| 339 |
|
| 340 |
// Right settings
|
| 341 |
$def_setting = isset($setting['htmLawedDef'][$for]) ? $setting['htmLawedDef'][$for] : array('show'=>1, 'save'=>0, 'help'=>'Tags allowed: a, em, strong, cite, code, ol, ul, li, dl, dt, dd');
|
| 342 |
if($node_type) {
|
| 343 |
$setting = isset($setting[$node_type][$for]) ? $setting[$node_type][$for] : $def_setting;
|
| 344 |
}
|
| 345 |
else {
|
| 346 |
$setting = $def_setting;
|
| 347 |
}
|
| 348 |
|
| 349 |
if(!empty($setting['show']) or !empty($setting['save'])) {
|
| 350 |
$setting = !empty($setting['default']) ? $def_setting : $setting;
|
| 351 |
return $setting['help'];
|
| 352 |
}
|
| 353 |
|
| 354 |
return;
|
| 355 |
}
|
| 356 |
|
| 357 |
// Long tips: Content-type always unknown
|
| 358 |
return t('HTML markup is restricted using the <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/index.php">htmLawed</a> filter to make input text more secure, and standards- and admin-compliant. More details about the restrictions in effect (that may vary from one content-type to another) may be available elsewhere, such as in the text of the input format filter-tips and on the input format configuration forms.') .
|
| 359 |
(!user_access('administer htmLawed (X)HTML filter/purifier') ? '' : ' ' . t('For information on configuring htmLawed, visit the htmLawed !help section.', array('!help' => l(t('help'), 'admin/help/htmLawed'))));
|
| 360 |
}
|
| 361 |
|
| 362 |
/*
|
| 363 |
* Help page on module usage
|
| 364 |
*/
|
| 365 |
function htmLawed_help($path, $arg) { // Drupal 6 diff.
|
| 366 |
switch ($path) {
|
| 367 |
case 'admin/help#htmLawed':
|
| 368 |
case 'admin/content/htmLawed':
|
| 369 |
$module_path = drupal_get_path('module', 'htmLawed');
|
| 370 |
include_once "$module_path/htmLawed/htmLawed.php"; // For version number
|
| 371 |
global $base_url;
|
| 372 |
return '<div>'. t('The htmLawed (X)HTML filter/purifier module restricts HTML markup in content as well as makes it more secure, and standards- and admin-compliant using the <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/index.php">htmLawed</a> (version !version) PHP software. Copies of the htmLawed <a href="!doc">documentation</a> and the module <a href="!readme">readme</a> files should be available on your site. A <a href="!handbook">handbook</a> detailing htmLawed module usage may be available on the Drupal website.', array('!doc' => $base_url. '/'. $module_path . '/htmLawed/htmLawed_README.htm', '!readme' => $base_url. '/'. $module_path . '/readme.txt', '!handbook'=>'http://drupal.org/search/apachesolr_search/htmlawed?filters=type%3abook', '!version' => hl_version())) . '<br /><br />' .
|
| 373 |
|
| 374 |
t('This module can be used to have the htmLawed-filtering configured differently for different text formats and content-types as well as for comments, teasers (like RSS newsfeed items), and other special content. ') . '<br /><br /><hr /><br />' .
|
| 375 |
|
| 376 |
t('To <strong>enable</strong> htmLawed per text format, visit the <em>!text_formats</em> section and choose to <em>configure</em> a text format that needs to include htmLawed-filtering. In the subsequently-displayed form, enable the htmLawed filter.', array('!text_formats' => l(t('Text formats'), 'admin/settings/filter'))) . '<blockquote><div>' . t('Because htmLawed does the task of the Drupal <em>HTML filter</em>, that filter can be disabled. Actions like <em>Correct broken HTML</em> that are used to balance or properly nest HTML tags can also be disabled. Unlike the Drupal filter, htmLawed can also be used to restrict HTML attributes and URL protocols, balance tags, etc., and that too in a content-type- and case-specific manner. Depending on the types of filters the text format uses, you may need to re-arrange the filters using the <em>rearrange</em> link on the form -- htmLawed would usually be the last filter to be run.') . '<br /><br />' .
|
| 377 |
|
| 378 |
t('If a filter that relies on the <, > or & character (such as Drupal <em>PHP evaluator</em>) is being used with the input format, then that filter should run before htmLawed. Further, if that filter generates HTML markup, then htmLawed should be configured appropriately to permit such markup.'). '</div></blockquote>' .
|
| 379 |
|
| 380 |
t('The <strong>customization</strong> of htmLawed is dictated by two parameters, <em>Config.</em> and <em>Spec.</em>. Setting specific htmLawed filter settings involves setting values for the two parameters in the htmLawed settings form. To get to the settings form, use the <em>Configure</em> link for a text format for which htmLawed has been enabled. On the settings form, a sub-form, <em>Default</em>, can be used to set the default values to be used for any content-type. Content (node)-type-specific sub-forms allow you to over-ride the default values as well as to choose to use (or disable) htmLawed.') . '<br /><br />' .
|
| 381 |
|
| 382 |
t('The <em>Config.</em> form-field is filled with comma-separated, quoted, key-value pairs like <code>"safe"=>1, "element"=>"a, em, strong"</code> (these are interpreted as PHP array elements). The <em>Spec.</em> field is an optional string of text... see htmLawed <a href="!doc">documentation</a> for more. Content of the <em>Help</em> field will be used as a note to inform users or yourself about the filter, such as what tags are allowed.', array('!doc' => $base_url. '/'. $module_path . '/htmLawed/htmLawed_README.htm')) . '<blockquote><div>' .
|
| 383 |
|
| 384 |
t('The form-fields are pre-filled the first time htmLawed is being configured for a text format. The values allow the <em>a, em, strong, cite, code, ol, ul, li, dl, dt</em> and <em>dd</em> HTML tags, deny the <em>id</em> and <em>style</em> attributes, and any unsafe markup (such as the scriptable <em>onclick</em> attribute). These same values may be used during the filtering process if the specific or default settings cannot be found. Note that emptying a <em>Config.</em> field does not mean that the default setting will be used.') . '</div></blockquote>' .
|
| 385 |
|
| 386 |
t('Individualized settings can be applied for <em>Body</em>, <em>Comment</em> and <em>Teaser</em>: the first refers to the main content; the second to user comments for the main content; and, the third, to the teasers (like RSS newsfeed items) generated from the main content. You may have a need for a fourth case, <em>Other</em>, if you use modules like <em>Views</em> that create extra input fields (like <em>Header</em>) that are not content (node)-type-specific. Content-type-specific settings for <em>Other</em> are obviously not possible') . '<br /><br />' .
|
| 387 |
|
| 388 |
t('For <em>Body</em> and <em>Comment</em>, enabling the filter for <em>save</em> can be used to filter input before storage in the database (core Drupal does not filter submissions; filtering is done dynamically when content is displayed on as web-pages), but you have to check if that affects the functioning of filters (other than the Drupal <em>PHP evaluator</em>) that rely on the <, > or & character. For <em>Teaser</em>, the htmLawed filtering is done at the end of all other filtering, including any prior htmLawed filtering because of <em>Body</em>, and the default settings will allow the <em>br</em> and <em>p</em> tags as well.') . '<br /><br /><hr /><br />' .
|
| 389 |
|
| 390 |
t('To control user <strong>permissions</strong> for editing of the htmLawed settings, !htmlawed_user_perm.', array('!htmlawed_user_perm' => l(t('visit the permissions page'), 'admin/user/permissions'))) . ' Ideally, only the main administrator would have the permission.<br /><br />' .
|
| 391 |
|
| 392 |
t('Content-type-specific htmLawed settings are <strong>deleted</strong> when a type is deleted. However, text-format-specific htmLawed settings are not automatically deleted when a format is deleted; you have to <em>!run_cron_manually</em> to get rid of the no-more-needed settings. Disabling htmLawed for a text format will not delete the associated settings. <em>!Uninstalling</em> the htmLawed module will delete all htmLawed-related settings, but disabling will not result in any deletion.', array('!run_cron_manually' => l(t('run cron manually'), 'admin/reports/status'), '!Uninstalling' => l(t('Uninstalling'), 'admin/build/modules/uninstall'))) . '<br /><br />' . // Drupal 6 diff
|
| 393 |
|
| 394 |
t('It is important to understand the security implications of the htmLawed settings in use and the limitations of htmLawed. To keep the htmLawed script included with the module updated, replace the <em>htmLawed.php</em> and <em>htmLawed_README.htm</em> files inside the <em>htmLawed</em> sub-folder of the module folder with newer versions downloaded from the <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/index.php">htmLawed</a>.') . '<br /><br /></div>';
|
| 395 |
break;
|
| 396 |
case 'admin/settings/filter/%/configure': // Drupal 7 diff
|
| 397 |
$setting = variable_get('htmLawed_format_'. arg(3), 0);
|
| 398 |
if(!is_array($setting)) {
|
| 399 |
return '<p>'. t('Though the htmLawed filter settings are pre-filled below, you <em>must save</em> the configuration for the filter to be activated.') .'</p>';
|
| 400 |
}
|
| 401 |
break;
|
| 402 |
case 'admin/settings/filter/%': // Drupal 7 diff
|
| 403 |
$setting = variable_get('htmLawed_format_'. arg(3), 0);
|
| 404 |
if(!is_array($setting)) {
|
| 405 |
return '<p>'. t('Though the htmLawed filter is enabled, you <em>must <a href="!conf" title="!tip">configure</a></em> it to activate it for this text format.', array('!conf'=>url('admin/settings/filter/'. arg(3). '/configure'), '!tip'=>'proceed to configuration form')) .'</p>'; // Drupal 7 diff
|
| 406 |
}
|
| 407 |
break;
|
| 408 |
}
|
| 409 |
}
|
| 410 |
|
| 411 |
/*
|
| 412 |
* The module_nodeapi hook is used for 'save' for 'Body' (also, effectively, for 'save' for 'Teaser') and for 'show' for 'Teaser'
|
| 413 |
* Calls _htmLawed_process() to filter data before it is stored
|
| 414 |
* The module_filter hook is for the 'show', and module_comment hook for 'Comment' for'save'
|
| 415 |
* No default filtering for 'save' if content-type-settings are unavailable as hook_filter will always be run later
|
| 416 |
* For filtering of others, see htmLawed_filter(), htmLawed_node_rss_item(), and htmLawed_node_presave()
|
| 417 |
*/
|
| 418 |
function htmLawed_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
|
| 419 |
$config = 0;
|
| 420 |
switch($op) {
|
| 421 |
// 'Teaser' 'show' for non-feed teaser; content already filtered, incl. by htmLawed_filter based on 'Body' 'show'
|
| 422 |
case 'alter':
|
| 423 |
$filters = array_keys(filter_list_format($node->format));
|
| 424 |
if(in_array('htmLawed/0', $filters) and isset($node->teaser)) {
|
| 425 |
$setting = variable_get('htmLawed_format_'. $node->format, 0);
|
| 426 |
if(!is_array($setting)) {
|
| 427 |
return;
|
| 428 |
}
|
| 429 |
$def_setting = isset($setting['htmLawedDef']['RSS']) ? $setting['htmLawedDef']['RSS'] : array('show'=>1, 'config'=>"'safe'=>1, 'elements'=>'a, em, strong, cite, code, ol, ul, li, dl, dt, dd, br, p', 'deny_attribute'=>'id, style'",'spec'=>'');
|
| 430 |
$setting = isset($setting[$node->type]['RSS']) ? $setting[$node->type]['RSS'] : $def_setting;
|
| 431 |
if(!empty($setting['show'])) {
|
| 432 |
$setting = !empty($setting['default']) ? $def_setting : $setting;
|
| 433 |
eval('$config = array('. $setting['config']. ');');
|
| 434 |
if(is_array($config)) {
|
| 435 |
$node->teaser = _htmLawed_process($node->teaser, $config, $setting['spec']);
|
| 436 |
}
|
| 437 |
}
|
| 438 |
}
|
| 439 |
break;
|
| 440 |
}
|
| 441 |
}
|
| 442 |
|
| 443 |
/*
|
| 444 |
* For 'save' for 'Body' (also, effectively, for 'save' for 'Teaser') - filter before saving to database
|
| 445 |
* For filtering of others, see htmLawed_filter(), htmLawed_node_rss_item(), htmLawed_comment(), and htmLawed_nodeapi()
|
| 446 |
*/
|
| 447 |
function htmLawed_node_presave($node) { // Drupal 7 new
|
| 448 |
$config = 0;
|
| 449 |
$filters = array_keys(filter_list_format($node->format));
|
| 450 |
if(in_array('htmLawed/0', $filters)) {
|
| 451 |
$setting = variable_get('htmLawed_format_'. $node->format, 0);
|
| 452 |
if(!is_array($setting)) {
|
| 453 |
return;
|
| 454 |
}
|
| 455 |
$def_setting = isset($setting['htmLawedDef']['Body']) ? $setting['htmLawedDef']['Body'] : array('config'=>"'safe'=>1, 'elements'=>'a, em, strong, cite, code, ol, ul, li, dl, dt, dd', 'deny_attribute'=>'id, style'",'spec'=>'');
|
| 456 |
$setting = isset($setting[$node->type]['Body']) ? $setting[$node->type]['Body'] : array();
|
| 457 |
if(!empty($setting['save'])) {
|
| 458 |
$setting = !empty($setting['default']) ? $def_setting : $setting;
|
| 459 |
eval('$config = array('. $setting['config']. ');');
|
| 460 |
if(is_array($config)) {
|
| 461 |
if(isset($node->body)) {
|
| 462 |
// Leave any PHP code & Drupal's teaser mark intact
|
| 463 |
$htmLawed_hook_parameter = (in_array('php/0', $filters) && strpos($node->body, '<?') !== FALSE) ? 'save_php' : 0;
|
| 464 |
$node->body = _htmLawed_process($node->body, $config, $setting['spec'], $htmLawed_hook_parameter);
|
| 465 |
$node->body = str_replace('<!--break-->', '<!--break-->', $node->body);
|
| 466 |
}
|
| 467 |
if(isset($node->teaser)) {
|
| 468 |
$htmLawed_hook_parameter = (in_array('php/0', $filters) && strpos($node->teaser, '<?') !== FALSE) ? 'save_php' : 0;
|
| 469 |
$node->teaser = _htmLawed_process($node->teaser, $config, $setting['spec'], $htmLawed_hook_parameter);
|
| 470 |
}
|
| 471 |
}
|
| 472 |
}
|
| 473 |
}
|
| 474 |
|
| 475 |
}
|
| 476 |
|
| 477 |
/*
|
| 478 |
* Filter RSS item
|
| 479 |
* Note content already filtered, incl. by htmLawed_filter based on 'Body' 'show'
|
| 480 |
* For filtering of others, see htmLawed_filter(), htmLawed_comment(), htmLawed_node_presave(), and htmLawed_nodeapi()
|
| 481 |
*/
|
| 482 |
function htmLawed_node_rss_item($node) { // Drupal 7 new
|
| 483 |
$config = 0;
|
| 484 |
$filters = array_keys(filter_list_format($node->format));
|
| 485 |
if(in_array('htmLawed/0', $filters) and isset($node->teaser)) {
|
| 486 |
$setting = variable_get('htmLawed_format_'. $node->format, 0);
|
| 487 |
if(!is_array($setting)) {
|
| 488 |
return;
|
| 489 |
}
|
| 490 |
$def_setting = isset($setting['htmLawedDef']['RSS']) ? $setting['htmLawedDef']['RSS'] : array('show'=>1, 'config'=>"'safe'=>1, 'elements'=>'a, em, strong, cite, code, ol, ul, li, dl, dt, dd, br, p', 'deny_attribute'=>'id, style'",'spec'=>'');
|
| 491 |
$setting = isset($setting[$node->type]['RSS']) ? $setting[$node->type]['RSS'] : $def_setting;
|
| 492 |
if(!empty($setting['show'])) {
|
| 493 |
$setting = !empty($setting['default']) ? $def_setting : $setting;
|
| 494 |
eval('$config = array('. $setting['config']. ');');
|
| 495 |
if(is_array($config)) {
|
| 496 |
$node->teaser = _htmLawed_process($node->teaser, $config, $setting['spec']);
|
| 497 |
}
|
| 498 |
}
|
| 499 |
}
|
| 500 |
}
|
| 501 |
|
| 502 |
/*
|
| 503 |
* Delete content-type htmLawed settings when the content-type is deleted
|
| 504 |
* Also see htmLawed_cron() and htmLawed_uninstall() in htmLawed.install
|
| 505 |
*/
|
| 506 |
function htmLawed_node_type($op, $info) {
|
| 507 |
switch($op) {
|
| 508 |
case 'delete':
|
| 509 |
$result = db_query('SELECT format AS format FROM {filter_format}');
|
| 510 |
while($format = db_fetch_object($result)) {
|
| 511 |
$format = $format->format;
|
| 512 |
$setting = variable_get('htmLawed_format_'. $format, NULL);
|
| 513 |
if(isset($setting[$info->type]) and is_array($setting[$info->type])) {
|
| 514 |
unset($setting[$info->type]);
|
| 515 |
variable_set('htmLawed_format_'. $format, $setting);
|
| 516 |
}
|
| 517 |
}
|
| 518 |
break;
|
| 519 |
}
|
| 520 |
}
|
| 521 |
|
| 522 |
/*
|
| 523 |
* This also helps display the htmLawed section on the administration-by-module page
|
| 524 |
*/
|
| 525 |
function htmLawed_perm() { // Drupal 7 diff
|
| 526 |
return array(
|
| 527 |
// This key should be same whereever user_access() is called
|
| 528 |
'administer htmLawed (X)HTML filter/purifier' => array(
|
| 529 |
'title' => t('Administer htmLawed (X)HTML filter/purifier'),
|
| 530 |
'description' => t('Manage the htmLawed (X)HTML filter/purifier, and select which roles may use them. %warning', array('%warning' => t('Warning: Give to trusted roles only; this permission has security implications.'))),
|
| 531 |
),
|
| 532 |
);
|
| 533 |
}
|
| 534 |
|
| 535 |
function htmLawed_theme() { // Drupal 6 new
|
| 536 |
return array(
|
| 537 |
'htmLawed_tabled_subform' => array(
|
| 538 |
'arguments' => array('subform' => NULL)
|
| 539 |
)
|
| 540 |
);
|
| 541 |
}
|
| 542 |
|
| 543 |
/*
|
| 544 |
* Render sub-forms for htmLawed settings in tabular format
|
| 545 |
*/
|
| 546 |
function theme_htmLawed_tabled_subform($subform = NULL) {
|
| 547 |
$output = '';
|
| 548 |
$my = array();
|
| 549 |
foreach($subform as $k=>$v) {
|
| 550 |
$my[substr(strrchr($k, '_'), 1)] = $v;
|
| 551 |
}
|
| 552 |
$rows[0][0] = array('data'=>drupal_render($my['guide']). (isset($my['default']) ? drupal_render($my['default']) : ''). (isset($my['show']) ? drupal_render($my['show']) : ''). (isset($my['save']) ? drupal_render($my['save']) : ''), 'style'=>'width: 50%');
|
| 553 |
$rows[0][1] = array('data'=>drupal_render($my['help']), 'style'=>'width: 50%');
|
| 554 |
$rows[1][0] = array('data'=>drupal_render($my['config']), 'style'=>'width: 50%');
|
| 555 |
$rows[1][1] = array('data'=>drupal_render($my['spec']), 'style'=>'width: 50%');
|
| 556 |
|
| 557 |
$output = theme('table', array(), $rows);
|
| 558 |
return $output;
|
| 559 |
}
|
| 560 |
|
| 561 |
/*
|
| 562 |
* The htmLawed filtering process
|
| 563 |
*/
|
| 564 |
function _htmLawed_process($text = '', $config = NULL, $spec = NULL, $hook_parameter = 0) {
|
| 565 |
$module_path = drupal_get_path('module', 'htmLawed');
|
| 566 |
include_once "$module_path/htmLawed/htmLawed.php";
|
| 567 |
if($hook_parameter == 'save_php'){
|
| 568 |
$config['hook'] = '_htmLawed_save_php';
|
| 569 |
}
|
| 570 |
$text = htmLawed($text, $config, $spec);
|
| 571 |
if($hook_parameter == 'save_php'){
|
| 572 |
$text = preg_replace(array('`\x83\?php(.+?)\?\x84`sme', '`\x83\?php(.*)$`sme'), array("'<?php'. str_replace(array('&', '<', '>'), array('&', '<', '>'), '$1'). '?>'", "'<?php'. str_replace(array('&', '<', '>'), array('&', '<', '>'), '$1')"), $text);
|
| 573 |
}
|
| 574 |
return $text;
|
| 575 |
}
|
| 576 |
|
| 577 |
/*
|
| 578 |
* Using htmLawed's hook function to preserve PHP code before 'save'
|
| 579 |
*/
|
| 580 |
function _htmLawed_save_php($text) {
|
| 581 |
return preg_replace(array('`<\?php(.+?)\?>`sme', '`<\?php(.*)$`sme'), array("\"\x83?php\". str_replace(array('<', '>', '&'), array('<', '>', '&'), '$1'). \"?\x84\"", "\"\x83?php\". str_replace(array('<', '>', '&'), array('<', '>', '&'), '$1')"), $text);
|
| 582 |
}
|
| 583 |
|
| 584 |
/*
|
| 585 |
* Content-type-specific and default htmLawed settings are stored in variable table in input-format specific fields: htmLawed_format_1, _2, etc.
|
| 586 |
* E.g., as array('story'=>array('Body'=>array('show'=>1, 'save'=>1,...), 'Comment'=>array('show'=>1...)), 'page'=>array('show'=>1...
|
| 587 |
* There is no 'save' key for 'RSS'.
|
| 588 |
* There are no 'save' or 'default' keys in the arrays of 'htmLawedDef'; also, 'show' is only for 'Other'
|
| 589 |
* 'Other' key is only for 'htmLawedDef'.
|
| 590 |
*/
|
| 591 |
function _htmLawed_store_setting($form_id = NULL, &$form) { // Many Drupal 6 diff
|
| 592 |
// Content-specific values
|
| 593 |
$content_types = node_get_types('names');
|
| 594 |
foreach($content_types as $k=>$v) {
|
| 595 |
foreach(array('Body', 'Comment', 'RSS') as $for) {
|
| 596 |
$val[$for] = array('default'=>$form['values']['htmLawed_'. $k. '_'. $for. '_default'], 'show'=>$form['values']['htmLawed_'. $k. '_'. $for. '_show'], 'config'=>$form['values']['htmLawed_'. $k. '_'. $for. '_config'], 'spec'=>$form['values']['htmLawed_'. $k. '_'. $for. '_spec'], 'help'=>$form['values']['htmLawed_'. $k. '_'. $for. '_help']);
|
| 597 |
unset($form['values']['htmLawed_'. $k. '_'. $for. '_default'], $form['values']['htmLawed_'. $k. '_'. $for. '_show'], $form['values']['htmLawed_'. $k. '_'. $for. '_config'], $form['values']['htmLawed_'. $k. '_'. $for. '_spec'], $form['values']['htmLawed_'. $k. '_'. $for. '_help']);
|
| 598 |
if($for != 'RSS') {
|
| 599 |
$val[$for]['save'] = $form['values']['htmLawed_'. $k. '_'. $for. '_save'];
|
| 600 |
unset($form['values']['htmLawed_'. $k. '_'. $for. '_save']);
|
| 601 |
}
|
| 602 |
}
|
| 603 |
$setting[$k] = $val;
|
| 604 |
}
|
| 605 |
|
| 606 |
// Default values
|
| 607 |
foreach(array('Body', 'Comment', 'Other', 'RSS') as $for) {
|
| 608 |
$def[$for] = array('config'=>$form['values']['htmLawed_htmLawedDef_'. $for. '_config'], 'spec'=>$form['values']['htmLawed_htmLawedDef_'. $for. '_spec'], 'help'=>$form['values']['htmLawed_htmLawedDef_'. $for. '_help']);
|
| 609 |
unset($form['values']['htmLawed_htmLawedDef_'. $for. '_config'], $form['values']['htmLawed_htmLawedDef_'. $for. '_spec'], $form['values']['htmLawed_htmLawedDef_'. $for. '_help']);
|
| 610 |
if($for == 'Other') {
|
| 611 |
$def[$for]['show'] = $form['values']['htmLawed_htmLawedDef_'. $for. '_show'];
|
| 612 |
unset($form['values']['htmLawed_htmLawedDef_'. $for. '_show']);
|
| 613 |
}
|
| 614 |
}
|
| 615 |
$setting['htmLawedDef'] = $def;
|
| 616 |
|
| 617 |
variable_set('htmLawed_format_'. $form['values']['format'], $setting);
|
| 618 |
}
|