summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY1
-rw-r--r--framework/Web/UI/WebControls/TReCaptcha.php66
-rw-r--r--framework/Web/UI/WebControls/TReCaptchaValidator.php59
3 files changed, 90 insertions, 36 deletions
diff --git a/HISTORY b/HISTORY
index 2c183ebb..8d3b5d17 100644
--- a/HISTORY
+++ b/HISTORY
@@ -15,6 +15,7 @@ BUG: Issue #425 - Error generating WSDL (cezarpirajant)
ENH: Issue #426 - Make TDataFieldAccessor capable to access data in nested arrays (ctrlaltca)
BUG: Issue #427 - Var name mismatch in TActiveFileUpload.php (piotr.knapik)
BUG: Issue #428 - Using a TActiveCustomValidator with a TActiveTextBox and AutoPostBack does not work as expected (ctrlaltca)
+BUG: Issue #431 - TReCaptcha does not work well with active controls (Gabor)
EHN: Permit to change the default cipher in TSecurityManager::setEncryption(); changed the default cipher from 3DES to AES256 (ctrlaltca)
EHN: Use php's hash_hmac() when available in TSecurityManager, and permit the use of all algorithms supported by php (ctrlaltca)
diff --git a/framework/Web/UI/WebControls/TReCaptcha.php b/framework/Web/UI/WebControls/TReCaptcha.php
index b63edad8..c6cf4185 100644
--- a/framework/Web/UI/WebControls/TReCaptcha.php
+++ b/framework/Web/UI/WebControls/TReCaptcha.php
@@ -135,6 +135,16 @@ class TReCaptcha extends TWebControl implements IValidatable
return $this->setViewState('Language', TPropertyValue::ensureString($value));
}
+ public function getCallbackScript()
+ {
+ return $this->getViewState('CallbackScript');
+ }
+
+ public function setCallbackScript($value)
+ {
+ return $this->setViewState('CallbackScript', TPropertyValue::ensureString($value));
+ }
+
protected function getChallengeFieldName()
{
return /*$this->ClientID.'_'.*/self::ChallengeFieldName;
@@ -212,21 +222,47 @@ class TReCaptcha extends TWebControl implements IValidatable
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
- $html = str_replace(
- array(self::ChallengeFieldName,self::ResponseFieldName),
- array($this->getChallengeFieldName(),$this->getResponseFieldName()),
- $html
- );
- */
- $writer->write($html);
+ $readyscript = 'Event.fire(document, '.TJavaScript::quoteString('captchaready:'.$this->getClientID()).')';
+ $cs = $this->Page->ClientScript;
+ $id = $this->getClientID();
+ $divid = $id.'_1_recaptchadiv';
+ $writer->write('<div id="'.htmlspecialchars($divid).'">');
+
+ if (!$this->Page->IsCallback)
+ {
+ $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
+ $html = str_replace(
+ array(self::ChallengeFieldName,self::ResponseFieldName),
+ array($this->getChallengeFieldName(),$this->getResponseFieldName()),
+ $html
+ );
+ */
+ $writer->write($html);
+
+ $cs->registerEndScript('ReCaptcha::EventScript', 'Event.observe(document, "dom:loaded", function() { '.$readyscript.'; } );');
+ }
+ else
+ {
+ $options = $this->getClientSideOptions();
+ $options['callback'] = new TJavaScriptLiteral('function() { '.$readyscript.'; '.$this->getCallbackScript().'; }');
+ $cs->registerScriptFile('ReCaptcha::AjaxScript', 'http://www.google.com/recaptcha/api/js/recaptcha_ajax.js');
+ $cs->registerEndScript('ReCaptcha::CreateScript::'.$id, implode(' ', array(
+ 'if (!$('.TJavaScript::quoteString($this->getResponseFieldName()).'))',
+ 'Recaptcha.create(',
+ TJavaScript::quoteString($this->getPublicKey()).', ',
+ TJavaScript::quoteString($divid).', ',
+ TJavaScript::encode($options),
+ ');',
+ )));
+ }
+
+ $writer->write('</div>');
}
}
-
diff --git a/framework/Web/UI/WebControls/TReCaptchaValidator.php b/framework/Web/UI/WebControls/TReCaptchaValidator.php
index cc1a4080..bba356b8 100644
--- a/framework/Web/UI/WebControls/TReCaptchaValidator.php
+++ b/framework/Web/UI/WebControls/TReCaptchaValidator.php
@@ -87,36 +87,53 @@ class TReCaptchaValidator extends TBaseValidator
parent::onPreRender($param);
$cs = $this->Page->getClientScript();
+ $cs->registerPradoScript('validator');
// 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)
+
+ // update validator display
+ if ($control = $this->getValidationTarget())
{
- // 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).');'
- );
+ $fn = 'captchaUpdateValidatorStatus_'.$this->getClientID();
- if ($control->getVisible(true))
- if ($this->_isvalid)
+ // check if we need to request a new captcha too
+ if ($this->Page->IsCallback)
{
- // 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();
+ if ($control->getVisible(true))
+ if (!is_null($this->_isvalid))
+ {
+ // if the response has been tested and we reach the pre-render phase
+ // then we need to regenerate the token, because it won't test positive
+ // anymore, even if solves correctly
+
+ $control->regenerateToken();
+ }
}
- }
+
+ $cs->registerEndScript($this->getClientID().'::validate', implode(' ',array(
+ // this function will be used to update the validator
+ 'function '.$fn.'(valid)',
+ '{',
+ ' var v = $('.TJavaScript::quoteString($this->getClientID()).');',
+ ' $('.TJavaScript::quoteString($this->getClientID().'_1').').value = valid;',
+ ' Prado.Validation.validateControl('.TJavaScript::quoteString($control->ClientID).'); ',
+ '}',
+ '',
+ // update the validator to the result if we're in a callback
+ // (if we're in initial rendering or a postback then the result will be rendered directly to the page html anyway)
+ $this->Page->IsCallback ? $fn.'('.$value.');' : '',
+ '',
+ // wait for the captcha to be constructed
+ 'Event.observe(document,"captchaready:'.$control->getClientID().'",function() { ',
+ // install event handler that clears the validation error when user changes the captcha response field
+ 'Event.observe('.TJavaScript::quoteString($control->getResponseFieldName()).',"keyup",function() { ',
+ $fn.'("1");',
+ '});',
+ '});',
+ )));
}
}
}
-