summaryrefslogtreecommitdiff
path: root/framework/Web
diff options
context:
space:
mode:
authorctrlaltca@gmail.com <>2011-12-19 13:20:38 +0000
committerctrlaltca@gmail.com <>2011-12-19 13:20:38 +0000
commite542ea49ceb77ad48f144a9f4ab1eaaafe4dc198 (patch)
treefcb0547f1128b705b828a59d4ac8f7c9222bbe02 /framework/Web
parentc35b6041631a11aa7ba822d03b3ad13794db17f9 (diff)
committed patch from #378
Diffstat (limited to 'framework/Web')
-rw-r--r--framework/Web/Javascripts/source/prado/validator/validation3.js45
-rw-r--r--framework/Web/UI/WebControls/TReCaptcha.php33
-rw-r--r--framework/Web/UI/WebControls/TReCaptchaValidator.php63
3 files changed, 130 insertions, 11 deletions
diff --git a/framework/Web/Javascripts/source/prado/validator/validation3.js b/framework/Web/Javascripts/source/prado/validator/validation3.js
index c0f770cf..bbf3929a 100644
--- a/framework/Web/Javascripts/source/prado/validator/validation3.js
+++ b/framework/Web/Javascripts/source/prado/validator/validation3.js
@@ -790,7 +790,6 @@ Prado.WebUI.TBaseValidator.prototype =
options.OnSuccess = options.OnSuccess || Prototype.emptyFunction;
options.OnError = options.OnError || Prototype.emptyFunction;
*/
-
/**
* Wether the validator is enabled (default true)
* @var {boolean} enabled
@@ -839,6 +838,9 @@ Prado.WebUI.TBaseValidator.prototype =
this.message = $(options.ID);
Prado.Registry.set(options.ID, this);
+
+ if (this.onInit) this.onInit();
+
if(this.control && this.message)
{
this.group = options.ValidationGroup;
@@ -1940,3 +1942,44 @@ Prado.WebUI.TCaptchaValidator = Class.extend(Prado.WebUI.TBaseValidator,
return crc ^ (-1);
}
});
+
+
+/**
+ * TReCaptchaValidator client-side control.
+ *
+ * @class Prado.WebUI.TReCaptchaValidator
+ * @extends Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TReCaptchaValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ onInit : function()
+ {
+ var obj = this;
+ var elements = document.getElementsByName(this.options.ResponseFieldName);
+ if (elements)
+ if (elements.length>=1)
+ {
+ Event.observe(elements[0],'change',function() { obj.responseChanged() });
+ Event.observe(elements[0],'keydown',function() { obj.responseChanged() });
+ }
+ },
+
+ responseChanged: function()
+ {
+ var field = $(this.options.ID+'_1');
+ if (field.value=='1') return;
+ field.value = '1';
+ Prado.Validation.validateControl(this.options.ID);
+ },
+
+ /**
+ * Evaluate validation state
+ * @function {boolean} ?
+ * @return True if the captcha has validate, False otherwise.
+ */
+ evaluateIsValid : function()
+ {
+ return ($(this.options.ID+'_1').value=='1');
+ }
+});
+
diff --git a/framework/Web/UI/WebControls/TReCaptcha.php b/framework/Web/UI/WebControls/TReCaptcha.php
index bb956bcb..50886276 100644
--- a/framework/Web/UI/WebControls/TReCaptcha.php
+++ b/framework/Web/UI/WebControls/TReCaptcha.php
@@ -51,12 +51,17 @@
* @package System.Web.UI.WebControls
* @since 3.2
*/
-class TReCaptcha extends TControl implements IValidatable
+class TReCaptcha extends TWebControl implements IValidatable
{
private $_isValid=true;
const ChallengeFieldName = 'recaptcha_challenge_field';
const ResponseFieldName = 'recaptcha_response_field';
+
+ public function getTagName()
+ {
+ return 'span';
+ }
/**
* Returns true if this control validated successfully.
@@ -135,7 +140,7 @@ class TReCaptcha extends TControl implements IValidatable
return /*$this->ClientID.'_'.*/self::ChallengeFieldName;
}
- protected function getResponseFieldName()
+ public function getResponseFieldName()
{
return /*$this->ClientID.'_'.*/self::ResponseFieldName;
}
@@ -170,18 +175,38 @@ class TReCaptcha extends TControl implements IValidatable
public function onPreRender($param)
{
parent::onPreRender($param);
+
if("" == $this->getPublicKey())
throw new TConfigurationException('recaptcha_publickey_unknown');
if("" == $this->getPrivateKey())
throw new TConfigurationException('recaptcha_privatekey_unknown');
+
+ // need to register captcha fields so they will be sent back also in callbacks
+ $page = $this->getPage();
+ $page->registerRequiresPostData($this->getChallengeFieldName());
+ $page->registerRequiresPostData($this->getResponseFieldName());
}
- public function render($writer)
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ }
+
+ public function regenerateToken()
+ {
+ // if we're in a callback, then schedule re-rendering of the control
+ // if not, don't do anything, because a new challenge will be rendered anyway
+ if ($this->Page->IsCallback)
+ $this->Page->ClientScript->registerEndScript($this->getClientID().'::refresh','Recaptcha.reload();');
+ }
+
+ public function renderContents($writer)
{
$writer->write(TJavaScript::renderScriptBlock(
'var RecaptchaOptions = '.TJavaScript::jsonEncode($this->getClientSideOptions()).';'
));
-
+
$html = recaptcha_get_html($this->getPublicKey());
/*
reCAPTCHA currently does not support multiple validations per page
diff --git a/framework/Web/UI/WebControls/TReCaptchaValidator.php b/framework/Web/UI/WebControls/TReCaptchaValidator.php
index ae94ea59..2898a913 100644
--- a/framework/Web/UI/WebControls/TReCaptchaValidator.php
+++ b/framework/Web/UI/WebControls/TReCaptchaValidator.php
@@ -39,12 +39,29 @@ class TReCaptchaValidator extends TBaseValidator
*/
protected function getClientClassName()
{
- return '';
+ return 'Prado.WebUI.TReCaptchaValidator';
}
public function getEnableClientScript()
{
- return false;
+ return true;
+ }
+
+ protected function getCaptchaControl()
+ {
+ $control = $this->getValidationTarget();
+ if (!$control)
+ throw new Exception('No target control specified for TReCaptchaValidator');
+ if (!($control instanceof TReCaptcha))
+ throw new Exception('TReCaptchaValidator only works with TReCaptcha controls');
+ return $control;
+ }
+
+ public function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $options['ResponseFieldName'] = $this->getCaptchaControl()->getResponseFieldName();
+ return $options;
}
/**
@@ -56,17 +73,51 @@ class TReCaptchaValidator extends TBaseValidator
*/
protected function evaluateIsValid()
{
- // check validity only once (if trying to evaluate multiple times, all redundant checks would fail)
+ // check validity only once (if trying to evaulate multiple times, all redundant checks would fail)
if (is_null($this->_isvalid))
{
- $control = $this->getValidationTarget();
- if(!($control instanceof TCaptcha))
- throw new TConfigurationException('recaptchavalidator_captchacontrol_invalid');
+ $control = $this->getCaptchaControl();
$this->_isvalid = $control->validate();
}
return ($this->_isvalid==true);
}
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+
+ $cs = $this->Page->getClientScript();
+
+ // communicate validation status to the client side
+ $value = $this->_isvalid===false ? '0' : '1';
+ $cs->registerHiddenField($this->getClientID().'_1',$value);
+
+ // check if we need to request a new captcha too
+ if ($this->Page->IsCallback)
+ {
+ // force update of validator display
+ if ($control = $this->getValidationTarget())
+ {
+ $cs->registerEndScript(
+ $this->getClientID().'::validate',
+ '$(\''.TJavaScript::quoteString($this->getClientID().'_1').'\').value = \''.TJavaScript::quoteString($value).'\';'.
+ 'Prado.Validation.validateControl(\''.TJavaScript::quoteString($control->ClientID).'\');'
+ );
+
+ if ($control->getVisible(true))
+ if ($this->_isvalid)
+ {
+ // if the challenge has been solved + we're in a callback and we still reach prerender phase,
+ // that means that some other validator failed and the user will be sent back to the page/form with
+ // the captcha control. in this case we need to force re-rendering of the control, because once
+ // solved, the old challenge won't validate anymore anyway
+
+ $control->regenerateToken();
+ }
+ }
+ }
+ }
+
}
?> \ No newline at end of file