Sujet : Hoa_Form_Element_InputCaptcha

Hey tout le monde,

J'ai confectionné un Hoa_Form_Element_InputCaptcha avec http://www.captcha.net/
Je vous partage ça ce soir, par contre c'est la version 0.1 !, assez propre mais pas paramétrable entièrement.
A ce soir ! smile

" L'imagination est plus importante que la connaissance. La connaissance est limitée alors que l'imagination englobe le monde entier, stimule le progrès, suscite l'évolution. " - Life in the cloud :: Getting Started with Hoa - Hoa débutant

Re : Hoa_Form_Element_InputCaptcha

Hey,

J'ai bricoler un inputCaptcha afin de faciliter les utilisateurs de Hoa.

1/ Ajouter l'élement de formulaire dans le framework Framework/Library/Form/Element/InputCaptcha.php

<?php

/**
 * Hoa Framework
 *
 *
 * @license
 *
 * GNU General Public License
 *
 * This file is part of Hoa Open Accessibility.
 * Copyright (c) 2007, 2008 Ivan ENDERLIN. All rights reserved.
 *
 * HOA Open Accessibility is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * HOA Open Accessibility is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with HOA Open Accessibility; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *
 * @category    Framework
 * @package     Hoa_Form
 * @subpackage  Hoa_Form_Element_InputCaptcha
 *
 */

/**
 * Hoa_Framework
 */
require_once 'Framework.php';

/**
 * Hoa_Form_Exception
 */
import('Form.Exception');

/**
 * Hoa_Form_Element_Abstract
 */
import('Form.Element.Abstract');

/**
 * Class Hoa_Form_Element_InputCaptcha.
 *
 * Describe the input type text element.
 *
 * @author      
 * @copyright   
 * @license     http://gnu.org/licenses/gpl.txt GNU GPL
 * @since       PHP 5
 * @version     0.1
 * @package     Hoa_Form
 * @subpackage  Hoa_Form_Element_InputCaptcha
 */

class Hoa_Form_Element_InputCaptcha extends Hoa_Form_Element_Abstract {

    /**
     * List of attributes.
     *
     * @var Hoa_Form_Element_Abstract array
     */
    protected $attributes = array(
        'id'              => array(
            'default'     => null,
            'required'    => true,
            'type'        => parent::ATTRIBUTE_TYPE_ID,
            'description' => null,
            'value'       => null
        ),
        'name'            => array(
            'default'     => null,
            'required'    => true,
            'type'        => parent::ATTRIBUTE_TYPE_CDATA,
            'description' => 'submit as part of form',
            'value'       => null
        )
    );



    /**
     * Build an input type password.
     *
     * @access  public
     * @param   mixed   $attributes    Attributes.
     * @param   mixed   $rest          Rest of options.
     * @return  void
     */
    public function __construct ( $attributes, $rest = null ) {

        parent::__construct($attributes, 'id');

        if(is_string($rest)) {

            $this->setLabel($rest);
            $this->setDecorator('InputCaptcha');
        }
        elseif(is_array($rest)) {

            if(isset($rest['label']))
                $this->setLabel($rest['label']);
            else
                $this->setLabel(null);

            //if(isset($rest['filter']))
                //$this->setFilter($rest['filter']);

            //if(isset($rest['validator']))
                //$this->setValidator($rest['validator']);

            //if(isset($rest['decorator']))
                //$this->setDecorator($rest['decorator']);
            //else
                $this->setDecorator('InputCaptcha');
        }
        else {

            $this->setDecorator('InputCaptcha');
            $this->setLabel(null);
        }
    }

    /**
     * To string method.
     *
     * @access  public
     * @return  string
     */
    public function __toString ( ) {

        try {
            return self::recaptcha_get_html('xxxxxx'); // Public Key
            //return '<input'. $this->getAttributesChain() . ' />';
        }
        catch ( Hoa_Form_Exception $e ) {

            return $e->__toString();
        }
    }

    /*
       * This is a PHP library that handles calling reCAPTCHA.
       *    - Documentation and latest version
       *          http://recaptcha.net/plugins/php/
       *    - Get a reCAPTCHA API Key
       *          http://recaptcha.net/api/getkey
       *    - Discussion group
       *          http://groups.google.com/group/recaptcha
       *
       * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
       * AUTHORS:
       *   Mike Crawford
       *   Ben Maurer
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy
       * of this software and associated documentation files (the "Software"), to deal
       * in the Software without restriction, including without limitation the rights
       * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       * copies of the Software, and to permit persons to whom the Software is
       * furnished to do so, subject to the following conditions:
       *
       * The above copyright notice and this permission notice shall be included in
       * all copies or substantial portions of the Software.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       * THE SOFTWARE.
    */

    /**
     * Gets the challenge HTML (javascript and non-javascript version).
     * This is called from the browser, and the resulting reCAPTCHA HTML widget
     * is embedded within the HTML form it was called from.
     * @param string $pubkey A public key for reCAPTCHA
     * @param string $error The error given by reCAPTCHA (optional, default is null)
     * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)

     * @return string - The HTML to be embedded in the user's form.
     */
    private function recaptcha_get_html ( $pubkey, $error = null, $use_ssl = false ) {

        if ($pubkey == null || $pubkey == '')
            die('To use reCAPTCHA you must get an API key from <a href="http://recaptcha.net/api/getkey">http://recaptcha.net/api/getkey</a>');

        if ($use_ssl)
            $server = 'https://api-secure.recaptcha.net';
        else
            $server = 'http://api.recaptcha.net';

        $errorpart = "";

        if ($error)
            $errorpart = "&amp;error=" . $error;

        return '
            <script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
            <noscript>
                  <iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
                  <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
                  <input type="hidden" name="recaptcha_response_field" id="name="recaptcha_response_field" value="manual_challenge"/>
            </noscript>
        ';
    }



}

J'ai utilisé qu'une partie de la librairie donné par captcha pour faire fonctionner cette classe. (cf la méthode recaptcha_get_html())


2/ Modifier la ligne 141 lors de l'appel de la méthode recaptcha_get_html(), vous devez insérer votre clé public disponible à cette adresse http://recaptcha.net/api/getkey.

3/ Ajouter le Décorateur du formulaire Framework/Library/Form/Decorateur/InputCaptcha.php

<?php

/**
 * Hoa Framework
 *
 *
 * @license
 *
 * GNU General Public License
 *
 * This file is part of Hoa Open Accessibility.
 * Copyright (c) 2007, 2009 Ivan ENDERLIN. All rights reserved.
 *
 * HOA Open Accessibility is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * HOA Open Accessibility is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with HOA Open Accessibility; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *
 * @category    Framework
 * @package     Hoa_Form
 * @subpackage  Hoa_Form_Decorator_InputCaptcha
 *
 */

/**
 * Hoa_Framework
 */
require_once 'Framework.php';

/**
 * Hoa_Form_Exception
 */
import('Form.Exception');

/**
 * Hoa_Form_Decorator_Abstract
 */
import('Form.Decorator.Abstract');

/**
 * Class Hoa_Form_Decorator_InputCaptcha.
 *
 * Decorate the input type text element.
 *
 * @author      
 * @copyright   
 * @license     http://gnu.org/licenses/gpl.txt GNU GPL
 * @since       PHP 5
 * @version     0.1
 * @package     Hoa_Form
 * @subpackage  Hoa_Form_Decorator_InputCaptcha
 */

class Hoa_Form_Decorator_InputCaptcha extends Hoa_Form_Decorator_Abstract {

    /**
     * Make a render of an input type text.
     *
     * @access  public
     * @param   Hoa_Form_Element_Abstract  $element      The element.
     * @param   Hoa_Form_Element_Label     $label        The associated label
     *                                                   element.
     * @param   Hoa_Validate_Abstract      $validator    The element validator
     *                                                   collection.
     * @return  string
     */
    public function render ( Hoa_Form_Element_Abstract $element,
        Hoa_Form_Element_Label    $label,
        Hoa_Validate_Abstract     $validator ) {

        return '  <p>' . $label . "\n" .
               '     ' . $element . $validator . '</p>' . "\n";
    }
}

Ce décorateur n'a rien d'exceptionnel !!

4/ Utilisation de Captcha dans un modele de formulaire :

import('Form.Element.InputCaptcha');

      $fieldset->addElements(array(
            'captcha'          => array(
                'type'      => Hoa_Form::ELEMENT_INPUT_CAPTCHA,
                'attribute' => array(
                    'id'    => 'recaptcha_response_field',
                    'name'  => 'recaptcha_response_field'
                )
            )
       ));

Je viens de faire à l'instant un minimum de paramètres notamment le nom et l'id.

5/ Pour vérifier captcha, je n'est pas cherché à utiliser l'AJAX. Désolé les amis :s

J'ai minifié d'un poil la librairie de captcha :

a) Créé un fichier dans votre Public/lib/recaptchalib.php (Complètement modifiable !!!)

<?php
/*
 * This is a PHP library that handles calling reCAPTCHA.
 *    - Documentation and latest version
 *          http://recaptcha.net/plugins/php/
 *    - Get a reCAPTCHA API Key
 *          http://recaptcha.net/api/getkey
 *    - Discussion group
 *          http://groups.google.com/group/recaptcha
 *
 * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
 * AUTHORS:
 *   Mike Crawford
 *   Ben Maurer
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

define("RECAPTCHA_API_SERVER", "http://api.recaptcha.net");
define("RECAPTCHA_API_SECURE_SERVER", "https://api-secure.recaptcha.net");
define("RECAPTCHA_VERIFY_SERVER", "api-verify.recaptcha.net");

/**
 * Encodes the given data into a query string format
 * @param $data - array of string elements to be encoded
 * @return string - encoded request
 */
function _recaptcha_qsencode ($data) {
        $req = "";
        foreach ( $data as $key => $value )
                $req .= $key . '=' . urlencode( stripslashes($value) ) . '&';

        // Cut the last '&'
        $req=substr($req,0,strlen($req)-1);
        return $req;
}



/**
 * Submits an HTTP POST to a reCAPTCHA server
 * @param string $host
 * @param string $path
 * @param array $data
 * @param int port
 * @return array response
 */
function _recaptcha_http_post($host, $path, $data, $port = 80) {

        $req = _recaptcha_qsencode ($data);

        $http_request  = "POST $path HTTP/1.0\r\n";
        $http_request .= "Host: $host\r\n";
        $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
        $http_request .= "Content-Length: " . strlen($req) . "\r\n";
        $http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
        $http_request .= "\r\n";
        $http_request .= $req;

        $response = '';
        if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
                die ('Could not open socket');
        }

        fwrite($fs, $http_request);

        while ( !feof($fs) )
                $response .= fgets($fs, 1160); // One TCP-IP packet
        fclose($fs);
        $response = explode("\r\n\r\n", $response, 2);

        return $response;
}





/**
 * A ReCaptchaResponse is returned from recaptcha_check_answer()
 */
class ReCaptchaResponse {
        var $is_valid;
        var $error;
}


/**
  * Calls an HTTP POST function to verify if the user's guess was correct
  * @param string $privkey
  * @param string $remoteip
  * @param string $challenge
  * @param string $response
  * @param array $extra_params an array of extra variables to post to the server
  * @return ReCaptchaResponse
  */
function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
{
    if ($privkey == null || $privkey == '') {
        die ("To use reCAPTCHA you must get an API key from <a href='http://recaptcha.net/api/getkey'>http://recaptcha.net/api/getkey</a>");
    }

    if ($remoteip == null || $remoteip == '') {
        die ("For security reasons, you must pass the remote ip to reCAPTCHA");
    }



        //discard spam submissions
        if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
                $recaptcha_response = new ReCaptchaResponse();
                $recaptcha_response->is_valid = false;
                $recaptcha_response->error = 'incorrect-captcha-sol';
                return $recaptcha_response;
        }

        $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/verify",
                                          array (
                                                 'privatekey' => $privkey,
                                                 'remoteip' => $remoteip,
                                                 'challenge' => $challenge,
                                                 'response' => $response
                                                 ) + $extra_params
                                          );

        $answers = explode ("\n", $response [1]);
        $recaptcha_response = new ReCaptchaResponse();

        if (trim ($answers [0]) == 'true') {
                $recaptcha_response->is_valid = true;
        }
        else {
                $recaptcha_response->is_valid = false;
                $recaptcha_response->error = $answers [1];
        }
        return $recaptcha_response;

}

/**
 * gets a URL where the user can sign up for reCAPTCHA. If your application
 * has a configuration page where you enter a key, you should provide a link
 * using this function.
 * @param string $domain The domain where the page is hosted
 * @param string $appname The name of your application
 */
function recaptcha_get_signup_url ($domain = null, $appname = null) {
    return "http://recaptcha.net/api/getkey?" .  _recaptcha_qsencode (array ('domain' => $domain, 'app' => $appname));
}

function _recaptcha_aes_pad($val) {
    $block_size = 16;
    $numpad = $block_size - (strlen ($val) % $block_size);
    return str_pad($val, strlen ($val) + $numpad, chr($numpad));
}

/* Mailhide related code */

function _recaptcha_aes_encrypt($val,$ky) {
    if (! function_exists ("mcrypt_encrypt")) {
        die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
    }
    $mode=MCRYPT_MODE_CBC;
    $enc=MCRYPT_RIJNDAEL_128;
    $val=_recaptcha_aes_pad($val);
    return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
}


function _recaptcha_mailhide_urlbase64 ($x) {
    return strtr(base64_encode ($x), '+/', '-_');
}

/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
function recaptcha_mailhide_url($pubkey, $privkey, $email) {
    if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
        die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
             "you can do so at <a href='http://mailhide.recaptcha.net/apikey'>http://mailhide.recaptcha.net/apikey</a>");
    }


    $ky = pack('H*', $privkey);
    $cryptmail = _recaptcha_aes_encrypt ($email, $ky);

    return "http://mailhide.recaptcha.net/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
}

/**
 * gets the parts of the email to expose to the user.
 * eg, given johndoe@example,com return ["john", "example.com"].
 * the email is then displayed as john...@example.com
 */
function _recaptcha_mailhide_email_parts ($email) {
    $arr = preg_split("/@/", $email );

    if (strlen ($arr[0]) <= 4) {
        $arr[0] = substr ($arr[0], 0, 1);
    } else if (strlen ($arr[0]) <= 6) {
        $arr[0] = substr ($arr[0], 0, 3);
    } else {
        $arr[0] = substr ($arr[0], 0, 4);
    }
    return $arr;
}

/**
 * Gets html to display an email address given a public an private key.
 * to get a key, go to:
 *
 * http://mailhide.recaptcha.net/apikey
 */
function recaptcha_mailhide_html($pubkey, $privkey, $email) {
    $emailparts = _recaptcha_mailhide_email_parts ($email);
    $url = recaptcha_mailhide_url ($pubkey, $privkey, $email);

    return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .
        "' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);

}


?>

b) Vérification côté Controller :

        
        // Vérification CAPTCHA
        require_once('lib/recaptchalib.php');
        $privatekey = 'xxxxxxx';
        $resp = recaptcha_check_answer($privatekey,
                                        $_SERVER["REMOTE_ADDR"],
                                        $_POST["recaptcha_challenge_field"],
                                        $_POST["recaptcha_response_field"]);

        if (!$resp->is_valid) {
            $this->view->error = true;
        }

c) Modifié la clé privé dans la vérification côté Controller



/************************************************************************************************/


Voila pour le moment c'est un début, je vais repassé dessus pour m'entrainer à mieux gérer les formulaire.
Il manque la possibilité de mettre des filtres, de modifié le décorateur, ou encore faire une vérif à la volée (validator).

Désolé si c'est un peu baclé je n'ai pas trop le temps :s

Dernière fois dit par Ecureuil Virtuel (22 Apr. 2010 19:01)

" L'imagination est plus importante que la connaissance. La connaissance est limitée alors que l'imagination englobe le monde entier, stimule le progrès, suscite l'évolution. " - Life in the cloud :: Getting Started with Hoa - Hoa débutant

Re : Hoa_Form_Element_InputCaptcha

Hey,

Petite modification à faire dans le décorateur Hoa_Form_Decorator_InputCaptcha dans la chaîne retourné enlever les balises <p></p> car pas valide sinon.

" L'imagination est plus importante que la connaissance. La connaissance est limitée alors que l'imagination englobe le monde entier, stimule le progrès, suscite l'évolution. " - Life in the cloud :: Getting Started with Hoa - Hoa débutant

4

Re : Hoa_Form_Element_InputCaptcha

Pourquoi non valide smile ?

« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Re : Hoa_Form_Element_InputCaptcha

Hey,

J'avais vu ça dans les outils de développement sur google chrome, j'avais une erreur qui apparaissait à la génération du code.
Il ne devait pas aimer l'iframe entre les balises <p></p> :

<p>
    <script type="text/javascript" src="http://api.recaptcha.net/challenge?k=6LdN8gsAAAAAAP9IXv7rCZU2YE9qGQX4PPxsfkyQ"></script> 
    <noscript> 
        <iframe src="http://api.recaptcha.net/noscript?k=6LdN8gsAAAAAAP9IXv7rCZU2YE9qGQX4PPxsfkyQ" height="300" width="500" frameborder="0"></iframe><br/> 
        <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea> 
        <input type="hidden" name="recaptcha_response_field" id="name="recaptcha_response_field" value="manual_challenge"/> 
      </noscript>
</p>
" L'imagination est plus importante que la connaissance. La connaissance est limitée alors que l'imagination englobe le monde entier, stimule le progrès, suscite l'évolution. " - Life in the cloud :: Getting Started with Hoa - Hoa débutant

6

Re : Hoa_Form_Element_InputCaptcha

Hey smile,

Travail sympa (mais j'aime pas le die() dans ton code tongue).
Je réfléchis à comment proposer du code « exécutable » (démo) dans Hoathis. Une idée ?

« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Re : Hoa_Form_Element_InputCaptcha

Hey,

C'est vrai que c'est difficile car ça impacte un librairie voir plusieurs Hoathis et ça implique tout une partie MVC.

Pour la partie mise en place, il faudrait que l'éditeur de son Hoathis puisse ajouter du code comme dans le forum.

Pour la partie demo, il faudrait mettre en place un svn et l'editeur peux mettre son appli.

Le problème est qu'il y aura trop de répétition du Framework, mais bon comme le Framework bouge et est légé...

Le SVN avec toute l'application demo de l'editeur Hoathis et sa documentation sous le forme du forum me semble être une très bonne idée ainsi que la possibilité de commenter.

Possibilité d'avoir un lien genre j'aime bien à la facebook rapide tongue pour aider le développeur.
Une partie commentaire.
Stats si possibles.


On peut s'amuser mais il y a le dev derrière tongue

" L'imagination est plus importante que la connaissance. La connaissance est limitée alors que l'imagination englobe le monde entier, stimule le progrès, suscite l'évolution. " - Life in the cloud :: Getting Started with Hoa - Hoa débutant

8

Re : Hoa_Form_Element_InputCaptcha

Le développement ce sera vous (et moi) wink.

« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »