写这篇文章的原因是向lilac dev组介绍一下如何入门 lilac bbs web 的开发,由于lilac bbs 是基于kbs系统的,所以我主要讲的也是基于kbs系统的web开发。
kbs系统的web主要分为三个部分:php页面开发,php扩展和底层的c语言函数库。
php页面开发主要涉及的就是我们常用的php常规开发,其实就是一个php的解释器解释运行php页面,再加上css、js和html那些东西。
php扩展是使用zend的特性,它可以将c语言编写的代码编译成二进制文件,然后将这个二进制文件加载为一个php的库文件(.so格式),由apache启动的时候检查注册,然后在上层的php页面中被动态载入、调用和释放。
至于底层的C语言函数库,其实就是用C语言写的函数的集合,可以供php扩展中的C语言代码调用的。仅此而已。
我打算用自底向上的方法讲,就举一个最简单的实例吧:用户登录。
首先,我们先看一个用C语言编写的验证用户信息的函数checkpasswd2,这个函数在libBBS/pass.c中:
71 int checkpasswd2(const char *passwd, const struct userec *user)
72 {
73 #ifdef CONV_PASS
74 if (user->passwd[0]) {
75 return checkpasswd(user->passwd, passwd);
76 } else
77 #endif
78 {
79 unsigned char md5passwd[MD5_DIGEST_LENGTH];
80
81 igenpass(passwd, user->userid, md5passwd);
82 /*
83 if (memcmp(md5passwd,user->md5passwd,MD5_DIGEST_LENGTH)) {
84 unsigned char w_md5passwd[MD5_DIGEST_LENGTH];
85 w_igenpass(passwd,user->userid,w_md5passwd);
86 if (memcmp(w_md5passwd,user->md5passwd,MD5_DIGEST_LENGTH)) return 0;
87 memcpy(user->md5passwd,md5passwd,MD5_DIGEST_LENGTH);
88 bbslog("5system","Convert %s password.",user->userid);
89 }
90 return 1;
91 */
92 return !(memcmp(md5passwd, user->md5passwd, MD5_DIGEST_LENGTH));
93 }
94 }
看起来应该很简单,比较明了。这就是一个最基本的kbs函数,几乎没有什么依赖项。这个函数可以被ssh、telnet和www这些上层的应用调用,但是底层就是这一个函数。
做完验证函数之后,我们需要编写一个php扩展。要使php页面能够用到这个checkpasswd2函数,那么我们需要有一个php扩展,其中有一个函数bbs_checkpasswd,这个函数其实是一个适配器,连接php页面的调用和checkpasswd2函数。这个函数在bbs2www/phplib/phpbbs.user.c:
PHP_FUNCTION(bbs_checkpasswd)
114 {
115 char *s;
116 int s_len;
117 char *pw;
118 int pw_len;
119 long ret;
120 int unum = 0;
121 long ismd5 = 0;
122 struct userec *user;
123 int ac = ZEND_NUM_ARGS();
124
125 if (ac != 2 || zend_parse_parameters(2 TSRMLS_CC, "ss", &s, &s_len, &pw, &pw_len) != SUCCESS) {
126 if (ac!= 3 || zend_parse_parameters(3 TSRMLS_CC, "ssl", &s, &s_len, &pw, &pw_len, &ismd5) != SUCCESS) {
127 WRONG_PARAM_COUNT;
128 }
129 }
130 if (s_len > IDLEN)
131 s[IDLEN] = 0;
132 if (pw_len > PASSLEN)
133 pw[PASSLEN] = 0;
134 if (pw[0] == '')
135 ret = 1;
136 else if ((s[0] != 0) && !(unum = getuser(s, &user)))
137 ret = 2;
138 else {
139 if (s[0] == 0)
140 user = getCurrentUser();
141 if (user) {
142 if (ismd5) {
143 ismd5 = !(memcmp(pw, user->md5passwd, MD5PASSLEN));
144 } else {
145 ismd5 = checkpasswd2(pw, user);
146 }
147 if (ismd5) {
148 ret = 0;
149 if (s[0] != 0)
150 setcurrentuser(user, unum);
151 } else {
152 ret = 1;
153 logattempt(user->userid, getSession()->fromhost, "www");
154 }
155 } else {
156 ret = 1;
157 }
158 }
159 RETURN_LONG(ret);
160 }
可以看出,这个函数与php密切相关,php zend会解析上层php页面调用变量,然后处理这些变量,而我们要做的,就是检查这些变量的合法性,然后将其传到checkpasswd2即可。
用户登陆的时候,首先会使用js检查输入信息合法性,然后转到bbslogin.php这个页面。我们可以发现有这么一句:
2 require("www2-funcs.php");
也就是说这个页面需要加载www2-funcs.php,那么我们再看看www2-funcs.php,发现
11 if (BUILD_PHP_EXTENSION==0)
12 @dl("$topdir/../libexec/bbs/libphpbbslib.so");
其实就是这句话,php使用了dl调用了我们编写的php扩展libphpbbslib.so,这个类似于C#中的dllimport调用COM一样。
好,我们回到bbslogin.php,加载之后,即可使用libphpbbslib.so的函数了。
24 if (($id!="guest")&&bbs_checkpasswd($id,$passwd)!=0) error_alert("用户密码错误,请重新登录!");
OK,就是这样的,php页面调用bbs_checkpasswd,然后得到返回值,就可以判断用户密码了。