やまものブログ

メモ書きブログです (^_^;A

CGI ~ C言語, 環境変数, GET, POST

CGI の基本を理解したく、http://mewc.to/CGI/image/banner1.gif に掲載の「CGI作成講座」第一章~第四章を動かしてみました。

第一章:Hello, World!
第二章:環境変数
第三章:フォームの利用(1)
第四章:フォームの利用(2)

上記に続く第五章、第六章、番外編はありがたく拝読させてもらいました

ここでは CGIPerl ではなく C言語で記述しています。

CGI の解説、GET/POST といった用語の意味は http://mewc.to/CGI/image/banner1.gif に掲載のとおりですので、以下では自分が実際に動かしたコードを掲載するのみとします。


第一章:Hello, World!
Cソースコードを編集します。

chello.c
#include <stdio.h>

int main(void){
    printf("Content-type: text/html\n\n");
    printf("<html><body><h1>hello, world!</h1></body></html>");
    return 0;
}

コンパイル・リンクして実行形式 chell.cgi を作成して /var/www/html/ へコピーします。
$ gcc -o chello.cgi chello.c
$ sudo cp -p chello.cgi /var/www/html/

http://192.168.11.12/chello.cgi にアクセスすると前回と同じく表示されました
hello, world!

192.168.11.12 は Apacheを立てている私のPCのIPアドレスで、前回から変わっていません。 Yahoo!ブログの機能で上記のURL にリンクがついてしまいますが、クリックしても Not Found になるかと思います


第二章:環境変数
getenv.c
#include <stdio.h>
#include <stdlib.h>

int main(void){
    printf("Content-type: text/html\n\n");
    //printf("<html><body><h4>PWD                = %s</h4></body></html>\n", getenv("PWD"));
    printf("<html><body><h4>HTTP_USER_AGENT    = %s</h4></body></html>\n", getenv("HTTP_USER_AGENT"));
    printf("<html><body><h4>REMOTE_HOST    = %s</h4></body></html>\n", getenv("REMOTE_HOST"));
    printf("<html><body><h4>REMOTE_ADDR    = %s</h4></body></html>\n", getenv("REMOTE_ADDR"));
    printf("<html><body><h4>QUERY_STRING    = %s</h4></body></html>\n", getenv("QUERY_STRING"));
    printf("<html><body><h4>REQUEST_METHOD    = %s</h4></body></html>\n", getenv("REQUEST_METHOD"));
    printf("<html><body><h4>CONTENT_LENGTH    = %s</h4></body></html>\n", getenv("CONTENT_LENGTH"));
    printf("<html><body><h4>HTTP_COOKIE    = %s</h4></body></html>\n", getenv("HTTP_COOKIE"));
    return 0;
}


コンパイル・リンクして実行形式 getenv を作成して /var/www/html/ へコピーします。


http://192.168.11.12/getenv.cgi にアクセスすると下記が表示されました
HTTP_USER_AGENT = Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0
REMOTE_HOST = (null)
REMOTE_ADDR = 192.168.11.12
QUERY_STRING =
REQUEST_METHOD = GET
CONTENT_LENGTH = (null)
HTTP_COOKIE = (null)


第三章:フォームの利用(1)
サンプルコードにあった split(), decode() が分からなかったので、下記では strtok() で似たような処理を実装しました。

get.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
    char buf_org[100];
    char buf[100];
    char *pch;
    struct{
        char name[10];
        char value[500];
    }query[10];
    int i, j;

    strcpy(buf_org, getenv("QUERY_STRING"));
    strcpy(buf, buf_org);

    pch = strtok(buf, "&");
    i = 0;
    while (pch != NULL){ strcpy(query[i++].value, pch); pch = strtok(NULL, "&"); }
    for(j=0; j<i; j++){
        pch = strtok(query[j].value, "=");
        strcpy(query[j].name, pch);
        strcpy(query[j].value, strtok(NULL, "="));
    }
    printf("Content-type: text/html\n\n");
    printf("<html><body><h4>QUERY_STRING:\t%s</h4></body></html>\n", buf_org);
    for(j=0; j<i; j++){
        printf("<html><body><h4>%s\t= %s</h4></body></html>\n", query[j].name, query[j].value);
    }
    return 0;
}

コンパイル・リンクして実行形式 get.cgi を作成して /var/www/html/ へコピーします。

さらに、入力フォームのページを HTML で用意します。

get.html
<FORM METHOD="GET" ACTION="http://192.168.11.12/get.cgi">
<INPUT TYPE="TEXT" NAME="handle" VALUE="Myu">
<INPUT TYPE="TEXT" NAME="link" VALUE="OK">
<INPUT TYPE="SUBMIT" VALUE="Submit">
</FORM>


http://192.168.11.12/get.html にアクセスし、フォームを入力します。
イメージ 1

"Submit"をクリックすると、、、
イメージ 2

URL の末尾にフォームに入力した文字列が続くところが GET の特徴です。
http://192.168.11.12/get.cgi?handle=yamamo&link=blog


第四章:フォームの利用(2)
第三章とやることは同じですが、GET ではなく POST を使っています。

post.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
    int ictlength;
    char *buf_org, *ctlength;

    char *buf;
    char *pch;
    struct{
        char name[10];
        char value[500];
    }query[10];
    int i, j;

    ctlength = getenv("CONTENT_LENGTH");
    ictlength = atoi(ctlength);
    if*1 == NULL){
        puts("Could not allocate memory !");
        exit(1);
    }
    if*2 != 1){
        puts("Could not read stdin !");
        exit(1);
    }
    buf_org[ictlength] = '\0';

    buf = malloc(ictlength + 1);
    strcpy(buf, buf_org);

    pch = strtok(buf, "&");
    i = 0;
    while (pch != NULL){ strcpy(query[i++].value, pch); pch = strtok(NULL, "&"); }
    for(j=0; j<i; j++){
        pch = strtok(query[j].value, "=");
        strcpy(query[j].name, pch);
        strcpy(query[j].value, strtok(NULL, "="));
    }
    printf("Content-type: text/html\n\n");
    printf("<html><body><h4>QUERY_STRING:\t%s</h4></body></html>\n", buf_org);
    for(j=0; j<i; j++){
        printf("<html><body><h4>%s\t= %s</h4></body></html>\n", query[j].name, query[j].value);
    }
    return 0;
}


コンパイル・リンクして実行形式 post.cgi を作成して /var/www/html/ へコピーします。

入力フォームのページも同様に HTML で用意します。GET を POSTに変えただけです。

post.html
<FORM METHOD="POST" ACTION="http://192.168.11.12/post.cgi">
<INPUT TYPE="TEXT" NAME="handle" VALUE="Myu">
<INPUT TYPE="TEXT" NAME="link" VALUE="OK">
<INPUT TYPE="SUBMIT" VALUE="Submit">
</FORM>

http://192.168.11.12/post.html にアクセスし、フォームを入力します。
イメージ 3

"Submit"をクリックすると、、、
イメージ 4

先ほどの GET との違いは、"Submit" した後の URL
http://192.168.11.12/post.cgi
に入力文字列が続かないことです。



以上、CGI の基本を理解できたような気がしました

*1:buf_org = malloc(ictlength + 1

*2:fread(buf_org,ictlength,1,stdin