[Utility.php] データベースを楽にする function()

前回のエントリ【データベースclassを使わない理由】から続きます。

前回のエントリで、システムの仕様レベルとして、

  • データベースは1つしか使わない
  • スコープを気にしないfunction()にしてしまう

このように、決め付けてしまおう。と書きました。
では、具体的なコードを書いていこうと思います。

このコードは、汎用的な関数になるので、Utility.phpなどと名前をつけたファイルに記述することをオススメします。

なお、 try{}chatch{} を使用するのと、エラー時にログを出力するので、次の関数が必要になります。(別のログ関数を利用している場合はwriteLog()関数を書き換えます)

[code language="php"]define('C_DB_HOST', 'localhost');
define('C_DB_USER', 'database_username');
define('C_DB_PASS', 'database_password');
define('C_DB_DBNAME', 'database_name');

$_G_DbConnection = false; // データベースコネクション[/code]

データベース接続に必要な情報を定数として宣言します。
便宜上、この場所に書いていますが、実際は定数宣言のためのPHPファイルを別途用意してそこに記述すると良いかと思います。

次に、データベースのコネクションを格納する変数を宣言します。
私は、$_G_ で始まる変数は、global として使う変数とルール付けしています。
$_G_DbConnection は、以下に記すfunction()の中だけで、それ以外の場所では使いません。

[code language="php"]/*
* データベースに接続する
*/
function dbConnect()
{
global $_G_DbConnection;
$_G_DbConnection = false;
$ErrorString = "";
try{
// 接続を試みる
$_G_DbConnection = mysql_connect(C_DB_HOST, C_DB_USER, C_DB_PASS);
if ($_G_DbConnection === false){
$ErrorString .= "mysql_connect[A] : " . C_DB_HOST . ' : ' . C_DB_USER;
} else {
// 文字コードをUTF-8に。(UTF-8と仮定)
if (mysql_query("SET NAMES utf8", $_G_DbConnection) === false){
$ErrorString .= "SET NAMES utf8";
} else {
// 使用するデータベースを選択
if (mysql_select_db(C_DB_DBNAME, $_G_DbConnection) === false){
$ErrorString .= "データベースが見つかりません。:" . C_DB_DBNAME;
}
}
}
} catch (Exception $E){
$ErrorString .= "mysql_connect[B] : " . C_DB_HOST . ' : ' . C_DB_USER;
}
if (strlen($ErrorString) > 0){
writeLog(C_LOG_ERROR, __FILE__, __LINE__, $ErrorString);
return false;
}
return true;
}
[/code]

データベースに接続します。定数値で、直にホスト名・ユーザー名・パスワード・データベース名を指定しているのは、【データベースは1つ】という仕様を決めたことで可能となる記述です。

正常時は、$_G_DbConnection にコネクションが格納され、戻り値としてtrueを返します。
失敗時は、$_G_DbConnection にfalseが格納され、戻り値としてfalseを返します。

mysql_connect()は、プログラムの開始で、1回だけ実行します。2回以上実行する必要はありません。呼び出し側では、mysql_connect()がfalseの時、500エラーを発行すると良いかと思います。

[code language="php"]/*
* mysql_real_escape_string()を実行する
* 戻り値:正常時 string, エラー時 === false
*/
function dbRealEscape($Text)
{
global $_G_DbConnection;
return mysql_real_escape_string($Text, $_G_DbConnection);
}
// 記述例
// $Sql = "select * from hoge where fuga = '" . dbRealEscape("ab''cd"e) . "'";
[/code]

引数として渡された文字列を、SQLとして安全な文字列に置き換えて返します。
記述例のようにして使います。

[code language="php"]/*
* sqlを実行する
* 戻り値:正常時 Result, エラー時 === false
*/
function dbRunSql($Sql)
{
global $_G_DbConnection;
$Result = mysql_query($Sql, $_G_DbConnection);
if ($Result === false){
writeLog(C_LOG_ERROR, __FILE__, __LINE__, "sql error : " . $Sql);
}
return $Result;
}
[/code]

引数のSQLを実行します。
戻り値は、mysql_query()関数の戻り値と同じです。
mysql_query()のリファレンスでご確認ください。

[code language="php"]/*
* 結果セットを開放する
*/
function dbFreeResult($Result)
{
if (is_resource($Result)) return mysql_free_result($Result);
return false;
}
[/code]

dbRunSql() で取得した結果セットを開放します。

[code language="php"]/*
* sqlから指定したフィールドの値を配列で取得
*/
function dbGetFields($Sql, $FieldNames)
{
$ret = false;
$Result = dbRunSql($Sql);
if ($row = mysql_fetch_array($Result)){
$ret = array();
if (is_array($FieldNames)){
foreach ($FieldNames as &$value){
$ret[$value] = $row[$value];
}
} else {
$ret[$FieldNames] = $row[$FieldNames];
}
}
dbFreeResult($Result);
if ($ret === false){
writeLog(C_LOG_ERROR, __FILE__, __LINE__, "sql error : " . $Sql);
}
return $ret;
}
[/code]

引数のSqlから、$FieldNamesで指定されたフィールドを連想配列として取得します。
$FieldNamesは、string、もしくは配列でフィールド名を指定します。
例えば、 select count(id) as Count from hoge など、 結果が1レコードであることが確定しているときに使用することを想定しています。

次は、これらの関数の使用例です。

[code language="php"]<?php
$HtmlBody = '';

// Utility.phpに関数が定義されていると仮定します。
include "./Utility.php";

// データベースに接続を試みる
if (dbConnect() === false){
writeLog(C_LOG_ERROR, __FILE__, __LINE__, "データベース接続エラー");
echo &quot;データベース 接続エラー<br />"
. "実際は、ここで500エラーを発行";
exit;
}

////////////////////////////////////////////////////
// SQL文を作成
$Sql = "select CURTIME() as CurrentTime";
// SQLを実行
$Result = dbRunSql($Sql);
// ここで、目的に応じて$Resultを処理します。
if ($Result === false){
$HtmlBody .= 'SQL実行エラー';
} else {
if ($row = mysql_fetch_array($Result)){
$HtmlBody .= "現在の時間は、" . $row["CurrentTime"];
}
}
// $Resultを開放
dbFreeResult($Result);

////////////////////////////////////////////////////
// SQL文を作成
$Sql = "select CURTIME() as CurrentTime";
// SQLを実行
$Result = dbGetFields($Sql, "CurrentTime");
if ($Result !== false){
$HtmlBody .= "<hr />" . $Result["CurrentTime"];
}

////////////////////////////////////////////////////
$HtmlBody .= getSample();
// スコープを気にせず使える
function getSample(){
// SQL文を作成
$Sql = "select CURTIME() as CT1, CURTIME() as CT2";
// 戻り値のフィールドリスト
$Fields = array("CT1", "CT2");
// SQLを実行
$Result = dbGetFields($Sql, $Fields);
if ($Result !== false){
return "<hr />" . $Result["CT1"] . " : " . $Result["CT2"];
}
return "";
}

?&gt;
[/code]