CGI Tips

ÃÖÀ±¼ö
´ëÀü ±¤¿ª½Ã À¯¼º±¸ À¯¼º¿ìü±¹ »ç¼­ÇÔ 122È£
Çѱ¹°úÇбâ¼ú¿¬±¸¿ø ¿¬±¸°³¹ßÁ¤º¸¼¾ÅÍ
E-mail : armian@www.kordic.re.kr
URL : http://stissbs.kordic.re.kr/~armian/
Abstract:
Internet»ó¿¡¼­ WWWÀÇ ÀÌ¿ëÀÚ°¡ ±ÞÁõÇÔ¿¡ µû¶ó, WWW¸¦ ÀÌ¿ëÇÑ ¼­ºñ½º´Â ÀÌÁ¦ ÀϹÝÀû ÀÎ »ç¾çÀÌ µÇ¾ú´Ù.
WWW¸¦ ÀÌ¿ëÇÑ ¼­ºñ½º´Â Á¤ÀûÀÎ ¹®¼­µéÀ» ¸ð¾Æ, ÇÏÀÌÆÛ¸µÅ©¸¦ ÅëÇØ º¸¿©ÁÖ´Â Á¤º¸Á¦°ø ¹æ½Ä°ú, »ç¿ëÀÚÀÇ ¿ä±¸¿¡ µû¶ó µ¿ÀûÀÎ ¹®¼­¸¦ »ý¼ºÇÏ¿© Á¦°øÇÏ´Â ¹æ½ÄÀÌ ÀÖ´Ù.
ÀÌ·¯ÇÑ µ¿ÀûÀÎ ¹®¼­´Â CGI¸¦ ÅëÇØ ±¸ÇöµÇ´Â °ÍÀÌ ÀϹÝÀûÀÎ ¹æ¹ýÀε¥, CGIÇÁ·Î±×·¡¹ÖÀÇ ¿ª »ç´Â ±×¸® ¿À·¡µÇÁö ¾Ê¾Æ¼­, ¾ÆÁ÷µµ ¸¹Àº ¹®Á¦Á¡À» ´ã°í ÀÖ´Ù.
º» °í¿¡¼­´Â ±×µ¿¾È CGI¸¦ ÀÌ¿ëÇÏ¿© »ç¿ëÀÚ ÀÎÅÍÆäÀ̽º¸¦ °³¹ßÇϸ鼭 ´À²¼´ø ¾î·Á¿ü´ø Á¡ °ú ÇØ°á¹æ¾ÈµéÀ» Á¦½ÃÇÏ¿©, CGIÇÁ·Î±×·¡¹ÖÀ» ½ÃÀÛÇϰíÀÚ ÇÏ´Â À̵鿡°Ô ¹Ì¾àÇϳª¸¶ µµ¿òÀ» ÁÖ°í ÀÚ ÇÑ´Ù.
Keywords:
CGI,Form,Debug

1. CGI & Debugging

CGI ÇÁ·Î±×·¡¹ÖÀ» ÀÛ¼ºÇÏ´Ùº¸¸é ¾Æ·¡¿Í °°Àº ¿¡·¯¸Þ½ÃÁö¸¦ ÀÚÁÖ Á¢ÇÏ°Ô µÈ´Ù. ÀϹÝÀûÀ¸·Î UNIX¿¡¼­ C ÇÁ·Î±×·¡¹ÖÀ» ÇÏ´Ù º¸¸é °Þ°Ô µÇ´Â "Segmentation fault"¿¡·¯°¡ ÀÌ·¯ÇÑ ½ÄÀ¸·Î Ç¥ÇöµÇ±â ¶§¹®ÀÌ´Ù.

<±×¸² 1> CGI & Error message

CGI ÇÁ·Î±×·¡¹Ö½Ã °¡Àå ¾î·Á¿î ºÎºÐÀº ¾Æ¸¶µµ À§¿Í °°Àº ¿¡·¯°¡ ³µÀ» ¶§, µð¹ö±ëÀ» ¾î¶»°Ô ÇØ¾ß ÇÏ´Â °¡ ÀÏ °ÍÀÌ´Ù. UNIX»ó¿¡¼­ÀÇ µð¹ö±ëÀº dbx°°Àº µð¹ö±ë ÅøÀ» »ç¿ëÇÏ¿© ½±°Ô ÇØ°áÇÒ ¼ö ÀÖ¾úÁö¸¸, CGI¿¡ ´ëÇÑ µð¹ö±ëÀº ÀüÇô ´Ù¸¥ »óȲÀ̱⠶§¹®ÀÌ´Ù.
°á±¹ CGI µð¹ö±ëÀ» ¼Õ½±°Ô Çϱâ À§Çؼ­´Â, ÀϹÝÀûÀÎ C ÇÁ·Î±×·¥°ú µ¿ÀÏÇÏ°Ô UNIX»ó¿¡¼­ ½ÇÇàµÉ ¼ö ÀÖµµ·Ï º¯È¯ÇØ¾ß ÇÏ´Â ÀÛ¾÷ÀÌ ÇÊ¿äÇÏ´Ù.
»ç½Ç CGI ÇÁ·Î±×·¥ÀÌ ÀϹÝÀûÀÎ CÇÁ·Î±×·¥°ú ´Ù¸¥ Á¡Àº ´Ü Çϳª, ÀÔ·ÂÀ¸·Î ¹Þ¾Æ µéÀÌ´Â ÆÄ¶ó ¹ÌÅ͵鿡 ó¸® ¹æ½Ä »ÓÀÌ´Ù. Áï, óÀ½ºÎÅÍ ÀÔ·ÂÀ» ¹ÞÀ» ¼ö Àִ â±¸¸¦ µÎ °¡ÁöÇüÅ·ΠÀÛ¼ºÀ» ÇÑ ´Ù¸é, µð¹ö±ë ¶§¹®¿¡ °í»ýÀ» ÇÒ Çʿ䰡 ¾ø´Ù´Â °á·ÐÀÌ ³ª¿Â´Ù. ¾Æ·¡¿¡ ÀÌ·¯ÇÑ ÇüÅÂÀÇ ¿¹Á¦ ÇÁ·Î±×·¥À» º¸¸é ½±°Ô ÀÌÇØÇÒ ¼ö ÀÖÀ» °ÍÀÌ´Ù.

1.1 µð¹ö±ëÀ» À§ÇÑ ¿¹Á¦ ÇÁ·Î±×·¥

#include <web.h> main(int argc, char *argv[]) { getentry entries[100]; register int x, m = 0; char *cl; char *ptr; #ifdef DEBUG /* µð¹ö±ëÀ» À§ÇÑ ·çƾ */ if (argc < 2) { printf("\n %s name1=val1 [name2=val2]......\n"); exit(0); } for(x=1; x < argc; x++) { ptr = (char *) strchr(argv[x],'='); if (ptr == NULL) { printf("\n Error in input...\n"); exit(0); } *ptr = '\0'; strcpy(entries[x-1].name,argv[x]); strcpy(entries[x-1].val,ptr+1); } m = argc-2; #else /* CGI InputÀ» ó¸®Çϱâ À§ÇÑ ·çƾ */ printf("Content-type: text/html%c%c", 10, 10); if (strcmp(getenv("REQUEST_METHOD"), "GET")) { exit(1); } cl = getenv("QUERY_STRING"); if (cl == NULL) { printf("No query information to decode.\n"); exit(1); } for (x = 0; cl[0] != '\0'; x++) { m = x; getword(entries[x].val, cl, '&'); plustospace(entries[x].val); unescape_url(entries[x].val); getword(entries[x].name, entries[x].val, '='); } #endif printf("\n<H1>Query Results</H1>"); printf("\nYou submitted the following name/value pairs:<p>%c", 10); printf("\n<ul>%c", 10); for (x = 0; x <= m; x++) printf("\n<li> <code>%s = %s</code>%c", entries[x].name, entries[x].val, 10); printf("\n</ul>%c", 10); }

1.2 ÄÄÆÄÀÏ ¹æ¹ý

        - µð¹ö±ëÀ» À§ÇÑ ÄÄÆÄÀÏ
                cc -o query query.c -DDEBUG

        - CGI ÇÁ·Î±×·¥À¸·Î ÄÄÆÄÀÏ
                cc -o query.cgi query.c 

1.3 ½ÇÇà°á°ú

[stissbs:WWW4 10 ] query name=armian tel=042-828-5045 <H1>Query Results</H1> You submitted the following name/value pairs:<p> <ul> <li> <code>name = armian</code> <li> <code>tel = 042-828-5045</code> </ul>

2. ȯ°æº¯¼ö¸¦ ÀÌ¿ëÇÑ Ã³¸®

2.1 GET,POST METHOD ó¸®

CGI¿¡¼­´Â µÎ °¡Áö ÇüÅÂÀÇ METHOD¸¦ »ç¿ëÇÏ¿© ºê¶ó¿ìÀú¿Í CGI»çÀÌ¿¡¼­ »ç¿ëµÇ´Â ÆÄ¶ó¹ÌÅ͸¦ Àü´ÞÇÑ´Ù. ¹Ù·Î GET Method¿Í POST MethodÀε¥, CGI ÇÁ·Î±×·¡¹Ö½Ã¿¡ Á¾Á¾ Method¸¦ ¹Ù²Ù¾î ¾ß ÇÒ Çʿ䰡 ¹ß»ýÇϱ⵵ Çϰí, µÎ °¡Áö Method¸¦ µ¿½Ã¿¡ Áö¿øÇÒ Çʿ䵵 ÀÖ´Ù. ÀÌ·¯ÇÑ »óȲÀ» ÇØ°áÇϱâ À§ÇØ, µÎ °¡Áö Method¸¦ ¸ðµÎ ´Ù »ç¿ëÇÒ ¼ö ÀÖµµ·Ï CGI ÇÁ·Î±×·¥ÀÇ ÆÄ ¶ó¹ÌÅÍ Ã³¸® ºÎºÐÀ» º¯°æÇÑ ÇÁ·Î±×·¥Àº ¾Æ·¡¿Í °°´Ù.

        printf("Content-type: text/html%c%c", 10, 10);

        if (!strcmp(getenv("REQUEST_METHOD"), "GET"))
        {
                ......
                GET METHOD ó¸® ·çƾ
                ......
        }
        else if (!strcmp(getenv("REQUEST_METHOD"), "POST"))
        {
                ......
                POST METHOD ó¸® ·çƾ
                ......
        }
        else
        {
                ......
                ERROR ó¸® ·çƾ
                ......
        }

2.2 HTTP_USER_AGENT¸¦ ÀÌ¿ëÇÑ Ã³¸®

HTTP_USER_AGENT¸¦ ÀÌ¿ëÇÏ¿©, »ó´ë¹æÀÇ ºê¶ó¿ìÀúŸÀÔÀ» ¾Ë ¼ö Àִµ¥, À̸¦ ÀÌ¿ëÇÏ¿© °¢°¢ÀÇ ºê¶ó¿ìÀú¿¡ Àû´çÇÑ Çü½ÄÀÇ Ãâ·ÂÀ» ÇàÇÒ ¼ö ÀÖ´Ù.
¿¹¸¦µé¾î, lynx°°Àº ¶óÀθðµå ºê¶ó¿ìÀú´Â ÅØ½ºÆ® ¹Û¿¡ Ãâ·ÂÀÌ ¾ÈµÇ¹Ç·Î, ´Ù¸¥ ºê¶ó¿ìÀú¿Í´Â ´Ù¸£°Ô Ãâ·ÂÀ» ÇØ¾ß ÇÑ´Ù.

<¿¹Á¦ ÇÁ·Î±×·¥>

agent = (char *)getenv("HTTP_USER_AGENT"); if (!strncmp(agent,"Lynx",4)) { ...... ÅØ½ºÆ® µ¥ÀÌÅ͸¦ Ãâ·Â ...... } else { ...... ¸ÖƼ¹Ìµð¾î µ¥ÀÌÅ͸¦ Ãâ·Â ...... }

2.3 REMOTE_ADDRÀ» ÀÌ¿ëÇÑ Ã³¸®

REMOTE_ADDR¸¦ »ç¿ëÇÏ¿© ÀÚ½ÅÀÇ È¨ÆäÀÌÁö·Î µé¾î¿Â »ó´ë¹æÀÇ IP ¾îµå·¹½º¸¦ ¾ò¾î³¾ ¼ö ÀÖ´Ù.
ƯÁ¤ÇÑ È£½ºÆ®¿¡ ´ëÇØ Ưº°ÇÑ ÇൿÀ» ÇØ¾ß ÇÒ ¶§ »ç¿ëÇÏ¸é µÈ´Ù.
¿¹¸¦µé¾î, UNIX½Ã½ºÅÛ¿¡¼­ °ü¸®ÀÚ(root)·ÎÀÇ ·Î±×ÀÎÀº ±× È£½ºÆ®¿¡¼­¸¸ °¡´ÉÇÏ°Ô ÇÒ ¼ö ÀÖ ´Â °Íó·³, Web BBS³ª Á¤º¸°Ë»ö½Ã½ºÅÛÀÇ °ü¶óÀڴ ƯÁ¤ÇÑ È£½ºÆ® ¶Ç´Âµµ¸ÞÀο¡¼­¸¸ ·Î±×ÀÎÇÏ°Ô ÇÒ ¼ö ÀÖ´Ù.

3. CGI Ãâ·Â

CGI¿¡¼­ ºê¶ó¿ìÀú·ÎÀÇ Ãâ·ÂÀº ±ÍïÀº ÀÛ¾÷ ÁßÀÇ ÇϳªÀÌ´Ù. ÀܼÕÁúµµ ¸¹ÀÌ µé¾î°¡°í, ¾à°£ÀÇ ¼öÁ¤À» ÇÏ·Á¸é, »õ·ÎÀÌ ÄÄÆÄÀϰú ¸µÅ© ÀÛ¾÷À» °ÅÃÄ¾ß Çϱ⠶§¹®¿¡, ½Ã°£µµ ¸¹ÀÌ »¯±â´Â ÀÛ¾÷ÀÌ´Ù.
´ÙÀ½ÀÇ µÎ ¿¹Á¦¸¦ ºñ±³ÇØ º¸¸é, ¾î¶°ÇÑ ¹æ¹ýÀÌ ´õ È¿À²ÀûÀΰ¡¸¦ ¹Ù·Î ¾Ë ¼ö ÀÖ´Ù. ÀÌ ¿¹Á¦µé Àº ºê¶ó¿ìÀú¸¦ ÅëÇØ ¼¼ °³ÀÇ ÀÔ·Â(name,title,color)À» ¹Þ¾Æ µé¿©, Ãâ·ÂÇÏ´Â °£´ÜÇÑ CGI ÇÁ·Î±×·¥ÀÌ ´Ù.
ù¹øÂ° ¿¹Á¦´Â ÀϹÝÀûÀÎ Ãâ·Â¹æ¹ýÀ¸·Î, ÇÁ·Î±×·¥³»¿¡¼­ printf()ÇÔ¼ö¸¦ »ç¿ëÇÏ¿© ¸ðµç Ãâ·ÂÀ» ÇàÇÏ´Â ¹æ¹ýÀÌ´Ù.
µÎ¹øÂ° ¿¹Á¦´Â ¿ÜºÎ È­ÀÏ·Î Ãâ·ÂÇϰíÀÚ ÇÏ´Â ³»¿ëÀ» HTML¹®¼­·Î ÀÛ¼ºÇØ ³õ°í, »ç¿ëÀÚÀÇ ÀԷ¿¡ µû¶ó Ãâ·Â³»¿ëÀ» º¯Çü½ÃÄÑ Ãâ·ÂÇÏ´Â ¹æ¹ýÀÌ´Ù.

<¿¹Á¦ 1> ÀϹÝÀûÀÎ Ãâ·Â¹æ¹ý

#include <web.h> main(int argc, char *argv[]) { getentry entries[100]; register int x, m = 0; char *cl; char *ptr; char name[100],title[100],color[100]; printf("Content-type: text/html%c%c", 10, 10); if (strcmp(getenv("REQUEST_METHOD"), "GET")) { exit(1); } cl = getenv("QUERY_STRING"); for (x = 0; cl[0] != '\0'; x++) { m = x; getword(entries[x].val, cl, '&'); plustospace(entries[x].val); unescape_url(entries[x].val); getword(entries[x].name, entries[x].val, '='); } for (x = 0; x <= m; x++) { if (!strcmp(entries[x].name,"name")) { strcpy(name,entries[x].val); continue; } if (!strcmp(entries[x].name,"title")) { strcpy(title,entries[x].val); continue; } if (!strcmp(entries[x].name,"color")) { strcpy(color,entries[x].val); continue; } } printf("<HTML>"); printf("\n<HEAD>"); printf("\n<TITLE> %s </TITLE>",title); printf("\n</HEAD>"); printf("\n<BODY BGCOLOR=%s>",color); printf("\n<H1><CENTER>%s</CENTER></H1>",title); printf("\n<HR>"); printf("\n<H4><PRE>"); printf("\n\tYour name : %s",name); printf("\n\tYour Title : %s",title); printf("\n\tYour Color : %s",color); printf("\n</PRE></H4>"); printf("\n<HR>"); printf("\n</BODY>"); printf("\n</HTML>"); }

<¿¹Á¦ 2-1> È­ÀÏÀ» ÀÌ¿ëÇÑ Ãâ·Â¹æ¹ý(HTML Prototype)

<HTML> <HEAD> <TITLE> :TITLE: </TITLE> </HEAD> <BODY BGCOLOR=:INPUTCOLOR:> <H1><CENTER>:TITLE:</CENTER></H1> <HR> <H4><PRE> Your name : :NAME: Your Title : :TITLE: Your Color : :INPUTCOLOR: </PRE></H4> <HR> </BODY> </HTML>

<¿¹Á¦ 2-2> È­ÀÏÀ» ÀÌ¿ëÇÑ Ãâ·Â¹æ¹ý(CGI ÇÁ·Î±×·¥)

#include <web.h> #define MAXBUFSIZE 1000 #define INPUTFILE "title.html" main(int argc, char *argv[]) { ..... char buffer[MAXBUFSIZE]; char newbuf[MAXBUFSIZE]; FILE *fp; .... fp = fopen(INPUTFILE,"r"); while(1) { fgets(buffer,MAXBUFSIZE,fp); if(feof(fp)) break; ptr = (char *)strstr(buffer,":TITLE:"); if (ptr) { *ptr = '\0'; sprintf(newbuf,"%s%s%s",buffer,title,ptr+7); puts(newbuf); continue; } ptr = (char *)strstr(buffer,":NAME:"); if (ptr) { *ptr = '\0'; sprintf(newbuf,"%s%s%s",buffer,name,ptr+6); puts(newbuf); continue; } ptr = (char *)strstr(buffer,":INPUTCOLOR:"); if (ptr) { *ptr = '\0'; sprintf(newbuf,"%s%s%s",buffer,color,ptr+12); puts(newbuf); continue; } puts(buffer); } fclose(fp); }

4. Stateless vs statefull

±âÁ¸ÀÇ ÀÎÅÍ³Ý ÀÀ¿ëµé(telnet, ftp µî)ÀÌ Å¬¶óÀÌ¾ðÆ®¿Í ¼­¹ö°¡ °è¼Ó Á¤º¸¸¦ À¯ÁöÇÏ´Â statefull ÀÎ ¹æ½Ä°ú ´Þ¸®, WWWÀº stateless¸¦ ±â¹ÝÀ¸·Î ¿î¿µµÇ¹Ç·Î Ŭ¶óÀÌ¾ðÆ®¿Í ¼­¹ö°£¿¡ Á¤º¸°¡ À¯Áö µÇÁö ¾Ê´Â´Ù. ÀÌ´Â WWW¸¦ ÀÌ¿ëÇÏ¿© ÀÀ¿ëÇÁ·Î±×·¥À» ÀÛ¼ºÇÏ·Á´Â ÇÁ·Î±×·¡¸Ó¿¡°Ô ¶Ç ´Ù¸¥ ÁüÀ» Áö¿öÁÖ°Ô µÇ¾ú´Ù.
stateless¸¦ statefulló·³ º¸ÀÌ°Ô Çϱâ À§ÇØ ¿©·¯°¡Áö Æí¹ýµéÀÌ µ¿¿øµÇ°í ÀÖ´Ù.
°ú°ÅÀÇ ÀÀ¿ëÇÁ·Î±×·¥µéÀº in-memory¸¦ »ç¿ëÇÏ¿© ÀÌ·¯ÇÑ Á¤º¸µéÀ» À¯ÁöÇÏ¿´Áö¸¸, CGIÇÁ·Î±× ·¥¿¡¼± file systemÀ» »ç¿ëÇÏ¿© ÀÌ·¯ÇÑ Á¤º¸µéÀ» À¯ÁöÇÒ ¼ö ¹Û¿¡ ¾ø´Ù.
´ÙÀ½ ¿¹Á¦´Â °£´ÜÇÑ ÇüÅ·ΠstatefullÀ» ±¸Çö ÇϱâÀ§ÇÑ ±âº»ÀûÀΠƲ¸¸ º¸¿© ÁØ´Ù.
½ÇÁ¦ÀûÀ¸·Î ÀÀ¿ëÇÁ·Î±×·¥À» ÀÛ¼ºÇϱâ À§Çؼ±, ´õ ¸¹Àº Á¤º¸µéÀÌ ÁÖ°í ¹Þ¾ÆÁ®¾ß¸¸ Çϸç, ÀÌ´Â ¿ÜºÎ È­ÀÏÀ» ÅëÇØ¼­ ±¸ÇöµÉ ¼öµµ ÀÖ°í, ¸Þ½ÃÁö Å¥µîÀ» »ç¿ëÇÏ¿© Á» ´õ °í±Þ½º·´°Ô ±¸ÇöÇÒ ¼öµµ ÀÖ´Ù.

<ÇÁ·Î±×·¥ 1 : daemon.c>

#include <stdio.h> #include <server.h> main() { int pid; fprintf(stdout,"Content-type: text/html%c%c", 10, 10); fprintf(stdout,"\n Server is starting...."); fclose(stdout); system("/home8/armian/public_html/cgi-src/statefull/server/server&"); }

<ÇÁ·Î±×·¥ 2 : server.c>

#include <stdio.h> #include <server.h> static int second; main() { FILE *fp; int pid; second = 0; fp = fopen(SERVERINFO,"w"); pid = getpid(); fprintf(fp,"%d",pid); fclose(fp); signal(SIGUSR1,c_action); for(;;) { sleep(4); second++; if (second > 9) break; } exit(0); } c_action() { int pid; FILE *fp; char buffer[100]; fp = fopen(CLIENTINFO,"r"); fgets(buffer,100,fp); fclose(fp); pid = atoi(buffer); second = 0; kill(pid, SIGUSR2); signal(SIGUSR1,c_action); }

<ÇÁ·Î±×·¥ 3 : client.c>

#include <signal.h> #include <web.h> #include <server.h> int s_action(); int pid; main(argc,argv) int argc; char *argv[]; { int mypid; FILE *fp; char buffer[100]; printf("Content-type: text/html%c%c", 10, 10); fp = fopen(SERVERINFO,"r"); fgets(buffer,100,fp); fclose(fp); pid = atoi(buffer); mypid = getpid(); fp = fopen(CLIENTINFO,"w"); fprintf(fp,"%d",mypid); fclose(fp); kill(pid, SIGUSR1); signal(SIGUSR2,s_action); sleep(4); printf("\n<p>PID of Server : %d",pid); printf("\n<p>Server is dead...."); exit(0); } s_action() { printf("\n<p>PID of Server : %d",pid); printf("\n<p>Server is alive...."); exit(0); }

Âü°í¹®Çå

[NCSA95a]
The Common Gateway Interface
URL: http://hoohoo.ncsa.uiuc.edu/cgi
[Leeds95a]
CGI Tutorial
URL: http://agora.leeds.ac.uk/nik/Cgi/start.html
[WWW-KR95a]
°¡ÀÚ, WebÀÇ ¼¼°è·Î! ,225p-231p
[È«¸ª91a]
UNIX ½Ã½ºÅÛ ÇÁ·Î±×·¡¹Ö