You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
5.8 KiB

#include "curl_utils.h"
#include <chrono>
// 回调函数,用于处理从服务器接收到的数据
size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* userp) {
size_t totalSize = size * nmemb;
userp->append((char*)contents, totalSize);
return totalSize;
}
// 回调函数,用于处理接收到的响应头
size_t HeaderCallback(char* buffer, size_t size, size_t nitems, void* userdata) {
HeaderData* headerData = static_cast<HeaderData*>(userdata);
std::string header(buffer, size * nitems);
if (!headerData->found && header.find("x-csrf-token:") == 0) {
size_t colonPos = header.find(':');
if (colonPos != std::string::npos) {
headerData->value = header.substr(colonPos + 1);
headerData->value.erase(0, headerData->value.find_first_not_of(" \t"));
headerData->value.erase(headerData->value.length() - 2);
headerData->found = true; // 标记为已找到
}
}
return size * nitems;
}
vector<string> split_regex(const string& str, const string& pattern) {
vector<string> tokens;
regex rgx(pattern);
sregex_token_iterator iter(str.begin(), str.end(), rgx, -1);
sregex_token_iterator end;
while (iter != end) {
tokens.push_back(*iter++);
}
return tokens;
}
string URLEncodeFTPPath(const std::string& path) {
CURL* curl = curl_easy_init();
if (!curl) return path;
std::string result;
std::string encoded_part;
// 分割路径,分别编码每个部分
size_t start = 0;
size_t end = path.find('/');
while (end != std::string::npos) {
std::string part = path.substr(start, end - start);
if (!part.empty()) {
char* encoded = curl_easy_escape(curl, part.c_str(), part.length());
if (encoded) {
result += encoded;
curl_free(encoded);
}
else {
result += part;
}
}
result += '/';
start = end + 1;
end = path.find('/', start);
}
// 最后一部分
if (start < path.length()) {
std::string part = path.substr(start);
char* encoded = curl_easy_escape(curl, part.c_str(), part.length());
if (encoded) {
result += encoded;
curl_free(encoded);
}
else {
result += part;
}
}
curl_easy_cleanup(curl);
return result;
}
// 写入回调函数(用于上传文件)
size_t read_callback(void* ptr, size_t size, size_t nmemb, FILE* stream) {
size_t retcode = fread(ptr, size, nmemb, stream);
return retcode;
}
int sendFileByFtp(string ftp_url, string file_path, string file_dir, string user, string pwd)
{
int result = 0;
CURL* curl;
CURLcode res;
// 初始化libcurl
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
string encoded_ftp_url = URLEncodeFTPPath(ftp_url);
// 1. 创建远程目录
curl_easy_setopt(curl, CURLOPT_URL, encoded_ftp_url.c_str());
curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str());
curl_easy_setopt(curl, CURLOPT_PASSWORD, pwd.c_str());
curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, CURLFTP_CREATE_DIR);
// 重要:对于非标准端口,可能需要额外设置
curl_easy_setopt(curl, CURLOPT_FTPPORT, "-"); // 被动模式
curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L); // 禁用 EPSV
// 启用详细日志查看具体问题
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
// 设置超时
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);
// 执行目录创建
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
WriteLog("FTP 创建目录失: %s (错误: %d)\n",
curl_easy_strerror(res), res);
result = 1;
goto end;
}
// 2. 上传文件到新目录
FILE* file = nullptr;
errno_t err = fopen_s(&file, file_path.c_str(), "rb");
if (err != 0 || file == nullptr) {
// 处理错误
WriteLog("无法打开本地文件>%s\n", file_path.c_str());
result = 1;
goto end;
}
//FILE* file = fopen(file_path.c_str(), "rb");
//if (!file) {
// WriteLog("无法打开本地文件>%s\n", file_path.c_str());
// result = 1;
// goto end;
//}
// 设置FTP上传选项
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_URL, file_dir.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
curl_easy_setopt(curl, CURLOPT_READDATA, file);
// 获取文件大小
fseek(file, 0, SEEK_END);
curl_off_t file_size = ftell(file);
fseek(file, 0, SEEK_SET);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, file_size);
// 执行文件上传
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
WriteLog("上传文件失败:%s\n", curl_easy_strerror(res));
result = 1;
}
else {
WriteLog("文件上传成功\n");
}
fclose(file);
curl_easy_cleanup(curl);
}
end:
curl_global_cleanup();
return result;
}
string postJSON(string url, string body, long& http_code, string& error)
{
string response_data = "";
CURL* curl;
CURLcode res;
// 初始化 libcurl 会话
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
// 设置要访问的 URL
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "http");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
// 设置请求头
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json; charset=UTF-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.size());
// 设置回调函数以接收响应数据
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);
// 执行请求
res = curl_easy_perform(curl);
// 检查错误
if (res != CURLE_OK)
{
error = curl_easy_strerror(res);
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
// 清理资源
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
// 清理全局环境
curl_global_cleanup();
return response_data;
}