Fi1osof 26 января 2014 1 31
В свое время мы с Ваней ака vanchelo работали над парочкой проектов, и там надо было использовать каптчу. Гугловую рекаптчу не охото было использовать, так как лень было регистрировать сайт в гугле, и Ваня там запилил свою каптчу. Но она не была оформлена в установочный пакет. Сегодня я подправил пару моментов, добавил системные настройки, чанк для вывода картинки, сниппет и процессор для проверки кода и оформил это в пакет modCaptcha.

Все работает. Ване огромное спасибо за исходный код!

Вызов каптчи: просто чанк modcaptcha.

Проверка доступна двумя способами:
1. Процессором.
2. Сниппетом. Данный сниппет все равно в итоге вызывает тот же процессор, но разница в том, что в него не обязательно передавать значение полученного кода параметром. Если код не был передан явно, сниппет попытается получить его из массива $_REQUEST['php_captcha'].

При этом, если код верный, сниппет должен вернуть строку 'true'. Процессор же не должен вернуть $response->isError().

P.S. Проект на Github: github.com/Fi1osof/modCaptcha

UPD: Выпустил modCaptcha-1.0.1-beta, в которой фиксится бага с некорректным завершением сессий (как минимум на modxcloud.com). Об этом писал здесь: modxclub.ru/blog/dokumentatsiya-dlya-spetsialistov/36.html
31 комментарий
vgrish1
vgrish 26 января 2014г в 18:52 #
Отличное дополнение!
Его очень не хватало… Спасибо вам большое ребята!
Fi1osof1
Fi1osof 26 января 2014г в 19:02 #
Пожалуйста!

Обкатаете — дайте знать все ли работает как надо.
vgrish1
vgrish 26 января 2014г в 19:25 #
да я на тестовом сайте сразу же попробовал))). Все работает как часики. Проверил как различает строчные и заглавные буквы…
Все работает, все ОК! СПС большое!
Fi1osof1
Fi1osof 26 января 2014г в 19:41 #
Ну и славненько :)
Собственно, есть же и другие пакеты. Но мы сталкивались с проблемой, что на modxcloud из-за их особенностей с сессиями каптча не работала (потому что сессия не корректно сохранялась). Андчир вот тоже недавно выпустил свою каптчу, но у него там ремарка записана:
Attention! Current CAPTCHA need to the standard PHP sessions. «System Settings» -> «Sessions and Cookies» -> «session_handler_class» clean (make blank).
Вот мы попытались сделать так, чтобы этих проблем не было, и надеюсь, получилось.
gsnx1
gsnx 05 февраля 2014г в 00:00 #
Спасибо за хорошее дополнение! Еще бы здесь прямо демку сделали вообще класс было бы! ))
Сразу просто увидеть демонстрацию было бы нагляднее)))
Fi1osof1
Fi1osof 05 февраля 2014г в 00:17 #
Будет со временем демка :)
Tramp13571
Tramp1357 12 марта 2014г в 00:00 #
Почему-то на картинке отрисовываются только линии, а текста нет. В чем может быть проблема?
Fi1osof1
Fi1osof 12 марта 2014г в 08:09 #
Шрифты не отрисовываются. Но почему — не ясно. Они там прикладываются сразу в пакете. Может настройка количества символов не корректно прописалась? Пришли доступы в личку.
Tramp13571
Tramp1357 12 марта 2014г в 10:18 #
Отправил в личку. Капча показывается на страничке регистрации.
Fi1osof1
Fi1osof 12 марта 2014г в 11:02 #
В логи MODX-а пишет:
[2014-03-12 09:55:25] (ERROR @ ...../core/components/modcaptcha/php-captcha.inc.php: 295) PHP warning: imagefttext() [function.imagefttext]: Could not find/open font

Сейчас на семинаре, и к сожалению не могу более детально изучить проблему, придется тебе самому еще покопать. Судя по всему какая-то ошибка в формировании путей к шрифтам.
Tramp13571
Tramp1357 12 марта 2014г в 13:17 #
Да, только проблема была в файле assets/components/modcaptcha/captcha.php, где шрифты объявляются, я добавил полный путь, и все заработало:
$fonts = array(
	dirname(__FILE__).'/fonts/VeraBd.ttf', 
	dirname(__FILE__).'/fonts/VeraIt.ttf',
	dirname(__FILE__).'/fonts/Vera.ttf');
Fi1osof1
Fi1osof 12 марта 2014г в 16:15 #
Странно. Я на быструю руку именно это и попробовал, но что-то не помогло, только пятерки появились. Ну заработало — славненько. В новой версии пропишем полные пути.
p
php-include 17 декабря 2014г в 18:34 #
Добрый день, как совместить с FormIt?
p
php-include 17 декабря 2014г в 19:33 #
Спс разобрался.
Fi1osof1
Fi1osof 17 декабря 2014г в 19:55 #
Не за что.
I
Ilya Igonkin 22 апреля 2015г в 17:34 #
Можете рассказать хотябы в кратце? Не могу найти информацию как его использовать.
K
Kyrt_God 01 июня 2015г в 14:52 #
Если каптча нужна для формы регистрации то делаем так:
1. Копируем сниппет «modcaptcha.check_captcha», назовем его «modcaptcha.preHook» и немного меняем ему код, эти строки:

if($response->isError()){
    $result = $response->getMessage();
}
else{
    $result = 'true';
}

меняем на эти:

if($response->isError()){
    $result = false;
}
else{
    $result = true;
}

Это нужно для Login'а ибо прехук должен возвращать булево значение.

2. В вызов сниппета Register добавляем 2 параметра:

&preHooks=`modcaptcha.preHook` 
&captcha_key=`mycaptcha` 

первый это сниппет для прехука, второй ключ каптчи
3. В форму регистрации добавляем

<input type="text" name="mycaptcha">
[[!$modcaptcha? &captcha_key=`mycaptcha`]]


После этих манипуляций должно работать.

PS У меня версия modx 2.3.3 там modCaptcha не заработал. Пришлось подправить немного процессор «modcaptcha/web/check»,
строку
$code = $this->getProperty('code');

заменил на
$code = $this->modx->request->parameters[$this->getProperty('method')][$key];


Не понятно ошибка это была или раньше modProcessor подгружал в свойства переменные из глобальных массивов, но в версии 2.3.3 этого не происходит.
Fi1osof1
Fi1osof 01 июня 2015г в 18:07 #
PS У меня версия modx 2.3.3 там modCaptcha не заработал. Пришлось подправить немного процессор «modcaptcha/web/check»,
Странно, у меня все работает, и не на одном сайте. Убедитесь что у вас последние версии пакетов modxSite и modCaptcha.
Fi1osof1
Fi1osof 01 июня 2015г в 18:10 #
Не понятно ошибка это была или раньше modProcessor подгружал в свойства переменные из глобальных массивов, но в версии 2.3.3 этого не происходит.
Если вы процессор через коннектор вызываете, то там глобальные устанавливаются (на уровне modConnectorRequest или modConnectorResponse). Если вы просто вызываете процессор через $modx->runProcessor(), то тогда в процессоре глобальных не будет. Их там и не было никогда. Надо явно тогда в него в вызов передавать $_REQUEST|$_GET|$_POST.
K
Kyrt_God 02 июня 2015г в 09:16 #
modCaptcha 1.0.3-beta поставил вчера из репозитория modx, modxSite 1.3.1-beta

Да вызывал напрямую в смарти-шаблоне через {processor}. Да и сниппет вызывает точно так же.

В теме же и сказано вызывайте через процессор или сниппет =)

Я убрал вот этот код из сниппета:

$key = $scriptProperties['captcha_key'];

if(empty($scriptProperties['code'])){
    $param = "_".strtoupper($method);
    
    if(isset($$param)){
        $p = $$param;
        
        $scriptProperties['code'] = (!empty($p[$key]) ? $p[$key] : "");
    }
}

И добавил вот такой в процессор.

public function process(){
        $key = $this->getProperty('captcha_key');

        $method = $this->getProperty('method');
        $code = $this->getProperty('code');
        
        if(empty($code)){
            $code = $this->modx->request->parameters[$method][$key];
        }
            
        $session_code = $_SESSION[$key];

В итоге параметр переданный из формы получается через modRequest, если 'code' не передан в процессор через настройки сниппета или процессора.
Fi1osof1
Fi1osof 02 июня 2015г в 12:23 #
public function process(){
        $key = $this->getProperty('captcha_key');

        $method = $this->getProperty('method');
        $code = $this->getProperty('code');
       
        if(empty($code)){
            $code = $this->modx->request->parameters[$method][$key];
        }
           
        $session_code = $_SESSION[$key];
Вот так делать и не надо. Не надо прописывать в процессоре работу с глобальными массивами запросов, а то как вы будете разграничивать обработку, когда у вас на странице больше одного вызова будет? Надо писать что-то типа {processor… params=$smarty.get}, то есть явно в вызов процессора передавать данные запроса.
K
Kyrt_God 02 июня 2015г в 12:45 #
Почему нет? параметр в $_REQUEST уникален, а если ключи разные то каждый вызов получит свой, мы ведь передаем в вызов «captcha_key» он и служит ключём в $_REQUEST, собственно как и «method» говорит в каком массиве искать.

Только что ради эксперимента создал два вызова процессора в шаблоне, создал 2 поля ввода и вывод 2-х картинок всё с разными «captcha_key». Каждый экземпляр отработал независимо от другого. =)

Fi1osof1
Fi1osof 02 июня 2015г в 12:48 #
создал 2 поля ввода и вывод 2-х картинок всё с разными «captcha_key». Каждый экземпляр отработал независимо от другого. =)
Для этого параметр captcha_key и создавался. Но еще раз: прописывать внутри процессора работы с глобальными переменными запросов — не правильно. Но спорить с вами не буду. Вы можете делать так, как вам больше нравится.
K
Kyrt_God 02 июня 2015г в 13:47 #
А тут и не производиться работа с глобальными переменными, это уже сделал modRequest, мы лишь спрашиваем у него переменную по ключу и имени массива, и то только в случае если в параметрах процессора не был найден параметр «code». Ведь он уже инстанцирован и содержит все эти данные и без нас. Почему не использовать?
Ответ «не правильно» без аргументации не ответ имхо.
Fi1osof1
Fi1osof 02 июня 2015г в 13:51 #
Гуглите «почему глобальные переменные плохо».
K
Kyrt_God 02 июня 2015г в 14:09 #
стоп стоп. Не путайте меня =) я нигде и не использовал глобальные переменные о которых вы говорите =)

переменные $method и $key получаются из Properties процессора, их значения по умолчанию задаются в initialize(), и перезаписываются в случае если были переданы через $scriptProperties. А вот уже основываясь на этом я получаю значение $code в $modx->request который в свою очередь обрабатывает массивы $_REQUEST и т.д. И это не я придумал, а создатели modx =)

Где тут глобальные переменные которые «плохие»? ))

плохие глобальные переменные это

$a = 111;
 
class A {
    public function myfunc() {
        global $a;
        echo $a;
    } 
}


Fi1osof1
Fi1osof 02 июня 2015г в 14:32 #
плохие глобальные переменные это

$a = 111;
 
class A {
    public function myfunc() {
        global $a;
        echo $a;
    }
}

$_REQUEST: Замечание:
Это 'суперглобальная' или автоматическая глобальная переменная. Это просто означает что она доступна во всех контекстах скрипта. Нет необходимости выполнять global $variable; для доступа к ней внутри метода или функции.
Источник.

Где тут глобальные переменные которые «плохие»? ))
$this->modx->request->parameters[$method][$key];

Метод modRequest::getParameters() работает с глобальными переменными, а значит работая с $this->modx->request->parameters вы работаете с глобальными переменными. А надо использовать методы $this->getProperties()/$this->getProperty().
K
Kyrt_God 02 июня 2015г в 14:23 #
У меня такое чувство что мы с вами говорим о разных вещах.

Ведь даже вот тут github.com/MODX-Club/modCaptcha/blob/master/core/components/modcaptcha/processors/modcaptcha/web/check.class.php
строка 29, и это не мой код, а ваш =)
$session_code = (!empty($_SESSION[$key]) ? $_SESSION[$key] : '');

$_SESSION это суперглобальный массив =)
Почему $_SESSION это не плохо, а $this->modx->request->parameters[$method][$key] плохо?

Fi1osof1
Fi1osof 02 июня 2015г в 14:37 #
Почему $_SESSION это не плохо, а $this->modx->request->parameters[$method][$key] плохо?
Сессия одна на все области видимости скрипта. Ее нельзя ни с чем спутать. Работая с сессией вы априори знаете, что работаете только с ней. А вот обрабатывая данные запроса в процессоре, вы рискуете обработать данные не своего запроса. Сейчас, с каптчей, вы рассчитываете только на то, что у вас есть уникальный ключ параметра запроса и типа это вас перестраховывает. Да, это отчасти так, но это всего лишь меньший риск при использовании неправильного подхода. Он тем и не правильный, что при большей вероятности неуникального ключа, возрастает вероятность и логической ошибки. Если вы используете правильный подход, он всегда вам больше дает шанса на то, что и результат будет правильный.

Но вот вам еще один вариант: попробуйте свой скрипт вызвать не со страницы, а через Console. Будет ли у вас там нужный? $this->modx->request->parameters[$method][$key]; И что вы будете делать, чтобы у вас этот параметр был в пост-запросе? Как отладку будете выполнять?
K
Kyrt_God 02 июня 2015г в 15:12 #
Легко!
Код в консоли:

<?php
$_REQUEST['mykey'] = '123';
$method = 'REQUEST';
$key = 'mykey';
echo $modx->request->parameters[$method][$key];

вывод:
123


по умолчанию $method задан в вашем же процессоре и его значение 'REQUEST', но в случае если процессор был запущен вот так

$scriptProperties['method'] = 'GET';
$modx->runProcessor('modcaptcha/web/check', $scriptProperties, array(
    'processors_path' => $path.'processors/',
))

То параметр будет перезаписан в параметрах modProcessor согласно вот этому куску кода:
modprocessor.class.php

function __construct(modX & $modx,array $properties = array()) {
        $this->modx =& $modx;
        $this->setProperties($properties);
    }

А вот так туда попадуют параметры по умолчанию, и если заметить они не перезаписывают те что передаются при инициализации через $scriptProperties

public function setDefaultProperties(array $properties = array()) {
        $this->properties = array_merge($properties,$this->properties);
        return $this->properties;
    }

Точно так же в параметры процессора попадают все остальные параметры.

Единственное что бы я поправил, и у себя поправлю это все таки сделаю вот так:

$code = $modx->request->getParameters($key, strtoupper($method));

в методе getParameters клсса modRequest нет привидения к верхнему регистру как ни странно.
Fi1osof1
Fi1osof 02 июня 2015г в 15:19 #
Легко!
Код в консоли:
$_REQUEST['mykey'] = '123';
$method = 'REQUEST';
$key = 'mykey';
echo $modx->request->parameters[$method][$key];
И опять работа с глобальной переменной… Кто бы сомневался.

по умолчанию $method задан в вашем же процессоре и его значение 'REQUEST'
Очевидно, что это рудимент, который, судя по истории процессора, даже никогда не использовался. Надо просто удалить будет.

Еще раз: делайте как вам больше нравится. Это из серии совета. Все на ваше усмотрение.
K
Kyrt_God 02 июня 2015г в 15:42 #
-1
И опять работа с глобальной переменной… Кто бы сомневался.
Ну если вы так желаете, то:
код в консоли:

<?php
$method = 'REQUEST';
$key = 'action';
echo $modx->request->getParameters($key, strtoupper($method));

вывод:
exec


'action' это POST переменная передаваемая коннектору консоли, а 'exec' её значение )

Очевидно, что это рудимент, который, судя по истории процессора, даже никогда не использовался. Надо просто удалить будет.
Ну учитывая то что есть REQUEST это понятно.
Не понятно то, что вы вместо того чтобы развивать компонент доказываете мне то чего нет. =) Я лично вам не нравлюсь, или ваша идеология программирования не совпадает с моей, я не знаю. Но факт в том что ничего «не правильного» и «плохого» в использовании modRequest внутри процессора нет, тем более что он уже там есть в объекте $this->modx->request.
Fi1osof1
Fi1osof 02 июня 2015г в 15:47 #
Не понятно то, что вы вместо того чтобы развивать компонент доказываете мне то чего нет. =)
Куда развивать? Вы будете учить как и что развивать? Вам не кажется это наглостью? Вам который раз говорится, что так не правильно, а вы гнете свое. Вы имеете право не использовать то, что мы предоставляем. Но учить как «правильно» в своем убеждающем формате — это уж извольте. Диалог закончен.
K
Kyrt_God 02 июня 2015г в 15:59 #
«это не правильно потому-что я так сказал» — вот ваш ответ между строк.

Как бы я не просил вас аргументировать ваш ответ, вы кроме придирок ничего так и не ответили. А сейчас просто сливаете разговор чтобы не оказаться не правым.

А по-поводу "… развивать ваш проект.." я написал специально чтобы посмотреть действительно ли задето ваше самолюбие, и вы это подтвердили. Вы уж извините меня за это. Я лишь хотел понять причину почему $_SESSION можно, а $_REQUEST нельзя.

Чтож пусть будет так. А пользоваться вашими компонентами я буду и впредь ибо они мне нравятся намного больше чем аналоги, хоть иногда и случаются вот такие казусы =)
Fi1osof1
Fi1osof 02 июня 2015г в 16:22 #
Я лишь хотел понять причину почему $_SESSION можно, а $_REQUEST нельзя.
Я вам ответил почему. Вы это не приняли как причину. Ваше право. Я не буду усиленно объяснять вам свою точку зрения. Но ваши пожелания не буду внедрять, потому как они мне будут мешать (это по опыту работы). Вполне вероятно и вы к этому когда-нибудь придете. А может и не придете.
Сейчас в компоненте ошибки нет. В той же сборке ShopModxBox проверка каптчи вызывается внутри процессора формы, в который передаются данные запроса явно. Единственное что в том процессоре следует доработать, так это передачу еще и параметра «captcha_key» (просто этот параметр появился позже, чем был написан тот процессор).
K
Kyrt_God 02 июня 2015г в 15:29 #
кстати совсем забыл по поводу вот этого:
Сессия одна на все области видимости скрипта.

Все суперглобальные массивы имеют один экземпляр на все области видимости =), а $_REQUEST, $_GET, $_POST, $_COOKIE и т.д. это все спуреглобальные переменные на ряду с $_SESSION

Единственное это то что данные в $_REQUEST, $_GET, $_POST, $_COOKIE нужно фильтровать ибо они не безопасны. Но так как в нашем случае идет обычное сравнение то фильтрация это излишний функционал.
K
Kyrt_God 02 июня 2015г в 10:44 #
Кстати ещё один момент по поводу переменных переменных и суперглобальных массивов.

«Warning
Please note that variable variables cannot be used with PHP's Superglobal arrays within functions or class methods. The variable $this is also a special variable that cannot be referenced dynamically.
»
php.net/manual/en/language.variables.variable.php
Авторизуйтесь или зарегистрируйтесь (можно через соцсети ), чтобы оставлять комментарии.