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

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