Acme-CPANModulesBundle-Import-PerlDancerAdvent-2018
view release on metacpan or search on metacpan
devdata/http_advent.perldancer.org_2018_21 view on Meta::CPAN
if $spam_1 || $spam_2;
# Ok, we seem to be a real human, so do something...
my $contact;
my $name = body_parameters->get( 'name' );
my $email = body_parameters->get( 'email' );
my $subject = body_parameters->get( 'subject' );
my $message = body_parameters->get( 'message' );
# Now, your code to do something with the form info:
# - Put it in a database
# - email it
# - etc. etc.
};</pre>
<p>We look to see if either of the spam-catching form fields is populated. If either one of them is populated,
we educate the bot in <a href="https://en.wikipedia.org/wiki/Three_Laws_of_Robotics">Asimov's Three Laws of Robotics</a>.
If not, we are reasonably certain we are dealing with a human, and we continue on our merry way.</p>
<h2><a name="front_end_magic"></a>Front-end magic</h2>
<p>The front end is where things get a little more interesting (note: I have deliberately omitted any styling for
the sake of brevity):</p>
<pre class="prettyprint"><form method="post" action="/contact" id="contact">
<label for="name">Name</label>
<input type="text" name="name" id="name" placeholder="First and last name">
<label for="email">Email Address</label>
<input type="text" name="email" id="email" placeholder="someone@example.com">
<label for="subject">Subject</label>
<input type="text" name="subject" id="subject" placeholder="Nature of inquiry?">
<label for="message">Message</label>
<textarea name="message" id="message" placeholder="Message text"></textarea>
<label class="visuallyhidden">Don't fill this in!<input type="text" name="spam_one" tabindex="-1"></label>
<input type="hidden" name="spam_two">
<input type="submit">Send Request</input>
</form></pre>
<p>For the most part, it's a standard HTML form with a couple of notable exceptions:</p>
<pre class="prettyprint"><label class="visuallyhidden">Don't fill this in!<input type="text" name="spam_one" tabindex="-1"></label></pre>
<p>This uses a special CSS class, <code>visuallyhidden</code>, to make this form field invisible to the user. By giving it
a <code>tabindex="-1"</code>, we make sure the user cannot accidentally tab to the field. There are still a few ways that
field could accidentally get focus however, so we help the user here by giving it a label that says "Don't fill
this in!"</p>
<p>What does <code>visuallyhidden</code> look like?</p>
<pre class="prettyprint">.visuallyhidden {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}</pre>
<p>The second preventative measure simply puts a hidden field on the page:</p>
<pre class="prettyprint"><input type="hidden" name="spam_two"></pre>
<p>Screen readers know to ignore this because it's hidden, and because it's hidden, the page won't show this field.
As a user, you won't ever have to fill it in.</p>
<p>Thankfully, a lot of spam bots are stupid, and blindly fill in any form field they see. They can't parse the CSS
in such a way that they can tell one of the fields is unusably hidden, and they often don't pay attention to
the hidden attribute... so they fall right into our trap. Enjoy your free education, spambot!</p>
<h2><a name="final_thoughts"></a>Final thoughts</h2>
<p>Is it foolproof? No, not by a longshot. Anyone who really wants to is going to find a way to spam you anyhow,
given a sufficient amount of time and motivation. But this will slow many down, and prevent a bunch, and
you won't drive sighted users away from your site. In the three and a half years I have used this, only two
spambots have made it through, and my server logs indicate that many others have tried.</p>
<h2><a name="author"></a>Author</h2>
<p>This article has been written by Jason Crome (CromeDome) for the Perl Dancer
Advent Calendar 2018.</p>
<h2><a name="copyright"></a>Copyright</h2>
<p>No copyright retained. Enjoy.</p>
<p>Jason A. Crome</p>
</div>
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'danceradvent'; // required: replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>
<div id="footer">
Powered by the
<a href="http://perldancer.org/" title="Perl Dancer - Perl web framework">
Dancer Perl web framework</a>
</div>
</div>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-25174467-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
( run in 0.639 second using v1.01-cache-2.11-cpan-39bf76dae61 )