I recently added a feature to pathauto that checks to see if the tokens a user has entered for their pattern make any sense.

It checks for a -raw companion and recommends that (which makes sense mostly just for pathauto)
It checks for whether the token makes sense in the realm (since pathauto specifically only works on node OR taxonomy OR user patterns at any given time).

Something like this should probably be in token (see fago's support)

Comments

fago’s picture

indeed a great improvement.
However from a usability point of view it would be much better if not fitting tokens wouldn't even appear in the list. In the case of raw tokens, I would consider this also as a security improvement as it helps avoiding XSS holes created through wrong tokens. So it would be awesome if the caller could say whether it needs raw or formatted tokens and only these are appearing and working.

How do you check if it's a raw token?

greggles’s picture

The code is pretty simple, it's up to the calling function to include the one valid namespace for tokens. Obviously extending that to include multiple namespaces would make sense. I think it's in pathauto.module and is the _pathauto_check_tokens or something like that.

About the raw values - all it does is look at the token - e.g. "title" and then says "if the token doesn't contain '-raw' and if there is a token called 'title-raw' then suggest title-raw"

It relies on the convention of naming tokens with -raw which isn't reliable but is better than nothing.

dave reid’s picture

Title: warn users if there tokens are bad » Provide an API to check for invalid tokens with certain context
Version: 5.x-1.x-dev » 7.x-1.x-dev
Assigned: greggles » dave reid

Badabing! :)

function token_check_context($text, $valid_types = array()) {
  $token_info = token_info();

  // Add the token types that are always valid in global context.
  foreach ($token_info['types'] as $type => $type_info) {
    if (empty($type_info['needs-data']) && !in_array($type, $valid_types)) {
      $valid_types[] = $type;
    }
  }

  $invalid_tokens = array();
  foreach (token_scan($text) as $type => $tokens) {
    if (!in_array($type, $valid_types)) {
      $invalid_tokens = array_merge($invalid_tokens, $tokens);
    }
    else {
      $invalid_tokens = array_merge($invalid_tokens, token_validate_tokens($type, $tokens));
    }
  }

  $invalid_tokens = array_values($invalid_tokens);
  return $invalid_tokens;
}

/**
 * Validate an array of tokens based on their token type.
 *
 * @param $type
 *   The type of tokens to validate (e.g. 'node', etc.)
 * @param $tokens
 *   A keyed array of tokens, and their original raw form in the source text.
 * @return
 *   An array with the invalid tokens in their original raw forms.
 */
function token_validate_tokens($type, $tokens) {
  $token_info = token_info();
  $invalid_tokens = array();

  foreach ($tokens as $token => $full_token) {
    $parts = explode(':', $token, 2);
    if (!isset($token_info['tokens'][$type][$parts[0]])) {
      $invalid_tokens[] = $full_token;
    }
    elseif (count($parts) == 2) {
      $sub_token_info = $token_info['tokens'][$type][$parts[0]];
      if ($type == 'date' && $parts[0] == 'custom') {
        continue;
      }
      elseif (empty($sub_token_info['type'])) {
        $invalid_tokens[] = $full_token;
      }
      else {
        $sub_tokens = token_find_with_prefix(array($token => $full_token), $parts[0]);
        $invalid_tokens = array_merge($invalid_tokens, token_validate_tokens($sub_token_info['type'], $sub_tokens));
      }
    }
  }

  return $invalid_tokens;
}

$test_tokens = array(
  // Valid tokens:
  '[node:title]',
  '[node:created:short]',
  '[node:created:custom:foobar]',
  '[node:created:custom:YYYY]',
  '[site:name]',
  '[site:slogan]',
  // Invalid tokens:
  '[node:title:foobar]',
  '[node:created:foobar]',
  '[node:created:short:ferzle]',
  '[nod:title]',
  '[site:foobar]',
);
$invalid_tokens = token_check_context(implode('', $test_tokens), array('node'));
var_export($invalid_tokens);

Outputs:

array (
  0 => '[node:title:foobar]',
  1 => '[node:created:foobar]',
  2 => '[node:created:short:ferzle]',
  3 => '[nod:title]',
  4 => '[site:foobar]',
)
dave reid’s picture

Status: Active » Fixed

Committed this with a test to HEAD.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.