|
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()) {
; C1 ^7 b# d2 w* t // Merge in defaults.
; V% p! x9 a7 C0 m X d& B $options += array(
, N1 f$ i- f; m P6 ~ 'fragment' => '',6 G3 P p' n# A K
'query' => '',
: @/ s" n& M6 Z5 Q8 C 'absolute' => FALSE,# c$ H( r, |; ]6 n
'alias' => FALSE,( T5 h0 Q4 L+ c- _& y7 ?
'prefix' => '',
6 e+ f, p2 a* ~( b% z6 @' i );* D/ E% F8 U$ j9 {5 |9 @# X8 r$ ?
2 d1 l6 S M. e0 L6 `6 }$ v0 t
...
1 C$ N7 L; `+ I4 f i ^) T2 [ " |0 O* c8 g5 Q
elseif (!empty($path) && !$options['alias']) {
4 E5 d& x# L. d' v _ $path = drupal_get_path_alias($path, isset($options['language']) ? $options['language']->language : '');% d- p# P) N# I
}. L% u, Z; {" h0 _2 e
5 H; j5 R' `8 R: S( b4 [$ t4 B/ P if (function_exists('custom_url_rewrite_outbound')) {5 ]# _* z9 _6 T4 E- U6 Z: F' [5 {
// Modules may alter outbound links by reference.
* Z# j3 k" d2 N9 \6 F4 k6 X! [ custom_url_rewrite_outbound($path, $options, $original_path);7 a; g% |* z# }$ s; }4 e+ N# T3 t" q) Q
}我们重点看下面的两个调用 drupal_get_path_alias 和 custom_url_rewrite_outbound。Drupal通过查询url_alias表,把要显示的URL更新为对应的alias就实现了别名的替换。 2). 处理别名的HTTP请求 Drupal在启动所有模块之前,先初始化URL,调用如下函数: function drupal_init_path() {
. P2 [+ L" }3 A0 c W4 D* L, \$ x if (!empty($_GET['q'])) {' Z* ?! y8 _: q3 _/ P* ?7 Q
$_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));
# ?" S4 {4 ~$ h8 B }
/ u* R9 e. p4 Y O2 U+ [# [! w else {$ X2 X" l6 k; z/ L! V5 I' Z
$_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));5 ]) X$ S7 u- N* V7 a" d
}$ U: n( C5 A) Y r
}! v( ^! n7 H8 o) |
4 Y' o8 u7 L: q) D/ b# s# C
function drupal_get_normal_path($path, $path_language = '') {
: k/ N# M2 {+ f0 M2 Z3 Q7 `$ I $result = $path;" j( E& R V1 A+ o5 {
if ($src = drupal_lookup_path('source', $path, $path_language)) {) v, ^. j1 I; E! F' m+ p
$result = $src;
2 Y# M4 ^0 R+ `% S9 w- {* e5 ? }
F6 @: g2 A W5 K$ k( x U& g if (function_exists('custom_url_rewrite_inbound')) {
% @. Y" }2 L8 R& }8 \0 h. X; I // Modules may alter the inbound request path by reference.
, j }* G4 l0 s/ G custom_url_rewrite_inbound($result, $path, $path_language);
' t1 a# m, L. U9 Q$ E }
+ q: P1 r/ C& A4 H return $result;
; U! v* z% ^. F4 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这两个函数。
具体代码如下: /**
+ b5 O, U' N' {/ _! b: h * Define custom_url_rewrite_inbound()$ S0 [6 \- j$ m* ~6 N+ B
* @author robbin+ ]+ q* N; \( s$ _3 Z
*/0 a# b" W) @5 y0 x9 Q* Z6 i( A3 I
if (!function_exists('custom_url_rewrite_inbound')) {. {: l1 M9 n E) m& `* U$ y- K
function custom_url_rewrite_inbound(&$result, $path, $path_language) {" K8 u! e1 o1 q
{fun_1}_url_inbound_alter($result, $path, $path_language);+ \) P" n( f; F* Q2 e
}
; p* p6 p/ R% y- }9 H* k}
2 g5 _2 Z s6 V1 O! f( s * f0 t" L/ u( P
/*** y9 q: U, }- o! W& G+ B! F. T
* Define custom_url_rewrite_outbound(). l0 S8 v4 a7 w
* @author robbin
5 @+ r$ F# P0 S& [2 t9 L */
; d K- m, \# F `if (!function_exists('custom_url_rewrite_outbound')) {/ h$ L0 ^) \' H
function custom_url_rewrite_outbound(&$path, &$options, $original_path) {" N. l( q* X( ^$ U* q' M
{fun_1}_url_outbound_alter($path, $options, $original_path);
0 h- F, j' J$ L2 Z R }3 F4 o5 f) I4 M8 Q5 i: S
}其中 {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 l. P6 |/ D# Z# X$ X 1 j5 z" R4 j% s* R9 N! N
$arg0 = arg(0); //should be user-name6 k: P& m1 T9 |& ^
$arg1 = arg(1); //should be connections/media/...
) U$ n, {' q( s' q2 W
- o r+ J' L, v0 q6 A if ($arg1) {8 {+ G) K2 j. ~' G2 L! I
$user_url = drupal_lookup_path('source', $arg0);
; F# h ~! r0 ] Z1 T if ($user_url != $arg0 && preg_match('{user/(\d+)}i', $user_url, $matches)) {+ d+ s& x1 c/ n N6 M
$user_id = $matches[1];2 y/ M4 G) ~- h
$result = "user/$user_id/$arg1";( Y/ L6 u4 ]$ `% K4 _( k( A
( v4 O2 m7 D" g- a$ ~, m2 W8 r, b //add this to tell global_redirect not to redirect this url again& P* T+ |" t7 F0 I9 a* n( Q4 ~) j r
$_REQUEST['q'] = $result;
4 j6 ^) s2 A$ ^) ~5 g2 r }0 q2 u# {$ U5 ^6 V# d7 g0 [# ]
}. C- m P* k- [( n
}
% `" I! l V( }$ {
7 a0 f0 N- X& q$ z: Jfunction my_redirect_url_outbound_alter (&$path, $options, $original_path) {
: v/ f: A5 z4 T) m //rewrite user's sub tab url to seo-friendly url* K0 F. Q/ @+ j* F* ?% ?
//such as, user/1/media --> robbin-zhao/media5 T; N9 u4 L9 S |9 C0 U( U+ q3 A
if (preg_match('{user/(\d+)/(\w+)}i', $path, $matches)) {8 c3 b3 ?! Z) Q+ |: G
$uid = $matches[1];
. S* w' Z4 |1 p# L $tab = $matches[2];; \* J& t3 m b; |1 n& {" {& v& L
, p' G4 H) e; Q+ t1 F4 k( x% o: b
$alias = drupal_lookup_path('alias', "user/$uid");
& w0 b8 x; \. E* K( s 2 H! \* h( y$ h) E1 L
if ($alias != $path) {; M7 }/ U) f( T" z
$path = "$alias/$tab";7 \8 L: f3 K: p6 O* J+ W& O
}/ n0 V, M5 z2 o5 l) W- E
//$path = ''
) W. f. @1 E& ]" p8 L }
3 `; |# r2 g! l5 v ~/ P} 优化过的代码已经提交到Drupal官方网站,并且已经是一个第三方模块,大家可以下载使用。 模块地址:http://drupal.org/project/rewrite_sub_link
声明: 本站所有文章欢迎转载,所有文章未说明,均属于原创,转载均请注明出处。 本文有效链接: http://www.drupal001.com/2011/12/drupal-custom-url-alias/ 版权所有: Drupal与高性能网站架构 http://www.drupal001.com |