• PHP备份MySQL数据库的详解


    一、标准的数据库导出内容讲解

    先看一个标准的数据库导出的sql内容:

    1. /*
    2.  Navicat Premium Data Transfer
    3.  Source Server         : 192.168.1.122
    4.  Source Server Type    : MySQL
    5.  Source Server Version : 50621
    6.  Source Host           : 192.168.1.122:3306
    7.  Source Schema         : db1
    8.  Target Server Type    : MySQL
    9.  Target Server Version : 50621
    10.  File Encoding         : 65001
    11.  Date: 20/07/2022 17:44:22
    12. */
    13. SET NAMES utf8mb4;
    14. SET FOREIGN_KEY_CHECKS = 0;
    15. -- ----------------------------
    16. -- Table structure for table1
    17. -- ----------------------------
    18. DROP TABLE IF EXISTS `table1`;
    19. CREATE TABLE `table1`  (
    20.   `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
    21.   `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
    22.   `age` int(11) NULL DEFAULT NULL,
    23.   PRIMARY KEY (`id`) USING BTREE,
    24.   INDEX `name`(`name`) USING BTREE,
    25.   INDEX `age`(`age`) USING BTREE
    26. ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
    27. -- ----------------------------
    28. -- Records of table1
    29. -- ----------------------------
    30. INSERT INTO `table1` VALUES (1, '王明', 30);
    31. INSERT INTO `table1` VALUES (2, '张芳', 28);
    32. SET FOREIGN_KEY_CHECKS = 1;

    标注导出的数据库信息:

    1. /*
    2.  Navicat Premium Data Transfer
    3.  Source Server         : 192.168.1.122
    4.  Source Server Type    : MySQL
    5.  Source Server Version : 50621
    6.  Source Host           : 192.168.1.122:3306
    7.  Source Schema         : db1
    8.  Target Server Type    : MySQL
    9.  Target Server Version : 50621
    10.  File Encoding         : 65001
    11.  Date: 20/07/2022 17:44:22
    12. */

    设置UTF-8编码格式:

    SET NAMES utf8mb4;

    取消外键约束 (参数为0) 和设置外键约束 (参数为1) : 

    1. SET FOREIGN_KEY_CHECKS = 0;
    2. SET FOREIGN_KEY_CHECKS = 1;

     表结构:

    1. -- ----------------------------
    2. -- Table structure for table1
    3. -- ----------------------------
    4. DROP TABLE IF EXISTS `table1`;
    5. CREATE TABLE `table1`  (
    6.   `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
    7.   `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
    8.   `age` int(11) NULL DEFAULT NULL,
    9.   PRIMARY KEY (`id`) USING BTREE,
    10.   INDEX `name`(`name`) USING BTREE,
    11.   INDEX `age`(`age`) USING BTREE
    12. ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

    表数据:

    1. -- ----------------------------
    2. -- Records of table1
    3. -- ----------------------------
    4. INSERT INTO `table1` VALUES (1, '王明', 30);
    5. INSERT INTO `table1` VALUES (2, '张芳', 28);

    二、PHP导出数据库的常用操作

    查询某个库是否存在,有两种写法:

    1. SELECT * FROM `information_schema`.SCHEMATA WHERE SCHEMA_NAME="db1";
    2. SHOW DATABASES LIKE "db1";

    查询某个表是否存在,有两种写法:

    1. SELECT * FROM `information_schema`.TABLES WHERE TABLE_NAME="table1";
    2. SHOW TABLES LIKE "table1";

    查询某个库的某个表的某个字段是否存在:

    SELECT * FROM `information_schema`.COLUMNS WHERE TABLE_SCHEMA="db1" AND TABLE_NAME="table1" AND COLUMN_NAME="name";

    获取某个库下的全部表名称:

    SHOW TABLES;

    获取表结构:

    SHOW CREATE TABLE `table1`;

    获取表数据,包括表字段和表数据:

    1. SHOW COLUMNS FROM `table1`;
    2. SELECT * FROM `table1`;

    完整的扩展类代码:

    1. header("Content-Type: text/html;charset=utf-8");
    2. /**
    3. * 备份数据库的扩展类
    4. */
    5. class BackService{
    6. private $config=[];
    7. private $handler;
    8. private $table = array(); //需要备份的表
    9. private $begin; //开始时间
    10. private $error; //错误信息
    11. public function __construct($config) {
    12. $config['path'] = './file/'; //默认路径
    13. $config['sqlbakname'] = 'bak.sql'; //备份文件名称
    14. $this->config = $config;
    15. $this->connect();
    16. }
    17. //首次进行pdo连接
    18. private function connect() {
    19. try{
    20. $this->handler = new \PDO("{$this->config['type']}:host={$this->config['hostname']};port={$this->config['hostport']};dbname={$this->config['database']}",
    21. $this->config['username'],
    22. $this->config['password'],
    23. array(
    24. \PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES {$this->config['charset']}",
    25. \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
    26. \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
    27. ));
    28. }catch (PDOException $e) {
    29. exit( "Error! ".$e->getMessage()."
      "
      );
    30. }
    31. }
    32. /**
    33. * 查询
    34. * @param string $sql
    35. * @return mixed
    36. */
    37. private function query($sql = '')
    38. {
    39. $stmt = $this->handler->query($sql);
    40. $stmt->setFetchMode(\PDO::FETCH_NUM);
    41. $list = $stmt->fetchAll();
    42. return $list;
    43. }
    44. /**
    45. * 获取全部表
    46. * @param string $dbName
    47. * @return array
    48. */
    49. private function get_dbname($dbName = '*') {
    50. $sql = "SHOW TABLES";
    51. $list = $this->query($sql);
    52. $tables = array();
    53. foreach($list as $value){
    54. $tables[] = $value[0];
    55. }
    56. return $tables;
    57. }
    58. /**
    59. * 获取表定义语句
    60. * @param string $dbName
    61. * @return mixed
    62. */
    63. private function get_dbhead($table = '') {
    64. $sql = "SHOW CREATE TABLE `{$table}`";
    65. $ddl = $this->query($sql)[0][1].";";
    66. return $ddl;
    67. }
    68. /**
    69. * 获取表数据
    70. * @param string $table
    71. * @return mixed
    72. */
    73. private function get_dbdata($table = '')
    74. {
    75. $sql = "SHOW COLUMNS FROM `{$table}`";
    76. $list = $this->query($sql);
    77. //字段
    78. $columns = '';
    79. foreach($list as $value){
    80. $columns .= "`".$value[0]."`,";
    81. }
    82. $columns = substr($columns, 0, -1);
    83. //需要返回的SQL
    84. $query = '';
    85. $data = $this->query("SELECT * FROM `{$table}`");
    86. foreach($data as $value){
    87. $dataSql = '';
    88. foreach($value as $v){
    89. $dataSql .= "'".$v."',";
    90. }
    91. $dataSql = substr($dataSql, 0, -1);
    92. $query .= "INSERT INTO `{$table}` ({$columns}) VALUES ({$dataSql});\r\n";
    93. }
    94. return $query;
    95. }
    96. /**
    97. * 写入文件
    98. * @param array $tables
    99. * @param array $ddl
    100. * @param array $data
    101. */
    102. private function writeToFile($tables = array(), $ddl = array(), $data = array())
    103. {
    104. $verRes = $this->query("SELECT VERSION()");
    105. $version = str_replace('.', '', str_replace('-log', '', $verRes[0][0]));
    106. $version = substr($version, 0, 1).'0'.substr($version, 1);
    107. $str = "/*\r\nMySQL Database Backup Tools\r\n";
    108. $str .= "Source Server Type : {$this->config['type']}\r\n";
    109. $str .= "Source Server Version : {$version}\r\n";
    110. $str .= "Source Host : {$this->config['hostname']}:{$this->config['hostport']}\r\n";
    111. $str .= "Source Schema : {$this->config['database']}\r\n\r\n";
    112. $str .= "Date: ".date('d/m/Y H:i:s')."\r\n*/\r\n";
    113. $str .= "SET NAMES utf8mb4;\r\n";
    114. $str .= "SET FOREIGN_KEY_CHECKS = 0;\r\n";
    115. $i = 0;
    116. foreach($tables as $table){
    117. $str .= "-- ----------------------------\r\n";
    118. $str .= "-- Table structure for {$table}\r\n";
    119. $str .= "-- ----------------------------\r\n";
    120. $str .= "DROP TABLE IF EXISTS `{$table}`;\r\n";
    121. $str .= $ddl[$i]."\r\n";
    122. $str .= "-- ----------------------------\r\n";
    123. $str .= "-- Records of {$table}\r\n";
    124. $str .= "-- ----------------------------\r\n";
    125. $str .= $data[$i]."\r\n";
    126. $i++;
    127. }
    128. if(!file_exists($this->config['path'])){
    129. mkdir($this->config['path']);
    130. }
    131. return file_put_contents($this->config['path'].$this->config['sqlbakname'], $str) ? true : false;
    132. }
    133. /**
    134. * 设置要备份的表
    135. * @param array $tables
    136. */
    137. private function setTables($tables = array())
    138. {
    139. if(!empty($tables) && is_array($tables)){
    140. //备份指定表
    141. $this->tables = $tables;
    142. }else{
    143. //备份全部表
    144. $this->tables = $this->get_dbname();
    145. }
    146. }
    147. /**
    148. * 备份
    149. * @param array $tables
    150. * @return bool
    151. */
    152. public function backup($tables = array())
    153. {
    154. //存储表定义语句的数组
    155. $ddl = array();
    156. //存储数据的数组
    157. $data = array();
    158. $this->setTables($tables);
    159. if(!empty($this->tables)){
    160. foreach($this->tables as $table){
    161. $tableIsExist = $this->query("SELECT * FROM `information_schema`.TABLES WHERE TABLE_NAME='{$table}'");
    162. if(!$tableIsExist){
    163. $this->error = "表 {$table} 不存在";
    164. exit($this->getError());
    165. }
    166. $ddl[] = $this->get_dbhead($table);
    167. $data[] = $this->get_dbdata($table);
    168. }
    169. //开始写入
    170. return $this->writeToFile($this->tables, $ddl, $data);
    171. }else{
    172. $this->error = '数据库中没有表';
    173. return false;
    174. }
    175. }
    176. /**
    177. * 错误信息
    178. * @return mixed
    179. */
    180. public function getError()
    181. {
    182. return $this->error;
    183. }
    184. /**
    185. * 恢复数据库
    186. */
    187. public function restore()
    188. {
    189. $filename = $this->config['sqlbakname'];
    190. $path = $this->config['path'].$filename;
    191. if(!file_exists($path)){
    192. $this->error("SQL文件不存在");
    193. return false;
    194. }else{
    195. $sql = $this->parseSQL($path);
    196. try{
    197. $this->handler->exec($sql);
    198. return true;
    199. }catch (PDOException $E){
    200. $this->error = $e->getMessage();
    201. return false;
    202. }
    203. }
    204. }
    205. /**
    206. * 解析SQL文件为SQL语句数组
    207. * @param string $path
    208. * @return array|mixed|string
    209. */
    210. private function parseSQL($path = '')
    211. {
    212. $sql = file_get_contents($path);
    213. $sql = explode("\r\n", $sql);
    214. //先消除 -- 注释
    215. $sql = array_filter($sql, function($data){
    216. if(empty($data) || preg_match('/.*--.*/', $data)){
    217. return false;
    218. }else{
    219. return true;
    220. }
    221. });
    222. $sql = implode('', $sql);
    223. //删除 /**/ 注释
    224. $sql = preg_replace('/\/\*.*\*\//', '', $sql);
    225. return $sql;
    226. }
    227. /**
    228. * 下载备份文件
    229. * @param string $fileName
    230. * @return array|mixed|string
    231. */
    232. public function downloadFile()
    233. {
    234. $fileName = $this->config['sqlbakname'];
    235. $fileName = $this->config['path'].$fileName;
    236. if(file_exists($fileName)){
    237. ob_end_clean();
    238. header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    239. header("Content-Description: File Transfer");
    240. header("Content-Type: application/octet-stream");
    241. header("Content-Length: ".filesize($fileName));
    242. header("Content-Disposition: attachment; filename=".basename($fileName));
    243. readfile($fileName);
    244. }else{
    245. $this->error="文件不存在";
    246. }
    247. }
    248. /**
    249. * 获取文件时间
    250. * @param string $file
    251. * @return string
    252. */
    253. private function getfiletime($file)
    254. {
    255. $path = $this->config['path'].$file;
    256. $a = filemtime($path);
    257. $time = date('Y-m-d H:i:s', $a);
    258. return $time;
    259. }
    260. /**
    261. * 获取文件大小
    262. * @param string $file
    263. * @return string
    264. */
    265. private function getfilesize($file)
    266. {
    267. $perms = stat($this->config['path'].$file);
    268. $size = $perms['size'];
    269. $a = ['B', 'KB', 'MB', 'GB', 'TB'];
    270. $pos = 0;
    271. while ($size >= 1024) {
    272. $size /= 1024;
    273. $pos++;
    274. }
    275. return round($size, 2).$a[$pos];
    276. }
    277. /**
    278. * 获取文件列表
    279. * @param string $order 级别
    280. * @return string
    281. */
    282. public function get_filelist($order = 0)
    283. {
    284. $filepath = opendir($this->config['path']);
    285. $fileAndFolderAyy = array();
    286. $i = 1;
    287. while (false != ($filename = readdir($filepath))) {
    288. if($filename != '.' && $filename != '..'){
    289. $i++;
    290. $fileAndFolderAyy[$i]['name'] = $filename;
    291. $fileAndFolderAyy[$i]['time'] = $this->getfiletime($filename);
    292. $fileAndFolderAyy[$i]['size'] = $this->getfilesize($filename);
    293. }
    294. }
    295. $order == 0 ? sort($fileAndFolderAyy) : rsort($fileAndFolderAyy);
    296. return $fileAndFolderAyy;
    297. }
    298. /**
    299. * 删除备份文件
    300. */
    301. public function delfile()
    302. {
    303. $filename = $this->config['sqlbakname'];
    304. $path = $this->config['path'].$filename;
    305. if(file_exists($path)){
    306. unlink($path);
    307. }
    308. return true;
    309. }
    310. }

  • 相关阅读:
    如何可视化编写和编排你的 K8s 任务
    从零开始,开发一个 Web Office 套件(4):新的问题—— z-index
    php+mysql羽毛球场地租赁管理系统
    1149. 文章浏览 II
    牛客:NC59 矩阵的最小路径和
    快照表转换成拉链表的方式(hive)初始化拉链&增量更新拉链
    抖音seo短视频矩阵SaaS源码部署--开源搭建(一)
    fastadmin 前端日期字段的添加和编辑
    vcruntime140_1.dll修复方法分享,教你安全靠谱的修复手段
    【GlobalMapper精品教程】029:栅格重分类案例详解
  • 原文地址:https://blog.csdn.net/m0_68949064/article/details/125897518