Initial commit
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
|
||||
namespace OT;
|
||||
class DataDictionary{
|
||||
|
||||
public function __construct($table){
|
||||
$this->headers = $table['header'];
|
||||
$this->rows = $table['rows'];
|
||||
$this->crossingChar = '+';
|
||||
$this->horizontalBorderChar = '-';
|
||||
$this->verticalBorderChar = '|';
|
||||
$this->borderFormat = '%s';
|
||||
$this->cellHeaderFormat = '%s';
|
||||
$this->cellRowFormat = '%s';
|
||||
$this->paddingChar = ' ';
|
||||
$this->padType = STR_PAD_RIGHT;
|
||||
}
|
||||
/**
|
||||
* Renders table to output.
|
||||
*
|
||||
* Example:
|
||||
* +---------------+-----------------------+------------------+
|
||||
* | ISBN | Title | Author |
|
||||
* +---------------+-----------------------+------------------+
|
||||
* | 99921-58-10-7 | Divine Comedy | Dante Alighieri |
|
||||
* | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
|
||||
* | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
|
||||
* +---------------+-----------------------+------------------+
|
||||
*
|
||||
*/
|
||||
public function render($out = true){
|
||||
if(!$this->rows)
|
||||
exit('invalid table content');
|
||||
//获得表头行首 +---------------+-----------------------+------------------+
|
||||
$output = $this->renderRowSeparator();
|
||||
//获取头部输出| ISBN | Title | Author |
|
||||
$output .= $this->renderRow($this->headers, $this->cellHeaderFormat);
|
||||
//header存在的话再输出行分割符
|
||||
if ($this->headers) {
|
||||
$output .= $this->renderRowSeparator();
|
||||
}
|
||||
//渲染每一行
|
||||
foreach ($this->rows as $row) {
|
||||
$output .= $this->renderRow($row, $this->cellRowFormat);
|
||||
}
|
||||
if ($this->rows) {
|
||||
$output .= $this->renderRowSeparator();
|
||||
}
|
||||
if($out){
|
||||
exit($output);
|
||||
}else{
|
||||
$this->cleanup();
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
public function renderWitoutHeadTail($out = true){
|
||||
if(!$this->rows)
|
||||
exit('invalid table content');
|
||||
//获取头部输出| ISBN | Title | Author |
|
||||
$output .= $this->renderRow($this->headers, $this->cellHeaderFormat);
|
||||
//header存在的话再输出行分割符
|
||||
if ($this->headers) {
|
||||
$output .= $this->renderRowSeparator();
|
||||
}
|
||||
//渲染每一行
|
||||
foreach ($this->rows as $row) {
|
||||
$output .= $this->renderRow($row, $this->cellRowFormat);
|
||||
}
|
||||
if($out){
|
||||
print($output);
|
||||
}else{
|
||||
$this->cleanup();
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
//渲染表格行起始分割行
|
||||
private function renderRowSeparator(){
|
||||
if (0 === $count = $this->getNumberOfColumns()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$markup = $this->crossingChar;
|
||||
for ($column = 0; $column < $count; $column++) {
|
||||
$markup .= str_repeat($this->horizontalBorderChar, $this->getColumnWidth($column))
|
||||
.$this->crossingChar
|
||||
;
|
||||
}
|
||||
|
||||
return sprintf($this->borderFormat, $markup).PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染表格行.
|
||||
*
|
||||
* Example: | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
|
||||
*
|
||||
* @param array $row
|
||||
* @param string $cellFormat
|
||||
*/
|
||||
private function renderRow(array $row, $cellFormat){
|
||||
if (empty($row)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$output = $this->renderColumnSeparator();
|
||||
for ($column = 0, $count = $this->getNumberOfColumns(); $column < $count; $column++) {
|
||||
$output .= $this->renderCell($row, $column, $cellFormat);
|
||||
$output .= $this->renderColumnSeparator();
|
||||
}
|
||||
$output .= $this->writeln('');
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* 带边距的渲染单元格.
|
||||
*
|
||||
* @param array $row
|
||||
* @param integer $column
|
||||
* @param string $cellFormat
|
||||
*/
|
||||
private function renderCell(array $row, $column, $cellFormat){
|
||||
$cell = isset($row[$column]) ? $row[$column] : '';
|
||||
return sprintf(
|
||||
$cellFormat,
|
||||
$this->str_pad(
|
||||
$this->paddingChar.$cell.$this->paddingChar,
|
||||
$this->getColumnWidth($column),
|
||||
$this->paddingChar,
|
||||
$this->padType
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染水平列分隔符.
|
||||
*/
|
||||
private function renderColumnSeparator(){
|
||||
return(sprintf($this->borderFormat, $this->verticalBorderChar));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取表格的列数.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getNumberOfColumns() {
|
||||
if (null !== $this->numberOfColumns) {
|
||||
return $this->numberOfColumns;
|
||||
}
|
||||
|
||||
$columns = array(0);
|
||||
$columns[] = count($this->headers);
|
||||
foreach ($this->rows as $row) {
|
||||
$columns[] = count($row);
|
||||
}
|
||||
|
||||
return $this->numberOfColumns = max($columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列宽.
|
||||
*
|
||||
* @param integer $column
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getColumnWidth($column) {
|
||||
if (isset($this->columnWidths[$column])) {
|
||||
return $this->columnWidths[$column];
|
||||
}
|
||||
|
||||
$lengths = array(0);
|
||||
$lengths[] = $this->getCellWidth($this->headers, $column);
|
||||
foreach ($this->rows as $row) {
|
||||
$lengths[] = $this->getCellWidth($row, $column);
|
||||
}
|
||||
|
||||
return $this->columnWidths[$column] = max($lengths) + 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单元格宽度.
|
||||
*
|
||||
* @param array $row
|
||||
* @param integer $column
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getCellWidth(array $row, $column) {
|
||||
if ($column < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isset($row[$column])) {
|
||||
return $this->strlen($row[$column]);
|
||||
}
|
||||
|
||||
return $this->getCellWidth($row, $column - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of a string, using mb_strlen if it is available.
|
||||
*
|
||||
* @param string $string The string to check its length
|
||||
*
|
||||
* @return integer The length of the string
|
||||
*/
|
||||
protected function strlen($string) {
|
||||
// if (!function_exists('mb_strlen')) {
|
||||
return (strlen($string) + mb_strlen($string,'UTF8')) / 2;
|
||||
// }
|
||||
|
||||
// if (false === $encoding = mb_detect_encoding($string)) {
|
||||
// return strlen($string);
|
||||
// }
|
||||
|
||||
// return mb_strlen($string, $encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after rendering to cleanup cache data.
|
||||
*/
|
||||
private function cleanup(){
|
||||
$this->columnWidths = array();
|
||||
$this->numberOfColumns = null;
|
||||
}
|
||||
|
||||
public function writeln($line=''){
|
||||
return $line.PHP_EOL;
|
||||
}
|
||||
|
||||
public function str_pad($input , $pad_length ,$pad_string , $pad_type){
|
||||
$strlen = $this->strlen($input);
|
||||
if($strlen < $pad_length){
|
||||
$difference = $pad_length - $strlen;
|
||||
switch ($pad_type) {
|
||||
case STR_PAD_RIGHT:
|
||||
return $input . str_repeat($pad_string, $difference);
|
||||
break;
|
||||
case STR_PAD_LEFT:
|
||||
return str_repeat($pad_string, $difference) . $input;
|
||||
break;
|
||||
default:
|
||||
$left = $difference / 2;
|
||||
$right = $difference - $left;
|
||||
return str_repeat($pad_string, $left) . $input . str_repeat($pad_string, $right);
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
return $input;
|
||||
}
|
||||
}
|
||||
|
||||
//生成当前数据库指定表的数据字典(字符串)
|
||||
public function generate($tableName=''){
|
||||
$this->crossingChar = '|';
|
||||
$out_array = array();
|
||||
$output = '';
|
||||
if($tableName){
|
||||
echo substr($tableName, strlen(C('DB_PREFIX'))).PHP_EOL;
|
||||
$rows = array();
|
||||
$array = M()->query('SHOW FULL COLUMNS FROM '.$tableName);
|
||||
foreach ($array as $key => $value) {
|
||||
$rows[] = array($value['Field'], $value['Type'], $value['Comment']);
|
||||
}
|
||||
|
||||
$this->headers = array('字段','类型','注释');
|
||||
$this->rows = $rows;
|
||||
$this->renderWitoutHeadTail();
|
||||
}
|
||||
echo PHP_EOL;
|
||||
}
|
||||
|
||||
public function generateAll(){
|
||||
$tables = M()->query('SHOW TABLE STATUS;');
|
||||
$tables = array_column($tables,'Name');
|
||||
foreach ($tables as $value) {
|
||||
$this->generate($value);
|
||||
$this->cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace OT;
|
||||
use Think\Db;
|
||||
|
||||
//数据导出模型
|
||||
class Database{
|
||||
/**
|
||||
* 文件指针
|
||||
* @var resource
|
||||
*/
|
||||
private $fp;
|
||||
|
||||
/**
|
||||
* 备份文件信息 part - 卷号,name - 文件名
|
||||
* @var array
|
||||
*/
|
||||
private $file;
|
||||
|
||||
/**
|
||||
* 当前打开文件大小
|
||||
* @var integer
|
||||
*/
|
||||
private $size = 0;
|
||||
|
||||
/**
|
||||
* 备份配置
|
||||
* @var integer
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* 数据库备份构造方法
|
||||
* @param array $file 备份或还原的文件信息
|
||||
* @param array $config 备份配置信息
|
||||
* @param string $type 执行类型,export - 备份数据, import - 还原数据
|
||||
*/
|
||||
public function __construct($file, $config, $type = 'export'){
|
||||
$this->file = $file;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开一个卷,用于写入数据
|
||||
* @param integer $size 写入数据的大小
|
||||
*/
|
||||
private function open($size){
|
||||
if($this->fp){
|
||||
$this->size += $size;
|
||||
if($this->size > $this->config['part']){
|
||||
$this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp);
|
||||
$this->fp = null;
|
||||
$this->file['part']++;
|
||||
session('backup_file', $this->file);
|
||||
$this->create();
|
||||
}
|
||||
} else {
|
||||
$backuppath = $this->config['path'];
|
||||
$filename = "{$backuppath}{$this->file['name']}-{$this->file['part']}.sql";
|
||||
if($this->config['compress']){
|
||||
$filename = "{$filename}.gz";
|
||||
$this->fp = @gzopen($filename, "a{$this->config['level']}");
|
||||
} else {
|
||||
$this->fp = @fopen($filename, 'a');
|
||||
}
|
||||
$this->size = filesize($filename) + $size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入初始数据
|
||||
* @return boolean true - 写入成功,false - 写入失败
|
||||
*/
|
||||
public function create(){
|
||||
$sql = "-- -----------------------------\n";
|
||||
$sql .= "-- Think MySQL Data Transfer \n";
|
||||
$sql .= "-- \n";
|
||||
$sql .= "-- Host : " . C('DB_HOST') . "\n";
|
||||
$sql .= "-- Port : " . C('DB_PORT') . "\n";
|
||||
$sql .= "-- Database : " . C('DB_NAME') . "\n";
|
||||
$sql .= "-- \n";
|
||||
$sql .= "-- Part : #{$this->file['part']}\n";
|
||||
$sql .= "-- Date : " . date("Y-m-d H:i:s") . "\n";
|
||||
$sql .= "-- -----------------------------\n\n";
|
||||
$sql .= "SET FOREIGN_KEY_CHECKS = 0;\n\n";
|
||||
return $this->write($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入SQL语句
|
||||
* @param string $sql 要写入的SQL语句
|
||||
* @return boolean true - 写入成功,false - 写入失败!
|
||||
*/
|
||||
private function write($sql){
|
||||
$size = strlen($sql);
|
||||
|
||||
//由于压缩原因,无法计算出压缩后的长度,这里假设压缩率为50%,
|
||||
//一般情况压缩率都会高于50%;
|
||||
$size = $this->config['compress'] ? $size / 2 : $size;
|
||||
|
||||
$this->open($size);
|
||||
return $this->config['compress'] ? @gzwrite($this->fp, $sql) : @fwrite($this->fp, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 备份表结构
|
||||
* @param string $table 表名
|
||||
* @param integer $start 起始行数
|
||||
* @return boolean false - 备份失败
|
||||
*/
|
||||
public function backup($table, $start){
|
||||
//创建DB对象
|
||||
$db = Db::getInstance();
|
||||
|
||||
//备份表结构
|
||||
if(0 == $start){
|
||||
$result = $db->query("SHOW CREATE TABLE `{$table}`");
|
||||
$result=array_values($result[0]);//重新排列数据,避免因在大小写导致数组下标不统一
|
||||
$sql = "\n";
|
||||
$sql .= "-- -----------------------------\n";
|
||||
$sql .= "-- Table structure for `{$table}`\n";
|
||||
$sql .= "-- -----------------------------\n";
|
||||
$sql .= "DROP TABLE IF EXISTS `{$table}`;\n";
|
||||
$sql .= trim($result[1]) . ";\n\n";
|
||||
if(false === $this->write($sql)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//数据总数
|
||||
$result = $db->query("SELECT COUNT(*) AS count FROM `{$table}`");
|
||||
$count = $result['0']['count'];
|
||||
|
||||
//备份表数据
|
||||
if($count){
|
||||
//写入数据注释
|
||||
if(0 == $start){
|
||||
$sql = "-- -----------------------------\n";
|
||||
$sql .= "-- Records of `{$table}`\n";
|
||||
$sql .= "-- -----------------------------\n";
|
||||
$this->write($sql);
|
||||
}
|
||||
|
||||
//备份数据记录
|
||||
$result = $db->query("SELECT * FROM `{$table}` LIMIT {$start}, 1000");
|
||||
foreach ($result as $row) {
|
||||
$row = array_map('addslashes', $row);
|
||||
$row = array_map('nl2huanhang', $row);//把记录集的换行换成特定字符,防止出错
|
||||
$sql = "INSERT INTO `{$table}` VALUES ('" . implode("', '", $row) . "');\n";
|
||||
if(false === $this->write($sql)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//还有更多数据
|
||||
if($count > $start + 1000){
|
||||
return array($start + 1000, $count);
|
||||
}
|
||||
}
|
||||
|
||||
//备份下一表
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function import($start){
|
||||
//还原数据
|
||||
$db = Db::getInstance();
|
||||
|
||||
if($this->config['compress']){
|
||||
$gz = gzopen($this->file[1], 'r');
|
||||
$size = 0;
|
||||
} else {
|
||||
$size = filesize($this->file[1]);
|
||||
$gz = fopen($this->file[1], 'r');
|
||||
}
|
||||
|
||||
$sql = '';
|
||||
if($start){
|
||||
$this->config['compress'] ? gzseek($gz, $start) : fseek($gz, $start);
|
||||
}
|
||||
|
||||
for($i = 0; $i < 1000; $i++){
|
||||
$sql .= $this->config['compress'] ? gzgets($gz) : fgets($gz);
|
||||
if(preg_match('/.*;$/', trim($sql))){
|
||||
$sql=huanhang2nl($sql);//将备份时 把换行符转成其它字符的内容再转回来
|
||||
if(false !== $db->execute($sql)){
|
||||
$start += strlen($sql);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$sql = '';
|
||||
} elseif ($this->config['compress'] ? gzeof($gz) : feof($gz)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return array($start, $size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 析构方法,用于关闭文件资源
|
||||
*/
|
||||
public function __destruct(){
|
||||
$this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user