123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- <?php
- /**
- * @file
- * Drupal placeholder/token replacement system.
- *
- * API functions for replacing placeholders in text with meaningful values.
- *
- * For example: When configuring automated emails, an administrator enters
- * standard text for the email. Variables like the title of a node and the date
- * the email was sent can be entered as placeholders like [node:title] and
- * [date:short]. When a Drupal module prepares to send the email, it can call
- * the token_replace() function, passing in the text. The token system will
- * scan the text for placeholder tokens, give other modules an opportunity to
- * replace them with meaningful text, then return the final product to the
- * original module.
- *
- * Tokens follow the form: [$type:$name], where $type is a general class of
- * tokens like 'node', 'user', or 'comment' and $name is the name of a given
- * placeholder. For example, [node:title] or [node:created:since].
- *
- * In addition to raw text containing placeholders, modules may pass in an array
- * of objects to be used when performing the replacement. The objects should be
- * keyed by the token type they correspond to. For example:
- *
- * @code
- * // Load a node and a user, then replace tokens in the text.
- * $text = 'On [date:short], [user:name] read [node:title].';
- * $node = node_load(1);
- * $user = user_load(1);
- *
- * // [date:...] tokens use the current date automatically.
- * $data = array('node' => $node, 'user' => $user);
- * return token_replace($text, $data);
- * @endcode
- *
- * Some tokens may be chained in the form of [$type:$pointer:$name], where $type
- * is a normal token type, $pointer is a reference to another token type, and
- * $name is the name of a given placeholder. For example, [node:author:mail]. In
- * that example, 'author' is a pointer to the 'user' account that created the
- * node, and 'mail' is a placeholder available for any 'user'.
- *
- * @see token_replace()
- * @see hook_tokens()
- * @see hook_token_info()
- */
- /**
- * Replaces all tokens in a given string with appropriate values.
- *
- * @param $text
- * A string potentially containing replaceable tokens.
- * @param $data
- * (optional) An array of keyed objects. For simple replacement scenarios
- * 'node', 'user', and others are common keys, with an accompanying node or
- * user object being the value. Some token types, like 'site', do not require
- * any explicit information from $data and can be replaced even if it is
- * empty.
- * @param $options
- * (optional) A keyed array of settings and flags to control the token
- * replacement process. Supported options are:
- * - language: A language object to be used when generating locale-sensitive
- * tokens.
- * - callback: A callback function that will be used to post-process the array
- * of token replacements after they are generated. For example, a module
- * using tokens in a text-only email might provide a callback to strip HTML
- * entities from token values before they are inserted into the final text.
- * - clear: A boolean flag indicating that tokens should be removed from the
- * final text if no replacement value can be generated.
- * - sanitize: A boolean flag indicating that tokens should be sanitized for
- * display to a web browser. Defaults to TRUE. Developers who set this
- * option to FALSE assume responsibility for running filter_xss(),
- * check_plain() or other appropriate scrubbing functions before displaying
- * data to users.
- *
- * @return
- * Text with tokens replaced.
- */
- function token_replace($text, array $data = array(), array $options = array()) {
- $text_tokens = token_scan($text);
- if (empty($text_tokens)) {
- return $text;
- }
- $replacements = array();
- foreach ($text_tokens as $type => $tokens) {
- $replacements += token_generate($type, $tokens, $data, $options);
- if (!empty($options['clear'])) {
- $replacements += array_fill_keys($tokens, '');
- }
- }
- // Optionally alter the list of replacement values.
- if (!empty($options['callback']) && function_exists($options['callback'])) {
- $function = $options['callback'];
- $function($replacements, $data, $options);
- }
- $tokens = array_keys($replacements);
- $values = array_values($replacements);
- return str_replace($tokens, $values, $text);
- }
- /**
- * Builds a list of all token-like patterns that appear in the text.
- *
- * @param $text
- * The text to be scanned for possible tokens.
- *
- * @return
- * An associative array of discovered tokens, grouped by type.
- */
- function token_scan($text) {
- // Matches tokens with the following pattern: [$type:$name]
- // $type and $name may not contain [ ] characters.
- // $type may not contain : or whitespace characters, but $name may.
- preg_match_all('/
- \[ # [ - pattern start
- ([^\s\[\]:]*) # match $type not containing whitespace : [ or ]
- : # : - separator
- ([^\[\]]*) # match $name not containing [ or ]
- \] # ] - pattern end
- /x', $text, $matches);
- $types = $matches[1];
- $tokens = $matches[2];
- // Iterate through the matches, building an associative array containing
- // $tokens grouped by $types, pointing to the version of the token found in
- // the source text. For example, $results['node']['title'] = '[node:title]';
- $results = array();
- for ($i = 0; $i < count($tokens); $i++) {
- $results[$types[$i]][$tokens[$i]] = $matches[0][$i];
- }
- return $results;
- }
- /**
- * Generates replacement values for a list of tokens.
- *
- * @param $type
- * The type of token being replaced. 'node', 'user', and 'date' are common.
- * @param $tokens
- * An array of tokens to be replaced, keyed by the literal text of the token
- * as it appeared in the source text.
- * @param $data
- * (optional) An array of keyed objects. For simple replacement scenarios
- * 'node', 'user', and others are common keys, with an accompanying node or
- * user object being the value. Some token types, like 'site', do not require
- * any explicit information from $data and can be replaced even if it is
- * empty.
- * @param $options
- * (optional) A keyed array of settings and flags to control the token
- * replacement process. Supported options are:
- * - language: A language object to be used when generating locale-sensitive
- * tokens.
- * - callback: A callback function that will be used to post-process the
- * array of token replacements after they are generated. Can be used when
- * modules require special formatting of token text, for example URL
- * encoding or truncation to a specific length.
- * - sanitize: A boolean flag indicating that tokens should be sanitized for
- * display to a web browser. Developers who set this option to FALSE assume
- * responsibility for running filter_xss(), check_plain() or other
- * appropriate scrubbing functions before displaying data to users.
- *
- * @return
- * An associative array of replacement values, keyed by the original 'raw'
- * tokens that were found in the source text. For example:
- * $results['[node:title]'] = 'My new node';
- *
- * @see hook_tokens()
- * @see hook_tokens_alter()
- */
- function token_generate($type, array $tokens, array $data = array(), array $options = array()) {
- $options += array('sanitize' => TRUE);
- $replacements = module_invoke_all('tokens', $type, $tokens, $data, $options);
- // Allow other modules to alter the replacements.
- $context = array(
- 'type' => $type,
- 'tokens' => $tokens,
- 'data' => $data,
- 'options' => $options,
- );
- drupal_alter('tokens', $replacements, $context);
- return $replacements;
- }
- /**
- * Returns a list of tokens that begin with a specific prefix.
- *
- * Used to extract a group of 'chained' tokens (such as [node:author:name])
- * from the full list of tokens found in text. For example:
- * @code
- * $data = array(
- * 'author:name' => '[node:author:name]',
- * 'title' => '[node:title]',
- * 'created' => '[node:created]',
- * );
- * $results = token_find_with_prefix($data, 'author');
- * $results == array('name' => '[node:author:name]');
- * @endcode
- *
- * @param $tokens
- * A keyed array of tokens, and their original raw form in the source text.
- * @param $prefix
- * A textual string to be matched at the beginning of the token.
- * @param $delimiter
- * An optional string containing the character that separates the prefix from
- * the rest of the token. Defaults to ':'.
- *
- * @return
- * An associative array of discovered tokens, with the prefix and delimiter
- * stripped from the key.
- */
- function token_find_with_prefix(array $tokens, $prefix, $delimiter = ':') {
- $results = array();
- foreach ($tokens as $token => $raw) {
- $parts = explode($delimiter, $token, 2);
- if (count($parts) == 2 && $parts[0] == $prefix) {
- $results[$parts[1]] = $raw;
- }
- }
- return $results;
- }
- /**
- * Returns metadata describing supported tokens.
- *
- * The metadata array contains token type, name, and description data as well
- * as an optional pointer indicating that the token chains to another set of
- * tokens.
- *
- * For example:
- * @code
- * $data['types']['node'] = array(
- * 'name' => t('Nodes'),
- * 'description' => t('Tokens related to node objects.'),
- * );
- * $data['tokens']['node']['title'] = array(
- * 'name' => t('Title'),
- * 'description' => t('The title of the current node.'),
- * );
- * $data['tokens']['node']['author'] = array(
- * 'name' => t('Author'),
- * 'description' => t('The author of the current node.'),
- * 'type' => 'user',
- * );
- * @endcode
- *
- * @return
- * An associative array of token information, grouped by token type.
- */
- function token_info() {
- $data = &drupal_static(__FUNCTION__);
- if (!isset($data)) {
- $data = module_invoke_all('token_info');
- drupal_alter('token_info', $data);
- }
- return $data;
- }
|