С++ и пересылка данных методом POST

F
На сайте с 21.07.2006
Offline
8
1236

Кто нибудь принимал файлы с помощью С++?

Тоесть в браузере


<html>
<body>
<form action="/cgi/loader.exe" enctype=multipart/form-data method=post>
<input type=file name='file1' ><br>
<!--
<input type=file name='file2' ><br>
<input type=file name='file3' ><br>
<input type=file name='file4' ><br>
-->
<input type=submit>
</form>
</body>
</html>

необходимо выбрать файл, нажать submit, а *.cgi на сервере вынимает из пришедших данных файл и сохраняет его на диск.

Написал програмку но она коректно сохраняет только текстовые файлы, ежели прислать jpg картинку то в ней совпадает только первых несколько десятков символов, а дальше все символы заменяются на буквы я.

Где зарыта собака?

Вот небольшой пример(сохраняю весь запрос в файл) который глючит аналогично:


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
printf("Content-type: text/html\n");
printf("Pragma: no-cache\n");
printf("\n");
char *REQUEST_METHOD=getenv("REQUEST_METHOD");
char *CONTENT_LENGTH=getenv("CONTENT_LENGTH");
int cmp_rez=strcmp(REQUEST_METHOD,"POST");
if (cmp_rez==0)
{
long int i;
char ch;
long int num_of_bytes=atoi(CONTENT_LENGTH);
FILE *fp;
fp=fopen("recived.dat","w");
for (i=0;i<num_of_bytes-100;i++)
{
ch=fgetc(stdin);
fputc(ch,fp);
}
fclose(fp);
}
return 1;
}
M
На сайте с 21.07.2005
Offline
70
#1

я не сишник, но мне немного не понятно зачем

printf("Content-type: text/html\n");
printf("Pragma: no-cache\n");
printf("\n");

при сохранении файла :\ в частности бинарного

Artisan
На сайте с 04.03.2005
Offline
357
#2

$ man 3 fgetc

If the stream is at end-of-file or a read error occurs, the routines return EOF. The routines feof(3) and and ferror(3) must be used to distinguish between end-of-file and error.
www.leak.info / ДАРОМ линки конкурентов и забытых доменов
F
На сайте с 21.07.2006
Offline
8
#3
Mitos:
я не сишник, но мне немного не понятно зачем

printf("Content-type: text/html\n");
printf("Pragma: no-cache\n");
printf("\n");

при сохранении файла :\ в частности бинарного

Это для того чтобы Apache не выдавал "Internal error", вобщем в данном коде вроде больше нагрузки не несет.

Artisan:
$ man 3 fgetc

If the stream is at end-of-file or a read error occurs, the routines return EOF. The routines feof(3) and and ferror(3) must be used to distinguish between end-of-file and error.

Прописал feof в коде и ferror, оказалось при загрузке картинки браузер присылает только первых +-50 байтов :-0

А как же взять остальную часть картинки?

PS: ferror выдает 0.

F
На сайте с 21.07.2006
Offline
8
#4

Написал я эту програмку, вот выкладываю решение моей проблемы на случай если ктото сюда попадет в своих поисках.

Вся проблема в том что данные из стандартного потока ввода читаются в текстовом режиме, некоторые байты поэтому искажаются и принимаются как управляющие. Все было бы просто если бы

нужно было читать из файла(переоткрыть файл делов то), но так как стандартный поток ввода уже открыт, его необходимо перевести в бинарный режим чтения не закрывая.

Вот функция(работает в Microsoft Visual C++ 6.0, в досовском С++ вроде такая тоже есть но без нижнего подчеркивания), которая в данном случае переводит стандартный поток ввода в бинарный режим чтения:

_setmode(_fileno(stdin),_O_BINARY); //(хочу заметить что найти нужную функцию в инете почемуто оказалось нелегко)

После того как stdin переведен в бинарный режим остается дело техники - разобрать данные POST запроса.

Вот моя програмка(скомпилировать в Microsoft Visual C++ 6.0 как консольное приложение и положить в папку cgi на веб сервере) по загрузке 4-х файлов.


// loader.cpp : Defines the entry point for the console application.

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "io.h"
#include "fcntl.h"

#define term_size 200
#define header_size 400

int get_header(char *tmp_header)
{
int stop,tmp_count;
char ch;
for (tmp_count=0,stop=0;((stop==0)&&(tmp_count<header_size));tmp_count++)
{
ch=fgetc(stdin);
tmp_header[tmp_count]=ch;
if (tmp_count>4)
{
if ((tmp_header[tmp_count-1]=='\n')&&(tmp_header[tmp_count]=='\n'))
{
stop=1;
tmp_header[tmp_count+1]=0;
}
if ((tmp_header[tmp_count-2]=='\n')&&(tmp_header[tmp_count-1]=='\r')&&(tmp_header[tmp_count]=='\n'))
{
stop=1;
tmp_header[tmp_count+1]=0;
}
}
}
return 1;
}

int get_filename(char *tmp_header, char *filename)
{
int i;
char *ptr;
ptr=strstr(tmp_header,"filename=");
for (;*ptr!='"';ptr++) { }
ptr++;
for (i=0;((i<29)&&(*ptr!='"'));ptr++)
{
if ((*ptr=='\\')||(*ptr=='/'))
{
i=0;
}
if ((*ptr!='\\')&&(*ptr!='/')&&(*ptr!='"'))
{
filename=*ptr;
i++;
}
filename=0;
}
return 1;
}

int get_filebody(char *terminator,char *filename,long int toread)
{
int i,stop,wr;
wr=0;
long int readed;
int term_len=strlen(terminator);
char *buffer=(char *)malloc(term_len+1);
buffer[0]=0;
readed=0;
char ch;
FILE *fp;
if ((strcmp(filename,""))!=0)
{
fp=fopen(filename,"wb");
wr=1;
}
for (i=0,stop=0;stop==0;)
{
ch=fgetc(stdin);
readed++;
if (terminator==ch)
{
buffer=ch;
buffer[i+1]=0;
i++;
}
else
{
if (strlen(buffer)==0)
{
//write ch only
if (wr==1) { fputc(ch,fp); }
}
else
{
//write buffer and ch
if (wr==1)
{
fwrite(buffer,strlen(buffer),1,fp);
fputc(ch,fp);
}
buffer[0]=0;
i=0;
}
}
if (term_len==i+1)
{
stop=1;
}
if (readed>=toread)
{
if (strlen(buffer)>0)
{
fwrite(buffer,strlen(buffer),1,fp);
}
stop=1;
}
}
if (wr==1)
{
fclose(fp);
}
return readed;
}

int main(int argc, char* argv[])
{
printf("Content-type: text/html\n");
printf("Pragma: no-cache\n");
printf("\n");
printf("Proga: loader.<br>\n");

char *REQUEST_METHOD=getenv("REQUEST_METHOD");
char *CONTENT_LENGTH=getenv("CONTENT_LENGTH");
printf("REQUEST_METHOD: %s.<br>\n",REQUEST_METHOD);
printf("CONTENT_LENGTH: %s.<br>\n",CONTENT_LENGTH);

int cmp_rez=strcmp(REQUEST_METHOD,"POST");
if (cmp_rez==0)
{
int tmp_count,stop;
char ch;
char terminator[term_size];
strset(terminator,'1');
long int num_of_bytes=atoi(CONTENT_LENGTH);
long int readed;
// пожалуй самое главное:
_setmode(_fileno(stdin),_O_BINARY); // устанавливаем стандартный поток ввода(stdin) в бинарный режим чтения!

//получаем терминатор - разделитель данных в POST запросе
terminator[0]='\r';
terminator[1]='\n';
for (tmp_count=2,stop=0;((stop==0)&&(tmp_count<term_size));tmp_count++)
{
ch=fgetc(stdin);
terminator[tmp_count]=ch;
if (tmp_count>5)
{
if (terminator[tmp_count]=='\n')
{
stop=1;
terminator[tmp_count]=0;
}
}
} // терминатор получен.

char tmp_header[header_size];
char filename[30]="";
long int term_len=strlen(terminator);
// загрузка первого файла
get_header(tmp_header); // прочитать заголовок перед телом файла
get_filename(tmp_header,filename); // взять из заголовка имя файла
readed=get_filebody(terminator,filename,num_of_bytes); // прочитать тело файла и сохранить
printf("filename:%s;<br>\n",filename);
filename[0]='\0';
// загрузка второго файла
get_header(tmp_header);
get_filename(tmp_header,filename);
num_of_bytes-=readed;
readed=get_filebody(terminator,filename,num_of_bytes);
printf("filename:%s;<br>\n",filename);
filename[0]='\0';
// загрузка трельего файла
get_header(tmp_header);
get_filename(tmp_header,filename);
num_of_bytes-=readed;
readed=get_filebody(terminator,filename,num_of_bytes);
printf("filename:%s;<br>\n",filename);
filename[0]='\0';
// загрузка четвертого файла
get_header(tmp_header);
get_filename(tmp_header,filename);
num_of_bytes-=readed;
readed=get_filebody(terminator,filename,num_of_bytes);
printf("filename:%s;<br>\n",filename);
filename[0]='\0';
}
return 1;
}

PS: не совсем сохранились сдвиги в коде:(

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий