Skip to content

Instantly share code, notes, and snippets.

@liamja
Last active March 22, 2024 09:06
Show Gist options
  • Save liamja/5c64f65a9e220618a3e535b126124b09 to your computer and use it in GitHub Desktop.
Save liamja/5c64f65a9e220618a3e535b126124b09 to your computer and use it in GitHub Desktop.
Laravel Helpers
<?php // Pop these in App\Providers\AppServiceProvider::boot()
// Exception Handling
Blade::directive('try', fn ($x) => '<?php try { ?>');
Blade::directive('catch', fn ($x) => "<?php } catch ($x) { ?>");
Blade::directive('finally', fn ($x) => '<?php } finally { ?>');
Blade::directive('endtry', fn ($x) => '<?php } ?>');
// JSON Encode
Blade::directive('json', fn ($x) => "<?php echo \Illuminate\Support\Js::encode($x); ?>");
// Quick ifs
Blade::if('isempty', fn (?iterable $value = []) => count($value) === 0);
Blade::if('hide', fn () => false);
// Carbon Macros
Carbon::macro('toUserTimezone', fn () => $this->setTimezone(user()->timezone ?? 'Europe/London'));
// Generate a unique token for a form, and store it in the cache or session
// On form submission, we can check the cache for existance of the token;
// If we've seen the token before, the form has already been submitted at least once.
Blade::directive('onlyonce', function () {
return <<<'PHP'
<?php echo '<input type="hidden" name="_only_once" value="'.Str::random(6).'">' ?>
PHP;
});
<?php declare(strict_types=1);
function user(): App\Models\User|Illuminate\Contracts\Auth\Authenticatable|null
{
return auth()->user();
}
/**
* Toggle a boolean variable.
*/
function toggle(bool &$var): void
{
$var = ! $var;
}
/**
* Get the contrast color for a given hex colour.
* Taken from https://stackoverflow.com/a/42921358
*/
function get_contrast_color($hexColor)
{
// hexColor RGB
$R1 = hexdec(substr($hexColor, 1, 2));
$G1 = hexdec(substr($hexColor, 3, 2));
$B1 = hexdec(substr($hexColor, 5, 2));
// Black RGB
$blackColor = '#000000';
$R2BlackColor = hexdec(substr($blackColor, 1, 2));
$G2BlackColor = hexdec(substr($blackColor, 3, 2));
$B2BlackColor = hexdec(substr($blackColor, 5, 2));
// Calc contrast ratio
$L1 = 0.2126 * pow($R1 / 255, 2.2) +
0.7152 * pow($G1 / 255, 2.2) +
0.0722 * pow($B1 / 255, 2.2);
$L2 = 0.2126 * pow($R2BlackColor / 255, 2.2) +
0.7152 * pow($G2BlackColor / 255, 2.2) +
0.0722 * pow($B2BlackColor / 255, 2.2);
$contrastRatio = 0;
if ($L1 > $L2) {
$contrastRatio = (int) (($L1 + 0.05) / ($L2 + 0.05));
} else {
$contrastRatio = (int) (($L2 + 0.05) / ($L1 + 0.05));
}
// If contrast is more than 5, return black color
if ($contrastRatio > 5) {
return '#000000';
} else {
// if not, return white color.
return '#FFFFFF';
}
}
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
use Symfony\Component\HttpFoundation\Response;
class PreventDoubleSubmits
{
/**
* Prevent double-submits of forms.
* Every form has a unique token which is generated when the form is rendered.
* Once the form is submitted, the token is saved to the user's session.
* On any subsequent requests, if the token is found in the user's session, we know that this form has already been submitted once before.
* Doing this check stops use from doing the same action twice, which could cause problems such as duplicate records in the database or sending the same email twice.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
// If the request is a "read-only" operation, then we don't need to check for double-submits, as no data is being modified.
if ($request->isMethodSafe()) {
return $next($request);
}
// If this is a Livewire update, then we don't want to check for double-submits
if ($request->route()?->getName() === 'livewire.message') {
return $next($request);
}
// Get the unique token from the submitted form data.
$token = $request->post('_only_once');
// If the token is missing, then we can't check for double-submits. Abort the request to prevent potential double-submits.
abort_if($token === null, 400, 'Missing _only_once token in form. Add @onlyonce inside the <form> tags.');
// Build up the session key by setting the prefix and the token.
$session_key = "only_once_tokens.{$token}";
// If the token is found in the user's session, then we know that this form has already been submitted once before.
// Abort the request so we don't
abort_if(Session::pull($session_key, false), 429, 'Form submitted more than once.');
// If the token is not found in the user's session, then we know that this is the first time the form has been submitted.
// Store the token in the user's session so that we can check for double-submits of this form on any subsequent requests.
Session::put($session_key, now()->timestamp);
return $next($request);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment