Created
March 30, 2012 15:57
-
-
Save firebus/2252420 to your computer and use it in GitHub Desktop.
NoCaptcha library for PHP forms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Provide a set of fields to filter submissions from bots without requiring | |
* a captcha or otherwise inconveniencing human users | |
* | |
* TODO: Be more flexible about which fields are included - by default include | |
* all but allow caller to specify a subset | |
* | |
* TODO: Why you gotta be so static? | |
*/ | |
class NoCaptchaUtil { | |
/** | |
* Generate a set of form inputs for various nocaptcha techniques | |
* | |
* @author Russell Uman for Splunk | |
* @copyright http://creativecommons.org/licenses/by/3.0/ | |
* | |
* @static | |
* | |
* @param string $formId A unique id for this form, probably named after the calling function | |
* | |
* @return string | |
*/ | |
public static function generateNoCaptchaHTML($formId) { | |
$timestamp = time(); | |
$referer = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; | |
$output = self::generateNoDisplayField(); | |
$output .= self::generateTimestampField($timestamp); | |
$output .= self::generateRefererField($referer); | |
$output .= self::generateNonceField($formId, $timestamp, $referer); | |
return $output; | |
} | |
/** | |
* Validate nocaptcha fields in a $formData array | |
* | |
* @static | |
* | |
* @param string $formId A unique id for this form, probably named after the calling function | |
* @param array $submission An array of form data, keyed by field name | |
* @param int $minTime If form is submitted in less than $minTime seconds, it is invalid | |
* @param int $maxTime If form is submitted in more than $maxTime seconds, it is invalid | |
* | |
* @return boolean | |
*/ | |
public static function validateNoCaptcha($formId, $submission, $minTime = 3, $maxTime = 86400) { | |
$valid = TRUE; | |
$errors = array(); | |
$errors['nodisplay'] = self::validateNoDisplayField($submission, $valid); | |
$errors['timestamp'] = self::validateTimestampField($submission, $minTime, $maxTime, $valid); | |
$errors['referer'] = self::validateRefererField($submission, $valid); | |
$errors['nonce'] = self::validateNonceField($formId, $submission, $valid); | |
if (!$valid) { | |
$logger = Logger::getInstance(); | |
$logger->info('Library::NoCaptchaUtil', $errors); | |
} | |
return $valid; | |
} | |
/** | |
* Generate HTML for a nodisplay text field | |
* | |
* @access private | |
* @static | |
* | |
* @return string HTML for this form field | |
*/ | |
private static function generateNoDisplayField() { | |
return '<input type="text" id="nodisplay" class="nocaptcha" style="display:none" name="nodisplay" tabindex="999">'; | |
} | |
/** | |
* Validate submission for a nodisplay field | |
* | |
* @access private | |
* @static | |
* | |
* @param array $submission An array of form data, keyed by field name | |
* @param boolean $valid Reference to boolean that stores overall validity | |
* | |
* @return string An error message, if any | |
*/ | |
private static function validateNoDisplayField($submission, &$valid) { | |
if (! empty($submission['nodisplay'])) { | |
$valid = FALSE; | |
return "nodisplay field contained $submission[nodisplay]"; | |
} | |
} | |
/** | |
* Generate HTML for a timestamp hidden field | |
* | |
* @access private | |
* @static | |
* | |
* @param string $timestamp Usually the current time | |
* | |
* @return string HTML for this form field | |
*/ | |
private static function generateTimestampField($timestamp) { | |
return '<input type="hidden" id="timestamp" name="timestamp" value="' . $timestamp . '">'; | |
} | |
/** | |
* Validate submission for a timestamp field | |
* | |
* @access private | |
* | |
* @param array $submission An array of form data, keyed by field name | |
* @param int $minTime If form is submitted in less than $minTime seconds, it is invalid | |
* @param int $maxTime If form is submitted in more than $maxTime seconds, it is invalid | |
* @param boolean $valid Reference to boolean that stores overall validity | |
* | |
* @return string An error message, if any | |
*/ | |
private static function validateTimestampField($submission, $minTime, $maxTime, &$valid) { | |
$now = time(); | |
if (($now - $submission['timestamp']) < $minTime | |
|| ($now - $submission['timestamp']) > $maxTime) { | |
$valid = FALSE; | |
return "timestamp start: $submission[timestamp] finish: $now difference: " . ($now - $submission['timestamp']) ; | |
} | |
} | |
/** | |
* Generate HTML for a referer hidden field | |
* | |
* @access private | |
* @static | |
* | |
* @param string $referer Concatenated server and uri for the current page - we'll expect this to match the referer when the form is submitted | |
* | |
* @return string HTML for this form field | |
*/ | |
private static function generateRefererField($referer) { | |
return '<input type="hidden" id="referer" name="referer" value="' . $referer . '">'; | |
} | |
/** | |
* Validate submission for a referer field | |
* | |
* @access private | |
* @static | |
* | |
* @param array $submission An array of form data, keyed by field name | |
* @param boolean $valid Reference to boolean that stores overall validity | |
* | |
* @return string An error message, if any | |
*/ | |
private static function validateRefererField($submission, &$valid) { | |
$referer_test = ''; | |
if (isset($_SERVER['HTTP_REFERER'])) { | |
$referer_test = preg_replace('/^https?:\/\//', '', $_SERVER['HTTP_REFERER']); | |
} | |
if ($submission['referer'] != $referer_test) { | |
$valid = FALSE; | |
return "referer submitted: $submission[referer] actual: $referer_test"; | |
} | |
} | |
/** | |
* Generate HTML for a nonce hidden field | |
* | |
* @access private | |
* @static | |
* | |
* @param string $formId A unique id for the current form - probably named after the calling function | |
* @param string $timestamp Usually the current time | |
* @param string $referer Concatenated server and uri for the current page - we'll expect this to match the referer when the form is submitted | |
* | |
* @return string HTML for this form field | |
*/ | |
private static function generateNonceField($formId, $timestamp, $referer) { | |
$nonce = $formId . $timestamp . $referer; | |
return '<input type="hidden" id="nonce" name="nonce" value="' . md5($nonce) . '">'; | |
} | |
/** | |
* Validate submission for a nonce field | |
* | |
* @access private | |
* @static | |
* | |
* @param string $formId A unique id for the current form - probably named after the calling function | |
* @param array $submission An array of form data, keyed by field name | |
* @param boolean $valid Reference to boolean that stores overall validity | |
* | |
* @return string An error message, if any | |
*/ | |
private static function validateNonceField($formId, $submission, &$valid) { | |
$nonceTest = $formId . $submission['timestamp'] . $submission['referer']; | |
if ($submission['nonce'] != md5($nonceTest)) { | |
$valid = FALSE; | |
return "nonce submitted: $submission[nonce] test: $nonceTest calculated: " . md5($nonceTest); | |
} | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A little library that implements a variety of anti-bot techniques for forms.
Citations