ここでは、C 言語用 CGI プログラミングライブラリ Cockatrice の使用方法について説明します。 デフォルトでのインストールでは、 必要なヘッダファイルとライブラリは以下のような構成で導入されます。
/usr/local/include/cockatrice.h /usr/local/lib/libcgi.a /usr/local/lib/libcgi.so.2 /usr/local/include/catoblepas.h /usr/local/lib/libcatoblepas.a /usr/local/lib/libcatoblepas.so.1 /usr/local/include/basilisk.h /usr/local/lib/libbasilisk.a /usr/local/lib/libbasilisk.so.1
上記構成において、 Cockatrice が CGI プログラミング用ライブラリで、 Catoblepas と Basilisk が HTML 作成支援ライブラリです。 Catoblepas は HTML 4.01 を Basilisk が HTML 2.0 と 3.2 用です。 Cockatrice-2.0 以降、CGI プログラミング部分と HTML Authoring 支援機能を分離したので、上記のような構成となりました。
#include <stdio.h>
#include <cockatrice.h>
int main(int argc, char * argv[])
{
CGI * cgi;
cgi = newCGI(CC_MODULE_STANDARD);
cgi->header("text/plain");
fprintf(stdout, "Hello, World!");
cgi->done();
return 0;
}
#include <stdio.h>
#include <cockatrice.h>
#include <catoblepas.h>
int main(int argc, char * argv[])
{
CGI * cgi;
HTML * html;
cgi = newCGI(CC_MODULE_STANDARD);
html = newHTML401(HTML4_Strict);
cgi->header("text/html");
html->html.begin();
html->head.begin();
html->title("WEB PAGE TITLE");
html->head.end();
html->body.begin();
html->p.begin();
html->print("Hello, World!");
html->p.end();
html->body.end();
html->html.end();
html->done();
cgi->done();
return 0;
}
Cockatrice を使用するには、必ず newCGI() を呼び出します。 引数 modules はライブラリで使用したい拡張モジュールを指定します。 現在、利用可能な拡張モジュールは次のいずれかの組み合わせです。
CC_MODULE_FILE | ファイルロック制御機能を提供 |
CC_MODULE_ENV | 環境変数アクセス機能を提供 |
CC_MODULE_DATE | 日付時刻取得機能を提供 |
CC_MODULE_CHECK | 文字列チェック機能を提供 |
CC_MODULE_SESSION | セッション管理機能を提供 |
CC_MODULE_SQLITE3 | SQLite3 データベース機能を提供 |
CC_MODULE_PGSQL8 | PostgreSQL データベース機能を提供 |
CC_MODULE_STANDARD | 標準機能のみを利用 |
int main(int argc, char * argv[])
{
CGI * cgi;
...
cgi = newCGI(CC_MODULE_DATE | CC_MODULE_SQLITE3);
...
cgi->done();
return 0;
}
"name" で指定する CGI パラメータを取得します。 成功した場合は、値を文字列で返します。 失敗した場合は、NULL を返します。
たとえば、次のようなフォームを考えます。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
...
</head>
<body>
<form action="/cgi-bin/test.cgi" method="post">
Name: <input type="text" name="name" value="Your Name">
E-Mail: <input type="text" name="email" value="Your E-Mail">
...
</form>
</body>
</html>
上記フォームではパラメータとして、名前と電子メールアドレスを記入してもらいます。
CGI ライブラリでは、次のようにしてパラメータを取得します。
cgi->param("name");
cgi->param("email");
つまり、input タグの name 属性で指定した名前を param() の引数として取り出すことができます。 この例では、POST メソッドを利用していますが、GET メソッドでも同様の方法です。
cgi->param() の返す値は、文字列ですので、
fprintf(stdout, "Input value: %s\n", cgi->param("email"));
では、入力された電子メールアドレスが表示されます。
"name" で指定する CGI パラメータを取得します。 成功した場合は、VList へのポインタを返します。 失敗した場合は、NULL を返します。 checkbox などの複数の選択値を使用する場合に利用します。
たとえば、次のようなフォームを考えます。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
...
</head>
<body>
<form action="/cgi-bin/checkbox.cgi" method="post">
<table border="0">
<tr>
<td><input type="checkbox" name="fruits" value="苺">いちご</td>
</tr>
<tr>
<td><input type="checkbox" name="fruits" value="林檎">りんご</td>
</tr>
<tr>
<td><input type="checkbox" name="fruits" value="蜜柑">みかん</td>
</tr>
<tr>
<td><input type="checkbox" name="fruits" value="葡萄">ぶどう</td>
</tr>
<tr>
<td><input type="checkbox" name="fruits" value="桃">もも</td>
</tr>
<tr>
<td><input type="checkbox" name="fruits" value="梨">なし</td>
</tr>
<tr>
<td><input type="checkbox" name="fruits" value="柿">かき</td>
</tr>
</table>
...
</form>
</body>
</html>
上記フォームでは果物の名前を好きなだけ選択できます。 Cockatrice では、次のようにしてパラメータを取得します。
VList * vp;
for (vp = cgi->params("fruits"); vp != NULL; vp = vp->next) {
fprintf(stdout, "Fruit: %s\n", vp->value);
}
"name" で指定した Cookie のパラメータ(NAME=VALUE)を取得します。 cgi->cookie->get("NAME") とすれば、 NAME に設定された VALUE を文字列として返します。
Cookie の NAME=VALUE を設定します。
(例)cgi->cookie->setName("NAME", "阿部康一");
Cookie のコメントを設定します。
デフォルトは、コメントなしです。
(例)cgi->cookie->setComment("NAME", "Cookie に関する説明");
Cookie のドメインを設定します。
デフォルトは、アクセスしたサーバのドメインになります。
(例)cgi->cookie->setDomain("NAME", "MysticWALL.COM");
Cookie の有効期限を設定します。
デフォルトは、即失効(つまり、キャッシュされない)になります。
引数は、秒です。以下の例は、10分間の有効期限を表します。
(例)cgi->cookie->setMaxAge("NAME", 600);
Cookie の有効パスを設定します。
デフォルトは、無指定(つまり、ブラウザにお任せ)になります。
(例)cgi->cookie->setPath("NAME", "/database");
Cookie が安全かを設定します。
デフォルトは、Non-Secure です。
(例)cgi->cookie->setSecure("NAME", true);
Cookie 発行元に Cookie を使ったセッションの初期化や継続について指示する。 RFC 2965 で追加されたパラメータ。
ユーザエージェント(つまり、ブラウザ)終了時、Cookie を破棄させるか設定する。 デフォルトは、破棄させない。 RFC 2965 で追加されたパラメータ。
Cookie が戻されるポートを制限します。 RFC 2965 で追加されたパラメータ。
FORM の FILE タイプを利用したアップロードファイルの操作には、 cgi->upload->open()、cgi->upload->store()、 cgi->upload->digest() を利用します。
アップロードされたファイルをオープンして、操作できます。 fclose() した場合は、その後のアクセスは不能となります。 成功した場合にはファイルポインタを、失敗した場合には NULL を返します。
アップロードファイルを指定されたファイル名で保存します。 成功した場合には 0 を、失敗した場合には -1 を返します。 一般的な、ファイルアップロードのための HTML ファイルは、 以下のような構造となります。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
...
</head>
<body>
<form action="/cgi-bin/upload.cgi" method="post" type="multipart/form-data">
Name: <input type="text" name="name" value="Your Name">
E-Mail: <input type="text" name="email" value="Your E-Mail">
File1: <input type="file" name="fname1" value="Attached Filename1">
File2: <input type="file" name="fname2" value="Attached Filename2">
...
</form>
</body>
</html>
CGI プログラムでは、 次のようにしてアップロードされたファイルにアクセスします。 アップロードされたファイルを保存するには、 次のようなコードを書きます。ただし、概要だけのコードです。
#include <stdio.h>
#include <cockatrice.h>
int main(int argc, char * argv[])
{
CGI * cgi;
cgi = newCGI(CC_MODULE_STANDARD);
...
cgi->upload->store("fname1", "upload1.txt");
cgi->upload->store("fname2", "upload2.txt");
...
cgi->done();
...
return 0;
}
アップロードファイルのダイジェストを計算します。 ファイルの整合性などの検査に利用できます。 digest_t には、次のいずれか一つを指定できます。
成功した場合には指定したアルゴリズムでのダイジェストの値を、 失敗した場合には NULL を返します。
URI に用いることができない記号や日本語を %nn の形式にエンコードします。
URI エンコードされた文字列をデコードします。
例えば、"かべちゃん" は、"%A4%AB%A4%D9%A4%C1%A4%E3%A4%F3" に変換されます。 この例では、漢字コードは日本語 EUC コードです。
cgi->uri->escape("かべちゃん");
cgi->uri->unescape("%A4%AB%A4%D9%A4%C1%A4%E3%A4%F3");
文字列のダイジェストを計算します。 ダイジェストを利用したパスワードの整合性などの検査に利用できます。 digest_t には、次のいずれか一つを指定できます。
任意の文字列の文字コードを日本語 EUC コード(EUC-JP)に変換します。 wkf をリンクしている場合は、 入力文字列は JIS, Shift-JIS, EUC-JP のいずれかを自動判断して変換します。 iconv をリンクしている場合は、 入力文字列は JIS, Shift-JIS, EUC-JP, UTF-8, UTF-16, UTF-32 のいずれかを自動判断して変換します。
利用する場合は、newCGI() で CC_MODULE_CHECK を指定する必要があります。
CGI * cgi = newCGI(CC_MODULE_CHECK);
Cockatrice では、カレンダー作成を目的とした日付と時刻に関する API を提供します。 利用する場合は、newCGI() で CC_MODULE_DATE を指定する必要があります。
CGI * cgi = newCGI(CC_MODULE_DATE);
西暦、月、日を引数に取り、二十四節気を返します。 二十四節気は、"春分", "清明", "穀雨", "立夏", "小満", "芒種", "夏至", "小暑", "大暑", "立秋", "処暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "冬至", "小寒", "大寒", "立春", "雨水", "啓蟄" です。
利用する場合は、newCGI() で CC_MODULE_ENV を指定する必要があります。
CGI * cgi = newCGI(CC_MODULE_ENV);
環境変数の取得には、
cgi->env->get("REMOTE_HOST");
のように char * cgi->env->get(char * name)
を利用します。
また、ウェブサーバで設定される主な環境変数は、 次の関数によって取得可能です。 ただし、CGI スクリプト名だけは、cgi->script_name でもアクセスできます。
利用する場合は、newCGI() で CC_MODULE_FILE を指定する必要があります。
CGI * cgi = newCGI(CC_MODULE_FILE);
電子掲示板システムなどのような、ファイルの書き込みを排他制御する 必要がある CGI プログラムで、ファイルをロックしたい場合には、 cgi->util->lock() / cgi->util->unlock() を利用します。
cgi->util->lock("/home/kouichi/public_html/bbs.db");
cgi->util->unlock("/home/kouichi/public_html/bbs.db");
Cockatrice では簡単なセッション管理機能を提供します。
利用する場合は、newCGI() で CC_MODULE_SESSION を指定する必要があります。
CGI * cgi = newCGI(CC_MODULE_SESSION);
Cockatrice では SQLite3 と
PostgreSQL
を使った簡単なデータベース操作機能を提供します。
現在の実装では、同時に複数のデータベースを操作できません。
利用する場合は、newCGI() で CC_MODULE_SQLITE3 か
CC_MODULE_PGSQL8 を指定する必要があります。
CGI * cgi = newCGI(CC_MODULE_SQLITE3);
SQLite の場合、 引数 dbname で指定した SQLite3 データベースをオープンします。 PostgreSQL の場合は、dbname で指定された文字列は、 PQconnectdb() への引数となります。 成功した場合は 0 を、失敗した場合は -1 を返します。
CGI * cgi = newCGI(CC_MODULE_PGSQL8);
...
cgi->database->open("dbname=access_log connect_timeout=10");
SQLite の場合は、データベースをクローズします。 PostgreSQL の場合は、サーバとの接続を切断します。
引数 sql_statement で指定した SQL 文を実行します。 INSERT や UPDATE 命令では、この API を利用します。 成功した場合は 0 を、失敗した場合は -1 を返します。
引数 sql_statement で指定した SQL 文を実行します。 SELECT 命令では、この API を利用します。 成功した場合は 0 を、失敗した場合は -1 を返します。
cgi->database->query() が成功した場合、 本 API を呼び出すと引数 results に column 毎の結果が一式返ります。 成功した場合は 0 を、失敗した場合は -1 を返します。
引数 sql_statement で指定した SQL 文の "single quote" を quote した結果を返します。 新たにメモリ領域を割り当てますので、 使用後は free(3) を使ってメモリ領域を解放してください。
cgi->header("text/html; charset=EUC-JP");
Cookie が設定されている場合は、
適切な HTTP ヘッダを生成してクライアントに送信します。
URL を引数に取り、レスポンスコード 302 の応答で、 Location フィールドを返します。
cgi->redirect("http://www.MysticWALL.COM/index-j.html");
上記の出力は、
Status: 302 Moved[CRLF]
Location: http://www.MysticWALL.COM/index-j.html[CRLF]
[CRLF]
となります。[CRLF] は明示的に表現しているだけです。
CGI ライブラリの使用を終了するには、done() を呼び出します。 ライブラリの終了時には、必ず呼び出すようにしてください。
また、シグナルハンドラの実装の際には、そこで即終了する場合は問題ないですが、 プログラムの実行を継続する場合には、必ず呼び出すようにしてください。
基本的な使い方は、ソースコードに次の一行を書き、
#include <cockatrice.h>
コンパイル時に cockatrice と md ライブラリをリンクします。
漢字コード変換ライブラリ wkf を利用する場合は、
wkf ライブラリも一緒にリンクします。
文字コード変換ライブラリが導入されている環境では、
wkf ライブラリの代わりに
iconv
ライブラリをリンクします。
例えば、環境変数の一覧表示プログラムの場合は、 次のようなソースコードになります。ファイル名は、printenv.c とします。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <cockatrice.h>
#include <catoblepas.h>
int main(int argc, char * argv[])
{
CGI * cgi;
cgi = newCGI(CC_MODULE_STANDARD);
if (cgi) {
HTML * html;
html = newHTML401(HTML4_Transitional);
if (html) {
extern char ** environ;
char ** ep;
cgi->header("text/html");
html->html.attr.lang = "ja";
html->html.begin();
html->head.begin();
html->title("Environment Variables");
html->head.end();
html->body.begin();
html->div.attr.trans.align = ALIGN_CENTER;
html->div.begin();
html->table.attr.border = 1;
html->table.begin();
for (ep = environ; *ep; ep++) {
String key;
String value;
key = *ep;
value = (String)strchr(key, '=');
if (value != NULL) {
*value++ = EOL;
}
html->tr.begin();
html->td.begin();
html->print(key);
html->td.end();
html->td.begin();
html->printe(value);
html->td.end();
html->tr.end();
}
html->table.end();
html->div.end();
html->body.end();
html->html.end();
html->done();
}
cgi->done();
}
return 0;
}
上記のソースコードのコンパイルは次のようにします。 '%' はシェルプロンプトです。
% gcc -o printenv.cgi -I/usr/local/include -L/usr/local/lib printenv.c -lcockatrice -lcatoblepas -lwkf -lmd
コンパイル後の使用方法は、次のようになります。
% w3m http://localhost/cgi-bin/printenv.cgi
以下は、表示例です。
PATH | /bin:/usr/bin:/usr/local/bin |
SERVER_SOFTWARE | Wyvern/2.0.8 |
GATEWAY_INTERFACE | CGI/1.1 |
SERVER_PROTOCOL | HTTP/1.0 |
SERVER_PORT | 80 |
SERVER_ROOT | /usr/local/wyvern |
SERVER_NAME | swordfish.MysticWALL.COM |
SERVER_ADMIN | kouichi@MysticWALL.COM |
DOCUMENT_ROOT | /home/kouichi/MysticWALL |
REQUEST_METHOD | GET |
SCRIPT_NAME | /cgi-bin/printenv.cgi |
QUERY_STRING | |
REMOTE_ADDR | ::ffff:127.0.0.1 |
REMOTE_PORT | 2379 |
AUTH_TYPE | Basic |
REMOTE_IDENT | kouichi |
HTTP_ACCEPT | text/*, image/*, video/*, application/* |
HTTP_ACCEPT_ENCODING | gzip, compress, bzip, bzip2, deflate |
HTTP_ACCEPT_LANGUAGE | ja |
HTTP_USER_AGENT | Mozilla/5.0 |