💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
1. <?php 2. /** 3. * 数据库控类库 4. * @author [我就叫小柯] <[972581428@qq.com]> 5. * @copyright Copyright (c) 2020 [环企优站科技] (https://www.h7uz.com) 6. * @version v1.0 7. */ 8. namespace databases; 9. use think\Db; 10. class Databases{ 11. private $db = ''; 12. private $datadir = '';//数据库备份地址 13. private $startrow = 0; 14. private $startfrom = 0; 15. private $complete = true; 16. 17. /** 18. * 构造函数 19. * @param string 公钥文件(验签和加密时传入) 20. * @param string 私钥文件(签名和解密时传入) 21. */ 22. public function __construct($dir){ 23. $this->db = Db::getConnection(); 24. $this->check_dir($dir); 25. } 26. 27. 28. protected function check_dir($datadir){ 29. if(!is_dir($datadir)){ 30. mkdir($datadir,0755,true); 31. } 32. $this->datadir = $datadir; 33. return $this; 34. } 35. 36. /** 37. * 当前数据库表 38. * @param $db_prefix 表前缀 39. * @return array 40. */ 41. public function db_list($db_prefix){ 42. return $this->db->query("SHOW TABLE STATUS LIKE '".$db_prefix."%'"); 43. } 44. 45. //导入数据库 46. public function backup($data,$tabelsarr,$file){ 47. $tableid = $data['tableid']; 48. $this->startfrom = $data['startfrom']; 49. $sizelimit = $data['sizelimit']; //分卷大小 50. $volume = $data['volume']; 51. //查询 52. $dataList = $this->db_list($data['db_prefix']); 53. foreach ($dataList as $row){ 54. $table_info[$row['Name']] = $row; 55. } 56. $tables = cache('backuptables'); 57. if(empty($tabelsarr) && empty($tables)) { 58. foreach ($dataList as $row){ 59. $tables[]= $row['Name']; 60. } 61. }else{ 62. $tables = []; 63. if(!$tableid) { 64. $tables = $tabelsarr; 65. cache('backuptables',$tables); 66. } else { 67. $tables = cache('backuptables'); 68. } 69. if( !is_array($tables) || empty($tables)) { 70. return ['status'=>0,'msg'=>lang('do_empty')]; 71. } 72. } 73. unset($dataList); 74. $sql = ''; 75. if(!$tableid) { 76. $sql .= "-- Usezanphp SQL Backup\n-- Time:".toDate(time())."\n-- https://www.h7uz.com \n\n"; 77. foreach($tables as $key=>$table) { 78. $sql .= "--\n-- Usezanphp Table `$table`\n-- \n"; 79. $sql .= "DROP TABLE IF EXISTS `$table`;\n"; 80. $info = $this->db->query("SHOW CREATE TABLE $table"); 81. $sql .= str_replace(array('USING BTREE','ROW_FORMAT=DYNAMIC'),'',$info[0]['Create Table']).";\n"; 82. } 83. } 84. for(; $this->complete && $tableid < count($tables) && strlen($sql) + 500 < $sizelimit * 1000; $tableid++) { 85. if($table_info[$tables[$tableid]]['Rows'] > 0){ 86. $sql .= $this->dumptablesql($tables[$tableid], $this->startfrom, strlen($sql),$table_info[$tables[$tableid]]['Auto_increment']); 87. if($this->complete) { 88. $this->startfrom = 0; 89. } 90. } 91. } 92. !$this->complete && $tableid--; 93. $filename = htmlspecialchars(strip_tags($file)); 94. $filename = !$filename ? 'Usezan_'.rand_string(5).'_'.date('YmdH') : $filename; 95. $filename_valume = sprintf($filename."-%s".'.sql', $volume); 96. if(trim($sql)){ 97. $putfile = $this->datadir . $filename_valume; 98. $r = file_put_contents($putfile , trim($sql)); 99. } 100. if($tableid < count($tables) || $r){ 101. return ['status'=>200,'msg'=>"备份数据库".$filename_valume."成功"]; 102. }else{ 103. cache('backuptables',null); 104. return ['status'=>200,'msg'=>lang('do_ok')]; 105. } 106. } 107. 108. /*** 109. * 恢复-删除 110. * @param $do 111. * @param $files 112. */ 113. public function db_recover($do,$files,$filename,$db_prefix=null){ 114. switch ($do) { 115. case 'del': 116. if (!empty($files) && is_array($files)) { 117. foreach ($files as $r){ 118. @unlink($r); 119. } 120. return ['status'=>200,'msg'=>'删除数据库成功(ˇˍˇ)']; 121. } else { 122. return ['status'=>200,'msg'=>'请选择要删除的数据库']; 123. } 124. break; 125. case 'import': 126. header('Content-Type:text/html;charset=UTF-8'); 127. $filelist = $this->dir_list($this->datadir); 128. foreach ((array)$filelist as $r){ 129. $file = explode('-',basename($r)); 130. if($file[0] == $filename){ 131. $files[] = $r; 132. } 133. } 134. $db_prefix = $db_prefix ? $db_prefix : config('database.prefix'); 135. foreach((array)$files as $file){ 136. //读取数据文件 137. $sqldata = file_get_contents($file); 138. $sqlFormat = $this->sql_split($sqldata, $db_prefix); 139. foreach ((array)$sqlFormat as $sql){ 140. $sql = trim($sql); 141. if (strstr($sql, 'CREATE TABLE')){ 142. preg_match('/CREATE TABLE `([^ ]*)`/', $sql, $matches); 143. $ret =$this->excuteQuery($sql); 144. }else{ 145. $ret = $this->excuteQuery($sql); 146. } 147. } 148. return ['status'=>200,'msg'=>'恢复数据库成功']; 149. } 150. break; 151. } 152. } 153. 154. /** 155. * 数据库修复、分析 156. * @param $tables 157. * @param $do 158. * @return array 159. */ 160. public function docommand($tables,$do){ 161. if(empty($tables)) return ['status'=>0,'msg'=>'请勾选数据表!']; 162. $tables = implode('`,`',$tables); 163. $r = $this->db->query("{$do} TABLE `{$tables}`"); 164. if(false != $r){ 165. return ['status'=>200,'msg'=>$do.'数据表成功!']; 166. }else{ 167. return ['status'=>0,'msg'=>$r['dberror']]; 168. } 169. } 170. 171. /** 172. * 下载 173. * @param $filename 174. */ 175. public function db_download($filename) { 176. if (strstr($filename,'sql')) { 177. $path = $this->datadir.$filename; 178. } else { 179. $path = $this->datadir.$filename.'.sql'; 180. } 181. @header("Content-disposition:attachment;filename=".$filename); 182. @header("Content-type:application/octet-stream"); 183. @header("Accept-Ranges: bytes"); 184. @header("Content-Length:".filesize($path)); 185. @header("Pragma:no-cache"); 186. @header("Expires:0"); 187. readfile($path); 188. } 189. 190. /*** 191. * 恢复操作 192. * @param string $sql 193. * @return mixed 194. */ 195. protected function excuteQuery($sql='') { 196. if(empty($sql)) return false; 197. $queryType = 'INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|LOAD DATA|SELECT .* INTO|COPY|ALTER|GRANT|TRUNCATE|REVOKE|LOCK|UNLOCK'; 198. if (preg_match('/^\s*"?(' . $queryType . ')\s+/i', $sql)) { 199. $data['result'] = $this->db->execute($sql); 200. $data['type'] = 'execute'; 201. }else { 202. $data['result'] = $this->db->query($sql); 203. $data['type'] = 'query'; 204. } 205. return $data; 206. } 207. 208. //组合、检查Sql 语句 209. protected function dumptablesql($table, $startfrom = 0, $currsize = 0,$auto_increment=0) { 210. $offset = 300; 211. $insertsql = ''; 212. $sizelimit = intval(input('param.sizelimit')); 213. $modelname = str_replace(config('database.prefix'),'',$table); 214. $model = Db::name($modelname); 215. $keyfield = $model->getPk(); 216. $rows = $offset; 217. while($currsize + strlen($insertsql) + 500 < $sizelimit * 1000 && $rows == $offset) { 218. if($auto_increment) { 219. $selectsql = "SELECT * FROM $table WHERE $keyfield > $startfrom ORDER BY $keyfield LIMIT $offset"; 220. } else { 221. $selectsql = "SELECT * FROM $table LIMIT $startfrom, $offset"; 222. } 223. $tabledumped = 1; 224. $row = $this->db->query($selectsql); 225. $rows = count($row); 226. foreach($row as $key=>$val) { 227. foreach ($val as $k=>$field){ 228. if(is_string($field)) { 229. $val[$k] = '\''. str_ireplace("'", "''", $field).'\''; //SQL指令安全过滤 230. } elseif($field === 0) { 231. $val[$k] = 0; 232. } elseif ($field == null){ 233. $val[$k] = 'NULL'; 234. } 235. } 236. if($currsize + strlen($insertsql) + 500 < $sizelimit * 1000) { 237. if($auto_increment) { 238. $startfrom = $row[$key][$keyfield]; 239. } else { 240. $startfrom++; 241. } 242. $insertsql .= "INSERT INTO `$table` VALUES (".implode(',', $val).");\n"; 243. } else { 244. $this->complete = false; 245. break 2; 246. } 247. } 248. } 249. $this->startfrom = $startfrom; 250. return $insertsql; 251. } 252. 253. /** 254. * [导入数据库] 255. * @param [type] $sql [数据库] 256. * @param [type] $tablepre [数据表] 257. * @return [type] 258. */ 259. protected function sql_split($sql,$tablepre) { 260. //检查表前缀 261. if($tablepre != "usezan_") $sql = str_replace("usezan_", $tablepre, $sql); 262. 263. $sql = str_replace("\r", "\n", $sql); 264. $ret = []; 265. $num = 0; 266. $queriesarray = explode(";\n", trim($sql)); 267. unset($sql); 268. foreach($queriesarray as $query){ 269. $ret[$num] = ''; 270. $queries = explode("\n", trim($query)); 271. $queries = array_filter($queries); 272. foreach($queries as $queryv){ 273. $str1 = substr($queryv, 0, 1); 274. if($str1 != '#' && $str1 != '-') $ret[$num] .= $queryv; 275. } 276. $num++; 277. } 278. return $ret; 279. } 280. 281. /** 282. * [检查文件或者目录] 283. * @param [type] $path [文件路径] 284. * @param string $exts [类型] 285. * @param array $list [返回数组] 286. * @return [type] 287. */ 288. public function dir_list($path, $exts = '', $d = '', $list= array()) { 289. $path = $this->dir_path($path); 290. $files = glob($path.'*'); 291. foreach($files as $v) { 292. $fileext = $this->fileext($v); 293. if (!$exts || preg_match("/\.($exts)/i", $v)) { 294. $list[] = $v; 295. if (is_dir($v)) { 296. $list = $this->dir_list($v, $exts, $list); 297. if($d && count(scandir($v)) == 2){ 298. @rmdir($v); 299. } 300. } 301. } 302. } 303. return $list; 304. } 305. 306. /** 307. * [检查目录是否合法] 308. * @param [type] $path [目录路径] 309. * @return [type] 310. */ 311. protected function dir_path($path) { 312. $path = str_replace('\\', '/', $path); 313. if(substr($path, -1) != '/') $path = $path.'/'; 314. return $path; 315. } 316. 317. /** 318. * [检查文件名称] 319. * @param [type] $filename [文件名称] 320. * @return [type] 321. */ 322. protected function fileext($filename) { 323. return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); 324. } 325. 326. 327. }