从 GETTEXT 获取的 C++ 变量作为 mysql_query 变量

标签 c++ mysql winapi unicode

我正在尝试执行以下操作:

  1. 将用户名输入用户字段
  2. 使用用户名作为变量进行 SEARCH mysql_query

我很难通过第 2 阶段,因为 mysql_query 将 const char* 作为查询字符串,我只能获取 char* 或 wchar_t* 形式的用户名

我也在用 unicode 编译。

我现在的代码:

void mysql_connect(HWND hLoginWnd) {

MYSQL *con, mysql;
MYSQL_RES *res;
mysql_init(&mysql);

mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "utf8");

mysql_real_connect(&mysql, "localhost", "root", "", "treenitaulu", 3306, NULL, 0);

char name[512], pass[512];
int lenUser = SendMessage(userField, WM_GETTEXT, 512, (LPARAM)name);
int lenPass = SendMessage(passField, WM_GETTEXT, 512, (LPARAM)pass);

if(lenUser > 0 && lenPass > 0) {

    std::string query = "SELECT pass FROM users WHERE name='" + std::string(name) + "'";

    mysql_query(&mysql, query.c_str());

}

}

我该怎么办?

最佳答案

您正在将 SQL 字符集设置为 UTF-8,因此使用 WideCharToMultiByte() 将检索到的 UI Unicode 字符串转换为 UTF-8,然后将转换后的数据传递给数据库查询。 UTF-8 编码数据可以使用 char 缓冲区存储,您可以传递 char*(或 char[]),其中 const char* 是预期的。例如:

std::string Utf8Encode(WCHAR *wStr, int wLen)
{
    int utf8len = WideCharToMultiByte(CP_UTF8, 0, wStr, wLen, NULL, 0, NULL, NULL);
    if (utf8len > 0)
    {
        std::vector<char> utf8(utf8len);
        utf8len = WideCharToMultiByte(CP_UTF8, 0, wStr, wLen, &utf8[0], utf8len, NULL, NULL);
        if (utf8len > 0)
            return std::string(&utf8[0], utf8len);
    }
    return std::string();
}

void mysql_connect(HWND hLoginWnd)
{
    MYSQL *con, mysql;
    MYSQL_RES *res;
    mysql_init(&mysql);

    mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "utf8");

    mysql_real_connect(&mysql, "localhost", "root", "", "treenitaulu", 3306, NULL, 0);

    WCHAR name[512];
    int lenUser = SendMessage(userField, WM_GETTEXTW, 512, (LPARAM)name);

    if (lenUser > 0)
    {
        std::string query = "SELECT pass FROM users WHERE name='" + Utf8Encode(name, lenUser) + "'";
        mysql_query(&mysql, query.c_str());
        ...
    }
}

话虽如此,在动态构建 SQL 语句时,您确实需要对字符串进行转义。它更安全,因为它不容易受到 SQL 注入(inject)攻击:

std::string Utf8EncodeAndEscape(MYSQL *mysql, WCHAR *wStr, int wLen)
{
    int utf8len = WideCharToMultiByte(CP_UTF8, 0, wStr, wLen, NULL, 0, NULL, NULL);
    if (utf8len > 0)
    {
        std::vector<char> utf8(utf8len);
        utf8len = WideCharToMultiByte(CP_UTF8, 0, wStr, wLen, &utf8[0], utf8len, NULL, NULL);
        if (utf8len > 0)
        {
            std::vector<char> escaped(utf8len*2+1);
            unsigned long escapedLen = mysql_real_escape_string(mysql, &escaped[0], &utf8[0], utf8len);
            if (escapedLen > 0)
                return std::string(&escaped[0], escapedLen);
        }
    }

    return std::string();
}

void mysql_connect(HWND hLoginWnd)
{
    MYSQL *con, mysql;
    MYSQL_RES *res;
    mysql_init(&mysql);

    mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "utf8");

    mysql_real_connect(&mysql, "localhost", "root", "", "treenitaulu", 3306, NULL, 0);

    WCHAR name[512];
    int lenUser = SendMessage(userField, WM_GETTEXTW, 512, (LPARAM)name);

    if (lenUser > 0)
    {
        std::string query = "SELECT pass FROM users WHERE name='" + Utf8EncodeAndEscape(&mysql, name, lenUser) + "'";
        mysql_query(&mysql, query.c_str());
        ...
    }
}

参数化查询同样安全,但比动态 SQL 语句更高效,尤其是当您需要多次执行同一语句时:

std::wstring Utf8Decode(char *utf8Str, int utf8Len)
{
    int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8Str, utf8Len, NULL, 0);
    if (wLen > 0)
    {
        std::vector<wchar_t> wStr(wLen);
        wLen = MultiByteToWideChar(CP_UTF8, 0, utf8Str, utf8Len, &wStr[0], wLen);
        if (wLen > 0)
            return std::wstring(&wStr[0], wLen);
    }
    return std::wstring();
}

MYSQL_STMT *stmt = mysql_stmt_init(&mysql);
if (stmt)
{    
    std::string query = "SELECT pass FROM users WHERE name=?"
    if (mysql_stmt_prepare(stmt, query.c_str(), query.length()) == 0)
    {
        if (mysql_stmt_param_count(stmt) == 1)
        {
            std::string utf8User = Utf8Encode(name, lenUser);
            unsigned long utf8len = utf8User.length();
            MYSQL_BIND param = {0};
            param.buffer_type = MYSQL_TYPE_STRING;
            param.buffer = utf8User.c_str();
            param.buffer_length = utf8len;
            param.length = &utf8len;
            param.is_unsigned = true;
            mysql_stmt_bind_param(stmt, &param);

            char result[512];
            unsigned long resultLen = 0;
            MYSQL_BIND result = {0};
            param.buffer_type = MYSQL_TYPE_STRING;
            param.buffer = &result[0];
            param.buffer_length = 512;
            param.length = &resultlen;
            param.is_unsigned = true;
            mysql_stmt_bind_result(stmt, &result);

            if (mysql_stmt_execute(stmt) == 0)
            {
                mysql_stmt_fetch(stmt);
                mysql_stmt_free_result(stmt); 

                SendMessage(passField, WM_SETTEXTW, 0, (LPARAM) Utf8Decode(result, resultLen).c_str());
            }
        }
    }
}

mysql_stmt_close(stmt); 

关于从 GETTEXT 获取的 C++ 变量作为 mysql_query 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19779694/

相关文章:

c++ - 具有相同签名的模板函数重载,为什么会这样?

c++ - 编译器似乎没有使用包含

php - fatal error : Call to a member function prepare() on string

具有内部连接和限制的mysql子查询

c++ - 限制 WINAPI 中的调整大小方向

c++ - 我的粒子群优化代码在 C++ 和 MATLAB 中生成了不同的答案

c++ - Visual Studio 强制使用没有签名文件编码的 UTF-8

mysql - 这个sql让我有点复杂

Delphi - WM_MOUSEWHEEL双重处理

c++ - Thread Local Storage 可以伪造/破解吗?