| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: token.module,v 1.7.4.33 2010/08/10 03:33:32 davereid Exp $ 3 4 /** 5 * @file 6 * The Token API module. 7 * 8 * The Token module provides an API for providing tokens to other modules. 9 * Tokens are small bits of text that can be placed into larger documents 10 * via simple placeholders, like %site-name or [user]. 11 * 12 * @ingroup token 13 */ 14 15 /** 16 * The default token prefix string. 17 */ 18 define('TOKEN_PREFIX', '['); 19 20 /** 21 * The default token suffix string. 22 */ 23 define('TOKEN_SUFFIX', ']'); 24 25 /** 26 * Implements hook_help(). 27 */ 28 function token_help($path, $arg) { 29 if ($path == 'admin/help#token') { 30 $output = '<dl>'; 31 $output .= '<dt>' . t('List of the currently available tokens on this site') . '</dt>'; 32 $output .= '<dd>' . theme('token_tree', 'all', TRUE, FALSE) . '</dd>'; 33 $output .= '</dl>'; 34 return $output; 35 } 36 } 37 38 /** 39 * Implements hook_theme(). 40 */ 41 function token_theme() { 42 return array( 43 'token_help' => array( 44 'arguments' => array('type' => 'all', 'prefix' => TOKEN_PREFIX, 'suffix' => TOKEN_SUFFIX), 45 'file' => 'token.pages.inc', 46 ), 47 'token_tree' => array( 48 'arguments' => array('token_types' => array(), 'global_types' => TRUE , 'click_insert' => TRUE), 49 'file' => 'token.pages.inc', 50 ), 51 ); 52 } 53 54 /** 55 * Sample implementation of hook_token_values(). 56 * 57 * @param type 58 * A flag indicating the class of substitution tokens to use. If an 59 * object is passed in the second param, 'type' should contain the 60 * object's type. For example, 'node', 'comment', or 'user'. If your 61 * implementation of the hook inserts globally applicable tokens that 62 * do not depend on a particular object, it should only return values 63 * when $type is 'global'. 64 * @param object 65 * Optionally, the object to use for building substitution values. 66 * A node, comment, user, etc. 67 * @return 68 * A keyed array containing the substitution tokens and the substitution 69 * values for the passed-in type and object. 70 */ 71 function token_token_values($type, $object = NULL) { 72 global $user; 73 $values = array(); 74 75 switch ($type) { 76 case 'global': 77 // Current user tokens. 78 $values['user-name'] = $user->uid ? $user->name : variable_get('anonymous', t('Anonymous')); 79 $values['user-id'] = $user->uid ? $user->uid : 0; 80 $values['user-mail'] = $user->uid ? $user->mail : ''; 81 82 // Site information tokens. 83 $values['site-url'] = url('<front>', array('absolute' => TRUE)); 84 $values['site-name'] = check_plain(variable_get('site_name', t('Drupal'))); 85 $values['site-slogan'] = check_plain(variable_get('site_slogan', '')); 86 $values['site-mission'] = filter_xss_admin(variable_get('site_mission', '')); 87 $values['site-mail'] = variable_get('site_mail', ''); 88 $values += token_get_date_token_values(NULL, 'site-date-'); 89 $values['site-date'] = $values['site-date-small']; 90 91 // Current page tokens. 92 $values['current-page-title'] = drupal_get_title(); 93 $alias = drupal_get_path_alias($_GET['q']); 94 $values['current-page-path'] = $alias; 95 $values['current-page-path-raw'] = check_plain($alias); 96 $values['current-page-url'] = url($_GET['q'], array('absolute' => TRUE)); 97 98 $page = isset($_GET['page']) ? $_GET['page'] : ''; 99 $pager_page_array = explode(',', $page); 100 $page = $pager_page_array[0]; 101 $values['current-page-number'] = (int) $page + 1; 102 $values['page-number'] = $values['current-page-number']; 103 104 break; 105 } 106 return $values; 107 } 108 109 /** 110 * Sample implementation of hook_token_list(). Documents the individual 111 * tokens handled by your module. 112 * 113 * @param type 114 * A flag indicating the class of substitution tokens to return 115 * information on. If this is set to 'all', a complete list is being 116 * built and your module should return its full list, regardless of 117 * type. Global tokens should always be returned, regardless of the 118 * $type passed in. 119 * @return 120 * A keyed array listing the substitution tokens. Elements should be 121 * in the form of: $list[$type][$token] = $description 122 */ 123 function token_token_list($type = 'all') { 124 $tokens = array(); 125 126 if ($type == 'global' || $type == 'all') { 127 // Current user tokens. 128 $tokens['global']['user-name'] = t('The name of the currently logged in user.'); 129 $tokens['global']['user-id'] = t('The user ID of the currently logged in user.'); 130 $tokens['global']['user-mail'] = t('The email address of the currently logged in user.'); 131 132 // Site information tokens. 133 $tokens['global']['site-url'] = t("The URL of the site's front page."); 134 $tokens['global']['site-name'] = t('The name of the site.'); 135 $tokens['global']['site-slogan'] = t('The slogan of the site.'); 136 $tokens['global']['site-mission'] = t("The optional 'mission' of the site."); 137 $tokens['global']['site-mail'] = t('The administrative email address for the site.'); 138 $tokens['global'] += token_get_date_token_info(t('The current'), 'site-date-'); 139 140 // Current page tokens. 141 $tokens['global']['current-page-title'] = t('The title of the current page.'); 142 $tokens['global']['current-page-path'] = t('The URL alias of the current page.'); 143 $tokens['global']['current-page-path-raw'] = t('The URL alias of the current page.'); 144 $tokens['global']['current-page-url'] = t('The URL of the current page.'); 145 $tokens['global']['current-page-number'] = t('The page number of the current page when viewing paged lists.'); 146 } 147 148 return $tokens; 149 } 150 151 /** 152 * General function to include the files that token relies on for the real work. 153 */ 154 function token_include() { 155 static $run = FALSE; 156 157 if (!$run) { 158 $run = TRUE; 159 $modules_enabled = array_keys(module_list()); 160 $modules = array('node', 'user', 'taxonomy', 'comment'); 161 $modules = array_intersect($modules, $modules_enabled); 162 foreach ($modules as $module) { 163 module_load_include('inc', 'token', "token_$module"); 164 } 165 } 166 } 167 168 /** 169 * Return the value of $original, with all instances of placeholder 170 * tokens replaced by their proper values. To replace multiple types 171 * at once see token_replace_multiple(). 172 * 173 * @param original 174 * A string, or an array of strings, to perform token substitutions 175 * on. 176 * @param type 177 * A flag indicating the class of substitution tokens to use. If an 178 * object is passed in the second param, 'type' should contain the 179 * object's type. For example, 'node', 'comment', or 'user'. If no 180 * type is specified, only 'global' site-wide substitution tokens are 181 * built. 182 * @param object 183 * Optionally, the object to use for building substitution values. 184 * A node, comment, user, etc. 185 * @param leading 186 * Character(s) to prepend to the token key before searching for 187 * matches. Defaults to an open-bracket. 188 * @param trailing 189 * Character(s) to append to the token key before searching for 190 * matches. Defaults to a close-bracket. 191 * @param flush 192 * A flag indicating whether or not to flush the token cache. 193 * Useful for processes that need to slog through huge numbers 194 * of tokens in a single execution cycle. Flushing it will 195 * keep them from burning through memory. 196 * The default is FALSE. 197 * @return The modified version of $original, with all substitutions 198 * made. 199 */ 200 function token_replace($original, $type = 'global', $object = NULL, $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX, $options = array(), $flush = FALSE) { 201 $full = token_get_values($type, $object, $flush, $options); 202 return _token_replace_tokens($original, $full->tokens, $full->values, $leading, $trailing); 203 } 204 205 /** 206 * Return the value of $original, with all instances of placeholder 207 * tokens replaced by their proper values. Contrary to token_replace(), 208 * this function supports replacing multiple types. 209 * 210 * @param original 211 * A string, or an array of strings, to perform token substitutions 212 * on. 213 * @param types 214 * An array of substitution classes and optional objects. The key is 215 * a flag indicating the class of substitution tokens to use. 216 * If an object is passed as value, the key should contain the 217 * object's type. For example, 'node', 'comment', or 'user'. The 218 * object will be used for building substitution values. If no type 219 * is specified, only 'global' site-wide substitution tokens are built. 220 * @param leading 221 * Character(s) to prepend to the token key before searching for 222 * matches. Defaults to an open-bracket. 223 * @param trailing 224 * Character(s) to append to the token key before searching for 225 * matches. Defaults to a close-bracket. 226 * @param flush 227 * A flag indicating whether or not to flush the token cache. 228 * Useful for processes that need to slog through huge numbers 229 * of tokens in a single execution cycle. Flushing it will 230 * keep them from burning through memory. 231 * The default is FALSE. 232 * @return The modified version of $original, with all substitutions 233 * made. 234 */ 235 function token_replace_multiple($original, $types = array('global' => NULL), $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX, $options = array(), $flush = FALSE) { 236 $full = new stdClass(); 237 $full->tokens = $full->values = array(); 238 foreach ($types as $type => $object) { 239 $temp = token_get_values($type, $object, $flush, $options); 240 $full->tokens = array_merge($full->tokens, $temp->tokens); 241 $full->values = array_merge($full->values, $temp->values); 242 } 243 return _token_replace_tokens($original, $full->tokens, $full->values, $leading, $trailing); 244 } 245 246 // Internally used function to replace tokens. 247 function _token_replace_tokens($original, $tokens, $values, $leading, $trailing) { 248 $tokens = token_prepare_tokens($tokens, $leading, $trailing); 249 return str_replace($tokens, $values, $original); 250 } 251 252 /** 253 * Return a list of valid substitution tokens and their values for 254 * the specified type. 255 * 256 * @param type 257 * A flag indicating the class of substitution tokens to use. If an 258 * object is passed in the second param, 'type' should contain the 259 * object's type. For example, 'node', 'comment', or 'user'. If no 260 * type is specified, only 'global' site-wide substitution tokens are 261 * built. 262 * @param object 263 * Optionally, the object to use for building substitution values. 264 * A node, comment, user, etc. 265 * @param flush 266 * A flag indicating whether or not to flush the token cache. 267 * Useful for processes that need to slog through huge numbers 268 * of tokens in a single execution cycle. Flushing it will 269 * keep them from burning through memory. 270 * The default is FALSE. 271 * @return 272 * A keyed array containing the substitution tokens and the substitution 273 * values for the passed-in type and object. 274 */ 275 function token_get_values($type = 'global', $object = NULL, $flush = FALSE, $options = array()) { 276 static $tokens; 277 static $running; 278 279 // Flush the static token cache. Useful for processes that need to slog through 280 // huge numbers of tokens in a single execution cycle. Flushing it will keep 281 // them from burning through memory. 282 if ($flush || !isset($tokens)) { 283 $tokens = array(); 284 } 285 286 // Since objects in PHP5 are always passed by reference, we ensure we're 287 // working on a copy of the object. 288 if (is_object($object)) { 289 $object = drupal_clone($object); 290 } 291 292 // Simple recursion check. This is to avoid content_view()'s potential 293 // for endless looping when a filter uses tokens, which load the content 294 // view, which calls the filter, which uses tokens, which... 295 if ($running) { 296 // We'll allow things to get two levels deep, but bail out after that 297 // without performing any substitutions. 298 $result = new stdClass(); 299 $result->tokens = array(); 300 $result->values = array(); 301 return $result; 302 } 303 304 $running = TRUE; 305 306 token_include(); 307 308 $id = _token_get_id($type, $object); 309 if ($id && isset($tokens[$type][$id])) { 310 $tmp_tokens = $tokens[$type][$id]; 311 } 312 else { 313 $tmp_tokens = module_invoke_all('token_values', $type, $object, $options); 314 $tokens[$type][$id] = $tmp_tokens; 315 } 316 317 // Special-case global tokens, as we always want to be able to process 318 // those substitutions. 319 if (!isset($tokens['global']['default'])) { 320 $tokens['global']['default'] = module_invoke_all('token_values', 'global'); 321 } 322 323 $all = _token_array_merge($tokens['global']['default'], $tokens[$type][$id]); 324 325 $result = new stdClass(); 326 $result->tokens = array_keys($all); 327 $result->values = array_values($all); 328 329 $running = FALSE; 330 331 return $result; 332 } 333 334 /** 335 * Merge two arrays of token values, checking and warning for duplication. 336 * 337 * Because array_merge will combinue elements that have the same key into an 338 * array instead of overriding the existing element, this causes problems since 339 * we need the values to always be a string. 340 * 341 * @param $array1 342 * An array of token values keyed by token name. 343 * @param $array2 344 * An array of token values keyed by token name. 345 * @return 346 * A merged array of token values keyed by token name. 347 */ 348 function _token_array_merge($array1, $array2) { 349 static $warned = array(); 350 351 $merged = array_merge($array1, $array2); 352 foreach ($merged as $key => $value) { 353 if (is_array($value)) { 354 if (empty($warned[$key])) { 355 // Only warn once about duplicate token. 356 watchdog('token', 'More than one module has defined the %key token.', array('%key' => $key), WATCHDOG_WARNING); 357 $warned[$key] = TRUE; 358 } 359 // Use the last-defined value (module with lowest weight). 360 $merged[$key] = array_pop($value); 361 } 362 } 363 364 return $merged; 365 } 366 367 /** 368 * A helper function that retrieves all currently exposed tokens, 369 * and merges them recursively. This is only necessary when building 370 * the token listing -- during actual value replacement, only tokens 371 * in a particular domain are requested and a normal array_marge() is 372 * sufficient. 373 * 374 * @param types 375 * A flag indicating the class of substitution tokens to use. If an 376 * object is passed in the second param, 'types' should contain the 377 * object's type. For example, 'node', 'comment', or 'user'. 'types' 378 * may also be an array of types of the form array('node','user'). If no 379 * type is specified, only 'global' site-wide substitution tokens are 380 * built. 381 * @return 382 * The array of usable tokens and their descriptions, organized by 383 * token type. 384 */ 385 function token_get_list($types = 'all') { 386 token_include(); 387 $return = array(); 388 settype($types, 'array'); 389 foreach (module_implements('token_list') as $module) { 390 $function = $module .'_token_list'; 391 foreach ($types as $type) { 392 $result = $function($type); 393 if (is_array($result)) { 394 foreach ($result as $category => $tokens) { 395 foreach ($tokens as $token => $title) { 396 // Automatically append a raw token warning. 397 if (substr($token, -4) === '-raw' && strpos($title, t('raw user input')) === FALSE && strpos($title, '1269441371') === FALSE) { 398 $title .= ' <em>' . t('Warning: Token value contains raw user input.') . '</em>'; 399 } 400 $return[$category][$token] = $title; 401 } 402 } 403 } 404 } 405 } 406 return $return; 407 } 408 409 /** 410 * A helper function that transforms all the elements of an 411 * array. Used to change the delimiter style from brackets to 412 * percent symbols etc. 413 * 414 * @param tokens 415 * The array of tokens keys with no delimiting characters 416 * @param leading 417 * Character(s) to prepend to the token key before searching for 418 * matches. Defaults to an open-bracket. 419 * @param trailing 420 * Character(s) to append to the token key before searching for 421 * matches. Defaults to a close-bracket. 422 * @return 423 * The array of token keys, each wrapped in the specified 424 * delimiter style. 425 */ 426 function token_prepare_tokens($tokens = array(), $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX) { 427 foreach ($tokens as $key => $value) { 428 $tokens[$key] = $leading . $value . $trailing; 429 } 430 return $tokens; 431 } 432 433 // Internal utility function used for static caching. There are 434 // almost certainly better ways to do this, but for the moment it's 435 // sufficient. 436 function _token_get_id($type = 'global', $object = NULL) { 437 if (!isset($object)) { 438 return "default"; 439 } 440 switch ($type) { 441 case 'node': 442 return isset($object->nid) ? $object->nid : 0; 443 case 'comment': 444 return isset($object->cid) ? $object->cid : 0; 445 case 'user': 446 return isset($object->uid) ? $object->uid : 0; 447 case 'taxonomy': 448 return isset($object->tid) ? $object->tid : 0; 449 default: 450 return crc32(serialize($object)); 451 } 452 } 453 454 /** 455 * Build a list of common date tokens for use in hook_token_list(). 456 * 457 * @param $description 458 */ 459 function token_get_date_token_info($description, $token_prefix = '') { 460 $tokens[$token_prefix . 'small'] = t("!description date in 'small' format. <em>(06/07/2010 - 23:28)</em>", array('!description' => $description)); 461 $tokens[$token_prefix . 'yyyy'] = t("!description year (four digit)", array('!description' => $description)); 462 $tokens[$token_prefix . 'yy'] = t("!description year (two digit)", array('!description' => $description)); 463 $tokens[$token_prefix . 'month'] = t("!description month (full word)", array('!description' => $description)); 464 $tokens[$token_prefix . 'mon'] = t("!description month (abbreviated)", array('!description' => $description)); 465 $tokens[$token_prefix . 'mm'] = t("!description month (two digits with leading zeros)", array('!description' => $description)); 466 $tokens[$token_prefix . 'm'] = t("!description month (one or two digits without leading zeros)", array('!description' => $description)); 467 $tokens[$token_prefix . 'ww'] = t("!description week (two digits with leading zeros)", array('!description' => $description)); 468 if (version_compare(PHP_VERSION, '5.1.0', '>=')) { 469 $tokens[$token_prefix . 'date'] = t("!description date (numeric representation of the day of the week)", array('!description' => $description)); 470 } 471 $tokens[$token_prefix . 'day'] = t("!description day (full word)", array('!description' => $description)); 472 $tokens[$token_prefix . 'ddd'] = t("!description day (abbreviation)", array('!description' => $description)); 473 $tokens[$token_prefix . 'dd'] = t("!description day (two digits with leading zeros)", array('!description' => $description)); 474 $tokens[$token_prefix . 'd'] = t("!description day (one or two digits without leading zeros)", array('!description' => $description)); 475 $tokens[$token_prefix . 'raw'] = t("!description in UNIX timestamp format (1269441371)", array('!description' => $description)); 476 $tokens[$token_prefix . 'since'] = t("!description in 'time-since' format. (40 years 3 months)", array('!description' => $description)); 477 return $tokens; 478 } 479 480 /** 481 * Build a list of common date tokens for use in hook_token_values(). 482 * 483 * @param $description 484 */ 485 function token_get_date_token_values($timestamp = NULL, $token_prefix = '') { 486 $tokens = array(); 487 $time = time(); 488 if (!isset($timestamp)) { 489 $timestamp = $time; 490 } 491 $timezone = variable_get('date_default_timezone', 0); 492 493 $formats = array( 494 'yyyy' => 'Y', 495 'yy' => 'y', 496 'month' => 'F', 497 'mon' => 'M', 498 'mm' => 'm', 499 'm' => 'n', 500 'ww' => 'W', 501 //'date' => 'N', // Provided later since it is PHP 5.1 only. 502 'day' => 'l', 503 'ddd' => 'D', 504 'dd' => 'd', 505 'd' => 'j', 506 ); 507 foreach ($formats as $token => $format) { 508 $tokens[$token_prefix . $token] = format_date($timestamp, 'custom', $format, $timezone); 509 } 510 511 $tokens[$token_prefix . 'small'] = format_date($timestamp, 'small', '', $timezone); 512 $tokens[$token_prefix . 'raw'] = $timestamp; 513 $tokens[$token_prefix . 'since'] = format_interval($time - $timestamp); 514 515 $timestamp += $timezone; 516 if (version_compare(PHP_VERSION, '5.1.0', '>=')) { 517 $tokens[$token_prefix . 'date'] = gmdate('N', $timestamp); 518 } 519 520 return $tokens; 521 } 522 523 /** 524 * Validate an tokens in raw text based on possible contexts. 525 * 526 * @param $text 527 * A string with the raw text containing the raw tokens. 528 * @param $valid_types 529 * An array of token types to validage against. 530 * @param leading 531 * Character(s) to prepend to the token key before searching for 532 * matches. Defaults to an open-bracket. 533 * @param trailing 534 * Character(s) to append to the token key before searching for 535 * matches. Defaults to a close-bracket. 536 * @return 537 * An array with the invalid tokens in their original raw forms. 538 */ 539 function token_get_invalid_tokens_by_context($text, $valid_types = array(), $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX) { 540 // Add the token types that are always valid in global context. 541 $valid_types[] = 'global'; 542 543 $invalid_tokens = array(); 544 $valid_tokens = token_get_list($valid_types); 545 foreach (token_scan($text, $leading, $trailing) as $token) { 546 $found = FALSE; 547 foreach ($valid_tokens as $category => $tokens) { 548 if (isset($tokens[$token])) { 549 $found = TRUE; 550 break; 551 } 552 } 553 if (!$found) { 554 $invalid_tokens[] = $token; 555 } 556 } 557 558 array_unique($invalid_tokens); 559 $invalid_tokens = token_prepare_tokens($invalid_tokens, $leading, $trailing); 560 return $invalid_tokens; 561 } 562 563 /** 564 * Build a list of all token-like patterns that appear in the text. 565 * 566 * @param $text 567 * The text to be scanned for possible tokens. 568 * @param leading 569 * Character(s) to prepend to the token key before searching for 570 * matches. Defaults to an open-bracket. 571 * @param trailing 572 * Character(s) to append to the token key before searching for 573 * matches. Defaults to a close-bracket. 574 * @return 575 * An array of discovered tokens. 576 */ 577 function token_scan($text, $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX) { 578 // Matches tokens with the following pattern: [$token] 579 $leading = preg_quote($leading, '/'); 580 $trailing = preg_quote($trailing, '/'); 581 preg_match_all("/{$leading}([^\s]+?){$trailing}/", $text, $matches); 582 return $matches[1]; 583 } 584 585 /** 586 * Validate a form element that should have tokens in it. 587 * 588 * Form elements that want to add this validation should have the #token_types 589 * parameter defined. 590 * 591 * For example: 592 * @code 593 * $form['my_node_text_element'] = array( 594 * '#type' => 'textfield', 595 * '#title' => t('Some text to token-ize that has a node context.'), 596 * '#default_value' => 'The title of this node is [node:title].', 597 * '#element_validate' => array('token_element_validate_token_context'), 598 * '#token_types' => array('node'), 599 * ); 600 * @endcode 601 */ 602 function token_element_validate_token_context(&$element, &$form_state) { 603 $value = isset($element['#value']) ? $element['#value'] : $element['#default_value']; 604 $invalid_tokens = token_get_invalid_tokens_by_context($value, $element['#token_types']); 605 if ($invalid_tokens) { 606 form_error($element, t('The %element-title is using the following invalid tokens: @invalid-tokens.', array('%element-title' => $element['#title'], '@invalid-tokens' => implode(', ', $invalid_tokens)))); 607 } 608 return $element; 609 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |