使用mysql保存密码

登录MySQL

这行命令告诉MySQL客户端程序用户root准备登录,-p表示告诉 MySQL 客户端程序提示输入密码。

mysql -u root -p

在这里插入图片描述

创建数据库

create database wifi;
use wifi;

在这里插入图片描述

create table password(user_password CHAR(8),primary key(user_password));

在这里插入图片描述

源码

代码编译

g++ wificreate.cpp -o wificreate -lmysqlclient

在这里插入图片描述

源码

#include <iostream>
#include <cstring>
#include <random>
#include <ctime>
#include <algorithm>
#include <mysql/mysql.h>

std::string generatePassword() {
    const char* const numbers = "0123456789";
    const char* const upperchar = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const char* const lowechar = "abcdefghijklmnopqrstuvwxyz";
    const char* const specials = "!@#$%^&*()-_=+[]{}|;:,.<>?";
    const int numChars = 8; // 密码长度

    std::string password;
    std::random_device rd;
    std::mt19937 generator(rd());
    std::uniform_int_distribution<> dis;

    // 初始化密码,确保包含至少一个数字、一个大写字母、一个小写字母和一个特殊字符
    password += numbers[dis(generator) % 10];
    password += upperchar[dis(generator) % 26];
    password += lowechar[dis(generator) % 26];
    password += specials[dis(generator) % 32];

    // 填充剩余的字符
    for (int i = 4; i < numChars; ++i) {
        std::string allChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()-_=+[]{}|;:,.<>?";
        dis = std::uniform_int_distribution<>(0, allChars.size() - 1);
        password += allChars[dis(generator)];
    }

    // 打乱密码中的字符顺序,以确保随机性
    std::shuffle(password.begin(), password.end(), generator);

    return password;
}

bool isPasswordValid(const std::string& password) {
    if (password.length() != 8) {
        return false;
    }

    bool hasDigit = false;
    bool hasUpper = false;
    bool hasLower = false;
    bool hasSpecial = false;

    const std::string specials = "!@#$%^&*()-_=+[]{}|;:,.<>?";

    for (char ch : password) {
        if (isdigit(ch)) {
            hasDigit = true;
        } else if (isupper(ch)) {
            hasUpper = true;
        } else if (islower(ch)) {
            hasLower = true;
        } else if (specials.find(ch) != std::string::npos) {
            hasSpecial = true;
        }

        if (hasDigit && hasUpper && hasLower && hasSpecial) {
            return true;
        }
    }

    return hasDigit && hasUpper && hasLower && hasSpecial;
}

bool insertOrUpdatePassword(MYSQL* conn, const std::string& password) {
    const char* insert_sql = "INSERT INTO password (user_password) VALUES (?) ON DUPLICATE KEY UPDATE user_password=VALUES(user_password)";
    MYSQL_STMT* stmt = mysql_stmt_init(conn);
    if (!stmt) {
        std::cerr << "stmt init failed" << std::endl;
        return false;
    }
    if (mysql_stmt_prepare(stmt, insert_sql, strlen(insert_sql))) {
        std::cerr << "prepare failed: " << mysql_error(conn) << std::endl;
        mysql_stmt_close(stmt);
        return false;
    }

    MYSQL_BIND bind[1];
    memset(bind, 0, sizeof(bind));

    bind[0].buffer_type = MYSQL_TYPE_STRING;
    bind[0].buffer = (char*)password.c_str();
    bind[0].buffer_length = password.length();

    if (mysql_stmt_bind_param(stmt, bind)) {
        std::cerr << "bind failed: " << mysql_error(conn) << std::endl;
        mysql_stmt_close(stmt);
        return false;
    }
    if (mysql_stmt_execute(stmt)) {
        std::cerr << "execute failed: " << mysql_error(conn) << std::endl;
        mysql_stmt_close(stmt);
        return false;
    }
    mysql_stmt_close(stmt);
    return true;
}
bool clearTable(MYSQL* conn, const char* table_name) {
    // 创建一个足够长的缓冲区来存储完整的 SQL 语句
    char clear_sql[256];
    snprintf(clear_sql, sizeof(clear_sql), "DELETE FROM %s", table_name);

    MYSQL_STMT* stmt = mysql_stmt_init(conn);
    if (!stmt) {
        std::cerr << "stmt init failed" << std::endl;
        return false;
    }
    if (mysql_stmt_prepare(stmt, clear_sql, strlen(clear_sql))) {
        std::cerr << "prepare failed: " << mysql_error(conn) << std::endl;
        mysql_stmt_close(stmt);
        return false;
    }

    if (mysql_stmt_execute(stmt)) {
        std::cerr << "execute failed: " << mysql_error(conn) << std::endl;
        mysql_stmt_close(stmt);
        return false;
    }
    mysql_stmt_close(stmt);
    return true;
}

int main(int argc,char* argv[]) {
    
    MYSQL connect;
    if (mysql_init(&connect) == NULL) {
        std::cerr << "mysql init err" << std::endl;
        exit(1);
    }
    if (!mysql_real_connect(&connect, "localhost", "root", "1", "wifi", 3306, NULL, 0)) {
        std::cerr << mysql_error(&connect) << std::endl;
        mysql_close(&connect);
        return 1;
    }

    std::string userPassWord = "";
    std::string rootPassWord = generatePassword();
    std::string initialPassword1 = rootPassWord;
    if (argc > 1) {
    if (strcmp(argv[1], "reset") == 0) {
        std::string initialPassword2 = initialPassword1;  // 假设这是初始密码
        if (!clearTable(&connect, "password")) {
            std::cerr << "Failed to clear the password table." << std::endl;
            mysql_close(&connect);
            return 1;
        }
        if (!insertOrUpdatePassword(&connect, initialPassword2)) {
            std::cerr << "Failed to reset password." << std::endl;
            mysql_close(&connect);
            return 1;
        } else {
            std::cout << "Password has been reset to: " << initialPassword2 << std::endl;
        }
        mysql_close(&connect);
        return 0;
    }
}

    if (!insertOrUpdatePassword(&connect, rootPassWord)) {
        std::cerr << "Failed to insert or update password in database." << std::endl;
        mysql_close(&connect);
        return 1;
    }
    std::cout << "insert success" << std::endl;
    std::cout << "Generated Password :" << rootPassWord << std::endl;
    for (;;) {
        std::cout << "Please enter user password: ";
        std::cin >> userPassWord;
        if (isPasswordValid(userPassWord)) {
            if (!clearTable(&connect, "password")) {
                std::cerr << "Failed to clear table." << std::endl;
            } else {
                std::cout << "Table cleared successfully!" << std::endl;
                if (!insertOrUpdatePassword(&connect, userPassWord)) {
                    std::cerr << "Failed to insert new password into database." << std::endl;
                } else {
                    std::cout << "New password inserted successfully!" << std::endl;
                    std::cout << "New rootPassword :" << userPassWord << std::endl;
                }
            }
            break;
        } else {
            std::cout << "Invalid password!!!" << std::endl;
        }
    }

    mysql_close(&connect);
    return 0;
}

清除函数

bool clearTable(MYSQL* conn, const char* table_name) {
    // 创建一个足够长的缓冲区来存储完整的 SQL 语句
    char clear_sql[256];
    snprintf(clear_sql, sizeof(clear_sql), "DELETE FROM %s", table_name);

    MYSQL_STMT* stmt = mysql_stmt_init(conn);
    if (!stmt) {
        std::cerr << "stmt init failed" << std::endl;
        return false;
    }
    if (mysql_stmt_prepare(stmt, clear_sql, strlen(clear_sql))) {
        std::cerr << "prepare failed: " << mysql_error(conn) << std::endl;
        mysql_stmt_close(stmt);
        return false;
    }

    if (mysql_stmt_execute(stmt)) {
        std::cerr << "execute failed: " << mysql_error(conn) << std::endl;
        mysql_stmt_close(stmt);
        return false;
    }
    mysql_stmt_close(stmt);
    return true;
}

snprintf()

函数原型

int snprintf(char *str, size_t size, const char *format, ...);

snprintf 是一个标准 C 库函数,用于将格式化的数据写入字符串中。它比 sprintf 更安全,因为它可以指定目标缓冲区的最大大小,从而避免缓冲区溢出的问题。

 snprintf(clear_sql, sizeof(clear_sql), "DELETE FROM %s", table_name);

函数参数

char *str

clear_sql:这是目标缓冲区,snprintf 将把格式化后的字符串写入这个变量。它应该是一个字符数组,足够大以存储最终的 SQL 语句。

size_t size

sizeof(clear_sql):这是目标缓冲区的大小。sizeof 运算符用于确定
clear_sql 数组的大小,以确保写入的数据不会超出数组的界限。

const char *format

“DELETE FROM %s”:这是格式化字符串,它包含了要构造的 SQL 语句的模板。%s 是一个占位符,用于插入一个字符串参数。

table_name:这是一个字符串变量,包含了要删除记录的表名。它将替换格式化字符串中的 %s 占位符。

函数功能

行代码的功能是生成一个 DELETE 语句,用于删除指定表 table_name 中的所有记录。例如,如果 table_name 是 “users”,那么生成的 SQL 语句将是 “DELETE FROM users”。

注意事项:

需要确保 table_name 是一个有效的表名,且不包含任何 SQL 注入攻击的风险。在实际应用中,如果 table_name 来自于用户输入,应该进行严格的验证和清理,以防止潜在的安全问题。
snprintf 会在字符串的末尾确保添加空字符(‘\0’),以形成一个正确的 C 字符串。
如果格式化后的字符串长度超过了 clear_sql 缓冲区的大小,snprintf 会根据缓冲区的大小截断字符串,以防止溢出。

MYSQL_STMT结构体

MYSQL_STMT* stmt = mysql_stmt_init(conn);

这行代码是在使用 MySQL C API 时,初始化一个语句对象的步骤。下面是详细解释:

MYSQL_STMT* stmt:

这是一个指向 MYSQL_STMT 结构的指针,MYSQL_STMT 是 MySQL C API 中用于表示预编译 SQL 语句的结构体。

mysql_stmt_init(conn):

mysql_stmt_init 函数用于初始化一个 MYSQL_STMT 结构体,为后续的预编译 SQL 语句做准备。
conn 参数是一个指向 M YSQL 结构的指针,它代表了一个与 MySQL 数据库的连接。这个连接必须在此之前已经成功建立。

功能:

当你调用 mysql_stmt_init(conn) 时,它会为指定的数据库连接 conn 创建一个新的语句对象。
如果初始化成功,函数会返回一个指向新初始化的 MYSQL_STMT 结构的指针,你可以使用这个指针来执行后续的 SQL 语句预编译、参数绑定、执行等操作。
如果初始化失败,函数会返回 NULL。

mysql_stmt_close

在使用完 MYSQL_STMT 对象后,应该调用 mysql_stmt_close 函数来释放与之相关的资源。
在调用 mysql_stmt_init 之前,必须确保 conn 指向的 MYSQL 结构已经通过 mysql_real_connect 或类似的函数成功连接到数据库。
mysql_stmt_init 只是初始化了一个语句对象,你需要使用 mysql_stmt_prepare 函数来准备(预编译)一个 SQL 语句,然后才能执行它。

mysql_stmt_prepare

mysql_stmt_prepare(stmt, clear_sql, strlen(clear_sql))

这行代码是在使用 MySQL C API 时,准备(预编译)一个 SQL 语句的步骤。下面是详细解释:

mysql_stmt_prepare 函数用于预编译一个 SQL 语句,这样可以提高性能,并且可以防止 SQL 注入攻击。

参数解释:

这个函数需要三个参数:一个 MYSQL_STMT 指针,指向要准备的 SQL 语句的字符串,以及 SQL 语句字符串的长度。

stmt

这是一个指向 MYSQL_STMT 结构的指针,它是一个语句对象,之前已经通过 mysql_stmt_init 函数初始化。

clear_sql

这是一个包含要预编译的 SQL 语句的字符串。

strlen(clear_sql)

这是 clear_sql 字符串的长度。使用 strlen 函数来获取长度是为了确保在预编译过程中,MySQL 知道字符串的确切结束位置。

功能:

当你调用 mysql_stmt_prepare(stmt, clear_sql, strlen(clear_sql)) 时,MySQL 会检查 clear_sql 字符串中的 SQL 语句,并准备执行它。
预编译的语句可以包含参数占位符(如 ?),这些占位符在后续的 mysql_stmt_bind_param 调用中会被具体的参数值替换。

返回值:

如果预编译成功,mysql_stmt_prepare 函数返回 0。
如果预编译失败,函数返回非零值,你可以通过 mysql_stmt_error 函数获取错误信息。

注意事项:

在调用 mysql_stmt_prepare 之前,必须确保 stmt 已经通过 mysql_stmt_init 函数初始化。
如果预编译失败,应该检查错误信息,并根据错误信息进行相应的处理。
预编译的语句在使用完成后应该通过 mysql_stmt_close 函数关闭,以释放资源。
预编译语句是数据库操作中的一个重要步骤,它可以提高数据库操作的安全性和效率。通过预编译,数据库服务器可以重用编译后的语句,而不需要每次都解析和编译 SQL 语句。

mysql_stmt_close(stmt)

mysql_stmt_close(stmt) 是 MySQL C API 中用来关闭语句对象的函数调用。下面是对这个函数调用的详细解释:

函数定义:

mysql_stmt_close 是一个函数,用于关闭之前通过 mysql_stmt_init 创建的 MYSQL_STMT 语句对象。

参数:

stmt

这是一个指向 MYSQL_STMT 结构的指针,代表要关闭的语句对象。

功能:

当你完成一个语句对象的所有数据库操作后(例如,预编译 SQL 语句、绑定参数、执行语句等),你应该调用 mysql_stmt_close 来释放与该语句对象关联的所有资源。
这个函数会关闭语句对象,并且释放内存和其他系统资源,确保不会有内存泄漏。

返回值:

mysql_stmt_close 函数没有返回值(它的返回类型是 void)。

注意事项:

在关闭语句对象之前,确保已经完成了所有需要的数据库操作。
如果 stmt 是 NULL,mysql_stmt_close 函数不会有任何效果,因为没有任何资源需要关闭。
在关闭语句对象后,不应该再使用该对象进行任何操作,因为它已经不再有效。
关闭语句对象是一个良好的编程实践,它有助于维护资源的有效管理,并确保应用程序的稳定性和性能。在编写使用 MySQL C API 的应用程序时,应该在不再需要语句对象时及时关闭它们。

mysql_stmt_execute(stmt)

mysql_stmt_execute(stmt) 是 MySQL C API 中用于执行预编译 SQL 语句的函数。下面是对这个函数调用的详细解释:

函数定义:

mysql_stmt_execute 函数用于执行一个已经通过 mysql_stmt_prepare 预编译的 MYSQL_STMT 语句对象。

参数:

stmt:这是一个指向 MYSQL_STMT 结构的指针,代表要执行的预编译语句对象。

功能:

当你调用 mysql_stmt_execute(stmt) 时,MySQL 会执行与 stmt 相关联的预编译 SQL 语句。
这个函数可以执行 SELECT、INSERT、UPDATE、DELETE 等类型的 SQL 语句,具体取决于预编译时提供的 SQL 语句。

返回值:

如果执行成功,mysql_stmt_execute 函数返回 0。
如果执行失败,函数返回非零值,你可以通过 mysql_error 函数获取错误信息,通过 mysql_stmt_errno 函数获取错误代码。

注意事项:

在调用 mysql_stmt_execute 之前,必须确保 stmt 已经通过 mysql_stmt_prepare 预编译。
如果预编译的 SQL 语句包含参数占位符(如 ?),则需要先通过 mysql_stmt_bind_param 函数绑定实际的参数值。
对于 SELECT 语句,执行后可能需要调用 mysql_stmt_store_result 来存储结果集,然后通过 mysql_stmt_fetch 函数来检索结果集中的行。
对于 INSERT、UPDATE 或 DELETE 等不返回结果集的语句,通常不需要存储结果集,但可以通过 mysql_stmt_affected_rows 函数获取受影响的行数。

插入函数

bool insertOrUpdatePassword(MYSQL* conn, const std::string& password) {
    const char* insert_sql = "INSERT INTO password (user_password) VALUES (?) ON DUPLICATE KEY UPDATE user_password=VALUES(user_password)";
    MYSQL_STMT* stmt = mysql_stmt_init(conn);
    if (!stmt) {
        std::cerr << "stmt init failed" << std::endl;
        return false;
    }
    if (mysql_stmt_prepare(stmt, insert_sql, strlen(insert_sql))) {
        std::cerr << "prepare failed: " << mysql_error(conn) << std::endl;
        mysql_stmt_close(stmt);
        return false;
    }

    MYSQL_BIND bind[1];
    memset(bind, 0, sizeof(bind));

    bind[0].buffer_type = MYSQL_TYPE_STRING;
    bind[0].buffer = (char*)password.c_str();
    bind[0].buffer_length = password.length();

    if (mysql_stmt_bind_param(stmt, bind)) {
        std::cerr << "bind failed: " << mysql_error(conn) << std::endl;
        mysql_stmt_close(stmt);
        return false;
    }
    if (mysql_stmt_execute(stmt)) {
        std::cerr << "execute failed: " << mysql_error(conn) << std::endl;
        mysql_stmt_close(stmt);
        return false;
    }
    mysql_stmt_close(stmt);
    return true;
}

mysql_stmt_bind_param(stmt, bind)

mysql_stmt_bind_param(stmt, bind) 是 MySQL C API 中用于将应用程序变量绑定到预编译 SQL 语句的参数占位符的函数。下面是对这个函数调用的详细解释:

函数定义:

mysql_stmt_bind_param 函数用于在执行预编译的 SQL 语句之前,将应用程序中的数据绑定到 SQL 语句中的参数位置上。

参数:

stmt

这是一个指向 MYSQL_STMT 结构的指针,代表已经预编译的 SQL 语句对象。

bind

这是一个指向 MYSQL_BIND 结构数组的指针,每个 MYSQL_BIND 结构定义了一个参数的绑定信息,包括参数的数据类型、指向数据的指针、长度等。

功能:

当你的 SQL 语句中包含参数占位符(如 ?),你可以使用 mysql_stmt_bind_param 来指定这些占位符应该被哪些实际的值替换。
这个函数允许你将 C 语言中的变量或数据结构绑定到 SQL 语句中的参数上,这样当 SQL 语句执行时,MySQL 服务器会使用这些绑定的值。

返回值:

如果绑定成功,mysql_stmt_bind_param 函数返回 0。
如果绑定失败,函数返回非零值,你可以通过 mysql_error 函数获取错误信息,通过 mysql_stmt_errno 函数获取错误代码。

注意事项:

在调用 mysql_stmt_bind_param 之前,必须确保 stmt 已经通过 mysql_stmt_prepare 预编译,并且 SQL 语句中包含了参数占位符。
bind 数组中的每个 MYSQL_BIND 结构必须正确初始化,包括设置 buffer_type、buffer、buffer_length 等字段。
对于输入参数和输出参数(例如,用于存储 SELECT 语句返回值的参数),需要分别设置 MYSQL_BIND 结构的相应字段。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值