図のような簡単なフォームを作って、データをCGIプログラムで
読み込み、受け取ったままのデータをブラウザに表示してみましょう。 このままでは、まだデコードしていないので、訳が分かりませんが、 入力データがどのように送られてくるのかを見てください。 |
<HTML> <HEAD> <TITLE>テストページ</TITLE> </HEAD> <BODY BGCOLOR=#a0d0ff> <FORM METHOD="get" ACTION="test2.cgi"> <INPUT TYPE="text" NAME="fieldname" SIZE="50"><BR> <INPUT TYPE="text" NAME="fieldname2" SIZE="50"><BR> <INPUT TYPE="text" NAME="fieldname3" SIZE="50"><BR> <INPUT TYPE="submit" VALUE="書き込み"> </FORM> </BODY> </HTML> | 左が、上に示したフォームのためのHTMLドキュメントです。 フォームから3つのデータを受け取って、test2.cgiという CGIプログラムを起動します。GETメソッドを指定しているので、 データの文字列は環境変数QUERY_STRINGにセットされます。 |
#include <stdio.h> #include <stdlib.h> #define getenv1(a) ((pdata=getenv(a)) ? pdata : "(NULL)") main() { int len; printf("Content-type: text/html\n\n"); printf("<HTML><HEAD></HEAD><BODY>\n"); printf("%s<BR>\n",getenv("QUERY_STRING")); printf("</BODY></HTML>\n"); } |
このプログラムについては、ほとんど説明不要と思います。
環境変数QUERY_STRINGを受け取ってプリントしているだけです。 getenv()の戻値がNULLであったときの対応をしていますが、 これは古いCコンパイラで、printf()にnullポインタが渡されると、 不正な動作をするためです。 |
でコンパイルした後、次のように、nobodyにも実行出来るようにします。cc -o test2.cgi test2.c
chmod 755 test2.cgi
うまくいったら、WWWで実行してみましょう。 上で作ったフォームのそれぞれのフィールドに以下のように入力して、 送信ボタンを押して下さい % setenv QUERY_STRING tatoeba % ./test2.cgi Content-type: text/html <HTML><HEAD></HEAD><BODY> tatoeba<BR> </BODY></HTML>
123次のように表示されたでしょう。
abc
ABC
フォームからの入力は、fieldname=123&fieldname2=abc&fieldname3=ABC
というようにエンコードされて、サーバーに渡されるのです、 このページの(3)でこのデータをデコードする例を示します。フィールド名1=値1&フィールド名2=値2・・・
<HTML> <HEAD> <TITLE>テストページ</TITLE> </HEAD> <BODY BGCOLOR=#a0d0ff> <FORM METHOD="post" ACTION="test1.cgi"> <INPUT TYPE="text" NAME="fieldname" SIZE="50"><BR> <INPUT TYPE="text" NAME="fieldname2" SIZE="50"><BR> <INPUT TYPE="text" NAME="fieldname3" SIZE="50"><BR> <INPUT TYPE="submit" VALUE="書き込み"> </FORM> </BODY> </HTML> | 左が、上に示したフォームのためのHTMLドキュメントです。 GETメソッドにしめしたドキュメントと同様のフォームを生成します。 フォームから3つのデータを受け取って、test1.cgiという CGIプログラムを起動します。POSTメソッドを指定しているので、 データの文字列は標準入力ストリームに流され、文字列の長さが、 環境変数CONTENT_LENGTHにセットされます。 |
#include <stdio.h> #include <stdlib.h> main() { int len; char *clen; char *data; clen=getenv("CONTENT_LENGTH"); if(clen==NULL){ printf("no contents.\n"); exit(1); } len=atol(clen); data=malloc(len+1); scanf("%s",data); data[len]='\0'; printf("Content-type: text/html\n\n"); printf("<HTML><HEAD></HEAD><BODY>\n"); printf("%s<BR>\n",data); printf("</BODY></HTML>\n"); } |
POSTメソッドなので、環境変数CONTENT_LENGTHがら、
文字列の長さを受け取って、バッファを作成します。
次にscanf()でデータを標準入力から取得します。
でコンパイルした後、次のように、nobodyにも実行出来るようにします。
|
シェルでうまくいったら、WWWでやってみましょう。 % setenv CONTENT_LENGTH 7 % echo "tatoeba"|./test1.cgi Content-type: text/html <HTML><HEAD></HEAD><BODY> tatoeba<BR> </BODY></HTML>
<HTML> <HEAD> <TITLE>テストページ</TITLE> </HEAD> <BODY BGCOLOR=#a0d0ff> <FORM METHOD="post" ACTION="test.cgi"> <INPUT TYPE="text" NAME="fieldname" SIZE="50"><BR> <INPUT TYPE="text" NAME="fieldname2" SIZE="50"><BR> <INPUT TYPE="text" NAME="fieldname3" SIZE="50"><BR> <INPUT TYPE="submit" VALUE="書き込み"> </FORM> </BODY> </HTML> | 左に示したHTMLはフォームデータを 以下に示すCGIプログラムに送信する ものです。特に説明は要らないですね。 |
#include <stdio.h> #include <stdlib.h> #include <string.h> main() { char *inputstring,*agent,*cLength,*name[20],*value[20]; int nfield; long i,length,MAXLEN=4096; int decode_form(),parse_form(); cLength=(char*)getenv("CONTENT_LENGTH"); length=atol(cLength); if(length>MAXLEN) {printf("CONTENT_LENGTH>MAXLEN\n");exit(0);} inputstring=(char*)malloc(length+1); scanf("%s",inputstring); printf("%s","Content-type: text/html\n\n\0"); printf("%s","<HTML><HEAD></HEAD><BODY>\n\0"); parse_form(inputstring,MAXLEN,name,value,&nfield); for(i=0;i<nfield;i++){ decode_form(name[i],strlen(name[i])); decode_form(value[i],strlen(value[i])); printf("%s ---> %s<BR>\n",name[i],value[i]); } printf("%s","\n</BODY></HTML>\n\0"); free(inputstring); exit(0); } | フォームからPOSTメソッドで入力を受け取り、 デコードして表示するプログラム例です。 環境変数CONTENT_LENGTHを取得して、バッファを準備し、 そこにフォームの内容を読み込みます。 後は、下に示すルーチンでフォームの切り分け(parse_form())と、 デコード(decode_form())を行います。 |
int parse_form(char* s_in,long maxl,char* name[],char* value[],int *p_nfld) { int i,cur_field; *p_nfld=0; i=0; cur_field=0; if(s_in[0]==NULL) return(-1); name[0]=s_in; while((s_in[++i]!=NULL)&&(i<maxl)){ if(s_in[i]=='='){ s_in[i]=NULL; value[cur_field]=s_in+i+1; } else if(s_in[i]=='&'){ s_in[i]=NULL; cur_field++; name[cur_field]=s_in+i+1; } } *p_nfld=cur_field+1; return(0); } | フォームを切り分けるルーチンの例です。 s_inは入力文字列へのポインタです。 このルーチンでは、入力文字列のバッファを出力文字列の バッファとしても再利用しています。 気持ちの悪い人は、書き直して下さい。 maxlは最大の入力の長さ、name[]、value[]は、それぞれ フィールド名、値のポインタの配列、p_nfldは解析された フィールド数へのポインタです。 |
int decode_form(char* s,long len) { int i,j; char buf,*s1; if(len==0)return(-1); s1=(char*)malloc(len); for(i=0,j=0;i<len;i++,j++) { if(s[i]=='+'){s1[j]=' ';continue;} if(s[i]!='%') {s1[j]=s[i];continue;} buf=((s[++i]>='A') ? s[i]-'A'+10 : s[i]-'0'); buf*=16; buf+=((s[++i]>='A') ? s[i]-'A'+10 : s[i]-'0'); s1[j]=buf; } for(i=0;i<j;i++) s[i]=s1[i]; s[i]='\0'; free(s1); return(0); } | 16進のコードをデコードするルーチンです。 %16進数というところに当たると、 ここの部分を通常のバイナリに置き換えます。 このルーチンもあまり説明は要らないと思います。 |
nkfsub(char* cp,char* s_in,char* s_out)です。
”s” シフトJIS”j”を指定する時には(まああまりないと思いますが) ターゲットの文字列はシフトJISやEUCの倍くらいになりますので、 ターゲット用のバッファは十分大きく取って下さい。
”j” JIS
”e” EUC