Further testing, integrating images generated from Neil's python goody.
[toast/cookiecaptcha.git] / FancyCaptcha.php
1 <?php
2
3 if ( defined( 'MEDIAWIKI' ) ) {
4
5 global $wgCaptchaDirectory;
6 $wgCaptchaDirectory = "$wgUploadDirectory/captcha"; // bad default :D
7
8 global $wgCaptchaSecret;
9 $wgCaptchaSecret = "CHANGE_THIS_SECRET!";
10
11
12 class FancyCaptcha extends SimpleCaptcha {
13         function keyMatch() {
14                 global $wgRequest, $wgCaptchaSecret;
15                 
16                 if( !isset( $_SESSION['ceAnswerVar'] ) ) {
17                         wfDebug( "FancyCaptcha: no session captcha key set, this is new visitor.\n" );
18                         return false;
19                 }
20                 
21                 $var  = $_SESSION['ceAnswerVar'];
22                 $salt = $_SESSION['captchaSalt'];
23                 $hash = $_SESSION['captchaHash'];
24                 
25                 $answer = $wgRequest->getVal( $var );
26                 $digest = $wgCaptchaSecret . $salt . $answer . $wgCaptchaSecret . $salt;
27                 $answerHash = substr( md5( $digest ), 0, 16 );
28                 
29                 if( $answerHash == $hash ) {
30                         wfDebug( "FancyCaptcha: answer hash matches expected $hash\n" );
31                         return true;
32                 } else {
33                         wfDebug( "FancyCaptcha: answer hashes to $answerHash, expected $hash\n" );
34                         return false;
35                 }
36         }
37         
38         function formCallback( &$out ) {
39                 $dest = 'wpCaptchaWord' . mt_rand();
40                 
41                 $img = $this->pickImage();
42                 if( !$img ) {
43                         die( 'aaargh' );
44                 }
45                 
46                 $_SESSION['ceAnswerVar'] = $dest;
47                 $_SESSION['captchaHash'] = $img['hash'];
48                 $_SESSION['captchaSalt'] = $img['salt'];
49                 $_SESSION['captchaViewed'] = false;
50                 wfDebug( "Picked captcha with hash ${img['hash']}, salt ${img['salt']}.\n" );
51                 
52                 $title = Title::makeTitle( NS_SPECIAL, 'Captcha/image' );
53                 $url = $title->getLocalUrl();
54                 
55                 
56                 $out->addWikiText( wfMsg( "captcha-short" ) );  
57                 $out->addHTML( <<<END
58                         <p><img src="$url" alt="Oh noes" /></p>
59                         <p><input name="$dest" id="$dest" /></p>
60 END
61                         );
62         }
63         
64         function pickImage() {
65                 global $wgCaptchaDirectory;
66                 $dir = opendir( $wgCaptchaDirectory );
67                 
68                 $n = mt_rand( 0, 16 );
69                 $count = 0;
70                 
71                 $entry = readdir( $dir );
72                 while( false !== $entry ) {
73                         $entry = readdir( $dir );
74                         if( preg_match( '/^image_([0-9a-f]+)_([0-9a-f]+)\\.png$/', $entry, $matches ) ) {
75                                 if( $count++ % 16 == $n ) {
76                                         return array(
77                                                 'salt' => $matches[1],
78                                                 'hash' => $matches[2],
79                                         );
80                                 }
81                         }
82                 }
83                 return false;
84         }
85         
86         function showImage() {
87                 global $wgOut;
88                 $wgOut->disable();
89                 if( !empty( $_SESSION['captchaViewed'] ) ) {
90                         wfHttpError( 403, 'Access Forbidden', "Can't view captcha image a second time." );
91                         return false;
92                 }
93                 $_SESSION['captchaViewed'] = wfTimestamp();
94                 
95                 if( isset( $_SESSION['captchaSalt'] ) ) {
96                         $salt = $_SESSION['captchaSalt'];
97                         if( isset( $_SESSION['captchaHash'] ) ) {
98                                 $hash = $_SESSION['captchaHash'];
99                                 
100                                 global $wgCaptchaDirectory;
101                                 $file = $wgCaptchaDirectory . DIRECTORY_SEPARATOR . "image_{$salt}_{$hash}.png";
102                                 if( file_exists( $file ) ) {
103                                         header( 'Content-type: image/png' );
104                                         readfile( $file );
105                                 }
106                         }
107                 } else {
108                         wfHttpError( 500, 'Internal Error', 'Requested bogus captcha image' );
109                 }
110         }
111 }
112
113 } # End invocation guard
114
115 ?>