Skip to content

Instantly share code, notes, and snippets.

@kikoseijo
Last active October 15, 2023 18:01
Show Gist options
  • Save kikoseijo/d4ec87a121cba7bcb6231bfa046be291 to your computer and use it in GitHub Desktop.
Save kikoseijo/d4ec87a121cba7bcb6231bfa046be291 to your computer and use it in GitHub Desktop.
Laravel Spatie backup with controller routes and views
<?php
namespace App\Http\Controllers;
use Alert;
use Artisan;
use Carbon\Carbon;
use Log;
use Spatie\Backup\Helpers\Format;
use Storage;
class BackupController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
$disk = Storage::disk(config('backup.backup.destination.disks')[0]);
$files = $disk->files(config('backup.backup.name'));
$backups = [];
// make an array of backup files, with their filesize and creation date
foreach ($files as $k => $f) {
// only take the zip files into account
if (substr($f, -4) == '.zip' && $disk->exists($f)) {
$backups[] = [
'file_path' => $f,
'file_name' => str_replace(config('backup.backup.name') . '/', '', $f),
'file_size' => Format::humanReadableSize($disk->size($f)),
'last_modified' => Carbon::createFromTimestamp($disk->lastModified($f)),
];
}
}
// reverse the backups, so the newest one would be on top
$backups = array_reverse($backups);
return view("admin.backups")->with(compact('backups'));
}
public function create()
{
try {
// start the backup process
Artisan::call('backup:run', ['--only-db' => 'true']);
$output = Artisan::output();
// log the results
Log::info("Backpack\BackupManager -- new backup started from admin interface \r\n" . $output);
// return the results as a response to the ajax call
Alert::success('New backup created');
return redirect()->back();
} catch (Exception $e) {
Flash::error($e->getMessage());
return redirect()->back();
}
}
/**
* Downloads a backup zip file.
*
* TODO: make it work no matter the flysystem driver (S3 Bucket, etc).
*/
public function download($file_name)
{
$file = config('backup.backup.name') . '/' . $file_name;
$disk = Storage::disk(config('backup.backup.destination.disks')[0]);
if ($disk->exists($file)) {
$fs = Storage::disk(config('backup.backup.destination.disks')[0])->getDriver();
$stream = $fs->readStream($file);
return \Response::stream(function () use ($stream) {
fpassthru($stream);
}, 200, [
"Content-Type" => $fs->getMimetype($file),
"Content-Length" => $fs->getSize($file),
"Content-disposition" => "attachment; filename=\"" . basename($file) . "\"",
]);
} else {
abort(404, "The backup file doesn't exist.");
}
}
/**
* Deletes a backup file.
*/
public function delete($file_name)
{
$disk = Storage::disk(config('backup.backup.destination.disks')[0]);
if ($disk->exists(config('backup.backup.name') . '/' . $file_name)) {
$disk->delete(config('backup.backup.name') . '/' . $file_name);
return redirect()->back();
} else {
abort(404, "The backup file doesn't exist.");
}
}
}
@if (count($backups))
<table class="table table-striped table-bordered">
<thead class="thead-dark">
<tr>
<th>File</th>
<th>Size</th>
<th>Date</th>
<th>Age</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach($backups as $backup)
<tr>
<td>{{ $backup['file_name'] }}</td>
<td>{{ $backup['file_size'] }}</td>
<td>
{{ date('d/M/Y, g:ia', strtotime($backup['last_modified'])) }}
</td>
<td>
{{ diff_date_for_humans($backup['last_modified']) }}
</td>
<td class="text-right">
<a class="btn btn-primary" href="{{ url('backup/download/'.$backup['file_name']) }}">
<i class="fas fa-cloud-download"></i> Download</a>
<a class="btn btn-xs btn-danger" data-button-type="delete" href="{{ url('backup/delete/'.$backup['file_name']) }}">
<i class="fal fa-trash"></i>
Delete
</a>
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="text-center py-5">
<h1 class="text-muted">No existen backups</h1>
</div>
@endif
@extends('layouts.crud')
@section('content')
<div class="container -body-block pb-5">
@card(['title' => 'Backups de la base de datos'])
@component('ui.menu-nav')
<li class="nav-item active mr-3">
<a href="{{ url('backup/create') }}" class="nav-link text-primary" title="Crear nuevo backup">
<i class="far fa-plus" aria-hidden="true"></i> Crear nuevo backup
</a>
</li>
@endcomponent
<div class="py-4"></div>
@include('admin.backups-table')
<div class="py-3"></div>
@endcard
</div>
@endsection
<div class="row">
<div class="col">
<div class="card">
@isset($title)
<div class="card-header">{{$title}}</div>
@endisset
<div class="card-body">
{{ $slot }}
</div>
</div>
</div>
</div>
<!DOCTYPE html>
<html lang="{{ config('app.locale') }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Sunnyface.com') }}</title>
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
<script>
window.AppRootData = {!! json_encode([
'csrfToken' => csrf_token(),
'state' => ['user' => Auth::user()]
]) !!};
</script>
</head>
<body>
<div id="app" class="boxx-wrapper">
@include('parts.header.admin')
<div class="album py-5 bg-light">
@include('ui.errors')
@yield('content')
</div>
@include('parts.footer')
@stack('modals')
</div>
<!-- Scripts -->
@if (app()->isLocal())
<script src="{{ mix('js/app.js') }}"></script>
@else
<script src="{{ mix('js/manifest.js') }}"></script>
<script src="{{ mix('js/vendor.js') }}"></script>
<script src="{{ mix('js/app.js') }}"></script>
@endif
@stack('scripts')
</body>
</html>
<?php
use Carbon\Carbon;
function diff_date_for_humans(Carbon $date) : string
{
return (new Jenssegers\Date\Date($date->timestamp))->ago();
}
function diff_string_for_humans($stringDate) : string
{
$date = Jenssegers\Date\Date::createFromFormat('Y-m-d H:i:s', $stringDate);
return (new Jenssegers\Date\Date($date))->ago();
}
function scannerTableLabel($stringDate) : string
{
$now = Jenssegers\Date\Date::now();
$date = Jenssegers\Date\Date::createFromFormat('Y-m-d H:i:s', $stringDate);
$printDate = (new Jenssegers\Date\Date($date))->ago();
$color = $now > $date ? 'info' : 'danger';
$res = '<span class="badge badge-'.$color.'" style="color:white;">SCANNER: ';
$res .= $printDate ;
$res .= '</span>';
return $res;
}
<nav class="navbar navbar-expand-md navbar-light bg-light">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#table-actions-nav-menu" aria-controls="table-actions-nav-menu" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="table-actions-nav-menu">
<ul class="navbar-nav mr-auto mt-2 mt-lg-0">
{{ $slot }}
</ul>
</div>
</nav>
Route::get('backup', 'BackupController@index');
Route::get('backup/create', 'BackupController@create');
Route::get('backup/download/{file_name}', 'BackupController@download');
Route::get('backup/delete/{file_name}', 'BackupController@delete');
@kikoseijo
Copy link
Author

Hi, Because its based on a plugin for backups from spatie, its trying to send you an email and this is the error you are getting i suppose.
use Spatie\Backup\Helpers\Format;

Check spatie plugin for further customization.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment