Просмотр файла app/Controllers/Admin/BackupController.php

Размер файла: 6.76Kb
  1. <?php
  2.  
  3. declare(strict_types=1);
  4.  
  5. namespace App\Controllers\Admin;
  6.  
  7. use App\Classes\Validator;
  8. use App\Models\User;
  9. use Illuminate\Database\Capsule\Manager as DB;
  10. use Illuminate\Http\Request;
  11.  
  12. class BackupController extends AdminController
  13. {
  14. public $date;
  15.  
  16. /**
  17. * Конструктор
  18. */
  19. public function __construct()
  20. {
  21. parent::__construct();
  22.  
  23. if (! isAdmin(User::BOSS)) {
  24. abort(403, __('errors.forbidden'));
  25. }
  26.  
  27. if (function_exists('set_time_limit')) {
  28. set_time_limit(600);
  29. }
  30.  
  31. $this->date = date('d-M-Y_H-i-s', SITETIME);
  32. }
  33.  
  34. /**
  35. * Главная страница
  36. *
  37. * @return string
  38. */
  39. public function index(): string
  40. {
  41. $files = glob(STORAGE . '/backups/*.{zip,gz,bz2,sql}', GLOB_BRACE);
  42. arsort($files);
  43.  
  44. return view('admin/backups/index', compact('files'));
  45. }
  46.  
  47. /**
  48. * Создание нового бэкапа
  49. *
  50. * @param Request $request
  51. * @param Validator $validator
  52. *
  53. * @return string
  54. */
  55. public function create(Request $request, Validator $validator): string
  56. {
  57. if ($request->isMethod('post')) {
  58. $sheets = check($request->input('sheets'));
  59. $method = $request->input('method');
  60. $level = int($request->input('level'));
  61.  
  62. $validator->equal($request->input('token'), $_SESSION['token'], __('validator.token'))
  63. ->notEmpty($sheets, ['sheets' => __('admin.backup.no_tables_save')])
  64. ->in($method, ['none', 'gzip', 'bzip'], ['method' => __('admin.backup.wrong_compression_method')])
  65. ->between($level, 0, 9, ['level' => __('admin.backup.wrong_compression_ratio')]);
  66.  
  67. if ($validator->isValid()) {
  68. $selectTables = DB::connection()->select('SHOW TABLE STATUS where name IN("' . implode('","', $sheets) . '")');
  69.  
  70. $limit = 3000;
  71. $filename = 'backup_'.$this->date.'.sql';
  72.  
  73. $fp = $this->fopen(STORAGE.'/backups/'.$filename, 'w', $method, $level);
  74.  
  75. foreach ($selectTables as $table) {
  76. $show = DB::connection()->selectOne("SHOW CREATE TABLE `{$table->Name}`");
  77. $columnsFields = DB::connection()->select("SHOW COLUMNS FROM `{$table->Name}`");
  78. $columns = '(' .implode(',', array_column($columnsFields, 'Field')) . ')';
  79.  
  80. $this->fwrite($fp, "--\n-- Structure table `{$table->Name}`\n--\n\n", $method);
  81. $this->fwrite($fp, "DROP TABLE IF EXISTS `{$table->Name}`;\n{$show->{'Create Table'}};\n\n", $method);
  82.  
  83. $total = DB::connection()->table($table->Name)->count();
  84.  
  85. if (! $total) {
  86. continue;
  87. }
  88.  
  89. $this->fwrite($fp, "--\n-- Dump table `{$table->Name}`\n--\n\n", $method);
  90. $this->fwrite($fp, "INSERT INTO `{$table->Name}` {$columns} VALUES ", $method);
  91.  
  92. for ($i = 0; $i < $total; $i += $limit) {
  93. $cols = DB::connection()->table($table->Name)->lockForUpdate()->limit($limit)->offset($i)->get();
  94.  
  95. foreach ($cols as $key => $col) {
  96. $records = get_object_vars($col);
  97. $columns = [];
  98.  
  99. foreach ($records as $record) {
  100. $record = is_int($record) || is_null($record) ? $record : "'" . str_replace("'", "''", $record) . "'";
  101. $columns[] = $record ?? 'null';
  102. }
  103.  
  104. $this->fwrite($fp, ($key || $i ? ',' : '') . '(' . implode(',', $columns) . ')', $method);
  105. unset($columns);
  106. }
  107. unset($cols);
  108. }
  109.  
  110. $this->fwrite($fp, ";\n\n", $method);
  111. }
  112.  
  113. $this->fclose($fp, $method);
  114.  
  115. setFlash('success', __('admin.backup.database_success_saved'));
  116. redirect('/admin/backups');
  117. } else {
  118. setInput($request->all());
  119. setFlash('danger', $validator->getErrors());
  120. }
  121. }
  122.  
  123. $tables = DB::connection()->select('SHOW TABLE STATUS');
  124.  
  125. $bzopen = function_exists('bzopen') ? true : false;
  126. $gzopen = function_exists('gzopen') ? true : false;
  127.  
  128. $levels = range(0, 9);
  129.  
  130. return view('admin/backups/create', compact('tables', 'bzopen', 'gzopen', 'levels'));
  131. }
  132.  
  133. /**
  134. * Удаляет сохраненный бэкап
  135. *
  136. * @param Request $request
  137. * @param Validator $validator
  138. *
  139. * @return void
  140. */
  141. public function delete(Request $request, Validator $validator): void
  142. {
  143. $file = $request->input('file');
  144.  
  145. $validator->equal($request->input('token'), $_SESSION['token'], __('validator.token'))
  146. ->notEmpty($file, __('admin.backup.backup_not_indicated'))
  147. ->regex($file, '|^[\w\.\-]+$|i', __('admin.backup.invalid_backup_name'))
  148. ->true(file_exists(STORAGE.'/backups/'.$file), __('admin.backup.backup_not_exist'));
  149.  
  150. if ($validator->isValid()) {
  151. unlink(STORAGE.'/backups/'.$file);
  152.  
  153. setFlash('success', __('admin.backup.backup_success_deleted'));
  154. } else {
  155. setFlash('danger', $validator->getErrors());
  156. }
  157.  
  158. redirect('/admin/backups');
  159. }
  160.  
  161. /**
  162. * Открывает поток
  163. *
  164. * @param string $name
  165. * @param string $mode
  166. * @param string $method
  167. * @param int $level
  168. *
  169. * @return bool|resource
  170. */
  171. private function fopen($name, $mode, $method, $level)
  172. {
  173. if ($method === 'bzip') {
  174. return bzopen($name . '.bz2', $mode);
  175. }
  176.  
  177. if ($method === 'gzip') {
  178. return gzopen($name . '.gz', "{$mode}b{$level}");
  179. }
  180.  
  181. return fopen($name, $mode . 'b');
  182. }
  183.  
  184. /**
  185. * Записывает данные в поток
  186. *
  187. * @param resource $fp
  188. * @param string $str
  189. * @param string $method
  190. */
  191. private function fwrite($fp, $str, $method): void
  192. {
  193. if ($method === 'bzip') {
  194. bzwrite($fp, $str);
  195. } elseif ($method === 'gzip') {
  196. gzwrite($fp, $str);
  197. } else {
  198. fwrite($fp, $str);
  199. }
  200. }
  201.  
  202. /**
  203. * Закрывает поток
  204. *
  205. * @param resource $fp
  206. * @param string $method
  207. */
  208. private function fclose($fp, $method): void
  209. {
  210. if ($method === 'bzip') {
  211. bzclose($fp);
  212. } elseif ($method === 'gzip') {
  213. gzclose($fp);
  214. } else {
  215. fflush($fp);
  216. fclose($fp);
  217. }
  218. }
  219. }