1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @desc 验证码类 |
4
|
|
|
* @author vicens<[email protected]> |
5
|
|
|
*/ |
6
|
|
|
|
7
|
|
|
|
8
|
|
|
|
9
|
|
|
namespace Vicens\Captcha; |
10
|
|
|
|
11
|
|
|
use Symfony\Component\HttpFoundation\Session\Session; |
12
|
|
|
|
13
|
|
|
class Captcha |
14
|
|
|
{ |
15
|
|
|
const DEFAULT_NAME = 'default'; |
16
|
|
|
|
17
|
|
|
protected $config = [ |
18
|
|
|
/** |
19
|
|
|
* 默认验证码长度 |
20
|
|
|
* @var int |
21
|
|
|
*/ |
22
|
|
|
'length' => 4, |
23
|
|
|
/** |
24
|
|
|
* 验证码内容 |
25
|
|
|
* @var string |
26
|
|
|
*/ |
27
|
|
|
'charset' => 'abcdefghijklmnpqrstuvwxyz123456789' |
28
|
|
|
]; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* 存储驱动 |
32
|
|
|
* @var Session |
33
|
|
|
*/ |
34
|
|
|
protected $store; |
35
|
|
|
|
36
|
|
|
|
37
|
|
|
public function __construct(Session $session, array $config = []) |
38
|
|
|
{ |
39
|
|
|
$this->store = $session; |
40
|
|
|
|
41
|
|
|
$this->setConfig($config); |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* 设置验证码配置 |
46
|
|
|
* @param array $config |
47
|
|
|
* @return $this |
48
|
|
|
*/ |
49
|
|
|
public function setConfig(array $config) |
50
|
|
|
{ |
51
|
|
View Code Duplication |
foreach ($config as $key => $value) { |
|
|
|
|
52
|
|
|
if (array_key_exists($key, $this->config)) { |
53
|
|
|
$this->config[$key] = $value; |
54
|
|
|
} |
55
|
|
|
} |
56
|
|
|
return $this; |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* 获取配置 |
61
|
|
|
* @return array |
62
|
|
|
*/ |
63
|
|
|
public function getConfig() |
64
|
|
|
{ |
65
|
|
|
return $this->config; |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* 生成验证码 |
70
|
|
|
* @param string $name |
71
|
|
|
* @param array $config |
72
|
|
|
* @return Image |
73
|
|
|
*/ |
74
|
|
|
public function make($name = null, array $config = []) |
75
|
|
|
{ |
76
|
|
|
|
77
|
|
|
$config = array_merge($config, $this->config); |
78
|
|
|
|
79
|
|
|
$code = $this->generate($config['charset'], $config['length']); |
80
|
|
|
|
81
|
|
|
$this->store($name, $code); |
82
|
|
|
|
83
|
|
|
return new Image($code, $config); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* 仅测试正确性, 不删除验证码 |
88
|
|
|
* @param $input |
89
|
|
|
* @param string $name |
90
|
|
|
* @return bool |
91
|
|
|
*/ |
92
|
|
|
public function test($input, $name = null) |
93
|
|
|
{ |
94
|
|
|
|
95
|
|
|
if (!($this->has($name) && $input)) { |
96
|
|
|
return false; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
//返回验证结果 |
100
|
|
|
return strtolower($input) == $this->get($name);//password_verify(strtolower($input), $this->get($name)); |
|
|
|
|
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* 检测正确性,并删除验证码 |
105
|
|
|
* @param $input |
106
|
|
|
* @param string $name |
107
|
|
|
* @return bool |
108
|
|
|
*/ |
109
|
|
|
public function check($input, $name = null) |
110
|
|
|
{ |
111
|
|
|
$result = $this->test($input, $name); |
112
|
|
|
|
113
|
|
|
$this->remove($name); |
114
|
|
|
|
115
|
|
|
return $result; |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* 生成验证码 |
120
|
|
|
* @param array|string $charset |
121
|
|
|
* @param int $length |
122
|
|
|
* @return string |
123
|
|
|
*/ |
124
|
|
|
protected function generate($charset, $length = 4) |
125
|
|
|
{ |
126
|
|
|
$characters = str_split($charset); |
127
|
|
|
|
128
|
|
|
$code = ''; |
129
|
|
|
for ($i = 0; $i < $length; $i++) { |
130
|
|
|
$code .= $characters[rand(0, count($characters) - 1)]; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
return $code; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* 加密字符串 |
139
|
|
|
* @param $value |
140
|
|
|
* @return bool|string |
141
|
|
|
*/ |
142
|
|
|
protected function hash($value) |
143
|
|
|
{ |
144
|
|
|
$hash = password_hash($value, PASSWORD_BCRYPT, array('cost' => 10)); |
145
|
|
|
|
146
|
|
|
if ($hash === false) { |
147
|
|
|
throw new \RuntimeException('Bcrypt hashing not supported.'); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
return $value; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* 返回存储到session中的键全名 |
155
|
|
|
* @param string $name |
156
|
|
|
* @return string |
157
|
|
|
*/ |
158
|
|
|
protected function getFullName($name) |
159
|
|
|
{ |
160
|
|
|
return 'captcha.' . $name ?: self::DEFAULT_NAME; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* @param $name |
165
|
|
|
* @return bool |
166
|
|
|
*/ |
167
|
|
|
protected function has($name) |
168
|
|
|
{ |
169
|
|
|
return $this->store->has($this->getFullName($name)); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* 存储验证码 |
174
|
|
|
* @param $name |
175
|
|
|
* @param $code |
176
|
|
|
*/ |
177
|
|
|
protected function store($name, $code) |
178
|
|
|
{ |
179
|
|
|
$this->store->set($this->getFullName($name), $this->hash(strtolower($code))); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* 从存储中获取验证码 |
184
|
|
|
* @param $name |
185
|
|
|
* @return mixed |
186
|
|
|
*/ |
187
|
|
|
protected function get($name) |
188
|
|
|
{ |
189
|
|
|
return $this->store->get($this->getFullName($name)); |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
/** |
193
|
|
|
* 从存储中删除验证码 |
194
|
|
|
* @param $name |
195
|
|
|
* @return mixed |
196
|
|
|
*/ |
197
|
|
|
protected function remove($name) |
198
|
|
|
{ |
199
|
|
|
return $this->store->remove($this->getFullName($name)); |
200
|
|
|
} |
201
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.