User login

Drupal và sub-domain

Đối với những site có rất nhiều nội dung, có lẽ chúng ta cần tạo những URL đơn giản, gọn gàng để người dùng dễ nhớ để truy cập lại sau này. Thí dụ, toila.net/thehong thì đẹp hơn toila.net/index.php?q=user/1, web.com/thongbao sẽ dễ nhớ hơn web.com/index.php?q=taxonomy/term/1+2+3 rất nhiều hay là thehong.yeublog.com sẽ chuyên nghiệp hơn là yeublog.com/index.php?module=blog&action=frontpage, ... Đối với sub-domain dạng sub folder thì vấn đề được giải quyết rất đơn giản, nhưng đối với sub-domain dạng *subdomain.domain.com* thì có một số trở ngại. Bài viết này nêu lên một số trở ngại và cách giải quyết.

Yêu cầu hệ thống

  1. Apache/server hỗ trợ mod_rewrite, cấu hình trên từng thư mục bằng tập tin .htaccess.
  2. Có cài đặt module rewrite.
  3. Host phải hỗ trợ chức năng subdomain wildcard -- subdomain ảo. Khi chức năng subdomain wildcard này được kích hoạt, các request đến server dưới dạng *http://foo.domainname.com/bar* sẽ được server hiểu là *http://domainname.com/bar*. Khi đó, các request đến Drupal site đều quy về một mối -- các request dạng http://foo.domainname.com/node/1, server sẽ gọi Drupal site của bạn với URL có dạng http://domainname.com/index.php?q=node/1

Cookie

Việc tạo tên SESSION trong Drupal phụ thuộc vào domain (và sub domain) được request, cho nên, cũng là một người truy cập, nhưng khi bạn truy cập http://domainname.com và khi bạn truy cập http://foo.domainame.com, thì đối với Drupal, bạn là hai người khác nhau. Tham khảo hàm config_init. Để giải quyết trở ngại này, chúng ta phải đồng bộ tên SESSION khi sử dụng các domain/sub-domain. Mở tập tin sites/settings/settings.php, thêm (bỏ comment) dòng:

  $cookie_domain = domainname.com';

Vấn đề còn lại giờ, chúng ta hải chỉnh lại tập tin .htaccess để Drupal hiểu được chính xác các yêu cầu của người dùng ứng với các domain/sub-domain:

  1. http://foo.domainname.com/ => http://domainname.com/index.php?q=foo
  2. http://bar.domainname.com/baz/blah => http://domainname.com/index.php?q=baz/blah

Rewrite

Apply patch này (áp dụng cho Drupal 5.7) để điều chỉnh lại tập tin .htaccess. Khi đó, .htaccess của Drupal sẽ có dạng sau:

  1. #
  2. # Apache/PHP/Drupal settings:
  3. #
  4.  
  5. # Protect files and directories from prying eyes.
  6. <FilesMatch "\.(engine|inc|info|install|module|profile|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(code-style\.pl|Entries.*|Repository|Root|Tag|Template)$">
  7. Order allow,deny
  8. </FilesMatch>
  9.  
  10. # Don't show directory listings for URLs which map to a directory.
  11. Options -Indexes
  12.  
  13. # Follow symbolic links in this directory.
  14. Options +FollowSymLinks
  15.  
  16. # Customized error messages.
  17. ErrorDocument 404 /index.php
  18.  
  19. # Set the default handler.
  20. DirectoryIndex index.php
  21.  
  22. # Override PHP settings. More in sites/default/settings.php
  23. # but the following cannot be changed at runtime.
  24.  
  25. # PHP 5, Apache 1 and 2.
  26. <IfModule mod_php5.c>
  27. php_value magic_quotes_gpc 0
  28. php_value register_globals 0
  29. php_value session.auto_start 0
  30. php_value mbstring.http_input pass
  31. php_value mbstring.http_output pass
  32. php_value mbstring.encoding_translation 0
  33. </IfModule>
  34.  
  35. # Requires mod_expires to be enabled.
  36. <IfModule mod_expires.c>
  37. # Enable expirations.
  38. ExpiresActive On
  39. # Cache all files for 2 weeks after access (A).
  40. ExpiresDefault A1209600
  41. # Do not cache dynamically generated pages.
  42. ExpiresByType text/html A1
  43. </IfModule>
  44.  
  45. # Various rewrite rules.
  46. <IfModule mod_rewrite.c>
  47. RewriteEngine on
  48.  
  49. # If your site can be accessed both with and without the 'www.' prefix, you
  50. # can use one of the following settings to redirect users to your preferred
  51. # URL, either WITH or WITHOUT the 'www.' prefix. Choose ONLY one option:
  52. #
  53. # To redirect all users to access the site WITH the 'www.' prefix,
  54. # (http://example.com/... will be redirected to http://www.example.com/...)
  55. # adapt and uncomment the following:
  56. RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
  57. RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
  58. #
  59. # To redirect all users to access the site WITHOUT the 'www.' prefix,
  60. # (http://www.example.com/... will be redirected to http://example.com/...)
  61. # uncomment and adapt the following:
  62. # RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
  63. # RewriteRule ^(.*)$ http://example.com/$1 [L,R=301]
  64.  
  65. # Modify the RewriteBase if you are using Drupal in a subdirectory or in a
  66. # VirtualDocumentRoot and the rewrite rules are not working properly.
  67. # For example if your site is at http://example.com/drupal uncomment and
  68. # modify the following line:
  69. # RewriteBase /drupal
  70. #
  71. # If your site is running in a VirtualDocumentRoot at http://example.com/,
  72. # uncomment the following line:
  73. # RewriteBase /
  74.  
  75. # Rewrite old-style URLs of the form 'node.php?id=x'.
  76. #RewriteCond %{REQUEST_FILENAME} !-f
  77. #RewriteCond %{REQUEST_FILENAME} !-d
  78. #RewriteCond %{QUERY_STRING} ^id=([^&]+)$
  79. #RewriteRule node.php index.php?q=node/view/%1 [L]
  80.  
  81. # Rewrite old-style URLs of the form 'module.php?mod=x'.
  82. #RewriteCond %{REQUEST_FILENAME} !-f
  83. #RewriteCond %{REQUEST_FILENAME} !-d
  84. #RewriteCond %{QUERY_STRING} ^mod=([^&]+)$
  85. #RewriteRule module.php index.php?q=%1 [L]
  86.  
  87. # Rewrite current-style URLs of the form 'index.php?q=x'.
  88. RewriteCond %{REQUEST_FILENAME} !-f
  89. RewriteCond %{REQUEST_FILENAME} !-d
  90. RewriteCond %{REQUEST_URI} ^/.+$
  91. RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
  92.  
  93. # Rewrite subdomain.example.com to example.com/index.php?q=subdomain
  94. RewriteCond %{REQUEST_URI} ^/$
  95. RewriteCond %{HTTP_HOST} ^(.+)\.example\.com$ [NC]
  96. RewriteRule ^.*$ index.php?q=%1 [L,QSA]
  97. </IfModule>
  98.  
  99. # $Id: .htaccess,v 1.81.2.4 2008/01/22 09:01:39 drumm Exp $

Ứng dụng

Chúng ta có thể áp dụng chức năng sub-domain cho các trường hợp sau:

  • Multi blogger sites - Mỗi user blog có một sub-domain.
  • Site bán hàng - Mỗi site, mỗi shop có một domain name riêng biệt.
  • Các tờ báo lớn, ...
  • Kết hợp với module path của Drupal để tạo các path tùy biến.
  • Kết hợp với module pathauto để hệ thống tự sinh ra các path đẹp cho: các node, hồ sơ người dùng, ...

Thế Hồng

Tham khảo

  • root Drupal 5's .htaccess file
  • Apache document: http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html

Comments

Generate URL

Hi Thế Hồng,

Hôm trước, Mình đang hỏi TH trên group như không nhớ password để login hỏi tiếp nên vào đây hỏi luôn TH cho tiện.

Vấn đề từ clean URL và dùng .htaccess để chuyển về url của drupal dạng ?q=xyz thì không vấn đề gì cả.

Vấn đề hôm trước mình thắc mắc là hệ thống url của drupal, kể cả pathauto mod của drupal không cho phép sinh ra url dạng http://sub.domain.com (ví dụ lấy term làm sub như http://term1.domain.com). Một số domain quản lý được dạng này đều phải patch vào mod path. TH có giải pháp nào làm chuyện này mà không cần patch path mod không?

Thks

Cái này thì phải hack

Cái này thì phải hack rồi, nếu sử dụng module views, bạn có thể sử dụng một số hook của views để xử lý ra được mảng $subdomains, và hack hàm url ra dạng sau (drupal 5):

function url($path = NULL, $query = NULL, $fragment = NULL, $absolute = FALSE) {
  if (isset($fragment)) {
    $fragment = '#'. $fragment;
  }
 
  // Return an external link if $path contains an allowed absolute URL.
  // Only call the slow filter_xss_bad_protocol if $path contains a ':' before any / ? or #.
  $colonpos = strpos($path, ':');
  if ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path)) {
    // Split off the fragment
    if (strpos($path, '#') !== FALSE) {
      list($path, $old_fragment) = explode('#', $path, 2);
      if (isset($old_fragment) && !isset($fragment)) {
        $fragment = '#'. $old_fragment;
      }
    }
    // Append the query
    if (isset($query)) {
      $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . $query;
    }
    // Reassemble
    return $path . $fragment;
  }
 
  global $base_url, $subdomains;
  static $script;
  static $clean_url;
 
  if (!isset($script)) {
    // On some web servers, such as IIS, we can't omit "index.php". So, we
    // generate "index.php?q=foo" instead of "?q=foo" on anything that is not
    // Apache.
    $script = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === FALSE) ? 'index.php' : '';
  }
 
  // Cache the clean_url variable to improve performance.
  if (!isset($clean_url)) {
    $clean_url = (bool)variable_get('clean_url', '0');
  }
 
  $base = ($absolute ? $base_url . '/' : base_path());
 
  // The special path '<front>' links to the default front page.
  if (!empty($path) && $path != '<front>') {
  	$_path = $path;
    $path = drupal_get_path_alias($path);
    $path = drupal_urlencode($path);
 
    if ($subdomains[$_path]) {
    	$base = preg_replace ('|http://w{0,3}|', 'http://' . $subdomains[$_path] . '.', $base_url);
 
    	if ($subdomains[$_path] == $path) {
    		return $base;
    	}
    }
 
    if (!$clean_url) {
      if (isset($query)) {
        return $base . $script .'?q='. $path .'&'. $query . $fragment;
      }
      else {
        return $base . $script .'?q='. $path . $fragment;
      }
    }
    else {
      if (isset($query)) {
        return $base . $path .'?'. $query . $fragment;
      }
      else {
        return $base . $path . $fragment;
      }
    }
  }
  else {
    if (isset($query)) {
      return $base . $script .'?'. $query . $fragment;
    }
    else {
      return $base . $fragment;
    }
  }
}

Nói thêm về cách xây dựng biến toàn cục $subdomains

Giả sử các node được trình bày ra giao diện thông qua views.

1. Sử dụng hook_views_table để định nghĩa một views-field

/**
 *  Implementation of hook_views_tables
 */
function something_views_tables () {
  return array (
    'subdomain' => array(
      'name' => 'node',
      'fields' => array(
        'alias' => array(
          'name' => t('Subdomain: Group alias'),
          'handler' => 'something_handler_field_alias',
          'notafield' => TRUE
        )
      )
    )
  );
}

2. Một hàm để handle views-field đã định nghĩa

/**
 * Tìm alias của shop và lưu vào mảng $subdomains
 */
function something_handler_field_alias ($fieldinfo, $fielddata, $value, $data) {
  global $subdomains;
 
  if ($data && !isset ($subdomains['node/' . $data->nid])) {
    // ...
    // Do your job here //
    // ...
    if (!empty ($alias)) {
    	$subdomains['node/' . $data->nid] = $alias;
    }
  }
}

3. Sử dụng hook_views_pre_query để tự động chèn views-field đã định nghĩa vào tất cả các view

function dv_og_views_pre_query (&$view) {
  array_unshift (
    $view->field,	
  	array (
      'vid' => 16,
      'tablename' => 'subdomain',
      'field' => 'alias',
      'handler' => '',
      'sortable' => 0,
      'defaultsort' => '', 
      'options' => '',
      'position' => 0,
      'fullname' => 'subdomain.alias',
      'id' => 'subdomain.alias',
      'queryname' => 'subdomain_alias'
  	)
  );
}

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <sup> <br> <p> <h3>
  • Lines and paragraphs break automatically.
  • Link to content with [[some text]], where "some text" is the title of existing content or the title of a new piece of content to create. You can also link text to a different title by using [[link to this title|show this text]]. Link to outside URLs with [[http://www.example.com|some text]], or even [[http://www.example.com]].
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]". PHP source code can also be enclosed in <?php ... ?> or <% ... %>.

More information about formatting options

CAPTCHA
This question is used to make sure you are a human visitor and to prevent spam submissions.
Image CAPTCHA
Copy the characters (respecting upper/lower case) from the image.