Chesscaptcha is a captcha system inspired by chess. The nice thing about this implementation is that it can also be used by non-chess players and that's because the default mode requires copying a given position on the input board, something that can be done by anyone. There is also the mate in one mode where the visitor has to be a chess player of course. We are happy that the developer of the project is a member of our team here at emar.
In this tutorial we'll be dealing with the installation of chesscaptcha in laravel and its use on an example registration form. Let's get started.
1. INSTALL WITH COMPOSER
In your terminal type the following:
composer require elioair/chesscaptcha
This will download the package in the vendor directory of your laravel project.
2. FILE ARRANGEMENT
Since this is a composite package meaning that it has both a php and a javascript side we have to move the required js files from the package's directory into the public directory. So in our case this will be done by moving the chesscaptcha.js (or the chesscaptcha.min.js) file from vendor/elioair/chesscaptcha/assets/js to the public/js folder.
Next we'll have to move - or copy if you don't care about duplicate files - the pieces folder under assets/img to the public/img/ folder. This is done because the javascript part won't be able to access image files that reside outside the public folder.
Lastly we'll have to set the path in the BoardImageCreator.php class file. So go in vendor/elioair/chesscaptcha/src/BoardImageCreator.php and in line 24 change the path to the one of your installation. In my case that was:
protected $pieceImageDir = "/var/www/mylaravelproject.dev/public/img/pieces/";
3. CREATE A FORM VIEW
We'll be using the default authentication controller that is built-in into Laravel so our form template will have to be created in a file structure specified by this. Let's create now the auth directory under resources/views and in this directory create the file register.blade.php that will hold the registration form and paste this in it:Open the routes.php file and paste these in.
@if (count($errors) > 0)
<div class="alert alert-danger">
<strong>Whoops!</strong> There were some problems with your input.<br><br>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<h1>Register</h1>
<form method="POST" action="/auth/register">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" name="name" placeholder="Name">
</div>
<div class="form-group">
<label for="email">Email address</label>
<input type="email" class="form-control" id="email" name="email" placeholder="Email">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" id="password" name="password" placeholder="Password">
</div>
<div class="form-group">
<label for="password_conf">Confirm Password</label>
<input type="password" class="form-control" id="password_conf" name="password_confirmation" placeholder="Retype Password">
</div>
<div class="checkbox">
<label>
<input type="checkbox"> I accept the terms
</label>
</div>
<!-- The #chesscaptcha div where the captcha will be rendered. If needed you can change the # in the $config array -->
<div id="chesscaptcha"><?php if($config['nojsfallback'] == 'yes'){ echo $chesscaptcha->noJsHtml($config['pieceImages']);}?></div>
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<button type="submit" id="submitform" class="btn btn-default">Register</button>
</form>
.....
<script src="/js/jquery.js"></script>
<!-- Bootstrap Core JavaScript -->
<script src="/js/bootstrap.min.js"></script>
4. CREATE THE ROUTES
Open the routes.php file and paste these in.
Route::get('auth/register', 'Auth\AuthController@getRegister');
Route::post('auth/register', 'Auth\AuthController@postRegister');
5. CHESSCAPTCHA CONFIGURATION
It is time now to configure the captcha system. In the beginning of the register.blade.php file put the following:
// The array that contains the configuration for the php side
$config = [
'divId'=>'chesscaptcha',
'whitesquare'=>'#f0d9b5',
'blacksquare'=>'#b58863',
'matemode'=>'no', // yes or no
'nojsfallback'=>'no', // yes or no; activate the fallback in case js is disabled
'titleoverride'=>'Copy the position below', // text override
'titlemateoverride'=>'Mate-In-One', // text override
'helpoverride'=>'Drag the pieces into the board to copy the given position. To remove a piece drag it out of the board.', // text override
'startoverride'=>'Start', // text override
'clearoverride'=>'Clear', // text override
'pieceStyle'=>'wikipedia', // the name of the piece style to use or 'random', default is 'wikipedia'
];
$chesscaptcha = new \Elioair\ChessCaptcha\ChessCaptcha($config['whitesquare'], $config['blacksquare'], $config['matemode'], $config['nojsfallback'], $config['pieceStyle']);
?>
and this near the end of the file after the jquery script request line. This is the configuration for the javascript part so you'll have to set the cc_pathtoimg parameter to the location of the piece images.
<script type="text/javascript">
// The object containing the configuration for the js side
var chessCaptchaParams = {
cc_divId: '<?php echo $config['divId'];?>',
cc_mateMode: '<?php echo $config['matemode']?>' === 'no' ? false : true,
cc_whiteSquare: '<?php echo $config['whitesquare'];?>',
cc_blackSquare: '<?php echo $config['blacksquare'];?>',
cc_titleOverride: '<?php echo $config['titleoverride'];?>',
cc_mateTitleOverride: '<?php echo $config['titlemateoverride'];?>',
cc_helpOverride: '<?php echo $config['helpoverride'];?>',
cc_startOverride: '<?php echo $config['startoverride'];?>',
cc_clearOverride: '<?php echo $config['clearoverride'];?>',
cc_sideToPlay: '<?php echo $chesscaptcha->chessCaptchaFenCode[2]; ?>',
cc_challenge: '<?php echo $chesscaptcha->chessCaptchaChallenge; ?>', // The image of the position
cc_matechallenge: '<?php echo $chesscaptcha->chessCaptchaFenCode[0];?>', // The fen code of matemode position
cc_pathtoimg: '/img/pieces',
cc_piecestyle: '<?php echo $chesscaptcha->chessCaptchaPieceStyle;?>',
};
</script>
<script type="text/javascript" src="/js/chesscaptcha.js"></script>
The complete register.blade.php code can be found in this Gist.
Now if you visit /auth/register in your browser you should see the form with the chesscaptcha in it.
6. VALIDATION OF THE INPUT DATA.
In this last step we'll validate the input data against the captcha challenge. We'll do it by editing the default authentication controller Controllers/Auth/AuthController.php and modifying the validator method. Also note that Laravel by default redirects to /home when the user is logged-in successfully and since we don't have such a route it is a good idea to add the private $redirectTo = '/'; right below use AuthenticatesAndRegistersUsers, ThrottlesLogins; inside the AuthController class. Next we'll have to add the custom validation rule by extending Validator and add some custom error messages - inline in this case - for the captcha input. So the modified validator method will look like this:
protected function validator(array $data)
{
// Extend the Validator to check also for the chesscaptcha
Validator::extend('chesscaptcha', function($attribute, $value, $parameters)
{
$noJs = false; // No disabled-javascript fallback
$colorTolerance = false; // Config param: Change this to true if you want to enable color tolerance
$validate = \Elioair\ChessCaptcha\ChessCaptcha::validate($value, $noJs, $colorTolerance);
return $validate;
});
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
'chesscaptchaposition' => 'required|chesscaptcha',
],
$messages = [
'chesscaptchaposition.required' => 'Empty chesscaptcha.',
'chesscaptcha' => 'Wrong chesscaptcha.',
]);
}
CONCLUSION
Although it might seem like a lot of work it is really easy to incorporate chess captcha to your websites' forms. As a system it is useful not only to avoid spammers when used as an alternative to distorted characters in regular mode but also to avoid, when set to mate-in-one mode, non-chess players accessing your site.