Completed
Push — master ( 71718d...90a3d2 )
by Rain
04:31
created

recaptchalib.php ➔ recaptcha_check_answer()   D

Complexity

Conditions 10
Paths 5

Size

Total Lines 46
Code Lines 31

Duplication

Lines 12
Ratio 26.09 %

Importance

Changes 0
Metric Value
cc 10
eloc 31
nc 5
nop 5
dl 12
loc 46
rs 4.983
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * This is a PHP library that handles calling reCAPTCHA.
4
 *    - Documentation and latest version
5
 *          http://recaptcha.net/plugins/php/
6
 *    - Get a reCAPTCHA API Key
7
 *          https://www.google.com/recaptcha/admin/create
8
 *    - Discussion group
9
 *          http://groups.google.com/group/recaptcha
10
 *
11
 * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
12
 * AUTHORS:
13
 *   Mike Crawford
14
 *   Ben Maurer
15
 *
16
 * Permission is hereby granted, free of charge, to any person obtaining a copy
17
 * of this software and associated documentation files (the "Software"), to deal
18
 * in the Software without restriction, including without limitation the rights
19
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
 * copies of the Software, and to permit persons to whom the Software is
21
 * furnished to do so, subject to the following conditions:
22
 *
23
 * The above copyright notice and this permission notice shall be included in
24
 * all copies or substantial portions of the Software.
25
 *
26
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
 * THE SOFTWARE.
33
 */
34
35
/**
36
 * The reCAPTCHA server URL's
37
 */
38
define("RECAPTCHA_API_SERVER", "http://www.google.com/recaptcha/api");
39
define("RECAPTCHA_API_SECURE_SERVER", "https://www.google.com/recaptcha/api");
40
define("RECAPTCHA_VERIFY_SERVER", "www.google.com");
41
42
/**
43
 * Encodes the given data into a query string format
44
 * @param $data - array of string elements to be encoded
45
 * @return string - encoded request
46
 */
47
function _recaptcha_qsencode ($data) {
48
        $req = "";
49
        foreach ( $data as $key => $value )
50
                $req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
51
52
        // Cut the last '&'
53
        $req=substr($req,0,strlen($req)-1);
54
        return $req;
55
}
56
57
58
59
/**
60
 * Submits an HTTP POST to a reCAPTCHA server
61
 * @param string $host
62
 * @param string $path
63
 * @param array $data
64
 * @param int port
65
 * @return array response
66
 */
67
function _recaptcha_http_post($host, $path, $data, $port = 80) {
68
69
        $req = _recaptcha_qsencode ($data);
70
71
        $http_request  = "POST $path HTTP/1.0\r\n";
72
        $http_request .= "Host: $host\r\n";
73
        $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
74
        $http_request .= "Content-Length: " . strlen($req) . "\r\n";
75
        $http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
76
        $http_request .= "\r\n";
77
        $http_request .= $req;
78
79
        $response = '';
80
        if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
81
                die ('Could not open socket');
0 ignored issues
show
Coding Style Compatibility introduced by
The function _recaptcha_http_post() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
82
        }
83
84
        fwrite($fs, $http_request);
85
86
        while ( !feof($fs) )
87
                $response .= fgets($fs, 1160); // One TCP-IP packet
88
        fclose($fs);
89
        $response = explode("\r\n\r\n", $response, 2);
90
91
        return $response;
92
}
93
94
95
96
/**
97
 * Gets the challenge HTML (javascript and non-javascript version).
98
 * This is called from the browser, and the resulting reCAPTCHA HTML widget
99
 * is embedded within the HTML form it was called from.
100
 * @param string $pubkey A public key for reCAPTCHA
101
 * @param string $error The error given by reCAPTCHA (optional, default is null)
102
 * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
103
104
 * @return string - The HTML to be embedded in the user's form.
105
 */
106
function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)
107
{
108
	if ($pubkey == null || $pubkey == '') {
109
		die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
0 ignored issues
show
Coding Style Compatibility introduced by
The function recaptcha_get_html() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
110
	}
111
112
	if ($use_ssl) {
113
                $server = RECAPTCHA_API_SECURE_SERVER;
114
        } else {
115
                $server = RECAPTCHA_API_SERVER;
116
        }
117
118
        $errorpart = "";
119
        if ($error) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $error of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
120
           $errorpart = "&amp;error=" . $error;
121
        }
122
        return '<script type="text/javascript" data-cfasync="false" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
123
124
	<noscript>
125
  		<iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
126
  		<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
127
  		<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
128
	</noscript>';
129
}
130
131
132
133
134
/**
135
 * A ReCaptchaResponse is returned from recaptcha_check_answer()
136
 */
137
class ReCaptchaResponse {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
138
	var $is_valid;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $is_valid.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
139
	var $error;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $error.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
140
}
141
142
143
/**
144
  * Calls an HTTP POST function to verify if the user's guess was correct
145
  * @param string $privkey
146
  * @param string $remoteip
147
  * @param string $challenge
148
  * @param string $response
149
  * @param array $extra_params an array of extra variables to post to the server
150
  * @return ReCaptchaResponse
151
  */
152
function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
153
{
154 View Code Duplication
	if ($privkey == null || $privkey == '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
155
		$recaptcha_response = new ReCaptchaResponse();
156
		$recaptcha_response->is_valid = false;
157
		$recaptcha_response->error = 'To use reCAPTCHA you must get an API key from <a href=\'https://www.google.com/recaptcha/admin/create\'>https://www.google.com/recaptcha/admin/create</a>';
158
		return $recaptcha_response;
159
	}
160
161 View Code Duplication
	if ($remoteip == null || $remoteip == '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
162
		$recaptcha_response = new ReCaptchaResponse();
163
		$recaptcha_response->is_valid = false;
164
		$recaptcha_response->error = 'For security reasons, you must pass the remote ip to reCAPTCHA';
165
		return $recaptcha_response;
166
	}
167
168
	//discard spam submissions
169
	if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
170
			$recaptcha_response = new ReCaptchaResponse();
171
			$recaptcha_response->is_valid = false;
172
			$recaptcha_response->error = 'incorrect-captcha-sol';
173
			return $recaptcha_response;
174
	}
175
176
	$response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
177
			array (
178
				   'privatekey' => $privkey,
179
				   'remoteip' => $remoteip,
180
				   'challenge' => $challenge,
181
				   'response' => $response
182
				   ) + $extra_params
183
			);
184
185
	$answers = explode ("\n", $response [1]);
186
	$recaptcha_response = new ReCaptchaResponse();
187
188
	if (trim ($answers [0]) == 'true') {
189
			$recaptcha_response->is_valid = true;
190
	}
191
	else {
192
			$recaptcha_response->is_valid = false;
193
			$recaptcha_response->error = $answers [1];
194
	}
195
	return $recaptcha_response;
196
197
}
198
199
/**
200
 * gets a URL where the user can sign up for reCAPTCHA. If your application
201
 * has a configuration page where you enter a key, you should provide a link
202
 * using this function.
203
 * @param string $domain The domain where the page is hosted
204
 * @param string $appname The name of your application
205
 */
206
function recaptcha_get_signup_url ($domain = null, $appname = null) {
207
	return "https://www.google.com/recaptcha/admin/create?" .  _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname));
208
}
209
210
function _recaptcha_aes_pad($val) {
211
	$block_size = 16;
212
	$numpad = $block_size - (strlen ($val) % $block_size);
213
	return str_pad($val, strlen ($val) + $numpad, chr($numpad));
214
}
215
216
/* Mailhide related code */
217
218
function _recaptcha_aes_encrypt($val,$ky) {
219
	if (! function_exists ("mcrypt_encrypt")) {
220
		die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
0 ignored issues
show
Coding Style Compatibility introduced by
The function _recaptcha_aes_encrypt() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
221
	}
222
	$mode=MCRYPT_MODE_CBC;
223
	$enc=MCRYPT_RIJNDAEL_128;
224
	$val=_recaptcha_aes_pad($val);
225
	return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
226
}
227
228
229
function _recaptcha_mailhide_urlbase64 ($x) {
230
	return strtr(base64_encode ($x), '+/', '-_');
231
}
232
233
/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
234
function recaptcha_mailhide_url($pubkey, $privkey, $email) {
235
	if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
236
		die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
0 ignored issues
show
Coding Style Compatibility introduced by
The function recaptcha_mailhide_url() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
237
		     "you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>");
238
	}
239
240
241
	$ky = pack('H*', $privkey);
242
	$cryptmail = _recaptcha_aes_encrypt ($email, $ky);
243
244
	return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
245
}
246
247
/**
248
 * gets the parts of the email to expose to the user.
249
 * eg, given johndoe@example,com return ["john", "example.com"].
250
 * the email is then displayed as [email protected]
251
 */
252
function _recaptcha_mailhide_email_parts ($email) {
253
	$arr = preg_split("/@/", $email );
254
255
	if (strlen ($arr[0]) <= 4) {
256
		$arr[0] = substr ($arr[0], 0, 1);
257
	} else if (strlen ($arr[0]) <= 6) {
258
		$arr[0] = substr ($arr[0], 0, 3);
259
	} else {
260
		$arr[0] = substr ($arr[0], 0, 4);
261
	}
262
	return $arr;
263
}
264
265
/**
266
 * Gets html to display an email address given a public an private key.
267
 * to get a key, go to:
268
 *
269
 * http://www.google.com/recaptcha/mailhide/apikey
270
 */
271
function recaptcha_mailhide_html($pubkey, $privkey, $email) {
272
	$emailparts = _recaptcha_mailhide_email_parts ($email);
273
	$url = recaptcha_mailhide_url ($pubkey, $privkey, $email);
274
275
	return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .
276
		"' 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]);
277
278
}
279
280
281