<?php
/**
 * -----------------------------------------------------------------------------
 *
 * SyL - Web Application Framework for PHP
 *
 * PHP version 4 (>= 4.3.x) or 5
 *
 * Copyright (C) 2006 k.watanabe
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * -----------------------------------------------------------------------------
 * @package   SyL
 * @author    k.watanabe <k.watanabe@syl.jp>
 * @copyright 2006 k.watanabe
 * @license   http://www.opensource.org/licenses/lgpl-license.php
 * @version   CVS: $Id: SyL_DB_Mysql.php,v 1.7 2006/12/23 11:13:09 seasonstream Exp $
 * @link      http://www.syl.jp/
 * -----------------------------------------------------------------------------
 */

/**
 * DB操作クラス（MySQL）
 *
 * ※MySQL 4.1以上
 *
 * @package   SyL
 * @author    k.watanabe <k.watanabe@syl.jp>
 * @copyright 2006 k.watanabe
 * @license   http://www.opensource.org/licenses/lgpl-license.php
 * @version   CVS: $Id: SyL_DB_Mysql.php,v 1.7 2006/12/23 11:13:09 seasonstream Exp $
 * @link      http://www.syl.jp/
 */
class SyL_DB_Mysql extends SyL_DB
{
    /**
     * エンコード変換テーブル
     *
     *  MySQL    <=> PHP
     *  (client)     (client)
     * 
     * ※全て小文字で記述
     *
     * @access protected
     * @var string
     */
    var $encode_table = array(
      // PHP, DB
      array('eucjp-win', 'ujis'),
      array('euc-jp',    'ujis'),
      array('sjis-win',  'sjis' ),
      array('sjis',      'sjis'),
      array('utf-8',     'utf8')
    );

    /**
     * DB接続実行
     * 
     * @access public
     * @param string データベース名
     * @param string ユーザー名
     * @param string パスワード
     * @param string ホスト名
     * @param string ポート番号
     * @param bool 持続的接続を行うか
     * @return boolean 接続OK: true, 接続NG: false
     */
    function openConnection($dbname, $user, $passwd, $host, $port, $persistent)
    {
        if ($host == '') {
            $host = 'localhost';
        }
        if ($port != '') {
            $host .= ':' . $port;
        }
        $this->connection = ($persistent) ? mysql_pconnect($host, $user, $passwd) : mysql_connect($host, $user, $passwd);
        if (is_resource($this->connection) && mysql_select_db($dbname, $this->connection)) {
            $this->setClientEncoding();
            return true;
        } else {
            return false;
        }
    }

    /**
     * クライアント側文字エンコーティング設定
     * 
     * @access public
     * @param string 文字コード
     */
    function setClientEncoding($client_encode='')
    {
        parent::setClientEncoding($client_encode);
        if ($this->client_encode)
            @mysql_query("SET NAMES {$this->client_encode}", $this->connection);
        }
    }

    /**
     * DB接続終了
     * 
     * @access public
     */
    function closeConnection()
    {
        if (is_resource($this->connection)) {
            mysql_close($this->connection);
            $this->connection = null;
        }
    }

    /**
     * 最後に起こったエラーメッセージを取得
     *
     * @access public
     * @return string 最後に起こったエラーメッセージ
     */
    function getLastError()
    {
        $error_no = mysql_errno($this->connection);
        $error_message = '';
        if ($error_no != 0) {
            $error_message = "[Error No {$error_no}] " . mysql_error($this->connection);
        }
        return $error_message;
    }

    /**
     * パラメータサニタイズ（無効化）処理
     * 
     * @access public
     * @param string サニタイズ対象文字列
     * @return string サニタイズ後文字列
     */
    function sanitize($parameter)
    {
        return !is_numeric($parameter) ? mysql_real_escape_string($parameter, $this->connection) : $parameter;
    }

    /**
     * トランザクション開始
     *
     * @access public
     */
    function begin()
    {
        parent::begin();
        @mysql_query('SET AUTOCOMMIT=0', $this->connection);
        @mysql_query('BEGIN', $this->connection);
    }

    /**
     * トランザクション破棄
     *
     * @access public
     */
    function rollback()
    {
        @mysql_query('ROLLBACK', $this->connection);
        @mysql_query('SET AUTOCOMMIT=1', $this->connection);
        parent::rollback();
    }

    /**
     * トランザクション確定
     *
     * @access public
     */
    function commit()
    {
        @mysql_query('COMMIT', $this->connection);
        @mysql_query('SET AUTOCOMMIT=1', $this->connection);
        parent::commit();
    }

    /**
     * SQLを実行し、DBリソースを取得
     *
     * @access public
     * @param string SQL文
     * @return mixed 実行OK: DBリソース, 実行NG: false
     */
    function executeSelect($sql)
    {
        $result = @mysql_query($sql, $this->connection);
        if ($result !== false) {
            return $result;
        } else {
            $this->executeTriggerError($this->getLastError());
            return false;
        }
    }

    /**
     * SQLを実行し、実行結果影響件数を取得
     *
     * @access public
     * @param string SQL文
     * @return mixed 実行OK: 実行結果影響件数, 実行NG: false
     */
    function executeUpdate($sql)
    {
        $result = @mysql_query($sql, $this->connection);
        if ($result !== false) {
            return mysql_affected_rows($this->connection);
        } else {
            $this->executeTriggerError($this->getLastError());
            return false;
        }
    }

    /**
     * SQL実行のみ
     *
     * @access public
     * @param string SQL文
     * @return boolean 実行OK: true, 実行NG: false
     */
    function executeNoReturn($sql)
    {
        $result = @mysql_query($sql, $this->connection);
        if ($result !== false) {
            return true;
        } else {
            $this->executeTriggerError($this->getLastError());
            return false;
        }
    }

    /**
     * SQL実行し、結果データを取得
     *
     * ・第3パラメータが、'one'の場合
     *    最初の1カラムを文字列として取得
     * ・第3パラメータが、'record'の場合
     *    最初の1レコードを配列として取得
     * ・第3パラメータが、'all'の場合
     *    全レコードを配列として取得
     *
     * @access public
     * @param string SQL文
     * @param mixed  実行結果を取得
     * @param string 結果取得フラグ
     * @return boolean 実行OK: true, 実行NG: false
     */
    function executeGet($sql, &$data, $get='all')
    {
        // SQL実行
        $this->execute($sql, $query);
    
        // 実行時エラー判定
        if (is_resource($query)) {
            switch ($get) {
            case 'one':
                if (mysql_num_rows($query) > 0) {
                    list($data) = mysql_fetch_row($query);
                } else {
                    $data = '';
                }
                break;
            case 'record':
                $data = mysql_fetch_assoc($query);
                if ($data === false) {
                    $data = array();
                } else {
                    $data = $this->changeFieldName($data);
                }
                break;
            case 'all':
                $data = array();
                while ($result = mysql_fetch_assoc($query)) {
                    $result = $this->changeFieldName($result);
                    $data[] = $result;
                }
                break;
            }
            mysql_free_result($query);
            return true;
        } else {
            $this->executeTriggerError($this->getLastError());
            return false;
        }
    }

    /**
     * SQLを実行し、ページ毎にデータを取得
     * ※実行前に「initializePage」メソッド実行必須
     * ※SQL文の「FROM」句の直前にタブ文字必須。（それ以外のタブ文字不可）
     *
     * @access public
     * @param string SQL文
     * @param array 実行結果格納配列
     * @param object ページオブジェクト
     * @param int 1ページの表示件数
     * @param int 表示対象ページ数 
     * @return bool 実行結果
     */
    function executePage($sql, &$result, &$page_control, $limit, $page=1)
    {
        // ページ制御クラス
        include_once dirname(dirname(__FILE__)) . '/SyL_Pager.php';
        $page_control = new SyL_Pager();
        $page_control->setCount($limit);
        $page_control->setPage($page);

        // 総件数取得SQL作成
        $sql_count = "SELECT COUNT(*) FROM (" . $sql . ") AS SyL$";
        // 件数取得SQL実行
        if (!$this->executeGet($sql_count, $record, 'one')) return false;
        $page_control->setCountAll( $record );

        // ページ単位レコード取得
        $sql_page  = $sql;
        $sql_page .= ' LIMIT ' . $page_control->getStartRecord() . ', ' . $page_control->getCount();

        // データ取得SQL実行
        return $this->executeGet($sql_page, $result, 'all');
    }

    /**
     * 日付フォーマット関数名を取得
     *
     * @access public
     *
     * @param string カラム名
     * @param string 日付型フォーマット 例） YYYY/MM/DD YYYY/MM/DD HH24:MI:SS
     * @return string 日付フォーマット関数名
     */
    function getSqlDateFormat($column_name, $format='%Y-%m-%d %H:%i:%s')
    {
        return "DATE_FORMAT('{$column_name}', '{$format}')";
    }

    /**
     * テーブル一覧を取得する
     *
     * @access public
     *
     * @return array テーブルリスト
     */
    function getTableList()
    {
        $tables     = array();
        $tables_tmp = array();
        $this->executeGet( "SHOW TABLES", $tables_tmp );
        foreach ($tables_tmp as $table) {
            list($key, $value) = each($table);
            $tables[] = $value;
        }
        return $tables;
    }

    /**
     * カラム一覧を取得する
     *
     * @access public
     *
     * @param string テーブル名
     * @return array カラムリスト
     */
    function getColumnList( $table_name )
    {
        $columns     = array();
        $columns_tmp = array();
        $this->executeGet( "SHOW COLUMNS FROM " . $table_name, $columns_tmp );
        foreach ($columns_tmp as $column) {
            $columns[] = $column['FIELD'];
        }
        return $columns;
    }
}

?>
