|
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()) {0 Y( a% l2 v2 X' @1 v- G$ {
// Merge in defaults.
$ n! Z+ Q- e8 m/ g $options += array(
. u: Q# Z9 E8 l 'fragment' => '',* |& O4 c6 u- b! i- ^
'query' => '',
8 l8 U4 U2 g. _ H" a0 ] 'absolute' => FALSE,& u. B8 w% ~. o/ v- E8 S
'alias' => FALSE,$ f0 k) @% J- J; a2 W' ?0 u
'prefix' => '',
( M0 o+ F* I4 G );
; l* W3 e( x. ]2 \7 s, t6 l 8 S) r. A1 K3 c
...$ Q) G8 \" |+ y0 H. {4 l }8 O. W
$ t3 `9 ^4 e4 g2 y/ ~1 S
elseif (!empty($path) && !$options['alias']) {
* X! O9 i& v9 B% o6 k1 A y: T $path = drupal_get_path_alias($path, isset($options['language']) ? $options['language']->language : '');: W. c' I4 A, }% N" U' {
}' ^4 J! P( J& J: q
6 p3 ^5 B) W* y9 |
if (function_exists('custom_url_rewrite_outbound')) {- x4 {9 R* O0 u+ t( V2 Z
// Modules may alter outbound links by reference.3 }/ M4 ~% Y" i' _! M( I* p' i
custom_url_rewrite_outbound($path, $options, $original_path);( a% k$ t8 H% y8 m8 x0 Z d1 v
}我们重点看下面的两个调用 drupal_get_path_alias 和 custom_url_rewrite_outbound。Drupal通过查询url_alias表,把要显示的URL更新为对应的alias就实现了别名的替换。 2). 处理别名的HTTP请求 Drupal在启动所有模块之前,先初始化URL,调用如下函数: function drupal_init_path() {/ i3 J. s6 Y& l8 R0 K
if (!empty($_GET['q'])) {
/ b: Q+ ?* d, g+ C# q0 r5 I $_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));
+ Q3 k7 u" `0 K( @. g! U2 { }
% T8 [# E( a( M else {. {/ M0 O( @( j( Y3 f# {) ]9 P
$_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
3 l2 k2 N) [) e1 T3 Q3 H' J3 R: G! Z ^ }
7 q, S* g+ q; L( @0 ~" R}$ h8 M8 l( L0 D! O6 p! J2 I9 x/ X
* _" }# D- r9 @4 J! [9 [0 jfunction drupal_get_normal_path($path, $path_language = '') {2 Q; U/ C" t( H' X8 Y! e, n# u
$result = $path;
1 p! K) ?2 e- `5 d if ($src = drupal_lookup_path('source', $path, $path_language)) {
6 ?$ r+ d' g. P* ]0 W9 M $result = $src;0 N* M" _2 R2 ?5 b
}/ ?2 @# g6 G% P! b; V: B
if (function_exists('custom_url_rewrite_inbound')) {
$ ?; R/ ~, F5 b! `, l6 l // Modules may alter the inbound request path by reference.- e. r+ g1 O8 K) [) H. K
custom_url_rewrite_inbound($result, $path, $path_language);
J( N; `2 R- x. k* ^ }) b0 {# v# l2 Z; T) o8 j) l9 R A
return $result;6 H, m7 o) u6 Z# J" J
}函数 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这两个函数。
具体代码如下: /**; M2 e: |1 u; C& ^1 G
* Define custom_url_rewrite_inbound()- |' t6 h/ F3 i9 |
* @author robbin, e. u( ?( X9 h! o: G4 O
*/4 e, B/ U6 i0 M* ?' K/ l( O/ E: s7 i
if (!function_exists('custom_url_rewrite_inbound')) {. l, I4 o' n5 X7 [0 f' H
function custom_url_rewrite_inbound(&$result, $path, $path_language) {
: X3 {6 h0 g7 @( Q+ k& N u2 m. S {fun_1}_url_inbound_alter($result, $path, $path_language);% L8 q" S N7 i* \3 Q4 `+ ?& k8 K
}5 c* m+ q( K8 H, f- [5 _
}3 @$ k; Q3 t! G7 O6 j3 j
' |, r$ H+ B+ x% D8 Z0 A/ k/**, X2 P- W, J- k% h: C
* Define custom_url_rewrite_outbound()
) \" B \2 u0 N# ^) {/ i * @author robbin
. }1 V& ^% x1 h6 B4 K0 ~ */4 I0 n0 M6 L5 G5 k% Y& X. V: j. r
if (!function_exists('custom_url_rewrite_outbound')) {
) w: z- m0 `% {0 R' _% E function custom_url_rewrite_outbound(&$path, &$options, $original_path) {% l' s" h3 `7 f; D3 n
{fun_1}_url_outbound_alter($path, $options, $original_path);
( @, v& w* `! W! h% H3 [$ R/ T }
( m# Z2 {+ x" 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) {
; w5 p1 p( K4 Q* e$ W
- P* n) w/ a$ R $arg0 = arg(0); //should be user-name
6 I% C' g5 q# u0 M0 w' [7 o $arg1 = arg(1); //should be connections/media/...
% m: y& R8 z+ h # r+ b9 r/ _+ v0 Q3 x
if ($arg1) {& v& i" }2 L( ^4 h# c' T
$user_url = drupal_lookup_path('source', $arg0);
& Q6 I* K0 p* v; |8 I; R if ($user_url != $arg0 && preg_match('{user/(\d+)}i', $user_url, $matches)) {9 _) k1 {0 p/ N+ ~. I
$user_id = $matches[1];5 U* X$ L: R2 n2 k
$result = "user/$user_id/$arg1";0 J( W- x7 e% \' [" I! }
' R9 G% h; @/ h) d1 M# m
//add this to tell global_redirect not to redirect this url again% K" ]* p: L* P% ^" z" C& K
$_REQUEST['q'] = $result;' Z: P% j) O7 Q# Q- K( m% g
}. [# u' u: i: o# j s
}' A, N. X; [/ {8 u9 ]3 p$ x& u
}, X6 m0 k7 t! m5 n, F
4 @$ \2 P5 k8 L; E) `function my_redirect_url_outbound_alter (&$path, $options, $original_path) {
8 z! I- u; Q, I/ J& ^% G7 N //rewrite user's sub tab url to seo-friendly url+ S( Q6 }& f y* B6 t
//such as, user/1/media --> robbin-zhao/media- n( `# r2 J8 ?. K1 a0 N/ v8 g
if (preg_match('{user/(\d+)/(\w+)}i', $path, $matches)) {( a- n8 y8 S# n( B4 L
$uid = $matches[1];
6 E U0 v) |" e" | $tab = $matches[2];/ X5 R4 I; A U
* |& W0 o. W& m$ i5 u $alias = drupal_lookup_path('alias', "user/$uid");/ o+ A8 l6 o k3 L
0 S8 M1 |" }8 l- K* P4 z if ($alias != $path) {
6 ?9 ?1 k/ ^8 q r, [& a $path = "$alias/$tab";3 ~: u& t( I! ]7 N9 m
}
0 x9 u% c; @4 V$ L8 d6 w' w( r //$path = ''/ m h% J3 y5 M1 ^- R8 y1 i9 I J( B
}
/ ~& ?/ n" Q3 r} 优化过的代码已经提交到Drupal官方网站,并且已经是一个第三方模块,大家可以下载使用。 模块地址:http://drupal.org/project/rewrite_sub_link
声明: 本站所有文章欢迎转载,所有文章未说明,均属于原创,转载均请注明出处。 本文有效链接: http://www.drupal001.com/2011/12/drupal-custom-url-alias/ 版权所有: Drupal与高性能网站架构 http://www.drupal001.com |