Computing hashes in PHP

I've done a little benchmark of PHP5's hashing functions, and especially the two most widely used hashing algorithms: MD5 and SHA-1. Results are surprising: PHP's default methods (namely, md5() and sha1()), aren't optimal at all... although there are faster equivalents included in one of the modules activated by default since PHP 5.1.2! The hash module offers functions to compute hashes of strings (hash()) or files (hash_file()), and even incremental (streaming) hashes, or HMAC keyed hashes!

My benchmark was done on a quad-Xeon machine, running Debian, with many custom-built packages; so take the results for what they are: the representation of a particular situation. The general conclusions drawn from the test are widely-applicable, though. SHA-256 hashing is included to show that even more complex hashing algorithms are executed faster than simpler ones using the default PHP functions. Please note that there is no "native" function to compute SHA-256 hashes in PHP.

Comparison of hashing functions in PHP

Lire la suite

Transférer un dépôt Subversion

Petit mémo rapide sur comment transférer un dépôt Subversion entre deux machines (par exemple) :

svnadmin dump /chemin/actuel/du/dépôt > dépôt.dump

Cette commande crée un "dump" du dépôt, qui inclue tous les fichiers et toutes les révisions (et donc peut être assez long à générer et conséquent en taille).

On transfère ensuite le fichier (scp, FTP, clé USB, pigeon voyageur...), et sur l'hôte de destination :

svnadmin create /chemin/du/nouveau/dépôt
svnadmin load /chemin/du/nouveau/dépôt < dépôt.dump

Et voilà !

Cachez cette requête que je ne saurais voir...

Une erreur idiote sur les requêtes MySQL : faire des calculs à la seconde près alors qu'on en a pas besoin.

Je m'explique. Soit une table d'article, on veut ceux de la semaine en cours :

SELECT * FROM articles
WHERE created_at >= <debut de semaine>;

On peut calculer <debut de semaine> de la manière suivante avec MySQL :

SELECT DATE(NOW() - INTERVAL WEEKDAY(NOW()) DAY)
AS debut_semaine;

En gros, on cherche la date (ie YYYY-mm-dd) du lundi comme la date du jour (NOW()) à laquelle on soustrait n jours, n étant égal au jour de la semaine (la numérotation commence à 0 pour le lundi). La fonction DATE() qui englobe le tout permet de comparer par rapport au lundi à minuit (par défaut, sans heure précisée, une date est considérée comme prise à minuit).

C'est bien joli tout ça... Mais les performances sont pourries. La requête prend chez moi 0.45 ms en moyenne, contre 0.15 ms pour les autres requêtes, qui sont parfois plus compliquées que cette requête. Pourquoi donc ?

Tout simplement parce que les autres requêtes sont effectuées contre le cache de MySQL, alors que celle-ci doit être recalculée à chaque fois. Pourquoi donc ?

A cause de NOW(), qui impose une précision inutile à la seconde (ou pire)... NOW() doit donc nécessairement être recalculée à chaque requête.

En pratique, est-ce que nous avons besoin d'une précision à la seconde ? Non. On cherche juste les articles de la semaine, donc qui datent de lundi minuit au maximum. Deux solutions s'offrent à nous : précalculer dans notre code la valeur de cette date butoir, ou bien utiliser CURDATE(), qui ne renvoie que la date actuelle, à la place de NOW(). Je précise que je n'ai pas testé la deuxième solution. J'ai choisi la première qui, codée en PHP, présente l'avantage d'être plus élégante.

munin-merger 1.0

Munin Logo

One annoying thing with Munin is that if you have more than one Munin central node to process the individual Munin nodes data, it's quite a pain in the neck to go and check them all.

Here comes munin-merger that takes as an input a list of Munin summary pages (accessible through HTTP, optionally password-protected), and output a merged version of the summary, containing every host analyzed by every Munin server, grouped by domain name.

You can download version 1.0 here: TAR.GZ | README.

GPG error : NO_PUBKEY sur apt-get update

Quand apt-get update vous sort des messages du genre :

W: GPG error: http://security.debian.org testing/updates Release: Les signatures suivantes n'ont pas pu être vérifiées car la clé publique n'est pas disponible : NO_PUBKEY numéro-de-clé

Mise à jour

Sur des versions récentes de Debian/Ubuntu :

sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com numéro-de-clé

Ancienne solution

La solution est sur le wiki Debian :

$ gpg --keyserver pgpkeys.mit.edu --recv-key numéro-de-clé
gpg: requesting key numéro-de-clé from hkp server pgpkeys.mit.edu
gpg: key numéro-de-clé: public key "Debian Archive Automatic Signing Key (2006) <ftpmaster@debian.org>" imported
gpg: Total number processed: 1
gpg:               imported: 1

$ gpg -a --export numéro-de-clé | sudo apt-key add -
gpg: no ultimately trusted keys found
OK

Transcription :

  1. On cherche la clé numéro machin sur un serveur de clés. Attention ! La clé donnée par apt-get est souvent plus longue que nécessaire : il faut se fier au numéro donné par la première commande en sortie (c'est la fin du numéro donné par apt).
  2. On exporte ensuite la clé, et on la donne à manger à apt-key, qui gère les clés GPG d'apt.

Et voilà !

Visiblement je peux pas m'empêcher de geeker

Un truc super pratique que j'ai découvert en tapant le post précédent : pour éviter d'avoir des lignes qui débordent, alors qu'on pourrait les couper (au tiret, par exemple), mais que Firefox ne le fait pas : Unicode vient à la rescousse !

En effet, le caractère "​" (code 200B), dénommé "Zero Width Space" (ZWSP), permet d'insérer une "possibilité d'espace", c'est-à-dire une espace sans châsse, invisible, mais qui permet le passage à la ligne si besoin :

​​This character is intended for line break control; it has no width, but its presence between two characters does not prevent increased letters spacing in justification.

Et ça marche !

C'est​...​Supercalifragilisticexpialidocious​!​C'est​vrai​que​ce​mot​trop​long​est​parfait'ment​atroce​Mais​faut​l'dire​et​vous​s'rez​à​la​page​et​plus​précoce,​Supercalifragilisticexpialidocious​!

(extrait de la chanson "Supercalifragilisticexpialidocious" du film "Mary Poppins")

Toutes les espaces de cette chanson ont été remplacés par des ZWSP, ainsi que les retours à la ligne.

Mémorandum Subversion, révision 2

Version courte du mémorandum.Le système de contrôle de révisions SVN utilise HTTP et WebDAV, deux standards pré-existants, pour transmettre ses données

Structure du repository

/
/branches/
/tags/
/trunk/
  • branches = versions en développement.
  • tags = versions gelées (= releases).
  • trunk = branche principale de développement.

Opérations sur les fichiers

Ajouter un/des fichiers/répertoires.

svn add nouveau

Copier un fichier/répertoire.

svn copy depuis vers

Supprimer un/des fichiers/répertoires.

svn delete vieux

Déplacer un fichier/répertoire.

svn move depuis vers

Opérations sur le dépôt

Récupérer une version de travail.Les actions de base réalisables sur les fichiers (hors édition)

svn checkout url

Import initial.

svn import dossier

Créer un dossier.

svn mkdir dossier

Mise à jour de la version locale par rapport au dépôt.

svn update

Opérations sur les changements

Envoyer un ensemble de changements au dépôt.

svn commit

"Diff" entre deux fichiers ou deux révisions d'un fichier.

svn diff

Liste des changements (historique).

svn log

Fusion des changements entre deux versions, deux branches...

svn merge

Signaler la résolution d'un conflit.

svn resolved

Annuler les modifications sur un fichier/répertoire de la copie locale.

svn revert

Liste des changements entre la version locale et le dépôt.

svn status

Mémorandum Subversion

Création du repository

Pour créer un nouveau projet dans un repository existant, avec comme structure :

|
|- /
   |
   |- mon-appli/
      |
      |- trunk/
      |- branches/
      |- tags/

C'est l'arborescence typique d'un repository Subversion. S'il n'y a qu'une seule application dedans, les répertoires trunk/, branches/ et tags/ sont à la racine, soit :

|
|- /
   |
   |- trunk/
   |- branches/
   |- tags/

Le path vers le repository est donc de la forme : http://www.example.com/repository/mon-appli. La partie avant "mon-appli" est variable, et dépend du serveur (ce peut être un "serveur" local, donc avec une URL en file:///, ou bien un serveur WebDAV - HTTP, quoi -, avec une URL en http://, ou bien https:// si la connexion est encryptée en SSL). Voir avec le "fournisseur" du repository pour l'URL exacte.

On crée donc l'arborescence en local, mais pas son contenu. Le plus simple est de se placer dans un dossier vide, dont le nom et la position importe peu, qui représente la racine du repository. On a donc (dans le cas de la première arborescence présentée) :

|
|- /home/moi/
   |
   |- mon-appli/
      |
      |- trunk/
      |- branches/
      |- tags/

Dans le répertoire /home/moi/, on tape :

svn import . http://www.example.org/repository

NB: le . représente le répertoire local (comme d'hab', quoi).

Et voilà ! On efface ensuite l'arborescence (voilà pourquoi il ne fallait pas y mettre de fichiers ;) ), et on "check out" une "working copy" toute neuve là où on veut bosser dessus. Il est plus pratique de ne récupérer que le trunk/ (les autres répertoires servent rarement, et on peut de toutes façons "travailler" dessus comme on en a besoin par leurs seules URL).

Accès au repositoryURL

Pour faire un "check out" d'une "working copy" (récupération d'une copie de travail) :

svn checkout http://www.example.org/repository/mon-appli/trunk

Ensuite, si on a des répertoires dans son arborescence de projet (dans le trunk/, par exemple) :

|
|- trunk/
   |
   |- tata/
   |- toto/
   |- tutu.txt

On peut accéder à n'importe lequel de ces répertoires (et en obtenir une "working copy" - copie de travail) par l'URL (pour l'exemple de toto/) :

svn checkout http://www.example.org/repository/mon-appli/trunk/toto

Modifications sur les fichiers en local

Pour modifier le contenu d'un fichier : utiliser son éditeur de texte / graphique / nawak préféré.

Pour ajouter un fichier au repository (après l'avoir créé) :

svn add fichier

Pour supprimer un fichier (avant de le supprimer physiquement - en fait à la place, puisque Subversion s'en charge) :

svn delete fichier

Pour déplacer un fichier (mêmes conditions que pour supprimer) :

svn move depuis vers

Pour copier un fichier (mêmes conditions) :

svn copy depuis vers

Qu'est-ce que j'ai fait ?!

Pour savoir quelles modifications on a apportées à la "working copy" (avant de faire un commit) :

svn status

Cette commande renvoie une liste des fichiers modifiés dans le répertoire courant (ou dans le dossier spécifié à sa suite, ou bien encore un seul fichier si c'est le path d'un fichier qui a été donné), préfixés de signes plus ou moins cabalistiques :

  • A : à ajouter au repository.
  • C : en conflit (changement en local + changements en même temps sur le repository).
  • D : à supprimer du repository.
  • M : élément modifié.
  • ? : élément non géré par Subversion.
  • ! : élément absent (suppression d'un fichier sans svn delete, par exemple).
  • I : élément ignoré par Subversion.

Pour faire un "diff" (format standardisé pour visualiser les changements ligne à ligne entre deux fichiers texte) :

svn diff
svn diff fichier
svn diff --revision 1:2 fichier

Dans l'ordre :

  • Diff sur tout le répertoire.
  • Diff sur le seul fichier (on peut aussi spécifier un répertoire à la place).
  • Diff sur le seul fichier pour les révisions 1 et 2.

Pour annuler des changements, et revenir à la version du repository :

svn revert

On peut également passer un fichier ou un répertoire ou un numéro de version.

Mise à jour de la working copy

svn update

Attention ! svn update est différent de cvs update. La version CVS de la commande permet de voir quels sont les changements qui ont été apportés à la "working copy". Dans le monde de SVN, il faut utiliser svn status pour ça. svn update met à jour votre version locale par rapport au repository distant !

And open APIs are sooooooooooo fine!

J'ai fait mon premier programme C qui serve vraiment à quelque chose (et non pas un simple "HelloWorld!"). Alors voilà, c'est basé sur libxml2 par Daniel Veillard, et ça processe les XIncludes (ou en français). Bon, c'est sûr, dans la catégorie truc-de-la-mort-qui-tue-les-canards-à-trois-pattes, on a vu mieux, mais bon ! Je suis 'achtement fier quand même :D ... même si, bon, en fait, c'est surtout une application de l'API libxml2... et que j'ai récupéré une partie du code dans les tutos du site de libxml2 (très bien fait, d'ailleurs). Et ça se compile (sous Debian, avec toutes les dépendances qui vont bien installées, principalement libxml2-dev), avec gcc -I/usr/include/libxml2 -lxml2 -o xincludeproc xinclude.c.

Lire la suite

Memorandum diff / patch

Pour faire un diff sur un fichier :

diff -u ancien nouveau > machin.diff

Pour appliquer le diff :

patch ancien machin.diff

Et pour être sûr de ne pas se tromper, à partir d'un zip :

unzip machin.zip
diff machin/machin.php machin-modifié/machin.php > machin.php.diff
rm -R machin
unzip machin.zip
patch machin/machin.php machin.php.diff

Où machin.php est, par exemple, la version "officielle" d'un programme, et l'arborescence :

|
|- /home/moi/
   |
   |- machin-modifié/
   |- machin.php.diff
   |- machin.zip