vendredi 26 septembre 2008

[Ubuntu] Connection au réseau au démarage

Si comme moi vous avez un serveur qui tourne sous ubuntu server (7.10) vous avez surement remarqué qu'il faut se connecter au réseau à chaque démarrage. Bien sur faire un dhclient c'est rapide mais ce n’est pas pratique quand on est à l'autre bout du globe et qu'on a accès à cette machine seulement via ssh ou tout simplement si on est faignant.
Pour ma part c'est la deuxième proposition qui m'a motivé à trouver une solution à ce problème.

Rien de bien compliqué, le but est d’effectuer une connexion au réseau au démarrage.

Pendant le démarrage, il est exécuté plusieurs scripts et l'un d’eux est /etc/init.d/rc.local. C'est le dernier script exécuté par l'init.

Nous allons donc éditer ce script avec la commande :
sudo nano /etc/init.d/rc.local

Il faut maintenant rajouter la ligne de connexion. Un "dhclient" fera l'affaire.
dhclient
Voila mais cette configuration n'est pas très propre à mon gout même si elle à le mérite de fonctionner. Nous allons donc aussi étudier l'édition du fichier /etc/network/interfaces et utiliser une configuration IP static (ce qui est préférable pour un serveur tout de même !!)

Donc éditons le fichier /etc/network/interfaces
sudo nano /etc/network/interfaces
Ici vous devez déjà avoir quelque ligne du style :
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
La première interface correspond à l'interface de loopback utilisé en local pour le System d'exploitation. La deuxième est notre interface à configurer.

Nous allons donc changer notre iface eth0 inet dhcp par
auto eth1
iface eth1 inet static
address 192.168.1.24
netmask 255.255.255.0
Il faut bien entendu que vous renseigner votre interface, votre adresse IP et votre masque à vous car ma config n'est surement pas la votre !
iface représente notre interface et sa méthode de connexion, address l’adresse IP et netmask le masque de sous réseau.

Et voila nous sauvegardons le tout et redémarrons et là, miracle ... notre ifconfig nous informe que nous somme correctement connecté !

mercredi 17 septembre 2008

[eXtrem Programming] PowerBuilder, Team Foundation Server, OrcaScript, MsBuild, Exchange and many more !

Ceci est la première version du rapport des activités produites durant mon
stage de 3 mois en entreprise. Elle concerne la mise en place de techniques
d'eXtrem Programming (XP). Ici les techniques mises en place sont :
-
L'intégration continue : La génération d'un exécutable à partir de sources
récupérées depuis un source control.
- Tests unitaires : La mise en place de
test unitaire
Le tout devra être communiqué aux développeurs. Cette partie
sera appelée reporting.

Le but principal de la mise en place d'une telle installation est la
propriété collective du code. En effet toutes les sources étant stockées sur un
même serveur et toujours accessibles, tout les développeurs ont accès aux
mêmes sources en même temps. De même ils peuvent déposer leurs contributions aux
projets.

C'est ce dernier point qui pose problème. En effet, cette méthode ne garantit
nullement que deux personnes ne modifient pas deux fichiers (distincts) qui
compileront très bien indépendamment l'un de l'autre (sur les machines des
utilisateurs respectifs) mais qui seraient en conflit lors du build de
l'application.

Il est donc nécessaire de mettre en place une solution à ce problème. Nous
allons donc mettre en place un système d'intégration continue qui vérifiera à
chaque changement si l'application ne subit pas de régression, ceci couplé à des
tests unitaires, la non régression de l'application sera complètement
vérifiée.

Pour vérifier si l'application ne subit pas de régression nous compilerons à
chaque changement l'intégralité du programme. Ainsi si des erreurs surviennent
nous en informerons les fautifs pour qu'il corrige leurs erreurs. Aussi les
erreurs étant détectés au plus vite elles seront corrigées aussi au plus vite
évitant des heures de débuggage pour déterminer leurs sources si elles avaient
été détectés plus tard !
Nous
pouvons aussi noter que l'intégration continu permet d'avoir en permanence une
version compilé avec les dernières sources de
disponible.

Les tests unitaires, eux, serviront à savoir si les changements effectués sur
une fonction n'influent pas négativement sur ses actions et valeurs de retours.
Les tests unitaires ne sont pas présentés dans ce
document.

Le service à mettre en place ici se base sur une installation existante.
Celle-ci comprend plusieurs produit développez à l'aide de PowerBuilder© de la
société Sybase© ainsi qu'un source control basé sur Visual Studio Team
Foundation Server© de la société
Microsoft©.

Notre solution devra bien entendu s'autogérer.

Suite de l'article en telechargement ici. J'attends vos retours, nombreux je l'espère même si il n'y doit pas y avoir des centaines de malades qui souhaitent faire de l'intégration continue avec PowerBuilder !!

Attention j'ai mi la version doc (7.6Mo) et la version rtf pour ceux qui n'ont pas Microsoft Word qui est beaucoup plus grosse ... (77Mo)

mardi 16 septembre 2008

[Linux] Appeler une page web à distance et à intervalles reguliers avec Cron, wget et htaccess

Pour le besoin d'un site internet les taches automatisées et planifiées sont très importantes. Sous linux ces taches s'appellent Cron. De plus les développeurs, pour la sécurité de leurs applications, protègent (et ils ont tout intérêt à le faire) leurs scripts d'automatisations par des .htaccess limitant l'accès à ceux ci par un système de login/mot de passe.
Si nous voulons automatiser l'exécution de ces pages l'une des méthodes est donc l'utilisation d'un cron. Nous utiliserons la commande wget pour récupérer la page et préciser les login/mot de passe.

Tout d'abord nous devons éditer nos taches cron. Pour ce faire :

Crontab –e
Vous arrivez dans la liste de vos taches. Par exemple vous pourriez avoir la mise à jour automatique de l'heure toute les heures avec la ligne :

# m h dom mon dow command
0 0 * * * ntpdate ntp.uhb.fr
(La première ligne est un commentaire elle n'est pas exécuté.)
Expliquons la configuration d'une nouvelle tache :
Le commentaire tout en haut nous donne la structure de rédaction d'une tache. Cette structure est la suivante :

Minute, Heure, Jour, Mois, Jour de la semaine, commande

Pour les minutes, heures, jours, mois et jours de la semaine vous pouvez spécifier une ou plusieurs valeurs ou une étoile correspondant à "tout". Ainsi pour effectuer une tache tout les mardis de janvier à minuit nous aurions :

# m h dom mon dow command
0 0 * 0 2 commande

Attention toute les valeurs commence à 0 et le jour de la semaine 0 est dimanche.
Comme vous l'avez compris le dernier paramètre est la commande à exécuter.
Vous pouvez aussi directement éditer les cron (qui sont stockés dans /etc/cron.d/) mais il vous faudra en plus renseigner le login de l'utilisateur qui exécutera la tache.
Enfin si vous voulez exécuter une tache plusieurs fois par heures (par exemple) il vous suffit de renseigner les valeurs séparé par des virgules comme ceci :

# m h dom mon dow command
0,20,30 0 * 0 2 commande

Ainsi la commande s'exécutera tout les mardi de janvier à minuit, minuit 20 et minuit 30.
Enfin si vous voulez exécuter une tache à intervalles réguliers par exemple toute les 2 minutes vous pouvez préciser */intervalle.

# m h dom mon dow command
*/2 * * * * commande

La commande s'exécutera toutes les deux minutes

Reste à renseigner la commande pour exécuter notre page. Nous utiliserons wget.
L'option –O redirige le flux.
L'option --http-user précise le login du htaccess
L'option --http-passwd précise le mot de passe du htaccess.
Enfin le dernier paramètre est la page à charger.
Ainsi :


0 18 * * * wget -0 /dev/null --http-user=admin --http-passwd=XXXXXX
www.site.com/cron/cron.php

Attention si vous référencer un site de la forme http://www.monsite.com/ qui est hebergé sur votre serveur noubliez pas de mettre, dans votre fichier hosts (/etc/hosts) une ligne du type :



127.0.0.1 www.monsite.com

lundi 15 septembre 2008

[Zend Framework] Faire un join

Il se peut que vous rencontriez une erreur de type :
Select query cannot join with another table in /var/www/ etc ...

Ceci est du à Zend Framework qui n'autorise pas par défaut de faire une simple jointure sur une table sous jacente.

L'objet Zend_Db_Table_Select est destiné à sélectionner des données sur une table précise. Des jointures peuvent être faites, mais il n'est pas possible de sélectionner des colonnes ne faisant pas partie de la table sous jacente. Cependant, ceci aurait pu être utile dans certains cas, et l'objet Zend_Db_Table_Select possède une clause spéciale déverrouillant cette limitation. Passez la valeur false à sa méthode setIntegrityCheck. Il est alors possible de sélectionner des colonnes hors table. Attention toutefois, l'objet row/rowset résultant sera verrouillé. Impossible d'y appeler save(), delete() ou même d'affecter une valeur à certains de ses champs. Une exception sera systématiquement levée.

Pour enlever cette protection vous devez spécifier setIntegrityCheck(false) dans votre requête.

Par exemple pour une classe simple de récupération de news j'ai :
<?php

/**
* News
*
* @author Lermit
* @version 1
*/

require_once 'Zend/Db/Table/Abstract.php';

class News extends Zend_Db_Table_Abstract {

protected $_name = 'news';
protected $_primary = 'news_id';
protected $_dependentTables = array("Users");
protected $_referenceMap = array(
    'Reporter' => array(
    'columns' => 'user_id',
    'refTableClass' => 'Users',
    'refColumns' => 'user_id'
    )
);

/**
* getLast
* retourne les $numberOfNews dernières news à partir de $start
* @author lermit
* @version 1
* @param $numberOfNews nombre de news
* @param $start à partir de la n-ieme news
* @return les news
*/
public function getLast($numberOfNews,$start)
{
    $select = $this->select()
        ->setIntegrityCheck(false)
        ->from( array('n' => $this->_name), array('text','date','user_id'))
        ->join(array('u' =>'users'),'u.user_id=n.user_id','login')
        ->order('date DESC')
        ->limit($numberOfNews,$start);

    return $this->fetchAll($select);
}
}

Tout d'abord je spécifie le nom et la clef primaire de ma table puis les relations de jointure avec les autres tables.
$_dependentTable = tableau de la/les classe(s) de la(des) table(s) dépendante(s).
$_referenceMap = tableau de tableaux de dépendances. Chaque dépendance est listée sous la forme d'un tableau construisant comme suit :
'columns' => 'colonne de la classe courante',
'refTableClass' => 'classe de la table à joindre',
'refColumns' => 'colonne de la table à joindre'
Bref ma requête utilise bien ->setIntegrityCheck(false) ce qui m'enlèvera cette fâcheuse erreur !!

[Divertissement] L'effet papillon

Voici le site d'un grand magasin hollandais : HEMA. Cette enseigne compte plus de 150 magasins au Pays Bas, en Belgique, au Luxembourg et en Allemagne …
Bref une grosse boite mais … pas démuni d'humour.
Je vous laisse jeter un œil sur leur site :
http://producten.hema.nl/

Le développeur a dut bien s'amuser.

vendredi 12 septembre 2008

[HTML] Ajout d'une icone

Pour ajouter une icône dans une page HTML il faut tout d'abord avoir une icône !! (Taille 16*16 ou 32*32 extension : ico)

Après il vous suffit d'ajouter ces lignes :

<!-- Ci-dessous l'icone du site -->
<link rel="icon" type="image/png" href="/images/favicon.ico" />
<!--[if IE]>

<link rel="shortcut icon" type="image/x-icon" href="/images/favicon.ico" />
<![endif]-->


La première ligne est la ligne standard à tous les navigateurs sauf IE.
Les lignes suivantes correspondent à l'ajout pour internet explorer en utilisant un "hack". Ainsi seul Internet Explorer lira cette ligne.

[Base de Données] Recherche du provider et de la chaine de connection ?

Pour ne plus chercher comment se connecter à tel ou tel base avec quel provider ? etc ...

Ce site web recense un nombre impressionnant de méthodes de connexions et pourrait en aider plus d'un ;)
http://www.connectionstrings.com/default.aspx
Bonne connexion !

[SQL Server] Mise en place du serveur, Mise en place d'un shema de base, activation du protocole TCP/IP



Pour faire des tests sur Entity Framework j'ai du installer une base de donnée de test. J'ai choisi Microsoft SQL Server Express 2005 car il est complètement intégré avec l'Entity Framework.

Tout d'abord il convient de télécharger SQL Server Express 2005. Il se trouve à cette adresse (40.9 Mo) :

http://msdn.microsoft.com/fr-fr/express/bb410791.aspx
Attention pour installer le serveur il faut avoir au préalable installer Windows Installer 3.1 (ou supérieur) qui est disponible ici. Il faut aussi posséder le dot net Framework 2 ou supérieur.Une fois le téléchargement fini il faut exécuter l'exécutable, l'installateur décompresse tout d'abord les données, il faut ensuite accepter la licence et enfin cliquer sur installer ! Vous arrivez après dans l'installateur en lui même. Il faut tout d'abord une vérification du système et vous informe des non conformités avec l'installation. Il vous demande votre nom et société puis les composants que vous voulez installer. Il faut sélectionner ce que vous avez besoin. Ici nous avons tout sélectionné. Pour le mode d'authentification vous pouvez choisir entre l'authentification Windows (qui fonctionne avec votre compte Windows) ou l'authentification mixte qui rajoute une entrée "non-Windows". Ceci permet de récupérer la base en cas de problèmes avec le réseau d'authentification Windows.Ensuite deux choix s'offrent à vous : activer les instances d'utilisateur qui si il est coché permet aux utilisateurs d'exécuter des instances séparé de l'instance parent. Ainsi chaque utilisateur peut avoir sa propre instance. Nous l'avons coché. L'autre option : Ajouter l'utilisateur au rôle Administrateur SQL Server permet à l'utilisateur qui installe la base de données d'être administrateur de celle-ci. Ensuite vous pouvez spécifier si vous voulez ou non envoyer des rapports à Microsoft sur le fonctionnement de son produit. Enfin l'installation se lance et après quelques minutes tout est fini.

Pour activer votre base de données sur le réseau il faut aller dans Gestionnaire de configuration SQL Server (nouvellement installé) et dans Configuration du réseau SQL Server 2005 -> Protocoles pour SQLEXPRESS sélectionner TCP/IP, bouton de droite activer. Activer aussi canaux nommées. Il faut ensuite redémarrer le service. Pour ceci dans Services SQL Server 2005, sélectionner SQL Server (SQLEXPRESS), bouton de droite, redémarrer. Enfin pour que le serveur puisse être facilement listé par les clients nous allons démarrer SQL Server Browser. Faire bouton de droite sur celui ci propriétés, Service, changer le Mode de démarrage en Automatique, cliquer sur ok. Ensuite bouton de droite démarrer.

Une fois l'installation terminée nous allons intégrer un schéma de base, proposé par Microsoft pour nos tests. Vous trouverez plusieurs schémas de base à cette adresse :

http://www.microsoft.com/sql/editions/express/starterschemas.mspx
Nous utiliserons ici le schéma Customers and Orders.
Pour l'intégrer facilement à notre base de données nous utiliserons le logiciel (gratuit) de Microsoft : Microsoft SQL Server Management Studio Express. Il se trouve à cette adresse (en bas !) :

http://www.microsoft.com/downloads/details.aspx?displaylang=fr&FamilyID=C243A5AE-4BD1-4E3D-94B8-5A0F62BF7796
L'installation est très simple.
Lancer ensuite SQL Server Management Studio Express (non ce n'est pas un nom à rallonge ...), connecter vous à votre base de donnée (dans nom du serveur, cliquer sur parcourir et votre base de donnée devrait s'afficher)
Sélectionner Bases de données, bouton de droite, Nouvelle base de données. Pour créer une nouvelle base de données qui nous servira pour nos tests. Sur votre nouvelle base de donnée, bouton de droite, nouvelle requête, copier ici votre code SQL. Nous avons nous copier l'intégralité du fichier cre_customers_and_orders.sql. Puis faite bouton de droite sur l'éditeur et exécuter.

Voila votre serveur SQL Server 2005 Express est installer et votre base de données créé.

mercredi 10 septembre 2008

[PHP] Le design pattern : Singleton

Le design pattern du singleton permet d'avoir une seule et unique instance d'une classe dans un programme.

Le principe est simple : Nous créons une classe maClasse et nous spécifions son constructeur comme élément privé. Ainsi les utilisateurs de la classe ne pourrons pas l'instancier librement. Nous créons aussi une fonction getInstance(), publique cette fois, qui, elle, se chargera de retourner l'instance de la classe.


class maClasse
{
    private static $instance;

    private function __contruct()
    {
        // Instanciation
    }

    public static function getInstance {
        if( !isset(self::instance))
        {
            self::$instance = new maClasse();
        }
    return self::$instance;
    }

}

Notre variable $instance doit être de type static pour ne pas être supprimée à chaque fois ;)
Notre fonction getInstance est donc très simple :
Nous vérifions que l'instance à été déclaré sinon nous la créons et enfin la retournons !

vendredi 5 septembre 2008

[Zend Framework] Generation de captcha avec ZF (anti bot)

Vous savez surement tous que le net fourmille de robots spammeur qui envahissent nos forums, nos boites mails, etc …
Pour luter contre ceux-ci on utilise des captcha, c'est le nom des petites images qu'on vous demande de recopier dans une textbox lors d'une inscription ou de ces questions qui vous demande la somme de deux et cinq. Bref c'est un mécanisme anti robot. Zend Framework, dans sa version 1.6 et supérieur, propose une manière d'en générer facilement et de les intégrer facilement avec Zend_Form.

Tout d'abord il faut créer un nouvel element captcha dans notre formulaire. Ceci ce fait facilement car ZF propose la classe Zend_Form_Element_Captcha.

$captcha = new Zend_Form_Element_Captcha(nom, param);

nom représente biensure le nom de votre élément et param un tableau avec les paramètres (en soit comme un élément normal!). Dans le tableau on peut rajouter l'option captcha qui va configurer notre captcha. Celle ci se décline aussi sous la forme d'un tableau qui se construit comme ceci :

'captcha' => array(
'captcha' => 'Type du captcha',
'wordLen' => Nombre de caractère à afficher,
'timeout' => Temps avant fin du captcha,
// Seulement dans le cas d'une image
'font' => 'Chemin vers la police de caractère',
'imgurl' => 'Ou seront stocker les images',
)
Le type du captcha peux être le suivant :
  • Image : Image comme on les connait
  • Dumb : directement le texte (Non sécurisé !)
  • Figlet : Lettre sous forme de dessin textuel. (Utile si vous n'avez pas accès à la librairie GD).
Enfin voila à quoi ceci peut ressembler :
$captcha = new Zend_Form_Element_Captcha('captcha', array(
'label' => "Copiez le code suivant :",
'captcha' => array(
'captcha' => 'Image',
'wordLen' => 6,
'timeout' => 300,
'font' => '../application/fonts/Candara.ttf',
'imgurl' => '/images/captcha',
),
));

jeudi 4 septembre 2008

[Zend Framework] Utilisation de la classe de traduction de ZF

Le Zend Framework (ZF) propose par défaut une classe de traduction très simple d'utilisation. Elle prend en compte de nombreux moyens de traduction comme les Array (PHP), CSV, Gettext, INI, TBX, TMX, Qt, XLIFF et XmlTm. Il est aussi possible de créer ses propres adaptateurs. Ici nous utiliserons Gettext car c'est le plus professionnel à mon gout. L'inconvénient est que le fichier de traduction est binaire et donc non lisible par l'homme et qu'il faut un logiciel pour générer ce fichier (il en existe des gratuits).

La classe de traduction de Zend Framework est Zend_Translate. La mise en place de la traduction se résume simplement à l'instanciation de cette classe. Ceci est fait comme ceci :

$translate = new
Zend_Translate('gettext','/languages/fr/LC_MESSAGES/lang.mo','fr');
Dans cette ligne nous créons tout d'abord un nouveau objet de type Zend_Translate. Le constructeur prend trois paramètres :
  • Le premier est l'adaptateur utilisé. Ici nous utilisons gettext mais vous pouvez très bien utiliser csv, tbx, …
  • Le deuxième paramètre est le chemin vers le fichier de traduction. Avec gettext il s'agit d'un fichier binaire d'extension mo.
  • Enfin le dernier paramètre est la langue chargé. Ici le français (fr).
Si vous avez plusieurs fichier de traduction (comme c'est souvent le cas !) il faut les ajouter avec

$translate->addTranslation('/languages/en/LC_MESSAGES/lang.mo','en');

A ce moment là vous pouvez déjà afficher vos messages. Pour cela il existe deux méthodes : La première avec la chaine d'origine, par exemple pour traduire 'Ma chaine à traduire' :

Print $translate->_("Ma chaine à traduire");
La deuxième à partir de l'id de la phrase traduite, par exemple pour la chaine traduite d'id 3 :

Print $translate->_(3);
Pour savoir dans quelle langue sera traduit notre phrase nous pouvons utiliser la méthode getLocale() qui retourne une instance de Zend_Locale ou un identifiant de localisation.

$langue = $translate->getLocale();
Pour spécifier la langue à utiliser il faut utiliser la méthode setLocale().

$translate->setLocale("en");
Pour améliorer les performances de l'application on peut spécifier à Zend_Translate un cache où il stockera des données pour y accéder plus rapidement. Ceci ce fait comme suit :

// Options du frontend et du backend
$frontendOptions = array('lifetime'
=> 7200, 'automatic_serialization' => true);
$backendOptions =
array('cache_dir' => '/tmp/' );
// Création d'un cache
$cache = Zend_Cache::factory(Core','File',$frontendOption,
$backendOptions);
// Spécifier à Zend_Translate le cache
Zend_Translate::setCache($cache);

Ainsi l'exécution sera plus rapide. Nous créons tout d'abord un cache en utilisant la factory de Zend_Cache. Les paramètres sont tout d'abord le frontend (ici Core) et le backend (ici File) suivit de leurs options. Ensuite nous spécifions à la classe Zend_Translate ce cache avec la méthode setCache.

mardi 2 septembre 2008

[AS3] Convertir une string en int ou float

Pour convertir une chaine de caractère en nombre il existe deux fonctions :
parseInt et parseFloat.

parseInt convertit la chaine de caractère en entier.

parseFloat convertit la chaine de caractère en nombre décimal.

l'utilisation est simple :
var iNumber:int = parseInt("234");
ou
var iNumber:float = parseFloat("234.423");
parseInt peut prendre aussi un deuxième paramètre qui permet de spécifier la base du nombre.
Par exemple pour récupérer un entier codé en hexadécimal nous ferions :
var iNumber:int = parseInt("1F3",16);

La base peut être comprise entre 2 et 36