| 1 |
<?php
|
| 2 |
// $Id: pathauto.inc,v 1.53 2009/10/20 17:52:41 greggles Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Miscellaneous functions for Pathauto.
|
| 7 |
*
|
| 8 |
* This also contains some constants giving human readable names to some numeric
|
| 9 |
* settings; they're included here as they're only rarely used outside this file
|
| 10 |
* anyway. Use _pathauto_include() if the constants need to be available.
|
| 11 |
*
|
| 12 |
* @ingroup pathauto
|
| 13 |
*/
|
| 14 |
|
| 15 |
/**
|
| 16 |
* Case should be left as is in the generated path.
|
| 17 |
*/
|
| 18 |
define('PATHAUTO_CASE_LEAVE_ASIS', 0);
|
| 19 |
|
| 20 |
/**
|
| 21 |
* Case should be lowercased in the generated path.
|
| 22 |
*/
|
| 23 |
define('PATHAUTO_CASE_LOWER', 1);
|
| 24 |
|
| 25 |
/**
|
| 26 |
* "Do nothing. Leave the old alias intact."
|
| 27 |
*/
|
| 28 |
define('PATHAUTO_UPDATE_ACTION_NO_NEW', 0);
|
| 29 |
|
| 30 |
/**
|
| 31 |
* "Create a new alias. Leave the existing alias functioning."
|
| 32 |
*/
|
| 33 |
define('PATHAUTO_UPDATE_ACTION_LEAVE', 1);
|
| 34 |
|
| 35 |
/**
|
| 36 |
* "Create a new alias. Delete the old alias."
|
| 37 |
*/
|
| 38 |
define('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 |
*/
|
| 45 |
define('PATHAUTO_UPDATE_ACTION_REDIRECT', 3);
|
| 46 |
|
| 47 |
/**
|
| 48 |
* Remove the punctuation from the alias.
|
| 49 |
*/
|
| 50 |
define('PATHAUTO_PUNCTUATION_REMOVE', 0);
|
| 51 |
|
| 52 |
/**
|
| 53 |
* Replace the punctuation with the separator in the alias.
|
| 54 |
*/
|
| 55 |
define('PATHAUTO_PUNCTUATION_REPLACE', 1);
|
| 56 |
|
| 57 |
/**
|
| 58 |
* Leave the punctuation as it is in the alias.
|
| 59 |
*/
|
| 60 |
define('PATHAUTO_PUNCTUATION_DO_NOTHING', 2);
|
| 61 |
|
| 62 |
/**
|
| 63 |
* Matches Unicode character classes.
|
| 64 |
*
|
| 65 |
* See: http://www.unicode.org/Public/UNIDATA/UCD.html#General_Category_Values
|
| 66 |
*
|
| 67 |
* The index only contains the following character classes:
|
| 68 |
* Lu Letter, Uppercase
|
| 69 |
* Ll Letter, Lowercase
|
| 70 |
* Lt Letter, Titlecase
|
| 71 |
* Lo Letter, Other
|
| 72 |
* Nd Number, Decimal Digit
|
| 73 |
* No Number, Other
|
| 74 |
*
|
| 75 |
* Copied from search.module's PREG_CLASS_SEARCH_EXCLUDE.
|
| 76 |
*/
|
| 77 |
define('PREG_CLASS_ALNUM',
|
| 78 |
'\x{0}-\x{2f}\x{3a}-\x{40}\x{5b}-\x{60}\x{7b}-\x{bf}\x{d7}\x{f7}\x{2b0}-'.
|
| 79 |
'\x{385}\x{387}\x{3f6}\x{482}-\x{489}\x{559}-\x{55f}\x{589}-\x{5c7}\x{5f3}-'.
|
| 80 |
'\x{61f}\x{640}\x{64b}-\x{65e}\x{66a}-\x{66d}\x{670}\x{6d4}\x{6d6}-\x{6ed}'.
|
| 81 |
'\x{6fd}\x{6fe}\x{700}-\x{70f}\x{711}\x{730}-\x{74a}\x{7a6}-\x{7b0}\x{901}-'.
|
| 82 |
'\x{903}\x{93c}\x{93e}-\x{94d}\x{951}-\x{954}\x{962}-\x{965}\x{970}\x{981}-'.
|
| 83 |
'\x{983}\x{9bc}\x{9be}-\x{9cd}\x{9d7}\x{9e2}\x{9e3}\x{9f2}-\x{a03}\x{a3c}-'.
|
| 84 |
'\x{a4d}\x{a70}\x{a71}\x{a81}-\x{a83}\x{abc}\x{abe}-\x{acd}\x{ae2}\x{ae3}'.
|
| 85 |
'\x{af1}-\x{b03}\x{b3c}\x{b3e}-\x{b57}\x{b70}\x{b82}\x{bbe}-\x{bd7}\x{bf0}-'.
|
| 86 |
'\x{c03}\x{c3e}-\x{c56}\x{c82}\x{c83}\x{cbc}\x{cbe}-\x{cd6}\x{d02}\x{d03}'.
|
| 87 |
'\x{d3e}-\x{d57}\x{d82}\x{d83}\x{dca}-\x{df4}\x{e31}\x{e34}-\x{e3f}\x{e46}-'.
|
| 88 |
'\x{e4f}\x{e5a}\x{e5b}\x{eb1}\x{eb4}-\x{ebc}\x{ec6}-\x{ecd}\x{f01}-\x{f1f}'.
|
| 89 |
'\x{f2a}-\x{f3f}\x{f71}-\x{f87}\x{f90}-\x{fd1}\x{102c}-\x{1039}\x{104a}-'.
|
| 90 |
'\x{104f}\x{1056}-\x{1059}\x{10fb}\x{10fc}\x{135f}-\x{137c}\x{1390}-\x{1399}'.
|
| 91 |
'\x{166d}\x{166e}\x{1680}\x{169b}\x{169c}\x{16eb}-\x{16f0}\x{1712}-\x{1714}'.
|
| 92 |
'\x{1732}-\x{1736}\x{1752}\x{1753}\x{1772}\x{1773}\x{17b4}-\x{17db}\x{17dd}'.
|
| 93 |
'\x{17f0}-\x{180e}\x{1843}\x{18a9}\x{1920}-\x{1945}\x{19b0}-\x{19c0}\x{19c8}'.
|
| 94 |
'\x{19c9}\x{19de}-\x{19ff}\x{1a17}-\x{1a1f}\x{1d2c}-\x{1d61}\x{1d78}\x{1d9b}-'.
|
| 95 |
'\x{1dc3}\x{1fbd}\x{1fbf}-\x{1fc1}\x{1fcd}-\x{1fcf}\x{1fdd}-\x{1fdf}\x{1fed}-'.
|
| 96 |
'\x{1fef}\x{1ffd}-\x{2070}\x{2074}-\x{207e}\x{2080}-\x{2101}\x{2103}-\x{2106}'.
|
| 97 |
'\x{2108}\x{2109}\x{2114}\x{2116}-\x{2118}\x{211e}-\x{2123}\x{2125}\x{2127}'.
|
| 98 |
'\x{2129}\x{212e}\x{2132}\x{213a}\x{213b}\x{2140}-\x{2144}\x{214a}-\x{2b13}'.
|
| 99 |
'\x{2ce5}-\x{2cff}\x{2d6f}\x{2e00}-\x{3005}\x{3007}-\x{303b}\x{303d}-\x{303f}'.
|
| 100 |
'\x{3099}-\x{309e}\x{30a0}\x{30fb}-\x{30fe}\x{3190}-\x{319f}\x{31c0}-\x{31cf}'.
|
| 101 |
'\x{3200}-\x{33ff}\x{4dc0}-\x{4dff}\x{a015}\x{a490}-\x{a716}\x{a802}\x{a806}'.
|
| 102 |
'\x{a80b}\x{a823}-\x{a82b}\x{d800}-\x{f8ff}\x{fb1e}\x{fb29}\x{fd3e}\x{fd3f}'.
|
| 103 |
'\x{fdfc}-\x{fe6b}\x{feff}-\x{ff0f}\x{ff1a}-\x{ff20}\x{ff3b}-\x{ff40}\x{ff5b}-'.
|
| 104 |
'\x{ff65}\x{ff70}\x{ff9e}\x{ff9f}\x{ffe0}-\x{fffd}');
|
| 105 |
|
| 106 |
/**
|
| 107 |
* Check to see if there is already an alias pointing to a different item.
|
| 108 |
*
|
| 109 |
* @param $alias
|
| 110 |
* A string alias (i.e. dst).
|
| 111 |
* @param $src
|
| 112 |
* A string that is the internal path.
|
| 113 |
* @param $language
|
| 114 |
* A string indicating the path's language.
|
| 115 |
* @return
|
| 116 |
* TRUE if an alias exists, FALSE if not.
|
| 117 |
*/
|
| 118 |
function _pathauto_alias_exists($alias, $src, $language = '') {
|
| 119 |
$alias_pid = db_result(db_query_range("SELECT pid FROM {url_alias} WHERE dst = '%s' AND src <> '%s' AND language = '%s'", array($alias, $src, $language), 0, 1));
|
| 120 |
if (function_exists('path_redirect_delete')) {
|
| 121 |
// Delete from path_redirect the exact same alias to the same node.
|
| 122 |
path_redirect_delete(array('path' => $alias, 'redirect' => $src));
|
| 123 |
|
| 124 |
// If there still is this alias used in path_redirect, then create a different alias
|
| 125 |
$redirect_rid = db_result(db_query_range("SELECT rid FROM {path_redirect} WHERE path = '%s'", $alias, 0, 1));
|
| 126 |
}
|
| 127 |
if ($alias_pid || !empty($redirect_rid)) {
|
| 128 |
return TRUE;
|
| 129 |
}
|
| 130 |
else {
|
| 131 |
return FALSE;
|
| 132 |
}
|
| 133 |
}
|
| 134 |
|
| 135 |
/**
|
| 136 |
* Returns old alias and pid if there is already an alias
|
| 137 |
* pointing to a different item.
|
| 138 |
*
|
| 139 |
* @param $src
|
| 140 |
* A string that is the internal path.
|
| 141 |
* @return
|
| 142 |
* An array with the keys "pid" and "old_alias" containing
|
| 143 |
* the "pid" and old "alias", respectively, of the old alias.
|
| 144 |
*/
|
| 145 |
function _pathauto_existing_alias_data($src) {
|
| 146 |
$output = array(
|
| 147 |
'pid' => '',
|
| 148 |
'old_alias' => ''
|
| 149 |
);
|
| 150 |
$result = db_query("SELECT pid, dst FROM {url_alias} WHERE src='%s'", $src);
|
| 151 |
if ($data = db_fetch_object($result)) {
|
| 152 |
// The item is already aliased, check what to do...
|
| 153 |
switch (variable_get('pathauto_update_action', PATHAUTO_UPDATE_ACTION_DELETE)) {
|
| 154 |
// Replace old alias - remember the pid to update
|
| 155 |
case PATHAUTO_UPDATE_ACTION_DELETE:
|
| 156 |
case PATHAUTO_UPDATE_ACTION_REDIRECT:
|
| 157 |
$output['pid'] = $data->pid;
|
| 158 |
// Add new alias in addition to old one
|
| 159 |
case PATHAUTO_UPDATE_ACTION_LEAVE:
|
| 160 |
$output['old_alias'] = $data->dst;
|
| 161 |
break;
|
| 162 |
// Do nothing
|
| 163 |
case PATHAUTO_UPDATE_ACTION_NO_NEW:
|
| 164 |
default:
|
| 165 |
break;
|
| 166 |
}
|
| 167 |
}
|
| 168 |
return $output;
|
| 169 |
}
|
| 170 |
|
| 171 |
/**
|
| 172 |
* Clean up a string value provided by a module.
|
| 173 |
*
|
| 174 |
* Resulting string contains only alphanumerics and separators.
|
| 175 |
*
|
| 176 |
* @param $string
|
| 177 |
* A string to clean.
|
| 178 |
* @param $clean_slash
|
| 179 |
* Whether to clean slashes from the given string.
|
| 180 |
* @return
|
| 181 |
* The cleaned string.
|
| 182 |
*/
|
| 183 |
function pathauto_cleanstring($string, $clean_slash = TRUE) {
|
| 184 |
// Default words to ignore
|
| 185 |
$ignore_words = array(
|
| 186 |
'a', 'an', 'as', 'at', 'before', 'but', 'by', 'for', 'from', 'is', 'in',
|
| 187 |
'into', 'like', 'of', 'off', 'on', 'onto', 'per', 'since', 'than', 'the',
|
| 188 |
'this', 'that', 'to', 'up', 'via', 'with',
|
| 189 |
);
|
| 190 |
|
| 191 |
// Replace or drop punctuation based on user settings
|
| 192 |
$separator = variable_get('pathauto_separator', '-');
|
| 193 |
$output = $string;
|
| 194 |
$punctuation = pathauto_punctuation_chars();
|
| 195 |
foreach ($punctuation as $name => $details) {
|
| 196 |
$action = variable_get('pathauto_punctuation_'. $name, PATHAUTO_PUNCTUATION_REMOVE);
|
| 197 |
if ($action != PATHAUTO_PUNCTUATION_DO_NOTHING) {
|
| 198 |
// Slightly tricky inline if which either replaces with the separator or nothing
|
| 199 |
$output = str_replace($details['value'], ($action ? $separator : ''), $output);
|
| 200 |
}
|
| 201 |
}
|
| 202 |
|
| 203 |
// If something is already urlsafe then don't remove slashes
|
| 204 |
if ($clean_slash) {
|
| 205 |
$output = str_replace('/', '', $output);
|
| 206 |
}
|
| 207 |
|
| 208 |
// Optionally transliterate (by running through the Transliteration module)
|
| 209 |
if (variable_get('pathauto_transliterate', FALSE)) {
|
| 210 |
if (module_exists('transliteration')) {
|
| 211 |
$output = transliteration_get($output);
|
| 212 |
}
|
| 213 |
else {
|
| 214 |
drupal_set_message(t('Pathauto could not transliterate the path, as the Transliteration module has been disabled.'), 'error');
|
| 215 |
}
|
| 216 |
}
|
| 217 |
|
| 218 |
// Reduce to the subset of ASCII96 letters and numbers
|
| 219 |
if (variable_get('pathauto_reduce_ascii', FALSE)) {
|
| 220 |
$pattern = '/[^a-zA-Z0-9\/]+/ ';
|
| 221 |
$output = preg_replace($pattern, $separator, $output);
|
| 222 |
}
|
| 223 |
|
| 224 |
// Get rid of words that are on the ignore list
|
| 225 |
$ignore_re = '\b'. preg_replace('/,/', '\b|\b', variable_get('pathauto_ignore_words', $ignore_words)) .'\b';
|
| 226 |
|
| 227 |
if (function_exists('mb_eregi_replace')) {
|
| 228 |
$output = mb_eregi_replace($ignore_re, '', $output);
|
| 229 |
}
|
| 230 |
else {
|
| 231 |
$output = preg_replace("/$ignore_re/i", '', $output);
|
| 232 |
}
|
| 233 |
|
| 234 |
// Always replace whitespace with the separator.
|
| 235 |
$output = preg_replace('/\s+/', $separator, $output);
|
| 236 |
|
| 237 |
// In preparation for pattern matching,
|
| 238 |
// escape the separator if and only if it is not alphanumeric.
|
| 239 |
if (isset($separator)) {
|
| 240 |
if (preg_match('/^[^'. PREG_CLASS_ALNUM .']+$/uD', $separator)) {
|
| 241 |
$seppattern = $separator;
|
| 242 |
}
|
| 243 |
else {
|
| 244 |
$seppattern = '\\'. $separator;
|
| 245 |
}
|
| 246 |
// Trim any leading or trailing separators.
|
| 247 |
$output = preg_replace("/^$seppattern+|$seppattern+$/", '', $output);
|
| 248 |
|
| 249 |
// Replace trailing separators around slashes.
|
| 250 |
$output = preg_replace("/$seppattern\/|\/$seppattern/", "/", $output);
|
| 251 |
|
| 252 |
// Replace multiple separators with a single one.
|
| 253 |
$output = preg_replace("/$seppattern+/", "$separator", $output);
|
| 254 |
|
| 255 |
// Optionally convert to lower case.
|
| 256 |
if (variable_get('pathauto_case', PATHAUTO_CASE_LOWER)) {
|
| 257 |
$output = drupal_strtolower($output);
|
| 258 |
}
|
| 259 |
}
|
| 260 |
|
| 261 |
// Enforce the maximum component length
|
| 262 |
$maxlength = min(variable_get('pathauto_max_component_length', 100), 128);
|
| 263 |
$output = _pathauto_truncate_chars($output, $maxlength, $separator);
|
| 264 |
|
| 265 |
return $output;
|
| 266 |
}
|
| 267 |
|
| 268 |
/**
|
| 269 |
* Apply patterns to create an alias.
|
| 270 |
*
|
| 271 |
* @param $module
|
| 272 |
* The name of your module (e.g., 'node').
|
| 273 |
* @param $op
|
| 274 |
* Operation being performed on the content being aliased
|
| 275 |
* ('insert', 'update', 'return', or 'bulkupdate').
|
| 276 |
* @param $placeholders
|
| 277 |
* An array whose keys consist of the translated placeholders
|
| 278 |
* which appear in patterns (e.g., t('[title]')) and values are the
|
| 279 |
* actual values to be substituted into the pattern (e.g., $node->title).
|
| 280 |
* @param $src
|
| 281 |
* The "real" URI of the content to be aliased (e.g., "node/$node->nid").
|
| 282 |
* @param $type
|
| 283 |
* For modules which provided pattern items in hook_pathauto(),
|
| 284 |
* the relevant identifier for the specific item to be aliased
|
| 285 |
* (e.g., $node->type).
|
| 286 |
* @param $language
|
| 287 |
* A string specify the path's language.
|
| 288 |
* @return
|
| 289 |
* The alias that was created.
|
| 290 |
*/
|
| 291 |
function pathauto_create_alias($module, $op, $placeholders, $src, $entity_id, $type = NULL, $language = '') {
|
| 292 |
if (($op != 'bulkupdate') and variable_get('pathauto_verbose', FALSE) && user_access('notify of path changes')) {
|
| 293 |
$verbose = TRUE;
|
| 294 |
}
|
| 295 |
else {
|
| 296 |
$verbose = FALSE;
|
| 297 |
}
|
| 298 |
|
| 299 |
// Retrieve and apply the pattern for this content type
|
| 300 |
if (!empty($type)) {
|
| 301 |
$pattern = trim(variable_get('pathauto_'. $module .'_'. $type .'_'. $language .'_pattern', ''));
|
| 302 |
if (empty($pattern)) {
|
| 303 |
$pattern = trim(variable_get('pathauto_'. $module .'_'. $type .'_pattern', ''));
|
| 304 |
}
|
| 305 |
}
|
| 306 |
if (empty($pattern)) {
|
| 307 |
$pattern = trim(variable_get('pathauto_'. $module .'_pattern', ''));
|
| 308 |
}
|
| 309 |
// No pattern? Do nothing (otherwise we may blow away existing aliases...)
|
| 310 |
if (empty($pattern)) {
|
| 311 |
return '';
|
| 312 |
}
|
| 313 |
|
| 314 |
if ($module == 'taxonomy') {
|
| 315 |
// Get proper path for term.
|
| 316 |
$term_path = taxonomy_term_path(taxonomy_get_term($entity_id));
|
| 317 |
if ($term_path != $src) {
|
| 318 |
// Quietly alias 'taxonomy/term/[tid]' with proper path for term.
|
| 319 |
$update_data = _pathauto_existing_alias_data($src);
|
| 320 |
_pathauto_set_alias($src, $term_path, $module, $entity_id, $update_data['pid'], FALSE, $update_data['old_alias'], $language);
|
| 321 |
// Set $src as proper path.
|
| 322 |
$src = $term_path;
|
| 323 |
}
|
| 324 |
}
|
| 325 |
|
| 326 |
// Special handling when updating an item which is already aliased.
|
| 327 |
$pid = NULL;
|
| 328 |
$old_alias = NULL;
|
| 329 |
if ($op == 'update' or $op == 'bulkupdate') {
|
| 330 |
if (variable_get('pathauto_update_action', PATHAUTO_UPDATE_ACTION_DELETE) == PATHAUTO_UPDATE_ACTION_NO_NEW) {
|
| 331 |
// Do nothing
|
| 332 |
return '';
|
| 333 |
}
|
| 334 |
$update_data = _pathauto_existing_alias_data($src);
|
| 335 |
$pid = $update_data['pid'];
|
| 336 |
$old_alias = $update_data['old_alias'];
|
| 337 |
}
|
| 338 |
|
| 339 |
// Replace the placeholders with the values provided by the module.
|
| 340 |
$alias = str_replace($placeholders['tokens'], $placeholders['values'], $pattern);
|
| 341 |
|
| 342 |
// Two or more slashes should be collapsed into one
|
| 343 |
$alias = preg_replace('/\/+/', '/', $alias);
|
| 344 |
|
| 345 |
// Trim any leading or trailing slashes
|
| 346 |
$alias = preg_replace('/^\/|\/+$/', '', $alias);
|
| 347 |
|
| 348 |
// Shorten to a logical place based on the last separator.
|
| 349 |
$separator = variable_get('pathauto_separator', '-');
|
| 350 |
$maxlength = min(variable_get('pathauto_max_length', 100), 128);
|
| 351 |
|
| 352 |
// Make sure we're not ending the alias in the middle of a word.
|
| 353 |
$alias = _pathauto_truncate_chars($alias, $maxlength, $separator);
|
| 354 |
|
| 355 |
// If the alias already exists, generate a new, hopefully unique, variant
|
| 356 |
if (_pathauto_alias_exists($alias, $src, $language)) {
|
| 357 |
$original_alias = $alias;
|
| 358 |
for ($i = 0; _pathauto_alias_exists(drupal_substr($alias, 0, $maxlength - strlen($i)) . $separator . $i, $src, $language); $i++) {
|
| 359 |
}
|
| 360 |
// Make room for the sequence number
|
| 361 |
$alias = drupal_substr($alias, 0, $maxlength - drupal_strlen($i));
|
| 362 |
$alias = $alias . $separator . $i;
|
| 363 |
// If verbose is on, alert the user why this happened
|
| 364 |
if ($verbose) {
|
| 365 |
drupal_set_message(t('The automatically generated alias %original_alias conflicted with an existing alias. Alias changed to %alias.',
|
| 366 |
array('%original_alias' => $original_alias, '%alias' => $alias)));
|
| 367 |
}
|
| 368 |
}
|
| 369 |
|
| 370 |
// Return the generated alias if requested.
|
| 371 |
if ($op == 'return') {
|
| 372 |
return $alias;
|
| 373 |
}
|
| 374 |
|
| 375 |
// If $pid is NULL, a new alias is created - otherwise, the existing
|
| 376 |
// alias for the designated src is replaced
|
| 377 |
_pathauto_set_alias($src, $alias, $module, $entity_id, $pid, $verbose, $old_alias, $language);
|
| 378 |
|
| 379 |
// Also create a related feed alias if requested, and if supported
|
| 380 |
// by the module
|
| 381 |
if (drupal_strlen(variable_get('pathauto_'. $module .'_applytofeeds', ''))) {
|
| 382 |
$feedappend = variable_get('pathauto_'. $module .'_applytofeeds', '');
|
| 383 |
|
| 384 |
// For forums and taxonomies, the src doesn't always form the base of the rss feed (ie. image galleries)
|
| 385 |
if ($module == 'taxonomy' || $module == 'forum') {
|
| 386 |
$update_data = _pathauto_existing_alias_data("taxonomy/term/$entity_id/$feedappend");
|
| 387 |
_pathauto_set_alias("taxonomy/term/$entity_id/$feedappend", "$alias/feed", $module, $entity_id, $update_data['pid'], $verbose, $update_data['old_alias'], $language);
|
| 388 |
}
|
| 389 |
else {
|
| 390 |
$update_data = _pathauto_existing_alias_data("$src/$feedappend");
|
| 391 |
_pathauto_set_alias("$src/$feedappend", "$alias/feed", $module, $entity_id, $update_data['pid'], $verbose, $update_data['old_alias'], $language);
|
| 392 |
}
|
| 393 |
}
|
| 394 |
|
| 395 |
return $alias;
|
| 396 |
}
|
| 397 |
|
| 398 |
/**
|
| 399 |
* Verify if the given path is a valid menu callback.
|
| 400 |
*
|
| 401 |
* Taken from menu_execute_active_handler().
|
| 402 |
*
|
| 403 |
* @param $path
|
| 404 |
* A string containing a relative path.
|
| 405 |
* @return
|
| 406 |
* TRUE if the path already exists.
|
| 407 |
*/
|
| 408 |
function _pathauto_path_is_callback($path) {
|
| 409 |
$menu = menu_get_item($path);
|
| 410 |
if (isset($menu['path']) && $menu['path'] == $path) {
|
| 411 |
return TRUE;
|
| 412 |
}
|
| 413 |
return FALSE;
|
| 414 |
}
|
| 415 |
|
| 416 |
/**
|
| 417 |
* Private function for Pathauto to create an alias.
|
| 418 |
*
|
| 419 |
* @param $src
|
| 420 |
* The internal path.
|
| 421 |
* @param $dst
|
| 422 |
* The visible externally used path.
|
| 423 |
* @param $pid
|
| 424 |
* If the item is currently aliased, the pid for that item.
|
| 425 |
* @param $verbose
|
| 426 |
* If the admin has enabled verbose, should be TRUE. Else FALSE or NULL.
|
| 427 |
* @param $old_alias
|
| 428 |
* If the item is currently aliased, the existing alias for that item.
|
| 429 |
* @param $language
|
| 430 |
* The path's language.
|
| 431 |
*/
|
| 432 |
function _pathauto_set_alias($src, $dst, $entity_type, $entity_id, $pid = NULL, $verbose = FALSE, $old_alias = NULL, $language = '') {
|
| 433 |
// Alert users that an existing callback cannot be overridden automatically
|
| 434 |
if (_pathauto_path_is_callback($dst)) {
|
| 435 |
if ($verbose && user_access('notify of path changes')) {
|
| 436 |
drupal_set_message(t('Ignoring alias %dst due to existing path conflict.', array('%dst' => $dst)));
|
| 437 |
}
|
| 438 |
return;
|
| 439 |
}
|
| 440 |
// Alert users if they are trying to create an alias that is the same as the internal path
|
| 441 |
if ($src == $dst) {
|
| 442 |
if ($verbose && user_access('notify of path changes')) {
|
| 443 |
drupal_set_message(t('Ignoring alias %dst because it is the same as the internal path.', array('%dst' => $dst)));
|
| 444 |
}
|
| 445 |
return;
|
| 446 |
}
|
| 447 |
|
| 448 |
// Skip replacing the current alias with an identical alias
|
| 449 |
if ($old_alias != $dst) {
|
| 450 |
path_set_alias($src, $dst, $pid, $language);
|
| 451 |
|
| 452 |
if (variable_get('pathauto_update_action', PATHAUTO_UPDATE_ACTION_DELETE) == PATHAUTO_UPDATE_ACTION_REDIRECT
|
| 453 |
&& function_exists('path_redirect_save')) {
|
| 454 |
if (!empty($old_alias)) {
|
| 455 |
$redirect = array(
|
| 456 |
'path' => $old_alias,
|
| 457 |
'redirect' => $src,
|
| 458 |
);
|
| 459 |
path_redirect_save($redirect);
|
| 460 |
}
|
| 461 |
}
|
| 462 |
if ($verbose && user_access('notify of path changes')) {
|
| 463 |
if (!empty($redirect)) {
|
| 464 |
drupal_set_message(t('Created new alias %dst for %src, replacing %old_alias. %old_alias now redirects to %dst.', array('%dst' => $dst, '%src' => $src, '%old_alias' => $old_alias)));
|
| 465 |
}
|
| 466 |
elseif ($pid) {
|
| 467 |
drupal_set_message(t('Created new alias %dst for %src, replacing %old_alias.', array('%dst' => $dst, '%src' => $src, '%old_alias' => $old_alias)));
|
| 468 |
}
|
| 469 |
else {
|
| 470 |
drupal_set_message(t('Created new alias %dst for %src.', array('%dst' => $dst, '%src' => $src)));
|
| 471 |
}
|
| 472 |
}
|
| 473 |
}
|
| 474 |
}
|
| 475 |
|
| 476 |
/**
|
| 477 |
* Generalized function to get tokens across all Pathauto types.
|
| 478 |
*
|
| 479 |
* @param $object
|
| 480 |
* A user, node, or category object.
|
| 481 |
* @return
|
| 482 |
* Tokens for that object formatted in the way that
|
| 483 |
* Pathauto expects to see them.
|
| 484 |
*/
|
| 485 |
function pathauto_get_placeholders($type, $object) {
|
| 486 |
if (function_exists('token_get_values')) {
|
| 487 |
$full = token_get_values($type, $object, TRUE);
|
| 488 |
$tokens = token_prepare_tokens($full->tokens);
|
| 489 |
$values = pathauto_clean_token_values($full);
|
| 490 |
return array('tokens' => $tokens, 'values' => $values);
|
| 491 |
}
|
| 492 |
// TODO at some point try removing this and see if install profiles have problems again.
|
| 493 |
watchdog('Pathauto', 'It appears that you have installed Pathauto, which depends on Token, but Token is either not installed or not installed properly.');
|
| 494 |
return array('tokens' => array(), 'values' => array());
|
| 495 |
}
|
| 496 |
|
| 497 |
/**
|
| 498 |
* Clean tokens so they are URL friendly.
|
| 499 |
*
|
| 500 |
* @param $full
|
| 501 |
* An array of token values that need to be "cleaned" for use in the URL.
|
| 502 |
* @return
|
| 503 |
* An array of the cleaned tokens.
|
| 504 |
*/
|
| 505 |
function pathauto_clean_token_values($full) {
|
| 506 |
foreach ($full->values as $key => $value) {
|
| 507 |
// If it's a "path" or "url friendly" token don't remove the "/" character
|
| 508 |
if (drupal_substr($full->tokens[$key], -4, 4) === 'path' || drupal_substr($full->tokens[$key], -8, 8) === 'path-raw' || drupal_substr($full->tokens[$key], -5, 5) === 'alias') {
|
| 509 |
$full->values[$key] = pathauto_cleanstring($value, FALSE);
|
| 510 |
}
|
| 511 |
else {
|
| 512 |
$full->values[$key] = pathauto_cleanstring($value);
|
| 513 |
}
|
| 514 |
}
|
| 515 |
return $full->values;
|
| 516 |
}
|
| 517 |
|
| 518 |
/**
|
| 519 |
* Return an array of arrays for punctuation values.
|
| 520 |
*
|
| 521 |
* Returns an array of arrays for punctuation values keyed by a name, including
|
| 522 |
* the value and a textual description.
|
| 523 |
* Can and should be expanded to include "all" non text punctuation values.
|
| 524 |
*
|
| 525 |
* @return
|
| 526 |
* An array of arrays for punctuation values keyed by a name, including the
|
| 527 |
* value and a textual description.
|
| 528 |
*/
|
| 529 |
function pathauto_punctuation_chars() {
|
| 530 |
$punctuation = array();
|
| 531 |
|
| 532 |
// Handle " ' ` , . - _ : ; | { [ } ] + = * & % ^ $ # @ ! ~ ( ) ? < > \
|
| 533 |
$punctuation['double_quotes'] = array('value' => '"', 'name' => t('Double quotes "'));
|
| 534 |
$punctuation['quotes'] = array('value' => "'", 'name' => t("Single quotes (apostrophe) '"));
|
| 535 |
$punctuation['backtick'] = array('value' => '`', 'name' => t('Back tick `'));
|
| 536 |
$punctuation['comma'] = array('value' => ',', 'name' => t('Comma ,'));
|
| 537 |
$punctuation['period'] = array('value' => '.', 'name' => t('Period .'));
|
| 538 |
$punctuation['hyphen'] = array('value' => '-', 'name' => t('Hyphen -'));
|
| 539 |
$punctuation['underscore'] = array('value' => '_', 'name' => t('Underscore _'));
|
| 540 |
$punctuation['colon'] = array('value' => ':', 'name' => t('Colon :'));
|
| 541 |
$punctuation['semicolon'] = array('value' => ';', 'name' => t('Semicolon ;'));
|
| 542 |
$punctuation['pipe'] = array('value' => '|', 'name' => t('Pipe |'));
|
| 543 |
$punctuation['left_curly'] = array('value' => '{', 'name' => t('Left curly bracket {'));
|
| 544 |
$punctuation['left_square'] = array('value' => '[', 'name' => t('Left square bracket ['));
|
| 545 |
$punctuation['right_curly'] = array('value' => '}', 'name' => t('Right curly bracket }'));
|
| 546 |
$punctuation['right_square'] = array('value' => ']', 'name' => t('Right square bracket ]'));
|
| 547 |
$punctuation['plus'] = array('value' => '+', 'name' => t('Plus +'));
|
| 548 |
$punctuation['equal'] = array('value' => '=', 'name' => t('Equal ='));
|
| 549 |
$punctuation['asterisk'] = array('value' => '*', 'name' => t('Asterisk *'));
|
| 550 |
$punctuation['ampersand'] = array('value' => '&', 'name' => t('Ampersand &'));
|
| 551 |
$punctuation['percent'] = array('value' => '%', 'name' => t('Percent %'));
|
| 552 |
$punctuation['caret'] = array('value' => '^', 'name' => t('Caret ^'));
|
| 553 |
$punctuation['dollar'] = array('value' => '$', 'name' => t('Dollar $'));
|
| 554 |
$punctuation['hash'] = array('value' => '#', 'name' => t('Hash #'));
|
| 555 |
$punctuation['at'] = array('value' => '@', 'name' => t('At @'));
|
| 556 |
$punctuation['exclamation'] = array('value' => '!', 'name' => t('Exclamation !'));
|
| 557 |
$punctuation['tilde'] = array('value' => '~', 'name' => t('Tilde ~'));
|
| 558 |
$punctuation['left_parenthesis'] = array('value' => '(', 'name' => t('Left parenthesis ('));
|
| 559 |
$punctuation['right_parenthesis'] = array('value' => ')', 'name' => t('right parenthesis )'));
|
| 560 |
$punctuation['question_mark'] = array('value' => '?', 'name' => t('Question mark ?'));
|
| 561 |
$punctuation['less_than'] = array('value' => '<', 'name' => t('Less than <'));
|
| 562 |
$punctuation['greater_than'] = array('value' => '>', 'name' => t('Greater than >'));
|
| 563 |
$punctuation['back_slash'] = array('value' => '\\', 'name' => t('Back slash \\'));
|
| 564 |
|
| 565 |
return $punctuation;
|
| 566 |
}
|
| 567 |
|
| 568 |
/**
|
| 569 |
* A Pathauto friendly version of truncate_utf8.
|
| 570 |
*
|
| 571 |
* @param $string
|
| 572 |
* The string to be truncated.
|
| 573 |
* @param $length
|
| 574 |
* An integer for the maximum desired length.
|
| 575 |
* @param $separator
|
| 576 |
* A string which contains the word boundary such as - or _.
|
| 577 |
*
|
| 578 |
* @return
|
| 579 |
* The string truncated below the maxlength.
|
| 580 |
*/
|
| 581 |
function _pathauto_truncate_chars($string, $length, $separator) {
|
| 582 |
if (drupal_strlen($string) > $length) {
|
| 583 |
$string = drupal_substr($string, 0, $length + 1); // leave one more character
|
| 584 |
if ($last_break = strrpos($string, $separator)) { // space exists AND is not on position 0
|
| 585 |
$string = substr($string, 0, $last_break);
|
| 586 |
}
|
| 587 |
else {
|
| 588 |
$string = drupal_substr($string, 0, $length);
|
| 589 |
}
|
| 590 |
}
|
| 591 |
return $string;
|
| 592 |
}
|