Zend Framework

Introduction au Framework Zend – Partie 4

Chose promise, chose due, malgré une semaine de retard, je vous offre la suite du tutoriel Zend sur la création d’un blog. Aujourd’hui, il va s’agir de la partie authentification de l’administrateur.

Je vais donc commencer par vous montrer la création d’un nouveau module (module admin). Ensuite je vais vous montrer la création d’un formulaire avec Zend (il faut bien vous identifier quelque part non ?) et pour finir, nous allons entrer dans les détails de l’authentification par base de données.

Tout d’abord, reprenez le projet concernant cette suite de sujets et créez le module admin basée sur la structure montrée lors du précédent sujet (organisation des dossiers). Pour qu’un module autre que default marche, il faut lui créer un bootstrap de module permettant de charger ses models, ses formulaires et surtout ses contrôleurs.

Comme vous pouvez le voir, toutes les classes du module admin commencent par le Namespace Admin_, ceci est normal et permet à Zend de trouver facilement vos classes. Si vous oubliez cette information, Zend vous retournera une erreur comme quoi il ne trouve pas vos classes. Faites donc attention.
Dans le Bootstrap aussi vous devez renseigner le Namespace utilisé. Si il diffère de celui renseigné au début du nom de vos classes, vous aurez le droit à la même erreur.

/application/modules/admin/Bootstrap.php :

class Admin_Bootstrap extends Zend_Application_Module_Bootstrap
{  
    protected function _initAutoload()
    {
        $moduleLoader = new Zend_Application_Module_Autoloader(array(
            'namespace' => 'Admin_',
            'basePath'  => APPLICATION_PATH . '/modules/admin'));
        $moduleLoader->addResourceType('Models', 'models', 'Models');
        $moduleLoader->addResourceType('Forms', 'forms', 'Forms');
        return $moduleLoader;
    }
}

Afin de tester si notre module marche bien, nous allons ajouter l’IndexController et la vue associée à l’indexAction : /application/modules/admin/controllers/IndexController.php

class Admin_IndexController extends Zend_Controller_Action 
{
    public function indexAction() {
        $this->view->title="Authentification utilisateur";
    }
}

/application/modules/admin/views/scripts/index/index.phtml

<h3>Authentification</h3>

Normalement, si vous tapez http://localhost/tutosite.com/admin, vous devriez tomber sur La page suivante :

Je vous dis félicitation, vous venez de créer votre premier module pour le site. Maintenant, nous allons nous attaquer à quelque-chose de plus dur. La création du formulaire d’authentification.

Il faut savoir que dans la classe Zend_form, un élément comprend la légende et l’élément input. On peut aussi rajouter certains filtres et des validateurs pour automatiser des traitements rébarbatifs en PHP (combien ont fait des tests sur des $_POST).

Pour l’authentification, je prends les deux champs traditionnels : Login et Password. Le login ne sera pas une adresse E-Mail mais un pseudo. Je vous le dis pour le choix des validateurs. Si vous choisissez un e-mail, vous pouvez rajouter un validateur d’adresse e-mail qui accepte vos infos si et seulement si votre email a une structure valide (a@a.a). Vous pouvez aller plus loin en vérifiant que le nom de domaine existe bien (hotmail.com validé alors qu’azdfes.azdf est refusé).

Je vais donc vous montrer la classe formulaire que j’utilise sans trop rentrer dans les détails. La documentation explique beaucoup mieux que moi. Je vous expliquerais juste l’utilité des filtres et des validateurs que j’utilise.

/application/modules/admin/forms/Identification.php

class Admin_Forms_Identification extends Zend_Form 
{ 
    public function init()
    {
        $this ->setMethod('post')
              ->setName('identification'); 

        $login = new Zend_Form_Element_Text('login');
        $login ->setLabel('Identifiant')
               ->setRequired(TRUE)
               ->addFilters(array('StringTrim', 'StripTags'))
               ->addValidators(array( array('validator' => 'StringLength', 'options' => array(0, 20))))
               ->getDecorator('label')->setOption('tag', null);

        $passwd = new Zend_Form_Element_Password('password');
        $passwd ->setLabel('Mot de Passe')
                ->setRequired(TRUE)
                ->addFilters(array('StringTrim', 'StripTags'))
                ->addValidators(array( array('validator' => 'StringLength', 'options' => array(0, 20))))
                ->getDecorator('label')->setOption('tag', null);

        $submit = new Zend_Form_Element_Submit('submit');
        $submit ->setLabel('Connexion')
                ->setIgnore(true);

        $this->addElement($login);
        $this->addElement($passwd);
        $this->addElement($submit);

        $this->setDecorators(array(
            array('ViewScript', array('viewScript' => 'identification.phtml'))
        ));
    }
}

Tout d’abord, les filtres que j’utilise servent à limiter la casse et les injections de code (même si Zend ne permet pas ce genre de choses. Striptags permet d’enlever de notre variable toutes les balises de code afin d’éviter les injections JavaScript par exemple. Le filtre StringTrim quand à lui permet de supprimer les espaces en trop en début et en fin de notre variable afin de ne pas tricher sur le nombre de caractères requis. Ensuite le validateur StringLength quand à lui permet de définir le nombre min/max de caractères requis pour valider le formulaire.

Pour les décorateurs, j’ai décidé de passer par une vue externe afin de définir ma propre présentation. Cela permet une meilleure flexibilité de présentation e nos formulaires. Je trouve que les décorateurs sont trop complexes et limités mais en même temps, je suis nul avec. Pour pouvoir faire ce que je veux, j’ai donc désactivé les balises mises par défaut autour de notre élément.

Comme je vous l’ai expliqué, j’utilise un script de vue pour mettre en forme mon formulaire. Je vous le fournis bien entendu pour que vous puissiez voir comment cela marche.

/application/modules/admin/views/scripts/identification.phtml

<form action="<?php echo $this->escape($this->element->getAction()); ?>"         
      method="<?php echo $this->escape($this->element->getMethod()); ?>"         
      class="formident">         

    <p>Vous devez vous identifier pour accéder au backoffice.</p>        
    <div>        
        <span class="labelform"><?php echo $this->element->login->renderLabel(); ?></span>       
        <span><?php echo $this->element->login->renderViewHelper(); ?></span>        
    </div>       
    <div>        
        <span class="labelform"><?php echo $this->element->password->renderLabel(); ?></span>        
        <span><?php echo $this->element->password->renderViewHelper(); ?></span>         
    </div>       
    <?php echo $this->element->submit->renderViewHelper(); ?>                
</form>

Pour pouvoir afficher notre vue, nous ajoutons juste ces lignes pour le moment dans notre contrôleur :

$form = new Admin_Forms_Identification();
$this->view->form = $form;
$this->view->message = null;

Et dans notre vue, juste ces ligne :

<?php 
    if(!empty($this->message))
    {
?>
<div class="warning"><?php echo $this->message; ?></div>
<?php  
    }
    $this->form->setAction($this->url());
    echo $this->form;
    echo md5(azerty);

Voici le rendu final de notre vue :

En ajoutant le code css suivant à notre style, nous pouvons obtenir le résultat suivant :

/**
 * Formulaire authentification
 */
.formident{
    text-align: center;
}
.formident div{
    margin-top: 3px;
    margin-bottom: 3px;
    position: relative;
    width: 300px;
    margin-left: 330px;
} 
.formident div .labelform{
    width: 100px;
    display:block;
    float: left;
    text-align: left;
}

Alors ? Ce n’est pas sympa ce que l’on peut faire ? Nous pouvons aussi rajouter des images et des effets visuels sympas, mais ce n’est pas le but de cet article.

Bien, maintenant nous pouvons enfin attaquer le vif du sujet : L’authentification.

Comme je vous l’ai expliqué, nous allons authentifier notre utilisateur par une base de données. Je vais donc vous fournir le script de la base avec la table utilisateur. Je vais me baser dessus pour tous les autres articles du tutoriel.

CREATE DATABASE `tutosite` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
USE `tutosite`;
CREATE TABLE IF NOT EXISTS `utilisateurs` (
    `idutilisateur` int(11) NOT NULL AUTO_INCREMENT,
    `login` varchar(50) NOT NULL,
    `passwd` varchar(100) NOT NULL,
PRIMARY KEY (`idutilisateur`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Bien évidemment, nous devons toucher les fichiers de configuration Zend pour pouvoir nous connecter à la base de donnée :

; Base de donnée
resources.db.adapter = PDO_MYSQL
resources.db.params.charset = UTF8
resources.db.params.host = localhost
resources.db.params.username = root
resources.db.params.password = passwd
resources.db.params.dbname = tutosite
resources.db.isDefaultTableAdapter = true

Voilà, maintenant que la connexion à la base de données fonctionne, voici les étapes à rajouter dans l’indexController->indexAction() pour s’identifier. J’ai commenté chaque ligne afin que vous ayez directement les explications :

if($this->_request->isPost())
{
    //on récupère le login
    $username = $this->_request->getPost('login');
    //on récupère le password  
    $password = $this->_request->getPost('password'); 

    if (empty($username)) 
    {
        $this->view->message = 'Veuillez saisir un identifiant';
    } 
    else
    {
        //on récupère la connexion à la base de donnée
        $dbAdapter = Zend_Db_Table::getDefaultAdapter();
        //récupération de l'adaptateur dbAdapter 
        $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
        //on indique le nom de la table 
        $authAdapter->setTableName('utilisateurs'); 
        //on indique la colonne du login 
        $authAdapter->setIdentityColumn('login');
        //on indique la colonne du mot de passe 
        $authAdapter->setCredentialColumn('passwd');
        //on dit que les mots de passes sont hashés en MD5
        $authAdapter->setCredentialTreatment('MD5(?)'); 

        //ajout des données du formulaire pour l'authentification
        $authAdapter->setIdentity($username);
        $authAdapter->setCredential($password);

        //lancement de l'authentification
        $auth = Zend_Auth::getInstance()->setStorage(new Zend_Auth_Storage_Session('admin'));
        $result = $auth->authenticate($authAdapter);

        if ($result->isValid()) 
        {
            //succès: on stoque dans un objet sessions toutes les infos de la ligne
            //de la table sauf le mot de passe pour des raisons de sécurité.
            $data = $authAdapter->getResultRowObject(null, 'password');
            $auth->getStorage()->write($data);
            //on redirige vers notre page admin
            $this->_redirect('/admin/accueil');
        } 
        else 
        {
            //failure: clear database row from session
            $this->view->message = "Echec de l'identification";
        } 
    }
}

Avant de tester ceci, sachez que nous allons être redirigés vers un nouveau contrôleur du module admin. Pour éviter à quelqu’un de non authentifié d’accéder à ce contrôleur, j’initialise la fonction preDispatch() qui permet d’effectuer des réglages avant la fin de l’initialisation du contrôleur.
/application/modules/admin/controllers/AccueilController.php :

class Admin_AccueilController extends Zend_Controller_Action 
{ 
    public function preDispatch()
    {
        $auth = Zend_Auth::getInstance()->setStorage(new Zend_Auth_Storage_Session('admin'));

        if (!$auth->hasIdentity()) {
            $this->_redirect('/admin/index');
        }
    }

    /**
     * The default action - show the home page
     */
    public function indexAction() 
    {
        $this->view->title = "Partie Administration - Accueil";
    }
}

/application/modules/admin/views/scripts/accueil/index.phtml

Partie Admin, vous êtes authentifiés.</code> Maintenant votre authentification est optionnelle. 

Pour vous déconnecter, il suffit de faire un lien vers l’action déconnexion de l’IndexController par exemple et qui serait comme ceci :

public function logoutAction()
{
    Zend_Auth::getInstance()->setStorage(new Zend_Auth_Storage_Session('admin'))->clearIdentity();
    $this->_redirect('/admin/index');
}

Pour éviter de tomber sur le formulaire d’identification, vous pouvez rajouter ceci autour de toutes les lignes de codes d’indexAction() afin d’arriver directement sur l’accueil admin :

$ident = Zend_Auth::getInstance()->setStorage(new Zend_Auth_Storage_Session('admin'))->getIdentity(); 
if($ident){
    $this->_redirect('/admin/accueil');
}else{
    //code authentification
}
Pour les mots de passe créez une page php de base avec juste un echo md5(‘motdepasse’) ; et après insérez votre nouvel utilisateur avec, comme mot de passe, celui qui vient d’être généré.

Voilà. Maintenant vous pouvez vous authentifier et rajouter d’autres utilisateurs à votre base de données. La prochaine fois, nous verrons les classes métiers et table_abstract pour ajouter nos premiers articles.