情報システム技術論’08 — ＃ 4
久野靖∗

2008.5.9

1

Web アプリケーション

1.1

Web アプリケーションの歴史• Perl による CGI プログラミング→豊富なライブラ
リ/モジュール• Java による Web アプリケーション→サーブレット、JSP。Java による開発ベースは多いのでそこに載せ□ Web ページ→最初は HTML による「動かない」ものるという意味では有利• (アプレットによる Java ブームが来た話は前回紹介)• PHP による Web アプリケーション→より簡便な設定/記述。その後、Ruby や Python など使用される言語• 最初は「せめてどんな文書があるか検索したい」という要求に対処するために isindex 機能というのがは多く作られた□ ブラウザ上で動くスクリプト (クライアント側プログラ• ブラウザの窓の隅に「検索入力蘭」が表れてそこに打ち込んだものがサーバに送られて処理できるミング)• Netscape ブラウザ 2.0 からブラウザ上で動くスクリプトをサポート□ フォームを用いた Web アプリケーション (サーバ側プログラミング)• 当初は「読み込み時に HTML を生成する」ことと「フォーム部品の内容を読み書きする」ことができる程• HTML2.0 でフォーム機能が標準化される→さまざまな形の入力欄が作れるようになった --- 入力欄、パ度→入力のチェック等

スワード入力欄、チェックボックス、ラジオボタン、選択メニュー、テキスト領域、送信ボタン、リセッ
トボタン• Netscape 5/IE 4 くらいから、フォーム部品以外の任意の HTML 要素も自由にいじれるようになってきた→より柔軟な表現が可能に (ユーザインタフェースが自由に操作可能)• スクロールする窓の中に GUI 部品が入っているというのは結構カルチャーショックだった記憶が…

• ただし、あくまでもブラウザ上で実行されるので、サーバ上のデータには手が届かない→用途に限界• 部品に記入するデータの集まり→「フォーム」としてサーバに送信→ CGI(後述) で処理□ Ajax (Asynchronous JavaScript and XML) ---• フォーム記入→送信→サーバ側で処理→結果ページ

サーバ側とクライアント側の連携

返送のサイクル (対話性はあまり高くない)• ユーザインタフェース→クライアントプログラム→□ しかし、サーバ上でコードが実行できるので、(ほぼ) 任サーバ側プログラムを「少しだけ」呼び出す→クラ意のクライアントサーバアプリケーションが可能。しかイアントプログラム→ユーザインタフェースに反映

もブラウザだけあればいいのでインストール不要 (巨大• ページ全体を更新しなくても「部分的に更新」しななメリット) →今日でも主流にがら動作できる→これまでの Web アプリケーション□ サーバ側アプリケーションの道具だて (ツール)…大きの形が大幅に変化

く変遷• 全部イチから組まなくてもよく使う機能がパッケージされたライブラリが複数存在 (prototype.js など)• CGI プログラム…C 言語による開発 (またはシェルスクリプト)□ Web サービス API• 多くのサイトが Web サービス API を公開→これらのAPI は直接ブラウザで使うのではなく、他の Web ア∗ 筑波大学大学院経営システム科学専攻

1

プリから間接的に呼び出して使うことを前提として1.2いる (無償/有償)。もちろん Ajax で使えるものも。

• 各サイトでは、API を呼び出すことで高度な機能をCGI□ CGI (Common Gateway Interface):

Web サーバからサーバ上のプログラムを呼び出す時の「インタフェース」(自分で作らなくても) 提供可能となる→「マッシュアップ」。

• 前回やったように、サーバを全部作るのは大変だし実際的でない→ブラウザとの応答はサーバが行い、必• 複数の API を有機的に組み合わせて役に立つサイト

要ならサーバが「下請けのプログラム」を呼び出すを作り出す可能性

ことで多様な Web アプリを柔軟に実現可能□ フレームワーク• ブラウザ→サーバ→プログラム:「環境変数」によって必要な情報を渡す (加えて method="post"で• Web アプリケーションの道具だてとして「プログラミング言語」と「データベース」を駆使して普通には標準入力からデータが読み込める)。

• プログラム→サーバ→ブラウザ:作るのではなく、予め枠組みを用意しておいて必要標準出力による:先頭に「ヘッダ情報」、続いて「空行」(ヘッダの終な箇所を差し替えることで構築するわりを表す)、その後に任意のデータ。
• ヘッダの種類によってサーバはどういう返値を返すか判断• XML による記述からアプリケーションを生成する (ジェネレータ方式)• Convention over configuration --- Ruby onContent-type: ...
Location: ...
Status: ...

Rail (RoR)。Ruby 言語をつかってドメイン固有言語 (DSL) ふうに記述し、それがそのまま Web アプリ
ケーションとして動作する→ 通常の返送→ リダイレクト→ 状態コードを指定□ 例: sam41.cgi --- 環境変数をそのまま表示 (プレーンテキスト出力)• OR マッピング --- リレーショナルデータベースのリレーション/タプルをオブジェクト指向言語のオブ#!/bin/shecho ’Content-type: text/plain’echo ’’←ヘッダ終わりenv←環境変数表示ジェクトに自動的に対応づけることで、SQL を用いて記述する繁雑さを解消する (本当に解消か?)• Ajax サポート --- 標準的なライブラリを自動的にWeb ページに組み込んで「JavaScript をほとんど書 □ 例:かずに」Ajax を活用←最低限のヘッダ

sam42.cgi --- ヘッダで別ページへ転送#!/bin/shecho ’Location: http://www.yahoo.com’echo ’’□ REST (REpresentational State Transfer)• Web アプリケーションや Web サービスの API はこれ□ 例: sam43.html (前 回 の フォー ム の 例) +まで「こういう指令を渡したらこういう動作」とい
sam34.cgi --- さっき の フォー ム の 結 果 受 け 取 り
う形でできていた→ RPC モデル(環境変数 QUERY STRING で GET のパラメタが受け取• RPC モデルでは、どのような指令が出せてそれがどれる)
ういう風に動作するのかはそれぞれのドキュメントを見ないと分からない<DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><html>• そうではなく、URI →「操作対象」、HTTP リクエスト <head>(GET、POST、DELETE、UPDATE、…) →「操作内容」 <title>Sample</title><style type="text/css">の形で表すのがよいのでは…REST 派の主張
.sheet { background-color: rgb(200,220,240);• この場合、URI がそれなりに対象を表すものとなる。
padding: 5px 10px }ブログなら「http://サーバ/誰/年/月/日」で特定 </style></head>の記事を指定するなど。
<body>• 本当にこういうことがいいのかどうか? 宗教みた <h1>フォームのテスト</h1><form name="f0" method="get" action="sam43.cgi">
い?
<div class="sheet">
名前: <input name="ident" type="text" size="12"><br>性別:
男性<input name="sex" type="radio" value="male" checked>

2

□ 例:

女性<input name="sex" type="radio" value="female"><br>
学年: <select name="grade"><option value="1" selected>1 年生</option><option value="2">2 年生</option><option value="3">3 年生</option></select><br><button name="cmd" value="x">提出</button></div></form></body></html>sam44.php --- 数を出力する<?php
header("Content-type: text/html; charset=euc-jp");?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><html><head><title>php sample</title><style type="text/css">
div.test { margin: 2px 20px; background: rgb(200,215,255) }</style></head><body>#!/bin/sh<?phpecho ’Content-type: text/html; charset=euc-jp’
for($i = 0; $i < 10; ++$i) {echo ’’
echo "<div class=’test’>番号{$i}です。 </div>";
echo ’<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">’ }echo ’<html><head><title>sample</title></head><body>’ ?>echo "<h1>見本</h1><p>$QUERY_STRING</p></body></html>" </body></html>□ しかしちゃんとパラメタを受け取って内部の処理も行い、結果の HTML を出力するのはかなり大変そうですね?

→

□ 解説:

• for 文とかは C や Java と同じ。変数は「＄」をつけ

PHP のようなサポートのありがた味る (シェルと同じ)。echo は PHP の命令で文字列を2

PHP による Web アプリケーション

2.1

PHP 入門出力する。「｛＄ｉ｝」は文字列中に変数の値を埋め込む。
□ 演習:

この例題をコピーして動かせ。動いたら出力の内容を変更して次のようなものを出力させてみよ。

□ PHP (Hypertext Prosessor) --- どこも「PHP」になってないと思うが、初期の名前が「Personal HomePage• 1 から 20 までの数tools」。ともかくプログラミング言語の 1 つ。

• 九九の表• 最大のアイデア:• fizzbuzz 問題 (1 から 100 までの数値を出力するが、ただし 3 の倍数の時は代わりに「fizz」、5 の倍数の「ほとんどは HTML なんだからHTML を書いて、ちょっとプログラムを使いたいとこだけプログラムを埋め込めばいい」

時は代わりに「buzz」、3 と 5 の公倍数の時は代わりに「fizzbuzz」と打ち出せ)。

• 「<?php ……PHP プログラム…… ?>」の中だけプロ
グラムコード• 残りの (外側の) 部分→そのまま出力 (実は PHP のフォームデータの受け取り

2.2

echo 文に翻訳されて実行されるけど一見 HTML がそ□ PHP の利点…豊富な組み込み機能 (多数のモジュールがのままあるように見える)選択可能)• 重要: ヘッダの出力動作は「先頭で」やらないといけない (HTML 本文に入った時はヘッダは終わってい □ HTML からのパラメタの受け取りなども簡単。
ることに注意)• 「$ GET[’名 前’]」「$ POST[’名 前’]」で□ 基本的なカタチ
method="get"、method="post" で 渡 さ れ た パ
ラメタがすぐ利用可能。

<?phpheader("Content-type: text/html; charset=euc-jp");/* その他ヘッダ出力はここで */?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><html><head><title>title...</title><style type="text/css">/* CSS 記述はここに */</style><head><body><?php/* ページ本体出力を含む動作 */?></body></html>□ 例:

sam43.php --- 先のフォームのパラメタを表示。

<?php
header("Content-type: text/html; charset=euc-jp");?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><html><head><title>php sample</title><style type="text/css">p { margin: 2px 20px; background: rgb(200,215,255) }</style></head><body><?php3• それが’clear’ だったら total、data とも 0 のまま

echo ’<p>こんにちは’.$_GET[’ident’].’ さん。</p>’;echo ’<p>性別は’.$_GET[’sex’].’ ですね。</p>’;echo ’<p>学年は’.$_GET[’grade’].’ ですね。</p>’;?></body></html>でよい。

• それが’calc’ だったら total に data を加える。ただし、数値の形をしているときだけ。(ブラウザから来たデータの形は絶対にそのまま信用してはいけな□ 前のようにフォーム (HTML) と処理 (PHP) を分けるといい。) そして total を表示。

まいち。

• 開発しにくい、分けてあるので分かりにくい• いずれにせよ、現在の total は type="hidden"で次回に受け渡す。

• ある結果を表示しつつ次の入力を入れたい。

• 最後にフォーム用意する。

• 次々に URI が移っていくのはやりづらい。
「ある特定□ 演習:の処理」は 1 つの URI で。

http://w3in/~kuno/ist06/sam45.php
http://w3in/~kuno/ist06/sam45b.php• → 1 つの PHP ページで処理+フォーム (初回は処理しないように)。
□ 例:

この PHP プログラムを久野のページで動かせ。

複数人数でバリバリ計算しても干渉しないことを確認す

sam45.php --- 合計の計算ること。別バージョン (sam45b.php) は干渉が起きるこ<?phpとを確認すること。
header("Content-type: text/html; charset=euc-jp");?>□ 演習: この PHP プログラムを自分のところに持って来<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">て動かせ。動くことを確認したら、足し算の他に「引き<html><head><title>php sample</title><style type="text/css">算」もできるように改造してみよ。 (もっと色々できる
div { padding: 10px; background: rgb(200,215,255) }ようにしてもよい。)</style></head><body><h1>合計を求める</h1><form method="get" action="#"><div><?php
2.3 セッション管理$total = 0; $data = 0;if(!isset($_GET[’cmd’])) {□ 先の例題は「アプリケーションに必要な全情報を毎回ブ
echo "<p>値を入れてください</p>";
ラウザとサーバで受け渡す」ことで成立していた。
} else if($_GET[’cmd’] == ’clear’) {echo "<p>クリアしました。</p>";□ データを一部サーバで保管しておこうとすると面倒に…
} else if($_GET[’cmd’] == ’calc’) {if(is_numeric($_GET[’total’])) $total = $_GET[’total’]; • たとえば total をファイルに格納しておくとどうな
if(is_numeric($_GET[’data’])) $total += $_GET[’data’];るか? (もちろん、これだけのデータならそんな必echo "<p>現在までの合計は{$total}です。</p>";} else {要はないが、もっと大量のデータがある場合など)
echo "<p>処理内容が不明です。</p>";}□ たとえば、先程の別バージョン…実は現在データをファ
echo "<input type=’hidden’ name=’total’ value=’{$total}’>";
イルに格納していた。そのため「総計」が 1 個しかなく?>干渉が起きる。
<input name="data" type="text" size="6"><button name="cmd" value="calc">計算</button><?php<button name="cmd" value="clear">クリア</button>
header("Content-type: text/html; charset=euc-jp");</div></form></body></html>?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">□ 解説:<html><head><title>php sample</title><style type="text/css">• 提出されてくるデータは total、data の 2 つ (プラdiv { padding: 10px; background: rgb(200,215,255) }ス cmd…後述)。これらに対応して PHP 側でも変数を </style></head><body><h1>合計を求める</h1>用意。初期値は 0。
<form method="get" action="#"><div>• isset() はそのデータがあるかどうか。なければ初 <?php$total = 0; $data = 0;
回のはず→単にメッセージを表示
if($fp = fopen(’data.txt’, ’r’)) {• cmd は押したボタンに応じた value の値が入って来$total = fgets($fp); fclose($fp);}
る。

4• コンピュータ業界では「ちょっとした情報」程度のif(!isset($_GET[’cmd’])) {echo "<p>値を入れてください</p>";意味} else if($_GET[’cmd’] == ’clear’) {• サーバからブラウザに Set-Cookie:ヘッダで情報をecho "<p>クリアしました。</p>"; $total = 0;
} else if($_GET[’cmd’] == ’calc’) {送るif(is_numeric($_GET[’total’])) $total = $_GET[’total’];if(is_numeric($_GET[’data’])) $total += $_GET[’data’]; • ブラウザがそれを記憶しておく
echo "<p>現在までの合計は{$total}です。</p>";• 同じサーバ/ディレクトリのリクエストでブラウザか} else {らサーバに Cookie:ヘッダで同じ情報を返送する
echo "<p>処理内容が不明です。</p>";}□ 3 つの方法の得失…
if($fp = fopen(’data.txt’, ’w’)) {fputs($fp, $total); fclose($fp);• type=hidden は全部のページに form がないといけ}?>ない<input name="data" type="text" size="6">• 「?」の後ろにくっつける方法はそれがブラウザの画<button name="cmd" value="calc">計算</button><button name="cmd" value="clear">クリア</button>
面で見える (うるさい?)</div></form></body></html>• クッキーは表だって見えない (ただしユーザの閲覧履歴を調査したり、さまざまな用途で使われるので□ 解説:嫌われることがある→ OFF にする人も)• fopen()、fgets()、fputs()、fclose() でファイ□ 重要なポイント:「ユーザ ID」などを直接セッション ID
ルのデータを読み書き。
として使ってはいけない• ファイルは Web サーバのユーザに読み書きできるようにしておく必要• ユーザ ID は「固定されている」→「他人が推測可
echo ’0’ >data.txt; chmod go+rw data.txt□ ファイルに書くのはいまいちか?

能」→自分が使用中に他人がその同じセッション ID

全部 hidden で受けを使ってサーバに接続可能→「自分のセッションの渡す?

やりとり」を途中から他人がやってしまうこと (セッションハイジャック) が可能に。

• ネット上に流せない機密データだと必ずサーバ上に• 乱数の ID であれば推測は困難。ネットを監視してい保管しなければならない。→ どうすればいい?
□ 答え:

ればその ID が行き来すること自体は観測可能だが、それぞれのユーザに対して「セッション ID」をSSL のように盗聴できないトランスポート上で使え割り当てる。

ばまず問題ない。

• セッション ID は外部から推測されにくいように乱数 □ PHP のセッション機能などで生成。
• 上記のように面倒なことがいろいろあるが、PHP で• 「総計」などの個別データはセッション ID と対で保は冒頭で session start() という関数を呼ぶだけで管する。
自動的にセッション追跡を行ってくれる• 割り当てたセッション ID をサーバ→ブラウザに送信• セッション機能が ON のときは配列「$ SESSION」にし、次にページデータが送信されるときにブラウザ入れたデータは同じセッションの中ではずっと維持→サーバに返送してもらうされる (これに格納したデータはずっと持っておい• 返送された ID を見れば「誰の作業の続き」かが分てもらえる)。
かる□ sam41.php:先の「合計」を PHP のセッション機能を使っ□ 具体的な送信/返送メカニズム…て書き直したもの• (1) type=hidden に入れて受け渡す<?phpsession_start();header("Content-type: text/html; charset=euc-jp");?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><html><head><title>php sample</title>• (2) URL の末尾に「?」に続けて ID 情報をつける• (3) クッキー情報に入れる□ クッキーとは?

5select 欄名,… from テーブル
where 条件 and 条件 and … ;<style type="text/css">
div { padding: 10px; background: rgb(200,215,255) }</style></head><body><h1>合計を求める</h1><form method="get" action="#"><div><?php
if(!isset($_GET[’cmd’])) {echo "<p>値を入れてください</p>";} else if($_GET[’cmd’] == ’clear’) {echo "<p>クリアしました。</p>";$_SESSION[’total’] = 0;
} else if($_GET[’cmd’] == ’calc’) {if(is_numeric($_GET[’data’]))$_SESSION[’total’] += $_GET[’data’];echo "<p>現在までの合計は".
$_SESSION[’total’]."です。 </p>";} else {echo "<p>処理内容が不明です。</p>";}?><input name="data" type="text" size="6"><button name="cmd" value="calc">計算</button><button name="cmd" value="clear">クリア</button></div></form></body></html>

覚えましたか :-)。なお、沢山でてきて欲しくないときは「;」の直前に「limit 個数」というのを入れておくと最大その個数で止まります。
□ 次に、PostgreSQL のインタプリタを起動します。
psql -d kuno ←とりあえず久野の% \d 書籍←今回は「書籍」のみ
Table "public. 書籍"
Column |Type| Modifiers----------+-----------------------+----------isbn| character(10)| not null
題名
| character varying(50) |著者| character varying(30) |出版社| character varying(20) |発行年月 | character(5)|価格| integer|
種別| character(4)|順位| integer|
Indexes: "書籍_pkey" PRIMARY KEY, btree (isbn)% select 題名 from 書籍 where 価格 > 2000 ;題名-----------------------------------------シニアマーケットに学ぶ資産運用アドバイス
アメリカの高校生が学ぶ経済学
Winny の技術(3 rows)% \q ← psql を終わる

□ 解説:

• 冒頭で session start() を呼ぶ (ヘッダと一緒の場所に入れる必要がある)• 以後$total の代わりに$ SESSION[’total’] を使うようにするだけ。この配列の内容は PHP 処理系に

□ このように、select 文だけ分かっていれば一応なんでよってずっと維持してもらえる (サーバが止まったらも検索はできるようになるわけです (ほんとか?)無くなるがそれまでは OK)。

□ 演習:

□ 演習:

• マシン「smb」で上記の psql コマンドを使って書籍データベースの内容をしばらく眺めてみよ。

• このプログラムをコピーして来て「電卓」にせよ。
• 動いたら「メモリ機能」をつけてみよ。具体的には「メモリ記憶」ボタンを押すと現在の総計がメモリに入る。

4「メモリ呼び出し」ボタンを押すと入力値のところにそのメモリの値が入る。(ヒント:

それには「<inputPHP と PostgreSQL の接続□ PHP からは簡単に各種の DBMS に接続してデータベース

name="data" type="text" value="入 れ た い 値"
size="6">」のように value で値を指定すればよの検索や更新が可能。
□ PostgreSQL の場合も次の 5 つの関数だけ知っておけばい。)よい。

3• $conn = pg connect(指定文字列) --- DBMS に接PostgreSQL による検索

続• $res = pg query($conn, SQL 文 の 文 字 列) ---□ この後、データベースから情報を取り出して来るのをやSQL を実行する

るので、最低限の SQL select 構文と PostgreSQL(Unix上のフリー DBMS) による演習をやります (データベース• $num = pg num rows($res) --- 結 果 の 列 数 を 返すとは何か等はすべて略)□ 覚えていただく構文はこれだけ:• $arr = pg fetch row($res) --- 結果の 1 列を配列として返す6• $str = pg escape string(文字列) --- 文字列を □ HTML のテーブルに使うタグは次のもの
安全にエスケープする• <table>...</table> --- テーブル要素□ 最後のはなぜ必要かというと、SQL Injection (ユーザ• <tbody>...</tbody> --- テーブル本体

データの中に SQL の命令を埋め込むことによってデー• <tr>...</tr> --- 本体中の 1 行タベースを勝手に操作するという攻撃) に対する防御の• <th>...</th>、<td>...</td> --- 1 行中の 1 セルため。
□ 簡単な例題:□ 演習:

書籍データを書名で検索<?phpheader("Content-type: text/html; charset=euc-jp");?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><html><head><title>php sample</title><style type="text/css">
div.test { padding: 4px; background: rgb(255,215,200) }td { margin: 2px 4px; padding:4px; background: rgb(200,215,255) }</style></head><body><form method="post" action="#"><div class="test"><p>検索語:<input type=’text’ name=’word’><button name="cmd" value="calc">検索</button><?phpif($_POST[’word’] == ’’) {echo "<p>検索キーワードを入れてください。</p>";} else if(!($conn = pg_connect("dbname=kuno"))) {echo "<p>データベース接続できません。</p>";} else {$word = pg_escape_string($_POST[’word’]);$res = pg_query($conn,"select isbn, 題名, 著者 from 書籍"." where 題名 like ’%".$word."%’");
if(pg_num_rows($res) > 0) {echo "<table><tbody><tr><th>ISBN</th>"."<th>題名</th><th>著者</th></tr>\n";while($a = pg_fetch_row($res)) {echo "<tr><td>{$a[0]}</td><td>{$a[1]}"."</td><td>{$a[2]}</td></tr>\n";}echo "</tbody></table>";} else {echo "<p>検索結果が空でした。</p>";}}?></div></form></body></html></div></form></body></html>□ 解説:• フォームは検索語と検索ボタンだけ• 検索語があればデータベースに接続し、「select ...
where 題名 like ’%xxx%’」で検索。パーセントはSQL の like で任意文字列にマッチさせられる。
• 結果を HTML のテーブルに加工して表示。
• なお「.」は文字列の連結演算 (長い文字列を行を分けて書くのに使用)

7• この PHP プログラムをコピーしてきて動かせ。
• もっと「さまざまな」検索ができるように改良してみよ。