Changeset 2175

Show
Ignore:
Timestamp:
08/29/2007 02:57:50 PM
Author:
xue
Message:

finished TCaptcha.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/demos/quickstart/protected/pages/Controls/Standard.page

    r2161 r2175  
    66  <li> 
    77  <a href="?page=Controls.Button">TButton</a> represents a click button on a Web page. It is mainly used to trigger page postback. 
     8  </li> 
     9 
     10  <li> 
     11  <a href="?page=Controls.Captcha">TCaptcha</a> displays a CAPTCHA to keep spammers from signing up for certain accounts online. 
    812  </li> 
    913 
  • trunk/demos/quickstart/protected/pages/GettingStarted/NewFeatures.page

    r2159 r2175  
    1111<li>Added a new control <a href="?page=Controls.TabPanel">TTabPanel</a> that displays tabbed views.</li> 
    1212<li>Added a new control <a href="?page=Controls.Keyboard">TKeyboard</a> that displays a virtual keyboard for text input.</li> 
    13 <li>Added a new module TCacheHttpSession that stores session data using a cache module to improve the session performance.</li> 
     13<li>Added a new control <a href="?page=Controls.Captcha">TCaptcha</a> that displays a CAPTCHA to keep spammers from signing up for certain accounts online. A related validator <tt>TCaptchaValidator</tt> is also implemented.</li> 
    1414<li>Added Oracle DB support to Active Record</li> 
    1515</ul> 
  • trunk/framework/Exceptions/messages/messages.txt

    r2158 r2175  
    434434keyboard_forcontrol_required                    = TKeyboard.ForControl cannot be empty. 
    435435keyboard_forcontrol_invalid                             = TKeyboard.ForControl '{0}' is invalid. 
     436 
     437captcha_tokenimagetheme_invalid                 = TCaptcha.TokenImageTheme must be an integer between {0} and {1}. 
     438captcha_tokenfontsize_invalid                   = TCaptcha.TokenFontSize must be an integer between {0} and {1}. 
     439captcha_mintokenlength_invalid                  = TCaptcha.MinTokenLength must be an integer between {0} and {1}. 
     440captcha_maxtokenlength_invalid                  = TCaptcha.MaxTokenLength must be an integer between {0} and {1}. 
     441captcha_tokenalphabet_invalid                   = TCaptcha.TokenAlphabet must be a string consisting of at least 2 characters. 
     442captcha_privatekey_unknown                              = TCaptcha.PrivateKey is unknown. Please make sure that your assets directory is writable by the Web server process. 
     443captcha_gd2_required                                    = TCaptcha requires PHP GD2 extension. 
     444captcha_imagettftext_required                   = TCaptcha requires PHP GD2 extension with TrueType font support. 
     445captcha_imagepng_required                               = TCaptcha requires PHP GD2 extension with PNG image format support. 
  • trunk/framework/Web/UI/WebControls/TCaptcha.php

    r2174 r2175  
    1919 * to determine if the input is entered by a real user instead of some program. 
    2020 * 
     21 * Unlike other CAPTCHA scripts, TCaptcha does not need session or cookie. 
     22 * 
    2123 * The token (a string consisting of alphanumeric characters) displayed is automatically 
    2224 * generated and can be configured in several ways. To specify the length of characters 
    2325 * in the token, set {@link setMinTokenLength MinTokenLength} and {@link setMaxTokenLength MaxTokenLength}. 
    2426 * To use case-insensitive comparison and generate upper-case-only token, set {@link setCaseSensitive CaseSensitive} 
    25  * to false. 
     27 * to false. More advanced users can try to set {@link setTokenAlphabet TokenAlphabet}, which 
     28 * specifies what characters can appear in tokens. 
     29 * 
     30 * To specify the appearance of the generated token image, set {@link setTokenImageTheme TokenImageTheme} 
     31 * to be an integer between 0 and 31. And to adjust the generated image size, set {@link setTokenFontSize TokenFontSize} 
     32 * (you may also set {@link TWebControl::setWidth Width}, but the scaled image may not look good.) 
    2633 * 
    2734 * Upon postback, user input can be validated by calling {@link validate()}. 
     
    3037 * remain the same during multiple postbacks. A new one can be generated by calling 
    3138 * {@link regenerateToken()} manually. 
     39 * 
     40 * The following template shows a typical use of TCaptcha control: 
     41 * <code> 
     42 * <com:TCaptcha ID="Captcha" /> 
     43 * <com:TTextBox ID="Input" /> 
     44 * <com:TCaptchaValidator CaptchaControl="Captcha" 
     45 *                        ControlToValidate="Input" 
     46 *                        ErrorMessage="You are challenged!" /> 
     47 * </code> 
    3248 * 
    3349 * @author Qiang Xue <qiang.xue@gmail.com> 
     
    4258        private $_privateKey; 
    4359 
     60        /** 
     61         * Checks the requirements needed for using TCaptcha. 
     62         */ 
    4463        public function onInit($param) 
    4564        { 
    4665                parent::onInit($param); 
    4766                $this->checkRequirements(); 
     67        } 
     68 
     69        /** 
     70         * @return integer the theme of the token image. Defaults to 0. 
     71         */ 
     72        public function getTokenImageTheme() 
     73        { 
     74                return $this->getViewState('TokenImageTheme',0); 
     75        } 
     76 
     77        /** 
     78         * Sets the theme of the token image. 
     79         * You may test each theme to find out the one you like the most. 
     80         * Below is the explanation of the theme value: 
     81         * It is treated as a 5-bit integer. Each bit toggles a specific feature of the image. 
     82         * Bit 0 (the least significant): whether the image is opaque (1) or transparent (0). 
     83         * Bit 1: whether we should add white noise to the image (1) or not (0). 
     84         * Bit 2: whether we should add a grid to  the image (1) or not (0). 
     85         * Bit 3: whether we should add some scribbles to the image (1) or not (0). 
     86         * Bit 4: whether the image background should be morphed (1) or not (0). 
     87         * @param integer the theme of the token image. It must be an integer between 0 and 31. 
     88         */ 
     89        public function setTokenImageTheme($value) 
     90        { 
     91                $value=TPropertyValue::ensureInteger($value); 
     92                if($value>=0 && $value<=31) 
     93                        $this->setViewState('TokenImageTheme',$value,0); 
     94                else 
     95                        throw new TConfigurationException('captcha_tokenimagetheme_invalid',0,31); 
     96        } 
     97 
     98        /** 
     99         * @return integer the font size used for displaying the token in an image. Defaults to 30. 
     100         */ 
     101        public function getTokenFontSize() 
     102        { 
     103                return $this->getViewState('TokenFontSize',30); 
     104        } 
     105 
     106        /** 
     107         * Sets the font size used for displaying the token in an image. 
     108         * This property affects the generated token image size. 
     109         * The image width is proportional to this font size. 
     110         * @param integer the font size used for displaying the token in an image. It must be an integer between 20 and 100. 
     111         */ 
     112        public function setTokenFontSize($value) 
     113        { 
     114                $value=TPropertyValue::ensureInteger($value); 
     115                if($value>=20 && $value<=100) 
     116                        $this->setViewState('TokenFontSize',$value,30); 
     117                else 
     118                        throw new TConfigurationException('captcha_tokenfontsize_invalid',20,100); 
    48119        } 
    49120 
     
    105176 
    106177        /** 
    107          * @return string the characters that may appear in the token. Defaults to '234578adefhijmnrtABDEFGHJLMNQRT'. 
     178         * @return string the characters that may appear in the token. Defaults to '234578adefhijmnrtABDEFGHJLMNRT'. 
    108179         */ 
    109180        public function getTokenAlphabet() 
    110181        { 
    111                 return $this->getViewState('TokenAlphabet','234578adefhijmnrtABDEFGHJLMNQRT'); 
     182                return $this->getViewState('TokenAlphabet','234578adefhijmnrtABDEFGHJLMNRT'); 
    112183        } 
    113184 
     
    119190                if(strlen($value)<2) 
    120191                        throw new TConfigurationException('captcha_tokenalphabet_invalid'); 
    121                 $this->setViewState('TokenAlphabet',$value,'234578adefhijmnrtABDEFGHJLMNQRT'); 
     192                $this->setViewState('TokenAlphabet',$value,'234578adefhijmnrtABDEFGHJLMNRT'); 
    122193        } 
    123194 
     
    242313                $options['caseSensitive']=$this->getCaseSensitive(); 
    243314                $options['alphabet']=$this->getTokenAlphabet(); 
     315                $options['fontSize']=$this->getTokenFontSize(); 
     316                $options['theme']=$this->getTokenImageTheme(); 
    244317                $str=serialize($options); 
    245318                return base64_encode(md5($privateKey.$str).$str); 
  • trunk/framework/Web/UI/WebControls/assets/captcha.php

    r2174 r2175  
    1111 */ 
    1212 
     13define('THEME_OPAQUE_BACKGROUND',0x0001); 
     14define('THEME_NOISY_BACKGROUND',0x0002); 
     15define('THEME_HAS_GRID',0x0004); 
     16define('THEME_HAS_SCRIBBLE',0x0008); 
     17define('THEME_MORPH_BACKGROUND',0x0010); 
     18 
    1319require_once(dirname(__FILE__).'/captcha_key.php'); 
    1420 
    1521$token='error'; 
     22$theme=0; 
     23 
    1624if(isset($_GET['options'])) 
    1725{ 
     
    2836                        $caseSensitive=$options['caseSensitive']; 
    2937                        $alphabet=$options['alphabet']; 
     38                        $fontSize=$options['fontSize']; 
     39                        $theme=$options['theme']; 
    3040                        $token=generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive); 
    3141                } 
     
    3343} 
    3444 
    35 displayToken($token); 
     45displayToken($token,$fontSize,$theme); 
    3646 
    3747function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive) 
     
    4151} 
    4252 
    43 function hash2string($hex,$alphabet=''
     53function hash2string($hex,$alphabet
    4454{ 
    4555        if(strlen($alphabet)<2) 
    46                 $alphabet='234578adefhijmnrtABDEFGHJLMNQRT'; 
     56                $alphabet='234578adefhijmnrtABDEFGHJLMNRT'; 
    4757        $hexLength=strlen($hex); 
    4858        $base=strlen($alphabet); 
     
    6070} 
    6171 
    62 function displayToken($token) 
    63 
     72function displayToken($token,$fontSize,$theme) 
     73
     74        if(($fontSize=(int)$fontSize)<22) 
     75                $fontSize=22; 
     76        if($fontSize>100) 
     77                $fontSize=100; 
    6478        $length=strlen($token); 
    65         $width=45*$length; 
    66         $height=70; 
     79        $padding=10; 
     80        $fontWidth=$fontSize; 
     81        $fontHeight=floor($fontWidth*1.5); 
     82        $width=$fontWidth*$length+$padding*2; 
     83        $height=$fontHeight; 
    6784        $image=imagecreatetruecolor($width,$height); 
     85 
     86        addBackground 
     87        ( 
     88                $image, $width, $height, 
     89                $theme&THEME_OPAQUE_BACKGROUND, 
     90                $theme&THEME_NOISY_BACKGROUND, 
     91                $theme&THEME_HAS_GRID, 
     92                $theme&THEME_HAS_SCRIBBLE, 
     93                $theme&THEME_MORPH_BACKGROUND 
     94        ); 
     95 
    6896        $font=dirname(__FILE__).DIRECTORY_SEPARATOR.'verase.ttf'; 
    69         $vred=rand(0,100); 
    70         $vgreen=rand(0,100); 
    71         $vblue=rand(0,100); 
    72         for($x=0;$x<$width;++$x) 
    73         { 
    74                 for($y=0;$y<$height;++$y) 
    75                 { 
    76                         $vred+=rand(-2,2); 
    77                         $vgreen+=rand(-2,2); 
    78                         $vblue+=rand(-2,2); 
    79                         if($vred<0) $vred=0; if($vred>150) $vred=75; 
    80                         if($vgreen<0) $vgreen=0; if($vgreen>150) $vgreen=75; 
    81                         if($vblue<0) $vblue=0; if($vblue>150) $vblue=75; 
    82                         $col = imagecolorallocate($image, $vred, $vgreen, $vblue); 
    83                         imagesetpixel($image, $x, $y, $col); 
    84             imagecolordeallocate($image, $col); 
    85                 } 
    86         } 
    87  
    88     imagefilter($image,IMG_FILTER_GAUSSIAN_BLUR); 
     97 
     98        if(function_exists('imagefilter')) 
     99        imagefilter($image,IMG_FILTER_GAUSSIAN_BLUR); 
     100 
    89101    for($i=0;$i<$length;$i++) 
    90102        { 
    91         $vred = rand(150, 240); 
    92                 $vgreen = rand(150, 240); 
    93                 $vblue = rand(150, 240); 
    94         $col = imagecolorallocate($image, $vred, $vgreen, $vblue); 
    95         $char = $token[$i]; 
    96         imagettftext($image, rand(40, 50), rand(-10, 20), 13 + (40 * $i), rand(50, imagesy($image) - 10), $col, $font, $char); 
    97         imagecolordeallocate($image, $col); 
     103        $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220)); 
     104        imagettftext($image,rand($fontWidth-10,$fontWidth),rand(-30, 30),$padding+$i*$fontWidth,rand($fontHeight-15,$fontHeight-10),$color,$font,$token[$i]); 
     105        imagecolordeallocate($image,$color); 
    98106    } 
    99     imagefilter($image,IMG_FILTER_GAUSSIAN_BLUR); 
    100107 
    101108        imagepng($image); 
     
    103110} 
    104111 
     112function addBackground($image,$width,$height,$opaque,$noisy,$hasGrid,$hasScribble,$morph) 
     113{ 
     114        $background=imagecreatetruecolor($width*2,$height*2); 
     115        $white=imagecolorallocate($background,255,255,255); 
     116        imagefill($background,0,0,$white); 
     117 
     118        if($opaque) 
     119                imagefill($background,0,0,imagecolorallocate($background,100,100,100)); 
     120 
     121        if($noisy) 
     122                addNoise($background,$width*2,$height*2); 
     123 
     124        if($hasGrid) 
     125                addGrid($background,$width*2,$height*2); 
     126 
     127        if($hasScribble) 
     128                addScribble($background,$width*2,$height*2); 
     129 
     130        if($morph) 
     131                morphImage($background,$width*2,$height*2); 
     132 
     133        imagecopy($image,$background,0,0,30,30,$width,$height); 
     134 
     135        if(!$opaque) 
     136                imagecolortransparent($image,$white); 
     137} 
     138 
     139function addNoise($image,$width,$height) 
     140{ 
     141        for($x=0;$x<$width;++$x) 
     142        { 
     143                for($y=0;$y<$height;++$y) 
     144                { 
     145                        if(rand(0,100)<25) 
     146                        { 
     147                                $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220)); 
     148                                imagesetpixel($image,$x,$y,$color); 
     149                    imagecolordeallocate($image,$color); 
     150                } 
     151                } 
     152        } 
     153} 
     154 
     155function addGrid($image,$width,$height) 
     156{ 
     157        for($i=0;$i<$width;$i+=rand(15,25)) 
     158        { 
     159                imagesetthickness($image,rand(2,6)); 
     160                $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); 
     161                imageline($image,$i+rand(-10,20),0,$i+rand(-10,20),$height,$color); 
     162                imagecolordeallocate($image,$color); 
     163        } 
     164        for($i=0;$i<$height;$i+=rand(15,25)) 
     165        { 
     166                imagesetthickness($image,rand(2,6)); 
     167                $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); 
     168                imageline($image,0,$i+rand(-10,20),$width,$i+rand(-10,20),$color); 
     169                imagecolordeallocate($image,$color); 
     170        } 
     171} 
     172 
     173function addScribble($image,$width,$height) 
     174{ 
     175        for($i=0;$i<8;$i++) 
     176        { 
     177                $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); 
     178                $points=array(); 
     179                for($j=1;$j<rand(5,10);$j++) 
     180                { 
     181                        $points[]=rand(2*(20*($i+1)),2*(50*($i+1))); 
     182                        $points[]=rand(30,$height+30); 
     183                } 
     184                imagesetthickness($image,rand(2,6)); 
     185                imagepolygon($image,$points,intval(sizeof($points)/2),$color); 
     186                imagecolordeallocate($image,$color); 
     187        } 
     188} 
     189 
     190function morphImage($image,$width,$height) 
     191{ 
     192        $tempImage=imagecreatetruecolor($width,$height); 
     193        $chunk=rand(1,5); 
     194        for($x=$y=0;$x<$width;$x+=$chunk) 
     195        { 
     196                $chunk=rand(1,5); 
     197                $y+=rand(-1,1); 
     198                if($y>=$height) $y=$height-5; 
     199                if($y<0) $y=5; 
     200                imagecopy($tempImage,$image,$x,0,$x,$y,$chunk,$height); 
     201        } 
     202        for($x=$y=0;$y<$height;$y+=$chunk) 
     203        { 
     204                $chunk=rand(1,5); 
     205                $x+=rand(-1,1); 
     206                if($x>=$width)  $x=$width-5; 
     207                if($x<0) $x=5; 
     208                imagecopy($image,$tempImage,$x,$y,0,$y,$width,$chunk); 
     209        } 
     210} 
     211 
    105212?>