WEBSITE: App submit form reCapatcha Patch

[email protected] (Paul) Sat, 10 Jul 2010 21:34:32 +0100
Newsgroups php.gtk.dev
Organization Original Webware Ltd
Message-ID <1278794072.24693.22.camel@paul-laptop>
Hiya,

noticed a sign when trying to add a php-gtk application saying the form
was down untill it was protected from spammers, so heres a patch that
adds the reCapatcha service.

the only thing that needs tobe done is to add a private and public key
from google to include/apps.inc which can be done using a google account
here: https://www.google.com/recaptcha/admin/create 

also made very slight change to remove register_globals usage from the
app adding part with really basic mysql query string sanitising (an
improvement but not compleate)

hope the patch is ok

-- 

Paul Lashbrook
Systems Architect
Original Webware Limited

Freephone : 0800 5200 560
T : +44 (0)1884 30 80 20
F : +44 (0)1884 30 80 21
Skype : paul.lashbrook

Follow Me on twitter! - http://twitter.com/paullashbrook
Follow Original Webware on twitter! - http://twitter.com/owltd

Original Webware Limited is Registered in England no 6681968.
Registered Office: Unit 9 Langlands Business Park, Uffculme, Devon, EX15
3DA
recapacthaAddAppForm (text/x-patch, 15.7 KB)
Index: apps/form.php
===================================================================
--- apps/form.php	(revision 297709)
+++ apps/form.php	(working copy)
@@ -9,9 +9,9 @@
 	// $form_submit - what the submit button should say
 	// 
 
-print('The submission form has been turned off until we modify the form to prevent spammers.');
+//print('The submission form has been turned off until we modify the form to prevent spammers.');
 
-/*
+
 ?>
 <script language='JavaScript'>
 <!--
@@ -119,8 +119,14 @@
 		<td align=right nowrap>Screen Shot:</td>
 		<td><input type=file name='screenshot'><br><small>(JPEG or PNG only, please)</small></td>
 	</tr>
-<?php } ?>
+<?php } 
+
+
+?>
+
+<tr><td  align=right nowrap colspan=2><? echo $capatcha_html; ?></td></tr>
 <tr valign=top>
+
 	<td align=right nowrap colspan=2>
 		<input type=reset value='Reset'>
 		<input type=submit value='<?php print($form_submit) ?>'>
@@ -129,5 +135,6 @@
 </table>
 </form>
 <?
+
 /* */
 ?>
Index: apps/add.php
===================================================================
--- apps/add.php	(revision 297709)
+++ apps/add.php	(working copy)
@@ -5,21 +5,41 @@
 // 
 
 require_once("apps.inc");
+require_once("recapatchalib.php");
+$capatcha = new recapatcha();
 
 commonHeader('Add an Application', false);
 appHeader();
 
 print("<h1>Add a PHPGTK Application</h1>");
 
+# was there a reCAPTCHA response?
+		if ($_POST['recaptcha_response_field']) {
+			$resp = $capatcha->recaptcha_check_answer ( $recapatcha_privatekey, $_SERVER ["REMOTE_ADDR"], $_POST["recaptcha_challenge_field"], $_POST['recaptcha_response_field'] );
+
+			if ($resp->is_valid) {
+				$cap_error = false;
+			} else {
+				# set the error code so that we can display it
+				$cap_error = $resp->error;
+			}
+		}else{
+			$cap_error = true;
+		}
+
 // 
 // if the form was submitted add it to the databas
 // 
-if( $action == "add" ) {
+if(isset( $_POST['action']) && $cap_error === false && $_POST['action'] == "add" ) {
 
-/*
-	if( !empty($_FILES[screenshot][name]) 
-		&& ereg("^image/", $_FILES[screenshot][type]) 
-		&& !ereg("gif", $_FILES[screenshot][type]) 
+
+
+		
+
+
+	if( !empty($_FILES['screenshot']['name']) 
+		&& ereg("^image/", $_FILES['screenshot']['type']) 
+		&& !ereg("gif", $_FILES['screenshot']['type']) 
 	)  {
 		$has_screenshot = 'Y';
 	}else {
@@ -27,11 +47,18 @@
 	}
 
 
+$cat_id = mysql_real_escape_string($_POST['cat_id']);
+$name = mysql_real_escape_string($_POST['name']);
+$has_screenshot = mysql_real_escape_string($_POST['has_screenshot']);
+$homepage_url = mysql_real_escape_string($_POST['homepage_url'] );
+$submitter = mysql_real_escape_string($_POST['submitter']);
+$blurb = mysql_real_escape_string($_POST['blurb']);
+
 	$res = mysql_query("
 			INSERT INTO app
-			(id, status, cat_id, date_added, name, has_screenshot, homepage_url, submitter, blurb)
+			(status, cat_id, date_added, name, has_screenshot, homepage_url, submitter, blurb)
 			VALUES
-			(0, 'P', $cat_id, NOW(), '$name', '$has_screenshot', '$homepage_url', '$submitter', '$blurb')
+			( 'P', $cat_id, NOW(), '$name', '$has_screenshot', '$homepage_url', '$submitter', '$blurb')
 		");
 
 	if( $res == true ) {
@@ -41,10 +68,12 @@
 		if( $has_screenshot == 'Y' ) {
 			$app_id = mysql_insert_id();
 
-			handleAppImage($_FILES[screenshot][tmp_name], $app_id);
+			handleAppImage($_FILES['screenshot']['tmp_name'], $app_id);
 
-			$screen_shot_link = "Screenshot : http://$_SERVER[SERVER_NAME]/apps/screenshot.php/$app_id.jpg\n";
+			$screen_shot_link = "Screenshot : http://{$_SERVER['SERVER_NAME']}/apps/screenshot.php/$app_id.jpg\n";
 			
+		}else{
+			$screen_shot_link = 'N/A';
 		}
 		
 		mail($mailto, "app '$name' submitted for approval.",
@@ -58,10 +87,10 @@
 			"\n" .
 			"Administrative Actions\n" .
 			"----------------------\n" .
-			"Approve: http://$_SERVER[SERVER_NAME]/apps/admin-apps.php?action=approve&app_id=$app_id\n" .
-			"Edit: http://$_SERVER[SERVER_NAME]/apps/admin-apps.php?action=edit&app_id=$app_id\n" .
-			"Reject: http://$_SERVER[SERVER_NAME]/apps/admin-apps.php?action=reject&app_id=$app_id\n" .
-			"Delete: http://$_SERVER[SERVER_NAME]/apps/admin-apps.php?action=delete&app_id=$app_id\n" .
+			"Approve: http://{$_SERVER['SERVER_NAME']}/apps/admin-apps.php?action=approve&app_id=$app_id\n" .
+			"Edit: http://{$_SERVER['SERVER_NAME']}/apps/admin-apps.php?action=edit&app_id=$app_id\n" .
+			"Reject: http://{$_SERVER['SERVER_NAME']}/apps/admin-apps.php?action=reject&app_id=$app_id\n" .
+			"Delete: http://{$_SERVER['SERVER_NAME']}/apps/admin-apps.php?action=delete&app_id=$app_id\n" .
 			"",
 			"From: $mailto");
 
@@ -71,9 +100,13 @@
 		print("<br>");
 		print("Error: (" . mysql_errno() . ") " . mysql_error() );
 	}
-*/
-    print('Submissions have been disabled until the form is safe from spammers.');
+
+   // print('Submissions have been disabled until the form is safe from spammers.');
 }else {
+
+		$capatcha_html = $capatcha->recaptcha_get_html ( $recapatcha_publickey, $cap_error );
+
+		
 	$form_app = (object) 0;
 	if( !empty($cat_id) ) { 
 		$form_app->cat_id = $cat_id;

Index: include/recapatchalib.php
===================================================================
--- include/recapatchalib.php	(revision 0)
+++ include/recapatchalib.php	(revision 0)
@@ -0,0 +1,263 @@
+<?php
+/*
+ * This is a PHP library that handles calling reCAPTCHA.
+ *    - Documentation and latest version
+ *          http://recaptcha.net/plugins/php/
+ *    - Get a reCAPTCHA API Key
+ *          https://www.google.com/recaptcha/admin/create
+ *    - Discussion group
+ *          http://groups.google.com/group/recaptcha
+ *
+ * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
+ * AUTHORS:
+ *   Mike Crawford
+ *   Ben Maurer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * The reCAPTCHA server URL's
+ */
+define ( "RECAPTCHA_API_SERVER", "http://www.google.com/recaptcha/api" );
+define ( "RECAPTCHA_API_SECURE_SERVER", "https://www.google.com/recaptcha/api" );
+define ( "RECAPTCHA_VERIFY_SERVER", "www.google.com" );
+
+
+class recapatcha {
+	
+	/**
+	 * Encodes the given data into a query string format
+	 * @param $data - array of string elements to be encoded
+	 * @return string - encoded request
+	 */
+	function _recaptcha_qsencode($data) {
+		$req = "";
+		foreach ( $data as $key => $value )
+			$req .= $key . '=' . urlencode ( stripslashes ( $value ) ) . '&';
+			
+		// Cut the last '&'
+		$req = substr ( $req, 0, strlen ( $req ) - 1 );
+		return $req;
+	}
+	
+	/**
+	 * Submits an HTTP POST to a reCAPTCHA server
+	 * @param string $host
+	 * @param string $path
+	 * @param array $data
+	 * @param int port
+	 * @return array response
+	 */
+	function _recaptcha_http_post($host, $path, $data, $port = 80) {
+		
+		$req = self::_recaptcha_qsencode ( $data );
+		
+		$http_request = "POST $path HTTP/1.0\r\n";
+		$http_request .= "Host: $host\r\n";
+		$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
+		$http_request .= "Content-Length: " . strlen ( $req ) . "\r\n";
+		$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
+		$http_request .= "\r\n";
+		$http_request .= $req;
+		
+		$response = '';
+		if (false == ($fs = @fsockopen ( $host, $port, $errno, $errstr, 10 ))) {
+			die ( 'Could not open socket' );
+		}
+		
+		fwrite ( $fs, $http_request );
+		
+		while ( ! feof ( $fs ) )
+			$response .= fgets ( $fs, 1160 ); // One TCP-IP packet
+		fclose ( $fs );
+		$response = explode ( "\r\n\r\n", $response, 2 );
+		
+		return $response;
+	}
+	
+	/**
+	 * Gets the challenge HTML (javascript and non-javascript version).
+	 * This is called from the browser, and the resulting reCAPTCHA HTML widget
+	 * is embedded within the HTML form it was called from.
+	 * @param string $pubkey A public key for reCAPTCHA
+	 * @param string $error The error given by reCAPTCHA (optional, default is null)
+	 * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
+
+	 * @return string - The HTML to be embedded in the user's form.
+	 */
+	function recaptcha_get_html($pubkey, $error = null, $use_ssl = false) {
+		if ($pubkey == null || $pubkey == '') {
+			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>" );
+		}
+		
+		if ($use_ssl) {
+			$server = RECAPTCHA_API_SECURE_SERVER;
+		} else {
+			$server = RECAPTCHA_API_SERVER;
+		}
+		
+		$errorpart = "";
+		if ($error) {
+			$errorpart = "&amp;error=" . $error;
+		}
+		return '<script type="text/javascript" src="' . $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
+
+	<noscript>
+  		<iframe src="' . $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
+  		<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
+  		<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
+	</noscript>';
+	}
+	
+	/**
+	 * Calls an HTTP POST function to verify if the user's guess was correct
+	 * @param string $privkey
+	 * @param string $remoteip
+	 * @param string $challenge
+	 * @param string $response
+	 * @param array $extra_params an array of extra variables to post to the server
+	 * @return ReCaptchaResponse
+	 */
+	function recaptcha_check_answer($privkey, $remoteip, $challenge, $response, $extra_params = array()) {
+		if ($privkey == null || $privkey == '') {
+			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>" );
+		}
+		
+		if ($remoteip == null || $remoteip == '') {
+			die ( "For security reasons, you must pass the remote ip to reCAPTCHA" );
+		}
+		
+		//discard spam submissions
+		if ($challenge == null || strlen ( $challenge ) == 0 || $response == null || strlen ( $response ) == 0) {
+			$recaptcha_response = new ReCaptchaResponse ();
+			$recaptcha_response->is_valid = false;
+			$recaptcha_response->error = 'incorrect-captcha-sol';
+			return $recaptcha_response;
+		}
+		
+		$response = self::_recaptcha_http_post ( RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify", array (
+				'privatekey' => $privkey, 
+				'remoteip' => $remoteip, 
+				'challenge' => $challenge, 
+				'response' => $response ) + $extra_params );
+		
+		$answers = explode ( "\n", $response [1] );
+		$recaptcha_response = new ReCaptchaResponse ();
+		
+		if (trim ( $answers [0] ) == 'true') {
+			$recaptcha_response->is_valid = true;
+		} else {
+			$recaptcha_response->is_valid = false;
+			$recaptcha_response->error = $answers [1];
+		}
+		return $recaptcha_response;
+	
+	}
+	
+	/**
+	 * gets a URL where the user can sign up for reCAPTCHA. If your application
+	 * has a configuration page where you enter a key, you should provide a link
+	 * using this function.
+	 * @param string $domain The domain where the page is hosted
+	 * @param string $appname The name of your application
+	 */
+	function recaptcha_get_signup_url($domain = null, $appname = null) {
+		return "https://www.google.com/recaptcha/admin/create?" . self::_recaptcha_qsencode ( array (
+				'domains' => $domain, 
+				'app' => $appname ) );
+	}
+	
+	function _recaptcha_aes_pad($val) {
+		$block_size = 16;
+		$numpad = $block_size - (strlen ( $val ) % $block_size);
+		return str_pad ( $val, strlen ( $val ) + $numpad, chr ( $numpad ) );
+	}
+	
+	/* Mailhide related code */
+	
+	function _recaptcha_aes_encrypt($val, $ky) {
+		if (! function_exists ( "mcrypt_encrypt" )) {
+			die ( "To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed." );
+		}
+		$mode = MCRYPT_MODE_CBC;
+		$enc = MCRYPT_RIJNDAEL_128;
+		$val = self::_recaptcha_aes_pad ( $val );
+		return mcrypt_encrypt ( $enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" );
+	}
+	
+	function _recaptcha_mailhide_urlbase64($x) {
+		return strtr ( base64_encode ( $x ), '+/', '-_' );
+	}
+	
+	/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
+	function recaptcha_mailhide_url($pubkey, $privkey, $email) {
+		if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
+			die ( "To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " . "you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>" );
+		}
+		
+		$ky = pack ( 'H*', $privkey );
+		$cryptmail = self::_recaptcha_aes_encrypt ( $email, $ky );
+		
+		return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . self::_recaptcha_mailhide_urlbase64 ( $cryptmail );
+	}
+	
+	/**
+	 * gets the parts of the email to expose to the user.
+	 * eg, given johndoe@example,com return ["john", "example.com"].
+	 * the email is then displayed as [email protected]
+	 */
+	function _recaptcha_mailhide_email_parts($email) {
+		$arr = preg_split ( "/@/", $email );
+		
+		if (strlen ( $arr [0] ) <= 4) {
+			$arr [0] = substr ( $arr [0], 0, 1 );
+		} else if (strlen ( $arr [0] ) <= 6) {
+			$arr [0] = substr ( $arr [0], 0, 3 );
+		} else {
+			$arr [0] = substr ( $arr [0], 0, 4 );
+		}
+		return $arr;
+	}
+	
+	/**
+	 * Gets html to display an email address given a public an private key.
+	 * to get a key, go to:
+	 *
+	 * http://www.google.com/recaptcha/mailhide/apikey
+	 */
+	function recaptcha_mailhide_html($pubkey, $privkey, $email) {
+		$emailparts = self::_recaptcha_mailhide_email_parts ( $email );
+		$url = self::recaptcha_mailhide_url ( $pubkey, $privkey, $email );
+		
+		return htmlentities ( $emailparts [0] ) . "<a href='" . htmlentities ( $url ) . "' 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] );
+	
+	}
+
+}
+/**
+ * A ReCaptchaResponse is returned from recaptcha_check_answer()
+ */
+class ReCaptchaResponse {
+	var $is_valid;
+	var $error;
+}
+
+?>
+
Index: include/apps.inc
===================================================================
--- include/apps.inc	(revision 297709)
+++ include/apps.inc	(working copy)
@@ -13,6 +13,10 @@
 //$mailto = '[email protected]';
 
 
+// recapacha keys
+$recapatcha_publickey = "ENTER_THE_KEY_PROVIDED_BY_www.google.com/recaptcha";
+$recapatcha_privatekey = "ENTER_THE_KEY_PROVIDED_BY_www.google.com/recaptcha";
+
 // 
 // this directory must exist and must be writable by the user the webserver runs as
 //
signature.asc (application/pgp-signature, 836 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)

iQIcBAABAgAGBQJMONlSAAoJEL2ZvilcQTG0uYkP/RiYoOiYzu67GiDqfd5Pjr9b
fvG/5YiEGYNC69hiUvtusbLygevocs0LFKuC2G8N5mqF4vMf5Gpom5062X0UmVW+
/cKngPze+OR+bN75RwKvU1MNEWLfVmMAYVc5+BEma/JdJZCz3rBW77q7neHhR+eR
Ukc6ok+XWoh86rCC/GPGXYbGCVEUSoRDLm7/XcuD0kX3UzRT391Z51tHQoJNE47f
U0IpCTyZxFHY7QcVDXTD3U1LXyBD3e4Reou8BmhrpOLc+vQYB2wmow99iMnUjjlp
g17zYoYsZmLeSCDDAo7xPo+9HqS8YbxXbueDA4gUBaVsxRBgrGdSIkH6hlqFEx1k
rmcD2s+Dk3YQEbkPwsJ6IDrTEIGpM74DzBq8+Hv7vC1s2sBubtsIBDKIhZYKR5Ry
p4p5PQvXI93AMDBK7QDhF0mgWLUz0ejujGTv5kJBKYwnBnIAI/MkTDlujw/HUq51
RmjcJ7poFkkaXq9trFBDz+jPXWY7tH1ENcxEEH2EcgM6SdeoICHHCHDJ493qzFmu
I0Rq8M5w/9N/3wHsdGLM2GEOOSrOXtUwSjfKKySMYlTsxeE92cGR/DpcZEiJCbxF
12a/JUOlURnzW4KMfURLM+A9B0F0nKxex4grKfVCQedAV9N8u+tsTUdPAqyE9Lgm
NAFVENKiOF8Rtw6VBoBZ
=U6+r
-----END PGP SIGNATURE-----