Отправить файл POST C ++

Я пытаюсь отправить текстовый файл через POST в мою форму upload.php в php на моем локальном веб-сервере с использованием C ++.

Вот мой 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);
}
?>

upload каталог существует в том же каталоге, что и upload.php (содержимое выше).

Вот код, который я использую для подготовки http-запроса и его отправки:

#include <windows.h>
#include <wininet.h>
#include <iostream>
#include <tchar.h>

#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   = "test.txt";   //Filename to be loaded
static char *filepath   = "C:\\wamp\\www\\post\\test.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[]     = "localhost";        //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%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;
}

Когда я выполняю upload.exe (содержимое выше). Я получаю следующий вывод:

OPEN_FILE
MEMORY_ALLOCATED    "1832340"SIZE_OK
FILE_CLOSE
---BOUNDARY---
Content Disposition: form-data; name="file"; filename="test.txt"Content-Type: text/plain
test
---BOUNDARY---
INTERNET_OPENED
INTERNET_CONNECTED
INTERNET_REQ_OPEN
INTERNET_SEND_OK

Вот журнал ошибок PHP:

[12-Nov-2014 20:09:58 Europe/Paris] PHP Stack trace:
[12-Nov-2014 20:09:58 Europe/Paris] PHP   1. {main}() C:\wamp\www\post\upload.php:0

Я немного сбит с толку относительно того, что это значит. Это ошибка?

Похоже, что все проходит (примечание: содержимое test.txt является «test»). Хотя, когда я смотрю в upload каталог. Файл test.txt там отсутствует. Каталог пуст. Может кто-нибудь помочь мне понять, в чем проблема? Спасибо!

УДАР Никто не знает, как это сделать, или это невозможно? Потому что, если это невозможно, просто скажи мне, чтобы я прекратил тратить свое время на поиски.

3

Решение

Тестируя ваш клиент C ++, я обнаружил, что переменная content который содержит содержимое файла, не заканчивается NULL поэтому, когда вы копируете его с sprintf вы копируете случайные байты до NULL появляется.

Измените распределение на это:

 content = (char*) malloc (sizeof(char)*(lSize+1));

И после прочтения содержимого файла сделайте это:

content[lSize] = '\0';

Кроме того, я вполне уверен, что BOUNDARY должен начинаться с новой строки. Так что внесите это изменение тоже:

 sprintf(buffer,"%s\r\n--%s--\r\n",buffer,boundary);

Редактировать:

Сравнивая обычный запрос формы HTML, я вижу, что содержимое должно начинаться после двух строк, поэтому измените это тоже:

sprintf(buffer,"%s\r\n%s",buffer,content);

Edit2:

После тестирования с кодом PHP я обнаружил еще несколько проблем с кодом C ++.
(кстати, в коде PHP есть опечатка: отсутствует ] в операторе if)

Граница не установлена ​​правильно.

Формат MIME должен быть таким:

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

test
--BOUNDARY

Заголовок HTTP должен быть таким:
Content-Type: multipart / form-data; граница = ГРАНИЦЫ

Итак sprintfs должно выглядеть так:

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%s",buffer,content);
sprintf(buffer,"%s\r\n--%s\r\n",buffer,boundary);

После внесения всех исправлений в этот пост код должен работать.

Подводить итоги:

  1. Я бы порекомендовал использовать настройку виртуальной машины для более простой отладки подобных проблем, потому что тогда вы можете использовать Wireshark \ Fidler \ Burp. (Вы также можете попробовать настроить прокси-сервер для localhost, но сам никогда не пробовал. Также вы можете попробовать использовать свой внешний IP-адрес в Интернете и настроить маршрутизатор для переадресации портов, но это слишком сложно для такого рода задач).
  2. Если это не поможет, NetCat может помочь. Не так легко и дружелюбно, но делает свою работу.
  3. Простое сравнение рабочего примера с выводом вашего запроса показывает, чего именно не хватает. Я использовал Beyond Compare для этого. Всегда работайте с программным обеспечением для сравнения, поскольку человеческий глаз может быть легко обманут.
  4. Наиболее очевидным было прочитать спецификацию Mime и увидеть, чего именно не хватает.
1

Другие решения

Других решений пока нет …