2016-04-29 91 views
-5

我試圖使用Windows socket HTTP將一個PNG圖像上傳到PHP腳本。一切似乎工作正常,但是當我嘗試在Windows畫圖中打開我的圖像時,出現錯誤消息:Image C++中的HTTP上傳已損壞

這不是有效的位圖文件。

我不知道什麼是錯的。我對HTTP頭字段有點新,所以我猜測頭可能是錯的。什麼可能導致這個?

的C++代碼(original C++ pastebin link):

#include <iostream> 
#include <winsock2.h> 
#include <string> 
#include <fstream> 
#include "windows.h" 
#include "stdio.h" 

using namespace std; 

#define PORT  80 
#define IP   "127.0.0.1" 
#define HOST  "locahost" 
#define RECEIVER "/up.php" 
#define COMPNAME "compname" 
#define PROGRAM "program" 
#define FILENAME "file" 
#define BOUNDARY "----------boundary" 
#define DUMMY_DATA "c2FzYXNhc2FzZGRmZGZkY2Q=" 
#define DUMMY_FILE "ok.png" 

//------------------------------------ 
string constructBody(string args[2], string file[2]); 
string readFile(string fileName); 
//------------------------------------ 

int main() { 
    // initiate the socket! 
    SOCKET dataSock; 
    WSADATA wsaData; 
    int error = WSAStartup(0x0202, &wsaData); 
    if (error != 0) { 
     WSACleanup(); 
     exit(1); // oh shit, this shouldn't happen! 
    } 
    // all internets, engage! 
    SOCKADDR_IN target; 
    target.sin_family = AF_INET; 
    target.sin_port = htons(PORT); 
    target.sin_addr.s_addr = inet_addr(IP); 
    dataSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (dataSock == INVALID_SOCKET) { 
     exit(1); // Houston, we have a problem! 
    } 
    connect(dataSock, (SOCKADDR*)&target, sizeof(target)); 

    string programNames[5][2] = {{"Browser", "Mozilla"}}; 
    string file[2] = {FILENAME, "Default.txt"}; 

    for (int i = 0; i < 1; i++) { 
     printf("Sending data for %s\n", (programNames[i][1]).c_str()); 
     string body = constructBody(programNames[i], file); 
     char header[1024]; 
     sprintf(header, "POST %s HTTP 1.1\r\n" 
         "Host: %s\r\n" 
         "Content-Length: %d\r\n" 
         "Connection: Keep-Alive\r\n" 
         "Content-Type: multipart/form-data; boundary=%s\r\n" 
         "\r\n", RECEIVER, IP, strlen(body.c_str()), BOUNDARY); 
//  printf("%s\n\n", header); 
     int p = send(dataSock, header, strlen(header), 0); 
//  printf("p == %d\n", p); 
     int k = send(dataSock, body.c_str(), strlen(body.c_str()), 0); 
//  printf("k == %d\n", k); 

     char buff[1024]; 
     recv(dataSock, buff, 1024, 0); 
     printf("%s\n\n", buff); 
    } 

    closesocket(dataSock); 
    WSACleanup(); 
} 

string readFile(string fileName) { 
    string fileContents; 
    ifstream tmp(fileName.c_str()); 
    getline(tmp, fileContents); 
    tmp.close(); 

    return fileContents; 
} 

string constructBody(string args[2], string file[2]) { 
    string body; 
    string CRLF = "\r\n"; 

    // first we add the args 
    body.append("--"+string(BOUNDARY)+CRLF); 
    body.append("Content-Disposition: form-data; name=\""+string(COMPNAME)+"\""+CRLF); 
    body.append(CRLF); 
    body.append(args[0]+CRLF); 
    body.append("--"+string(BOUNDARY)+CRLF); 
    body.append("Content-Disposition: form-data; name=\""+string(PROGRAM)+"\""+CRLF); 
    body.append(CRLF); 
    body.append(args[1]+CRLF); 

    // now we add the file 
    body.append("--"+string(BOUNDARY)+CRLF); 
    body.append("Content-Disposition: form-data; name=\""+string(FILENAME)+"\"; filename=\""+string(DUMMY_FILE)+"\""+CRLF); 
    body.append("Content-Type: media-type"+CRLF); 
    body.append(CRLF); 
    body.append(DUMMY_DATA+CRLF); 
    body.append("--"+string(BOUNDARY)+"--"+CRLF); 
    body.append(CRLF); 

// printf(body.c_str()); exit(0); 

    return body; 
} 

PHP代碼(original PHP pastebin link):

<?php 
/* ===== CONSTANTS ===== */ 
$ROOT_DIR = 'FILES'; 
$COMPUTER_NAME = 'compname'; 
$PROGRAM = 'program'; 
$FILENAME = 'file'; 
$CHUNK_SIZE = 1024; 
/* ===================== */ 

//===================================== 
/** 
    Function that gets current time and formats it into pretty looking date 
*/ 
function makeDate() { 
    return strftime('%Y-%m-%d, %H.%M'); 
} 
//===================================== 
// check here if the parameters are set. If it's not then it's safe to say some one is snooping around... 
if (isset($_POST[$COMPUTER_NAME], $_POST[$PROGRAM], $_FILES[$FILENAME])) { 
    // construct a full path and create it 
    $fullPath = $ROOT_DIR.'\\'.$_POST[$COMPUTER_NAME].'\\'.$_POST[$PROGRAM].'\\'.makeDate(); 
    mkdir($fullPath, 0777, true); 

    // move the files and rename them as temporary 
    $filename = $_FILES[$FILENAME]['name']; 
    move_uploaded_file(($_FILES[$FILENAME]['tmp_name']), $fullPath.'\\'.$filename.'.tmp'); 

    // decode received files 
    $src = fopen($fullPath.'\\'.$filename.'.tmp', 'rb'); 
    $dst = fopen($fullPath.'\\'.$filename, 'wb'); 
    while (!feof($src)) { 
     fwrite($dst, base64_decode(fread($src, $CHUNK_SIZE))); 
    } 
    fclose($dst); 
    fclose($src); 
    unlink($fullPath.'\\'.$filename.'.tmp'); // remove the temp file after decoding it 

    echo 'OK!'; 
} else { 
    echo 'oh no :('; 
} 
//===================================== 
?> 
+3

請提供[最小,完整和可驗證示例](http://stackoverflow.com/help/mcve) – teivaz

回答

0

在最低限度,C++代碼正在讀取PNG文件爲文本文件,並將內容視爲空終止的字符串。它也似乎只讀到第一行結尾。你想要做的是對.png文件的二進制讀取。

嘗試更改您的readFile()函數以使用與此example相同的二進制讀取功能。

請注意,在該示例中,首先讀取文件大小,以便分配足夠大小的緩衝區。您可能不想手動處理緩衝區管理,因此您可以選擇使用vector<char>,並且將爲您分配/釋放關聯的內存資源。有關vector<>的參考指南,請參閱此link

像這樣的東西可能更接近你想要什麼:

bool readFile(string fileName, vector<char> &fileContents) { 
    vector<char> fileContents; 
    std::ifstream is (fileName.c_str(), std::ifstream::binary); 
    bool success = is; 

    if (success) { 
     // get length of file: 
     is.seekg (0, is.end); 
     int length = is.tellg(); 
     is.seekg (0, is.beg); 

     fileContents.resize(length); 
     is.read(fileContents, length); 
     is.close(); 
    } 

    return success; 
} 

有了這些變化,你必須改變你怎麼稱呼readFile()。有趣的是,readFile()在您發佈的代碼中實際上未被調用,因此constructBody()中會有一個點,您聲明一個fileContents變量並調用readFile()來填充它。

考慮這種使用readFile()

vector<char> fileContents; 
bool success = readFile(filename, fileContents); 

在同一個函數以後,你要輸出fileContentsbody緩衝區。

fileContents一樣,body變量不應該是string,以避免偶然的空終止。在這種情況下最好使用vector<char>,並且所有對body.append()的調用都需要更新以正確附加內容和行尾。它應該是直截了當的,但仍需要一些額外的工作來完成。

我還沒有深入研究PHP代碼,因爲這將是您閱讀和發送.png文件時遇到的第一個主要問題。無論是完全是別的東西。您需要確保PHP代碼接收的文件內容與原始.png文件的實際內容相匹配,並且您可以提供調試輸出來執行此操作。在匹配之前,它可能仍然是C++代碼中的一個問題。