国外设计欣赏网站 - DOOOOR.com

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,微信登陆

搜索

[Drupal教程] Drupal自定义代码实现URL重写

[复制链接]
发表于 4-20-2012 21:26 | 显示全部楼层 |阅读模式

Drupal中使用URL别名在SEO以及网站用户体验方面非常重要,通常我们使用如下几个模块,

  1. path(核心模块)
  2. pathauto
  3. path_redirect
  4. 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()) {6 K" U0 V) k0 _7 J* K
  // Merge in defaults.
; _  h! H+ v# e% E2 V( E  $options += array(/ _4 l8 ?7 N2 V, _/ t( A! F
    'fragment' => '',
. U; y$ T0 l- C6 z/ G* E+ Z    'query' => '',
2 p, p, ]& D' X" A: A5 M) R    'absolute' => FALSE,
$ V) ~5 m: u# ~7 U8 F9 s3 I    'alias' => FALSE,
+ Y7 G4 S- J" T8 s/ R/ ^( s    'prefix' => '',7 Y! H* Q0 x* W# Q' q7 G, x, Q
  );
6 V% w1 p1 }7 b1 r+ `" s& e9 P. c& d' B" Y 
$ c/ X! _9 U& c( G/ b) | ...; n0 P4 F7 ~+ u  w  X7 j$ A
 $ y# D4 q' s3 J/ f7 o
  elseif (!empty($path) && !$options['alias']) {
* o1 X, G' r8 i" K4 g+ E3 S4 p( W    $path = drupal_get_path_alias($path, isset($options['language']) ? $options['language']->language : '');
" R* g  M8 K8 y( X$ t8 L! S  }& B& F6 R4 F7 ?2 j0 ^) m0 `
 
  s6 Y3 W; y+ j$ @6 _  if (function_exists('custom_url_rewrite_outbound')) {- s. k5 F6 b! u' {
    // Modules may alter outbound links by reference.
1 a# k( e4 l8 ~& R$ X- ~* V: m7 k% m    custom_url_rewrite_outbound($path, $options, $original_path);
; ?$ a0 v7 o* ?& {3 ]  }

我们重点看下面的两个调用 drupal_get_path_alias 和 custom_url_rewrite_outbound。Drupal通过查询url_alias表,把要显示的URL更新为对应的alias就实现了别名的替换。

2). 处理别名的HTTP请求

Drupal在启动所有模块之前,先初始化URL,调用如下函数:

function drupal_init_path() {
2 c& Q) x2 f' P  if (!empty($_GET['q'])) {
- W3 |" w' O' z2 l/ u. m    $_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));
% R7 a! C. s4 x9 p7 e1 e  }; i* W. q, W. X$ o
  else {8 ^9 k9 Y/ ]4 T0 |
    $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));, {5 h" F5 U. h
  }3 w) T6 G' n7 R' [  v1 c
}
7 l! |( i6 d; n 7 q. F  R5 [0 I, H/ `9 }. L$ s, h
function drupal_get_normal_path($path, $path_language = '') {1 i9 V- ?' K  G- ]4 j) O1 r  j
  $result = $path;7 Q+ }2 a- d8 k8 w
  if ($src = drupal_lookup_path('source', $path, $path_language)) {
$ Z" q% n' t: |+ t    $result = $src;: A( ~' G8 \4 x' e# b) q5 W/ X
  }& W! ~% @# g) f
  if (function_exists('custom_url_rewrite_inbound')) {& l; p& [+ V9 a2 ?7 Z* i: r
    // Modules may alter the inbound request path by reference.
+ {* ], @  |8 m) ?3 v$ y" b    custom_url_rewrite_inbound($result, $path, $path_language);1 }; \$ U5 S2 q$ D/ O
  }2 w1 A# |3 R6 o0 o. t$ N' J4 V- N
  return $result;! B1 _; q9 O  v. ]1 q. S
}

函数 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文件里面,根本掉用不到,这里提供一个目前较为合理的解决方案:

  1. 写一个inc文件,放到(任意)自定义模块下面,比如 my-core/my-core.rewrite.inc
  2. 修改settings文件,include这个文件。比如 include “sites/all/modules/custom/my-core/my-core.rewrite.inc”;
  3. 在该文件中加入inbound和outbound这两个函数。

具体代码如下:

/**; ~& H0 ?7 D0 I# b
 * Define custom_url_rewrite_inbound()
2 Y5 H- @, W6 j4 X* ^ * @author robbin# ?/ Z. D& t* V6 z) F9 i" a5 a
 */
6 A$ \2 v" s& g# Fif (!function_exists('custom_url_rewrite_inbound')) {; E: ]- E! i9 }. V# f3 D
  function custom_url_rewrite_inbound(&$result, $path, $path_language) {
, L  ~. l* x0 o+ x. D    {fun_1}_url_inbound_alter($result, $path, $path_language);
+ }. B  T( P2 O3 A) m  }* v( W6 \# J. b5 b8 @+ o
}6 x. e) E; D1 E- @1 J" k) }* ?- d% |3 @
 . X# w/ Y7 r$ C& P' r
/**
0 y$ D1 `6 [) C0 d * Define custom_url_rewrite_outbound()
* L* q* Y5 Q* e3 R * @author robbin
  u, s" m: Z7 R */6 }5 ~. A, P) ?8 [+ z% E3 v
if (!function_exists('custom_url_rewrite_outbound')) {
" `+ E% {1 D" P0 o% o  R1 y) j0 h  function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
3 e% y4 ]0 d6 p# G9 |! x    {fun_1}_url_outbound_alter($path, $options, $original_path);
) I, g" ?: Q7 `2 P+ p4 j8 I  }
! |; x2 y8 D  c/ ]. 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) {& E. C3 `' \2 _( R! r
 
6 L& Q' q3 z( F  $arg0 = arg(0); //should be user-name( W/ \" Z$ ~0 S! ?2 R1 t  B
  $arg1 = arg(1); //should be connections/media/...
0 l% u- A+ y* m; {: `' Y% W8 T' t6 L 
, r0 X9 x/ T1 X0 v  if ($arg1) {! l) |8 i$ L; H5 x! o4 o% ^
    $user_url = drupal_lookup_path('source', $arg0);
# u6 y' A! ]5 Q* \8 {    if ($user_url != $arg0 && preg_match('{user/(\d+)}i', $user_url, $matches)) {
3 M+ T7 F3 L1 u# z      $user_id = $matches[1];
& X* s0 I% R3 {2 F/ `$ a! `      $result = "user/$user_id/$arg1";) f9 e! {) v1 _9 L' v: i6 [: z
 ; i! ^5 E1 X  w1 _9 p0 J/ P0 z$ y9 p
      //add this to tell global_redirect not to redirect this url again+ k2 k" _' \# P2 h& T
      $_REQUEST['q'] = $result;
6 S* S; \# n6 k! j* W" g/ r" z6 D% U    }0 l5 E0 O( o1 q+ |1 C  O0 W
  }" d6 I2 f# M9 h/ Z
}: A8 V6 T/ U* w) K
 1 T. }$ W6 H1 H& S& L
function my_redirect_url_outbound_alter (&$path, $options, $original_path) {
% }' |; a% q- V9 h$ M  //rewrite user's sub tab url to seo-friendly url
! X8 y; d0 Z/ _  //such as, user/1/media --> robbin-zhao/media& e3 r4 c# w7 n" G9 |& }3 \# ^1 h
  if (preg_match('{user/(\d+)/(\w+)}i', $path, $matches)) {
  @  O& m4 \# b/ b% x8 y    $uid = $matches[1];7 s' o7 L: z4 W4 \) y- A* z
    $tab = $matches[2];
7 {, t3 c/ t3 T+ D 2 L! H. T5 Z& r
    $alias = drupal_lookup_path('alias', "user/$uid");5 {6 ]" X; C5 |6 P
 
' X0 w# ?( `9 e3 @- R$ m    if ($alias != $path) {
, Y% {3 O& o/ E      $path = "$alias/$tab";( l1 f* Y7 f* k: w. \
    }
6 i: N; e6 J( E& G    //$path = ''$ Q. H3 F0 V0 Y# A$ D  K4 m; ^
  }
" R0 R) u# Y' E& `8 k; e}


优化过的代码已经提交到Drupal官方网站,并且已经是一个第三方模块,大家可以下载使用。
模块地址:http://drupal.org/project/rewrite_sub_link





声明: 本站所有文章欢迎转载,所有文章未说明,均属于原创,转载均请注明出处。 
本文有效链接: http://www.drupal001.com/2011/12/drupal-custom-url-alias/ 
版权所有: Drupal与高性能网站架构 http://www.drupal001.com

|2011-2026-版权声明|平台(网站)公约|DOOOOR 设计网 ( 吉ICP备2022003869号 )

GMT+8, 6-18-2025 23:08 , Processed in 2.530580 second(s), 113 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表