/[drupal]/contributions/modules/pathauto/pathauto.inc
ViewVC logotype

Contents of /contributions/modules/pathauto/pathauto.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.54 - (show annotations) (download) (as text)
Thu Oct 22 00:11:35 2009 UTC (5 weeks, 1 day ago) by greggles
Branch: MAIN
CVS Tags: HEAD
Changes since 1.53: +9 -9 lines
File MIME type: text/x-php
bug #343851 by dbabbage, MGN: pathauto_cleanstring() does not convert to lowercase (consolidate all text altering code to pathauto_cleanstring)
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 }

  ViewVC Help
Powered by ViewVC 1.1.2