You are here

customfilter.module in Custom filter 6.2

Allow users to define custom filters.

File

customfilter.module
View source
<?php

/**
 * @file
 * Allow users to define custom filters.
 */
class CustomFilter implements ArrayAccess {
  const API_VERSION = '2.1';
  const API_MINIMUM_VERSION = '2.1';
  private static $instance;
  private $vars = array();
  public function __call($name, $arguments) {
    $flist = array();
    foreach (module_implements('customfilter_api') as $module) {
      $result = module_invoke($module, 'customfilter_api');
      $bool = array(
        isset($result) && is_array($result) && isset($result['version']) && version_compare($result['version'], self::API_MINIMUM_VERSION, '>') && version_compare($result['version'], self::API_VERSION, '<'),
      );
      if ($bool) {
        $result = module_invoke($module, 'customfilter_function_info');
        if (isset($result) && is_array($result)) {
          $flist = array_merge($flist, $result);
        }
      }
    }
    if (isset($flist[$name])) {
      $result = call_user_func_array($flist[$name]['function'], $arguments);
      if (isset($result)) {
        return $result;
      }
      else {
        return '';
      }
    }
    else {
      return '';
    }
  }
  private function __clone() {
  }
  private function __construct() {
  }
  public function __get($name) {
    return isset($this->vars[$name]) ? $this->vars[$name] : NULL;
  }
  public function __isset($name) {
    return isset($this->vars[$name]);
  }
  public function __set($name, $value) {
    $this->vars[$name] = $value;
  }
  public function __unset($name) {
    unset($this->vars[$name]);
  }
  public function offsetExists($offset) {
    return isset($this->vars[$offset]);
  }
  public function offsetGet($offset) {
    return isset($this->vars[$offset]) ? $this->vars[$offset] : NULL;
  }
  public function offsetSet($offset, $value) {
    $this->vars[$offset] = $value;
  }
  public function offsetUnset($offset) {
    unset($this->vars[$offset]);
  }
  public static function singleton() {
    if (!isset(self::$instance)) {
      self::$instance = new CustomFilter();
    }
    return self::$instance;
  }

}

/**
 * Implements hook_filter().
 */
function customfilter_filter($op, $delta = 0, $format = -1, $text = '') {
  $filters = _customfilter_get_filters();
  switch ($op) {
    case 'description':
      return _customfilter_get_filter_descriptions($delta, 'description');
    case 'list':
      $flist = array();
      foreach ($filters as $filter) {
        $flist[$filter['fid']] = _customfilter_get_filter_descriptions($filter['fid'], 'name');
      }
      return $flist;
    case 'no cache':
      return isset($filters[$delta]['cache']) ? !$filters[$delta]['cache'] : TRUE;
    case 'process':

      // If the text passed is an empty string, then return it immediately.
      if (empty($text)) {
        return '';
      }

      // If the filter cannot be loaded from the database, then return the text
      // passed to the function.
      if (!isset($filters[$delta])) {
        return $text;
      }
      $globals =& _customfilter_globals('push');
      $globals->text = $text;
      $rules = _customfilter_get_rules($delta);
      if (is_array($rules) && count($rules)) {

        // Prepare the stack used to save the parent rule.
        $globals->stack = array();
        foreach ($rules as $rule) {
          if ($rule['enabled']) {
            $globals->stack[] = $rule;
            $globals->text = preg_replace_callback($rule['pattern'], '_customfilter_process', $globals->text);
            array_pop($globals->stack);
          }
        }
      }
      $result = $globals->text;
      _customfilter_globals('pop');
      return $result;
    default:
      return $text;
  }
}

/**
 * Implements hook_filter_tips().
 */
function customfilter_filter_tips($delta, $format, $long = FALSE) {
  return _customfilter_get_filter_descriptions($delta, $long ? 'longtip' : 'shorttip');
}

/**
 * Implements hook_flush_caches().
 */
function customfilter_flush_caches() {
  return array(
    'cache_customfilter',
  );
}

/**
 * Implements hook_perm().
 */
function customfilter_perm() {
  return array(
    'administer customfilter',
  );
}

/**
 * Menu object load function.
 */
function customfilter_description_load($id) {
}

/**
 * Menu object load function.
 */
function customfilter_filter_load($id) {
}

/**
 * Menu object load function.
 */
function customfilter_rule_load($id) {
}
function customfilter_cache_clear($type, $fid = NULL) {
  switch ($type) {
    case 'all':
      cache_clear_all("*", 'cache_customfilter', TRUE);
      break;
    case 'filters':
      cache_clear_all('filters', 'cache_customfilter');
      cache_clear_all(isset($fid) ? "rules:{$fid}" : "rules", 'cache_customfilter', TRUE);
      break;
  }
}

/**
 * Delete a rule from the database table.
 * @param $rid
 *   The rule ID.
 */
function _customfilter_delete_rule($rid) {
  $result = db_query("SELECT * FROM {customfilter_rule} where prid = %d", $rid);
  while ($rule = db_fetch_object($result)) {
    _customfilter_delete_rule($rule->rid);
  }
  db_query("DELETE FROM {customfilter_rule} WHERE rid = %d", $rid);
}

/**
 * Get the list of filters.
 *
 * @return
 *   An array of filters.
 */
function _customfilter_get_filters() {
  if ($cache = cache_get('filters', 'cache_customfilter')) {
    $filters = $cache->data;
  }
  else {
    $filters = array();
    $result = db_query("SELECT * FROM {customfilter_filter}");
    while ($filter = db_fetch_array($result)) {
      $filters[$filter['fid']] = $filter;
    }
    cache_set('filters', $filters, 'cache_customfilter');
  }
  return $filters;
}
function _customfilter_get_filter_descriptions($fid = 0, $col = '') {
  global $language;
  if ($fid) {
    $obj = db_fetch_object(db_query_range("SELECT * FROM {customfilter_filter_description} WHERE fid = %d AND language in ('%s', '')", $fid, $language->language, 0, 1));
    if ($obj === FALSE) {
      $obj = new stdClass();
      $obj->fid = 0;
      $obj->language = '';
      $obj->id = '';
      $obj->name = '';
      $obj->description = '';
      $obj->longtip = '';
      $obj->shorttip = '';
    }
    return empty($col) ? $obj : (isset($obj->{$col}) ? $obj->{$col} : '');
  }
  else {
    $descriptions = array();
    $result = db_query("SELECT * FROM {customfilter_filter_description}");
    while ($description = db_fetch_object($result)) {
      $descriptions[$description->fdid] = $description;
    }
    return $descriptions;
  }
}

/**
 * Retrieve the replacement rules for a specific filter.
 *
 * @param $fid
 *   The filter ID.
 * @param $root
 *   The root rule.
 * @param $nocache
 *   If FALSE, the function will get the rules from the cache table, if there
 *   are any.
 *
 * @return
 *   An array of rules, which include any subrules.
 */
function _customfilter_get_rules($fid, $root = 0, $use_cache = TRUE) {
  if ($use_cache && ($cache = cache_get("rules:{$fid}:{$root}", 'cache_customfilter'))) {
    $rules = $cache->data;
  }
  else {
    $rules = array();
    $result = db_query("SELECT * FROM {customfilter_rule} WHERE fid = %d and prid = %d ORDER BY weight", $fid, $root);
    while ($rule = db_fetch_array($result)) {
      $rule['sub'] = _customfilter_get_rules($fid, $rule['rid'], FALSE);
      $rules[$rule['rid']] = $rule;
    }
    if ($use_cache) {
      cache_set("rules:{$fid}:{$root}", $rules, 'cache_customfilter');
    }
  }
  return $rules;
}

/**
 * Return an object that contains the global variables used during the
 * execution of a rule.
 */
function &_customfilter_globals($op = '') {
  $globals =& Vars::staticValue(__FUNCTION__, array());
  $index =& Vars::staticValue(__FUNCTION__ . '_index', 0);
  if ($op == 'push') {
    $globals[++$index] = new stdClass();
  }
  elseif ($op == 'pop' && $index) {
    unset($globals[$index--]);
  }
  return $globals[$index];
}
function _customfilter_process($matches) {
  $globals =& _customfilter_globals();
  $result = $matches[0];
  $rule = end($globals->stack);
  $code = $rule['code'];
  $pattern = $rule['pattern'];
  $replacement = $rule['replacement'];
  if (is_array($sub = $rule['sub']) && count($sub)) {
    foreach ($sub as $subrule) {
      if ($subrule['enabled']) {
        $globals->stack[] = $subrule;
        $substr =& $matches[$subrule['matches']];
        $substr = preg_replace_callback($subrule['pattern'], '_customfilter_process', $substr);
        array_pop($globals->stack);
      }
    }
    if ($code) {
      _customfilter_replace_callback($replacement, TRUE);
      $result = _customfilter_replace_callback($matches);
    }
    else {
      $result = $replacement;
      $rmatches = array();
      $reps = array();
      preg_match_all('/([^\\\\]|^)(\\$([0-9]{1,2}|\\{([0-9]{1,2})\\}))/', $replacement, $rmatches, PREG_OFFSET_CAPTURE);
      foreach ($rmatches[4] as $key => $val) {
        if ($val == '') {
          $index = $rmatches[3][$key][0];
        }
        else {
          $index = $rmatches[4][$key][0];
        }
        $offset = $rmatches[2][$key][1];
        $length = drupal_strlen($rmatches[2][$key][0]);
        $reps[] = array(
          'index' => $index,
          'offset' => $offset,
          'length' => $length,
        );
      }
      krsort($reps);
      foreach ($reps as $rep) {
        $result = substr_replace($result, $matches[$rep['index']], $rep['offset'], $rep['length']);
      }
    }
  }
  elseif ($code) {
    $code =& Vars::staticValue('_customfilter_replace_callback');
    $code = $replacement;
    $result = preg_replace_callback($pattern, '_customfilter_replace_callback', $result);
  }
  else {
    $result = preg_replace($pattern, $replacement, $result);
  }
  return $result;
}

/**
 * Helper function for preg_replace_callback().
 */
function _customfilter_replace_callback($matches) {
  $code =& Vars::staticValue(__FUNCTION__, '');
  if ($code) {
    $customfilter = CustomFilter::singleton();
    @eval($code);
  }
  return isset($result) ? $result : '';
}

Functions

Namesort descending Description
customfilter_cache_clear
customfilter_description_load Menu object load function.
customfilter_filter Implements hook_filter().
customfilter_filter_load Menu object load function.
customfilter_filter_tips Implements hook_filter_tips().
customfilter_flush_caches Implements hook_flush_caches().
customfilter_perm Implements hook_perm().
customfilter_rule_load Menu object load function.
_customfilter_delete_rule Delete a rule from the database table.
_customfilter_get_filters Get the list of filters.
_customfilter_get_filter_descriptions
_customfilter_get_rules Retrieve the replacement rules for a specific filter.
_customfilter_globals Return an object that contains the global variables used during the execution of a rule.
_customfilter_process
_customfilter_replace_callback Helper function for preg_replace_callback().

Classes

Namesort descending Description
CustomFilter @file Allow users to define custom filters.