nyroBlog
Bannière NyroBlog, par Nyro
Image par Nyro - ?

Tag : Travail


Sortie de Filezilla 3

FilezillaParfois je regarde si les logiciels que j'utilise et qui n'ont pas de mise à jours automatiques sont sortis dans une nouvelle version.

Ce fut le cas la semaine dernière pour Filezilla et bonne surprise quand j'arrive sur le site : il a changé, avec un nouveau logo. Direction la partie téléchargement et ho, magique, ils ont sorti la version 3 !

Je m'empresse de la télécharger. Je l'installe et je lance : A première vue, pas beaucoup de changements, si ce n'est une impression de légéreté par rapport à la version 2.2.32 que j'utilise quotidiennement. Un petit tour dans les options. Oups, pas mal de fonctionnalités ont disparus apparemment, en laissant apparaître quelques nouvelles.

Direction le gestionnaire de sites, et là, bonne surprise, les mêmes options avec quelques minimes ajouts, et la configuration avancé se fait par onglet et non plus dans une nouvelle fenêtre, ce qui est plus pratique à l'utilisation.

Pour tester tout ça, il va falloir que je transfert mes settings de sites actuels. Il est inconcevable pour moi de tout retaper à la main. Un petit tour sur google et le forum de filezilla pour trouver qu'il suffit simplement d'importer le filezilla.xml de l'ancienne version. Parfait. Je teste, et alerte : En raison de différences dans le format des données, seuls les paramètres host, port, utilisateur et mot de passe seront importés. Oups, ça me plaît pas ça. En effet, pour quasiment tous les sites j'ai paramétrer le dossier local et distant pour arriver directement, certains doivent utiliser le PASV Mode etc...

Bon je teste quand même. Ca marche, c'est joli et toujours cette sensation de gain en poids. je double-clique sur un fichier, pensant l'éditer comme configurer dans mon ancienne version. Le fichier part en téléchargement. Ah bon ok, allons paramétrer ça dans la configuration. Je cherche, je cherche et je ne trouve pas. Cette fonctionnalité n'est tout simplement pas implémenter dans cette version pour le moment. Mais elle est très demandé sur le forum, donc elle ne devrait pas tardé. Parmi les changements dans l'interface, l'affichage des listes d'attentes a été amélioré. On a maintenant 3 onglets en bas : Fichiers dans la file d'attente, Transferts échoués et Transferts réussis. Le dernier est donc tout nouveau puisqu'avant on avait aucune historisation des fichiers envoyés. un bon point. Par contre, pour les échoués, il faut penser à regarder tout en bas afin de voir si le nombre de fichiers échoués est apparu, affiché l'onglet, clique-droit sur les fichiers pour les remettre dans la file d'attente, afficher l'onglet des fichiers dans la file d'attent et traité cette file d'attente. Un peu plus laborieux au début, mais ça sera sans doute plus aisé après un temps d'adaptation.

Et puis ce problème de configuration m'embête vraiment. Je cherche sur google ou le forum de filezilla. Je trouve un script en PHP qui à première vue ne fait pas les changements de versions, il se charge juste de réécrire les données dans le bon format XML, sans trop chercher plus loin. Qu'à cela ne tienne, je ferai le mien.

Pour le faire, j'ai tout simplement ouvert les fichiers de configuration de chaque version dans mon éditeur de texte favori, Notepad++. Je change un paramètre dans la 2.2.32, le même changement dans la version 3 (ou l'équivalent) et je paramètre mon script PHP pour prendre en compte ces changements. J'ai un peu galéré pour les mots de passe. En effet, dans la version 2, ils sont crypté. Crypter est un bien grand mot, puisque le cryptage n'est pas propre à chaque ordinateur, mais gérer en dur dans la programmation de Filezilla, avec une clé, FILEZILLA1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ. Cette clé est donc connue de tous, puisque Filezilla est Open source.

Qu'en est-il dans le version 3 ? Les mots de passe ne sont tout simplement pas crypté. Après réflexion, c'est vrai que ce n'est pas vraiment utile puisque déjà dans la version 2, ils sont décryptables très facilement. Petite recherche d'une fonction de décryptage. J'en trouverai sur le forum en VB .Net et Javascript, mais pas en PHP. Ok, j'utiliserai la version JavaScript pour la porter en PHP, et tout ce passera bien.

Après une heure environ de recherche tout doucement pour être sûr d'avoir les bons transferts, le script de transfert des settings est en place. Petit message sur le forum de Filezilla pour le proposer à qui le veut.

Bien sûr, les sources PHP5 sont disponibles.

En résumé : Vous pouvez tester cette dernière version de Filezilla mais vous devrez sans doute attendre de faire un passage définitif vers cette version. Je suis revenu à l'heure actuelle sur la version 2, surveillant bien tranquillement le RSS et le forum du projet.

Scriptaculous : Callbacks de l'effet Shake.

Comme j'ai oublié mes photos de ce week-end (à Beverly Hills), un petit poste programmation.

Je m'amuse avec Scriptaculous pour faire des retours d'informations intéressants aux utilisateurs. Durant mes tests, je me suis rendu compte que les callback que je donnai à l'effet Shake n'était jamais exécuter.

Un petit tour dans le fichier effects.js et je me rends compte que rien n'est fait pour le faire. En effet, l'effet Shake est simplement une combinaison de 6 effets Move les uns après les autres, dans des sens différents. Et les options de callback données à l'effet Shake ne sont pas retranscrit à chacun d'entre eux.

Qu'à cela ne tienne, voici le bout de code permettant de palier à ça (dont la modification de ce fameux effet) :

Effect.combinedOptions = function(options) {	
	var ret = {
		start:{},
		update:{},
		finish:{}
	};
	
	if (options.beforeStart)
		Object.extend(ret.start,{'beforeStart':options.beforeStart});
	
	if (options.beforeUpdate) {
		Object.extend(ret.start,{'beforeUpdate':options.beforeUpdate});
		Object.extend(ret.update,{'beforeUpdate':options.beforeUpdate});
		Object.extend(ret.finish,{'beforeUpdate':options.beforeUpdate});
	}
	if (options.afterUpdate) {
		Object.extend(ret.start,{'afterUpdate':options.afterUpdate});
		Object.extend(ret.update,{'afterUpdate':options.afterUpdate});
		Object.extend(ret.finish,{'afterUpdate':options.afterUpdate});
	}
	
	if (options.afterFinish)
		Object.extend(ret.finish,{'afterFinish':options.afterFinish});
	
	return ret;
}

Effect.Shake = function(element) {
  element = $(element);
  var options = Effect.combinedOptions(arguments[1] || {});
  var oldStyle = {
    top: element.getStyle('top'),
    left: element.getStyle('left') };
  return new Effect.Move(element, 
      Object.extend(options.start,{ x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      Object.extend(options.update,{ x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      Object.extend(options.update,{ x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      Object.extend(options.update,{ x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      Object.extend(options.update,{ x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      Object.extend(options.finish,{ x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
        effect.element.undoPositioned().setStyle(oldStyle);
  }})) }})) }})) }})) }})) }}));
}

Le combinedOptions prendra donc en paramètre l'objet option de l'effet Shake pour en ressortir un autre, dans lequel on aura inséré les callback nécessaires selon si l'effet Move est au début, au milieu ou à la fin de l'effet Shake.

Et voilà, c'est tout bon maintenant.

A mon avis ce bug existe pour beaucoup d'autres effets de combinaisons, vous pouvez employer la même technique (et la combinedOptions pour les corriger). J'ai soumis le code sur le wiki de scriptaculous.

Je n'avais jamais testé auparavant Scriptaculous et prototype. C'est une nouvelle façon de voir le javascript et c'est tellement agréable de coder avec ces framework que je crois que je ne pourrai plus m'en passer, après seulement quelques jours d'utilisation...

PHP : un système de cache très simple et efficace

Lorsqu'on doit lister des éléments provenant d'une base de données avec énormément de liaisons dans la requête, le traitement prend quelques secondes et le serveur en prend un coup à chaque affichage de page.

Pour palier à ça, il faut mettre en place un système de cache des pages de listing.

Un système de cache consiste en l'enregistrement de la page une fois totalement traitée (donc ce qu'on affiche, le code HTML final) puis à le ressortir lors de l'appel suivant de la même page. Bien sûr, dans tout bon système de cache, on peut spécifier la durée de vie de ce cache (1 heure par exemple) pour qu'il soit effacé au delà et remplacé par un nouveau.

Avec ceci, on gagne donc en ressource serveur (beaucoup moins de connexions vers le serveur MySQL) mais les pages affichées ne sont pas synchronisées à l'instant T, on a 1 heure maximum de décalage. Même si ce n'est pas énorme, ce peut être handicapant dans certains cas, il faut le garder à l'esprit.

Pour un site que j'ai mis en ligne samedi dernier, qui utilise jusqu'à 11 tables dans ses listings, j'ai dû mettre en place un tel système pour gagner en temps d'affichage. L'avantage est que les listings changent une ou deux fois par jour au grand maximum, pas du tout pour la plupart. Le temps du cache est donc pour l'instant d'une heure, mais il est possible que je le monte à 2 voir 3 heures.

Pour mettre en place un tel système, j'ai regardé s'il n'existait pas un bout de code ou une classe sous licence GPL prête à l'emploi. Après quelques googlisations, j'ai trouvé mon bonheur.

Un petit tour dans le code pour changer le dossier d'enregistrement du cache afin de le rendre inaccessible depuis le site, et pour voir comment il générait ses noms de cache.

Il utilise simplement l'URL de la page demandée, y ajoute tous les paramètres donnés en GET et en fait le MD5 (pour avoir toujours la même longueur de nom fichier et pas de problèmes avec des caractères spéciaux) et y donne l'extension .cache.

Le gros plus de cette classe, c'est qu'elle permet de mettre en cache la page PHP zone par zone. On peut ainsi imaginer une page avec une partie sans cache (le menu avec les infos de connexion par exemple), une partie avec un cache d'une heure (un listing qui change assez souvent) et une partie avec un cache d'une journée (un classement journalier par exemple).

De plus, si vous voulez forcer la reconstruction du cache, il suffit de mettre le paramètre rebuild en GET dans l'URL de la page.

Une classe à ajouter à votre librairie de toute urgence ! (et le site dans vos favoris...)


Modification de décembre 2010

Comme le fichier n'est plus accessible depuis le lien donné plus haut, voici le fichier que j'avais gardé dans mes archives.

PHP/MySQL : Mettre en place des catégories sur différents niveaux

On a toujours besoin de trier ses produits, articles, billet ou autres dans des catégories.

Si on en a beaucoup, on veut pouvoir d?finir plusieurs niveaux de catégories.

Je vais vous montrer ici comment on peut simplement gérer différents niveaux de catégories. Par exemple, on peut avoir :

Auto-Moto
Auto
Berline
4x4
Coupé
Moto
125
250
Immobilier
Location
Achat

On voit ici qu'on peut aller jusqu'à 3 niveaux de profondeur (Berline ou 125 par exemple) mais qu'on a aussi des catégories au 2ème niveau (Location). Avec un nombre fixe de niveaux, c'est assez simple : une table MySQL pour chaque niveau, avec chacun un identifiant vers sa catégorie mère et le tour est joué. Là, nous allons devoir faire autrement.

1) La table MySQL
Pour commencer, voici la structure de la table MySQL que j'utilise :

CREATE TABLE cat (
id_cat int not null auto_increment primary key,
rid_cat int default '0',
nom varchar(50) not null
);

id_cat : identifiant unique de la catégorie.
rid_cat : clé étrangère, qui fait référence à la catégorie mère, s'il y en a une.
nom : le nom de la catégorie.

Avec cette table, n'importe quel élément qui doit être rattaché à une catégorie le sera avec son id_cat, indifférement de son niveau, puisque toutes les catégories sont stockées dans cette même table.

Maintenant que la façon de stockée ces catégories est en place, voyons comment tirer parti de cette structure

2) La récupération des catégories mères
Pour la navigation, il est toujours agréable de mettre en place en haut de la page le cheminement des catégories depuis l'accueil.
Par exemple Accueil > Auto-Moto > Auto quand on se trouve sur la page des autos, avec un lien sur chaque intitulé pour revenir sur la page concernée.

Pour récupérer toutes les catégories mères d'une catégorie donnée, nous allons utiliser une fonction récursive. Les mathophobes, rester avec nous, il n'y a pas de grands rapports avec les suites ou séries mathématiques que vous connaissez. Le rapport vient du fait que cette fonction va faire des appels à elle-même pour avancer dans la hiérarchie. Voici cette fonction PHP :

function recupMere($idCat) {
$data = mysql_fetch_array(mysql_query("SELECT id_cat,rid_cat,nom FROM cat WHERE id_cat='$idCat'"));
$ret = '';
if (!empty($data['rid_cat'])) $ret = recupMere($data['rid_cat']).' > ';
$ret.= $data['nom'];
return $ret;
}

En fait, on continue la recherche de la mère tant que rid_cat n'est pas vide. A chaque nouvelle catégorie rencontrée, on concatène avec > comme séparateur pour arriver au résultat escompté.

3) La récupération des catégories filles
Pour la première fonction, la simplicité venait du fait qu'une catégorie a 0 ou 1 catégorie mère, ce qui permet de créer la chaine simplement. Pour récupérer les filles, c'est un peu plus compliqué selon ce qu'on veut en faire. Voici par exemple une fonction permettant de créer une liste déroulante avec toutes les sous-catégories de la catégorie demandée :

function selFilles($idCat=0, $mere='') {
$ret = '';
$req = mysql_query("SELECT id_cat,nom FROM cat WHERE rid_cat='$idCat'");
while ($row = mysql_fetch_array($req)) {
$ret.= ''."\n";
$ret.= selFilles($row['id_cat'],$mere.$row['nom'].' > ');
}
return $ret;
}
Le premier paramètre sert à spécifier la catégories à partir de laquelle on veut afficher les sous-catégories. Par défaut il vaut 0, ce qui veut dire qu'on afficherait toutes les catégories de la base. Avec notre exemple, on obtiendrai ceci :
Le second paramètre est utilisé pour conserver le chemin parcourut jusque là. On aurait pu aussi rappeler la première fonction, mais on économise ainsi des requêtes MySQL, autant ne pas s'en priver !

Bien sûr, on peut imaginer des autres applications, pour sortir les catégories dans un fichier XML pour une utilisation dans Flash par exemple.

Vous pouvez télécharger les sources, avec quelques exemples et la base de donnée utilisée dans l'exemple.

Si vous avez d'autres idées ou suggestions pour cet article, n'hésitez pas, les commentaires sont là pour ça.

Un peu de lightbox dans Dotclear

Si je poste moins en ce moment, c'est que je suis en pleine préparation de mon voyage à Los Angeles.

Beaucoup d'amis m'ont demander de tenir à jour ce blog, avec notemment un max de photos. J'ai donc décider d'installer un plugin sur mon dotclear pour que ce soit plus sympa à regarder.

Je me suis tourner vers une solution intégrant lightbox car je le trouve très bien, et son code est propre.

Le plugin que j'ai donc installé (et que je teste avec ce billet) et donc clikimage qui permet d'intégrer des images depuis son disque dur ou une url, avec création de vignettes ou non. L'affichage en grand peut se faire dans une popup HTML ou un light box.

Pour utiliser le lightbox, il vous faudra installer un autre plugin simplement nommé lightbox que vous trouverez ici.
NB : Une petite erreur s'est glissé dans ce plugin, pour affiche l'image de loading et l'image d'erreur. Pour la corrigé, il faut modifier le fichier dotclear/ecrire/tools/lightbox/js/lightbox.js aux lignes 62 et 63 pour rajouter un / devant les urls des images, et il n'y a plus de problèmes. (ou bien indiquer le chemin complet depuis la racine de votre site)

Voici le résultat avec quelques une de mes photos du 14 juillet, hébergés sur FlickR : 14 Juillet 01 14 Juillet 02 14 Juillet 03 14 Juillet 04 14 Juillet 05 14 Juillet 06 14 Juillet 07 14 Juillet 08 14 Juillet 09



Le résultat est très satisfaisant, non ?