Закачка файла спомощью C++ stdin и cgi?
Пока что я написал закачку одного файла.
НО вот проблема: если в файле текст английский или руский - закачивается нормально, а если закачивать маленькую картинку, то первых несколько десятков "ироглифов" заканчивается нормально а дальше идут одни буквы "я":( .
В чем тут может быть проблема? Может я не правильно читаю из stdin?
вот код html странички:
[HTML]
<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>
[/HTML]
Вот сишный код:
#include<stdlib.h>
#include<string.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;
long int readed;
int term_len=strlen(terminator);
char *buffer=(char *)malloc(term_len+1);
buffer[0]=0;
readed=0;
char ch;
FILE *fp;
fp=fopen(filename,"w");
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
fputc(ch,fp);
}
else
{
//write buffer and ch
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;
}
}
fclose(fp);
return 1;
}
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)
{
int i;
long int num_of_bytes=atoi(CONTENT_LENGTH);
char terminator[term_size];
strset(terminator,'1');
char ch;
int tmp_count;
int stop;
for (tmp_count=0,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;
}
}
}
long int term_len=strlen(terminator);
//printf("CONTENT_LENGTH= %i\n",num_of_bytes);
//printf("terminator= %s<br>\nlenght_t:%i<br>\n",terminator,term_len);
char tmp_header[header_size];
strset(tmp_header,'1');
get_header(tmp_header);
char filename[30]="";
get_filename(tmp_header,filename);
get_filebody(terminator,filename,num_of_bytes-term_len-strlen(tmp_header));
}
return 1;
}
текстовые данные приходят нормально, а данные из jpg сначала приходят правильно а потом почемуто все заменяются буквами я.
Вот маленький код упростил для большей наглядности:
#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;
}
ЗЫ: возможно надо уточнить для когото один момент: для демонстрации надо поставить на веб сервер, скомпилированую
екзешку положить в каталог для cgi приложений и послать ей с помощью браузера и приведеного выше html кода файлик сначала
текстовый (посмореть результат в файле recived.dat)а потом jpg(посмореть результат в файле recived.dat).
ЗЗЫ: Может эта тема больше подходит для раздела "Web программирование"?
Попробуй поставить jpeg/image.
Попробуй поставить jpeg/image.
Эта замена ничего не меняет(на всякий случай проверил), так как та строка для вебсервера а я пишу в файл.
И вообще, ты уверен, что stdin/stdout работают с двоичными данными?
Создай объект типа ifstream, читай оттуда операторами >> (если писать в стиле С++), или же работай с помощью fgetc, но не потоками С++... Некрасиво это :)
И еще пара рекомендаций.
Во-первых, не пиши tmp_count++, пиши ++tmp_count, поскольку прединкремент работает быстрее.
Во-вторых, в записи
Быстрее-то быстрее, а вот только если в цикле нужно пройтись от 0 до 100, что ж ты с прединкрементом будешь писать так?
:D
А теперь выведи в цикле i на консоль.
Учи матчасть!
И еще пара рекомендаций.
Во-первых, не пиши tmp_count++, пиши ++tmp_count, поскольку прединкремент работает быстрее.
М-да... удивили оба автора... :\
при закачке, читай Content-length тогда точно будешь знать когда нужно прервать чтение STDIN...
заголовок от данных отделяется \n\n.....
вроде бы так. надеюсь поможет. код посмотреть не смог подробненько... извиняй если чего не так :)
при закачке, читай Content-length тогда точно будешь знать когда нужно прервать чтение STDIN...
заголовок от данных отделяется \n\n.....
вроде бы так. надеюсь поможет. код посмотреть не смог подробненько... извиняй если чего не так :)
Все это так но вот проблема оказалась в том что из стандартного потока ввода(stdin) данные читаются в текстовом режиме, в связи с этим некоторые байты искажаются при чтении (принимаются за управляющие).
И вообще, ты уверен, что stdin/stdout работают с двоичными данными?
Не уверен, но как то ведь написали разработчики языка PHP загрузку файлов, PHP насколько мне известно на С разработали.
Уже обыскался искать, не знаю как перевести стандартный поток ввода в бинарный режим чтения.
http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.13
а эт если пользуешь stdin (из stdio.h)
http://www.cplusplus.com/reference/clibrary/cstdio/
Что удивительного?
Постинкремент, по идее, запоминает старое значение объекта, после чего совершает действие над объектом и возвращает старое значение.
Прединкремент же просто выполняет действие и возвращает *this.
Как видим, в постинкременте тратится время на создание объекта. Это касается, кстати, и простых типов, компилятор может и не соптимизировать это...
А если объект с некопируемой семантикой (noncopyable)? Постинкремента не будет вообще?
Читаем http://www.gotw.ca/gotw/055.htm:
T T::operator++(int)
{
T old( *this ); // remember our original value
// Примечание Чебуратора. Здесь-то и тратится лишнее время
++*this; // always implement postincrement
// in terms of preincrement
return old; // return our original value
}