このページでは、共通処理の一元化について説明します。
ここまでの実習で、htmlentities()関数のショートカット関数he()を作成したり、データベース接続を行う処理を記述したりしました。
この2点の処理は、様々なプログラムで利用することになります。
そこで、共通処理を切り出したファイルにまとめて、開発効率を上げていく工夫をします。
共通処理として考えられるもの
まずは共通処理として考えられる要素について挙げていきましょう。
he関数
htmlentities()のショートカットとしてよく使うことになります。
この関数の定義をプログラムごとに記述するのは無駄ですので、一元化しましょう。
データベースの接続を行う記述
通常のアプリケーションでは、ほぼ全機能でデータベースアクセスを行うことになります。
データベース接続関連の記述を一元化しましょう。
共通処理が分散していることでのデメリット
既存の、共通化できる記述が分散している状況で開発を進めていくと、どのようなデメリットに直面するか考えてみましょう。
修正が大変で、修正漏れが発生しやすい
he関数が全ページの上部に書かれていると、he関数の動作を修正したいときなどに、非常に不便です。
また、修正する際に、修正漏れが発生しやすくなります。
『同じコードを複数書かない』というつもりで、一元化を目指していきましょう。
ソースコードの可読性が落ちる
過去に書いたソースコードや、他人の書いたソースコードを読み解くのは大変なことです。
同じ記述が散らばっていると、ひとつひとつを目視していかないといけません。(そして、結局、あれとこれは同じことが書いてあるじゃないか! と気づくことになりますね)
同じ目的のコードを一元化することで、ソースコードを読み解く労力が減り、メンテナンスしやすくなります。
共通処理を切り出す
それでは共通処理の切り出しを行います。
systemディレクトリ作成
まずは、アプリケーションのルートディレクトリ(つまりindex.phpなどと同じ階層)の中に、『system』というディレクトリを作成してください。
ここに、共通で使用するファイルを設置していきます。
systemディレクトリを開いたら、.htaccessというファイルを作成します。
.htaccessというのは、Webサーバであるapacheで使用する、設定を上書きするためのファイルです。
.htaccessファイルを設置することで、該当ディレクトリ(今回はsystem)のアクセス権限などを変更できます。
.htaccessは、通常のWindowsエクスプローラーでは作成できません。(ファイル名が不正だとして、エラーが表示されます)
そこで、以下の手順で作成します。
- エクスプローラー上で「a.htaccess」を作成
- テキストエディタで「a.htaccess」を開く
- 「別名で保存」などの操作で、「.htaccess」として保存
ついでに、「.htaccess」という拡張子のファイルを開く規定のプログラムとして、任意のテキストエディタを指定しておくと便利です。
作成した.htaccessを開いたら、以下のように修正します。
deny from all
上記の記述により、Web上からのアクセスを全部シャットアウトできます。
(systemには共通ライブラリや隠しておくべきファイルを設置するからです。本当はsystemディレクトリ自体を非公開領域に設置するのがいいのですが、今回の説明上、やむを得ずこうしています)
共通処理を記述したファイルを設置
systemディレクトリに以下のファイルを作成します。
common.php
共通処理を束ねるプログラム。
config.php
システムの設定を記載しておくプログラム。
データベース設定など、環境によって値が変わるような変数を定義します。
lib.php
共通で使用する関数などを定義しておくプログラム。
内容は以下のようにします。
<?php // 関連ファイルをロード require_once "config.php"; require_once "lib.php"; // データベース接続を確立 try { $db = new PDO("mysql:host={$db_host};dbname={$db_name};charset=utf8", $db_user, $db_user); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // エラーモードの設定 $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // prepareのエミュレーションを停止 } catch (PDOException $e) { // エラー発生時 exit("データベースの接続に失敗しました"); }
<?php // 設定値定義 $db_host = "localhost"; // データベースのホスト $db_name = "app1"; // データベースの名前 $db_user = "app1"; // データベース接続ユーザー $db_pass = "xxxxxx"; // データベース接続パスワード
<?php // htmlentitiesのショートカット関数 function he($str){ return htmlentities($str, ENT_QUOTES, "UTF-8"); } // ホワイトリストによる変数抽出 function whitelist($list){ $request = array(); // 配列の初期化 foreach ($list as $word) { // $whitelistの中身を繰り返し $request[$word] = null; // nullという空白値を初期値にする if (isset($_REQUEST[$word])) { // 送信されてきた値の存在確認 $word = str_replace("\0", "", $word); // ヌルバイト除去 $request[$word] = $_REQUEST[$word]; // 明示された変数のみ$requestに格納 } } return $request; }
※上記には、he関数に加え、ホワイトリスト編集を作成する関数「whitelist」を記載しました。
systemディレクトリの内部は、以下のようになります。
既存のプログラムを修正
共通処理を定義しておいたので、既存のプログラムの共通処理を削除し、かつ「common.php」を全プログラムから呼び出すようにします。
それぞれ、以下のように修正します。
<?php require_once "system/common.php";?> <?php $page_title = "トップページ";?> <?php require "header.php";?> <p> 閲覧ありがとうございます。<br> こちらはxxxの日記ページです。 </p> <h2>メニュー</h2> <ul> <li> <a href="blog.php">ブログ</a> </li> <li> <a href="inquiry.php">お問い合わせ</a> </li> </ul> <?php require "footer.php";?>
<?php require_once "system/common.php";?> <?php // ホワイトリスト変数の作成 $whitelist = array("send", "uname", "email", "body"); $request = whitelist($whitelist); $page_message = ""; // ページに表示するメッセージ $page_error = ""; // エラーメッセージ // エラーチェック if (isset($request["send"])) { if ($request["email"] == "") { $page_error = "メールアドレスを入力してください\n"; } if ($page_error == "") { if (!preg_match('/^([a-zA-Z0-9\.\_\-\+\?\#\&\%])*@([a-zA-Z0-9\_\-])+([a-zA-Z0-9\.\_\-]+)+$/', $request["email"])) { $page_error = "メールアドレスを正しく入力してください\n"; } } } // 送信実行 if (isset($request["send"]) && $page_error == "") { // 初期設定 mb_language("japanese"); // メール送信の際のおまじない mb_internal_encoding("UTF-8"); // メール送信の際のおまじない // 送信本文の作成 $mail_body = ""; if (isset($request["uname"])) { $mail_body .= "[お名前]\n"; $mail_body .= "{$request["uname"]}\n"; } if (isset($request["email"])) { $mail_body .= "[メールアドレス]\n"; $mail_body .= "{$request["email"]}\n"; } if (isset($request["body"])) { $mail_body .= "[お問い合わせ内容]\n"; $mail_body .= "{$request["body"]}\n"; } // 送信実行 $subject = "お問い合わせがありました"; $admin_email = "you@example.com"; // あなたのメールアドレスを入力してください $add_header = "From:" . $admin_email; $result = mb_send_mail($admin_email, $subject, $mail_body, $add_header); // 完了 $page_message = $request["uname"] . "さん、送信ありがとうございました!"; } ?> <?php $page_title = "お問い合わせ";?> <?php require "header.php";?> <p> <?php echo he($page_message); ?> </p> <p class="attention"> <?php echo he($page_error); ?> </p> <p> お問い合わせは以下よりお願いします </p> <form action="inquiry.php" method="post"> <div> お名前<br> <input type="text" name="uname" size="30" value="<?php echo he($request["uname"]); ?>"> </div> <div> メールアドレス <span class="attention">[必須]</span><br> <input type="text" name="email" size="30" value="<?php echo he($request["email"]); ?>"> </div> <div> お問い合わせ内容<br> <textarea name="body" rows="5" cols="20"><?php echo he($request["body"]); ?></textarea> </div> <div> <input type="submit" name="send" value="送信する"> </div> </form> <?php require "footer.php";?>
<?php require_once "system/common.php";?> <?php // データの問い合わせ $rows_post = array(); // 配列の初期化 try { $stmt = $db->prepare("SELECT * FROM posts ORDER BY post_created DESC"); $stmt->execute(); // クエリの実行 $rows_post = $stmt->fetchAll(); // SELECT結果を二次元配列に格納 } catch (PDOException $e) { // エラー発生時 exit("クエリの実行に失敗しました"); } ?> <?php $page_title = "ブログ";?> <?php require "header.php";?> <?php foreach ($rows_post as $row_post) {;?> <article> <h2> <?php echo he($row_post["post_title"]);?> </h2> <time> <?php echo he($row_post["post_created"]);?> </time> <p> <?php echo nl2br(he($row_post["post_content"]));?> </p> </article> <?php }?> <?php require "footer.php";?>
これで、共通ロジックの一元化が完了しました。
ここまでのコンテンツは、以下よりダウンロードできます。
データベースのパスワードなどは、適宜修正ください。