??xml version="1.0" encoding="utf-8" standalone="yes"?>一区二区成人,国产96在线亚洲,久久久精品日韩欧美http://www.aygfsteel.com/rain1102/category/37651.html<br/><font color="green" style="font-family: 华文行楷;font-size:16px;">子曰Q危邦不入,乱邦不居。天下有道则见,无道则隐?lt;/font><font color="#3C1435"></font>zh-cnFri, 20 Feb 2009 09:44:56 GMTFri, 20 Feb 2009 09:44:56 GMT60Windows下IIS+PHP 5.2的安装与配置http://www.aygfsteel.com/rain1102/archive/2009/01/07/250374.htmlEric.ZhouEric.ZhouWed, 07 Jan 2009 09:05:00 GMThttp://www.aygfsteel.com/rain1102/archive/2009/01/07/250374.htmlhttp://www.aygfsteel.com/rain1102/comments/250374.htmlhttp://www.aygfsteel.com/rain1102/archive/2009/01/07/250374.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/250374.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/250374.htmlWindows下PHP的安装虽然简单,但如果不注意ҎQ仍然会让你头疼。此外,PHP 5.2版本与之?.x版本也有一些不同,所以有必要记录一下,避免下次忘记了这L安装配置Ҏ?br />
步骤一Q下载php 5.2 for windows的安装包Q解压至C:\php。注意此解压目录可以是在M盘下Q然而目录名不能包含I格Q?br /> 以下是php5.2的文件目录:
c:\php
   |
   +--dev
   |  |
   |  |-php5ts.lib
   |
   +--ext                 -- extension DLLs for PHP
   |  |
   |  |-php_bz2.dll
   |  |
   |  |-php_cpdf.dll
   |  |
   |  |-..
   |
   +--extras
   |  |
   |  +--mibs             -- support files for SNMP
   |  |
   |  +--openssl          -- support files for Openssl
   |  |
   |  +--pdf-related      -- support files for PDF
   |  |
   |  |-mime.magic
   |
   +--pear                -- initial copy of PEAR
   |
   |
   |-go-pear.bat          -- PEAR setup script
   |
   |-fdftk.dll
   |
   |-..
   |
   |-php-cgi.exe          -- CGI executable
   |
   |-php-win.exe          -- executes scripts without an opened command prompt
   |
   |-php.exe              -- CLI executable - ONLY for command line scripting
   |
   |-..
   |
   |-php.ini-dist         -- default php.ini settings
   |
   |-php.ini-recommended  -- recommended php.ini settings
   |
   |-php5activescript.dll
   |
   |-php5apache.dll
   |
   |-php5apache2.dll
   |
   |-..
   |
   |-php5ts.dll           -- core PHP DLL
   |
   |-...

步骤二:c:\php目录下的php.ini-recommendedQ或php.ini-dist文gQ官Ҏ荐ؓ前者)复制到当前目录,q修Ҏ件名为php.iniQ?br />
步骤三:~辑php.ini。主要修改如下两行的|
extension_dir = "c:\php\ext"
doc_root = "c:\inetpub\wwwroot"

修改旉要删除掉q两行行首的;注释。extension_dir的gؓphp安装目录下的ext目录Qdoc_root的gؓIIS讄的主目录Q?br />
步骤四:讄环境变量。在Path后添加如下的|
;:\php
然后重启计算机?br />
步骤五:打开Internet信息服务Q找?#8220;默认|站”Q将|站停止。然后打开“属?#8221;c在“属?#8221;中扑ֈ“ȝ?#8221;标签Q单?#8220;配置”按钮Q添加应用程序映。其值分别ؓQ?br /> 可执行文Ӟc:\php\php5isapi.dll
扩展名:.php
其余不用修改Q确定后Q重新启动默认网站;

步骤六:在c:\inetpub\wwwroot下新Z个文件hello.php。输入内容:
<html>
  <head>
    <title>World</title>
  </head>

  <body>
    <?php echo "Hello world" ?>
   
  </body>
</html>
保存后,打开览器,输入地址Q?a href="http://localhost/hello.php">http://localhost/hello.php。如果网中昄Hello world则说明安装正。我们也可以在网中通过查看hello.php的源代码Q如果源代码中没有php代码Q也说明安装是正的?br />



Eric.Zhou 2009-01-07 17:05 发表评论
]]>
OG(Organic Group) 模块介绍http://www.aygfsteel.com/rain1102/archive/2007/12/20/168950.htmlEric.ZhouEric.ZhouThu, 20 Dec 2007 02:21:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/20/168950.htmlhttp://www.aygfsteel.com/rain1102/comments/168950.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/20/168950.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/168950.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/168950.htmlDescription
让用者可以徏立ƈ理他们自己的群l。每一个群l可以拥有自q成员Qƈ有一个群l首,让群l成员可以在此张贴文章、彼此交?br /> 有的组需要管理者审核后才能加入Q或甚至需要透过邀h能加入。群l可以拥有自q版型、语pR分cȝQ有多个讑֮目Qƈ可与View模块整合?br /> Enable users to create and manage their own 'groups'. Each group can have subscribers, and maintains a group page where subscribers can post into. Posts may be placed into multiple groups (i.e. cross-posting) and individual posts may be shared with non-subscribers or not. Membership to groups may be open, closed, moderated, or invitation only. Add-on modules are available for group image galleries, group calendars, group vocabulary, group stores, and so on.

Groups may choose their own theme and language. Groups have RSS feeds, and so on.

Installation
安装以后Q需要新Z个内容类型,比如QgroupsQ然后把q个groups内容cd与OG兌Q进入Organic groups configurationQ设|Group home page 为groups 内容cdQ?/p>

 

相关模块Q?br /> ------------------------------------------------------------------
OG Actions
  1. http://drupal.org/project/og_actions
  2. The og_actions module is a collection of 5 actions for use with the actions module and workflow module. These actions facilitate the use of organic groups with the actions and workflow modules, allowing administrators to create rules to modify the organic group information for specific nodes.

---------------------------------------------------------------------------------
OG Aggregator

  1. http://drupal.org/project/og_aggregator
  2. 可以?Organic Groups 拥有自己?RSS Aggregator?
  3. A module to create individual aggregator for Organic Groups using Aggregator.
    Key features
    ------------------
    - Feed content filter (including keyword filter and excluding keyword filter)
    - An individual feed page of every feed source is available
    Requirements
    ------------------
    - Aggregator module
    - OG module

---------------------------------------------------------------------------------
OG Audience

  1. http://drupal.org/project/og_audience
  2. The OG Audience module provides an "audience" tab and/or a block on node pages that allows Organic Groups (OG) users to change the audience of existing content. A user can add a node to one or more of his subscribed groups. A group administrator can remove a node from his group(s).
    Users with the proper permission can change the audience of a node even if they do not have the permission to edit the node.

---------------------------------------------------------------------------------
OG Author

  1. http://drupal.org/project/og_author
  2. This is a small module to set the authoring group for any group post.
    This module has been sponsored by http://www.wiki9999.org/

---------------------------------------------------------------------------------
OG Block Visibility

  1. http://drupal.org/project/og_block_visibility
  2. 可以讑֮区块仅出现在某个组里,例如可以用来让每个群l拥有自qD选单Q或是让组可以自己推荐的内容等?
  3. This module allows you to specify that a block should be visible only within a selected group. This can be used for many purposes, from providing each organic group with its own navigation menu, to allowing a group to highlight its own featured content, etc.

---------------------------------------------------------------------------------
OG Calendar

  1. http://drupal.org/project/og_calendar
  2. 让每个群l都可以拥有一个活动行事历Q仅昄该群l的zd?
  3. This module provides each group with a calendar showing only the group's events.
    Sponsored by Raven Brooks of BuyBlue.
    Developed by CivicSpace Labs.

---------------------------------------------------------------------------------
OG Forum

  1. http://drupal.org/project/og_forum
  2. 让每个群l都拥有一个讨论版Qƈ限制Z有群l成员可以检视该讨论区里的文章?
  3. Creates a forum per organic group and restricts viewing forum nodes by group membership.
    Go ahead and use the dev release from the 30th of August. It contains a bug fix to 2.0.

---------------------------------------------------------------------------------
OG Galleries

  1. http://drupal.org/project/og_galleries
  2. A module to create individual image galleries for Organic Groups using Taxonomy and Views. A public gallery is created, along with galleries for each group which are private to that group. Your galleries are controlled by a Views view, and you can set the url, fields, and filters as you like by changing the view. Node types can be image nodes, CCK nodes, or any other content type. Add items to the galleries by selecting a gallery when the node is edited.

---------------------------------------------------------------------------------
OG Gradebook

  1. http://drupal.org/project/og_gradebook
  2. Creates a gradebook per organic group and restricts viewing grades by group membership.

---------------------------------------------------------------------------------
OG Join Role

  1. http://drupal.org/project/og_joinrole
  2. The OG Join Role module simply adds a "join organic groups" permission to the Organic Groups module. A use case for this would be if you have a site where only members of a certain role are allowed to join an organic group.
    The module is written in an all-or-nothing sort of way - either certain roles can join any and all groups or they can join no groups. It will not work on a per-group basis.
    In addition to granting/denying permission to join a group, the module also modifies any text and/or links to join a group unless the user has the proper role. For example, the module removes any "og/subscribe" links on the page and replaces them with "nicer" text that you define in the admin settings.

---------------------------------------------------------------------------------
OG Minutes

  1. http://drupal.org/project/og_minutes
  2. This module makes Organic groups and Minutes work together. It allows to filter users so that the list of potential attendees in Minutes shows only the members of the group(s) to which the related event belongs.

---------------------------------------------------------------------------------
OG moderated posts

  1. http://drupal.org/project/og_moderate
  2. This module moderates public posts from organic groups module. Moderated posts will be hidden from anonymous visitors. Moderation needs to be done by node administrators or another module.

---------------------------------------------------------------------------------
OG Project

  1. http://drupal.org/project/og_project
  2. Allows the Project issue tracking module to function properly on a site that has Organic groups enabled. Without this module, the issue tracker does not work if you enable organic groups.

---------------------------------------------------------------------------------
OG promote

  1. http://drupal.org/project/og_promote
  2. Promote users that join certain groups to a special role.
    Choose one role that all users who join the groups you select will be promoted to. Should a user leave that group, he will be demoted again.

---------------------------------------------------------------------------------
OG Public Access

  1. http://drupal.org/project/og_public_access
  2. The OG Public Access module allows Organic Groups (OG) administrators to control public access to their groups' content. This module does not require group administrators to be granted the site-wide administer nodes permission.
    The use case for this module is for a site with teams of writers submitting content privately in their groups, and editors controlling what is allowed to go public in specific groups.

---------------------------------------------------------------------------------
OG Roles

  1. http://drupal.org/project/og_roles
  2. This module allows you to, for each group type, specify a list of roles that group administrators are allowed to assign.

---------------------------------------------------------------------------------
OG Teampage

  1. http://drupal.org/project/og_teampage
  2. This module provides a table view with all members (subscribers) of an organic group.

---------------------------------------------------------------------------------
OG User Roles

  1. http://drupal.org/project/og_user_roles
  2. This module allows you to assign group-specific roles to users which are restricted to the groups they are in. In other words, using this module, you can assign the role "contributor" to a user in a group, and the user will only have the permissions of that role while he is in that particular group.
    Requires og.module and og_forums.module.
    Read the history of this module: http://drupal.org/node/87679
    Other features of this module allow you to:

     

    1. Assign a default role to all new users who sign up to your site.
    2. Notify group admin of new group subscribers. Requires mimemail.module.
    3. Set a default "Founder" group role for users who create groups.
    4. Set a default group role for new subscribers to a group.
    5. Create subgroups. Requires og_subgroups.module.
    6. Comes with it's own access control for optionally integrating the taxonomy access control (TAC) and organic groups (OG) modules. See: http://groups.drupal.org/node/3700.
    7. Supports Content Access (http://www.drupal.org/project/content_access) and Access Control List (http://www.drupal.org/project/acl) access control modules. See http://groups.drupal.org/node/5392
    8. Works with OG Vocabulary (http://www.drupal.org/project/og_vocab) module. See this issue: http://drupal.org/node/162649

---------------------------------------------------------------------------------
OG Vocab

  1. http://drupal.org/project/og_vocab
  2. 让每个群l都可以拥有自己的分c(vocabulariesQ?
  3. Provide each organic group with its own vocabularies.



Eric.Zhou 2007-12-20 10:21 发表评论
]]>
模块介绍QBook Reviewhttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168775.htmlEric.ZhouEric.ZhouWed, 19 Dec 2007 08:17:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168775.htmlhttp://www.aygfsteel.com/rain1102/comments/168775.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168775.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/168775.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/168775.html
  • http://drupal.org/project/bookreview
  • 一个新的节点类型,内徏多个与书c数据相关的字段Q包括书名、封面图片、出版者、作者、网站连l、版权、ISBN、页数、h根{摘要、目录、评论等Qƈ可连l到外部的网l书店?br /> 定义了特D的书评节点Q方便发布图书评论?
  • The book review module allows a site to publish book reviews. A book review is simply a glorified node, providing custom fields that are appropriate to writing a book review.


  • Eric.Zhou 2007-12-19 16:17 发表评论
    ]]>
    模块介绍QArticlehttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168698.htmlEric.ZhouEric.ZhouWed, 19 Dec 2007 03:59:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168698.htmlhttp://www.aygfsteel.com/rain1102/comments/168698.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168698.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/168698.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/168698.html
  • http://drupal.org/project/article
  • Q意类型的节点ҎcdQtaxonomyQ整理在一起集中显C,如生zȝ?,技术类?等。用户可以按照分cL览?
  • The article module allows for nodes of any type to be organized and displayed in a centralized location. This allows the site administrator to organize nodes of several different types in one place. The user can navigate the nodes by selecting different categories in the taxonomy tree associated with the article module.


  • Eric.Zhou 2007-12-19 11:59 发表评论
    ]]>
    模块介绍QAdmin RSShttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168694.htmlEric.ZhouEric.ZhouWed, 19 Dec 2007 03:48:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168694.htmlhttp://www.aygfsteel.com/rain1102/comments/168694.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168694.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/168694.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/168694.html
  • http://drupal.org/project/adminrss
  • 提供包含待审核的节点和响应的RSS feedQ方便管理者随时得知网站的最新状况,快速做出反应?
  • The AdminRSS module creates RSS feeds for the administrative information for Drupal websites.
    These feeds are protected with a keystring that must be set in admin/settings/adminrss page.
    The resulting pages can then be read at:
    adminrss/node/keystring - RSS feed for unapproved nodes
    adminrss/comment/keystring - RSS feed for unapproved comments
    This can be most useful if you are managing a number of different drupal websites and rather than visiting each one to see if there are comments/nodes that need to be approved you can use an RSS reader to find out.
    Thanks to Fredrik Jonsson and Gabor Hojtsy for their modules adminblock and commentrss which were heavily cribbed from to develop this module.


  • Eric.Zhou 2007-12-19 11:48 发表评论
    ]]>
    模块介绍QAdmin blockhttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168692.htmlEric.ZhouEric.ZhouWed, 19 Dec 2007 03:45:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168692.htmlhttp://www.aygfsteel.com/rain1102/comments/168692.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/19/168692.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/168692.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/168692.html
  • http://drupal.org/project/adminblock
  • 用于帮助理员方便的监管评论和文章。如果你的站点设|成发文需要审批,那么理员每ơ都要进入内容管理查看审扚w列。而此模块通过区块昄所有等待审批的评论和文章队列,一目了Ӟ可以方便快速地完成审批
    提供一个区块,用来昄所有待审核的响应和节点。每一个项目都有自q~辑与删除连l,便于快速管理?
  • The adminblock module enables admins to display a block with the comments approval queue and the node moderation queue. Each item gets their own edit link and delete link for quick administration.


  • Eric.Zhou 2007-12-19 11:45 发表评论
    ]]>
    模块介绍Qfreelinkinghttp://www.aygfsteel.com/rain1102/archive/2007/12/18/168545.htmlEric.ZhouEric.ZhouTue, 18 Dec 2007 09:38:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/18/168545.htmlhttp://www.aygfsteel.com/rain1102/comments/168545.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/18/168545.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/168545.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/168545.html
    介:
    freelinking 模块入格式增加一个过滤,为已l存在或者将要存在的内容建立链接Q它能够自动Cؓ关键词徏立链接,能够通过 “wiki 风格” 为内Ҏ供链接?br />
    链接Q?/strong>
    http://drupal.org/project/freelinking


    Eric.Zhou 2007-12-18 17:38 发表评论
    ]]>
    模块介绍QForum Accesshttp://www.aygfsteel.com/rain1102/archive/2007/12/18/168543.htmlEric.ZhouEric.ZhouTue, 18 Dec 2007 09:37:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/18/168543.htmlhttp://www.aygfsteel.com/rain1102/comments/168543.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/18/168543.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/168543.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/168543.html介:
    q个模块让你可以某个论坛设|ؓU有Q你可以军_那个用户角色可以览、编辑、删除和发表帖子Q还可以为每个论坛版面设|版丅R?

     

    q个模块需?ACL 模块?

     

    链接Q?/strong>

     

    http://drupal.org/project/forum_access


    Eric.Zhou 2007-12-18 17:37 发表评论
    ]]>
    为分cM及分cM息的CRUD操作d邮g通知功能http://www.aygfsteel.com/rain1102/archive/2007/12/18/168474.htmlEric.ZhouEric.ZhouTue, 18 Dec 2007 06:03:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/18/168474.htmlhttp://www.aygfsteel.com/rain1102/comments/168474.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/18/168474.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/168474.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/168474.html<?php

    /**
    * Implementation of hook_taxonomy().
    *
    * Sends email when changes to vocabularies or terms occur.
    */
    function taxonomymonitor_taxonomy($op, $type, $array = array()) {
     $to = 'vipzhour@163.com';
     $name = check_plain($array['name']);

     // $type is either 'vocabulary' or 'term'.
     switch ($type) {
      case 'vocabulary':
       switch($op) {
        case 'insert':
         $subject = t('Vocabulary @voc was added.', array('@voc'=>$name));
         break;
        case 'update':
         $subject = t('Vocabulary @voc was changed.', array('@voc'=>$name));
         break;
        case 'delete':
         $subject = t('Vocabulary @voc was deleted.', array('@voc'=>$name));
         break;
       }
       break;
      case 'term':
       switch($op) {
        case 'insert':
         $subject = t('Term @term was added.', array('@term'=>$name));
         break;
        case 'update':
         $subject = t('Term @term was changed.', array('@term'=>$name));
         break;
        case 'delete':
         $subject = t('Term @term was deleted.', array('@term'=>$name));
         break;
       }
     }

     // Dump the vocabulary or term information out and send it along.
     $body = print_r($array, TRUE);

     // Send the email.
     drupal_mail('taxonomymonitor-notify', $to, $subject, $body);
    }



    Eric.Zhou 2007-12-18 14:03 发表评论
    ]]>
    模块介绍Qaudiohttp://www.aygfsteel.com/rain1102/archive/2007/12/17/168237.htmlEric.ZhouEric.ZhouMon, 17 Dec 2007 07:25:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/17/168237.htmlhttp://www.aygfsteel.com/rain1102/comments/168237.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/17/168237.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/168237.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/168237.html介:
    audio 模块允许有权限的用户上传音频文gQ它使用 getID3 library 来读?ID3 meta-tag 信息?

              q个模块q附带一?XSPF Flash 播放?/a>?

    链接Q?/strong>

     http://drupal.org/project/audio

    To install the audio module
    ---------------------------

    1. Extract the 'audio' module directory, including all its subdirectories, into
       your sites/all/modules directory.


    2. Install the getID3 package - optional but recommended. MAKE SURE YOU READ
       THE SECURITY NOTE BELOW!

       a. Download the project getId3 version from SourceForge.net. The latest
          version tested with the audio module is 1.7.7. Earlier versions contain
          bugs that will cause you headaches.

       b. Extract the archive into the sites/all/modules/audio/getid3 directory. When you're
          finished the directory structure should look something like:

            drupal/
              sites/
                all/
                  modules/
                    audio/
                      getid3/
                        README.txt
                        [...]
                        getid3/
                          getid3.php
                          write.php

      c. *** IMPORTANT ***
         YOU MUST DELETE THE 'demos' FOLDER OF THE ID3 LIBRARY. FAILURE TO DO SO
         OPENS UP A MASSIVE SECURITY HOLE AND MAKES YOUR SITE EXTREMELY VULNERABLE
         TO ATTACKS!

    3. Enable the audio, audio_getid3 and audio_image modules on the
       admin >> build >> modules page. The database tables will be created
       automagically for you at this point.

    4. Go to admin >> settings >> audio and check that the path to the getID3
       package is configured correctly. If you follow the above directory
       structure, the path should be "sites/all/modules/audio/getid3/getid3/".



    Eric.Zhou 2007-12-17 15:25 发表评论
    ]]>
    The Filter Systemhttp://www.aygfsteel.com/rain1102/archive/2007/12/13/167400.htmlEric.ZhouEric.ZhouThu, 13 Dec 2007 02:05:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/13/167400.htmlhttp://www.aygfsteel.com/rain1102/comments/167400.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/13/167400.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/167400.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/167400.html<?php
    // $Id$

    /**
     * @file
     * A silly module to assist whizbang novelists who are in a rut by providing a
     * random sentence generator for their posts.
     */

    /**
     * Implementation of hook_filter().
     */
    function creativejuice_filter($op, $delta = 0, $format = -1, $text = '') {
      switch ($op) {
        case 'list':
          return array(
            0 => t('Creative Juices filter'),
            1 => t('The name of my second filter'),
          );

        case 'description':
          switch ($delta) {
            case 0:
              return t('Enables users to insert random sentences into their posts.');
            case 1:
              return t('If this module provided a second filter, the description for that second filter would go here.');
            // Should never return here as value of $delta never exceeds the last index of the 'list' array.
            default:
              return;
          }
          break;

        case 'settings':
            // No settings user interface for this filter.
          break;

        case 'no cache':
          return FALSE;

        case 'prepare':
          return $text;

        case 'process':
          return preg_replace_callback("|\[juice!\]|i", 'creativejuice_sentence', $text);

        default:
          return $text;
      }
    }

    /**
     * Generate a random sentence.
     */
    function creativejuice_sentence() {
      $phrase[0][] = t('A majority of us believe');
      $phrase[0][] = t('Generally speaking,');
      $phrase[0][] = t('As times carry on');
      $phrase[0][] = t('Barren in intellect,');
      $phrase[0][] = t('Deficient in insight,');
      $phrase[0][] = t('As blazing blue sky poured down torrents of light,');
      $phrase[0][] = t('Aloof from the motley throng,');
      $phrase[1][] = t('life flowed in its accustomed stream');
      $phrase[1][] = t('he ransacked the vocabulary');
      $phrase[1][] = t('the grimaces and caperings of buffoonery');
      $phrase[1][] = t('the mind freezes at the thought');
      $phrase[1][] = t('she reverted to another matter');
      $phrase[1][] = t('he lived as modestly as a hermit');

      $phrase[2][] = t('through the red tape of officialdom.');
      $phrase[2][] = t('as it set anew in some fresh and appealing form.');
      $phrase[2][] = t('supported by evidence.');
      $phrase[2][] = t('as fatal as the fang of the most venomous snake.');
      $phrase[2][] = t('as full of spirit as a gray squirrel.');
      $phrase[2][] = t('as dumb as a fish.');
      $phrase[2][] = t('like a damp-handed auctioneer.');
      $phrase[2][] = t('like a bald ferret.');

      foreach ($phrase as $key => $value) {
        $rand_key = array_rand($phrase[$key]);
        $sentence[] = $phrase[$key][$rand_key];
      }

      return implode(' ', $sentence);
    }

    /**
     * Implementation of hook_filter_tips().
     */
    function creativejuice_filter_tips($delta, $format, $long = FALSE) {
      if ($long) {
        // Detailed explanation for http://example.com/?q=filter/tips page.
        return t('The Creative Juices filter is for those times when your brain is incapable of being creative. These time comes for everyone, when even strong coffee and a barrel of jelly beans does not create the desired effect. When that happens, you can simply enter the [juice!] tag into your posts...');
      }
      else {
        // Short explanation for underneath a post's textarea.
        return t('Insert a random sentence into your post with the [juice!] tag.');
      }
    }



    Eric.Zhou 2007-12-13 10:05 发表评论
    ]]>
    PoormanscronQ调用crondQ?/title><link>http://www.aygfsteel.com/rain1102/archive/2007/12/11/167035.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Tue, 11 Dec 2007 11:58:00 GMT</pubDate><guid>http://www.aygfsteel.com/rain1102/archive/2007/12/11/167035.html</guid><wfw:comment>http://www.aygfsteel.com/rain1102/comments/167035.html</wfw:comment><comments>http://www.aygfsteel.com/rain1102/archive/2007/12/11/167035.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/rain1102/comments/commentRss/167035.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/rain1102/services/trackbacks/167035.html</trackback:ping><description><![CDATA[<span lang="EN-US" style="font-size: 9pt; color: #003150; font-family: Verdana; mso-fareast-font-family: 宋体; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">Poormanscron:<br /> </span><span style="font-size: 9pt; color: #003150; font-family: 宋体; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">通过用户的浏览来调用</span><span lang="EN-US" style="font-size: 9pt; color: #003150; font-family: Verdana; mso-fareast-font-family: 宋体; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">cron</span><span style="font-size: 9pt; color: #003150; font-family: 宋体; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">dQ不能讄</span><span lang="EN-US" style="font-size: 9pt; color: #003150; font-family: Verdana; mso-fareast-font-family: 宋体; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">crontab</span><span style="font-size: 9pt; color: #003150; font-family: 宋体; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的站点也能简单地解决</span><span lang="EN-US" style="font-size: 9pt; color: #003150; font-family: Verdana; mso-fareast-font-family: 宋体; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">cron</span><span style="font-size: 9pt; color: #003150; font-family: 宋体; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">q行的问题?br /> <p>A module which runs the Drupal cron operations without needing the cron application. </p> <p>For every page view, this module checks to see if the last cron run was more than 1<br /> hour ago (this period is configurable). If so, the cron hooks are executed,<br /> and Drupal is happy. These cron hooks fire after all HTML is returned to the browser,<br /> so the user who kicks off the cron jobs should not notice any delay.</p> </span><img src ="http://www.aygfsteel.com/rain1102/aggbug/167035.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/rain1102/" target="_blank">Eric.Zhou</a> 2007-12-11 19:58 <a href="http://www.aygfsteel.com/rain1102/archive/2007/12/11/167035.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Taxonomy Access ControlQ管理用户对不同cd文章的访问权限)http://www.aygfsteel.com/rain1102/archive/2007/12/11/167031.htmlEric.ZhouEric.ZhouTue, 11 Dec 2007 11:47:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/11/167031.htmlhttp://www.aygfsteel.com/rain1102/comments/167031.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/11/167031.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/167031.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/167031.htmlTaxonomy Access Control:
    理用户对不同类别文章的讉K权限?/span>

    Access control for user roles based on taxonomy categories (vocabulary, terms).

    • Automatically controls access to taxonomy terms and nodes (based on their category terms)
    • Configuration page for each user roles
    • Five permission types (View, Update, Delete, Create, List)

    http://drupal.org/project/taxonomy_access



    Eric.Zhou 2007-12-11 19:47 发表评论
    ]]>
    SmileyQ表情符Q?/title><link>http://www.aygfsteel.com/rain1102/archive/2007/12/11/167020.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Tue, 11 Dec 2007 11:15:00 GMT</pubDate><guid>http://www.aygfsteel.com/rain1102/archive/2007/12/11/167020.html</guid><wfw:comment>http://www.aygfsteel.com/rain1102/comments/167020.html</wfw:comment><comments>http://www.aygfsteel.com/rain1102/archive/2007/12/11/167020.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/rain1102/comments/commentRss/167020.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/rain1102/services/trackbacks/167020.html</trackback:ping><description><![CDATA[<span lang="EN-US" style="font-size: 9pt; color: #003150; font-family: Verdana; mso-fareast-font-family: 宋体; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">Smiley:<br /> </span><span style="font-size: 9pt; color: #003150; font-family: 宋体; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">使用表情W,自带了一些基本的表情W,用户可以自己d?/span><img src ="http://www.aygfsteel.com/rain1102/aggbug/167020.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/rain1102/" target="_blank">Eric.Zhou</a> 2007-12-11 19:15 <a href="http://www.aygfsteel.com/rain1102/archive/2007/12/11/167020.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ExcerptQ摘要模块)和Side ContentQ边栏导读)http://www.aygfsteel.com/rain1102/archive/2007/12/11/167018.htmlEric.ZhouEric.ZhouTue, 11 Dec 2007 11:05:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/11/167018.htmlhttp://www.aygfsteel.com/rain1102/comments/167018.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/11/167018.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/167018.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/167018.htmlExcerpt:
    摘要模块?/span>Drupal发布内容时只能用正文的开头作摘要Q然后根据设定自动截取摘要。启用摘要模块就可以不受此限Ӟ发布内容时将单独有一个摘要栏供作者随意填写?br /> Side Content:
    在发布节点内Ҏ可以部分内定w择性的昄在边栏的区块里,可以用于某部分内容,cM有的书籍或杂志的ҎD?/span>

    Eric.Zhou 2007-12-11 19:05 发表评论
    ]]>
    Working with Blockshttp://www.aygfsteel.com/rain1102/archive/2007/12/04/165125.htmlEric.ZhouEric.ZhouTue, 04 Dec 2007 03:50:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/04/165125.htmlhttp://www.aygfsteel.com/rain1102/comments/165125.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/04/165125.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/165125.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/165125.html1
    Q?/span>Understanding How Blocks Are Themed

    During a page request, the theme system will ask the block system to return a list of blocks for

    each region. It does this when generating the variables to send to the page template (usually

    page.tpl.php). To gather the themed blocks for the left and right sidebars, Drupal executes the

    following:

    $sidebar_left = theme('blocks', 'left');

    $sidebar_right = theme('blocks', 'right');

    // And any other regions exposed by hook_regions().

    You might remember that theme('blocks') is actually a call to theme_blocks(). Here’s what theme_blocks() actually does:

    function theme_blocks($region) {

    $output = '';

    if ($list = block_list($region)) {

    foreach ($list as $key => $block) {

    $output .= theme('block', $block);

    }

    }

    return $output;

    }

    2Q?/span>Using the Block Hook

    function hook_block($op = 'list', $delta = 0, $edit = array())

    <?php

    // $Id$

    /**

     * @file

     * Implements various blocks to improve pending content workflow.

     */

     

    /**

     * Implementation of hook_block().

     */

    function approval_block($op = 'list', $delta = 0, $edit = array()) {

     switch ($op) {

        case 'list':

          $blocks[0]['info'] = t('Pending comments');

          $blocks[1]['info'] = t('Unpublished nodes');

          return $blocks;

        case 'configure':

          // Only in block 0 (the Pending comments block) can one

          // set the number of comments to display.

          if ($delta == 0) {

            $form['approval_block_num_posts'] = array(

              '#type' => 'textfield',

              '#title' => t('Number of pending comments to display'),

              '#default_value' => variable_get('approval_block_num_posts', 5),

            );

          }

          return $form;

        case 'save':

          if ($delta == 0) {

            variable_set('approval_block_num_posts', (int) $edit['approval_block_num_posts']);

          }

          break;

        case 'view':

          if ($delta == 0 &&user_access('administer comments')) {

            // Retrieve the number of pending comments to display that

            // we saved earlier in the 'save' op, defaulting to 5.

            $num_posts = variable_get('approval_block_num_posts', 5);

            // Query the database for unpublished comments.

            $result = db_query_range('SELECT c.* FROM {comments} c WHERE c.status = %d ORDER BY c.timestamp', COMMENT_NOT_PUBLISHED, 0, $num_posts);

            // Preserve our current location so user can return after editing.

            $destination = drupal_get_destination();

            $items = array();

            while ($comment = db_fetch_object($result)) {

              $items[] = l($comment->subject, 'node/'. $comment->nid, array(), NULL, 'comment-'. $comment->cid). ' '. l(t('[edit]'), 'comment/edit/'. $comment->cid, array(), $destination);

            }

            $block['subject'] = t('Pending comments');

            // We theme our array of links as an unordered list.

            $block['content'] = theme('item_list', $items);

          }

          elseif ($delta == 1 && user_access('administer nodes')) {

            // Query the database for the 5 most recent unpublished nodes.

            // Unpublished nodes have their status column set to 0.

            $result = db_query_range('SELECT title, nid FROM {node} WHERE status = 0 ORDER BY changed DESC', 0, 5);

            $destination = drupal_get_destination();

            while ($node = db_fetch_object($result)) {

              $items[] = l($node->title, 'node/'. $node->nid). ' '. l(t('[edit]'), 'node/'. $node->nid .'/edit', array(), $destination);

            }

            $block['subject'] = t('Unpublished nodes');

            // We theme our array of links as an unordered list.

            $block['content'] = theme('item_list', $items);

          }

          return $block;

     }   

    }

    drupal_get_destination()

    This function remembers the page you were on before you submitted a form, so after you update the comment form to publish or delete a comment, you’ll be automatically redirected from whence you came.



    Eric.Zhou 2007-12-04 11:50 发表评论
    ]]>The Theme Systemhttp://www.aygfsteel.com/rain1102/archive/2007/12/04/165075.htmlEric.ZhouEric.ZhouTue, 04 Dec 2007 01:29:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/04/165075.htmlhttp://www.aygfsteel.com/rain1102/comments/165075.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/04/165075.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/165075.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/165075.htmltheme-name_breadcrumb()

    theme-engine_ breadcrumb()

    theme_ breadcrumb()

    Defining Additional Template Files

    First, create a file within your theme directory named breadcrumb.tpl.php. This is the new template file for breadcrumbs. Because we wanted to change the <div> tag to a <span> tag, go ahead and populate the file with the following:

    <span class="breadcrumb"><?php print $breadcrumb ?></span>

    That’s easy enough for a designer to edit. Now you need to let Drupal know to call

    this template file when looking to render its breadcrumbs. Inside template.php, override theme_breadcrumb() as you did previously, but this time you’re going to tell this function to use the template file instead of just the function:

    function mytheme_breadcrumb($breadcrumb) {

     if (!empty($breadcrumb)) {

           $variables = array(

                  'breadcrumb' => implode(' -> ', $breadcrumb)

           );

           return _phptemplate_callback('breadcrumb', $variables);

     }

    }

    The magic inside this function is happening with _phptemplate_callback(). Its first parameter is the name of the template file to look for, and the second parameter is an array of variables to pass to the template file. You can create and pass along as many variables as you need into your template files.

    Defining New Block Regions

    function mytheme_regions() {

           return array(

                  'left' => t('left sidebar'),

                  'right' => t('right sidebar'),

                  'content_top' => t('content top'),

                  'content_bottom' => t('content bottom'),

                  'header' => t('header'),

                  'footer' => t('footer')

           );

    }

    To print out the content top region in your page template, use <?php print $content_top ?>.



    Eric.Zhou 2007-12-04 09:29 发表评论
    ]]>Working with Nodeshttp://www.aygfsteel.com/rain1102/archive/2007/12/04/165071.htmlEric.ZhouEric.ZhouTue, 04 Dec 2007 01:28:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/04/165071.htmlhttp://www.aygfsteel.com/rain1102/comments/165071.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/04/165071.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/165071.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/165071.htmlCreating a Node Module

    1Q?/span>Creating the .info File

    Let’s also create the joke.info file and add it to the joke folder.

    ; $Id$

    name = Joke

    description = Provides a joke node type with a punchline.

    version = "$Name$"

    2Q?/span>Creating the .install File

    <?php

    function joke_install() {

           switch ($GLOBALS['db_type']) {

                  case 'mysql':

                  case 'mysqli':

                         db_query("CREATE TABLE {joke} (

                                nid int unsigned NOT NULL default '0',

                                vid int unsigned NOT NULL default '0',

                                punchline text NOT NULL,

                                PRIMARY KEY (nid,vid),

                                UNIQUE KEY vid (vid),

                                KEY nid (nid)

                         ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");

                         break;

                  case 'pgsql':

                         db_query("CREATE TABLE {joke} (

                                nid int unsigned NOT NULL default '0',

                                vid int unsigned NOT NULL default '0',

                                punchline text NOT NULL,

                                PRIMARY KEY (nid,vid),

                                UNIQUE KEY vid (vid),

                                KEY nid (nid)

                         )");

                  break;

           }

    }

    function joke_uninstall() {

           db_query('DROP TABLE {joke}');

    }

    3Q?/span>Creating the .module File

    <?php

    function joke_perm() {

           return array('create joke', 'edit joke', 'delete joke');

    }

    /**

    * @file

    * Provides a "joke" node type.

    */

    /**

    * Implementation of hook_node_info().

    */

    function joke_node_info() {

           // We return an array since a module can define multiple node types.

           // We're only defining one node type, type 'joke'.

           return array(

                  'joke' => array(

                         'name' => t('Joke'), // Required.

                         'module' => 'joke', // Required.

                         'description' => t('Tell us your favorite joke!'), // Required.

                         'has_title' => TRUE,

                         'title_label' => t('Title'),

                         'has_body' => TRUE,

                         'body_label' => t('Joke'),

                         'min_word_count' => 2,

                         'locked' => TRUE

                  )

           );

    }

    function joke_menu($may_cache) {

           $items = array();

           if ($may_cache) {

                  $items[] = array(

                         'path' => 'node/add/joke',

                         'title' => t('Joke'),

                         'access' => user_access('create joke'),

                  );

           }

           return $items;

    }

    function joke_access($op, $node) {

           global $user;

           if ($op == 'create') {

                  return (user_access('create joke'));

           }

           if ($op == 'update') {

                  return (user_access('edit joke') && ($user->uid == $node->uid));

           }

           if ($op == 'delete') {

                  return (user_access('delete joke') && ($user->uid == $node->uid));

           }

    }

    function joke_form($node) {

           // Get metadata for this node type

           // (we use it for labeling title and body fields).

           // We defined this in joke_node_info().

           $type = node_get_types('type', $node);

           $form['title'] = array(

                  '#type' => 'textfield',

                  '#title' => check_plain($type->title_label),

                  '#required' => TRUE,

                  '#default_value' => $node->title,

                  '#weight' => -5

           );

           $form['body_filter']['body'] = array(

                  '#type' => 'textarea',

                  '#title' => check_plain($type->body_label),

                  '#default_value' => $node->body,

                  '#rows' => 7,

                  '#required' => TRUE

           );

           $form['body_filter']['filter'] = filter_form($node->format);

           $form['punchline'] = array(

                  '#type' => 'textfield',

                  '#title' => t('Punchline'),

                  '#required' => TRUE,

                  '#default_value' => $node->punchline,

                  '#weight' => 5

           );

           return $form;

    }

    function joke_validate($node) {

           //Enforce a minimum word length of 3.

           if (isset($node->punchline) && str_word_count($node->punchline) <= 3) {

                  $type = node_get_types('type', $node);

                  form_set_error('punchline', t('The punchline of your @type is too short. You need at least three words.', array('@type'=> $type->name)));

           }

    }

    function joke_insert($node) {

           db_query("INSERT INTO {joke} (nid, vid, punchline) VALUES (%d, %d, '%s')",

           $node->nid, $node->vid, $node->punchline);

    }

    function joke_update($node) {

           if ($node->revision) {

                  joke_insert($node);

           } else {

                  db_query("UPDATE {joke} SET punchline = '%s' WHERE vid = %d", $node->punchline, $node->vid);

           }

    }

    /**

    * Implementation of hook_delete().

    */

    function joke_delete(&$node) {

           // Delete the related information we were saving for this node.

           db_query('DELETE FROM {joke} WHERE nid = %d', $node->nid);

    }

    /**

    * Implementation of hook_load().

    */

    function joke_load($node) {

           drupal_add_js('misc/collapse.js');

           return db_fetch_object(db_query('SELECT punchline FROM {joke} WHERE vid = %d', $node->vid));

    }

    function joke_view($node, $teaser = FALSE, $page = FALSE) {

           if (!$teaser) {

                  // Use Drupal's default node view.

                  $node = node_prepare($node, $teaser);

                  $node->guffaw = str_repeat(t('Ha!'), mt_rand(0, 10));

                  // Now add the punchline.

                  /**

                  $node->content['punchline'] = array(

                         '#value' => theme('joke_punchline', $node),

                         '#weight' => 2

                  );

                  */

           }

           if ($teaser) {

                  // Use Drupal's default node view.

                  $node = node_prepare($node, $teaser);

           }

           return $node;

    }

    function theme_joke_punchline($node) {

           $output = '<div class="joke-punchline">'.check_plain($node->punchline). '</div><br />';

           $output .= '<div class="joke-guffaw">'.check_plain($node->guffaw). '</div>';

           return $output;

    }



    Eric.Zhou 2007-12-04 09:28 发表评论
    ]]>Working with Usershttp://www.aygfsteel.com/rain1102/archive/2007/12/03/164862.htmlEric.ZhouEric.ZhouMon, 03 Dec 2007 06:32:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/03/164862.htmlhttp://www.aygfsteel.com/rain1102/comments/164862.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/03/164862.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/164862.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/164862.html1QIntroduction to hook_user()

    Implementing hook_user() gives your modules a chance to react to the different operations performed on a user account, and to modify the $user object. Let’s examine the function signature:

    function hook_user($op, &$edit, &$user, $category = NULL)

    The $op parameter is used to describe the current operation being performed on the user account and can have many different values:

    • after_update: Called after the $user object has been saved to the database.

    • categories: Returns an array of categories that appear as Drupal menu local tasks when the user edits the user account. See profile_user() in profile.module for an implementation.

    • delete: A user has just been deleted from the database. This is an opportunity for the module to remove information related to the user from the database.

    • form: Inject an additional form field element into the user edit form being displayed.

    • insert: The new user account is about to be created and inserted into the database.

    • login: The user has successfully logged in.

    • logout: The user just logged out and his or her session has been destroyed.

    • load: The user account was successfully loaded. The module may add additional information into the $user object.

    • register: The user account registration form is about to be displayed. The module may add additional form elements to the form.

    • submit: The user edit form has been submitted. Modify the account information before it is sent to user_save().

    • update: The existing user account is about to be saved to the database.

    • validate: The user account has been modified. The module should validate its custom

    data and raise any necessary errors.

    • view: The user’s account information is being displayed. The module should return

    its custom additions to the display as an array. The view operation ultimately calls

    theme_user_profile to format the user profile page. More details on this shortly.

    The $edit parameter is an array of the form values submitted when a user account is being created or updated. Notice that it’s passed by reference, so any changes you make will actually change the form values.

    The $user object is also passed by reference, so any changes you make will actually change the $user information.

    The $category parameter is the active user account category being edited.

    ?strong>Caution Don’t confuse the $user parameter within hook_user() with the global $user object. The $user parameter is the user object for the account currently being manipulated. The global $user object is the user currently logged in.

    2.The User Registration Process

    Add a legalagree.module

    <?php

    function legalagree_user($op, &$edit, &$user, $category = NULL) {

           switch ($op) {

                  // User is registering

                  case 'register':

                         //Add a fieldset containing radio buttons to the user registration form

                         $fields['legal_agreement'] = array(

                                '#type' => 'fieldset',

                                '#title' => t('Legal Agreement')

                         );

                         $fields['legal_agreement']['decision'] = array(

                                '#type' => 'radios',

                                '#options' => array(t('I disagree'), t('I agree')),

                                '#default_value' => 0,

                                '#description' => t('By registering at %site-name, you agree that

                                at any time, we (or our surly, brutish henchmen) may enter your place of

                                residence and smash your belongings with a ball-peen hammer.',

                                array('%site-name' => variable_get('site_name', 'drupal')))

                         );

                         return $fields;

                  case 'validate':

                         // Make sure the user selected radio button 1 ('I agree').

                         // the validate op is reused when a user updates information on

                         // The 'my account' page, so we use isset() to test whether we are

                         // on the registration page where the decision field is present.

                         if (isset($edit['decision']) && $edit['decision'] != '1') {

                                form_set_error('decision', t('You must agree to the legal agreement before

                                registration can be completed.'));

                         }

                         return;

                  case 'insert':

                         // Record information for future lawsuit.

                         watchdog('user', t('User %user agreed to legal terms', array('%user' => $user->name)));

                         return;

           }

    }

    3QAdding Data to the $user Object

    Loginhistory.module

    <?php

    function loginhistory_user($op, &$edit, &$account, $category = NULL) {

           switch($op) {

                  case 'login':

                         // Record timestamp in database

                         db_query("INSERT INTO {login_history} (uid, timestamp) values (%d, %d)", $account->uid, $account->login);

                         break;

                  case 'load':

                         // Add the number of times user has logged in.

                         $account->loginhistory_count = db_result(db_query("SELECT COUNT(timestamp) as count FROM {login_history} WHERE uid = %d", $account->uid));

                         break;

                  case 'view':

                         // Add a field displaying number of logins.

                         $items['login_history'] = array(

                                'title' => t('Number of logins'),

                                'value' => $account->loginhistory_count,

                                'class' => 'member'

                         );

                         return array(t('History')=>$items);

           }

    }

    Loginhistory.install

    <?php

    function loginhistory_install() {

           switch ($GLOBALS['db_type']) {

                  case 'mysql':

                  case 'mysqli':

                         db_query("CREATE TABLE {login_history} (

                                uid int NOT NULL default '0',

                                timestamp int NOT NULL default '0',

                                KEY (uid)

                         )/*!40100 DEFAULT CHARACTER SET UTF8 */");

                         break;

                  case 'pgsql':

                         db_query("CREATE TABLE {login_history} (

                                uid int_unsigned default '0',

                                timestamp int_unsigned NOT NULL default '0',

                                KEY (uid)

                         )");

                         break;

           }

    }

    function loginhistory_uninstall() {

           db_query("DROP TABLE {login_history}");

    }

    4QSimple External Authentication

    Let’s implement a very simple external authentication module that might be used inside a company where simple usernames are used. Suppose your company only hires people named Dave, and usernames are assigned based on first and last names. This module authenticates anyone whose username begins with the string dave, so the users davebrown, davesmith, and davejones will all successfully log in.

    <?php

    /**

    * Implementation of hook_auth()

    */

    function authdave_auth($username, $pass, $server) {

           // Does username begin with 'dave'?

           if (substr(drupal_strtolower($username), 0, 4 ) == 'dave') {

                  // Make a global variable to note that we did the authentication.

                  global $authdave_authenticated;

                  $authdave_authenticated = TRUE;

                  return TRUE;

           }

           else {

                  return FALSE;

           }

    }

    If a row in the users table does not exist for this user, one will be created. However, no e-mail address has been provided at login like it was for Drupal’s default local user registration, so a module this simple is not a real solution if your site relies on sending e-mail to users. You’ll want to set the mail column of the users table so you will have an e-mail address associated with the user. To do this, you can have your module respond to the insert operation of the user hook, which is fired whenever a new user is inserted:

    /**

    * Implementation of hook_user()

    */

    function authdave_user($op, &$edit, &$account, $category = NULL) {

           switch($op) {

                  case 'insert':

                         // New user was just added; if we did authentication,

                         // look up email address of user in a legacy database.

                         global $authdave_authenticated;

                         if ($authdave_authenticated) {

                                $email = mycompany_email_lookup($account->name);

                                // Set email address in the user table for this user.

                                db_query("UPDATE {users} SET mail = '%s' WHERE uid = %d", $email,

                                $account->uid);

                         }

                         break;

           }

    }



    Eric.Zhou 2007-12-03 14:32 发表评论
    ]]>
    Working with Databaseshttp://www.aygfsteel.com/rain1102/archive/2007/12/03/164780.htmlEric.ZhouEric.ZhouMon, 03 Dec 2007 02:02:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/03/164780.htmlhttp://www.aygfsteel.com/rain1102/comments/164780.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/03/164780.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/164780.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/164780.htmlDefining Database Parameters

    $db_url = 'mysql://username:password@localhost/databasename';

    ?/span>NoteIf you are in a situation where you are writing a stand-alone PHP script or you have existing PHP code outside of Drupal that needs access to Drupal’s database, you will want to want to call include_once ('includes/bootstrap.inc') and then call drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE) to generate an active connection. At that point, you can use db_query(), as explained in the next section.

    Performing Simple Queries

    db_query('SELECT * FROM {joke} WHERE vid = %d', $node->vid);

    db_query("INSERT INTO {joke} (nid, vid, punchline) VALUES (%d, %d, '%s')",

    $node->nid, $node->vid, $node->punchline);

    db_query("UPDATE {joke} SET punchline = '%s' WHERE vid = %d", $node->punchline,

    $node->vid);

    db_query('DELETE FROM {joke} WHERE nid = %d', $node->nid);

    Retrieving Query Results

    There are various ways to retrieve query results depending on whether you need a single row or the whole result set, or you are planning to get a range of results for internal use or for display as a paged result set.

    1Q?/span>Getting a Single Value

    $sql = "SELECT COUNT(*) FROM {node} WHERE type = 'blog' AND status = 1";

    $total = db_result(db_query($sql));

    2Q?/span>Getting Multiple Rows

    $sql = "SELECT * FROM {node} WHERE type = 'blog' AND status = 1";

    $result = db_query(db_rewrite_sql($sql));

    while ($data = db_fetch_object($result)) {

           $node = node_load($data->nid);

           print node_view($node, TRUE);

    }

    The preceding code snippet will print out all published nodes that are of type blog. (The status field in the node table is 0 for unpublished nodes and 1 for published nodes.) We will cover db_rewrite_sql()shortly. The db_fetch_object()function grabs a row from the result set as an object. To retrieve the result as an array, use db_fetch_array(). The practice of retrieving rows as objects is common since most developers prefer its less verbose syntax.

    3Q?/span>Getting a Limited Range of Results

    $type = 'blog';

    $status = 1;

    $sql = "SELECT * FROM {node} n WHERE type = '%s' AND status = %d ORDER BY

    n.created DESC";

    $result = db_query_range(db_rewrite_sql($sql), $type, $status, 0, 10);

    4Q?/span>Getting Results for Paged Display

    $sql = "SELECT * FROM {node} n WHERE type = 'blog' AND status = 1 ORDER BY

    n.created DESC"

    $result = pager_query(db_rewrite_sql($sql), 0, 10);

    while ($data = db_fetch_object($result)) {

    $node = node_load($data->nid);

    print node_view($node, TRUE);

    }

    // Add links to remaining pages of results.

    print theme('pager', NULL, 10);

    Although pager_query() is not really part of the database abstraction layer, it is good to know when you need to create a paged result set with navigation. A call to theme('pager') at the end will display the navigation links to the other pages. You don’t need to pass the total number of results to theme('pager') because the number of results is remembered internally from the pager_query() call.

    5Q?/span>Deleting Tables on Uninstall

    The Administer ?Modules page has an Uninstall tab that not only allows modules to be disabled,but also removes their data from the database. If you want to enable the deletion of your module’s tables on this page, implement the uninstall hook in your module’s .install file. You might want to delete any variables you’ve defined at the same time.

    function annotate_uninstall() {

    db_query("DROP TABLE {annotations}");

    variable_del('annotate_nodetypes');

    }

    6Q?/span>Writing Your Own Database Abstraction Layer

    First, we make a copy of includes/database.mysql.inc and rename it as

    includes/database.dnabase.inc. Then we change the logic inside each wrapper function to map to DNAbase’s functionality instead of MySQL’s functionality. When all is said and done, we have the following functions declared in our file:

    _db_query($query, $debug = 0)

    db_affected_rows()

    db_connect($url)

    db_decode_blob($data)

    db_distinct_field($table, $field, $query)

    db_encode_blob($data)

    db_error()

    db_escape_string($text)

    db_fetch_array($result)

    db_fetch_object($result)

    db_lock_table($table)

    db_next_id($name)

    db_num_rows($result)

    db_query_range($query)

    db_query_temporary($query)

    db_result($result, $row = 0)

    db_status_report($phase)

    db_table_exists($table)

    db_unlock_tables()

    db_version()



    Eric.Zhou 2007-12-03 10:02 发表评论
    ]]>
    The Menu Systemhttp://www.aygfsteel.com/rain1102/archive/2007/12/03/164779.htmlEric.ZhouEric.ZhouMon, 03 Dec 2007 02:01:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/12/03/164779.htmlhttp://www.aygfsteel.com/rain1102/comments/164779.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/12/03/164779.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/164779.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/164779.htmlAccess Control

    Usually menu access is controlled by defining permissions inside the

    module using hook_perm() and testing those permissions using user_access().

    function mymenu_perm() {

           return array('receive greeting', 'receive goodbye');

    }

    function mymenu_menu($may_cache) {

           $items = array();

           if ($may_cache) {

                  // Define a static menu item.

                  $items[] = array(

                         'title' => t('Greeting'),

                         'path' => 'mymenu',

                         'weight' => -10,

                         'callback' => 'mymenu_hello',

                         'callback arguments' => array(t('Hi!'), t('Ho!')),

                         'access' => user_access('receive greeting')

                  );

                  $items[] = array(

                         'title' => t('Farewell'),

                         'path' => 'mymenu/goodbye',

                         'callback' => 'mymenu_goodbye',

                         'access' => user_access('receive goodbye')

                  );

           }

           return $items;

    }

    Assigning Callbacks Without Adding a Link to the Menu

    Often you may want to map a URL to a function without creating a visible menu item. You

    can do this by assigning the MENU_CALLBACK type to your menu item, as in this example from

    node.module:

    $items[] = array(

           'path' => 'rss.xml',

           'title' => t('RSS feed'),

           'callback' => 'node_feed',

           'access' => user_access('access content'),

           'type' => MENU_CALLBACK

    );

    Displaying Menu Items As Tabs

    In Drupal’s admittedly obscure menu lingo, a callback that is displayed as a tab is known as a

    local task and has the type MENU_LOCAL_TASK or MENU_DEFAULT_LOCAL_TASK. The title of a local

    task should be a short verb, such as “add” or “list.” Local tasks usually act on some kind of

    object, such as a node, user, or workflow.

    Local tasks must have a parent item in order for the tabs to be rendered. A common practice

    is to assign a callback to a root path like milkshake, and then assign local tasks to paths that

    extend that path, like milkshake/prepare, milkshake/drink, and so forth. Drupal has built-in

    support for two levels of tabbed local tasks.

    function milkshake_menu($may_cache) {

           $items = array();

           if ($may_cache) {

                  $items[] = array(

                         'path' => 'milkshake',

                         'title' => t('Milkshake flavors'),

                         'callback' => 'milkshake_overview',

                         'access' => TRUE

                  );

                  $items[] = array(

                         'path' => 'milkshake/list',

                         'title' => t('List flavors'),

                         'type' => MENU_DEFAULT_LOCAL_TASK, //默认选上?/span>menu

                         'access' => TRUE,

                         'weight' => 0

                  );

                  $items[] = array(

                         'path' => 'milkshake/add',

                         'title' => t('Add flavors'),

                         'callback' => 'milkshake_add',

                         'type' => MENU_LOCAL_TASK,

                         'access' => TRUE,

                         'weight' => 1

                  );

                  $items[] = array(

                         'path' => 'milkshake/list/fruity',

                         'title' => t('Fruity flavors'),

                         'callback' => 'milkshake_list',

                         'type' => MENU_LOCAL_TASK,

                         'access' => TRUE,

                  );

                  $items[] = array(

                         'path' => 'milkshake/list/candy',

                         'title' => t('Candy flavors'),

                         'callback' => 'milkshake_list',

                         'type' => MENU_LOCAL_TASK,

                         'access' => TRUE,

                  );

           }

           return $items;

    }

    function milkshake_overview() {

           $output = t('The following flavors are available...');

           // ... more code here

           return $output;

    }

    function milkshake_add() {

           return t('milkshake add');

    }

    If you want the menu item to show up in the administrative menu block, you have to make

    the type a MENU_NORMAL_ITEM instead of a MENU_LOCAL_TASK. And if you want it to show up in both

    places, use the following:

    'type' => MENU_NORMAL_ITEM | MENU_LOCAL_TASK

    Programmatically Modifying Existing Menus

    1Q?/span>Wrapping Calls to Menu Items

    /**

    * Implementation of hook_menu().

    */

    function mymodule_menu($may_cache) {

           $items = array();

           if (!$may_cache && module_exist('devel')) { // Make sure devel.module is enabled.

                  $items[] = array(

                         'path' => 'devel/cache/clear', // Same path that devel.module uses.

                         'title' => t('Wrap cache clear'),

                         'callback' => 'mymodule_clear_cache',

                         'type' => MENU_CALLBACK,

                         'access' => user_access('access devel information') // Same as devel.module.

                  );

           }

    }

    function mymodule_clear_cache() {

           drupal_set_message('We got called first!');

           // Wrap the devel function normally called.

           devel_cache_clear();

    }

    2Q?/span>Deleting Existing Menus

    $items[] = array(

           'path' => 'node/add',

           'title' => t('This should not show up'),

           'callback' => 'drupal_not_found',

           'type' => MENU_CALLBACK

    );

    Adding to Existing Menus

    $items[] = array(

           'path' => 'admin/user/user/eradicate',

           'title' => t('Eradicate all users'),

           'callback' => 'mymodule_eradicate_users',

           'type' => MENU_LOCAL_TASK,

           'access' => TRUE

    );



    Eric.Zhou 2007-12-03 10:01 发表评论
    ]]>
    创徏annotate modulehttp://www.aygfsteel.com/rain1102/archive/2007/11/29/164010.htmlEric.ZhouEric.ZhouThu, 29 Nov 2007 07:41:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/11/29/164010.htmlhttp://www.aygfsteel.com/rain1102/comments/164010.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/11/29/164010.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/164010.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/164010.html         ?/span>sites/all/modules下面创徏一?/span>annotate文g?/span>

    2.         创徏annotate module的信息文?/span>(annotate.info)

    ; $Id: annotate.info v 1.1.2.3 2007/06/18 23:06:32 dww Exp $

    name = Annotate

    description = Allows users to annotate nodes.

    package = Example

    version = 5.5

    //dependencies = node blog

    project = "annotate"

    datestamp = "1193367002"

    3.         创徏annotate module的实际的module功能文g(annotate.module),所以的功能都在此文件中定义.

    <?php

    // $Id$

    /**

    * @file

    * Lets users add private annotations to nodes.

    *

    * Adds a text field when a node is displayed

    * so that authenticated users may make notes.

    */

    4.         q时候到Administer?/span> Site building?/span> Modules中就可以看到刚才d?/span>annotate模组.但这时候激zd在导航栏里面是看不到annotate讄菜单?/span>.

    5.         实现Hook(钩子),d一下代?/span>,重新Ȁz?/span>annotate模组,q样可以看到在Administer?/span> Site configuration下多了一?/span>Annotation settings菜单

    /**

    * Implementation of hook_menu().

    */

    function annotate_menu($may_cache) {

        $items = array();

        if ($may_cache) {

                  $items[] = array(

                  'path' => 'admin/settings/annotate',

                  'title' => t('Annotation settings'),

                  'description' => t('Change how annotations behave.'),

                  'callback' => 'drupal_get_form',

                  'callback arguments' => array('annotate_admin_settings'),

                  'access' => user_access('administer site configuration')

                  );

           }

           return $items;

    }

    6.         上面有行'callback' => 'drupal_get_form'代码,q有一?/span> 'callback arguments' => array('annotate_admin_settings'). q里当用户通过http://www.example.com/?q=admin/settings/annotate讉K的时?/span>,会调用drupal_get_form()函数,q且通过它的form ID annotate_admin_settings来调?/span>annotate_admin_settings()函数.所以我们要自己定义q个Ҏ.

    /**

    * Define the settings form.

    */

    function annotate_admin_settings() {

           $form['annotate_nodetypes'] = array(

                  '#type' => 'checkboxes',

                  '#title' => t('Users may annotate these node types'),

                  '#options' => node_get_types('names'), //q回所?/span>nodecdl成的数l?/span>

                  '#default_value' => variable_get('annotate_nodetypes', array('story')),

                  '#description' => t('A text field will be available on these node types to make

                  user-specific notes.'),

           );

           $form['array_filter'] = array('#type' => 'hidden');

           return system_settings_form($form);

    }

    7.         实现hook_nodeapi(),?/span>Drupal?/span>node做各U各L操作的时候对调用此函?/span>.

    /**

    * Implementation of hook_nodeapi().

    */

    function annotate_nodeapi(&$node, $op, $teaser, $page) {

           switch ($op) {

                  case 'view':

                         global $user;

                         // If only the node summary is being displayed, or if the

                         // user is an anonymous user (not logged in), abort.

                         if ($teaser || $user->uid == 0) {

                                break;

                         }

                         $types_to_annotate = variable_get('annotate_nodetypes', array('story'));

                         if (!in_array($node->type, $types_to_annotate)) {

                                break;

                         }

                         // Add our form as a content item.

                         $node->content['annotation_form'] = array(

                                '#value' => drupal_get_form('annotate_entry_form', $node),

                                '#weight' => 10

                         );

           }

    }

    8.         下面我们要定?/span>annotate form,作ؓ面现实内容

    /**

    * Define the form for entering an annotation.

    */

    function annotate_entry_form($node) {

           $form['annotate'] = array(

                  '#type' => 'fieldset',

                  '#title' => t('Annotations')

           );

           $form['annotate']['nid'] = array(

                  '#type' => 'value',

                  '#value' => $node->nid

        );

           $form['annotate']['note'] = array(

                  '#type' => 'textarea',

                  '#title' => t('Node'),

                  '#default_value' => $node->annotation,

                  '#description' => t('Make your personal annotations about this content

    here. Only you (and the site administrator) will be able to see them.')

           );

           $form['annotate']['submit'] = array(

                  '#type' => 'submit',

                  '#value' => t('Update')

           );

           return $form;

    }

    9.         到目前ؓ止对?/span>annotate的内Ҏ们还有做处理.从这里开?/span>,我们p?/span>annotate的数据存储到数据库里?/span>,很多module里面都有.install文g,该文件就是创建数据库表文?/span>.我们要创Z?/span>annotate.install文g

    <?php

    // $Id$

    function annotate_install() {

           drupal_set_message(t('Beginning installation of annotate module.'));

           switch ($GLOBALS['db_type']) {

                  case 'mysql':

                  case 'mysqli':

                         db_query("CREATE TABLE annotations (

                                uid int NOT NULL default 0,

                                nid int NOT NULL default 0,

                                note longtext NOT NULL,

                                timestamp int NOT NULL default 0,

                                PRIMARY KEY (uid, nid)

                                ) /*!40100 DEFAULT CHARACTER SET utf8 */;"

                         );

                         $success = TRUE;

                         break;

                  case 'pgsql':

                         db_query("CREATE TABLE annotations (

                                uid int NOT NULL DEFAULT 0,

                                nid int NOT NULL DEFAULT 0,

                                note text NOT NULL,

                                timestamp int NOT NULL DEFAULT 0,

                                PRIMARY KEY (uid, nid)

                                );"

                         );

                         $success = TRUE;

                         break;

                  default:

                         drupal_set_message(t('Unsupported database.'));

           }

           if ($success) {

                  drupal_set_message(t('The module installed tables successfully.'));

           } else {

                  drupal_set_message(t('The installation of the annotate module was unsuccessful.'),'error');

           }

    }

    10.     q里要到数据?/span>system表里?/span>annotatel删?/span>,然后重新Ȁz?/span>annotate模组.d提交事g.

    /*

    * Save the annotation to the database.

    */

    function annotate_entry_form_submit($form_id, $form_values) {

           global $user;

           $nid = $form_values['nid'];

           $note = $form_values['note'];

           db_query("DELETE FROM {annotations} WHERE uid = %d and nid = %d", $user->uid, $nid);

           db_query("INSERT INTO {annotations} (uid, nid, note, timestamp) VALUES (%d, %d, '%s', %d)", $user->uid, $nid, $note, time());

           drupal_set_message(t('Your annotation was saved.'));

    }

    11.     Z实现在现?/span>annotate的时候读取数据库里面的数据现?/span>,q里要修改一下前面的hook_nodeapi函数.修改以后的ؓ:

    /**

    * Implementation of hook_nodeapi().

    */

    function annotate_nodeapi(&$node, $op, $teaser, $page) {

           switch ($op) {

                  case 'view':

                         global $user;

                         // If only the node summary is being displayed, or if the

                         // user is an anonymous user (not logged in), abort.

                         if ($teaser || $user->uid == 0) {

                                break;

                         }

                         $types_to_annotate = variable_get('annotate_nodetypes', array('story'));

                         if (!in_array($node->type, $types_to_annotate)) {

                                break;

                         }

                         // Get previously saved note, if any.

                         $result = db_query("SELECT note FROM {annotations} WHERE uid = %d AND nid = %d", $user->uid, $node->nid);

                         $node->annotation = db_result($result);

                         // Add our form as a content item.

                         $node->content['annotation_form'] = array(

                                '#value' => drupal_get_form('annotate_entry_form', $node),

                                '#weight' => 10

                         );

           }

    }

    q样在重新激zM用一下就可以?/span>!



    Eric.Zhou 2007-11-29 15:41 发表评论
    ]]>
    把玩Drupal模組Q?Hook System運作介 http://www.aygfsteel.com/rain1102/archive/2007/11/29/163972.htmlEric.ZhouEric.ZhouThu, 29 Nov 2007 05:23:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/11/29/163972.htmlhttp://www.aygfsteel.com/rain1102/comments/163972.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/11/29/163972.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/163972.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/163972.html׃, 2006-05-09 20:07 ?jimmy
    模組pȝ是drupal很重要的運作方式Qdrupal依靠著少的核心E式Q便能讓模組能做CQ何事情?/p>

    drupal只有21個檔案在include裡頭Q每ơ必會loading進來Q其他的全都攑֜modules?br /> 也就是說Q除了那qN檔案以外Q全部的p都把他當成module在寫。諸如CMS最基本的功能,文章理、評論、討論區、分?..{的功能Q全部都寫在module裡,include裡頭所提供的是各種apiQ檔案處理函式、資料n存取、表單生?..{等Q這樣的分層,module便可以專心的開發各種功能?/p>

    當然Q這樣的架構不夠o人注目。有a多web app架構Q對於模i?QmoduleQ、插Ӟplug-inQ?..{的運作Q通常是讓他們各自為政,自己q自q事情。多是用核心提供的object和functionQ加上module自己外的codeQ達到module要做到的外功能。但是drupal的核心運作卻不是如此?/p>

    drupal處理使用的程式為modules/user.module。如果今天想要在看用者資料的同時Q也想看看所有用者過ȝ表文章的listQ那該怎麼寫呢Q?/p>

    直接一?/strong>Q更改user.modueQ在示時,順便L章資料n抓相關的資料Q然而這樣M是一個好方式Q今天Q何想要對使用者增加新功能的時候,都得trace一ơuser.module的codeQ看懂他在嘋啥,然後把新的code安插在合適的地方... 最後可能增加user.module的複雜度Q增加維護那支module的難度,共同開發時,更是一個危險的方式?/p>

    W二E方?/strong>Q重寫一個新的瀏覽頁面Q重新寫一個SELECT的語句,讓SELECT的時候除了用者資a,也把文章資料一hZQ然後顯C到不同的頁面。但是這樣很浪費,明明跟user.module重複的功能達C半以上,那是不是之後要新增功能,都得重寫一ơ呢Q?/p>

    上面兩種方式在drupal中也都可以達成,然而熟悉Drupal的hM會如此。Drupal的開D很聰明Q他的模i系i(module systemQ考慮C模組再利用這一點,每個模i都視為可以再利用的資源Q只要寫module的h惛_Q透過模組pȝ便可以跟所有的module交互作用?/p>

    W三E方?/strong>?code>modules/user.moduleZQ他x處理包含新增、修攏V刪除、註冊、登?...{所有與使用者相關的功能。在進行每個重要的功能時,user.module都會呼叫一個函式去掃所有的moduleQ看看是否有其他的module要在user.module進行此動作時Q也進行一些其他想要做的事情,這就是drupal重要?a rel="nofollow">Hook System?br /> example:
    在drupal user.module裡頭可以扑ֈ如下的程式碼

    function user_view($uid = 0) {
    // ... skip
    // moudle_invoke掃描所有的module
    // 看看有沒有modulename_user這個function
    // 有個話q'view'這個功能的部䆾要加上什?
    foreach (module_list() as $module) {
    if ($data = module_invoke($module, 'user', 'view', '', $account)) {
    // do something...
    }
    }
    // ... skip
    }
    

    所以,W三E方式,不用重寫Q也不用改到user.moduleQ只要自己新增module和寫一個functionQ便可以輕鬆讓瀏覽使用者資a時Q加上過往文章?br /> example:
    新增自己的moduleQ與hook systemR密運作
    新增sample.module

    function sample_user($type, &$edit, &$user, $category = NULL) {
    if ($type == 'view') {
    return /*過往文章Q型別為一陣列*/;
    }
    }
    

    這就是drupal把眾多主要功能都寫成module的原因,讓所有模i之間都可以交互利用Q或是寫i別人利用,或是利用別h的moduleQ像I木一樣推砌成惌的功能,d不浪費資源?/p>

    參考資源:
    詳細的用法在Q?br /> http://drupaldocs.org/api/head/function/hook_user
    Module developer's guideQ?br /> http://drupal.org/node/508



    Eric.Zhou 2007-11-29 13:23 发表评论
    ]]>
    模块介绍QjRatinghttp://www.aygfsteel.com/rain1102/archive/2007/11/29/163956.htmlEric.ZhouEric.ZhouThu, 29 Nov 2007 03:49:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/11/29/163956.htmlhttp://www.aygfsteel.com/rain1102/comments/163956.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/11/29/163956.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/163956.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/163956.html介:
    q个模块使用 jQuery 技术ؓ节点提供评分功能Q当 javascript 被禁止时Q用标准Ş式,如果启用 javascript 可以通过囄 (如五? 动态进行评分?

     

    q个模块能够?views 模块协作Q它提供一?views 字段Q让评分l果可以通过 views 昄?

     

    链接Q?/strong>

     

    http://drupal.org/project/jrating


    Eric.Zhou 2007-11-29 11:49 发表评论
    ]]>
    Drupal的Captchahttp://www.aygfsteel.com/rain1102/archive/2007/11/29/163957.htmlEric.ZhouEric.ZhouThu, 29 Nov 2007 03:49:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/11/29/163957.htmlhttp://www.aygfsteel.com/rain1102/comments/163957.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/11/29/163957.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/163957.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/163957.html大家在访问我的博客留a的时候,L会发现有一?#8220;考考智?#8221;Q很多h和我_“q个太侮辱我的智商了Q?#8221;Q其实这个题目只是和大家开一个玩W,但是放这个的真正目的是ؓ了防spam?br /> 啥是Sapm呢?癑ֺ癄的解释是Q?br /> -----------------------------------
    SPAM是stupid person advertesing method的简U?意思ؓ兜售信息[邮gQ广告,新闻Q文章]Q非索要信息。基本与垃圾邮gQjunk mailQ同?/p>

    x指在Internet上利用Emailq行q播式的q告宣传的行为。这U行为给很多人的信箱里塞入大量无x无用的信息,因此来受Ch们的厌恶Q在国q已l属非法行ؓ?/p>

    Spam最初来?
    spam即SPAMQ原是一个罐装肉的牌子。对于这个牌子名字的来源有很多解释,官方版本_它是”Specially Processed Assorted Meat”Ҏ加工q的混和肉?br /> q种SPAM肉有D|间非常普及,C无处不在Qo厌的E度。后来(1970q_Monty Python剧团有个很流行的Sketch comedyQ一U短的pd喜剧Q叫SpamQ剧中两位顾客试囄一份没有SPAM的早,但最后却没能成功?br /> 于是Q许多年后的现在QSpam被用来统UC联网上到处散布垃圑ֹ告消息的现象
    -------------------------
    其实说白了就是用自动化的工P在网上批量的发布一些广告信息,用EmailQ或者论坛,或者博客?br /> 现在论坛在发帖的时候,都会有验证码之类的,也是Z防止Spam?br /> Drupal作ؓ成熟的CMSQ自然有很多人对其进行Spam骚扰Q而Drupal也有很多的插件反Spam?/p>

    最常用的是Captcha模块?br /> 安装好Captcha模块以后Q我们会在用L理目录下扑ֈ一个Captcha理。这个管理看h很简单,只有单单的几V?/p>

    W一的意思是Q在有admin captcha权限的用LForm下面加上Captcha理链接。这样一般要勾上Q这L话,你就可以方便的修Ҏ一处要加Captcha的地方了?br /> 接下来的选项是讄各个地方的Captcha。对于Captchaq有很多相关的模块,大家可以去Drupal上查到。有很多U,比如囄Q比如算术,q有Riddler可以讄一些问题,比如一q有几个月之cȝ。可以对每一个Captcha Point讄一UCaptcha查方法?br /> 在这里,要注意的地方是,如果惛_加一个Captcha Point的话Q就要把W一Ҏ勾,然后以管理员w䆾M要添加Captcha的FormQ下面会有一个链接,点一下就好了。这个当时我找了好久Q最好逼到了看了Captcha代码Q准备去修改数据库的时候才发现Q呵c?br /> 下面是一些描qͼq有另一个选项Q选上以后Q用户需要在每一ơ输入的时候都输入Captcha?br /> 我们看到Captchaq有很多其他的设|信息,比如囄查设|,Riddler讄Q都比较单,点几下就明白了?br /> 对于Captcha的权限,有以下两个:一个是理CaptchaQ一个是跌Captcha查?/p>

    Eric.Zhou 2007-11-29 11:49 发表评论
    ]]>
    E-Mail field(cck邮g栏位)http://www.aygfsteel.com/rain1102/archive/2007/11/28/163796.htmlEric.ZhouEric.ZhouWed, 28 Nov 2007 12:18:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/11/28/163796.htmlhttp://www.aygfsteel.com/rain1102/comments/163796.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/11/28/163796.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/163796.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/163796.htmlq个模块会ؓcck增加一个聚合栏位,用户可以在那儿添加feedQ这个feed会加入到全站聚合里?br /> 官方发布: http://drupal.org/project/feedfield



    Eric.Zhou 2007-11-28 20:18 发表评论
    ]]>
    CCK Field Permissions(cck栏位权限)http://www.aygfsteel.com/rain1102/archive/2007/11/28/163794.htmlEric.ZhouEric.ZhouWed, 28 Nov 2007 12:07:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/11/28/163794.htmlhttp://www.aygfsteel.com/rain1102/comments/163794.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/11/28/163794.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/163794.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/163794.html 比如使用video_cck(cck视频栏位)l一个类型的noded一个video fieldQ这时候就可以控制一些用户可以添加视频,一些不可以d视频。用CCK Field PermissionsQ开启以后到Administer->Site configuration->CCK Field Permissions来设|对哪些node起作用,然后讄每个node的fieldsQ想通过CCK Field Permissions控制的就打勾Q保存!然后到User management->Access control里面讄控制Q?br />
    下蝲地址Q?a >http://drupal.org/project/cck_field_perms

    Eric.Zhou 2007-11-28 20:07 发表评论
    ]]>
    video_cck(cck视频栏位)http://www.aygfsteel.com/rain1102/archive/2007/11/28/163790.htmlEric.ZhouEric.ZhouWed, 28 Nov 2007 11:55:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/11/28/163790.htmlhttp://www.aygfsteel.com/rain1102/comments/163790.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/11/28/163790.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/163790.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/163790.htmlq个模块提供一个多媒体栏位Q只要填入视频网址Q即可自动播放。目前默认支持大多数p视频|站Q如Qyoutube。稍做修改,也可以支持国内视频网站的视频?/p> 需要结合CCK模块一起用!
    启动以后?Administer->Content management->Video CCK configuration下设|支持哪些网站视频!
    下蝲地址Qhttp://drupal.org/project/video_cck


    Eric.Zhou 2007-11-28 19:55 发表评论
    ]]>
    ApacheBench(ab)和eAccelerator使用配置http://www.aygfsteel.com/rain1102/archive/2007/11/28/163757.htmlEric.ZhouEric.ZhouWed, 28 Nov 2007 09:33:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/11/28/163757.htmlhttp://www.aygfsteel.com/rain1102/comments/163757.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/11/28/163757.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/163757.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/163757.htmlApacheBench(ab)

    服务器负载太大而媄响程序效率也是很常见的,Apache服务器自带有一个叫AB(ApacheBench)的工P在bin目录下。用这个轻巧的工具我们可以Ҏ务器q行负蝲试Q?br />
    基本用法:

    ab -n 全部h?-c q发?试url


    ?ab -n 1000 -c 50 http://www.abc.com/a.php

    得到l果cM?后面颜色字ؓ中文译):

    Server Software:        Apache/2.0.55
    Server Hostname:        localhost
    Server Port:            80

    Document Path:          /1.php
    Document Length:        82522 bytes  #h文档大小

    Concurrency Level:      50           #q发? 
    Time taken for tests:   92.76140 seconds #全部h完成耗时
    Complete requests:      10000          #全部h?br /> Failed requests:        1974           #p|的请?br />   (Connect: 0, Length: 1974, Exceptions: 0)
    Write errors:           0
    Total transferred:      827019400 bytes #M输大?br /> HTML transferred:       825219400 bytes
    Requests per second:    108.61 [#/sec] (mean) #每秒h?q_)
    Time per request:       460.381 [ms] (mean) #每次q发h旉(所有ƈ?
    Time per request:       9.208 [ms] (mean, across all concurrent requests)  #每一h旉(q发q_)  
    Transfer rate:          8771.39 [Kbytes/sec] received #传输速率

    Connection Times (ms) #q接旉
                 min  mean[+/-sd] median   max
    Connect(#q接):        0    0   2.1      0      46
    Processing(#处理):    31  458  94.7    438    1078
    Waiting(#{待):       15  437  87.5    422     938
    Total:         31  458  94.7    438    1078


    其它参数:

    -n requests     全部h?br /> -c concurrency  q发?br /> -t timelimit    最传等待回应时?br /> -p postfile     POST数据文g
    -T content-type POST Content-type
    -v verbosity    How much troubleshooting info to print
    -w              Print out results in HTML tables
    -i              Use HEAD instead of GET
    -x attributes   String to insert as table attributes
    -y attributes   String to insert as tr attributes
    -z attributes   String to insert as td or th attributes
    -C attribute    加入cookie, eg. 'Apache=1234. (repeatable)
    -H attribute    加入http? eg. 'Accept-Encoding: gzip'
                    Inserted after all normal header lines. (repeatable)
    -A attribute    http验证,分隔传递用户名及密?br /> -P attribute    Add Basic Proxy Authentication, the attributes
                    are a colon separated username and password.
    -X proxy:port   代理服务?br /> -V              查看ab版本
    -k              Use HTTP KeepAlive feature
    -d              Do not show percentiles served table.
    -S              Do not show confidence estimators and warnings.
    -g filename     Output collected data to gnuplot format file.
    -e filename     Output CSV file with percentages served
    -h              Display usage information (this message)


    About eAccelerator
    eAccelerator是一个的免费、开源的PHP模块Q它能够为提供PHP加速、优化、加码、和动态内容缓存功能。它通过存储PH脚本~译后的状态而加快执行PHP脚本的速度Q而不需要频J的~译q个PHP脚本。而且它能优化PHP脚本Q以提高执行PHP的速度。eAccelerator特色是减了服务?/span>负蝲、PHP脚本加?-10倍?br /> 对应你的php版本下蝲相应的dll文gQ如果是PHP 5.2.5请下?a target="_blank">eAccelerator 0952 for PHP 5.2.5 eLoader 0952 for PHP 5.2.5

    Attachment Size
    eAccelerator 095 Final for PHP 5.1.6 120 KB
    095_final_useful _files.zip 41.97 KB
    eAccelerator 0.9.5 Final for PHP 5.1.5 120 KB
    eAccelerator 095 Final for PHP 5.1.6 Optimized for Size 108 KB
    eAccelerator 095 Final for PHP 5.2.0 120 KB
    eAccelerator 095 Final for PHP 5.0.5 120 KB
    eAccelerator 095 for PHP 5.0.4 (OLDER PHP VERSION) 120 KB
    eAccelerator 0951 for PHP 5.2.2 120 KB
    eAccelerator 0951 for PHP 5.2.1 120 KB
    eAccelerator 0951 for PHP 5.2.2 Built with VC2005 SP1 128 KB
    eAccelerator 0951 for PHP 5.1.4 120 KB
    eAccelerator 0951 for PHP 5.2.3 120 KB
    eAccelerator 0951 for PHP 5.2.0 (OLDER PHP VERSION) 120 KB
    eAccelerator 0951 for PHP 5.2.4 120 KB
    eLoader 0951 for PHP 5.2.4 28 KB
    0952_final_useful _files.zip 42.27 KB
    eLoader 0952 for PHP 5.2.3 28 KB
    eAccelerator 0952 for PHP 5.2.3 120 KB
    eLoader0952_5.2.4.dll 28 KB
    eAccelerator 0952 for PHP 5.2.4 120 KB
    eAccelerator 0952 for PHP 5.2.5 120 KB
    eLoader 0952 for PHP 5.2.5 28 KB


    We have been using this PHP accelerator (0.9.5), on multiple servers, for a long time. It's used on some high traffic sites without any problem.
    Install:
    a) Download a copy of eAccelerator that is compatible with your version of PHP.
    This can be an issue with eAccelerator. Sometimes it can take a little time before the Windows binaries are available for the most recent version of PHP.
    b) Copy a compatible eaccelerator.dll to your PHP extensions folder (like:D:\php\ext replace with your actual folder location).
    Make sure the configuration directive extension_dir in your php.ini is properly pointing to your extensions folder.
    Like: extension_dir = "D:/php/ext"
    //dll文g复制到D:/php/ext下.
    c) Create a folder (with the appropriate permissions) for the temporary cached files.
    For example: D:\temp\eaccelerator
    //创徏tmp目录 权限可写
    d) Add the following to your php.ini (as the first loaded extension):
    .
    ;extension=php_yaz.dll
    ;extension=php_zip.dll
    //~辑php.ini 在extension=php_zip.dll之后MU字部分

    [eaccelerator]
    zend_extension_ts="D:\php\ext\eAccelerator0952_5.2.3.dll"
    zend_extension="D:\php\ext\eAccelerator0952_5.2.3.dll"
    eaccelerator.cache_dir = "D:\temp\eaccelerator"
    eaccelerator.shm_size="64"
    eaccelerator.enable="1"
    eaccelerator.optimizer="1"
    eaccelerator.debug ="0"
    eaccelerator.check_mtime="1"
    eaccelerator.filter=""
    eaccelerator.shm_max="0"
    eaccelerator.shm_ttl ="0"
    eaccelerator.shm_prune_period="0"
    eaccelerator.shm_only="0"
    eaccelerator.compress="1"
    eaccelerator.compress_level="9"
    eaccelerator.keys= "shm"
    eaccelerator.sessions="shm"
    eaccelerator.c
    zend_extension="D:\php\ext\eLoader0952_5.2.3.dll"
    ;;;;;;;;;;;;;;;;;;;
    ; Module Settings ;
    ;;;;;;;;;;;;;;;;;;;
    .
    .
    e) Restart your Web Server.You can see..

    Eric.Zhou 2007-11-28 17:33 发表评论
    ]]>|站多语a版本Q-Drupalhttp://www.aygfsteel.com/rain1102/archive/2007/11/22/162379.htmlEric.ZhouEric.ZhouThu, 22 Nov 2007 06:53:00 GMThttp://www.aygfsteel.com/rain1102/archive/2007/11/22/162379.htmlhttp://www.aygfsteel.com/rain1102/comments/162379.htmlhttp://www.aygfsteel.com/rain1102/archive/2007/11/22/162379.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/162379.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/162379.html在官方网站上看到有两个module可以实现国际化多语言版本Q首先看到的是menutranslationQ而此module只是实现了对menu实现的国际化多语a控制Q显然不适合一般的要求Q但q个module配置很简单,只需要加入i18n可以了Q基本不需要配|什么的?br /> 与是ql看了一下功能强大的localizer。此module需要自己配|很多?br />

    Installation instructions (New installation: Localizer 1.10 on Drupal 5.1 and Drupal 5.2)

    1. Download the latest Localizer module from http://drupal.org/project/localizer
    2. Download the flags icons from http://www.speedtech.it/files/localizer-flags.tgz
    3. Download pre-patched core files from
       http://www.speedtech.it/files/localizer-sites-all-5.1-1.10.tgz (Drupal 5.1)
       http://www.speedtech.it/files/localizer-sites-all-5.2-1.10.tgz (Drupal 5.2)  
    4. Extract localizer-5.x-1.10.tgz archive under sites/all/modules (create the modules directory if needed)
       This will create sites/all/modules/localizer that contains the Localizer-related module code.
    5. Extract localizer-flags.tgz under sites/all/modules/localizer. This
       will create sites/all/modules/localizer/flags with the flag files in it.
    6. Extract localizer-sites-all-5.1-1.10.tgz (or localizer-sites-all-5.2-1.10.tgz) under sites/all (it already
       has the modules and localizer directory, so the contents will go into
       sites/all/modules/localizer.
    7. To the end of your sites/default/settings.php file, append and save
       (overwrite the file):
       $conf= array
       (
          'cache_inc' =>
          'sites/all/modules/localizer/system/includes/cache.inc',
       );
    8. Login to your site as administrator (UID=1)
    9. Under Administer > Site building > modules, enable all the
       Localizer-related modules you need. Click Save configuration.
    10. Visit www.yoursite.com/update.php and run the update script.
    11. Under Administer > Site configuration > Localizer to configure options.
    12. Enjoy!


    Upgrade instructions (Upgrade from older versions of Localizer to Localizer
    1.10 on Drupal 5.1 and Drupal 5.2)

    1. Download the latest Localizer module from http://drupal.org/project/localizer
    2. Download the flags icons from http://www.speedtech.it/files/localizer-flags.tgz
    3. Download pre-patched core files from
       http://www.speedtech.it/files/localizer-sites-all-5.1-1.10.tgz (Drupal 5.1)
       http://www.speedtech.it/files/localizer-sites-all-5.2-1.10.tgz (Drupal 5.2)  
    4. Login to your site as administrator and under Administer > Site
       building > modules, disable all the Localizer-related modules
    5. Delete the old module/localizer directory (could be sites/all/modules/localizer)
    6. Return the Drupal 5.x modules that you previously patched for
       Localizer versions prior to 1.10 to their original state. (In other
       words, download Drupal 5.x and extract the the following files from
       the tarball: block.module, menu.module, taxonomy.module, bootstrap.inc,
       and common.inc. Upload these to your site, overwriting the existing
       modules.)
    7. Extract localizer-5.x-1.10.tgz archive under sites/all/modules
       (create the modules directory if needed) This will create
       sites/all/modules/localizer that contains the Localizer-related module code.
    8. Extract localizer-flags.tgz under sites/all/modules/localizer. This
       will create sites/all/modules/localizer/flags with the flag files in it.
    9. Extract localizer-sites-all-5.1-1.10.tgz (or localizer-sites-all-5.2-1.10.tgz) under sites/all (it already
       has the modules and localizer directory, so the contents will go into
       sites/all/modules/localizer.
    10. To the end of your sites/default/settings.php file, append and
       save (overwrite the file):
       $conf= array
       (

           'cache_inc' =>
       'sites/all/modules/localizer/system/includes/cache.inc',

       );
    11. Login to your site as administrator (UID=1)
    12. Under Administer > Site building > modules, enable all the
        Localizer-related modules you need. Click Save configuration.
    13. Visit www.yoursite.com/update.php and run the update script.
    14. Under Administer > Site configuration > Localizer to configure
        options.
    15. Enjoy!

    按照它的说明文gQ很快就可以实现国际化多语言版本的网站了!此module可以对nodeQblock{等实现国际?

    Eric.Zhou 2007-11-22 14:53 发表评论
    ]]>
    վ֩ģ壺 | ԭ| ̩| ɽ| | ɽ| ɽ| ɽ| | | | | | | | κ| | ƽ̶| | | ˻| ޻| ̫| ½| | | ־| | ӱʡ| | ԭ| ƽ| | | | Դ| ½| | | Ȫ| ˮ|