【问题标题】:Send file using POST [ Unable to upload ] in C++在 C++ 中使用 POST [无法上传]发送文件
【发布时间】:2018-05-09 03:57:55
【问题描述】:

我在将文件发送到我的服务器时遇到问题。我检查了其他一些问题,试图解决大部分问题,但最后我无法上传文件 这是我的 C++ 代码:

   #define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <wininet.h>
#include <iostream>
#include <tchar.h>
#pragma warning(disable : 4996)
#pragma comment(lib,"wininet.lib")
#define ERROR_OPEN_FILE       10
#define ERROR_MEMORY          11
#define ERROR_SIZE            12
#define ERROR_INTERNET_OPEN   13
#define ERROR_INTERNET_CONN   14
#define ERROR_INTERNET_REQ    15
#define ERROR_INTERNET_SEND   16

using namespace std;

int main()
{
    // Local variables
    static char *filename = "perf.txt";   //Filename to be loaded
    static char *filepath = "C:\\perf.txt";   //Filename to be loaded
    static char *type = "text/plain";
    static char boundary[] = "BOUNDARY";            //Header boundary
    static char nameForm[] = "file";     //Input form name
    static char iaddr[] = "2e8cd930.ngrok.io";        //IP address
    static char url[] = "/post/upload.php";         //URL

    char hdrs[512] = { '-' };                  //Headers
    char * buffer;                   //Buffer containing file + headers
    char * content;                  //Buffer containing file
    FILE * pFile;                    //File pointer
    long lSize;                      //File size
    size_t result;

    // Open file
    pFile = fopen(filepath, "rb");
    if (pFile == NULL)
    {
        printf("ERROR_OPEN_FILE");
        getchar();
        return ERROR_OPEN_FILE;
    }
    printf("OPEN_FILE\n");

    // obtain file size:
    fseek(pFile, 0, SEEK_END);
    lSize = ftell(pFile);
    rewind(pFile);

    // allocate memory to contain the whole file:
    content = (char*)malloc(sizeof(char)*(lSize + 1));
    if (content == NULL)
    {
        printf("ERROR_MEMORY");
        getchar();
        return ERROR_OPEN_FILE;
    }
    printf("MEMORY_ALLOCATED\t \"%d\" \n", &lSize);
    // copy the file into the buffer:
    result = fread(content, 1, lSize, pFile);
    if (result != lSize)
    {
        printf("ERROR_SIZE");
        getchar();
        return ERROR_OPEN_FILE;
    }
    printf("SIZE_OK\n");

    content[lSize] = '\0';

    // terminate
    fclose(pFile);
    printf("FILE_CLOSE\n");
    //allocate memory to contain the whole file + HEADER
    buffer = (char*)malloc(sizeof(char)*lSize + 2048);

    //print header
    sprintf(hdrs, "Content-Type: multipart/form-data; boundary=%s", boundary);
    sprintf(buffer, "-%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n", boundary, nameForm, filename);
    sprintf(buffer, "%sContent-Type: %s\r\n", buffer, type);
    sprintf(buffer, "%s\r\n\r\n%s", buffer, content);
    sprintf(buffer, "%s\r\n-%s-\r\n", buffer, boundary);

    printf("%s", buffer);

    //Open internet connection
    HINTERNET hSession = InternetOpen("WINDOWS", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (hSession == NULL)
    {
        printf("ERROR_INTERNET_OPEN");
        getchar();
        return ERROR_OPEN_FILE;
    }
    printf("INTERNET_OPENED\n");

    HINTERNET hConnect = InternetConnect(hSession, iaddr, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
    if (hConnect == NULL)
    {
        printf("ERROR_INTERNET_CONN");
        getchar();
        return ERROR_INTERNET_CONN;
    }
    printf("INTERNET_CONNECTED\n");

    HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST", _T(url), NULL, NULL, NULL, INTERNET_FLAG_RELOAD, 1);
    if (hRequest == NULL)
    {
        printf("ERROR_INTERNET_REQ");
        getchar();

    }
    printf("INTERNET_REQ_OPEN\n");

    BOOL sent = HttpSendRequest(hRequest, hdrs, strlen(hdrs), buffer, strlen(buffer));

    if (!sent)
    {
        printf("ERROR_INTERNET_SEND");
        getchar();
        return ERROR_INTERNET_CONN;
    }
    printf("INTERNET_SEND_OK\n");

    InternetCloseHandle(hSession);
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hRequest);

    getchar();
    return 0;
} 

这是我的 PHP 代码 [upload.php],我已经更改了上传文件夹权限以供其他人创建和删除文件:

<?php
$uploaddir = 'upload/';

if (is_uploaded_file(isset($_FILES['file']['tmp_name'])?($_FILES['file'['tmp_name']]):0)) 
{
    $uploadfile = $uploaddir . basename($_FILES['file']['name']);
    echo "File ". $_FILES['file']['name'] ." uploaded successfully. ";

    if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) 
    {
        echo "File was moved! ";
    }
    else
    {
        print_r($_FILES);
    }
}
else 
{
    print_r($_FILES);
}
?>

使用 Wireshark 我的发布请求和响应是 [ 我已经尝试在 Content -Type 行之后用 1 行替换两个新行,但没有帮助 更改分隔符后:

    POST /post/upload.php HTTP/1.1
Content-Type: multipart/form-data; boundary=BOUNDARY
User-Agent: WINDOWS
Host: 2e8cd930.ngrok.io
Content-Length: 130
Cache-Control: no-cache

-BOUNDARY
Content-Disposition: form-data; name="file"; filename="perf.txt"
Content-Type: text/plain


Whats Up?
-BOUNDARY-
HTTP/1.1 200 OK
Date: Sat, 25 Nov 2017 11:25:16 GMT
Server: Apache/2.4.27 (Debian)
Content-Length: 10
Content-Type: text/html; charset=UTF-8

Array
(
)

我不知道为什么我的服务器回复带有 Array ()。文件未上传。

【问题讨论】:

  • 至少你的结束分隔符和标题中的分隔符都是错误的。 — 不是边界的一部分,因此将其从标题中删除。结束分隔符也需要——到底。您的 sprintfs 也很糟糕,因为它们一遍又一遍地复制现有数据,而不是附加新数据。而且你在 body 之前缺少了 \r。
  • 对不起,我不明白你的意思。您能否详细说明或编辑代码以便我理解

标签: php c++ http winapi post


【解决方案1】:

我能看到的第一个问题:

您在标题中说分隔符是—BOUNDARY,然后使用与实际分隔符相同的字符串。这是错误的。格式是

—DELIMITER
content
—DELIMITER
content
—DELIMITER—

所以你的标题应该只写BOUNDARY作为分隔符。

Content-Type: multipart/form-data; boundary=BOUNDARY

您还需要将结尾的 添加到结束分隔符。

在将标题与正文分开时,您也有\r\n\n。应该是\r\n\r\n

这些错误将导致 MIME 解析器无法在任何地方找到任何表单数据。

就性能而言,您不应该使用sprintf 来追加数据,方法是将缓冲区放在首位,然后是您要追加的内容。这会导致太多复制已经存在的数据。您应该使用 strncat 而不是因为所有内容都是要附加的字符串。或者监控字符串长度并在末尾使用sprintf 追加。请参阅this question 了解更多信息。

【讨论】:

  • 我已经更改了分隔符并且我的更新请求在上面,但我仍然无法上传文件??任何建议
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 1970-01-01
  • 2013-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-16
相关资源
最近更新 更多