如何用CGI C实现同时上传多个文件?

如何用CGI C实现同时上传多个文件?

好不容易在google里搜到一个没用CGIC库的上传文件的CGI C代码,工作得怪happy的,只是不能同时上传多个文件.不敢专功,留下来给需要的人!对CGI不熟,请问如何才能实现用CCI C同时上传多个文件?

[Copy to clipboard] [ - ]
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <fcntl.h>

//want to check file extensions? 1=yes 0=no
#define CHECKEXT 1

//define max size of uploads to 100k
#define MAXSIZE 2000000

//define upload directory relative to cgi-bin
#define UPLOADIR "/tmp/upload"

// buffer for storing boundary line and file name
#define MAXLINE 512

char szBoundary[MAXLINE];
char szFile[MAXLINE];

//filename to write to
char myFile[MAXLINE];

//basename of uploaded file
//buffer of arbitrary size for reading from STDIN
#define BUFFSIZE 16*1024
char szBuff[BUFFSIZE];

/************************************************** *************************
* For file upload, CGI variables look like this:
* CONTENT_TYPE=multipart/form-data;
boundary=-----
----------------------14422580032340
CONTENT_LENGTH=216
STDIN contains the following information:

-----------------------------14422580032340
Content-Disposition: form-data;
name="file";
filename="/home/user/myup.jpg"
Content-Type: text/plain
Data from file goes here----
-------------------------14422580032340

*************************************************************************/
/*sub routine to test extensions it only allows 1 dot in name, ie myup.1.jpg
* is not allowed but myup-1.tar.gz is OK because tar.gz is a defined extension*/

int getext(const char *filename)
{
char *p, *q;
int len,i,isgood = 0;
char *goodext[9] = {"gif","jpg","jpeg","png","bmp","tgz","gz","txt","tar.gz"};
char ext[7]; //6 chars plus '\0'

/*move to first dot */
if (!(p = strchr(filename, '.')))
return 0;

/* move past the dot */
++p;

/*move to end of string */
if (!(q = strchr(p, '\0')))
return 0;

len = q - p;
memcpy(ext, p, len);
ext[len] = '\0';

for (i=0;i<=9;i++)
{
if(strcmp(ext,goodext[i]) == 0)
{
isgood = 1;
}
}

return isgood;
}

/////////////////////////////////////////////////////////////

int main(int argc, char **argv[])
{
int rc = 0;
char *up= UPLOADIR;
char *psz1; char *psz2;
FILE *out = NULL;
long i, total, count;
char *ContentLength;

/* Pointer to CONTENT_LENGTH environment variable. */
long InCount;

/* The supposed number of incoming bytes. */
char *filename;

printf("Content-type: text/html\n\n");
printf("<html>");
printf("<head><title>File Upload</title></head>\n");

printf("<center><h1>File Upload Status</h1></center>\n");

ContentLength = getenv("CONTENT_LENGTH");
InCount = atol(ContentLength);

if (InCount > MAXSIZE)
{
rc=7;
goto Error;
}

// null out file name buffer
memset(szFile, 0, sizeof(szFile));

// first line should be MIME boundary, prepend cr/lf
szBoundary[0] = '\r';
szBoundary[1] = '\n';
szBoundary[2] = '\0';

if (fgets(&szBoundary[2], sizeof(szBoundary)-2, stdin) == NULL)
{
rc = 1;
goto Error;
}

//strip terminating CR / LF
if ((psz1=strchr(&szBoundary[2],'\r')) != NULL)
{
*psz1 = '\0';
}

if ((psz1=strchr(&szBoundary[2],'\n')) != NULL)
{
*psz1 = '\0';
}

// second line should contain "Content-Disposition:
if (fgets(szBuff, sizeof(szBuff), stdin) == NULL)
{
rc = 2;
goto Error;
}

// get filename keyword
if ((psz1=strstr(szBuff, "filename=")) == NULL)
{
rc = 3;
goto Error;
}

// get pointer to actual filename (it's in quotes)
psz1+=strlen("filename=");

if ((psz1 = strtok(psz1, " \"")) == NULL)
{
rc = 4;
goto Error;
}

// remove leading path for both PC and UNIX systems
if ((psz2 = strrchr(psz1,'\\')) != NULL)
{
psz1 = psz2+1;
}
if ((psz2 = strrchr(psz1,'/')) != NULL)
{
psz1 = psz2+1;
}

//psz1 now points to a file name, try to create it in our system
sprintf(szFile, "%s/%s",up,psz1);

//file to actually write
sprintf(myFile, "%s", psz1);

//basename of file
filename= myFile;

//check for valid extension
if (CHECKEXT)
{
if ((getext(filename))== 0)
{
rc = 8;
goto Error;
}
}

// determine if file exists, and don't allow overwritting
if ((out = fopen(szFile, "rb")) != NULL)
// file already exists!
{
rc = 5;
goto Error;
}


if ((out = fopen(szFile, "wb+")) == NULL)
{
rc = 6;
goto Error;
}

// throw away until we get a blank line
while (fgets(szBuff, sizeof(szBuff), stdin) != NULL)
{
if (strlen(szBuff) <= 2)
{
break;
}
}

// copy the file
while ((count=fread(szBuff, 1, sizeof(szBuff), stdin)) != 0)
{
if ((i=fwrite(szBuff, 1, count, out)) != count)
{
rc = 7;
goto Error;
}
//disk write error
}

// re read last 128 bytes of file, handling files < 128 bytes
if ((count = ftell(out)) == -1)
{
rc = 8;
goto Error;
}

if (count > 128)
{
count = 128;
}

if (fseek(out, 0-count, SEEK_END) != 0)
{
rc = 9;
goto Error;
}

// get the new position
if ((total = ftell(out)) == -1)
{
rc = 10;
goto Error;
}

// and read the data
count = fread(szBuff, 1, sizeof(szBuff), out);
szBuff[count] = '\0';

// determine offset of terminating boundary line
rc = 11;
for (i=0; i<=(count-(long)strlen(szBoundary)); i++)
{
if ((szBuff[i] == szBoundary[0])
&& (strncmp(szBoundary, &szBuff[i], strlen(szBoundary)) == 0))
{
total+=i;
rc = 0;
break;
}
}

// if rc is still set, we didn't find the terminating boundary line
if (rc != 0)
{
goto Error;
}

if (total == 0)
{
rc = 11;
goto Error;
}

// truncate the file at the correct length by writing 0 bytes
fflush(out);

Error: if (out != NULL)
{
fclose(out);
}

switch (rc)
{
case 0: // success
printf("The file <b> %s %d bytes</b> was uploaded sucessfully.",myFile,InCount);
break;

case 5: // file exists
printf ("The file %s already exists and cannot be overwritten.Please try again with a different file.\n", myFile);
break;

case 7: // file too big
printf ("The file <b> %s </b> is too big. Try again.",myFile);
break;

case 8: // file is not an allowed type
printf ("The file <b> %s </b> is not an allowed type. Try again.",myFile);
break;

case 11: // 0 byte file
printf("The file <b>%s </b>contains no data.<br>Please try again with a different file.", myFile);
unlink(szFile);
break;

default: // all other cases
printf("Error %d uploading file<b>%s </b>Please try again.", rc, myFile);
unlink(szFile);
break;
}

if ((psz1=getenv("HTTP_REFERER")) != NULL)
{
printf("<p><A HREF =\"%s\">Back</A>", psz1);
}

printf("</html>\n");

return 0;
}

无非就是数据的格式的装箱和解析过程

我06年写的一个模拟upload的过程支持多个文件。

http://code.google.com/p/rfc1867/