1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Shetabit\Captcha\Drivers\Simple; |
4
|
|
|
|
5
|
|
|
use Illuminate\Support\Facades\View; |
6
|
|
|
use Illuminate\Support\ServiceProvider; |
7
|
|
|
use Shetabit\Captcha\Abstracts\Driver; |
8
|
|
|
|
9
|
|
|
class SimpleDriver extends Driver |
10
|
|
|
{ |
11
|
|
|
protected $serviceProvider; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Driver settings. |
15
|
|
|
* |
16
|
|
|
* @var object |
17
|
|
|
*/ |
18
|
|
|
protected $settings; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* SimpleDriver constructor. |
22
|
|
|
* Construct the class with the relevant settings. |
23
|
|
|
* |
24
|
|
|
* SimpleDriver constructor. |
25
|
|
|
* @param ServiceProvider $serviceProvider |
26
|
|
|
* @param $settings |
27
|
|
|
*/ |
28
|
|
|
public function __construct(ServiceProvider $serviceProvider, $settings) |
29
|
|
|
{ |
30
|
|
|
$this->serviceProvider = $serviceProvider; |
31
|
|
|
$this->settings = (object) $settings; |
32
|
|
|
|
33
|
|
|
$this->bindViews() |
34
|
|
|
->bindRoutes() |
35
|
|
|
->publishResources(); |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Bind driver views |
40
|
|
|
* |
41
|
|
|
* @return $this |
42
|
|
|
*/ |
43
|
|
|
protected function bindViews() |
44
|
|
|
{ |
45
|
|
|
$this->serviceProvider->bindViewFile(__DIR__ . '/resources/views', 'captchaSimpleDriver'); |
|
|
|
|
46
|
|
|
|
47
|
|
|
return $this; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Bind driver routes |
52
|
|
|
* |
53
|
|
|
* @return $this |
54
|
|
|
*/ |
55
|
|
|
protected function bindRoutes() |
56
|
|
|
{ |
57
|
|
|
$this->serviceProvider->bindRouteFile(__DIR__ . '/routes.php'); |
|
|
|
|
58
|
|
|
|
59
|
|
|
return $this; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Publish driver assets |
64
|
|
|
* |
65
|
|
|
* @return $this |
66
|
|
|
*/ |
67
|
|
|
protected function publishResources() |
68
|
|
|
{ |
69
|
|
|
$destinationPath = resource_path('views/vendor/captchaSimpleDriver'); |
70
|
|
|
|
71
|
|
|
$this->serviceProvider |
72
|
|
|
->publish(__DIR__ . '/resources/views', $destinationPath, 'views') |
|
|
|
|
73
|
|
|
->publish(__DIR__ . '/resources/assets', $destinationPath.'/assets', 'assets'); |
74
|
|
|
|
75
|
|
|
return $this; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* Prepare CAPTCHA image and memorize its token. |
80
|
|
|
* |
81
|
|
|
* @return false|string |
82
|
|
|
*/ |
83
|
|
|
public function prepareCaptchaImage() |
84
|
|
|
{ |
85
|
|
|
$settings = $this->settings; |
86
|
|
|
|
87
|
|
|
$token = $this->randomString( |
88
|
|
|
$settings->characters, |
89
|
|
|
$settings->length[0], |
90
|
|
|
$settings->length[1] |
91
|
|
|
); |
92
|
|
|
|
93
|
|
|
// save token in memory |
94
|
|
|
$this->pushInMemory($settings->sessionKey, $token); |
95
|
|
|
|
96
|
|
|
$image = $this->drawImage( |
97
|
|
|
$token, |
98
|
|
|
$settings->width, |
99
|
|
|
$settings->height, |
100
|
|
|
$settings->foregroundColors, |
101
|
|
|
$settings->backgroundColor, |
102
|
|
|
$settings->letterSpacing, |
103
|
|
|
$settings->fontSize, |
104
|
|
|
$settings->fontFamily |
105
|
|
|
); |
106
|
|
|
|
107
|
|
|
return $image; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* Generate captcha. |
112
|
|
|
* |
113
|
|
|
* @return mixed |
114
|
|
|
*/ |
115
|
|
|
public function generate() |
116
|
|
|
{ |
117
|
|
|
return View::make( |
|
|
|
|
118
|
|
|
'captchaSimpleDriver::captcha', |
119
|
|
|
[ |
120
|
|
|
'routeName' => $this->settings->route, |
121
|
|
|
'errorsName' => config('captcha.validator'), |
122
|
|
|
] |
123
|
|
|
); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Verify token. |
128
|
|
|
* |
129
|
|
|
* @param null|$token |
130
|
|
|
* @return bool |
131
|
|
|
*/ |
132
|
|
|
public function verify($token = null) |
133
|
|
|
{ |
134
|
|
|
$storedToken = $this->pullFromMemory($this->settings->sessionKey); |
135
|
|
|
|
136
|
|
|
if (empty($this->settings->sensitive)) { |
137
|
|
|
$storedToken = mb_strtolower($storedToken); |
138
|
|
|
$token = mb_strtolower($token); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
return $token == $storedToken; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Save token in memory. |
146
|
|
|
* |
147
|
|
|
* @param $key |
148
|
|
|
* @param $value |
149
|
|
|
* @return $this |
150
|
|
|
*/ |
151
|
|
|
protected function pushInMemory($key, $value) |
152
|
|
|
{ |
153
|
|
|
session()->put($key, $value); |
154
|
|
|
|
155
|
|
|
return $this; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Retrieve token from memory. |
160
|
|
|
* |
161
|
|
|
* @return mixed |
162
|
|
|
*/ |
163
|
|
|
protected function pullFromMemory($key) |
164
|
|
|
{ |
165
|
|
|
$value = session()->pull($key); |
166
|
|
|
|
167
|
|
|
if (! empty($value)) { |
168
|
|
|
session()->forget($key); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
return $value; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* Create new canvas. |
176
|
|
|
* |
177
|
|
|
* @param $width |
178
|
|
|
* @param $height |
179
|
|
|
* @return resource |
180
|
|
|
*/ |
181
|
|
|
protected function canvas($width, $height) |
182
|
|
|
{ |
183
|
|
|
$canvas = imagecreatetruecolor($width, $height); |
184
|
|
|
|
185
|
|
|
return $canvas; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Generate image |
190
|
|
|
* |
191
|
|
|
* @param $token |
192
|
|
|
* @param $width |
193
|
|
|
* @param $height |
194
|
|
|
* @param $foregroundColors |
195
|
|
|
* @param $backgroundColor |
196
|
|
|
* @param $letterSpacing |
197
|
|
|
* @param $fontSize |
198
|
|
|
* @param $fontFamily |
199
|
|
|
* @return false|string |
200
|
|
|
*/ |
201
|
|
|
protected function drawImage( |
202
|
|
|
$token, |
203
|
|
|
$width, |
204
|
|
|
$height, |
205
|
|
|
$foregroundColors, |
206
|
|
|
$backgroundColor, |
207
|
|
|
$letterSpacing, |
208
|
|
|
$fontSize, |
209
|
|
|
$fontFamily |
210
|
|
|
) { |
211
|
|
|
$canvas = $this->canvas($width, $height); |
212
|
|
|
|
213
|
|
|
$this->fillWithColor($canvas, $backgroundColor); |
214
|
|
|
|
215
|
|
|
$offsetX = ($width - strlen($token) * ($letterSpacing + $fontSize * 0.66)) / 2; |
216
|
|
|
$offsetY = ceil(($height) / 1.5); |
217
|
|
|
|
218
|
|
|
// write token |
219
|
|
|
for ($i = 0; $i < strlen($token); $i++) { |
220
|
|
|
$randomForegroundColor = $foregroundColors[mt_rand(0, count($foregroundColors) - 1)]; |
221
|
|
|
imagettftext( |
222
|
|
|
$canvas, |
223
|
|
|
$this->settings->fontSize, |
224
|
|
|
ceil(mt_rand(0,10)), |
225
|
|
|
$offsetX, |
|
|
|
|
226
|
|
|
$offsetY, |
|
|
|
|
227
|
|
|
$this->prepareColor($canvas, $randomForegroundColor), |
228
|
|
|
$fontFamily, |
229
|
|
|
$token[$i] |
230
|
|
|
); |
231
|
|
|
$offsetX += ceil($fontSize * 0.66) + $letterSpacing; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
//Scratches foreground |
235
|
|
|
for ($i = 0; $i < $this->settings->scratches[0]; $i++) { |
236
|
|
|
$randomForegroundColor = $foregroundColors[mt_rand(0, count($foregroundColors) - 1)]; |
237
|
|
|
|
238
|
|
|
$this->drawScratch($canvas, $width, $height, $randomForegroundColor); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
//Scratches background |
242
|
|
|
for ($i = 0; $i < $this->settings->scratches[1]; $i++) { |
243
|
|
|
$this->drawScratch($canvas, $width, $height, $backgroundColor); |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
ob_start(); |
247
|
|
|
imagepng($canvas); |
248
|
|
|
$content = ob_get_contents(); |
249
|
|
|
ob_end_clean(); |
250
|
|
|
|
251
|
|
|
imagedestroy($canvas); |
252
|
|
|
|
253
|
|
|
return $content; |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
/** |
257
|
|
|
* Fill canvas with the given color |
258
|
|
|
* |
259
|
|
|
* @param $canvas |
260
|
|
|
* @param $color |
261
|
|
|
* @return $this |
262
|
|
|
*/ |
263
|
|
|
protected function fillWithColor($canvas, $color) |
264
|
|
|
{ |
265
|
|
|
$fillColor = $this->prepareColor($canvas, $color); |
266
|
|
|
|
267
|
|
|
imagefill($canvas, 0, 0, $fillColor); |
268
|
|
|
|
269
|
|
|
return $this; |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
/** |
273
|
|
|
* Draw scratches |
274
|
|
|
* |
275
|
|
|
* @param $img |
276
|
|
|
* @param $imageWidth |
277
|
|
|
* @param $imageHeight |
278
|
|
|
* @param $hex |
279
|
|
|
*/ |
280
|
|
|
private function drawScratch($img, $imageWidth, $imageHeight, $hex) |
281
|
|
|
{ |
282
|
|
|
$rgb = $this->hexToRgb($hex); |
283
|
|
|
|
284
|
|
|
imageline( |
285
|
|
|
$img, |
286
|
|
|
mt_rand(0, floor($imageWidth / 2)), |
287
|
|
|
mt_rand(1, $imageHeight), |
288
|
|
|
mt_rand(floor($imageWidth / 2), $imageWidth), |
289
|
|
|
mt_rand(1, $imageHeight), |
290
|
|
|
imagecolorallocate($img, $rgb['red'], $rgb['green'], $rgb['blue']) |
|
|
|
|
291
|
|
|
); |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* prepare a color |
296
|
|
|
* |
297
|
|
|
* @param $canvas |
298
|
|
|
* @param $color |
299
|
|
|
* @return int |
300
|
|
|
*/ |
301
|
|
|
private function prepareColor($canvas, $hexColor) |
302
|
|
|
{ |
303
|
|
|
$rgbColor = $this->hexToRGB($hexColor); |
304
|
|
|
|
305
|
|
|
return imagecolorallocate( |
306
|
|
|
$canvas, |
307
|
|
|
$rgbColor['red'], |
|
|
|
|
308
|
|
|
$rgbColor['green'], |
|
|
|
|
309
|
|
|
$rgbColor['blue'] |
|
|
|
|
310
|
|
|
); |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
/** |
314
|
|
|
* Create a random string |
315
|
|
|
* |
316
|
|
|
* @param string $characters |
317
|
|
|
* @param int $minLength |
318
|
|
|
* @param int $maxLength |
319
|
|
|
* @return string |
320
|
|
|
*/ |
321
|
|
|
private function randomString($characters = '123456789' , $minLength = 4, $maxLength = 6) |
322
|
|
|
{ |
323
|
|
|
$randomLength = mt_rand($minLength, $maxLength); |
324
|
|
|
$string = []; |
325
|
|
|
|
326
|
|
|
for ($i = 0; $i < $randomLength; $i++) { |
327
|
|
|
$string[] = $characters[mt_rand(1, mb_strlen($characters) - 1)]; |
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
$string = implode($string); |
331
|
|
|
|
332
|
|
|
return $string; |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
/** |
336
|
|
|
* Convert hex color to rgb |
337
|
|
|
* |
338
|
|
|
* @param $hexColor |
339
|
|
|
* @return array |
340
|
|
|
*/ |
341
|
|
|
private function hexToRGB($hexColor) |
342
|
|
|
{ |
343
|
|
|
$hexColor = ($hexColor[0] == '#') ? substr($hexColor, 1) : $hexColor; |
344
|
|
|
|
345
|
|
|
// Separate colors |
346
|
|
|
switch(strlen($hexColor)) { |
347
|
|
|
case 6: |
348
|
|
|
$red = $hexColor[0].$hexColor[1]; |
349
|
|
|
$green = $hexColor[2].$hexColor[3]; |
350
|
|
|
$blue = $hexColor[4].$hexColor[5]; |
351
|
|
|
break; |
352
|
|
|
case 3: |
353
|
|
|
$red = str_repeat($hexColor[0],2); |
354
|
|
|
$green = str_repeat($hexColor[1],2); |
355
|
|
|
$blue = str_repeat($hexColor[2],2); |
356
|
|
|
break; |
357
|
|
|
default: |
358
|
|
|
$red = $green = $blue = 0; |
359
|
|
|
break; |
360
|
|
|
} |
361
|
|
|
|
362
|
|
|
// Convert hex to dec |
363
|
|
|
$red = hexdec($red); |
364
|
|
|
$green = hexdec($green); |
365
|
|
|
$blue = hexdec($blue); |
366
|
|
|
|
367
|
|
|
return [ |
368
|
|
|
'red' => $red, |
369
|
|
|
'green' => $green, |
370
|
|
|
'blue' => $blue, |
371
|
|
|
]; |
372
|
|
|
} |
373
|
|
|
} |
374
|
|
|
|