database.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. <?php
  2. define('CURSCRIPT', 'database');
  3. //error_reporting(E_ALL ^ E_NOTICE ^ E_STRICT);
  4. //ini_set("display_errors", 1);
  5. error_reporting(0);
  6. set_time_limit(0);
  7. require_once dirname(__FILE__) . '/global.php';
  8. require_once MYMPS_INC . '/db.class.php';
  9. $allowpart = array('backup' => '数据库备份', 'restore' => '数据库恢复', 'optimize' => '数据库优化', 'check' => '数据库检查', 'repair' => '数据库修复');
  10. !(in_array($part, array_keys($allowpart))) && ($part = 'backup');
  11. $here = $allowpart[$part];
  12. $action = (isset($action) ? trim($action) : '');
  13. $tabletype = ('4.1' < $db->version() ? 'Engine' : 'Type');
  14. $version = MPS_VERSION;
  15. if ($admin_cityid) {
  16. write_msg('您没有权限访问该页!');
  17. }
  18. $backupdir = $mymps_global['cfg_backup_dir'];
  19. if ($part == 'backup') {
  20. chk_admin_purview('purview_数据库备份');
  21. if ($action != 'doaction') {
  22. $mymps_tables = fetchtablelist($db_mymps);
  23. $defaultfilename = date('ymd') . '_' . random(8);
  24. include mymps_tpl('db_' . $part);
  25. }
  26. else {
  27. $db->query('SET SQL_QUOTE_SHOW_CREATE=0', 'SILENT');
  28. if (!($filename) || preg_match('/(\\.)(exe|jsp|asp|aspx|cgi|fcgi|pl)(\\.|$)/i', $filename)) {
  29. write_msg('导出文件格式非法');
  30. }
  31. $time = GetTime($timestamp);
  32. if ($type == 'mymps') {
  33. $tables = arraykeys2(fetchtablelist($db_mymps), 'Name');
  34. }
  35. else if ($type == 'custom') {
  36. $tables = array();
  37. if (empty($setup)) {
  38. if ($tables = $db->fetch_first('SELECT value FROM `' . $db_mymps . 'config` WHERE description=\'custombackup\'')) {
  39. $tables = ($charset == 'utf-8' ? utf8_unserialize($tables['value']) : unserialize($tables['value']));
  40. }
  41. }
  42. else {
  43. $customtablesnew = (empty($customtables) ? '' : addslashes(serialize($customtables)));
  44. $db->query('DELETE FROM `' . $db_mymps . 'config` WHERE description = \'custombackup\' AND type = \'database\'');
  45. $db->query('INSERT INTO `' . $db_mymps . 'config` (description, value, type) VALUES (\'custombackup\', \'' . $customtablesnew . '\',\'database\')');
  46. $tables = &$customtables;
  47. }
  48. if (!(is_array($tables)) || empty($tables)) {
  49. write_msg('请选择你要备份的数据库表');
  50. }
  51. }
  52. $volume = intval($volume) + 1;
  53. $idstring = '# Identify: ' . base64_encode($timestamp . ',' . $version . ',' . $type . ',' . $method . ',' . $volume) . "\n";
  54. if($sqlcharset==""){$sqlcharset=$dbcharset;}
  55. $dumpcharset = ($sqlcharset ? $sqlcharset : $dbcharset);
  56. //echo $dumpcharset;
  57. //die();
  58. $setnames = ($sqlcharset && ('4.1' < $db->version()) && (!($sqlcompat) || ($sqlcompat == 'MYSQL41')) ? 'SET NAMES \'' . $dumpcharset . '\';' . "\n\n" : '');
  59. if ('4.1' < $db->version()) {
  60. if ($sqlcharset) {
  61. $db->query('SET NAMES \'' . $sqlcharset . '\';' . "\n\n");
  62. }
  63. if ($sqlcompat == 'MYSQL40') {
  64. $db->query('SET SQL_MODE=\'MYSQL40\'');
  65. }
  66. else if ($sqlcompat == 'MYSQL41') {
  67. $db->query('SET SQL_MODE=\'\'');
  68. }
  69. }
  70. $backupfilename = MYMPS_ROOT . $backupdir . '/' . str_replace(array('/', '\\', '.'), '', $filename);
  71. $sqldump = '';
  72. $tableid = intval($tableid);
  73. $startfrom = intval($startfrom);
  74. $complete = TRUE;
  75. for(; $complete && $tableid < count($tables) && strlen($sqldump) + 500 < $sizelimit * 1000; $tableid++) {
  76. $sqldump .= sqldumptable($tables[$tableid], $startfrom, strlen($sqldump));
  77. if($complete) {
  78. $startfrom = 0;
  79. }
  80. }
  81. $dumpfile = $backupfilename . '-%s' . '.sql';
  82. if(!($complete)){$tableid--;}
  83. if (trim($sqldump)) {
  84. $sqldump = $idstring . '# <?exit();?>' . "\n" . '# Mymps Multi-Volume Data Dump Vol.' . $volume . "\n" . '# Version: Mymps ' . $version . "\n" . '# Time: ' . $time . "\n" . '# Type: ' . $type . "\n" . '# Table Prefix: ' . $db_mymps . "\n" . '#' . "\n" . '# Mymps Home: http://www.mymps.com.cn' . "\n" . '# Please visit our website for newest infomation about Mymps' . "\n" . '# --------------------------------------------------------' . "\n\n\n" . $setnames . $sqldump;
  85. $dumpfilename = sprintf($dumpfile, $volume);
  86. @$fp = fopen($dumpfilename, 'wb');
  87. @flock($fp, 2);
  88. if (@!(fwrite($fp, $sqldump))) {
  89. @fclose($fp);
  90. write_msg('数据库备份失败,请检查备份目录的读写权限');
  91. }
  92. else {
  93. fclose($fp);
  94. unset($sqldump);
  95. unset($content);
  96. write_msg('数据文件 #' . $volume . ' 备份成功,系统将自动继续...', '?part=backup&type=' . rawurlencode($type) . '&filename=' . rawurlencode($filename) . '&method=multivol&sizelimit=' . rawurlencode($sizelimit) . '&volume=' . rawurlencode($volume) . '&tableid=' . rawurlencode($tableid) . '&startfrom=' . rawurlencode($startrow) . '&extendins=' . rawurlencode($extendins) . '&sqlcharset=' . rawurlencode($sqlcharset) . '&sqlcompat=' . rawurlencode($sqlcompat) . '&action=doaction');
  97. }
  98. }
  99. else {
  100. $volume--;
  101. for ($i = 1; $i <= $volume; $i++) {
  102. $filename = sprintf($dumpfile, $i);
  103. $filelist .= $filename . '<br>';
  104. }
  105. $db->query('DELETE FROM `' . $db_mymps . 'config` WHERE description = \'latestbackup\' AND type = \'database\'');
  106. $db->query('INSERT INTO `' . $db_mymps . 'config` (description, value, type) VALUES (\'latestbackup\', \'' . $timestamp . '\',\'database\')');
  107. write_msg('恭喜您,全部 ' . $volume . ' 个备份文件成功创建,备份完成。<br /><br />' . $filelist, 'olmsg');
  108. }
  109. }
  110. }
  111. else if ($part == 'restore') {
  112. chk_admin_purview('purview_数据库还原');
  113. if ($action == 'dorestore') {
  114. $readerror = 0;
  115. $datafile = '';
  116. if ($from == 'server') {
  117. $datafile = $datafile_server;
  118. }
  119. if (@$fp = fopen($datafile, 'rb')) {
  120. $sqldump = fgets($fp, 256);
  121. $identify = explode(',', base64_decode(preg_replace('/^# Identify:\\s*(\\w+).*/s', '\\1', $sqldump)));
  122. $dumpinfo = array('method' => $identify[3], 'volume' => intval($identify[4]));
  123. $sqldump .= fread($fp, filesize($datafile));
  124. fclose($fp);
  125. }
  126. else if ($autoimport) {
  127. updatecaches();
  128. write_msg('恭喜,数据还原操作成功!', 'olmsg');
  129. }
  130. else {
  131. write_msg('很遗憾,数据还原失败。', 'olmsg');
  132. }
  133. $sqlquery = splitsql($sqldump);
  134. unset($sqldump);
  135. foreach ($sqlquery as $sql ) {
  136. $sql = syntablestruct(trim($sql), '4.1' < $db->version(), $dbcharset);
  137. if ($sql != '') {
  138. $db->query($sql, 'SILENT');
  139. if (($sqlerror = $db->error()) && ($db->errno() != 1062)) {
  140. $db->halt('MySQL Query Error', $sql);
  141. }
  142. }
  143. }
  144. $datafile_next = preg_replace('/-(' . $dumpinfo['volume'] . ')(\\..+)$/', '-' . ($dumpinfo['volume'] + 1) . '\\2', $datafile_server);
  145. if ($dumpinfo['volume'] == 1) {
  146. write_msg('分卷数据第一卷成功导入数据库。<br /><br />您需要自动导入本次备份的其他分卷吗?<br /><br /><center><input class="gray" value="确定" type=button onclick="location.href=\'?part=restore&from=server&datafile_server=' . $datafile_next . '&autoimport=yes&action=dorestore\'">&nbsp;&nbsp;&nbsp;&nbsp;<input class="gray" type="button" onclick="location.href=\'?part=restore&from=server&datafile_server=' . $datafile_next . '&action=dorestore\'" value="取消"></center>', 'olmsg');
  147. }
  148. else if ($autoimport) {
  149. write_msg('数据文件 ' . $dumpinfo['volume'] . '# 成功导入,程序将自动继续。', '?part=restore&from=server&datafile_server=' . $datafile_next . '&autoimport=yes&action=dorestore');
  150. }
  151. else {
  152. updatecaches();
  153. write_msg('恭喜,数据还原操作成功。', 'olmsg');
  154. }
  155. }
  156. else if ($action == 'dodelete') {
  157. if (is_array($delete)) {
  158. foreach ($delete as $filename ) {
  159. $file_path = MYMPS_ROOT . $backupdir . '/' . str_replace(array('/', '\\'), '', $filename);
  160. if (is_file($file_path)) {
  161. @unlink($file_path);
  162. }
  163. else {
  164. $i = 1;
  165. while (1) {
  166. $file_path = MYMPS_ROOT . $backupdir . '/' . str_replace(array('/', '\\'), '', $filename . '-' . $i . '.sql');
  167. if (is_file($file_path)) {
  168. @unlink($file_path);
  169. $i++;
  170. }
  171. else {
  172. break;
  173. }
  174. }
  175. }
  176. }
  177. write_msg('恭喜,成功删除指定备份文件。', 'database.php?part=restore');
  178. }
  179. else {
  180. write_msg('操作失败,请检查备份目录的文件读写权限。');
  181. }
  182. }
  183. else {
  184. $backuptype = array('mymps' => 'Mymps全部数据表', 'custom' => '自定义备份');
  185. $exportlog = $exportsize = $exportziplog = array();
  186. if (is_dir(MYMPS_ROOT . $backupdir)) {
  187. $dir = dir(MYMPS_ROOT . $backupdir);
  188. while ($entry = $dir->read()) {
  189. $entry = MYMPS_ROOT . $backupdir . '/' . $entry;
  190. if (is_file($entry)) {
  191. if (preg_match('/\\.sql$/i', $entry)) {
  192. $filesize = filesize($entry);
  193. $fp = fopen($entry, 'rb');
  194. $identify = explode(',', base64_decode(preg_replace('/^# Identify:\\s*(\\w+).*/s', '\\1', fgets($fp, 256))));
  195. fclose($fp);
  196. $key = preg_replace('/^(.+?)(\\-\\d+)\\.sql$/i', '\\1', basename($entry));
  197. $exportlog[$key][$identify[4]] = array('version' => $identify[1], 'type' => $identify[2], 'method' => $identify[3], 'volume' => $identify[4], 'filename' => $entry, 'dateline' => filemtime($entry), 'size' => $filesize);
  198. $exportsize[$key] += $filesize;
  199. }
  200. }
  201. }
  202. $dir->close();
  203. }
  204. else {
  205. write_msg('无法识别备份的数据库文件目录');
  206. }
  207. include mymps_tpl('db_' . $part);
  208. }
  209. }
  210. else if ($part == 'optimize') {
  211. chk_admin_purview('purview_数据库维护');
  212. @set_time_limit(0);
  213. $optimizetable = '';
  214. $totalsize = 0;
  215. $tablearray = array($db_mymps);
  216. include !(submit_check('optimize_submit')) ? mymps_tpl('db_' . $part) : mymps_tpl('db_result');
  217. }
  218. else if ($part == 'check') {
  219. chk_admin_purview('purview_数据库维护');
  220. $optimizetable = '';
  221. $totalsize = 0;
  222. $tablearray = array($db_mymps);
  223. include !(submit_check('check_submit')) ? mymps_tpl('db_' . $part) : mymps_tpl('db_result');
  224. }
  225. else if ($part == 'repair') {
  226. chk_admin_purview('purview_数据库维护');
  227. $optimizetable = '';
  228. $totalsize = 0;
  229. $tablearray = array($db_mymps);
  230. include !(submit_check('repair_submit')) ? mymps_tpl('db_' . $part) : mymps_tpl('db_result');
  231. }
  232. function createtable($sql, $db_charset)
  233. {
  234. $type = strtoupper(preg_replace('/^\\s*CREATE TABLE\\s+.+\\s+\\(.+?\\).*(ENGINE|TYPE)\\s*=\\s*([a-z]+?).*$/isU', '\\2', $sql));
  235. $type = (in_array($type, array('MYISAM', 'HEAP')) ? $type : 'MYISAM');
  236. return preg_replace('/^\\s*(CREATE TABLE\\s+.+\\s+\\(.+?\\)).*$/isU', '\\1', $sql) . ('4.1' < mysql_get_server_info() ? ' ENGINE=' . $type . ' DEFAULT CHARSET=' . $db_charset : ' TYPE=' . $type);
  237. }
  238. function arraykeys2($array, $key2)
  239. {
  240. $return = array();
  241. foreach ($array as $val ) {
  242. $return[] = $val[$key2];
  243. }
  244. return $return;
  245. }
  246. function syntablestruct($sql, $version, $db_charset)
  247. {
  248. if (strpos(trim(substr($sql, 0, 18)), 'CREATE TABLE') === false) {
  249. return $sql;
  250. }
  251. $sqlversion = (strpos($sql, 'ENGINE=') === false ? false : true);
  252. if ($sqlversion === $version) {
  253. return $sqlversion && $db_charset ? preg_replace(array('/ character set \\w+/i', '/ collate \\w+/i', '/DEFAULT CHARSET=\\w+/is'), array('', '', 'DEFAULT CHARSET=' . $db_charset), $sql) : $sql;
  254. }
  255. if ($version) {
  256. return preg_replace(array('/TYPE=HEAP/i', '/TYPE=(\\w+)/is'), array('ENGINE=MEMORY DEFAULT CHARSET=' . $dbcharset, 'ENGINE=\\1 DEFAULT CHARSET=' . $dbcharset), $sql);
  257. }
  258. else {
  259. return preg_replace(array('/character set \\w+/i', '/collate \\w+/i', '/ENGINE=MEMORY/i', '/\\s*DEFAULT CHARSET=\\w+/is', '/\\s*COLLATE=\\w+/is', '/ENGINE=(\\w+)(.*)/is'), array('', '', 'ENGINE=HEAP', '', '', 'TYPE=\\1\\2'), $sql);
  260. }
  261. }
  262. function sqldumptable($table, $startfrom = 0, $currsize = 0)
  263. {
  264. global $db;
  265. global $sizelimit;
  266. global $startrow;
  267. global $extendins;
  268. global $sqlcompat;
  269. global $sqlcharset;
  270. global $dumpcharset;
  271. global $usehex;
  272. global $complete;
  273. global $excepttables;
  274. global $dbcharset;
  275. $offset = 300;
  276. $tabledump = '';
  277. $tablefields = array();
  278. $db->query("set names ".$dbcharset.";");
  279. $query = $db->query('SHOW FULL COLUMNS FROM ' . $table, 'SILENT');
  280. if (!($query) && ($db->errno() == 1146)) {
  281. return NULL;
  282. }
  283. else if (!($query)) {
  284. $usehex = false;
  285. }
  286. else {
  287. while ($fieldrow = $db->fetch_array($query)) {
  288. $tablefields[] = $fieldrow;
  289. }
  290. }
  291. if (!($startfrom)) {
  292. $createtable = $db->query('SHOW CREATE TABLE ' . $table, 'SILENT');
  293. if (!($db->error())) {
  294. $tabledump = 'DROP TABLE IF EXISTS ' . $table . ';' . "\n";
  295. }
  296. else {
  297. return '';
  298. }
  299. $create = $db->fetch_row($createtable);
  300. if (strpos($table, '.') !== false) {
  301. $tablename = substr($table, strpos($table, '.') + 1);
  302. $create[1] = str_replace('CREATE TABLE ' . $tablename, 'CREATE TABLE ' . $table, $create[1]);
  303. }
  304. $tabledump .= $create[1];
  305. if (($sqlcompat == 'MYSQL41') && ($db->version() < '4.1')) {
  306. $tabledump = preg_replace('/TYPE\\=(.+)/', 'ENGINE=\\1 DEFAULT CHARSET=' . $dumpcharset, $tabledump);
  307. }
  308. if (('4.1' < $db->version()) && $sqlcharset) {
  309. $tabledump = preg_replace('/(DEFAULT)*\\s*CHARSET=.+/', 'DEFAULT CHARSET=' . $sqlcharset, $tabledump);
  310. }
  311. $tablestatus = $db->fetch_first('SHOW TABLE STATUS LIKE \'' . $table . '\'');
  312. $tabledump .= ($tablestatus['Auto_increment'] ? ' AUTO_INCREMENT=' . $tablestatus['Auto_increment'] : '') . ';' . "\n\n";
  313. if (($sqlcompat == 'MYSQL40') && ('4.1' <= $db->version()) && ($db->version() < '5.1')) {
  314. if ($tablestatus['Auto_increment'] != '') {
  315. $temppos = strpos($tabledump, ',');
  316. $tabledump = substr($tabledump, 0, $temppos) . ' auto_increment' . substr($tabledump, $temppos);
  317. }
  318. if ($tablestatus['Engine'] == 'MEMORY') {
  319. $tabledump = str_replace('TYPE=MEMORY', 'TYPE=HEAP', $tabledump);
  320. }
  321. }
  322. }
  323. $tabledumped = 0;
  324. $numrows = $offset;
  325. $firstfield = $tablefields[0];
  326. if ($extendins == '0') {
  327. while ((($currsize + strlen($tabledump) + 500) < ($sizelimit * 1000)) && ($numrows == $offset)) {
  328. if ($firstfield['Extra'] == 'auto_increment') {
  329. $selectsql = 'SELECT * FROM ' . $table . ' WHERE ' . $firstfield['Field'] . ' > ' . $startfrom . ' LIMIT ' . $offset;
  330. }
  331. else {
  332. $selectsql = 'SELECT * FROM ' . $table . ' LIMIT ' . $startfrom . ', ' . $offset;
  333. }
  334. $tabledumped = 1;
  335. $rows = $db->query($selectsql);
  336. $numfields = $db->num_fields($rows);
  337. $numrows = $db->num_rows($rows);
  338. while ($row = $db->fetch_row($rows)) {
  339. $comma = $t = '';
  340. for ($i = 0; $i < $numfields; $i++) {
  341. //if (5.4 <= $db->version()) {
  342. //$t .= $comma . ($usehex && !(empty($row[$i])) && (strexists($tablefields[$i]['Type'], 'char') || strexists($tablefields[$i]['Type'], 'text')) ? '0x' . bin2hex($row[$i]) : '\'' . mysql_real_escape_string($row[$i],$db->link) . '\'');
  343. //}
  344. //else {
  345. $t .= $comma . ($usehex && !(empty($row[$i])) && (strexists($tablefields[$i]['Type'], 'char') || strexists($tablefields[$i]['Type'], 'text')) ? '0x' . bin2hex($row[$i]) : '\'' . @mysql_escape_string($row[$i]) . '\'');
  346. //}
  347. $comma = ',';
  348. }
  349. if ((strlen($t) + $currsize + strlen($tabledump) + 500) < ($sizelimit * 1000)) {
  350. if ($firstfield['Extra'] == 'auto_increment') {
  351. $startfrom = $row[0];
  352. }
  353. else {
  354. $startfrom++;
  355. }
  356. $tabledump .= 'INSERT INTO ' . $table . ' VALUES (' . $t . ');' . "\n";
  357. }
  358. else {
  359. $complete = false;
  360. break 2;
  361. }
  362. }
  363. }
  364. $startrow = $startfrom;
  365. $tabledump .= "\n";
  366. }
  367. return $tabledump;
  368. }
  369. function splitsql($sql)
  370. {
  371. $sql = str_replace("\r", "\n", $sql);
  372. $ret = array();
  373. $num = 0;
  374. $queriesarray = explode(';' . "\n", trim($sql));
  375. unset($sql);
  376. foreach ($queriesarray as $query ) {
  377. $queries = explode("\n", trim($query));
  378. foreach ($queries as $query ) {
  379. $ret[$num] .= ($query[0] == '#' ? NULL : $query);
  380. }
  381. $num++;
  382. }
  383. return $ret;
  384. }
  385. function slowcheck($type1, $type2)
  386. {
  387. $t1 = explode(' ', $type1);
  388. $t1 = $t1[0];
  389. $t2 = explode(' ', $type2);
  390. $t2 = $t2[0];
  391. $arr = array($t1, $t2);
  392. sort($arr);
  393. if ($arr == array('mediumtext', 'text')) {
  394. return true;
  395. }
  396. else {
  397. if ((substr($arr[0], 0, 4) == 'char') && (substr($arr[1], 0, 7) == 'varchar')) {
  398. return true;
  399. }
  400. }
  401. return false;
  402. }
  403. function sizecount($filesize)
  404. {
  405. if (1073741824 <= $filesize) {
  406. $filesize = (round(($filesize / 1073741824) * 100) / 100) . ' GB';
  407. }
  408. else if (1048576 <= $filesize) {
  409. $filesize = (round(($filesize / 1048576) * 100) / 100) . ' MB';
  410. }
  411. else if (1024 <= $filesize) {
  412. $filesize = (round(($filesize / 1024) * 100) / 100) . ' KB';
  413. }
  414. else {
  415. $filesize = $filesize . ' Bytes';
  416. }
  417. return $filesize;
  418. }
  419. is_object($db) && $db->Close();
  420. $db = $mymps_global = $part = $action = $here = NULL;
  421. ?>