2017-11-11 14 views
1

Apache2 웹 서버에서 실행되는 PHP 응용 프로그램을 사용하여 파일을 업로드하려고 시도하는 C++ 프로그램이 있습니다. 나는 무엇을해야할지 잘 모르는 매우 이상한 문제가 있습니다. 그래서 httpSendRequest() 함수를 사용하여 HTTP 요청을 만들고 wireshark wireshark image에서 볼 때 올바른 형식으로 나타납니다. 그러나 파일이 업로드되지 않았고 아파치에 대한 access.log 파일을 볼 때 패킷 캡처에 명확하게 존재하지만 사용자 에이전트 또는 콘텐츠 길이가 표시되지 않습니다. apache error image동일한 패킷에 대해 Apache2 access.log가 다릅니다.

참고로 200 상태를 반환 한 요청은 httpSendRequest를 사용하는 내 프로그램 대신에 트랩 제품군을 사용하여 보낸 동일한 패킷이며 웹 브라우저를 사용하여 파일을 성공적으로 업로드 할 수도 있습니다.

다음은 대부분 httpSendRequest를 사용하여 요청을 작성하는 코드로 this codeguru post에서 직접 가져온 것입니다. 여기

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


#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 *type  = "image/jpg"; 
    static char boundary[] = "PaulRules";   //Header boundary 
    static char nameForm[] = "fileToUpload";  //Input form name 
    static char iaddr[]  = "192.168.0.105";  //IP address 
    static char url[]  = "upload.php";   //URL 

    char hdrs[255];     //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 (filename , "rb"); 
    if (pFile==NULL) return ERROR_OPEN_FILE; 

    // 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); 
    if (content == NULL) return ERROR_MEMORY; 

    // copy the file into the buffer: 
    result = fread (content,1,lSize,pFile); 
    if (result != lSize) return ERROR_SIZE; 

    // terminate 
    fclose (pFile); 

    //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=\"fileToUpload\"; filename=\"test.bmp\"\r\n",boundary,nameForm,filename); 
    sprintf(buffer,"%sContent-Type: %s\r\n\r\n",buffer,type); 

    int cb = strlen(buffer); 
    char * bp = buffer + cb; 
    memcpy(bp, content, lSize); 
    bp += lSize; 
    int cw = sprintf(bp,"\r\n--%s--\r\n",boundary); 

    //Open internet connection 
    HINTERNET hSession = InternetOpen("Paul was here :)",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); 
    if(hSession==NULL) return ERROR_INTERNET_OPEN; 

    HINTERNET hConnect = InternetConnect(hSession, iaddr,INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1); 
    if(hConnect==NULL) return ERROR_INTERNET_CONN; 

    HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST",url, NULL, NULL, (const char**)"*/*", 0, 1); 
    if(hRequest==NULL) return ERROR_INTERNET_REQ; 

    BOOL sent= HttpSendRequest(hRequest, hdrs, strlen(hdrs), buffer, cb + lSize + cw); 
    if(!sent) return ERROR_INTERNET_SEND; 

    //close any valid internet-handles 
    InternetCloseHandle(hSession); 
    InternetCloseHandle(hConnect); 
    InternetCloseHandle(hRequest); 

    return 0; 
} 

그리고

서버 측

<?php 
$target_dir = "recvFile/"; 
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]); 
$uploadOk = 1; 
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION); 

// Check if file already exists 
if (file_exists($target_file)) { 
    echo "File already exists"; 
    $uploadOk = 0; 
} 

// Check file size 
if ($_FILES["fileToUpload"]["size"] > 500000) { 
    echo "File to large"; 
    $uploadOk = 0; 
} 

// Check if $uploadOk is set to 0 by an error 
if ($uploadOk == 0) { 
    echo "ERROR File not uploaded"; 
} 

//attempt to upload the file 
else { 
    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) { 
     //echo "The file ". basename($_FILES["fileToUpload"]["name"]). " has been uploaded."; 
     echo "Command:1"; 
    } 
    else { 
     echo $_FILES["fileToUpload"]["tmp_name"]; 
     echo "ERROR uploading file"; 
    } 
} 
?> 
+0

인가 완전히 작동 코드 콜론은 User-Agent 제품의 tok에서 합법적 인 문자입니다. 엉? – IInspectable

+0

@IInspectable 나는 그것이 합법적이라고 확신하지만 어쨌든 불필요하기 때문에 그것을 없애 버렸다. 같은 문제가 남아있다. – pchihak

답변

1

소스 파일이 "test.txt"하지만 당신이 "test.bmp"에 업로드의 PHP 스크립트입니다. 그들에게 같은 확장자를 부여하십시오.

type = "image/jpg"; 

"image/*" 또는 "text/*"로 변경 type이는 텍스트 있어야 경우.

작업 결과가 "Command 1" 인 것으로 보이는 것이 좋습니다. 파일이있을 수 있지만 예상 한 파일이 아닙니다. 그렇지 않은 경우, PHP 측에서 추출 할 수있는 오류를 확인하십시오.

sprintf(buffer,"--%s\r\nContent-Disposition: form-data; \ 
name=\"fileToUpload\"; filename=\"test.bmp\"\r\n", 
boundary,nameForm,filename); 

하나의 형식 지정자 "%s"과 4 개의 매개 변수가 있습니다. 마지막 두 매개 변수를 제거하십시오.

사용 HttpOpenRequest이 권장되는 방법 :

const char *accept[] = { "image/*", NULL }; // or `"text/*"` 
HttpOpenRequest(hConnect, "POST",url, NULL, NULL, accept, 0, 1); 


코드는 그냥 완전성을 위해 C++

#include <Windows.h> 
#include <Wininet.h> 
#include <iostream> 
#include <fstream> 
#include <sstream> 
#include <string> 

#pragma comment(lib, "wininet.lib") 

int main() 
{ 
    HINTERNET hsession = NULL; 
    HINTERNET hconnect = NULL; 
    HINTERNET hrequest = NULL; 

    const char* server = "localhost"; 
    const char* url = "upload.php"; 
    const char* type = "image/*"; 
    std::string filename = "test.bmp"; 

    std::ifstream infile("c:\\test\\test.bmp", std::ios::binary); 
    if(!infile) 
     return 0; 

    std::ostringstream oss; 
    oss << infile.rdbuf(); 

    std::string headers = "Content-type: multipart/form-data, boundary=uniquestring"; 

    std::string data = "--uniquestring\r\n\ 
Content-Disposition: form-data; name=\"fileToUpload\"; filename=\"%1\"\r\n\ 
Content-Type: %2\r\n\ 
\r\n\ 
%3\r\n\ 
--uniquestring--"; 

    data.replace(data.find("%1"), 2, filename); 
    data.replace(data.find("%2"), 2, type); 
    data.replace(data.find("%3"), 2, oss.str()); 

    hsession = InternetOpen("appname", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); 
    if(!hsession) 
     goto cleanup; 

    hconnect = InternetConnect(hsession, server, INTERNET_DEFAULT_HTTP_PORT, 
     NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1); 
    if(!hconnect) 
     goto cleanup; 

    const char *accept[] = { type, NULL }; 
    hrequest = HttpOpenRequest(hconnect, "POST", url, NULL, NULL, accept, 0, 1); 
    if(!hrequest) 
     goto cleanup; 

    BOOL sent = HttpSendRequest(hrequest, headers.data(), headers.size(), 
     &data[0], data.size()); 
    if(sent) 
    { 
     DWORD bufsize = 4096; 
     std::string read(bufsize, 0); 
     InternetReadFile(hrequest, &read[0], bufsize, &bufsize); 
     read.resize(bufsize); 
     std::cout << read << "\n"; 
    } 
    else 
    { 
     goto cleanup; 
    } 

cleanup: 
    if(hrequest) InternetCloseHandle(hrequest); 
    if(hconnect) InternetCloseHandle(hconnect); 
    if(hsession) InternetCloseHandle(hsession); 
    return 0; 
} 
+0

.txt 파일을 .jpg 형식으로 업로드하려고 시도했을 때 실제로 서버가 손상되었다고 생각했습니다. 정말 고마워하는 모든 도움에 감사드립니다! – pchihak

+0

좋습니다. 코드는 C 언어로 작성되었습니다. 여기에 C++ 11 코드를 추가하여 더 쉽게 만들 수 있습니다. –

1

를 사용하여 여기에

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

using namespace std; 
int main() 
{ 
    // Local variables 
    static char *filename = "Desert.jpg"; //Filename to be loaded 
    static char *type  = "multipart/form-data"; 
    static char boundary[] = "PaulRules";   //Header boundary 
    static char nameForm[] = "fileToUpload";  //Input form name 
    static char iaddr[]  = "192.168.0.105";  //IP address 
    static char url[]  = "upload.php";   //URL 

    char hdrs[255];     //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 (filename , "rb"); 

    // 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); 

    // copy the file into the buffer: 
    result = fread (content,1,lSize,pFile); 

    // terminate 
    fclose (pFile); 

    //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=\"fileToUpload\"; filename=\"%s\"\r\n",boundary, filename); 
    sprintf(buffer,"%sContent-Type: %s\r\n\r\n",buffer,type); 

    int cb = strlen(buffer); 
    char * bp = buffer + cb; 
    memcpy(bp, content, lSize); 
    bp += lSize; 
    int cw = sprintf(bp,"\r\n--%s--\r\n",boundary); 

    //Open internet connection 
    HINTERNET hSession = InternetOpen("Winsock",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); 

    HINTERNET hConnect = InternetConnect(hSession, iaddr,INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1); 

    const char* accept[] = {"*/*", NULL}; 
    HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST",url, NULL, NULL, accept, 0, 1); 

    BOOL sent= HttpSendRequest(hRequest, hdrs, strlen(hdrs), buffer, cb + lSize + cw); 

    DWORD dwSize, dwRead; 
    CHAR szBuffer[1024]; 
    if(!InternetQueryDataAvailable(hRequest, &dwSize, 0, 0)){ 
     std::cout << "QUERYDATA ERROR: " << GetLastError() << std::endl; 
    } 
    else{ 
     while(InternetReadFile(hRequest, szBuffer, sizeof(szBuffer)-1, &dwRead) && dwRead) { 
     szBuffer[dwRead] = 0; 
     dwRead=0; 
     } 
     cout << szBuffer; 
    } 

    //close any valid internet-handles 
    InternetCloseHandle(hSession); 
    InternetCloseHandle(hConnect); 
    InternetCloseHandle(hRequest); 

    return 0; 
}