├── .gitignore
├── LICENSE
├── README.md
├── composer.json
├── phpunit.xml
├── readme_bootstrap_sample.png
├── src
├── MathCaptcha.php
├── MathCaptchaServiceProvider.php
├── config
│ └── math-captcha.php
└── resources
│ └── lang
│ ├── de
│ └── math-captcha.php
│ ├── en
│ └── math-captcha.php
│ └── sv
│ └── math-captcha.php
└── tests
├── .gitkeep
└── MathCaptchaTest.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | composer.phar
3 | composer.lock
4 | .DS_Store
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017-2018 Matthias Lill
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Very simple math captcha for Laravel5
2 |
3 | A simple math question (`+`,`-`,`*`) to validate user input.
4 |
5 | ## Installation
6 |
7 | ```
8 | composer require elic-dev/laravel-math-captcha
9 | ```
10 |
11 | ### Setup Laravel > 5.5
12 |
13 | This package supports Laravel Package Auto-Discovery.
14 |
15 | ### Setup Laravel <= 5.4
16 |
17 | You can add the ServiceProvider to the providers array in `app/config/app.php`.
18 |
19 | ```
20 | ElicDev\MathCaptcha\MathCaptchaServiceProvider::class,
21 | ```
22 |
23 |
24 | ## Usage
25 |
26 | This package only returns the question and the input. You have to position it within your labels and form classes.
27 |
28 | ```php
29 | {{ app('mathcaptcha')->label() }}
30 | {!! app('mathcaptcha')->input() !!}
31 | ```
32 |
33 | Display it wihtin Bootstrap as example:
34 |
35 | ```
36 |
37 | Please solve the following math function: {{ app('mathcaptcha')->label() }}
38 | {!! app('mathcaptcha')->input(['class' => 'form-control', 'id' => 'mathgroup']) !!}
39 | @if ($errors->has('mathcaptcha'))
40 |
41 | {{ $errors->first('mathcaptcha') }}
42 |
43 | @endif
44 |
45 | ```
46 |
47 | Looks like
48 |
49 | 
50 |
51 |
52 | #### Validation
53 |
54 | Add `'mathcaptcha' => 'required|mathcaptcha'` to rules array.
55 |
56 |
57 | ```php
58 | $this->validate($request, [
59 | 'mathcaptcha' => 'required|mathcaptcha',
60 | ]);
61 |
62 | ```
63 |
64 | Add corresponding translation string to your `lang/validation.php` files.
65 |
66 | #### Reset
67 |
68 | This package does not generate a new math question for each request. Once the
69 | form has been submited without validation erros you can reset the library to force
70 | generate a new question.
71 |
72 | ```php
73 | app('mathcaptcha')->reset();
74 | ```
75 |
76 | ## Configuration
77 |
78 | ### Operands, Min, Max
79 |
80 | You can adjust the available operands (`+`,`-`,`*`) and minimum or maximum randum
81 | values used. Some users might stuggle with more complex math operations.
82 |
83 |
84 | ```
85 | php artisan vendor:publish --provider="ElicDev\MathCaptcha\MathCaptchaServiceProvider" --tag=config
86 | ```
87 |
88 | ### Display as text
89 |
90 | It is possible to show the math question as text (e.g. "Four plus Five"). You can adjust a setting in the config file. This requires translations and a language files. A few languages are provided with this package.
91 |
92 |
93 | ```
94 | php artisan vendor:publish --provider="ElicDev\MathCaptcha\MathCaptchaServiceProvider" --tag=lang
95 | ```
96 |
97 |
98 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "elic-dev/laravel-math-captcha",
3 | "description": "A simple math captcha for Laravel form validation.",
4 | "keywords": ["captcha", "math-captcha", "math", "laravel", "laravel5"],
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "Matthias Lill",
9 | "email": "m.lill@gmx.de"
10 | }
11 | ],
12 | "autoload": {
13 | "psr-4": {
14 | "ElicDev\\MathCaptcha\\": "src/"
15 | }
16 | },
17 | "extra": {
18 | "laravel": {
19 | "providers": [
20 | "ElicDev\\MathCaptcha\\MathCaptchaServiceProvider"
21 | ]
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | ./tests/
16 |
17 |
18 |
--------------------------------------------------------------------------------
/readme_bootstrap_sample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elic-dev/laravel-math-captcha/8c79f79297126b43e388ac8f0ab0f7da4bb0fb5b/readme_bootstrap_sample.png
--------------------------------------------------------------------------------
/src/MathCaptcha.php:
--------------------------------------------------------------------------------
1 | session = $session;
21 | }
22 |
23 | /**
24 | * Returns the math question as string. The second operand is always a larger
25 | * number then the first one. So it's on first position because we don't want
26 | * any negative results.
27 | *
28 | * @return string
29 | */
30 | public function label()
31 | {
32 | if (config('math-captcha.text')) {
33 | return sprintf("%s %s %s",
34 | trans('mathcaptcha::math-captcha.numbers.' . $this->getMathSecondOperator()),
35 | trans('mathcaptcha::math-captcha.operands.' . $this->getMathOperand()),
36 | trans('mathcaptcha::math-captcha.numbers.' . $this->getMathFirstOperator())
37 | );
38 | } else {
39 | return sprintf("%d %s %d", $this->getMathSecondOperator(), $this->getMathOperand(), $this->getMathFirstOperator());
40 | }
41 | }
42 |
43 | /**
44 | * Returns the math input field
45 | * @param array $attributes Additional HTML attributes
46 | * @return string the input field
47 | */
48 | public function input(array $attributes = [])
49 | {
50 | $default = [];
51 | $default['type'] = 'text';
52 | $default['id'] = 'mathcaptcha';
53 | $default['name'] = 'mathcaptcha';
54 | $default['required'] = 'required';
55 | $default['value'] = old('mathcaptcha');
56 |
57 | $attributes = array_merge($default, $attributes);
58 |
59 | $html = ' buildAttributes($attributes) . '>';
60 |
61 | return $html;
62 | }
63 |
64 | /**
65 | * Laravel input validation
66 | * @param string $value
67 | * @return boolean
68 | */
69 | public function verify($value)
70 | {
71 | return $value == $this->getMathResult();
72 | }
73 |
74 | /**
75 | * Reset the math operators to regenerate a new question.
76 | *
77 | * @return void
78 | */
79 | public function reset()
80 | {
81 | $this->session->forget('mathcaptcha.first');
82 | $this->session->forget('mathcaptcha.second');
83 | $this->session->forget('mathcaptcha.operand');
84 | }
85 |
86 | /**
87 | * Operand to be used ('*','-','+')
88 | *
89 | * @return character
90 | */
91 | protected function getMathOperand()
92 | {
93 | if (!$this->session->get('mathcaptcha.operand')) {
94 | $this->session->put(
95 | 'mathcaptcha.operand',
96 | config('math-captcha.operands.' . array_rand(config('math-captcha.operands')))
97 | );
98 | }
99 |
100 | return $this->session->get('mathcaptcha.operand');
101 | }
102 |
103 | /**
104 | * The first math operand.
105 | *
106 | * @return integer
107 | */
108 | protected function getMathFirstOperator()
109 | {
110 | if (!$this->session->get('mathcaptcha.first')) {
111 | $this->session->put(
112 | 'mathcaptcha.first',
113 | rand(config('math-captcha.rand-min'), config('math-captcha.rand-max'))
114 | );
115 | }
116 |
117 | return $this->session->get('mathcaptcha.first');
118 | }
119 |
120 | /**
121 | * The second math operand
122 | * @return integer
123 | */
124 | protected function getMathSecondOperator()
125 | {
126 | if (!$this->session->get('mathcaptcha.second')) {
127 | $this->session->put(
128 | 'mathcaptcha.second',
129 | $this->getMathFirstOperator() + rand(config('math-captcha.rand-min'), config('math-captcha.rand-max'))
130 | );
131 | }
132 |
133 | return $this->session->get('mathcaptcha.second');
134 | }
135 |
136 | /**
137 | * The math result to be validated.
138 | * @return integer
139 | */
140 | protected function getMathResult()
141 | {
142 | switch ($this->getMathOperand()) {
143 | case '+':
144 | return $this->getMathFirstOperator() + $this->getMathSecondOperator();
145 | case '*':
146 | return $this->getMathFirstOperator() * $this->getMathSecondOperator();
147 | case '-':
148 | return abs($this->getMathFirstOperator() - $this->getMathSecondOperator());
149 | default:
150 | throw new \Exception('Math captcha uses an unknown operand.');
151 | }
152 | }
153 |
154 | /**
155 | * Build HTML attributes.
156 | *
157 | * @param array $attributes
158 | *
159 | * @return string
160 | */
161 | protected function buildAttributes(array $attributes)
162 | {
163 | $html = [];
164 | foreach ($attributes as $key => $value) {
165 | $html[] = $key . '="' . $value . '"';
166 | }
167 | return count($html) ? ' ' . implode(' ', $html) : '';
168 | }
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/src/MathCaptchaServiceProvider.php:
--------------------------------------------------------------------------------
1 | app['validator']->extend('mathcaptcha', function ($attribute, $value) {
17 | return $this->app['mathcaptcha']->verify($value);
18 | });
19 |
20 | $this->publishes([
21 | __DIR__ . '/config' => config_path(),
22 | ], 'config');
23 |
24 | $this->loadTranslationsFrom(__DIR__ . '/resources/lang', 'mathcaptcha');
25 | $this->publishes([
26 | __DIR__ . '/resources/lang' => resource_path('lang/vendor/mathcaptcha'),
27 | ], 'lang');
28 | }
29 |
30 | /**
31 | * Register the application services.
32 | *
33 | * @return void
34 | */
35 | public function register()
36 | {
37 | $this->app->singleton('mathcaptcha', function ($app) {
38 | return new MathCaptcha($this->app['session']);
39 | });
40 |
41 | $this->mergeConfigFrom(
42 | __DIR__ . '/config/math-captcha.php', 'math-captcha'
43 | );
44 | }
45 |
46 | /**
47 | * Get the services provided by the provider.
48 | *
49 | * @return array
50 | */
51 | public function provides()
52 | {
53 | return ['mathcaptcha'];
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/config/math-captcha.php:
--------------------------------------------------------------------------------
1 | [
11 | '+',
12 | '-',
13 | '*',
14 | ],
15 |
16 | /**
17 | * What should be a minimum random value
18 | */
19 | 'rand-min' => 2,
20 |
21 | /**
22 | * What should be a maximum random value
23 | */
24 | 'rand-max' => 5,
25 |
26 | /**
27 | * Use text instead of numbers
28 | */
29 | 'text' => false,
30 |
31 | ];
32 |
--------------------------------------------------------------------------------
/src/resources/lang/de/math-captcha.php:
--------------------------------------------------------------------------------
1 | [
5 | '0' => 'Null',
6 | '1' => 'Eins',
7 | '2' => 'Zwei',
8 | '3' => 'Drei',
9 | '4' => 'Vier',
10 | '5' => 'Fünf',
11 | '6' => 'Sechs',
12 | '7' => 'Sieben',
13 | '8' => 'Acht',
14 | '9' => 'Neun',
15 | '10' => 'Zehn',
16 | '11' => 'Elf',
17 | '12' => 'Zwölf',
18 | ],
19 | 'operands' => [
20 | '+' => 'plus',
21 | '-' => 'minus',
22 | '*' => 'mal',
23 | '/' => 'geteilt durch',
24 | ],
25 | ];
26 |
--------------------------------------------------------------------------------
/src/resources/lang/en/math-captcha.php:
--------------------------------------------------------------------------------
1 | [
5 | '0' => 'Zero',
6 | '1' => 'One',
7 | '2' => 'Two',
8 | '3' => 'Three',
9 | '4' => 'Four',
10 | '5' => 'Five',
11 | '6' => 'Six',
12 | '7' => 'Seven',
13 | '8' => 'Eight',
14 | '9' => 'Nine',
15 | '10' => 'Ten',
16 | '11' => 'Eleven',
17 | '12' => 'Twelve',
18 | ],
19 | 'operands' => [
20 | '+' => 'plus',
21 | '-' => 'minus',
22 | '*' => 'times',
23 | '/' => 'divided by',
24 | ],
25 | ];
26 |
--------------------------------------------------------------------------------
/src/resources/lang/sv/math-captcha.php:
--------------------------------------------------------------------------------
1 | [
5 | '0' => 'Noll',
6 | '1' => 'Ett',
7 | '2' => 'Två',
8 | '3' => 'Tre',
9 | '4' => 'Fyra',
10 | '5' => 'Fem',
11 | '6' => 'Sex',
12 | '7' => 'Sju',
13 | '8' => 'Åtta',
14 | '9' => 'Nio',
15 | '10' => 'Tio',
16 | '11' => 'Elva',
17 | '12' => 'Tolv',
18 | ],
19 | 'operands' => [
20 | '+' => 'Plus',
21 | '-' => 'Minus',
22 | '*' => 'Gånger',
23 | '/' => 'Delat med',
24 | ],
25 | ];
26 |
--------------------------------------------------------------------------------
/tests/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elic-dev/laravel-math-captcha/8c79f79297126b43e388ac8f0ab0f7da4bb0fb5b/tests/.gitkeep
--------------------------------------------------------------------------------
/tests/MathCaptchaTest.php:
--------------------------------------------------------------------------------
1 | captcha = new MathCaptcha();
14 | }
15 |
16 | public function testDisplay()
17 | {
18 | $this->assertTrue($this->captcha instanceof MathCaptcha);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------