第87章 CGIプログラミング その8


インターネット上ではよく、アンケート調査を見かけます。 今回は簡単なアンケート調査のCGIについて考えます。



「面白い」「普通」「面白くない」のいずれかを選択して「送信」ボタンを押します。



するとお礼の表示が出てきます。



「結果を見る」ボタンを押すと、今までのアンケート結果が表示されます。



では、まずHTMLソースを見てみましょう。

<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<TITLE>アンケート</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2>アンケート</H2>
</CENTER>
このサイトの感想をお知らせください。<BR>
<FORM METHOD="POST" ACTION="ques01.cgi">
<INPUT TYPE="radio" NAME="KANSO" VALUE="OMOSHIROI" CHECKED>面白い<BR>
<INPUT TYPE="radio" NAME="KANSO" VALUE="FUTSU">普通<BR>
<INPUT TYPE="radio" NAME="KANSO" VALUE="OMOSHIROKUNAI">面白くない<BR>
<CENTER>
<INPUT TYPE="SUBMIT" VALUE="送信">
<INPUT TYPE="BUTTON" VALUE="結果を見る" onClick="location='result01.cgi'">
</CENTER>
</FORM>
</BODY>
</HTML>
CGIのファイルは通常決められた位置でしか実行できないようになっているので、実際には ACTION="ques01.cgi"のところには、パスがつきます。

また、この例のようにボタンが複数ついていて、ボタンごとに実行するCGIが異なる場合 1つのボタンはSUBMITでよいのですが、残りのボタンはJavaScriptを利用して CGIプログラムを呼び出すようにします。

では、CGIプログラムを見てみましょう。

// ques01.c

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <process.h>

int getstring(char *, char *, char *);
int setfile(char *);

int main()
{
    int i;
    char c, buf[64], result[32], fname[64];

    for (i = 0; (c = getchar()) != EOF; i++) {
        if (c != '\r' && c != '\n')
            buf[i] = c;
        else
            i--;
    }
    buf[i] = '\0';

    getstring(buf, "KANSO", result);
    
    if (strcmp(result, "OMOSHIROI") == 0) {
        strcpy(fname, "0.txt");
    } else if (strcmp(result, "FUTSU") == 0) {
        strcpy(fname, "1.txt");
    } else {
        strcpy(fname, "2.txt");
    }
    setfile(fname);

    //HTML表示用
    printf("Content-type:text/html\n\n");
    printf("<HTML>\n");
    printf("<HEAD>\n");
    printf("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=Shift_JIS\">\n");
    printf("<TITLE>ありがとうございました</TITLE>\n");
    printf("</HEAD>\n");
    printf("<BODY BGCOLOR=\"#FFFF00\">\n");
    printf("<FONT SIZE=\"4\" COLOR=\"#0000FF\">"
        "アンケートにご協力ありがとうございました<BR>");
    printf("<A HREF=\"javascript:history.go(-1)\">Back</A>\n");
    printf("</BODY>\n");
    printf("</HTML>\n");

    return 0;
}
「送信」ボタンを押すと呼び出されるプログラムです。

この時送られてくる文字列は「KANSO=***」となります。***の部分は ラジオボタンのチェックされた項目によりOMOSHIROI, FUTSU, OMOSHIROKUNAIの いずれかになります。このまま、これらの文字列で場合分けしてもよいのですが ここでは、第82章で作ったgetstring関数で文字列を切り分けることにします。

ラジオボタンの「面白い」にチェックがついていれば0.txtを、普通なら1.txtを、その他(面白くない)なら、2.txtのファイル名をsetfile関数に渡します。そして、お礼のHTMLを出力します。

int getstring(char *src, char *element, char *dest)
{
    int len;
    char *data, *amp;
    char *temp;

    len = (int)strlen(src) + 1;
    temp = (char *)malloc(len);

    len = (int)strlen(src);
    if (len >= 1024) {
        free(temp);
        return -1;
    }

    strcpy(temp, src);

    data = strstr(temp, element);
    if(data == NULL) {
        strcpy(dest, "no element");
        free(temp);
        return -2;
    }

    len = (int)strlen(element) + 1;

    amp = strstr(data, "&");
    if (amp == NULL) {
        strcpy(dest, data + len);
        if (dest[0] == '\0') {
            strcpy(dest, "no data");
            free(temp);
            return 0;
        }
        free(temp);
        return 1;
    }
    data[(int)(amp-data)] = '\0';
    strcpy(dest, data + len);

    if (dest[0] == '\0') {
        strcpy(dest, "no data");
        free(temp);
        return 0;
    }

    free(temp);
    return 0;
}
文字列を切り分ける関数です。詳しくは第82章を参照してください。
int setfile(char *filename)
{
    FILE *fp;
    int cnt;

    fp = fopen(filename, "r");

    if (fp == NULL) {
        exit(-1);
    }
    fscanf(fp, "%d", &cnt);
    fclose(fp);
    cnt++;
    fp = fopen(filename, "w");
    if (fp == NULL) {
        exit(-2);
    }
    fprintf(fp, "%d", cnt);
    fclose(fp);

    return 0;
}
引数で指定されたファイルをオープンし、数値を読み出し、これに1を加えて 再度書き込みます。カウンターの時とほとんど同じ要領です。

これで、「送信」ボタンを押すと、選択された項目のファイルの数値を1増やす仕組みが できました。つぎは、アンケート結果を読み出すプログラムです。

// result01.c
// ques01.cとセットになっています

#include <stdio.h>
#include <process.h>

int main()
{
    FILE *fp;
    char fname[][16] = {"0.txt", "1.txt", "2.txt"};
    int i, result[3];

    for (i = 0; i < 3; i++) {
        fp = fopen(fname[i], "r");
        if (fp == NULL)
            exit(-1);
        fscanf(fp, "%d", &result[i]);
        fclose(fp);
    }

    printf("Content-type:text/html\n\n");
    printf("<HTML>\n");
    printf("<HEAD>\n");
    printf("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=Shift_JIS\">\n");
    printf("<TITLE>アンケート結果</TITLE>\n");
    printf("</HEAD>\n");
    printf("<BODY BGCOLOR=\"#FFFF00\">\n");
    printf("アンケート結果<BR>\n");
    printf("<TABLE BORDER=\"4\">\n");
    printf("<TD>面白い</TD><TD>%d</TD><TR>\n", result[0]);
    printf("<TD>普通</TD><TD>%d</TD><TR>\n", result[1]);
    printf("<TD>面白くない</TD><TD>%d</TD>\n", result[2]);
    printf("</TABLE><BR>\n");
    printf("<A HREF=\"javascript:history.go(-1)\">Back</A><BR>\n");
    printf("</BODY>\n");
    printf("</HTML>\n");

    return 0;
}
0.txt, 1.txt, 2.txtから数値を読み出して、それぞれ、result[0], result[1], result[2] に保存します。

あとは、HTMLを出力してそれぞれの数値を表示するだけですね。

今回は、チェックされた項目ごとに別ファイルにチェック回数を保存しましたが、 アンケート項目が多数ある場合はファイルが増えすぎて問題になるかもしれません。 1つのファイルに保存する方法も検討してみてください。

今回はsetfile関数が-1や-2を返しても、呼び出し元ではこれをチェックしていません。 ファイル入出力に失敗したばあい、エラー表示をするように改良してみてください。


[Index][総合Index] [Previous Chapter] [Next Chapter]

Update Feb/23/2003 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。