LibCurl 和 Sql 命令

LibCurl & Sql Commands

我是c++的初学者,有两个小问题。

1 - 我想获取用户的 public 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

在此先感谢您的帮助。

如果您只对 IP 地址感兴趣,没有其他兴趣,请查询 https://ifconfig.me/ip instead of https://ifconfig.me/?action=render. And then use a 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) + ")";
...

更好的选择是使用参数化查询。这不仅会堵塞此类攻击的漏洞,而且还会让数据库为您处理任何必要的输入字符串转义,例如:

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);