Drupal中使用URL别名在SEO以及网站用户体验方面非常重要,通常我们使用如下几个模块, - path(核心模块)
- pathauto
- path_redirect
- global_redirect
一般情况下,给一个URL设置一个别名,全站的所有URL都会更新用这个别名来代替原来的URL。 比如: /user/1 —> /robbin-zhao
这样设置的URL会被保存在url_alias表中。 这里有两个术语: 1. outbound URL 输出URL,或者显示/打印的URL。 2. inbound URL 请求URL,可以理解为进来的URL。 了解了术语之后,我们理解一下Drupal处理URL别名的方式,
1). 输出别名 在输出URL的时候,核心函数是URL function url($path = NULL, $options = array()) {; t) f/ H3 V' a3 Y
// Merge in defaults.; S! A5 C& C* |; D b v2 k0 a8 u
$options += array(
! N8 E3 d+ v& U$ b1 S 'fragment' => '',6 d3 |1 e1 k& L, s# m& k* Z0 B; ?
'query' => '',4 z6 W# B/ f( D1 [$ @ F
'absolute' => FALSE,
. `7 {/ C3 M5 q/ d 'alias' => FALSE,
0 J% e' Z0 o& Y8 ?* n3 i 'prefix' => '',1 g3 Q6 z7 q- H" }* l
);/ B, ~# n) K4 A; _, _
) y* i, n' c. ]4 u+ t ...4 `& {; {$ z- \: C- y
" g7 w( ~, T3 h6 N3 \ elseif (!empty($path) && !$options['alias']) {! ]9 i: s3 k$ e& D
$path = drupal_get_path_alias($path, isset($options['language']) ? $options['language']->language : '');
( h3 l# c& d$ U% c& _ `1 \ }
. [9 d6 |+ z! C- ]9 J* ] 1 ~3 x/ b9 y2 x, S, n" Z) ^
if (function_exists('custom_url_rewrite_outbound')) {3 R1 {% j$ l1 Q. t
// Modules may alter outbound links by reference.3 ^" W6 M1 D. E6 S8 Q. v5 L" |2 v
custom_url_rewrite_outbound($path, $options, $original_path);! `+ |) R+ V j2 y8 b8 |: ~
} 我们重点看下面的两个调用 drupal_get_path_alias 和 custom_url_rewrite_outbound。Drupal通过查询url_alias表,把要显示的URL更新为对应的alias就实现了别名的替换。 2). 处理别名的HTTP请求 Drupal在启动所有模块之前,先初始化URL,调用如下函数: function drupal_init_path() {
! |. z5 h0 a& o1 o# j4 g+ C" R if (!empty($_GET['q'])) {* x6 ^/ w( t+ F* I- m' e" T) W4 _
$_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));" v/ W B& Z6 ~8 O+ S
}
+ M8 {9 t' {- {% H7 w2 Q! E# V else {* }; ~3 s9 u! E. b+ e
$_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
6 S- p2 O# b2 s% N* ]5 x& B; h }9 U3 ]8 ~ u- Q4 P7 H* [
}# F& t! h+ Q7 r$ P
1 A0 \) K# y6 C9 [: m( @" I, i
function drupal_get_normal_path($path, $path_language = '') {( _. k* d( N/ t+ q# d" e* C
$result = $path;: q) m" g+ q, h8 _) q D- t6 H0 e
if ($src = drupal_lookup_path('source', $path, $path_language)) {
9 D+ N0 V& Q5 b; h! l; O, ~! S, F+ I' ^ $result = $src;' ~/ \4 O* h6 z+ p4 B/ x& S, `
}) N' P" L2 y8 O2 L" W: j
if (function_exists('custom_url_rewrite_inbound')) {" P" e# N+ Y d' _
// Modules may alter the inbound request path by reference.
* Y4 n/ o/ y) c, a# }4 I5 N' b4 W custom_url_rewrite_inbound($result, $path, $path_language);
$ G) `: L- X' t% q% b }9 @7 i% ]3 a3 [: ^0 C7 z$ G
return $result;7 P1 G2 o7 |. E" u' o; G% E: i( R
} 函数 drupal_get_normal_path 主要是查询url_alias表,得到当前URL的实际地址,比如 user/1, 然后把这个URL赋给 $_GET['q']来实现具体的URL重写功能。 在有些情况下,我们需要批量修改一些URL的别名,如果我们用drupal默认的url_alias, 但又有一些问题,首先,更新所有的URL脚本比较繁琐,数据量大的情况需要batch,操作数据不方便。其次,如果用户量大,会产生严重的Drupal性能问题,因此,可以考虑到不用url_alias,举个例子,比如我们希望更新user下面的所有tab url, 如:user/1/info, user/1/blog, user/1/message,user/1/mail … 每个用户有多个URL需要更新,如果有1百万用户,那么就会有上百万、千万的alias数据,对于维护、性能都是很大问题。 自定义函数实现URL重写 通过查看Drupal的URL流程,可以发现,Drupal在处理输出URL的时候,会调用一个自定义函数:custom_url_rewrite_outbound,在处理HTTP请求的URL时, 也会调用一个自定义函数:custom_url_rewrite_inbound,所以我们可以实现这两个函数来实现URL重写。 注意,由于这是单个函数而不是hook,如果每个函数都实现,很容易相互冲突,比如fb模块(facebook),url_alter(用于自定义代码来实现URL重写,主要实现了上面的两个函数)。但是由于这两个函数容易冲突(不是hook),其次,url_alter对inbound URL处理有问题,因为Drupal在调用custom_url_rewrite_inbound这个自定义函数的时候,是在加载所有模块之前,所以把这个函数写在module文件里面,根本掉用不到,这里提供一个目前较为合理的解决方案: - 写一个inc文件,放到(任意)自定义模块下面,比如 my-core/my-core.rewrite.inc
- 修改settings文件,include这个文件。比如 include “sites/all/modules/custom/my-core/my-core.rewrite.inc”;
- 在该文件中加入inbound和outbound这两个函数。
具体代码如下: /**
8 _! p( J. i& \* U4 V. } * Define custom_url_rewrite_inbound()' m( F. h, P5 y" Y: I
* @author robbin9 q- `5 w0 B0 h
*/
& Q, v" g$ h3 Z$ Bif (!function_exists('custom_url_rewrite_inbound')) {' V8 p w! u( g7 q
function custom_url_rewrite_inbound(&$result, $path, $path_language) {9 X0 X2 k9 d4 `/ E9 ~$ ^* k$ [
{fun_1}_url_inbound_alter($result, $path, $path_language);
7 t3 X6 P' P9 V7 B; z }
2 d8 O- c6 W+ q8 B2 R* H! E% i}- w( |3 j& b, w6 R1 Z# P
( u, _- M ]+ q( |9 w$ P/**
& e1 {. J, E) ?# C * Define custom_url_rewrite_outbound()+ n: n8 V. [, t
* @author robbin1 \' e/ ^! D6 w% W
*/" G; ?3 Y# S# c+ c! d6 ]
if (!function_exists('custom_url_rewrite_outbound')) {9 m9 P) j* W- V# p5 J# x
function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
9 O: o# G8 t: J; ]* p {fun_1}_url_outbound_alter($path, $options, $original_path);$ Y3 G3 f, m8 z# a
}
L9 W& u/ k& | N} 其中 {fun_1}_url_inbound_alter、{fun_1}_url_outbound_alter 表示一组处理inbound/outbound的函数,命名规则最好按照如上方式,因为一些第三方模块以及hook都是这个规则,容易理解。 可以添加多个函数,比如{fun_2}_url_inbound_alter等等,每添加一个,在上面的位置调用函数,以做到每组不通功能的函数分开。如果第三方模块,也需要实现重写,一般情况下,这些模块会实现类似 {module}_url_inbound_alter这样的函数,直接把这个函数加到上面对应的位置来调用即可,比如(facebook模块的fb_url_inbound_alter等)。这里给出函数的简要说明: //修改result的值为最终实际的URL $result是引用传值 hook_url_inbound_alter(&$result, $path, $path_language); //修改$path的值为想要的别名的URL $path是引用传值 hook_url_outbound_alter(&$path, $options, $original_path);
最后,还有一点要注意,自定义inbound函数,有时可能会和global_redirect冲突,(没用这个模块,写了类似的函数,也会冲突),因为redirect模块会检查当前的真是url(从outbound中获取)和当前请求的URL不一样,比如真实url是user/1,而当前的请求是 robbin-zhao,它会自动跳转,导致一个无限循环跳转的bug。 解决办法就是在inbound函数里面设置一个全局变量,阻止继续调转。设置 $_REQUEST['q'] = $result; 的值为最终实际URL的值,而不是别名。 示例代码 function my_redirect_url_inbound_alter (&$result, $path, $path_language) {
# t1 T$ e/ P" [" p! q+ P6 ^: p
4 B, {8 e* K5 }/ a# h6 g; B) A $arg0 = arg(0); //should be user-name
9 j' f3 c6 P" _6 N $arg1 = arg(1); //should be connections/media/...
1 w; ~2 n/ l* I7 o3 ?/ O7 s. z. i , r4 n4 [" r6 c5 X. f% t
if ($arg1) {
- J6 c7 _7 u7 [# j9 B; w" ? $user_url = drupal_lookup_path('source', $arg0);
, E+ i5 T& h+ j( ~ if ($user_url != $arg0 && preg_match('{user/(\d+)}i', $user_url, $matches)) {
4 W. i) v1 h6 G6 b $user_id = $matches[1];( u) O \( j6 G* J0 r; X
$result = "user/$user_id/$arg1";% \; P/ V2 Q# E- f4 `1 S
2 S9 Q! B2 c) N. g //add this to tell global_redirect not to redirect this url again. \8 k1 f, L' S, M3 ?& |
$_REQUEST['q'] = $result;2 u* m3 t! `* X- U, @5 H: b, H% D- ^
}
# c3 O( p8 K; j$ U! x }5 ` G' f' C- |. W" c7 K! \: q
}4 J! G' V# ?; G; v% Z( W, H! j
2 B( L8 ]' B) S+ N" R1 ?function my_redirect_url_outbound_alter (&$path, $options, $original_path) {
! c2 ^& e. ]2 O3 ]- ` //rewrite user's sub tab url to seo-friendly url
2 v' G; B! d+ [ }) E: S' {! } //such as, user/1/media --> robbin-zhao/media
, l4 }6 D- o/ M2 v1 w) \7 ~ if (preg_match('{user/(\d+)/(\w+)}i', $path, $matches)) {
4 g1 p/ a$ K' c, @( x2 O7 e $uid = $matches[1];4 O/ t# q2 J/ D# ]* Z
$tab = $matches[2];
+ S0 v t; L- [3 N
9 z% K. J5 s2 S $alias = drupal_lookup_path('alias', "user/$uid");6 ?4 U' ^9 E' Q8 N: }+ a. {; r
" _. `9 _6 F* M6 U
if ($alias != $path) {8 B6 W3 l& G9 Y1 m; f4 T; L
$path = "$alias/$tab";
3 R& a3 U( ], Y, t }
2 [3 S5 j& ]" x6 i" K+ d //$path = ''
. t& R7 H+ j6 h0 m% i T }
1 e% ]. O3 b5 {$ U! J- S} 优化过的代码已经提交到Drupal官方网站,并且已经是一个第三方模块,大家可以下载使用。 模块地址:http://drupal.org/project/rewrite_sub_link
声明: 本站所有文章欢迎转载,所有文章未说明,均属于原创,转载均请注明出处。 本文有效链接: http://www.drupal001.com/2011/12/drupal-custom-url-alias/ 版权所有: Drupal与高性能网站架构 http://www.drupal001.com |