:-y

Le premier utilisateur de KrISS blog autre que moi-même :-)

jeudi 26 juillet 2012 - 17:31

Je pensais vous écrire un petit article demain avant les vacances pour vous parler des news concernant KrISS feed, mais je n'ai pas pu attendre, car je viens de tomber sur Azikan, le premier utilisateur de kriss blog !

Évidemment, mon premier sentiment a été la joie, mais ensuite, je me suis vite rendu compte que je n'avais pas commité les modifications qui corrigeaient les bugs découverts au fil des discussions concernant KrISS feed.

Voilà qui est chose faite et je vous présente donc la version 4 de KrISS blog qui en plus de corriger quelques rares et exceptionnels bugs... possède la nouvelle sauvegarde automatique des éditions d'articles vachement plus KISS que ce que j'avais mis en place avec javascript. Le principe est simple quand on poste un article en cours d'édition et qu'entre temps, nous avons perdu la connexion (car oui, ça peut être long pour écrire un article), au lieu de perdre l'article, ça le stocke dans une variable de SESSION. Transparent pour l'utilisateur, il retrouvera son article en se reconnectant. Elle est pas belle la vie.

À demain pour quelques informations concernant KrISS feed.

Ma vision du KISS pour KrISS feed

lundi 02 juillet 2012 - 18:53

La première fois que j'ai entendu parlé du principe KISS, c'était en lisant les discussions du projet shaarli de Sebsauvage.

Si l'acronyme peut vouloir dire beaucoup de choses, la notion qui se cache derrière est tout à fait simple et compréhensible. Je pense aussi que cette notion est relative. Je vous avais parlé de Leed annoncé comme KISS et que j'avais envisagé pour me passer de Google Reader. Leed utilisait SQLite (maintenant MySQL) et pour moi, ce n'était pas suffisamment KISS.

Je suis plutôt d'accord avec la définition du principe KISS de Idleman et des commentaires qui complètent sa définition. Je vais quand même vous donner ma vision du KISS pour kriss feed et ne je ne vais donc pas vous parler des nouvelles fonctionnalités (même si j'ai corrigé la lecture de certains flux qui définissent les namespaces dans chaque balise plutôt que dans la balise racine, et si j'ai amélioré certains comportements concernant la mise à jour en mode show et le fait de ne plus avoir à appuyer deux fois sur 'n' quand de nouveaux articles apparaissent) :

- pour les utilisateurs finaux, je compte laisser un unique fichier à télécharger car je pense que c'est le plus simple et qu'il n'y a pas besoin que ce soit plus compliqué ;

- pour la partie développement, j'ai ajouté sur github le dossier contenant les sources qui permettent de maintenir kriss feed beaucoup plus facilement. J'ai utilisé les standards Symfony et Zend que j'ai fait valider grâce à phpcs (il faut ajouter le standard Symfony qui n'y est pas par défaut). J'ai commenté les sources afin de générer une petite documentation et ajouté un script bash permettant de compiler le fichier index.php pour les utilisateur finaux (les commentaires DocBlock sont supprimés n'étant pas vraiment utiles pour les utilisateurs finaux).

Le principe KISS n'est pas forcément simple et immédiat à mettre en place. Quand j'ai repris le code de picoblog, je voulais utiliser le même principe KISS. Je vous ai parlé du problème que j'ai rencontré quand ma session s'était terminée pendant l'édition d'un article et que j'avais de ce fait perdu mon article. Pour corriger ce problème, j'ai pensé dans un premier temps que la bonne solution était d'utiliser un peu de javascript. À l'utilisation, ce n'est pas très pratique et après réflexion, je me suis dit qu'il fallait que j'envisage d'utiliser les session php qui permettrait de rendre tout ceci invisible à l'utilisateur et donc beaucoup plus pratique.

Tout ça pour dire que la simple volonté de programmer KISS n'est pas suffisante pour rendre un projet vraiment KISS et c'est pourquoi, il ne faut pas avoir peur de reconsidérer le code encore et encore et encore et encore :

<blockquote>But don't be afraid of refactor your code over and over and over and over again.</blockquote>

KrISS feed 2 de sortie !

vendredi 22 juin 2012 - 19:30

Je vous présente KrISS feed dans sa deuxième version !

(La démo ne permet que d'afficher les flux, sans faire de mise à jour, sans marquer les articles comme lus ou non lus, etc.)

Beaucoup de changements depuis la première version et maintenant ça y est, je n'utilise plus Google Reader comme lecteur de flux principal !!! (je le garde encore 1 semaine ou 2 pour m'assurer que KrISS feed fait bien son travail, mais j'ai bon espoir)

Évidemment, je suis égoïste et je l'ai codé principalement pour répondre à mes besoins, mais j'ai aussi pensé un peu à vous.

Pour cela, j'ai fait deux modes principaux : 'show' et 'reader'.

- Le 'show' est le plus fonctionnel pour le moment car je vous l'ai dit, je suis égoïste. Ainsi, il est possible de lire rapidement les nouveaux articles (et uniquement les nouveaux). L'affichage est très épuré pour ne laisser place qu'à un petit menu (qui peut s'agrandir en cliquant sur le nombre d'items) et un seul article. Il suffit ensuite de cliquer sur les flèches pour naviguer avec les articles suivants et précédents ou alors de taper sur 'n', 'p' (emacs), 'j', 'k' (vi), 'flèche de gauche ou de droite' !!

Dans ce mode les flux se mettent automatiquement à jour et il n'y a pas besoin contrairement à Google Reader (et cela m'énervait au possible) d'actualiser l'affichage en cliquant sur le nombre d'items. C'était long et chiant, mais cela n'est qu'une histoire ancienne maintenant. Quand le nombre d'items augmente, il suffit de continuer à cliquer sur 'n' et la lecture continue. Que du bonheur !

Je suis égoïste, mais également magnanime ; aussi j'ai ajouté un 'keep unread', même si je ne trouve pas cela très utile. Si vous utilisez un smartphone, il suffit de slider à gauche ou à droite pour naviguer (j'ai essayé sur mon S700i de 2004, mais je ne comprends pas pourquoi cela ne marche pas, je compte donc sur vous pour me signaler les éventuels bugs). Je ne voulais pas inclure tout JQuery/JQueryMobile pour ça, j'ai donc juste inclus la partie qui me semblait utile.

Pour valider, il faut toujours passer à l'article suivant ('n'), ce qui veut dire qu'il n'est pas possible de marquer des articles comme 'keep unread' en faisant des ('p'). À voir à l'usage si cela est gênant...

- Le 'reader' est un affichage plus classique et moins fonctionnel pour le moment. Il me sert surtout pour ajouter, déplacer, marquer tout/flux/dossier/article comme lus/non lus. Il est grandement à améliorer.

Le principal problème est la mise à jour qui n'est pas du tout automatisée. Pour le moment, il faut la faire manuellement et attendre... Il va falloir que je réfléchisse comment la faire sans que cela ne soit gênant pour la lecture (les problèmes sont légèrement différents que dans le mode 'show').

Je n'ai toujours pas pris le temps de faire l'affichage compact sous forme de liste, ce n'était pas dans mes priorités et je n'ai pas eu de demandes dans ce sens.

Entre temps j'ai essayé RSS lounge... et voici un petit retour... je télécharge, j'installe, j'ai le joli message "Installation finie. Vous pouvez maintenant utiliser rsslounge.". Je clique sur le lien et paf ! une page toute blanche :-( ça commence bien... Je modifie le .htaccess pour afficher les erreurs et j'obtiens : 'Internal Server Error'... super... Je regarde sur la FAQ et je fais les modifs mais toujours rien. Je n'ai pas encore commencé à utiliser RSS lounge que ça m'énerve déjà. Je cherche un peu sur le net et je tombe sur un forum qui explique que cela peut venir du transfert avec filezilla et qu'il faut choisir le transfert de fichiers binaires. Je recommence et ça marche enfin. J'importe mon fichier opml et là c'est la catastrophe, ça prend une plombe, c'est méga long, je clique un peu de partout pour tester, ça plante mon navigateur et là j'abandonne.

Pour résumer :
- 'show' : gestion ajax pour le mode 'show' avec les raccourcis qui vont bien, possibilité de conserver en 'non lu', mise à jour entièrement automatique, possibilité de partager avec shaarli.

TODO : pas grand chose à ajouter sauf si vous avez des propositions (moi cela me convient parfaitement pour le moment) ;

- 'reader' : affiche les flux en rouge en cas d'erreur (flux non XML, problème de la dernière update, problème d'articles manqués par rapport à la dernière mise à jour), possibilité de naviguer entre les différentes pages (next, previous avec les mêmes raccourcis 'n', 'p'...)

TODO : ne fait pas les mises à jour en ajax (principale priorité), ne sauvegarde pas l'état des dossiers (ouverts/fermés) (ce qui est chiant sur les téléphones avec les flux en haut qui sont tout le temps affichés), ne permet pas de supprimer plusieurs flux en même temps, ou encore de les déplacer dans des dossiers.

J'ai pris quelques libertés : j'espère que vous ne m'en voudrez pas, mais je ne choisis pas les liens de la balise 'link' pour les flux feedburner, ce sont des adresses proxy de Google (http://feedproxy.google.com/), ce n'est pas grand chose, mais c'est toujours ça de pris.

J'ai encore du boulot c'est ça ? En attendant, bon essayage !

(Définitivement tl;dr cet article...)

Adieu Google Reader ? Bonjour KrISS feed !

vendredi 08 juin 2012 - 17:44

2 semaines sans poster, ça commençait à faire un peu long. Mais aujourd'hui, j'ai une bonne nouvelle à vous annoncer, je suis en train de me faire un petit lecteur de flux RSS que j'ai envie de partager avec vous.

Chez Google, il y a encore 2 services dont je me sers tous les jours, ou presque, c'est Gmail et Google Reader et je souhaite dans un premier temps me séparer de ce dernier. J'ai bien évidemment regardé les alternatives et pour ne pas les citer rssLounge et Tiny Tiny RSS sont sans aucun doute les plus utilisées. Sauf que bon, utiliser MySQL pour ça, je vois pas vraiment l'intérêt (toujours dans l'optique de l'auto-hébergement). Je lis aussi que Idleman veut lancer un projet léger pour lire les flux et là je me dis chouette, allons regarder Leed qui n'utilise que 'SQLite'. Bon pourquoi pas, mais encore un peu compliqué à mettre en place et ne répond pas encore suffisamment à mes besoins.

Mes besoins :
- lire mes flux rapidement (Google Reader permet de naviguer très rapidement dans les flux avec les touches 'j', 'n' (next) ou 'k', 'p' (previous))
- partager rapidement avec kriss link (comment ça il n'existe pas encore ? C'est un shaarli en plus simple, je vous laisse imaginer) => ceci implique que kriss feed n'a pas besoin de gérer les favoris ou autre pour stocker les articles intéressants ; pour moi, c'est le travail de shaarli qui le fait déjà très bien ;
- simple à mettre en place, à mettre à jour (un seul fichier index.php à remplacer à chaque mise à jour) et à sauvegarder (le fichier 'data.php' pour 80 flux et + de 1000 articles ne faisait pas 1 Mo, pourquoi se 'compliquer' la vie avec SQL ?).
- mise à jour automatique un peu comme les autoblogs ce qui éviterait de passer nécessairement par un cron (oui je sais, il faudrait que je me mette aux autoblogs, promis je le ferais) avec en plus une sauvegarde automatique qui permettrait de lire les flux offline plus facilement (pas dans les priorités) ;
- d'ajouter un flux à partir d'un site automatiquement grâce à un petit bookmarklet (pas dans les priorités) ;

C'est parti, je reprends le code de kriss blog, je le modifie un peu et j'obtiens kriss feed. Alors je vous préviens tout de suite et je m'en excuse d'avance, mais je ne compte pas quitter Google Reader tout de suite, car kriss feed n'est pas suffisamment mature.

Cependant, kriss feed permet déjà :
- d'ajouter/supprimer des flux, d'importer/exporter des fichiers opml (conserve les dossiers et descriptions associés aux flux) ;
- de mettre à jour manuellement flux, dossier ou tout ;
- de marquer comme lus les flux, les dossiers ou tout (les messages lus qui ne sont plus dans les flux après une update sont supprimés) ;
- de trier ses flux par dossier (un flux peut appartenir à plusieurs dossiers ou à aucun, comme le propose Google Reader) ;
- d'afficher les articles avec une pagination définie dans les préférences.

Une petit démo est disponible ici : http://tontof.net/feed

Il ne permet pas encore :
- de n'afficher que les nouveaux messages ;
- de mettre à jour automatiquement les flux, (j'envisage d'utiliser 2/3 types de mises à jour, auto (qui détecte si un flux à besoin de se mettre à jour souvent en fonction de la fréquence des précédents posts), max ou un nombre de minutes fixées par l'utilisateur (qui permet de mettre à jour toutes les 'max' ou 'n' minutes) ;
- de faire la différence entre 'description' et 'content' des flux ;
- d'utiliser un 'redirector' ;
- de limiter le nombre d'articles à sauvegarder (si vous ne marquez pas les messages non lus, ils ne se supprimeront jamais du fichier 'data.php') ;
- d'afficher rapidement les images (avec un mur d'images) comme semble le proposer rssLounge d'après les screenshots (pas dans les priorités);
- d'afficher rapidement les articles comme je le souhaite avec au moins 'n' et 'p' (troll emacs) (la plus grosse partie du travail).

Je crois qu'il va falloir que je me mette sérieusement à AJAX :-)

Bon, je vous le dis tout de suite, je ne suis pas fier de mon code (comment ça, il manque des htmlspecialchars ?), mais je le partage quand même pour que vous puissiez tester toutes les fonctionnalités et que vous n'hésitiez pas à faire des propositions d'améliorations, en plus de celles proposées, je ne connais que Google Reader ce qui limite un peu les idées. J'espère que ce n'est pas trop prématuré, mais comme je vais être très peu disponible les jours qui arrivent, je ne voulais pas attendre d'avantage.

Au fait, pas la peine de reredemander, ça ne marche pas sur free :-p

GIF, APNG, WebP versus Canvas

vendredi 25 mai 2012 - 23:58

Je vous avais préparé un petit article pour vous parler d'images animées. C'est dommage mais l'article n'était pas encore tout à fait prêt quand je me suis rendu compte que j'aurai pu le publier pour l'anniversaire du GIF animé (Korben). Je n'ai jamais utilisé de javascript dans un flux RSS, je ne sais donc pas ce que ça va donner. Si cela ne s'affiche pas correctement, n'hésitez pas à venir directement sur le site.

Si seulement je n'avais pas eu tous ces partiels et soutenances à préparer...

On m'a demandé quand est-ce que je mettrais en place sur ce site quelques images pour faire des illustrations... Je compte intégrer l'ajout d'images à kriss blog, mais en attendant, voilà en avant-première une petite alternative aux formats GIF, APNG, WebP et autres formats qui permettent/permettront d'animer une image.

Pourquoi une alternative ?

Tout d'abord, il faut savoir qu'à la base GIF est un format propriétaire qui ne satisfaisait pas vraiment tout le monde. Maintenant ce format est vieux et les brevets associés ne sont plus vraiment gênants...

D'autres solutions ont été proposées comme alternatives à ce format comme le format APNG ou le format de Google WebP qui devrait supporter les animations dans ses futures versions. Ces formats ne sont malheureusement pas supportés par tous les navigateurs, et pour une fois pas seulement Internet Explorer, mais le format APNG n'est pas non plus supporté par Chrome et Safari et le format WebP n'est supporté que par Chrome et Opera. Bravo Opera qui supporte tous ces formats nativement !

Mais alors pourquoi une alternative ?

Tout d'abord, je pense que c'est bien d'avoir le choix et je pense qu'il peut être intéressant d'utiliser la balise canvas comme une alternative qui sera compatible avec tous les navigateurs (récents) et qui devrait permettre un paramétrage plus avancé des animations.

Des solutions existent déjà :
- afficher successivement plusieurs images png à l'aide d'un script : exemple (solution qui ne m'a pas vraiment convaincue)
- utiliser des sprites et un script pour animer tout ça exemple 1, exemple 2.
J'ai trouvé ces solutions intéressantes, mais elles sont "compliquées" à mettre en place et ne permettent pas vraiment de configurer l'animation. Je me suis donc inspiré et j'ai adapté tout ça.

Une image vaut mille mots alors voici un petit exemple :

(source : Wikipedia : Balle.gif)

- on convertit le gif en png avec des sprites :
montage Balle.gif -tile 1x -geometry +0+0 balle.png (merci ImageMagick)
- on met un background transparent (pas obligatoire) :
convert balle.png -transparent white balle.png (merci ImageMagick)
- on obtient cette image :

- on met les images à animer dans un canvas, un petit script et voilà le résultat
<script src="//tontof.net/js/acanvas.js"></script>
<canvas height="50" width="50"><img src="//tontof.net/img/balle.png" width="50" height="50"></canvas>


- à partir de la même image, il est possible de modifier l'animation


Je ferai un autre article pour présenter les différentes options, car je n'ai pas encore tout développé ce que j'ai en tête, et je trouve cet article bien assez long :-)
Je vous laisse regarder le code source si vous ne voulez pas attendre le prochain article consacré à acanvas.

Avantages :
- simple d'utilisation : un simple script js à inclure, une balise canvas qui encadre l'image avec les dimensions du sprite et c'est tout
- compatible sur tous les navigateurs récents ? (juste testé sur firefox et sur le navigateur mobile android 2.3.5 pour le moment)
- hautement paramétrable grâce à javascript et permet d'animer également une image fixe sans sprite
- peut réduire la taille de l'image (2361 octets pour l'image gif, 1549 octets pour l'image png, soit 35% de réduction)... dépend bien évidemment du type d'image, l'exemple étant clairement avantageux pour png.

Inconvénients :
- nécessite javascript, sinon affiche l'image à la place toute réduite.
- ne gère pas encore les gif où seulement des parties changent un peu comme les Cinemagraph qui n'encodent que les parties qui bougent dans le gif.
- doit être plus gourmand en ressources qu'un simple fichier image, même si je pense avoir un peu limité en utilisant un setTimeout dans le code à la place de setInterval.

Linux vs python turtle !

vendredi 11 mai 2012 - 10:08

J'aime linux !

Imaginez que vous donniez des cours à la fac depuis quelques temps et que votre administrateur réseau vous demande gentiment de prévoir vos besoins en logiciels en mai/juin alors que bien souvent vous ne connaissez vos enseignements qu'en juillet, voire septembre... quand ce n'est pas janvier...

Difficile en effet. Heureusement d'une année sur l'autre vous avez plus ou moins les mêmes enseignements, et du coup, les mêmes besoins en logiciels. Ouf on est sauvé !

Cela fait 2 ans que j'enseigne python (qui est une option) à des premières années en licence. Ils n'ont bien souvent jamais programmé, certains ne sont même pas destinés à faire de l'informatique plus tard. Mon but est donc de faire un cours introductif à la programmation sans qu'il ne soit trop barbant. Difficile en seulement 20h...

Heureusement python est intuitif, simple et grâce au module turtle, il est possible de faire des choses simples et sympathiques comme quand on était en primaire et qu'on faisait de la programmation logo... comment ? on me dit que cela ne se fait plus ? dommage je pense que c'était un bon moyen de faire réfléchir les plus jeunes... Encore faut-il qu'on veuille qu'ils réfléchissent...

Passons, la personne qui avait fait du python les autres années (coucou Laurent) avait également utilisé turtle. Je n'ai donc pas eu de soucis la première année et tout marchait très bien. Cette année, je n'ai donc pas demandé à installer de logiciel particulier. Sauf que voilà au moment de faire le TP, les étudiants me disent que import turtle ne marche pas. Je me rappelle qu'il était installé sur le serveur spécifique à la filière informatique et leur dit donc de faire un ssh sur ce serveur. Sauf que non, la machine a été mise à jour et cela ne marche tout simplement plus :-(

ImportError: No module named _tkinter, please install the python-tk package

Oh mon dieu comment je vais faire ? Quand j'ai eu l'audace de demander en milieu d'année à ce que inkscape soit installé, on m'a de nouveau gentiment dit que ce n'était pas possible, les demandes d'installation de logiciels ne peuvent pas être fait quand on veut c'est trop compliqué à gérer... Sur le serveur, cela doit revenir à faire une ligne de commande c'est ça ?

Bon ben c'est parti, google install the python-tk package

Il faut donc commencer par installer tcl puis tk

On commence par tcl :
tar xvfz tcl8.5.11-src.tar.gz
cd tcl8.5.11/unix/
./configure --prefix=/home/login/L1/Python/local
make
make install

On recommence pour tk :
tar xvzf tk8.5.11-src.tar.gz
cd tk8.5.11/unix/
./configure --prefix=/home/login/L1/Python/local
make
make install

On fixe les variables d'environnement qui vont bien :
setenv C_INCLUDE_PATH /home/login/L1/Python/local/include
setenv LIBRARY_PATH /home/login/L1/Python/local/lib
setenv LD_LIBRARY_PATH /home/login/L1/Python/local/lib
ou
export C_INCLUDE_PATH=/home/login/L1/Python/local/include
export LIBRARY_PATH=/home/login/L1/Python/local/lib
export LD_LIBRARY_PATH=/home/login/L1/Python/local/lib
selon votre $SHELL

On va chercher python.
Tiens on va prendre la version 2.7.3 ou 3.2.3, ça changera des versions 2.5 et 2.6 de la fac...
(Attention à la syntaxe de programmation qui est différente entre python2 et python3 !)
tar xvfz Python-3.2.3.tgz
cd Python-3.2.3
./configure --prefix=/home/login/L1/Python/local
make
make install

Et pour finir :
cd /home/login/L1/Python/local/bin
./python3
>>> import turtle

Enjoy !

Bon écoutez moi tous, pour le tp, ne lancer pas python mais /home/login/L1/Python/local/bin/python3

Être root aurait été plus simple, mais y a pas à dire,
j'aime linux !

Kriss blog (version 3)

lundi 07 mai 2012 - 18:29

Je pense avoir terminé, dans un premier temps, ce que je voulais ajouter à picoblog.
Dans cette version 3 de kriss blog, il est maintenant possible :
- d'ajouter des articles privés (utile pour l'édition de plusieurs articles en parallèle) ;
- de publier des articles dans le futur (il suffit de fixer la date à laquelle on veut que l'article apparaisse (ne fonctionne pas encore si le cache est activé)) ;
- de modérer les commentaires avec du BBCode (si vous dîtes trop de choses méchantes, je pourrais les modérer);
- de lire les articles plus facilement sur les mobiles (HTML5 et CSS simplifié : avec un joli score à gtmetrix Page speed : 100% et Yslow : 98%) ;
- d'activer l'auto sauvegarde pendant l'édition d'article pour éviter de perdre un article en cours d'édition (je stocke dans le localStorage du navigateur).

J'avais partagé sur les liens publics du hollandais volant, un outil permettant de sauvegarder automatiquement les données de formulaire quand Timo avait parlé du problème de perte d'un article en cours d'édition. Ce lien avait été repris par Sebsauvage. C'est peut-être un détail pour vous, mais cela avait flatté mon égo et je m'étais dit à l'époque qu'il fallait vraiment que je commence à penser à faire moi aussi un blog pour que je puisse partager des choses qui je l'espère seront utiles pour vous.

Au final, je ne sais pas comment Timo a résolu son problème pour blogotext, mais pour mes besoins de sauvegarde, j'ai juste écrit 2 petites fonctions javascript légèrement inspirées de howtocreate. Un petit setInterval de 1 min et si l'utilisateur perd son article, il suffit de charger les données sauvegardées.

(pour mettre un peu de couleur, j'ai utilisé highlight_string de php, mais il s'agit effectivement de javascript... Il faudrait que j'ajoute dans les TODOs la coloration syntaxique ?) :

<?php 
var id="edit_form";
function 
saveForm(){
  var 
document.getElementById(id);
  var as;

  for (var 
i=0fO={};f.elements[i]; i++){
    var 
f.elements[i];
    if (
e.type){
      var 
e.type.toLowerCase();
      if( 
== "text"
        
|| == "textarea"
        
|| == "password"
        
|| == "datetime"
        
|| == "datetime-local"
        
|| == "date"
        
|| == "month"
        
|| == "week"
        
|| == "time"
        
|| == "number"
        
|| == "range"
        
|| == "email"
        
|| == "url" ) {
        
fO[e.name]=e.value;
      } else if(( 
== "radio" || == "checkbox" )
                   && 
e.checked) {
        
fO[e.name]=e.value;
      }
    }
  }
  
localStorage.toform=JSON.stringify(fO);
}

function 
loadForm(){
  if (
typeof(localStorage.toform) != "undefined"
      
&& localStorage.toform !== null) {
    var 
document.getElementById(id);

    for (var 
i=0fI=JSON.parse(localStorage.toform);
           
f.elements[i];
           
i++) {
      var 
f.elements[i];
      if (
e.type) {
        var 
e.type.toLowerCase();
        if( 
== "text"
          
|| == "textarea"
          
|| == "password"
          
|| == "datetime"
          
|| == "datetime-local"
          
|| == "date"
          
|| == "month"
          
|| == "week"
          
|| == "time"
          
|| == "number"
          
|| == "range"
          
|| == "email"
          
|| == "url" ) {
          
e.value fI[e.name];
        } else if(( 
== "radio"
                      
|| == "checkbox" )) {
          if (
fI.hasOwnProperty(e.name)
              && 
e.value==fI[e.name]) {
            
e.checked true;  
          }
        }
      }
    }
  }
}
 
?>


Maintenant que kriss blog est pleinement fonctionnel, je vais pouvoir commencer à vous parler un peu d'autres choses, alors à la prochaine :-)

Un blog statique

mercredi 25 avril 2012 - 17:46

Avant de me lancer dans ce blog, j'ai longtemps hésité entre les différentes méthodes et moteurs de blogs existants. Dans l'optique de l'auto-hébergement, il me fallait un outil qui soit simple et efficace. Dans mes recherches, je me suis donc intéressé aux moteurs de blogs statiques et il en existe beaucoup (32 static website generator et d'autres).

J'ai été surpris de voir qu'il en existait très peu (pas) en php (php s'utilise aussi en ligne de commande après tout). Python est sans doute le langage de programmation qui ressort le plus. Seulement voilà, je voulais aussi avoir la possibilité de générer des pages dynamiques comme pour ajouter des commentaires. Le problème, c'est que ces outils utilisent des services externes, comme disqus... Oui, mais moi je ne voulais pas.

La solution que j'ai choisie est l'utilisation d'un cache local. Le principe est tout simple. Les pages statiques sont générées en fonction des besoins. Quand un utilisateur veut accéder à une page, si la page existe dans le cache local, elle est appelée, sinon elle est générée et stockée dans le cache. C'est une solution intermédiaire entre statique et dynamique.

Bien sûr, tout n'a pas été aussi simple et je ne garantis pas qu'il n'y ait pas de bogue. Un détail qui m'avait échappé est le problème des captchas dans les commentaires. Un captcha dans un fichier du cache n'a aucun sens, aussi, j'ai dû ajouter un bouton qui au lieu d'envoyer directement le commentaire, génère un captcha avant. Une étape de plus avant de pouvoir commenter. Cette étape n'est présente que si l'option du cache est activée dans la configuration. Je ne l'ai pas encore activée, j'avais peur que cela vous empêche de commenter :-p

Dans les news en plus du cache, j'ai ajouté la possibilité d'autoriser ou pas les commentaires pour chaque article. Il est possible d'arrêter temporairement l'ajout de commentaires, sans perdre ceux qui ont déjà été postés.

Dans les prochaines améliorations de kriss blog, je vais penser à enregistrer automatiquement les articles en cours d'édition. Pourquoi ? Tout simplement, parce qu'après une heure d'inactivité, la session est perdue. Sauf que je n'y avais pas pensé, mais rédiger un article ça peut prendre facilement bien plus qu'une heure. Et oui, vous ne le saviez pas, mais il m'est déjà arrivé de perdre un article. Celui sur les captchas, j'ai dû le faire deux fois et la deuxième fois il était forcément moins bien. Ça m'apprendra, j'aurai dû faire un copier-coller avant de l'envoyer.

Kriss blog

vendredi 20 avril 2012 - 20:47

Bienvenue à toi petit Mathis !

Ce n'était pas prévu pour tout de suite, mais je suis tontof pour la deuxième fois depuis hier soir. Au moins ce ne sera pas compliqué pour retenir les anniversaires.

Chose promise chose due, voici le code de kriss blog. Le nom est sans surprise inspiré du principe de programmation KISS. J'ai hésité à changer de nom, mais même si je compte garder le principe minimaliste de picoblog proposé par BohwaZ, les fonctionnalités que j'ai et que je compte ajouter vont rendre kriss blog différent du projet original.

La TODO list est encore très sommaire, mais j'envisage de :
- convertir en html5
- sauvegarder automatiquement l'édition d'articles
- coder en utilisant la syntaxe PEAR
- pouvoir poster des messages futurs automatiquement

J'ai déjà fait quelques modifications importantes :
- mise en place d'une procédure d'installation
- ajout d'un titre par article
- ajout des commentaires
- ajout d'un captcha

Pour le captcha, une petite classe php et le tour est joué. J'ai cherché des polices ASCII pour m'en créer une petite perso :
 _   _   __  _   __  __  __     ___ ___         _ _ 
|_| |_) | | \ |__ |_ / _ |_| | | |_/ | |||
| | |_) |__ |_/ |__ | \_/ | | _|_ _| | \ |__ | |
__   _   _   _   _   _  ___                     ___ 
| | / \ |_| | | |_| (_ | | | \ / \ / \_/ |_| /
| | \_/ | |_\ | \ _) | |_| v w / \ _| /__
 _       _   _       _   _   __  _   _  
|/| /| _| _| |_| |_ |_ | |_| |_|
|_| | |_ _| | _| |_| / |_| _|


Il est possible de définir sa propre police, il suffit juste que les caractères soient de la même largeur. Par défaut, le constructeur utilise la police ci-dessus. Et pour finir, voici cette petite classe qui permet de générer une chaîne automatiquement et de l'encoder facilement pour obtenir un captcha dans une balise pre.


<?php 
/**
 * Captcha management class
 * 
 * Features:
 * - Use an ASCII font by default but can be customized
 *   (letter width should be the same)
 * - generate random strings with 5 letters
 * - convert string into captcha using the ASCII font
 */

class Captcha
{
    public 
$alphabet="";
    public 
$alphabet_font;
    public 
$col_font 0;
    public 
$row_font 0;

    public function 
__construct($alpha_font=array(
                                    
'A'=>" _ |_|| |",
                                    
'B'=>" _ |_)|_)",
                                    
'C'=>" __|  |__",
                                    
'D'=>" _ | \\|_/",
                                    
'E'=>" __|__|__",
                                    
'F'=>" __|_ |  ",
                                    
'G'=>" __/ _\\_/",
                                    
'H'=>"   |_|| |",
                                    
'I'=>"___ | _|_",
                                    
'J'=>"___ | _| ",
                                    
'K'=>"   |_/| \\",
                                    
'L'=>"   |  |__",
                                    
'M'=>"_ _|||| |",
                                    
'N'=>"__ | || |",
                                    
'O'=>" _ / \\\\_/",
                                    
'P'=>" _ |_||  ",
                                    
'Q'=>" _ | ||_\\",
                                    
'R'=>" _ |_|| \\",
                                    
'S'=>" _ (_  _)",
                                    
'T'=>"___ |  | ",
                                    
'U'=>"   | ||_|",
                                    
'V'=>"   \\ / v ",
                                    
'W'=>"   \\ / w ",
                                    
'X'=>"   \\_// \\",
                                    
'Y'=>"   |_| _|",
                                    
'Z'=>"___ / /__",
                                    
'0'=>" _ |/||_|",
                                    
'1'=>"    /|  |",
                                    
'2'=>" _  _||_ ",
                                    
'3'=>" _  _| _|",
                                    
'4'=>"   |_|  |",
                                    
'5'=>" _ |_  _|",
                                    
'6'=>" _ |_ |_|",
                                    
'7'=>" __  | / ",
                                    
'8'=>" _ |_||_|",
                                    
'9'=>" _ |_| _|"),
                                
$row_font=3){
        
$this->alphabet_font $alpha_font;

        
$keys array_keys($this->alphabet_font);

        foreach (
$keys as $k){
            
$this->alphabet .= $k;
        }

        if (
$keys[0]){
            
$this->row_font $row_font;
            
$this->col_font =
                (int)
strlen($this->alphabet_font[$keys[0]])/$this->row_font;
        }
    }

    public function 
generateString($len=5){
        
$i=0;
        
$str='';
        while (
$i<$len){
            
$str.=$this->alphabet[mt_rand(0,strlen($this->alphabet)-1)];
            
$i++;
        }
        return 
$str;
    }

    public function 
convertString($str_in){
        
$str_out="\n";
        
$str_out.='<pre>';
        
$str_out.="\n";
        
$i=0;
        while(
$i<$this->row_font){
            
$j=0;
            while(
$j<strlen($str_in)){
                
$str_out.= substr($this->alphabet_font[$str_in[$j]],
                                  
$i*$this->col_font,
                                  
$this->col_font)." ";
                
$j++;
            }
            
$str_out.= "\n";
            
$i++;
        }
        
$str_out.='</pre>';
        return 
$str_out;
    }
}
 
?>

Joyeux anniversaire

mercredi 18 avril 2012 - 19:00

Cela fait 2 ans jour pour jour, 2 ans déjà que Tontof existe. Aujourd'hui était donc le jour idéal pour se lancer.

Depuis quelques temps l'idée me trottait dans la tête. Et puis, j'ai hésité à me lancer dans l'auto-hébergement, et j'ai finalement choisi l'option de facilité en prenant un hébergeur... ce n'est que partie remise.

Qu'est-ce que vous trouverez sur tontof.net ? Un peu de tout mais surtout des choses qui concernent le libre, linux, l'informatique et bien sûr d'autres activités diverses et variées que je vous laisserai découvrir. Je cherche à m'émanciper et à quitter les services privés qui je sais ne font pas bon usage de toutes nos informations. Et puis j'en ai marre de devoir accepter qu'une application ait besoin d'accéder à la liste de mes contacts pour une boussole. Alors je partagerai avec vous les codes que je développe pour répondre à des besoins précis sans avoir à baisser son...

Bref, vous avez compris.

Alors pour commencer, il a fallu que je me trouve un joli moteur pour faire mon blog. J'ai pensé à blogotext de Timo que je suis régulièrement, mais cela me semblait un peu trop compliqué et je cherchais un outil encore plus minimaliste. Dans sa liste de moteurs de blog, je me suis très vite orienté vers picoblog . J'ai regardé le code, il m'a bien plu et j'ai commencé à ajouter les choses qui me manquaient :
- une installation automatique
- une gestion de session sécurisée
- des commentaires

Il me reste encore beaucoup d'autres choses à faire, mais je ne voulais pas attendre pour vous rejoindre. Je partagerai évidemment avec vous ce code, mais pour vous faire patienter, je vous livre la gestion de la session que j'ai réalisée grâce au code de Sebsauvage.
Comme je ne voulais pas plusieurs fichiers et que je voulais ajouter d'autres possibilités, j'ai fait un mixte avec shaarli pour créer une classe Session qui permet de gérer facilement les sessions.

J'espère que cela vous plaira. N'hésitez pas à faire des critiques dans les commentaires et à m'ajouter dans vos amis facebook, google+ et twitter. Ah ben non je suis bête j'ai pas de compte. Mais vous pouvez maintenant me suivre grâce à mon flux RSS :-)

Au fait, j'allais oublier. Très bon anniversaire Noé !

Edit : 2013-08-31 : voir http://tontof.net/kriss/php5/session pour une version à jour

<?php 
/**
 * Session management class
 * http://www.developpez.net/forums/d51943/php/langage/sessions/
 * http://sebsauvage.net/wiki/doku.php?id=php:session
 * http://sebsauvage.net/wiki/doku.php?id=php:shaarli
 *
 * Features:
 * - Everything is stored on server-side (we do not trust client-side data,
 *   such as cookie expiration)
 * - IP addresses + user agent are checked on each access to prevent session
 *   cookie hijacking (such as Firesheep)
 * - Session expires on user inactivity (Session expiration date is
 *   automatically updated everytime the user accesses a page.)
 * - A unique secret key is generated on server-side for this session
 *   (and never sent over the wire) which can be used
 *   to sign forms (HMAC) (See $_SESSION['uid'] )
 * - Token management to prevent XSRF attacks.
 * 
 * TODO:
 * - log login fail
 * - prevent brute force (ban IP)
 *
 * HOWTOUSE:
 * - Just call Session::init(); to initialize session and
 *   check if connected with Session::isLogged()
 */

class Session
{  
    
// If the user does not access any page within this time,
    // his/her session is considered expired (in seconds).
    
public static $inactivity_timeout 3600;
    private static 
$_instance;
 
    
// constructor
    
private function __construct()
    {
        
// Use cookies to store session.
        
ini_set('session.use_cookies'1);
        
// Force cookies for session  (phpsessionID forbidden in URL)
        
ini_set('session.use_only_cookies'1);
        if (!
session_id()){
            
// Prevent php to use sessionID in URL if cookies are disabled.
            
ini_set('session.use_trans_sid'false);
            
session_start(); 
        }
    } 

    
// initialize session
    
public static function init()
    {
        if (!isset(
self::$_instance)) {
            
self::$_instance = new Session();
        }
    }

    
// Returns the IP address, user agent and language of the client
    // (Used to prevent session cookie hijacking.)
    
private static function _allInfos()
    {
        
$infos $_SERVER["REMOTE_ADDR"];
        if (isset(
$_SERVER['HTTP_X_FORWARDED_FOR'])) {
            
$infos.=$_SERVER['HTTP_X_FORWARDED_FOR'];
        }
        if (isset(
$_SERVER['HTTP_CLIENT_IP'])) {
            
$infos.='_'.$_SERVER['HTTP_CLIENT_IP'];
        }
        
$infos.='_'.$_SERVER['HTTP_USER_AGENT'];
        
$infos.='_'.$_SERVER['HTTP_ACCEPT_LANGUAGE'];
        return 
sha1($infos);
    }
 
    
// Check that user/password is correct and init some SESSION variables.
    
public static function login($login,$password,$login_test,$password_test,
                                 
$pValues = array())
    {
        foreach (
$pValues as $key => $value) { 
            
$_SESSION[$key] = $value
        } 
        if (
$login==$login_test && $password==$password_test){
            
// generate unique random number to sign forms (HMAC)
            
$_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand());
            
$_SESSION['info']=Session::_allInfos(); 
            
$_SESSION['username']=$login;
            
// Set session expiration.
            
$_SESSION['expires_on']=time()+Session::$inactivity_timeout;
            return 
true;
        }
        return 
false;
    }
 
    
// Force logout
    
public static function logout()
    {
        unset(
$_SESSION['uid'],$_SESSION['info'],$_SESSION['expires_on']);
    } 

    
// Make sure user is logged in.
    
public static function isLogged()
    {
        if (!isset (
$_SESSION['uid'])
            || 
$_SESSION['info']!=Session::_allInfos()
            || 
time()>=$_SESSION['expires_on']){
            
Session::logout();
            return 
false;
        }
        
// User accessed a page : Update his/her session expiration date.
        
$_SESSION['expires_on']=time()+Session::$inactivity_timeout;  
        return 
true;
    }

    
// Returns a token.
    
public static function getToken()
    {
        if (!isset(
$_SESSION['tokens'])){
            
$_SESSION['tokens']=array();
        }
        
// We generate a random string and store it on the server side.
        
$rnd sha1(uniqid('',true).'_'.mt_rand());
        
$_SESSION['tokens'][$rnd]=1;  
        return 
$rnd;
    }

    
// Tells if a token is ok. Using this function will destroy the token.
    // return true if token is ok.
    
public static function isToken($token)
    {
        if (isset(
$_SESSION['tokens'][$token]))
        {
            unset(
$_SESSION['tokens'][$token]); // Token is used: destroy it.
            
return true// Token is ok.
        
}
        return 
false// Wrong token, or already used.
    
}
}
 
?>