Conjunto de cambios 49072ea en sipes para modules_contrib/pathauto/pathauto.inc


Ignorar:
Fecha y hora:
26/05/2016 18:10:02 (hace 8 años)
Autor:
José Gregorio Puentes <jpuentes@…>
Branches:
stable, version-3.0
Children:
2efe680
Parents:
cd414e9
Mensaje:

se actualizo el modulo

Fichero:
1 editado

Leyenda

No modificado
Añadido
Eliminado
  • modules_contrib/pathauto/pathauto.inc

    r177a560 r49072ea  
    11<?php
    2 // $Id: pathauto.inc,v 1.45.2.29 2010/09/27 15:52:58 greggles Exp $
    32
    43/**
     
    65 * Miscellaneous functions for Pathauto.
    76 *
     7 * This also contains some constants giving human readable names to some numeric
     8 * settings; they're included here as they're only rarely used outside this file
     9 * anyway. Use module_load_include('inc', 'pathauto') if the constants need to
     10 * be available.
     11 *
    812 * @ingroup pathauto
    913 */
     14
     15/**
     16 * Case should be left as is in the generated path.
     17 */
     18define('PATHAUTO_CASE_LEAVE_ASIS', 0);
     19
     20/**
     21 * Case should be lowercased in the generated path.
     22 */
     23define('PATHAUTO_CASE_LOWER', 1);
     24
     25/**
     26 * "Do nothing. Leave the old alias intact."
     27 */
     28define('PATHAUTO_UPDATE_ACTION_NO_NEW', 0);
     29
     30/**
     31 * "Create a new alias. Leave the existing alias functioning."
     32 */
     33define('PATHAUTO_UPDATE_ACTION_LEAVE', 1);
     34
     35/**
     36 * "Create a new alias. Delete the old alias."
     37 */
     38define('PATHAUTO_UPDATE_ACTION_DELETE', 2);
     39
     40/**
     41 * "Create a new alias. Redirect from old alias."
     42 *
     43 * This is only available when the Path Redirect module is.
     44 */
     45define('PATHAUTO_UPDATE_ACTION_REDIRECT', 3);
     46
     47/**
     48 * Remove the punctuation from the alias.
     49 */
     50define('PATHAUTO_PUNCTUATION_REMOVE', 0);
     51
     52/**
     53 * Replace the punctuation with the separator in the alias.
     54 */
     55define('PATHAUTO_PUNCTUATION_REPLACE', 1);
     56
     57/**
     58 * Leave the punctuation as it is in the alias.
     59 */
     60define('PATHAUTO_PUNCTUATION_DO_NOTHING', 2);
     61
     62/**
     63 * Matches Unicode characters that are word boundaries.
     64 *
     65 * Characters with the following General_category (gc) property values are used
     66 * as word boundaries. While this does not fully conform to the Word Boundaries
     67 * algorithm described in http://unicode.org/reports/tr29, as PCRE does not
     68 * contain the Word_Break property table, this simpler algorithm has to do.
     69 * - Cc, Cf, Cn, Co, Cs: Other.
     70 * - Pc, Pd, Pe, Pf, Pi, Po, Ps: Punctuation.
     71 * - Sc, Sk, Sm, So: Symbols.
     72 * - Zl, Zp, Zs: Separators.
     73 *
     74 * Non-boundary characters include the following General_category (gc) property
     75 * values:
     76 * - Ll, Lm, Lo, Lt, Lu: Letters.
     77 * - Mc, Me, Mn: Combining Marks.
     78 * - Nd, Nl, No: Numbers.
     79 *
     80 * Note that the PCRE property matcher is not used because we wanted to be
     81 * compatible with Unicode 5.2.0 regardless of the PCRE version used (and any
     82 * bugs in PCRE property tables).
     83 *
     84 * @see http://unicode.org/glossary
     85 */
     86define('PATHAUTO_PREG_CLASS_UNICODE_WORD_BOUNDARY',
     87  '\x{0}-\x{2F}\x{3A}-\x{40}\x{5B}-\x{60}\x{7B}-\x{A9}\x{AB}-\x{B1}\x{B4}' .
     88  '\x{B6}-\x{B8}\x{BB}\x{BF}\x{D7}\x{F7}\x{2C2}-\x{2C5}\x{2D2}-\x{2DF}' .
     89  '\x{2E5}-\x{2EB}\x{2ED}\x{2EF}-\x{2FF}\x{375}\x{37E}-\x{385}\x{387}\x{3F6}' .
     90  '\x{482}\x{55A}-\x{55F}\x{589}-\x{58A}\x{5BE}\x{5C0}\x{5C3}\x{5C6}' .
     91  '\x{5F3}-\x{60F}\x{61B}-\x{61F}\x{66A}-\x{66D}\x{6D4}\x{6DD}\x{6E9}' .
     92  '\x{6FD}-\x{6FE}\x{700}-\x{70F}\x{7F6}-\x{7F9}\x{830}-\x{83E}' .
     93  '\x{964}-\x{965}\x{970}\x{9F2}-\x{9F3}\x{9FA}-\x{9FB}\x{AF1}\x{B70}' .
     94  '\x{BF3}-\x{BFA}\x{C7F}\x{CF1}-\x{CF2}\x{D79}\x{DF4}\x{E3F}\x{E4F}' .
     95  '\x{E5A}-\x{E5B}\x{F01}-\x{F17}\x{F1A}-\x{F1F}\x{F34}\x{F36}\x{F38}' .
     96  '\x{F3A}-\x{F3D}\x{F85}\x{FBE}-\x{FC5}\x{FC7}-\x{FD8}\x{104A}-\x{104F}' .
     97  '\x{109E}-\x{109F}\x{10FB}\x{1360}-\x{1368}\x{1390}-\x{1399}\x{1400}' .
     98  '\x{166D}-\x{166E}\x{1680}\x{169B}-\x{169C}\x{16EB}-\x{16ED}' .
     99  '\x{1735}-\x{1736}\x{17B4}-\x{17B5}\x{17D4}-\x{17D6}\x{17D8}-\x{17DB}' .
     100  '\x{1800}-\x{180A}\x{180E}\x{1940}-\x{1945}\x{19DE}-\x{19FF}' .
     101  '\x{1A1E}-\x{1A1F}\x{1AA0}-\x{1AA6}\x{1AA8}-\x{1AAD}\x{1B5A}-\x{1B6A}' .
     102  '\x{1B74}-\x{1B7C}\x{1C3B}-\x{1C3F}\x{1C7E}-\x{1C7F}\x{1CD3}\x{1FBD}' .
     103  '\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}' .
     104  '\x{1FFD}-\x{206F}\x{207A}-\x{207E}\x{208A}-\x{208E}\x{20A0}-\x{20B8}' .
     105  '\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}' .
     106  '\x{2116}-\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}' .
     107  '\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}-\x{214D}\x{214F}' .
     108  '\x{2190}-\x{244A}\x{249C}-\x{24E9}\x{2500}-\x{2775}\x{2794}-\x{2B59}' .
     109  '\x{2CE5}-\x{2CEA}\x{2CF9}-\x{2CFC}\x{2CFE}-\x{2CFF}\x{2E00}-\x{2E2E}' .
     110  '\x{2E30}-\x{3004}\x{3008}-\x{3020}\x{3030}\x{3036}-\x{3037}' .
     111  '\x{303D}-\x{303F}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{3190}-\x{3191}' .
     112  '\x{3196}-\x{319F}\x{31C0}-\x{31E3}\x{3200}-\x{321E}\x{322A}-\x{3250}' .
     113  '\x{3260}-\x{327F}\x{328A}-\x{32B0}\x{32C0}-\x{33FF}\x{4DC0}-\x{4DFF}' .
     114  '\x{A490}-\x{A4C6}\x{A4FE}-\x{A4FF}\x{A60D}-\x{A60F}\x{A673}\x{A67E}' .
     115  '\x{A6F2}-\x{A716}\x{A720}-\x{A721}\x{A789}-\x{A78A}\x{A828}-\x{A82B}' .
     116  '\x{A836}-\x{A839}\x{A874}-\x{A877}\x{A8CE}-\x{A8CF}\x{A8F8}-\x{A8FA}' .
     117  '\x{A92E}-\x{A92F}\x{A95F}\x{A9C1}-\x{A9CD}\x{A9DE}-\x{A9DF}' .
     118  '\x{AA5C}-\x{AA5F}\x{AA77}-\x{AA79}\x{AADE}-\x{AADF}\x{ABEB}' .
     119  '\x{E000}-\x{F8FF}\x{FB29}\x{FD3E}-\x{FD3F}\x{FDFC}-\x{FDFD}' .
     120  '\x{FE10}-\x{FE19}\x{FE30}-\x{FE6B}\x{FEFF}-\x{FF0F}\x{FF1A}-\x{FF20}' .
     121  '\x{FF3B}-\x{FF40}\x{FF5B}-\x{FF65}\x{FFE0}-\x{FFFD}');
    10122
    11123/**
     
    54166 */
    55167function _pathauto_existing_alias_data($source, $language = '') {
    56   return db_fetch_array(db_query_range("SELECT pid, dst AS alias FROM {url_alias} WHERE src = '%s' AND language IN ('%s', '') ORDER BY language DESC, pid DESC", $source, $language, 0, 1));
     168  return db_fetch_array(db_query_range("SELECT pid, dst AS alias, language FROM {url_alias} WHERE src = '%s' AND language IN ('%s', '') ORDER BY language DESC, pid DESC", $source, $language, 0, 1));
    57169}
    58170
     
    61173 *
    62174 * Performs the following possible alterations:
     175 * - Remove all HTML tags.
    63176 * - Process the string through the transliteration module.
    64177 * - Replace or remove punctuation with the separator character.
     
    76189 * @param $string
    77190 *   A string to clean.
     191 * @param array $options
     192 *   (optional) A keyed array of settings and flags to control the Pathauto
     193 *   clean string replacement process. Supported options are:
     194 *   - langcode: A language code to be used when translating strings.
     195 *
    78196 * @return
    79197 *   The cleaned string.
    80198 */
    81199function pathauto_cleanstring($string) {
    82   $output = $string;
    83 
    84   // Optionally remove accents and transliterate
    85   if (variable_get('pathauto_transliterate', FALSE)) {
    86     static $translations;
    87 
    88     if (!isset($translations)) {
    89       $translations = FALSE;
    90       if ($file = _pathauto_get_i18n_file()) {
    91         $translations = parse_ini_file($file);
    92       }
    93     }
    94 
    95     if (!empty($translations)) {
    96       $output = strtr($output, $translations);
    97     }
    98   }
    99 
    100   // Replace or drop punctuation based on user settings
    101   $separator = variable_get('pathauto_separator', '-');
    102   $punctuation = pathauto_punctuation_chars();
    103   foreach ($punctuation as $name => $details) {
    104     $action = variable_get('pathauto_punctuation_'. $name, 0);
    105     // 2 is the action for "do nothing" with the punctuation
    106     if ($action != 2) {
    107       // Slightly tricky inline if which either replaces with the separator or nothing
    108       $output = str_replace($details['value'], ($action ? $separator : ''), $output);
    109     }
    110   }
    111 
    112   // Reduce strings to letters and numbers
    113   if (variable_get('pathauto_reduce_ascii', FALSE)) {
    114     $pattern = '/[^a-zA-Z0-9\/]+/';
    115     $output = preg_replace($pattern, $separator, $output);
    116   }
    117 
    118   // Calculate and statically cache the ignored words regex expression.
    119   static $ignore_words_regex;
    120   if (!isset($ignore_words_regex)) {
    121     $ignore_words = array(
    122       'a', 'an', 'as', 'at', 'before', 'but', 'by', 'for', 'from', 'is', 'in',
    123       'into', 'like', 'of', 'off', 'on', 'onto', 'per', 'since', 'than', 'the',
    124       'this', 'that', 'to', 'up', 'via', 'with',
     200  // Use the advanced drupal_static() pattern, since this is called very often.
     201  static $drupal_static_fast;
     202  if (!isset($drupal_static_fast)) {
     203    $drupal_static_fast['cache'] = &pathauto_static(__FUNCTION__);
     204  }
     205  $cache = &$drupal_static_fast['cache'];
     206
     207  // Generate and cache variables used in this function so that on the second
     208  // call to pathauto_cleanstring() we focus on processing.
     209  if (!isset($cache)) {
     210    $cache = array(
     211      'separator' => variable_get('pathauto_separator', '-'),
     212      'strings' => array(),
     213      'transliterate' => variable_get('pathauto_transliterate', FALSE) && module_exists('transliteration'),
     214      'punctuation' => array(),
     215      'reduce_ascii' => (bool) variable_get('pathauto_reduce_ascii', FALSE),
     216      'ignore_words_regex' => FALSE,
     217      'lowercase' => (bool) variable_get('pathauto_case', PATHAUTO_CASE_LOWER),
     218      'maxlength' => min(variable_get('pathauto_max_component_length', 100), _pathauto_get_schema_alias_maxlength()),
    125219    );
    126     $ignore_words = variable_get('pathauto_ignore_words', $ignore_words);
     220
     221    // Generate and cache the punctuation replacements for strtr().
     222    $punctuation = pathauto_punctuation_chars();
     223    foreach ($punctuation as $name => $details) {
     224      $action = variable_get('pathauto_punctuation_' . $name, PATHAUTO_PUNCTUATION_REMOVE);
     225      switch ($action) {
     226        case PATHAUTO_PUNCTUATION_REMOVE:
     227          $cache['punctuation'][$details['value']] = '';
     228          break;
     229        case PATHAUTO_PUNCTUATION_REPLACE:
     230          $cache['punctuation'][$details['value']] = $cache['separator'];
     231          break;
     232        case PATHAUTO_PUNCTUATION_DO_NOTHING:
     233          // Literally do nothing.
     234          break;
     235      }
     236    }
     237
     238    // Generate and cache the ignored words regular expression.
     239    $ignore_words = variable_get('pathauto_ignore_words', PATHAUTO_IGNORE_WORDS);
    127240    $ignore_words_regex = preg_replace(array('/^[,\s]+|[,\s]+$/', '/[,\s]+/'), array('', '\b|\b'), $ignore_words);
    128241    if ($ignore_words_regex) {
    129       $ignore_words_regex = '\b' . $ignore_words_regex . '\b';
    130     }
     242      $cache['ignore_words_regex'] = '\b' . $ignore_words_regex . '\b';
     243      if (function_exists('mb_eregi_replace')) {
     244        $cache['ignore_words_callback'] = 'mb_eregi_replace';
     245      }
     246      else {
     247        $cache['ignore_words_callback'] = 'preg_replace';
     248        $cache['ignore_words_regex'] = '/' . $cache['ignore_words_regex'] . '/i';
     249      }
     250    }
     251  }
     252
     253  // Empty strings do not need any proccessing.
     254  if ($string === '' || $string === NULL) {
     255    return '';
     256  }
     257
     258  $langcode = NULL;
     259  if (!empty($options['language']->language)) {
     260    $langcode = $options['language']->language;
     261  }
     262  elseif (!empty($options['langcode'])) {
     263    $langcode = $options['langcode'];
     264  }
     265
     266  // Check if the string has already been processed, and if so return the
     267  // cached result.
     268  if (isset($cache['strings'][$langcode][$string])) {
     269    return $cache['strings'][$langcode][$string];
     270  }
     271
     272  // Remove all HTML tags from the string.
     273  $output = strip_tags(decode_entities($string));
     274
     275  // Optionally transliterate (by running through the Transliteration module)
     276  if ($cache['transliterate']) {
     277    $output = transliteration_get($output, $cache['reduce_ascii'] ? '' : '?', $langcode);
     278  }
     279
     280  // Replace or drop punctuation based on user settings
     281  $output = strtr($output, $cache['punctuation']);
     282
     283  // Reduce strings to letters and numbers
     284  if ($cache['reduce_ascii']) {
     285    $output = preg_replace('/[^a-zA-Z0-9\/]+/', $cache['separator'], $output);
    131286  }
    132287
    133288  // Get rid of words that are on the ignore list
    134   if ($ignore_words_regex) {
    135     if (function_exists('mb_eregi_replace')) {
    136       $words_removed = mb_eregi_replace($ignore_words_regex, '', $output);
    137     }
    138     else {
    139       $words_removed = preg_replace("/$ignore_words_regex/i", '', $output);
    140     }
     289  if ($cache['ignore_words_regex']) {
     290    $words_removed = $cache['ignore_words_callback']($cache['ignore_words_regex'], '', $output);
    141291    if (drupal_strlen(trim($words_removed)) > 0) {
    142292      $output = $words_removed;
     
    145295
    146296  // Always replace whitespace with the separator.
    147   $output = preg_replace('/\s+/', $separator, $output);
     297  $output = preg_replace('/\s+/', $cache['separator'], $output);
    148298
    149299  // Trim duplicates and remove trailing and leading separators.
    150   $output = _pathauto_clean_separators($output);
     300  $output = _pathauto_clean_separators($output, $cache['separator']);
    151301
    152302  // Optionally convert to lower case.
    153   if (variable_get('pathauto_case', 1)) {
     303  if ($cache['lowercase']) {
    154304    $output = drupal_strtolower($output);
    155305  }
    156306
    157   // Enforce the maximum component length.
    158   $maxlength = min(variable_get('pathauto_max_component_length', 100), _pathauto_get_schema_alias_maxlength());
    159   $output = drupal_substr($output, 0, $maxlength);
     307  // Shorten to a logical place based on word boundaries.
     308  $output = pathauto_truncate_utf8($output, $cache['maxlength'], TRUE);
     309
     310  // Cache this result in the static array.
     311  $cache['strings'][$langcode][$string] = $output;
    160312
    161313  return $output;
     
    176328 */
    177329function _pathauto_clean_separators($string, $separator = NULL) {
     330  static $default_separator;
     331
     332  if (!isset($separator)) {
     333    if (!isset($default_separator)) {
     334      $default_separator = variable_get('pathauto_separator', '-');
     335    }
     336    $separator = $default_separator;
     337  }
     338
    178339  $output = $string;
    179340
    180   if (!isset($separator)) {
    181     $separator = variable_get('pathauto_separator', '-');
    182   }
    183 
    184   // Clean duplicate or trailing separators.
    185341  if (strlen($separator)) {
    186     // Escape the separator.
     342    // Trim any leading or trailing separators.
     343    $output = trim($output, $separator);
     344
     345    // Escape the separator for use in regular expressions.
    187346    $seppattern = preg_quote($separator, '/');
    188347
    189     // Trim any leading or trailing separators.
    190     $output = preg_replace("/^$seppattern+|$seppattern+$/", '', $output);
     348    // Replace multiple separators with a single one.
     349    $output = preg_replace("/$seppattern+/", $separator, $output);
    191350
    192351    // Replace trailing separators around slashes.
    193352    if ($separator !== '/') {
    194       $output = preg_replace("/$seppattern+\/|\/$seppattern+/", "/", $output);
    195     }
    196 
    197     // Replace multiple separators with a single one.
    198     $output = preg_replace("/$seppattern+/", $separator, $output);
     353      $output = preg_replace("/\/+$seppattern\/+|$seppattern\/+|\/+$seppattern/", "/", $output);
     354    }
    199355  }
    200356
     
    216372 */
    217373function pathauto_clean_alias($alias) {
     374  $cache = &pathauto_static(__FUNCTION__);
     375
     376  if (!isset($cache)) {
     377    $cache = array(
     378      'maxlength' => min(variable_get('pathauto_max_length', 100), _pathauto_get_schema_alias_maxlength()),
     379    );
     380  }
     381
    218382  $output = $alias;
    219383
    220   // Trim duplicate, leading, and trailing back-slashes.
     384  // Trim duplicate, leading, and trailing separators. Do this before cleaning
     385  // backslashes since a pattern like "[token1]/[token2]-[token3]/[token4]"
     386  // could end up like "value1/-/value2" and if backslashes were cleaned first
     387  // this would result in a duplicate blackslash.
     388  $output = _pathauto_clean_separators($output);
     389
     390  // Trim duplicate, leading, and trailing backslashes.
    221391  $output = _pathauto_clean_separators($output, '/');
    222392
    223   // Trim duplicate, leading, and trailing separators.
    224   $output = _pathauto_clean_separators($output);
    225 
    226   // Enforce the maximum length.
    227   $separator = variable_get('pathauto_separator', '-');
    228   $maxlength = min(variable_get('pathauto_max_length', 100), _pathauto_get_schema_alias_maxlength());
    229   $output = drupal_substr($output, 0, $maxlength);
     393  // Shorten to a logical place based on word boundaries.
     394  $output = pathauto_truncate_utf8($output, $cache['maxlength'], TRUE);
    230395
    231396  return $output;
     
    240405 *   Operation being performed on the content being aliased
    241406 *   ('insert', 'update', 'return', or 'bulkupdate').
    242  * @param $placeholders
    243  *   An array whose keys consist of the translated placeholders
    244  *   which appear in patterns (e.g., t('[title]')) and values are the
    245  *   actual values to be substituted into the pattern (e.g., $node->title).
    246407 * @param $source
    247408 *   An internal Drupal path to be aliased.
     409 * @param $data
     410 *   An array of keyed objects to pass to token_replace(). For simple
     411 *   replacement scenarios 'node', 'user', and others are common keys, with an
     412 *   accompanying node or user object being the value.  Only one key/value pair
     413 *   is supported, otherwise you may pass the results from
     414 *   pathauto_get_placeholders() here.
    248415 * @param $entity_id
    249  *   The entity ID (node ID, user ID, etc.).
     416 *   (deprecated) The entity ID (node ID, user ID, etc.). This parameter is
     417 *   deprecated and is not actually used.
    250418 * @param $type
    251419 *   For modules which provided pattern items in hook_pathauto(),
     
    260428 * @see pathauto_get_placeholders()
    261429 */
    262 function pathauto_create_alias($module, $op, $placeholders, $source, $entity_id, $type = NULL, $language = '') {
    263   // Retrieve and apply the pattern for this content type
    264   if (!empty($type)) {
    265     $pattern = trim(variable_get("pathauto_{$module}_{$type}_{$language}_pattern", ''));
    266     if (empty($pattern)) {
    267       $pattern = trim(variable_get("pathauto_{$module}_{$type}_pattern", ''));
    268     }
    269   }
     430function pathauto_create_alias($module, $op, $source, $data, $entity_id = NULL, $type = NULL, $language = '') {
     431  // Retrieve and apply the pattern for this content type.
     432  $pattern = pathauto_pattern_load_by_entity($module, $type, $language);
     433
     434  // Allow other modules to alter the pattern.
     435  $context = array(
     436    'module' => $module,
     437    'op' => $op,
     438    'source' => $source,
     439    'data' => $data,
     440    'type' => $type,
     441    'language' => &$language,
     442  );
     443  drupal_alter('pathauto_pattern', $pattern, $context);
     444
    270445  if (empty($pattern)) {
    271     $pattern = trim(variable_get("pathauto_{$module}_pattern", ''));
    272   }
    273   // No pattern? Do nothing (otherwise we may blow away existing aliases...)
    274   if (empty($pattern)) {
     446    // No pattern? Do nothing (otherwise we may blow away existing aliases...)
    275447    return '';
    276448  }
    277449
    278   if ($module == 'taxonomy') {
    279     // Get proper path for term.
    280     $term_path = taxonomy_term_path(taxonomy_get_term($entity_id));
    281     if ($term_path != $source) {
    282       // Quietly alias 'taxonomy/term/[tid]' with proper path for term.
    283       $update_data = _pathauto_existing_alias_data($source, $language);
    284       _pathauto_set_alias($source, $term_path, $module, $entity_id, $update_data['pid'], FALSE, $update_data['old_alias'], $language);
    285       // Set $source as proper path.
    286       $source = $term_path;
    287     }
     450  // Support for when $source and $placeholders were swapped.
     451  if (is_array($source) && is_string($data)) {
     452    $placeholders = $source;
     453    $source = $data;
     454  }
     455  elseif (is_array($data) && !isset($data['tokens']) && !isset($data['values'])) {
     456    $placeholders = pathauto_get_placeholders(key($data), current($data), $pattern, array('language' => (object) array('language' => $language)));
     457  }
     458  else {
     459    $placeholders = $data;
    288460  }
    289461
     
    292464  if ($op == 'update' || $op == 'bulkupdate') {
    293465    if ($existing_alias = _pathauto_existing_alias_data($source, $language)) {
    294       switch (variable_get('pathauto_update_action', 2)) {
    295         case 0:
     466      switch (variable_get('pathauto_update_action', PATHAUTO_UPDATE_ACTION_DELETE)) {
     467        case PATHAUTO_UPDATE_ACTION_NO_NEW:
    296468          // If an alias already exists, and the update action is set to do nothing,
    297469          // then gosh-darn it, do nothing.
     
    315487
    316488  // Allow other modules to alter the alias.
    317   $context = array(
    318     'module' => $module,
    319     'op' => $op,
    320     'source' => $source,
    321     'entity_id' => $entity_id,
    322     'type' => $type,
    323     'language' => $language,
    324     'pattern' => $pattern,
    325   );
     489  $context['source'] = &$source;
     490  $context['pattern'] = $pattern;
    326491  drupal_alter('pathauto_alias', $alias, $context);
    327492
     
    331496  }
    332497
    333   // If the alias already exists, generate a new, hopefully unique, variant
    334   if (_pathauto_alias_exists($alias, $source, $language)) {
    335     $maxlength = min(variable_get('pathauto_max_length', 100), _pathauto_get_schema_alias_maxlength());
    336     $separator = variable_get('pathauto_separator', '-');
    337     $original_alias = $alias;
    338 
    339     $i = 0;
    340     do {
    341       // Append an incrementing numeric suffix until we find a unique alias.
    342       $unique_suffix = $separator . $i;
    343       $alias = drupal_substr($original_alias, 0, $maxlength - drupal_strlen($unique_suffix, TRUE)) . $unique_suffix;
    344       $i++;
    345     } while (_pathauto_alias_exists($alias, $source, $language));
    346 
     498  // If the alias already exists, generate a new, hopefully unique, variant.
     499  $original_alias = $alias;
     500  pathauto_alias_uniquify($alias, $source, $language);
     501  if ($original_alias != $alias) {
    347502    // Alert the user why this happened.
    348503    _pathauto_verbose(t('The automatically generated alias %original_alias conflicted with an existing alias. Alias changed to %alias.', array(
     
    363518    'language' => $language,
    364519  );
    365   _pathauto_set_alias($path, $existing_alias, $op);
    366 
    367   // Also create a related feed alias if requested and supported.
    368   $feedappend = trim(variable_get('pathauto_' . $module . '_applytofeeds', ''));
    369   if (drupal_strlen($feedappend)) {
    370     // For forums and taxonomies, the source doesn't always form the base of the RSS feed (i.e. image galleries)
    371     if ($module == 'taxonomy' || $module == 'forum' && !empty($entity_id)) {
    372       $source = "taxonomy/term/{$entity_id}";
    373     }
    374 
    375     // Build the feed path alias array and send it off to be created.
    376     $path = array(
    377       'source' => "$source/$feedappend",
    378       'alias' => "$alias/feed",
    379       'language' => $language,
    380     );
    381     $existing_alias = _pathauto_existing_alias_data($path['source'], $path['language']);
    382     _pathauto_set_alias($path, $existing_alias, $op);
    383   }
    384 
    385   return $alias;
     520  $success = _pathauto_set_alias($path, $existing_alias, $op);
     521  return $success ? $alias : NULL;
     522}
     523
     524/**
     525 * Check to ensure a path alias is unique and add suffix variants if necessary.
     526 *
     527 * Given an alias 'content/test' if a path alias with the exact alias already
     528 * exists, the function will change the alias to 'content/test-0' and will
     529 * increase the number suffix until it finds a unique alias.
     530 *
     531 * @param $alias
     532 *   A string with the alias. Can be altered by reference.
     533 * @param $source
     534 *   A string with the path source.
     535 * @param $langcode
     536 *   A string with a language code.
     537 */
     538function pathauto_alias_uniquify(&$alias, $source, $langcode) {
     539  if (!_pathauto_alias_exists($alias, $source, $langcode)) {
     540    return;
     541  }
     542
     543  // If the alias already exists, generate a new, hopefully unique, variant
     544  $maxlength = min(variable_get('pathauto_max_length', 100), _pathauto_get_schema_alias_maxlength());
     545  $separator = variable_get('pathauto_separator', '-');
     546  $original_alias = $alias;
     547
     548  $i = 0;
     549  do {
     550    // Append an incrementing numeric suffix until we find a unique alias.
     551    $unique_suffix = $separator . $i;
     552    $alias = pathauto_truncate_utf8($original_alias, $maxlength - drupal_strlen($unique_suffix), TRUE) . $unique_suffix;
     553    $i++;
     554  } while (_pathauto_alias_exists($alias, $source, $langcode));
    386555}
    387556
     
    399568  $menu = menu_get_item($path);
    400569  if (isset($menu['path']) && $menu['path'] == $path) {
     570    return TRUE;
     571  }
     572  elseif (is_file('./' . $path) || is_dir('./' . $path)) {
     573    // Do not allow existing files or directories to get assigned an automatic
     574    // alias. Note that we do not need to use is_link() to check for symbolic
     575    // links since this returns TRUE for either is_file() or is_dir() already.
    401576    return TRUE;
    402577  }
     
    417592 * @param $op
    418593 *   An optional string with the operation being performed.
    419  * @return
    420  *   TRUE if the path was saved, or NULL otherwise.
     594 *
     595 * @return
     596 *   The saved path from path_save() or NULL if the path was not saved.
    421597 *
    422598 * @see path_set_alias()
     
    440616  }
    441617
    442   $path += array(
    443     'pid' => NULL,
    444     'language' => '',
    445   );
    446 
    447618  // Skip replacing the current alias with an identical alias
    448619  if (empty($existing_alias) || $existing_alias['alias'] != $path['alias']) {
     620    $path += array('pid' => NULL, 'language' => '');
     621
    449622    // If there is already an alias, respect some update actions.
    450623    if (!empty($existing_alias)) {
    451       switch (variable_get('pathauto_update_action', 2)) {
    452         case 0:
     624      switch (variable_get('pathauto_update_action', PATHAUTO_UPDATE_ACTION_DELETE)) {
     625        case PATHAUTO_UPDATE_ACTION_NO_NEW:
    453626          // Do not create the alias.
    454627          return;
    455         case 1:
     628        case PATHAUTO_UPDATE_ACTION_LEAVE:
    456629          // Create a new alias instead of overwriting the existing by leaving
    457630          // $path['pid'] empty.
    458631          break;
    459         case 3:
     632        case PATHAUTO_UPDATE_ACTION_REDIRECT:
    460633          // Create a redirect
    461634          if (module_exists('path_redirect') && function_exists('path_redirect_save')) {
    462635            $redirect = array(
    463636              'source' => $existing_alias['alias'],
     637              'language' => $existing_alias['language'],
    464638              'redirect' => $path['source'],
    465639            );
     
    468642          // Intentionally fall through to the next condition since we still
    469643          // want to replace the existing alias.
    470         case 2:
     644        case PATHAUTO_UPDATE_ACTION_DELETE:
    471645          // Both the redirect and delete actions should overwrite the existing
    472646          // alias.
     
    491665    }
    492666
    493     return TRUE;
     667    return $path;
    494668  }
    495669}
     
    532706 * Generalized function to get tokens across all Pathauto types.
    533707 *
     708 * @param $type
     709 *   The token type to pass to token_get_values().
    534710 * @param $object
    535  *   A user, node, or category object.
     711 *   The object to pass to token_get_values().
     712 * @param $text
     713 *   (optional) The string that will be replaced with tokens. If provided
     714 *   and the token_scan() function is available it will be used to trim down
     715 *   the number of tokens that need to be passed to
     716 *   pathauto_clean_token_values().
     717 *
    536718 * @return
    537719 *   Tokens for that object formatted in the way that
    538720 *   Pathauto expects to see them.
    539721 */
    540 function pathauto_get_placeholders($type, $object) {
    541   if (!function_exists('token_get_values')) {
    542     // TODO at some point try removing this and see if install profiles have problems again.
    543     watchdog('Pathauto', 'It appears that you have installed Pathauto, which depends on token, but token is either not installed or not installed properly.');
    544     return array('tokens' => array(), 'values' => array());
    545   }
    546 
    547   $options = array('pathauto' => TRUE);
     722function pathauto_get_placeholders($type, $object, $text = '', array $options = array()) {
     723  $options += array('pathauto' => TRUE);
     724
    548725  $full = token_get_values($type, $object, TRUE, $options);
     726
     727  // Attempt to reduce the tokens to only the ones that will actually be used
     728  // before passing into pathauto_clean_token_values().
     729  static $token_scan_exists;
     730  if (!isset($token_scan_exists)) {
     731    $token_scan_exists = function_exists('token_scan');
     732  }
     733  if ($token_scan_exists && !empty($text)) {
     734    $used_tokens = token_scan($text);
     735    foreach ($full->tokens as $index => $token) {
     736      if (!in_array($token, $used_tokens)) {
     737        unset($full->tokens[$index]);
     738        unset($full->values[$index]);
     739      }
     740    }
     741  }
     742
    549743  $tokens = token_prepare_tokens($full->tokens);
    550744  $values = pathauto_clean_token_values($full, $options);
     
    571765      // should have each segment cleaned, and then glued back together to
    572766      // construct a value resembling an URL.
    573       $segments = array_map('pathauto_cleanstring', $value);
     767      $segments = array();
     768      foreach ($value as $segment) {
     769        $segments[] = pathauto_cleanstring($segment, $options);
     770      }
    574771      $replacements[$token] = implode('/', $segments);
    575772    }
     
    580777    else {
    581778      // Token is not an URL, so it should have its value cleaned.
    582       $replacements[$token] = pathauto_cleanstring($value);
     779      $replacements[$token] = pathauto_cleanstring($value, $options);
    583780    }
    584781  }
     
    598795 */
    599796function pathauto_punctuation_chars() {
    600   static $punctuation;
     797  $punctuation = &pathauto_static(__FUNCTION__);
    601798
    602799  if (!isset($punctuation)) {
    603     $punctuation = array();
    604     $punctuation['double_quotes']      = array('value' => '"', 'name' => t('Double quotes "'));
    605     $punctuation['quotes']             = array('value' => "'", 'name' => t("Single quotes (apostrophe) '"));
    606     $punctuation['backtick']           = array('value' => '`', 'name' => t('Back tick `'));
    607     $punctuation['comma']              = array('value' => ',', 'name' => t('Comma ,'));
    608     $punctuation['period']             = array('value' => '.', 'name' => t('Period .'));
    609     $punctuation['hyphen']             = array('value' => '-', 'name' => t('Hyphen -'));
    610     $punctuation['underscore']         = array('value' => '_', 'name' => t('Underscore _'));
    611     $punctuation['colon']              = array('value' => ':', 'name' => t('Colon :'));
    612     $punctuation['semicolon']          = array('value' => ';', 'name' => t('Semicolon ;'));
    613     $punctuation['pipe']               = array('value' => '|', 'name' => t('Pipe |'));
    614     $punctuation['left_curly']         = array('value' => '{', 'name' => t('Left curly bracket {'));
    615     $punctuation['left_square']        = array('value' => '[', 'name' => t('Left square bracket ['));
    616     $punctuation['right_curly']        = array('value' => '}', 'name' => t('Right curly bracket }'));
    617     $punctuation['right_square']       = array('value' => ']', 'name' => t('Right square bracket ]'));
    618     $punctuation['plus']               = array('value' => '+', 'name' => t('Plus +'));
    619     $punctuation['equal']              = array('value' => '=', 'name' => t('Equal ='));
    620     $punctuation['asterisk']           = array('value' => '*', 'name' => t('Asterisk *'));
    621     $punctuation['ampersand']          = array('value' => '&', 'name' => t('Ampersand &'));
    622     $punctuation['percent']            = array('value' => '%', 'name' => t('Percent %'));
    623     $punctuation['caret']              = array('value' => '^', 'name' => t('Caret ^'));
    624     $punctuation['dollar']             = array('value' => '$', 'name' => t('Dollar $'));
    625     $punctuation['hash']               = array('value' => '#', 'name' => t('Hash #'));
    626     $punctuation['at']                 = array('value' => '@', 'name' => t('At @'));
    627     $punctuation['exclamation']        = array('value' => '!', 'name' => t('Exclamation !'));
    628     $punctuation['tilde']              = array('value' => '~', 'name' => t('Tilde ~'));
    629     $punctuation['left_parenthesis']   = array('value' => '(', 'name' => t('Left parenthesis ('));
    630     $punctuation['right_parenthesis']  = array('value' => ')', 'name' => t('Right parenthesis )'));
    631     $punctuation['question_mark']      = array('value' => '?', 'name' => t('Question mark ?'));
    632     $punctuation['less_than']          = array('value' => '<', 'name' => t('Less than <'));
    633     $punctuation['greater_than']       = array('value' => '>', 'name' => t('Greater than >'));
    634     $punctuation['slash']              = array('value' => '/', 'name' => t('Slash /'));
    635     $punctuation['back_slash']         = array('value' => '\\', 'name' => t('Backslash \\'));
     800    $cid = 'pathauto:punctuation:' . $GLOBALS['language']->language;
     801    if ($cache = cache_get($cid)) {
     802      $punctuation = $cache->data;
     803    }
     804    else {
     805      $punctuation = array();
     806      $punctuation['double_quotes']      = array('value' => '"', 'name' => t('Double quotation marks'));
     807      $punctuation['quotes']             = array('value' => '\'', 'name' => t("Single quotation marks (apostrophe)"));
     808      $punctuation['backtick']           = array('value' => '`', 'name' => t('Back tick'));
     809      $punctuation['comma']              = array('value' => ',', 'name' => t('Comma'));
     810      $punctuation['period']             = array('value' => '.', 'name' => t('Period'));
     811      $punctuation['hyphen']             = array('value' => '-', 'name' => t('Hyphen'));
     812      $punctuation['underscore']         = array('value' => '_', 'name' => t('Underscore'));
     813      $punctuation['colon']              = array('value' => ':', 'name' => t('Colon'));
     814      $punctuation['semicolon']          = array('value' => ';', 'name' => t('Semicolon'));
     815      $punctuation['pipe']               = array('value' => '|', 'name' => t('Vertical bar (pipe)'));
     816      $punctuation['left_curly']         = array('value' => '{', 'name' => t('Left curly bracket'));
     817      $punctuation['left_square']        = array('value' => '[', 'name' => t('Left square bracket'));
     818      $punctuation['right_curly']        = array('value' => '}', 'name' => t('Right curly bracket'));
     819      $punctuation['right_square']       = array('value' => ']', 'name' => t('Right square bracket'));
     820      $punctuation['plus']               = array('value' => '+', 'name' => t('Plus sign'));
     821      $punctuation['equal']              = array('value' => '=', 'name' => t('Equal sign'));
     822      $punctuation['asterisk']           = array('value' => '*', 'name' => t('Asterisk'));
     823      $punctuation['ampersand']          = array('value' => '&', 'name' => t('Ampersand'));
     824      $punctuation['percent']            = array('value' => '%', 'name' => t('Percent sign'));
     825      $punctuation['caret']              = array('value' => '^', 'name' => t('Caret'));
     826      $punctuation['dollar']             = array('value' => '$', 'name' => t('Dollar sign'));
     827      $punctuation['hash']               = array('value' => '#', 'name' => t('Number sign (pound sign, hash)'));
     828      $punctuation['at']                 = array('value' => '@', 'name' => t('At sign'));
     829      $punctuation['exclamation']        = array('value' => '!', 'name' => t('Exclamation mark'));
     830      $punctuation['tilde']              = array('value' => '~', 'name' => t('Tilde'));
     831      $punctuation['left_parenthesis']   = array('value' => '(', 'name' => t('Left parenthesis'));
     832      $punctuation['right_parenthesis']  = array('value' => ')', 'name' => t('Right parenthesis'));
     833      $punctuation['question_mark']      = array('value' => '?', 'name' => t('Question mark'));
     834      $punctuation['less_than']          = array('value' => '<', 'name' => t('Less-than sign'));
     835      $punctuation['greater_than']       = array('value' => '>', 'name' => t('Greater-than sign'));
     836      $punctuation['slash']              = array('value' => '/', 'name' => t('Slash'));
     837      $punctuation['back_slash']         = array('value' => '\\', 'name' => t('Backslash'));
     838
     839      // Allow modules to alter the punctuation list and cache the result.
     840      drupal_alter('pathauto_punctuation_chars', $punctuation);
     841      cache_set($cid, $punctuation);
     842    }
    636843  }
    637844
     
    655862
    656863/**
     864 * Truncates a UTF-8-encoded string safely to a number of characters.
     865 *
     866 * This is a functional backport of Drupal 7's truncate_utf8().
     867 *
     868 * @param $string
     869 *   The string to truncate.
     870 * @param $max_length
     871 *   An upper limit on the returned string length, including trailing ellipsis
     872 *   if $add_ellipsis is TRUE.
     873 * @param $wordsafe
     874 *   If TRUE, attempt to truncate on a word boundary. Word boundaries are
     875 *   spaces, punctuation, and Unicode characters used as word boundaries in
     876 *   non-Latin languages; see PREG_CLASS_UNICODE_WORD_BOUNDARY for more
     877 *   information.  If a word boundary cannot be found that would make the length
     878 *   of the returned string fall within length guidelines (see parameters
     879 *   $max_return_length and $min_wordsafe_length), word boundaries are ignored.
     880 * @param $add_ellipsis
     881 *   If TRUE, add t('...') to the end of the truncated string (defaults to
     882 *   FALSE). The string length will still fall within $max_return_length.
     883 * @param $min_wordsafe_length
     884 *   If $wordsafe is TRUE, the minimum acceptable length for truncation (before
     885 *   adding an ellipsis, if $add_ellipsis is TRUE). Has no effect if $wordsafe
     886 *   is FALSE. This can be used to prevent having a very short resulting string
     887 *   that will not be understandable. For instance, if you are truncating the
     888 *   string "See myverylongurlexample.com for more information" to a word-safe
     889 *   return length of 20, the only available word boundary within 20 characters
     890 *   is after the word "See", which wouldn't leave a very informative string. If
     891 *   you had set $min_wordsafe_length to 10, though, the function would realize
     892 *   that "See" alone is too short, and would then just truncate ignoring word
     893 *   boundaries, giving you "See myverylongurl..." (assuming you had set
     894 *   $add_ellipses to TRUE).
     895 *
     896 * @return
     897 *   The truncated string.
     898 */
     899function pathauto_truncate_utf8($string, $max_length, $wordsafe = FALSE, $add_ellipsis = FALSE, $min_wordsafe_length = 1) {
     900  $ellipsis = '';
     901  $max_length = max($max_length, 0);
     902  $min_wordsafe_length = max($min_wordsafe_length, 0);
     903
     904  if (drupal_strlen($string) <= $max_length) {
     905    // No truncation needed, so don't add ellipsis, just return.
     906    return $string;
     907  }
     908
     909  if ($add_ellipsis) {
     910    // Truncate ellipsis in case $max_length is small.
     911    $ellipsis = drupal_substr(t('...'), 0, $max_length);
     912    $max_length -= drupal_strlen($ellipsis);
     913    $max_length = max($max_length, 0);
     914  }
     915
     916  if ($max_length <= $min_wordsafe_length) {
     917    // Do not attempt word-safe if lengths are bad.
     918    $wordsafe = FALSE;
     919  }
     920
     921  if ($wordsafe) {
     922    $matches = array();
     923    // Find the last word boundary, if there is one within $min_wordsafe_length
     924    // to $max_length characters. preg_match() is always greedy, so it will
     925    // find the longest string possible.
     926    $found = preg_match('/^(.{' . $min_wordsafe_length . ',' . $max_length . '})[' . PATHAUTO_PREG_CLASS_UNICODE_WORD_BOUNDARY . ']/u', $string, $matches);
     927    if ($found) {
     928      $string = $matches[1];
     929    }
     930    else {
     931      $string = drupal_substr($string, 0, $max_length);
     932    }
     933  }
     934  else {
     935    $string = drupal_substr($string, 0, $max_length);
     936  }
     937
     938  if ($add_ellipsis) {
     939    $string .= $ellipsis;
     940  }
     941
     942  return $string;
     943}
     944
     945/**
    657946 * Fetch an array of non-raw tokens that have matching raw tokens.
    658947 *
     
    683972  return $raw_tokens;
    684973}
    685 
    686 /**
    687  * Return all the possible paths of the i18n-ascii.txt transliteration file.
    688  *
    689  * @return
    690  *   An array of possible file paths.
    691  */
    692 function _pathauto_get_i18n_possible_files() {
    693   $file = 'i18n-ascii.txt';
    694   $files = array(
    695     conf_path() . '/' . $file,
    696     "sites/all/$file",
    697     drupal_get_path('module', 'pathauto') . '/' . $file,
    698   );
    699   // Always prefer $conf['pathauto_i18n_file'] if defined.
    700   if ($conf_file = variable_get('pathauto_i18n_file', '')) {
    701     array_unshift($files, $conf_file);
    702   }
    703   return $files;
    704 }
    705 
    706 /**
    707  * Fetch the path to the i18n-ascii.txt transliteration file
    708  *
    709  * @return
    710  *   The complete path or FALSE if not found in any of the possible paths.
    711  *
    712  * @see _pathauto_get_i18n_possible_files()
    713  */
    714 function _pathauto_get_i18n_file() {
    715   static $i18n_file;
    716 
    717   if (!isset($i18n_file)) {
    718     $i18n_file = FALSE;
    719     foreach (_pathauto_get_i18n_possible_files() as $file) {
    720       if (file_exists($file)) {
    721         $i18n_file = $file;
    722         break;
    723       }
    724     }
    725   }
    726 
    727   return $i18n_file;
    728 }
Nota: Vea TracChangeset para ayuda en el uso del visor de conjuntos de cambios.