您正在將SQL字符集設置爲UTF-8,因此請使用WideCharToMultiByte()
將retreived UI Unicode字符串轉換爲UTF-8,然後將轉換後的數據傳遞給數據庫查詢。可以使用char
緩衝區存儲UTF-8編碼的數據,並且您可以傳遞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注入攻擊:
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, ¶m);
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);
聖竹。那個傻瓜做了個訣竅! Unicode使生活如此艱難......謝謝你。哦,什麼是參數化查詢?谷歌沒有帶來任何亮光。編輯:找到它。 「準備好的聲明」。 –