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 */ 67218f96cSAndreas Gohr 777e00bf9SAndreas Gohr// must be run within Dokuwiki 877e00bf9SAndreas Gohrif(!defined('DOKU_INC')) die(); 977e00bf9SAndreas Gohrif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); 107218f96cSAndreas Gohr 11a285df67SAndreas Gohr/** 12a285df67SAndreas Gohr * Class helper_plugin_captcha 13a285df67SAndreas Gohr */ 1477e00bf9SAndreas Gohrclass helper_plugin_captcha extends DokuWiki_Plugin { 1577e00bf9SAndreas Gohr 1623d379a8SAndreas Gohr protected $field_in = 'plugin__captcha'; 1723d379a8SAndreas Gohr protected $field_sec = 'plugin__captcha_secret'; 1823d379a8SAndreas Gohr protected $field_hp = 'plugin__captcha_honeypot'; 1923d379a8SAndreas Gohr 2023d379a8SAndreas Gohr /** 2123d379a8SAndreas Gohr * Constructor. Initializes field names 2223d379a8SAndreas Gohr */ 23104ec268SAndreas Gohr public function __construct() { 2423d379a8SAndreas Gohr $this->field_in = md5($this->_fixedIdent().$this->field_in); 2523d379a8SAndreas Gohr $this->field_sec = md5($this->_fixedIdent().$this->field_sec); 2623d379a8SAndreas Gohr $this->field_hp = md5($this->_fixedIdent().$this->field_hp); 2723d379a8SAndreas Gohr } 2823d379a8SAndreas Gohr 2977e00bf9SAndreas Gohr /** 3077e00bf9SAndreas Gohr * Check if the CAPTCHA should be used. Always check this before using the methods below. 3177e00bf9SAndreas Gohr * 3277e00bf9SAndreas Gohr * @return bool true when the CAPTCHA should be used 3377e00bf9SAndreas Gohr */ 34104ec268SAndreas Gohr public function isEnabled() { 3577e00bf9SAndreas Gohr if(!$this->getConf('forusers') && $_SERVER['REMOTE_USER']) return false; 3677e00bf9SAndreas Gohr return true; 3777e00bf9SAndreas Gohr } 3877e00bf9SAndreas Gohr 3977e00bf9SAndreas Gohr /** 4077e00bf9SAndreas Gohr * Returns the HTML to display the CAPTCHA with the chosen method 4177e00bf9SAndreas Gohr */ 42104ec268SAndreas Gohr public function getHTML() { 4377e00bf9SAndreas Gohr global $ID; 4477e00bf9SAndreas Gohr 4577e00bf9SAndreas Gohr $rand = (float) (rand(0, 10000)) / 10000; 46a285df67SAndreas Gohr $this->storeCaptchaCookie($this->_fixedIdent(), $rand); 47a285df67SAndreas Gohr 489e312724SAndreas Gohr if($this->getConf('mode') == 'math') { 499e312724SAndreas Gohr $code = $this->_generateMATH($this->_fixedIdent(), $rand); 509e312724SAndreas Gohr $code = $code[0]; 519e312724SAndreas Gohr $text = $this->getLang('fillmath'); 52df8afac4SAndreas Gohr } elseif($this->getConf('mode') == 'question') { 53a285df67SAndreas Gohr $code = ''; // not used 54df8afac4SAndreas Gohr $text = $this->getConf('question'); 559e312724SAndreas Gohr } else { 5677e00bf9SAndreas Gohr $code = $this->_generateCAPTCHA($this->_fixedIdent(), $rand); 579e312724SAndreas Gohr $text = $this->getLang('fillcaptcha'); 589e312724SAndreas Gohr } 59f044313dSAndreas Gohr $secret = $this->encrypt($rand); 6077e00bf9SAndreas Gohr 6128c14643SAndreas Gohr $txtlen = $this->getConf('lettercount'); 6228c14643SAndreas Gohr 6377e00bf9SAndreas Gohr $out = ''; 6477e00bf9SAndreas Gohr $out .= '<div id="plugin__captcha_wrapper">'; 6523d379a8SAndreas Gohr $out .= '<input type="hidden" name="'.$this->field_sec.'" value="'.hsc($secret).'" />'; 669e312724SAndreas Gohr $out .= '<label for="plugin__captcha">'.$text.'</label> '; 6723d379a8SAndreas Gohr 6877e00bf9SAndreas Gohr switch($this->getConf('mode')) { 699e312724SAndreas Gohr case 'math': 709d6f09afSAndreas Gohr case 'text': 719d6f09afSAndreas Gohr $out .= $this->_obfuscateText($code); 7277e00bf9SAndreas Gohr break; 7377e00bf9SAndreas Gohr case 'js': 749d6f09afSAndreas Gohr $out .= '<span id="plugin__captcha_code">'.$this->_obfuscateText($code).'</span>'; 7577e00bf9SAndreas Gohr break; 7677e00bf9SAndreas Gohr case 'image': 7777e00bf9SAndreas Gohr $out .= '<img src="'.DOKU_BASE.'lib/plugins/captcha/img.php?secret='.rawurlencode($secret).'&id='.$ID.'" '. 7877e00bf9SAndreas Gohr ' width="'.$this->getConf('width').'" height="'.$this->getConf('height').'" alt="" /> '; 7977e00bf9SAndreas Gohr break; 8077e00bf9SAndreas Gohr case 'audio': 8177e00bf9SAndreas Gohr $out .= '<img src="'.DOKU_BASE.'lib/plugins/captcha/img.php?secret='.rawurlencode($secret).'&id='.$ID.'" '. 8277e00bf9SAndreas Gohr ' width="'.$this->getConf('width').'" height="'.$this->getConf('height').'" alt="" /> '; 8377e00bf9SAndreas Gohr $out .= '<a href="'.DOKU_BASE.'lib/plugins/captcha/wav.php?secret='.rawurlencode($secret).'&id='.$ID.'"'. 8477e00bf9SAndreas Gohr ' class="JSnocheck" title="'.$this->getLang('soundlink').'">'; 8577e00bf9SAndreas Gohr $out .= '<img src="'.DOKU_BASE.'lib/plugins/captcha/sound.png" width="16" height="16"'. 8677e00bf9SAndreas Gohr ' alt="'.$this->getLang('soundlink').'" /></a>'; 8777e00bf9SAndreas Gohr break; 8852e95008SAndreas Gohr case 'figlet': 8952e95008SAndreas Gohr require_once(dirname(__FILE__).'/figlet.php'); 9052e95008SAndreas Gohr $figlet = new phpFiglet(); 9152e95008SAndreas Gohr if($figlet->loadfont(dirname(__FILE__).'/figlet.flf')) { 9252e95008SAndreas Gohr $out .= '<pre>'; 9352e95008SAndreas Gohr $out .= rtrim($figlet->fetch($code)); 9452e95008SAndreas Gohr $out .= '</pre>'; 9552e95008SAndreas Gohr } else { 9652e95008SAndreas Gohr msg('Failed to load figlet.flf font file. CAPTCHA broken', -1); 9752e95008SAndreas Gohr } 9852e95008SAndreas Gohr break; 9977e00bf9SAndreas Gohr } 100df8afac4SAndreas Gohr $out .= ' <input type="text" size="'.$txtlen.'" name="'.$this->field_in.'" class="edit" /> '; 10123d379a8SAndreas Gohr 10223d379a8SAndreas Gohr // add honeypot field 1039d63c05fSlainme $out .= '<label class="no">'.$this->getLang('honeypot').'<input type="text" name="'.$this->field_hp.'" /></label>'; 10477e00bf9SAndreas Gohr $out .= '</div>'; 10577e00bf9SAndreas Gohr return $out; 10677e00bf9SAndreas Gohr } 10777e00bf9SAndreas Gohr 10877e00bf9SAndreas Gohr /** 10977e00bf9SAndreas Gohr * Checks if the the CAPTCHA was solved correctly 11077e00bf9SAndreas Gohr * 11177e00bf9SAndreas Gohr * @param bool $msg when true, an error will be signalled through the msg() method 11277e00bf9SAndreas Gohr * @return bool true when the answer was correct, otherwise false 11377e00bf9SAndreas Gohr */ 114104ec268SAndreas Gohr public function check($msg = true) { 115478e363cSAndreas Gohr global $INPUT; 116478e363cSAndreas Gohr 117478e363cSAndreas Gohr $field_sec = $INPUT->str($this->field_sec); 118478e363cSAndreas Gohr $field_in = $INPUT->str($this->field_in); 119478e363cSAndreas Gohr $field_hp = $INPUT->str($this->field_hp); 120478e363cSAndreas Gohr 121478e363cSAndreas Gohr // reconstruct captcha from provided $field_sec 122478e363cSAndreas Gohr $rand = $this->decrypt($field_sec); 1239e312724SAndreas Gohr 1249e312724SAndreas Gohr if($this->getConf('mode') == 'math') { 1259e312724SAndreas Gohr $code = $this->_generateMATH($this->_fixedIdent(), $rand); 1269e312724SAndreas Gohr $code = $code[1]; 127df8afac4SAndreas Gohr } elseif($this->getConf('mode') == 'question') { 128df8afac4SAndreas Gohr $code = $this->getConf('answer'); 1299e312724SAndreas Gohr } else { 13077e00bf9SAndreas Gohr $code = $this->_generateCAPTCHA($this->_fixedIdent(), $rand); 1319e312724SAndreas Gohr } 13277e00bf9SAndreas Gohr 133478e363cSAndreas Gohr // compare values 134478e363cSAndreas Gohr if(!$field_sec || 135478e363cSAndreas Gohr !$field_in || 13614e271ebSPatrick Brown $rand === false || 137478e363cSAndreas Gohr utf8_strtolower($field_in) != utf8_strtolower($code) || 138a285df67SAndreas Gohr trim($field_hp) !== '' || 139a285df67SAndreas Gohr !$this->retrieveCaptchaCookie($this->_fixedIdent(), $rand) 14023d379a8SAndreas Gohr ) { 14177e00bf9SAndreas Gohr if($msg) msg($this->getLang('testfailed'), -1); 14277e00bf9SAndreas Gohr return false; 14377e00bf9SAndreas Gohr } 14477e00bf9SAndreas Gohr return true; 14577e00bf9SAndreas Gohr } 14677e00bf9SAndreas Gohr 14777e00bf9SAndreas Gohr /** 148*cde3ece1SAndreas Gohr * Get the path where a captcha cookie would be stored 149a285df67SAndreas Gohr * 150a285df67SAndreas Gohr * We use a daily temp directory which is easy to clean up 151a285df67SAndreas Gohr * 152a285df67SAndreas Gohr * @param $fixed string the fixed part, any string 153a285df67SAndreas Gohr * @param $rand float some random number between 0 and 1 154a285df67SAndreas Gohr * @return string the path to the cookie file 155a285df67SAndreas Gohr */ 156a285df67SAndreas Gohr protected function getCaptchaCookiePath($fixed, $rand) { 157a285df67SAndreas Gohr global $conf; 158a285df67SAndreas Gohr $path = $conf['tmpdir'] . '/captcha/' . date('Y-m-d') . '/' . md5($fixed . $rand) . '.cookie'; 159a285df67SAndreas Gohr io_makeFileDir($path); 160a285df67SAndreas Gohr return $path; 161a285df67SAndreas Gohr } 162a285df67SAndreas Gohr 163a285df67SAndreas Gohr /** 164*cde3ece1SAndreas Gohr * remove all outdated captcha cookies 165*cde3ece1SAndreas Gohr */ 166*cde3ece1SAndreas Gohr public function _cleanCaptchaCookies() { 167*cde3ece1SAndreas Gohr global $conf; 168*cde3ece1SAndreas Gohr $path = $conf['tmpdir'] . '/captcha/'; 169*cde3ece1SAndreas Gohr $dirs = glob("$path/*", GLOB_ONLYDIR); 170*cde3ece1SAndreas Gohr $today = date('Y-m-d'); 171*cde3ece1SAndreas Gohr foreach($dirs as $dir) { 172*cde3ece1SAndreas Gohr if(basename($dir) === $today) continue; 173*cde3ece1SAndreas Gohr if(!preg_match('/\/captcha\//', $dir)) continue; // safety net 174*cde3ece1SAndreas Gohr io_rmdir($dir, true); 175*cde3ece1SAndreas Gohr } 176*cde3ece1SAndreas Gohr } 177*cde3ece1SAndreas Gohr 178*cde3ece1SAndreas Gohr /** 179a285df67SAndreas Gohr * Creates a one time captcha cookie 180a285df67SAndreas Gohr * 181a285df67SAndreas Gohr * This is used to prevent replay attacks. It is generated when the captcha form 182a285df67SAndreas Gohr * is shown and checked with the captcha check. Since we can not be sure about the 183a285df67SAndreas Gohr * session state (might be closed or open) we're not using it. 184a285df67SAndreas Gohr * 185a285df67SAndreas Gohr * We're not using the stored values for displaying the captcha image (or audio) 186a285df67SAndreas Gohr * but continue to use our encryption scheme. This way it's still possible to have 187a285df67SAndreas Gohr * multiple captcha checks going on in parallel (eg. with multiple browser tabs) 188a285df67SAndreas Gohr * 189a285df67SAndreas Gohr * @param $fixed string the fixed part, any string 190a285df67SAndreas Gohr * @param $rand float some random number between 0 and 1 191a285df67SAndreas Gohr */ 192a285df67SAndreas Gohr protected function storeCaptchaCookie($fixed, $rand) { 193a285df67SAndreas Gohr $cache = $this->getCaptchaCookiePath($fixed, $rand); 194a285df67SAndreas Gohr touch($cache); 195a285df67SAndreas Gohr } 196a285df67SAndreas Gohr 197a285df67SAndreas Gohr /** 198a285df67SAndreas Gohr * Checks if the captcha cookie exists and deletes it 199a285df67SAndreas Gohr * 200a285df67SAndreas Gohr * @param $fixed string the fixed part, any string 201a285df67SAndreas Gohr * @param $rand float some random number between 0 and 1 202a285df67SAndreas Gohr * @return bool true if the cookie existed 203a285df67SAndreas Gohr */ 204a285df67SAndreas Gohr protected function retrieveCaptchaCookie($fixed, $rand) { 205a285df67SAndreas Gohr $cache = $this->getCaptchaCookiePath($fixed, $rand); 206a285df67SAndreas Gohr if(file_exists($cache)) { 207a285df67SAndreas Gohr unlink($cache); 208a285df67SAndreas Gohr return true; 209a285df67SAndreas Gohr } 210a285df67SAndreas Gohr return false; 211a285df67SAndreas Gohr } 212a285df67SAndreas Gohr 213a285df67SAndreas Gohr /** 21477e00bf9SAndreas Gohr * Build a semi-secret fixed string identifying the current page and user 21577e00bf9SAndreas Gohr * 21677e00bf9SAndreas Gohr * This string is always the same for the current user when editing the same 21727d84d8dSAndreas Gohr * page revision, but only for one day. Editing a page before midnight and saving 21827d84d8dSAndreas Gohr * after midnight will result in a failed CAPTCHA once, but makes sure it can 21927d84d8dSAndreas Gohr * not be reused which is especially important for the registration form where the 22027d84d8dSAndreas Gohr * $ID usually won't change. 221104ec268SAndreas Gohr * 222104ec268SAndreas Gohr * @return string 22377e00bf9SAndreas Gohr */ 224104ec268SAndreas Gohr public function _fixedIdent() { 22577e00bf9SAndreas Gohr global $ID; 22677e00bf9SAndreas Gohr $lm = @filemtime(wikiFN($ID)); 22727d84d8dSAndreas Gohr $td = date('Y-m-d'); 22877e00bf9SAndreas Gohr return auth_browseruid() . 22977e00bf9SAndreas Gohr auth_cookiesalt() . 23027d84d8dSAndreas Gohr $ID . $lm . $td; 23177e00bf9SAndreas Gohr } 23277e00bf9SAndreas Gohr 23377e00bf9SAndreas Gohr /** 2349d6f09afSAndreas Gohr * Adds random space characters within the given text 2359d6f09afSAndreas Gohr * 2369d6f09afSAndreas Gohr * Keeps subsequent numbers without spaces (for math problem) 2379d6f09afSAndreas Gohr * 2389d6f09afSAndreas Gohr * @param $text 2399d6f09afSAndreas Gohr * @return string 2409d6f09afSAndreas Gohr */ 2419d6f09afSAndreas Gohr protected function _obfuscateText($text) { 2429d6f09afSAndreas Gohr $new = ''; 2439d6f09afSAndreas Gohr 2449d6f09afSAndreas Gohr $spaces = array( 2459d6f09afSAndreas Gohr "\r", 2469d6f09afSAndreas Gohr "\n", 2479d6f09afSAndreas Gohr "\r\n", 2489d6f09afSAndreas Gohr ' ', 2499d6f09afSAndreas Gohr "\xC2\xA0", // \u00A0 NO-BREAK SPACE 2509d6f09afSAndreas Gohr "\xE2\x80\x80", // \u2000 EN QUAD 2519d6f09afSAndreas Gohr "\xE2\x80\x81", // \u2001 EM QUAD 2529d6f09afSAndreas Gohr "\xE2\x80\x82", // \u2002 EN SPACE 2539d6f09afSAndreas Gohr // "\xE2\x80\x83", // \u2003 EM SPACE 2549d6f09afSAndreas Gohr "\xE2\x80\x84", // \u2004 THREE-PER-EM SPACE 2559d6f09afSAndreas Gohr "\xE2\x80\x85", // \u2005 FOUR-PER-EM SPACE 2569d6f09afSAndreas Gohr "\xE2\x80\x86", // \u2006 SIX-PER-EM SPACE 2579d6f09afSAndreas Gohr "\xE2\x80\x87", // \u2007 FIGURE SPACE 2589d6f09afSAndreas Gohr "\xE2\x80\x88", // \u2008 PUNCTUATION SPACE 2599d6f09afSAndreas Gohr "\xE2\x80\x89", // \u2009 THIN SPACE 2609d6f09afSAndreas Gohr "\xE2\x80\x8A", // \u200A HAIR SPACE 2619d6f09afSAndreas Gohr "\xE2\x80\xAF", // \u202F NARROW NO-BREAK SPACE 2629d6f09afSAndreas Gohr "\xE2\x81\x9F", // \u205F MEDIUM MATHEMATICAL SPACE 2639d6f09afSAndreas Gohr 2649d6f09afSAndreas Gohr "\xE1\xA0\x8E\r\n", // \u180E MONGOLIAN VOWEL SEPARATOR 2659d6f09afSAndreas Gohr "\xE2\x80\x8B\r\n", // \u200B ZERO WIDTH SPACE 2669d6f09afSAndreas Gohr "\xEF\xBB\xBF\r\n", // \uFEFF ZERO WIDTH NO-BREAK SPACE 2679d6f09afSAndreas Gohr ); 2689d6f09afSAndreas Gohr 2699d6f09afSAndreas Gohr $len = strlen($text); 2709d6f09afSAndreas Gohr for($i = 0; $i < $len - 1; $i++) { 2719d6f09afSAndreas Gohr $new .= $text{$i}; 2729d6f09afSAndreas Gohr 2739d6f09afSAndreas Gohr if(!is_numeric($text{$i + 1})) { 2749d6f09afSAndreas Gohr $new .= $spaces[array_rand($spaces)]; 2759d6f09afSAndreas Gohr } 2769d6f09afSAndreas Gohr } 2779d6f09afSAndreas Gohr $new .= $text{$len - 1}; 2789d6f09afSAndreas Gohr return $new; 2799d6f09afSAndreas Gohr } 2809d6f09afSAndreas Gohr 2819d6f09afSAndreas Gohr /** 282a02b2219SPatrick Brown * Generate some numbers from a known string and random number 283a02b2219SPatrick Brown * 284a02b2219SPatrick Brown * @param $fixed string the fixed part, any string 285a02b2219SPatrick Brown * @param $rand float some random number between 0 and 1 286a02b2219SPatrick Brown * @return string 287a02b2219SPatrick Brown */ 2883ee37481SAndreas Gohr protected function _generateNumbers($fixed, $rand) { 289a02b2219SPatrick Brown $fixed = hexdec(substr(md5($fixed), 5, 5)); // use part of the md5 to generate an int 290a02b2219SPatrick Brown $rand = $rand * 0xFFFFF; // bitmask from the random number 291a02b2219SPatrick Brown return md5($rand ^ $fixed); // combine both values 292a02b2219SPatrick Brown } 293a02b2219SPatrick Brown 294a02b2219SPatrick Brown /** 29528c14643SAndreas Gohr * Generates a random char string 29677e00bf9SAndreas Gohr * 297104ec268SAndreas Gohr * @param $fixed string the fixed part, any string 298104ec268SAndreas Gohr * @param $rand float some random number between 0 and 1 29923d379a8SAndreas Gohr * @return string 30077e00bf9SAndreas Gohr */ 301104ec268SAndreas Gohr public function _generateCAPTCHA($fixed, $rand) { 302a02b2219SPatrick Brown $numbers = $this->_generateNumbers($fixed, $rand); 30377e00bf9SAndreas Gohr 30477e00bf9SAndreas Gohr // now create the letters 30577e00bf9SAndreas Gohr $code = ''; 3069a516edaSPatrick Brown $lettercount = $this->getConf('lettercount') * 2; 3079a516edaSPatrick Brown if($lettercount > strlen($numbers)) $lettercount = strlen($numbers); 3089a516edaSPatrick Brown for($i = 0; $i < $lettercount; $i += 2) { 30977e00bf9SAndreas Gohr $code .= chr(floor(hexdec($numbers[$i].$numbers[$i + 1]) / 10) + 65); 31077e00bf9SAndreas Gohr } 31177e00bf9SAndreas Gohr 31277e00bf9SAndreas Gohr return $code; 31377e00bf9SAndreas Gohr } 31477e00bf9SAndreas Gohr 3159e312724SAndreas Gohr /** 3169e312724SAndreas Gohr * Create a mathematical task and its result 3179e312724SAndreas Gohr * 318104ec268SAndreas Gohr * @param $fixed string the fixed part, any string 319104ec268SAndreas Gohr * @param $rand float some random number between 0 and 1 320104ec268SAndreas Gohr * @return array taks, result 3219e312724SAndreas Gohr */ 322104ec268SAndreas Gohr protected function _generateMATH($fixed, $rand) { 323a02b2219SPatrick Brown $numbers = $this->_generateNumbers($fixed, $rand); 3249e312724SAndreas Gohr 3259e312724SAndreas Gohr // first letter is the operator (+/-) 3269e312724SAndreas Gohr $op = (hexdec($numbers[0]) > 8) ? -1 : 1; 3279e312724SAndreas Gohr $num = array(hexdec($numbers[1].$numbers[2]), hexdec($numbers[3])); 3289e312724SAndreas Gohr 3299e312724SAndreas Gohr // we only want positive results 3309e312724SAndreas Gohr if(($op < 0) && ($num[0] < $num[1])) rsort($num); 3319e312724SAndreas Gohr 3329e312724SAndreas Gohr // prepare result and task text 3339e312724SAndreas Gohr $res = $num[0] + ($num[1] * $op); 3349d6f09afSAndreas Gohr $task = $num[0].(($op < 0) ? '-' : '+').$num[1].'=?'; 3359e312724SAndreas Gohr 3369e312724SAndreas Gohr return array($task, $res); 3379e312724SAndreas Gohr } 33877e00bf9SAndreas Gohr 33977e00bf9SAndreas Gohr /** 34077e00bf9SAndreas Gohr * Create a CAPTCHA image 341104ec268SAndreas Gohr * 342104ec268SAndreas Gohr * @param string $text the letters to display 34377e00bf9SAndreas Gohr */ 344104ec268SAndreas Gohr public function _imageCAPTCHA($text) { 34577e00bf9SAndreas Gohr $w = $this->getConf('width'); 34677e00bf9SAndreas Gohr $h = $this->getConf('height'); 34777e00bf9SAndreas Gohr 348dc091fd0SAndreas Gohr $fonts = glob(dirname(__FILE__).'/fonts/*.ttf'); 349dc091fd0SAndreas Gohr 35077e00bf9SAndreas Gohr // create a white image 35128c14643SAndreas Gohr $img = imagecreatetruecolor($w, $h); 35228c14643SAndreas Gohr $white = imagecolorallocate($img, 255, 255, 255); 35328c14643SAndreas Gohr imagefill($img, 0, 0, $white); 35477e00bf9SAndreas Gohr 35577e00bf9SAndreas Gohr // add some lines as background noise 35677e00bf9SAndreas Gohr for($i = 0; $i < 30; $i++) { 35777e00bf9SAndreas Gohr $color = imagecolorallocate($img, rand(100, 250), rand(100, 250), rand(100, 250)); 35877e00bf9SAndreas Gohr imageline($img, rand(0, $w), rand(0, $h), rand(0, $w), rand(0, $h), $color); 35977e00bf9SAndreas Gohr } 36077e00bf9SAndreas Gohr 36177e00bf9SAndreas Gohr // draw the letters 36228c14643SAndreas Gohr $txtlen = strlen($text); 36328c14643SAndreas Gohr for($i = 0; $i < $txtlen; $i++) { 364dc091fd0SAndreas Gohr $font = $fonts[array_rand($fonts)]; 36577e00bf9SAndreas Gohr $color = imagecolorallocate($img, rand(0, 100), rand(0, 100), rand(0, 100)); 36677e00bf9SAndreas Gohr $size = rand(floor($h / 1.8), floor($h * 0.7)); 36777e00bf9SAndreas Gohr $angle = rand(-35, 35); 36877e00bf9SAndreas Gohr 36928c14643SAndreas Gohr $x = ($w * 0.05) + $i * floor($w * 0.9 / $txtlen); 37077e00bf9SAndreas Gohr $cheight = $size + ($size * 0.5); 37177e00bf9SAndreas Gohr $y = floor($h / 2 + $cheight / 3.8); 37277e00bf9SAndreas Gohr 37377e00bf9SAndreas Gohr imagettftext($img, $size, $angle, $x, $y, $color, $font, $text[$i]); 37477e00bf9SAndreas Gohr } 37577e00bf9SAndreas Gohr 37677e00bf9SAndreas Gohr header("Content-type: image/png"); 37777e00bf9SAndreas Gohr imagepng($img); 37877e00bf9SAndreas Gohr imagedestroy($img); 37977e00bf9SAndreas Gohr } 38077e00bf9SAndreas Gohr 381f044313dSAndreas Gohr /** 382f044313dSAndreas Gohr * Encrypt the given string with the cookie salt 383f044313dSAndreas Gohr * 384f044313dSAndreas Gohr * @param string $data 385f044313dSAndreas Gohr * @return string 386f044313dSAndreas Gohr */ 387f044313dSAndreas Gohr public function encrypt($data) { 388f044313dSAndreas Gohr if(function_exists('auth_encrypt')) { 389f044313dSAndreas Gohr $data = auth_encrypt($data, auth_cookiesalt()); // since binky 390f044313dSAndreas Gohr } else { 391f044313dSAndreas Gohr $data = PMA_blowfish_encrypt($data, auth_cookiesalt()); // deprecated 392f044313dSAndreas Gohr } 393f044313dSAndreas Gohr 394f044313dSAndreas Gohr return base64_encode($data); 395f044313dSAndreas Gohr } 396f044313dSAndreas Gohr 397f044313dSAndreas Gohr /** 398f044313dSAndreas Gohr * Decrypt the given string with the cookie salt 399f044313dSAndreas Gohr * 400f044313dSAndreas Gohr * @param string $data 401f044313dSAndreas Gohr * @return string 402f044313dSAndreas Gohr */ 403f044313dSAndreas Gohr public function decrypt($data) { 404f044313dSAndreas Gohr $data = base64_decode($data); 40509870f99SPatrick Brown if($data === false || $data === '') return false; 406f044313dSAndreas Gohr 407f044313dSAndreas Gohr if(function_exists('auth_decrypt')) { 408f044313dSAndreas Gohr return auth_decrypt($data, auth_cookiesalt()); // since binky 409f044313dSAndreas Gohr } else { 410f044313dSAndreas Gohr return PMA_blowfish_decrypt($data, auth_cookiesalt()); // deprecated 411f044313dSAndreas Gohr } 412f044313dSAndreas Gohr } 41377e00bf9SAndreas Gohr} 414