Tools.php
14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
<?php
/**
* tpshop
* ============================================================================
* 版权所有 2015-2027 深圳搜豹网络科技有限公司,并保留所有权利。
* 网站地址: http://www.tp-shop.cn
* ----------------------------------------------------------------------------
* 这不是一个自由软件!您只能在不用于商业目的的前提下对程序代码进行修改和使用 .
* 不允许对程序代码以任何形式任何目的的再发布。
* ============================================================================
* Author: 当燃
*
* Date: 2016-03-09
*/
namespace app\admin\controller;
use think\db;
class Tools extends Base {
public function index(){
$dbtables = DB::query('SHOW TABLE STATUS');
$total = 0;
foreach ($dbtables as $k => $v) {
$dbtables[$k]['size'] = format_bytes($v['Data_length'] + $v['Index_length']);
$total += $v['Data_length'] + $v['Index_length'];
}
$this->assign('list', $dbtables);
$this->assign('total', format_bytes($total));
$this->assign('tableNum', count($dbtables));
return $this->fetch('',getAdmStoId());
}
public function backup(){
@ini_set('memory_limit', '1024M');
//防止备份数据过程超时
function_exists('set_time_limit') && set_time_limit(0);
// send_http_status('310');
$tables = I('tables/a', array());
if (empty($tables)) {
$this->error('请选择要备份的数据表');
}
$time = time();//开始时间
// 检查存储目录不存在则创建
if(!file_exists(UPLOAD_PATH.'sqldata')){
mkdir(UPLOAD_PATH.'sqldata');
}
$path = UPLOAD_PATH."sqldata/tpshop_tables_" . date("Ymd").get_rand_str(3,0);
$pre = "# -----------------------------------------------------------\n";
$sqlNo = "# Description:备份的数据表[结构]:" . implode(",", $tables) . "\n";
//取得表结构信息
//1,表示表名和字段名会用``包着的,0 则不用``
DB::execute("SET SQL_QUOTE_SHOW_CREATE = 1");
foreach ($tables as $table) {
$sqlTable.="# 表的结构 {$table} \n";
$sqlTable .= "DROP TABLE IF EXISTS `{$table}`;\n";
$tmp = DB::query("SHOW CREATE TABLE {$table}");
$sqlTable .= $tmp[0]['Create Table'] . " ;\n\n";
}
$file_str = $pre . $sqlNo . $sqlTable . $outstr;
$file = $path . "_1". ".sql";
if (!file_put_contents($file, $file_str, FILE_APPEND)) {
$this->error("备份文件写入失败!", U('Tools/index'));
}
$outstr = ""; // 转存变量后 这里又清空了
$file_n = 2; // 第几个sql 文件
$backedTable = array(); // 已经备份了哪些表
//表中的数据
foreach ($tables as $table) {
$backedTable[] = $table;
$outstr.="\n\n# 转存表中的数据:{$table} \n";
$tableInfo = DB::query("SHOW TABLE STATUS LIKE '{$table}'");
$pagesize = 10000;
$page = ceil($tableInfo[0]['Rows'] / $pagesize); // 算一下有多少页
// 组装每一页的 insert 语句
for ($i = 1; $i <= $page; $i++) {
$offset = ($i-1) * $pagesize; // 起始位置
$query = DB::query("SELECT * FROM {$table} LIMIT $offset, $pagesize");
$insertSql = "";
foreach ($query as $val) {
$temSql = ""; // 当前这一页的插入语句
$tn = 0;
foreach ($val as $v) { // 每一行没一个字段的语句拼装
$temSql.=$tn == 0 ? "" : ",";
$temSql.=$v == '' ? "''" : "'{$v}'";
$tn++;
}
$insertSql .= "INSERT INTO `{$table}` VALUES ({$temSql});\n";
}
$sqlNo = "\n# Time: " . date("Y-m-d H:i:s") . "\n" .
"# -----------------------------------------------------------\n" .
"# SQLFile Label:#{$file_n}\n# -----------------------------------------------------------\n\n\n";
$sqlNo .= "# Description:备份的数据表[数据]:" . $table . $sqlNo;
$path = UPLOAD_PATH."sqldata/tpshop_{$table}_" . date("Ymd").get_rand_str(3,0);
$file = $path . "_" . $file_n . ".sql";
$outstr = $pre . $sqlNo . $outstr.$insertSql;
if (!file_put_contents($file, $outstr, FILE_APPEND)) {
$this->error("备份文件写入失败!", U('Tools/index'));
}
$outstr = "";
$backedTable = array();
$backedTable[] = $table;
$file_n++;
}
}
$time = time() - $time;
exit(json_encode(array('status'=>1,'msg'=>"成功备份数据表,本次备份共生成了" . ($file_n-1) . "个SQL文件。耗时:{$time} 秒")));
}
public function restore(){
$size = 0;
$pattern = "*.sql";
$filelist = glob(UPLOAD_PATH."sqldata/".$pattern);
$fileArray = array();
foreach ($filelist as $i => $file) {
//只读取文件
if (is_file($file)) {
$_size = filesize($file);
$size += $_size;
$name = basename($file);
$pre = substr($name, 0, strrpos($name, '_'));
$number = str_replace(array($pre. '_', '.sql'), array('', ''), $name);
$fileArray[] = array(
'name' => $name,
'pre' => $pre,
'time' => filemtime($file),
'size' => $_size,
'number' => $number,
);
}
}
if(empty($fileArray)) $fileArray = array();
krsort($fileArray); //按备份时间倒序排列
$this->assign('vlist', $fileArray);
$this->assign('total', format_bytes($size));
$this->assign('filenum', count($fileArray));
return $this->fetch('',getAdmStoId());
}
/**
* 读取要导入的sql文件列表并排序后插入SESSION中
*/
private function getRestoreFiles() {
$sqlfilepre = I('sqlfilepre','');//获取sql文件前缀 tpshop_tp_article_cat_20170206pno_4.sql.html
if (empty($sqlfilepre)) {
$this->error('请选择要还原的数据文件!');
}
$pattern = $sqlfilepre. "*.sql";
$sqlFiles = glob(UPLOAD_PATH."sqldata/".$pattern);
if (empty($sqlFiles)) {
$this->error('不存在对应的SQL文件!');
}
//将要还原的sql文件按顺序组成数组,防止先导入不带表结构的sql文件
$files = array();
foreach ($sqlFiles as $sqlFile) {
$sqlFile = basename($sqlFile);
$k = str_replace(".sql", "", str_replace($sqlfilepre . "_", "", $sqlFile));
$files[$k] = $sqlFile;
}
unset($sqlFiles, $sqlfilepre);
ksort($files);
return $files;
}
/**
* 执行还原数据库操作
*/
public function restoreData() {
@ini_set('memory_limit', '1024M');
function_exists('set_time_limit') && set_time_limit(0); //防止备份数据过程超时
//取得需要导入的sql文件
if (!isset($_SESSION['cacheRestore']['files'])) {
$_SESSION['cacheRestore']['starttime'] = time();
$_SESSION['cacheRestore']['files'][] = I('sqlfilepre','');//$this->getRestoreFiles();
}
$files = $_SESSION['cacheRestore']['files'];
if (empty($files)) {
unset($_SESSION['cacheRestore']);
$this->error('不存在对应的SQL文件');
}
//取得上次文件导入到sql的句柄位置
$position = isset($_SESSION['cacheRestore']['position']) ? $_SESSION['cacheRestore']['position'] : 0;
$execute = 0;
foreach ($files as $fileKey => $sqlFile) {
$file = UPLOAD_PATH."sqldata/". $sqlFile;
if (!file_exists($file))
continue;
$file = fopen($file, "r");
$sql = "";
fseek($file, $position); //将文件指针指向上次位置
while (!feof($file)) {
$tem = trim(fgets($file));
//过滤,去掉空行、注释行(#,--)
if (empty($tem) || $tem[0] == '#' || ($tem[0] == '-' && $tem[1] == '-'))
continue;
//统计一行字符串的长度
$end = (int) (strlen($tem) - 1);
//检测一行字符串最后有个字符是否是分号,是分号则一条sql语句结束,否则sql还有一部分在下一行中
if ($tem[$end] == ";") {
$sql .= $tem;
DB::execute($sql);
$sql = "";
$execute++;
if ($execute > 500) {
$_SESSION['cacheRestore']['position'] = ftell($file);
$imported = isset($_SESSION['cacheRestore']['imported']) ? $_SESSION['cacheRestore']['imported'] : 0;
$imported += $execute;
$_SESSION['cacheRestore']['imported'] = $imported;
//echo json_encode(array("status" => 1, "info" => '如果导入SQL文件卷较大(多)导入时间可能需要几分钟甚至更久,请耐心等待导入完成,导入期间请勿刷新本页,当前导入进度:<font color="red">已经导入' . $imported . '条Sql</font>', "url" => U('Database/restoreData', array(get_randomstr(5) => get_randomstr(5)))));
$this->success('如果SQL文件卷较大(多),则可能需要几分钟甚至更久,<br/>请耐心等待完成,<font color="red">请勿刷新本页</font>,<br/>当前导入进度:<font color="red">已经导入' . $imported . '条Sql</font>', U('Tools/restoreData', array(get_rand_str(5,0) => get_rand_str(5,0))));
exit();
}
} else {
$sql .= $tem;
}
}
//错误位置结束
fclose($file);
unset($_SESSION['cacheRestore']['files'][$fileKey]);
$position = 0;
}
$time = time() - $_SESSION['cacheRestore']['starttime'];
unset($_SESSION['cacheRestore']);
$this->success("导入成功,耗时:{$time} 秒钟", U('Tools/restore'));
}
/**
* 优化
*/
public function optimize() {
$batchFlag = I('get.batchFlag', 0, 'intval');
//批量删除
if ($batchFlag) {
$table = I('key', array());
}else {
$table[] = I('tablename' , '');
}
if (empty($table)) {
$this->error('请选择要优化的表');
}
$strTable = implode(',', $table);
if (!DB::query("OPTIMIZE TABLE {$strTable} ")) {
$strTable = '';
}
$this->success("优化表成功" . $strTable, U('Tools/index'));
}
/**
* 修复
*/
public function repair() {
$batchFlag = I('get.batchFlag', 0, 'intval');
//批量删除
if ($batchFlag) {
$table = I('key', array());
}else {
$table[] = I('tablename' , '');
}
if (empty($table)) {
$this->error('请选择修复的表');
}
$strTable = implode(',', $table);
if (!DB::query("REPAIR TABLE {$strTable} ")) {
$strTable = '';
}
$this->success("修复表成功" . $strTable, U('Tools/index'));
}
public function restoreUpload()
{
$file = request()->file('sqlfile');
// 移动到框架应用根目录/public/uploads/ 目录下
$save_url = 'public/upload/sqldata';
$info = $file->validate(['size'=>100000000,'ext'=>'sql',])->move($save_url,'');
if($info){
if (file_exists($save_url.'/'.$info->getFilename)) {
$this->success("上传成功", U('Tools/restore'));
} else {
$this->error('文件不存在');
}
}else{
// 上传失败获取错误信息
$this->error($file->getError());
}
}
/**
* 下载
*/
public function downFile() {
$file = $this->request->param('file');
$type = $this->request->param('type');
if (empty($file) || empty($type) || !in_array($type, array("zip", "sql"))) {
$this->error("下载地址不存在");
}
$path = array("zip" => UPLOAD_PATH."zipdata/", "sql" => UPLOAD_PATH."sqldata/");
$filePath = $path[$type] . $file;
if (!file_exists($filePath)) {
$this->error("该文件不存在,可能是被删除");
}
$filename = basename($filePath);
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . $filename . '"');
header("Content-Length: " . filesize($filePath));
readfile($filePath);
}
/**
* 删除sql文件
*/
public function delSqlFiles() {
$batchFlag = I('get.batchFlag', 0, 'intval');
//批量删除
if ($batchFlag) {
$files = I('key', array());
}else {
$files[] = I('sqlfilename' , '');
}
if (empty($files)) {
$this->error('请选择要删除的sql文件');
}
foreach ($files as $file) {
$a = unlink(UPLOAD_PATH."sqldata". '/' . $file);
}
if($a){
$this->success("已删除:" . implode(",", $files), U('Tools/restore'));
}else{
$this->error("删除失败:" . implode(",", $files), U('Tools/restore'));
}
}
public function region(){
$parent_id = I('parent_id',0);
if($parent_id == 0){
$parent = array('id'=>0,'name'=>"中国省份地区",'level'=>0);
}else{
$parent = M('region')->where("id=$parent_id")->find();
}
$region = M('region')->where("parent_id=$parent_id")->select();
$this->assign('parent',$parent);
$this->assign('region',$region);
return $this->fetch('',getAdmStoId());
}
public function regionHandle(){
$data = I('post.');
$id = I('id');
$referurl = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : U("Tools/region");
if(empty($id)){
$data['level'] = $data['level']+1;
if(empty($data['name'])){
$this->error("请填写地区名称", $referurl);
}else{
$res = M('region')->where("parent_id = ".$data['parent_id']." and name='".$data['name']."'")->find();
if(empty($res)){
M('region')->add($data);
$this->success("操作成功", $referurl);
}else{
$this->error("该区域下已有该地区,请不要重复添加", $referurl);
}
}
}else{
M('region')->where("id=$id or parent_id=$id")->delete();
$this->success("操作成功", $referurl);
}
}
}