1 | <?php |
---|
2 | // $Id: pathauto.inc,v 1.45.2.29 2010/09/27 15:52:58 greggles Exp $ |
---|
3 | |
---|
4 | /** |
---|
5 | * @file |
---|
6 | * Miscellaneous functions for Pathauto. |
---|
7 | * |
---|
8 | * @ingroup pathauto |
---|
9 | */ |
---|
10 | |
---|
11 | /** |
---|
12 | * Check to see if there is already an alias pointing to a different item. |
---|
13 | * |
---|
14 | * @param $alias |
---|
15 | * A string alias. |
---|
16 | * @param $source |
---|
17 | * A string that is the internal path. |
---|
18 | * @param $language |
---|
19 | * A string indicating the path's language. |
---|
20 | * @return |
---|
21 | * TRUE if an alias exists, FALSE if not. |
---|
22 | */ |
---|
23 | function _pathauto_alias_exists($alias, $source, $language = '') { |
---|
24 | $pid = db_result(db_query_range("SELECT pid FROM {url_alias} WHERE src <> '%s' AND dst = '%s' AND language IN ('%s', '') ORDER BY language DESC, pid DESC", $source, $alias, $language, 0, 1)); |
---|
25 | |
---|
26 | if (module_exists('path_redirect') && function_exists('path_redirect_delete_multiple')) { |
---|
27 | // Delete from path_redirect the exact same alias to the same node. |
---|
28 | path_redirect_delete_multiple(NULL, array('source' => $alias, 'redirect' => $source)); |
---|
29 | |
---|
30 | // If there still is this alias used in path_redirect, then create a different alias. |
---|
31 | $redirects = path_redirect_load_multiple(NULL, array('source' => $alias)); |
---|
32 | } |
---|
33 | |
---|
34 | if ($pid || !empty($redirects)) { |
---|
35 | return TRUE; |
---|
36 | } |
---|
37 | else { |
---|
38 | return FALSE; |
---|
39 | } |
---|
40 | } |
---|
41 | |
---|
42 | /** |
---|
43 | * Fetches an existing URL alias given a path and optional language. |
---|
44 | * |
---|
45 | * @param $source |
---|
46 | * An internal Drupal path. |
---|
47 | * @param $language |
---|
48 | * An optional language code to look up the path in. |
---|
49 | * @return |
---|
50 | * FALSE if no alias was found or an associative array containing the |
---|
51 | * following keys: |
---|
52 | * - pid: Unique path alias identifier. |
---|
53 | * - alias: The URL alias. |
---|
54 | */ |
---|
55 | function _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)); |
---|
57 | } |
---|
58 | |
---|
59 | /** |
---|
60 | * Clean up a string segment to be used in an URL alias. |
---|
61 | * |
---|
62 | * Performs the following possible alterations: |
---|
63 | * - Process the string through the transliteration module. |
---|
64 | * - Replace or remove punctuation with the separator character. |
---|
65 | * - Remove back-slashes. |
---|
66 | * - Replace non-ascii and non-numeric characters with the separator. |
---|
67 | * - Remove common words. |
---|
68 | * - Replace whitespace with the separator character. |
---|
69 | * - Trim duplicate, leading, and trailing separators. |
---|
70 | * - Convert to lower-case. |
---|
71 | * - Shorten to a desired length and logical position based on word boundaries. |
---|
72 | * |
---|
73 | * This function should *not* be called on URL alias or path strings because it |
---|
74 | * is assumed that they are already clean. |
---|
75 | * |
---|
76 | * @param $string |
---|
77 | * A string to clean. |
---|
78 | * @return |
---|
79 | * The cleaned string. |
---|
80 | */ |
---|
81 | function 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', |
---|
125 | ); |
---|
126 | $ignore_words = variable_get('pathauto_ignore_words', $ignore_words); |
---|
127 | $ignore_words_regex = preg_replace(array('/^[,\s]+|[,\s]+$/', '/[,\s]+/'), array('', '\b|\b'), $ignore_words); |
---|
128 | if ($ignore_words_regex) { |
---|
129 | $ignore_words_regex = '\b' . $ignore_words_regex . '\b'; |
---|
130 | } |
---|
131 | } |
---|
132 | |
---|
133 | // 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 | } |
---|
141 | if (drupal_strlen(trim($words_removed)) > 0) { |
---|
142 | $output = $words_removed; |
---|
143 | } |
---|
144 | } |
---|
145 | |
---|
146 | // Always replace whitespace with the separator. |
---|
147 | $output = preg_replace('/\s+/', $separator, $output); |
---|
148 | |
---|
149 | // Trim duplicates and remove trailing and leading separators. |
---|
150 | $output = _pathauto_clean_separators($output); |
---|
151 | |
---|
152 | // Optionally convert to lower case. |
---|
153 | if (variable_get('pathauto_case', 1)) { |
---|
154 | $output = drupal_strtolower($output); |
---|
155 | } |
---|
156 | |
---|
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); |
---|
160 | |
---|
161 | return $output; |
---|
162 | } |
---|
163 | |
---|
164 | /** |
---|
165 | * Trims duplicate, leading, and trailing separators from a string. |
---|
166 | * |
---|
167 | * @param $string |
---|
168 | * The string to clean path separators from. |
---|
169 | * @param $separator |
---|
170 | * The path separator to use when cleaning. |
---|
171 | * @return |
---|
172 | * The cleaned version of the string. |
---|
173 | * |
---|
174 | * @see pathauto_cleanstring() |
---|
175 | * @see pathauto_clean_alias() |
---|
176 | */ |
---|
177 | function _pathauto_clean_separators($string, $separator = NULL) { |
---|
178 | $output = $string; |
---|
179 | |
---|
180 | if (!isset($separator)) { |
---|
181 | $separator = variable_get('pathauto_separator', '-'); |
---|
182 | } |
---|
183 | |
---|
184 | // Clean duplicate or trailing separators. |
---|
185 | if (strlen($separator)) { |
---|
186 | // Escape the separator. |
---|
187 | $seppattern = preg_quote($separator, '/'); |
---|
188 | |
---|
189 | // Trim any leading or trailing separators. |
---|
190 | $output = preg_replace("/^$seppattern+|$seppattern+$/", '', $output); |
---|
191 | |
---|
192 | // Replace trailing separators around slashes. |
---|
193 | 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); |
---|
199 | } |
---|
200 | |
---|
201 | return $output; |
---|
202 | } |
---|
203 | |
---|
204 | /** |
---|
205 | * Clean up an URL alias. |
---|
206 | * |
---|
207 | * Performs the following alterations: |
---|
208 | * - Trim duplicate, leading, and trailing back-slashes. |
---|
209 | * - Trim duplicate, leading, and trailing separators. |
---|
210 | * - Shorten to a desired length and logical position based on word boundaries. |
---|
211 | * |
---|
212 | * @param $alias |
---|
213 | * A string with the URL alias to clean up. |
---|
214 | * @return |
---|
215 | * The cleaned URL alias. |
---|
216 | */ |
---|
217 | function pathauto_clean_alias($alias) { |
---|
218 | $output = $alias; |
---|
219 | |
---|
220 | // Trim duplicate, leading, and trailing back-slashes. |
---|
221 | $output = _pathauto_clean_separators($output, '/'); |
---|
222 | |
---|
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); |
---|
230 | |
---|
231 | return $output; |
---|
232 | } |
---|
233 | |
---|
234 | /** |
---|
235 | * Apply patterns to create an alias. |
---|
236 | * |
---|
237 | * @param $module |
---|
238 | * The name of your module (e.g., 'node'). |
---|
239 | * @param $op |
---|
240 | * Operation being performed on the content being aliased |
---|
241 | * ('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). |
---|
246 | * @param $source |
---|
247 | * An internal Drupal path to be aliased. |
---|
248 | * @param $entity_id |
---|
249 | * The entity ID (node ID, user ID, etc.). |
---|
250 | * @param $type |
---|
251 | * For modules which provided pattern items in hook_pathauto(), |
---|
252 | * the relevant identifier for the specific item to be aliased |
---|
253 | * (e.g., $node->type). |
---|
254 | * @param $language |
---|
255 | * A string specify the path's language. |
---|
256 | * @return |
---|
257 | * The alias that was created. |
---|
258 | * |
---|
259 | * @see _pathauto_set_alias() |
---|
260 | * @see pathauto_get_placeholders() |
---|
261 | */ |
---|
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 | } |
---|
270 | 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)) { |
---|
275 | return ''; |
---|
276 | } |
---|
277 | |
---|
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 | } |
---|
288 | } |
---|
289 | |
---|
290 | // Special handling when updating an item which is already aliased. |
---|
291 | $existing_alias = NULL; |
---|
292 | if ($op == 'update' || $op == 'bulkupdate') { |
---|
293 | if ($existing_alias = _pathauto_existing_alias_data($source, $language)) { |
---|
294 | switch (variable_get('pathauto_update_action', 2)) { |
---|
295 | case 0: |
---|
296 | // If an alias already exists, and the update action is set to do nothing, |
---|
297 | // then gosh-darn it, do nothing. |
---|
298 | return ''; |
---|
299 | } |
---|
300 | } |
---|
301 | } |
---|
302 | |
---|
303 | // Replace the placeholders with the values provided by the module. |
---|
304 | $alias = str_replace($placeholders['tokens'], $placeholders['values'], $pattern); |
---|
305 | |
---|
306 | // Check if the token replacement has not actually replaced any values. If |
---|
307 | // that is the case, then stop because we should not generate an alias. |
---|
308 | // @see token_scan() |
---|
309 | $pattern_tokens_removed = preg_replace('/\[([^\s]+?)\]/', '', $pattern); |
---|
310 | if ($alias === $pattern_tokens_removed) { |
---|
311 | return ''; |
---|
312 | } |
---|
313 | |
---|
314 | $alias = pathauto_clean_alias($alias); |
---|
315 | |
---|
316 | // 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 | ); |
---|
326 | drupal_alter('pathauto_alias', $alias, $context); |
---|
327 | |
---|
328 | // If we have arrived at an empty string, discontinue. |
---|
329 | if (!drupal_strlen($alias)) { |
---|
330 | return ''; |
---|
331 | } |
---|
332 | |
---|
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 | |
---|
347 | // Alert the user why this happened. |
---|
348 | _pathauto_verbose(t('The automatically generated alias %original_alias conflicted with an existing alias. Alias changed to %alias.', array( |
---|
349 | '%original_alias' => $original_alias, |
---|
350 | '%alias' => $alias, |
---|
351 | )), $op); |
---|
352 | } |
---|
353 | |
---|
354 | // Return the generated alias if requested. |
---|
355 | if ($op == 'return') { |
---|
356 | return $alias; |
---|
357 | } |
---|
358 | |
---|
359 | // Build the new path alias array and send it off to be created. |
---|
360 | $path = array( |
---|
361 | 'source' => $source, |
---|
362 | 'alias' => $alias, |
---|
363 | 'language' => $language, |
---|
364 | ); |
---|
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; |
---|
386 | } |
---|
387 | |
---|
388 | /** |
---|
389 | * Verify if the given path is a valid menu callback. |
---|
390 | * |
---|
391 | * Taken from menu_execute_active_handler(). |
---|
392 | * |
---|
393 | * @param $path |
---|
394 | * A string containing a relative path. |
---|
395 | * @return |
---|
396 | * TRUE if the path already exists. |
---|
397 | */ |
---|
398 | function _pathauto_path_is_callback($path) { |
---|
399 | $menu = menu_get_item($path); |
---|
400 | if (isset($menu['path']) && $menu['path'] == $path) { |
---|
401 | return TRUE; |
---|
402 | } |
---|
403 | return FALSE; |
---|
404 | } |
---|
405 | |
---|
406 | /** |
---|
407 | * Private function for Pathauto to create an alias. |
---|
408 | * |
---|
409 | * @param $path |
---|
410 | * An associative array containing the following keys: |
---|
411 | * - source: The internal system path. |
---|
412 | * - alias: The URL alias. |
---|
413 | * - pid: (optional) Unique path alias identifier. |
---|
414 | * - language: (optional) The language of the alias. |
---|
415 | * @param $existing_alias |
---|
416 | * (optional) An associative array of the existing path alias. |
---|
417 | * @param $op |
---|
418 | * An optional string with the operation being performed. |
---|
419 | * @return |
---|
420 | * TRUE if the path was saved, or NULL otherwise. |
---|
421 | * |
---|
422 | * @see path_set_alias() |
---|
423 | */ |
---|
424 | function _pathauto_set_alias($path, $existing_alias = NULL, $op = NULL) { |
---|
425 | $verbose = _pathauto_verbose(NULL, $op); |
---|
426 | |
---|
427 | // Alert users that an existing callback cannot be overridden automatically |
---|
428 | if (_pathauto_path_is_callback($path['alias'])) { |
---|
429 | if ($verbose) { |
---|
430 | _pathauto_verbose(t('Ignoring alias %alias due to existing path conflict.', array('%alias' => $path['alias']))); |
---|
431 | } |
---|
432 | return; |
---|
433 | } |
---|
434 | // Alert users if they are trying to create an alias that is the same as the internal path |
---|
435 | if ($path['source'] == $path['alias']) { |
---|
436 | if ($verbose) { |
---|
437 | _pathauto_verbose(t('Ignoring alias %alias because it is the same as the internal path.', array('%alias' => $path['alias']))); |
---|
438 | } |
---|
439 | return; |
---|
440 | } |
---|
441 | |
---|
442 | $path += array( |
---|
443 | 'pid' => NULL, |
---|
444 | 'language' => '', |
---|
445 | ); |
---|
446 | |
---|
447 | // Skip replacing the current alias with an identical alias |
---|
448 | if (empty($existing_alias) || $existing_alias['alias'] != $path['alias']) { |
---|
449 | // If there is already an alias, respect some update actions. |
---|
450 | if (!empty($existing_alias)) { |
---|
451 | switch (variable_get('pathauto_update_action', 2)) { |
---|
452 | case 0: |
---|
453 | // Do not create the alias. |
---|
454 | return; |
---|
455 | case 1: |
---|
456 | // Create a new alias instead of overwriting the existing by leaving |
---|
457 | // $path['pid'] empty. |
---|
458 | break; |
---|
459 | case 3: |
---|
460 | // Create a redirect |
---|
461 | if (module_exists('path_redirect') && function_exists('path_redirect_save')) { |
---|
462 | $redirect = array( |
---|
463 | 'source' => $existing_alias['alias'], |
---|
464 | 'redirect' => $path['source'], |
---|
465 | ); |
---|
466 | path_redirect_save($redirect); |
---|
467 | } |
---|
468 | // Intentionally fall through to the next condition since we still |
---|
469 | // want to replace the existing alias. |
---|
470 | case 2: |
---|
471 | // Both the redirect and delete actions should overwrite the existing |
---|
472 | // alias. |
---|
473 | $path['pid'] = $existing_alias['pid']; |
---|
474 | break; |
---|
475 | } |
---|
476 | } |
---|
477 | |
---|
478 | // Save the path array. |
---|
479 | path_set_alias($path['source'], $path['alias'], $path['pid'], $path['language']); |
---|
480 | |
---|
481 | if ($verbose) { |
---|
482 | if (!empty($redirect)) { |
---|
483 | _pathauto_verbose(t('Created new alias %alias for %source, replacing %old_alias. %old_alias now redirects to %alias.', array('%alias' => $path['alias'], '%source' => $path['source'], '%old_alias' => $existing_alias['alias']))); |
---|
484 | } |
---|
485 | elseif (!empty($existing_alias['pid'])) { |
---|
486 | _pathauto_verbose(t('Created new alias %alias for %source, replacing %old_alias.', array('%alias' => $path['alias'], '%source' => $path['source'], '%old_alias' => $existing_alias['alias']))); |
---|
487 | } |
---|
488 | else { |
---|
489 | _pathauto_verbose(t('Created new alias %alias for %source.', array('%alias' => $path['alias'], '%source' => $path['source']))); |
---|
490 | } |
---|
491 | } |
---|
492 | |
---|
493 | return TRUE; |
---|
494 | } |
---|
495 | } |
---|
496 | |
---|
497 | /** |
---|
498 | * Output a helpful message if verbose output is enabled. |
---|
499 | * |
---|
500 | * Verbose output is only enabled when: |
---|
501 | * - The 'pathauto_verbose' setting is enabled. |
---|
502 | * - The current user has the 'notify of path changes' permission. |
---|
503 | * - The $op parameter is anything but 'bulkupdate' or 'return'. |
---|
504 | * |
---|
505 | * @param $message |
---|
506 | * An optional string of the verbose message to display. This string should |
---|
507 | * already be run through t(). |
---|
508 | * @param $op |
---|
509 | * An optional string with the operation being performed. |
---|
510 | * @return |
---|
511 | * TRUE if verbose output is enabled, or FALSE otherwise. |
---|
512 | */ |
---|
513 | function _pathauto_verbose($message = NULL, $op = NULL) { |
---|
514 | static $verbose; |
---|
515 | |
---|
516 | if (!isset($verbose)) { |
---|
517 | $verbose = variable_get('pathauto_verbose', FALSE) && user_access('notify of path changes'); |
---|
518 | } |
---|
519 | |
---|
520 | if (!$verbose || (isset($op) && in_array($op, array('bulkupdate', 'return')))) { |
---|
521 | return FALSE; |
---|
522 | } |
---|
523 | |
---|
524 | if ($message) { |
---|
525 | drupal_set_message($message); |
---|
526 | } |
---|
527 | |
---|
528 | return $verbose; |
---|
529 | } |
---|
530 | |
---|
531 | /** |
---|
532 | * Generalized function to get tokens across all Pathauto types. |
---|
533 | * |
---|
534 | * @param $object |
---|
535 | * A user, node, or category object. |
---|
536 | * @return |
---|
537 | * Tokens for that object formatted in the way that |
---|
538 | * Pathauto expects to see them. |
---|
539 | */ |
---|
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); |
---|
548 | $full = token_get_values($type, $object, TRUE, $options); |
---|
549 | $tokens = token_prepare_tokens($full->tokens); |
---|
550 | $values = pathauto_clean_token_values($full, $options); |
---|
551 | return array('tokens' => $tokens, 'values' => $values); |
---|
552 | } |
---|
553 | |
---|
554 | /** |
---|
555 | * Clean tokens so they are URL friendly. |
---|
556 | * |
---|
557 | * @param $full |
---|
558 | * An array of token values from token_get_values() that need to be "cleaned" |
---|
559 | * for use in the URL. |
---|
560 | * |
---|
561 | * @return |
---|
562 | * An array of the cleaned tokens. |
---|
563 | */ |
---|
564 | function pathauto_clean_token_values($full, $options = array()) { |
---|
565 | $replacements = array(); |
---|
566 | foreach ($full->values as $key => $value) { |
---|
567 | $token = $full->tokens[$key]; |
---|
568 | if (strpos($token, 'path') !== FALSE && is_array($value) && !empty($options['pathauto'])) { |
---|
569 | // If the token name contains 'path', the token value is an array, and |
---|
570 | // the 'pathauto' option was passed to token_get_values(), then the token |
---|
571 | // should have each segment cleaned, and then glued back together to |
---|
572 | // construct a value resembling an URL. |
---|
573 | $segments = array_map('pathauto_cleanstring', $value); |
---|
574 | $replacements[$token] = implode('/', $segments); |
---|
575 | } |
---|
576 | elseif (preg_match('/(path|alias|url|url-brief)(-raw)?$/', $token)) { |
---|
577 | // Token name matches an URL-type name and should be left raw. |
---|
578 | $replacements[$token] = $value; |
---|
579 | } |
---|
580 | else { |
---|
581 | // Token is not an URL, so it should have its value cleaned. |
---|
582 | $replacements[$token] = pathauto_cleanstring($value); |
---|
583 | } |
---|
584 | } |
---|
585 | return $replacements; |
---|
586 | } |
---|
587 | |
---|
588 | /** |
---|
589 | * Return an array of arrays for punctuation values. |
---|
590 | * |
---|
591 | * Returns an array of arrays for punctuation values keyed by a name, including |
---|
592 | * the value and a textual description. |
---|
593 | * Can and should be expanded to include "all" non text punctuation values. |
---|
594 | * |
---|
595 | * @return |
---|
596 | * An array of arrays for punctuation values keyed by a name, including the |
---|
597 | * value and a textual description. |
---|
598 | */ |
---|
599 | function pathauto_punctuation_chars() { |
---|
600 | static $punctuation; |
---|
601 | |
---|
602 | 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 \\')); |
---|
636 | } |
---|
637 | |
---|
638 | return $punctuation; |
---|
639 | } |
---|
640 | |
---|
641 | /** |
---|
642 | * Fetch the maximum length of the {url_alias}.dst field from the schema. |
---|
643 | * |
---|
644 | * @return |
---|
645 | * An integer of the maximum URL alias length allowed by the database. |
---|
646 | */ |
---|
647 | function _pathauto_get_schema_alias_maxlength() { |
---|
648 | static $maxlength; |
---|
649 | if (!isset($maxlength)) { |
---|
650 | $schema = drupal_get_schema('url_alias'); |
---|
651 | $maxlength = $schema['fields']['dst']['length']; |
---|
652 | } |
---|
653 | return $maxlength; |
---|
654 | } |
---|
655 | |
---|
656 | /** |
---|
657 | * Fetch an array of non-raw tokens that have matching raw tokens. |
---|
658 | * |
---|
659 | * @return |
---|
660 | * An array of tokens. |
---|
661 | */ |
---|
662 | function _pathauto_get_raw_tokens() { |
---|
663 | static $raw_tokens; |
---|
664 | |
---|
665 | if (!isset($raw_tokens)) { |
---|
666 | $raw_tokens = array(); |
---|
667 | |
---|
668 | // Build one big list of tokens. |
---|
669 | foreach (token_get_list('all') as $tokens) { |
---|
670 | $raw_tokens = array_merge($raw_tokens, array_keys($tokens)); |
---|
671 | } |
---|
672 | |
---|
673 | // Filter out any tokens without -raw as a suffix. |
---|
674 | foreach ($raw_tokens as $index => $token) { |
---|
675 | if (substr($token, -4) !== '-raw') { |
---|
676 | unset($raw_tokens[$index]); |
---|
677 | } |
---|
678 | } |
---|
679 | |
---|
680 | array_unique($raw_tokens); |
---|
681 | } |
---|
682 | |
---|
683 | return $raw_tokens; |
---|
684 | } |
---|
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 | } |
---|