xref: /plugin/captcha/helper.php (revision cde3ece1b2b75d735e60463369185c6646617354)
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).'&amp;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).'&amp;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).'&amp;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