Home PHP Ezpublish script en ligne de commande

Ezpublish script en ligne de commande

  Eric B. Ingénieur Développeur 5 min 20 janvier 2014

On ne le soupçonne pas forcément, mais eZpublish dispose d’outils forts utiles pour développer des scripts PHP en ligne de commande. Ces outils permettent de « charger un environnement », de passer  facilement des paramètres au code et de communiquer avec la console de ligne de commande.

Ces outils sont principalement eZScript et eZCLI.  eZScript s’occupera principalement du contexte des scripts et eZCLI s’occupera de l’affichage des informations vers la console. Cependant si le script n’est lancé que via l’utilisation d’un cron, il faudra privilégier eZLOG qui sera plus approprié qu’ eZCLI.

 

Pourquoi eZ Publish en ligne de Commande ?

L’intérêt d’utiliser eZ Publish via une ligne de commande réside principalement dans « le travail de masse »,  comme par exemple l’import et l’export de données, l’envoi massif de mail, une mise à jour de données ou tout autre travail nécessitant un temps d’exécution assez long. Dans une configuration basique lorsque PHP est lancé en « CLI »(via une ligne de commande) il s’exécute jusqu’à la fin du script sans contrainte de temps, ce qui n’est pas le cas lorsqu’il s’exécute en HTTP (via un navigateur web).  L’autre avantage est qu’en mode « CLI » on ne générera pas de HTML, donc toutes les « ressources » servent principalement au traitement du script,  permettant ainsi un gain en terme de performance.

 

Notre exercice :

Pour mettre en pratique nous allons créer un script pour régénérer en masse les mots de passe des utilisateurs du site. Le script devra prendre en compte plusieurs paramètres :

  • Le type de contenu de l’utilisateur
  • Le mode de régénération du mot de passe (Le même pour tout le monde ou différent pour tous)
  • Le script récapitulera les paramètres et affichera le nombre d’utilisateurs qui vont être modifiés
  • Le script attendra la validation de l’utilisateur (entrée clavier) pour lancer la procédure.
  • Le script enverra un mail à l’utilisateur pour lui donner le nouveau mot de passe.

Ce script peut s’avérer utile si une faille de sécurité est survenue et que par mesure de précaution on désire réinitialiser les mots de passes des utilisateurs. Il peut aussi s’avérer utile lorsque l’on récupère les données d’une base pour la connecter à son environnement de développement et disposer de compte utilisateur dont on connaît les mots de passe.

 

Conventions :

Par convention on place ces scripts dans le répertoire d’une de ses extensions eZ Publish( /bin/php/ étant préconisé). Pour l’exercice nous appellerons le script resetpassword.php.

 

Création du script :

En premier lieu on charge l’autoload ezpublish, cela nous permettra de disposer de toutes les classes déclarées dans ezpublish.

require 'autoload.php';

 

On initialise par la suite notre objet eZCLI, sans oublier de préciser que l’on utilisera les styles de couleur.

//Instanciate the cli object
$cli = eZCLI::instance();
//To have a colorized output
$cli->setUseStyles(true);

 

Maintenant que nous pouvons afficher efficacement des informations, nous devons instancier l’environnement de script pour bénéficier correctement des fonctionnalités d’eZ Publish et disposer  d’un outil de script pratique. Dans les fonctions intéressantes il y a l’arrêt propre du script et la possibilité de passer facilement des options.

$script = eZScript::instance( array( 'description' => ( "WEBNET reset password script\n"),
                                     'use-session' => false,
                                     'use-modules' => true,
                                     'use-extensions' => true ) );

 

Comme on peut le voir c’est le tableau d’arguments qui permet de spécifier son environnement, ici on utilise les modules et les extensions mais pas les sessions. On pourrait aussi spécifier un siteacces ou bien même un user.

Pour notre script nous aurons besoin de passer des paramètres (mot de passe générique, classe du user etc.), rien de plus simple, il suffit de les déclarer et même petit bonus, on peut ajouter un texte d’aide.

// Options processing
$options = $script->getOptions(
    '[password:][classes_identifier:][same_password:]',
    '',
    array(
        'password'                      => 'New password to set to user, default is webnet',
        'classes_identifier'            => 'User classes to reset, default is licencie',
        'same_password'                 => 'To create a new password for account(value != 1) or to give the same password for all account(value = 1). By default value is 1',
    )
);

 

Dans notre cas nous déclarons dans les arguments de la méthode :

  • Premier argument : la liste des options (password, class_identifier, same_password)
  • Deuxième argument : Inutile dans notre cas
  • Troisième argument : La liste des textes pour l’aide (lorsque l’on lance le script avec l’option -h).

Une fois cette partie réalisée il faut initialiser le script puis écrire notre code (pour notre part nous préconisons l’utilisation d’un  try catch). L’exercice étant axé sur l’utilisation de l’objet eZCLI et de l’objet  eZscript nous ne détaillerons que le code qui leur est « liés ».

Par sécurité nous allons demander à l’utilisateur de vérifier ses options et de confirmer le lancement du code. C’est là qu’intervient l’objet « CLI ». Il va nous permettre d’afficher efficacement et en couleur des informations à l’écran.

L’objet « CLI » dispose de quatre méthodes d’affichage d’informations, trois sont des affichages préformatés (notice, warning, error), le quatrième (output), quant à lui, permet l’affichage personnalisé.

  • Notice affiche le texte en blanc
  • Warning affiche le texte en jaune
  • Error affiche le texte en rouge
  • Output vous permet de mettre votre propre formatage.

Comme tout le monde ne connaît pas de tête le formatage « ligne de commande », on peut utiliser  les 51 styles préconçus de l’objet eZCLI grâce à la méthode stylize (à laquelle on passe le texte et le style désiré). On peut ainsi afficher facilement des textes en rouge, vert, bleu, jaune.
Il faut aussi savoir que les méthodes notice, warning, error, et output « effectue » par défaut un retour à la ligne  (mais ce comportement peut être modifié).

    //Mon texte avec retour à la ligne
    $cli->output($cli->stylize('green', 'mon texte avec retour à la ligne' ));
    //Mon texte sans retour à la ligne (false en deuxième argument)
    $cli->output($cli->stylize('green', 'Mon texte sans retour à la ligne' ), false);

 

On peut dans tous les cas utiliser des tabulations(\t) et ajouter des retours à la lignes (ex :\r\n mais il faire attention au système d’exploitation).

Dans notre exemple nous utiliserons un texte blanc sur fond vert, un texte vert et un texte bleu

    $cli->output($cli->stylize('green-bg', '=================================' ));
    $cli->output($cli->stylize('green-bg', '   Parameters and configuration   ' ));
    $cli->output($cli->stylize('green-bg', '=================================' ));
    $cli->output($cli->stylize('green',"New password\t : " . $password));
    $cli->output($cli->stylize('green',"Same password\t : " . $same_password));
    $cli->output($cli->stylize('green',"User classes\t : " . $identifier));
    $cli->output($cli->stylize('green',"user count\t : " . $count));
    $cli->output($cli->stylize('green-bg', '================================='));
    $cli->output($cli->stylize('cyan', "\n" . 'Check parameters before launch the script.' ));
    $cli->output($cli->stylize('green', "\n" . 'Continue [Y/n] ?'));
    $choix = trim(fgets(STDIN));
    if($choix != "Y") {
        $cli->error('Script abort.');
    }

ce qui donnera :

Ezpublish Capture 1

 

Pour la confirmation nous utiliserons la fonction fgets qui « attendra/écoutera » la saisie de l’utilisateur. Ici seule la saisie de Y majuscule permet le lancement du script. Le reste du code est du PHP des plus simples.

Pour rendre le script et son affichage plus vivant, nous afficherons son évolution en précisant quel est l’utilisateur en cours de modification ainsi que le nombre d’utilisateurs déjà modifiés.

Sans instruction spécifique, les informations s’afficheront les unes derrières les autres, faisant ainsi défiler l’écran de la console et rendant la lecture difficile. Pour pallier à cela il nous faut utiliser les fonctions storePosition et restorePosition de l’objet eZCLI qui vont nous permettre d’afficher les informations sur une même ligne.

$pos_store =  $cli->storePosition();
$pos_restore =  $cli->restorePosition();
…
...
$cli->output( $pos_store . $cli->stylize('green', 'New password for ' . $user->Login . " \t" . $i . "/" . $count) . $pos_restore, false);

La dernière touche reste l’arrêt du script lorsque le traitement est fini.

$script->shutdown();

 

Voilà vous avez désormais les bases pour utiliser les objets eZCLI et eZScript et lancer des scripts en ligne de commande dans eZpublish. A savoir qu’il existe aussi un objet  ezcConsoleProgressbar qui permet l’affichage comme son nom l’indique d’une barre de progression dans la console de commande.

 

Lancer le script :

Maintenant que nous avons le code voyons comment l’exécuter. Il suffit tout simplement de se mettre à la racine du site et de lancer le script : php extension/[mon_module]/bin/php/monscript.php

 

Pour notre exercice

Même mot de passe :

php extension/[mon_module]/bin/php/resetpassword.php --password=nouveaumotdepass --classes_identifier=my_user_class

 

Mot de passe différent :

php extension/[mon_module]/bin/php/resetpassword.php --same_password=0 --classes_identifier=my_user_class

 

Le script ayant des valeurs par défaut les options ne sont pas obligatoires. On peut imaginer aisément une variante du script utilisant un fichier de configuration pour renseigner les « options ».

Si on désire l’aide :

php extension/mon_module/bin/php/monscript.php -help

 

Ezpublish - ecran 2

 

Attention :  si vous lancez le script en étant root il faut ajouter –allow-root-user

Si vous avez lancé l’aide, vous verrez que l’on peut passer diverses options, notamment le siteacces qui permet de ne charger que la configuration d’un site.  Les autres options restant très contextuelles vous n’aurez à les utiliser qu’en de rares occasions, méfiez-vous de l’option –quiet qui bloque les affichages de eZCLI et –no-colors peut être pratique dans un environnement Windows qui n’interprète pas les couleurs dans la console de ligne de commande.

Il ne vous reste plus qu’à faire votre propre expérience.

Sécurité :

Pour éviter tout lancement intempestif de ce script, faites en sorte qu’il ne puisse être lancé que par un utilisateur « spécifique » ou rajouter la saisie obligatoire du login et mot de passe d’un utilisateur ezpublish pour lancer le script.

Exemple :

$cli->notice('Saisir l\'identifiant et le mot de passe d\'un utilisateur ');
$cli->notice('login');
$login = trim(fgets(STDIN));
$cli->notice('password');
$password = trim(fgets(STDIN));

$script = eZScript::instance( array( 'description' => ( "WEBNET reset password script\n"),
                                     'use-session' => false,
                                     'use-modules' => true,
                                     'user' => array('login'=> $login, 'password'=> $password),
                                     'use-extensions' => true ) );

.. Puis vérifier que le log est ok

Si vous avez beaucoup d’utilisateurs, faites attention à ne pas saturer votre serveur mail.

 

Script :

<?php
/**
 * @file
 * @author EB webnet
 * script to reset password of users
 */

require 'autoload.php';
//Instanciate the cli object
$cli = eZCLI::instance();
//To have a colorized output
$cli->setUseStyles(true);
//Instanciate the script objet with define environnement
$script = eZScript::instance(array('description' => ( "WEBNET reset password script\n"),
            'use-session' => false,
            'use-modules' => true,
            'use-extensions' => true));
//Start the script
$script->startup();

// Options processing
$options = $script->getOptions(
        '[password:][classes_identifier:][same_password:]', '', array(
    'password' => 'New password to set to user, default is webnet',
    'classes_identifier' => 'User classes to reset, default is licencie',
    'same_password' => 'To create a new password for account(value != 1) or to give the same password for all account(value = 1). By default value is 1',
        )
);
$script->initialize();
$script->setUseDebugAccumulators(true);
try {
    $password = 'UnM0tD1ff1c1le';
    $identifier = 'user';
    $same_password = true;
    if (isset($options['same_password']) && $options['same_password'] != 1) {
        $same_password = false;
    }
    if (!empty($options['password'])) {
        $password = $options['password'];
    }
    if (!empty($options['classes_identifier'])) {
        $identifier = $options['classes_identifier'];
    }
    $db = eZDB::instance();
    $value = $db->escapeString($identifier);
    /**
     * request to retrieve id.
     * Note we exclude anymous
     */
    $sql = "SELECT  DISTINCT  ezo.id
    FROM ezcontentobject AS ezo
    INNER JOIN ezcontentclass AS ezc ON ezc.id = ezo.contentclass_id
    INNER JOIN ezcontentobject_tree AS ezt ON ezt.contentobject_id = ezo.id AND ezt.contentobject_version = ezo.current_version
    WHERE ezc.identifier = '$value' AND ezo.id != 10;";
    $rows = $db->arrayQuery($sql);
    $count = count($rows);

    if($same_password){
        $same_password_text ='Yes';
        $password_add ='';
    }else{
        $same_password_text = 'No';
        $password_add =' (unused for this instance)';
    }
    /**
     * Display parameters
     */
    $cli->output($cli->stylize('green-bg', '================================='));
    $cli->output($cli->stylize('green-bg', '   Parameters and configuration   '));
    $cli->output($cli->stylize('green-bg', '================================='));
    $cli->output($cli->stylize('green', "New password\t : " . $password . $password_add));
    $cli->output($cli->stylize('green', "Same password\t : " . $same_password_text));
    $cli->output($cli->stylize('green', "User classes\t : " . $identifier));
    $cli->output($cli->stylize('green', "user count\t : " . $count));
    $cli->output($cli->stylize('green-bg', '================================='));
    $cli->output($cli->stylize('cyan', "\n" . 'Check parameters before launch the script.'));
    $cli->output($cli->stylize('green', "\n" . 'Continue [Y/n] ?'));
    /**
     * Wait for confirmation
     */
    $choix = trim(fgets(STDIN));
    /**
     * Only Y could launch script
     */
    if ($choix != "Y") {
        $cli->error('Script abort.');
    } else {
        if ($count > 0) {
            /**
             * To display information in the same line
             */
            $pos_store = $cli->storePosition();
            $pos_restore = $cli->restorePosition();
            for ($i = 0; $i < $count; $i++) {
                /**
                 * Load User
                 */
                $user = eZUser::fetch($rows[$i]['id']);
                if (is_object($user)) {
                    /**
                     * Check if we need to generate a password
                     */
                    if (!$same_password) {
                        $password = eZUser::createPassword(6);
                    }
                    /**
                     * update user
                     */
                    $user->setAttribute( "password_hash", eZUser::createHash( $user->Login, $password, eZUser::site(),
                                                                          eZUser::hashType() ) );
                    $user->setAttribute( "password_hash_type", eZUser::hashType() );
                    /**
                     * save user
                     */
                    $user->store();
                    /**
                     * Send a mail to user
                     * it's just a example, make your own mail
                     */
                    $mail = new eZMail();
                    $mail->setSender( '[email protected]' );
                    //$mail->setReceiver( $user->Email );
                    $mail->setReceiver( '[email protected]' );
                    $mail->setSubject( 'Your password have been regenerated' );
                    $body = "Hello,\n\n";
                    $body .= "Your password have been regenerated.\n\n";
                    $body .= "login : " . $user->Login . "\n";
                    $body .= "password : " . $password . "\n\n";
                    $body .= 'www.mysite.com';
                    $mail->setBody($body);
                    eZMailTransport::send( $mail );
                    /**
                     * Display informations
                     */
                    $cli->output($pos_store . $cli->stylize('green', 'New password for ' . $user->Login . " \t" . $i . "/" . $count) . $pos_restore, false);
                }
            }
        } else {
            /**
             * this exeption launch the shutdown of the script
             */
            throw new Exception('No user found...');
        }
        $cli->notice("\n" . 'Reset password is finish.');
    }
    /**
     * A clean script stop
     */
    $script->shutdown();
} catch (Exception $e) {
    $errCode = $e->getCode();
    $errCode = $errCode != 0 ? $errCode : 1; // If an error has occured, script must terminate with a status other than 0
    $script->shutdown($errCode, $e->getMessage() . "\n" . 'Shutdown sequence initiated..');
}

 

Références :

http://pubsvn.ez.no/doxygen/4.7/html/classeZCLI.html
http://pubsvn.ez.no/doxygen/4.7/html/classeZScript.html

http://www.ezpedia.org/ez/command_line_scripts

Lire les articles similaires

Laisser un commentaire

Social Share Buttons and Icons powered by Ultimatelysocial