## Использование капчи

По умолчанию FormLister может использовать модицифированную капчу MODX и Google Recaptcha. Также в наличии SmsCaptcha - для отправки формы необходимо ввести код, полученный в смс-сообщении (отправку сообщения необходимо реализовывать отдельно).

Для подключения необходимо указать имя папки с файлами капчи (папки находятся в assets/snippets/FormLister/lib/captcha/) в параметре &captcha.

В параметре &captchaParams задаются в виде массива настройки капчи. Например:
```
&captchaParams=`{
"width":200,
"height":120
}`
```

Имя поля, в которое пользователь вводит значение капчи, задается параметром captchaField (по умолчанию - vericode). Правило валидации для этого поля создается автоматически.

Капча выводится в шаблоне формы с помощью плейсхолдера [+captcha+].

### modxCaptcha

Модификация стандартной капчи MODX.

Настройки:
* width и height - ширина и высота картинки с капчей (значение по умолчанию - 100 и 60);
* inline - формат вывода. Если значение параметра равно 1, то в плейсхолдер [+captcha+] выводится картинка в base64-формате. Если 0, то выводится ссылка на файл connector.php, генерирующий картинку. Значение по умолчанию - 1;
* connectorDir - путь к папке с файлом connector.php, если параметр inline равен 0. Значение по умолчанию - assets/snippets/FormLister/lib/captcha/modxCaptcha/;
* errorEmptyCode - текст сообщения об ошибке, если поле со значением капчи не заполнено. Значение по умолчанию - "Введите проверочный код";
* errorCodeFailed - текст сообщения об ошибке, если введено неверное значение капчи. Значение по умолчанию - "Неверный проверочный код" 

### reCaptcha

Капча Google reCAPTCHA V2. На странице с формой должен быть подключен скрипт:
```
<script src='https://www.google.com/recaptcha/api.js'></script>
```

Значение параметра captchaField должно быть "g-recaptcha-response" (см. [документацию](https://developers.google.com/recaptcha/docs/verify)). 

Настройки:
* secretKey, siteKey - ключи для доступа к api reCAPTCHA; 
* size, theme, badge, callback, expired_callback, tabIndex, type - см. [документацию](https://developers.google.com/recaptcha/docs/display#render_param);
* errorCodeFailed - текст сообщения об ошибке, если пользователь не прошел проверку. Значение по умолчанию - "Вы не прошли проверку"

### smsCaptcha

Настройки: 
* codeLifeTime - срок действия введенного кода, секунд. Если пользователь попытается ввести код до истечения срока, то будет выведено сообщение errorCodeUsed. Значение по умолчанию - 86400 (сутки);
* errorEmptyCode - сообщение об ошибке, если пользователь получил, но не ввел код. Значение по умолчанию - "Введите код авторизации"; 
* errorCodeRequired - сообщение об ошибке, если пользователь не запросил код. Значение по умолчанию - "Получите код авторизации"; 
* errorCodeFailed - сообщение об ошибке, если пользователь ввел неверный код авторизации. Значение по умолчанию - "Неверный код авторизации";
* errorCodeExpired - сообщение об ошибке, если пользователь не ввел полученный код в течение заданного времени. Значение по умолчанию - "Код авторизации истек, получите новый"; 
* errorCodeUsed - сообщение об ошибке, если пользователь уже вводил код для текущей формы. Значение по умолчанию - "Код авторизации уже использовался".

Чтобы использовать эту капчу необходимо предварительно создать таблицу в базе данных:
```
<?php
include_once(MODX_BASE_PATH.'assets/snippets/FormLister/lib/captcha/smsCaptcha/model.php');
$sms = new \SmsModel($modx);
$sms->createTable();
```

Для отправки кода необходимо создать отдельную форму и указать в параметре prepareProcess сниппет:
 ```
<?php
//удаляем из номера телефона все, кроме цифр
$rawPhone = preg_replace('/[^\d]+/','',$data['phone']);
//задаем значение, по которому будет определяться для какой формы генерируется код
$formid = 'basic';
//в сессии будем хранить номер телефона, это нужно для проверки кода в основной форме, потом его можно использовать в каких-то целях, например убрать из основной формы поле для ввода телефона, а в письме использовать телефон из сессии
$session_key = $formid.'.smscaptcha';
if (empty($rawPhone)) {
    $FormLister->setValid(false);
    $FormLister->addError('phone','phone','Неверный номер телефона');   
} else {
    //загружаем класс для работы с таблицей
    $sms = $FormLister->loadModel('SmsModel','assets/snippets/FormLister/lib/captcha/smsCaptcha/model.php');
    $flag = false;
    //проверяем, есть ли в таблице запись для заданного номера и идентификатора формы
    $data = $sms->getData('+'.$rawPhone,$formid);
    if ($data->getID()) {
        //если есть и код не истек
        if ($sms->get('expires') > time()) {
            //смотрим, использован ли код
            if ($sms->get('active')) {
                $FormLister->addMessage('Вы уже использовали код.');
            } else {
                $FormLister->addMessage('Код уже был отправлен. Подождите несколько минут прежде чем запросить новый.');
            }
        //если код истек, то удаляем запись и разрешаем выдать новый
        } else {
            $sms->delete($sms->getID());
            $flag = true;
        }
    } else {
        $flag = true;
    }
    //если можно выдать новый код
    if ($flag) {
        $code = mt_rand(1000,9999);
        
        //здесь отправляется смс и результат помещается в переменную $result
        /** 
         *  
         */ 
        $result = array('status'=>true);
        
        //проверяем отправлена ли смс
        if (is_array($result) && $result['status']) {
            //создаем запись в таблице, время жизни кода - 3 минуты
            $result = $sms->create()->fromArray(array(
                'phone'=>('+'.$rawPhone),
                'formid'=>$formid,
                'expires'=>(time() + 60*3),
                'ip'=> \APIhelpers::getUserIP(),
                'code'=>$code
            ))->save(); 
            //если получилось записать, то сохраняем в сессию номер телефона
        if ($result) {
            $_SESSION[$session_key] = '+'.$rawPhone;
        } else {
            $FormLister->setValid(false);
            $FormLister->addMessage('Не удалось отправить смс');
        }
    } else {
        //если нельзя выдать код, то запрещаем дальнейшую обработку формы
        $FormLister->setValid(false);
    }
}
?>
```

Полностью вызов FormLister:
```
[!FormLister?
&formid=`code`
&submitLimit=`0`
&protectSubmit=`0`
&rules=`{
"phone":{
    "required":"Обязательно введите номер телефона",
    "phone":"Введите номер правильно"
}
}`
&prepareProcess=`setSmsCaptcha`
&captcha=`modxCaptcha`
&formTpl=`@CODE:
<div class="row">
    <div class="col-md-8 col-md-offset-2">
        <div class="well">
            <form class="form-horizontal" method="post">
                <input type="hidden" name="formid" value="code">

                <div class="form-group[+phone.errorClass+][+phone.requiredClass+]">
                    <label for="phone" class="col-sm-2 control-label">* Телефон</label>
                    <div class="col-sm-10">
                        <input type="text" class="form-control" placeholder="+375 29 123 45 67" name="phone" value="[+phone.value+]">
                            [+phone.error+]
                    </div>
                </div>
[+form.messages+]
                <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-10">
                        <button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-envelope"></i> Отправить</button>
                    </div>
                </div>
                <img src="[+captcha+]">
                <input name="vericode">
                    [+vericode.error+]
            </form>
        </div>
    </div>
</div>`
&successTpl=`@CODE:Код авторизации отправлен на номер [+phone.value+]. Срок действия кода - 3 минуты.`
!]
```
