This post no longer reflects the state of the art. See here .
CAPTCHAs – “Completely Automated Public Turing test to tell Computers and Humans Apart”s – are known as the foremost means to stop registrations by SPAM programs, so-called “Bots”. In phpBB, a visual confirmation CAPTCHA is used.
The key here is the “Completely Automated” part, meaning that the software – phpBB – creates the question and the correct answer without interaction by a user. This has the drawback that computers are usually able to find the answer as well, given time to adjust. This is an active field in research. In the end it is an arms race. A new CAPTCHA will usually buy a few months of peace, before the major Bot vendors adjust their products.
This article is about presenting some reasons behind our CAPTCHAs; it is not intended to be a case for or against CAPTCHAs in general or particular. It is not about other means to combat SPAM, but only about CAPTCHAs.
The CAPTCHAs of phpBB
CAPTCHAs first became part of the phpBB package with version 2.0.10, when the need for some means to stop registration of Bot users became obvious. (Actually it was bundled from 2.0.5 onwards, but not installed) For that purpose, the well known CAPTCHA from the 2.1 branch (which later became 3.0) was backported to 2.0. We all know that the CAPTCHA was very simple to beat, but it did the job at the time.
For a while.
However, as the development of what was later to become 3.0 proceeded, it became clear that it would not do to for a future version and so Robert “Xore” Hetzler took the task of developing an unique new set of CAPTCHAs for the development version.
The concept was having a powerful plugin system to allow a vast array of different CAPTCHAs, with a large number of configuration options. However, as development picked up again for the beta versions, it was decided that the system was too ambitious for the 3.0 line and should be pushed back.
In its stead, a Free Type based 3rd party CAPTCHA was bundled with the Beta versions. However, NeoThermic soon found out that it was broken by default.
As a result, the CAPTCHA code by Xore was resurrected and surveyed for CAPTCHA implementations that were compatible with subsilver2 and prosilver, while being unique enough to keep Bots away. Two such algorithms were developed to work with the downsized CAPTCHA code, one of which was finally selected to become the default CAPTCHA of Olympus.
We selected it, because it was very unlike existing implementations; naturally we are and always were aware of ways to break it – but that’s a different story. To this day, the bundled implementation works reasonably well. We are always working on possible replacements, should that change.
Default CAPTCHAs
The major issue with a CAPTCHA bundles with a software like phpBB is that it has to satisfy a very restrictive set of requirements.
At the very least it has to
- work properly out of the box
- work regardless of language settings
- be solvable for almost all humans
- and few Bots
The first is very important. Any approach that requires users to register to a service like recaptcha or to set up questions and answers is not acceptable. Users can switch to such a solution later on, but for the initial setup that would be very bad indeed.
2. is often overlooked, but very important nonetheless: the CAPTCHA has to work regardless of language and cultural background.
3. is rather obvious, but can be surprisingly difficult. Not everyone is able to see 3d effects in 2d images; some people are unable to identify emotions, some can’t tell red and green apart and so on. Finally, there is 4.; meaning that almost any existing solution won’t work.
Custom CAPTCHAs
A CAPTCHA just created for your site is a different story altogether. Here you can use tricks specific to your audience, like questions or images specific to the topic of you page. In fact, even very simple approaches will work as long as they are unique. Most custom CAPTCHAs would be broken in a matter of hours, should they be included in a package like phpBB. But on your unique page, a custom CAPTCHA can be an excellent defense.
CAPTCHA Services
At the moment, CAPTCHA services like reCaptcha or MSR’s Asirra are very fashionable. Conceptually the problem is that such solutions don’t work out of the box; they require the administrator to register for the service. Moreover, they usually rely on javascript. There also is the lingering problem that breaking such services would open up all pages using them. This incentive makes it likely that spammers will invest the money required to break services, leading once more to the same situation we are in already. If you are looking into readily available solutions to stop bots from registering, then services like the above are very good ideas indeed.
Q&A, Kitten Auth et al
The most frequently asked questions regarding CAPTCHAs are “Why don’t you use a Q&A approach?” and “What about kitten auth?”. In fact those are excellent questions. “Question & Answer” subsumes approaches where a somewhat not-trivial question is asked upon registration, with the user having to provide an answer within certain parameters. The problems with this approach are manifold. For starters, google will answer many questions, so that many good questions are not effective. Then, the program has to be able to verify that the entered solution was correct. What about typos? What about writing “two” instead of “2″? What about internationalisation? What to do once a bot has a correct answer? When doing multiple choice – how to prevent brute forcing? The list goes on. The main issue certainly is: the approach is not a CAPTCHA at all, but merely a challenge where the questions and answers are very finite. Any given set of questions and answers bundled with the software or downloadable will be known by bots instantly.
An attempt to sidestep the language issue is kitten auth. Kitten auth presents the user with a set of images, some of which satisfy a question (show kittens). This has the drawback that – like with Q&A – the number of questions is very finite. Any freely available set of images bundled can be hashed by bots, meaning that only unique picture sets will provide any barrier at all. Simple distortions are not even remotely enough to throw image identification algorithms off.
So the answer to all questions about kitten-auth and Q&A has to be: go for it if it works for you; it wouldn’t if we were to use it.
Audio CAPTCHAs
Sometimes the question arises why there are so few audio based CAPTCHAs. Generally the answer is threefold:
- Internationalisation is almost impossible; letters are pronounced differently.
- Many users do not have sound enabled
- The noise needed to fool audio recognition programs also makes it impossible for humans to solve the CAPTCHA
.
Animated CAPTCHAs
Sometimes there are attempts to use flash or java to display CAPTCHAs. This approach has an underlying problem: the java or flash program that displays the CAPTCHA runs on the client computer and thus needs to know the code it is supposed to display. Bots can just extract that seed and don’t bother with the flash/java shell around it. Also it requires the client to have the particular platform installed, which is not a good assumption either.
Limitations
The lessons about CAPTCHAs certainly include:
- Any CAPTCHA bundled with a major application is doomed
- There are always spammers using humans to pass the CAPTCHA
- There are always humans incorrectly rejected by the CAPTCHA
A simple Q&A CAPTCHA for phpBB3
The current 3.0 CAPTCHA implementation is lacking plug ability, something that had to be done to get it working in finite time. However, even so it is possible to use CAPTCHA classes other than the ones bundled without having to adjust code outside the CAPTCHA class.
The following code shall provide an example for a simple Q&A CAPTCHA that can be installed simply by replacing the existing captcha_gd file. Then the user would have to provide a question by altering the language entries and a set of images satisfying the question and another set not doing so. The images have to be in the “correct” respectively “incorrect” directories.
The code is very simple and not fleshed out to the degree one would expect from a MOD or so; it is merely given as an example.
- Code: Select all
- Code: Select all
<span class="syntaxdefault"><?php<br /></span><span class="syntaxcomment">/**<br />*<br />* @package VC<br />* @version $Id: $<br />* @copyright (c) 2008 phpBB Group<br />* @license http://opensource.org/licenses/gpl-license.php GNU Public License<br />*<br />*/
/**<br />* @ignore<br />*/<br /></span><span class="syntaxkeyword">if (!</span><span class="syntaxdefault">defined</span><span class="syntaxkeyword">(</span><span class="syntaxstring">'IN_PHPBB'</span><span class="syntaxkeyword">))<br />{<br /> exit;<br />}
class </span><span class="syntaxdefault">captcha<br /></span><span class="syntaxkeyword">{<br /> var </span><span class="syntaxdefault">$width </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">360</span><span class="syntaxkeyword">;<br /> var </span><span class="syntaxdefault">$height </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">96</span><span class="syntaxkeyword">;
</span><span class="syntaxcomment">/**<br /> * Create the image containing $code with a seed of $seed<br /> */<br /> </span><span class="syntaxkeyword">function </span><span class="syntaxdefault">execute</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$code</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$seed</span><span class="syntaxkeyword">)<br /> {<br /> global </span><span class="syntaxdefault">$phpbb_root_path</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$config</span><span class="syntaxkeyword">;<br /> </span><span class="syntaxdefault">srand</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$seed</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">mt_srand</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$seed</span><span class="syntaxkeyword">);
</span><span class="syntaxcomment">// Create image<br /> </span><span class="syntaxdefault">$capt </span><span class="syntaxkeyword">= new </span><span class="syntaxdefault">yes_no_captcha</span><span class="syntaxkeyword">();<br /> </span><span class="syntaxdefault">init</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$code</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">width</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">height</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$phpbb_root_path </span><span class="syntaxkeyword">. </span><span class="syntaxstring">'images/captcha/smilies'</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">$img </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">$capt</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">paint</span><span class="syntaxkeyword">();
</span><span class="syntaxcomment">// Send image<br /> </span><span class="syntaxdefault">header</span><span class="syntaxkeyword">(</span><span class="syntaxstring">'Content-Type: image/png'</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">header</span><span class="syntaxkeyword">(</span><span class="syntaxstring">'Cache-control: no-cache, no-store'</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">imagepng</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$img</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">imagedestroy</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$img</span><span class="syntaxkeyword">);<br /> }
}
</span><span class="syntaxcomment">/**<br />* @package VC<br />*/<br /></span><span class="syntaxkeyword">class </span><span class="syntaxdefault">yes_no_captcha<br /></span><span class="syntaxkeyword">{<br /> var </span><span class="syntaxdefault">$letter_img </span><span class="syntaxkeyword">= array();<br /> var </span><span class="syntaxdefault">$path</span><span class="syntaxkeyword">;<br /> var </span><span class="syntaxdefault">$img</span><span class="syntaxkeyword">;<br /> var </span><span class="syntaxdefault">$width </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">;<br /> var </span><span class="syntaxdefault">$height </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">;<br /> var </span><span class="syntaxdefault">$x_per_letter</span><span class="syntaxkeyword">;
</span><span class="syntaxcomment">/**<br /> * Init method<br /> * @param string $code The correct answer<br /> * @param int $width The number of pixels in the x direction<br /> * @param int $height The number of pixels in the y direction<br /> * @param string $path The path to load the images one. Needs to contain directories "correct" and "incorrect" with right respectively wrong pictures<br /> */<br /> </span><span class="syntaxkeyword">function </span><span class="syntaxdefault">init</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$code</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$width</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$height</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$path</span><span class="syntaxkeyword">)<br /> {<br /> global </span><span class="syntaxdefault">$phpbb_root_path</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$phpEx</span><span class="syntaxkeyword">;
</span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">width </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">$width</span><span class="syntaxkeyword">;<br /> </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">height </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">$height</span><span class="syntaxkeyword">;<br /> </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">path </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">$path</span><span class="syntaxkeyword">;
</span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">img </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">imagecreatetruecolor</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">width</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">height</span><span class="syntaxkeyword">);<br /> if (!</span><span class="syntaxdefault">function_exists</span><span class="syntaxkeyword">(</span><span class="syntaxstring">'filelist'</span><span class="syntaxkeyword">))<br /> {<br /> include(</span><span class="syntaxdefault">$phpbb_root_path </span><span class="syntaxkeyword">. </span><span class="syntaxstring">'includes/functions_admin.' </span><span class="syntaxkeyword">. </span><span class="syntaxdefault">$phpEx</span><span class="syntaxkeyword">);<br /> }<br /> </span><span class="syntaxdefault">$images </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">filelist</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$phpbb_root_path </span><span class="syntaxkeyword">. </span><span class="syntaxdefault">$path</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">$code_len </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">strlen</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$code</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">$anticode_len </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">mt_rand</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$code_len </span><span class="syntaxkeyword">- </span><span class="syntaxdefault">1</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$code_len </span><span class="syntaxkeyword">+ </span><span class="syntaxdefault">1</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">$rand_str </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">md5</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">mt_rand</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">2000000000</span><span class="syntaxkeyword">));<br /> </span><span class="syntaxdefault">$rand_str </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">str_replace</span><span class="syntaxkeyword">(</span><span class="syntaxstring">'0'</span><span class="syntaxkeyword">, </span><span class="syntaxstring">'Z'</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">strtoupper</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">base_convert</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$rand_str</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">16</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">35</span><span class="syntaxkeyword">)));<br /> </span><span class="syntaxdefault">$anticode </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">substr</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$rand_str</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$anticode_len</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">$codes </span><span class="syntaxkeyword">= array(<br /> </span><span class="syntaxstring">'correct' </span><span class="syntaxkeyword">=> </span><span class="syntaxdefault">$code</span><span class="syntaxkeyword">,<br /> </span><span class="syntaxstring">'incorrect' </span><span class="syntaxkeyword">=> </span><span class="syntaxdefault">$anticode</span><span class="syntaxkeyword">,<br /> );
</span><span class="syntaxdefault">$letters_correct </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">;<br /> </span><span class="syntaxdefault">$letters_incorrect </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">;<br /> while(</span><span class="syntaxdefault">$letters_correct </span><span class="syntaxkeyword">< </span><span class="syntaxdefault">strlen</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$codes</span><span class="syntaxkeyword">[</span><span class="syntaxstring">'correct'</span><span class="syntaxkeyword">]) || </span><span class="syntaxdefault">$letters_incorrect </span><span class="syntaxkeyword">< </span><span class="syntaxdefault">strlen</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$codes</span><span class="syntaxkeyword">[</span><span class="syntaxstring">'incorrect'</span><span class="syntaxkeyword">]))<br /> {<br /> </span><span class="syntaxdefault">$which </span><span class="syntaxkeyword">= (</span><span class="syntaxdefault">$letters_correct </span><span class="syntaxkeyword">< </span><span class="syntaxdefault">strlen</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$codes</span><span class="syntaxkeyword">[</span><span class="syntaxstring">'correct'</span><span class="syntaxkeyword">]) && </span><span class="syntaxdefault">$letters_incorrect </span><span class="syntaxkeyword">< </span><span class="syntaxdefault">strlen</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$codes</span><span class="syntaxkeyword">[</span><span class="syntaxstring">'incorrect'</span><span class="syntaxkeyword">]) ? </span><span class="syntaxdefault">mt_rand</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">) : (</span><span class="syntaxdefault">$letters_correct letter_img</span><span class="syntaxkeyword">[] = array(<br /> </span><span class="syntaxstring">'letter' </span><span class="syntaxkeyword">=> </span><span class="syntaxdefault">$codes</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">$name</span><span class="syntaxkeyword">][</span><span class="syntaxdefault">$i</span><span class="syntaxkeyword">],<br /> </span><span class="syntaxstring">'image' </span><span class="syntaxkeyword">=> </span><span class="syntaxdefault">$name </span><span class="syntaxkeyword">. </span><span class="syntaxstring">'/'</span><span class="syntaxkeyword">. (</span><span class="syntaxdefault">$images</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">$name </span><span class="syntaxkeyword">. </span><span class="syntaxstring">'/'</span><span class="syntaxkeyword">][</span><span class="syntaxdefault">mt_rand</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">count</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$images</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">$name </span><span class="syntaxkeyword">. </span><span class="syntaxstring">'/'</span><span class="syntaxkeyword">]) -</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">)]),<br /> );<br /> }
</span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">x_per_letter </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">floor</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">width </span><span class="syntaxkeyword">/ </span><span class="syntaxdefault">count</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">letter_img</span><span class="syntaxkeyword">));<br /> }
function </span><span class="syntaxdefault">paint</span><span class="syntaxkeyword">()<br /> {<br /> </span><span class="syntaxdefault">$count </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">count</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">letter_img</span><span class="syntaxkeyword">);<br /> for (</span><span class="syntaxdefault">$index </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">; </span><span class="syntaxdefault">$index write_letter</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$index</span><span class="syntaxkeyword">);<br /> }<br /> return </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">img</span><span class="syntaxkeyword">;<br /> }
function </span><span class="syntaxdefault">write_letter</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$index</span><span class="syntaxkeyword">)<br /> {<br /> </span><span class="syntaxdefault">$imgfile </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">path </span><span class="syntaxkeyword">. </span><span class="syntaxstring">'/' </span><span class="syntaxkeyword">. </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">letter_img</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">$index</span><span class="syntaxkeyword">][</span><span class="syntaxstring">'image'</span><span class="syntaxkeyword">];<br /> </span><span class="syntaxdefault">$imagedata </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">getimagesize</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$imgfile</span><span class="syntaxkeyword">);<br /> switch (</span><span class="syntaxdefault">$imagedata</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">2</span><span class="syntaxkeyword">])<br /> {<br /> case </span><span class="syntaxdefault">1 </span><span class="syntaxkeyword">:<br /> </span><span class="syntaxdefault">$img </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">imagecreatefromgif</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$imgfile</span><span class="syntaxkeyword">);<br /> break;
case </span><span class="syntaxdefault">2 </span><span class="syntaxkeyword">:<br /> </span><span class="syntaxdefault">$img </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">imagecreatefromjpeg</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$imgfile</span><span class="syntaxkeyword">);<br /> break;
case </span><span class="syntaxdefault">3 </span><span class="syntaxkeyword">:<br /> </span><span class="syntaxdefault">$img </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">imagecreatefrompng</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$imgfile</span><span class="syntaxkeyword">);<br /> break;
default : return </span><span class="syntaxdefault">false</span><span class="syntaxkeyword">;<br /> }<br /> </span><span class="syntaxdefault">$black </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">imagecolorallocate</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">img</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">$img_rot </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">imagerotate</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$img</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">mt_rand</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">30</span><span class="syntaxkeyword">) - </span><span class="syntaxdefault">15</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$black</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">$position_x </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">x_per_letter </span><span class="syntaxkeyword">* </span><span class="syntaxdefault">$index</span><span class="syntaxkeyword">;
</span><span class="syntaxdefault">$color </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">imagecolorallocate</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$img_rot</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">10</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">245</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">imagecopyresized</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">img</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$img_rot</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$position_x</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">x_per_letter</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">height </span><span class="syntaxkeyword">/ </span><span class="syntaxdefault">2</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">imagesx</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$img_rot</span><span class="syntaxkeyword">), </span><span class="syntaxdefault">imagesy</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$img_rot</span><span class="syntaxkeyword">));<br /> </span><span class="syntaxdefault">imagestring</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">img</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">5</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">$position_x </span><span class="syntaxkeyword">+ </span><span class="syntaxdefault">mt_rand</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">5</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">10</span><span class="syntaxkeyword">), </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">height </span><span class="syntaxkeyword">/ </span><span class="syntaxdefault">2 </span><span class="syntaxkeyword">+ </span><span class="syntaxdefault">mt_rand</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">5</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">10</span><span class="syntaxkeyword">), </span><span class="syntaxdefault">$this</span><span class="syntaxkeyword">-></span><span class="syntaxdefault">letter_img</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">$index</span><span class="syntaxkeyword">][</span><span class="syntaxstring">'letter'</span><span class="syntaxkeyword">], </span><span class="syntaxdefault">$color</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">imagedestroy</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$img</span><span class="syntaxkeyword">);<br /> </span><span class="syntaxdefault">imagedestroy</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$img_rot</span><span class="syntaxkeyword">);<br /> }<br />}
</span><span class="syntaxdefault">?></span>
captcha_gd
As an example, the class used with “Enter the letters underneath smiling emoticons” (which is a very bad idea, so don’t do that at home) and the 3.0 smilies.
And for the future? You’ll see …
Update
An early prototype for the phpBB 3.1 CAPTCHA plugins can now be found in our SVN repository.
Posted by Elias on August 28th, 2008 at 4:04 pm:
Very nice article.
Good information.