dimanche, 30 décembre 2007

Je télécharge mes MP3 et les écoute légalement.

Le parlement et le conseil national ont accepté le 5 Octobre 2007 presque sans aucune résistance une loi fédérale sur le droit d'auteur et les droits voisins.

Pour toute question à propos du référendum lancé, que dit en passant j'encourage fortement à signer, rendez-vous sur le site No Swiss DMCA.
Je n'essayerai pas non plus de déterminer à quelles mesures techniques, notées efficaces, le texte de loi fait peut bien faire référence.

Cette loi, plus précisément l'article 39a alinéa 4 donné ci-après, combiné à l'approbation du Tribunal fédéral (TF) sur l'introduction d'une redevance sur les supports numériques (baladeurs MP3, iPod et autres enregistreurs à disques durs) entrée en vigueur au 1er septembre 2007, me mène à la conclusion suivante :

Je vais télécharger de la musique sur mon réseau peer-to-peer préféré, ripper des CDs et retirer les DMA de mes MP3 restants (autrement dit : contourner les mesures techniques efficaces) et l'écouter (exclusivement) sur mon baladeur MP3 récemment acquis. Celui-ci étant taxé, je m'affranchis de toute autre taxe, et je deviens entièrement légal. Idem pour les divx !

Art 39a
4 L’interdiction de contourner ne peut pas frapper celui qui contourne une mesure technique efficace exclusivement dans le but de procéder à une utilisation licite.
PS : cet article n'est pas illégale au sens de l'Art 39a 3a, c'est-à-dire que cet article ne fait pas promotion visant à contourner des mesures techniques efficaces.
PPS : la critique de la double imposition à une taxe sur les droits d'auteurs des musiques achetées sur un online music shop et écoutées sur un baladeur taxé fera l'objet d'un autre article.

Offrir un réseau wifi ouvert pour rentabiliser sa connexion Internet

J'écrivais il y a un bon moment comment un administrateur réseau peu scrupuleux pouvait arrondir ses fins de mois en détournant les publicités des sites visités par les utilisateurs
interne.

Cette technique s'adapte très simplement à un réseau wifi ouvert...

Mais attention au click through rate trop élevé :)

samedi, 15 décembre 2007

Twitter, un vrai service Web 2.0 (le retour)

Pour commencer j'ose espérer que le 2ème degré du message précédent a été perçu.

Twitter est selon moi un vrai service Web 2.0, c'est-à-dire qu'il ne sert à rien. On n'est pas plus heureux en l'ayant découvert et ça ne fait pas avancer la société de l'utiliser.

Mais au-delà de considération subjectives à son sujet, les technologies et les techniques d'addiction mises en oeuvre sur ce site sont suffisamment intéressantes pour être discutées ici :

Premièrement les méthodes de publication disponibles sont autant multiples que variées :

  • Interface web,
  • SMS,
  • IM (client jabber),
  • ...
On voit d'entrée que le service est fait pour être mis-à-jour en permanence, très facilement par IM quand on est devant un ordinateur relié à Internet, mais aussi via des dispositifs mobiles une fois le clavier de l'ordinateur hors de porté. Ainsi un utilisateur peut à tout moment renseigner ses lecteurs virtuels et potentiels sur ce qu'il est en train de faire. L'aspect mise-à-jour via téléphone portable est très important, car il permet de modifier le statut lors des sorties, donc quand c'est le plus croustillant.

Un aspect important pour renforcer l'addiction est la possibilité d'émettre un rappel (SMS ou email) en cas de non mise-à-jour prolongée.

Deuxièmement les différents formats de lecture possibles sont aussi standard que tendance : on retrouve ainsi la "social timeline" sur sa page personnelle au style très épuré Web 2.0 et le fameux flux RSS. La communauté de lecteurs n'est pas en reste non plus, avec son lot de features pour se créer un réseau d'amis.

Pour conclure sur cet article plutôt bullshit'stisant pour reprendre les termes d'autres, je dirais que mis à part le côté "sert-à-rien" il pourrait remplacer à merveille les blogs que les jeunes s'efforcent d'utiliser de la manière dont Twitter oblige, la possibilité de mettre les photos en mois. Et que le côté publication d'activité via IM est réellement bien fait.

Twitter, un vrai service Web 2.0

D'abord il y a eu les blogs, qui permettaient de raconter sa vie
passionnante de tous les jours, puis maintenant il y a Twitter, qui force de
résumer sa vie passionnante en 140 caractères.

Comme je n'ai pas une vie passionnante, 140 caractères sont longtemps suffisant pour expliquer que je vais au travail, je suis bloqué sur un problème en PHP, j'ai vu un site super, j'ai mangé au Delectis à midi et que "Tien, c'est déjà 16h30 alors je vais rentrer".

Donc je vous invite tous à retrouver le fil RSS de ma vie La vie au format RSS de Benoit Perroud.

Getting Things Done® (GTD® aussi) : le sydrome du "Ca c'est fait !"

Un mot très en vogue en ce moment (cf Google trend sur getting things done), GTD® est une méthodologie d'organisation des tâches quotidiennes à accomplir. Dévoilée dans un livre écrit par David Allen publié en 2001, Getting Things Done®, the art of stress-free productivity, elle reprend un certain nombre de choses connues en matière de gestion du temps mais les systématise dans un processus structuré, gage d'efficacité.

Cette systématique est intéressante car elle peut nous faire prendre conscience de la méthodologie que peut-être certain utilisaient déjà et ainsi nous amener à y réfléchir en vue de l'optimiser à nos besoins.

L'objectif de GTD® est de porter toute la créativité et l'énergie sur la seule action qu'on a délibérément choisi de faire et d'approcher au mieux un état de productivité sans stress annoncé.

Les 2 concepts mis en exergue par cette théorie sont les suivants :

  • Les tâches sont interdépendantes
  • Les priorités des tâches dépendent d'un contexte
Fort de ce constat, GTD® nous donne une systématique pour
  • recenser les tâches et les reporter sur des listes par sujet,
  • identifier celle qui peuvent être exécutées immédiatement et les reporter sur une TODO list
  • les réaliser dans un ordre de priorité dépendant du contexte (temps à disposition, état de fatigue, endroit, ...).
Une fois la tâche accomplie, GTD® propose une phase de revue durant laquelle la tâche est notée comme faite (le fameux syndrome du "Ca c'est fait !", qui n'est en réalité rien qu'un petit vu sur la TODO list mais qui procure une satisfaction bien au-delà du consentement, mais là je m'égare...) et le cycle organisationnel peut recommencer.

GTD® ne propose pas de support spécifique pour la liste des tâches à accomplir (TODO list), mais précise que le moyen utilisé doit être fiable.

Une petite corollaire de GTD® que je trouve intéressantes est que les tâches prenant moins de 2 minutes sont faites immédiatement. Car "moins de 2 minutes" est à peu près le temps pris pour la gestion organisationnelle de la tâche.

Pour ceux qui comme moi pensent que la curiosité n'est pas toujours un vilain défaut :
  • http://www.davidco.com/what_is_gtd.php
  • http://fr.wikipedia.org/wiki/Getting_Things_Done
  • http://wiki.43folders.com/index.php/Productivity_pr0n
Getting Things Done® et GTD® sont des marques déposées depuis 2005.

dimanche, 9 décembre 2007

60 millions de hashes md5 !

Sur mon petit projet de revserse md5 lookup database, je viens de dépasser les 60'000'000 de hashes md5 dans la base de données interne, qui fait maintenant 4.2 GB.

En gros j'ai introduit dans la base tous les hashes de 4 lettres composés des caractères a-z, A-Z, 0-9, ., -, _, !, $, *, %, &, /, (, ), =, ?, #, @, +, ", [, ], {, }, et tous les hashes de 5 lettres composés de caractères a-z.

On remarque que sur l'échantillon généré les hashes sont bien uniformément répartis, mais on a une préférence non significative pour les hashes commençant pas 0x46.

La prochaine étape est les hashes de 5 à 7 lettres composés des caractéres a-z et 0-9, ce qui nous fait ~80'000'000'000 de hashes supplémentaires...
Ensuite je prendrais les dictionnaires Openoffice afin de générer les hashes de mots existants.

Happy md5 cracking sur md5.noisette.ch.

dimanche, 25 novembre 2007

Fonction url_get_contents en PHP

Plutôt que d'utiliser un bien moche file_get_contents($url)$url est une url, je vous propose une petite fonction url_get_contents($url) utilisant l'extension curl de PHP qui permet aussi bien de télécharger le contenu d'une url via GET que POST :

function url_get_contents($url, $post = null) {
$curl = curl_init();
curl_setopt ($curl, CURLOPT_URL, $url);
curl_setopt ($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt ($curl, CURLOPT_HEADER, 0);
curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, 0);
//curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, 1); // if no safe_mode neither open_basedir

if (is_array($post)) {
curl_setopt ($curl, CURLOPT_POST, 1);
curl_setopt ($curl, CURLOPT_POSTFIELDS, $post);
}

$html = curl_exec ($curl);
curl_close ($curl);
return $html;
}

L'utilisation est réellement simple :

$content = url_get_contents('http://www.noisette.ch');

Reverse MD5 databases aggregator

J'écrivais il y a à peu près une année un message à propos des reverses MD5 et de la problématique que ces bases de données posent.
Suite à un message au sujet de l'utilisation de Google comme base de données de hash (en anglais), j'ai remis à jour mon aggrégateur de revse MD5.

Il questionne maintenant pas moins de 8 bases de données en plus de sa base de données propre, et permet maintenant de recevoir un mail quand le hash est trouvé après-coup.

Une petite API est disponible pour intégrer le service dans vos propres applications, notemment pour déterminer si un mot de passe sera crackable en O(1).

Happy md5 cracking sur md5.noisette.ch.

mardi, 9 octobre 2007

Contourner le blocage du port SMTP

Votre provider bloque le port tcp/25 (SMTP) et donc vous ne pouvez pas envoyer de mails via votre serveur mail préféré ?

Une solution toute simple mais qui nécessite d'avoir un compte shell sur un serveur quelconque (qui peut être votre ordinateur local), qu'on va nommer srv_shell dans cet exemple, est de faire un tunnel entre votre ordinateur local, le srv_shell et votre serveur de mail préféré, appelé srv_mail ici.

La commande à exécuter sur votre ordinateur local est la suivante :

ssh -NL 2525:srv_mail:25 user@srv_shell
L'utilisation d'un clé ssh est encouragée.

Ensuite dans votre logiciel d'envoi de mail préféré il suffit de spécifier comme serveur sortant localhost sur le port 2525.

Et hop la sécurité le côté ennuyeux à ce type de sécurité mis en place par l'administrateur est bypassé. J'y reviendrai d'ailleurs dans un autre article, car il m'est arrivé récemment ce genre de mésaventure : ip fixe avec serveur Exchange + Storm Worm = blacklistage de l'ip...

Une deuxième solution pourrait venir à l'esprit si on possède son propre serveur dédié, mais je vais expliquer pourquoi cette solution est à bannir au plus vite.

La deuxième idée est d'utiliser un logiciel comme rinetd ou redir, qui ont pour but de rediriger le traffic adressé à un port vers un autre. Donc tout ce qui arriverait sur le port 2525 de srv_shell serait redirigé vers le port 25 du srv_mail. Le problème de cette solution est quand les deux serveurs srv_shell et srv_mail sont les mêmes, la connexion sur le port 25 est redirigé par la même machine, le service mail va donc recevoir une connexion depuis localhost. Et comme la très grande majorité des services mails sont configurés pour que localhost puisse envoyer sans restrictions des mails, cette configuration ouvre un open-relay. Quiconque trouve ce port 2525 sur votre serveur pourra l'utilisé pour spammer le monde entier -> la redirection de port sur un serveur mail est donc à bannir.

lundi, 8 octobre 2007

Création manuelle d'un botnet "localisé"

Une méchante idée m'est venue en lisant un article de Slashdot : Cracked Linux Boxes Used to Wield Windows Botnets.

Afin de se composer un réseau de botnets, il serait extrêmement simple à une personne malveillante de vendre des routers ADSL modifiés (rootkités) sur des sites comme Ebay ou Ricardo en Suisse. L'utilisation pour l'acheteur pourrait être strictement similaire, au point qu'il ne se douterait pas que quelqu'un d'autre à la main sur son nouveau routeur.

Dans cet ordre d'idée, on voit de plus en plus de router ADSL se faire rootkiter à la suite d'un piratage d'un ordinateur. La raison principale : un mot de passe par défaut... Idem pour les connexions wireless : on la casse (l'histoire d'une journée pour du WEP avec du matériel correct) avant de s'attaquer au router !

En résumé, il serait presque rentable de se monter un botnet "localisé" et persistant, car placé dans des endroits stratégiques.

Deux petites recommandations pour éviter toutes mauvaises surprises : TOUJOURS modifier le mot de passe de vos routeurs (quitte à le noter dessous, le pirates devant hacker votre webcam et le robot téléguidé du petit frère pour réussir à placer le mot de passe dans le champs de vision de la webcam), et abandonner les connexions wireless...

vendredi, 28 septembre 2007

La surjection, nouvelle maladie ?

La prochaine fois que vous allez chez le médecin, dites-lui que vous souffrez d'une surjection et que je avez besoin d'un injection pour retrouver un état stable de bijection...

lundi, 24 septembre 2007

Implémentation paresseuse du "Visitor pattern" en PHP

Sans m'étendre sur les bienfaits du Visitor pattern, dont le but est de séparer un algorithme de sa structure de données, je souhaite proposer ici une implémentation paresseuse mais possible en PHP.

En théorie ce pattern repose sur 2 interfaces qui permettent de faire un double dispatch (appeler depuis un objets visitable la fonction lui correspondant dans le visiteur) :

  • Visitable qui contient une fonction apply(Visitor $v)
  • Visitor qui contient une fonction visit(Visitable $v)
Puisqu'en PHP il n'est pas possible de faire de la surcharge de paramètres de fonction (polymorphisme), il faut donc appeler les fonctions différemment selon les types de structure de données.

En Java :
interface Visitor {
void visit(Wheel wheel);
void visit(Engine engine);
void visit(Body body);
void visit(Car car);
}
abstract class Visitable {
void apply(Visitor visitor) {
visitor.apply(this);
}
}

En PHP :
interface Visitor {
public function visitWheel($wheel);
public function visitEngine($engine);
public function visitBody($body);
public function visitCar($car);
}
interface Visitable {
public function apply(Visitor $visitor);
}

On remarque donc qu'en PHP on devra réécrire toutes les fonctions apply pour qu'elles appellent la fonction visit___ correspondant à leur type.
Mais paresseux comme je suis, la redéfinition de la fonction apply pour chaque visitable me parait un tâche trop répétitive et ennuyeuse. L'idée sous-jacente est de faire un dispatch dynamique en fonction du type du visitable, de la façon suivante :
abstract class Visitable {
public function visit(Visitable $visitable)
{
$func = array(&$this, 'visit' . get_class($visitable));
if (!is_callable($func)) {
trigger_error('[' . get_class($this) . '] Class ' . get_class($this) . ' has no visit' . get_class($visitable) . ' function', E_USER_ERROR);
}
call_user_func($func, $visitable);
}
}

Ainsi le visiteur devrait implémenter les fonctions standards visitWheel, visitEngine, ... mais leur dispatching devient automatique !

Mis à part la lourdeur de la fonction call_user_func, le reste de cette implémentation dynamique reste intéressante.

Références :
http://en.wikipedia.org/wiki/Visitor_pattern
http://en.wikipedia.org/wiki/Double_dispatch#Double_dispatch_is_more_than_function_overloading

Plus d'information pour les intéressés :
http://www.polyglotinc.com/reflection.html
http://www.javaworld.com/javaworld/javatips/jw-javatip98.html

mardi, 18 septembre 2007

Offre d'emploi : customer care

Ma petite startup, leader en suisse romande sur le marché des logiciels immobiliers, recherche un nouveau collaborateur afin d'assurer le support technique et la formation de ses nombreux clients.

Plus concrètement, le poste consisterait à répondre par téléphone/email aux questions techniques et d'assurer la formation des nouveaux clients sur les logiciels.

Le profile recherché est le suivant :

  • Langue maternelle française, bon niveau en allemand un plus
  • Excellentes capacités en communication, autant orales qu'écrites
  • Bonne capacité à comprendre et résoudre les problèmes
  • Capacité de travailler sur plusieurs tâches en parallèle
  • Bonne compréhension de l'architecture client-serveur
Les postulations peuvent être directement adressées à info _A_T_ migtechnology _P_O_I_N_T_ ch.

dimanche, 16 septembre 2007

Algue? piézo-phosphorescente

Mercredi 12 septembre 2007, tard le soir, plage de Vieux-boucaux dans les Landes française.

Nous étions alors en vacances entre amis. Une soirée des plus tranquilles, avec comme il se doit un passage sur la plage pour boire quelque breuvage local. Cadre peu crédible pour la suite de l'histoire si nous n'avions pas été 9 à être témoin du phénomène que nous avons découvert ce soir-là.

C'est en s'approchant de l'océan qu'on aperçut des points lumineux autour de nos pas. Des points d'une légère lumière bleutée s'illuminaient à chaque pression de nos pieds sur le sol dans un rayon d'une vingtaine de centimètres, avant de disparaitre 3 secondes plus tard.
Phénomène qui nous a émerveillé une bonne partie de la soirée, mais qui reste un mystère pour nos esprits curieux...

Une hypothèse d'une algue ou d'un organisme piézo-phosphorescent est de mise, car les points de couleurs apparaissaient dans une zone semblable à la zone de compression imposée par nos pas...

Mais les hypothèses les plus folles ont été imaginées sous cette nuit claire et chargée d'étoiles filantes.

lundi, 20 août 2007

Générateur automatique de visualisation de site

Un nom qui ne donne pas très bien en français, mais j'ai développé avec une petite équipe un générateur automatique de visualisation de site.

Le principe est simple : on donne une url au générateur qui nous retourne une image qui est une copie d'écran du site qu'on aurait eu dans notre navigateur. Le coeur du générateur utilise le moteur Gecko pour le rendu de la page web.

Une démo du service de génération de visualisation de site est disponible en ligne, et l'idée est de développer une puissant API pour interfacer le service. L'idée principale de l'API est d'utiliser une url de callback qui permettra au service directement de retourner l'image une fois générée afin d'éviter au client de devoir poller pour controler si l'image est créée ou pas.

Les possibilités du service sont les suivantes :

  • Taille des images paramétrables (120x90, 160x120, 320x240, 640x480, 1024x768)
  • Format d'image JPEG ou PNG
  • Ajout de délai avant la capture (pour les sites en flash par exemple)
  • Mise-à-jour hebdomadaire, mensuelle ou annuelle des captures
Les feedbacks sont bien évidemment encouragés, et d'autres news sur l'API & CO suivront.

jeudi, 16 août 2007

Uniqid ou la contre-intuitivité des arguments

D'après le manuel PHP, le prototype de la fonction uniqid est le suivant :

string uniqid ( [string prefix [, bool more_entropy]] )
Le deuxième paramètre à l'air réellement intéressant, dans la mesure où il assure une meilleure unicité de la chaine produite. Une propriété qui de toute évidence nous intéresse si on utilise cette fonction uniqid.

Sans s'étendre sur la probabilité de collision entre les 2 appels (ce que j'étendrai plus longuement dans un autre article), je voulais juste montrer la différence de vitesse d'exécution qu'induisait ce paramètre more_entropy. Un petit script faisant 100 appels à uniqid avec une valeur possible du paramètre, nous donne le résultat suivant (!) :

100 * uniquid(mt_rand()) en 0.799283981323 seconde

100 * uniquid(mt_rand(), true) en 0.00346183776855 seconde

Chose extrêmement intéressante, le temps d'exécution de la fonction est 3 ordres de grandeurs en dessous si on demande une meilleures unicité du résultat.

La question obligée est donc : pourquoi est-ce que cette fonctionne ne prend pas par défaut cette option, puisqu'elle a tous les avantages (meilleures résultats, plus rapide) ?

lundi, 13 août 2007

Types ENUM avec MySQL

Toujours en train de travailler avec MySQL, et encore pour un bon moment, voici une particularité du type enum :

Soit un champ field2 :

`field2` enum('0','1') NOT NULL default '0'
Soit une requête :
SELECT * FROM ... WHERE ... AND field2 = 1
Le résultat de cette requête est intéressant dans le sens où MySQL va sélectionner tous les tuples dont la valeur du champ field2 vaut '0'. Pourquoi cela ? Parce qu'en passant le 1 sous forme d'entier, MySQL va l'associer à la première valeur de l'énumération, '0' donc. Dans le même ordre d'idée WHERE ... AND field2 = 2 sélectionnera tous les tuples dont field2 vaut '1'.

La requête

SELECT * FROM ... WHERE ... AND field2 = '1'
fournira quant à elle la juste réponse. Attention donc avec les types des valeurs, surtout en PHP...

lundi, 6 août 2007

Mysql NT vs Unix : quand les systèmes de fichier font des différences

La question posée ici est la suivante : le nom des tables dans une base de données MySQL est-il sensible à la casse ou pas ?

La réponse dépend du système sur lequel le serveur tourne... Et cette différence vient même d'une manière plus intrinsèque du système de fichier sur lequel repose la base de données.

Explication :

Pour MySQL, une base de données est un répertoire du même nom dans lequel se trouvent des fichiers représentant les tables. Le nom des fichiers est naturellement identique aux tables, à l'extension prêt.

Pour savoir sur une base existe, MySQL va chercher si le répertoire correspondant existe. Du même principe pour accéder à un table il va ouvrir le fichier lié.

Sur un système de fichier Unix, ext3 ou reiserfs par exemple, un fichier base1/table1.MYI n'est pas le même que base1/tAbLe1.MYI, donc une requête "SELECT * FROM table1" ou "SELECT * FROM tAbLe1" ne produira pas le même résultat. Sur un système de fichier NTFS par contre, les chemins ci-dessus pointeront vers le même fichier, et donc les 2 requêtes précédents fonctionneront.

En conclusion, le nom des bases et tables MySQL sont sensibles à la casse sur un système Unix, et non sensible à la casse sur un système Windows.

lundi, 14 mai 2007

Citer Montaigne quand on parle d'informatique

Chose pas forcément aisée, mais Jean Véronis, professeur de linguistique et d'informatique à l'université de Montpellier y est parvenu à merveille jeudi 18 janvier, dans la capsule de Monsieur Pain.

"Scrobbler" Tome II, jeudi 18 janvier 2007

La capsule, une émission à écouter et ré-écouter...

vendredi, 6 avril 2007

Je sers mon pays...

Joyeuses Pâques !

Pendant que les uns vont profiter du climats printanier annoncé pour ce week-end de Pâques, d'autres remplissent leurs obligations de citoyens en gardant un parc véhicule (4 piranha 8x8, 3 eagles et quelques duros) ...

Un ingénieur, un vrai

Samedi 31 mars a eu lieu la cérémonie de remise des diplômes : la Magistrale. Très belle cérémonie, en collaboration avec le cirque StarLight qui animaient les pauses inter-discours. Même Paul Allen était présent et serrait la main de tous les nouveaux ingénieurs. Non là je fabule un peu sur la poignée de main, mais Paul était bien présent et nous a fait un discours de 40 minutes. Une galerie de photo de la Magistrale 2007 est disponible.

Puis fut le temps de la remise des diplômes, donc du passage sur scène et de la photo de la volée "Master in Computer Science Printemps 2007".

Et petite cerise sur le gâteau, qui est aussi l'aboutissement du travail régulier que j'ai fourni tout au long de mon travail de Master, j'ai reçu le prix de la Société Suisse des entreprises en qualité de deuxième meilleure moyenne du cycle Master de la faculté d'Informatique. Voilà une ligne de plus à ajouter à mon CV :)

samedi, 31 mars 2007

Camp de ski avec l'école primaire de Prez-vers-Noréaz

La semaine du 26 au 30 mars 2007 a eu lieu le camp de ski de l'école primaire de Prez-vers-Noréaz à Villars-sur-Ollon. Une semaine magnifique retransmise en mots et en images sur le site de l'école de Prez-vers-Noréaz.

mardi, 13 mars 2007

Travail de Master : quelques chiffres (suite)

Quelques chiffres supplémentaires pour mon travail et mon Master en général :

  • Note finale du travail de Master : 6 (sur 6 donc :))
  • Moyenne de Master (sur 93 crédits) : 5.79
  • Et pas une note en dessous de 5.
Je tenais juste à remercier Marius Erni, Dominique Bongard et Samuel Gmehlin grâce à qui j'ai réussi à me surpasser durant ces presque 2 ans de Master.

samedi, 24 février 2007

Bon anniversaire !

Avec pas mal de retard, hop une année de plus. Ca me fait maintenant 20 ans et 6 ans d'expérience :)

jeudi, 22 février 2007

Travail de Master : quelques chiffres

Rendu vendredi 16 février 2007 à 11h10 et défendu le vendredi suivant, soit le 23 février à 10h30, voici quelques chiffres au sujet de mon travail de Master :

Analyse et ingénierie inverse de récepteur satellite Free-To-Air


Le projet se déroulait sur 24 semaines, donc 120 jours. Retranchés des 8 jours de vacances dont j'ai pu jouir, ça nous fait 112 jours de travail effectif.

Au final un rapport de 70 pages, 17'426 mots pour 109'036 caractères, et une présentation de 45 minutes supportée par 44 slides encouragé par 300 visites de mon superviseur.

Mon projet c'est aussi 10'000 lignes de code réparties dans 4 projets (dont IDA Pro et Mame) écrites en 1000 heures de travail grâce à 100 litres de Coca-cola Light. C'est aussi 200 heures de trajets en voiture, 16'800 km parcourus sur l'autoroute A12 entre Matran et Lausanne-Blécherette, 384 mails envoyés en interne et 1640 mails en externe, donc une moyenne de plus de 27 mails envoyés par jour.

Tout cela pour un travail dont je suis entièrement satisfait, quant par le cadre de travail offert par l'équipe du CSO Office du groupe Kudelski que par les résultats intéressants que j'ai développés.

Et bien entendu la note finale que je vous laisse deviner reflète la qualité du travail :)

mercredi, 14 février 2007

Article de L'Objectif

Je suis dans le journal L'Objectif paru vendredi 9 février 2007. Je vous laisse découvrir l'article, en précisant que les noms correspondant à la photo sont faux. Il ne s'agit pas de Frédéric Neukomm derrière à gauche, mais bien Miguel Egger, un employé.



dimanche, 4 février 2007

Digression sur l'incohérence entre les discours et les actions

L'argent n'est pas une finalité, mais un moyen.
Cette phrase qui résonne dans ma tête depuis sa rédaction par Tristan Nitot, directeur de Mozilla Europe (voir l'article en question : les revenus du projet Mozilla), est le départ de cette digression sur mon dégout par rapport à la société capitaliste actuelle.

Quand un projet fonctionne, quel qu'il soit, tout le monde veut sa part du gâteau et en tirer les bénéfices. Les exemples sont nombreux. Ils passent par la Fondation Mozilla (discuté sur un précédent billet : La liberté a un prix), ou récemment en discutant avec mon père d'une jeune gymnaste à l'artistique, dotée d'un énorme talent, qui ne trouve pas d'entrainements adaptés à son niveau dans notre canton et qui s'entraine donc ailleurs, et concours maintenant sous les couleurs de cet autre canton. La finalité pour cette gymnaste est sa progression et son épanouissement, où elle s'entraine et qui elle représente n'est qu'une question de gout et de couleurs. La finalité dans cette histoire doit revenir à la jeune fille, et non pas à l'entraineur du club dans lequel par chance elle s'est présentée un jour... Ce genre d'attribution de finalité n'est que trop souvent appliqué. En politique je n'en parle même pas...

La question devrait plutôt être :

Quelle est la finalité de mon combat (action, engagement) ? Mon propre confort ou celui des autres, de la société, de celui/celle pour qui je me bats ou de ce pour quoi je me bats ? Est-ce que ça va plus me rapporter à moi qu'à la personne que j'aide ?

Est-ce que je suis le cheminement "Faites comme je dis et pas comme je fais" (cf les beaux discours sur l'environnement faits par des dirigeants venus en jet privés lors du WEF), ou "C'est l'intention qui compte" ?

Autant de points qui me révoltent en silence. Autant d'efforts gaspillés par les seuls caprices de gens plus fortunés... J'entendais à la radio un témoignage d'une personne concernant l'éventuelle introduction d'une taxe de circulation au centre de Montreux : "Moi je gagne très bien ma vie, et je me réjouis d'avoir les routes [du centre de Montreux] pour moi tout seul."
Ne comprenez vous pas dans ces propos les fondements même du socialisme ? Le partage des richesses, le cout de la vie en fonction du revenu ? Comment justifier la différence de la proportion de la TVA (de 7.6% chez nous) sur un litre de lait par exemple pour quelqu'un qui gagne 150'000.- par rapport à quelqu'un qui gagne 60'000 ? Tellement d'idée qui sont simplement balayées par des arguments populistes qui dit par exemple "Si vous votez pour nous, nous améliorerons les conditions de vie en limitant le chômage grâce au durcissant la loi sur les étrangers", mais en cachant à la vox populi que ce "nous" fera passer par la même occasion un tarif dégressif des impôts et des avantages fiscaux pour les grandes fortunes. Comment garder un avis objectif, un esprit critique quand la politique passe par du markéting de masse, ne tenant plus compte des idées à défendre mais les moyens mis en place pour la faire passer.

La vanité. C'est par ce nom que l'homme est mauvais. Par ce nom que l'homme pille peu scrupuleusement la planète. Par ce nom que l'homme est prêt à tuer son voisin si il peut y gagner une miette de terre. Par ce nom que certains hommes sont honteusement riche. Par ce nom que l'homme a asservi l'homme, qu'il a massacré l'homme, qu'il a violé l'homme.
C'est par ce nom que les bonnes actions ne durent pas longtemps et finissent par se transformer en corruption. C'est ce nom que je maudis tous les matins...

jeudi, 1 février 2007

PEAR::Mail_Queue2

C'est annoncé officiellement par le mainteneur actuel du projet, je prête mes 10 doigts pour le développement du paquet PEAR::Mail_Queue2, qui est une réécriture de PEAR::Mail_Queue. En effet ce dernier souffre, comme on peut le lire sur l'interface reportant les bugs, de problèmes internes assez ennuyeux et qui ne peuvent pas être corrigés sans casser la compatibilité arrière (backward compatibility, ou BC pour les intimes).

Comme le paquet PEAR::Mail_Queue est noté comme stable, la BC doit être gardée, d'où le paquet Mail_Queue2.

Au menu :

  • Destinataires multiples,
  • Processing concurrent,
  • Management des erreurs,
  • Meilleure gestion du buffer de queue,
  • Multithreading (!, mais uniquement pour Unix)
  • SMTP persistante,
  • ... (et tout ce qui me passera par la tête et sur la mailinglist) ...

jeudi, 25 janvier 2007

Tarpitting, ou comment faire perdre de l'argent aux spammers

Le tarpitting (désolé maman pour l'utilisation d'un mot d'anglais de plus dans mes billets) est un concept émergeant dans le domaine de la protection des mails.

Comme on s'aperçoit qu'on est mal embranché pour réduire la quantité de spam (voir We are loosing this war badly), des solutions en désespoir de cause se mettent petit à petit en place : autant essayer d'ennuyer le plus possible les spammers, en ajoutant un délai lors de la réception d'emails. La constatation est simple : si pour délivrer un mail, on ajoute un temps d'attente d'une seconde, l'utilisateur normal ne sera pas pénaliser car il n'est pas à une seconde près, mais le spammer qui envoie 1'000'000 de spam se verra pénaliser d'un million de seconde d'attente, soit plus de 11 jours. Bien sûr il peutva paralléliser l'envoi de ses mails, mais cela ne va réduire que linéairement son temps de pénalité.

De plus en plus de solution de la sorte voient le jour (principalement les systèmes de greylisting implémentent le tarpitting), et personnellement j'encourage fortement ce genre de solutions : si le mail courant est détecté comme du spam (pour éviter de reproduire ce couteux temps d'attente aux mailing "propres"), je temporise sa réception.

Spammers, chez moi vous allez perdre votre argent, car le temps, c'est de l'argent !

vendredi, 19 janvier 2007

De la sécurité des sessions PHP

Dans la majorité des espaces requierant une authentification sur un site web, le soin du suivi de l'utilisateur est laissé aux sessions, ces petits cookies qui viennent se placer chez le client afin de permettre à l'application web de le reconnaitre lors du passage à la page suivante.

Ce modèle de sécurité a du être imaginé à cause de la nature "connexionless" du protocole HTTP, c'est-à-dire la fermeture de la connexion TCP au serveur entre 2 chargements de page consécutifs (contrairement aux modèles de connexions "continues").

Malheureusement différentes techniques pour voler ces informations de sessions existent, elles se nomment credential token stealing, et sont souvent réalisables grâce à des failles de type XSS.

Cet article va expliquer quel est le point faible des sessions, ainsi que présenter une solution pour en améliorer la sécurité. Un exemple d'implémentation sera une fois de plus donné en PHP.

Problèmes des sessions

Le problème lié aux sessions est que l'identité de l'utilisateur, une fois identifiée, repose entièrement sur ce cookie. Si une personne malveillante parvient à obtenir la valeur du cookie, elle pourra alors se faire passer pour la personne légitime aux yeux de l'application.

Meilleure emprunte (fingerprint)

Une première amélioration est d'associer la valeur du cookie à d'autres éléments qu'une personne malveillante ne peut pas modifier : l'ip de connexion, la signature du navigateur, etc...
Tous ces éléments combinés ensemble donnent ce qu'on appelle l'emprunte de la session, et tous ces éléments sont nécessaires pour pouvoir usurper une identité. La principale difficulté est l'adresse ip de connexion, mais si la personne malveillante est sur le même sous-réseau que la personne légitime, l'adresse ip n'est plus un problème. Autre désavantage d'un fingerprinting étendu, si la personne légitime est sur une connexion à adresse ip dynamique, elle devra se réauthentifier à chaque changement d'adresse ip.

ID de session temporaire

Une autre amélioration est la regénération dynamique de la valeur du cookie. A chaque nouvelle connexion, on test si l'utilisateur est légitime, et on génère une nouvelle valeur qu'on lui envoie.
Si une personne malveillante arrive à voler un cookie, sa valeur ne sera que temporaire et dès le prochain chargement de page, la valeur volée devient obsolète.
Mais cela est aussi vrai à l'inverse, si la personne malveillante arrive à usurper l'identité avant que la personne légitime ne redemande une page, c'est la personne légitime qui sera déconnectée du site.

Implémentation en PHP

Une combinaison des 2 méthodes améliorera la sécurité des sessions, sans pour autant la rendre infaillible.

Voici une petite implémentation en PHP :

<?php
/*
* Inspirated from SecureSession class
* initially written by Vagharshak Tozalakyan <vagh@armdex.com>
*/
class SecureSession {

private $_check_browser;
private $_check_ip_blocks = 0;
private $_padding = '*ftt56+g zwc%&gh7/3-lf%254*6c_qm';
private $_regenerate_id = true;
private $_session_var_name = __CLASS__;

public function _construct($check_browser = true,
$check_ip_block = 0, $regenerate_id = true)
{
$this->_check_browser = $check_browser;
$this->_check_ip_block = $check_ip_block;
$this->_regenerate_id = $regenerate_id;

$_SESSION[$this->_session_var_name] = $this->_fingerprint();
$this->_regenerateId();
}

public function isValid()
{
$this->_regenerateId();
return (isset($_SESSION[$this->_session_var_name])
&& $_SESSION[$this->_session_var_name] == $this->_fingerprint());
}

private function _fingerprint()
{
$fingerprint = "";
if ($this->_check_browser) {
$fingerprint .= $_SERVER['HTTP_USER_AGENT'];
}
if ($this->_check_ip_blocks) {
$num_blocks = min(abs(intval($this->check_ip_blocks)), 4);
$blocks = explode('.', $_SERVER['REMOTE_ADDR']);
for ($i=0; $i<$num_blocks; $i++) {
$fingerprint .= $blocks[$i] . '.';
}
}
return sha1($fingerprint . $this->_padding);
}

private function _regenerateId()
{
if ($this->_regenerate_id && function_exists('session_regenerate_id')) {
session_regenerate_id(true);
}
}
}

?>

jeudi, 18 janvier 2007

A quoi juge-t-on qu'on est trop "geek" ?

Voilà que je me surprends à ajouter subtilement des ; à la fin des lignes d'une lettre de demande de congé pour l'armée...


Cette fois mes craintes se justifient : je suis vraiment un geek.

mercredi, 17 janvier 2007

Une authentification sur les serveurs smtp des providers

Non content de perdre la guerre du spam, les providers contre-attaques.

Relayé par Rags, voici le mail explicatif de Green :

Chers clients de green.ch

Dans le cadre d'un projet commun, les 4 grands fournisseurs de service internet en
Suisse (Bluewin, Cablecom, green.ch et Sunrise) mettent en place des mesures pour
combattre l'affluence massive des spams. La 1.ère étape est l'imposition de
l'authentification du serveur SMTP (Simple Mail Transfert Protocole). Cela signifie
que votre programme eMail, pour la récéption et l'envoi des emails, doit toujours
s'authentifier au niveau du serveur mail avec un nom d'utilisateur et mot de passe.

Il est possible que cela soit déjà le cas à votre niveau. Pour être sûr, nous vous
invitons à procéder à une vérification.

Le guide pour le paramétrage exacte ainsi que la configuration de votre compte eMail
se trouve ici: http://dtg.green.ch nous vous invitons à suivre la démarche pas à
pas.

Si vous utilisez exclusivement le Webmail pour vos eMails, vous ne devez rien
entreprendre.

Il est préférable d'effectuer le contrôle tout de suite afin de vous assurer que vos
eMails seront aussi envoyés à l'avenir.

Nous vous remercions de votre coopération.

Avec nos meilleures salutations

Votre équipe de support de green.ch


Les clients des providers vont donc immédiatement devoir modifier les paramètres de leur compte mail sortant afin d'y ajouter une authentification.

Cette authentification a deux effets :
  • premièrement elle est ABSOLUMENT INUTILE contre l'envoi de spam, puisque les malwares qui envoient du spam passent très majoritairement par des open-proxies, ou se connectent directement sur le smtp du MX du domaine.
  • deuxièmement elle force à avoir une adresse email @<super_provider_de_luxe>, ce qui rend les clients dépendant d'eux, car il est pénible de changer une adresse email déjà diffusée à tous ses amis/contacts. Elle empêche de ce fait le confort d'utilisation que nous fourni des adresses email comme Gmail (à noter que le webmail n'est pas touché par cette restriction).

A mon humble avis, cette solution a dû être trouvée par les économistes du top management et ne sert qu'à se donner un semblant de paraitre d'essayer de combattre le spam, tout en fidélisant de force leur clients.

De ce point de vue, chapeau, il n'aurait jamais été si facile de faire passer la pilule sans cet argument de combattre le spam. D'un point de vu efficacité réelle, autant dire que c'est même pas un pet de constipé dans l'eau, c'est de la poudre aux yeux sans poudre. J'espère simplement que vous, chers providers, avez pensé à renforcer vos équipes de
hotline
, et que vous les avez former pour répondre à la question : "Je reçois toujours autant de spam, que faire ?".

Je serais tellement content de pouvoir expliquer mon poing point de vue à un décideur d'une de ces entreprises...

mardi, 16 janvier 2007

Les 7 règles fondamentales en sécurité

Très souvent oubliées ou minimisées, voici les 7 règles fondamentales en sécurité :

  1. Least privilege : on ne donne que le privilege minimum
  2. Defense in depth : on protége à tous les niveaux
  3. Choke point : on emprunte qu’un seul chemin pour aller au but
  4. Weakest link : la sécurité globale est égale à la sécurité du maillon le plus faible
  5. Default deny : plutôt que d’énumérer les cas pas permis, au risque d’en oublier, on énumère les cas permis.
  6. User participation : on éduque les utilisateurs par rapport à la sécurité
  7. Simplicity : on applique le principe de simplicité
A appliquer sans modération !

lundi, 15 janvier 2007

Statistiques fournies par FeedBurner

Je suis relativement content de mon blog sur Blogger.com, les principaux problèmes que j'y vois sont :

  • Pas la possibilité de faire des trackbacks
  • Pas de statistiques de fréquentation.
Le premier problème n'a pas l'air prêt de se régler, le deuxième peut en revanche être contourner en passant par Feedburner.

Chose faite, il serait bien d'actualiser vos bookmarks de feed et s'abonner à http://feeds.feedburner.com/BenoitPerroud plutôt que l'alternative de Blogger.

dimanche, 14 janvier 2007

Form flooding

Les formulaires sont un des points vulnérables d'une application web, car c'est notamment à travers eux que les "clients" peuvent injecter des données dans l'application.

De plus, même si le formulaire est suffisamment protégé contre l'injection de données, qu'elle soit XSS, SQL, string format ou autre, le formulaire reste vulnérable à un flood :

Comment réagit votre formulaire si un client bien authentifié décide de poster 1'000'000 de fois le formulaire ?


Ce genre d'attaque peut avoir des effets très néfastes...

Il y a plusieurs méthodes pour s'en prémunir, et je vais en présenter une qui, contrairement au captcha, ne requiert pas d'intervention de la part de l'utilisateur (on ne peut pas faire de captcha dans un webservice...), mais protège tout de même notre formulaire.

On va donc attribuer à chaque formulaire un identifiant unique, qui est entré dans une table (ou en var de session) conjointement avec un timestamp. L'identifiant nous permettra d'éviter (au pire de remarquer) la soumission multiple du même formulaire, et grâce au timestamp, nous pourrons mesurer le temps entre le chargement de la page contenant le formulaire et son renvoi au serveur, temps qui ne devrait pas être inférieur à une voir plusieurs secondes pour un utilisateur humain, selon la taille du formulaire.

En recevant le formulaire, le serveur peut donc contrôler si :

1. Le formulaire est valide, i.e. l'identifiant du formulaire est valide
2. Le formulaire n'a pas été envoyé plusieurs fois.
3. Le délai de soumission du formulaire n'est pas trop élevé pour une session donnée.

L'implémentation de cette solution est elle aussi multiple, mais j'en donne un exemple ci-dessous :


__toString(); ?> ...
*
* if (isset($_POST)) {
* $canary = Form_Protector::factory($_POST);
* if (!$canary->is_valid()) {
* if ($canary->exists()) {
* // le canary n'existait pas dans la db, afficher un message d'erreur et recharger la page
* } else {
* // le formulaire a été posté trop rapidement, on peut donc compter le nombre de soumissions durant les 5 dernières minutes, et prendre une des actions suivante
* // --> soit on blacklist l'ip un moment,
* // --> soit on sleep(30) pour temporiser (tarpitting)
* }
* } else {
* // le canary est valide, tout est bien dans le meilleur des mondes.
* }
* }
*/

define("_TIME_TO_SUBMIT_FORM", 2); // temps que l'utilisateur fait pour submiter un formulaire
class Form_Protector {

protected $_canary;
protected $_ip;
protected $_date_request;
protected $_date_request;
protected $_exists = false;

public static $input_name = 'form_protector_canary';

protected function __construct($canary = 0, $ip = "") {
$this->_ip = $_SERVER['REMOTE_ADDR'];
if ($canary === 0) {
$this->_canary = rand();
$this->_insert();
} else {
$this->_canary = $canary;
if ($ip !== "") $this->_ip = $ip;
$this->_load();
}
}

protected function _load() {
$query = sprintf("SELECT * FROM form_protector
WHERE canary = %d AND ip = '%s'" . int_val($this->_canary),
mysql_real_secape($this->_ip));
// query,
// load $this->_date_request, $this->_date_request = time();
// si pas un champ est retourné, on passe $this->_exists à true; et on UPDATE ... SET date_response = $this->_date_request
}

protected function _insert() {
$this->_date_request = time();
$query = sprintf("INSERT INTO form_protector (canary, ip, date_request) VALUES (%d, %s, %d)", int_val($this->_canary), mysql_real_secape($this->_ip), $this->_date_request);
// query
// si pas d'erreur : $this->_exists = true;
}

public function is_valid() {
if ($this->_date_request + _TIME_TO_SUBMIT_FORM <>_exists;
}
public function __toString() {
return '<input value="' . $this->_canary . '" name="form_protector_canary" type="hidden">';
}

public static factory($params = NULL) {
if (is_array($params) && isset($params[self::$name])) {
$canary = $params[self::$name];
} else {
if ($params === NULL) {
$canary = 0;
} else {
$canary = $params;
}
}
return new Form_protector($canary);
}
}

?>

We are losing this war badly

Ou "Quand les RFCs sont trop difficiles à comprendre..."

Quand un serveur SMTP se connecte à un autre pour envoyer un mail, il doit s'annoncer. Cela fait parti du protocole SMTP définit dans la RFC 2821

- Connexion TCP à <server_destinataire> (telnet <server_destinataire> 25 pour simuler le comportent)
- HELO <server_name> (ou EHLO dans le cas de ESMTP)

Ce HELO <server_name> est une petite politesse introduite dans le protocole, mais qui permet, en plus de choisir la version de SMTP lors de l'échange, d'ajouter des tests pour détecter le spam.

En effet, à l'heure actuelle la plupart des moteurs SMTP utilisés pour envoyer du spam ne s'annoncent pas correctement. Le <server_name> est très souvent remplacé par une chaine de caractères aléatoires.
Si on part du principe qu'un serveur mail légitime a une adresse ip fixe, la correspondance entre l'ip inverse de <server_name> et de l'ip de la connexion du serveur serait un très bon test pour contrer le spam. Le problème devient un cauchemar quand même des providers ne configurent par correctement leurs serveurs SMTP :

Received: from smtp-auth-be-03.sunrise.ch (mail-proxy-be-01.sunrise.ch [194.158.229.48])
(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
by dns3.omne-serveurs.net (Postfix) with ESMTP id 342991EEE10
for ; Sun, 31 Dec 2006 02:16:16 +0100 (CET)


Dans cet exemple, il s'agit d'un serveur Sunrise qui s'annonce smtp-auth-be-03.sunrise.ch, et dont l'ip est 194.158.229.48. C'est presque juste, le seul détail est que le reverse de 194.158.229.48 est mail-proxy-be-01.sunrise.ch.

Received: from swip.net (mailfe05.tele2.ch [212.247.154.136])
by dns3.omne-serveurs.net (Postfix) with ESMTP id 0173F763C3C
for ; Wed, 10 Jan 2007 07:54:31 +0100 (CET)


Dans ce deuxième exemple, la configuration est pire : le serveur qui se connecte avec l'ip 212.247.154.136, s'annonce comme étant swip.net, alors que le reverse de swip.net est 212.247.156.1.

En résumé, parce que les personnes qui administrent des serveurs mails ne sont pas un peu plus scrupuleux, comme il est dit dans cet article
We are losing this war badly

jeudi, 11 janvier 2007

Nabuchodonosor, Roi de Babylone, écrivez-moi cela en 4 lettres.


Nabuchodonosor, Roi de Babylone, écrivez-moi cela en 4 lettres.


Cette expression est ma dernière signature en date, et comme d'habitude personne ne comprend son sens profond, alors je me vois contrains de l'expliquer.

Le but de cette phrase est de faire paraitre quelque chose compliqué alors qu'elle ne l'est en réalité pas (tout le monde peut écrire cela en 4 lettres : c e l a. Pas besoin d'être roi de Babylone pour le faire).

Il en est de même dans beaucoup de domaine de l'ingénierie, où des gens ont la fâcheuse tendance à compliquer des concepts simples (pour justifier leur travail, pour faire plus vendeur, ou pour n'importe quelle autre raison qui m'échappe). Il y a bien évidement des cas où cette complication est nécessaire (pour un obfuscateur de code source par exemple), mais retenons et appliquons la devise d'Albert Einstein :

Faites les choses aussi simple que possible, mais pas plus simple.

mardi, 9 janvier 2007

Optimisation du nombre de requêtes SQL dans les collections d'objets et relation n-m

L'orientation objet de PHP n'est plus contestable, mais les problèmes d'optimisation persistent.

Par exemple le malheureusement célèbre n+1 pattern, qui fait que pour afficher une liste de n objets, le + 1 étant la requête qui sélectionne tous les ids des objets à instancier, n + 1 requêtes SQL seront effectuées.

De même dans des relations n-m, la majorité des implémentations sélectionnent les n objets (en n + 1 requêtes donc), puis pour chacun on sélectionne les m objets de la relation. On obtient donc n * m + 1 requêtes.

Le but de cet article est de présenter deux techniques qui, combinées, réduisent les n * m + 1 requêtes en n + m + 1.

Les deux techniques que je vais illustrer ici se nomment object caching et grouped fetching. Elles se combinent très bien, ce qui permet d'optimiser drastiquement les performances d'un script PHP, du points de vue I/O (moins de requêtes), vitesse d'exécution et même mémoire utilisée (les objets ne sont pas dupliqués).

Object caching :

Le principe de l'object caching est de rendre le constructeur de l'objet privé (au pire protégé) et de l'instancier au moyen d'une factory. Puis on ajoute à la classe un tableau statique dans lequel les références des objets instanciés seront placés. La factory va donc regarder dans le tableau de références si l'objet existe, et si ça n'est pas le cas elle va le créer, l'ajouter au tableau et le retourner.


class A {
protected static $objects_cache = array();

public static function factory($id, $class = __CLASS__)
{
if (array_key_exists($id, $class::$objects_cache)) {
return $class::$objects_cache[$id];
} else {
$o = new $class($id);
$class::$objects_cache[$id] = $o;
return $o;
}
}
}


Cette solution pourrait encore être améliorée si les objets pouvaient être partagés entre toutes les instances de PHP. Ce n'est pas le cas à cause de l'architecture share nothing de PHP, et c'est un des points forts des serveurs d'applications.
Un autre désavantage de ce concept, si on a un script qui tourne suffisamment longtemps pour que le grabage collector se lance, est que tous les objets créés sont toujours référencés, même ceux qui pourraient être des candidats potentiels à la finalisation. Ce problème est résolu dans d'autres langages, en Java par exemple grâce aux références faibles (WeakReference).

Grouped fetching

Le principe du grouped fetching, dérivé d'une solution proposée par notre ami Colder, est de charger les données des objets de manière asynchrone et en bloque. Quand un objet est instancié, il est marqué comme non chargé, et sa référence est placée dans un tableau global de la classe. Puis lors d'un accès à un champ non chargé, la classe va sélectionner dans la base de données tous les objets instanciés mais pas encore chargés. Plus on retarde les accès aux attributs d'un objet, plus on va paralléliser les requêtes SQL.


class A {
private static $_to_load = array();
private $_is_loaded = false;
public function __construct($id)
{
$this->id = $id;
self::$_to_load[$id] = $this;
}

public function __get($attribut)
{
if (!$this->_is_loaded) {
self::_groupedLoad();
}
return $this[$attribut];
}

private function _setLoaded()
{
$this->is_loaded = true;
}

private static function _groupedLoad()
{
$ids = implode(', ', self::$_to_load);
$query = 'SELECT * FROM ' . self::$_table . ' WHERE id IN ( ' . $ids . ' ) ';
$res = db_query($query);
while ($row = $res->getNext()) {
self::_to_load[$row['id']]->_initByArray($row);
self::_to_load[$row['id']]->_setLoaded;
}
}
}


L'overhead de ce concept est très faible (un tableau de références supplémentaire), et le nombre d'accès à la base de données sont grandement réduit. Mais le problème de la finalisation des objets se repose aussi.

lundi, 8 janvier 2007

Lettre au père Noël

Trouvé sur linuxfr, tellement plein de vrai que je suis obligé de broadcaster :

Lettre au père Noël

dimanche, 7 janvier 2007

Samourai

Et voici un autre jeu à boire intéressant, appris sur le tas dans de sombres circonstances, et dont l'issue fut fatale pour plus d'un d'entre nous. Il s'appelle Samourai , et le principe est très simple : des personnes autour d'une table devant accomplir chacun leur tour une ou plusieurs actions.

Les actions sont simples, elles consistent à désigner la personne suivante à réaliser l'action, à boire un verre de vodka cul-sec réaliser un gage ou faire un action collective.

Le nom des actions étant normalement en japonais, je me permets d'y faire ici une transcription phonétique.

L'action la plus simple consiste à désigner son voisin direct par un coup de coude latéral, le poing du bras donnant le coup de coude dans la paume l'autre main, en criant "Hi-ha". La seule contrainte sur cette action est qu'elle doit se faire dans la même direction que le coup de coude reçu (donc on reçoit un coup de coude du coté gauche et on renvoie un coup de coude sur notre droite, respectivement le coté gauche de notre voisin).

La deuxième action permet de désigner n'importe quelle personne autour de la table. Cela se fait en tendant sa main bien droite en direction de cette personne et en criant "Katana".

L'action "Oups" permet de faire sauter le tour du voisin dans lequel l'action de se déplace. Elle se réalise en décrivant un cercle de la taille d'un ballon de foot avec ses 2 mains.

L'action pour bloquer le coup de coude et faire repartir le mouvement dans le sens contraire s'appelle "Wasaï". Elle se réalise en plaçant devant soi son avant-bras à la verticale et son poing contre son coude opposé, le tout en criant "Wasaï". Si on reçoit un "Hi-ha" par la gauche, on doit lever son avant-bras droite, de manière à avoir le coude gauche à l'horizontal pour répondre à son voisin de gauche.

Les 2 prochaines actions peuvent être exécuter en plus de l'action de base, et tous les autres joueurs doivent y répondre :
Si le jour crie "Aligato", les autres joueurs joignent leurs mains dans un signe de prière, s'inclinent vers le joueur qui a prononcé ce mot et réponde "Aligato san".
De même si le joueur crie "Samourai", les autres joueurs imitent l'action de resserrer un noeud autour de la taille en criant "Hou".

Puis vient le moment du gage. Le joueur qui exécute incorrectement un action cité doit donc boire un verre exécuter un gage. Avant son gage, il doit prononcer "Arakiri", que tout le monde doit applaudir, puis il doit remercier Yogi à la fin du gage. Si ces 2 parties du gage sont mal exécutées, le gage entier doit être refait.

Dernière action en date, similaire à "Katana", le joueur désigne un autre joueur en criant "Nikon". Le joueur visé doit alors viser un autre joueur en imitant d'avoir un appareil photo dans les mains et crie "click-clack".

A noter qu'il serait judicieux d'introduire progressivement les règles, avec dans l'ordre :

  1. "Hi-ha"
  2. "Wasaï"
  3. "Oups"
  4. "Samourai"
  5. "Katana"
  6. "Aligato"
  7. "Nikon"


Bonne guerre Bon jeu !

De l'art d'éviter les requêtes SQL inutiles

Dans le domaine de l'optimisation, une chose simple à faire est d'essayer de réduire au strict minimum le nombre de requêtes à faire à la base de données.

Je souhaite simplement rendre attentif au problème posé par les procédures embarquées et autres tirggers :

Dans le cas d'une mise-à-jour d'un objet mappé sur une table d'une base de données, les champs de l'objet sont remplacés (après nettoyage...) par ceux du formulaire. On pourrait donc penser qu'il est inutile de faire un SELECT juste après un UPDATE, car les données mises-à-jour sont celles fournies.

Cela est vrai sans compter sur les triggers déclenchés en cas de mises-à-jour : sans un SELECT après l'UPDATE, certains champs peuvent contenir des données fausses car non traitées par le trigger. Les champs auto-timestamp de Mysql sont un exemple tout simple de trigger à ne pas oublier...

jeudi, 4 janvier 2007

Bonne année (2007) !

Version geek :

<?php

if (date('n') === 1
&& ($day = date('j')) >= 1 && $day < 10) {
echo '<p>Bonne année ' . date('Y') . ' à tous !</p>';
}

?>


Version "Le Chat" :
Meilleurs voeux pour toute la vie.. Comme ça c'est fait une
fois pour toutes !