Adding files from the ReCAPTCHA extension, with minor modifications
[toast/cookiecaptcha.git] / recaptchalib.php
1 <?php\r
2 /*\r
3  * This is a PHP library that handles calling reCAPTCHA.\r
4  *    - Documentation and latest version\r
5  *          http://recaptcha.net/plugins/php/\r
6  *    - Get a reCAPTCHA API Key\r
7  *          http://recaptcha.net/api/getkey\r
8  *    - Discussion group\r
9  *          http://groups.google.com/group/recaptcha\r
10  *\r
11  * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net\r
12  * AUTHORS:\r
13  *   Mike Crawford\r
14  *   Ben Maurer\r
15  *\r
16  * Permission is hereby granted, free of charge, to any person obtaining a copy\r
17  * of this software and associated documentation files (the "Software"), to deal\r
18  * in the Software without restriction, including without limitation the rights\r
19  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
20  * copies of the Software, and to permit persons to whom the Software is\r
21  * furnished to do so, subject to the following conditions:\r
22  *\r
23  * The above copyright notice and this permission notice shall be included in\r
24  * all copies or substantial portions of the Software.\r
25  *\r
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
27  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
28  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
29  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
30  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
31  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
32  * THE SOFTWARE.\r
33  */\r
34 \r
35 /**\r
36  * The reCAPTCHA server URL's\r
37  */\r
38 $recaptcha_api_server = 'http://api.recaptcha.net';\r
39 $recaptcha_api_secure_server = 'https://api-secure.recaptcha.net';\r
40 $recaptcha_verify_server = 'api-verify.recaptcha.net';\r
41 \r
42 \r
43 /**\r
44  * Encodes the given data into a query string format\r
45  * @param $data - array of string elements to be encoded\r
46  * @return string - encoded request\r
47  */\r
48 function _recaptcha_qsencode ($data) {\r
49         $req = "";\r
50         foreach ( $data as $key => $value )\r
51                 $req .= $key . '=' . urlencode( stripslashes($value) ) . '&';\r
52 \r
53         // Cut the last '&'\r
54         $req=substr($req,0,strlen($req)-1);\r
55         return $req;\r
56 }\r
57 \r
58 \r
59 \r
60 /**\r
61  * Submits an HTTP POST to a reCAPTCHA server\r
62  * @param string $host\r
63  * @param string $path\r
64  * @param array $data\r
65  * @param int port\r
66  * @return array response\r
67  */\r
68 function _recaptcha_http_post($host, $path, $data, $port = 80) {\r
69 \r
70         $req = _recaptcha_qsencode ($data);\r
71 \r
72         $http_request  = "POST $path HTTP/1.0\r\n";\r
73         $http_request .= "Host: $host\r\n";\r
74         $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";\r
75         $http_request .= "Content-Length: " . strlen($req) . "\r\n";\r
76         $http_request .= "User-Agent: reCAPTCHA/PHP\r\n";\r
77         $http_request .= "\r\n";\r
78         $http_request .= $req;\r
79 \r
80         $response = '';\r
81         if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {\r
82                 die ('Could not open socket');\r
83         }\r
84 \r
85         fwrite($fs, $http_request);\r
86 \r
87         while ( !feof($fs) )\r
88                 $response .= fgets($fs, 1160); // One TCP-IP packet\r
89         fclose($fs);\r
90         $response = explode("\r\n\r\n", $response, 2);\r
91 \r
92         return $response;\r
93 }\r
94 \r
95 \r
96 \r
97 /**\r
98  * Gets the challenge HTML (javascript and non-javascript version).\r
99  * This is called from the browser, and the resulting reCAPTCHA HTML widget\r
100  * is embedded within the HTML form it was called from.\r
101  * @param string $pubkey A public key for reCAPTCHA\r
102  * @param string $error The error given by reCAPTCHA (optional, default is null)\r
103  * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)\r
104 \r
105  * @return string - The HTML to be embedded in the user's form.\r
106  */\r
107 function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)\r
108 {\r
109         global $recaptcha_api_server, $recaptcha_api_ssl_server;\r
110 \r
111         if ($pubkey == null || $pubkey == '') {\r
112                 die ("To use reCAPTCHA you must get an API key from <a href='http://recaptcha.net/api/getkey'>http://recaptcha.net/api/getkey</a>");\r
113         }\r
114         \r
115         if ($use_ssl) {\r
116            $server = $recaptcha_api_ssl_server;\r
117         } else {\r
118            $server = $recaptcha_api_server;\r
119         }\r
120         $errorpart = "";\r
121         if ($error) {\r
122            $errorpart = "&amp;error=" . $error;\r
123         }\r
124         return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>\r
125 \r
126         <noscript>\r
127                 <iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br>\r
128                 <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>\r
129                 <input type="hidden" name="recaptcha_response_field" value="manual_challenge">\r
130         </noscript>';\r
131 }\r
132 \r
133 \r
134 \r
135 \r
136 /**\r
137  * A ReCaptchaResponse is returned from recaptcha_check_answer()\r
138  */\r
139 class ReCaptchaResponse {\r
140         var $is_valid;\r
141         var $error;\r
142 }\r
143 \r
144 \r
145 /**\r
146   * Calls an HTTP POST function to verify if the user's guess was correct\r
147   * @param string $privkey\r
148   * @param string $remoteip\r
149   * @param string $challenge\r
150   * @param string $response\r
151   * @return ReCaptchaResponse\r
152   */\r
153 function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response)\r
154 {\r
155         if ($privkey == null || $privkey == '') {\r
156                 die ("To use reCAPTCHA you must get an API key from <a href='http://recaptcha.net/api/getkey'>http://recaptcha.net/api/getkey</a>");\r
157         }\r
158 \r
159         if ($remoteip == null || $remoteip == '') {\r
160                 die ("For security reasons, you must pass the remote ip to reCAPTCHA");\r
161         }\r
162 \r
163         \r
164         \r
165         //discard spam submissions\r
166         if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {\r
167                 $recaptcha_response = new ReCaptchaResponse();\r
168                 $recaptcha_response->is_valid = false;\r
169                 $recaptcha_response->error = 'incorrect-captcha-sol';\r
170                 return $recaptcha_response;\r
171         }\r
172 \r
173         global $recaptcha_verify_server;\r
174         $response = _recaptcha_http_post ($recaptcha_verify_server, "/verify",\r
175                                           array (\r
176                                                  'privatekey' => $privkey,\r
177                                                  'remoteip' => $remoteip,\r
178                                                  'challenge' => $challenge,\r
179                                                  'response' => $response\r
180                                                  )\r
181                                           );\r
182 \r
183         $answers = explode ("\n", $response [1]);\r
184         $recaptcha_response = new ReCaptchaResponse();\r
185 \r
186         if (trim ($answers [0]) == 'true') {\r
187                 $recaptcha_response->is_valid = true;\r
188         }\r
189         else {\r
190                 $recaptcha_response->is_valid = false;\r
191                 $recaptcha_response->error = $answers [1];\r
192         }\r
193         return $recaptcha_response;\r
194 \r
195 }\r
196 \r
197 /**\r
198  * gets a URL where the user can sign up for reCAPTCHA. If your application\r
199  * has a configuration page where you enter a key, you should provide a link\r
200  * using this function.\r
201  * @param string $domain The domain where the page is hosted\r
202  * @param string $appname The name of your application\r
203  */\r
204 function recaptcha_get_signup_url ($domain = null, $appname = null) {\r
205         return "http://recaptcha.net/api/getkey?" .  _recaptcha_qsencode (array ('domain' => $domain, 'app' => $appname));\r
206 }\r
207 \r
208 \r
209 \r
210 /* Mailhide related code */\r
211 \r
212 function _recaptcha_aes_encrypt($val,$ky) {\r
213         if (! function_exists ("mcrypt_encrypt")) {\r
214                 die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");\r
215         }\r
216         $mode=MCRYPT_MODE_CBC;   \r
217         $enc=MCRYPT_RIJNDAEL_128;\r
218         $val=str_pad($val, (16*(floor(strlen($val) / 16)+(strlen($val) % 16==0?2:1))), chr(16-(strlen($val) % 16)));\r
219         return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");\r
220 }\r
221 \r
222 \r
223 function _recaptcha_mailhide_urlbase64 ($x) {\r
224         return strtr(base64_encode ($x), '+/', '-_');\r
225 }\r
226 \r
227 /* gets the reCAPTCHA Mailhide url for a given email, public key and private key */\r
228 function recaptcha_mailhide_url($pubkey, $privkey, $email) {\r
229         if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {\r
230                 die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .\r
231                      "you can do so at <a href='http://mailhide.recaptcha.net/apikey'>http://mailhide.recaptcha.net/apikey</a>");\r
232         }\r
233         \r
234 \r
235         $ky = pack('H*', $privkey);\r
236         $cryptmail = _recaptcha_aes_encrypt ($email, $ky);\r
237         \r
238         return "http://mailhide.recaptcha.net/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);\r
239 }\r
240 \r
241 /**\r
242  * gets the parts of the email to expose to the user.\r
243  * eg, given johndoe@example,com return ["john", "example.com"].\r
244  * the email is then displayed as john...@example.com\r
245  */\r
246 function _recaptcha_mailhide_email_parts ($email) {\r
247         $arr = preg_split("/@/", $email );\r
248 \r
249         if (strlen ($arr[0]) <= 4) {\r
250                 $arr[0] = substr ($arr[0], 0, 1);\r
251         } else if (strlen ($arr[0]) <= 6) {\r
252                 $arr[0] = substr ($arr[0], 0, 3);\r
253         } else {\r
254                 $arr[0] = substr ($arr[0], 0, 4);\r
255         }\r
256         return $arr;\r
257 }\r
258 \r
259 /**\r
260  * Gets html to display an email address given a public an private key.\r
261  * to get a key, go to:\r
262  *\r
263  * http://mailhide.recaptcha.net/apikey\r
264  */\r
265 function recaptcha_mailhide_html($pubkey, $privkey, $email) {\r
266         $emailparts = _recaptcha_mailhide_email_parts ($email);\r
267         $url = recaptcha_mailhide_url ($pubkey, $privkey, $email);\r
268         \r
269         return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .\r
270                 "' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);\r
271 \r
272 }\r
273 \r
274 \r
275 ?>\r