新入职的公司需要我在公司的板卡上开发一个CGI网页用于配置系统参数,减少了客户直接配置内核文件的复杂过程,
主要功能要包括:
1.CGI登录(只有密码校验),
2.配置文件传输(CGI文件传输)
3.打开网页要读取本地文件显示当前配置参数
4.下拉框动态显示当前选用的协议文件
5.CGI网页跳转,即登录完成需要跳转至系统设置页面
做好的效果如下:
登录界面
系统配置页面,即登录完成跳转页面如下:
下面详细描述具体实现
step1:
对于BOA服务器的移植网络上有众多文章,这里不在赘述,只晒出BOA.conf文件供参考,BOA.conf文件位于usr/local/boa
上图中表明了BOA文件夹位置以及我们的索引网页维index,即如果配置好了BOA服务器,如果在浏览器输入开发板IP,将直接访问usr/local/boa/index.html文件
step2:第一个网页制作:登录界面
登录界面CGI程序只要捕获服务器发过来的密码数据即可,然后校验实现跳转,html代码如下:
皮肤代码设计CSS代码未上传,上图中采用的是GET通讯,传输数据少于2k可用GET,CGI程序如下
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( int argc, char *argv[] )
{
char *UserInput = NULL; // index the user input data.
char *request_method = NULL; //index the html transfer type.
int data_len = 0; // index the input data's length.
printf("Content-type:text/html;charset=utf-8\n\n"); //response header.
printf("\n");
// HTML page header.
printf("<html><head>");
printf("<title>%s</title></head>", "Login Err");
printf("<body>");
if( ! getenv("REQUEST_METHOD") )
{
printf("No client request from user !\n");
return -1;
}
request_method = getenv("REQUEST_METHOD"); // trans-type.
// trans-type : GET
if( ! strcmp( request_method, "GET" ) )
{
if( getenv( "QUERY_STRING" ) )
{
UserInput = getenv( "QUERY_STRING" );
}
data_len = strlen( UserInput );
if( NULL == UserInput || 0 == data_len )
{
printf( "There's no input data !\n" );
return -1;
}
UserInput[data_len] = '\0';
//printf("method = %s, data_len = %d<br>", request_method, data_len);
//printf("data: %s", UserInput);
if(!strcmp(&UserInput[7],"1357"))
{
printf("<meta http-equiv=\"Refresh\" content=\"0;URL=config.cgi\"> ");
}
else
{
printf("key err<BR>\nyou input key is:<BR>\n %s",&UserInput[7]);
}
}
printf("</body></html>");
fflush( stdout );
return 0;
}
上图中,通过获取通讯字串判断具体字符,然后实现跳转,登陆成功则跳转至config.cgi页面,否则提示错误
step3:
对于登录界面简单的数据处理没必要用到CGIC库,但是对于配置界面需要进行复杂数据处理的页面,需要借助CGIC库的代码
1.移植CGIC库:http://blog.youkuaiyun.com/tiantang46800/article/details/7530930,具体见博客,不在赘述
我们整个配置界面需要读取/data目录下的CONFIG文件,然后解析文件中的IP,PORT等一系列参数显示在网页上,所以HTML是动态的,需要每次启动浏览器读取CONFIG文件更新数据,在用户输入配置参数后我们需要将用户设置信息回写到CONFIG文件并且下拉菜单需要动态显示当前/data文件夹底下有多少so协议文件,然后根据用户操作写入,具体流程图如下
这一步骤全部使用CGIC模拟网页,不在使用HTML语言编辑网页,具体代码如下
#include <stdio.h>
#include "cgic.h"
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include<linux/reboot.h>
#define SOFILENUM 10
#define SOFILELEN 20
char Ip[20]={0};
char Port[20]={0};
char Rs232[20]={0};
char Rs485[20]={0};
char HardVersion[20]={0};
char SoftVersion[20]={0};
char IMEI[20]={0};
char MAC[20]={0};
char Baudrate[20]={0};
char Lib[20]={0};
char Porttype[20]={0};
char TotleSoFile[10][20];
char TotleSoNum=0;
const char *BaudrateTable[] =
{
"2400",
"4800",
"9600",
"14400",
"19200",
"38400",
"57600",
"115200",
"230400",
"460800",
"921600"
};
char *porttable[]=
{
"1",
"2"
};
enum ErrLog
{
ErrSucceed,
ErrOpenField,
ErrNoFile
};
char *ErrSoNews[]=
{
"",
"通讯文件上载失败",
""
};
char *ErrUpNews[]=
{
"",
"升级文件上载失败",
""
};
char *ErrMD5News[]=
{
"",
"MD5文件上载失败",
""
};
/*
Find the '=' pos and get the config dat
*/
static int DatPos(char *dat , int index )
{
int i=0;
if(index==0)//find the config file
{
while((*dat++)!='=')
{
i++;
}
return i;
}
else //find the *.so file
{
while(*dat&&*(dat+1))
{
if(*dat=='s'&&*(dat+1)=='o')
{
return 1;
}
dat++;
}
return 0;
}
}
/*Find How many So file */
void GetFileOfSo(void)
{
FILE *stream;
FILE *wstream;
char buf[1024];
memset( buf,0,sizeof(buf));
stream = popen( " ls /data/*.so", "r" );
wstream = fopen( "/data/Numberso.txt", "w+");
chmod(wstream ,777);
fread( buf, sizeof(char), sizeof(buf), stream);
fwrite( buf, 1, sizeof(buf), wstream );
pclose( stream );
fclose( wstream );
}
void GetMAC(void)
{
FILE *stream;
stream = popen( "cat /etc/mac", "r" );
fread( MAC, sizeof(char), sizeof(MAC), stream);
pclose( stream );
}
void GetSoFileList(void)
{
FILE *fd;
TotleSoNum=0;
char StrLine[1024];
int i;
if((fd = fopen("/data/Numberso.txt","r")) == NULL)
{
return;
}
while (!feof(fd))
{
fgets(StrLine,1024,fd);
i=DatPos(StrLine,1);
if(i==1) //find a so file
{
strcpy(TotleSoFile[TotleSoNum++], &StrLine[6]);
}
else
{
break;
}
}
fclose(fd);
}
/*When open html we should read configfile to fix it*/
void ReadTandaConf(void)
{
FILE *fd;
char StrLine[1024];
char ptr[20];
int i=0;
if((fd = fopen("/data/Tanda.conf","r")) == NULL)
{
return;
}
while (!feof(fd))
{
fgets(StrLine,1024,fd);
if(StrLine[0]=='#'||StrLine[0]==' ')
{
continue;
}
else
{
i=DatPos(StrLine , 0);
memset(ptr , 0 , sizeof(ptr));
strncpy(ptr , StrLine , 3);
ptr[3]='\0';
if(!strcmp(ptr , "Har"))
{
strncpy(HardVersion,&StrLine[i+1],sizeof(HardVersion));
HardVersion[sizeof(HardVersion)-1]='\0';
continue;
}
if(!strcmp(ptr , "Sof"))
{
strncpy(SoftVersion,&StrLine[i+1],sizeof(SoftVersion));
SoftVersion[sizeof(SoftVersion)-1]='\0';
continue;
}
if(!strcmp(ptr , "IME"))
{
strncpy(IMEI,&StrLine[i+1],sizeof(IMEI));
IMEI[sizeof(IMEI)-1]='\0';
continue;
}
if(!strcmp(ptr , "ip="))
{
strncpy(Ip,&StrLine[i+1],sizeof(Ip));
Ip[sizeof(Ip)-1]='\0';
continue;
}
if(!strcmp(ptr , "por")&&StrLine[4]=='=')
{
strncpy(Port,&StrLine[i+1],sizeof(Port));
Port[sizeof(Port)-1]='\0';
continue;
}
#if 1
if(!strcmp(ptr , "rs2"))
{
strncpy(Rs232,&StrLine[i+1],sizeof(Rs232));
Rs232[sizeof(Rs232)-1]='\0';
continue;
}
if(!strcmp(ptr , "rs4"))
{
strncpy(Rs485,&StrLine[i+1],sizeof(Rs485));
Rs485[sizeof(Rs485)-1]='\0';
continue;
}
#endif
if(!strcmp(ptr , "bau"))
{
strncpy(Baudrate,&StrLine[i+1],sizeof(Baudrate));
Baudrate[sizeof(Baudrate)-1]='\0';
continue;
}
if(!strcmp(ptr , "pro"))
{
strncpy(Lib,&StrLine[i+3],sizeof(Lib));
Lib[sizeof(Lib)-1]='\0';
continue;
}
if(!strcmp(ptr , "por")&&StrLine[4]=='t')//porttype
{
strncpy(Porttype,&StrLine[i+1],sizeof(Porttype));
Porttype[sizeof(Porttype)-1]='\0';
continue;
}
}
}
fclose(fd);
}
void WriteConfDat(void)
{
FILE *fd;
int SoChoice;
int bauChoice;
int portchoice;
int i;
ReadTandaConf();
cgiFormStringNoNewlines("ip", Ip, sizeof(Ip));
cgiFormStringNoNewlines("port", Port, sizeof(Port));
cgiFormRadio("porttype", porttable, 2, &portchoice, 0);
cgiFormSelectSingleNormal("bau", BaudrateTable, 11, &bauChoice, 0);
//printf("<p>bau=%s ,%d<p>\n",BaudrateTable[bauChoice],bauChoice);
GetSoFileList();
cgiFormSelectSingle("net", TotleSoFile, TotleSoNum, &SoChoice, 0);
fd=fopen("/data/Tanda.conf" ,"w");
if(fd)
{
fputs("###################################\n",fd);
fputs("# Tanda Adapter Config File #\n",fd);
fputs("###################################\n\n",fd);
fputs("#HardVersion\nHardVersion=",fd);
fputs(HardVersion, fd);
fputs("\n\n",fd);
fputs("#SoftVersion\nSoftVersion=",fd);
fputs(SoftVersion, fd);
fputs("\n\n",fd);
fputs("#IMEI\nIMEI=",fd);
fputs(IMEI, fd);
fputs("\n\n",fd);
fputs("Service IP\nip=",fd);
fputs(Ip , fd);
fputs("\n\n",fd);
fputs("#Service Port\nport=",fd);
fputs(Port , fd);
fputs("\n\n",fd);
fputs("#rs232port=/dev/ttymxc\nrs232port=",fd);
fputs(Rs232, fd);
fputs("\n\n",fd);
fputs("#rs485port=/dev/ttymxc\nrs485port=",fd);
fputs(Rs485, fd);
fputs("\n\n",fd);
fputs("#Baudrate\nbaudrate=",fd);
if(bauChoice==0)
fputs(Baudrate, fd);
else
fputs(BaudrateTable[bauChoice], fd);
fputs("\n\n",fd);
fputs("#protocolName\nprotocolName=./",fd);
fputs(TotleSoFile[SoChoice] , fd);
fputs("\n\n",fd);
fputs("#Connect Port Select\nporttype=",fd);
fputs(porttable[portchoice], fd);
fputs("\n\n",fd);
fclose(fd);
}
else
{
printf("err");
}
}
/*上载通讯文件*/
enum ErrLog UpLoadsoFile(void)
{
cgiFilePtr file;
FILE *fd;
char name[1024];
char path[50];
char contentType[1024];
int size;
unsigned int got;
char *tmp = NULL;
if (cgiFormFileName("sofile", name, sizeof(name)) != cgiFormSuccess) {
return ErrNoFile;
}
//fprintf(cgiOut, "The filename submitted was: ");
//cgiHtmlEscape(name);
//fprintf(cgiOut, "<p>\n");
cgiFormFileSize("sofile", &size);
//fprintf(cgiOut, "The file size was: %d bytes<p>\n", size);
cgiFormFileContentType("sofile", contentType, sizeof(contentType));
//fprintf(cgiOut, "The alleged content type of the file was: ");
//cgiHtmlEscape(contentType);
//fprintf(cgiOut, "<p>\n");
//fprintf(cgiOut, "Of course, this is only the claim the browser made when uploading the file. Much like the filename, it cannot be trusted.<p>\n");
//fprintf(cgiOut, "The file's contents are shown here:<p>\n");
if (cgiFormFileOpen("sofile", &file) != cgiFormSuccess) {
return ErrNoFile;
}
/*write file */
tmp=(char *)malloc(sizeof(char)*size);
strcpy(path , "/data/");
strcat(path, name);
fd=fopen(path ,"w+");
if(fd==NULL)
{
return ErrOpenField;
}
//fprintf(cgiOut, "<pre>\n");
while (cgiFormFileRead(file, tmp, size, &got) ==
cgiFormSuccess)
{
fwrite(tmp, size, sizeof(char), fd);
//cgiHtmlEscapeData(tmp, size);
}
//fprintf(cgiOut, "</pre>\n");
cgiFormFileClose(file);
free(tmp);
fclose(fd);
return ErrSucceed;
}
enum ErrLog UpLoadUpdateFile(void)
{
cgiFilePtr file;
FILE *fd;
char name[1024];
char path[50];
char contentType[1024];
int size;
unsigned int got;
char *tmp = NULL;
if (cgiFormFileName("updatefile", name, sizeof(name)) != cgiFormSuccess) {
return ErrNoFile;
}
cgiFormFileSize("updatefile", &size);
cgiFormFileContentType("updatefile", contentType, sizeof(contentType));
if (cgiFormFileOpen("updatefile", &file) != cgiFormSuccess) {
return ErrNoFile;
}
/*write file */
tmp=(char *)malloc(sizeof(char)*size);
strcpy(path , "/data/update/");
strcat(path, name);
fd=fopen(path ,"w+");
if(fd==NULL)
{
return ErrOpenField;
}
while (cgiFormFileRead(file, tmp, size, &got) ==
cgiFormSuccess)
{
fwrite(tmp, size, sizeof(char), fd);
}
cgiFormFileClose(file);
free(tmp);
fclose(fd);
return ErrSucceed;
}
enum ErrLog UpLoadMD5File(void)
{
cgiFilePtr file;
FILE *fd;
char name[1024];
char path[50];
char contentType[1024];
int size;
unsigned int got;
char *tmp = NULL;
if (cgiFormFileName("MD5file", name, sizeof(name)) != cgiFormSuccess) {
return ErrNoFile;
}
//fprintf(cgiOut, "The filename submitted was: ");
//cgiHtmlEscape(name);
//fprintf(cgiOut, "<p>\n");
cgiFormFileSize("MD5file", &size);
//fprintf(cgiOut, "The file size was: %d bytes<p>\n", size);
cgiFormFileContentType("MD5file", contentType, sizeof(contentType));
//fprintf(cgiOut, "The alleged content type of the file was: ");
//cgiHtmlEscape(contentType);
//fprintf(cgiOut, "<p>\n");
//fprintf(cgiOut, "Of course, this is only the claim the browser made when uploading the file. Much like the filename, it cannot be trusted.<p>\n");
//fprintf(cgiOut, "The file's contents are shown here:<p>\n");
if (cgiFormFileOpen("MD5file", &file) != cgiFormSuccess) {
return ErrNoFile;
}
/*write file */
tmp=(char *)malloc(sizeof(char)*size);
strcpy(path , "/data/update/");
strcat(path, name);
fd=fopen(path ,"w+");
if(fd==NULL)
{
return ErrOpenField;
}
//fprintf(cgiOut, "<pre>\n");
while (cgiFormFileRead(file, tmp, size, &got) ==
cgiFormSuccess)
{
fwrite(tmp, size, sizeof(char), fd);
//cgiHtmlEscapeData(tmp, size);
}
//fprintf(cgiOut, "</pre>\n");
cgiFormFileClose(file);
free(tmp);
fclose(fd);
return ErrSucceed;
}
void SubmitHandle(void)
{
volatile int i;
system("chmod 777 /data");
system("chmod 777 /data/update");
i=UpLoadsoFile();
printf("%s",ErrSoNews[i]);
printf("<BR>\n");
i=UpLoadUpdateFile();
printf("%s",ErrUpNews[i]);
printf("<BR>\n");
i=UpLoadMD5File();
printf("%s",ErrMD5News[i]);
printf("<BR>\n");
}
void ShowIndex(void)
{
FILE *fd;
char StrLine[1024];
int i=0;
GetFileOfSo();
GetMAC();
ReadTandaConf();
fprintf(cgiOut, "<!-- 2.0: multipart/form-data is required for file uploads. -->");
fprintf(cgiOut, "<form method=\"POST\" enctype=\"multipart/form-data\" ");
fprintf(cgiOut, " action=\"");
cgiValueEscape(cgiScriptName);
fprintf(cgiOut, "\">\n");
fprintf(cgiOut, "<p>\n");
fprintf(cgiOut ,"<table id=\"table\" cellpadding=\"5\" width=\"60%\" border=\"1px\" align=\"center\" border-radius=\"5px\">");
fprintf(cgiOut ,"<tr bgcolor=\"#E0F0F\"></tr><br>");
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">硬件版本号:</td><td>%s</td></tr>",HardVersion);
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">软件版本号:</td><td>%s</td></tr>",SoftVersion);
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">MAC:</td><td>%s</td></tr>",MAC);
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">IMEI:</td><td>%s</td></tr>",IMEI);
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">服务器IP:</td><td><input name=\"ip\" value=%s size=\"30\"></td></tr>",Ip);
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">端口号:</td><td><input name=\"port\" value=%s size=\"30\"></td></tr>",Port);
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">通讯接口选择:</td>");
if(Porttype[0]=='1')
{
fprintf(cgiOut , "<td><input type=\"radio\" name=\"porttype\" value=\"1\" checked>rs232") ;
fprintf(cgiOut , "<input type=\"radio\" name=\"porttype\" value=\"2\">rs485</td></tr>");
}
else
{
fprintf(cgiOut , "<td><input type=\"radio\" name=\"porttype\" value=\"1\">rs232") ;
fprintf(cgiOut , "<input type=\"radio\" name=\"porttype\" value=\"2\" checked>rs485</td></tr>");
}
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">波特率:</td><td><select name =\"bau\">");
fprintf(cgiOut ,"<option value=\"%s\">%s",Baudrate,Baudrate);
for(i=0 ; i<11 ; i++)
{
if((Baudrate[0]==BaudrateTable[i][0])&&(Baudrate[1]==BaudrateTable[i][1]))
{
continue;
}
fprintf(cgiOut ,"<option value=\"%s\">%s",BaudrateTable[i],BaudrateTable[i]);
}
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">通讯文件上载:</td>");
fprintf(cgiOut , "<td align=\"left\" width=\"20%\"><div class=\"file-box\"> <input type='text' name='textfield' id='textfield' class='txt' /> ");
fprintf(cgiOut , "<input type='button' class='btn' value='浏览' /> <input type=\"file\" name=\"sofile\" class=\"file\" id=\"fileField\" size=\"28\" οnchange=\"document.getElementById('textfield').value=this.value\" /> </div> ");
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">通讯协议:</td><td><select name =\"net\">");
fprintf(cgiOut ,"<option value=\"%s\">%s",Lib,Lib);
if((fd = fopen("/data/Numberso.txt","r")) == NULL)
{
return;
}
#if 1
while (!feof(fd))
{
fgets(StrLine,1024,fd);
i=DatPos(StrLine,1);
if(i==1) //find a so file
{
strcpy(TotleSoFile[TotleSoNum], &StrLine[6]);
if(!strcmp(&StrLine[6] , Lib))
{
continue;
}
fprintf(cgiOut ,"<option value=\"%s\">%s",TotleSoFile[TotleSoNum],TotleSoFile[TotleSoNum]);
TotleSoNum++;
}
else
{
break;
}
}
#endif
fclose(fd);
fprintf(cgiOut ,"</select></td></tr>");
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">升级文件上载:</td>");
fprintf(cgiOut , "<td align=\"left\" width=\"20%\"><div class=\"file-box\"> <input type='text' name='textfield1' id='textfield1' class='txt' /> ");
fprintf(cgiOut , "<input type='button' class='btn' value='浏览' /> <input type=\"file\" name=\"updatefile\" class=\"file\" id=\"fileField1\" size=\"28\" οnchange=\"document.getElementById('textfield1').value=this.value\" /> </div> ");
fprintf(cgiOut ,"<tr><td align=\"center\" width=\"20%\">MD5文件上载:</td>");
fprintf(cgiOut , "<td align=\"left\" width=\"20%\"><div class=\"file-box\"> <input type='text' name='textfield2' id='textfield2' class='txt' /> ");
fprintf(cgiOut , "<input type='button' class='btn' value='浏览' /> <input type=\"file\" name=\"MD5file\" class=\"file\" id=\"fileField2\" size=\"28\" οnchange=\"document.getElementById('textfield2').value=this.value\" /> </div> ");
fprintf(cgiOut ,"<tr><td></td><td align=\"left\"><input class =\"button\" input type=\"submit\"name=\"Setting\" value=\"确认\" οnclick=\"javaScript:alert('请求已发送')\">");
fprintf(cgiOut, "</table></form>\n");
}
int cgiMain()
{
/* Send the content type, letting the browser know this is HTML */
//cgiHeaderContentType("text/html charset=UTF-8");
printf("Content-type:text/html;charset=utf-8\n\n");
/* Top of the page */
fprintf(cgiOut, "<HTML><HEAD>\n");
fprintf(cgiOut, "<TITLE>适配器配置</TITLE>\n");
fprintf(cgiOut , "<style>#table{border-radius:20px;border:0px;background:#CCCCCC;}#table td{color:##00CED1;font-family:\"仿宋\";color:#666666;border:0px;}#h1{color:#CCCCCC;font-family:\"仿宋\";}");
fprintf(cgiOut, "input{font-family:\"仿宋\";height:30px;color:#0;border : 0;background:#F0FFFF;}.button{margin-right:10px;background:#666666;width:80px;border-radius:5px;color:#FAF0E6;}");
fprintf(cgiOut, ".button:active{background:#666666;}.file-box{ position:relative;width:340px;} .txt{ height:30px;; border:1px solid #CCCCCC; width:180px;} ");
fprintf(cgiOut, ".btn{ background-color:#666666; border:1px solid #CDCDCD;height:30px; width:70px;} .file{ position:absolute; top:0; right:80px; height:30px; filter:alpha(opacity:0);opacity: 0;width:260px } </style>");
fprintf(cgiOut, "</HEAD>");
fprintf(cgiOut, "<BODY style=\"background:#666666\"><h1 id = \"h1\"align=\"center\"> </h1>");
if ((cgiFormSubmitClicked("Setting") == cgiFormSuccess))
{
SubmitHandle();
WriteConfDat();
system("reboot");
}
ShowIndex();
fprintf(cgiOut, "</BODY></HTML>\n");
return 0;
}
打开网页需要从这个config文件读取相关信息到网页,同时需要读取/data文件夹底下有多少SO文件并且显示,data底下文件构造如下: