libcurl和sql命令

mo49yndu  于 2021-07-27  发布在  Java
关注(0)|答案(1)|浏览(369)

我是c++的初学者,我有两个小问题。
1-我想获取用户的公共ip地址。为此,我使用如下 curl :

CURL* curl;
    CURLcode verif;
    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, "https://ifconfig.me/?action=render");
    verif = curl_easy_perform(curl);
    curl_easy_cleanup(curl);

但当我运行程序时,它会写入ip,但我不知道如何将其存储到变量中。我应该怎么做才能做到这一点?
2-我想向数据库发送请求,但我的语法有一些问题。我的代码:

int query_state = mysql_query(db, "INSERT INTO `account` (`id`, `id_user`, `ip`, `last_join`) VALUES (NULL, '" << id << "', '" << ip_user << "', '" << date << "')");

但我的“<<”有个错误。错误在请求中:(null,“<<id
事先谢谢你的帮助。

pkbketx9

pkbketx91#

如果您只对ip地址感兴趣,而对其他内容不感兴趣,请查询https://ifconfig.me/ip 而不是https://ifconfig.me/?action=render. 然后使用 CURLOPT_WRITEFUNCTION 回调将输出保存到变量,例如 std::string 例如:

size_t write_str(char *ptr, size_t size, size_t nmemb, void *userdata);
{
    size_t numBytes = size * nmemb;
    static_cast<std::string*>(userdata)->append(ptr, numBytes);
    return numBytes;
}

...

std::string ip_user;
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "https://ifconfig.me/ip");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_str);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ip_user);
CURLcode verif = curl_easy_perform(curl);
curl_easy_cleanup(curl);

至于数据库,你不能用 << 以您尝试的方式连接字符串。这就是为什么编译器会出错。
如果你真的想用 << 对于串联,则需要使用 std::ostringstream 收集子字符串,然后可以调用 str() 方法提取已完成的 std::string 例如:


# include <sstream>

std::ostringstream oss;
oss << "INSERT INTO account (id, id_user, ip, last_join) VALUES (NULL, '" << id << "', '" << ip_user << "', '" << date << "')";
std::string sql = oss.str();
int query_state = mysql_query(db, sql.c_str());

否则,只需使用普通字符串 + 改为串联:

std::string sql = "INSERT INTO account (id, id_user, ip, last_join) VALUES (NULL, '" + id + "', '" + ip_user + "', '" + date + "')";
int query_state = mysql_query(db, sql.c_str());

尽管如此,请注意,这种手动构建的sql语句很容易受到sql注入攻击。要避免此类攻击,必须对输入字符串进行转义,例如 mysql_real_escape_string_quote() ,这样攻击者就不能提供格式错误的输入,从而破坏sql语句执行恶意操作,例如:

std::string sql_escape(MYSQL *db, const std::string &s char quote = '\'')
{
    std::string escaped;
    escaped.resize((s.length() * 2) + 1);
    escaped.resize(mysql_real_escape_string_quote(db, &escaped[0], s.c_str(), s.length(), quote));
    return escaped;
}
std::ostringstream oss;
oss << "INSERT INTO account (id, id_user, ip, last_join) VALUES (NULL, " << sql_escape(db, id) << ", " << sql_escape(db, ip_user) << ", " << sql_escape(db, date) << ")";
std::string sql = oss.str();
...
std::string sql = "INSERT INTO account (id, id_user, ip, last_join) VALUES (NULL, " + sql_escape(db, id) + ", " + sql_escape(db, ip_user) + ", " + sql_escape(db, date) + ")";
...

更好的选择是使用参数化查询。它不仅可以堵住此类攻击的漏洞,还可以让db为您处理任何必要的输入字符串转义,例如:

std::string sql = "INSERT INTO account (id, id_user, ip, last_join) VALUES (NULL, ?, ?, ?)";
MYSQL_BIND params[3] = {};

params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = &id[0]; // or id.data() in C++17
params[0].buffer_length = params[0].length = id.length();

params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = &ip_user[0]; // or ip_user.data() in C++17
params[1].buffer_length = params[1].length = ip_user.length();

params[2].buffer_type = MYSQL_TYPE_STRING;
params[2].buffer = &date[0]; // or date.data() in C++17
params[2].buffer_length = params[2].length = date.length();

MYSQL_STMT *stmt = mysql_stmt_init(db);
mysql_stmt_prepare(stmt, sql.c_str(), sql.length());
mysql_stmt_bind_param(stmt, params);
mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);

相关问题