HttpOpenRequest () Wininet c++ e PHP
Posted
技术标签:
【中文标题】HttpOpenRequest () Wininet c++ e PHP【英文标题】: 【发布时间】:2020-09-29 23:40:41 【问题描述】:我有这个代码,但它不工作。我通过 Postman 对其进行了测试,php 可以正确获取数据。问题出在 C++ 中,它没有通过 POST 发送文件。怎么了?
这个想法是让 DLL 生成 .txt
文件并将此文件 POST 到 PHP,在那里它将接收并将其插入数据库。
void PHP_Autentication (void)
static TCHAR frmdata[] = "-----------------------------og94kfkldjs7ekk\r\nContent-Disposition: form-data; name=\"arquivo\"; filename=\"g.txt\"\r\nContent-Type: text/plain\r\n\r\nCodex Anti-Hack\r\n-----------------------------og94kfkldjs7ekk--\r\n";
static TCHAR hdrs[] = "Content-Type: multipart/form-data; boundary=---------------------------og94kfkldjs7ekk";
HINTERNET hSession = InternetOpen("MyBrowser",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if(!hSession)
PHP_DC();
HINTERNET hConnect = InternetConnect(hSession, _T (carrega.IP_Server_and_Hard),INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
if(!hConnect)
PHP_DC();
LPCTSTR rgpszAcceptTypes[] = _T("*/*"), NULL;
HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST", _T("sentinela/sentinela.php"), NULL, NULL, rgpszAcceptTypes, 0, 1);
if(hRequest==NULL)
PHP_DC();
BOOL sent= HttpSendRequest(hRequest, hdrs, strlen(hdrs), frmdata, strlen(frmdata));
if(!sent)
PHP_DC();
char buffer[2048] = ;
DWORD bufferSize = sizeof(buffer);
BOOL success = HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, buffer, &bufferSize, NULL);
if(!success)
PHP_DC();
std::cout << buffer << std::endl;
ZeroMemory(buffer, sizeof(buffer));
success = InternetReadFile(hRequest, buffer, sizeof(buffer), &bufferSize);
if(!success)
PHP_DC();
else
InternetCloseHandle(hSession);
InternetCloseHandle(hConnect);
InternetCloseHandle(hRequest);
PHP 文件是这样的:
<?php
session_start();
define('HOST', '111.111.111.111');
define('USUARIO', 'user');
define('SENHA', 'pass');
define('DB', 'db');
$conexao = mysqli_connect(HOST,USUARIO,SENHA);
$db_select = mysqli_select_db($conexao, DB);
$arquivo_tmp = $_FILES['arquivo']['tmp_name'];
$dados = file($arquivo_tmp);
foreach($dados as $linha)
var_dump($dados);
$mac = $dados[0];
$serial = $dados[1];
$namepc = $dados[2];
$idgame = $dados[3];
$ip = $dados[4];
$userpc = $dados[5];
$sql = "INSERT INTO log (id, user, mac_addr, serial, uName, ip, date) VALUES ('NULL', '$idgame',
'$mac', '$serial', '$namepc', '$ip', now())";
mysqli_query($conexao,$sql);
?>
要在 POST 中发送的文件是 .txt
,其中包含:
【问题讨论】:
你编译你的项目时是否定义了UNICODE
?您并没有真正正确地管理您的 TCHAR
数据。您不能将 _T()
宏与变量一起使用,只能与文字一起使用,因此 _T(carrega.IP_Server_and_Hard)
无效。 (const char*)"POST"
应该是 _T("POST")
。 strlen(hdrs)
应该是 _tcslen(hdrs)
。 frmdata
根本不应该使用 TCHAR
,因为 MIME 不允许使用 16 位 Unicode 编码,只能使用 7 位 ASCII 编码
既然你可以让 PHP 与 Postman 一起工作,我强烈建议你使用像 Wireshark 这样的数据包嗅探器来捕获原始 HTTP 数据并将 Postman 请求与你的 WinInet 请求进行比较,看看有什么他们之间实际上是不同的。
@RemyLebeau 字符集是:使用多字节字符集。它不是 unicode。我应该在 frmdata 上使用什么而不是 TCHAR?
对于frmdata
,您需要使用char[]
而不是TCHAR[]
,因为无论您是为Unicode 还是MBCS 编译,它都需要使用1 字节字符。但是由于您正在为 MBCS 编译而不是 TCHAR
映射到 char
,所以这不是您现在的问题。但在编写使用TCHAR
的代码时,您需要注意这一点。不要像你一样混合char
/wchar_t
/tchar
API,如果你以后更改配置,就会发生不好的事情。你真的不应该使用 TCHAR
,它是 Win9x/ME 时代过时的 API。
话虽如此,PHP_DC()
究竟做了什么?它是否记录来自GetLastError()
和InternetGetLastResponseInfo()
的WinInet 错误?您在这段代码中有很多地方可能在 PHP 获取数据之前发生故障,但您没有指出故障实际发生的位置。您是否尝试过自己调试此代码?
【参考方案1】:
您根本没有发送.txt
文件。您正在发送一个硬编码字符串"Codex Anti-Hack"
。
要发送实际的.txt
文件,您可以:
HttpSendRequest()
。在运行时查询文件大小以了解分配缓冲区的大小。例如:
#include <vector>
#include <memory>
#include <algorithm>
#include <type_traits>
struct HINTERNET_deleter
using pointer = HINTERNET;
// in VC2010: use this instead:
// typedef HINTERNET pointer;
void operator()(HINTERNET hInternet) const InternetCloseHandle(hInternet);
;
using HINTERNET_ptr = std::unique_ptr<std::remove_pointer<HINTERNET>::type, HINTERNET_deleter>;
// in VC2010: use this instead:
// typedef std::unique_ptr<std::remove_pointer<HINTERNET>::type, HINTERNET_deleter> HINTERNET_ptr;
struct HFILE_deleter
using pointer = HANDLE;
// in VS2010, use this instead:
// typedef HANDLE pointer;
void operator()(HANDLE hFile) const if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
;
using HFILE_ptr = std::unique_ptr<std::remove_pointer<HANDLE>::type, HFILE_deleter>;
// in VS2010, use this instead:
// typedef std::unique_ptr<std::remove_pointer<HANDLE>::type, HFILE_deleter> HFILE_ptr;
bool PHP_Autentication()
static char frmdata_1[] = "-----------------------------og94kfkldjs7ekk\r\n"
"Content-Disposition: form-data; name=\"arquivo\"; filename=\"g.txt\"\r\n"
"Content-Type: text/plain\r\n"
"\r\n";
static DWORD frmdata_1_len = sizeof(frmdata_1) - 1;
static char frmdata_2[] = "\r\n"
"-----------------------------og94kfkldjs7ekk--\r\n";
static DWORD frmdata_2_len = sizeof(frmdata_2) - 1;
static TCHAR hdrs[] = "Content-Type: multipart/form-data; boundary=---------------------------og94kfkldjs7ekk";
static DWORD hdrs_len = (sizeof(hdrs) / sizeof(hdrs[0])) - 1;
HFILE_ptr hFile( CreateFile(_T("path\\filename.txt"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL) );
if (hFile.get() == INVALID_HANDLE_VALUE)
// error handling...
return false;
DWORD dwFileSize = GetFileSize(hFile.get(), NULL);
if (dwFileSize == INVALID_FILE_SIZE)
// error handling...
return false;
std::vector<char> frmdata(frmdata_1_len + dwFileSize + frmdata_2_len);
std::copy_n(frmdata_1, frmdata_1_len, &frmdata[0]);
DWORD dwOffset = frmdata_1_len;
while (dwFileSize > 0)
DWORD dwNumRead;
if ((!ReadFile(hFile.get(), &frmdata[dwOffset], dwFileSize, &dwNumRead, NULL)) || (dNumRead == 0))
// error handling...
return false;
dwOffset += dwNumRead;
dwFileSize -= dwNumRead;
std::copy_n(frmdata_2, frmdata_2_len, &frmdata[dwOffset]);
HINTERNET_ptr hSession( InternetOpen(_T("MyBrowser"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0) );
if (!hSession)
// error handling...
return false;
HINTERNET_ptr hConnect( InternetConnect(hSession.get(), carrega.IP_Server_and_Hard, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1) );
if (!hConnect)
// error handling...
return false;
LPCTSTR rgpszAcceptTypes[] = _T("*/*"), NULL;
HINTERNET_ptr hRequest( HttpOpenRequest(hConnect.get(), _T("POST"), _T("sentinela/sentinela.php"), NULL, NULL, rgpszAcceptTypes, 0, 1) );
if (!hRequest)
// error handling...
return false;
if (!HttpSendRequest(hRequest.get(), hdrs, hdrs_len, frmdata.data(), frmdata.size()))
// error handling...
return false;
DWORD dwStatusCode, dwIndex = 0;
if (!HttpQueryInfo(hRequest.get(), HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwStatusCode, sizeof(dwStatusCode), &dwIndex))
// error handling...
return false;
TCHAR buffer[2048] = ;
DWORD bufferSize = sizeof(buffer);
dwIndex = 0;
if (!HttpQueryInfo(hRequest.get(), HTTP_QUERY_RAW_HEADERS_CRLF, buffer, &bufferSize, &dwIndex))
// error handling...
return false;
#ifdef UNICODE
std::ostream &t_cout = std::wcout;
#else
std::ostream &t_cout = std::cout;
#endif
t_cout.write(buffer, bufferSize / sizeof(TCHAR));
t_cout << std::endl;
return ((dwStatusCode / 100) == 2);
使用HttpSendRequestEx()
代替HttpSendRequest()
,这样可以在MIME数据中间使用ReadFile()
和InternetWriteFile()
分块发送文件数据。例如:
#include <vector>
#include <memory>
#include <algorithm>
#include <type_traits>
struct HINTERNET_deleter
using pointer = HINTERNET;
// in VC2010: use this instead:
// typedef HINTERNET pointer;
void operator()(HINTERNET hInternet) const InternetCloseHandle(hInternet);
;
using HINTERNET_ptr = std::unique_ptr<std::remove_pointer<HINTERNET>::type, HINTERNET_deleter>;
// in VC2010: use this instead:
// typedef std::unique_ptr<std::remove_pointer<HINTERNET>::type, HINTERNET_deleter> HINTERNET_ptr;
struct HFILE_deleter
using pointer = HANDLE;
// in VS2010, use this instead:
// typedef HANDLE pointer;
void operator()(HANDLE hFile) const if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
;
using HFILE_ptr = std::unique_ptr<std::remove_pointer<HANDLE>::type, HFILE_deleter>;
// in VS2010, use this instead:
// typedef std::unique_ptr<std::remove_pointer<HANDLE>::type, HFILE_deleter> HFILE_ptr;
bool WriteToInet(HINTERNET hRequest, LPCVOID buffer, DWORD size)
LPCBYTE ptr = (LPCBYTE) buffer;
DWORD dwNumWritten;
while (size > 0)
if (!InternetWriteFile(hRequest, ptr, size, &dwNumWritten))
return false;
ptr += dwNumWritten;
size -= dwNumWritten;
return true;
bool PHP_Autentication()
static char frmdata_1[] = "-----------------------------og94kfkldjs7ekk\r\n"
"Content-Disposition: form-data; name=\"arquivo\"; filename=\"g.txt\"\r\n"
"Content-Type: text/plain\r\n"
"\r\n";
static DWORD frmdata_1_len = sizeof(frmdata_1)-1;
static char frmdata_2[] = "\r\n"
"-----------------------------og94kfkldjs7ekk--\r\n";
static DWORD frmdata_2_len = sizeof(frmdata_2)-1;
static TCHAR hdrs[] = "Content-Type: multipart/form-data; boundary=---------------------------og94kfkldjs7ekk";
static DWORD hdrs_len = (sizeof(hdrs) / sizeof(hdrs[0])) - 1;
HFILE_ptr hFile( CreateFile(_T("path\\filename.txt"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL) );
if (hFile.get() == INVALID_HANDLE_VALUE)
// error handling...
return false;
DWORD dwFileSize = GetFileSize(hFile.get(), NULL);
if (dwFileSize == INVALID_FILE_SIZE)
// error handling...
return false;
HINTERNET_ptr hSession( InternetOpen(_T("MyBrowser"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0) );
if (!hSession)
// error handling...
return false;
HINTERNET_ptr hConnect( InternetConnect(hSession.get(), carrega.IP_Server_and_Hard, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1) );
if (!hConnect)
// error handling...
return false;
LPCTSTR rgpszAcceptTypes[] = _T("*/*"), NULL;
HINTERNET_ptr hRequest( HttpOpenRequest(hConnect.get(), _T("POST"), _T("sentinela/sentinela.php"), NULL, NULL, rgpszAcceptTypes, INTERNET_FLAG_NO_CACHE_WRITE, 1) );
if (!hRequest)
// error handling...
return false;
INTERNET_BUFFERS buf;
ZeroMemory(&buf, sizeof(buf));
buf.dwStructSize = sizeof(buf);
buf.lpcszHeader = hdrs;
buf.dwHeadersLength = hdrs_len;
buf.dwHeadersTotal = hdrs_len;
buf.lpvBuffer = NULL;
buf.dwBufferLength = 0;
buf.dwBufferTotal = frmdata_1_len + dwFileSize + frmdata_2_len;
buf.dwOffsetLow = 0;
buf.dwOffsetHigh = 0;
if (!HttpSendRequestEx(hRequest.get(), &buf, NULL, 0, 1))
// error handling...
return false;
if (!WriteToInet(hRequest.get(), frmdata_1, frmdata_1_len))
// error handling...
return false;
BYTE buffer[2048];
while (dwFileSize > 0)
DWORD dwNumRead;
if ((!ReadFile(hFile.get(), buffer, sizeof(buffer), &dwNumRead, NULL)) || (dwNumRead == 0))
// error handling...
return false;
if (!WriteToInet(hRequest.get(), buffer, dwNumRead))
// error handling...
return false;
dwFileSize -= dwNumRead;
if (!WriteToInet(hRequest.get(), frmdata_2, frmdata_2_len))
// error handling...
return false;
if (!HttpEndRequest(hRequest.get(), NULL, 0, 0))
// error handling...
return false;
DWORD dwStatusCode, dwIndex = 0;
if (!HttpQueryInfo(hRequest.get(), HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwStatusCode, sizeof(dwStatusCode), &dwIndex))
// error handling...
return false;
TCHAR buffer[2048] = ;
DWORD bufferSize = sizeof(buffer);
dwIndex = 0;
if (!HttpQueryInfo(hRequest.get(), HTTP_QUERY_RAW_HEADERS_CRLF, buffer, &bufferSize, &dwIndex))
// error handling...
return false;
#ifdef UNICODE
std::ostream &t_cout = std::wcout;
#else
std::ostream &t_cout = std::cout;
#endif
t_cout.write(buffer, bufferSize / sizeof(TCHAR));
t_cout << std::endl;
return ((dwStatusCode / 100) == 2);
【讨论】:
@RemyLeabeu 非常感谢您的帮助!但是在尝试编译时,我得到了一些错误。会不会是编译器的原因?我使用 Visual Studio 2010。我会留下带有错误图像和代码的链接,以防您查看。我将不胜感激。 [prnt.sc/uqvx6f] [github.com/matheusgratao/Codex/blob/master/Server_Ban.cpp] @mgratao 有一些错别字,我现在已经修正了。但是您还使用了没有完整 C++11 实现的旧编译器,在这种情况下,它不支持using
别名,您必须将其更改为 typedef
s。
使用最后的代码它工作了!非常感谢您的帮助和耐心。还有一个问题。只有本地主机在工作。我的网站位于共享主机上,因此我无法通过 IP 访问它,只能通过域访问它。您知道您是否有其他方式使用 InternetConnect?
@mgratao InternetConnect()
可以很好地处理主机名和 IP。这就是它的设计方式。如果它不适合您,那么您可能没有正确使用它。例如,要访问http://server
,请将lpszServerName
设置为"server"
,将dwService
设置为INTERNET_DEFAULT_HTTP_PORT
。要访问https://server
,请将lpszServiceName
设置为"service"
,将dwService
设置为INTERNET_DEFAULT_HTTPS_PORT
以上是关于HttpOpenRequest () Wininet c++ e PHP的主要内容,如果未能解决你的问题,请参考以下文章
您可以传递给 Wininet 函数 HttpOpenRequest 的最大 URL 长度是多少?