libcurl庫的使用支援http、https、ftp(上傳、下載、遠端目錄列表獲取)
阿新 • • 發佈:2019-01-25
這裡是libcurl庫的一個簡單封裝,支援跨平臺。
宣告:
本文章可以轉載,但必須註明源部落格地址。共享的demo和curltools類不允許個人上傳網路賺取積分和現金,如有發現必定追究責任,請慎重。
直接下載我上傳的資源把curl資料夾解壓到工程程式碼目錄下匯入curltools標頭檔案和原始檔到工程中,方可直接使用。
1、支援協議:http、https(短連線封裝模式)
2、支援ca證書
3、支援表單提交
4、支援ftp上傳/下載/遠端目錄列表獲取(長連線封裝模式)
5、支援STL string 字元全域性替換功能
http呼叫如圖:
FTP呼叫如圖:
FTP效果如圖:
標頭檔案:
#pragma once #include <string> #include <vector> #include "include/curl.h" #include "include/easy.h" #pragma comment(lib,"curl/lib/libcurl.lib") /************************************************************************/ /* libcurl庫封裝 ssdwujianhua 2017年6月7日 13:17:11 */ /************************************************************************/ //表單key對應的型別 enum E_KEY_TYPE { e_key_text, //文字型別 e_key_iamge //圖片型別 }; //表單資訊結構 typedef struct { std::string strKey; std::string strVal; E_KEY_TYPE eKeyType; void Set(std::string key, std::string val, E_KEY_TYPE eType) { strKey = key; strVal = val; eKeyType = eType; } }POST_LIST, *LPPOST_LIST; //表單資料 #define _POST_LIST_DATA_ std::vector<POST_LIST> class CTools { public: static std::string replace(const char *pszSrc, const char *pszOld, const char *pszNew); static const char * getAppPath(); }; class CUrlHttp { public: CUrlHttp(void); ~CUrlHttp(void); static int Request(std::string strRequestType, std::string strUrl, std::string &strReport, std::vector<std::string> vecHeader, std::string strParam="", std::string strCookie="", std::string strCaPath="", int nTimeOut=0); //有圖片建議使用表單提交比較方便 static int RequestSSL(std::string strUrl, std::string &strReport, _POST_LIST_DATA_ listParam, std::vector<std::string> vecHeader, std::string strCookie="", std::string strCaPath="", int nTimeOut=0); }; class CUrlFtp { public: CUrlFtp(); ~CUrlFtp(); typedef struct { size_t type; //0:資料夾 1:檔案 std::string name; //名稱 std::string permissions; //許可權 }FILE_INFO, *LPFILE_INFO; public: int connect(const char *user, const char *password, const char * ip, short port=21); void close(); int download(const char * remoteFile, const char * localFile, size_t timeOut=0); int upload(const char * remoteFile, const char * localFile, size_t timeOut=0); int dirlist(const char * remote, std::vector<FILE_INFO> &vecFileInfo); const char * getLastError(); private: CURL *curl; std::string m_ip; std::string m_user; std::string m_password; short m_port; std::string m_lastError; };
原始檔:
#include "curltools.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #ifdef WIN32 #include <io.h> #else #include <unistd.h> #endif //引數文件地址:https://curl.haxx.se/libcurl/c/libcurl-tutorial.html namespace _CURL_ { /** * buf: 從伺服器返回的buffer * unit: buufer的單位 * bufSize: buffer的大小 * data: 儲存從伺服器返回的內容 * 注意這個函式會被呼叫多次 */ static size_t write_data(void *buf, size_t unit, size_t bufSize, std::string * data) { int size = unit * bufSize; char * tmp = (char*)malloc(size + 1); memcpy(tmp, buf, size); tmp[size] = '\0'; data->append(tmp); free(tmp); return size; } static size_t ftp_read(void *ptr, size_t size, size_t nmemb, void *stream) { curl_off_t nread; size_t retcode = fread(ptr, size, nmemb, (FILE *)stream); nread = (curl_off_t)retcode; return retcode; } //ftp 檔案結構 typedef struct FtpFile { char filename[512]; //檔名稱 FILE *stream; //檔案操作指標 }FTP_FILE, *LPFTP_FILE; static size_t ftp_write(void *buffer, size_t size, size_t nmemb,void *stream) { struct FtpFile *out = (struct FtpFile *)stream; if(out && !out->stream) { out->stream = fopen(out->filename, "wb"); if(!out->stream) return -1; } return fwrite(buffer, size, nmemb, out->stream); } //智慧初始化curl庫和釋放curl庫 class CurlIntelligence { public: CurlIntelligence() { curl_global_init(CURL_GLOBAL_ALL); } ~CurlIntelligence() { curl_global_cleanup(); } }; } _CURL_::CurlIntelligence g_curl; /* * 函式: * replace(替換字串) * 引數: * pszSrc:源字串 * pszOld:需要替換的字串 * pszNew:新字串 * 返回值: * 返回替換後的字串 * ssdwujianhua 2017/12/04 */ std::string CTools::replace(const char *pszSrc, const char *pszOld, const char *pszNew) { std::string strContent, strTemp; strContent.assign( pszSrc ); std::string::size_type nPos = 0; while( true ) { nPos = strContent.find(pszOld, nPos); if ( nPos == std::string::npos ) { break; } strTemp = strContent.substr(nPos+strlen(pszOld), strContent.length()); strContent.replace(nPos,strContent.length(), pszNew ); strContent.append(strTemp); nPos +=strlen(pszNew) - strlen(pszOld)+1; //防止重複替換 避免死迴圈 } return strContent; } const char * CTools::getAppPath() { static std::string appPath; if ( appPath.empty() ) { char szBuf[1024]; memset(szBuf, '\0', 1024); #ifdef _WIN32 GetModuleFileName(NULL, szBuf, 1024); std::string temp = szBuf; std::string::size_type pos = temp.find_last_of("\\")+1; appPath = temp.substr(0, pos); #else getcwd(szBuf, 1024); appPath.assign(szBuf); appPath.append("/"); #endif } return appPath.c_str(); } CUrlHttp::CUrlHttp(void) { } CUrlHttp::~CUrlHttp(void) { } /* * 函式: * Request(請求函式) * 引數: * strRequestType:請求型別(get,post) * strUrl:請求url地址 * strReport:回執資訊 * strHeader:請求頭 * strCookie:cookie資訊 * strCaPath:ca轉成pem證書路徑 * strParam:請求引數(get的時候此引數填空) * nTimeOut:超時設定預設是0秒 是無限等待 * 返回值: * 0表示成功 非0表示錯誤程式碼 * ssdwujianhua 2017/06/06 */ int CUrlHttp::Request(std::string strRequestType, std::string strUrl, std::string &strReport, std::vector<std::string> vecHeader, std::string strParam/* ="" */, std::string strCookie/* ="" */, std::string strCaPath/* ="" */, int nTimeOut/* =0 */) { CURL * curl; curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); if ( strRequestType.compare("post")==0 || strRequestType.compare("POST") == 0 ) { curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strParam.c_str()); } else { curl_easy_setopt(curl, CURLOPT_POST, 0);//get請求 } //設定http頭 curl_slist * headers = NULL; for ( int i=0; i<vecHeader.size(); i++ ) { if (!vecHeader.at(i).empty()) { headers = curl_slist_append(headers, vecHeader.at(i).c_str()); } } if (headers != NULL) { curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); } //判斷是否有證書 if(strCaPath.empty()) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); } else { //預設情況就是PEM,所以無需設定,另外支援DER //curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM"); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true); curl_easy_setopt(curl, CURLOPT_CAINFO, strCaPath.c_str()); } std::string strReportHeader;//回執回來的頭資料 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); //可以看到除錯資訊 //接受伺服器的ssl證書而不管合不合法 (相當於命令列中的--insecure) curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); //curl_easy_setopt(curl,CURLOPT_HEADERFUNCTION,_CURL_::write_data); //curl_easy_setopt(curl, CURLOPT_WRITEHEADER, &strReportHeader); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _CURL_::write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &strReport); if ( nTimeOut > 0 ) { curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, nTimeOut); curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeOut); } if (!strCookie.empty()) { curl_easy_setopt(curl, CURLOPT_COOKIEFILE, strCookie.c_str()); } CURLcode code = curl_easy_perform(curl); if ( headers != NULL ) { curl_slist_free_all(headers); } curl_easy_cleanup(curl); //打印出來 // std::string strReportData; // strReportData.append(strReportHeader); // strReportData.append(strReport); // TRACE("request:%s url:%s report:%s", strRequestType.c_str(), strUrl.c_str(), strReportData.c_str()); return code; } /* * 函式: * RequestSSL(表單提交) * 引數: * strUrl:請求url地址 * strReport:回執資訊 * vecHeader:請求頭 * strCookie:cookie資訊 * listParam:表單列表 * strCaPath:ca轉成pem證書路徑 * nTimeOut:超時設定預設是0秒 是無限等待: * 返回值: * 0表示成功 非0表示錯誤程式碼 * ssdwujianhua 2017/07/21 */ int CUrlHttp::RequestSSL(std::string strUrl, std::string &strReport, _POST_LIST_DATA_ listParam, std::vector<std::string> vecHeader, std::string strCookie/* ="" */, std::string strCaPath/* ="" */, int nTimeOut/* =0 */) { CURLcode code; CURL * curl; curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); //err = curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, "dfsdf"); //設定http頭 curl_slist * headers = NULL; for ( int i=0; i<vecHeader.size(); i++ ) { if (!vecHeader.at(i).empty()) { headers = curl_slist_append(headers, vecHeader.at(i).c_str()); } } if (headers != NULL) { curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); } struct curl_httppost *post=NULL; struct curl_httppost *last=NULL; CURLFORMcode errf; for ( int i=0; i<listParam.size(); i++ ) { POST_LIST post_list = listParam.at(i); if (post_list.eKeyType == e_key_iamge ) //圖片型別 直接提交圖片路徑 { errf = curl_formadd(&post, &last, CURLFORM_COPYNAME, post_list.strKey.c_str(), CURLFORM_FILE,post_list.strVal.c_str(),CURLFORM_CONTENTTYPE, "image/jpeg",CURLFORM_END); } else { errf = curl_formadd(&post, &last, CURLFORM_COPYNAME, post_list.strKey.c_str(), CURLFORM_COPYCONTENTS, post_list.strVal.c_str(),CURLFORM_END); } } curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _CURL_::write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &strReport); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); //判斷是否有證書 if(strCaPath.empty()) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); } else { //預設情況就是PEM,所以無需設定,另外支援DER //curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM"); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true); curl_easy_setopt(curl, CURLOPT_CAINFO, strCaPath.c_str()); } //設定超時時間 if ( nTimeOut > 0 ) { curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, nTimeOut); curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeOut); } curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,1); //是否抓取跳轉後的頁面 /* Set the form info */ curl_easy_setopt(curl, CURLOPT_HTTPPOST, post); // curl_easy_setopt(curl, CURLOPT_HEADER, 0); //不讀取返回頭的資料 //設定http cookie if (!strCookie.empty()) { curl_easy_setopt(curl, CURLOPT_COOKIEFILE, strCookie.c_str()); } code = curl_easy_perform(curl); /* post away! */ //獲取請求返回的值 如:200 //code = curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE, &RESPONSE_CODE); /* free the post data again */ if ( headers != NULL ) { curl_slist_free_all(headers); } curl_formfree(post); curl_easy_cleanup(curl); return code; } /******************************************************************************************** * curl FTP 類封裝 * * * *********************************************************************************************/ CUrlFtp::CUrlFtp() { curl = NULL; } CUrlFtp::~CUrlFtp() { close(); } /* * 函式: * connect(ftp連線) * 引數: * user:ftp帳號 * password:ftp密碼 * ip:ftpip * port:ftp埠 * 返回值: * 成功返回0 失敗返回-1 * ssdwujianhua 2017/12/29 */ int CUrlFtp::connect( const char *user, const char *password, const char * ip, short port /*=21*/) { curl = curl_easy_init(); if ( curl == NULL ) { m_lastError.assign("curl initialization failure!"); printf("curl initialization failure!\n"); return -1; } //設定登入帳號和密碼 std::string spider; spider.append(user); spider.append(":"); spider.append(password); curl_easy_setopt(curl, CURLOPT_USERPWD, spider.c_str()); std::string url; url.append("ftp://");; url.append(ip); if ( port != 0 ) { url.append(":"); char szPort[10]; sprintf(szPort, "%d", port); url.append(szPort); } curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); CURLcode code = curl_easy_perform(curl); if ( code != CURLE_OK ) { m_lastError = curl_easy_strerror( code ); printf("ftp connect failure: %s!\n", m_lastError.c_str()); close(); return -1; } m_ip.assign(ip); m_user.assign(user); m_password.assign(password); m_port = port; m_lastError.assign("ftp connect success!"); printf("ftp connect success!\n"); return 0; } /* * 函式: * close(ftp關閉) * 引數: * 無 * 返回值: * 無 * ssdwujianhua 2017/12/29 */ void CUrlFtp::close() { if ( curl != NULL ) { curl_easy_cleanup(curl); curl = NULL; } } /* * 函式: * download(ftp檔案下載) * 引數: * remoteFile:遠端檔案路徑 * localFile:本地檔案路徑 * timeOut:超時時間 單位秒 * 返回值: * 成功返回0 失敗返回-1 * ssdwujianhua 2017/12/29 */ int CUrlFtp::download(const char * remoteFile, const char * localFile, size_t timeOut /*= 0*/) { if ( curl == NULL ) { m_lastError.assign("ftp disconnect!"); printf("ftp disconnect!"); return -1; } std::string newRemotePath = CTools::replace(remoteFile, "\\", "/" ); std::string newLocalPath = CTools::replace(localFile, "\\", "/" ); _CURL_::FTP_FILE ftpfile; sprintf(ftpfile.filename, "%s",newLocalPath.c_str()); ftpfile.stream = NULL; std::string url; url.append("ftp://");; url.append(m_ip); url.append(":"); char szPort[10]; sprintf(szPort, "%d", m_port); url.append(szPort); url.append("/"); url.append(newRemotePath); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _CURL_::ftp_write); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); if ( timeOut > 0 ) { curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, timeOut); } CURLcode code = curl_easy_perform(curl); if ( code != CURLE_OK ) { m_lastError = curl_easy_strerror( code ); printf("ftp download failure: %s!\n", m_lastError.c_str()); return -1; } if (ftpfile.stream != NULL ) { fclose(ftpfile.stream); ftpfile.stream = NULL; } m_lastError.assign("ftp upload success!"); return 0; } /* * 函式: * upload(ftp檔案上傳) * 引數: * remoteFile:遠端檔案路徑 * localFile:本地檔案路徑 * timeOut:超時時間 單位秒 * 返回值: * 成功返回0 失敗返回-1 * ssdwujianhua 2017/12/29 */ int CUrlFtp::upload(const char * remoteFile, const char * localFile, size_t timeOut/*=0*/) { if ( curl == NULL ) { m_lastError.assign("ftp disconnect!"); printf("ftp disconnect!"); return -1; } std::string newRemotePath = CTools::replace(remoteFile, "\\", "/" ); std::string newLocalPath = CTools::replace(localFile, "\\", "/" ); CURLcode code; FILE *hd_src; struct stat file_info; curl_off_t fsize; std::size_t nItem = newRemotePath.find_last_of("/"); std::string remoteFileName = newRemotePath.substr(nItem+1);//檔名稱 std::string remotePath = newRemotePath.substr(0, nItem);//遠端路徑 struct curl_slist *headerlist = NULL; char buf_1 [256] = "RNFR while-uploading"; char buf_2 [256]; //遠端檔名稱 sprintf(buf_2,"RNTO %s", remoteFileName.c_str()); if(stat(newLocalPath.c_str(), &file_info)) { m_lastError.assign("the uploaded file does not exist!"); printf("the uploaded file does not exist(%s)!\n", localFile); return -1; } fsize = (curl_off_t)file_info.st_size; hd_src = fopen(newLocalPath.c_str(), "rb"); if ( hd_src == NULL ) { m_lastError.assign("file open failed!"); printf("file open failed(%s)!\n", localFile); return -1; } headerlist = curl_slist_append(headerlist, buf_1); headerlist = curl_slist_append(headerlist, buf_2); curl_easy_setopt(curl, CURLOPT_READFUNCTION, _CURL_::ftp_read); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); //設定ftp url std::string url = "ftp://"; url.append(m_ip); url.append(":"); char szPort[10]; sprintf(szPort, "%d", m_port); url.append(szPort); url.append("/"); url.append(remotePath); url.append("/"); url.append("while-uploading"); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_POSTQUOTE, headerlist); curl_easy_setopt(curl, CURLOPT_READDATA, hd_src); curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,(curl_off_t)fsize); if ( timeOut > 0 ) { curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, timeOut); } code = curl_easy_perform(curl); curl_slist_free_all(headerlist); if ( code != CURLE_OK ) { fclose(hd_src); m_lastError = curl_easy_strerror( code ); printf("ftp upload failure: %s!\n", m_lastError.c_str()); return -1; } fclose(hd_src); m_lastError.assign("ftp upload success!"); return code; } /* * 函式: * dirlist(遠端目錄列表獲取) * 引數: * remote:遠端目錄路徑 * vecFileInfo:輸出遍歷得到的資料夾和檔案 * 返回值: * 成功返回0 失敗返回-1 * ssdwujianhua 2017/12/29 */ int CUrlFtp::dirlist(const char * remote, std::vector<FILE_INFO> &vecFileInfo) { if ( curl == NULL ) { m_lastError.assign("ftp disconnect!"); printf("ftp disconnect!"); return -1; } std::string remotePath = CTools::replace(remote, "\\", "/" ); if ( remotePath.size() == 0 ) { remotePath.append("/"); } if ( remotePath[remotePath.length()-1] != '/') { remotePath.append("/"); } std::string url; url.append("ftp://");; url.append(m_ip); url.append(":"); char szPort[10]; sprintf(szPort, "%d", m_port); url.append(szPort); url.append("/"); url.append(remotePath); std::string response; curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _CURL_::write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); CURLcode code = curl_easy_perform(curl); if ( code != CURLE_OK ) { m_lastError = curl_easy_strerror( code ); printf("ftp connect failure: %s!\n", m_lastError.c_str()); return -1; } //解析ftp資料得到檔案和資料夾屬性 std::string::size_type pos=0, index=0, len=0; while( true ) { std::string row= ""; pos = response.find("\r\n", pos)+2; if ( pos < index ) { break; } len = pos - index;//需要擷取的字串長度 row = response.substr(index, len); //得到每行資料 index = pos; std::string::size_type rowPos=0, rowIndex=0, rowLen=0; //得到名稱 FILE_INFO fileInfo; rowPos = row.find_last_of(' ')+1; std::string name = row.substr(rowPos, row.length()); if ( name.size() == 0 || name[0] == '.') { continue; } fileInfo.name = name; //得到檔案許可權和檔案型別 rowPos = row.find_first_of(' '); std::string data = row.substr(0,rowPos); if ( data.size() != 0 ) { if (data[0] == 'd') { //資料夾 fileInfo.type = 0; fileInfo.permissions = data.substr(1, data.length()); } else { //檔案 fileInfo.type = 1; fileInfo.permissions = data.substr(1, data.length()); } } vecFileInfo.push_back(fileInfo); } m_lastError.assign(""); return 0; } /* * 函式: * getLastError(最後錯誤資訊) * 引數: * 無 * 返回值: * 對應的錯誤資訊 * ssdwujianhua 2017/12/29 */ const char * CUrlFtp::getLastError() { return m_lastError.c_str(); }