プログラム関連

DBアクセスクラス - dfwLib2

DBアクセスクラス

DBにアクセスするためのPDOラッパークラスを提供しています。

require_once することで DBクラス が使用できます。

require_once(dirname(__FILE__).'/../lib/DB.class.php');
require_once('DB.class.php');

DB接続先指定

  $GLOBALS['dfw']['db']['default'] = array(
      'dsn' => 'mysql:dbname=XXXXX;host=localhost;charset=utf8',
      'user' => 'tateno',
      'pass' => 'system',
      'hosts_match' => array(
            'xxxxxxx' => array('dsn' => 'mysql:dbname=XXXXX;host=xxxxxx;charset=utf8', 'user' => 'hoge', 'pass' => 'taro'),
            'develop' => array('dsn' => 'mysql:dbname=XXXXX;host=xxxxxx;charset=utf8'),
      ),
      'names_match' => array(
            'xxxxxxx' => array('dsn' => 'mysql:dbname=XXXXX;host=xxxxxx;charset=utf8', 'user' => 'hoge', 'pass' => 'taro'),
            'develop' => array('dsn' => 'mysql:dbname=XXXXX;host=xxxxxx;charset=utf8'),
      ),
  );

'hosts_match' は ホスト名 $_SERVER['HTTP_HOST'] に「キー」が含まれていた場合(部分一致)、使用する DSN、ID、PASS を切り替えます(オンライン向け)。

'names_match' は __サーバ名 php_uname('n')__ に「キー」が含まれていた場合(部分一致)、使用する DSN、ID、PASS を切り替えます(バッチプログラム向け)。

'hosts_match'、'names_match' はオプションです。

初期化(シングルトン)

設定情報(array)を渡して初期化します。

$db = DB::init(); // $GLOBALS['dfw']['db']['default'] 設定を使用します
$db = DB::init('master'); // $GLOBALS['dfw']['db']['master'] 設定を使用します

シングルトンを使用しない場合は、以下のように new を用いてオブジェクトを生成します。

$db = new DB('slave');

DBクローズ(コネクション切断)

明示的に接続名を指定してクローズします。

$db->close(); // $GLOBALS['dfw']['db']['default'] 設定コネクションをクローズします
$db->close('master'); // $GLOBALS['dfw']['db']['master'] 設定コネクションをクローズします

SQL実行の流れ

  • (1) SQL定義
$db->setSql('SELECT * FROM memo WHERE name=:name AND flag=:flag');
  • (2-1) SQLパラメータ設定(通常のやり方)
$db->set('name', 'tatenosystem');
$db->set('flag', 1);
  • (2-2) SQLパラメータ設定(連想配列で一度に設定)
$params = array();
$params['name'] ='tatenosystem';
$params['flag'] = 1;
$db->sets( $params );
  • (2-3) SQL INコマンド(INに設定する場合)
$db->setSql('SELECT * FROM memo WHERE name IN (:names)'); 
$db->setIn( 'names', array('tatenosystem', 'mahata', 'hoge') );  // IN の場合は setIn メソッド。配列を設定
  • (3-1)SQL実行(1レコード取得)
$item = $db->execFetchOne();
var_dump( $item );
  • (3-2) SQL実行(全レコード取得)
$items = $db->execFetchAll();
var_dump( $items );

簡単な使い方

-SELECT

$db->setSql('SELECT * FROM memo WHERE name = :name OR id = :id'); 
$db->set('name', 'tatenosystem');
$db->set('id', 35);
$data = $db->execFetchAll();  // 戻り値は全レコード

-UPADTE

$db->setSql('UPDATE memo SET name = :name WHERE id = :id'); 
$db->set('name', 'tatenosystem');
$db->set('id', 35);
$rtn = $db->exec();  // exec() の戻り値は更新レコード件数

-INSERT

$db->setSql('INSERT INTO memo (name, age) VALUES (:name, :age)'); 
$db->set('name', 'baby');
$db->set('age', 2);
$rtn = $db->exec();  // exec() の戻り値は更新レコード件数

-INSERT(メソッド使用)

$params = array('name' => 'baby', 'age' => 2);
$rtn = $db->insert('table_name', $params);  // insert() の戻り値は更新レコード件数

-REPLACE(メソッド使用)

$params = array('name' => 'baby', 'age' => 2);
$rtn = $db->replace('table_name', $params);  // replace() の戻り値は更新レコード件数

すこし凝った使い方

-SELECT実行(1レコードずつ取得)

$db->exec();
while( true ) {
 $item = $db->fetch();
 if( empty($item) ) break; // 取得終了時は空配列となる
 var_dump( $item );
}

-SELECT実行(10レコードずつ取得)

$db->exec();
while( true ) {
 $item = $db->fetchNum( 10 );
 if( empty($item) ) break; // 取得終了時は空配列となる
 var_dump( $item );
}

便利なINSERTメソッド

INSERT命令はSQL文を書かずに実行できるメソッドがあります。

戻り値は更新行数(成功時は1)となります。

$db = new DB();
$params = array( 'title'=>'ほげタイトル', 'description'=>'ほげんほげん' );
$ret = $db->insert( 'my_table', $params ); // INSERT実行

上記実行のSQLは、

INSERT INTO my_table ( title, description ) VALUES ( "ほげタイトル", "ほげんほげん" );

となります。

NOW()関数が使えます。

$db = new DB();
$params = array( 'title'=>'ほげタイトル', 'created_at'=>'NOW()' );
$ret = $db->insert( 'my_table', $params ); // INSERT実行

上記実行のSQLは、

INSERT INTO my_table ( title, created_at ) VALUES ( "ほげタイトル", NOW() );

となります。

同様のやり方で REPLACE も使用できます。

$ret = $db->replace( 'my_table', $params ); // REPLACE実行

2つのエラーハンドリングモード

try-catch (デフォルト)

try-catch でエラーハンドリングを行います。

try {
    $db = DB::init($config);
    
    $db->setSql('SELECT * FROM ROD_BOOKS WHERE ID IN (:hoge)');
    $db->setIn('hoge', array(56,57,58,59,60,41));
    
    $db->exec();
} catch (PDOException $e) {
    var_dump($e->getMessage());
}
  • PHP5 以降であれば set_exception_handler が使用できます。
function exception_handler($e) {
   var_dump($e->getMessage());
}

set_exception_handler('exception_handler');

$db = DB::init($config);
    
$db->setSql('SELECT * FROM ROD_BOOKS WHERE ID IN (:hoge)');
$db->setIn('hoge', array(56,57,58,59,60,41));
 
$db->exec();
// 明示的な例外発生
throw new Exception('HogeHoge_Error');

メソッドの戻り値でエラーハンドリング

下記設定を行うとメソッドの戻り値でエラーハンドリングが行えます(ver1.0と同様)

$GLOBALS['dfw']['db']['trymode'] = false;

DBメソッドエラー時は false(boolean) が返却されます。

$rtn = $db->exec();
if ($rtn === false) {
  echo 'DB execエラー';
  var_dump($db->getErrorMessage());
}

コンストラクタのエラーチェックのみ isConnect メソッドを使用します。

isConnect メソッドは「メソッド戻り値エラーハンドリング」専用です。

$db = DB::init();
if ( ! $db->isConnect() ) {
  echo 'DBコネクトエラー'
  var_dump($db->getErrorMessage());
}

以下のメソッドのエラー時は false(boolean) が返却されます。

  • exec()
  • fetch()
  • fetchAll()
  • execFetchAll()
  • execFetchOne()
  • insert()
  • multiInsert()

以下のエラー内容取得メソッドは「メソッド戻り値エラーハンドリング」専用です。

  • getPdoException()
  • getErrorMessage()
  • getErrorCode()

トランザクション機能

※トランザクション非対応DBMSでは使用できません

  • トランザクションの開始
$rtn = $db->beginTransaction();

成功した場合に true を、失敗した場合に false を返します。

  • コミット
$rtn = $db->commit();

成功した場合に true を、失敗した場合に false を返します。

  • ロールバック
$rtn = $db->rollBack();

成功した場合に true を、失敗した場合に false を返します。

その他の機能

マルチINSERT

$params = array(
  array('column1' => 'value1', 'column2' => 'value2','column3' => 'value3'),
  array('column1' => 'value1', 'column2' => 'value2','column3' => 'value3'),
  array('column1' => 'value1', 'column2' => 'value2','column3' => 'value3'),
);
$rtn = $db->multiInsert('table_naame', $params);

※マルチINSERT対応DBMSのみ動作

※マルチINSERTを使用する際は、使用しているDBMSのマルチINSERT機能をよく理解してから使用してください

マルチREPLACE

マルチINSERTと同様

$rtn = $db->multiReplace('table_naame', $params);

※マルチREPLACE対応DBMSのみ動作

※マルチREPLACEを使用する際は、使用しているDBMSのマルチREPLACE機能をよく理解してから使用してください

最終行の取得(最終INSERT id の取得)

$id = $db->lastInsertId();

※PDO lastInsertId()のラッパー関数

その他 Tips

SQL処理がエラーになる

実際に実行されているSQL文を getSql メソッドで表示させて、問題がないか確認してください。

  • try-catch の場合
try {
    $db = DB::init($config);
    $db->setSql('SELECT * FROM ROD_BOOKS WHERE ID IN (:hoge)');
    $db->setIn('hoge', array(56,57,58,59,60,41));
    $db->exec();
} catch (PDOException $e) {
    var_dump($db->getSql());        // 実行に失敗したSQL文の表示
}
  • メソッド戻り値エラーハンドリングの場合
$db = DB::init($config);
$db->setSql('SELECT * FROM ROD_BOOKS WHERE ID IN (:hoge)');
$db->setIn('hoge', array(56,57,58,59,60,41));
$rtn = $db->exec();
if ($rtn === false) {
   var_dump($db->getSql());        // 実行に失敗したSQL文の表示
}

insert/replace メソッドでの現在時刻設定

MySQLでの現在時刻SQL関数 NOW() を使用できます。

$paramas = array(
    'name' => 'hogehoge',
    'createad_at' => 'NOW()',
);

insert('table_name', $params);

デフォルト値の NOW() 以外を使用する場合は、setNowSqlFunction メソッドでSQL関数名を指定してください(MySQL以外を使用している場合)。

$db->setNowSqlFunction( 'clock_timestamp()' );

PDO オブジェクトの取得

getPdo メソッドを使用します。

$pdoObject = $db->getPdo();
echo $db->getPdo()->getAttribute(PDO::ATTR_TIMEOUT);

セキュリティについて

SQL文生成で変数を利用すると「SQLインジェクション」が発生する恐れがあります。

$db->setSql('SELECT * FROM hoge WHERE id='.$_GET['id']);   // 【危険】「SQLインジェクション」発生!
$db->setSql('SELECT * FROM hoge WHERE id='.$id);   // 【危険】「SQLインジェクション」発生の恐れ!
$db->setSql('SELECT * FROM hoge WHERE id=:id);   // 正しいSQL設定
$db->set('id', $_GET['id']);  // $_GET['id']はバリデーション処理済みであること