1
0

Database.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. <?php
  2. namespace app\admin\controller;
  3. use think\Db;
  4. use app\common\util\Dir;
  5. use app\common\util\Database as dbOper;
  6. class Database extends Base
  7. {
  8. var $_db_config;
  9. public function __construct()
  10. {
  11. parent::__construct();
  12. }
  13. public function index()
  14. {
  15. $group = input('group');
  16. if($group=='import'){
  17. //列出备份文件列表
  18. $path = trim( $GLOBALS['config']['db']['backup_path'], '/').DS;
  19. if (!is_dir($path)) {
  20. Dir::create($path);
  21. }
  22. $flag = \FilesystemIterator::KEY_AS_FILENAME;
  23. $glob = new \FilesystemIterator($path, $flag);
  24. $list = [];
  25. foreach ($glob as $name => $file) {
  26. if(preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql(?:\.gz)?$/', $name)){
  27. $name = sscanf($name, '%4s%2s%2s-%2s%2s%2s-%d');
  28. $date = "{$name[0]}-{$name[1]}-{$name[2]}";
  29. $time = "{$name[3]}:{$name[4]}:{$name[5]}";
  30. $part = $name[6];
  31. if(isset($list["{$date} {$time}"])){
  32. $info = $list["{$date} {$time}"];
  33. $info['part'] = max($info['part'], $part);
  34. $info['size'] = $info['size'] + $file->getSize();
  35. } else {
  36. $info['part'] = $part;
  37. $info['size'] = $file->getSize();
  38. }
  39. $extension = strtoupper($file->getExtension());
  40. $info['compress'] = ($extension === 'SQL') ? '无' : $extension;
  41. $info['time'] = strtotime("{$date} {$time}");
  42. $list["{$date} {$time}"] = $info;
  43. }
  44. }
  45. }
  46. else{
  47. $group='export';
  48. $list = Db::query("SHOW TABLE STATUS");
  49. }
  50. $this->assign('list',$list);
  51. $this->assign('title',lang('admin/database/title'));
  52. return $this->fetch('admin@database/'.$group);
  53. }
  54. public function export($ids = '', $start = 0)
  55. {
  56. if ($this->request->isPost()) {
  57. if (empty($ids)) {
  58. return $this->error(lang('admin/database/select_export_table'));
  59. }
  60. if (!is_array($ids)) {
  61. $tables[] = $ids;
  62. } else {
  63. $tables = $ids;
  64. }
  65. $have_admin = false;
  66. $admin_table='';
  67. foreach($tables as $k=>$v){
  68. if(strpos($v,'_admin')!==false){
  69. $have_admin=true;
  70. $admin_table = $v;
  71. unset($tables[$k]);
  72. }
  73. }
  74. if($have_admin){
  75. $tables[] = $admin_table;
  76. }
  77. //读取备份配置
  78. $config = array(
  79. 'path' => $GLOBALS['config']['db']['backup_path'] .DS,
  80. 'part' => $GLOBALS['config']['db']['part_size'] ,
  81. 'compress' => $GLOBALS['config']['db']['compress'] ,
  82. 'level' => $GLOBALS['config']['db']['compress_level'] ,
  83. );
  84. //检查是否有正在执行的任务
  85. $lock = "{$config['path']}backup.lock";
  86. if(is_file($lock)){
  87. return $this->error(lang('admin/database/lock_check'));
  88. } else {
  89. if (!is_dir($config['path'])) {
  90. Dir::create($config['path'], 0755, true);
  91. }
  92. //创建锁文件
  93. file_put_contents($lock, $this->request->time());
  94. }
  95. //生成备份文件信息
  96. $file = [
  97. 'name' => date('Ymd-His', $this->request->time()),
  98. 'part' => 1,
  99. ];
  100. // 创建备份文件
  101. $database = new dbOper($file, $config);
  102. if($database->create() !== false) {
  103. // 备份指定表
  104. foreach ($tables as $table) {
  105. $start = $database->backup($table, $start);
  106. while (0 !== $start) {
  107. if (false === $start) {
  108. return $this->error(lang('admin/database/backup_err'));
  109. }
  110. $start = $database->backup($table, $start[0]);
  111. }
  112. }
  113. // 备份完成,删除锁定文件
  114. unlink($lock);
  115. }
  116. return $this->success(lang('admin/database/backup_ok'));
  117. }
  118. return $this->error(lang('admin/database/backup_err'));
  119. }
  120. /**
  121. * 恢复数据库 [参考原作者 麦当苗儿 <[email protected]>]
  122. * @param string|array $ids 表名
  123. * @param integer $start 起始行数
  124. * @author 橘子俊 <[email protected]>
  125. * @return mixed
  126. */
  127. public function import($id = '')
  128. {
  129. if (empty($id)) {
  130. return $this->error(lang('admin/database/select_file'));
  131. }
  132. $name = date('Ymd-His', $id) . '-*.sql*';
  133. $path = trim( $GLOBALS['config']['db']['backup_path'] , '/').DS.$name;
  134. $files = glob($path);
  135. $list = array();
  136. foreach($files as $name){
  137. $basename = basename($name);
  138. $match = sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d');
  139. $gz = preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql.gz$/', $basename);
  140. $list[$match[6]] = array($match[6], $name, $gz);
  141. }
  142. ksort($list);
  143. // 检测文件正确性
  144. $last = end($list);
  145. if(count($list) === $last[0]){
  146. foreach ($list as $item) {
  147. $config = [
  148. 'path' => trim($GLOBALS['config']['db']['backup_path'], '/').DS,
  149. 'compress' => $item[2]
  150. ];
  151. $database = new dbOper($item, $config);
  152. $start = $database->import(0);
  153. // 导入所有数据
  154. while (0 !== $start) {
  155. if (false === $start) {
  156. return $this->error(lang('admin/database/import_err'));
  157. }
  158. $start = $database->import($start[0]);
  159. }
  160. }
  161. return $this->success(lang('admin/database/import_ok'));
  162. }
  163. return $this->error(lang('admin/database/file_damage'));
  164. }
  165. public function optimize($ids = '')
  166. {
  167. if (empty($ids)) {
  168. return $this->error(lang('admin/database/select_optimize_table'));
  169. }
  170. if (!is_array($ids)) {
  171. $table[] = $ids;
  172. } else {
  173. $table = $ids;
  174. }
  175. $tables = implode('`,`', $table);
  176. $res = Db::query("OPTIMIZE TABLE `{$tables}`");
  177. if ($res) {
  178. return $this->success(lang('admin/database/optimize_ok'));
  179. }
  180. return $this->error(lang('admin/database/optimize_err'));
  181. }
  182. public function repair($ids = '')
  183. {
  184. if (empty($ids)) {
  185. return $this->error(lang('admin/database/select_repair_table'));
  186. }
  187. if (!is_array($ids)) {
  188. $table[] = $ids;
  189. } else {
  190. $table = $ids;
  191. }
  192. $tables = implode('`,`', $table);
  193. $res = Db::query("REPAIR TABLE `{$tables}`");
  194. if ($res) {
  195. return $this->success(lang('admin/database/repair_ok'));
  196. }
  197. return $this->error(lang('admin/database/repair_ok'));
  198. }
  199. public function del($id = '')
  200. {
  201. if (empty($id)) {
  202. return $this->error(lang('admin/database/select_del_file'));
  203. }
  204. $name = date('Ymd-His', $id) . '-*.sql*';
  205. $path = trim($GLOBALS['config']['db']['backup_path']).DS.$name;
  206. array_map("unlink", glob($path));
  207. if(count(glob($path)) && glob($path)){
  208. return $this->error(lang('del_err'));
  209. }
  210. return $this->success(lang('del_ok'));
  211. }
  212. public function sql()
  213. {
  214. if($this->request->isPost()){
  215. $param=input();
  216. $validate = \think\Loader::validate('Token');
  217. if(!$validate->check($param)){
  218. return $this->error($validate->getError());
  219. }
  220. $sql = trim($param['sql']);
  221. if(!empty($sql)){
  222. $sql = str_replace('{pre}',config('database.prefix'),$sql);
  223. //查询语句返回结果集
  224. if(strtolower(substr($sql,0,6))=="select"){
  225. }
  226. else{
  227. Db::execute($sql);
  228. }
  229. }
  230. $this->success(lang('run_ok'));
  231. }
  232. return $this->fetch('admin@database/sql');
  233. }
  234. public function columns()
  235. {
  236. $param = input();
  237. $table = $param['table'];
  238. if(!empty($table)){
  239. $list = Db::query('SHOW COLUMNS FROM '.$table);
  240. $this->success(lang('obtain_ok'),null, $list);
  241. }
  242. $this->error(lang('param_err'));
  243. }
  244. public function rep()
  245. {
  246. if($this->request->isPost()){
  247. $param = input();
  248. $table = $param['table'];
  249. $field = $param['field'];
  250. $findstr = $param['findstr'];
  251. $tostr = $param['tostr'];
  252. $where = $param['where'];
  253. $validate = \think\Loader::validate('Token');
  254. if(!$validate->check($param)){
  255. return $this->error($validate->getError());
  256. }
  257. if(!empty($table) && !empty($field) && !empty($findstr) && !empty($tostr)){
  258. $sql = "UPDATE ".$table." set ".$field."=Replace(".$field.",'".$findstr."','".$tostr."') where 1=1 ". $where;
  259. Db::execute($sql);
  260. return $this->success(lang('run_ok'));
  261. }
  262. return $this->error(lang('param_err'));
  263. }
  264. $list = Db::query("SHOW TABLE STATUS");
  265. $this->assign('list',$list);
  266. return $this->fetch('admin@database/rep');
  267. }
  268. public function inspect()
  269. {
  270. $param = input();
  271. if ($param['ck']) {
  272. $pre = config('database.prefix');
  273. $schema = Db::query('select * from information_schema.columns where table_schema = ?', [config('database.database')]);
  274. $col_list = [];
  275. $sql = '';
  276. foreach ($schema as $k => $v) {
  277. $col_list[$v['TABLE_NAME']][$v['COLUMN_NAME']] = $v;
  278. }
  279. $tables = ['actor', 'art', 'gbook', 'link', 'topic', 'type', 'vod'];
  280. $param['tbi'] = intval($param['tbi']);
  281. if ($param['tbi'] >= count($tables)) {
  282. mac_echo(lang('admin/database/clear_ok'));
  283. die;
  284. }
  285. $check_arr = ["<script>", "<iframe>"];
  286. $rel_val = ["/<script[\s\S]*?<\/script>/is","/<iframe[\s\S]*?<\/iframe>/is"];
  287. mac_echo('<style type="text/css">body{font-size:12px;color: #333333;line-height:21px;}span{font-weight:bold;color:#FF0000}</style>');
  288. foreach ($col_list as $k1 => $v1) {
  289. $pre_tb = str_replace($pre, '', $k1);
  290. $si = array_search($pre_tb, $tables);
  291. if ($pre_tb !== $tables[$param['tbi']]) {
  292. continue;
  293. }
  294. mac_echo(lang('admin/database/check_tip1',[$k1]));
  295. $where = [];
  296. foreach ($v1 as $k2 => $v2) {
  297. if (strpos($v2['DATA_TYPE'], 'int') === false) {
  298. $where[$k2] = ['like', mac_like_arr(join(',', $check_arr)), 'OR'];
  299. }
  300. }
  301. if (!empty($where)) {
  302. $field = array_keys($where);
  303. $field[] = $tables[$si] . '_id';
  304. $list = Db::name($pre_tb)->field($field)->whereOr($where)->fetchSql(false)->select();
  305. mac_echo(lang('admin/database/check_tip2',[count($list)]));
  306. foreach ($list as $k3 => $v3) {
  307. $update = [];
  308. $col_id = $tables[$si] . '_id';
  309. $col_name = $tables[$si] . '_name';
  310. $val_id = $v3[$col_id];;
  311. $val_name = strip_tags($v3[$col_name]);
  312. $ck = false;
  313. $where2 = [];
  314. $where2[$col_id] = $val_id;
  315. foreach ($v3 as $k4 => $v4) {
  316. if ($k4 != $col_id) {
  317. $val = $v4;
  318. foreach ($check_arr as $kk => $vv) {
  319. $val = preg_replace($rel_val[$kk], "", $val);
  320. }
  321. if ($val !== $v4) {
  322. $update[$k4] = $val;
  323. $ck = true;
  324. }
  325. }
  326. }
  327. if ($ck) {
  328. $r = Db::name($pre_tb)->where($where2)->update($update);
  329. mac_echo($val_id . '、' . $val_name . ' ok');
  330. }
  331. }
  332. }
  333. }
  334. $param['tbi']++;
  335. $url = url('database/inspect') . '?' . http_build_query($param);
  336. mac_jump($url, 3);
  337. exit;
  338. }
  339. return $this->fetch('admin@database/inspect');
  340. }
  341. }