51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

DeepSeek+半天实现一个lighttpd服务程序

问题:

几个问题:

1、lighttpd作为服务器,如何实现CGI程序对开发板的IP、子网掩码等进行配置。

2、CGI登录怎么实现。

3、模版文件如何实现。通过CGI程序读取html文件后,动态替换其中的模板参数。


交叉编译:

./configure CC=arm-rockchip830-linux-uclibcgnueabihf-gcc 
--host=arm-openwrt-linux-muslgnueabi target=arm-linux 
--enable-utf8 
--enable-unicode-properties 
--prefix=$(pwd)/install 
--without-pcre2 --without-zlib

修改modules.conf配置CGI

##
## plain old CGI (mod_cgi)
##
include conf_dir + "/conf.d/cgi.conf"

修改/conf.d/cgi.conf

cgi.assign                 = ( ".pl"  => "/usr/bin/perl",
                               ".rb"  => "/usr/bin/ruby",
                               ".cgi" => "",
                               ".erb" => "/usr/bin/eruby",
                               ".py"  => "/usr/bin/python" )

网页保存路径:lighttpd.conf 注释掉用户名配置

#server.username  = "lighttpd"
#server.groupname = "lighttpd"

## Document root

server.document-root = server_root + "/htdocs"

启动:将install目录修改为lighttpd

/lighttpd/sbin/lighttpd -f /lighttpd/config/lighttpd.conf -m /lighttpd/lib

CGI程序保存路径,这个问题其实也好理解,http服务的网页根路径下,存放一个cgi-bin的路径,然后将cgi程序拷贝的这个路径下。


问题2:登录如何实现。

网页侧:

    <div class="layui-container" style="margin-top: 20px;">
        <form class="layui-form" action="/cgi-bin/login.cgi"  method="POST">
            <div class="layui-form-item">
                <label class="layui-form-label">用户名</label>
                <div class="layui-input-block">
                    <input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input">
                </div>
            </div>
            <div class="layui-form-item">
                <label class="layui-form-label">密码</label>
                <div class="layui-input-block">
                    <input type="password" name="password" id="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">
                </div>
            </div> 
            <div class="layui-form-item">
                <div class="layui-input-block">
                    <button class="layui-btn" lay-submit lay-filter="formDemo">登录</button> 
                </div>
            </div>
        </form>
    </div>

CGI侧:login.c 编译命令:arm-openwrt-linux-muslgnueabi-gcc -o login.cgi login.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 函数:解码 URL 编码的字符串
void url_decode(char *str) {
    char *src = str;
    char *dst = str;
    while (*src) {
        if (*src == '+') {
            *dst = ' ';
        } else if (*src == '%' && src[1] && src[2]) {
            *dst = (char) strtol(src + 1, NULL, 16);
            src += 2;
        } else {
            *dst = *src;
        }
        src++;
        dst++;
    }
    *dst = '\0';
}
// 解析 URL 编码的表单数据
void parse_form_data(char *data, char *username, char *password) {
    char *token;
    char *key, *value;
  
#if 0
printf("<h1>Received Data:</h1>\n");
`printf("&lt;p&gt;%s&lt;/p&gt;\n",&nbsp;data);
printf("&lt;ul&gt;\n");

printf("&lt;/ul&gt;\n");&nbsp;
`
#endif 
char *saveptr; 
token = strtok_r(data, "&", &saveptr);
while (token) {
key = strtok(token, "=");
value = strtok(NULL, "=");
`	if&nbsp;(key&nbsp;&amp;&amp;&nbsp;value)&nbsp;{
		url_decode(key);
		url_decode(value);
		//printf("&lt;li&gt;&lt;strong&gt;%s:&lt;/strong&gt;&nbsp;%s&lt;/li&gt;\n",&nbsp;key,&nbsp;value);
		if&nbsp;(strcmp(key,&nbsp;"username")&nbsp;==&nbsp;0)&nbsp;{
			strncpy(username,&nbsp;value,&nbsp;50);
		}
		if&nbsp;(strcmp(key,&nbsp;"password")&nbsp;==&nbsp;0)&nbsp;{
			strncpy(password,&nbsp;value,&nbsp;50);
		}
		&nbsp;
	}

	token&nbsp;=&nbsp;strtok_r(NULL,&nbsp;"&amp;",&nbsp;&amp;saveptr);
}
`
}
static char* readFileContents(const char* filename, size_t* fileSize) {
    if (filename == NULL){
return NULL;
    }
    // 打开文件
    FILE* file = fopen(filename, "rb");
    if (file == NULL) {
        perror("Failed to open file");
        return NULL;
    }
    // 移动文件指针到末尾,获取文件大小
    fseek(file, 0, SEEK_END);
    long size = ftell(file);
    if (size < 0) {
        perror("Failed to determine file size");
        fclose(file);
        return NULL;
    }
    // 重置文件指针到文件开头
    rewind(file);
    // 分配内存缓冲区
    char* buffer = (char*)malloc(size + 128); // +1 是为了存储结尾的 '\0'
    if (buffer == NULL) {
        perror("Failed to allocate memory");
        fclose(file);
        return NULL;
    }
    // 读取文件内容到缓冲区
    size_t bytesRead = fread(buffer, 1, size, file);
    if (bytesRead != size) {
        perror("Failed to read the complete file");
        free(buffer);
        fclose(file);
        return NULL;
    }
    // 添加字符串结束符(对于二进制文件可选)
    buffer[size] = '\0';
    
if (buffer[size -1] == '\n' || buffer[size -2] == '\n'){
if (buffer[size -2] == '\n'){
    buffer[size -2] = '\0';
}else{
    buffer[size -1] = '\0'; 
} 
}
    // 关闭文件
    fclose(file);
    // 返回文件大小和内容
    if (fileSize != NULL) {
        *fileSize = size;
    }
    return buffer;
}
int main() {
    // 获取请求方法
    char *request_method = getenv("REQUEST_METHOD");
    if (!request_method) {
        printf("Content-Type: text/html\r\n\r\n");
        printf("<h1>Error: No request method.</h1>\n");
        return 1;
    }
    char username[50] = {0};
    char password[50] = {0};
    if (strcmp(request_method, "GET") == 0) {
        // 处理 GET 请求
        char *query_string = getenv("QUERY_STRING");
        if (!query_string) {
            printf("Content-Type: text/html\r\n\r\n");
            printf("<h1>Error: No form data received.</h1>\n");
            return 1;
        }
        parse_form_data(query_string, username, password);
    } else if (strcmp(request_method, "POST") == 0) {
        // 处理 POST 请求
        char *content_length_str = getenv("CONTENT_LENGTH");
        if (!content_length_str) {
            printf("Content-Type: text/html\r\n\r\n");
            printf("<h1>Error: No content length.</h1>\n");
            return 1;
        }
        int content_length = atoi(content_length_str);
        char *data = malloc(content_length + 1);
        fread(data, 1, content_length, stdin);
        data[content_length] = '\0';
        parse_form_data(data, username, password); 
        free(data);
 
    } else {
        printf("Content-Type: text/html\r\n\r\n");
        printf("<h1>Error: Unsupported request method.</h1>\n");
        return 1;
    }
    // 简单的用户验证
    if (strcmp(username, "admin") == 0 && strcmp(password, "admin") == 0) {
        // 登录成功,跳转到欢迎页面
        //printf("Location: /home.html\r\n\r\n");
//回显home.html界面
char ip[128] = "\0";
char netmask[128] = "\0";
char gateway[128] = "\0";
`	size_t&nbsp;fileSize&nbsp;=&nbsp;0;
	char&nbsp;*fileContent&nbsp;=&nbsp;readFileContents("/lighttpd/htdocs/cgi-bin/ip.config",&nbsp;&amp;fileSize);
	const&nbsp;char&nbsp;*delimiter&nbsp;=&nbsp;"#";
	if&nbsp;(fileContent&nbsp;!=&nbsp;NULL){&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//sscanf(fileContent,&nbsp;"%s#%s#%s",&nbsp;ip,&nbsp;netmask,&nbsp;gateway);
		//&nbsp;使用&nbsp;strtok&nbsp;分割字符串
		char&nbsp;*token&nbsp;=&nbsp;strtok(fileContent,&nbsp;delimiter);

		//&nbsp;输出分割后的字符串
		int&nbsp;count&nbsp;=&nbsp;0;
		int&nbsp;i=0;
		while&nbsp;(token&nbsp;!=&nbsp;NULL)&nbsp;{
			//printf("Part&nbsp;%d:&nbsp;%s\n",&nbsp;++count,&nbsp;token);
			if&nbsp;(i==0){
				sprintf(ip,&nbsp;"%s",&nbsp;token);
			}else&nbsp;if&nbsp;(i==1){
				sprintf(netmask,&nbsp;"%s",&nbsp;token);
				
			}else&nbsp;if&nbsp;(i==2){
				sprintf(gateway,&nbsp;"%s",&nbsp;token);
				
			}else{
			}
			
			i++;
			token&nbsp;=&nbsp;strtok(NULL,&nbsp;delimiter);
		}

	}&nbsp;
	printf("Location:&nbsp;/home.html?ip=%s&amp;netmask=%s&amp;gateway=%s\r\n\r\n",&nbsp;
			ip,&nbsp;netmask,&nbsp;gateway
			);
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(fileContent!=&nbsp;NULL){
	&nbsp;&nbsp;&nbsp;&nbsp;free(fileContent);
	}
	if&nbsp;(sipFileContent!=&nbsp;NULL){
	&nbsp;&nbsp;&nbsp;&nbsp;free(sipFileContent);
	}
`
    } else {  
        // 登录失败,显示错误信息
        printf("Content-Type: text/html\r\n\r\n");
        printf("<h1>Login Failed!</h1>\n");
        printf("<p>Invalid %s or %s.</p>\n",username,password);
        printf("<p><a href='/index.html'>Try again</a></p>\n");
    }
    return 0;
}


问题3、模版文件如何实现。CGI程序读取html文件后,动态替换其中的模板参数。

html文件侧:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>CGI Form Example</title>
</head>
<body>
    <h1>Enter Your Details</h1>
    <form action="/cgi-bin/echo.cgi" method="post">
        <label for="username">Username:</label>
        <input type="text" id="username" name="username" required><br><br>
        <label for="email">Email:</label>
        <input type="email" id="email" name="email" required><br><br>
        <input type="submit" value="Submit">
    </form>
</body>
</html>

CGI程序侧:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 替换字符串中的占位符
void replace_placeholder(char *str, const char *placeholder, const char *value) {
    char buffer[4096]; // 更大的缓冲区,防止溢出
    char *pos;
    int placeholder_len = strlen(placeholder);
    int value_len = strlen(value);
    while ((pos = strstr(str, placeholder)) != NULL) {
        // 复制占位符之前的部分
        strncpy(buffer, str, pos - str);
        buffer[pos - str] = '\0';
        // 添加替换值
        strcat(buffer, value);
        // 添加占位符之后的部分
        strcat(buffer, pos + placeholder_len);
        // 将结果复制回原字符串
        strcpy(str, buffer);
    }
}
int main() {
    // 设置 HTTP 响应头
    printf("Content-Type: text/html\r\n\r\n");
    // 获取查询字符串(GET 参数)
    char *query_string = getenv("QUERY_STRING");
    if (!query_string) {
        printf("<h1>Error: No query string.</h1>\n");
        return 1;
    }
    // 解析查询字符串
    char username[50] = {0};
    char email[50] = {0};
    char *token;
    token = strtok(query_string, "&");
    while (token != NULL) {
        if (strstr(token, "username=") == token) {
            strncpy(username, token + 9, 50);
        } else if (strstr(token, "email=") == token) {
            strncpy(email, token + 6, 50);
        }
        token = strtok(NULL, "&");
    }
    // 读取 HTML 模板文件
    FILE *file = fopen("/lighttpd/htdocs/home.html", "r");
    if (!file) {
        printf("<h1>Error: Unable to open template file.</h1>\n");
        return 1;
    }
    // 读取文件内容
    char template[4096] = {0};
    fread(template, 1, sizeof(template), file);
    fclose(file);
    // 替换占位符
    replace_placeholder(template, "{{username}}", username);
    replace_placeholder(template, "{{email}}", email);
    // 输出动态生成的 HTML
    printf("%s", template);
    return 0;
}



呱牛笔记





赞(0)
未经允许不得转载:工具盒子 » DeepSeek+半天实现一个lighttpd服务程序