| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- <?php
- /**
- * The zdb library of zentaopms, can be used to bakup and restore a database.
- *
- * @copyright Copyright 2009-2015 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
- * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author Yidong Wang <yidong@cnezsoft.com>
- * @package Zdb
- * @version $Id$
- * @link http://www.zentao.net
- */
- class zdb
- {
- /**
- * dbh
- *
- * @var object
- * @access public
- */
- public $dbh;
- /**
- * Construct
- *
- * @access public
- * @return void
- */
- public function __construct()
- {
- global $dbh;
- $this->dbh = $dbh;
- }
- /**
- * Get all tables.
- *
- * @param string $type base|view. if type is 'base', just get base table.
- * @access public
- * @return array
- */
- public function getAllTables($type = 'base')
- {
- global $config;
- $allTables = array();
- $sql = 'show full tables';
- if($config->db->driver == 'dm') $sql = "select OBJECT_NAME AS Tables_in_{$config->db->name}, OBJECT_TYPE as Table_type from all_objects where owner='{$config->db->name}' and OBJECT_TYPE in('TABLE','VIEW');";
- $stmt = $this->dbh->query($sql);
- while($table = $stmt->fetch(PDO::FETCH_ASSOC))
- {
- $tableType = strtolower($table['Table_type']);
- if($type == 'base' && $tableType != 'base table' && $tableType != 'table') continue;
- if($type == 'view' && $tableType != 'view') continue;
- $tableName = $table["Tables_in_{$config->db->name}"];
- $allTables[$tableName] = $tableType == 'base table' ? 'table' : $tableType;
- }
- return $allTables;
- }
- /**
- * Get table fields.
- *
- * @param string $table
- * @access public
- * @return array
- */
- public function getTableFields($table)
- {
- try
- {
- $this->dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
- $sql = "DESC $table";
- $rawFields = $this->dbh->query($sql)->fetchAll();
- $this->dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL);
- }
- catch (PDOException $e)
- {
- global $dao;
- $dao->sqlError($e);
- }
- $fields = array();
- foreach($rawFields as $field) $fields[$field->field] = $field;
- return $fields;
- }
- /**
- * Diff current table fields with a fields array.
- *
- * @param string $table
- * @param array $fields
- * @access public
- * @return array
- */
- public function diffTable($table, $fields)
- {
- $tableFields = $this->getTableFields($table);
- $diff = array_udiff_assoc($fields, $tableFields,
- function($a, $b)
- {
- return (array)$a == (array)$b ? 0 : 1;
- }
- );
- return $diff;
- }
- /**
- * Add a column to a table, or modify a existing column.
- *
- * @param string $table
- * @param object $column
- * @param boolean $add if true, add $column as a new column, otherwise modify a existing column to $column.
- * @access public
- * @return object
- */
- public function updateColumn($table, $column, $add = true)
- {
- $return = new stdclass();
- $return->result = true;
- $return->error = '';
- $query = "ALTER TABLE `$table` " . ($add ? 'ADD' : 'MODIFY COLUMN') . " `$column->field` $column->type" . ($column->null == 'NO' ? ' NOT NULL' : '') . (is_null($column->default) ? '' : " DEFAULT '$column->default'") . (empty($column->extra) ? '' : " $column->extra") . ';';
- try
- {
- $this->dbh->exec($query);
- return $return;
- }
- catch(PDOException $e)
- {
- $return->result = false;
- $return->error = $e->getMessage();
- $return->sql = $query;
- return $return;
- }
- }
- /**
- * Create a table with fields.
- *
- * @param string $name
- * @param array $fields
- * @access public
- * @return object
- */
- public function createTable($name, $fields)
- {
- $return = new stdclass();
- $return->result = true;
- $return->error = '';
- $createTableQuery = "CREATE TABLE `$name` (";
- foreach($fields as $field)
- {
- $createColumnQuery = "`$field->field` $field->type" . ($field->null == 'NO' ? ' NOT NULL' : '') . (is_null($field->default) ? '' : " DEFAULT '$field->default'") . (empty($field->extra) ? '' : " $field->extra") . ", ";
- if(!empty($field->key))
- {
- if($field->key === 'PRI') $createColumnQuery .= "PRIMARY KEY (`{$field->field}`), ";
- if($field->key === 'MUL') $createColumnQuery .= "KEY `{$field->field}` (`{$field->field}`), ";
- if($field->key === 'UNI') $createColumnQuery .= "UNIQUE KEY `{$field->field}` (`{$field->field}`), ";
- }
- $createTableQuery .= $createColumnQuery;
- }
- $createTableQuery = rtrim($createTableQuery, ', ');
- $createTableQuery .= ") ENGINE=MyISAM DEFAULT CHARSET=utf8;";
- try
- {
- $this->dbh->exec($createTableQuery);
- return $return;
- }
- catch(PDOException $e)
- {
- $return->result = false;
- $return->error = $e->getMessage();
- $return->sql = $createTableQuery;
- return $return;
- }
- }
- /**
- * Dump db.
- *
- * @param string $fileName
- * @param array $tables
- * @access public
- * @return object
- */
- public function dump($fileName, $tables = array())
- {
- /* Init the return. */
- $return = new stdclass();
- $return->result = true;
- $return->error = '';
- /* Get all tables in database. */
- $allTables = $this->getAllTables();
- /* Dump all tables when tables is empty. */
- if(empty($tables))
- {
- $tables = $allTables;
- }
- else
- {
- foreach($tables as $table) $tables[$table] = $allTables[$table];
- }
- /* 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;
- }
- global $config;
- /* Open this file. */
- $fp = fopen($fileName, 'w');
- fwrite($fp, "SET NAMES {$config->db->encoding};\n");
- $this->dbh->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
- foreach($tables as $table => $tableType)
- {
- /* Check table exists. */
- if(!isset($allTables[$table])) continue;
- /* Create sql code. */
- $backupSql = "DROP " . strtoupper($tableType) . " IF EXISTS `$table`;\n";
- $desc = $this->dbh->query("desc `$table`")->fetchAll();
- if(empty($desc)) continue;
- $schemaSQL = $this->getSchemaSQL($table, $tableType);
- if($schemaSQL->result) $backupSql .= $schemaSQL->sql;
- fwrite($fp, $backupSql);
- if($tableType != 'table') continue;
- $nullFields = array();
- foreach($desc as $field) $nullFields[$field->Field] = ($field->Null == 'YES' || $field->Null == 'Y');
- /* Create key sql for insert. */
- $fields = "`" . join('`,`', array_map('addslashes', array_keys($nullFields))) . "`";
- $rows = $this->dbh->query("select * from `$table`");
- $values = array();
- $batchNum = 200;
- while($row = $rows->fetch(PDO::FETCH_ASSOC))
- {
- /* Create a value sql. */
- $row = array_map('addslashes', $row);
- $value = array();
- foreach($row as $fieldName => $fieldValue)
- {
- $length = strlen($fieldValue);
- $fieldValue = "'{$fieldValue}'";
- if($length == 0 and !empty($nullFields[$fieldName])) $fieldValue = 'null';
- $value[] = $fieldValue;
- }
- $values[] = '(' . join(',', $value) . ')';
- if(count($values) == $batchNum)
- {
- /* Write sql code. */
- fwrite($fp, "INSERT INTO `$table`($fields) VALUES " . implode(",\n", $values) . ";\n");
- $values = array();
- }
- }
- if($values) fwrite($fp, "INSERT INTO `$table`($fields) VALUES " . implode(",\n", $values) . ";\n");
- }
- /* Get all views in database. */
- $allViews = $this->getAllTables('view');
- foreach($allViews as $table => $tableType)
- {
- $createView = $this->dbh->query("show create view `$table`")->fetch(PDO::FETCH_ASSOC);
- if($createView && isset($createView['Create View']))
- {
- $backupSql = "DROP VIEW IF EXISTS `$table`;\n";
- $backupSql .= $createView['Create View'] . ";\n";
- }
- fwrite($fp, $backupSql);
- }
- fclose($fp);
- return $return;
- }
- /**
- * Import DB
- *
- * @param string $fileName
- * @access public
- * @return object
- */
- 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');
- $sql = '';
- $startTags = '^DROP TABLE|^CREATE TABLE|^INSERT INTO|^SET|^DROP VIEW|^CREATE .*VIEW';
- $isInsert = false;
- while(!feof($fp))
- {
- $line = fgets($fp);
- if(empty($line)) continue;
- $sqlStart = false;
- $sqlEnd = false;
- $execSQL = false;
- if(empty($sql) and preg_match("/{$startTags}/", $line)) $sqlStart = true;
- if(!$isInsert and $sqlStart and strpos($line, 'INSERT INTO') === 0) $isInsert = true;
- $endTag = $isInsert ? "[^\\\]\'\);$" : ";$";
- if(preg_match("/{$endTag}/", $line)) $sqlEnd = true;
- if(!$sqlEnd && $isInsert && preg_match('/\,\s*null\);$/', $line)) $sqlEnd = true;
- if($sqlStart && $sqlEnd) // Only one line sql. e.g. DROP TABLE IF EXISTS `blog`;
- {
- $sql = $line;
- $execSQL = true;
- }
- elseif($sqlStart && !$sqlEnd) // Start sql line. e.g. CREATE TABLE `zt_account` (
- {
- $sql = $line;
- $execSQL = false;
- }
- elseif(!$sqlStart && !$sqlEnd) // Not start and not end. e.g. `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
- {
- $sql .= $line;
- $execSQL = false;
- }
- elseif($sqlEnd) // More line sql, and end line. e.g. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
- {
- $sql .= $line;
- $execSQL = true;
- }
- if($execSQL)
- {
- try
- {
- $this->dbh->exec($sql);
- }
- catch(PDOException $e)
- {
- $return->result = false;
- $return->error .= $e->getMessage() . "\n";
- }
- $sql = '';
- $isInsert = false;
- }
- }
- return $return;
- }
- /**
- * Get schema SQL.
- *
- * @param string $table
- * @access public
- * @return object
- */
- public function getSchemaSQL($table, $type = 'table')
- {
- $return = new stdclass();
- $return->result = true;
- $return->error = '';
- try
- {
- $sql = "SHOW CREATE $type `$table`";
- $createSql = $this->dbh->query($sql)->fetch(PDO::FETCH_ASSOC);
- $return->sql = $createSql['Create ' . ucfirst($type)] . ";\n";
- return $return;
- }
- catch(PDOException $e)
- {
- $return->result = false;
- $return->error = $e->getMessage();
- return $return;
- }
- }
- /**
- * Add slashes for string or string list.
- *
- * @param string|string[] $data
- * @return string|string[]
- */
- public function addslashes($data)
- {
- if(is_string($data)) return addslashes($data);
- $arrayIsList = function (array $array) : bool {
- if (function_exists('array_is_list')) {
- return array_is_list($array);
- }
- if ($array === []) {
- return true;
- }
- $current_key = 0;
- foreach ($array as $key => $noop) {
- if ($key !== $current_key) {
- return false;
- }
- ++$current_key;
- }
- return true;
- };
- if((function_exists('array_is_list') && $arrayIsList($data)) || (is_array($data) && array_keys($data) === array_keys(array_keys($data))))
- {
- $result = array();
- foreach($data as $item)
- {
- if(is_string($item))
- $result[] = addslashes($item);
- elseif(is_null($item))
- $result[] = null;
- else
- $result[] = $item;
- }
- return $result;
- }
- return $data;
- }
- }
|