掲示板プログラム全体で使うユーザー定義関数をまとめたファイルです。
<?php #指定した掲示板を変数に入れる function target_set() { if(isset($_GET['target'])) { $bbs_target = $_GET['target']; #対象の掲示板 } elseif(isset($_POST['target'])) { $bbs_target = $_POST['target']; } else { header("Location: ./index.php"); #対象掲示板が指定されていなければindexに転送 exit(); } $log_list = loglist(1); if(!in_array($bbs_target, $log_list)) { #対象掲示板がデータベース上になければindexに転送 header("Location: ./index.php"); exit(); } return($bbs_target); } #mysqlに保存されているmainを除くスレッドのリストを作る function loglist($enable_main = 0, $remove_array = array(NULL)) { #グローバルにする変数 global $db; if($enable_main == 1) { $tables[0] = 'main'; } else { $tables = array(); } $result = $db->query('SELECT id,table_name FROM access ORDER BY id'); while($tmp = $result->fetch()) { if(in_array($tmp[0], $remove_array)) { continue; } $tables[$tmp['id']] = $tmp['table_name']; } return($tables); } #mysqlに保存されているスレッドの説明名をリストにする function bbslist($enable_main = 0, $remove_array = array(NULL)) { #グローバルにする変数 global $db; $result = $db->query('SELECT id,table_name,bbs_name FROM access ORDER BY id'); if($enable_main == 1) { $tables[0] = array('main' => 'main'); } else { $tables = array(); } while($tmp = $result->fetch()) { if(in_array($tmp[0], $remove_array)) { continue; } $tables[$tmp['id']] = array($tmp['table_name'] => $tmp['bbs_name']); } return($tables); } #指定された登録スレッド名から説明スレッド名を取得 function enname2janame($target_bbs) { #グローバルにする変数 global $db; if($target_bbs == 'main') { return 'main'; } $result = $db->query("SELECT bbs_name FROM access WHERE table_name='${target_bbs}'"); $tmp = $result->fetch(); return $tmp[0]; } #ランダム文字列生成 function rand_strings($str_len = 12) { $result = NULL; #生成する文字列の長さを指定 $str_len #この文字列からランダムに文字を抜き出す $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; for($i = 0; $i < $str_len; $i++){ #変数に入った文字列からランダムに1文字を抜き出して「$result」に追記 $result .= $chars{mt_rand(0, strlen($chars)-1)}; } return($result); } #ユーザーID取得 function get_userid($target_user = NULL) { #グローバルにする変数 global $db; #値の確認 if($target_user == NULL) { return array(FALSE, "ユーザー名を指定してください。"); } #ユーザーIDを取得 $stmt = $db->prepare('SELECT id FROM auth WHERE username=:target_user'); $stmt->bindParam(':target_user', $target_user); $flag = $stmt->execute(); if (!$flag) { $info = $stmt->errorInfo(); return array(FALSE, $info[2].$target_user."のIDを取得できませんでした。"); } $row = $stmt->fetch(); return array(TRUE, $row[0]); } #指定されたユーザー名のアクセス権を取得 function get_usermod($target_user = NULL, $target_table = NULL) { #グローバルにする変数 global $db; #値の確認 if($target_user == NULL) { return array(FALSE, "ユーザー名を指定してください。"); } if($target_table == NULL) { return array(FALSE, "スレッド名を指定してください。"); } $get_userid_result = get_userid($target_user); if($get_userid_result[0]) { $target_userid = $get_userid_result[1]; } else { return array(FALSE, $get_userid_result[1]."\n"); } #アクセス権を取得 $stmt = $db->prepare("SELECT `${target_userid}` FROM access WHERE table_name=:target_table"); $stmt->bindParam(':target_table', $target_table); $flag = $stmt->execute(); if (!$flag) { $info = $stmt->errorInfo(); return array(FALSE, $info[2].$target_user."について正常にデータベースから取得できませんでした。(get_usermod)\n"); } $row = $stmt->fetch(); return array(TRUE, $row[$target_userid]); } ?>
ユーザー名、スレッドの英語名・日本語名、表示対象スレッド名の取得などをするユーザー定義関数(サブルーチン)を一つのファイルにまとめたものです。それぞれのファイルに直接書くより1ヶ所にまとめたほうが管理・修正がしやすいという利点があります。
では解説を。
target_set (2~20行目)
引数: なし、戻り値: 対象スレッドの英語名
対象スレッドをPOST/GETから取得し、スレッド名がデータベースに登録されていなければスレッド入場ページであるindex.phpに転送する。
4~11行目
HTTPのPOSTもしくはGETで送信される対象スレッド名を変数$bbs_targetに代入します。POSTとGET両方から送信されている場合、GETで送信されたほうを優先して取り込みます。
POST/GETどちらにもデータがなかった場合、indexに転送します。
13~17行目
スレッド英語名のリストを取得して、取り込んだ対象スレッド名に一致するデータがなかった場合indexに転送します。
19行目
変数の戻り値として対象スレッド名を返します。
loglist (22~40行目)
引数: mainスレッドをリストに含めるか(0 or 1) ,main以外でリストに含めないスレッド名(配列)、戻り値: スレッド英語名(配列)
accessテーブル内に登録されたスレッド英語名のリストを配列として返します。accessテーブルに登録されない(ログインできる人ならだれでも読み書きできる特殊なスレッド)であるmainスレッドをリストに含めるかを決められます。デフォルトではmainスレッドはリストに含まれません。
main以外でリストから除外したいスレッドがあれば、第2引数に配列で指定します。
24~25行目
関数内では外の変数にアクセスできないため、データベース接続用の変数$dbをグローバルとして宣言します。これにより$dbは関数内からでもアクセスできるようになります。これは各関数それぞれで指定する必要があります。以降の関数ではこの解説は省略します。
27~31行目
第一引数を格納する変数$enable_mainを読み出し、返すリストにmainスレッドを含めるかどうか、フラグが立っているか確認します。1なら処理元に返す配列変数$tablesにあらかじめmainを代入しておき、それ以外(デフォルトの0を想定している)なら配列を初期化しておきます。
32行目
PDOを使ってデータベースに処理を依頼します。
accessテーブルに登録されているスレッド全てを登録順(id順)に取得します。
33~39行目
データベースが出力したデータを、配列変数$tablesのキーにスレッドのidを使いながらひとつづつ代入していきます。
第2引数に指定されたリストに含めないスレッド名が出てきたときは$tablesに代入せず次の値をとりにループの先頭に戻ります。
while構文のループ条件にデータベース出力取得を利用し、データベース出力がなくなると自動的にループが終わるようになっています。
bbslist (42~60行目)
引数: mainスレッドをリストに含めるか(0 or 1) ,main以外でリストに含めないスレッド名(配列)、戻り値: スレッドid, {スレッド英語名, スレッド日本語名(配列)}(配列)
loglistとほぼ同じなので違う点だけ述べて解説は省略させていただきます。
loglistと違うのは戻り値として2次元配列を使っているというだけで、一度でスレッド日本語名も合わせて取得してしまおう、というためだけに作られた関数です。
戻り値は $tables[<id>][0] = スレッド英語名、 $tables[<id>][1] = スレッド日本語名 となっています。
enname2janame (62~73行目)
引数: 取得したいスレッド英語名
スレッド英語名から日本語名を返す関数です。
67~69行目
対象スレッドがmainの場合、スレッドを登録しておくaccessテーブルにデータがないので例外として処理します。mainスレッドは日本語名もmainです。
70~72行目
データベースから対象スレッドの日本語名を取得し、処理元に返します。スレッド名の重複は英語・日本語共に許されないのでもともと1件しか返ってこないことが前提です。
rand_strings (76~87行目)
引数: 文字列の長さ
英数字からランダムな文字列を取得します。引数を省略すると12文字になります。
78行目
戻り値を代入する変数を初期化します。84行目の処理のために必要です。
81行目
ランダムな文字列を作るために、抜き出す元の文字列を変数$charsに用意します。
82~85行目
for文で$str_lenの値だけ繰り返します。変数$iをカウンタとして使います。
mt_randでまず乱数を作り、$charsの頭から何文字目を抜き出すかを決め、出てきた文字を$resultの末尾に連結します。mt_randには第一引数に最小値(0)を、第2引数に最大値($str_lenの長さ)を与えます。
86行目
完成したランダムな文字列を処理元に返して完了です。
get_userid (90~110行目)
引数: 対象ユーザー名
指定されたユーザー名のIDをデータベースから取得します。
95~98行目
引数の確認をします。デフォルトではNULL値が代入されるようになっているので単純です。
エラーとして配列で返しています。処理元に返った時にエラーメッセージを簡単に出力できるようにするための工夫です。/wwwroot/admin-tool.phpなどの関数ではこの形式で引数の処理結果を出力しています。
100~108行目
PDOのステートメントを使ってauthテーブルから対象ユーザーのidを取得します。SQLに直接書かず、ステートメントを使うことで攻撃に強くなるそうです。
まずテンプレートとなるSQLを用意し(101行目)、SQL内の指定した部分を変数の値で置換します(102行目)。次にSQLを実行して(103行目)、エラーが起きていないか確認します(104~107行目)。実行結果を受け取って(108行目)、必要な部分を処理元に返せば終了です。
ユーザー名が重複する事は許されませんし、よってidが2つ以上返ってくることもないのでこのような処理をさせています。
get_usermod (114~144行目)
引数: 対象ユーザー名、対象スレッド名
指定されたスレッドへユーザーが持アクセス権限を取得します。0なら読み書き不可、1なら読み込み可、2なら読み書き可です。
118~124行目
値を確認します。
126~131行目
データベースではユーザーはidで管理されているので、対象ユーザーのidをあらかじめ取得しておきます。get_useridの戻り値は配列で、最初の箱には成功したかを知らせるTRUE/FALSEが代入されています。if文の条件に値を直接与えれば簡単に関数の処理が成功したかどうか分かります。この関数はユーザーが存在しているかの確認にもなっています。
133~141行目
実際にステートメントを使ってaccessテーブルからアクセス権を取得します。
143行目
処理元に実行結果を返します。データベース出力を格納している変数$rowはキーにユーザーidを使っているのでarrayの第2変数はこうなります。
Posted in PHPで動く掲示板プログラム |