项目(购物商城)

main函数

cpp 复制代码
#include "fun.h"
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>
int main(int argc, char **argv)
{
    int listfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == listfd)
    {
        perror("socket");
        return 1;
    }

    struct sockaddr_in ser, cil;
    bzero(&ser, sizeof(ser));
    bzero(&cil, sizeof(cil));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(80);
    ser.sin_addr.s_addr = INADDR_ANY;
    int ret = bind(listfd, (SA)&ser, sizeof(ser));
    if (-1 == ret)
    {
        perror("bind");
        return 1;
    }

    listen(listfd, 3);

    while (1)
    {
        socklen_t len = sizeof(cil);
        int conn = accept(listfd, (SA)&cil, &len);
        if (-1 == conn)
        {
            perror("accept");
            continue;
        }

        char buf[1024] = {0};
        int ret = recv(conn, buf, sizeof(buf), 0);
        if (ret <= 0)
        {
            close(conn);
            continue;
        }
        printf("%s\n", buf);
        fflush(stdout);

        char *url = strtok(buf, " ");
        url = strtok(NULL, " ");
        char *val = strtok(NULL, "\r");

        if (0 == strcmp(url, "/"))
        {
            send_file(conn, "./log_in.html", FILE_HTML);
        }
        else if (0 == strncmp(url, "/login", 6))
        {
            char *name = strstr(url, "username=");
            name += 9;
            char *pass = strchr(name, '=');
            pass += 1;
            char *end = strchr(name, '&');
            *end = '\0';

            int is_signup = (strstr(url, "action=signup") != NULL);

            sqlite3 *db = NULL;
            int ret = sqlite3_open("1.db", &db);
            if (ret != SQLITE_OK)
            {
                fprintf(stderr, "sqlite3_open %s\n", sqlite3_errmsg(db));
                sqlite3_close(db);
                break;
            }
            char *errmsg = NULL;
            int flag = sql_login(db, errmsg, name, pass);
            // 在 main 函数中,当用户登录成功后:
            if (flag)
            {
                // 打开商品数据库
                sqlite3 *db2 = NULL;
                int ret2 = sqlite3_open("16web/123.db", &db2);
                if (ret2 != SQLITE_OK)
                {
                    fprintf(stderr, "open 123.db error: %s\n", sqlite3_errmsg(db2));
                    sqlite3_close(db2);
                    close(conn);
                    continue;
                }
                send_homepage(db2, conn);
            }
            else
            {
                if (is_signup)
                {
                    int errmsg_signup = sql_signup(db, errmsg, name, pass);
                    if (errmsg_signup)
                    {
                        int flag = sql_login(db, errmsg, name, pass);

                        if (flag)
                        {
                            sqlite3 *db2 = NULL;
                            int ret2 = sqlite3_open("16web/123.db", &db2);
                            if (ret2 != SQLITE_OK)
                            {
                                fprintf(stderr, "open 123.db error: %s\n", sqlite3_errmsg(db2));
                                sqlite3_close(db2);
                                close(conn);
                                continue;
                            }
                            send_homepage(db2, conn);
                        }
                    }
                    else
                    {
                        send_file(conn, "./log_error.html", FILE_HTML);
                    }
                }
                else
                {
                    send_file(conn, "./log_error.html", FILE_HTML);
                }
            }
            sqlite3_close(db);
        }

        else if (0 == strncmp(url, "/search", 7))
        {
            char *want_find = strstr(url, "want=");
            if (!want_find)
            {
                const char *badreq = "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n";
                send(conn, badreq, strlen(badreq), 0);
                close(conn);
                continue;
            }
            want_find += 5;
            urldecode(want_find);

            sqlite3 *db = NULL;
            int ret = sqlite3_open("16web/123.db", &db);
            if (ret != SQLITE_OK)
            {
                fprintf(stderr, "DB open error: %s\n", sqlite3_errmsg(db));
                sqlite3_close(db);
                close(conn);
                continue;
            }

            // 使用参数化查询防止 SQL 注入(推荐)
            const char *sql =
                "SELECT goods_name, keywords, goods_desc, goods_thumb, goods_img FROM goods WHERE goods_name "
                "LIKE ? LIMIT 1;";
            sqlite3_stmt *stmt;
            if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK)
            {
                fprintf(stderr, "Prepare error: %s\n", sqlite3_errmsg(db));
                sqlite3_close(db);
                close(conn);
                continue;
            }

            char like_pattern[512];
            snprintf(like_pattern, sizeof(like_pattern), "%%%s%%", want_find);
            sqlite3_bind_text(stmt, 1, like_pattern, -1, SQLITE_STATIC);

            char response[8192] = {0};
            int total = 0;

            if (sqlite3_step(stmt) == SQLITE_ROW)
            {
                const char *name = (const char *)sqlite3_column_text(stmt, 0);
                const char *keywords = (const char *)sqlite3_column_text(stmt, 1);
                const char *desc = (const char *)sqlite3_column_text(stmt, 2);
                const char *thumb = (const char *)sqlite3_column_text(stmt, 3);
                const char *image = (const char *)sqlite3_column_text(stmt, 4);

                total = snprintf(response, sizeof(response),
                    "HTTP/1.1 200 OK\r\n"
                    "Content-Type: text/html; charset=utf-8\r\n"
                    "Connection: close\r\n"
                    "\r\n"
                    "<!DOCTYPE html>\n"
                    "<html><head><meta charset=\"utf-8\"><title>%s</title></head>\n"
                    "<style>\n"
                    "body{background-image: url(background.jpg);"
                    "background-repeat: no-repeat;"
                    "background-size: cover;"
                    "background-position: center;"
                    "text-align: center;"
                    "margin: 0;"
                    "padding: 20px;"
                    "min-height: 100vh;"
                    "box-sizing: border-box;}"
                    "  </style>\n"
                    "<body>\n"
                    "<h1>%s</h1>\n"
                    "<p><b>关键词:</b> %s</p>\n"
                    "<p><b>描述:</b> %s</p>\n",
                    name, name, keywords ? keywords : "", desc ? desc : "");

                if (image && strlen(image) > 0)
                {
                    char goods_img[4096];
                    snprintf(goods_img, sizeof(goods_img), "/16web/%s", image);
                    total += snprintf(response + total, sizeof(response) - total,
                        "<p><img src=\"%s\" alt=\"%s\" style=\"max-width:300px;\"></p>\n", goods_img, name);
                }

                total += snprintf(response + total, sizeof(response) - total, "</body></html>");
                send(conn, response, total, 0);
            }
            else
            {
                const char *notfound = "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n<h1>未找到商品</h1>";
                send(conn, notfound, strlen(notfound), 0);
            }

            sqlite3_finalize(stmt);
            sqlite3_close(db);
        }

        else if (0 == strncmp(url, "/sousuo", 7))
        {
            char *want_find = strstr(url, "want=");
            if (!want_find)
            {
                const char *badreq = "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n";
                send(conn, badreq, strlen(badreq), 0);
                close(conn);
                continue;
            }
            want_find += 5;       // 跳过 "want="
            urldecode(want_find); // 解码 URL 编码(如 %E6%89%8B%E6%9C%BA → 手机)

            // 打开数据库
            sqlite3 *db = NULL;
            if (sqlite3_open("16web/123.db", &db) != SQLITE_OK)
            {
                fprintf(stderr, "DB open error: %s\n", sqlite3_errmsg(db));
                sqlite3_close(db);
                close(conn);
                continue;
            }

            // ✅ 安全的参数化查询:使用 ? 占位符
            const char *sql = "SELECT goods_name, goods_thumb FROM goods WHERE goods_name LIKE ?";
            sqlite3_stmt *stmt;
            if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK)
            {
                fprintf(stderr, "SQL prepare failed: %s\n", sqlite3_errmsg(db));
                sqlite3_close(db);
                close(conn);
                continue;
            }

            // 构造 LIKE 模式:%用户输入%
            char like_pattern[512];
            snprintf(like_pattern, sizeof(like_pattern), "%%%s%%", want_find);

            // 绑定参数(自动处理特殊字符,防注入)
            sqlite3_bind_text(stmt, 1, like_pattern, -1, SQLITE_STATIC);

            // 构建 HTML 响应
            char response[65536] = {0};
            int total = snprintf(response, sizeof(response),
                "HTTP/1.1 200 OK\r\n"
                "Content-Type: text/html; charset=utf-8\r\n"
                "Connection: close\r\n"
                "\r\n"
                "<!DOCTYPE html>\n"
                "<html>\n"
                "<head>\n"
                "  <meta charset=\"utf-8\">\n"
                "  <title>搜索结果</title>\n"
                "  <style>\n"
                "    .product { display: inline-block; margin: 10px; text-align: center; width: 180px; }\n"
                "    .product img { max-width: 160px; height: auto; border: 1px solid #ddd; }\n"
                "    .product p { font-size: 14px; margin: 5px 0; }\n"
                "body{background-image: url(background.jpg);"
                "background-repeat: no-repeat;"
                "background-size: cover;"
                "background-position: center;"
                "text-align: center;"
                "margin: 0;"
                "padding: 20px;"
                "min-height: 100vh;"
                "box-sizing: border-box;}"
                "  </style>\n"
                "</head>\n"
                "<body>\n");

            int found = 0;
            // 遍历所有匹配的商品
            while (sqlite3_step(stmt) == SQLITE_ROW && total < (int)sizeof(response) - 1000)
            {
                found = 1;
                const char *name = (const char *)sqlite3_column_text(stmt, 0);
                const char *thumb = (const char *)sqlite3_column_text(stmt, 1); // 第1列!

                // 对商品名进行 URL 编码,用于生成安全链接
                char encoded_name[2048];
                strncpy(encoded_name, name, sizeof(encoded_name) - 1);
                encoded_name[sizeof(encoded_name) - 1] = '\0';
                urlencode(encoded_name);

                total += snprintf(response + total, sizeof(response) - total,
                    "<div class=\"product\">\n"
                    "  <a href=\"/search?want=%s\"><img src=\"/16web/%s\" alt=\"%s\"></a>\n"
                    "  <p><a href=\"/search?want=%s\">%s</a></p>\n"
                    "</div>\n",
                    encoded_name, thumb ? thumb : "", name, encoded_name, name);
            }

            if (!found)
            {
                total +=
                    snprintf(response + total, sizeof(response) - total, "<p>未找到包含"%s"的商品。</p>", want_find);
            }

            total += snprintf(response + total, sizeof(response) - total, "</body></html>");
            send(conn, response, total, 0);

            // 清理资源
            sqlite3_finalize(stmt);
            sqlite3_close(db);
        }

        else if (strlen(url) > 4 && 0 == strcmp(&url[strlen(url) - 4], ".jpg"))
        {
            send_file(conn, url + 1, FILE_JPG);
        }
        else if (strlen(url) > 4 && 0 == strcmp(&url[strlen(url) - 4], ".ico"))
        {
            send_file(conn, "label.ico", FILE_PNG);
        }
        else if (strlen(url) > 4 && 0 == strcmp(&url[strlen(url) - 4], ".png"))
        {
            send_file(conn, url + 1, FILE_PNG);
        }
        else if (strlen(url) > 4 && 0 == strcmp(&url[strlen(url) - 4], ".bmp"))
        {
            send_file(conn, url + 1, FILE_BMP);
        }
        else if (strlen(url) > 5 && 0 == strcmp(&url[strlen(url) - 5], ".html"))
        {
            send_file(conn, url + 1, FILE_HTML);
        }
        close(conn);
    }
    close(listfd);
    return 0;
}

fun.c

cpp 复制代码
#include "fun.h"
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>

long file_size(char *file)
{
    int fd = open(file, O_RDONLY);
    if (-1 == fd)
    {
        perror("file size open error");
        fprintf(stderr, "filename is %s\n", file);
        return 0;
    }
    long size = lseek(fd, 0, SEEK_END);
    return size;
}

int send_head(int conn, char *file, FILE_TYPE type)
{
    char buf[256] = {0};
    char *http_cmd[7] = {NULL};
    http_cmd[0] = "HTTP/1.1 200 OK\r\n";
    http_cmd[1] = "Date: Wed, 31 Dec 2025 01:58:31 GMT\r\n";
    switch (type)
    {
    case FILE_HTML:
        http_cmd[2] = "Content-Type: text/html;charset=utf-8\r\n";
        break;
    case FILE_PNG:
        http_cmd[2] = "Content-Type: image/png\r\n";
        break;
    case FILE_JPG:
        http_cmd[2] = "Content-Type: image/jpeg\r\n";
        break;
    case FILE_BMP:
        http_cmd[2] = "Content-Type: image/bmp\r\n";
    default:
        http_cmd[2] = "Content-Type: text/html;charset=utf-8\r\n";
    }

    http_cmd[3] = buf;
    sprintf(buf, "content-length: %ld\r\n", file_size(file));
    http_cmd[4] = "Connection: keep-closed\r\n";
    http_cmd[5] = "Server: MYWEBSer\r\n";
    http_cmd[6] = "Content-Language: zh-CN\r\n\r\n";

    int i = 0;
    for (i = 0; i < 7; i++)
    {
        send(conn, http_cmd[i], strlen(http_cmd[i]), 0);
    }
    return 0;
}

int send_file(int conn, char *filename, FILE_TYPE type)
{
    send_head(conn, filename, type);
    int fd = open(filename, O_RDONLY);
    if (-1 == fd)
    {
        perror("open");
        return 1;
    }
    while (1)
    {
        char buf[4096] = {0};
        int rd_ret = read(fd, buf, sizeof(buf));
        if (rd_ret <= 0)
        {
            break;
        }
        send(conn, buf, rd_ret, 0);
    }
    close(fd);
    return 0;
}

int select_login(void *arg, int col, char **result, char **title)
{
    *(int *)arg = 1;
    return 0;
}
int sql_login(sqlite3 *db, char *errmsg, char *name, char *pass)
{
    int flag = 0;
    char sql_cmd[1024] = {0};
    sprintf(sql_cmd, "select * from html where id = '%s' and pass = '%s';", name, pass);
    int ret = sqlite3_exec(db, sql_cmd, select_login, &flag, &errmsg);
    if (ret != SQLITE_OK)
    {
        fprintf(stderr, "sqlite3_exec %s\n", errmsg);
        sqlite3_free(errmsg);
    }
    return flag;
}
int sql_signup(sqlite3 *db, char *errmsg, char *name, char *pass)
{
    char sql_cmd[1024] = {0};
    sprintf(sql_cmd, "insert into html values('%s','%s');", name, pass);
    int ret = sqlite3_exec(db, sql_cmd, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK)
    {
        fprintf(stderr, "sqlite3_exec %s\n", errmsg);
        return 0;
        sqlite3_free(errmsg);
    }
    return 1;
}

#define BURSIZE 2048

int hex2dec(char c)
{
    if ('0' <= c && c <= '9')
    {
        return c - '0';
    }
    else if ('a' <= c && c <= 'f')
    {
        return c - 'a' + 10;
    }
    else if ('A' <= c && c <= 'F')
    {
        return c - 'A' + 10;
    }
    else
    {
        return -1;
    }
}

char dec2hex(short int c)
{
    if (0 <= c && c <= 9)
    {
        return c + '0';
    }
    else if (10 <= c && c <= 15)
    {
        return c + 'A' - 10;
    }
    else
    {
        return -1;
    }
}

//编码一个url
void urlencode(char url[])
{
    int i = 0;
    int len = strlen(url);
    int res_len = 0;
    char res[BURSIZE];
    for (i = 0; i < len; ++i)
    {
        char c = url[i];
        if (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '/' || c == '.')
        {
            res[res_len++] = c;
        }
        else
        {
            int j = (short int)c;
            if (j < 0)
                j += 256;
            int i1, i0;
            i1 = j / 16;
            i0 = j - i1 * 16;
            res[res_len++] = '%';
            res[res_len++] = dec2hex(i1);
            res[res_len++] = dec2hex(i0);
        }
    }
    res[res_len] = '\0';
    strcpy(url, res);
}

// 解码url
void urldecode(char url[])
{
    int i = 0;
    int len = strlen(url);
    int res_len = 0;
    char res[BURSIZE];
    for (i = 0; i < len; ++i)
    {
        char c = url[i];
        if (c != '%')
        {
            res[res_len++] = c;
        }
        else
        {
            char c1 = url[++i];
            char c0 = url[++i];
            int num = 0;
            num = hex2dec(c1) * 16 + hex2dec(c0);
            res[res_len++] = num;
        }
    }
    res[res_len] = '\0';
    strcpy(url, res);
}

// fun.c
int callback(void *data, int argc, char **argv, char **azColName)
{
    struct SearchResult *result = (struct SearchResult *)data;

    if (result->count >= 50)
    {
        return 0; // 超过上限,不再保存
    }

    struct GoodsItem *item = &result->items[result->count];

    // 安全复制字段(对照 SELECT 顺序!)
    strncpy(item->goods_name, argv[0] ? argv[0] : "", 512 - 1);
    strncpy(item->keywords, argv[1] ? argv[1] : "", 1024 - 1);
    strncpy(item->goods_thumb, argv[2] ? argv[2] : "", 1024 - 1);
    strncpy(item->goods_img, argv[3] ? argv[3] : "", 1024 - 1);
    strncpy(item->original_img, argv[4] ? argv[4] : "", 1024 - 1);

    // 确保字符串以 \0 结尾
    item->goods_name[512 - 1] = '\0';
    item->keywords[1024 - 1] = '\0';
    item->goods_thumb[1024 - 1] = '\0';
    item->goods_img[1024 - 1] = '\0';
    item->original_img[1024 - 1] = '\0';

    result->count++;
    return 0;
}

int send_homepage(sqlite3 *db2, int conn)
{
    const char *sql = "SELECT goods_name, goods_thumb FROM goods;";
    sqlite3_stmt *stmt;
    if (sqlite3_prepare_v2(db2, sql, -1, &stmt, NULL) != SQLITE_OK)
    {
        fprintf(stderr, "SQL prepare error: %s\n", sqlite3_errmsg(db2));
        sqlite3_close(db2);
        close(conn);
    }

    // 构建响应
    char response[65536] = {0};
    int total = snprintf(response, sizeof(response),
        "HTTP/1.1 200 OK\r\n"
        "Content-Type: text/html; charset=utf-8\r\n"
        "Connection: close\r\n"
        "\r\n"
        "<!DOCTYPE html>\n"
        "<html>\n"
        "<head>\n"
        "  <meta charset=\"utf-8\">\n"
        "  <style>\n"
        "    .product { display: inline-block; margin: 10px; text-align: center; width: 180px; }\n"
        "    .product img { max-width: 160px; height: auto; border: 1px solid #ddd; }\n"
        "    .product p { font-size: 14px; margin: 5px 0; }\n"
        "body{		background-image: url(background.jpg);"
        "background-repeat: no-repeat;"
        "background-size: cover;"
        "background-position: center;"
        "text-align: center;"
        "margin: 0;"
        "padding: 20px;"
        "min-height: 100vh;"
        "box-sizing: border-box;}"
        "  </style>\n"
        "</head>\n"
        "<body>\n"
        "<form action=\"/sousuo\" method=\"GET\" class=\"search-box\">\n"
        "<input type=\"text\" name=\"want\" placeholder=\"搜索\" required>\n"
        "<input type=\"submit\" value=\"搜索\">\n"
        "</form>\n");

    while (sqlite3_step(stmt) == SQLITE_ROW) //&& total < (int)sizeof(response) - 1000)
    {
        const char *name = (const char *)sqlite3_column_text(stmt, 0);
        const char *thumb = (const char *)sqlite3_column_text(stmt, 1);

        // 使用 urlencode 对商品名进行编码,以便安全地作为 URL 参数传递
        char encoded_name[2048];
        strcpy(encoded_name, name);
        urlencode(encoded_name);

        total += sprintf(response + total, 

            "<div class=\"product\">\n"
            "  <a href=\"/search?want=%s\"><img src=\"/16web/%s\" alt=\"%s\"></a>\n"
            "  <p><a href=\"/search?want=%s\">%s</a></p>\n"
            "</div>\n",
            encoded_name, thumb, name, encoded_name, name);
    }
    total += sprintf(response + total,
        "</body>\n"
        "</html>\n");

    send(conn, response, total, 0);

    sqlite3_finalize(stmt);
    sqlite3_close(db2);
    return 0;
}

fun.h

cpp 复制代码
#ifndef __FUN_H_
#define __FUN_H_
#include <sqlite3.h>
typedef struct sockaddr *(SA);
typedef enum
{
    FILE_HTML,
    FILE_PNG,
    FILE_JPG,
    FILE_BMP
} FILE_TYPE;
long file_size(char* file);
int send_head(int conn, char* file, FILE_TYPE type);
int send_file(int conn, char* filename, FILE_TYPE type);
int select_login(void *arg, int col, char **result, char **title);
int sql_login(sqlite3 *db,char *errmsg,char *name ,char *pass);
int sql_signup(sqlite3 *db,char *errmsg,char *name ,char *pass);
int hex2dec(char c);
char dec2hex(short int c);
void urlencode(char url[]);
void urldecode(char url[]);


int callback(void *data, int argc, char **argv, char **azColName);
// fun.h

struct GoodsItem {
    char goods_name[512];
    char keywords[1024];
    char goods_thumb[1024];
    char goods_img[1024];
    char original_img[1024];
    char goods_desc[1024];
};

struct SearchResult {
    int count;                          // 实际找到多少个
    struct GoodsItem items[50];         // 商品列表
};

int send_homepage(sqlite3 *db2, int conn);
#endif

上述为程序源码。

下面就是实现效果,

1.登录界面

2.未注册则跳转注册界面

3.注册完成后登录则进入商城界面

4.点击搜索框可搜索商品(例:搜索三星)

(点击图形也可跳转详情界面。。。。)

5.跳转搜索三星后界面

(点击图片则进入详情页)

6.进入详情页

程序到这执行基本完毕。(也可退回点击其他商品进行查看商品详情)

相关推荐
Qhumaing16 小时前
C++学习:【PTA】数据结构 7-2 实验6-2(图-邻接表)
数据结构·c++·学习
方便面不加香菜16 小时前
基于顺序表实现通讯录项目
c语言·数据结构
摸鱼仙人~16 小时前
大模型文章生成的风格个性化与多文体写作:一套可落地的方法论
linux·运维·服务器
煤球王子16 小时前
浅学文件系统4(页面缓存)
linux
peixiuhui16 小时前
Iotgateway技术手册-1. 项目概述
linux·网关·iot·modbus·数据采集网关·iotgateway·采集软件
wdfk_prog16 小时前
[Linux]学习笔记系列 -- [fs]sysfs
linux·笔记·学习
AllFiles16 小时前
Linux 网络故障排查:如何诊断与解决 ARP 缓存溢出问题
linux·后端
꧁Q༒ོγ꧂16 小时前
算法详解(三)--递归与分治
开发语言·c++·算法·排序算法
爬山算法16 小时前
Hibernate(30)Hibernate的Named Query是什么?
服务器·前端·hibernate