HTML
,
CGI
の紹介
稲元 勉
2014
年 4 月 14 日
1
はじめに
ソフトウェア工学演習では,構築するソフトウェアを Webアプリケーションに限定している.この理由,および HTML (Hyper-Text Markup Language)[1],CGI (Com-mon Gateway Interface)[2]の概要を紹介する.ここで,“紹介” としていることから分かるように,本 資料の目的は,それらの技術の詳細を述べることにはな い.HTML や CGI の解説資料は,書店にも Web 上に も大量に存在する.系統だった知識を得たいならば書籍 (手軽には中古本)の購入を,とりあえず言葉の意味を知 りたいならば Web 上で検索しいくつかのページを見る ことを,それぞれ推奨する.
2
Web
アプリケーションに限定する
理由
近年では,ほぼすべてのアプリケーションソフトウェ アが,マウスで操作する GUI を備えているといえる.そ うではない,CUI しか備えないソフトウェアも存在する が,一般のエンドユーザ向けとはいいがたいと思われる. GUIを備えるアプリケーションソフトウェアを作るため には,それが実行される OS 用の適切な GUI ライブラリ が必要であり,かつそのライブラリに含まれる関数など の使い方を覚えなければならない.ライブラリを使うた めの学習は,有益ではあるものの,アプリケーションソ フトウェア開発にあたっての周辺に過ぎず,本質ではな い場合が多い. そのような GUI ライブラリの学習コストを避ける方途 の一つとして,Web ブラウザ(以降,たんにブラウザ) の利用があげられる.ブラウザ上にボタンやメニューを 表示し,操作できるようにすれば,GUI ライブラリを使 用する必要はなくなる.さらに,高度/最先端の機能を 有するものでなければ,どのような OS にもブラウザは 提供されており,OS ごとの差異に注意を払う必要はない といえる.以上の理由から,ソフトウェア工学演習では, 構築するアプリケーションは Web アプリケーションに限 定することとする.3
HTML
の紹介
3.1
HTML
の役割
パソコンを含む多くの機器が接続して形成している巨 大なネットワークであるインターネット内に,ある情報 がべつのある情報と関係することを表すハイパーリンク により,多種多様な文書・画像・音楽などを結びつけた ネットワークが存在する.これが WWW (World Wide Web, Web) であり,その基本的構成要素である文書は Webページと呼ばれ,Web ページを記述するための代表 的形式が HTML である.本資料では,HTML 形式で記 述された Web ページを,HTML ページあるいは HTML ファイルと呼ぶ. なお,本資料で扱う HTML のバージョンは,2014 年 中に正式勧告されそうな HTML5 ではなく,歴史が長く 枯れている(安定して使用できる) 4 とする.3.2
タグと属性
HTMLファイルは,“タグ” と呼ばれる文字列で囲まれ た部分から構成される.タグの役割は,それが含む部品 の,文書内での役割や体裁を指定することにある.タグは 階層構造をとることができ,図 1 に例示するように,あ るタグの中身が別のタグをもつことが一般的である.ま た,タグは “属性” と呼ばれるパラメータを持っており, その値を指定することで,振る舞いや体裁を変更するこ とができる. 3.2.1 タグ タグは,HTML ファイルにおいて,ある文章の体裁 を変更したり,その文書全体における役割を指定する ための文字列である1.文章などの前に置かれるタグは “開始タグ” と呼ばれ,タグ名を tag_name とすれば “<tag_name>” と記述される.文章などの後に置かれ るタグは “終了タグ” と呼ばれ,タグ名を tag_name と すれば “</tag_name>” と,開始タグに “/” を挿入し 1近年では,体裁と役割を明確に分け,体裁は CSS (Cascading Style Sheets)で,役割は文書自体で指定することが推奨され,かつ一般的と なってきている.</tag1>
</tag4>
図 1: タグが形成する階層構造のイメージ たような文字列として記述される.そして,タグおよび タグに囲まれた部分は “要素” と呼ばれる. タグの種類は HTML の仕様 [1] により定められており, 中身が存在すべきものと,そうでない(中身がなくてよ い)ものに大別される.前者のタグのうち代表的なもの として以下があげられる. • html: Web ページ全体を囲み,当該文書が HTML ページであることを表す. • head: HTML ページのタイトルといった情報を含む. • body: HTML ページの,タイトルといった情報を除 いた,本質的内容を含む. • title: HTML ページのタイトルを表す. • p: 段落 (paragraph) を表す.字下げや空白の挿入な ど,見易くなるための体裁の調節をともなう. • a: ここに含まれる中身からハイパーリンクを張る. リンク先は,後述する href 属性を用いて指定する. • div: 複数行にわたる領域を作成する2.当該領域に 含まれる部品に対し一括して体裁などを指定できる. • span: 単一行の領域を作成する3 .当該領域に含まれ る部品(多くの場合,単純な文字列)に対して,一 括して体裁などを指定できる. 2ブロック要素と呼ばれる. 3インライン要素と呼ばれる. • h1, ..., h6: 見出し (heading) を表す.数字の小さい ほうがより大きな単位の見出しである.たとえば,通 常の設定では,h1 タグで囲まれた文字列は h2 タグ で囲まれた文字列よりも大きな文字で表示される. • table: 表を作成する.表中の行は,table タグの中 身のうち tr (table row) タグにより囲まれた中身と なる.行中のセルは,tr タグの中身のうち td (table data)タグにより囲まれた中身となる.• ol, ul: それぞれ順序つき (ordered),順序なし (un-ordered)リストを表す. • li: ol タグや ul タグの内部で,リストの要素を表す. • form: CGI プログラムへデータを渡す際に使用する. formタグの中身では,渡すデータの種類におうじて, つぎのようなタグを使用する. – input: 一行ほどの文字列や選ばれた選択肢など を渡す.また,CGI プログラムへのデータ送信 を行う. – textarea: 複数行の文字列を渡す. – select: 複数の選択肢の中の一つを選んで渡す. 中身を持たないタグのうちでは,以下が代表的と考え られる. • img: 画像 (image) を表す.画像ファイルは,後述す る src 属性を用いて指定する. • br: 改行 (break line) を表す.p タグとは異なり,空 白を挿入するといった調節は行われない. • hr: 水平 (horizontal) 線を表す. • meta: head 要素に含まれ,HTML ページの情報(メ タデータ)を指定する. タグ名は,大文字・小文字が区別されず,たとえば “<HTML> ... </HTML>”と “<html> ... </html>” は同じである.しかし,XHTML との親和性から,本資 料では小文字を使うこととする. 多くのタグは,その中身にほかのタグを含むという階 層構造をとったり,一つの文書内に複数存在することが できる.このようなことが許されないタグとして,html や body があげられる.その禁則は,たとえば以下のよ うに記述できる. • 一つのファイルが複数の HTML ページに対応するこ とはないため,html タグは一つだけである. • html タグは,ほかのすべてのタグを含む最大のタグ であり,ほかのタグに含まれることはない.
リスト 1: 単純な HTML ページ
1 <html> <head>
3 < t i t l e>s i m p l e web page</ t i t l e> </head> 5 <body> <h1>c h a p t e r 1</h1> 7 <h2> s e c t i o n 1</h2> <p>p a r a g r a p h 1 .</p> 9 <p>p a r a g r a p h 2 : b e f o r e b r .<br> a f t e r b r .</p> 11 <h2> s e c t i o n 2</h2> <p>f o o b a r .</p> 13 <hr> 15 <h1>c h a p t e r 2</h1> 17 <h2> s e c t i o n 1</h2> <h2> s e c t i o n 2</h2> 19 </body> </html> 図 2: 単純な HTML ページの表示画面 • head タグ,body タグは,HTML ページの情報,中 身を伝えるものであるので,html タグの直下に,ど ちらも一つずつ,含まれる.また,これらのタグが htmlタグ以外のタグの中身に含まれることはない. このようなルールに従う,きわめて単純な HTML ペー ジをリスト 1 に示す.このファイルを Firefox で開くと, 図 2 に示すように表示される. 3.2.2 属性 あるタグで指定可能な属性は,HTML の仕様 [1] で規 定されており,タグごとに異なる.とくに重要な属性と しては,以下があげられる. • id: 文書内で一意である ID(通し名)を振る.ID は, ハイパーリンクのリンク先として使用できる. • name: id 属性と同様に文書内の ID を振ったり,form タグ内で使われるデータ送信用のタグにおいては,個 別データと紐づけられる変数名を指定する. • href: a タグにおいて,ハイパーリンク先を指定する. リンク元は,a タグの中身となる. • src: img タグにおいて,表示する画像ファイルを指 定する. • action: form タグにおいて,渡すデータを処理する CGIプログラムを指定する. • method: form タグにおいて,データの送信方法を指 定する. • http-equiv: meta タグにより指定するメタデータの 種類を指定する. • content: meta タグにより指定するメタデータの中 身を指定する. • style: CSS の書式によって体裁などを指定する.
3.3
HTML
ページの例
リスト 1 に示した HTML ページは,単純であること を優先して作成したものであり,HTML-lint[3] でチェッ クすれば分かるように,HTML 仕様への準拠は不十分で ある.また,ページ内で使われる文字の文字コードを指 定していないため,日本語などを使った場合には文字化 けし,適切に読めない可能性が高い.仕様への準拠や日 本語などの使用に留意した単純な HTML ページの一例 を,リスト 2 に示す.このファイルを Firefox で開いた イメージは,図 3 のようになる.リスト 2: 仕様に準拠する単純な HTML ページ
< !DOCTYPE HTML PUBLIC
2 "−//W3C//DTD␣HTML␣ 4 . 0 1 ␣ T r a n s i t i o n a l //EN"> <html lang=" j a ">
4 <head>
<meta h t t p−equiv=" Content−type "
6 content=" t e x t / html ; ␣ c h a r s e t=UTF−8"> < t i t l e>仕様に準拠する単純な HTML ページ</ t i t l e> 8 </head> 10 <body> <div id="TOC"> 12 <o l>
< l i><a href="#C1 ">第 1 章</a> 14 <ul>
< l i><a href="#C1 . S1 ">1 . 1 節</a></ l i> 16 < l i><a href="#C1 . S2 ">1 . 2 節</a></ l i>
</ ul> 18 </ l i>
< l i><a href="#C2 ">第 2 章</a> 20 <ul>
< l i><a href="#C2 . S1 ">2 . 1 節</a></ l i> 22 < l i><a href="#C2 . S2 ">2 . 2 節</a></ l i>
</ ul> 24 </ l i> </ o l> 26 </ div> 28 <hr> 30 <div> <h1 id=" C1 ">第 1 章</h1> 32 <h2 id=" C1 . S1 ">1 . 1 節</h2> <p>第 1 段落.</p> 34 <p>第 2 段落.改行前<br>改行後 </p> 36 <h2 id=" C1 . S2 ">1 . 2 節</h2> 38 <p>ほげ</p> </ div> 40 <hr> 42 <div> 44 <h1 id=" C2 ">第 2 章</h1> <h2 id=" C2 . S1 ">2 . 1 節</h2> 46 <h2 id=" C2 . S2 ">2 . 2 節</h2> </ div> 48 </body> 50 </html>
4
CGI
の紹介
4.1
CGI
の役割
基本的な Web ページは静的・一方向的である.そのよう なページを閲覧する際,ユーザは同一の内容を Web サー バから受け取ることになる.近年では,JavaScript が広 く利用されるようになり,ユーザの操作におうじて内容 の変化する動的 Web ページが膾炙している.また,Ajax と呼ばれる一連の技術を利用することで,ユーザが入力 したデータにおうじて即時に変化する双方向的動的 Web ページも一般的になりつつある. CGIは,このような現況において,ユーザが入力した データにおうじてサーバの振る舞いを変えるという,双 図 3: 仕様に準拠する単純な HTML ページの表示画面 方向的やり取りを支えている技術である.検索サービス などを提供する企業により,Ajax を用いて検索を行いや すくするためのスクリプト・ライブラリなどが無償で配 布されており,そのようなライブラリを使うだけならば CGIについての知識はあまり必要ない.しかし,新奇な サービスを考案・開始するなど,ライブラリを使うだけ ではなく作ることができるためには,CGI に関する知識 は必須と考えられる.具体的には,Ajax により即時に変 化する Web ページが存在するとき,その内部では form タグが使用され,どこかのサーバと CGI によりデータを やり取りしている.たとえば,Google[4] のトップページ の HTML ソースを見ると,図 4 に示すように,form タ グを使っていることが分かる.4.2
Web
ページと CGI プログラム間のやり
取り
CGIが提供する機能は,大きく三つに整理できる. 1. ブラウザを介して,ユーザが Web サーバ上でプログ ラム(CGI プログラムと呼ぶ)を実行すること.図 4: Google のトップページのソース(抜粋)
2. ブラウザを介してユーザが与えたデータを,CGI プ ログラムが受け取ること.
3. Webサーバが,CGI プログラムの出力を,Web ペー ジとしてブラウザへ返すこと.
CGIプログラムと(Ajax を用いない)Web ページと のやり取りは,つぎのようになる. 1. ユーザがブラウザを用いて Web ページへアクセス する. 2. 当該 Web ページ上でユーザが適宜操作することで, ユーザが入力/選択したデータを処理せよという指 示が,ブラウザから Web サーバへ送られる. 3. Webサーバは,ブラウザから送られた指示に基づき, CGIプログラムを実行し,ユーザにより入力/選択 されたデータを渡す. 4. CGIプログラムは,ユーザにより入力/選択された データを適宜処理し,何らかの結果を出力する. 5. Webサーバは,CGI プログラムからの出力を受け 取る. 6. Webサーバは,CGI プログラムの出力をブラウザへ 返す. 7. ブラウザは,Web サーバから返された内容を Web ページとして表示する. このやり取りのイメージを図 5 に示す.
user browser Web server(httpd) (CGI program)Web server time 1. 2. 3. 4. 5. 6. 7. 図 5: CGI を用いる Web ページとのやり取りのイメージ
4.3
データの送信
ある HTML ページから CGI プログラムへデータを送 信するためには,form タグを用いる.form タグの action 属性により実行する CGI プログラムを指定し,method 属性によりデータの送信方法を指定する.なお,本資料 では,ユーザが入力/選択したデータが,HTML ページ 内で表示される際に問題とならないよう適宜符号化され た(URL 符号化 [5])ものを,フォームデータと呼ぶこと にする.ユーザが入力/選択したデータは,form タグ経 由で CGI プログラムが受け取るフォームデータとは異な る点に注意する. 4.3.1 method属性による送信方法の指定 データの送信方法は,form タグの method 属性により 指定する.method 属性の値は GET, POST4のいずれかである.それらのおもな違いを表 1 に示す. GETメソッドは, • フォームデータのサイズが小さく, • 同じフォームデータが与えられれば,同じ結果が返 され, • パスワードなどの機密情報を,フォームデータが含 んでいない 場合に用いられる.キーワードを与えて検索サービスを 提供するサーバの CGI プログラムが,GET メソッドの 使われる典型例であるといえる.GET メソッドが使われ ない場合には,POST メソッドが使われる. 4.3.2 タグによるデータ送信 デ ー タ の 入 力 / 選 択 に は ,form タ グ に 含 ま れ る , textareaタグ,input タグ,または select タグを用いる. これらのタグは,文字列といった一連のデータを CGI プ ログラムへ送る.それら 3 種類のタグには name という
表 1: GET と POST のおもな違い method フォームデー タのサイズ フォームデータの渡され方 URL 結果へのリンク &キャッシュ GET 限定的 環境変数を介して フォームデータが表示される 可能 POST 多い 標準入力を介して フォームデータが表示されない 不可能 属性があり,この属性はタグで渡される変数の名前を指 定しているといえる.textarea タグは複数行の文字列を 入力するために,select タグは複数の選択肢をリスト状に 表示し,そのなかから選択肢 (option) を選ぶために,そ れぞれ用いる.input タグは type という属性を持ち,そ の値を指定することで,表 2 に示すようにさまざまな機 能を発揮できる. 変数の値は,つぎのようにして指定する. • textarea タグ: その中身.
• select タグ: このタグが含む option タグの value 属 性の値.
• input タグ: type 属性の値が radio, checkbox, hidden のいずれかならば value 属性の値.そうでなければ, 基本的に,その中身. 変数の名前および値は,基本的に, 1. URLとして扱えるように,名前と値のどちらも URL 符号化 [5] されたあと, 2. 変数名とその値をイコール (=) で連結し, 3. このペアを全変数にわたってアンパサンド (&) で連 結したうえで, CGIプログラムへ送信される.
4.4
CGI
プログラムの例
CGIプログラムは,フォームデータを適切に処理でき るのであれば,どのような言語で実装してもよい.フォー ムデータは基本的に文字列であるため,高度な文字列処 理を手軽に行える Perl, PHP, Python, Ruby といった言 語の使われることが多い.ソフトウェア工学演習では,そ れらの言語の学習に時間を割くことを避けて,これまで に習ってきた C 言語により実装することとする. 4.4.1 フォームデータを用いないプログラム フォームデータを用いないプログラムは,CGI プログ ラムとしてはあまり意味がないが,動的に HTML ページ が生成される様子を眺める点では意味があると思われる. 実行するたびにサイコロの目を返すプログラムソースの 一例を,リスト 3 に示す.また,このプログラムを CGI プログラムとして動かすための HTML ページの一例を, リスト 4 に示す. 4.4.2 フォームデータをたんに出力するプログラム CGIプログラムは,環境変数を介してさまざまな情報を 得る [2].たとえば,REQUEST_METHOD という環境 変数を調べることで,フォームデータの送信方法(POST であるか,GET であるか)を判定することができる.こ のような主要な環境変数を表 3 に示す. 環境変数の値は,(stdlib.h でプロトタイプが宣言され ている)標準関数に含まれる,getenv という関数を用い て取得することができる.また,フォームデータの取得手 続きは,環境変数 REQUEST_METHOD の値によって 異なる.この環境変数の値におうじて取得したフォーム データをそのまま(URL 符号化を元に戻したりせずに) 出力する CGI プログラムのソースの一例を,リスト 5 に 示す. 4.4.3 cgilibを用いてフォームデータを出力する例 現実的な CGI プログラムでは, 1. &をデリミタとしてフォームデータを分割し, 2. 分割後のデータの「=」より左を変数名,右をその 値とし, 3. それぞれ URL 符号化の反対の処理(復号化)を行う ことで,もとの入力データを復元・使用する.このよう な処理は広く使用される定型的なものであり,そのため の多くのライブラリが作成・配布されている.本資料で は,そのようなライブラリの一例として,cgilib[6] を用い たプログラムを例示する.なお,cgilib は GPL[7] という ライセンスのもとで頒布されており,cgilib にもともと含 まれているファイル群に手を加えないとしても, • 2 次派生プログラムのソースにおいて GPL を明記 する; • 2 次派生プログラムの利用ライセンスも GPL とする;表 2: input タグが発揮できるおもな機能 type属性の値 機能 text 一行の文字列を入力. password ブラウザ上では読めないように表示される一行の文字列を入力.暗号化されているわけではないの で注意. radio 複数の選択肢のうちの一つを選択. checkbox 各選択肢を個別に選択.複数選ぶことも,まったく選ばないことも可能. file アップロードするファイルを選択. hidden ブラウザ上に表示されないため,ユーザからは見えず,通常は変更できない変数を保持.少し工夫 すれば,ユーザが見ることも変更することもできるので注意.
submit formタグが含むデータを CGI プログラムへ送信する. reset formタグ内で入力/選択されたデータをクリアする.
表 3: CGI プログラムから参照できる主要な環境変数
環境変数 保持している情報
REQUEST_METHOD formタグの method 属性で指定されたフォームデータ送信方法. QUERY_STRING 送信方法が GET である場合のフォームデータ.
CONTENT_LENGTH 送信方法が POST である場合に,標準入力から読み取れるフォームデータのバイト数. PATH_INFO CGIプログラム自体のURL以降,送信方法がGETである場合には&までの,URLの一部.
• 複製・頒布する際には cgilib のみならず 2 次派生プ ログラムのソースも提供する,あるいは提供手段を 提供する; といった対応が必要と考えられる点に注意する.このよ うに,GPL にしたがうプログラムを利用する際にはきわ めて高度な注意が必要であり,例えば GPL にしたがう プログラムソースの一部を社内で開発したプログラムの ソースに含めると,そのプログラム全体のソースの公表 を可能とする,あるは社内で開発したプログラムの複製・ 頒布を中止することが求められる. cgilibを用いて CGI 経由で与えられたデータを変数ご とに表示するプログラムのソースをリスト 6 に示す.この ソースをコンパイルするための手続きは,付録 A に示す. また,このプログラムの動作をテストするための HTML ページの一例を,リスト 7 に示す. な お ,本 小 節 で 説 明 し た プ ロ グ ラ ム は ,フォー ム デ ー タ を 復 号 化 し て い る た め ,HTML ペ ー ジ 内 で 使 用 す る と 危 険 な 文 字 も そ の ま ま 出 力 さ れ る 点 に 注 意 す る .た と え ば ,textarea タ グ に「<form action="http://somewhere/virus.cgi" method="GET"><input type="submit" value="押さ ないで"></form>」などと入力すれば,CGI プログラ ムを実行した出力の中に,べつの CGI プログラムを呼 び出す form タグを含めることができる.好奇心などで そのフォームの送信ボタンを押下すると,ページに含ま れるデータが外部へ送信されてしまう. 4.4.4 cgilib を用いて変数を保持する例 ある CGI プログラムに入力したデータを,その CGI プログラムあるいはほかの CGI プログラムで利用するた めには,type 属性が hidden である input タグを用いて 対応する変数を保持することが典型的である.たとえば, リスト 8 にソースを示す CGI プログラムは,ある空でな い文字列を,空でない文字列が新たに指定されれば置き 換えながら,保持し続けるものである. なお,type 属性が hidden である変数の値は,ブラウ ザ上に表示されないだけであり,HTML で書かれたソー スを見れば確認できる.CGI プログラム間で機密情報を, このようにして渡していくことは推奨できない.
5
おわりに
本資料では,HTML と CGI を簡単に説明した.詳細 は,たとえば Web 上で検索すると見つかるホームペー ジ [8] など,ほかの資料を参考されたい.また,C 言語で CGIプログラムを作成するためのライブラリとして cgilib を紹介し,その使用例を示した.このライブラリを含め, 多くの有用なライブラリやプログラムが GPL のもと公 開されているが,GPL 汚染 [9] という言葉が生じている ように,それらの利用の際には十分注意する必要がある.リスト 3: サイコロを振る CGI プログラムのソース /∗ 実行するたびに 1−6 の数字を表示するプログラム ∗/ 2 #include < s t d i o . h> 4 #include <t i m e . h> #include < s t d l i b . h> 6 #de f i n e HTML_HEADER(CHAR_SET) \
8 " Content−type : ␣ t e x t /html ; ␣ c h a r s e t=" CHAR_SET " \n\n " 10 i n t main ( void )
{
12 const time_t now = t i m e (NULL ) ; /∗ 時刻を取得 ( c f . man −a time ) ∗/
i n t num ; 14 s r a n d ( ( unsigned ) now ) ; /∗ 擬似乱数系列の初期値を設定 ∗/ 16 num = rand ( ) % 6 + 1 ; /∗ サイコロを振る ∗/ 18 /∗ ページの文字コードは UTF−8 とする ∗/ 20 p u t s (HTML_HEADER( "UTF−8" ) ) ; p u t s ( "<html><body>" ) ; 22 /∗ HTML による記述を出力 ∗/ 24 p r i n t f ( "<p>s e e d ␣=␣%l d ; ␣ d i c e ␣=␣%d</p>\n " , now , num ) ;
26 p u t s ( "<form ␣ a c t i o n =\"/~ inamoto / c g i−bin /CGI−d i c e . c g i \" ␣method=\"GET\">\n " " ␣<i n p u t ␣ t y p e =\" s u b m i t \ " ␣ v a l u e =\" ␣もう一度振る␣ \">\n " 28 "</form>" "</html></body>" ) ; 30 return 0 ; 32 } リスト 4: サイコロを振る CGI プログラムを用いる HTML ページ <html> 2 <head>
<meta h t t p−equiv=" Content−type " c o n t e n t s=" t e x t /html ; ␣ c h a r s e t=UTF−8"> 4 < t i t l e>サイコロを振る CGI プログラム</ t i t l e>
</head> 6
<body>
8 <form action=" /~ inamoto / c g i−bin /CGI−d i c e . c g i " method="GET"> <input type=" s u b m i t " value="サイコロを振る ">
10 </form> </body> 12 </html>
A
cgilib
を用いるソースから
CGI
プ
ログラムを作成する手続き
ここで説明する手続きでは,以下を前提する. • 作業するユーザのホームディレクトリは,~user で ある. • プログラムのソースは,~user/workspace/cgi/src というディレクトリの下に,sample.c という名前 で置かれている. • sample.c の中では,cgilib の一部であるヘッダファ イル cgi.h が,「#include <cgi.h>」という書式で インクルードされている. • CGI プログラムは,~user/public_html/cgi-bin というディレクトリの下に,sample.cgi という名 前で設置する. これらの前提における設定(例えば CGI プログラム名な ど)は,実際の状況におうじて異なる点に注意する. cgilibを用いるソースから CGI プログラムを作成する 手続きは,つぎのようになる. 1. cgilib のソースをこのホームページ [6] から取得 し ,~user/workspace/cgi/src と い う ディレ ク ト リ に 保 存 す る .こ の 結 果 ,本 資 料 作 成 時 点 で の cgilib の最新バージョンは 0.7 であるため, ~user/workspace/cgi/src/cgilib-0.7.tar.gz という(アーカイブ)ファイルが作成される.リスト 5: フォームデータを出力する単純な CGI プログラムのソース /∗ フォームデータをたんに出力するプログラム ∗/ 2 #include < s t d i o . h> 4 #include < s t d l i b . h> #include < s t r i n g . h> 6 #include <e r r n o . h> #include < a s s e r t . h> 8 #de f i n e HTML_HEADER(CHAR_SET) \
10 " Content−type : ␣ t e x t /html ; ␣ c h a r s e t=" CHAR_SET " \n\n " 12 i n t main ( void )
{
14 i n t d a t a _ s i z e ; /∗ フォームデータのデータサイズ ∗/
char ∗ buf = NULL; /∗ フォームデータを保持しておくところ ∗/
16 char ∗cp ;
18 p u t s (HTML_HEADER( "UTF−8" ) ) ; /∗ Web ページの文字コードは UTF−8 が一般的 ∗/ p u t s ( "<html><body>" ) ;
20
/∗ 送信方法は POST .標準入力から読み取る ∗/
22 i f ( ( cp = g e t e n v ( "REQUEST_METHOD" ) ) && ( ! s t r c m p ( cp , "POST" ) ) ) { cp = g e t e n v ( "CONTENT_LENGTH" ) ; /∗ データサイズを取得 ∗/
24 a s s e r t ( cp ) ;
d a t a _ s i z e = a t o i ( cp ) ; /∗ 数字を,数値へ変換 ∗/
26 b u f = ( char∗) malloc ( data_size + 1 ) ; /∗ メモリを確保.\0 用に +1 ∗/ cp = f g e t s ( buf , d a t a _ s i z e + 1 , s t d i n ) ; /∗ データを取得 ∗/ 28 b u f [ d a t a _ s i z e ] = ’ \0 ’ ; } e l s e i f ( cp && ( ! s t r c m p ( cp , "GET" ) ) ) { 30 /∗ 送信方法は GET .環境変数から読み取る ∗/ cp = g e t e n v ( "QUERY_STRING" ) ; 32 a s s e r t ( cp ) ; d a t a _ s i z e = s t r l e n ( cp ) ; /∗ サイズを取得 ∗/
34 b u f = ( char∗) malloc ( data_size + 1 ) ; /∗ メモリを確保.\0 用に +1 ∗/ memcpy ( buf , cp , d a t a _ s i z e + 1 ) ; /∗ データを取得 ∗/ 36 } e l s e { f p r i n t f ( s t d e r r , " i n v a l i d ␣ method : ␣%s \n " , cp ) ; 38 e x i t (EXIT_FAILURE ) ; } 40 /∗ フォームデータを処理.今回はそのまま出力 ∗/ 42 p r i n t f ( " form ␣ d a t a ␣ f o l l o w s :< br >\n " ) ; f p u t s ( buf , s t d o u t ) ; 44 p u t s ( " \n</body></html>" ) ; 46 f r e e ( b u f ) ; /∗ メモリを解放 ∗/ 48 return 0 ; 50 } 2. 端末を開いてつぎのように入力することで,アーカ イブファイルを展開する. (a) cd ~user/workspace/cgi/src (b) tar zxvf cgilib-0.7.tar.gz この結果,~user/workspace/cgi/src/cgilib-0.7 というディレクトリが作成される. 3. プログラムソースをコンパイルする.cgilib 内で必 要なソースファイルは cgi.c, aux.c, cookies.c の三つであるため,コンパイルのために端末へ入力 するコマンドは以下のようになる. (a) gcc -I cgilib-0.7 -o ~user/public_html/cgi-bin/sample.cgi sample.c cgilib-0.7/cgi.c cgilib-0.7/aux.c cgilib-0.7/cookies.c なお,このコマンドは,資料の上では改行されてい るが,端末上では改行せず一行で入力する.
参考文献
[1] HTML 4.01 Specification: http://www.w3.org/TR/ html401/(2014 年 3 月 21 日閲覧).[2] The WWW Common Gateway Inter-face 1.1: http://tools.ietf.org/html/
draft-robinson-www-interface-00(2014 年 3月 27 日閲覧).
[3] 石野恵一郎: Another HTML-lint gateway, http: //cetus.sakura.ne.jp/htmllint/htmllint.html (2014 年 3 月 21 日閲覧).
[4] Google, Inc.: http://www.google.co.jp/(2014 年 3月 26 日閲覧).
[5] URL Character Encoding Issues: http://tools. ietf.org/html/rfc1738#section-2.2(2014 年 3 月 21 日閲覧).
[6] Lightweight CGI Library: http://www.infodrom. org/projects/cgilib/(2014 年 4 月 2 日閲覧). [7] GNU 一般公衆利用許諾契約書(非公式翻訳版): http://sourceforge.jp/projects/opensource/ wiki/licenses\%2FGNU_General_Public_License (2014 年 4 月 2 日閲覧). [8] とほほの WWW 入門: http://www.tohoho-web. com/www.htm(2014 年 4 月 3 日閲覧). [9]「気にしていますか? オープンソースのソースコード 混入」: http://itpro.nikkeibp.co.jp/article/ OPINION/20061124/254769/?ST=network(2014 年 4月 3 日閲覧).
リスト 6: cgilib を用いてデータを変数ごとに表示する CGI プログラムのソース
/∗∗∗
2 C o p y r i g h t (C) INAMOTO Tsutomu & Ehime U n i v e r s i t y
4 This program i s f r e e s o f t w a r e ; you can r e d i s t r i b u t e i t and/ or m o d i f y i t under t h e te r m s o f t h e GNU G e n e r a l P u b l i c L i c e n s e
6 a s p u b l i s h e d by t h e Free S o f t w a r e Foundation ; e i t h e r v e r s i o n 2 o f t h e L i c e n s e , or ( a t your o p t i o n ) any l a t e r v e r s i o n .
8
This program i s d i s t r i b u t e d i n t h e hope t h a t i t w i l l b e u s e f u l ,
10 b u t WITHOUT ANY WARRANTY; w i t h o u t even t h e i m p l i e d w a r r a n t y o f MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See t h e
12 GNU G e n e r a l P u b l i c L i c e n s e f o r more d e t a i l s .
14 You s h o u l d have r e c e i v e d a copy o f t h e GNU G e n e r a l P u b l i c L i c e n s e a l o n g w i t h t h i s program ; i f not , w r i t e t o t h e Free S o f t w a r e
16 Foundation , I n c . , 59 Temple P l a c e − S u i t e 330 , Boston , MA 02111−1307, USA. ∗∗∗/ 18 /∗ ↑ GPL ∗/ 20 #i n c l u d e < s t d l i b . h> 22 #i n c l u d e < s t d i o . h> #i n c l u d e < s t r i n g . h> 24 #i n c l u d e <e r r n o . h> 26 #i n c l u d e < c g i . h>
28 i n t main ( i n t a r g c , char ∗∗ argv )
{ 30 s _ c g i ∗ c g i ; char ∗∗ vars , ∗∗ f i l e s ; 32 i n t i ; 34 c g i = c g i I n i t ( ) ; /∗ c g i l i b の初期化 ∗/ c g i S e t T y p e ( " t e x t / html ; ␣ c h a r s e t=UTF−8" ) ; /∗ 文字コードを UTF−8 に ∗/ 36 c g i H e a d e r ( ) ; /∗ HTTP ヘッダを出力 ∗/ 38 p u t s ( "<html><body>" ) ; 40 v a r s = c g i G e t V a r i a b l e s ( c g i ) ; /∗ 変数名の一覧を取得 ∗/ i f ( v a r s ) { 42 p u t s ( "<p>␣変数一覧␣</p>\n<d l >" ) ; f o r ( i = 0 ; v a r s [ i ] ; i ++) { 44 /∗ 変数名と復号化された値を出力 ∗/ p r i n t f ( "<dt>%s </dt >\n<dd>%s </dd>\n " , v a r s [ i ] , c g i G e t V a l u e ( c g i , v a r s [ i ] ) ) ; 46 } p u t s ( "</d l >" ) ; 48 c g i F r e e L i s t ( v a r s ) ; /∗ メモリを解放 ∗/ 50 } 52 f i l e s = c g i G e t F i l e s ( c g i ) ; /∗ アップロードされたファイルの一覧を取得 ∗/ i f ( f i l e s ) { 54 p u t s ( "<p>␣ファイル一覧␣</p>\n<d l >" ) ; f o r ( i = 0 ; f i l e s [ i ] ; i ++) { 56 s _ f i l e ∗ f i l e v a r ; char b u f f e r [ 1 0 2 4 ] ; 58 FILE ∗ fp ; char ∗e1 , ∗ e2 ; 60 f i l e v a r = c g i G e t F i l e ( c g i , f i l e s [ i ] ) ; 62 p r i n t f ( "<dt>␣クライアント側のファイル名␣ : ␣%s ; ␣サーバ側のファイル名␣ : ␣%s </dt >\n<dd>" , ( e 1 = c g i E s c a p e ( f i l e v a r−>f i l e n a m e ) ) , ( e 2 = c g i E s c a p e ( f i l e v a r−>t m p f i l e ) ) ) ; 64 f r e e ( e 1 ) ; f r e e ( e 2 ) ; /∗ cgiEscape 内部で確保したメモリを解放 ∗/ 66 i f ( ! ( f p = f o p e n ( f i l e v a r−>t m p f i l e , " r " ) ) ) { /∗ ファイルを開く ∗/ p r i n t f ( " f a i l e d ␣ i n ␣ o p e n i n g ␣ f i l e : ␣%s<br >\n " , s t r e r r o r ( e r r n o ) ) ; 68 e x i t (EXIT_FAILURE ) ; } 70 while ( f g e t s ( b u f f e r , s i z e o f ( b u f f e r ) , f p ) ) { /∗ ファイルの中身を出力 ∗/ p r i n t f ( "%s " , b u f f e r ) ; /∗ \n はスペースと同じように解釈され,そこでは改行されない ∗/ 72 } f c l o s e ( f p ) ; 74 p u t s ( "</dd></d l >" ) ; } 76 c g i F r e e L i s t ( f i l e s ) ; } 78 p u t s ( "</body></html>" ) ; 80 c g i F r e e ( c g i ) ; /∗ メモリを解放 ∗/ 82 return EXIT_SUCCESS ; 84 }
リスト 7: データ表示用 CGI プログラムを使用する HTML ページの例
<html> 2 <head>
<meta h t t p−equiv=" Content−type " c o n t e n t s=" t e x t / html ; ␣ c h a r s e t=UTF−8"> 4 < t i t l e>c g i−dump</ t i t l e>
</head> 6
<body>
8 <h1>送信方法がGET</h1>
<form a c t i o n=" /~ i n a m o t o / c g i−bin /CGI−decoded−dump . c g i " method="GET"> 10 <h2>i n p u t</h2>
<u l>
12 < l i>t y p e 属性が t e x t <input type=" t e x t " value=" i n p u t ␣ p l z . " name="GET−t e x t "> </ l i>
14 < l i>t y p e 属性が p a s s w o r d <input type=" p a s s w o r d " value=" p a s s w o r d ␣ p l z . " name="GET−password "> </ l i>
16 < l i>t y p e 属性が r a d i o <input type=" r a d i o " value=" y e s " name=" レディオ ">y e s <input type=" r a d i o " checked value="いいえ " name=" レディオ ">いいえ 18 </ l i>
< l i>t y p e 属性が c h e c k b o x
20 <input type=" c h e c k b o x " value=" a p p l e " name="GET−checkbox ">apple <input type=" checkbox " value=" みかん " name="GET−checkbox ">みかん <input type=" checkbox " value="いちご" name="GET−checkbox ">いちご
</ l i>
22 < l i>t y p e 属性が h i d d e n <input type=" h i d d e n " value=" h i d d e n ␣ v a l u e " name="GET−hidden "> </ l i>
24 </ u l>
26 <h2>t e x t a r e a</h2>
<text ar ea name="GET−t e x t a r e a ">テキストエリア</ textarea> 28
<h2> s e l e c t</h2>
30 <s e l e c t name="GET−s e l e c t ">
<option value="選 択 肢1 ">選 択 肢1</ option> <option value=" o p t i o n ␣ 2 ">o p t i o n 2</ option> <option value=" 選択肢3 ">選択肢3</ option>
32 </ s e l e c t> <br>
34 <input type=" s u b m i t " value="送信 "> <input type=" r e s e t " value=" リセット "> </form>
36
<hr> 38
<h1>送信方法がPOST</h1>
40 <form a c t i o n=" /~ i n a m o t o / c g i−bin /CGI−decoded−dump . c g i " method="POST"> <h2>i n p u t</h2>
42 <u l>
< l i>t y p e 属性が p a s s w o r d
44 <input type=" p a s s w o r d " value=" p a s s w o r d ␣ p l z . " name="POST−password "> </ l i>
46 </ u l>
48 <h2>t e x t a r e a</h2>
<text ar ea name="POST−t e x t a r e a ">テキストエリア</ textarea> 50 <br>
<input type=" s u b m i t " value="送信 "> <input type=" r e s e t " value=" リセット "> 52 </form>
54 <hr>
56 <h2>ファイルをアップロードする場合</h2>
<form a c t i o n=" /~ i n a m o t o / c g i−bin /CGI−decoded−dump . c g i " method="POST" enctype=" m u l t i p a r t /form−data "> 58 <h2>i n p u t</h2>
<u l>
60 < l i>t y p e 属性が t e x t <input type=" t e x t " value=" i n p u t ␣ p l z . " name=" form−t e x t "> </ l i>
62 < l i>t y p e 属性が p a s s w o r d <input type=" p a s s w o r d " value=" p a s s w o r d ␣ p l z . " name=" form−password "> </ l i>
64 < l i>t y p e 属性が r a d i o <input type=" r a d i o " value=" y e s " name=" レディオ ">y e s <input type=" r a d i o " checked value="いいえ " name=" レディオ ">いいえ 66 </ l i>
< l i>t y p e 属性が c h e c k b o x <input type=" c h e c k b o x " value=" a p p l e " name=" form−checkbox ">apple
68 <input type=" c h e c k b o x " value="みかん " name=" form−checkbox ">みかん
<input type=" c h e c k b o x " value="いちご " name=" form−checkbox ">いちご
70 </ l i>
< l i>t y p e 属性が h i d d e n <input type=" h i d d e n " value=" h i d d e n ␣ v a l u e " name=" form−hidden "> 72 </ l i>
< l i s t y l e=" f o n t−weight : ␣ bold ">type 属性が f i l e <input type=" f i l e " name=" form− f i l e ">
74 </ l i> </ u l> 76 <br>
<input type=" s u b m i t " value="送信 "> <input type=" r e s e t " value=" リセット "> 78 </form>
</body> 80 </html>
リスト 8: 文字列を保持し続ける CGI プログラムのソース
/∗ ∗∗
2 C o p y r i g h t (C) INAMOTO Tsutomu & Ehime U n i v e r s i t y
4 T h i s program i s f r e e s o f t w a r e ; you can r e d i s t r i b u t e i t and / o r m o d i f y i t under t h e t e r m s o f t h e GNU G e n e r a l P u b l i c L i c e n s e
6 a s p u b l i s h e d by t h e Free S o f t w a r e F o u n d a t i o n ; e i t h e r v e r s i o n 2 o f t h e L i c e n s e , o r ( a t y o u r o p t i o n ) any l a t e r v e r s i o n .
8
T h i s program i s d i s t r i b u t e d i n t h e hope t h a t i t w i l l b e u s e f u l ,
10 b u t WITHOUT ANY WARRANTY; w i t h o u t e v e n t h e i m p l i e d w a r r a n t y o f MERCHANTABILITY o r FITNESS FOR A PARTICULAR PURPOSE. See t h e
12 GNU G e n e r a l P u b l i c L i c e n s e f o r more d e t a i l s .
14 You s h o u l d h a v e r e c e i v e d a copy o f t h e GNU G e n e r a l P u b l i c L i c e n s e a l o n g w i t h t h i s program ; i f not , w r i t e t o t h e Free S o f t w a r e
16 Foundation , I n c . , 59 Temple P l a c e − S u i t e 330 , Boston , MA 02111 −1307 , USA. ∗∗ ∗/
18
/∗ 変数を保持し続ける ∗/
20
#de f i n e VAR_NAME " r e m a i n i n g "
22 #de f i n e NEW_NAME " new_name "
24 #include < s t d i o . h> #include < s t d l i b . h> 26 #include < s t r i n g . h> #include < c g i . h> 28 i n t main ( void ) 30 { s _ c g i ∗ c g i ; 32 char ∗∗ vars , ∗cp ; char v a r _ v a l u e [ 1 0 2 4 ] = " " ; /∗ サイズ固定 ∗/ 34 i n t i ; 36 c g i = c g i I n i t ( ) ; /∗ c g i l i b の初期化 ∗/ c g i S e t T y p e ( " t e x t / html ; ␣ c h a r s e t=UTF−8" ) ; /∗ 文字コードを UTF−8 に ∗/ 38 c g i H e a d e r ( ) ; /∗ HTTP ヘッダを出力 ∗/ 40 v a r s = c g i G e t V a r i a b l e s ( c g i ) ; /∗ 変数名の一覧を取得 ∗/ i f ( v a r s ) { 42 f o r ( i = 0 ; v a r s [ i ] ; i ++) { i f ( ! s t r c m p ( v a r s [ i ] , VAR_NAME) ) { 44 s t r n c p y ( v a r _ v a l u e , c g i G e t V a l u e ( c g i , VAR_NAME) , s i z e o f ( v a r _ v a l u e ) ) ; /∗ 変数の値をコピー ∗/ break ; 46 } } 48 c g i F r e e L i s t ( v a r s ) ; /∗ メモリを解放 ∗/ } 50 i f ( ( cp = c g i G e t V a l u e ( c g i , NEW_NAME) ) && s t r c m p ( cp , " " ) ) { /∗ べつの所定の変数が空でなければ ∗/ 52 s t r n c p y ( v a r _ v a l u e , cp , s i z e o f ( v a r _ v a l u e ) ) ; /∗ 変数の値を変更 ∗/ } 54 p r i n t f ( "<html><body><p>␣%s ␣=␣%s </p>" , VAR_NAME, v a r _ v a l u e ) ; /∗ 値を参考までに表示 ∗/
56 p r i n t f ( "<form ␣ a c t i o n =\"/~ inamoto / c g i−bin /CGI−hidden . c g i \" ␣method=\"POST\"> " ) ; p r i n t f ( "新しい値␣ : ␣<i n p u t ␣ t y p e =\" t e x t \ " ␣ v a l u e =\"\" ␣name=\"%s \"> " , NEW_NAME) ; 58 i f ( s t r c m p ( v a r _ v a l u e , " " ) ) { p r i n t f ( "<i n p u t ␣ t y p e =\" h i d d e n \ " ␣name=\"% s \ " ␣ v a l u e =\"% s \"> " , 60 VAR_NAME, v a r _ v a l u e ) ; /∗ hidden 変数として保持 ∗/ } 62 p u t s ( "<i n p u t ␣ t y p e =\" s u b m i t \ " ␣ v a l u e =\" ␣実行␣\"></form></body></html>" ) ; 64 c g i F r e e ( c g i ) ; /∗ メモリを解放 ∗/ 66 return EXIT_SUCCESS ; }