Aller au contenu | Aller au menu

grab our rss feed

[phpsymfony.com] - Blog par un programmeur pour les programmeurs

Blog de Guillaume BRETOU. Recense les trucs et astuces en programmation et autres codes en PHP, javascript, java, CSS, SQL, Bash...

[PHP] Spécifier une connexion en utf-8 avec Doctrine DBAL

Lorsque vous utilisez Doctrine DBAL (sur un projet Silex par exemple), voici comment spécifier l'encodage de la base de données.

Ajoutez une classe étendue de DoctrineServiceProvider et surchargez la méthode register(). Vous devrez utiliser le système d'event.

Exemple pour une base de données Mysql



use Silex\Application;
use Doctrine\DBAL\Event\Listeners\MysqlSessionInit;

class DoctrineServiceProvider extends \Silex\Provider\DoctrineServiceProvider
{
  public function register(Application $app)
  {
      parent::register($app);
      $app['db.event_manager']->addEventSubscriber(new MysqlSessionInit('utf8','utf8_unicode_ci'));
  }
}

Notez qu'avec le système d'event, vous pourrez réaliser d'autres actions telles que la mise en place de Behaviors.

[Java] Débuter avec le développement Android

Ayant reçu un Samsung GALAXY S II (en remplacement de mon HTC Touch HD qui a rendu l’âme), j'ai tout de suite accroché au système des applications disponibles sur l'Android Market. Pour aller plus loin que la simple utilisation, J'ai voulu regarder comment créer une application sous Android.

Comme le veux la coutume, impossible de passer à coté de l'éternel "Hello World" quand on débute avec une nouvelle technologie. Voici les différentes étapes que j'ai suivi pour faire fonctionner mon application sous Windows : 

Installation

Tout d'abord, vous devez vous assurer d'avoir le JDK. Vous pourrez le télécharger ici : http://www.oracle.com/technetwork/java/javase/downloads/index.html

Sélectionnez la version qui correspond à votre OS.

Ensuite, vous devrez télécharger le SDK Android ici : http://developer.android.com/sdk/index.html

Pour simplifier l'utilisation du SDK en ligne de commande, nous allons renseigner le chemin vers le répertoire tools du SDK dans le PATH. Sous Windows 7, démarrer > rechercher "paramètres systèmes avancés". Cliquer sur le bouton "Variables d'environnement". Puis, dans la variables système, changer la valeur de la variable PATH pour y ajouter le path vers le dossier tools du SDK.

Configuration

Dans notre cas, nous considérerons l'utilisation de l'IDE Eclipse. Pour installer les plugins nécessaire, il faut suivre la documentation ici : http://developer.android.com/sdk/eclipse-adt.html#downloading

Notre environnement est désormais prêt et nous allons pouvoir créer l'application;

Commencez par créer un nouveau projet Android dans eclipse. Un Clic droit dans le package explorer puis sélectionnez "New" puis "Project ...".

Sélectionnez "Android Project" puis Next.

Choisissez un nom au projet, nous l'appellerons "HelloAndroid". Pour le reste de cet écran, le paramétrage par défaut est suffisant. Cliquez sur "Next".

Choisissez ensuite le SDK Android dans la liste. On prendra pour cet example la version 2.3.3. Cliquez ensuite sur "Next".

Enfin, choisissez un nom pour le package "HelloWorldAndroid" puis "Finish"

Dans le dernier écran, vous devrez remplir les champs :

  1. Application name : nom de l'application. Dans notre exemple nous utiliserons "Hello Android"
  2. Pckage name : il s'agit du namespace du package. Dans notre exemple, nous utiliserons "com.example.helloandroid". Veuillez à bien respecter les règles de nommage de package java. Sinon, vous pourrez rencontrer l'erreur "Aplication package XXX must have a minimum of 2 segments"
  3. Create Activity : laissez cette case cochée. Cela va permettre la génération d'une classe étendue de Activity sur laquelle nous allons travailler.

Cliquez sur "Finish".

Le système va ensuite générer le projet.

Dans src/com.example.helloandroid/HelloAndroid.java remplacez le code par  :

package com.example.helloandroid;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class HelloAndroid extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView tv = new TextView(this);
        tv.setText("Hello, Android");
        setContentView(tv);

    }
}

Astuce : sous eclipse, vous pouvez faire Ctrl Shift O pour importer les packages manquants.

Comme vous vous en doutez, l'idée est d'afficher "Hello, Android" sur l'écran.

Nous allons maintenant tester notre développement. Pour cela, nous allons utiliser un AVD.

Créer un AVD

AVD (pour Android Virtual Device) est un émulateur qui vous permet de choisir un type d'appareil compatible et de le configurer afin de tester votre application.
Nous allons donc créer un AVD pour vérifier que notre application fonctionne bien.

Pour créer un AVD, il faut commencer par installer de nouveaux packages.
Lancer l'utilitaire "SDK Manager" en tant qu'administrateur.
Puis cocher les packages correspondant aux différentes versions que vous souhaitez installer. Veuillez à bien sélectionner le SDK Android 2.3.3 car c'est celui ci que nous utiliserons pour tester notre application Hello world.

Cliquez ensuite sur "Install"
Notez l'emplacement du téléchargement.

Il faudra ensuite enregistrer le bon path pour les SDK dans eclipse. Pour cela, dans eclipse, allez dans Window > Preference > Android.

Hebergement gratuit d'image et photo


Ensuite, cliquez sur Window > AVD Manager
Cliquez sur "New ...". Le système affiche une nouvelle fenêtre vous permettant de configurer votre AVD
  1. name (obligatoire) : nom de l'AVD.
  2. target (obligatoire) : version du SDK d'android. Sélectionnez 2.3.3

Pour le reste, le paramétrage par défaut est suffisant.


Tester l'application


Tester l'application est très simple. Sous eclipse, cliquez sur le projet à tester, puis Run > Run.
Sélectionnez "Android application"
Sélectionner une source de capture pour la vidéo, puis OK.

Le système va lancer le programme dans l'émulateur. Un peu de patience, cela peut prendre du temps...

Vous obtenez alors le tant attendu "Hello, Android" !

Hebergement gratuit d'image et photo


Sources :
http://ydisanto.developpez.com/tutoriels/android/debuter/
http://developer.android.com/resources/tutorials/hello-world.html

[Mysql] Mise à jour d'un mot de passe root de mysql oublié

Vous avez oublié le mot de passe root de mysql ? Pas de problème, il existe une solution pour cela.

Commencez par couper votre serveur mysql :

/etc/init.d/mysqld stop

Lancez la commande suivante :

/usr/bin/mysqld_safe --skip-grant-tables &


Cela permettra de lancer le serveur en arrière plan. L'option --skip-grant-tables vous permet de passer outre l'authentification.
Attention : vous ne pourrez toutefois pas créer d'utilisateur, ni modifier de droits dans ce mode.

Connectez vous en tant que root :

mysql -uroot mysql

mysql> update user SET Password=PASSWORD('MyNewPassword') Where User='root';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> exit;
Bye

Vous pouvez maintenant killer le processus lancé en arrière plan. Puis, relancez votre serveur mysql :

/etc/init.d/mysqld start

Vérifiez que votre identifiant a bien été pris en compte :

mysql -uroot -pMyNewPassword

C'est terminé !

[sf2] Symfony 2 : c'est parti !

C'est annoncé sur le blog officiel de Symfony : la release stable 2.0 est sortie ce jour.

A cette occasion, plusieurs "launch parties" sont prévues pour permettre aux développeurs de se réunir pour fêter cet évènement.

Vous trouverez la liste des évènements ici.

Pour ma part, ayant déjà joué un peu avec la béta, je vais préparer un nouveau projet et je posterai différents articles sur son utilisation.

[Bash] Remplacement de caractères de retour à la ligne par des espaces

Supposons que vous ayez la liste suivante :

gbretou@gunix:~$ cat test.txt
aaa
bbb
ccc
ddd

Et que vous voulez un résultat sur une ligne, vous pouvez utiliser tr pour convertir vos sauts de ligne en espace simple.

gbretou@gunix:~$ cat test.txt | tr '\n' ' '
aaa bbb ccc ddd ati@gm21:~$

Si vous avez un svn st long comme le bras et que vous commitez en ligne de commande :

svn st | sed 's/^[AM]//g' | tr '\n' ' ' | xargs svn ci -m'My super fun commit message'

Si vous voulez éviter des fichiers, pensez au grep -v après le svn st ;)

[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

[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

[VI] Permissions root lors de l'édition d'un fichier verrouillé en écriture

Combien de fois, en éditant vos fichiers php.ini par exemple, avez-vous eu ce message  "Alerte: Modification d'un fichier en lecture seule"

Voici la solution : 

:w !sudo tee %

Avec cette commande, vous n'aurez plus besoin de quitter vi pour le relancer en root juste après.

[Linux] Utilisation courante de tar

tar est un utilitaire d'archivage permettant de stocker et d'extraire des fichiers d'une archive.

Voici des cas d'utilisation de cet utilitaire que vous serez amenés à rencontrer le plus souvent dans votre (belle) vie de programmeur :


Création d'archive à partir d'un répertoire :

tar -cvf archive.tar %DIR%

Création d'archive gz à partir d'un répertoire :

tar -cvzf archive.tar.gz %DIR%

Création d'archive bzip2 à partir d'un répertoire :

tar -cvjf archive.tar.bz %DIR%


Extraction du contenu d'une archive dans le répertoire courant :

tar -xvf archive.tar

Extraction du fichier test.txt contenu dans une archive dans le répertoire courant :

tar -xvf archive.tar test.txt

Extraction du contenu d'une archive gzippée dans le dossier %DIR% : 

tar -xvzf archive.tar.gz -C %DIR%

Extraction du contenu d'une archive bzip2 dans le répertoire courant : 

tar -xvjf archive.tar.bz


Pour tous renseignements supplémentaires : man tar est votre ami.

[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] . "\n";
        }
        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("[\n\r\t ]+", "Please cut   \t me \n 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)

[Apache] Module mod_pagespeed

Depuis l'année dernière, la vitesse de chargement d'une page est devenue un critère pris en compte dans l'algorithme de classement de Google. Il est donc utile, pour le bien de son pagerank, et pour le bien de ses utilisateurs de travailler sur ce critère.

Il existe de nombreux axes permettant de réduire le temps de chargement des pages :

  • Quantité de données sur une page,
  • Complexité algorithmique,
  • Compression des données,
  • ...

Pour ma part, je me suis interessé au module mod_pagespeed pour Apache 2. Il s'agit d'un module développé par Google.

Ce module va permettre d'optimiser les pages web et les ressources qu'elles comportent. Ceci est réalisé par la réécriture des ressources par des filtres qui implémentent les meilleurs pratiques du développement web. mod_pagespeed inclut de multiples filtres qui optimisent les feuilles de style CSS, le javascript et le HTML. Il inclut également des filtres pour l'optimisation des images JPEG et PNG.

Les filtres possibles sont :

  • Concaténation de fichiers CSS
  • Optimisation des images (mise à l'échelle, recompression)
  • Minification du javascript
  • ...

Une liste exhaustive peut-être trouvée sur ici.

Installation (sur Debian) :

 wget https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-beta_current_i386.deb
 sudo dpkg -i mod-pagespeed-beta_current_i386.deb
 sudo /etc/init.d/apache2 restart

Pour le moment, je n'ai testé ce module qu'avec un petit site. Je vais voir les résultats et posterai un retour d'expérience après avoir testé sur un site plus conséquent.

Lien vers le site officiel du projet.

[python] Spécial Noel : Tirage "aléatoire" d'une liste de cadeau de noel

Article spécial noël !

Voici un script en python qui vous permettra de faire une liste de cadeaux "aléatoire" en fonction d'une liste de participants. Ainsi, vous saurez qui va offrir un cadeau à qui.

Vous précisez en entrée les participants.

L'algorithme utilisé par ce programme n'est pas efficace dans la mesure où il mélange les tableaux (offreurs et receveurs) puis vérifie que l'ensemble est une solution du système.

Néanmoins, les résultats sont rapides pour 7 participants.

import random
senders   = ['AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF', 'GGG']
receivers = senders[:]

complete = False
while complete == False:
       random.shuffle(receivers)
       complete = True
       for i in range(len(receivers)):
               if receivers[i] == senders[i]:
                       complete = False

for i in range(len(receivers)):
       print senders[i] + " doit offrir un cadeau a " + receivers[i]

C'était par le même occasion un petit défi me permettant de découvrir python, langage que je souhaiterais approfondir par la suite.

[Linux] Mise en place adresse IP statique sur Debian Lenny

Pour mettre en place une adresse IP fixe sur une debian, éditez le fichier /etc/network/interfaces

Exemple :

gbretou@gunix:~$ cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug eth0
#iface eth0 inet dhcp
iface eth0 inet static
        address 192.168.0.177
        netmask 255.255.255.0
        network 192.168.0.0
        broadcast 192.168.0.255
        gateway 192.168.0.254

Pour configurer les DNS, vous devrez éditer le fichier /etc/resolv.conf

Exemple :

gbretou@gunix:~$ cat /etc/resolv.conf
nameserver 192.168.1.1

[VirtualBox] Augmentation taille disque dur virtuel VDI avec HD Clone

Lorsque l'on se créé une machine virtuelle avec VirtualBox, il faut associer un disque dur virtuel qui sera attaché à la machine. On lui spécifie une taille à la création et on commence à utiliser sa VM.

Sauf que, plus le temps passe, plus votre disque se remplit, jusqu'au jour où vous vous rendez compte que vous devez augmenter la taille de votre disque dur.

Voici les différentes étapes à suivre pour mener à bien votre mission.

Nous allons procéder en 2 étapes :

 - création d'un nouveau disque de taille supérieure

 - copie du disque principal vers le nouveau disque

(Personnellement, j'ai compté moins d'une heure pour la totalité de l'opération. Cette information est donnée à titre indicatif car de multiples paramètres peuvent intervenir (puissance machine, taille originale, collègue qui vient vous raconter sa vie, ...).

Création d'un nouveau disque dur virtuel

Cliquez sur configuration ->puis stockage

Sélectionnez votre contrôleur, puis Ajouter un nouveau disque dur.

Créez vous un nouveau média avec une taille fixe ou dynamique. Je n'ai pas fais de benchmarks qui permettrait de savoir si un type de disque est mieux qu'un autre. Puis donnez lui une taille supérieure à celle de votre disque dur.

Par défaut, ce disque sera en esclave secondaire.

Montez ensuite l'image de HD Clone. Vous pourrez la télécharger ici. Prenez la version universal package.

Vérifiez enfin l'ordre de boot (ordre d'amorçage en français). Il faut booter sur le lecteur de cd-rom avant le disque dur.

Copie du disque dur principal

Une fois ceci fait, vous pouvez démarrer votre VM.

J'ai pris quelques screenshots pour mieux vous guider durant le processus :

Choisissez Drive -> Drive, puis Next

Sélectionnez le disque source ...

Puis le disque cible

Choisissez des options pour la copie (les options par défaut sont suffisantes)

Vous pourrez ensuite ajuster vos partitions. Si vous souhaitez utiliser la totalité du disque, gardez les valeurs par défaut.

La copie commence dès que vous cliquez sur "Start"

Une fois la copie terminée, choisissez "automatically" lorsque HD Clone vous propose d'ajuster automatiquement des données de partition.

Vous pouvez ensuite éteindre la VM.

Retirez HD Clone du lecteur de CD virtuel.

Retirez l'ancien disque dur (le plus petit) de la liste.

Puis relancez votre VM

Et :

df -h

Et voila, c'est terminé vous avez votre nouveau disque dur.

Pour ma part, j'ai eu des erreurs lors de la copie. Ces erreurs ont toutefois été résolues avec l'utilisation de fsck.

[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

[Linux] Utilisation de screen - screen sheet cheat

Êtes-vous du genre à ouvrir plusieurs fois putty pour travailler sur un même serveur ? Un premier pour lancer des programmes, un deuxième avec un tail -f sur des logs, un troisième pour ...

Si c'est le cas, cet article est fait pour vous. En effet, je parlerais de screen, une commande de Linux, qui va vous faire gagner beaucoup de temps.

Qu'est ce que screen ?

screen est un utilitaire disponible sur linux permettant aux utilisateurs d'accéder à des terminaux différents dans un seul terminal ou via une seule session. Il est très utile lorsque l'on doit lancer de multiples programmes en ligne de commande.

Comment ca marche ?

Pour l'installer, s'il ne l'est pas déjà, il suffit de lancer la commande suivante :

sudo aptitude install screen


Ensuite, vous devrez renseigner un fichier ~/.screenrc

Voici le contenu du screenrc que j'utilise. Si vous en avez des plus pratiques, n'hésitez pas à me les proposer ;)


gbretou@gunix:~$ cat ~/.screenrc
# Supprimer le message de dérrage
startup_message off

# Permettre un retour en arriè plus grand, par déut 100 lignes.
defscrollback 35000

# Afficher une barre bleue, avec en vert le nom de la machine en vert.
# Suivi des screens dont en rouge la fenêe affichéen cours.
# Avec la date et la charge du serveur.
hardstatus on
hardstatus alwayslastline "%{= BG} %{..G}[%H] %{..W}% %-Lw%{.rW}%n+%f %t%{-}%+Lw %=%{..G}[%d/%m/%y %0c] [%l]"
# supprimer le clignotement de l'éan.
vbell off
autodetach on # permettre de se décher en cas de coupure.
nonblock on # Si une fenêe ne rénd pas, ne pas bloquer toute la session en attendant une ré

# On ouvre 3 screens au dérrage de screen
# Le premier sera un terminal spéfique pour l'user root
screen -t root  0 su -
# Le second est un terminal utilisateur de base
screen -t bash1 1 bash
# Le troisiè est aussi un terminal utilisateur de base
screen -t bash2 2 bash


(merci @informathic pour cet exemple de fichier)


Vous pouvez maintenant lancer screen avec la commande éponyme.


Vous verrez alors un terminal avec une barre en bas de page avec plusieurs couleurs. Cette barre contient les différents écrans qui existent pour votre session screen.


Pour naviguer à travers eux vous pouvez faire :


ctrl a puis X où X est le numéro de l'écran auquel vous souhaitez accéder (exemple ctrl a 1 pour accéder à l'écran 1)


Vous pouvez aller à l'écran suivant avec :


ctrl a puis n


Et dans l'autre sens avec :


ctrl a puis p


______________________________


Pour créer un nouvel écran :


screen


ou :


ctrl a puis c


______________________________


Pour fermer un écran (si vous fermez le dernier écran d'une session screen, la session termine automatiquement) :


exit


ou


ctrl a puis k


______________________________


Renommer un écran :


ctrl a puis A


______________________________


Pour scroller dans un écran :


ctrl a puis Echap


______________________________


Splitter un écran en deux régions :


ctrl a puis shift s

______________________________

Supprimer une région d'un split :

ctrl a puis shift x


______________________________


Passer d'un split à l'autre :


ctrl a puis Tab


Un split est comme un écran, vous avez donc accès aux mêmes commandes / combinaisons. C'est très pratique pour du dev !


______________________________


Pour créer une nouvelle session screen en lui donnant un nom :


screen -S "plop"


______________________________


Pour obtenir la liste des différents session screen :


screen -ls


______________________________


Détacher un screen :


screen -d


ou


ctrl a puis d


______________________________


Reprendre un screen :


screen -r (sans option s'il n'en existe qu'un seul ou le nom de la session si il y en a plusieurs)


______________________________


Effectivement, c'est un peu barbare vu comme ca. Mais vous apprendrez à le maitriser et vous rendrez rapidement compte de son caractère incontournable !



[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.

[jQuery] Liste des évènements sur un élément

Grâce à la célèbre extension de Firefox, firebug, vous pouvez voir les évènements qui sont associés à un élément lorsque vous mettez des écouteurs avec jQuery.
Pour se faire, utilisez la commande suivante :

$('#id').data( "events" );

[Vim] Coloration syntaxique sous vim

Si comme moi, vous vous posez la question à chaque réinstallation de Linux, comment activer la coloration syntaxique avec Vim, voici comment faire :

Editer votre fichier ~/.vimrc pour ajouter

syn on

En espérant ne pas oublier la prochaine fois ;)

[Reflexion] Les méfaits de la duplication

Afin de changer un peu de mes articles purement techniques, j'ai décidé d'écrire sur des thèmes plus généraux, qui ne touchent pas uniquement le PHP ou symfony.
Pour cet article, j'ai décidé de me faire une réflexion sur un problème très récurrent dans le développement : la duplication et ses méfaits.

Dans notre travail de tous les jours nous sommes souvent confrontés à ce problème, soit directement, soit indirectement.

Les raisons de la duplication

La duplication de code peut être volontaire ou involontaire.

La duplication volontaire


Il y a forcement des moments dans la vie d'un développeur où l'on se sent obligé de dupliquer. On a l'impression que c'est la seule alternative possible. Ce qui est faux. Si vous tombez devant ce cas, c'est que vous avez fait de mauvais choix : l'architecture de votre composant n'est pas bonne. Une bonne façon d'éviter de rencontrer ce problème est de découpler au maximum vos composants. Voici un exemple :
Vous avez un programme qui doit exécuter consécutivement une tâche A et une tâche B complètement indépendantes. Vous codez alors une fonction qui fait AB sans découpler votre code. Mais alors, que va-t-il se passer si on vous demande de coder un nouveau comportement AC où C est une autre tâche indépendante de A ? Certains développeur vont avoir tendance à vouloir reprendre le code de la fonction AB pour créer votre fonction AC. Or, la, il y a duplication de la fonctionnalité A.

Par ailleurs, il y a des moments où les contraintes de temps sont très fortes sur un projet. Il faut "faire ça le plus rapidement possible". Devant cette contrainte, le développeur est tenté de reprendre du code d'un endroit pour le copier à un autre (l'éternel ctrl c ctrl v). Si au moment du développement on a l'impression d'avoir gagner du temps, lorsqu'il faut se replonger dedans pour débugger ou apporter des évolutions, on se rend vite compte de l'erreur : il faut repasser sur autant de code dupliqué.

Il y a même dans certains cas de la duplication obligatoire. Ce type de duplication est dépendant du langage notamment en C++ où dans un premier temps vous déclarer vos fonctions dans un fichier header, puis vous devez coder la fonction ensuite dans un autre fichier. Ce type de duplication est moins grave car en cas d'oubli de modification la déclaration, vous détecterez une erreur tout de suite car vous aurez une erreur de compilation.

La duplication involontaire

La duplication involontaire se produit suite à des erreurs d'origine humaine.

Il y a effectivement des projets sur lesquels beaucoup de développeurs travaillent en même temps. Si leur domaine d'application n'est pas clairement défini ou si ils travaillent sur des fonctionnalités liées, il y a des risques de créer de la duplication de code. Le meilleure moyen de lutter contre ce type de duplication est de favoriser la communication au sein de l'équipe de développement et de découper au maximum le travail des développeurs afin d'éviter qu'ils ne travaillent sur des .

La duplication peut aussi venir d'une erreur dans l'architecture de l'application. Par exemple, on retrouve ce type de duplication dans le cas d'un modèle de données où il y a des données calculées. J'ai récemment travaillé sur un projet de vente de séjours en ligne où nos produits avaient des disponibilités. Ces disponibilités étaient représentées par une table et on trouvait en colonne :
 - vente_max : correspondant au stock de la disponibilité
 - vente_tmp : correspondant aux ventes en cours
 - vente_actuel : correspondant aux ventes de commandes validées

L'ajout de ces 3 colonnes était une bonne idée : elle permettait d'éviter de faire des requêtes en masse pour vérifier qu'une disponibilité était libre.
En SQL, pour récupérer les disponibilités libres, cela se traduisait par :

... WHERE d.vente_max > d.vente_actuel + d.vente_tmp

Mais cette tranquillité à un coût.

Les problèmes posés

La duplication pose de multiples problèmes. Tout d'abord, au niveau de la maintenance d'une application.

Dans le cas précédent, il faut s'assurer que les colonnes vente_actuel et vente_tmp sont correctement remplies sinon on risque d'avoir des incohérences sur la base de données. Pire, si des stocks sont pris mais jamais libérés en cas d'annulation, on peut arriver à une rupture de stocks qui entraine un maque à gagner. Afin de répondre à cette problématique, on doit mettre un écouteur sur les évènements de création et de suppression.Avec symfony, cela est très simple, il suffit de surcharger les méthodes save() et delete() des objets.

Je prend un autre exemple. Toujours sur ce même projet de vente de séjours en ligne, le client souhaitait ajouter un statut de visibilité sur ses produits (visible uniquement sur le front office, le back office, les deux ou complètement désactivé). Pas de problème, le champ statut existait déjà, il suffisait juste d'ajouter des valeurs dans un enum. je me met à la recherche du code du moteur de recherche.
Puis, je tombe sur le commentaire avec le texte suivant :

/* Si cette requête vient à changer, il faut également modifier la requête du coverflow et des incontournables */

Le développeur ayant codé ceci ne travaille plus ce projet. Heureusement.
Bien évidemment, ce commentaire part d'un "bon sentiment" : le développeur voulait attirer l'attention sur la nécessité de modifier d'autres portions du code.
Toutefois, le développeur qui a ajouté ceci n'a pas poussé sa réflexion sur son code. Il a choisit la simplicité sur le moment.
Maintenant que j'ai récupéré ce projet et que je dois modifier cette requête, je dois le faire aux deux autres emplacements spécifiés dans le commentaire. Ce qui me fait perdre du temps.
De plus, est-ce que ce commentaire est à jour ? N y aurait-il pas une autre partie dans laquelle cette requête a été mise (ceci pause d'ailleurs le problème de duplication de la documentation et non seulement du code) ?
Je dois donc faire une recherche sur tout le projet sur un pattern dont je ne suis pas certain. Je perd encore du temps. Je trouve des résultats, effectivement la documentation n'était pas à jour. Il n y a rien de pire que de la documentation fausse ou incomplète.
Je fais les changements sur les autres requêtes et je perd encore du temps...

Au final, pour faire un changement simple, j'ai du modifier plusieurs parties du code du projet dont la plupart étaient totalement identiques. A total, j'ai peut-être passé 5 fois plus de temps que si l'information avait été à un et un seul endroit. De plus, si je n'ai pas modifié toutes les requêtes, on risque de passer à côté d'une régression, qui sans détection préalable risque d'être trouvée par le client. Ce n'est pas sérieux.

Des solutions ...

Un des bon principe de programmation est DRY : Don't Repeat Yourself. C'est-à-dire qu'une fonctionnalité ne doit exister qu'à un et un seul endroit. Plus d'informations sur le concept DRY.
Vous devrez aussi parallèlement faire un travail de conception et de réflexion afin de segmenter votre code en un maximum de petits morceaux de codes. De cette manière vous allez grandement favoriser la réutilisation dans votre programme et vous éviterez les duplications.
De plus, lorsque l'on vous demandera de changer le comportement d'un composant, vous n'aurez qu'un seul et unique endroit où changer votre code. Vous mesurerez alors mieux les impacts d'une modification sur votre programme.

Afin de mieux illustrer mes propos, je vous propose un exemple très simple : vous devez mettre en place 4 fichiers PDF (création de commande, modification, annulation, confirmation) sur votre application. Chacun d'eux se compose d'un header commun à tous, d'un contenu spécifique à chaque PDF et d'un footer commun à tous. Quelle architecture allez-vous adopter pour votre programme ?

Pour ma part, je pense que le plus efficace est de créer :
 - une classe pdfBase
Puis des classes héritant de pdfBase
 - une classe pdfCreation
 - une classe pdfUpdate
 - une classe pdfCancel
 - une classe pdfConfirm

Dans votre constructeur de pdfBase vous aurez :

$this->generateHeader();
$this->generateContent();
$this->generateFooter();

Vos méthodes generateHeader() et generateFooter() seront à placer dans votre classe pdfBase puisqu'elles sont communes.
La méthode generateContent sera à placer dans chacune des classes filles puisque le contenu sera spécifique. Vous pourrez même définir une méthode abstraite dans la classe pdfBase pour forcer vos classes filles à l'implémenter.

Ainsi, vous pouvez constater que cette architecture vous permet d'éviter la duplication. Et, lorsque votre client vous demandera de changer l'image contenue dans le header, vous n'aurez que le fichier pdfBase à modifier, ce qui est un gain de temps.

Pour réaliser cet article, je me suis basé sur ma propre expérience ainsi que le très bon libre "The pragmatic programmer" que je vous recommande vivement.

- page 1 de 3