C语言构建WEB管理系统(三):CGI程序解析GET数据

来源:互联网 发布:js选择器innerhtml 编辑:程序博客网 时间:2024/05/29 13:25

【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途】

在上一节我们看到了第一个CGI程序,该程序仅仅是为了帮助理解CGI程序如何获取客户端提交的数据,只是输出环境变量没有做任何事,在实际应用中我们需要首先解析这些数据,然后提取其中我们需要的数据(如在登录时我们需要提取用户名和密码)。

        我们现在已经知道在使用GET方式时,客户端提交的数据保存在环境变量QUERY_STRING中,所以我们需要做的就是获取环境变量QUERY_STRING,然后解析其中数据。我们继续使用上一节的表单示例,稍作修改,表单中有如下内容:
 用户名: <inputtype="text" name="用户名"/><br/> 密码: <inputtype="password" name="密码" /><br/><inputtype="radio" name="语言" value="English"/> English <br/>
 <inputtype="radio" name="语言" value="Chinese"/> 简体中文 <inputtype="hidden" name="sessionid" value="1234567890"/><br/><inputtype="submit" value="登录"><br/>
使用上一节的print.cgi获取环境变量QUERY_STRING的值为:
%E7%94%A8%E6%88%B7%E5%90%8D=shallnet&%E5%AF%86%E7%A0%81=cn&%E8%AF%AD%E8%A8%80=Chinese&sessionid=1234567890
此时浏览器地址栏内容为:http://shallnet.cn/cgi-bin/print.cgi?%E7%94%A8%E6%88%B7%E5%90%8D=shallnet&%E5%AF%86%E7%A0%81=cn&%E8%AF%AD%E8%A8%80=Chinese&sessionid=1234567890
所以我们首先做的就是要从中提取客户登录信息,包括用户名用户名、密码、语言、以及隐含域sessionid。
我们可以看到表单提交的信息出现在表单所请求CGI程序的URL中问号后面,且各个表单各个元素都以“NAME=VALUE”的方式出现,NAME为表单元素的NAME属性,VALUE为表单元素的VALUE属性,如表单元素“用户名”在QUERY_STRING中为“%E7%94%A8%E6%88%B7%E5%90%8D=shallnet”。不同表单元素之间用“&”分开。
        但是我们发现“用户名”在QUERY_STRING中变为%E7%94%A8%E6%88%B7%E5%90%8D,“密码”为%E5%AF%86%E7%A0%81,而在上一节没有使用中文时却没有相应变换,这是由于web服务器和浏览器对一些特殊字符不能正确处理,可能会导致某种误会,因此在数据传输之前,浏览器会对表单内客户输入的数据中特殊字符进行编码。在web系统中“=”分隔NAME和VALUE属性,“&”分隔不同输入数据,所以如果在表单的输入中包含这些特殊字符,这些字符也会被编码。web系统会将这些不能正确处理的特殊字符转换成它的十六进制数的形式,如“=”将会被转换成“%3D”。
        所以想要处理表单提交的数据,还必须对数据进行解码,以把他还原成客户在web页面上输入时的形式。一般解码有以下工作:
1. 从QUERY_STRING中找出代表各个表单元素所存储数据的“NAME=VALIE”对。
2. 表单属性中有存放“+”的,则将其转换为空格。
3. 将表单属性中存放的数据中十六进制数“%HH“转换成相应的字符。

以下为解析QUERY_STRING的代码:
/*该函数主要做解码工作*/int sln_string_unescape(char **attr, const char *src, int len){    int         pos = 0, src_pos = 0;    char        escape_char;    char        *p = NULL;    p = (char *)malloc(len + 1);    if (NULL == p) {        return -1;    }    while (src_pos < len) {        switch (src[src_pos]) {            case '%':    /*表单属性中存放的数据中十六进制数“%HH“转换成相应的字符*/                escape_char = sln_hex2bin(src[src_pos+1]);    /*sln_hex2bin() 函数负责将字符转换为其对应的ASCII码*/                escape_char <<= 4;                escape_char |= sln_hex2bin(src[src_pos+2]);                p[pos] = escape_char;                src_pos += 3;                break;            case '+':    /*表单属性中有存放“+”的,则将其转换为空格*/                p[pos] = '\x20';                src_pos++;                break;            default:                p[pos] = src[src_pos];                src_pos++;                break;        }        pos++;    }    *attr = p;    return 0;} 

/*该函数解析传入的表单数据并输出解析结果*/void sln_cgi_content_parse(char *input_content, int len){    char        *start = NULL, *end = NULL;    char        *attr = NULL, *value = NULL;    int         attr_len, value_len;    start = (char *)input_content;    while ((end = strchr(start, '='))) {        *end = '\0';        attr_len = end - start;        sln_string_unescape(&attr, start, attr_len);        start = end + 1;        //if not find '&', then the last char is end        end = strchr(start, '&');        if (NULL != end) {            *end = '\0';        } else {            end = (char *)&input_content[len - 1];        }        value_len = end - start;        sln_string_unescape(&value, start, value_len);        start = end + 1;        if (end - input_content > len) {            break;        }        fprintf(stdout, "<P>NAME: %s, VALUE: %s</P>\n", attr, value);    }} 

/*输出包含解析结果的页面*/int main(int argc, const char *argv[]){......    fprintf(stdout, "<HTML>\n");    fprintf(stdout, "<HEAD>\n");    fprintf(stdout, "<TITLE>CGI解析GET数据</TITLE>\n");    fprintf(stdout, "<HEAD>\n");    fprintf(stdout, "<BODY>\n");    fprintf(stdout, "<H3>以下为解析后数据</H3>\n");    sln_cgi_content_parse(data, strlen(data));    fprintf(stdout, "本网页由CGI自动生成!\n");    fprintf(stdout, "</BODY>");    fprintf(stdout, "</HTML>");......}

下面是运行及结果:

点击登录之后页面跳转:
2 0
原创粉丝点击