<?php
/**
 * $db = new DB( array ( array('192.168.1.239','3306', 'socialgame', 'socialgame', '')));
 */
class muDB{
    private $host;//主机
    private $port;//端口
    private $user;//用户
    private $password;//密码
    private $dbname;//db名
    /**
     * mysqli对象
     * @var mysqli
     */
    static private $mysqli;//mysqli对象
    /**
     * @var mysqli_stmt
     */
    static private $stmt;//预处理对象
    /**
     * 为了兼容老版 采用二维数组
     * 参数 array ( array('192.168.1.239:3306', 'socialgame', 'socialgame', ''))
     * @param unknown_type $servers
     */
    public function __construct( $servers){
        $servers = $servers[0];//为了兼容老版
        $aHost = explode(':', $servers[0]);
        $this->host = $aHost[0];
        $this->port = isset( $aHost[1]) ? $aHost[1] : '3306';//默认端口3306
        $this->user = $servers[1];
        $this->password = $servers[2];
        $this->dbname = $servers[3];
    }
    /**
     * 检查并连接数据库
     * @return mysqli
     */
    public function connect(){

        if ( isset(self::$mysqli[$this->host]) && !empty(self::$mysqli[$this->host]) ) {//如果已经连接
            return self::$mysqli[$this->host];
        }
        if ( ! class_exists('mysqli')) {
            die('This Lib Requires The Mysqli Extention!');
        }
        self::$mysqli[$this->host] = new mysqli($this->host, $this->user, $this->password, $this->dbname, $this->port);

        if ( $error = mysqli_connect_error()) {
            $backtrace = array();
            $straces = debug_backtrace();
            foreach ((array) $straces as $k => $v)
            {
                if ($k == 0)
                {
                    continue;
                }
                $backtrace['backtrace'][$k]['file'] = $v['file'];
                $backtrace['backtrace'][$k]['line'] = $v['line'];
                $backtrace['backtrace'][$k]['function'] = $v['function'];
                $backtrace['backtrace'][$k]['args'] = $v['args'];
            }
            $errstr .= "backtrace:".var_export($backtrace, true);
            $this->errorlog( $error, "host:{$this->host},user:{$this->user},pwd:{$this->password},dbname:{$this->dbname},port:{$this->port},strace:{$errstr}");
        }
        self::$mysqli[$this->host]->query("SET SQL_MODE=''");
//        self::$mysqli[$this->host]->query("SET SQL_MODE='',CHARACTER_SET_CONNECTION='utf8',CHARACTER_SET_RESULTS='utf8',CHARACTER_SET_CLIENT='binary',NAMES 'utf8'");
        return self::$mysqli[$this->host];
    }
    /**
     * 执行sql
     * @param string $query

    public function query( $query){
    $this->connect();

    $result = self::$mysqli[$this->host]->query( $query);
    $error = mysqli_error( self::$mysqli[$this->host]);



    if ( $error) {
    $this->errorlog( $error, $query);
    }
    return $result;
    }
     */
    public function query( $query , $showError = true){
        $this->connect();

        $result = self::$mysqli[$this->host]->query( $query);
        $error = mysqli_error( self::$mysqli[$this->host]);
        if ( $error ) {
            $this->errorlog( $error, $query , $showError);
        }
        return $result;
    }

    public function numRows($result=null){ //Return number of rows in selected table
        if( is_object( $result)){
            return $result->num_rows;
        }
        return 0;
    }
    //查询一条记录
    public function getOne($query, $mode = MYSQLI_ASSOC){
        $result = $this->query($query);
        if ( ! is_object( $result)) {
            return array();
        }
        $re = $result->fetch_array( $mode);
        if ( ! is_array($re)) {
            $re = array();
        }
        return $re;
    }
    //查询多条记录
    public function getAll($query, $mode = MYSQLI_ASSOC){
        $result = $this->query($query);
        if ( ! is_object( $result)) {
            return array();
        }
        $dataList = array();
        while ($row = $result->fetch_array( $mode)) {
            $dataList[] = $row;
        }
        return $dataList;
    }
    /**
     * 缓存多行数据
     */
    public function getCacheAll($sql, $expire, $mode=MYSQLI_ASSOC, $key=false){
        $key = $key===false ? md5($sql) : $key;
        if( ($temp = ocache::cache()->get($key)) === false){
            $temp = $this->getAll($sql, $mode);
            ocache::cache()->set($key, $temp, $expire);
        }
        return $temp;
    }

    /**
     * 缓存一行数据
     */
    public function getCacheOne($sql, $expire, $mode=MYSQLI_ASSOC, $key=false){
        $key = $key===false ? md5($sql) : $key;
        if( ($temp = ocache::cache()->get($key)) === false){
            $temp = $this->getOne($sql, $mode);
            ocache::cache()->set($key, $temp, $expire);
        }
        return $temp;
    }
    public function fetchArray($result=null,$mode=MYSQLI_ASSOC){
        if ( ! is_object($result)) {
            return array();
        }
        $row = $result->fetch_array( $mode);
        return is_array($row) ? $row : array();
    }
    public function fetchAssoc($result=null){
        if ( ! is_object($result)) {
            return array();
        }
        $row = $result->fetch_assoc();
        return is_array($row) ? $row : array();
    }
    //获取最新插入的记录ID
    public function insertID(){
        return self::$mysqli[$this->host]->insert_id;
    }
    /**
     *
     * sql执行的影响行数
     */
    public function affectedRows(){
        return self::$mysqli[$this->host]->affected_rows;
    }
    /**
     *
     * 关闭数据库
     */
    public function close(){
        self::$mysqli[$this->host]->close();
        unset(self::$mysqli[$this->host]);
    }
    /**
     * 安全性检测.调用escape存入的,一定要调unescape取出
     */
    public function escape( $string){
        if ( oo::functions()->isPhpVersion()) {
            return addslashes( trim($string));
        }
        return mysql_escape_string( trim($string));
    }

    public function unescape( $string){
        return stripslashes( $string);
    }
    /**
     * 事务处理章节
     */
    public function Start(){
        $this->connect();
        self::$mysqli[$this->host]->autocommit( false);
    }
    /**
     *
     *	提交事务
     */
    public function Commit(){
        self::$mysqli[$this->host]->commit();
        self::$mysqli[$this->host]->autocommit( true);//恢复自动提交
    }
    public function CommitId(){
        $aId = $this->getOne('SELECT LAST_INSERT_ID()', MYSQL_NUM);
        return (int)$aId[0];
    }
    public function Rollback(){
        self::$mysqli[$this->host]->rollback();
    }
    /**
     * mysqli 预处理章节
     */
    /**
     * 该方法准备要执行的预处理语句
     * @return mysqli_stmt
     */
    public function stmtPrepare( $query){
        if ( ! $query) {
            $this->errorlog('no query');
        }
        $this->connect();
        self::$stmt = self::$mysqli[$this->host]->prepare( $query);
        return self::$stmt;
    }

    /**
     * ping 用于保持php和mysql连接不超时
     * 多用于死循环
     */
    public function ping() {
        if (self::$mysqli[$this->host]) {
            return self::$mysqli[$this->host]->ping();
        } else {
            return false;
        }
    }
    /**
     * MYSQL报错日志
     * @param string $msg
     */
    private function errorlog( $msg='', $query='' ,$errorDie = true){
        $date = date( 'Ymd');
        $file = FCPATH . '/deBUG/mysql/' . $date . '.php';
        $error = '';
        if ( ! is_dir( FCPATH . '/deBUG/phperror')) {
            mkdir( FCPATH . '/deBUG/mysql',  0775);
        }
        if ( ! file_exists( $file)) {
            touch($file) && chmod($file, ENVIRONMENT == 'production' ? 0664 : 0666);
            $error = "<?php\nexit();\n";
        }
        $query = oo::functions()->escape( $query);
        $error .= date('Y-m-d H:i:s') . "-- ". mysqli_errno( self::$mysqli[$this->host]) . "-- msg:". $msg . ";" . " query:". $query;
        $backtrace = array();
        $straces = debug_backtrace();
        foreach ((array) $straces as $k => $v)
        {
            if ($k == 0)
            {
                continue;
            }
            $backtrace['backtrace'][$k]['file'] = $v['file'];
            $backtrace['backtrace'][$k]['line'] = $v['line'];
            $backtrace['backtrace'][$k]['function'] = $v['function'];
            $backtrace['backtrace'][$k]['args'] = $v['args'];
        }
        $error .= "backtrace:".var_export($backtrace, true);
        if ( ! ENVIRONMENT == 'production') {
            echo $error;
        }
        @file_put_contents( $file, $error . " \n ", FILE_APPEND | LOCK_EX);
        // 		oo::funModel('logs')->debug($error, 'mysql'.$date);
//        if($errorDie)
//            die(date('Y-m-d H:i:s').'-DB Insvalid!!!');
    }

}
