Ⅵ. Webアプリケーションの開発①

 先に構築した「日本の世界遺産」データベースを検索して、結果を表示するWebアプリケーションを作成します。この事例には、検索型Webアプリケーション開発の要点が詰め込まれています。開発の過程を通して、HTML5, CSS3, JavaScript, PHP, MySQLがどんな機能を分担しどのように動作するかを、しっかり把握してください。
 この章ではアプリケーションの開発方針と全体構成を明らかにして、CSSによる画面のデザインを行い、データベース操作ライブラリを作成します。

1.開発の基本方針

 規模の大きいWebアプリケーションの開発では、しばしば統合開発環境とかフレームワークといった開発ツールが使われます。複数のメンバーで大がかりなシステムを開発する場合は、各人のコードの記述がバラバラになるのを防いだり、コードの再利用を図るために有効なツールです。
 しかしこれを利用することで、複雑なWebアプリケーションの仕組みや動作が抽象化(あるいは隠蔽)されることから、全体像を細部にわたって把握することは難しくなります。
 冒頭に掲げたように、ここでは開発を通してHTML5, CSS3, JavaScript, PHP, MySQLがどんな機能を分担しどのように動作するかを理解することが目的なので、最も原始的な方法で開発することにします。また、不特定多数の利用者を対象とする場合に考慮すべきブラウザの違い等については、コードを判りにくくすることを避けるため除外します。
 これらのことから、開発に先だって以下の基本方針を設定することにします。

①開発はテキストエディターだけで行う

 すべてのファイルはテキストの記述だけで作成します。使い慣れたテキストエディターを準備してください。構成ファイルの中でテキストでないものは、背景画面に貼り付けるGIFファイルが唯一の例外です。


②それぞれの言語が装備している基本機能だけを利用する

 画面デザインも通信制御も特別なAPIや外付けのモジュールは利用しません。


③PHPのMySQL操作用の関数はラップする

 データベースの操作は、MySQLを意識させないシンプルなラップ関数を作成して、これをすべてのデータベース操作で共用メソッドとして使用します。


④セキュリティ対策は行わない

 SQLインジェクション対策を考えると、キー入力や更新を伴わない場合も、慣習としてSQL文に入力項目は直接連結しないほうがいいのですが、ここでは考慮しません。


⑤HTML5とCSS3に未対応のブラウザへの対策はしない

 Webアプリケーションを広く公開する場合はこれらの対策が必要ですが、ここでは考慮しません。


2.アプリケーション全体の構成

 アプリケーションは検索ページ「index.html」と結果表示ページ「result.html」から成り立っています。
 大きな流れは、検索ページの検索ボタンをクリックすることで、検索条件をクッキーに保存して結果表示ページを呼びます。これはJavaScriptで記述されたindex.jsの役割です。
 呼ばれた結果表示ページは、クッキーから検索条件を取り出してSQL文を組み立て、データベースの検索を実行します。データベースに接続してSQL文を実行させ結果を取得するのは、PHPで記述したmysqlmdl.phpの役割です。検索結果を取得して表形式に編集した結果でHTMLを生成し、ブラウザに書き出すことで結果一覧を表示させます。
 検索ページにはタブフォルダーを設置しますが、どのタブが選択されているかは、検索ページ内の隠しフィールドcurrent_tabに保持させます。タブフォルダーも検索結果の一覧表も、デザインはすべてCSSで記述します。

 次に、Raspberry Piサーバー上に配置するフォルダーと、格納するファイルの関係をまとめておきます。ドキュメントルート配下に今回開発するWebアプリケーション用のフォルダーWorldHeritageを作成し、2つのページのHTMLはここに格納します。その配下に4つのフォルダーを作成して、それぞれ図のようなファイルを格納します。

 後で見るように、HTML内でファイルを参照する場合はURL形式のパス(URIとも言います)を指定します。この時に気をつけるのは、HTMLの場所からの相対パスを指定することです。例えば、mysqlmdl.phpは「inc/mysqlmdl.php」、または「./inc/mysqlmdl.php」のように指定します。このようにしておくことで、将来WorldHeritageを別のフォルダーの配下に移動させるようなことになっても、何ら影響を受けません。上位のフォルダーの関連を厳密に絶対パスで指定してしまうと、煩わしい修正を迫られることになります。

3.CSSを使ってWebページをデザインする

(1)共用CSS

 両方のページに共通な2つのCSSがあります。reset.cssは「リセットCSS」と呼ばれるもので、Webブラウザそれぞれが持っているデフォルトのCSSを一度リセットするものです。出所は忘れましたが、ネットで公開されているたくさんのファイルから入手したものです。
 もうひとつのcommon.cssでは、ページ全体のデザインを記述しています。
@charset "UTF-8";
/*
 * common.css : ページ全体のデザイン
 */
body {
	background: url(../img/wallpaper.gif);
}

h1 {
	color: #aa0000;
	font-size: 24px;
	width: 80%;
	position: absolute;
	top: 20px;
	left: 60px;
	text-align: left;
}
 5行目ではセレクタに<body>タグを記述して、続く6行目でbodyの背景に貼り付けるgifファイルを指定しています。なお、ここで使用するimgフォルダーに収納した画像ファイルは、『Webデザイナーが作った超シンプル素材集』の背景画像を利用させていただきました。
 9行目では<h1>タグで表示する文字のフォントサイズや位置、長さなどを規定しています。これで、2つのページに共通したデザインが出来上がりました。
 これらのスタイルシートは慣習的にcssフォルダーに格納します。


(2)検索ページのデザイン

 検索ページには、検索項目別のタブがついたタブフォルダーを設置することにします。検索項目は次の4種類です。
   ・都道府県
   ・登録年度
   ・構成遺産内訳
   ・遺産分類
 これらを、次のようなタブフォルダーに割り付けることにして、具体的なデザインを考えてみましょう。


 タブフォルダーは見出しの部分とタブページで構成します。HTML内でのタブフォルダーについての記述は、ブロック要素<div>をネストさせることにして、あらかじめ次のようなブロック構成を考えておきます。タブフォルダー全体をtabboxクラスとし、タブ見出しのグループにtabs、個々のタブページはtabというクラスを設定していることに注意してください。
<div class="tabbox"> <p class="tabs">
  4つのタブ見出しに対応したイベントを記述
</p> <div id="tab1" class="tab">
  タブページtab1に配置するパーツ等の記述
</div>
    :     :
<div id="tab4" class="tab">
  タブページtab4に配置するパーツ等の記述
</div>

 このブロック構成をもとに、検索ページのスタイルシート「index.css」を記述します。6行目のセレクタでは、外側のdivブロックのtabboxクラス、つまりdiv.tabboxでタブ見出しのスタイルを決め、15行目でpタグのtabsクラスp.tabsで見出しの高さを、20行目のアンカータグで形状や影などを指定します。31行目からの4行では、4つのタブ見出しそれぞれのカラーを指定しています。
@charset "UTF-8";

/*
 * index.css : タブフォルダーとタブページのデザイン
 */
div.tabbox {
	margin: 0px;
	padding: 0px;
	width: 500px;
	height: 100px;
	padding-top: 60px;
	padding-left:60px;
}

p.tabs {
	margin: 0px;
	padding: 0px;
	height: 15px;
}
p.tabs a {
	display: block; float: left;
	margin: 0px 1px 0px 0px;
	padding: 4px;
	width: 100px;
	text-align: center;
	color: #0000bb;
	box-shadow: 2px 0px 0px rgba(0, 0, 0, 0.5);
	border-radius: 10px 10px 0 0;
	text-decoration: none;
}
p.tabs a.tab1 { background-color: #ffffdd; }
p.tabs a.tab2 { background-color: #ddffff; }
p.tabs a.tab3 { background-color: #ffddff; }
p.tabs a.tab4 { background-color: #ccffcc; }

/* タブ・ページ */
div.tab {
	padding: 20px 40px;
	height: 230px;
	overflow: auto; clear: left;
	border-radius: 0 10px 10px;
	box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.5);
}
div#tab1 { background-color: #ffffdd; }
div#tab2 { background-color: #ddffff; }
div#tab3 { background-color: #ffddff; }
div#tab4 { background-color: #ccffcc; }
 次にタブページの指定です。37行目では、内側のdivブロック要素のtabクラスを指定して、メッセージの表示位置やページの高さなどのスタイルを記述します。続く44行目からの4行では、タブ見出しと同じ背景色を指定しています。


(3)結果表示ページのデザイン

 検索結果を一覧表に編集する場合のデザインを、スタイルシートresult.cssに記述します。
 まずHTMLの大まかな構成を考えてみましょう。id名contentsとクラスresultTableに注目してください。
<body> <section id="contents"> <section class="resultTable">
    検索結果から<table><thead><tr><th>~</th>・・・・</tr></head>          <tbody><tr><td>~</td>・・・・</tr>・・・・</tbody></table>     のようなHTML文を生成する
</section> </section>
    :     :

 スタイルシートの6行目ではid名contentsの表示位置を決め、11行目でresultTableクラスの上下左右のマージンを設定しています。15行目では<table>タグで表示するテーブルの表示幅や行高、背景色を設定、それに続いてth,tdタグなどのスタイルを記述しています。
 最後の32行目では、テーブルの先頭項目の表示幅と表示位置を指定しています。
@charset "UTF-8";

/*
 * result.css: 検索結果テーブルのデザイン
 */
#contents {
	padding: 2px;
	padding-left: 40px;
}

.resultTable {
	padding: 5px 20px 20px;
}

.resultTable table {
	width: 600px;
	line-height: 1.0;
	background: #fff;
}
.resultTable th,
.resultTable td {
	padding: 5px 10px;
	border: 1px solid #ccc;
}
.resultTable thead th {
	padding: 10px;
	background: #f6f6f6;
	color: #666;
	white-space: nowrap;
}

table td:nth-child(1) { text-align: center; width: 20px; }


4.データベース操作メソッドをライブラリ化する

 PHPにはMySQLを操作するための関数やメソッドが3種類用意されています。古くはmysql、そしてmysqiとPDO_MySQLです。ポピュラーだったmysqlはPHP5.5版で非推奨となり、PHP7では削除されました。もし多数のHTMLファイル内でこれらの関数を直書きしていたら、それらを個々に新たな関数やメソッドに修正してテストすることが必要になります。また、MySQLから他のデータベース管理システムに移行する場合も、同様の問題が発生します。
 ところで、以降の説明では関数とかメソッドという用語が登場しますが、どちらも特定の機能を実行する小さなプログラム部品と考えてください。実際は両者には大きな違いがあるのですが、当面の話の進行には差し支えないと思います。
 関数は、それが関数であることを表すfunction文に続けて、プログラム部品名、つまり関数名を書きます。関数名に続いてカッコを書き、カッコ内には関数に引き渡す複数の変数をカンマで区切って指定します。この変数は引数(ひきすう)と呼びます。引数が不要な場合はカッコだけを書きます。関数はこうして渡された変数を使用して処理を行い、一般的には結果をreturn文に続く変数名で外部に連絡します。関数の処理コードは、引数のカッコに続く中括弧"{"から"}"の間に記述します。関数それ自体は何もできませんが、主処理から呼び出されることで動作し、結果を呼び出し元に返すことができるのです。
 なおラップ関数とは、すでに存在している関数やメソッドを、使いやすいようにする目的で別の関数名で包む、つまりラップして提供するものです。
 前置きが長くなりましたが、先のような問題を解決するために、データベースの基本操作に分かりやすい名前を付けて、データベース管理システム固有の関数やメソッドをラップする方法を考えます。ラップするということは、処理上は余分なオーバーヘッドを増加させることになりますが、通常はほとんど問題ありません。むしろこうしてライブラリ化しておくことで、他のデータベース管理システムに移行する場合はライブラリ内だけを修正すればいいので、修正やテストの手間を極小化できるメリットは大きいと言えるでしょう。

<?php
	/*
	 * データベース利用情報の指定
	 */
	$targ_db = "world_heritage";	//データベース名
	$user_id = "*****";				//利用者ID
	$user_pwd= "********";			//パスワード

	ini_set('display_errors', 0);	//PHP実行時のエラー出力を抑制する

	/*
	 * MySQL Wrapper関数
	 */
	//データベースを開く
	function openDatabase($db, $uid, $pwd) {
		$con = new mysqli("localhost", $uid, $pwd, $db);
		if ($con->connect_error) {
			echo "データベース接続に失敗しました .... " . mysqli_connect_error();
			return null;
		}
		else
			return $con;
	}

	//クエリーを実行する
	function execQuery($con, $sql) {
		$rs = $con->query($sql);
		return $rs;
	}

	//結果セットを取得する
	function getResultSet($rs) {
		$row = $rs->fetch_assoc();
		return $row;
	}

	//データベースを閉じる
	function closeDatabase($con) {
		$con->close();
	}
?>
 5~7行には、便宜的に利用情報を列記しています。
 9行目は、データベース接続などでエラーが発生した場合に、システムが割り込んで難解なエラーメッセージを表示するのを防ぐための記述です。php.iniの設定などで対応している場合は不要です。
 今回のために準備したメソッドは次の通りです。
  ①openDatabase(データベース名, ユーザーID, パスワード)
    引数で指定したデータベースに接続して接続オブジェクトを返却します。
    接続できないとエラーメッセージを表示してNULLを返却します。
  ②executeQuery(接続オブジェクト, SQL文)
    接続先のデータベースに対して、指定したSQL文を実行して結果オブジェクトを返却します。
    実行に失敗するとNULLを返却します。
  ③getResultSet(結果オブジェクト)
    結果オブジェクトの行、つまりレコードを、文字列の連想配列として返却します。
    結果セットにもうレコードが存在しない場合はNULLを返却します。
  ④closeDatabase(接続オブジェクト)
    接続先のデータベースを閉じて資源を開放します。

 HTMLの先頭部分にmysqlmdl.phpを組み込むことによって、これらのメソッドでデータベースを操作することができるようにます。なお、ここではmysqliを利用してコードを記述しています。具体的な使用例は次章のコードを参考にしてください。
 作成したファイルはmysqlmdl.phpの名前でincフォルダーに格納しておきましょう。