1 | <?php
|
---|
2 | /**
|
---|
3 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
---|
4 | * @author Andreas Gohr <[email protected]>
|
---|
5 | */
|
---|
6 | // must be run within Dokuwiki
|
---|
7 | if(!defined('DOKU_INC')) die();
|
---|
8 | if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
|
---|
9 | require_once(DOKU_INC.'inc/blowfish.php');
|
---|
10 |
|
---|
11 | class helper_plugin_captcha extends DokuWiki_Plugin {
|
---|
12 |
|
---|
13 | /**
|
---|
14 | * Check if the CAPTCHA should be used. Always check this before using the methods below.
|
---|
15 | *
|
---|
16 | * @return bool true when the CAPTCHA should be used
|
---|
17 | */
|
---|
18 | function isEnabled(){
|
---|
19 | if(!$this->getConf('forusers') && $_SERVER['REMOTE_USER']) return false;
|
---|
20 | return true;
|
---|
21 | }
|
---|
22 |
|
---|
23 | /**
|
---|
24 | * Returns the HTML to display the CAPTCHA with the chosen method
|
---|
25 | */
|
---|
26 | function getHTML(){
|
---|
27 | global $ID;
|
---|
28 |
|
---|
29 | $rand = (float) (rand(0,10000))/10000;
|
---|
30 | $code = $this->_generateCAPTCHA($this->_fixedIdent(),$rand);
|
---|
31 | $secret = PMA_blowfish_encrypt($rand,auth_cookiesalt());
|
---|
32 |
|
---|
33 | $out = '';
|
---|
34 | $out .= '<div id="plugin__captcha_wrapper">';
|
---|
35 | $out .= '<input type="hidden" name="plugin__captcha_secret" value="'.hsc($secret).'" />';
|
---|
36 | $out .= '<label for="plugin__captcha">'.$this->getLang('fillcaptcha').'</label> ';
|
---|
37 | $out .= '<input type="text" size="5" maxlength="5" name="plugin__captcha" id="plugin__captcha" class="edit" /> ';
|
---|
38 | switch($this->getConf('mode')){
|
---|
39 | case 'text':
|
---|
40 | $out .= $code;
|
---|
41 | break;
|
---|
42 | case 'js':
|
---|
43 | $out .= '<span id="plugin__captcha_code">'.$code.'</span>';
|
---|
44 | break;
|
---|
45 | case 'image':
|
---|
46 | $out .= '<img src="'.DOKU_BASE.'lib/plugins/captcha/img.php?secret='.rawurlencode($secret).'&id='.$ID.'" '.
|
---|
47 | ' width="'.$this->getConf('width').'" height="'.$this->getConf('height').'" alt="" /> ';
|
---|
48 | break;
|
---|
49 | case 'audio':
|
---|
50 | $out .= '<img src="'.DOKU_BASE.'lib/plugins/captcha/img.php?secret='.rawurlencode($secret).'&id='.$ID.'" '.
|
---|
51 | ' width="'.$this->getConf('width').'" height="'.$this->getConf('height').'" alt="" /> ';
|
---|
52 | $out .= '<a href="'.DOKU_BASE.'lib/plugins/captcha/wav.php?secret='.rawurlencode($secret).'&id='.$ID.'"'.
|
---|
53 | ' class="JSnocheck" title="'.$this->getLang('soundlink').'">';
|
---|
54 | $out .= '<img src="'.DOKU_BASE.'lib/plugins/captcha/sound.png" width="16" height="16"'.
|
---|
55 | ' alt="'.$this->getLang('soundlink').'" /></a>';
|
---|
56 | break;
|
---|
57 | case 'figlet':
|
---|
58 | require_once(dirname(__FILE__).'/figlet.php');
|
---|
59 | $figlet = new phpFiglet();
|
---|
60 | if($figlet->loadfont(dirname(__FILE__).'/figlet.flf')){
|
---|
61 | $out .= '<pre>';
|
---|
62 | $out .= rtrim($figlet->fetch($code));
|
---|
63 | $out .= '</pre>';
|
---|
64 | }else{
|
---|
65 | msg('Failed to load figlet.flf font file. CAPTCHA broken',-1);
|
---|
66 | }
|
---|
67 | break;
|
---|
68 | }
|
---|
69 | $out .= '</div>';
|
---|
70 | return $out;
|
---|
71 | }
|
---|
72 |
|
---|
73 | /**
|
---|
74 | * Checks if the the CAPTCHA was solved correctly
|
---|
75 | *
|
---|
76 | * @param bool $msg when true, an error will be signalled through the msg() method
|
---|
77 | * @return bool true when the answer was correct, otherwise false
|
---|
78 | */
|
---|
79 | function check($msg=true){
|
---|
80 | // compare provided string with decrypted captcha
|
---|
81 | $rand = PMA_blowfish_decrypt($_REQUEST['plugin__captcha_secret'],auth_cookiesalt());
|
---|
82 | $code = $this->_generateCAPTCHA($this->_fixedIdent(),$rand);
|
---|
83 |
|
---|
84 | if(!$_REQUEST['plugin__captcha_secret'] ||
|
---|
85 | !$_REQUEST['plugin__captcha'] ||
|
---|
86 | strtoupper($_REQUEST['plugin__captcha']) != $code){
|
---|
87 | if($msg) msg($this->getLang('testfailed'),-1);
|
---|
88 | return false;
|
---|
89 | }
|
---|
90 | return true;
|
---|
91 | }
|
---|
92 |
|
---|
93 | /**
|
---|
94 | * Build a semi-secret fixed string identifying the current page and user
|
---|
95 | *
|
---|
96 | * This string is always the same for the current user when editing the same
|
---|
97 | * page revision.
|
---|
98 | */
|
---|
99 | function _fixedIdent(){
|
---|
100 | global $ID;
|
---|
101 | $lm = @filemtime(wikiFN($ID));
|
---|
102 | return auth_browseruid().
|
---|
103 | auth_cookiesalt().
|
---|
104 | $ID.$lm;
|
---|
105 | }
|
---|
106 |
|
---|
107 | /**
|
---|
108 | * Generates a random 5 char string
|
---|
109 | *
|
---|
110 | * @param $fixed string - the fixed part, any string
|
---|
111 | * @param $rand float - some random number between 0 and 1
|
---|
112 | */
|
---|
113 | function _generateCAPTCHA($fixed,$rand){
|
---|
114 | $fixed = hexdec(substr(md5($fixed),5,5)); // use part of the md5 to generate an int
|
---|
115 | $numbers = md5($rand * $fixed); // combine both values
|
---|
116 |
|
---|
117 | // now create the letters
|
---|
118 | $code = '';
|
---|
119 | for($i=0;$i<10;$i+=2){
|
---|
120 | $code .= chr(floor(hexdec($numbers[$i].$numbers[$i+1])/10) + 65);
|
---|
121 | }
|
---|
122 |
|
---|
123 | return $code;
|
---|
124 | }
|
---|
125 |
|
---|
126 |
|
---|
127 | /**
|
---|
128 | * Create a CAPTCHA image
|
---|
129 | */
|
---|
130 | function _imageCAPTCHA($text){
|
---|
131 | $w = $this->getConf('width');
|
---|
132 | $h = $this->getConf('height');
|
---|
133 |
|
---|
134 | // create a white image
|
---|
135 | $img = imagecreate($w, $h);
|
---|
136 | imagecolorallocate($img, 255, 255, 255);
|
---|
137 |
|
---|
138 | // add some lines as background noise
|
---|
139 | for ($i = 0; $i < 30; $i++) {
|
---|
140 | $color = imagecolorallocate($img,rand(100, 250),rand(100, 250),rand(100, 250));
|
---|
141 | imageline($img,rand(0,$w),rand(0,$h),rand(0,$w),rand(0,$h),$color);
|
---|
142 | }
|
---|
143 |
|
---|
144 | // draw the letters
|
---|
145 | for ($i = 0; $i < strlen($text); $i++){
|
---|
146 | $font = dirname(__FILE__).'/VeraSe.ttf';
|
---|
147 | $color = imagecolorallocate($img, rand(0, 100), rand(0, 100), rand(0, 100));
|
---|
148 | $size = rand(floor($h/1.8),floor($h*0.7));
|
---|
149 | $angle = rand(-35, 35);
|
---|
150 |
|
---|
151 | $x = ($w*0.05) + $i * floor($w*0.9/5);
|
---|
152 | $cheight = $size + ($size*0.5);
|
---|
153 | $y = floor($h / 2 + $cheight / 3.8);
|
---|
154 |
|
---|
155 | imagettftext($img, $size, $angle, $x, $y, $color, $font, $text[$i]);
|
---|
156 | }
|
---|
157 |
|
---|
158 | header("Content-type: image/png");
|
---|
159 | imagepng($img);
|
---|
160 | imagedestroy($img);
|
---|
161 | }
|
---|
162 |
|
---|
163 |
|
---|
164 | }
|
---|