LesleyB has asked for the wisdom of the Perl Monks concerning the following question:
Hi
I've three methods for using Captcha::reCAPTCHA (v 0.92) presented below - one with CGI only and two with CGI::FormBuilder and TT2.
Method 0 works well and not only displays the HTML markup it also provides for recaptcha.net's error messaging capability.
In both the CGI::FB/TT2 methods I attempt to use the invalid field to show an error message but that doesn't work in either method.
In Method 1, the HTML markup has been manually inserted into the template and the error management in the script works but I cannot achieve any indication of the error message in the output. The HTML markup is static and I will never present an error parameter to the recaptcha server.
In Method 2, I attempt to use the Captcha::reCAPTCHA get_html method and assign this to a field value - which I then attempt to print out in the form but all I get is ARRAY(0x865c8dc). I've attempted to step through this array in the template but no joy. The HTML markup is only printed when I use Data::Dumper on the variable containing the return value of the Captcha::reCAPTCHA get_html method.
I would like Method 2 to work. The get_html method Returns a string containing the HTML that should be used to display the captcha.. It uses HTML::Tiny to construct the string and I have v1.03 installed.
Using either Data::Dumper($crc_html); or print $crc_html; in Method 2 outputs the HTML markup and so creates the captcha. I am left wondering why the assignment to the $crc_field{'values'} key returns an apparently empty array in the template and how to get the results of the get_html method into a template. Any suggestions gratefully received.
Code is attached below. Any code review also welcome!
Regards LesleyMethod 0
Uses CGI and the Captcha::reCAPTCHA get_html method. (The example supplied with Captcha::reCAPTCHA modified for use with the CGI module.)
#!/usr/bin/perl # Simple CGI Captcha use strict; use warnings; use Captcha::reCAPTCHA; use CGI; use lib "/path/to/keys"; use Keys qw(PRIVATE_KEY PUBLIC_KEY); $| = 1; my $q = CGI->new; my $c = Captcha::reCAPTCHA->new; my $error = undef; print "Content-type: text/html\n\n"; print <<EOT; <html> <body> <form action="" method="post"> EOT # Check response if ( $q->param( 'recaptcha_response_field' ) ) { my $result = $c->check_answer( PRIVATE_KEY, $ENV{'REMOTE_ADDR'}, $q->param( 'recaptcha_challenge_field' ), $q->param( 'recaptcha_response_field' ) ); if ( $result->{is_valid} ) { print "Yes!"; } else { $error = $result->{error}; } } # Generate the form print $c->get_html( PUBLIC_KEY, $error ); print <<EOT; <br/> <input type="submit" value="submit" /> </form> </body> </html> EOT
Method 1
Uses TT2 and CGI::FormBuilder with the Captcha::reCPATCHA markup manually inserted into the template. Recognises a failed captcha but doesn't exploit the error messages available via Method 0.
Template 1
[%- INCLUDE headConst.1.0 -%] [%- PROCESS head -%] <div id="pagebody"> [%- form.start %] <div class="formelement"> <div class="cf_label">[% form.field.email.label %]</div> [% +form.field.email.field %] [%- IF form.field.email.invalid -%] <span class="cf_err">*Please correct this entry.</span> [%- END %] </div><!-- formelement (email) --> <div class="formelement"> <script type="text/javascript" src="http://api.recaptcha.net +/challenge?k=6LeiTAMAAAAAAGCJ606o9RHGHnuj2nBFes-OF0Az"> </script> <div class="cf_label"> <noscript> <iframe src="http://api.recaptcha.net/noscript?k=6LeiTAMAA +AAAAGCJ606o9RHGHnuj2nBFes-OF0Az" 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> </div> [%- IF form.field.crc_field.invalid -%] <span class="cf_err">*Please retry.</span> [%- END %] </div> <div class="formelement"> <div class="cf_label">[% form.field.send.label %] </div> [% +form.field.send.field %] </div><!-- formelement (submit) --> [% form.end %] </div><!-- pagebody --> [% PROCESS foot %]
Script 1
#!/usr/bin/perl -T use strict; use warnings; use CGI; use CGI::Carp qw(fatalsToBrowser); use CGI::FormBuilder; use CGI::FormBuilder::Template::TT2; use Email::Valid qw(address); use Captcha::reCAPTCHA; use Data::Dumper; use lib "/path/to/keys"; use Keys qw(PRIVATE_KEY PUBLIC_KEY); $CGI::POST_MAX = 1048576; # max 1MB allowed $CGI::DISABLE_UPLOADS = 1; # disable file uploads delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # Make %ENV safer $ENV{PATH} = '/usr/bin:/usr/local/bin:usr/lib'; ## set the global data my $crc = Captcha::reCAPTCHA->new; my $crc_error = undef; my $formdata ; my %valid = ( ## initially all valid 'email' => 0, 'crc' => 0, ); my $addr; my %email = ( ## the email field name => 'email', id => 'email', label => 'Your email address : ', values => $formdata->{email}, tabindex => 2, size => 50, maxlength =>100, invalid => $valid{'email'}, ); my %crc_field = ( type => 'hidden', name => 'crc', id => 'crc', invalid => $valid{'crc'}, values => sprintf("%s",$crc->get_html(PUBLIC_KEY, $crc_error)), ); my %send = ( ## the submit button name => 'send', id => 'send', type => 'submit', value => 'Send', label => 'Hit this button :', tabindex => 5, ); my @formfields = ('email', 'crc_field', 'send', ); ## the elements in +the form my $form = CGI::FormBuilder->new( template => { ## the templ +ate being used type=> 'TT2', template => 'method1.tt', variable => 'form', engine => { INCLUDE_PATH => './templates', RELATIVE => '1', } }, id => 'form', fields => \@formfields , ## declares +where the formfields can be found method => 'post', ## the HTML +form method action => $ENV{SCRIPT_NAME}, ## ensure th +e action is set properly sticky => 1, #debug => 2, ## sets the + debug level int[0,3] ? ); sub setfields { $form->field( %email ); $form->field( %crc_field ); $form->field( %send ); } sub chk_email { # uses Email::Valid to check $addr is a valid email address my $addr = shift; my $emv = Email::Valid->new(); $emv->tldcheck(1); $emv->mxcheck(1); $addr = $emv->address(-address => $addr) if $addr; return $addr; } sub chk_form { # check the form data server side # returns true if it is ok my $ok = 0; ## not ok yet $formdata = $form->field; ## retrieve the form data my $addr = &chk_email($formdata->{'email'}) ; ## check the +email address if (defined $addr) { $valid{'email'} = 1; $ok = 1; } else { $valid{'email'} = 0; } } ## program starts # &setfields(); # set the form fields if ($form->submitted ) { my $ok = &chk_form(); ## check the form contents # Now check reCAPTCHA response my $crc_result; my $crc_response; my $crc_challenge; ## captcha data extracted from the form via cgi parameters $crc_response = $form->cgi_param( 'recaptcha_response_field' ) ; $crc_challenge = $form->cgi_param( 'recaptcha_challenge_field' ) ; $crc_result = $crc->check_answer( PRIVATE_KEY, $ENV{'REMOTE_ADDR'}, $crc_challenge, $crc_response, ); ## so now i have the result which may or may not contain the error ## $crc_result->{'is-valid'} will be either 0 or 1. if ( ( $crc_result->{is_valid} ) && $ok ) { ## passed all the valid +ation ##&cf_print(); print "Content-type: text/html\n\nall ok\n<br />"; } else { ## failed validation - there's an error if ($valid{'email'} == 0 ) { $email{'invalid'} = 1; } else { $email{'invalid'} = 0; } if ( (!( $crc_result->{is_valid} )) ) { $crc_field{'values'} = $crc_result->{error}; $crc_field{'invalid'} = 1; } &setfields(); # set the form fields print $form->render(header => 1); ## re render the form and deal w +ith the validity of the fields in the template print "looked baad\n"; print "xxx".$crc_response."xxx\n<br />"; print "xxx".$crc_challenge."xxx\n<br />"; print Dumper($crc_result); print "ok : ".$ok."<br />\n"; } } else { print $form->render(header => 1); }
Method 2
Uses TT2 and CGI::FormBuilder with the Captcha::reCPATCHA get_html method used to retrieve the HTML markup. Attempts to display the retrieved HTML fail but the HTML markup is printed out when Data::Dumper is used or the $crc_html variable is printed out directly.
Template 2
[%- INCLUDE headConst.1.0 -%] [%- PROCESS head -%] <div id="pagebody"> [%- form.start %] <div class="formelement"> <div class="cf_label">[% form.field.email.label %]</div> [% +form.field.email.field %] [%- IF form.field.email.invalid -%] <span class="cf_err">*Please correct this entry.</span> [%- END %] </div><!-- formelement (email) --> <div class="formelement"> [%- IF form.field.crc_field.values -%] [% form.field.crc_field.values -%] [%- END -%] [%- FOREACH val IN form.field.crc_field.values -%] value = [% val %] [%- END -%] [%- IF form.field.crc_field.invalid -%] <span class="cf_err">*Please retry.</span> [%- END %] </div><!-- formelement (captcha) --> <div class="formelement"> <div class="cf_label">[% form.field.send.label %] </div> [% +form.field.send.field %] </div><!-- formelement (submit) --> [% form.end %] </div><!-- pagebody --> [% PROCESS foot %]
Script 2
#!/usr/bin/perl -T use strict; use warnings; use CGI; use CGI::Carp qw(fatalsToBrowser); use CGI::FormBuilder; use CGI::FormBuilder::Template::TT2; use Email::Valid qw(address); use Captcha::reCAPTCHA; use lib "/path/to/keys"; use Keys qw(PRIVATE_KEY PUBLIC_KEY); use Data::Dumper; $CGI::POST_MAX = 1048576; # max 1MB allowed $CGI::DISABLE_UPLOADS = 1; # disable file uploads delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # Make %ENV safer $ENV{PATH} = '/usr/bin:/usr/local/bin:usr/lib'; ## set the global data my $crc = Captcha::reCAPTCHA->new; my $crc_error = undef; my $crc_html = $crc->get_html(PUBLIC_KEY, $crc_error); my $formdata ; my %valid = ( ## initially all valid 'email' => 0, 'crc' => 0, ); my $addr; my %email = ( ## the email field name => 'email', id => 'email', label => 'Your email address : ', values => $formdata->{email}, tabindex => 2, size => 50, maxlength =>100, invalid => $valid{'email'}, ); my %crc_field = ( type => 'hidden', name => 'crc', id => 'crc', invalid => $valid{'crc'}, values => $crc_html, ); my %send = ( ## the submit button name => 'send', id => 'send', type => 'submit', value => 'Send', label => 'Hit this button :', tabindex => 5, ); my @formfields = ('email', 'crc_field', 'send', ); ## the elements in +the form my $form = CGI::FormBuilder->new( template => { ## the templ +ate being used type=> 'TT2', template => 'method2.tt', variable => 'form', engine => { INCLUDE_PATH => './templates', RELATIVE => '1', } }, id => 'form', fields => \@formfields , ## declares +where the formfields can be found method => 'post', ## the HTML +form method action => $ENV{SCRIPT_NAME}, ## ensure th +e action is set properly sticky => 1, #debug => 2, ## sets the + debug level int[0,3] ? ); sub setfields { $form->field( %email ); $form->field( %crc_field ); $form->field( %send ); } sub chk_email { # uses Email::Valid to check $addr is a valid email address my $addr = shift; my $emv = Email::Valid->new(); $emv->tldcheck(1); $emv->mxcheck(1); $addr = $emv->address(-address => $addr) if $addr; return $addr; } sub chk_form { # check the form data server side # returns true if it is ok my $ok = 0; ## not ok yet $formdata = $form->field; ## retrieve the form data my $addr = &chk_email($formdata->{'email'}) ; ## check the +email address if (defined $addr) { $valid{'email'} = 1; $ok = 1; } else { $valid{'email'} = 0; } } ## program starts # &setfields(); # set the form fields if ($form->submitted ) { my $ok = &chk_form(); ## check the form contents # Now check reCAPTCHA response my $crc_result; my $crc_response; my $crc_challenge; ## captcha data extracted from the form via cgi parameters $crc_response = $form->cgi_param( 'recaptcha_response_field' ) ; $crc_challenge = $form->cgi_param( 'recaptcha_challenge_field' ) ; $crc_result = $crc->check_answer( PRIVATE_KEY, $ENV{'REMOTE_ADDR'}, $crc_challenge, $crc_response, ); ); ## so now i have the result which may or may not contain the error ## $crc_result->{'is-valid'} will be either 0 or 1. if ( ( $crc_result->{is_valid} ) && $ok ) { ## passed all the valid +ation ##&cf_print(); print "Content-type: text/html\n\nall ok\n<br />"; } else { ## failed validation - there's an error $crc_html = $crc->get_html(PUBLIC_KEY, $crc_error); if ($valid{'email'} == 0 ) { $email{'invalid'} = 1; } else { $email{'invalid'} = 0; } if ( (!( $crc_result->{is_valid} )) ) { $crc_field{'values'} = $crc_result->{error}; $crc_field{'invalid'} = 1; } else { $crc_field{'invalid'} = 0; } &setfields(); # set the form fields print $form->render(header => 1); ## re render the form and deal w +ith the validity of the fields in the template print "looked baad\n"; print "xxx".$crc_response."xxx\n<br />"; print "xxx".$crc_challenge."xxx\n<br />"; print Dumper($crc_result); print Dumper($crc_html); print "ok : ".$ok."<br />\n"; } } else { print $form->render(header => 1); print Dumper($crc_html); }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Captcha::reCAPTCHA with CGI::FormBuilder and TT2
by LesleyB (Friar) on Nov 19, 2008 at 11:10 UTC |