??xml version="1.0" encoding="utf-8" standalone="yes"?>
步骤一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 />
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 Aggregator
---------------------------------------------------------------------------------
OG Audience
---------------------------------------------------------------------------------
OG Author
---------------------------------------------------------------------------------
OG Block Visibility
---------------------------------------------------------------------------------
OG Calendar
---------------------------------------------------------------------------------
OG Forum
---------------------------------------------------------------------------------
OG Galleries
---------------------------------------------------------------------------------
OG Gradebook
---------------------------------------------------------------------------------
OG Join Role
---------------------------------------------------------------------------------
OG Minutes
---------------------------------------------------------------------------------
OG moderated posts
---------------------------------------------------------------------------------
OG Project
---------------------------------------------------------------------------------
OG promote
---------------------------------------------------------------------------------
OG Public Access
---------------------------------------------------------------------------------
OG Roles
---------------------------------------------------------------------------------
OG Teampage
---------------------------------------------------------------------------------
OG User Roles
---------------------------------------------------------------------------------
OG Vocab
q个模块需?ACL 模块?
/**
* 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);
}
q个模块q附带一?XSPF Flash 播放?/a>?
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/".
/**
* @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.');
}
}
A module which runs the Drupal cron operations without needing the cron application.
For every page view, this module checks to see if the last cron run was more than 1
hour ago (this period is configurable). If so, the cron hooks are executed,
and Drupal is happy. These cron hooks fire after all HTML is returned to the browser,
so the user who kicks off the cron jobs should not notice any delay.
Access control for user roles based on taxonomy categories (vocabulary, terms).
http://drupal.org/project/taxonomy_access
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.
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 ?>.
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;
}
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;
}
}
$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()
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
);
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>!
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: 所以,W三E方式,不用重寫Q也不用改到user.moduleQ只要自己新增module和寫一個functionQ便可以輕鬆讓瀏覽使用者資a時Q加上過往文章?br />
example: 這就是drupal把眾多主要功能都寫成module的原因,讓所有模i之間都可以交互利用Q或是寫i別人利用,或是利用別h的moduleQ像I木一樣推砌成惌的功能,d不浪費資源?/p>
參考資源:
在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
}
新增自己的moduleQ與hook systemR密運作
新增sample.modulefunction sample_user($type, &$edit, &$user, $category = NULL) {
if ($type == 'view') {
return /*過往文章Q型別為一陣列*/;
}
}
詳細的用法在Q?br />
http://drupaldocs.org/api/head/function/hook_user
Module developer's guideQ?br />
http://drupal.org/node/508
]]>
q个模块能够?views 模块协作Q它提供一?views 字段Q让评分l果可以通过 views 昄?
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>
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 |
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!