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()) {/ Y: V# r9 V5 v, d6 N4 E! P. F
// Merge in defaults.: n. q" O) a' B2 G- x. ]! l
$options += array(/ K! e+ {, G' Z/ y+ K% `$ }1 H& U7 c6 {
'fragment' => '',) L8 b& C1 a' ?- p
'query' => '',
0 n5 Q" B8 U# l& p% ` w5 o 'absolute' => FALSE,: I/ S+ _6 {5 y- W( {
'alias' => FALSE,, D0 t6 D' X3 ~
'prefix' => '',
], N- q8 z( L );; n1 e8 n2 S0 J1 o( n" k" K; m
* Y% J+ U/ j0 q1 j0 k+ ^ ...
% s9 A6 y/ M+ A$ X
$ D" \. z: Y7 V) K elseif (!empty($path) && !$options['alias']) {+ `0 N; g$ Q* [5 d1 ^/ F* T$ ?
$path = drupal_get_path_alias($path, isset($options['language']) ? $options['language']->language : '');
9 C$ j8 a4 b, G5 Y$ z6 Z, V. ] }4 ]' m S' v/ u4 F8 k+ S
, m9 n3 G' ^& L5 y7 M, \
if (function_exists('custom_url_rewrite_outbound')) {
% {. Q9 s3 j& F$ C+ T: \ // Modules may alter outbound links by reference.6 N( C$ A* {# K
custom_url_rewrite_outbound($path, $options, $original_path);8 P1 B& \/ S( w: I
} 我们重点看下面的两个调用 drupal_get_path_alias 和 custom_url_rewrite_outbound。Drupal通过查询url_alias表,把要显示的URL更新为对应的alias就实现了别名的替换。 2). 处理别名的HTTP请求 Drupal在启动所有模块之前,先初始化URL,调用如下函数: function drupal_init_path() {0 ~% M; g7 j) q1 w2 l3 S
if (!empty($_GET['q'])) {$ g9 j C1 X) I1 Q5 Y. ?9 D
$_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));
" z4 W) Z5 v( k, H* e, Y, l }
% ^2 I/ Z% |5 n, J5 l else {3 D( N! l$ Z5 t. }" I3 g
$_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));9 k. b! a2 `) e: a" n. b
}3 w' W: }# w z' K$ A
}" a- D1 {# I0 J$ v4 J9 |$ h" Y: {" O
( U7 F, b; Q1 _4 |3 h$ ]
function drupal_get_normal_path($path, $path_language = '') {
; `5 M5 P9 v3 i6 I4 u4 _/ {5 [ $result = $path;" w h! k* l) Z5 x
if ($src = drupal_lookup_path('source', $path, $path_language)) {1 S/ I+ e) ~7 V& X. p$ [+ o
$result = $src;# a) G3 i9 S/ k0 D. T! d
}
* J+ ~& A: H$ A if (function_exists('custom_url_rewrite_inbound')) {5 e4 v" C7 z2 V4 \& j
// Modules may alter the inbound request path by reference.9 h7 P2 g7 x' ?9 U
custom_url_rewrite_inbound($result, $path, $path_language);; R0 t5 C o6 Z7 L# e
} \1 m8 K2 Z! V' k+ Y8 Y6 Y
return $result;% ~0 V% T* D$ x1 `# 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这两个函数。
具体代码如下: /**+ c. D; g- t6 w) y( i3 _" j7 \& D3 ?
* Define custom_url_rewrite_inbound()
4 D0 f1 ^7 `! d2 t: h9 p f! H* C * @author robbin
) S$ e' c. q2 i */1 O+ ?6 A. T5 i$ M3 f& N/ j
if (!function_exists('custom_url_rewrite_inbound')) {
9 h2 D+ g3 M- c8 f4 b; M6 }6 ? function custom_url_rewrite_inbound(&$result, $path, $path_language) {
5 [4 Y9 k$ `: c5 Q2 j+ i {fun_1}_url_inbound_alter($result, $path, $path_language);
0 Z2 w. V; X% i B& e4 f+ [ }
0 \9 x$ {6 y, L/ H5 J& L* U}. s& e3 H8 V6 e: J
2 d; j/ f( ?2 C$ i' o
/**
* U* @& t! d' T8 |4 P1 m( k * Define custom_url_rewrite_outbound()
: S# ~! {$ k* G/ l5 Z) B/ s * @author robbin
! o( G- u$ }4 v1 j */
( ?; I: Y! u# ~ M& nif (!function_exists('custom_url_rewrite_outbound')) {6 a+ o; a( t, K& ` R
function custom_url_rewrite_outbound(&$path, &$options, $original_path) {6 s, S1 f& a7 T
{fun_1}_url_outbound_alter($path, $options, $original_path);
% n' Y; F( V2 [ }2 K& G3 T$ e. ^9 L$ I4 s# u0 M3 U
} 其中 {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) {
3 P% [, L7 I& T9 p6 G: H3 A- w 5 K, U1 H9 [$ D
$arg0 = arg(0); //should be user-name2 P6 t' E" k& L. E4 l0 f
$arg1 = arg(1); //should be connections/media/...
9 Q% S% @/ E/ {: {7 m& F: m% C$ o t0 m ) r! J' P- |$ h% q! Q: u4 X
if ($arg1) {
# p B8 D$ I6 S" s8 ?2 \; G $user_url = drupal_lookup_path('source', $arg0);
: Z; h+ }6 D8 M& t- D if ($user_url != $arg0 && preg_match('{user/(\d+)}i', $user_url, $matches)) {# R+ |9 b0 v9 G; J- d3 F& P
$user_id = $matches[1];9 X2 z9 _$ H! j! i4 a' G3 q
$result = "user/$user_id/$arg1";3 k4 I( y" M; g. U5 ]
3 M4 U' X+ l/ f$ L, n' P6 q7 `
//add this to tell global_redirect not to redirect this url again
) {* |) I5 Z& m' m $_REQUEST['q'] = $result;
/ N! q/ z! K$ h# O9 t2 e }" }& p+ @. }4 E3 b) G0 y5 I. k2 P' j
}
5 t4 Z9 M* `3 n( a5 R8 c+ s}4 c' u8 p% t s Y" J( v/ |
& q% p n @2 _function my_redirect_url_outbound_alter (&$path, $options, $original_path) {/ q$ J0 S0 \/ Q! C
//rewrite user's sub tab url to seo-friendly url0 o0 q3 D7 J/ ~ R1 ?
//such as, user/1/media --> robbin-zhao/media' f' q& G @1 E
if (preg_match('{user/(\d+)/(\w+)}i', $path, $matches)) {, I) n) I) y$ Y' k% h6 A
$uid = $matches[1];1 r4 n, x9 q* l+ m, T
$tab = $matches[2];
: W; m5 a0 k: Y {: ^7 o; P! g
( O. v) O1 D3 ~ $alias = drupal_lookup_path('alias', "user/$uid");
6 k2 h$ F5 r- A% _ ' S7 y+ y- _6 e) ?
if ($alias != $path) {: _5 X/ L+ V" [ I& ?+ n8 q4 o
$path = "$alias/$tab";
. c4 k( q* \) B: e1 H }1 w5 ?6 K! l. k0 @5 D; T/ _- O
//$path = ''$ _2 d# p4 Z1 F L4 y* p8 A
}
4 n+ `8 \$ U |} 优化过的代码已经提交到Drupal官方网站,并且已经是一个第三方模块,大家可以下载使用。 模块地址:http://drupal.org/project/rewrite_sub_link
声明: 本站所有文章欢迎转载,所有文章未说明,均属于原创,转载均请注明出处。 本文有效链接: http://www.drupal001.com/2011/12/drupal-custom-url-alias/ 版权所有: Drupal与高性能网站架构 http://www.drupal001.com |