[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/token/ -> token.module (source)

   1  <?php
   2  
   3  /**
   4   * @file
   5   * The Token API module.
   6   *
   7   * The Token module provides an API for providing tokens to other modules.
   8   * Tokens are small bits of text that can be placed into larger documents
   9   * via simple placeholders, like %site-name or [user].
  10   *
  11   * @ingroup token
  12   */
  13  
  14  /**
  15   * The default token prefix string.
  16   */
  17  define('TOKEN_PREFIX', '[');
  18  
  19  /**
  20   * The default token suffix string.
  21   */
  22  define('TOKEN_SUFFIX', ']');
  23  
  24  /**
  25   * Implements hook_help().
  26   */
  27  function token_help($path, $arg) {
  28    if ($path == 'admin/help#token') {
  29      $output = '<dl>';
  30      $output .= '<dt>' . t('List of the currently available tokens on this site') . '</dt>';
  31      $output .= '<dd>' . theme('token_tree', 'all', TRUE, FALSE) . '</dd>';
  32      $output .= '</dl>';
  33      return $output;
  34    }
  35  }
  36  
  37  /**
  38   * Return an array of the core modules supported by token.module.
  39   */
  40  function _token_core_supported_modules() {
  41    return array('node', 'user', 'taxonomy', 'comment', 'menu', 'book');
  42  }
  43  
  44  /**
  45   * Implements hook_menu().
  46   */
  47  function token_menu() {
  48    $items = array();
  49  
  50    // Devel token pages.
  51    if (module_exists('devel')) {
  52      $items['node/%node/devel/token'] = array(
  53        'title' => 'Tokens',
  54        'page callback' => 'token_devel_token_object',
  55        'page arguments' => array('node', 1),
  56        'access arguments' => array('access devel information'),
  57        'type' => MENU_LOCAL_TASK,
  58        'file' => 'token.pages.inc',
  59        'weight' => 5,
  60      );
  61      $items['user/%user/devel/token'] = array(
  62        'title' => 'Tokens',
  63        'page callback' => 'token_devel_token_object',
  64        'page arguments' => array('user', 1),
  65        'access arguments' => array('access devel information'),
  66        'type' => MENU_LOCAL_TASK,
  67        'file' => 'token.pages.inc',
  68        'weight' => 5,
  69      );
  70    }
  71  
  72    return $items;
  73  }
  74  
  75  /**
  76   * Implements hook_theme().
  77   */
  78  function token_theme() {
  79    return array(
  80      'token_help' => array(
  81        'arguments' => array('type' => 'all', 'prefix' => TOKEN_PREFIX, 'suffix' => TOKEN_SUFFIX),
  82        'file' => 'token.pages.inc',
  83      ),
  84      'token_tree' => array(
  85        'arguments' => array('token_types' => array(), 'global_types' => TRUE , 'click_insert' => TRUE),
  86        'file' => 'token.pages.inc',
  87      ),
  88    );
  89  }
  90  
  91  /**
  92   * Implements hook_token_values().
  93   */
  94  function token_token_values($type, $object = NULL) {
  95    global $user;
  96    $values = array();
  97  
  98    switch ($type) {
  99      case 'global':
 100        // Current user tokens.
 101        $values['user-name']    = $user->uid ? $user->name : variable_get('anonymous', t('Anonymous'));
 102        $values['user-id']      = $user->uid ? $user->uid : 0;
 103        $values['user-mail']    = $user->uid ? $user->mail : '';
 104  
 105        // Site information tokens.
 106        $values['site-url']     = url('<front>', array('absolute' => TRUE));
 107        $values['site-name']    = check_plain(variable_get('site_name', t('Drupal')));
 108        $values['site-slogan']  = check_plain(variable_get('site_slogan', ''));
 109        $values['site-mission'] = filter_xss_admin(variable_get('site_mission', ''));
 110        $values['site-mail']    = variable_get('site_mail', '');
 111        $values += token_get_date_token_values(NULL, 'site-date-');
 112  
 113        // Current page tokens.
 114        $values['current-page-title'] = drupal_get_title();
 115        $alias = drupal_get_path_alias($_GET['q']);
 116        $values['current-page-path-raw'] = $alias;
 117        $values['current-page-path'] = check_plain($alias);
 118        $values['current-page-url'] = url($_GET['q'], array('absolute' => TRUE));
 119  
 120        $page = isset($_GET['page']) ? $_GET['page'] : '';
 121        $pager_page_array = explode(',', $page);
 122        $page = $pager_page_array[0];
 123        $values['current-page-number'] = (int) $page + 1;
 124  
 125        // Backwards compatability for renamed tokens.
 126        $values['site-date'] = $values['site-date-small'];
 127        $values['page-number'] = $values['current-page-number'];
 128  
 129        break;
 130    }
 131    return $values;
 132  }
 133  
 134  /**
 135   * Implements hook_token_list().
 136   */
 137  function token_token_list($type = 'all') {
 138    $tokens = array();
 139  
 140    if ($type == 'global' || $type == 'all') {
 141      // Current user tokens.
 142      $tokens['global']['user-name']    = t('The name of the currently logged in user.');
 143      $tokens['global']['user-id']      = t('The user ID of the currently logged in user.');
 144      $tokens['global']['user-mail']    = t('The email address of the currently logged in user.');
 145  
 146      // Site information tokens.
 147      $tokens['global']['site-url']     = t("The URL of the site's front page.");
 148      $tokens['global']['site-name']    = t('The name of the site.');
 149      $tokens['global']['site-slogan']  = t('The slogan of the site.');
 150      $tokens['global']['site-mission'] = t("The optional 'mission' of the site.");
 151      $tokens['global']['site-mail']    = t('The administrative email address for the site.');
 152      $tokens['global'] += token_get_date_token_info(t('The current'), 'site-date-');
 153  
 154      // Current page tokens.
 155      $tokens['global']['current-page-title']    = t('The title of the current page.');
 156      $tokens['global']['current-page-path']     = t('The URL alias of the current page.');
 157      $tokens['global']['current-page-path-raw'] = t('The URL alias of the current page.');
 158      $tokens['global']['current-page-url']      = t('The URL of the current page.');
 159      $tokens['global']['current-page-number']   = t('The page number of the current page when viewing paged lists.');
 160    }
 161  
 162    return $tokens;
 163  }
 164  
 165  /**
 166   * General function to include the files that token relies on for the real work.
 167   */
 168  function token_include() {
 169    static $run = FALSE;
 170  
 171    if (!$run) {
 172      $run = TRUE;
 173      $modules_enabled = array_keys(module_list());
 174      $modules = array_intersect(_token_core_supported_modules(), $modules_enabled);
 175      foreach ($modules as $module) {
 176        module_load_include('inc', 'token', "token_$module");
 177      }
 178    }
 179  }
 180  
 181  /**
 182   * Replace all tokens in a given string with appropriate values.
 183   *
 184   * @param $text
 185   *   A string potentially containing replaceable tokens.
 186   * @param $type
 187   *   (optional) A flag indicating the class of substitution tokens to use. If
 188   *   an object is passed in the second param, 'type' should contain the
 189   *   object's type. For example, 'node', 'comment', or 'user'. If no type is
 190   *   specified, only 'global' site-wide substitution tokens are built.
 191   * @param $object
 192   *   (optional) An object to use for building substitution values (e.g. a node
 193   *   comment, or user object).
 194   * @param $leading
 195   *   (optional) Character(s) to prepend to the token key before searching for
 196   *   matches. Defaults to TOKEN_PREFIX.
 197   * @param $trailing
 198   *   (optional) Character(s) to append to the token key before searching for
 199   *   matches. Defaults to TOKEN_SUFFIX.
 200   * @param $options
 201   *   (optional) A keyed array of settings and flags to control the token
 202   *   generation and replacement process. Supported options are:
 203   *   - clear: A boolean flag indicating that tokens should be removed from the
 204   *     final text if no replacement value can be generated.
 205   * @param $flush
 206   *   (optional) A flag indicating whether or not to flush the token cache.
 207   *   Useful for processes that need to slog through huge numbers of tokens
 208   *   in a single execution cycle. Flushing it will keep them from burning
 209   *   through memory. Defaults to FALSE.
 210   *
 211   * @return
 212   *   Text with tokens replaced.
 213   */
 214  function token_replace($text, $type = 'global', $object = NULL, $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX, $options = array(), $flush = FALSE) {
 215    return token_replace_multiple($text, array($type => $object), $leading, $trailing, $options, $flush);
 216  }
 217  
 218  /**
 219   * Replace all tokens in a given string with appropriate values.
 220   *
 221   * Contrary to token_replace() this function supports replacing multiple types.
 222   *
 223   * @param $text
 224   *   A string potentially containing replaceable tokens.
 225   * @param $types
 226   *   (optional) An array of substitution classes and optional objects. The key
 227   *   is a flag indicating the class of substitution tokens to use. If an object
 228   *   is passed as value, the key should contain the object's type. For example,
 229   *   'node', 'comment', or 'user'. The object will be used for building
 230   *   substitution values. If no type is specified, only 'global' site-wide
 231   *   substitution tokens are built.
 232   * @param $leading
 233   *   (optional) Character(s) to prepend to the token key before searching for
 234   *   matches. Defaults to TOKEN_PREFIX.
 235   * @param $trailing
 236   *   (optional) Character(s) to append to the token key before searching for
 237   *   matches. Defaults to TOKEN_SUFFIX.
 238   * @param $options
 239   *   (optional) A keyed array of settings and flags to control the token
 240   *   generation and replacement process. Supported options are:
 241   *   - clear: A boolean flag indicating that tokens should be removed from the
 242   *     final text if no replacement value can be generated.
 243   * @param $flush
 244   *   (optional) A flag indicating whether or not to flush the token cache.
 245   *   Useful for processes that need to slog through huge numbers of tokens
 246   *   in a single execution cycle. Flushing it will keep them from burning
 247   *   through memory. Defaults to FALSE.
 248   *
 249   * @return
 250   *   Text with tokens replaced.
 251   */
 252  function token_replace_multiple($text, $types = array('global' => NULL), $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX, $options = array(), $flush = FALSE) {
 253    $full = new stdClass();
 254    $full->tokens = $full->values = array();
 255  
 256    // Allow global token replacement by default.
 257    if (empty($types) || !is_array($types)) {
 258      $types = array('global' => NULL);
 259    }
 260  
 261    foreach ($types as $type => $object) {
 262      $temp = token_get_values($type, $object, $flush, $options);
 263      $full->tokens = array_merge($full->tokens, $temp->tokens);
 264      $full->values = array_merge($full->values, $temp->values);
 265    }
 266  
 267    // Support clearing out tokens that would not be replaced.
 268    if (!empty($options['clear'])) {
 269      foreach (token_scan($text) as $token) {
 270        if (!in_array($token, $full->tokens)) {
 271          $full->tokens[] = $token;
 272          $full->values[] = '';
 273        }
 274      }
 275    }
 276  
 277    $tokens = token_prepare_tokens($full->tokens, $leading, $trailing);
 278    return str_replace($tokens, $full->values, $text);
 279  }
 280  
 281  /**
 282   * Return a list of valid substitution tokens and their values for
 283   * the specified type.
 284   *
 285   * @param $type
 286   *   (optional) A flag indicating the class of substitution tokens to use. If an
 287   *   object is passed in the second param, 'type' should contain the
 288   *   object's type. For example, 'node', 'comment', or 'user'. If no
 289   *   type is specified, only 'global' site-wide substitution tokens are
 290   *   built.
 291   * @param $object
 292   *   (optional) An object to use for building substitution values (e.g. a node
 293   *   comment, or user object).
 294   * @param $flush
 295   *   (optional) A flag indicating whether or not to flush the token cache.
 296   *   Useful for processes that need to slog through huge numbers of tokens
 297   *   in a single execution cycle. Flushing it will keep them from burning
 298   *   through memory. Defaults to FALSE.
 299   * @param $options
 300   *   (optional) A keyed array of settings and flags to control the token
 301   *   generation process.
 302   *
 303   * @return
 304   *   An object with two properties:
 305   *   - tokens: All the possible tokens names generated.
 306   *   - values: The corresponding values for the tokens.
 307   *
 308   * Note that before performing actual token replacement that the token names
 309   * should be run through token_prepare_tokens().
 310   */
 311  function token_get_values($type = 'global', $object = NULL, $flush = FALSE, $options = array()) {
 312    static $tokens;
 313    static $running;
 314  
 315    // Flush the static token cache. Useful for processes that need to slog through
 316    // huge numbers of tokens in a single execution cycle. Flushing it will keep
 317    // them from burning through memory.
 318    if ($flush || !isset($tokens)) {
 319      $tokens = array();
 320    }
 321  
 322    // Since objects in PHP5 are always passed by reference, we ensure we're
 323    // working on a copy of the object.
 324    if (is_object($object)) {
 325      $object = drupal_clone($object);
 326    }
 327  
 328    // Simple recursion check. This is to avoid content_view()'s potential
 329    // for endless looping when a filter uses tokens, which load the content
 330    // view, which calls the filter, which uses tokens, which...
 331    if ($running) {
 332      // We'll allow things to get two levels deep, but bail out after that
 333      // without performing any substitutions.
 334      $result = new stdClass();
 335      $result->tokens = array();
 336      $result->values = array();
 337      return $result;
 338    }
 339  
 340    $running = TRUE;
 341  
 342    token_include();
 343  
 344    $id = _token_get_id($type, $object);
 345    if ($id && isset($tokens[$type][$id])) {
 346      $tmp_tokens = $tokens[$type][$id];
 347    }
 348    else {
 349      $tmp_tokens = module_invoke_all('token_values', $type, $object, $options);
 350      $tokens[$type][$id] = $tmp_tokens;
 351    }
 352  
 353    // Special-case global tokens, as we always want to be able to process
 354    // those substitutions.
 355    if (!isset($tokens['global']['default'])) {
 356      $tokens['global']['default'] = module_invoke_all('token_values', 'global');
 357    }
 358  
 359    $all = array_merge($tokens['global']['default'], $tokens[$type][$id]);
 360  
 361    $result = new stdClass();
 362    $result->tokens = array_keys($all);
 363    $result->values = array_values($all);
 364  
 365    $running = FALSE;
 366  
 367    return $result;
 368  }
 369  
 370  /**
 371   * A helper function that retrieves all currently exposed tokens,
 372   * and merges them recursively. This is only necessary when building
 373   * the token listing -- during actual value replacement, only tokens
 374   * in a particular domain are requested and a normal array_marge() is
 375   * sufficient.
 376   *
 377   * @param $types
 378   *   A flag indicating the class of substitution tokens to use. If an
 379   *   object is passed in the second param, 'types' should contain the
 380   *   object's type. For example, 'node', 'comment', or 'user'. 'types'
 381   *   may also be an array of types of the form array('node','user'). If no
 382   *   type is specified, only 'global' site-wide substitution tokens are
 383   *   built.
 384   *
 385   * @return
 386   *   The array of usable tokens and their descriptions, organized by
 387   *   token type.
 388   */
 389  function token_get_list($types = 'all') {
 390    token_include();
 391    $return = array();
 392    settype($types, 'array');
 393    foreach (module_implements('token_list') as $module) {
 394      foreach ($types as $type) {
 395        $module_token_list = module_invoke($module, 'token_list', $type);
 396        if (isset($module_token_list) && is_array($module_token_list)) {
 397          foreach ($module_token_list as $category => $tokens) {
 398            foreach ($tokens as $token => $title) {
 399              // Automatically append a raw token warning.
 400              if (substr($token, -4) === '-raw' && strpos($title, t('raw user input')) === FALSE && strpos($title, t('UNIX timestamp format')) === FALSE) {
 401                $title .= ' <em>' . t('Warning: Token value contains raw user input.') . '</em>';
 402              }
 403              $return[$category][$token] = $title;
 404            }
 405          }
 406        }
 407      }
 408    }
 409    // Sort the tokens by name.
 410    foreach (array_keys($return) as $category) {
 411      ksort($return[$category]);
 412    }
 413    return $return;
 414  }
 415  
 416  /**
 417   * A helper function to prepare raw tokens for replacement.
 418   *
 419   * @param $tokens
 420   *   The array of tokens names with no delimiting characters.
 421   * @param $leading
 422   *   String to prepend to the token. Default is TOKEN_PREFIX.
 423   * @param $trailing
 424   *   String to append to the token. Default is TOKEN_SUFFIX.
 425   *
 426   * @return
 427   *   An array of the formatted tokens.
 428   */
 429  function token_prepare_tokens($tokens = array(), $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX) {
 430    foreach ($tokens as $key => $value) {
 431      $tokens[$key] = $leading . $value . $trailing;
 432    }
 433    return $tokens;
 434  }
 435  
 436  /**
 437   * A helper function to return an object's ID for use in static caching.
 438   */
 439  function _token_get_id($type = 'global', $object = NULL) {
 440    if (!isset($object)) {
 441      return "default";
 442    }
 443    switch ($type) {
 444      case 'node':
 445        return isset($object->nid) ? $object->nid : 0;
 446      case 'comment':
 447        return isset($object->cid) ? $object->cid : 0;
 448      case 'user':
 449        return isset($object->uid) ? $object->uid : 0;
 450      case 'taxonomy':
 451        return isset($object->tid) ? $object->tid : 0;
 452      default:
 453        return crc32(serialize($object));
 454    }
 455  }
 456  
 457  /**
 458   * Build a list of common date tokens for use in hook_token_list().
 459   *
 460   * @param $description
 461   */
 462  function token_get_date_token_info($description, $token_prefix = '') {
 463    $time = time();
 464    $tokens[$token_prefix . 'small']  = t("!description date in 'small' format. (%date)", array('!description' => $description, '%date' => format_date($time, 'small')));
 465    $tokens[$token_prefix . 'yyyy']   = t("!description year (four digit)", array('!description' => $description));
 466    $tokens[$token_prefix . 'yy']     = t("!description year (two digit)", array('!description' => $description));
 467    $tokens[$token_prefix . 'month']  = t("!description month (full word)", array('!description' => $description));
 468    $tokens[$token_prefix . 'mon']    = t("!description month (abbreviated)", array('!description' => $description));
 469    $tokens[$token_prefix . 'mm']     = t("!description month (two digits with leading zeros)", array('!description' => $description));
 470    $tokens[$token_prefix . 'm']      = t("!description month (one or two digits without leading zeros)", array('!description' => $description));
 471    $tokens[$token_prefix . 'ww']     = t("!description week (two digits with leading zeros)", array('!description' => $description));
 472    if (version_compare(PHP_VERSION, '5.1.0', '>=')) {
 473      $tokens[$token_prefix . 'date'] = t("!description date (numeric representation of the day of the week)", array('!description' => $description));
 474    }
 475    $tokens[$token_prefix . 'day']    = t("!description day (full word)", array('!description' => $description));
 476    $tokens[$token_prefix . 'ddd']    = t("!description day (abbreviation)", array('!description' => $description));
 477    $tokens[$token_prefix . 'dd']     = t("!description day (two digits with leading zeros)", array('!description' => $description));
 478    $tokens[$token_prefix . 'd']      = t("!description day (one or two digits without leading zeros)", array('!description' => $description));
 479    $tokens[$token_prefix . 'raw']    = t("!description in UNIX timestamp format (%date)", array('!description' => $description, '%date' => $time));
 480    $tokens[$token_prefix . 'since']  = t("!description in 'time-since' format. (%date)", array('!description' => $description, '%date' => format_interval($time - 360, 2)));
 481    return $tokens;
 482  }
 483  
 484  /**
 485   * Build a list of common date tokens for use in hook_token_values().
 486   */
 487  function token_get_date_token_values($timestamp = NULL, $token_prefix = '', $langcode = NULL) {
 488    static $formats;
 489  
 490    if (!isset($formats)) {
 491      $formats = array();
 492      $formats['small'] = variable_get('date_format_short', 'm/d/Y - H:i');
 493      $formats['yyyy']  = 'Y';
 494      $formats['yy']    = 'y';
 495      $formats['month'] = 'F';
 496      $formats['mon']   = 'M';
 497      $formats['mm']    = 'm';
 498      $formats['m']     = 'n';
 499      $formats['ww']    = 'W';
 500      if (version_compare(PHP_VERSION, '5.1.0', '>=')) {
 501        $formats['date'] = 'N';
 502      }
 503      $formats['day']   = 'l';
 504      $formats['ddd']   = 'D';
 505      $formats['dd']    = 'd';
 506      $formats['d']     = 'j';
 507    }
 508  
 509    $time = time();
 510    if (!isset($timestamp)) {
 511      $timestamp = $time;
 512    }
 513  
 514    $tokens = array();
 515    foreach ($formats as $token => $format) {
 516      $tokens[$token_prefix . $token] = token_format_date($timestamp, 'custom', $format, NULL, $langcode);
 517    }
 518    $tokens[$token_prefix . 'raw'] = $timestamp;
 519    $tokens[$token_prefix . 'since'] = format_interval($time - $timestamp, 2, $langcode);
 520  
 521    return $tokens;
 522  }
 523  
 524  /**
 525   * A copy of format_date() that supports the 'N' date format character.
 526   *
 527   * @see format_date()
 528   */
 529  function token_format_date($timestamp, $type = 'medium', $format = '', $timezone = NULL, $langcode = NULL) {
 530    global $user;
 531    static $timezones = array();
 532  
 533    // Statically cache each user's timezone so it doesn't need to be re-fetched
 534    // ever call.
 535    if (!isset($timezones[$user->uid])) {
 536      if (!empty($user->uid) && variable_get('configurable_timezones', 1) && strlen($user->timezone)) {
 537        $timezones[$user->uid] = $user->timezone;
 538      }
 539      else {
 540        $timezones[$user->uid] = variable_get('date_default_timezone', 0);
 541      }
 542    }
 543  
 544    $timestamp += $timezones[$user->uid];
 545  
 546    switch ($type) {
 547      case 'custom':
 548        // No change to format.
 549        break;
 550      case 'small':
 551        $format = variable_get('date_format_short', 'm/d/Y - H:i');
 552        break;
 553      case 'large':
 554        $format = variable_get('date_format_long', 'l, F j, Y - H:i');
 555        break;
 556      case 'medium':
 557      default:
 558        $format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
 559    }
 560  
 561    $max = strlen($format);
 562    $date = '';
 563    for ($i = 0; $i < $max; $i++) {
 564      $c = $format[$i];
 565      if (strpos('AaDlM', $c) !== FALSE) {
 566        $date .= t(gmdate($c, $timestamp), array(), $langcode);
 567      }
 568      elseif ($c == 'F') {
 569        // Special treatment for long month names: May is both an abbreviation
 570        // and a full month name in English, but other languages have
 571        // different abbreviations.
 572        $date .= trim(t('!long-month-name ' . gmdate($c, $timestamp), array('!long-month-name' => ''), $langcode));
 573      }
 574      elseif (strpos('BdgGhHiIjLmnNsStTUwWYyz', $c) !== FALSE) {
 575        // This condition was modified to allow the 'N' date format character.
 576        $date .= gmdate($c, $timestamp);
 577      }
 578      elseif ($c == 'r') {
 579        $date .= token_format_date($timestamp - $timezone, 'custom', 'D, d M Y H:i:s O', $timezone, $langcode);
 580      }
 581      elseif ($c == 'O') {
 582        $date .= sprintf('%s%02d%02d', ($timezone < 0 ? '-' : '+'), abs($timezone / 3600), abs($timezone % 3600) / 60);
 583      }
 584      elseif ($c == 'Z') {
 585        $date .= $timezone;
 586      }
 587      elseif ($c == '\\') {
 588        $date .= $format[++$i];
 589      }
 590      else {
 591        $date .= $c;
 592      }
 593    }
 594  
 595    return $date;
 596  }
 597  
 598  /**
 599   * Validate an tokens in raw text based on possible contexts.
 600   *
 601   * @param $value
 602   *   A string with the raw text containing the raw tokens, or an array of
 603   *   tokens from token_scan().
 604   * @param $valid_types
 605   *   An array of token types to validage against.
 606   * @param $leading
 607   *   Character(s) to prepend to the token key before searching for
 608   *   matches. Defaults to TOKEN_PREFIX.
 609   * @param $trailing
 610   *   Character(s) to append to the token key before searching for
 611   *   matches. Defaults to TOKEN_SUFFIX.
 612   *
 613   * @return
 614   *   An array with the invalid tokens in their original raw forms.
 615   */
 616  function token_get_invalid_tokens_by_context($value, $valid_types = array(), $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX) {
 617    if (in_array('all', $valid_types)) {
 618      $valid_types = array('all');
 619    }
 620    else {
 621      // Add the token types that are always valid in global context.
 622      $valid_types[] = 'global';
 623    }
 624  
 625    $invalid_tokens = array();
 626    $valid_tokens = array();
 627    $value_tokens = is_string($value) ? token_scan($value, $leading, $trailing) : $value;
 628  
 629    foreach (token_get_list($valid_types) as $category => $tokens) {
 630      $valid_tokens += $tokens;
 631    }
 632  
 633    foreach ($value_tokens as $token) {
 634      if (isset($valid_tokens[$token])) {
 635        continue;
 636      }
 637      elseif (preg_match('/^(.*[_-])([^-_])+$/', $token, $matches)) {
 638        // Allow tokens that do not have a direct match to tokens listed in
 639        // hook_token_info() to be matched against a 'wildcard' token name.
 640        if (isset($valid_tokens[$matches[1] . '?'])) {
 641          // [token-name-?] wildcards.
 642          continue;
 643        }
 644        elseif (isset($valid_tokens[$matches[1] . '????'])) {
 645          // [token-name-????] wildcards.
 646          continue;
 647        }
 648        elseif (is_numeric($matches[2]) && isset($valid_tokens[$matches[1] . 'N'])) {
 649          // [token-name-N] wildcards if N is a numeric value.
 650          continue;
 651        }
 652      }
 653      $invalid_tokens[] = $token;
 654    }
 655  
 656    array_unique($invalid_tokens);
 657    $invalid_tokens = token_prepare_tokens($invalid_tokens, $leading, $trailing);
 658    return $invalid_tokens;
 659  }
 660  
 661  /**
 662   * Build a list of all token-like patterns that appear in the text.
 663   *
 664   * @param $text
 665   *   The text to be scanned for possible tokens.
 666   * @param $leading
 667   *   Character(s) to prepend to the token key before searching for
 668   *   matches. Defaults to TOKEN_PREFIX.
 669   * @param $trailing
 670   *   Character(s) to append to the token key before searching for
 671   *   matches. Defaults to TOKEN_SUFFIX.
 672   *
 673   * @return
 674   *   An array of discovered tokens.
 675   */
 676  function token_scan($text, $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX) {
 677    // Matches tokens with the following pattern: [$token]
 678    $leading = preg_quote($leading, '/');
 679    $trailing = preg_quote($trailing, '/');
 680    preg_match_all("/{$leading}([^\s]+?){$trailing}/", $text, $matches);
 681    return $matches[1];
 682  }
 683  
 684  /**
 685   * Validate a form element that should have tokens in it.
 686   *
 687   * Form elements that want to add this validation should have the #token_types
 688   * parameter defined.
 689   *
 690   * For example:
 691   * @code
 692   * $form['my_node_text_element'] = array(
 693   *   '#type' => 'textfield',
 694   *   '#title' => t('Some text to token-ize that has a node context.'),
 695   *   '#default_value' => 'The title of this node is [title].',
 696   *   '#element_validate' => array('token_element_validate'),
 697   *   '#token_types' => array('node'),
 698   *   '#min_tokens' => 1,
 699   *   '#max_tokens' => 10,
 700   * );
 701   * @endcode
 702   */
 703  function token_element_validate(&$element, &$form_state) {
 704    $value = isset($element['#value']) ? $element['#value'] : $element['#default_value'];
 705  
 706    if (!drupal_strlen($value)) {
 707      // Empty value needs no further validation since the element should depend
 708      // on using the '#required' FAPI property.
 709      return $element;
 710    }
 711  
 712    $tokens = token_scan($value);
 713    $title = empty($element['#title']) ? $element['#parents'][0] : $element['#title'];
 714  
 715    // Validate if an element must have a minimum number of tokens.
 716    if (isset($element['#min_tokens']) && count($tokens) < $element['#min_tokens']) {
 717      // @todo Change this error message to include the minimum number.
 718      $error = format_plural($element['#min_tokens'], 'The %element-title cannot contain fewer than one token.', 'The %element-title must contain at least @count tokens.', array('%element-title' => $title));
 719      form_error($element, $error);
 720    }
 721  
 722    // Validate if an element must have a maximum number of tokens.
 723    if (isset($element['#max_tokens']) && count($tokens) > $element['#max_tokens']) {
 724      // @todo Change this error message to include the maximum number.
 725      $error = format_plural($element['#max_tokens'], 'The %element-title must contain as most one token.', 'The %element-title must contain at most @count tokens.', array('%element-title' => $title));
 726      form_error($element, $error);
 727    }
 728  
 729    // Check if the field defines specific token types.
 730    if (!empty($element['#token_types'])) {
 731      $invalid_tokens = token_get_invalid_tokens_by_context($tokens, $element['#token_types']);
 732      if ($invalid_tokens) {
 733        form_error($element, t('The %element-title is using the following invalid tokens: @invalid-tokens.', array('%element-title' => $title, '@invalid-tokens' => implode(', ', $invalid_tokens))));
 734      }
 735    }
 736  
 737    return $element;
 738  }
 739  
 740  /**
 741   * Deprecated. Use token_element_validate() instead.
 742   */
 743  function token_element_validate_token_context(&$element, &$form_state) {
 744    return token_element_validate($element, $form_state);
 745  }
 746  
 747  /**
 748   * Find tokens that have been declared twice by different modules.
 749   */
 750  function token_find_duplicate_tokens() {
 751    token_include();
 752    $all_tokens = array();
 753  
 754    foreach (module_implements('token_list') as $module) {
 755      $module_token_list = module_invoke($module, 'token_list', 'all');
 756      if (!isset($module_token_list) || !is_array($module_token_list)) {
 757        // Skip modules that do not return an array as that is a valid return
 758        // value.
 759        continue;
 760      }
 761      if (in_array($module, _token_core_supported_modules())) {
 762        $module = 'token';
 763      }
 764      foreach ($module_token_list as $type => $tokens) {
 765        foreach (array_keys($tokens) as $token) {
 766          $all_tokens[$type . ':' . $token][] = $module;
 767        }
 768      }
 769    }
 770  
 771    foreach ($all_tokens as $token => $modules) {
 772      if (count($modules) < 2) {
 773        unset($all_tokens[$token]);
 774      }
 775    }
 776  
 777    return $all_tokens;
 778  }
 779  
 780  /**
 781   * Get a translated menu link by its mlid, without access checking.
 782   *
 783   * This function is a copy of menu_link_load() but with its own cache and a
 784   * simpler query to load the link. This also skips normal menu link access
 785   * checking by using _token_menu_link_translate().
 786   *
 787   * @param $mlid
 788   *   The mlid of the menu item.
 789   *
 790   * @return
 791   *   A menu link translated for rendering.
 792   *
 793   * @see menu_link_load()
 794   * @see _token_menu_link_translate()
 795   */
 796  function token_menu_link_load($mlid) {
 797    static $cache = array();
 798  
 799    if (!is_numeric($mlid)) {
 800      return FALSE;
 801    }
 802  
 803    if (!isset($cache[$mlid])) {
 804      $item = db_fetch_array(db_query("SELECT * FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = %d", $mlid));
 805      if (!empty($item)) {
 806        _token_menu_link_translate($item);
 807      }
 808      $cache[$mlid] = $item;
 809    }
 810  
 811    return $cache[$mlid];
 812  }
 813  
 814  /**
 815   * Get a translated book menu link by its mlid, without access checking.
 816   *
 817   * This function is a copy of book_link_load() but with its own cache and a
 818   * simpler query to load the link. This also skips normal menu link access
 819   * checking by using _token_menu_link_translate().
 820   *
 821   * @param $mlid
 822   *   The mlid of the book menu item.
 823   *
 824   * @return
 825   *   A book menu link translated for rendering.
 826   *
 827   * @see book_link_load()
 828   * @see _token_menu_link_translate()
 829   */
 830  function token_book_link_load($mlid) {
 831    static $cache = array();
 832  
 833    if (!is_numeric($mlid)) {
 834      return FALSE;
 835    }
 836  
 837    if (!isset($cache[$mlid])) {
 838      $item = db_fetch_array(db_query("SELECT * FROM {menu_links} ml INNER JOIN {book} b ON b.mlid = ml.mlid LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = %d", $mlid));
 839      if (!empty($item)) {
 840        _token_menu_link_translate($item);
 841      }
 842      $cache[$mlid] = $item;
 843    }
 844  
 845    return $cache[$mlid];
 846  }
 847  
 848  function _token_menu_link_translate(&$item) {
 849    $map = array();
 850  
 851    if (!is_array($item['options'])) {
 852      $item['options'] = unserialize($item['options']);
 853    }
 854  
 855    if ($item['external']) {
 856      $item['access'] = 1;
 857      $item['href'] = $item['link_path'];
 858      $item['title'] = $item['link_title'];
 859      $item['localized_options'] = $item['options'];
 860    }
 861    else {
 862      $map = explode('/', $item['link_path']);
 863      _menu_link_map_translate($map, $item['to_arg_functions']);
 864      $item['href'] = implode('/', $map);
 865  
 866      // Note - skip callbacks without real values for their arguments.
 867      if (strpos($item['href'], '%') !== FALSE) {
 868        $item['access'] = FALSE;
 869        return FALSE;
 870      }
 871  
 872      $item['access'] = TRUE;
 873      _menu_item_localize($item, $map, TRUE);
 874    }
 875  
 876    // Allow other customizations - e.g. adding a page-specific query string to the
 877    // options array. For performance reasons we only invoke this hook if the link
 878    // has the 'alter' flag set in the options array.
 879    if (!empty($item['options']['alter'])) {
 880      drupal_alter('translated_menu_link', $item, $map);
 881    }
 882  
 883    return $map;
 884  }
 885  
 886  /**
 887   * Find all ancestors of a given menu link ID.
 888   *
 889   * @param $mlid
 890   *   A menu link ID.
 891   *
 892   * @return
 893   *   An array of menu links from token_menu_link_load() with the root link
 894   *   first, and the menu link with ID $mlid last.
 895   */
 896  function token_menu_link_get_parents_all($mlid) {
 897    $parents = array();
 898  
 899    while (!empty($mlid)) {
 900      $link = token_menu_link_load($mlid);
 901      array_unshift($parents, $link);
 902      $mlid = $link['plid'];
 903    }
 904  
 905    return $parents;
 906  }
 907  
 908  /**
 909   * Deprecated. Use the raw return value of token_menu_link_get_parents_all() instead.
 910   */
 911  function _menu_titles($menu_link, $nid) {
 912    $titles = array();
 913    $parents = token_menu_link_get_parents_all($menu_link['mlid']);
 914    foreach ($parents as $mlid => $parent) {
 915      $titles[] = $parent['title'];
 916    }
 917    return $titles;
 918  }


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7