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,其中包含:

00:00:AA:AA:00:00 123456789 桌面-11111 123456789 192.168.0.0 琼

【问题讨论】:

你编译你的项目时是否定义了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 文件,您可以:

动态分配整个 MIME 数据缓冲区,填充它,然后将其传递给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 别名,您必须将其更改为 typedefs。 使用最后的代码它工作了!非常感谢您的帮助和耐心。还有一个问题。只有本地主机在工作。我的网站位于共享主机上,因此我无法通过 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 长度是多少?

HttpOpenRequest () Wininet c++ e PHP

Delphi SOAP 超时?

对友好 URL 的 POST 请求失败

在 php 上接收 HTTP Post 数据

Wininet 客户端端口 - delphi 2010