国外设计欣赏网站 - 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()) {
/ ]1 O& ^' q$ B: Z! \. A  // Merge in defaults.
  Z, }$ a4 Y! R. X8 E/ g  $options += array(
' w0 r% e& E! l+ T/ i8 Q) O    'fragment' => '',
4 Q! S+ L8 |% f    'query' => '',
( ^4 {7 b- G+ b# ]5 `    'absolute' => FALSE,9 L0 w: w" y' r. C% `' O
    'alias' => FALSE,4 t$ s1 N( Q9 `7 ^3 Q% ?: u5 a
    'prefix' => '',
% u: ~9 z" G: Q$ t: u  );" N& Z& T, Q( C' v
 8 E2 ^) x( |) q1 X9 {
 ...
3 m1 F+ I- }8 `" E) v# A 
$ m4 {/ m5 `( c; {8 H" U$ m* m  elseif (!empty($path) && !$options['alias']) {8 M' V  A- _7 E  W
    $path = drupal_get_path_alias($path, isset($options['language']) ? $options['language']->language : '');
$ E* @8 w' N* H/ @3 y  }$ e) E& G) r) R/ s# L7 p* \- o
 
  H) f, V- Q( ~) u# P" c) `  if (function_exists('custom_url_rewrite_outbound')) {. O5 D& U8 l$ T! v6 X" g
    // Modules may alter outbound links by reference.
2 J* y( W+ h: ?4 x. m8 H! I- z    custom_url_rewrite_outbound($path, $options, $original_path);- e- F8 @3 U7 T; O# X
  }

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

2). 处理别名的HTTP请求

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

function drupal_init_path() {5 c& S7 }9 @* p* {1 ~
  if (!empty($_GET['q'])) {
8 \  D  M5 r# X3 D# z$ o! {    $_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));8 M$ q! A) E- T* {) Y! a
  }  B- B) A( F  @% ~
  else {
2 E8 {/ [0 y- a7 H3 V/ O3 `    $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
& ?2 L8 ^/ s: @6 i2 Q  }: `! z( J, f: I2 I9 I0 b. e; Q5 M% I0 B
}/ C6 k% G% u$ [: k) y
 ' f, D$ m9 G6 [* E* I
function drupal_get_normal_path($path, $path_language = '') {
) h$ z8 F# q3 A5 m" p  $result = $path;
/ Q! a- S' J+ Q0 J- E- Z/ V. o  if ($src = drupal_lookup_path('source', $path, $path_language)) {
& s7 ~: r! i0 [  T1 {8 T    $result = $src;
  j* ~* }7 V# t" ~( `  }
4 o! X' ^3 I1 o  if (function_exists('custom_url_rewrite_inbound')) {8 W0 f# r$ k7 \3 }5 t5 U
    // Modules may alter the inbound request path by reference.. g3 l6 f0 S1 z% x' I
    custom_url_rewrite_inbound($result, $path, $path_language);: ^% b, z( @5 B0 u) H% v
  }, ?5 a; G0 W6 y" S; l
  return $result;4 R; p: Z4 E1 \- F5 ^0 O  ~
}

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

具体代码如下:

/**
% }2 F: Q) X& s* F# ?5 v, K7 I * Define custom_url_rewrite_inbound()! J& U5 \- X; S2 t2 ^$ R
 * @author robbin8 K  K7 n8 [5 F0 e* E# L
 */# r  W: h9 w: }4 `- ]  `7 V8 }
if (!function_exists('custom_url_rewrite_inbound')) {
  f& h' r2 y1 i$ }+ o6 R  function custom_url_rewrite_inbound(&$result, $path, $path_language) {  [8 U, \' T/ d+ f- f! c
    {fun_1}_url_inbound_alter($result, $path, $path_language);
/ Y, b4 e, J4 z/ s# m$ i+ A  }
5 h( s1 f# [" r( }5 I% P1 Q}
. Y8 f$ i& _1 |3 m8 p- B 
) ?3 F2 O6 n  E! S! K/**  P7 J( g) X2 o& d" f
 * Define custom_url_rewrite_outbound()
) V( ~% ~1 T9 P  v* S# M3 g7 P * @author robbin2 c% u: M; }% L5 H4 e- X
 */
7 Q8 B  {; I2 P" z$ A* ~" ?if (!function_exists('custom_url_rewrite_outbound')) {
. Q& M( u  g1 k! C  function custom_url_rewrite_outbound(&$path, &$options, $original_path) {# J' r7 D: ~5 S% ]0 Z: s; x
    {fun_1}_url_outbound_alter($path, $options, $original_path);: u# A5 ^  a* [
  }* |9 f! B  s' }& _% 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) {7 c  u5 V) }- M! e' e& ?3 ]4 I
 " r3 B6 E% [! S7 _5 x& Y) T
  $arg0 = arg(0); //should be user-name
- I& v6 Q3 g1 g! ~9 s  $arg1 = arg(1); //should be connections/media/...
" P5 U/ B' Y9 P6 ^ . u5 L9 y* I! N2 E& b
  if ($arg1) {) w5 w' q$ F( d  b5 w" e3 q# s" ?
    $user_url = drupal_lookup_path('source', $arg0);2 o9 m% R! N1 ?  _1 a% M: m
    if ($user_url != $arg0 && preg_match('{user/(\d+)}i', $user_url, $matches)) {
+ o5 c6 d) r4 V, m# W1 I      $user_id = $matches[1];& k& Z5 K. E* H! [$ z9 \
      $result = "user/$user_id/$arg1";
( ?/ m, `' d: |* a# M 
9 V, g6 g8 N( F+ _( y2 _: d/ B      //add this to tell global_redirect not to redirect this url again" |4 a% N. J; i6 y, W) r4 ?
      $_REQUEST['q'] = $result;
- `: p5 u' i! J: y9 i5 ]9 ^: Z    }
+ d+ I$ c, z$ h  z0 p& |* c* I  }
) |# L3 `  f- X}
3 X2 H( C. ?, o2 T, |( R: r2 I 4 R$ F3 m+ J* P- Z
function my_redirect_url_outbound_alter (&$path, $options, $original_path) {2 z1 P$ d4 O7 m5 Z
  //rewrite user's sub tab url to seo-friendly url' A( A3 m. n6 i
  //such as, user/1/media --> robbin-zhao/media* @0 }1 S) `$ m# H2 i; U, ~7 R
  if (preg_match('{user/(\d+)/(\w+)}i', $path, $matches)) {: T$ r) V7 h  {5 {0 S& v( ?
    $uid = $matches[1];
( I/ p1 v; D4 ^7 g- u1 f    $tab = $matches[2];0 _; v' W7 K: t- l
 
- t; r! }5 Q9 n/ E- N1 h    $alias = drupal_lookup_path('alias', "user/$uid");& M: r' V0 d! c* v5 `6 s4 p# t
 
! v" M; f3 h0 d6 C# t# ~    if ($alias != $path) {
6 j5 j$ U5 w7 b( Q4 U0 `      $path = "$alias/$tab";
9 ]2 h. V3 J3 q4 H    }
5 l2 w$ G+ P9 v' G" |5 ^% j# u    //$path = ''9 Z- h' w+ |, H
  }
/ A. h% Y' `7 }* ~% Q& y, D' ?( Z}


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

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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