Skip to content

Commit c50f19e

Browse files
Add files via upload
1 parent dd26d13 commit c50f19e

File tree

10 files changed

+205
-0
lines changed

10 files changed

+205
-0
lines changed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
# Laravel Anti-Spam Package
3+
4+
A Laravel package to prevent spam submissions using Google reCAPTCHA, honeypots, form submission timeouts, and random questions.
5+
6+
## Installation
7+
8+
```bash
9+
composer require vendor/laravel-anti-spam
10+
```
11+
12+
## Configuration
13+
14+
Publish the configuration file:
15+
16+
```bash
17+
php artisan vendor:publish --tag=config --provider="AntiSpam\\AntiSpamServiceProvider"
18+
```
19+
20+
## Usage
21+
22+
Include the honeypot in your form:
23+
24+
```blade
25+
<form method="POST" action="/submit">
26+
@csrf
27+
@include('antispam::honeypot')
28+
<label for="random_answer">{{ session('random_question') }}</label>
29+
<input type="text" name="random_answer">
30+
<button type="submit">Submit</button>
31+
</form>
32+
```

composer.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
{
3+
"name": "vendor/laravel-anti-spam",
4+
"description": "Laravel package to prevent spam submissions",
5+
"type": "library",
6+
"license": "MIT",
7+
"authors": [
8+
{
9+
"name": "Your Name",
10+
"email": "[email protected]"
11+
}
12+
],
13+
"autoload": {
14+
"psr-4": {
15+
"AntiSpam\\": "src/"
16+
}
17+
},
18+
"require": {
19+
"php": ">=7.4",
20+
"illuminate/support": "^8.0|^9.0|^10.0"
21+
}
22+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
<?php
3+
return [
4+
'incorrect_answer' => 'Your answer to the question was incorrect.',
5+
];
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
<?php
3+
return [
4+
'incorrect_answer' => 'Sorunun cevabı yanlış.',
5+
];

src/AntiSpamServiceProvider.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
<?php
3+
namespace AntiSpam;
4+
5+
use Illuminate\Support\ServiceProvider;
6+
7+
class AntiSpamServiceProvider extends ServiceProvider
8+
{
9+
public function register()
10+
{
11+
$this->mergeConfigFrom(__DIR__ . '/Config/antispam.php', 'antispam');
12+
}
13+
14+
public function boot()
15+
{
16+
$this->publishes([
17+
__DIR__ . '/Config/antispam.php' => config_path('antispam.php'),
18+
], 'config');
19+
20+
$this->loadViewsFrom(__DIR__ . '/Views', 'antispam');
21+
}
22+
}

src/Config/antispam.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
<?php
3+
return [
4+
'recaptcha' => [
5+
'enabled' => true,
6+
'site_key' => env('RECAPTCHA_SITE_KEY', ''),
7+
'secret_key' => env('RECAPTCHA_SECRET_KEY', ''),
8+
],
9+
'timeout' => [
10+
'enabled' => true,
11+
'minimum_seconds' => 3,
12+
],
13+
'honeypot' => [
14+
'enabled' => true,
15+
'field_name' => 'hidden_field',
16+
],
17+
'random_questions' => [
18+
'enabled' => true,
19+
'questions' => [
20+
'en' => [
21+
'What is 2 + 2?' => '4',
22+
'What is the capital of France?' => 'Paris',
23+
'What color is the sky on a clear day?' => 'blue',
24+
],
25+
'tr' => [
26+
'2 + 2 kaç eder?' => '4',
27+
'Türkiye’nin başkenti neresidir?' => 'Ankara',
28+
'Gökyüzü açık bir günde ne renktir?' => 'mavi',
29+
],
30+
],
31+
],
32+
];

src/Helpers/QuestionGenerator.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
<?php
3+
namespace AntiSpam\Helpers;
4+
5+
class QuestionGenerator
6+
{
7+
public static function getRandomQuestion(): string
8+
{
9+
$questions = self::getLocalizedQuestions();
10+
return array_rand($questions);
11+
}
12+
13+
public static function getLocalizedQuestions(): array
14+
{
15+
$lang = app()->getLocale();
16+
$questions = config('antispam.random_questions.questions');
17+
return $questions[$lang] ?? $questions['en'];
18+
}
19+
20+
public static function getAnswerForQuestion(string $question): ?string
21+
{
22+
$questions = self::getLocalizedQuestions();
23+
return $questions[$question] ?? null;
24+
}
25+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
<?php
3+
namespace AntiSpam\Middleware;
4+
5+
use Closure;
6+
use Illuminate\Http\Request;
7+
use AntiSpam\Helpers\QuestionGenerator;
8+
9+
class AntiSpamMiddleware
10+
{
11+
public function handle(Request $request, Closure $next)
12+
{
13+
$config = config('antispam');
14+
15+
if ($config['honeypot']['enabled']) {
16+
$field = $config['honeypot']['field_name'];
17+
if ($request->has($field) && !empty($request->input($field))) {
18+
abort(403, 'Spam detected.');
19+
}
20+
}
21+
22+
if ($config['timeout']['enabled']) {
23+
$startTime = session('form_start_time');
24+
if ($startTime && now()->diffInSeconds($startTime) < $config['timeout']['minimum_seconds']) {
25+
abort(403, 'Submission too fast.');
26+
}
27+
}
28+
29+
if ($config['random_questions']['enabled']) {
30+
$question = session('random_question');
31+
$answer = QuestionGenerator::getAnswerForQuestion($question);
32+
if (!$answer || $request->input('random_answer') !== $answer) {
33+
abort(403, __('antispam::messages.incorrect_answer'));
34+
}
35+
}
36+
37+
return $next($request);
38+
}
39+
}

src/Traits/HasAntiSpam.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
<?php
3+
namespace AntiSpam\Traits;
4+
5+
use AntiSpam\Helpers\QuestionGenerator;
6+
7+
trait HasAntiSpam
8+
{
9+
public function initializeAntiSpam()
10+
{
11+
if (config('antispam.timeout.enabled')) {
12+
session(['form_start_time' => now()]);
13+
}
14+
15+
if (config('antispam.random_questions.enabled')) {
16+
session(['random_question' => QuestionGenerator::getRandomQuestion()]);
17+
}
18+
}
19+
}

src/Views/honeypot.blade.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
@if(config('antispam.honeypot.enabled'))
3+
<input type="text" name="{{ config('antispam.honeypot.field_name') }}" style="display:none;">
4+
@endif

0 commit comments

Comments
 (0)