国外设计欣赏网站 - 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()) {
2 I$ R( L) x4 R" u4 d  // Merge in defaults." W" @  y/ C, P1 t$ a
  $options += array(  p, o0 h% v+ e9 C+ f, t5 z/ a
    'fragment' => ''," f" T5 e( E" L
    'query' => '',6 r. y+ G6 ]6 j# Z' u
    'absolute' => FALSE,$ \8 O# z4 `3 Y& V' K; N8 V) F+ I# @
    'alias' => FALSE,; e* Z( ?6 U! Z
    'prefix' => '',9 D1 Q3 K- ^' `# A4 S" k; D  g
  );/ i5 ^  g1 r) H9 d4 ^# K- m
 ! i! ^* r! I) j$ D% i
 ...- s3 V8 @5 q) E* q$ R
 
, Q/ [" |4 h" |+ q) v  elseif (!empty($path) && !$options['alias']) {- o& E) l. R) B& e6 ]4 ]
    $path = drupal_get_path_alias($path, isset($options['language']) ? $options['language']->language : '');
2 Z" v2 A& i1 H9 @  }
2 {& g% \3 B0 J- F0 j4 {9 y 
$ _7 X; x% k3 W2 S, g  if (function_exists('custom_url_rewrite_outbound')) {9 S' ?) C7 T( T  g9 G) }1 w2 ?/ v! t
    // Modules may alter outbound links by reference.0 {( V1 l+ d/ ~% P/ j
    custom_url_rewrite_outbound($path, $options, $original_path);+ [# ?0 a% {& E6 s# Z& R2 Z/ ]
  }

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

2). 处理别名的HTTP请求

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

function drupal_init_path() {  l! _( h$ K+ t& m9 b
  if (!empty($_GET['q'])) {
$ H4 F$ q3 v3 \! o    $_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));
! U" Z' G+ B/ V2 ~& h  }
2 N8 @; k& ^- x) l% r0 _  else {
) g# I; Q5 W& a. F+ s- m) H    $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
/ }5 q2 I$ d1 d' e2 R' B  }6 F, r* ^! E( h7 P" B
}
# |* f2 S3 @  h& @2 Y , |* Z; t/ {8 d- z6 Z& Q4 e1 G6 N# ]
function drupal_get_normal_path($path, $path_language = '') {
' {+ ~8 w( g  d, P9 d- N! i. `  $result = $path;
2 K/ m6 `9 B! V$ S) I, K% j7 Z3 X  if ($src = drupal_lookup_path('source', $path, $path_language)) {
6 E6 m. H! Q1 u$ S' V) j    $result = $src;
0 J: z* h* Y  \5 T  }" C& O$ \1 J  Q
  if (function_exists('custom_url_rewrite_inbound')) {
$ D' W$ ]  h: k7 n5 ^* E% C    // Modules may alter the inbound request path by reference.
! H. a. f$ w- \    custom_url_rewrite_inbound($result, $path, $path_language);
+ W% p' r- i6 {7 f# u* B  b2 N+ r  }
! M- p: ^2 K5 [' o5 x5 {  return $result;* Y% P0 w, 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文件里面,根本掉用不到,这里提供一个目前较为合理的解决方案:

  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这两个函数。

具体代码如下:

/**
. s9 E+ Y' P5 G& d * Define custom_url_rewrite_inbound()  c2 }" O7 |* W
 * @author robbin
& V, m0 a3 b- J/ d */$ e+ R- t4 L% }/ t- l+ @! M
if (!function_exists('custom_url_rewrite_inbound')) {' n. f7 T$ I: m& z2 d
  function custom_url_rewrite_inbound(&$result, $path, $path_language) {! ^/ U: g0 c3 Z9 m- O. `
    {fun_1}_url_inbound_alter($result, $path, $path_language);6 `6 q/ H. }. {& m' J
  }
+ G4 [; E2 L& l! s3 z}- e2 {/ s' ^. A- A6 Z9 o
 " D2 B0 J$ S. ?; E9 K
/**
) a- X' f: Y  t' g4 O * Define custom_url_rewrite_outbound()1 f, K7 C+ _. w. I& v: ]
 * @author robbin
3 y- f# K) T4 |# e9 n */
3 E3 {" w. R' ^; O6 V: Oif (!function_exists('custom_url_rewrite_outbound')) {, M& }/ }  y% X6 A
  function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
: [, d  e% o: P0 O. t    {fun_1}_url_outbound_alter($path, $options, $original_path);
. ~( g, ~" G/ S3 h2 Z8 W7 b  }, P% p* K$ O* J: A( R# x
}

其中 {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) {
1 R3 z/ Z& x! n: n$ g& @# x + E' ?$ _& k' K% g" V
  $arg0 = arg(0); //should be user-name
* K& {- F* o! P  r0 a5 z, w, s  $arg1 = arg(1); //should be connections/media/...
& ~0 R. v! r- v5 ~ 9 ]6 q8 Y2 T# x8 a, G/ w/ K0 z
  if ($arg1) {
' A0 _- [0 h9 `0 z5 [8 [' A- S( ^    $user_url = drupal_lookup_path('source', $arg0);9 Q- S0 ?: Y0 e) J$ [
    if ($user_url != $arg0 && preg_match('{user/(\d+)}i', $user_url, $matches)) {$ Q5 A8 A5 ]4 J8 t6 n# Z7 W3 t
      $user_id = $matches[1];3 Y% p9 y; m- Q3 E4 m7 Q
      $result = "user/$user_id/$arg1";% o/ b0 F# r" {9 \8 v; ?# O* r
 + n8 B5 G1 [# D
      //add this to tell global_redirect not to redirect this url again
  m2 Y- r! K. Y      $_REQUEST['q'] = $result;
4 v& L5 t0 C3 F* L8 c8 _    }* K: q2 k$ Z5 h1 i
  }9 A3 _$ D* r! ~  x& Y+ r
}
, B% h2 M1 H6 x( B 
) m/ \" g  V- L4 ]8 ~( ifunction my_redirect_url_outbound_alter (&$path, $options, $original_path) {. u* b9 m) G# B/ w0 E1 w, m6 d4 S
  //rewrite user's sub tab url to seo-friendly url
; E; j% e( c6 f  //such as, user/1/media --> robbin-zhao/media# s9 d" |/ w. F' b+ l. j* B
  if (preg_match('{user/(\d+)/(\w+)}i', $path, $matches)) {4 S& }. u  G/ s! v% t; Z
    $uid = $matches[1];% }9 b, S: ]& d9 a4 T0 Z, V4 b% F
    $tab = $matches[2];
+ C4 `/ w$ @( v' S; ` * Z5 V) s* \5 o* X4 h! n
    $alias = drupal_lookup_path('alias', "user/$uid");3 [& H) D( c/ @  b& H' D
 
- H+ Y/ n1 a3 n. z: z5 d3 ?$ t    if ($alias != $path) {: m$ o) B, X7 K4 e; x1 Y
      $path = "$alias/$tab";
6 M8 e1 k/ q5 k3 x; Z- a+ R    }
6 F) k- J1 H, C( c5 _4 T    //$path = ''
* v! v3 q1 c% H2 E( W: a  }  A# W: }+ |3 C% D; V
}


优化过的代码已经提交到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, 4-19-2025 15:33 , Processed in 0.600897 second(s), 115 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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