profanity.module in Profanity 7
Main {profanity} file.
File
profanity.moduleView source
<?php
/**
* @file
* Main {profanity} file.
*/
/**
* Implements hook_permission().
*/
function profanity_permission() {
return array(
'administer profanity' => array(
'title' => 'Administer profanity',
),
);
}
/**
* Implements hook_menu().
*/
function profanity_menu() {
$items = array();
$items['admin/config/content/profanity/settings'] = array(
'title' => 'Settings',
'description' => 'Configuration for the Profanity module.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'profanity_admin_settings',
),
'access arguments' => array(
'administer profanity',
),
'type' => MENU_LOCAL_ACTION,
);
return $items;
}
/**
* Implements of hook_ctools_plugin_directory().
*/
function profanity_ctools_plugin_directory($module, $type) {
if ($type == 'export_ui') {
return 'plugins/export_ui';
}
}
/**
* Implements of hook_ctools_plugin_api().
*/
function profanity_ctools_plugin_api($owner, $api) {
if ($owner == 'profanity' && $api == 'default_profanity_lists') {
return array(
'version' => 1,
);
}
}
/**
* Implements hook_default_profanity_list().
*
* Provide a default list.
*/
/*function profanity_default_profanity_list() {
$export = array();
$list = new stdClass();
$list->api_version = 1;
$list->name = 'my_default_list';
$list->title = 'My default list';
$list->description = 'Default profanity list';
$list->mydata = 'x';
$export['my_default_list'] = $list;
return $export;
}*/
/**
* Load a single list.
*
* @param string $pid
* The list identifier.
*/
function profanity_list_load($pid) {
ctools_include('export');
$result = ctools_export_load_object('profanity_list', 'names', array(
$pid,
));
if (isset($result[$pid])) {
return $result[$pid];
}
}
/**
* Export a profanity_list.
*
* @param object $obj
* The profanity object.
* @param string $indent
* An identifier.
*
* @return string
* The export definition.
*/
function profanity_list_export($obj, $indent = '') {
ctools_include('export');
$output = ctools_export_object('profanity_list', $obj, $indent);
return $output;
}
/**
* Implements hook_views_api().
*/
function profanity_views_api() {
return array(
'api' => '3.0',
);
}
/**
* Implements hook_filter_info().
*/
function profanity_filter_info() {
$filters = array();
$filters['profanity'] = array(
'title' => t('Profanity'),
'description' => t('Allows you to replace any occurances of profanity or specific words with either a character repeated to the same length as the original or a phrase.'),
'process callback' => '_profanity_filter',
'settings callback' => '_profanity_filter_settings',
'default settings' => array(
'lists' => array(),
),
);
return $filters;
}
/**
* Implements hook_token_info().
*/
function profanity_token_info() {
$info = array();
// Build up an array of lists so we can provide helpful description text.
$wordlists = profanity_get_lists_flat();
if (!empty($wordlists)) {
$lists = array();
foreach ($wordlists as $name => $label) {
$lists[] = check_plain("{$label} ({$name})");
}
$lists_replacement = t('Possible lists: !lists', array(
'!lists' => implode(', ', $lists),
));
}
else {
$lists_replacement = t("There aren't any word lists defined, you'll need to add at least one first before using this token.");
}
// Add in tokens for all entities which have a label.
foreach (entity_get_info() as $entity_type => $entity_info) {
if (empty($entity_info['entity keys']['label'])) {
continue;
}
// Taxonomy tokens use different type text, not the entity type name.
if ($entity_type === 'taxonomy_vocabulary') {
$entity_type = 'vocabulary';
}
elseif ($entity_type === 'taxonomy_term') {
$entity_type = 'term';
}
$title_property = $entity_info['entity keys']['label'];
$info['tokens'][$entity_type][$title_property . '-profanity'] = array(
'name' => t('@label - profanity filtered', array(
'@label' => ucfirst($title_property),
)),
'description' => t('The @label for this entity processed by a specified profanity word list. Use with the word list machine name. !replacements', array(
'@label' => $title_property,
'!replacements' => $lists_replacement,
)),
'dynamic' => TRUE,
);
}
// Add in current page token.
$info['tokens']['current-page']['title-profanity'] = array(
'name' => t('Title'),
'description' => t('The title of the current page profanity filtered. Use with the word list machine name. !replacements', array(
'!replacements' => $lists_replacement,
)),
'dynamic' => TRUE,
);
return $info;
}
/**
* Implements hook_tokens().
*/
function profanity_tokens($type, $tokens, array $data = array(), array $options = array()) {
$replacements = array();
$sanitize = !empty($options['sanitize']);
// Current page token.
if ($type == 'current-page') {
foreach ($tokens as $name => $original) {
if (strpos($name, 'title-profanity') === 0) {
$title = drupal_get_title();
$name_parts = explode(':', $name);
if (!empty($name_parts[1])) {
$page_title = profanity_list_execute($name_parts[1], $title);
$replacements[$original] = $sanitize ? $page_title : decode_entities($page_title);
}
}
}
}
// Entity label tokens.
$entity_info = entity_get_info();
// If we can't work out a label property, bail out.
if (empty($entity_info[$type]['entity keys']['label'])) {
return $replacements;
}
$title_property = $entity_info[$type]['entity keys']['label'];
if (!empty($data[$type]->{$title_property})) {
foreach ($tokens as $name => $original) {
if (strpos($name, $title_property . '-profanity') === 0) {
$name_parts = explode(':', $name);
if (!empty($name_parts[1])) {
$replacements[$original] = profanity_list_execute($name_parts[1], $data[$type]->{$title_property});
}
}
}
}
return $replacements;
}
/**
* Implements hook_entity_property_info_alter().
*/
function profanity_entity_property_info_alter(&$info) {
$lists = variable_get('profanity_supply_entity_properties_lists', array());
if (variable_get('profanity_supply_entity_properties', 0) && !empty($lists)) {
$entity_info = entity_get_info();
foreach ($entity_info as $entity_type => $entity) {
if (empty($entity['entity keys']['label'])) {
continue;
}
$title_property = $entity['entity keys']['label'];
$info[$entity_type]['properties']["profanity_{$title_property}"] = array(
'label' => t('@label profanity filtered', array(
'@label' => ucfirst($title_property),
)),
'description' => t('The @label property passed through profanity filters.', array(
'@label' => $title_property,
)),
'type' => 'text',
'computed' => TRUE,
'getter callback' => 'profanity_entity_property_getter',
);
}
}
}
/**
* Implements hook_entity_load().
*/
function profanity_entity_prepare_view($entities, $entity_type, $langcode) {
// If title filtering is enabled check the type.
if (variable_get('profanity_protect_the_titles', 0) && in_array($entity_type, variable_get('profanity_title_entities', array()), TRUE)) {
$entity_info = entity_get_info();
foreach ($entities as $entity_id => $entity) {
foreach (variable_get('profanity_title_lists', array()) as $list_name) {
if (empty($entity_info[$entity_type]['entity keys']['label'])) {
break;
}
$title_property = $entity_info[$entity_type]['entity keys']['label'];
$entity->{'original_' . $title_property} = $entity->{$title_property};
$entity->{$title_property} = profanity_list_execute($list_name, $entity->{$title_property});
}
}
}
}
/**
* Function to return a flat list array of machine name indexes and
* label values.
*/
function profanity_get_lists_flat() {
static $flat_lists;
ctools_include('export');
if (!isset($flat_lists)) {
$flat_lists = array();
$lists = ctools_export_load_object('profanity_list');
if (!empty($lists)) {
$options = array();
foreach ($lists as $list) {
$flat_lists[$list->name] = check_plain($list->title);
}
}
}
return $flat_lists;
}
/**
* Filter settings callback for profanity filter.
*/
function _profanity_filter_settings($form, $form_state, $filter, $format, $defaults) {
// Load lists.
$options = profanity_get_lists_flat();
$settings['lists'] = array(
'#title' => t('Lists to run'),
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => isset($filter->settings['lists']) ? $filter->settings['lists'] : $defaults['lists'],
'#description' => t('Select which lists will be applied to text.'),
);
return $settings;
}
function _profanity_filter($text, $filter, $format, $langcode, $cache, $cache_id) {
if (empty($filter->settings['lists'])) {
return $text;
}
// Run through each list and apply to the text.
foreach ($filter->settings['lists'] as $list_name) {
$text = profanity_list_execute($list_name, $text);
}
return $text;
}
/**
* Helper function for use in replacing or validating.
*/
function profanity_list_execute($list_name, $text, $return_text = TRUE) {
$list = profanity_list_load($list_name);
if (!$list) {
return $return_text ? $text : FALSE;
}
$words = trim($list->words, ',');
$words = explode(',', $words);
if (empty($words)) {
return $return_text ? $text : FALSE;
}
$count = 0;
// Match partials, for example the word "christ" would match in
// "christmas" and be potentially changed to "******mas".
if ($list->match_partial) {
// Character replacement.
if ($list->replacement_mode == 0) {
// This following method won out when tracking time to execute.
$replacements = profanity_list_get_replacements($list);
if ($list->case_sensitive) {
$text = str_replace($words, $replacements, $text, $count);
}
else {
$text = str_ireplace($words, $replacements, $text, $count);
}
}
elseif ($list->replacement_mode == 1) {
if ($list->case_sensitive) {
$text = str_replace($words, $list->replacement_phrase, $text, $count);
}
else {
$text = str_ireplace($words, $list->replacement_phrase, $text, $count);
}
}
}
else {
$wordlist = implode('|', array_map('preg_quote', $words));
$modifiers = $list->case_sensitive ? NULL : "/i";
// Character replacement.
if ($list->replacement_mode == 0) {
$replace = new ProfanityPregCallback($wordlist, $modifiers, $list->replacement_character);
$text = $replace
->execute($text);
$count = $replace
->get_count();
}
elseif ($list->replacement_mode == 1) {
$text = preg_replace("/\\b({$wordlist})\\b{$modifiers}", $list->replacement_phrase, $text, -1, $count);
}
}
$found = $count > 0;
return $return_text ? $text : $found;
}
/**
* Grab a list of replacements from cache or set the cache and return.
*/
function profanity_list_get_replacements($list) {
$replacements =& drupal_static(__FUNCTION__);
if (!isset($replacements[$list->name])) {
if ($cache = cache_get('profanity_list:' . $list->name)) {
$replacements[$list->name] = $cache->data;
}
else {
$replacements[$list->name] = array();
$words = trim($list->words, ',');
$words = explode(',', $words);
if (empty($words)) {
return array();
}
// Match partials.
if ($list->match_partial && $list->replacement_mode == 0) {
foreach ($words as $word) {
$replacements[$list->name][] = str_repeat($list->replacement_character, strlen(utf8_decode($word)));
}
}
cache_set('profanity_list:' . $list->name, $replacements[$list->name], 'cache');
}
}
return $replacements[$list->name];
}
/**
* Admin settings form callback.
*/
function profanity_admin_settings() {
$form = array();
$form['profanity_protect_the_titles'] = array(
'#type' => 'checkbox',
'#title' => t('Run profanity filters on Entity titles?'),
'#default_value' => variable_get('profanity_protect_the_titles', 0),
'#description' => t('Tick this to enable more options.'),
);
$form['titles'] = array(
'#type' => 'fieldset',
'#title' => t('Entity title settings'),
'#states' => array(
'visible' => array(
':input[id="edit-profanity-protect-the-titles"]' => array(
'checked' => TRUE,
),
),
),
);
$entity_options = array();
foreach (entity_get_info() as $entity_type => $entity_info) {
$entity_options[$entity_type] = filter_xss($entity_info['label']);
}
$form['titles']['profanity_title_entities'] = array(
'#type' => 'checkboxes',
'#title' => t('Which Entity types should have their titles processed?'),
'#options' => $entity_options,
'#default_value' => variable_get('profanity_title_entities', array()),
'#states' => array(
'required' => array(
':input[id="edit-profanity-protect-the-titles"]' => array(
'checked' => TRUE,
),
),
),
);
$form['titles']['profanity_title_lists'] = array(
'#type' => 'checkboxes',
'#title' => t('Which lists should be applied?'),
'#options' => profanity_get_lists_flat(),
'#default_value' => variable_get('profanity_title_lists', array()),
'#states' => array(
'required' => array(
':input[id="edit-profanity-protect-the-titles"]' => array(
'checked' => TRUE,
),
),
),
);
$form['profanity_supply_entity_properties'] = array(
'#type' => 'checkbox',
'#title' => t('Supply a profanity filtered title property for all entities'),
'#default_value' => variable_get('profanity_supply_entity_properties', 0),
);
$form['profanity_supply_entity_properties_fieldset'] = array(
'#type' => 'fieldset',
'#title' => t('User registration validation settings'),
'#states' => array(
'visible' => array(
':input[id="edit-profanity-supply-entity-properties"]' => array(
'checked' => TRUE,
),
),
),
);
$form['profanity_supply_entity_properties_fieldset']['profanity_supply_entity_properties_lists'] = array(
'#type' => 'checkboxes',
'#title' => t('Which lists should be applied?'),
'#options' => profanity_get_lists_flat(),
'#default_value' => variable_get('profanity_supply_entity_properties_lists', array()),
'#states' => array(
'required' => array(
':input[id="edit-profanity-supply-entity-properties"]' => array(
'checked' => TRUE,
),
),
),
);
$form['profanity_protect_user_reg'] = array(
'#type' => 'checkbox',
'#title' => t('Prevent users registering with a username that contains matches'),
'#default_value' => variable_get('profanity_protect_user_reg', 0),
'#description' => t("Tick this to choose which lists are run against the entered username. Users won't be able to register until they choose a username which doesn't contain a matched word."),
);
$form['user_reg'] = array(
'#type' => 'fieldset',
'#title' => t('User registration validation settings'),
'#states' => array(
'visible' => array(
':input[id="edit-profanity-protect-user-reg"]' => array(
'checked' => TRUE,
),
),
),
);
$form['user_reg']['profanity_protect_user_reg_lists'] = array(
'#type' => 'checkboxes',
'#title' => t('Which lists should be applied?'),
'#options' => profanity_get_lists_flat(),
'#default_value' => variable_get('profanity_protect_user_reg_lists', array()),
'#states' => array(
'required' => array(
':input[id="edit-profanity-protect-user-reg"]' => array(
'checked' => TRUE,
),
),
),
);
$form['user_reg']['profanity_protect_user_reg_message'] = array(
'#type' => 'textfield',
'#title' => t('Error message to display when matched words are found'),
'#default_value' => variable_get('profanity_protect_user_reg_message', "The username you've entered contains a word or words which aren't allowed."),
'#states' => array(
'required' => array(
':input[id="edit-profanity-protect-user-reg"]' => array(
'checked' => TRUE,
),
),
),
);
return system_settings_form($form);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function profanity_form_user_register_form_alter(&$form, $form_state, $form_id) {
if (!variable_get('profanity_protect_user_reg', 0)) {
return;
}
$form['#validate'][] = 'profanity_user_register_validate';
}
/**
* Form validation callback.
*/
function profanity_user_register_validate($form, &$form_state) {
if (variable_get('profanity_protect_user_reg', 0)) {
$matched = FALSE;
foreach (variable_get('profanity_protect_user_reg_lists', array()) as $list_name) {
if (profanity_list_execute($list_name, $form_state['values']['name'], FALSE) > 0) {
$matched = TRUE;
break;
}
}
if ($matched) {
form_set_error('name', variable_get('profanity_protect_user_reg_message', "The username you've entered contains a word or words which aren't allowed."));
}
}
}
class ProfanityPregCallback {
private $wordlist;
private $modifiers;
private $character;
private $count = 0;
public function __construct($wordlist, $modifiers, $character) {
$this->wordlist = $wordlist;
$this->modifiers = $modifiers;
$this->character = $character;
}
public function execute($text) {
return preg_replace_callback("/\\b(" . $this->wordlist . ")\\b" . $this->modifiers, array(
$this,
'match_replace',
), $text, -1);
}
public function match_replace($matches) {
$this->count = $this->count + 1;
return str_repeat($this->character, strlen(utf8_decode($matches[0])));
}
public function get_count() {
return $this->count;
}
}
/**
* Get the label property for a passed entity filtered for profanity.
*/
function profanity_entity_property_getter($data, array $options, $name, $type, $info) {
$entity_info = entity_get_info($type);
$title_property = $entity_info['entity keys']['label'];
$text = $data->{$title_property};
foreach (variable_get('profanity_supply_entity_properties_lists', array()) as $list_name) {
$text = profanity_list_execute($list_name, $text);
}
return $text;
}
/**
* Form submit handler.
*/
function profanity_crud_form_submit($form, &$form_state) {
// Carry out the standard submit process.
$form_state['object']
->edit_form_submit($form, $form_state);
// Clear any caches for this list.
cache_clear_all('profanity_list:' . $form_state['values']['name'], 'cache');
}
Functions
Classes
Name | Description |
---|---|
ProfanityPregCallback |