1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* @title Captcha Class |
4
|
|
|
* @desc Generates a captcha and manages the display of the image. |
5
|
|
|
* |
6
|
|
|
* @author Pierre-Henry Soria <[email protected]> |
7
|
|
|
* @copyright (c) 2012-2018, Pierre-Henry Soria. All Rights Reserved. |
8
|
|
|
* @license GNU General Public License; See PH7.LICENSE.txt and PH7.COPYRIGHT.txt in the root directory. |
9
|
|
|
* @package PH7 / Framework / Security / Spam / Captcha |
10
|
|
|
* @version 0.9 |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
namespace PH7\Framework\Security\Spam\Captcha; |
14
|
|
|
|
15
|
|
|
defined('PH7') or exit('Restricted access'); |
16
|
|
|
|
17
|
|
|
use PH7\Framework\Navigation\Browser; |
18
|
|
|
use PH7\Framework\Session\Session; |
19
|
|
|
use PH7\Framework\Util\Various; |
20
|
|
|
|
21
|
|
|
class Captcha |
22
|
|
|
{ |
23
|
|
|
/** @var Session */ |
24
|
|
|
private $oSession; |
25
|
|
|
|
26
|
|
|
/** @var Str */ |
27
|
|
|
private $sStr; |
28
|
|
|
|
29
|
|
|
/** @var string */ |
30
|
|
|
private $sFont; |
31
|
|
|
|
32
|
|
|
/** @var int */ |
33
|
|
|
private $iStringWidth; |
34
|
|
|
|
35
|
|
|
/** @var int */ |
36
|
|
|
private $iHeight; |
37
|
|
|
|
38
|
|
|
/** @var int */ |
39
|
|
|
private $iWidth; |
40
|
|
|
|
41
|
|
|
/** @var int */ |
42
|
|
|
private $iSize = 36; |
43
|
|
|
|
44
|
|
|
/** @var int */ |
45
|
|
|
private $iMargin = 25; |
46
|
|
|
|
47
|
|
|
/** @var array */ |
48
|
|
|
private $aBox; |
49
|
|
|
|
50
|
|
|
/** @var array */ |
51
|
|
|
private static $aMatrixBlur = [ |
52
|
|
|
[1, 1, 1], |
53
|
|
|
[1, 1, 1], |
54
|
|
|
[1, 1, 1] |
55
|
|
|
]; |
56
|
|
|
|
57
|
|
|
/** @var array */ |
58
|
|
|
private $aColor = []; |
59
|
|
|
|
60
|
|
|
/** @var resource */ |
61
|
|
|
private $rImg; |
62
|
|
|
|
63
|
|
|
/** @var resource */ |
64
|
|
|
private $rBlack; |
65
|
|
|
|
66
|
|
|
/** @var resource */ |
67
|
|
|
private $rRed; |
68
|
|
|
|
69
|
|
|
/** @var resource */ |
70
|
|
|
private $rWhite; |
71
|
|
|
|
72
|
|
|
public function __construct() |
73
|
|
|
{ |
74
|
|
|
$this->oSession = new Session; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Show the captcha image. |
79
|
|
|
* |
80
|
|
|
* @param int $iRandom |
81
|
|
|
* |
82
|
|
|
* @return void |
83
|
|
|
*/ |
84
|
|
|
public function show($iRandom = null) |
85
|
|
|
{ |
86
|
|
|
if (!empty($iRandom)) { |
87
|
|
|
$this->sStr = Various::genRnd($iRandom, 5); |
88
|
|
|
} else { |
89
|
|
|
$this->sStr = Various::genRnd('pH7_Pierre-Henry_Soria_Sanz_González_captcha', 5); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
$this->oSession->set('rand_code', $this->sStr); |
93
|
|
|
|
94
|
|
|
$this->sFont = $this->getFont(); |
95
|
|
|
//$sBackground = PH7_PATH_DATA . 'background/' . mt_rand(1, 5) . '.png'; |
|
|
|
|
96
|
|
|
|
97
|
|
|
$this->aBox = imagettfbbox($this->iSize, 0, $this->sFont, $this->sStr); |
98
|
|
|
$this->iWidth = $this->aBox[2] - $this->aBox[0]; |
|
|
|
|
99
|
|
|
$this->iHeight = $this->aBox[1] - $this->aBox[7]; |
|
|
|
|
100
|
|
|
unset($this->aBox); |
101
|
|
|
|
102
|
|
|
$this->iStringWidth = round($this->iWidth / strlen($this->sStr)); |
|
|
|
|
103
|
|
|
|
104
|
|
|
//$this->rImg = imagecreatefrompng($sBackground); |
|
|
|
|
105
|
|
|
$this->rImg = imagecreate($this->iWidth + $this->iMargin, $this->iHeight + $this->iMargin); |
106
|
|
|
$this->aColor = [ |
107
|
|
|
imagecolorallocate($this->rImg, 0x99, 0x00, 0x66), |
108
|
|
|
imagecolorallocate($this->rImg, 0xCC, 0x00, 0x00), |
109
|
|
|
imagecolorallocate($this->rImg, 0x00, 0x00, 0xCC), |
110
|
|
|
imagecolorallocate($this->rImg, 0x00, 0x00, 0xCC), |
111
|
|
|
imagecolorallocate($this->rImg, 0xBB, 0x88, 0x77) |
112
|
|
|
]; |
113
|
|
|
|
114
|
|
|
$this->rBlack = imagecolorallocate($this->rImg, 0, 0, 0); |
|
|
|
|
115
|
|
|
$this->rRed = imagecolorallocate($this->rImg, 200, 100, 90); |
|
|
|
|
116
|
|
|
$this->rWhite = imagecolorallocate($this->rImg, 255, 255, 255); |
|
|
|
|
117
|
|
|
|
118
|
|
|
imagefilledrectangle($this->rImg, 0, 0, 399, 99, $this->rWhite); |
119
|
|
|
|
120
|
|
|
$this->mixing(); |
121
|
|
|
|
122
|
|
|
imageline($this->rImg, mt_rand(2, $this->iWidth + $this->iMargin), mt_rand(1, $this->iWidth + $this->iMargin), mt_rand(1, $this->iHeight + $this->iMargin), mt_rand(2, $this->iWidth + $this->iMargin), $this->rBlack); |
123
|
|
|
imageline($this->rImg, mt_rand(2, $this->iHeight + $this->iMargin), mt_rand(1, $this->iHeight + $this->iMargin), mt_rand(1, $this->iWidth + $this->iMargin), mt_rand(2, $this->iHeight + $this->iMargin), $this->rRed); |
124
|
|
|
imageline($this->rImg, mt_rand(2, $this->iHeight + $this->iMargin), mt_rand(1, $this->iWidth + $this->iMargin), mt_rand(1, $this->iWidth + $this->iMargin), mt_rand(2, $this->iHeight + $this->iMargin), $this->aColor[array_rand($this->aColor)]); |
125
|
|
|
unset($this->rBlack, $this->rRed, $this->rWhite); |
126
|
|
|
|
127
|
|
|
|
128
|
|
|
imageconvolution($this->rImg, self::$aMatrixBlur, 9, 0); |
129
|
|
|
imageconvolution($this->rImg, self::$aMatrixBlur, 9, 0); |
130
|
|
|
|
131
|
|
|
(new Browser)->noCache(); |
132
|
|
|
header('Content-type: image/png'); |
133
|
|
|
imagepng($this->rImg); |
134
|
|
|
imagedestroy($this->rImg); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* @param string $sCode The random code. |
139
|
|
|
* |
140
|
|
|
* @return bool |
141
|
|
|
*/ |
142
|
|
|
public function check($sCode) |
143
|
|
|
{ |
144
|
|
|
if ($sCode === null) { |
145
|
|
|
return false; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
if ($sCode === $this->oSession->get('rand_code')) { |
149
|
|
|
return true; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
return false; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* The HTML code for displaying the captcha. |
157
|
|
|
* |
158
|
|
|
* @return void |
159
|
|
|
*/ |
160
|
|
|
public function display() |
161
|
|
|
{ |
162
|
|
|
// Md5 parameter in the img tag to the captcha that the browser does not cache the captcha |
163
|
|
|
echo // The captcha stylesheet that is now in the file form.css |
164
|
|
|
'<div class="center"> |
165
|
|
|
<img class="border captcha" src="', PH7_URL_ROOT, 'asset/file/captcha/?r=', md5(time()), '" id="captcha" alt="Captcha Image" /> |
166
|
|
|
<a class="captcha_button" href="#" onclick="document.getElementById(\'captcha\').src =\'', PH7_URL_ROOT, 'asset/file/captcha/?r=\' + Math.random(); return false"><img src="', PH7_URL_STATIC, PH7_IMG, 'icon/reload.png" onclick="this.blur()" id="refresh" alt="Refresh Image" title="Refresh Image" /></a> |
167
|
|
|
</div>'; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @return void |
172
|
|
|
*/ |
173
|
|
|
private function mixing() |
174
|
|
|
{ |
175
|
|
|
for ($i = 0, $iLength = strlen($this->sStr); $i < $iLength; ++$i) { |
176
|
|
|
$sText = $this->sStr[$i]; // A string can be seen as an array |
177
|
|
|
$iAngle = mt_rand(-70, 70); |
178
|
|
|
|
179
|
|
|
imagettftext( |
180
|
|
|
$this->rImg, |
181
|
|
|
mt_rand($this->iSize / 2, $this->iSize), |
182
|
|
|
$iAngle, |
183
|
|
|
($i * $this->iStringWidth) + $this->iMargin, |
184
|
|
|
$this->iHeight + mt_rand(1, $this->iMargin / 2), |
185
|
|
|
$this->aColor[array_rand($this->aColor)], |
186
|
|
|
$this->sFont, |
187
|
|
|
$sText |
188
|
|
|
); |
189
|
|
|
} |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
/** |
193
|
|
|
* @return string The font path of captcha. |
194
|
|
|
*/ |
195
|
|
|
private function getFont() |
196
|
|
|
{ |
197
|
|
|
//$count = count(glob(PH7_PATH_DATA . '/font/*.ttf')); |
|
|
|
|
198
|
|
|
//return PH7_PATH_DATA . '/font/' . mt_rand(1,$count) . '.ttf'; |
|
|
|
|
199
|
|
|
return PH7_PATH_DATA . '/font/4.ttf'; |
200
|
|
|
} |
201
|
|
|
} |
202
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.