Friday, December 19, 2008

Apache log in terminal

The location of the log is in : /var/log/apache2
Then use sudo tail -f error.log
Simple right?

Friday, December 05, 2008

Change terminal title on Mac Leopard

The leopard ships with tabbing feature for terminal, which is cool. However, the problem with that is you can not change the title at all. I found a little shell script may do the trick froom http://pseudogreen.org/blog/set_tab_names_in_leopard_terminal.html, here is the snippy of the function:


function set_window_and_tab_title
{
local title="$1"
if [[ -z "$title" ]]; then
title="root"
fi

local tmpdir=~/Library/Caches/${FUNCNAME}_temp
local cmdfile="$tmpdir/$title"

# Set window title
echo -n -e "\e]0;${title}\a"

# Set tab title
if [[ -n ${CURRENT_TAB_TITLE_PID:+1} ]]; then
kill $CURRENT_TAB_TITLE_PID
fi
mkdir -p $tmpdir
ln /bin/sleep "$cmdfile"
"$cmdfile" 10 &
CURRENT_TAB_TITLE_PID=$(jobs -x echo %+)
disown %+
kill -STOP $CURRENT_TAB_TITLE_PID
command rm -f "$cmdfile"
}


Thursday, November 27, 2008

Apache Set up Vitrual Host

Here are the configuration for Apache when setting up virtual host

NameVirtualHost *:80


ServerName dev.leoman730.com
DocumentRoot /Applications/MAMP/htdocs/dev_leoman730



ServerName ocmgt.leoman730.com
DocumentRoot /Applications/MAMP/htdocs/dev_ocmgt



Also remember to modify the hosts file accordingly in order for it to work.

Some more helpful tip can be found: Here

Set up virtual host on MAMP

1. Open your httpd.conf
This file will reside in /Applications/MAMP/conf/apache/httpd.conf .

2. Go to the bottom of httpd.conf find the vhost section, usually locates at the bottom of the file,
add virtual host like this:
<====IF PORT SET TO 8080 ==>
NameVirtualHost *:8080


ServerName dev.domain.net
DocumentRoot /Applications/MAMP/htdocs/dev_domain



ServerName test.domain.net
DocumentRoot /Applications/MAMP/htdocs/test_domain


<====IF PORT SET TO 80 ==>
NameVirtualHost *:80


ServerName dev.domain.net
DocumentRoot /Applications/MAMP/htdocs/dev_domain



ServerName test.domain.net
DocumentRoot /Applications/MAMP/htdocs/test_domain



3. Modify host file, the host file is located at:
/etc/hosts

Open the file, then add entry:
127.0.0.1 dev.domanin.net
127.0.0.1 test.domain.net

4. Restart Apache server.

NOTE:
IF YOU ARE USING PORT 8080 FOR MAMP, YOU CAN ACCESS THE SITE LIKE: http:test.domain.com:8080
IF YOU ARE USING PORT 80 FOR MAMP, YOU CAN ACCESS THE SITE LIKE: http:test.domain.com (If you cannt restar apache from MAMP after set the port 80, make sure no other apache server is using the port already)

Setting Up SVN on mac

Here's a tutorial provide information on how to set up entire svn environment for mac.
SVN SET UP

Thursday, November 20, 2008

Ajax weirness

When doing an ajax call through javascript, sometimes it may seems like nothing is happening in firebug, instead it thrown an javascript error.
One thing to check is to make sure the permission is correctly setup in the ajax script. The problem i have is that when the php script get call, it upload an image to the server, if upload directory's permission not properly set up, the weirness of this ajax call occur.

Using biwise operator to implement user access

Here's a way to use biwise operator to implement user access of special section on a site.

1. Define Constants:
PER_ADD = 1 (000001)
PERM_EDIT = 2 (000010)
PERM_DELETE = 4 (000100)
PERM_VIEW = 8 (001000)

2. Define user access level code:
EDIT => 63 (111111)
READ => 8 (000100)
NOACCESS=>0(000000)

3. Each user is associate with one or more access level code base on the section.

4. The algorithm to perform user access check is like this:
if((userAccessCode & PERM_EDIT) == PERM_EDIT){
grand access
}else{
access denial
}


How this works?
Using above example, if the user access code for a special section is defined as 63 which the binary representation is 111111, and we want to check if the user has edit permission for the section, then we can use the & biwise operator to figure it out. Sine the PERM_EDIT is define as 2 (000010), so

1 1 1 1 1 1 (63)
& 0 0 0 0 1 0 (2)
--------------
0 0 0 0 1 0 (2)

which if((userAccessCode & PERM_EDIT) == PERM_EDIT){ } will return true, so user can modify this section.

Other example, if the user access code is 8 (000100),

0 0 0 1 0 0 (63)
& 0 0 0 0 1 0 (8)
--------------
0 0 0 0 0 0 (0)

which if((userAccessCode & PERM_EDIT) == PERM_EDIT){ } will return false, so user can not modify this section.


Here's a list of possible combinations:
0 & 0 = 0
8 & 8 = 8 (Read)
63 & 8 = 8 (Read)
63 & 2 = 2 (Write)
8 & 2 = 0 (No write)

Monday, September 29, 2008

Javascript editor for Eclipse

Recently I was searching for a plug-in for Javascript in Eclipse. And I come up find out a very good plug-in call: Skyway builder. It looks very promising to me. Some feature I like are Code-formating, auto-completion with diff js library such as JQuery, ExtJS...
The plug-in is free from non-commercial use and it is relatively cheap for commercial user.
It could be download at: Ext智能提示 - Eclipse 3.2

Monday, September 22, 2008

Calling a scripting function from .bash_login

This rather a very simple issue that i have encounter couple days ago. Yeah, I don't consider myself a console scripting guru. So don't sunrise if you see me to post this. ^_^.
So I have a function "conn_remote" define inside my .bash_login file, when started up the a terminal, I see that the .bash_login file is actually gotten read as it print "Welcome to to bash" (which I defined it in the .bash_login file); however, when i try to call the "conn_remote" function, it said "command not defined".
After some chatting with ppl in IRC, I realize the cause to this is because my .bash_login not defined as the source. So to solve this issue, I put a command "source .bash_login" whenever a new terminal is fired up, and after this is defined, i was able to call my function freely.

Thursday, September 11, 2008

Refresh a treepanel

An easy way to updatte a treepanel in Ext:

Ext.getCmp('treepanel_id'). getRootNode().reload();

Refer to:http://extjs.com/forum/showthread.php?t=23441 to get more info

Monday, September 08, 2008

Wednesday, September 03, 2008

Prototype: How to truncate a string

A very nice utility to truncate a string in prototype:

var test_string = "this is a test string/0";
var new_string = test_string.truncate(test_string.length- 2, '');

So the new_string should be "this is a test string. Remember though, don't ignore the second paremeter, which now specify there will not be any suffix.

Monday, August 18, 2008

Drupal TINYMCE cause problem in user edit

This is a weir issue I found out today on tinymce, so far i am not sure what is the root cause to this issue.
After turned on and create a profile for tinymce, i cannt access user edit page, when click edit, it print out a blank page with a link said "disable tinymce" at the upper left corner, and the page looks like keep looping, by looking at the url, it looks like this"xxx?destination=admin%2Fuser%2Fuser".
As of now, to solve the issue, i disable tinymce module. Anyone find a solution for that please let me know.

Friday, August 15, 2008

Security Research Paper outline



This paper will not talk about the detail under the hood but provide wide range of security vanerbility information and also provide some tips on how to protect and increase individual scurity awareness.



Abstract


Introduction

  • The original purpose of internet (papaer form DCN2)


Some example of current security issue --> give some statistics


Security issue in detail


Privacy

  • Adware, spyware, Tojans horse, Rootkid
  • ISP
  • Email (PGP) SSL, VPN, --> talk about use some name, but dictionary attack
  • IE Problem --active X
  • Password





Attacks --> google hack

  • DoS
  • DDoS
  • Bufferoverflow
  • Packet sniffer
  • Port scanning



Why security is an issue?
There's no 100% secure application


Protection

  • Firewall --> talk about window xp sp2
  • Anti-virus
  • Password
  • VMware as sandbox




Conlcusion

Sunday, August 10, 2008

10 usesul CSS trick much know

1. Reset browser defaults then reset the browser font size
2. Design centered horizontally (fixed width)
3. Controlling position:absolute, relatively
4. Position an element center screen
5. Global rules that can be re-used
6. IE6 double margin on floated elements
7. Simple navigation bar
8. Table-less contact form
9. Footer hooked to browser bottom
10. Multiple classes applied to one element

More info, see this: Article

Tuesday, August 05, 2008

Make cool tag cloud easily

This is an very useful site to help make tag cloud:
http://tagcrowd.com/

Monday, July 28, 2008

array_merge_recursive error

Today, I ran into a problem with Drupal, when in the admin page, I see this message on top of the page:
array_merge_recursive() [function.array-merge-recursive]: recursion detected

The reason why this was show up because"
drupal_add_js('sites/all/modules/pmg_import/pmg_import.js');

is put into xxx_menu hook.

The best practice is to put that into the xxx_init() function.

Tuesday, July 22, 2008

PHP4 VS PHP5

Just find this article great on the different between PHP4 and PHP5.

http://www.webmaster-talk.com/php-forum/78717-differences-between-php4-and-php5.html

Monday, July 21, 2008

Cool and easy way to find timestamp

I just find this is cool and useful when try to try a timestamp for particular date in PHP. Of course, there are many ways to do it, but may you find this one quick and easy in PHP.


echo strtotime("now"), "\n";
echo strtotime("10 September 2000"), "\n";
echo strtotime("+1 day"), "\n";
echo strtotime("+1 week"), "\n";
echo strtotime("+1 week 2 days 4 hours 2 seconds"), "\n";
echo strtotime("next Thursday"), "\n";
echo strtotime("last Monday"), "\n";

COUNT and GROUP BY

When using "COUNT" and "GROUP BY" in mysql, make sure that the count condition to run after group by, otherwise the sql will fail.
Example:

SELECT count(node.uid) as num, node.uid,
node.created AS node_created
FROM node
WHERE (node.type in ('advisor_update')) AND (node.status <> 0)
AND num > 2
GROUP BY node.uid
ORDER BY node_created DESC;


SELECT count(node.uid) as num, node.uid,
node.created AS node_created
FROM node
WHERE (node.type in ('advisor_update')) AND (node.status <> 0)
GROUP BY node.uid
HAVING num > 2
ORDER BY node_created DESC;


The fist statement will fail, use the 2nd statement instead.

Friday, July 18, 2008

String Index using string[index] or string.charAt(index)

I found this issue today on string index of javascript for IE 7.

It seems like IE7 does't like String[index] at all, but it works with string.charAt(indext).


Try this out:

function memberlink_txtchange(id){
var value = $('#'+id).val();
var int_var;
var new_var = '';
for(var i = 0; i < value.length; i++){
if(checknumber(value.charAt(i))){
new_var += value.charAt(i);
}
}

$('#'+id).val(new_var);
return true;
}

Drupal write query relate to revision control

When write sql in drupal that related to revision control, the best practice is ONLY use nid in the node table, for the rest of the tables, use vid instead. That will prevent contents from syn. See this example for reference:

$query ="SELECT DISTINCT n.nid FROM content_type_event e
INNER JOIN node n ON n.nid = e.nid
INNER JOIN content_field_feature cff ON cff.vid = n.vid
INNER JOIN content_field_date_and_time cfdt ON cfdt.vid = n.vid
WHERE n.status = '1' AND cfdt.delta = '0'
AND cff.field_feature_value ='1'
ORDER BY cfdt.field_date_and_time_value ASC LIMIT 2";

Friday, June 27, 2008

Empty line on source page

When creating a custom module for drupal, make sure do not leave empty line after the last line of code; otherwise, it may create empty space (line) on top of the source document. See pic below:

Wednesday, March 12, 2008

Programmatically insert cck field

Ok, after couple hrs of strive on the net. This is an example on how to insert a cck field pro grammatically.
More reference on: http://drupal.org/node/159186

function dpci_admin_update_2(){
$cck_path = drupal_get_path("module","Content");
include_once($cck_path."/content_admin.inc");
include_once($cck_path."/content_crud.inc");
include_once($cck_path."/content.module");

$field_widget_type = 'text-options_onoff';
$label = 'My Check Box';
$content_type = 'page';
$field_name = 'my_check_box';
$properties['field_widget_type']='text-options_onoff';

// First step of creating the field - create the basic field (corresponds
// to page 1 of the Add field UI).
$default_field_add = array(
'label' => $label,
'type_name' => $content_type,
'field_widget_type' => $field_widget_type,
'op' => 'Create field',
'submit' => 'Create field',
'form_id' => '_content_admin_field_add_new',
);
// Create our new field.
_content_admin_field_add_new_submit('_content_admin_field_add_new', $default_field_add);

// Second step, update the field with our custom properties.
$default_field_edit = array(
'label' => $label,
'type_name' => $content_type,
'weight' => -10,
'description' => 'Some description',
'default_value_php' => '',
'group' => 0,
'required' => 1,
'multiple' => FALSE,
'text_processing' => 0,
'max_length' => '',
'allowed_values' => '0|dont check
1|check',
'allowed_values_php' => '',
'op' => 'Save field settings',
'submit' => 'Save field settings',
'type_name' => $content_type,
'field_name' => 'field_'.$field_name,
'form_id' => '_content_admin_field',
'default_value' => array(), // This might be cruft
'referenceable_types' => array(), // Used in nodereference fields and userreference
);

foreach($default_field_edit AS $key => $value) {
if (isset($properties[$key])) {
$default_field_edit[$key] = $properties[$key];
}
}

// Derive the widget and type from the input type.
$widget_parts = explode('-', $properties['field_widget_type']);
$default_field_edit['widget_type'] = $widget_parts[1];
$default_field_edit['module'] = $widget_parts[0] .', optionwidgets';

_content_admin_field_submit('_content_admin_field_add_new', $default_field_edit);

return array();
}

Monday, March 10, 2008

Quick way to remove an element from array in php

  1. // our initial array
  2. $arr = Array("blue", "green", "red", "yellow", "green", "orange", "yellow", "indigo", "red");
  3. print_r($arr);
  4. // remove the elements who's values are yellow or red
  5. $arr = array_diff($arr, array("yellow", "red"));
  6. print_r($arr);

Wednesday, March 05, 2008

MYSQL Backup and Restore from Command Line

To backup a database:
mysqldump dbname >dbname.sql

To backup a single table:
mysqldump dbname tbname >tbname.sql

To Restore a database:
Create a db named "mydb"
mysql -u username -p mydb < dbname.sql
Reference: http://www.abbeyworkshop.com/howto/lamp/MySQL_Export_Backup/index.html

Friday, February 29, 2008

Finding duplication entry using SQL

Here's a handy query for finding duplicates in a table. Suppose you
want to find all email addresses in a table that exist more than once:

SELECT email,
COUNT(email) AS NumOccurrences
FROM users
GROUP BY email
HAVING ( COUNT(email) > 1 )

You could also use this technique to find rows that occur exactly once:

SELECT email
FROM users
GROUP BY email
HAVING ( COUNT(email) = 1 )

Reference: http://www.petefreitag.com/item/169.cfm

Tuesday, February 19, 2008

CLR and JIT in .net

CLR 就是 Common Language Runtime 是用来运行.net的代码的。
JIT 是 Just In Time。 .net 的代码在编译的时候会通过两个步骤,首先它会被编译成一种中间语言也就是MSIL,然后通过JIT将这中中间语言转换成本地的机器代码。所以把整它能够在不同的机器上提供最好的性能和执行效率。

About Object.dispose() in .NET 2.0

Dispose 方法一般会调用 GC.SuppressFinalize,因此在您使用 Dispose 之后,系统已经认为该对象已经释放,也不会尝试再次处置该对象。
您需要区分“对象资源被回收”和“对象被回收”两个不同的概念。
例如,f 是一个 Form 类型的对象,则在内存中,f 本身是一个托管指针,您如果使用了 Dispose 方法,那么 f 指向的 Form 对象中的资源将被释放,也就是说 f 现在指向的 Form 对象已经是无效的,甚至可能指向已经被别的对象占用的空间。
但是 f 自身仍然占有一个指针的空间(内容是原来的 Form 对象的地址),即使您使用 f = null,那么 f 只是自身的内容变成 null。f 对象本身仍然占用了一个指针的空间。
您永远无法控制一个托管指针本身的释放(也就是说您无法尝试通知垃圾回收器把 f 自身的空间处置)。垃圾回收器会自动地在 f 对象脱离生存期(如离开了声明的方法,或所在的类实例被处置)后回收该空间。
一般程序上所说的用 null 来释放空间是这样的:
object obj = XXXX;
obj = null;
这里如果把 obj 设置为 null,那么 obj 原来指向的那块空间可能就变成无人可访问了。这时候垃圾回收程序会回收那块空间,但是同样不会回收 obj 本身的空间。
将处置后对象设置为 null 一般来说在程序使用上有一定意义,因为您可以通过和 null 作比较方便的判断某个对象是否有效。如果不设置为 null,而您又处置了对象,那么如果您只是使用 obj != null 的方式来判断,之后对 obj 作某些操作,那么会引发 ObjectDisposedException。

===================================================

Object a = new Object();
此时 a 是一个指针,我们假设他占用 4 个字节(内存 1),而 Object 是一个对象,可能会占用 32 个字节(内存 2)。a 的 4 个字节的内容就是那个 Object 对象所在的位置。
a = null;
此处将 a 设置为 null,只是更改了 a 自身的值(把 a 自己的 4 个字节全部置 0),但是结果是使原来 a 指向的内容(内存 2)无法访问。垃圾回收器会看到这一情况,然后回收那个不可访问的对象。同时如果继续使用 a,那么代码运行的时候会检查到您试图获取位置 0 中对象的内容,而位置 0 表示空位置,因此会提示您 NullReferenceException。
如果用
a.Dispose();
那么程序会手动清理干净内存 2 中的一些资源(比如图像资源)。但是此时 a 的内容没有变化,指向的位置还是内存 2。这时就出现一个问题,a 无法在被使用(因为其中的内容已经被处置)。这时候如果您继续使用 a,那么系统不会检测到 NullReferenceException,但是因为实际上里面的内容已经被释放而用作他用,在尝试读取的时候系统会引发 ObjectDisposedException,也就是检测到您尝试读取已经释放掉的位置的内容。

Tuesday, January 15, 2008

Drupal: Multi-site installation

In drupal, it is possible to create multiple sites from ONE drupal instance. There are lots of information out on the web show how to do it, but many times are confusing. Following are some summary steps to create multiple sites in drupal:

There are two url form for multi site: subdomain (site1.domain.com, site2.domain.com) and suburl (domain.com/site1, domain.com/site2).

Example:
I want to create couple sites: www.gt.com; www.gt.com/site1; site2.gt.com. I can also create something like this: site1.gt.com/site2

1. Add virtual server to apache
NameVirtualHost *:80


ServerAdmin name@databasepublish.com
DocumentRoot "c:/wamp/www"
ServerName localhost

AllowOverride All
Allow from all





ServerAdmin name@databasepublish.com
DocumentRoot "c:/wamp/www/multisite"
ServerName gt.com //this is good enough to take care of gt.com/site1; gt.com/site2 ... (but make sure set the symbolic link otherwise you will get "page not found" error
ServerAlias *.multisite.com //this takes care of: site1.gt.com; site2.gt.com .....
ErrorLog logs/multisite_error_log
CustomLog logs/air-access_log common


AllowOverride All



( REMEMBER: all sites must point to the drupal base installation directory, also make sure to set symbolic link if using suburl format)

2. Modify window host file to point to the domain name, the location of the host file can be refer from http://leoman730.blogspot.com/2007/07/hostfile-location.html


3. Create new directories ("gt.com"; "site1.gt.com"; "gt.com.site2" under ) in path_to_drupal_installation/sites.

Tip: the directory name must match the site location by replacing '/' with '.'

Copy the settings.php file the default directory into these new directories.
Modify the settings.php accordingly for base_url, and db_url parameter.

Ex: in "gt.com.site2" directory, the base_url should be set to
$base_url = 'http://gt.com/site2';

Also need to modify the db_url to point to the correct database for each site


4. Create symbolic link for subsite (This is need is using suburl format)
I am using wamp as example, add alias by create a new alias file. The code should looks like this:

Alias /site1 "c:/wamp/www/multisite/" //multiple alias can be added here


Options Indexes FollowSymLinks MultiViews
AllowOverride all
Order allow,deny
Allow from all



4. Don't run the install script yet. Create new database for each site using any available tool such as phpadmin, or mysql admin

5. If the re-write moudle for appach has not been turned on yet, you need to turn that on: See this post for more info: http://drupal.org/node/15365. Turn this on will enable drupal Clean URL feature

6. Very Important. After all these modification, restart apache server and mysql server

7. Go to the new site and run the install.php

Tuesday, January 08, 2008

Drupal: Clean URL setting

It happened to me last time when I have a fresh drupal instance install on my local machine, when I tried to enable "Clean URL" in the admin setting, it bing me back to the homepage. After digging the web for a while, I found that the cause of this is the setting in the apache httpd.conf file. Refer to: http://drupal.org/node/15365 for detail. Basically what we need to do is to enable the rewrite module. After enabled the module, restart the server, and it would work perfectly.

Friday, January 04, 2008

Drupal way :: A good article on Cache mechanism

An very helpful article on druapl cache mechanism that post from Lullabot:

Original article: click here

A beginner's guide to caching data

Building complicated, dynamic content in Drupal is easy, but it can come at a price. A lot of the stuff that makes a Web 2.0 site so cool can spell 'performance nightmare' under heavy load, thrashing the database to perform complex queries and expensive calculations every time a user looks at a node or loads a particular page.

One solution is to turn on page caching on Drupal's performance options administration page. That speeds things up for anonymous users by caching the output of each page, greatly reducing the number of DB queries needed when they hit the site. That doesn't help with logged in users, however: because page level caching is an all-or-nothing affair, it only works for the standardized, always-the-same view that anonymous users see when they arrive.

Eventually there comes a time when you have to dig in to your code, identify the database access hot spots, and add caching yourself. Fortunately, Drupal's built-in caching APIs and some simple guidelines can make that task easy.

The basics

The first rule of optimization and caching is this: never do something time consuming twice if you can hold onto the results and re-use them. Let's look at a simple example of that principle in action:

function my_module_function($reset = FALSE) {
static
$my_data;
if (!isset(
$my_data) || $reset) {
// Do your expensive calculations here, and populate $my_data
// with the correct stuff..
}
return
$my_data;
}
?>

The important part to look at in this function is the static variable named $my_data. Static variables start out empty the first time a function is called, but they keep the data they're populated with even when the function is called again. That means that we can check if the variable is already populated, and if so return it immediately without doing any more work.

This pattern appears all over the place in Drupal -- including key functions like node_load(). Calling node_load() for a particular node ID requires database hits the first time, but the resulting information is kept in a static variable for the duration of the page load. That way, displaying a node once in a list, a second time in a block, and a third time in a list of related links (for example) doesn't require three full trips to the database.

Another important feature is the use of the $reset variable. Caching is good, but occasionally you want to be sure you're getting the absolute freshest data available. Using a 'reset' variable in your function, and always performing the 'expensive' version of the function if it's set to TRUE, lets you bypass caching when you really need to.

Drupal's cache functions

You might notice that the static variable technique only stores data for the duration of a single page load. For even better performance, it's often possible to cache data in a more permanent fashion...

function my_module_function($reset = FALSE) {
static
$my_data;
if (!isset(
$my_data) || $reset) {
if (!
$reset && ($cache = cache_get('my_module_data')) && !empty($cache->data)) {
$my_data = unserialize($cache->data);
}
else {
// Do your expensive calculations here, and populate $my_data
// with the correct stuff..
cache_set('my_module_data', 'cache', serialize($my_data));
}
}
return
$my_data;
}
?>

This version of the function still uses the static variable, but it adds another layer: database caching. Drupal's APIs provide three key functions you'll need to be familiar with: cache_get(), cache_set(), and cache_clear_all(). Let's look at how they're used.

After the initial check of the static variable, this function checks Drupal's cache for data stored with a particular key. If it finds it, and the $cache->data element isn't empty, it unserializes the stored data and sticks it into the $my_data variable.

If no cached version is found (or if we called the function using the $reset parameter), the function does the actual work of generating the data. Then it serializes it, and save it TO the cache so future requests will find it. The key that you pass in as the first parameter can by anything you choose, though it's important to avoid colliding with any other modules' keys. Starting the key with the name of your module is always a good idea.

The end result? A slick little function that saves time whenever it can -- first checking for an in-memory copy of the data, then checking the cache, and finally calculating it from scratch if necessary. You'll see this pattern a lot if you dig into the guts of data-intensive Drupal modules.

Keeping up to date

What happens, though, if the data that you've cached becomes outdated and needs to be recalculated? By default, cached information stays around until some module explicitly calls the cache_clear_all() function, emptying out your record. If your data is updated sporadically, you might consider simply calling cache_clear_all('my_module_data', 'cache') each time you save the changes to it. If you're caching quite a few pieces of data (perhaps versions of a particular block for each role on the site), there's a third 'wildcard' parameter:

('my_module', 'cache', TRUE);
?>

This clears out all the cache values whose keys start with 'my_module'.

If you don't need your cached data to be perfectly up-to-the-second, but you want to keep it reasonably fresh, you can also pass in an expiration date to the cache_set() function. For example:

('my_module_data', 'cache', serialize($my_data), time() + 360);
?>

The final parameter is a unix timestamp value representing the 'expiration date' of the cache data. The easiest way to calculate it is to use the time() function, and add the data's desired lifetime in seconds. Expired entries will be automatically discarded as they pass that date.

Advanced caching

You might have noticed that cache_set()'s second parameter is 'cache' -- the name of the table that stores the default cache data. If you're storing large amounts of data in the cache, you can set up your own dedicated cache table and pass its name into the function. That will help keep your cache lookups speedy no matter what other modules are sticking into their own tables. The Views module uses that technique to maintain full control over when its cache data is cleared.

If you're really hoping to squeeze the most out of your server, Drupal also supports the use of alternative caching systems. By changing a single line in your site's settings.php file, you can point it to different implementations of the standard cache_set(), cache_get(), and cache_clear_all() functions. File-based caching, integration with the open source memcached project, and other approaches are all possible. As long as you've used the standard Drupal caching functions, your module's code won't have to be altered.

A few caveats

Like all good things, it's possible to overdo it with caching. Sometimes, it just doesn't make sense -- if you're looking up a single record from a table, saving the result to a database cache is silly. Using the Devel module is a good way to spot the functions where caching will pay off: it can log the queries that are used on your site and highlight the ones that are slow, or the ones that are repeated numerous times on each page.

Other times, the data you're using will just be a bad fit for the standard caching system. If you need to join cached data in SQL queries, for example, cache_set()'s practice of string data as a serialized string will be a problem. In those cases, you'll need to come up with a solution that's specific to your module. VotingAPI maintains one table full of individual votes and another table full of calculated results (averages, sums, etc.) for quick joining when sorting and filtering nodes.

Finally, it's important to remember that the cache is not long term storage! Since other modules can call cache_clear_all() and wipe it out, you should never put something into it if you can't recalculate it again using the original source data.

Go west, young Drupaler!

Congratulations: you now have a powerful set of tools to speed up your code! Go forth, and optimize.

Thursday, January 03, 2008

Drupal menu cache

There's an very annoying issue in drupal menu. Suppose you are writing your own module and register it with some menu paths. What if later on you want to change some of the path setting in your module, for example, changing access privilege of a form. I discovered that even I save all my modification, my drupal site still not getting anything changed.
After some diggings, the main cause of these problem is the menu_cache table, where it cache the meun path for fast access. Root cause, modifying the module menu path does not automatically update the menu_cache table. Action, clean all cache in the menu_cache table, the change gets reflected.

Note: Caching cause a lot of confusion when developing in drupal, getting an understanding of how caching mechanism work in drupal is necessary. Also, sometimes is useful to clean cache of your browser when testing.

Wednesday, January 02, 2008

drupal_set_message

Recently I found this is a very useful function to gain information of a drupal page. It could print out the info on top of the page.

For example, to get all the name of text area field, I can put the follow little code on:

function mythemename_tinymce_theme($init, $textarea_name, $theme_name, $is_running) {
drupal_set_message($textarea_name);
}