从邮件服务商取得用户通讯录的方法

我们在使用facebook开心网这些SNS网站的时候,里面有一项功能,就是通过邮件邀请好友,它可以导出你在Hotmail、Gmail、Yahoo、网易、新浪等Web Mail里的通讯录,然后给这些好友发送邀请信,这种病毒式营销推广方式起到了非常好的效果,facebook、开心网这些网站得以迅速壮大,这项功能也成了SNS网站的标配,从技术角度,我们就来探讨一下实现这项功能的原理和方法。

先说Gmail、Hotmail,Google和MS还是非常强大的,Google提供了Account Authentication API,它允许第三方的网站通过它的认证服务后,通过Google的Service取得用户的数据,包括通讯录等,MS也有Windows Live ID服务,不过我对微软的东西研究的不深,MSDN上找到的Windows Live ID SDK的资料,http://msdn.microsoft.com/en-us/library/bb404787.aspx

接下来说说其他邮件系统的取得方式,主要的原理就是通过模拟用户行为,登陆Web Mail系统,取得用户通讯录的信息,很多Web Mail都提供通讯录CSV格式的下载服务,我们取得这个CSV文件就可以了,网易的邮件系统似乎已经不提供CSV文件的下载,那只能通过通讯录页面的HTML分析,来取得信息,所以相对复杂一些,而Sohu的通讯录虽然前端采用了Ajax,但后端取得通讯返回的格式是Json,应该是最方便。

接下来说模拟用户行为,其实就是通过在自己服务器端向Web Mail发送相对的HTTP请求,而模拟出用户登陆的行为,在Linux下,我们用cURL这个组件,在编译PHP的时候把cURL编译进去,使PHP支持cURL,cURL非常好用,也非常强大,在libcurl里有大多数开发语言的支持,如果使用JAVA的话,还可以使用Apache的HttpClient

我们要模拟出用户登陆Web Mail的过程,我们就要对通常情况下,登陆Web Mail的HTTP请求过程有所了解,HttpWatch是一个非常好的工具,在做为插件安装倒IE和FireFox上,在IE或是FireFox里就可以看到所有的HTTP请求的信息了。

httpwatch

我们看看网易163的邮件的登陆过程

00:00:00.000    跳转提示
+ 0.000        0.231    1543    2352    POST    200    text/html; charset=UTF-8    http://reg.163.com/login.jsp?type=1&url=http://entry.mail.163.com/coremail/fcg/ntesdoor2?lightweight%3D1%26verifycookie%3D1%26language%3D-1%26style%3D35
0.231    1543    2352    1 request
00:00:00.462        0.177    0    0    GET    (History Cache)    image/x-icon    http://reg.163.com/favicon.ico
00:00:00.469    网易电子邮箱 – 简约3.0Beta
+ 0.000        0.118    1703    604    GET    302    Redirect to http://g4a30.mail.163.com/jy3/main.jsp?sid=gAJQIqzzbBwvsaVoDhzztmnXQvBRiMuz    http://entry.mail.163.com/coremail/fcg/ntesdoor2?lightweight=1&verifycookie=1&language=-1&style=35&username=xxx
+ 0.245        0.366    1664    6788    GET    200    text/html;charset=GBK    http://g4a30.mail.163.com/jy3/main.jsp?sid=gAJQIqzzbBwvsaVoDhzztmnXQvBRiMuz
+ 0.422        0.158    0    0    GET    (Cache)    text/css    http://mimg.126.net/p/jy3style/lib/0903090940/jscss/globle.css
+ 0.659        0.087    0    0    GET    (Cache)    application/x-javascript    http://mimg.126.net/p/jy3style/js/0903090940/tools.js
+ 0.816        0.067    0    0    GET    (Cache)    text/css    http://mimg.126.net/p/jy3style/lib/0903090940/cmcss/skin_blue.css
+ 0.998        0.578    1586    5521    GET    200    text/html;charset=GBK    http://g4a30.mail.163.com/jy3/top.jsp?sid=gAJQIqzzbBwvsaVoDhzztmnXQvBRiMuz
+ 1.015        0.624    1589    24844    GET    200    text/html;charset=GBK    http://g4a30.mail.163.com/jy3/folder.jsp?sid=gAJQIqzzbBwvsaVoDhzztmnXQvBRiMuz
+ 1.025        0.316    1590    10490    GET    200    text/html;charset=GBK    http://g4a30.mail.163.com/jy3/welcome.jsp?sid=gAJQIqzzbBwvsaVoDhzztmnXQvBRiMuz
+ 1.034        3.174    1592    2043    GET    200    text/html;charset=GBK    http://g4a30.mail.163.com/jy3/justfresh.jsp?sid=gAJQIqzzbBwvsaVoDhzztmnXQvBRiMuz
+ 1.280        0.439    0    0    GET    (Cache)    text/css    http://mimg.126.net/p/jy3style/lib/0903090940/jscss/globle.css
+ 1.632        0.407    0    0    GET    (Cache)    text/css    http://mimg.126.net/p/jy3style/lib/0903090940/jscss/globle.css
+ 1.647        0.432    0    0    GET    (Cache)    text/css    http://mimg.126.net/p/jy3style/lib/0903090940/jscss/welcome2.css
+ 1.876        0.235    0    0    GET    (Cache)    text/css    http://mimg.126.net/p/jy3style/lib/0903090940/jscss/globle.css
+ 2.179        0.117    0    0    GET    (Cache)    application/x-javascript    http://mimg.126.net/p/jy3style/js/0903090940/tools.js
+ 2.263        0.167    0    0    GET    (Cache)    application/x-javascript    http://mimg.126.net/p/jy3style/js/0903090940/tools.js
+ 2.354        0.207    0    0    GET    (Cache)    application/x-javascript    http://mimg.126.net/p/jy3style/js/0903090940/tools.js
+ 2.488        0.209    0    0    GET    (Cache)    text/css    http://mimg.126.net/p/jy3style/lib/0903090940/cmcss/skin_blue.css
+ 2.614        0.152    0    0    GET    (Cache)    text/css    http://mimg.126.net/p/jy3style/lib/0903090940/cmcss/skin_blue.css
+ 2.619        0.192    0    0    GET    (Cache)    application/x-javascript    http://mimg.126.net/p/jy3style/js/0903090940/welcome.js
+ 2.740        0.325    0    0    GET    (Cache)    text/css    http://mimg.126.net/p/jy3style/lib/0903090940/cmcss/skin_blue.css
4.208    9724    50290    20 requests
00:00:00.878        0.124    0    0    GET    (History Cache)    image/x-icon    http://www.163.com/favicon.ico
00:00:03.572    网易电子邮箱 – 简约3.0Beta
+ 0.000        0.541    0    0    GET    (Cache)    text/html; charset=GB2312    http://mimg.163.com/tianqi/city_simple/58367_090311.html
+ 0.531        0.715    1424    250    GET    304    text/css    http://mimg.163.com/jy3style/lib/jscss/ifr_weather2.css
+ 1.614        0.245    0    0    GET    (Cache)    image/gif    http://mimg.163.com/jy3style/lib/images/weather2.gif
1.859    1424    250    3 requests

首先,将用户名和密码POST到http://reg.163.com/login.jsp?type=1&url=http://entry.mail.163.com/coremail/fcg/ntesdoor2?lightweight%3D1%26verifycookie%3D1%26language%3D-1%26style%3D35,reg.163.com是网易通行证,后面的url是用户登陆网易通行证后要转向的地址,在这里我们看到就是http://entry.mail.163.com/coremail/fcg/ntesdoor2,这就是网易邮件的入口,在我们模拟登陆的时候,可以不传这个url过去,至于用户名和密码表单的name,看mail.163.com的HTML代码就知道了。相关错误处理,在POST到http://reg.163.com/login.jsp这个地址之后,返回的信息要取得的,因为如果用户输错了用户名或是密码,还是应该要提示用户的,而且在错误的情况下,也不用往下进行了,reg.163.com返回的错误页面里有“您的密码不正确”或是“用户名不正确”这样的信息,以此就可以判断用户是否成功登陆了。

之后我们要模拟用户访问http://entry.mail.163.com/coremail/fcg/ntesdoor2?lightweight=1&verifycookie=1&language=-1&style=35&username=xxx,就是登陆邮件的过程,注意,这里是个GET方法,用POST方法是不行的,访问entry.mail.163.com这个URL之后,会返回一个302码,就是要Redirect转向,到http://g4a30.mail.163.com/jy3/main.jsp?sid=gAJQIqzzbBwvsaVoDhzztmnXQvBRiMuz这个地址,这也就是大家看到的邮件登陆进去的首页了,注意这个sid要抓出来,应该是登陆的一个token,还有http://g4a30.mail.163.com这个地址,网易邮件是个集群,有非常多的服务器,你们每次上去的服务器是随随机的,用你的sid访问其他服务器也是没问题的,比如http://g1a98.mail.163.com/jy3/main.jsp?sid=gAJQIqzzbBwvsaVoDhzztmnXQvBRiMuz,所以这个服务器地址你可以写死。

解析来我们要看看网易邮件通讯录的URL,在UI看到是http://g4a30.mail.163.com/jy3/address/addrlist.jsp?sid=gAJQIqzzbBwvsaVoDhzztmnXQvBRiMuz&gid=all,我们模拟用户访问这个URL,然后抓取这个页面的内容HTML,分析一下,就可以了,在PHP里有个很好的HTML Parser工具PHP Simple HTML DOM Parser,可以像jQuery一样取得页面元素,这样就很方便的取得页面信息了。

其他一些Web Mail的登陆过程分析也是类似的,如果是取得CSV文件就更简单了,通过取到的通讯录内容,就可以在SNS网站上邀请了。

在这里我向国内这些大的门户网站或是Mail服务商提个建议,现在的互联网是一个开放化、平台化的趋势,网站应该开放自己的资源,可以让第三方的的应用更方便的访问,固步自封是不能发展的,试想如果QQ开放他的好友平台,引入第三方应用,那它将轻松超过Facebook,成为世界第一大SNS社区。

试用Nginx

Nginx是一款性能非常强劲的Web服务器,也可以用来做反向代理服务器,现在用Nginx做服务器站点越来越多了。

netcraft_chart_with_lighttpd

上图是Nginx和Lighttpd的主机数量比较

最近我试用了一下Nginx,做了一个Nginx+Tomcat的测试,具体步骤如下:

groupadd www
useradd -g www www

wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-7.8.tar.gz
wget http://sysoev.ru/nginx/nginx-0.7.39.tar.gz

tar zxvf pcre-7.8.tar.gz
cd pcre-7.8
./configure
make
make install
cd ..

tar zxvf nginx-0.7.39.tar.gz
cd nginx-0.7.39
./configure –user=www –group=www –prefix=/usr/local/nginx –with-http_stub_status_module –with-http_ssl_module
make
make install

cd /usr/local/nginx/conf/

我们编辑nginx.conf文件,内容如下

user  www www;
worker_processes  3;

error_log  logs/error.log  notice;

pid        logs/nginx.pid;

events {
use epoll;
worker_connections  1024;
}

http {
include       mime.types;
default_type  application/octet-stream;

include    /usr/local/nginx/conf/proxy.conf;

log_format  main  ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘”$status” $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘;

#access_log  logs/access.log  main;

sendfile        on;
tcp_nopush     on;

#keepalive_timeout  0;
keepalive_timeout  65;

#gzip  on;

server {
listen       80;
server_name  localhost;

#charset koi8-r;

access_log  logs/localhost.access.log  main;

#location / {
#    root   html;
#    index  index.html index.htm;
#}

location / {
proxy_pass http://localhost:8080;
}

#location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
#    expires      30d;
#}

#location ~ .*\.(js|css)?$ {
#   expires      1h;
#}

location /NginxStatus {
stub_status             on;
access_log              on;
auth_basic              “NginxStatus”;
}

#error_page  404              /404.html;

# redirect server error pages to the static page /50x.html
#
error_page   500 502 503 504  /50x.html;
location = /50x.html {
root   html;
}

}

}

同时我们要在/usr/local/nginx/conf下创建proxy.conf文件,内容如下

proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 32 4k;

保存之后,进入/usr/local/nginx/目录下,执行sbin/nginx,即可启动Nginx。

客户端浏览器输入http://ServerIP,可以看到Tomcat的欢迎页面,证明Ngnix已经转发HTTP请求给后端的Tomcat了,打开http://ServerIP/NginxStatus可以查看Nginx的状态,在Shell下我们还可以查看一下HTTP头

curl -I http://localhost
HTTP/1.1 200 OK
Server: nginx/0.7.39
Date: Thu, 05 Mar 2009 02:08:54 GMT
Content-Type: text/html;charset=ISO-8859-1
Connection: keep-alive
Content-Length: 8132

关于Nginx的配置,还是需要看它的文档http://wiki.nginx.org/Main,国内张宴的《Nginx 0.7.x + PHP 5.2.8(FastCGI)搭建胜过Apache十倍的Web服务器(第4版)[原创]》非常不错,可以参考。

追逐互联网的梦想

离第一次上网已有10年时间了,我想还没有一样东西像互联网一样,如此深刻的改变着我们的生活,互联网带给了我梦想,并在着10年中不懈的追逐着这个梦想。

1998-2000是一波互联网浪潮的年代,99年的时候我创建了自己的网站–“爱情工作室”。

2000年,郑州,之所以在郑州,是因为周爱民(如今中国软件响当当的人物)忽悠我来做AV95互联网方面的工作,互联网在中国那时也算是刚起步,专业杀毒和互联网结合的前途也是不可限量,当时就来了AV95公司的所在地郑州,当时和爱民住在一个屋子里,几乎是晚上工作,白天休息,不得不承认,爱民兄绝对是为软件而生的,当时已经把JavaScript搞的是如火纯清,Delphi、win32更是不在话下,让我顶礼膜拜,不过爱民兄忠实的很随M$,而我后来却选择了JAVA。

在AV95时间不长,北京的一家互联网公司就来收购“爱情工作室”,收购金额不高,并且收购之后我要继续为其工作,我想了想,这也算是一个机会,就离开了AV95,也算是开始了一段创业生活,我找来一个在网上认识的朋友–一叶飞(这家伙现在已经不知去向了),说服他和我一起做,他当时刚刚大学毕业,郑州也没什么好工作,他就和我一起开始开始了这番“事业”。

我们在友爱路租了一处房子,是顶楼,阳台正对着碧沙岗公园,很快就到了盛夏季节,中原的夏天是很热的,空气中没有一丝风,我们租的房子是两间,其中一间有空调,我们就把电脑放在这间,早上我们起来洗漱好,就坐到电脑面前了,一叶飞会打开音箱,播放MP3,我们的MP3里的歌有很多,伍佰、动力火车、唐朝、黑豹、王菲等等,歌曲从早放到晚也不会重复,我们便在音乐的伴随下开始了工作,网站开发、编辑、美工都是自己在做,中午和傍晚,我们两个就会忍受着酷暑出去吃饭,回到屋子里都是一身大汗,要在空调下猛吹,日子一天一天,很充实、也很快乐,当时并没有考虑过太多的盈利模式、网站的未来,只是为了自己的兴趣在做这些事情,当时我已经想到了将网站做成完全的社区模式,所有内容由网友发起,也曾经计划个人日记这些产品,现在看来不就是Web2.0、博客吗?

2001年随着第一波互联网泡沫的破灭,我也结束了和北京网站的合作,爱情工作室也终结了,一叶飞去了北京,由于我父母是上海人,所以我选择了上海,开始了软件、互联网的另一段生活,如今8、9年过去了,我仍然不能忘记那段日子,因为对于我,互联网的梦想从未停止过,我将永远做互联网的追梦人。

用jQuery Form Plugin实现Ajax无刷新的文件上传

在我以前的意识里,觉得用JavaScript或Ajax提交文件表单似乎是一件麻烦的事情,也没有太仔细的研究,后来看jQuery的时候,发现了jQuery Form Plugin这个插件,它方便的实现了Ajax方式的表单提交,例子里也包括了文件表单的提交,那我也来试一下吧,还是用Kohana(最近专注于这个,而且PHP开发要快多了,要是用Struts,要费好多功夫)。

要Kohana支持上传,先要配置一些upload的参数,把system\config\upload.php拷贝到application/config下,里面的参数做好设置,具体参考Kohana的文档吧,之后创建一个Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Myupload_Controller extends Top_Controller {
 
	public function index() {
		$view = new View ("upload");		
		$view->msg = "Upload File";
 
		$view->render ( TRUE );
	}
 
	public function upload() {		
		$filename = upload::save('myfile');
		echo $filename;
 
		exit ();
	}
 
}

Top_Controller为我自己创建的类,也继承自Kohana的Controller,之后创建upload.php的view文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<html>
<head>
<title><?php echo $msg;?></title>
<script type="text/javascript" src="<?=url::base()?>js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="<?=url::base()?>js/jquery.form.js"></script>
<script type="text/javascript"> 
        // wait for the DOM to be loaded 
        $(document).ready(function() { 
        	var options = { 
        		target:        '#fileinfo'   // target element(s) to be updated with server response         
        	};
 
        	$('#myForm').submit(function() { 
        		$(this).ajaxSubmit(options);
        		return false; 
        	});
 
        }); 
</script>
</head>
 
<body>
<h2><?php echo $msg;?></h2>
<form id="myForm" action="<?=url::base()?>myupload/upload" method="post"
	enctype="multipart/form-data">
	<input name="myfile" type="file" />
	<input type="submit" value="Submit Comment" />
</form>
<div id="fileinfo"></div>
</body>
</html>

在这里我们用jQuery Form Plugin来提交表单,之后将信显示在“fileinfo”这个div里,去试试效果吧。

http://malsup.com/jquery/form/里有详细的API和例子,同时http://malsup.com/jquery/里也有其他的一些不错的jQuery的插件。

Kohana的Events和Hooks研究

Kohana是一个使用PHP5的面向对象的MVC框架,是从CodeIgniter衍生出来,研究了几天,感觉还不错,就是它的文档实在太简陋了,在看到它的Events机制和Hooks机制时,确实有点不明白,文档上说的实在太简单了,后来我在Google上搜索了一下,找到两篇文章《Events and hooks in Kohana》《Practical Kohana Hooks example: PHPIDS》,上面讲了一下Kohana的Events和Hooks,并举了例子,我也开始慢慢理解了它的含义。

在Kohana的Events中,默认定义了很多的Events(例如system.ready、system.pre_controller等等),中文理解就是事件,也就是触发点,在程序在运行到某个位置时,会被触发,具体就是调用Event::run方法,我们在Kohana.php里可以看到在不同的位置执行了不同的Event::run方法,那么Hooks的意义在于当一个事件被触发之前,可以通过已加载的Hooks来修改事件的回调,有点绕口,说白了就是在事件发生之前,做点事情,举个例子,你安排了今天的日程,下午3点要开会,那么在3点开会就是一个Event(事件),那么到3点的时刻,你希望提醒你一下,你在你的手机里定了一个闹钟,在3点的时候会响,这就是一个Hook,可以看出Hook是基于Event的。

我们可以创建自己的Hook程序,并加载如默认的Events里,但是默认的Events不一定能满足我们的需要,比如我们在Web应用中经常使用的权限校验,判断这个用户是否登陆过,我们虽然可以使用默认Events里的system.pre_controller,但是这个Event是针对所有的Controller的,有些Controller是不需要校验用户的,还好Kohana允许自己定义Event,下面我们还是举例说明吧。

要使用Hooks,首先要在application/config/config.php里将$config[‘enable_hooks’]置为TRUE。

之后我们定义自己的Event,我们在application/controllers目录下建立base.php,代码如下:

1
2
3
4
5
6
7
class Base_Controller extends Controller  {
 
	public function __construct() {
		parent::__construct();
		Event::run("base.construct");
	}	
}

我们继承了Kohana的Controller,在构造函数里定义了Event,名字叫“base.construct”,以后我们的Controller都继承自Base_Controller,那么在对象创建的时候都会触发base.construct事件。

Hook的文件放在application/hooks下,我们就创建一个hook文件sessioncheck.php,代码如下:

1
2
3
4
5
6
7
8
9
class SessionCheck {
 
	public function check() {
		echo "check session ...";
	}
 
}
 
Event::add('base.construct', array('SessionCheck','check'));

我们将SessionCheck的check方法加载到了base.construct事件上,也就是在触发base.construct事件之前,会执行SessionCheck的check方法。

接下来我们写一个Controller,在application/controllers目录下建立first.php,代码如下:

1
2
3
4
5
6
7
class First_Controller extends Base_Controller  {
 
	public function index() {
		echo "First - index";
		exit();
	}
}

我们执行一下看看会有什么提示,http://localhost/kohana/first,显示

check session …First – index

没问题了,在Controller构造时,执行了Hook里的方法。

从JavaEye上找的Google翻译JavaScript脚本

在Blog或新闻发布的时候,我们希望URL是一段有意义的字串,例如我Blog里的《Linux下切分Tomcat的catalina.out日志文件》文章链接是https://i.laoer.com/2009/02/18/rotating-catalina-out-in-tomcat-using-cronolog/,这样有利于SEO(搜索引擎优化),对于我们母语为中文的小虾,有时候要翻译标题还是有点头疼的,还好有了Google翻译,让翻译的事情变得简单了一点,但对于开发者,怎么使用户也方便的翻译,特别是在写Blog的时候就能把标题翻译好,还要动点脑筋,我看到JavaEye里发布新闻的地方有个“让Google帮助生成永久链接”的功能挺好的,看了一下他们的源码,得到以下这段,顺别也解释一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script type="text/javascript" src="http://www.google.com/jsapi"></script> //载入Google的jsapi
 
<script type="text/javascript">  
 
  function slugify(str) { //这个方法应该是将字符转为小写,并把一些特殊字符转为"-"
    return str.toLowerCase().replace(/[^a-z0-9-_]+/g, '-').replace(/^-|-$/g, '');
  }
 
  google.load("language", "1"); //载入Google的language Ajax库
 
  function translate_title() { //这里就是翻译文章标题了,里面的方法需要jQuery支持,之前要引入jQuery的包,这里就省略了
    if($F("news_title").blank()) {
      alert("请先填写标题");
      return;
    }
    $("news_slug_url").value = "正在翻译中...";
    google.language.translate($F("news_title"), "zh", "en", function(result) {
      if (!result.error) {
        $("news_slug_url").value = slugify(result.translation);
      }
    });
  }  
</script>

这里有个地方要说一下,Google的Ajax库API还是挺好的,可以load几种Ajax的库,另外Google的Web 工具包也可以看看。

修改Oracle连接数

在SQL/PLUS下,先检查一下当前连接数
show parameter process;
show parameter session;

修改命令,根据自己实际情况修改数值
alter system set processes=300 scope = spfile;
alter system set sessions=350 scope = spfile;

之后重启Oracle

Linux下切分Tomcat的catalina.out日志文件

随着Tomcat的运行,catalina.out文件会越来越大,虽然Tomcat每日会生成一个catalina.ymd.log的文件,但catalina.out主文件仍然不断增加,需要对catalina.out按日切分才好,在网上找了一下,看到一篇《rotating catalina.out in tomcat 5.5 using cronolog》,就用公司的Tomcat配置一下。

cronolog工具已经在服务器上装过,一个对日志切分的小工具,其主页在http://cronolog.org/,我们也用它来切分Apache的日志。

进入Tomcat的bin目录,打开catalina.sh文件,找到tomcat启动的相关行,或者你直接查找catalina.out,一般我们修改下面行中的内容(因为我们一般不会在-security条件下运行),

1
2
3
4
5
6
7
8
9
10
11
12
13
    else$_RUNJAVA$JAVA_OPTS $CATALINA_OPTS \
    -Djava.endorsed.dirs=”$JAVA_ENDORSED_DIRS-classpath$CLASSPATH” \
    -Dcatalina.base=”$CATALINA_BASE” \
    -Dcatalina.home=”$CATALINA_HOME” \
    -Djava.io.tmpdir=”$CATALINA_TMPDIR” \
    org.apache.catalina.startup.Bootstrap “$@” start  \
    >>$CATALINA_BASE/logs/catalina.out 2>&1 &
 
    if [ ! -z "$CATALINA_PID" ]; then
    echo $! > $CATALINA_PID
    fi
    fi

修改
org.apache.catalina.startup.Bootstrap “$@” start  \
>> “$CATALINA_BASE”/logs/catalina.out 2>&1 &

org.apache.catalina.startup.Bootstrap “$@” start 2>&1 \
| /usr/local/sbin/cronolog “$CATALINA_BASE”/logs/catalina.%Y-%m-%d.out >> /dev/null &
同时,上面有一行
touch “$CATALINA_BASE”/logs/catalina.out
可以注释掉,完成之后重起Tomcat就可以了,在logs目录下可以看到catalina.2009-02-18.out的日志,是按日生成的。

Mysql的一些常用命令

自定义Mysql启动命令

/usr/local/mysql/bin/mysqld –defaults-extra-file=/usr/local/mysql/my.cnf –basedir=/usr/local/mysql –datadir=/usr/local/mysql/data –user=mysql –log-error=/usr/local/mysql/data/localhost.localdomain.err –pid-file=/usr/local/mysql/data/localhost.localdomain.pid –socket=/tmp/mysql.sock –port=3306

通过定义里面的参数,可以在一个机子上启动多个Mysql实例在不同的端口

CREATE USER ‘username’@’%’ IDENTIFIED BY ‘password’;
创建用户,%代表可以来自任何主机,如果是本机,可以写localhost

GRANT ALL PRIVILEGES ON * . * TO ‘username’@’%’ IDENTIFIED BY ‘password’ WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0
给用户赋所有权限,也可以根据需要,赋特定的权限

导出一个库
mysql/bin/mysqldump -u user -p password dbname > /full/path/dbname.sql

导入一个库
mysql -u user -p password –default-character-set=utf8 dbname < /full/path/dbname.sql --default-character-set是指定数据库编码

Redhat Linux下src rpm的安装方法

方法一:
1. 执行rpm -i your-package.src.rpm
2. cd /usr/src/redhat/SPECS
3. rpmbuild -bp your-package.specs 一个和你的软件包同名的specs文件
4. cd /usr/src/redhat/BUILD/your-package/ 一个和你的软件包同名的目录
5. ./configure 这一步和编译普通的源码软件一样,可以加上参数
6. make
7. make install

方法二:
1. 执行rpm -i you-package.src.rpm
2. cd /usr/src/redhat/SPECS (前两步和方法一相同)
3. rpmbuild -bb your-package.specs 一个和你的软件包同名的specs文件

这时,在/usr/src/redhat/RPM/i386/ (根据具体包的不同,也可能是i686,noarch等等) 在这个目录下,有一个新的rpm包,这个是编译好的二进制文件。执行:

rpm -i new-package.rpm即可安装完成。