发送文件POST C ++

时间:2014-11-12 19:41:20

标签: php c++ http winapi post

我正在尝试使用C ++通过POST将文本文件发送到我的localhost网络服务器上的php中的upload.php表单。

这是我的请求的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文件不在那里。该目录为空。任何人都可以帮我理解问题所在吗?感谢您!

BUMP 没有人知道怎么做或者不可能吗?因为如果不可能,那就告诉我,这样我就可以不再浪费时间去搜索。

1 个答案:

答案 0 :(得分:1)

测试你的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标头应如下所示:     内容类型:multipart / form-data;边界=边界

所以sprintf应该是这样的:

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. 我建议使用VM设置来更轻松地调试这类问题,因为这样你就可以使用Wireshark \ Fidler \ Burp了。 (您也可以尝试为localhost配置代理,我自己也没试过。也可以尝试使用外部Internet IP并配置路由器进行端口转发,但这对于这类任务来说太复杂了。) / LI>
  2. 如果这没有帮助,NetCat可能会有所帮助。不是那么容易和友好,而是完成工作。
  3. 简单地将工作示例与您的请求输出进行比较,可以准确显示缺少的内容。我为此使用了Beyond Compare。始终使用比较软件,因为人眼可以轻易欺骗。
  4. 最明显的是阅读Mime规范,看看究竟缺少什么。