PHPSymfony - Blog par un programmeur pour les programmeurs

To content | To menu | To search

Monday, June 13 2011

[Silex] Premiere utilisation du micro-framework PHP 5.3 Silex

Présentation de Silex


Silex est un micro-framework pour PHP 5.3 basé sur les briques de Symfony 2 et de Pimple. Ce framework a été créé dans l'objectif de proposer un système simple permettant de réaliser des applications simples sans avoir à utiliser un framework complexe.
Silex a été créé par Fabien Potencier et Igor Wiedler.

Le projet : Jeudi croissants


Nous allons réaliser un projet que vous devriez aimer (ou pas).
Tous les jeudis, nous avons la coutume suivante : une personne désignée doit ramener les croissants et les pains au chocolat pour tout le monde.
Cette personne change bien évidemment chaque semaine.
Nous allons donc réaliser une application se composant de 3 pages:
 - d'un front permettant de voir qui est la prochaine personne qui doit ramener les croissants
 - d'une page permettant d'augmenter la participation d'un membre
 - d'une page permettant de réduire la participation d'un membre

Cette application n'a pas pour objectif d'être un monstre en matière de sécurité. Il n y aura pas de gestion d'utilisateurs avec des permissions.
Cette coutume est bien évidemment ancrée sous le nom de jeudi croissants (donc pas de Tuesday crescent ou autres ...).

Mise en place du projet et installation de Silex


Commencons par configurer un vhost très simple :


NameVirtualHost *:80
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName jeudi.local
ServerAlias jeudi.local
DocumentRoot /var/www/jeudi/
DirectoryIndex index.php
<Directory /var/www/jeudi>
Options Indexes FollowSymLinks MultiViews
#AllowOverride None
Order allow,deny
allow from all
</Directory>
</VirtualHost>


N'oubliez pas de renseigner jeudi.local dans votre fichier /etc/hosts, d'activer le vhost et de recharger la conf apache.

Pour l'installation de Silex c'est très facile. Il suffit de récupérer le phar et c'est terminé !

cd /var/www/
mkdir jeudi
cd jeudi
wget "http://silex-project.org/get/silex.phar"

Nous aurons besoin du moteur de template Twig pour ce projet.
Twig n'étant pas inclus dans le phar, vous devrez donc le télécharger vous même. Copiez le dans /var/www/jeudi/vendor/twig

Concernant le stockage des données, nous allons utiliser un simple fichier texte data.txt.

cd /var/www/jeudi
mkdir data
touch data/data.txt

Voici un jeu de fixtures pour votre fichier :

gbretou:5
atisset:3
mwolff:3


Assurez vous que le fichier est accessible en écriture.
NB. Il est possible d'utiliser Doctrine 2 avec Silex. Il existe en effet une extension. Cela fera l'objet soit d'une mise à jour de cet article, soit d'un prochain article.

Le code de l'application


On commence donc avec un fichier index.php très basique :

//index.php

<?php
require_once __DIR__.'/silex.phar';
$app = new Silex\Application();
// definitions
$app->run();


Nous allons devoir ajouter un service pour gérer les intéractions avec le fichier. Nous allons donc créer la classe ParticipationService.
Ce service devra être enregistré dans l'application Silex.


//index.php
require_once __DIR__.'/ParticipationService.php';
//...
$app['participation'] = $app->share(function () {
    return new ParticipationService('./data/data.txt');
});

Vous trouverez la classe ParticipationService dans l'archive en pièce jointe.

Afin de pouvoir utiliser Twig, il faudra enregistrer l'extension :

$app->register(new Silex\Extension\TwigExtension(), array(
    'twig.path'       => __DIR__.'/views',
    'twig.class_path' => __DIR__.'/vendor/twig/lib',
));


twig.path doit pointer sur votre dossier contenant les fichiers templates.
twig.class_path doit pointer sur le dossier contenant les classes de Twig.

Nous avons défini que l'application devait se composer de 3 routes :
 - une route pour la visualisation
 - une route pour l'incrémentation
 - une route pour la décrémentation

La visualisation


Nous allons définir la route suivante :

//index.php
$app->get('/', function () use ($app) {
    return $app['twig']->render('index.twig', array(
        'name'           => 'admin',
        'participations' => $app['participation']->getParticipations(),
        'next'           => $app['participation']->getNext(),
        'matrix'         => $app['participation']->getParticipationMatrix(),
    ));
});


Avec ce code, lors de l'accès à la homepage du site, le système traitera le template index.twig dans lequel on injecte plusieurs variables : name, participations, next et matrix. Ces variables sont récupérées par le service ParticipationService.

L'incrémentation et la décrémentation


Voici les routes pour l'incrémentation et la décrémentation :

//index.php
$app->get('/increase/{name}/{count}', function ($name, $count) use ($app) {
    try
    {
        $app['participation']->increaseParticipation($name, $count);
        return $app['twig']->render('update.twig', array(
            'name' => $name,
        ));
    }
    catch (Exception $e)
    {
        return $app['twig']->render('error.twig', array(
            'exception' => $e->getMessage(),
        ));
    }
});

$app->get('/decrease/{name}/{count}', function ($name, $count) use ($app) {
    try
    {
        $app['participation']->decreaseParticipation($name, $count);
        return $app['twig']->render('update.twig', array(
            'name' => $name,
        ));
    }
    catch (Exception $e)
    {
        return $app['twig']->render('error.twig', array(
            'exception' => $e->getMessage(),
        ));
    }
});


Chaque route se compose de parties variables encadrées par des {}. Ces variables sont ensuite récupérées et transférées à la closure manuellement.
Afin d'avoir une application RESTFUL, on pourrait utiliser un put plutôt qu'un get pour les modifications.

Pour vous aider dans vos développements, pensez à activer le mode debug :

$app['debug'] = true;



Edit du 17/06/2011
:
Il est possible de catcher les exceptions mieux que je ne l'ai fait : voir la partie sur les error handlers. Je mettrai le code à jour.

Conclusion


Vous trouverez une archive contenant l'application. N'hésitez pas à me faire part de vos remarques.

J'ai aimé

 - La rapidité et la simplicité : on a une application avec un feedback visuel en quelques secondes
 - La documentation : pour mon utilisation, j'ai trouvé la documentation claire

Je n'ai pas aimé (?)

J'aurais souhaité utiliser des tâches pour mettre à jour les informations de participation. Cependant, d'après ce que j'ai constaté, Silex fournit une console qui ne prend en paramètre que 3 valeurs possibles : check, update et version. Je ne sais pas s'il est possible d'étendre ce système pour définir des tâches personnalisées dans le framework.


Comme l'a souligné scrumasteriswatchingu, si vous avez installé suhosin, vous devez ajouter la directive suivante dans votre php.ini
suhosin.executor.include.whitelist = phar


PS : La coutume Jeudi Croissant a été inventé mwolff ;p

L'application Jeudi croissant est disponible sur bitbucket : https://bitbucket.org/guiguiboy/jeudi-croissant

Edit du 16/03/2012
Le projet a été mis à jour pour utiliser la dernière version de Silex

Tuesday, May 24 2011

[PHP] Durée de vie et expiration des sessions

La gestion de l'expiration des sessions de PHP n'est pas triviale surtout quand on utilise le mécanisme par défaut.

En effet, les informations de sessions sont stockées dans des fichiers sur le serveur. Ces fichiers sont supprimés par une routine (garbage collector) qui détruit les données obsolètes.

Vous devrez jongler entre les 3 paramètres suivants :

 - session.gc_maxlifetime : spécifie une période en secondes pendant laquelle les données sont considérées comme corretes. Une fois cette période passée, les données sont alors considères comme obsolètes et sont susceptibles d'être supprimées par le garbage collector.

- session.gc_probability : à utiliser conjointement avec session.gc_divisor : permet de définir la probabilité que la routine de garbage collection soit lancé à chaque requête

- session.gc_divisor : à utiliser conjointement avec session.gc_probability : permet de définir une probabilité que la routine de garbage collection soit lancée à chaque requête

(Ces trois paramètres doivent être définis avant l'appel à session_start() si vous souhaitez modifier leur valeur via votre script)

Avec les valeurs par défaut (session.gc_probability = 1 et session.gc_divisor = 100), vous aurez donc une probabilité de 1% que la routine de garbage collection soit lancée à chaque requête.

Vous serez donc tenter d'ajuster les valeurs des deux derniers paramètres afin de maximiser la probabilité d'exécution de la routine de garbage collection.

Vous devez être conscient que le mécanisme est couteux et si vous avez de multiples sessions ouvertes sur votre site, une fréquence d'exécution trop importante peut entrainer des ralentissements

Tuesday, February 8 2011

[PHP] remplacement de split par preg_split : split2preg_split

Depuis PHP 5.3, la fonction split est devenue obsolète (voir le manuel PHP).

Il convient donc de la remplacer par preg_split, son équivalente plus moderne qui utilise l'extension PCRE.

J'ai donc développé un bout de code qui va permettre de remplacer les appels split par preg_split.

Voici le script : (il affiche sur la sortie standard le fichier converti)


<?php

/****************************************************************************/
/************************ split2preg_split **********************************/
/************************ author : gbretou **********************************/
/****************************************************************************/


$file       = $_SERVER['argv'][1];
$lines      = file($file);
foreach ($lines as $line)
{
        if (preg_match('|(.*)(?<![a-zA-Z0-9-_])(split\(([\'\"\$]{1}(.*)[\'\"]?),(.*)$)|', $line, $matches))
        {
                $pattern = $matches[3];
                $pattern = recalculateRegex($pattern);
                echo $matches[1] . "preg_split(" . $pattern . "," . $matches[5] . " ";
        }
        else
        {
                echo $line;
        }
}

/**
 * Recalculates the regex
 * 2 cases :
 *  - case 1 : a PHP variable is provided for the pattern
 *  - case 2 : a simple string is provided
 */
function recalculateRegex($pattern)
{

        $delimiter = '/';
    if (substr($pattern, 0, 1) == '$')
    {
            return sprintf("'%s' . str_replace('%s', '\%s', %s) . '%s'",
            $delimiter,
            $delimiter,
            $delimiter,
                    $pattern,
            $delimiter
            );
    }
    else
    {
            return sprintf("%s%s%s%s%s",
                    substr($pattern, 0, 1),
                    $delimiter,
                    str_replace($delimiter, "\$delimiter", substr($pattern, 1, -1)),
                    $delimiter,
                    substr($pattern, 0, 1)
            );
    }

}

?>


Pour le lancer sur un fichier PHP, vous pouvez faire :

php split_modifier.php [FICHIER]

ou si vous souhaitez le lancer sur tous les fichiers PHP d'un répertoire :

find . -name '*.php' | xargs php split_modifier.php

Ce programme présente plusieurs limites :

 - si votre split est sur plusieurs lignes, il ne sera pas pris en compte car l'expression régulière ne sera pas matchée

 - le fait d'ajouter un délimiteur ne permet pas de convertir toutes les expressions POSIX en PCRE (exemple)

 - il affiche le résultat sur la sortie standard et ne fait pas de remplacement directement dans le fichier

En fonction des retours que j'aurais, je modifierais le script.

Néanmoins, pour le deuxième point, je vous propose de créer vos propres tests puis de comparer si le retour du fichier avec split est identique que celui avec preg_split. Voici déjà quelques lignes : 


<?php

$delimiter = "/";
var_dump(split('/', "test / test"));
var_dump(split('\|', "test / test")); //this is a comment
var_dump(split('\|', "test | test"));
var_dump(split('/ ', "test / test")); //this is a comment
var_dump(split('[/.-]', '31-12-2010'));
var_dump(split('[/.-]', '31/12/2010'));
var_dump(split("[ \t ]+", "Please cut   \t me in pieces"));
var_dump(split('\|/', 'test /test |/ test / test'));
var_dump(split($delimiter, 'test / test / test / test'));
var_dump(preg_split('|t/t|', 'this another test')); //must not be changed
var_dump(my_split('/', 'this / is / another / test'));

function my_split($pattern, $value) //must not be changed!
{
    return split($pattern, $value);
}

?>


Pour faire une comparaison, je vous propose de suivre le cheminement suivant :

 - mettez vos tests avec split dans le fichier split_test.php

 - remplacez vos split par preg_split dans un fichier preg_split_test.php

 - lancez les deux fichiers puis comparez leur retour via un diff.

(MAJ le 18/02 pour gestion des fonctions)

Wednesday, November 10 2010

[PHP] Slides des conférences du forum PHP 2010

Si comme moi, vous n'avez pas eu la chance d'aller à cet évènement incontournable qu'est le forum PHP, voici au moins les slides pour ne pas tout louper  ;)

Optimisation LAMP :

http://www.slideshare.net/cyruss666/optimisation-lamp

Propel :

http://prezi.com/20zx62inia2y/apprendre-en-persistant-propel-php-forum-2010/

Git :

http://www.slideshare.net/ubermuda/m-5725576

Revue de code :

http://www.slideshare.net/jmf/revues-de-code-forum-php-2010

Développer mieux en PHP avec symfony :

http://www.slideshare.net/hhamon/mieux-dvelopper-en-php-avec-symfony

Les frameworks PHP :

http://www.slideshare.net/xavierlacot/forum-php-2010-les-frameworks-essentiels-danslecosystemephpxavierlacotbastienjaillotcleverage

Le SEO pour les développeurs :

http://s.billard.free.fr/referencement/?2010/11/10/623-le-seo-pour-les-developpeurs

PHP et Windwos :

http://www.slideshare.net/LeTesteur/php-forum-2010-php-et-microsoft

Zend framework 2 :

http://www.slideshare.net/mikaelkael/zf2-cequivachanger

Xdebug :

http://derickrethans.nl/talks/xdebug-afup10.pdf

Friday, November 5 2010

[PHP] Yet Another Password generation class

Voici une classe de génération de mots de passe que j'utilise.

Cette classe, sans grande prétention, permet juste de générer un mot de passe en spécifiant 5 paramètres :

  • un nombre de minuscules
  • un nombre de majuscules
  • un nombre de caractères numériques
  • un nombre de caractères spéciaux
  • un nombre de caractère total

Une vérification est faite sur le nombre de caractères maximum, c'est-à-dire que la somme des quatre premiers paramètres ne doit pas être supérieur au dernier.

Bien évidemment, si la somme des quatre premiers paramètres est inférieure au dernier paramètre, la classe va alors remplir aléatoirement le reste.


J'ai inclus des exemples en fin de fichier.


La classe est en annexe.

Edit du 25/05

Suite à une remarque pertinente, j'ai réduit la plage des caractères spéciaux disponibles.

Thursday, September 23 2010

[symfony] Supprimer le timeout sur les sessions symfony 1.3 et 1.4

Pour supprimer (ou changer) le timeout sur les sessions, vous devez éditer le fichier factories.yml de votre application avec le code suivant :

all:
  user:
    param:
      timeout:   false # Session lifetime in seconds





Friday, September 10 2010

[PHP] Installation extension Xdebug PHP 5.3 sur Debian Lenny

Xdebug est une extension PHP qui permet de facilement debugger ses scripts PHP en vous donnant de nombreuses informations utiles.
Parmi ces informations utiles, on retrouve

Pour l'installation, vous avez deux options.

La première : avec pecl


pecl install xdebug

Pour ma part, cela n'a pas fonctionné car ma version de zend engine était trop récente (lien vers un problème similaire). Du coup, je l'ai compilé à la main.

La deuxième : à la main


Dans un premier temps, téléchargez l'archive puis récupérez son contenu

wget http://xdebug.org/files/xdebug-2.1.0.tgz
tar -xvzf xdebug-2.1.0.tgz

Ensuite, on va compiler le module xdebug

cd xdebug-2.1.0
phpize

Si la commande phpize n'existe pas, c'est qu'il vous manque un paquet. Lancez cette commande pour le récupérer :

aptitude install php5-dev

Puis exécutez

./configure
make



Si, encore une fois make n'est pas une commande disponible, il vous faut récupérer un autre paquet :

aptitude install build-essential

Copiez ensuite le module (qui se trouve dans le répertoire module) avec vos autres modules. Pour trouver ce répertoire, exécuter la commande suivante :

php -i | grep 'extension_dir'


Pour finir, éditez votre fichier de configuration php.ini

vim /etc/php5/apache2/php.ini

Pour ajouter la ligne suivante :

zend_extension = /path/to/your/extension/directory/xdebug.so

Redémarrez votre serveur HTTP

/etc/init.d/apache2 restart

Pour tester, lancez un phpinfo().

Saturday, August 21 2010

[PHP] Désactivation et remplacement des short tags PHP

La syntaxe des short tags <?= ?> et <? ?> peuvent sembler plus rapide à saisir dans un premier temps mais celle-ci comporte des inconvénients :

Tout d'abord, le fait d'utiliser des balises PHP longues <?php ?> vous assurent une portabilité de votre application sur tous les serveurs, y compris ceux sur lesquels vous n'avez pas la main sur la configuration (je pense par exemple aux serveurs mutualisés).

Ensuite parce qu'il y a confusion possible avec la balise xml :

<?xml version="1.0" encoding="utf-8" standalone="yes"?>

Enfin, les short tags seront obsolètes en PHP 6.

Donc, une bonne pratique de programmation est de désactiver leur utilisation. Pour cela, direction le php.ini et trouvez la ligne :

short_open_tag = On

Remplacer On par Off.

Maintenant que vous avez changé votre configuration, il vous faut remplacer les short tags par leur équivalent dans votre code. Ainsi :

<? devient <?php

et

<?= devient <?php echo

Pour le remplacement, ca se passe sur le blog de Geoffrey.

Monday, July 19 2010

[PHP] Erreur date() sur PHP 5.3

Après un passage à PHP 5.3, vous aurez probablement le message d'erreur suivant :

PHP Warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. [...]

Comme le message le précise, il faut définir le paramètre date.timezone dans votre php.ini. Voici la liste des fuseaux horaires supportés : http://php.net/manual/fr/timezones.php.

Vous pouvez également utiliser la fonction date_default_timezone_set.

Notez que le paramètre date.timezone doit être setté pour Symfony2.

[PHP] Mise à jour php vers 5.3 sur Debian Lenny

Comme vous le savez, Symfony 2 nécessitera au moins PHP 5.3.2 pour tourner.
Voici comment mettre à jour votre PHP :

ATTENTION - certaines fonctions PHP sont devenues obsolètes. Vous devez vous assurez que la mise à jour de posera pas de problème surtout si vous mettez à jour un serveur de production.

Ajoutez ces deux lignes dans votre fichier /etc/apt/sources.list deb

deb http://php53.dotdeb.org lenny all
deb-src http://php53.dotdeb.org lenny all

Lancez ensuite les commandes :
wget http://www.dotdeb.org/dotdeb.gpg
cat dotdeb.gpg | sudo apt-key add -
Puis, lancez la commande

sudo apt-get update

Puis

sudo apt-get install php5

Pour vérifier, lancez la commande :

php -v

Source : http://www.dotdeb.org/instructions/