长格式命令行参数解析类

下面是一个摘自php手册的一个长格式的命令行参数解析类,感觉实现的思想还不错:

<?php
/**********************************************
 * Simple argv[] parser for CLI scripts
 * Diego Mendes Rodrigues – So Paulo – Brazil
 * diego.m.rodrigues [at] gmail [dot] com
 * May/2005
 **********************************************/

class ArgParser{
    var 
$argc
;
    var 
$argv
;
    var 
$parsed
;
    var 
$force_this
;

    function ArgParser($force_this="") {
        global 
$argc$argv
;
        
$this->argc $argc
;
        
$this->argv $argv
;
        
$this->parsed 
= array();

        array_push($this->parsed,
            array(
$this->argv[0
]) );

        if ( !empty($force_this) )
            if ( 
is_array($force_this
) )
                
$this->force_this $force_this
;

        //Sending parameters to $parsed
        
if ( $this->argc 
) {
            for(
$i=$i$this->argc $i
++) {
                
//We only have passed -xxxx
                
if ( substr($this->argv[$i],0,1) == "-" 
) {
                    
//Se temos -xxxx xxxx
                    
if ( $this->argc > ($i+1
) ) {
                        if ( 
substr($this->argv[$i+1],0,1) != "-" 
) {
                            
array_push($this->parsed
,
                                array(
$this->argv[$i
],
                                
$this->argv[$i+1
]) );
                            
$i
++;
                            continue;
                        }
                    }
                }
                
//We have passed -xxxxx1 xxxxx2
                
array_push($this->parsed
,
                    array(
$this->argv[$i
]) );
            }
        }

        //Testing if all necessary parameters have been passed
        
$this->force
();
    }

    //Testing if one parameter have benn passed
    
function passed($argumento
) {
        for(
$i=$i$this->argc $i
++) 
            if ( 
$this->parsed[$i][0] == $argumento 
)
                return 
$i
;
        return 
0
;
    }

    //Testing if you have passed a estra argument, -xxxx1 xxxxx2
    
function full_passed($argumento
) {
        
$findArg $this->passed($argumento
);
        if ( 
$findArg 
)
            if ( 
count($this->parsed[$findArg] ) > 

                return 
$findArg
;
        return 
0
;
    }

    //Returns  xxxxx2 at a " -xxxx1 xxxxx2" call
    
function get_full_passed($argumento
) {
        
$findArg $this->full_passed($argumento
);

        if ( $findArg )
            return 
$this->parsed[$findArg][1
];

        return;
    }

    //Necessary parameters to script
    
function force
() {
        if ( 
is_array$this->force_this 
) ) {
            for(
$i=$icount($this->force_this) ; $i
++) {
                if ( 
$this->force_this[$i][1] == 
"SIMPLE" 
                    
&& !$this->passed($this->force_this[$i][0
])
                )
                die(
"nnMissing " $this->force_this[$i][0] . "nn"
);

                if ( $this->force_this[$i][1] == "FULL"
                    
&& !$this->full_passed($this->force_this[$i][0
]) 
                )
                die(
"nnMissing " $this->force_this[$i][0] ." <arg>nn"
);
            }
        }
    }
}

//Example
$forcar 
= array(
    array(
"-name""FULL"
),
    array(
"-email","SIMPLE"
) );

$parser = new ArgParser($forcar);

if ( $parser->passed("-show") ) 
    echo 
"nGoing…:"
;

echo "nName: " $parser->get_full_passed("-name");

if ( $parser->full_passed("-email") )  
    echo 
"nEmail: " $parser->get_full_passed("-email"
);
else
    echo 
"nEmail: default"
;

if ( $parser->full_passed("-copy") )
    echo 
"nCopy To: " $parser->get_full_passed("-copy"
);

echo "nn";

?>

httpwatch 与 gzip

    我非常喜欢使用httpwatch来查看客户端与服务器之间的交互,我一贯是看httpwatch里面的stream选项,因为这样看到的都是最原始的请求和相应数据,但是有一天我的这种做法受到的挑战,因为服务器的响应时作了gzip压缩的,这样不能很直观地看到响应的内容,怎么办呢?

目前这里有三个办法,当然肯定还有其他办法。

办法1.  自己做一个小工具来解压压缩的数据

        该办法比较麻烦,而且不够通用,我根本没有尝试过这种办法。

办法2.  httpwatch看到的请求的数据复制到文本文件里,然后将accept请求头去掉,打开cmd,使用telnet来访问

        该办法比上一种办法稍微好一点,比较简单易行,但是缺点有二:

        一、对于不允许重放的请求无效

        二、对于https的请求无效

           其实,对于https的请求,可以借助openssl来完成,命令:

           openssl s_client -connect host:port 

          然后就像用telnet那样输入明文就可以了

办法3.  使用curl自己构造请求串

        该办法可以避免办法二里面的第二个缺点,即:对于走https的请求也可以搞定;但是要求你机器上有curl命令,而且操作也比较麻烦

办法4.  使用firefox,通过如下配置可以使得返回的数据不压缩,这个利用了http协议的知识

         一、在firefox地址栏里输入:   about:config

        二、查找network.http.accept-encoding  清空即可

什么是缘分 — 百度知道

“缘分”本应该是一个富有喜剧色彩的词,但是不知道从何时起,“缘分”一词总让人觉得伤感。至少在我的感觉中,“缘分”基本只剩下了“缘”,而基本没有了“分”;于是,谈起“缘分”似乎并不是幸福,而更像是“痛苦”。

走在一起是缘分,一起在走是幸福。

虽然我不是因为你而来到这个世界,但是却因为你而更加眷恋这个世界。

缘分很自然地到来,有很无情地离开;昨日的欢乐变成了今日的失落;尽管无情,却也无奈。

若你流泪,湿的总是我的脸;
若你伤悲,苦的总是我的心;
不认识你多少,也无痛苦,也无烦恼;
认识你更好,宁可痛苦,宁可烦恼。

有一种感觉,总在难眠时才承认是相思;
有一种缘分,总在梦醒后才相信是永恒;
有一种心情,总在离别后才明白是失落;
有一种目光,总在分手后才相信是眷恋。

百度知道–缘分

什么是缘分啊
 缘分 什么人都在说缘分 可是什么是缘分啊 缘分是一种莫名其妙的感觉 是一种命中注定的情景 是某些人一直在追求的目标 大学生总在谈缘分 有些人一见面就说缘分啊 就我个人而言我真的不相信什么缘分 我只相信当你看到你喜欢的女孩或者机遇 你一定要抓住 一定不要让它错过 不努力的话 你一辈子都不会有机会 更不必说什么缘分 当你成功以后在笑谈人生时 你也许会说出这两个字 让我们为了缘分而努力 为了今生的夙愿而努力 其实这世界上本没有路走的人多了也便成了路 随缘赋

 爱愈浓,伤愈深。

 此情非绕梁三日之期,

 亦无海誓山盟之约。

 试问人世间情为何物?

 此情像雾.像雨.又像风。

 聚亦缘,散亦缘。

 一切随缘尽相怡!

 后记:此诗为一日语文课讲至林黛玉进贾府由感而发,联想至自己拿得起放不下,为情所困,为情所伤,急书于此。谨此对情感之中受伤之人表示同情,同为天涯沦落人,相逢何必曾相识!
 

 缘分是前世感情的延续,
 缘分是今世的擦肩而过。
 缘分是前世不变的誓言,
 缘分是今生痛苦的约定。
 缘分是一次机遇的把握,
 缘分是一种爱慕的流逝。
 缘分是相遇时美好梦想,
 缘分是别离后苦涩回忆。

 

 

人与人之间能够相遇相知,或是相亲相爱,是必然,也是偶然。正象张爱玲在她的文字中所描写的那样:“于千百人中,遇到你所要遇到的人,于千百年中,在时间的无垠的荒野中,有两个人,没有早一步,也没有晚一步,就这样相逢了,也没有什么可说的,只有轻轻地道一声:哦,你也在这里吗?”在茫茫人海中,冥冥之中总有一个人在未知的地方等你到来,而你来到这个世间也只是为了遇见他,与他牵手,成就一世情缘,这就是缘分。

缘分是个抽象的概念,它摸不着,看不见,猜不透。很多的机缘巧合是无法说清楚的。你也许在无意中遇见了某人,在无缘无故中会心系某人,毫无原由地牵挂他(她),说不清、道不明地心中引起无尽的相思。这一切的不经意,却让人感觉到冥冥中确实有一股力量存在,心不信缘,身却深深陷落在情缘之中不能自拔。

 缘本天定,强求无用。缘起、缘灭、缘聚、缘散都是没有理由,没有原因的。命运的多变让我们无所适从。人世际间的缘分,是在生活中邂逅,又在生活中流失。有些人曾经与你心心相印,也曾经相携相扶,后来随着空间的阻隔和时间的流逝,那缘分也就由浓而淡,由淡而终至于无了。很多的情缘是不随人愿。不是每个人都拥有缘,也不是每一个寻觅的人都可以抓住缘。人世际间的分分合合,在生活中演绎出的许多恩恩怨怨,有缘无分,源头水尾难以相见;有情无缘,行色匆匆远隔天涯;这都是很痛苦的事。可人生就有着太多的不可知,一个念头,一次决定,往往便可能拥有或错过一份缘。选择了爱是因为缘,而选择了不爱却也是为了缘,生命如此,生活亦如此。“悄悄的我走了/正如我悄悄的来/挥一挥衣袖/不带走一片彩云…..”世间事不是每段缘都能成真,不是每个美丽的开始都有美丽丰满的结局。这既无道理可言,也无结局可言,所以人生就有了那么多的痛与悲,苦与伤。

缘分在风雨中会生锈,誓言会因冷漠而退却,只有那曾经写在掌心的爱却深深铭刻在心灵上,伴着你远走走天涯海角……。缘分很自然的来,也很无情的去。当往昔的繁华落尽,带着一身的疲惫与憔悴回头首,往日欢乐变冷漠是无情也无奈,在患得患失之间找寻旧时残存的点点记忆,奢望着或许能够淡忘一切一切的烦恼……。尘缘如梦,几翻起浮总不平,到如今都成烟雨……,情也成空,宛如回首袖底风,飘在深深旧梦中……。

人生无不散之筵席,当尘缘因为现实的种种原因散尽时,我们不能够用对与错来衡量它的行为,就如一朵花该凋谢它就会凋谢。一片叶该飘落它就飘落。没有什么人能阻止,也没有什么力量能阻挡。一个人该走他就会走,一段情该断它就会断。没有什么人能挽留,也没有什么力量能改变。世间的万事万物,一切因缘而定, 缘来则聚,缘尽则散。也许正因为有缘相伴,我们感情的星空里,才有了永结同心的誓言,才有了天涯共比翼的浪漫。也因为缘的散却,才繁衍出人际间的悲欢离合,使我们更懂得呵护人生。

 人生在世,随缘而安。缘来不拒,缘去不哀。在拥有的时候,不需许下誓言,也不必要求承诺。学会用心去领会,感悟。好好珍惜,珍惜人间的温情,人与人的和谐相处,广结善缘,共同收获人情的美好。 在失去的时候我们不必强求,也不必苦苦挽留,因为情缘散尽,感情注定难以为继时刻意追求的往往没结果,为什么不选择有尊严的结束。亦如杏林子说的那样:曾经相遇,曾经相拥,曾经在彼此生命中光照,即使无缘也无憾。将故事珍藏在记忆的深处,让伤痛慢慢地愈合。让自己知道心灵之约曾经那么深刻地存在过。当明月西倾阳光初洒的时候,再次用真的自己去面对,去珍惜每一秒生命,每一段缘份。

 做你想做的梦,做你想要做的事,去你想要去的地方,成为你想要成为的人,因为你只有一次生命来满足你的要求。祝福你有无限的快乐使你的生活甜美,无数的尝试磨练你变的坚强,无尽的痛苦使你称的上一个真正的人,万贯的钱财,以给我买一个礼物。永远设身处地的为他人着想,当你受伤的时候,别人的心或许也在痛。一句无心的话可能引起一场争斗,一句残酷的话可能会毁坏一个人的生活,一句及时的话可能会平复波浪,一句充满爱心的话可能会治逾别人的伤口。

 爱的真谛,是让你爱的人完全的做他自己,而不是让他成为你理想的人,否则,你爱的只是你在他身上找到的你的影子。最快乐的人不是最完美的人,他们只是充分的利用了他们所能握在手中的。哭过的人,受过伤的人,追求过的人,尝试过的人,充满感激的人,才是真正懂得快乐的人。
 爱从一个微笑开始,在热吻中得以延伸,却随眼泪逝去。但我还是要说:“请相信爱情,渴望爱情,等待属于自己的那份爱情。”

 不要因为也许会改变,就不肯说出那句美丽的誓言;不要因为也许会分离,就不敢求一次倾心的相遇
 生命中最悲哀的事莫过于放弃追逐你所爱的人,看着他远离。他对于你的重要并不能使他回馈给你什么。无论你追逐多久,你还是要让他走。

 人生其实有太多的偶遇,缘份往往就潜藏其中。只是有人回避它、怀疑它,不愿相信缘份的到来,而让它一次一次地错过。如果心为之所动,就应该去正视它。或许,那会成为一瞬间的永恒,成为一生中最美丽的一页。
 我的朋友,好好把握生命中每一份光照吧!

 

原文链接:http://zhidao.baidu.com/question/17145277.html

 

相关文章

走在一起是缘分: http://www.360doc.com/content/090527/09/77484_3668212.html

 

PHP mc-client 自动重连的奥秘

我们知道memcache的PHP客户端在连接mc后,如果中间memcached宕掉了,你们重启之后,mc-client会自动连接到server的,这是如何做到的呢?

先写一个test脚本:

<?php
$mc
= new Memcache
();
$mc->connect("10.10.10.10",11211
);

while(1){
$ret = $mc->set("a","a"
);
if(
$ret
) {
echo
"okn"
;
} else {
echo
"failn"
;
}
sleep(1
);
}

?>

启动脚本后,先宕掉memcached,再启动memcached:

                                   间隔时间
第一次失败的时间: 1240491343.709920
第一次重连:      1240491358.751046 15s
第二次重连:      1240491373.790693 15s
第三次重连:      1240491388.829329 15s
第四次重连:      1240491403.869810 15s

结论: mc client 失败后,如果没有主动重连,在15s后再使用该连接,将尝试重连,在15s内根本就不做尝试重连的动作,即使服务器15s内
又恢复正常服务,mc client也是不知道的

——————————————-

关于pconnect的研究:

先写一个test脚本:

<?php
$mc
= new Memcache();
while(
1){
$mc->pconnect("10.55.38.18",11211);
$ret = $mc->set("a","a");
if(
$ret) {
echo
"okn";
} else {
echo
"failn";
}
sleep(1);
}
?>

1. 虽然pconnect是针对apache类程序开发的,但是命令行程序里有相同的效果
2. 虽然$mc->pconnect("10.55.38.18",11211);是写在了循环里面,但是通过tcpdump发现,并没有每次都重连mc
3. 虽然好像每次都重连,其实都还是完全有connect里的机制来控制了,就是说循环里面的pconnect与写到循环外面没有任何的区别
4. 如果把里面的pconnect 换成connect,则效果就和我们想象的一样了,这样,不管服务器端是否有异常,每次都是真正的连接

程序在$mc->pconnect("10.55.38.18",11211);时报的两种错误:
第一种:Warning: Memcache::pconnect(): Can’t connect to 10.55.38.18:11211, Unknown error (0) in /usr/home/junjie2/testmc.php on line 4

第二种:PHP Warning:  Memcache::pconnect(): Can’t connect to 10.55.38.18:11211, Connection refused (111) in /usr/home/junjie2/testmc.php on line 4

前者是因为并没有真正去连接,只是发现连接不可用(已关闭)就直接返回错误了
后者是第一次失败的15s之后,就尝试做一次真正的重新连接,因为这是memcached还没有重启,就返回了 Connection refused,这样下次pconnect,又接着返回第一种错误,直到又过15s

php的memcahce-2.2.4 中文件 php_memcache.h 中有如下定义

#define MMC_DEFAULT_RETRY 15                             /* retry failed server after x seconds */

即:  15s内是不做真正的连接的。

注意: memcache客户端默认设置的超时时间为1s, 极容易超时的,所以你要知道,当超时后,客户端会主动关闭连接的,因为它以为服务器down了,然后就是15s内的操作统统返回失败。

如何避免这种问题呢?

办法一: 在第一个测试脚本中,使用了connect,而不是pconnect, 连接操作是在循环体外的;如果connect(注意不是pconnect)发生在循环体内就能及时发现连接已有效了,就不需要等待15s了,当然,这样的话,每次都是真实的重新连接了,而且特别需要注意的是,如果这样的话,close()操作也一定要写在循环体里面,否则你将创建n多连接,知道不允许你在连接了。

办法二: 使用addServer的方式: bool Memcache::addServer     ( string $host    [, int $port = 11211    [, bool $persistent    [, int $weight    [, int $timeout    [, int $retry_interval    [, bool $status    [, callback $failure_callback    [, int $timeoutms   ]]]]]]]] )

    将$retry_interva 设置为0,这样就每次都重新连接了。


关于http 压力测试工具

1. ab 、 webbench 、http_load的特点
这些测试工具都是单进程、非线程的程序,它的并发是通过异步实现的,虽然也实现的并发,就是说,同时确实存在着n个并发,但是需要注意的是,对于一个非常简单的接口来讲,客户端要做的事情和服务器端要做的事情差不太多;这时,一个单进程的程序去压一个多进程的程序,显然客户端可能一直忙于发请求,接受响应,而服务器端却很清闲,甚至n/3个httpd子进程就可以搞定n个并发了,这就是为什么n个并发,而服务器端的httpd子进程数却远小于n的可能的原因之一。

2. siege
siege 是一个单进程多线程的程序,只是测试结果数据太少,不太能说明问题

3. 尽管如此,我们还是可以用ab做多进程的并发的,如下:

for i in seq 1 50;do  nohup /data1/apache/bin/ab -n 10000 -c 1 "http://10.20.30.40/test.php" >ab.$i.txt &;done

这就是一个并发50,总数50万的ab压力测试

关于keep-alive

你的服务器是否打开了keep-alive 呢?看看httpd.conf 就知道了,但是也不是必须的,简单测试一下就知道了,用第三个请求比较稳妥一些,看看下面的几个请求,顺便理解一下HTTP/1.0  与 HTTP/1.1 的几个区别:

请求1:
———————————-
GET / HTTP/1.1
Host: phpor.net

返回结果的编码格式:Transfer-Encoding: chunked
没有立即关闭连接,说明:HTTP/1.1 默认支持(启用)keep-alive

———————————-

请求2:
———————————-
GET / HTTP/1.0
Host: pengyou.sina.com.cn
Connection: Keep-Alive

返回结果的编码格式:Content-Length: 5556       说明: HTTP/1.0 还不支持Transfer-Encoding: chunked的传输编码方式
没有立即关闭连接,说明:HTTP/1.0 也可以使用 keep-alive
———————————-

请求3:
———————————-
GET / HTTP/1.1
Host: phpor.net
Connection: Keep-Alive

这个就肯定keep-alive了
———————————-

请求4:
———————————-
GET / HTTP/1.0
Host: phpor.net

这个请求就;
1. 不能Transfer-Encoding: chunked
2. 不能keep-alive
———————————-

结论:
要了解某个server是否打开了keep-alive ,只需用telnet发一个类似于前三种的请求,看看是否立即关闭了就行了

全组合 之 PHP实现

<?php
$arr
= array(
array(
‘A1’,‘A2’
),
array(
‘B1’,‘B2’
),
array(
‘C1’,‘C2’
)
);

print_r(zuhe($arr,false));
// or
zuhe($arr,true
);

/**
* @param: $arr: array for deal
* @param: $echo: print at end or not
*/
function zuhe($arr, $echo = true
) {
$len = count($arr
);
if (
$len == 0
) return array();
if (
$len == 1
) {
if (
$echo
) {
foreach(
$arr[0] as $val
) {
echo
$val ."\n"
;
}
} else {
return
$arr[0
];
}
exit();
}
$tmparr
= array();
foreach(
$arr[0] as $val0
) {
foreach(
$arr[1] as $val1
) {
$tmparr[] = $val0 ."\t". $val1
;
}
}
array_shift($arr
);
array_shift($arr
);
array_unshift($arr, $tmparr
);
return
zuhe($arr, $echo
);
}
/**
* result:
* A1 B1 C1
* A1 B1 C2
* A1 B2 C1
* A1 B2 C2
* A2 B1 C1
* ….
* A2 B2 C2
*/
?>

实现2:

<?php

$arr = array(
    
‘gateway’=>array(‘set’,‘noset’
),
    
‘returntype’=>array(‘META’,‘TEXT’,‘TEXT2’
),
    
‘url’=>array(‘login.php’,‘set&not_login.php’,‘noset’
),
    
‘st’=>array(‘ok’,‘err’,‘no’
)
);

echo implode("\t\t\t\t",array_keys($arr))."\n"."\n";
//print_r(zuhe($arr,false));
// or
zuhe($arr,true, –20
);

/**
 * @param: $arr: array for deal
 * @param: $echo: print at end or not
 */
function zuhe($arr$echo true$width "\t"
) {
    
$len count($arr
);
    if (
$len == 
) return array();
    if (
$len == 1
) {
        if (
$echo
) {
            foreach( 
$arr[0] as $val
) {
                echo 
$val ."\n"
;
            }
        } else {
            return 
$arr[0
];
        }
        exit();
    }
    
$tmparr 
= array();
    
$arr0 array_shift($arr
);
    
$arr1 array_shift($arr
);
    foreach(
$arr0 as $val0
) {
        foreach(
$arr1 as $val1
) {
            if (
$width == "auto"
) {
                
// 希望能自动调整列宽,为实现
            
}else if ($width == "\t"
) {
                
$tmparr[] = $val0 ."\t"$val1
;
            } else {
                
$tmparr[] = sprintf("%${width}s",$val0) .sprintf("%${width}s",$val1
);
            }
        }
    }

    array_unshift($arr$tmparr);
    return 
zuhe($arr$echo$width
);
}
/**
 * result:
 * A1    B1    C1
 * A1     B1  C2
 * A1   B2  C1
 * A1   B2  C2
 * A2   B1  C1
 * ….
 * A2   B2  C2
 */

?>

利用openssl创建一个简单的CA

本文旨在利用开源openssl软件,在Linux(或UNIX/Cygwin)下创建一个简单的CA。我们可以利用这个CA进行PKI、数字证书相关的测试。比如,在测试用Tomcat或Apache构建HTTPS双向认证时,我们可以利用自己建立的测试CA来为服务器端颁发服务器数字证书,为客户端(浏览器)生成文件形式的数字证书(可以同时利用openssl生成客户端私钥)。

该简单的CA将建立在用户自己的目录下($HOME/testca),无需超级用户(root)权限。

一. 创建CA
1. 创建CA需要用到的目录和文件:
执行命令如下:
mkdir "$HOME/testca"
cd "$HOME/testca"
mkdir newcerts private conf
chmod g-rwx,o-rwx private
echo "01" > serial
touch index.txt

说明:
$HOME/testca为待建CA的主目录。其中newcerts子目录将存放CA签署(颁发)过的数字证书(证书备份目录)。而private目录用于存放CA的私钥。目录conf只是用于存放一些简化参数用的配置文件。

文件serial和index.txt分别用于存放下一个证书的序列号和证书信息数据库。
当然,偷懒起见,可以只用按照本文操作即可,不一定需要关心各个目录和文件的作用。

2. 生成CA的私钥和自签名证书(即根证书)
创建文件:
vi "$HOME/testca/conf/gentestca.conf"
文件内容如下:
####################################
[ req ]
default_keyfile = $ENV::HOME/testca/private/cakey.pem
default_md = md5
prompt = no
distinguished_name = ca_distinguished_name
x509_extensions = ca_extensions

[ ca_distinguished_name ]
organizationName = TestOrg
organizationalUnitName = TestDepartment
commonName = TestCA
emailAddress = ca_admin@testorg.com

[ ca_extensions ]
basicConstraints = CA:true
########################################

然后执行命令如下:
cd "$HOME/testca"
openssl req -x509 -newkey rsa:2048 -out cacert.pem -outform PEM -days 2190 -config "$HOME/testca/conf/gentestca.conf"
执行过程中需要输入CA私钥的保护密码,假设我们输入密码: 888888

可以用如下命令查看一下CA自己证书的内容
openssl x509 -in cacert.pem -text -noout

3. 创建一个配置文件,以便后续CA日常操作中使用:
vi "$HOME/testca/conf/testca.conf"
文件内容如下:
####################################
[ ca ]
default_ca = testca # The default ca section

[ testca ]
dir = $ENV::HOME/testca # top dir
database = $dir/index.txt # index file.
new_certs_dir = $dir/newcerts # new certs dir

certificate = $dir/cacert.pem # The CA cert
serial = $dir/serial # serial no file
private_key = $dir/private/cakey.pem # CA private key
RANDFILE = $dir/private/.rand # random number file

default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = md5 # message digest method to use
unique_subject = no # Set to ‘no’ to allow creation of
# several ctificates with same subject.
policy = policy_any # default policy

[ policy_any ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

########################################

二. CA的日常操作
1. 根据证书申请请求签发证书
假设收到一个证书请求文件名为req.pem,文件格式应该是PKCS#10格式(标准证书请求格式)。

首先可以查看一下证书请求的内容,执行命令:
openssl req -in req.pem -text -noout
将看到证书请求的内容,包括请求者唯一的名字(DN)、公钥信息(可能还有一组扩展的可选属性)。

执行签发命令:
openssl ca -in req.pem -out cert.pem -config "$HOME/testca/conf/testca.conf"
执行过程中会要求输入访问CA的私钥密码(刚才设置的888888)。

完成上一步后,签发好的证书就是cert.pem,另外$HOME/testca/newcerts里也会有一个相同的证书副本(文件名为证书序列号)。
你可以执行以下语句来查看生成的证书的内容:
openssl x509 -in cert.pem -text -noout

2. 吊销证书(作废证书)
一般由于用户私钥泄露等情况才需要吊销一个未过期的证书。(当然我们用本测试CA时其时很少用到该命令,除非专门用于测试吊销证书的情况)
假设需要被吊销的证书文件为cert.pem,则执行以下命令吊销证书:
openssl ca -revoke cert.pem -config "$HOME/testca/conf/testca.conf"

3. 生成证书吊销列表文件(CRL)
准备公开被吊销的证书列表时,可以生成证书吊销列表(CRL),执行命令如下:
openssl ca -gencrl -out testca.crl -config "$HOME/testca/conf/testca.conf"
还可以添加-crldays和-crlhours参数来说明下一个吊销列表将在多少天后(或多少小时候)发布。

可以用以下命令检查testca.crl的内容:
openssl crl -in testca.crl -text -noout

三. 自己生成公钥密钥,并用测试CA签发数字证书
我们在平时测试时,可以自己用openssl为服务器或用户生成公钥密钥,并用上面创建的CA签发对应私钥(密钥)的数字证书。
假设,我们就用刚才创建CA的操作系统用户为名为testuser的用户创建数字证书,我们要把待创建的私钥、证书等都放在目录$HOME/testuser下:

1. 创建密钥和证书请求(证书请求里包含了公钥)
创建$HOME/testuser目录并执行命令:
mkdir $HOME/testuser
cd $HOME/testuser
openssl req -newkey rsa:1024 -keyout testkey.pem -keyform PEM -out testreq.pem -outform PEM -subj "/O=TestCom/OU=TestOU/CN=testuser"
执行过程中需要输入私钥的保护密码,假设我们输入密码: 222222

执行完后,testkey.pem即为用户的密钥,而testreq.pem即为证书请求。
可以用openssl req -in testreq.pem -text -noout查看证书请求的内容。

2. 用测试CA为testuser签发证书
同样还在$HOME/testuser目录下执行命令:
openssl ca -in testreq.pem -out testcert.pem -config "$HOME/testca/conf/testca.conf"
执行过程中需要输入CA的密钥保护密码(刚才设置的888888),并且最后询问你是否要给该用户签发证书时要选y。

执行完后,testcert.pem即为证书,
可以用命令openssl x509 -in testcert.pem -text -noout查看证书内容。

3. 制作一个PKCS12格式的文档(个人数字证书)
我们制作的这个PKCS#12文件将包含密钥、证书和颁发该证书的CA证书。该文件可以直接用于服务器数字证书或个人数字证书。
把前几步生成的密钥和证书制作成一个pkcs12文件的方法执行命令:
openssl pkcs12 -export -in testcert.pem -inkey testkey.pem -out testuser.p12 -name testuser -chain -CAfile "$HOME/testca/cacert.pem"
执行过程中需要输入保护密钥的密码(222222),以及新的保护pkcs12文件的密码。

执行完后,testuser.p12即为pkcs12文件。你可以直接拷贝到windows下,作为个人数字证书,双击导入IE后就可以使用了。该文件也可以直接用于tomcat作为服务器证书使用(我尽量在近期再写一篇关于如何自己用tomcat建立HTTPS双向认证测试环境的文章)。

若要查看testuser.p12的内容可以用命令openssl pkcs12 -in testuser.p12

说明:
– 本文中名词“个人数字证书”意识为包含私钥和证书的实体,而不是单指只保护公钥的数字证书。
– openssl版本OpenSSL 0.9.8g 19