<?php
/**
 * The zdb library of chanzhieps, can be used to bakup and restore a database.
 *
 * @copyright   Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
 * @license     ZPLV1.2 (http://zpl.pub/page/zplv12.html)
 * @author      Yidong Wang <yidong@cnezsoft.com>
 * @package     Zdb
 * @version     $Id$
 * @link        http://www.chanzhi.org
 */
class zdb
{
    /**
     * dbh 
     * 
     * @var object   
     * @access public
     */
    public $dbh;

    /**
     * Line ender.
     * 
     * @var string
     * @access public
     */
    const LINE_ENDER = ";_ZDB_LINE_ENDER_\n";

    /**
     * Construct 
     * 
     * @access public
     * @return void
     */
    public function __construct()
    {
        global $dbh;
        $this->dbh = $dbh;
    }

    /**
     * Dump db. 
     * 
     * @param  string $fileName 
     * @param  array  $tables 
     * @access public
     * @return object
     */
    public function dump($fileName, $tables = array(), $fields = array(), $mode = 'data,schema', $condations = array(), $replaces = array())
    {
        /* Init the return. */
        $return = new stdclass();
        $return->result = true;
        $return->error  = '';

        /* Get all tables in database. */
        $allTables = array();
        $stmt      = $this->dbh->query('show tables');
        while($table = $stmt->fetch(PDO::FETCH_ASSOC))
        {
            $table = current($table);
            $allTables[$table] = $table;
        }

        /* Dump all tables when tables is empty. */
        if(empty($tables)) $tables = $allTables;

        /* Check file. */
        if(empty($fileName))
        {
            $return->result = false;
            $return->error  = 'Has not file';
            return $return;
        }
        if(!is_writable(dirname($fileName)))
        {
            $return->result = false;
            $return->error  = 'The directory is not writable';
            return $return;
        }

        /* Open this file. */
        $fp = fopen($fileName, 'w');
        fwrite($fp, "SET NAMES utf8" . self::LINE_ENDER);
        foreach($tables as $table)
        {
            /* Check table exists. */
            if(!isset($allTables[$table])) continue;

            /* Create sql code. */
            $backupSql = '';
            if(strpos($mode, 'schema') !== false) $backupSql .= "DROP TABLE IF EXISTS `$table`" . self::LINE_ENDER;
            if(strpos($mode, 'schema') !== false) $backupSql .= $this->getSchemaSQL($table);
            if(strpos($mode, 'data') !== false)   $backupSql .= $this->getDataSQL($table, zget($condations, $table), zget($fields, $table, '*'), zget($replaces, $table));

            /* Write sql code. */
            fwrite($fp, $backupSql);
        }
        fclose ($fp);
        return $return;
    }

    /**
     * Import DB 
     * 
     * @access public
     * @return void
     */
    public function import($fileName)
    {
        $return = new stdclass();
        $return->result = true;
        $return->error  = '';

        if(!file_exists($fileName))
        {
            $return->result = false;
            $return->error  = "File is not exists";
            return $return;
        }

        $fp     = fopen($fileName, 'r');
        $sqlEnd = 0;
        while(($buffer = fgets($fp)) !== false)
        {
            $buffer = str_replace(self::LINE_ENDER, ';', $buffer);
            $line = trim($buffer);
            if(empty($line)) continue;

            if($sqlEnd == 0) $sql = '';
            $quotNum = substr_count($line, "'") - substr_count($line, "\'");
            if(substr($line, -1) == ';' and $quotNum % 2 == 0 and $sqlEnd == 0)
            {
                $sql .= $buffer;
            }
            elseif($quotNum % 2 == 1 and $sqlEnd == 0)
            {
                $sql   .= $buffer;
                $sqlEnd = 1;
            }
            elseif(substr($line, -1) == ';' and $quotNum % 2 == 1 and $sqlEnd == 1)
            {
                $sql   .= $buffer;
                $sqlEnd = 0;
            }
            elseif(substr($line, -1) == ';' and $quotNum % 2 == 0 and $sqlEnd == 2)
            {
                $sql   .= $buffer;
                $sqlEnd = 0;
            }
            else
            {
                $sql .= $buffer;
                $sqlEnd = $sqlEnd == 0 ? 2 : $sqlEnd;
            }

            if($sqlEnd == 0)
            {
                if(strtolower($sql) == 'set names utf8;' and !$this->dbh->query($sql)) $sql = 'SET CHARACTER SET utf8;';

                try
                {
                    $this->dbh->query($sql);
                }
                catch(PDOException $e)
                {
                    $return->result = false;
                    $return->error  = $e->getMessage();
                    return $return;
                }
            }
        }
        return $return;
    }

    /**
     * Get schema SQL.
     * 
     * @param  string    $table 
     * @access public
     * @return string
     */
    public function getSchemaSQL($table)
    {
        $createSql = $this->dbh->query("show create table `$table`")->fetch(PDO::FETCH_ASSOC);
        return $createSql['Create Table'] . self::LINE_ENDER;
    }

    /**
     * Get data SQL.
     * 
     * @param  string    $table 
     * @access public
     * @return string
     */
    public function getDataSQL($table, $where = '', $fields = '*', $replace = false)
    {
        if(empty($fields)) $fields = '*';
        $rows = $this->dbh->query("select {$fields} from `$table` $where")->fetchAll(PDO::FETCH_ASSOC);
        $sql  = '';
        if(!empty($rows))
        {
            /* Create key sql for insert. */
            $keys = array_keys(current($rows));
            $keys = array_map('addslashes', $keys);
            $keys = join('`,`', $keys);
            $keys = "`" . $keys . "`";

            /* Create all value sql. */
            $values = array();
            foreach($rows as $row)
            {
                $value = array_values($row);
                $value = array_map('addslashes', $value);
                $value = join("','", $value);
                $value = "'" . $value . "'";

                $values[] = "($value)";
            }

            if(!$replace) $sql .= "INSERT  INTO `$table`($keys) VALUES" . join(',', $values) . self::LINE_ENDER;
            if($replace)  $sql .= "REPLACE INTO `$table`($keys) VALUES" . join(',', $values) . self::LINE_ENDER;
        }
        return $sql;
    }
}
