Я пытался загрузить изображение PNG с помощью сокетов Windows HTTP в скрипт PHP. Кажется, все работает нормально, но когда я пытаюсь открыть свое изображение в Windows Paint, я получаю сообщение об ошибке:
Это не правильный файл растрового изображения.
Я не знаю, что не так. Я немного новичок в полях заголовка HTTP, поэтому я думаю, что заголовок может быть неправильным. Что может быть причиной этого?
Код C ++ (оригинальная ссылка на C ++):
#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 (оригинальная ссылка на PHP):
<?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 :(';
}
//=====================================
?>
По крайней мере, код C ++ читает файл .png как текстовый файл и обрабатывает содержимое как строку с нулевым символом в конце. Также кажется, что он читает только до конца первой строки. То, что вы хотите сделать, это двоичное чтение файла .png.
Попробуйте изменить свой readFile()
Функция использовать ту же возможность двоичного чтения, как это пример.
Обратите внимание, что в этом примере размер файла читается первым, чтобы выделить буфер адекватного размера. Вы можете не захотеть иметь дело с управлением буфером вручную, поэтому вы можете использовать vector<char>
вместо этого, и связанный ресурс памяти будет выделен / освобожден для вас. Обратитесь к этому ссылка на сайт для справочного руководства для vector<>
,
Нечто подобное может быть ближе к тому, что вы хотите:
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);
Позже в той же функции вы захотите вывести fileContents
к body
буфер.
Как с fileContents
, body
переменная не должна быть string
, чтобы избежать случайного нулевого завершения. Лучше использовать vector<char>
в этом случае, а также и все вызовы body.append()
нужно будет обновить, чтобы правильно добавить содержимое и окончания строк. Это должно быть просто, но все же потребует некоторой дополнительной работы для завершения.
Я не углубился в код PHP, так как это будет первая серьезная проблема, связанная с чтением и отправкой файла .png. Будь то что-то еще, целиком. Вы захотите убедиться, что содержимое файла, полученного кодом PHP, совпадает с фактическим содержимым исходного файла .png, и вы можете предоставить отладочную информацию для этого. Пока они не совпадают, это, вероятно, все еще проблема в коде C ++.
Других решений пока нет …