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()) {4 m& ~9 }- q2 ?; X; X7 {" X
// Merge in defaults.
& O: O7 ]& k7 Y- S6 ~; `- x7 q $options += array(
8 ?3 e9 J. B6 J" Q _. W7 `3 S 'fragment' => '',; `% g$ G( h0 @, o
'query' => '',
, R1 i$ K* L- c; {- t' b 'absolute' => FALSE,
. @; [* L4 S. ]3 w) Y) F 'alias' => FALSE,3 `0 f8 m1 q- D$ y$ `
'prefix' => '',4 E( [& m+ d1 X
);
( Y" L% _. z/ \( b- w5 B' m ' X3 h) c4 D6 h" |
...3 n9 q1 B" N$ Z$ u) x% j. Y
$ s2 X' t) ]4 k# x
elseif (!empty($path) && !$options['alias']) {
, ^8 {0 p- W/ [/ S) h2 a1 f+ v/ [ $path = drupal_get_path_alias($path, isset($options['language']) ? $options['language']->language : '');9 c3 m0 J; L* k$ |
}, f0 n# Y; q# l
! ]; C# H, f6 X, B4 w# V, M# m) H if (function_exists('custom_url_rewrite_outbound')) {
. v% z6 ~( `1 K, i, {! s) S // Modules may alter outbound links by reference.2 L2 ^/ ?$ M. _( U2 Q
custom_url_rewrite_outbound($path, $options, $original_path);
- v- M n( Z* W1 u } 我们重点看下面的两个调用 drupal_get_path_alias 和 custom_url_rewrite_outbound。Drupal通过查询url_alias表,把要显示的URL更新为对应的alias就实现了别名的替换。 2). 处理别名的HTTP请求 Drupal在启动所有模块之前,先初始化URL,调用如下函数: function drupal_init_path() {
3 O' n* }, c: r2 I) Q! v if (!empty($_GET['q'])) {- F/ @; U9 x9 e- J# G0 r A
$_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));
% z5 Y5 N2 S1 a2 ?) V3 @6 o" } }1 }: Y' Z8 l0 ?+ c/ q" L" @1 {
else {
$ R1 ?4 `( Q6 @# E2 Z3 ]* r $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));/ |$ ]% C x# {. ?! m w
} _+ v7 k" Q5 f0 h3 t" e: @
}" W. {' u0 G' j0 G! D l. j
. ~ x. x; a0 h8 I9 b: s" w# A3 ~' U) c
function drupal_get_normal_path($path, $path_language = '') {: |- A5 V# k2 k; B; S
$result = $path;4 ^9 a1 I" k- ^- {8 d" t
if ($src = drupal_lookup_path('source', $path, $path_language)) {9 V ]7 b: V. M( \
$result = $src;
! Z5 u3 a1 z5 ?/ t }# N( \2 }6 x3 Y: \
if (function_exists('custom_url_rewrite_inbound')) {
& {# A+ S8 F* A7 @: q // Modules may alter the inbound request path by reference.
( }- w& V0 I/ D& A custom_url_rewrite_inbound($result, $path, $path_language);3 g v3 ]* y) L
}/ O' \% ^* f* w! r: |9 M8 B$ F5 ^
return $result;6 P% d8 d4 y+ d$ r9 x3 t
} 函数 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这两个函数。
具体代码如下: /**
% c) V6 m) S, [* \+ Q * Define custom_url_rewrite_inbound()
4 R$ Z, ~4 g1 a * @author robbin
* o, F& K( U& Q% S */
5 h5 @/ Y. s* B# n) }4 p' r% Gif (!function_exists('custom_url_rewrite_inbound')) {
# I- U A( V$ O- k& q function custom_url_rewrite_inbound(&$result, $path, $path_language) {
4 g" @3 H# a. ?( f {fun_1}_url_inbound_alter($result, $path, $path_language);( _" v0 `+ f( _) p8 |! ^
}
8 B3 p- v3 Q$ W" p B" U# K ]}
- d% t2 ^5 z$ D. @) y7 ~, I
% b/ _3 B" x7 O/ ?' x6 ~: R/**
5 h" C9 U C) p. U8 o * Define custom_url_rewrite_outbound()2 j ?; J2 N1 U7 j/ p1 a
* @author robbin
# Q, ]5 V8 F$ I8 U& N! h$ r */
0 u1 ~7 P, D f+ Y$ |5 dif (!function_exists('custom_url_rewrite_outbound')) {; R" V/ h# a# V F, ?
function custom_url_rewrite_outbound(&$path, &$options, $original_path) {' d$ X+ y' H' Y# l
{fun_1}_url_outbound_alter($path, $options, $original_path);
# [; ^: ]$ X: e/ j }2 ?* R) D5 I3 R, O. `
} 其中 {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) {4 F- F5 D! Z( r) S, w
" v q0 W/ }* ~3 r6 @6 p4 ^
$arg0 = arg(0); //should be user-name
" D7 t b$ A- P $arg1 = arg(1); //should be connections/media/...
4 ~" F' l# k+ B" D# a) D1 G: v) { # x7 l9 a$ G. d& f
if ($arg1) {
. ]& Z0 g# ~/ W1 P+ K5 d+ P $user_url = drupal_lookup_path('source', $arg0);* @3 ]$ k/ h: P- D. R, r5 `
if ($user_url != $arg0 && preg_match('{user/(\d+)}i', $user_url, $matches)) {
! Z" `. H2 d% }! l: j $user_id = $matches[1];0 V$ E8 P* \/ B3 `) s
$result = "user/$user_id/$arg1";
& {0 s0 w( }: O5 y. g% {1 ?9 @ 0 ?" V& O& g ]0 e% ?7 ]4 t
//add this to tell global_redirect not to redirect this url again
$ {, M+ q0 A& Y6 u0 u* \ $_REQUEST['q'] = $result;
# s1 b; p6 _5 n! i M } N* |0 J; v8 S* n2 {( e5 j& W
}3 p( _) z- Y! d7 I
}
' f2 {+ ]6 t$ d0 s8 t; U' @
; {: p( n/ i% h; hfunction my_redirect_url_outbound_alter (&$path, $options, $original_path) {; ]5 o d& p: L2 b; O# E" C; W
//rewrite user's sub tab url to seo-friendly url
L$ {9 m" ]- m3 p9 m' P i* Z //such as, user/1/media --> robbin-zhao/media
( x. I6 C5 P. g8 k; A) v* ~ if (preg_match('{user/(\d+)/(\w+)}i', $path, $matches)) {: t& s' Y6 O7 P6 W4 f
$uid = $matches[1];
, M+ A* f& R! a' Z/ i $tab = $matches[2];
: [' j) y1 R9 E4 \
# @. E7 p! E1 ?6 z $alias = drupal_lookup_path('alias', "user/$uid");" c! @; e6 C+ r; P8 `% c
+ C, `$ A, r( t
if ($alias != $path) {, d4 h$ C: N8 S. X; i! v: L6 Q) r
$path = "$alias/$tab";
: D: g+ T, U' V8 G7 _ }6 a: R; f1 \, D
//$path = ''. }, P" v0 r. C1 {
}
% {7 z) ?4 k9 B7 W7 ?} 优化过的代码已经提交到Drupal官方网站,并且已经是一个第三方模块,大家可以下载使用。 模块地址:http://drupal.org/project/rewrite_sub_link
声明: 本站所有文章欢迎转载,所有文章未说明,均属于原创,转载均请注明出处。 本文有效链接: http://www.drupal001.com/2011/12/drupal-custom-url-alias/ 版权所有: Drupal与高性能网站架构 http://www.drupal001.com |