177e00bf9SAndreas Gohr<?php 277e00bf9SAndreas Gohr/** 377e00bf9SAndreas Gohr * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 477e00bf9SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 577e00bf9SAndreas Gohr */ 677e00bf9SAndreas Gohr// must be run within Dokuwiki 777e00bf9SAndreas Gohrif(!defined('DOKU_INC')) die(); 877e00bf9SAndreas Gohrif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 977e00bf9SAndreas Gohrrequire_once(DOKU_INC.'inc/blowfish.php'); 1077e00bf9SAndreas Gohr 1177e00bf9SAndreas Gohrclass helper_plugin_captcha extends DokuWiki_Plugin { 1277e00bf9SAndreas Gohr 1377e00bf9SAndreas Gohr /** 1477e00bf9SAndreas Gohr * return some info 1577e00bf9SAndreas Gohr */ 1677e00bf9SAndreas Gohr function getInfo(){ 1777e00bf9SAndreas Gohr return confToHash(dirname(__FILE__).'/info.txt'); 1877e00bf9SAndreas Gohr } 1977e00bf9SAndreas Gohr 2077e00bf9SAndreas Gohr /** 2177e00bf9SAndreas Gohr * Check if the CAPTCHA should be used. Always check this before using the methods below. 2277e00bf9SAndreas Gohr * 2377e00bf9SAndreas Gohr * @return bool true when the CAPTCHA should be used 2477e00bf9SAndreas Gohr */ 2577e00bf9SAndreas Gohr function isEnabled(){ 2677e00bf9SAndreas Gohr if(!$this->getConf('forusers') && $_SERVER['REMOTE_USER']) return false; 2777e00bf9SAndreas Gohr return true; 2877e00bf9SAndreas Gohr } 2977e00bf9SAndreas Gohr 3077e00bf9SAndreas Gohr /** 3177e00bf9SAndreas Gohr * Returns the HTML to display the CAPTCHA with the chosen method 3277e00bf9SAndreas Gohr */ 3377e00bf9SAndreas Gohr function getHTML(){ 3477e00bf9SAndreas Gohr global $ID; 3577e00bf9SAndreas Gohr 3677e00bf9SAndreas Gohr $rand = (float) (rand(0,10000))/10000; 3777e00bf9SAndreas Gohr $code = $this->_generateCAPTCHA($this->_fixedIdent(),$rand); 3877e00bf9SAndreas Gohr $secret = PMA_blowfish_encrypt($rand,auth_cookiesalt()); 3977e00bf9SAndreas Gohr 4077e00bf9SAndreas Gohr $out = ''; 4177e00bf9SAndreas Gohr $out .= '<div id="plugin__captcha_wrapper">'; 4277e00bf9SAndreas Gohr $out .= '<input type="hidden" name="plugin__captcha_secret" value="'.hsc($secret).'" />'; 4377e00bf9SAndreas Gohr $out .= '<label for="plugin__captcha">'.$this->getLang('fillcaptcha').'</label> '; 4477e00bf9SAndreas Gohr $out .= '<input type="text" size="5" maxlength="5" name="plugin__captcha" id="plugin__captcha" class="edit" /> '; 4577e00bf9SAndreas Gohr switch($this->getConf('mode')){ 4677e00bf9SAndreas Gohr case 'text': 4777e00bf9SAndreas Gohr $out .= $code; 4877e00bf9SAndreas Gohr break; 4977e00bf9SAndreas Gohr case 'js': 5077e00bf9SAndreas Gohr $out .= '<span id="plugin__captcha_code">'.$code.'</span>'; 5177e00bf9SAndreas Gohr break; 5277e00bf9SAndreas Gohr case 'image': 5377e00bf9SAndreas Gohr $out .= '<img src="'.DOKU_BASE.'lib/plugins/captcha/img.php?secret='.rawurlencode($secret).'&id='.$ID.'" '. 5477e00bf9SAndreas Gohr ' width="'.$this->getConf('width').'" height="'.$this->getConf('height').'" alt="" /> '; 5577e00bf9SAndreas Gohr break; 5677e00bf9SAndreas Gohr case 'audio': 5777e00bf9SAndreas Gohr $out .= '<img src="'.DOKU_BASE.'lib/plugins/captcha/img.php?secret='.rawurlencode($secret).'&id='.$ID.'" '. 5877e00bf9SAndreas Gohr ' width="'.$this->getConf('width').'" height="'.$this->getConf('height').'" alt="" /> '; 5977e00bf9SAndreas Gohr $out .= '<a href="'.DOKU_BASE.'lib/plugins/captcha/wav.php?secret='.rawurlencode($secret).'&id='.$ID.'"'. 6077e00bf9SAndreas Gohr ' class="JSnocheck" title="'.$this->getLang('soundlink').'">'; 6177e00bf9SAndreas Gohr $out .= '<img src="'.DOKU_BASE.'lib/plugins/captcha/sound.png" width="16" height="16"'. 6277e00bf9SAndreas Gohr ' alt="'.$this->getLang('soundlink').'" /></a>'; 6377e00bf9SAndreas Gohr break; 64*52e95008SAndreas Gohr case 'figlet': 65*52e95008SAndreas Gohr require_once(dirname(__FILE__).'/figlet.php'); 66*52e95008SAndreas Gohr $figlet = new phpFiglet(); 67*52e95008SAndreas Gohr if($figlet->loadfont(dirname(__FILE__).'/figlet.flf')){ 68*52e95008SAndreas Gohr $out .= '<pre>'; 69*52e95008SAndreas Gohr $out .= rtrim($figlet->fetch($code)); 70*52e95008SAndreas Gohr $out .= '</pre>'; 71*52e95008SAndreas Gohr }else{ 72*52e95008SAndreas Gohr msg('Failed to load figlet.flf font file. CAPTCHA broken',-1); 73*52e95008SAndreas Gohr } 74*52e95008SAndreas Gohr break; 7577e00bf9SAndreas Gohr } 7677e00bf9SAndreas Gohr $out .= '</div>'; 7777e00bf9SAndreas Gohr return $out; 7877e00bf9SAndreas Gohr } 7977e00bf9SAndreas Gohr 8077e00bf9SAndreas Gohr /** 8177e00bf9SAndreas Gohr * Checks if the the CAPTCHA was solved correctly 8277e00bf9SAndreas Gohr * 8377e00bf9SAndreas Gohr * @param bool $msg when true, an error will be signalled through the msg() method 8477e00bf9SAndreas Gohr * @return bool true when the answer was correct, otherwise false 8577e00bf9SAndreas Gohr */ 8677e00bf9SAndreas Gohr function check($msg=true){ 8777e00bf9SAndreas Gohr // compare provided string with decrypted captcha 8877e00bf9SAndreas Gohr $rand = PMA_blowfish_decrypt($_REQUEST['plugin__captcha_secret'],auth_cookiesalt()); 8977e00bf9SAndreas Gohr $code = $this->_generateCAPTCHA($this->_fixedIdent(),$rand); 9077e00bf9SAndreas Gohr 9177e00bf9SAndreas Gohr if(!$_REQUEST['plugin__captcha_secret'] || 9277e00bf9SAndreas Gohr !$_REQUEST['plugin__captcha'] || 9377e00bf9SAndreas Gohr strtoupper($_REQUEST['plugin__captcha']) != $code){ 9477e00bf9SAndreas Gohr if($msg) msg($this->getLang('testfailed'),-1); 9577e00bf9SAndreas Gohr return false; 9677e00bf9SAndreas Gohr } 9777e00bf9SAndreas Gohr return true; 9877e00bf9SAndreas Gohr } 9977e00bf9SAndreas Gohr 10077e00bf9SAndreas Gohr /** 10177e00bf9SAndreas Gohr * Build a semi-secret fixed string identifying the current page and user 10277e00bf9SAndreas Gohr * 10377e00bf9SAndreas Gohr * This string is always the same for the current user when editing the same 10477e00bf9SAndreas Gohr * page revision. 10577e00bf9SAndreas Gohr */ 10677e00bf9SAndreas Gohr function _fixedIdent(){ 10777e00bf9SAndreas Gohr global $ID; 10877e00bf9SAndreas Gohr $lm = @filemtime(wikiFN($ID)); 10977e00bf9SAndreas Gohr return auth_browseruid(). 11077e00bf9SAndreas Gohr auth_cookiesalt(). 11177e00bf9SAndreas Gohr $ID.$lm; 11277e00bf9SAndreas Gohr } 11377e00bf9SAndreas Gohr 11477e00bf9SAndreas Gohr /** 11577e00bf9SAndreas Gohr * Generates a random 5 char string 11677e00bf9SAndreas Gohr * 11777e00bf9SAndreas Gohr * @param $fixed string - the fixed part, any string 11877e00bf9SAndreas Gohr * @param $rand float - some random number between 0 and 1 11977e00bf9SAndreas Gohr */ 12077e00bf9SAndreas Gohr function _generateCAPTCHA($fixed,$rand){ 12177e00bf9SAndreas Gohr $fixed = hexdec(substr(md5($fixed),5,5)); // use part of the md5 to generate an int 12277e00bf9SAndreas Gohr $numbers = md5($rand * $fixed); // combine both values 12377e00bf9SAndreas Gohr 12477e00bf9SAndreas Gohr // now create the letters 12577e00bf9SAndreas Gohr $code = ''; 12677e00bf9SAndreas Gohr for($i=0;$i<10;$i+=2){ 12777e00bf9SAndreas Gohr $code .= chr(floor(hexdec($numbers[$i].$numbers[$i+1])/10) + 65); 12877e00bf9SAndreas Gohr } 12977e00bf9SAndreas Gohr 13077e00bf9SAndreas Gohr return $code; 13177e00bf9SAndreas Gohr } 13277e00bf9SAndreas Gohr 13377e00bf9SAndreas Gohr 13477e00bf9SAndreas Gohr /** 13577e00bf9SAndreas Gohr * Create a CAPTCHA image 13677e00bf9SAndreas Gohr */ 13777e00bf9SAndreas Gohr function _imageCAPTCHA($text){ 13877e00bf9SAndreas Gohr $w = $this->getConf('width'); 13977e00bf9SAndreas Gohr $h = $this->getConf('height'); 14077e00bf9SAndreas Gohr 14177e00bf9SAndreas Gohr // create a white image 14277e00bf9SAndreas Gohr $img = imagecreate($w, $h); 14377e00bf9SAndreas Gohr imagecolorallocate($img, 255, 255, 255); 14477e00bf9SAndreas Gohr 14577e00bf9SAndreas Gohr // add some lines as background noise 14677e00bf9SAndreas Gohr for ($i = 0; $i < 30; $i++) { 14777e00bf9SAndreas Gohr $color = imagecolorallocate($img,rand(100, 250),rand(100, 250),rand(100, 250)); 14877e00bf9SAndreas Gohr imageline($img,rand(0,$w),rand(0,$h),rand(0,$w),rand(0,$h),$color); 14977e00bf9SAndreas Gohr } 15077e00bf9SAndreas Gohr 15177e00bf9SAndreas Gohr // draw the letters 15277e00bf9SAndreas Gohr for ($i = 0; $i < strlen($text); $i++){ 15377e00bf9SAndreas Gohr $font = dirname(__FILE__).'/VeraSe.ttf'; 15477e00bf9SAndreas Gohr $color = imagecolorallocate($img, rand(0, 100), rand(0, 100), rand(0, 100)); 15577e00bf9SAndreas Gohr $size = rand(floor($h/1.8),floor($h*0.7)); 15677e00bf9SAndreas Gohr $angle = rand(-35, 35); 15777e00bf9SAndreas Gohr 15877e00bf9SAndreas Gohr $x = ($w*0.05) + $i * floor($w*0.9/5); 15977e00bf9SAndreas Gohr $cheight = $size + ($size*0.5); 16077e00bf9SAndreas Gohr $y = floor($h / 2 + $cheight / 3.8); 16177e00bf9SAndreas Gohr 16277e00bf9SAndreas Gohr imagettftext($img, $size, $angle, $x, $y, $color, $font, $text[$i]); 16377e00bf9SAndreas Gohr } 16477e00bf9SAndreas Gohr 16577e00bf9SAndreas Gohr header("Content-type: image/png"); 16677e00bf9SAndreas Gohr imagepng($img); 16777e00bf9SAndreas Gohr imagedestroy($img); 16877e00bf9SAndreas Gohr } 16977e00bf9SAndreas Gohr 17077e00bf9SAndreas Gohr 17177e00bf9SAndreas Gohr} 172