ZZZ http://zzz.rezo.net/ une sorte de fatras... fr SPIP - www.spip.net <span class="caps">ZZZ</span> http://zzz.rezo.net/local/cache-vignettes/L144xH93/siteon0-21452.png http://zzz.rezo.net/ 93 144 Réparer le charset d'une base SPIP http://zzz.rezo.net/Reparer-le-charset-d-une-base-SPIP.html http://zzz.rezo.net/Reparer-le-charset-d-une-base-SPIP.html 2012-12-30T09:13:21Z text/html fr Fil Logiciels libres Multilinguisme Web <p>Quand on part d'une vieille installation de SPIP il arrive qu'on enregistre les données en utf-8 dans des tables déclarées en latin1. Ca ne gêne pas le fonctionnement normal du site, mais ça empêche d'utiliser proprement les outils MySQL, de la ligne de commande (qui affiche des « é » à la place des « é ») au moteur de recherche FULLTEXT, qui ne retrouve pas les mots accentués. Méthode de nettoyage. 0/ Faire toutes les sauvegardes, travailler sur un site de tests, etc. La procédure prend plusieurs minutes. (...)</p> - <a href="http://zzz.rezo.net/-SPIP-.html" rel="directory">SPIP</a> / <a href="http://zzz.rezo.net/+-Logiciels-libres-+.html" rel="tag">Logiciels libres</a>, <a href="http://zzz.rezo.net/+-Multilinguisme-+.html" rel="tag">Multilinguisme</a>, <a href="http://zzz.rezo.net/+-Web-+.html" rel="tag">Web</a> <div class='rss_chapo'><p>Quand on part d'une vieille installation de <span class="caps">SPIP</span> il arrive qu'on enregistre les données en <code class='spip_code' dir='ltr'>utf-8</code> dans des tables déclarées en <code class='spip_code' dir='ltr'>latin1</code>. Ca ne gêne pas le fonctionnement normal du site, mais ça empêche d'utiliser proprement les outils MySQL, de la ligne de commande (qui affiche des « é » à la place des « é ») au moteur de recherche <span class="caps">FULLTEXT</span>, qui ne retrouve pas les mots accentués. Méthode de nettoyage.</p></div> <div class='rss_texte'><p><strong>0/</strong> Faire toutes les sauvegardes, travailler sur un site de tests, etc. La procédure prend plusieurs minutes. Pour éviter toute connerie dans cet intervalle, tu peux vouloir mettre le site en berne, en mettant dans <code class='spip_code' dir='ltr'>config/mes_options.php</code> :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code> header('Status: 503 Service Unavailable');<br /> die('Maintenance en cours, revenez plus tard.');</code></div> <p><strong>1/</strong> dumper la base spip en latin1, la réimporter en utf8 dans une base spip2</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>mysqldump --opt --default-character-set=latin1 --no-create-info spip > spip-data.sql</code></div> <div style='text-align: left;' class='spip_code' dir='ltr'><code>mysqldump --opt --default-character-set=latin1 --no-data spip > spip-struct.sql</code></div> <p>on corrige tous les charsets déclarés dans la structure</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>perl -pi -e's/latin1/utf8/g;' spip-struct.sql</code></div> <p>On importe la structure corrigée des tables</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>mysql spip2 < spip-struct.sql</code></div> <p>Si le site comporte des tables ayant une <span class="caps">PRIMARY</span> <span class="caps">KEY</span> sur un champ accentué, il peut y avoir des doublons, non détectés jusqu'ici, qui empêcheront la réimportation. On fait alors sauter cette primary key :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>mysql spip2#<br /> ALTER TABLE spip_urls DROP PRIMARY KEY; </code></div> <p>on corrige dans les toutes premières lignes des données la déclaration de charset :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>perl -pi -e's/SET NAMES latin1/SET NAMES utf8/g;' spip-data.sql </code></div> <p>On réimporte ensuite les données :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>mysql spip2 < spip-data.sql</code></div> <p><strong>2/</strong> Modifier les meta de charset :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>mysql spip2#<br /> REPLACE spip_meta (nom,valeur,impt,maj) VALUES<br /> ('charset_sql_base', 'utf8', 'oui', NOW()),<br /> ('charset_collation_sql_base', 'utf8_general_ci', 'oui', NOW()),<br /> ('charset_sql_connexion', 'utf8', 'oui', NOW()),<br /> ('charset', 'utf-8', 'oui', NOW());</code></div> <p><strong>3/</strong> Vérifier le fichier config/connect.php :<br class='autobr' /> il faut qu'il ait la ligne :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>define('_MYSQL_SET_SQL_MODE',true);</code></div> <p>… et le connecter sur spip2.</p> <p><strong>4/</strong> purger le cache des meta :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>rm tmp/meta_cache.php</code></div> <p><strong>5/</strong> éventuellement, vider le cache (mais sans obligation)</p></div> DotSPIP http://zzz.rezo.net/DotSPIP.html http://zzz.rezo.net/DotSPIP.html 2012-01-28T18:50:43Z text/html fr Fil Web <p>DotSPIP est une application pour Mac OS X qui permet de convertir facilement des fichiers texte de tout type vers les raccourcis SPIP. DotSPIP s'utilise simplement par glisser-déposer : on lâche un fichier, ou une série de fichiers, sur l'icone, et le résultat arrive à la fois à l'écran et dans le presse-papiers. Il ne reste plus qu'à le coller dans SPIP. Lien de téléchargement : Après téléchargement de l'image disque, installer l'application dans le dossier Applications et déposer son icone dans le (...)</p> - <a href="http://zzz.rezo.net/-SPIP-.html" rel="directory">SPIP</a> / <a href="http://zzz.rezo.net/+-Web-+.html" rel="tag">Web</a> <img class='spip_logos' alt="" align="right" src='http://zzz.rezo.net/local/cache-vignettes/L150xH150/arton83-44a94.png' width='150' height='150' style='height:150px;width:150px;' /> <div class='rss_chapo'><p>DotSPIP est une application pour Mac <span class="caps">OS</span> X qui permet de convertir facilement des fichiers texte de tout type vers les raccourcis <span class="caps">SPIP</span>.</p></div> <div class='rss_texte'><p>DotSPIP s'utilise simplement par glisser-déposer : on lâche un fichier, ou une série de fichiers, sur l'icone, et le résultat arrive à la fois à l'écran et dans le presse-papiers. Il ne reste plus qu'à le coller dans <span class="caps">SPIP</span>.</p> <p><i>Lien de téléchargement :</i></p> <p><span class='spip_document_61 spip_documents spip_documents_center'><br class='autobr' /> <a href="https://github.com/Fil/DotSPIP/releases" class="spip_out"><img src='http://zzz.rezo.net/local/cache-vignettes/L150xH150/imagedisque-3abaa.png' width='150' height='150' alt="" style='height:150px;width:150px;' /></a></span></p> <p>Après téléchargement de l'image disque, installer l'application dans le dossier Applications et déposer son icone dans le Dock.</p> <p><span class='spip_document_62 spip_documents spip_documents_right' style='float:right; width:500px;'> <img src='http://zzz.rezo.net/local/cache-vignettes/L500xH119/dock-d671c.png' width='500' height='119' alt="" style='height:119px;width:500px;' /></span></p> <p> </p> <p><i>Formats acceptés :</i></p> <p><strong>rtf</strong>, <strong>doc</strong>, <strong>docx</strong>, <strong>html</strong>, <strong>odt</strong>, <strong>epub</strong>, <strong>txt</strong>…</p> <p>Il est aussi possible de déposer directement un signet depuis un navigateur Web : DotSPIP se chargera d'appeler la page pour la convertir en raccourcis <span class="caps">SPIP</span>.</p> <p> </p> <p><i>Compatibilité :</i></p> <p>Testé avec les systèmes Snow Leopard (10.6) et Lion (10.7). (L'application ne fonctionne pas sur Mac 10.5 et inférieur, car elle exploite une fonction nécessitant <span class="caps">PHP</span> 5.3.0 au moins.)</p> <p> </p> <p><span class='spip_document_58 spip_documents spip_documents_center'> <img src='http://zzz.rezo.net/local/cache-vignettes/L500xH500/dropspip-4e7d3.png' width='500' height='500' alt="" style='height:500px;width:500px;' /></span></p> <p><i>Goodies :</i></p> <p>DotSPIP modifie à la volée les guillemets (si l'auteur n'en a pas mis elle-même) en fonction de la langue du document.</p> <p> </p> <p><i>Évolutions :</i></p> <p>Ce logiciel ne demande qu'à évoluer, son but est d'être le plus utile tout en restant aussi simple que possible.</p> <p>J'attends vos remarques avec impatience ; si vous avez des fichiers tests pour lesquels ce convertisseur ne fait pas ce qu'on en attendrait, n'hésitez pas à me les envoyer.</p> <p>Parmi les projets envisagés :<br />— exporter au format markdown<br />— compatibilité linux<br />— traiter les images <br />— lire d'autres formats, notamment <span class="caps">PDF</span></p> <p> </p> <p><i>Remerciements :</i></p> <p>— Sveinbjorn Thordarson pour <a href="http://sveinbjorn.org/platypus_tutorial" class='spip_out' rel='external'>Platypus</a> (<a href="http://sveinbjorn.org/donations" class='spip_out' rel='external'>€</a>)<br />— Baroug pour l'<a href="http://www.flickr.com/photos/baroug/" class='spip_out' rel='external'>icône</a><br />— les vieux de la vieille de <span class="caps">SPIP</span> pour la fonction <code class='spip_code' dir='ltr'>sale()</code><br />— Vincent pour les <a href="http://www.spip-contrib.net/Correction-typographique-des" class='spip_out' rel='external'>guillemets</a><br />— <span class="caps">ARNO</span>* pour <a href="http://www.paris-beyrouth.org/tutoriaux-spip/article/le-convertisseur-office2spip" class='spip_out' rel='external'>Office2SPIP</a></p></div> Terminer l'installation de Varnish http://zzz.rezo.net/Terminer-l-installation-de-Varnish.html http://zzz.rezo.net/Terminer-l-installation-de-Varnish.html 2011-04-10T20:06:06Z text/html fr Fil Web <p>Ce qui suit est peut-être un peu abscons, mais il faut bien en passer par là pour terminer l'installation : tester la communication, passer Apache sur un port secondaire, passer Varnish en frontal, et fignoler. Maintenant que notre serveur sait communiquer avec Varnish, on va passer ce dernier en « frontal » sur le port http standard (:80). On dira à Apache d'écouter un port secondaire (:8080). Les visiteurs interrogeront donc Varnish, qui ira le cas échéant interroger Apache. Ultimes (...)</p> - <a href="http://zzz.rezo.net/-Varnish-.html" rel="directory">Varnish</a> / <a href="http://zzz.rezo.net/+-Web-+.html" rel="tag">Web</a> <div class='rss_chapo'><p>Ce qui suit est peut-être un peu abscons, mais il faut bien en passer par là pour terminer l'installation : tester la communication, passer Apache sur un port secondaire, passer Varnish en frontal, et fignoler.</p></div> <div class='rss_texte'><p>Maintenant que notre serveur sait communiquer avec Varnish, on va passer ce dernier en « frontal » sur le port http standard (:80). On dira à Apache d'écouter un port secondaire (:8080). Les visiteurs interrogeront donc Varnish, qui ira le cas échéant interroger Apache.</p> <h3 class='h3 spip'>Ultimes vérifications</h3> <p>D'abord, quelques vérifications du bon fonctionnement du système. Un outil indispensable pour vérifier les entêtes est <code class='spip_code' dir='ltr'>curl</code>, qu'on va lancer dans une fenêtre shell :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>curl -D head http://localhost/spip-2.1/ >/dev/null && cat head</code></div> <p>Voici le résultat typique :</p> <form action='' method='get'><div> <input type='hidden' name='exec' value='' /> <textarea readonly='readonly' cols='40' rows='12' class='spip_cadre' dir='ltr'>HTTP/1.1 200 OK Date: Sun, 10 Apr 2011 19:32:19 GMT Server: Apache/2.0.63 (Unix) PHP/5.2.11 DAV/2 X-Powered-By: PHP/5.2.11 Vary: Cookie,Accept-Encoding Composed-By: SPIP 2.1.10 @ www.spip.net + images(1.0.1), ... statsjs(0.1), varnish(0.2) X-Spip-Cache: 3600 Last-Modified: Sun, 10 Apr 2011 19:32:19 GMT X-Varnish-Ttl: 3600 Transfer-Encoding: chunked Content-Type: text/html; charset=utf-8</textarea></div></form> <p>Concentrons-nous sur l'entête qui nous intéresse :</p> <form action='' method='get'><div> <input type='hidden' name='exec' value='' /> <textarea readonly='readonly' cols='40' rows='2' class='spip_cadre' dir='ltr'>X-Varnish-Ttl: 3600</textarea></div></form> <p>On voit ici que <span class="caps">SPIP</span> a bien envoyé l'entête destiné à Varnish.</p> <p>Maintenant, si on regarde la même page telle que servie par Varnish, sur le port temporaire (:6081) :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>curl -D head http://localhost:6081/spip-2.1/ >/dev/null && cat head</code></div> <p>on obtient :</p> <form action='' method='get'><div> <input type='hidden' name='exec' value='' /> <textarea readonly='readonly' cols='40' rows='15' class='spip_cadre' dir='ltr'>HTTP/1.1 200 OK Server: Apache/2.0.63 (Unix) PHP/5.2.11 DAV/2 X-Powered-By: PHP/5.2.11 Vary: Cookie,Accept-Encoding Composed-By: SPIP 2.1.10 @ www.spip.net + images(1.0.1), ... statsjs(0.1), varnish(0.2) X-Spip-Cache: 3600 Last-Modified: Sun, 10 Apr 2011 19:27:14 GMT Content-Type: text/html; charset=utf-8 Content-Length: 13108 Date: Sun, 10 Apr 2011 19:35:13 GMT X-Varnish: 1133668195 Via: 1.1 varnish Connection: keep-alive X-Varnish-Age: 0</textarea></div></form> <p>Concentrons-nous sur les entêtes pertinents :</p> <form action='' method='get'><div> <input type='hidden' name='exec' value='' /> <textarea readonly='readonly' cols='40' rows='3' class='spip_cadre' dir='ltr'>X-Varnish: 1133668195 Via: 1.1 varnish X-Varnish-Age: 0</textarea></div></form> <p>On voit que Varnish a traité cette requête (qui a pour n° 1133668195), et qu'il est allé demander la ressource à Apache.</p> <p>Maintenant lançons une deuxième fois la commande ; le bloc ci-dessus devient :</p> <form action='' method='get'><div> <input type='hidden' name='exec' value='' /> <textarea readonly='readonly' cols='40' rows='3' class='spip_cadre' dir='ltr'>X-Varnish: 1133668226 1133668195 Via: 1.1 varnish X-Varnish-Age: 10</textarea></div></form> <p>Ici on voit que notre réponse (1133668226) a été servie depuis la mémoire cache de Varnish, qui est allé chercher la ressource qu'il avait obtenue lors de la requête 1133668195 ; la ressource date d'il y a 10 secondes.</p> <p>Continuons à surveiller <code class='spip_code' dir='ltr'>X-Varnish-Age:</code> en lançant la commande de manière répétitive :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>watch "curl -D head http://localhost:6081/spip-2.1/ >/dev/null 2>/dev/null && cat head"</code></div> <p>On voit toutes les deux secondes que l'âge de la page demandée augmente de deux secondes… tout va bien. Maintenant via le navigateur allons modifier un contenu, ou recalculer une page, via l'<span class="caps">URL</span> d'origine (port :80). On constate que la page n'est pas rafraichie. En effet <i>le système ne se purge que lorsque la modification de contenu passe par Varnish.</i></p> <p>Allons maintenant modifier le contenu en nous connectant à travers Varnish (sur la port :6081) : on constate que l'âge de la ressource retombe à zéro à chaque fois qu'on fait une modification.</p> <h3 class='h3 spip'>Installer Varnish en frontal</h3> <p>Désormais il ne reste plus qu'à installer Varnish sur le port :80 ; pour cela il faut :</p> <p>— configurer Apache pour qu'il écoute le port :8080 à la place du port :80 (probablement en éditant <code class='spip_code' dir='ltr'>/etc/apache2/ports.conf</code>).</p> <p>— configurer Varnish pour qu'il aille chercher les ressources sur <code class='spip_code' dir='ltr'>127.0.0.1:8080</code> ; c'est au début du fichier <code class='spip_code' dir='ltr'>/etc/varnish/default.conf</code></p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>backend default {<br /> .host = "127.0.0.1";<br /> .port = "80";<br /> ...<br /> }</code></div> <p>— relancer Apache puis lancer Varnish sur le port 80 ; sur Debian, on va modifier la variable <code class='spip_code' dir='ltr'>VARNISH_LISTEN_PORT=6081</code> dans <code class='spip_code' dir='ltr'>/etc/default/varnish</code>, puis relancer.</p> <p>On peut ensuite répéter les tests ci-dessus, en remplaçant les numéros de ports par :80 (pour Varnish) et :8080 (pour Apache).</p> <h3 class='h3 spip'>Fignoler</h3> <p><strong>Fermer l'accès direct à Apache.</strong> Si le serveur Apache répond à tout l'Internet sur le port :8080, il est probable que Google le repérera et viendra lui parler directement, indexant ainsi deux fois les sites (sur chacun des ports), et allant à l'encontre du but visé. Il faut donc configurer Apache pour qu'il ne réponde que sur localhost (<code class='spip_code' dir='ltr'>127.0.0.1</code>).</p> <p><strong>Obtenir l'<span class="caps">IP</span> du client en aval.</strong> Désormais le « client » que voit Apache est toujours Varnish, donc une même machine ayant un seul numéro <span class="caps">IP</span>. Ce n'est pas génial ni pour les logs, ni pour des logiciels qui peuvent vouloir faire du contrôle d'accès ou de la géolocalisation à partir du numéro <span class="caps">IP</span>. Pour résoudre ce problème, le plus simple est d'installer l'extension pour Apache nommée <code class='spip_code' dir='ltr'>mod_rpaf</code> (<a href="http://stderr.net/apache/rpaf/" class='spip_url spip_out auto' rel='nofollow external'>http://stderr.net/apache/rpaf/</a>) : celle-ci permet de « faire croire » à Apache que le numéro <span class="caps">IP</span> est bien celui du client en aval. Ainsi la manipe est totalement transparente pour les applications, qui du coup n'ont pas besoin d'être modifiées ni configurées.</p></div> Interfacer Varnish & SPIP http://zzz.rezo.net/Interfacer-Varnish-SPIP.html http://zzz.rezo.net/Interfacer-Varnish-SPIP.html 2011-03-29T20:53:21Z text/html fr Fil Web <p>Principe de communication Les communications entre notre application (ici il s'agira surtout de SPIP, mais le principe vaut pour d'autres applications) et notre proxy inverse Varnish se font par l'entremise des entêtes HTTP émises par l'application. Nous introduisons les header() suivants : X-Varnish-TTL : 120 Cet entête indique que la page doit avoir un TTL, dans Varnish, de 120 secondes ; dans SPIP il sera émis dans les conditions suivantes : implicitement, en prenant la durée de cache de (...)</p> - <a href="http://zzz.rezo.net/-Varnish-.html" rel="directory">Varnish</a> / <a href="http://zzz.rezo.net/+-Web-+.html" rel="tag">Web</a> <div class='rss_texte'><h3 class='h3 spip'>Principe de communication</h3> <p>Les communications entre notre application (ici il s'agira surtout de <span class="caps">SPIP</span>, mais le principe vaut pour d'autres applications) et notre proxy inverse Varnish se font par l'entremise des entêtes <span class="caps">HTTP</span> émises par l'application.</p> <p>Nous introduisons les <code class='spip_code' dir='ltr'>header()</code> suivants :</p> <p><img src='http://zzz.rezo.net/local/cache-vignettes/L8xH11/puce-32883.gif' width='8' height='11' class='puce' alt="-" style='height:11px;width:8px;' /> <code class='spip_code' dir='ltr'>X-Varnish-TTL: 120</code><br class='manualbr' />Cet entête indique que la page doit avoir un <span class="caps">TTL</span>, dans Varnish, de 120 secondes ; dans <span class="caps">SPIP</span> il sera émis dans les conditions suivantes :</p> <ol class="spip"><li> implicitement, en prenant la durée de cache de la page : <code class='spip_code' dir='ltr'>TTL = min(durée du cache, 600)</code></li> <li> ou bien explicitement via la balise <code class='spip_code' dir='ltr'>#HTTP_HEADER{X-Varnish-TTL: 120}</code></li> </ol> <p>L'appel <code class='spip_code' dir='ltr'>#HTTP_HEADER{X-Varnish-TTL: 0}</code> permet de dire à Varnish de ne pas conserver la page produite (par exemple parce qu'elle contient du code en <span class="caps">PHP</span> qu'on veut faire tourner à chaque hit).</p> <p><img src='http://zzz.rezo.net/local/cache-vignettes/L8xH11/puce-32883.gif' width='8' height='11' class='puce' alt="-" style='height:11px;width:8px;' /> <code class='spip_code' dir='ltr'>X-Varnish-Purge: *</code><br class='manualbr' />Cet entête indique à Varnish tout purger ; il est émis par la fonction <code class='spip_code' dir='ltr'>suivre_invalideur()</code>, à chaque modification des données. Il est également émis lorsqu'un changement de date provoque la publication d'un « article post-daté ».</p> <p>De plus Varnish pourra aussi, indépendamment des entêtes envoyés par l'application, se baser sur l'<span class="caps">URL</span> pour invalider certaines pages.</p> <p>Ainsi :</p> <ol class="spip"><li> l'<span class="caps">URL</span> <code class='spip_code' dir='ltr'>…?var_mode=calcul</code> est détectée par Varnish (indépendamment des entêtes de <span class="caps">SPIP</span> décrites ci-dessus), et invalide la page concernée (et celle-ci seulement).</li> <li> l'<span class="caps">URL</span> <code class='spip_code' dir='ltr'>…?var_mode=(recalcul|images)</code> est détectée par Varnish et invalide tout le cache de Varnish (notamment, parce qu'un recalcul d'une page peut provoquer la modification d'un fichier de <span class="caps">CSS</span> ou javascript associé).</li> <li> l'<span class="caps">URL</span> de suppression du cache <span class="caps">SPIP</span> depuis l'espace privé (un clic sur le bouton dans <code class='spip_code' dir='ltr'>?exec=vider_cache</code>) invalide aussi tout le cache Varnish.</li> </ol> <h3 class='h3 spip'>Implémentation</h3> <p>Cette approche me semble au final plus simple que celle donnée par la doc de Varnish, qui passe par la définition d'une méthode <span class="caps">HTTP</span> non standard <code class='spip_code' dir='ltr'>PURGE</code>. Pour l'implémenter, j'ai construit un fichier de configuration pour Varnish, ainsi qu'un plugin pour <span class="caps">SPIP</span>.</p> <p><i>Remarque :</i> les deux éléments (configuration et plugin) sont conçus pour fonctionner de concert, mais il est tout à fait possible d'utiliser la configuration pour Varnish sans installer le plugin <span class="caps">SPIP</span>. Les pages « dynamiques » produites par <span class="caps">SPIP</span> ne seront alors pas enregistrées dans le cache de Varnish, qui y stockera néanmoins tous les fichiers statiques (images, javascript, <span class="caps">CSS</span> etc.) selon des règles « assez bonnes ».</p> <p>Autrement dit, sur un serveur hébergeant plusieurs sites, on peut installer Varnish sans installer le plugin sur tous les sites : seuls les sites <span class="caps">SPIP</span> ayant installé le plugin en tireront le maximum, mais les autres ne seront pas pénalisés.</p> <h3 class='h3 spip'>Télécharger le plugin</h3> <p>La configuration de Varnish et le plugin <span class="caps">SPIP</span> sont téléchargeables depuis <span class="caps">SPIP</span>-Zone : <a href="http://zone.spip.org/trac/spip-zone/browser/_plugins_/varnish" class='spip_url spip_out auto' rel='nofollow external'>http://zone.spip.org/trac/spip-zone/browser/_plugins_/varnish</a></p> <p>Le plugin nécessite l'usage du plugin <a href="http://www.spip-contrib.net/StatsJS-compter-les-visites-avec-un-mouchard" class='spip_out' rel='external'>StatsJS</a>, car, dès lors qu'on demande à Varnish de servir directement les pages <span class="caps">SPIP</span>, celui-ci ne peut plus comptabiliser les visites des pages de la façon habituelle.</p> <h3 class='h3 spip'>Configuration de Varnish</h3> <p>Voici le fichier de configuration, commentaires inclus :</p> <form action='' method='get'><div> <input type='hidden' name='exec' value='' /> <textarea readonly='readonly' cols='40' rows='599' class='spip_cadre' dir='ltr'># # Configuration de varnish (varnish-cache.org) # optimisée pour SPIP # # Varnish est un proxy inverse, installé sur le serveur Web, # qui permet : # # - 1. Rapidité. Absorbe une demande importante sur une même URL # et y répond directement sans solliciter apache # - 2. Tolérance aux pannes. Renvoie des pages depuis sa mémoire cache # même lorsque apache est planté # - 3. Souplesse dans l'affectation de serveur(s) apache à différentes # applications (par ex. load balancing, changement de serveur, etc) # - 4. Moindre consommation de CPU : économique et écologique # # La configuration ci-dessous permet d'optimiser son fonctionnement # avec SPIP ; elle s'applique sans problème à des serveurs # hébergeant aussi d'autres types de scripts, qui peuvent utiliser # les mêmes mécanismes de communication X-Varnish-Message et X-Varnish-Purge # ## -- BACKEND PRINCIPAL -- ## ## Tout d'abord, nous allons définir l'adresse du serveur apache hébergeant ## nos sites Web (ce que varnish appelle le backend). ## ## Dans notre cas, le serveur apache est accessible sur le ## port 8080 de l'interface 127.0.0.1 ; il répond aux mêmes requêtes que ## lorsqu'il est configuré sur le port 80 : ## GET / HTTP/1.0 ## Host: nomdusite.tld ## ## Pour ce backend, nous définissons un temps de latence avant le premier octet ## de 300s ; ainsi, lorsqu'une page demande un temps de calcul très long (par ## exemple un POST d'un long article), on attend jusqu'à 5 minutes avant de ## déclarer forfait et d'envoyer une erreur 500. ## http://vincentfretin.ecreall.com/articles/varnish-guru-meditation-on-timeout ## ## De plus, varnish va lancer chaque seconde une requête de test sur une URL ## type ; si 2 requêtes sur les 3 dernières sont en faute, il déclarera le ## backend "malade" ("sick") et passera en mode "tolérance aux pannes", ## jusqu'à ce que le backend revienne en bonne santé ("healthy"). ## backend default { .host = "127.0.0.1"; .port = "80"; .first_byte_timeout = 300s; .probe = { # Ici mettre un hit vers un petit fichier fixe sur le backend #.url = "/"; .request = "GET /prive/images/searching.gif HTTP/1.0" "Host: zzz.rezo.net" "Connection: close"; .timeout = 34 ms; .interval = 3s; .window = 3; .threshold = 2; } } ## -- BACKEND DE TEST D'ERREUR 503 -- ## ## Ce backend "guru" est toujours en panne ; il est destiné à provoquer ## une erreur 503, ce qui permet d'afficher délibérément le message d'erreur ## qu'on définira en fin de ce fichier de configuration ## => http://nomdusite.tld/I'm-a-guru ## backend guru { .host = "127.0.0.1"; .port = "8082"; # !!il faut choisir un numéro de port inutilisé } ## -- RECV -- ## Cette fonction est appelée à chaque connexion d'un client sur varnish. ## ## Elle normalise la requête : ## - en supprimant les cookies inutiles ## - en unifiant les différents types de Accept-Encoding ## sub vcl_recv { ## -- GRACE -- ## ## La "grace" sert dans deux scénarios : ## ## - a. "Absorber" la connexion *simultanée* de plusieurs clients ## sur une même URL : le temps que le backend calcule et renvoie ## la nouvelle réponse, on s'autorise à servir une réponse en cache ## mais dont la date de péremption est dépassée de moins de 30s. ## - b. "Panne" : si le backend est en panne, on s'autorise à servir ## des contenus mis en cache mais dont la date de péremption est ## dépassée (jusqu'à une heure). ## if (req.backend.healthy) { set req.grace = 30s; } else { set req.grace = 1h; } ## -- COOKIES -- ## ## On nettoie ici les cookies qui n'impactent pas SPIP ; ## essentiellement les cookies de tracking statistique, mais aussi ## les cookies d'options traitées côté client (vs. côté serveur). ## Attention les cookies importants côté serveur (cookie de session admin, ## par exemple) ne doivent *pas* être nettoyés. ## if (req.http.Cookie) { ## __utm[a-z] = cookies google analytics ## xtvrn = cookies xiti set req.http.Cookie = regsuball(req.http.Cookie, "(^|; ) *(__utm[a-z]|xtvrn)=[^;]+;? *", "\1"); ## _pk.* = cookies piwik ## => attention, sur l'URL de piwik, ne pas nettoyer les cookies piwik if (req.url !~ "/piwik\.php") { set req.http.Cookie = regsuball(req.http.Cookie, "(^|; ) *(_pk_[^=]+)=[^;]+;? *", "\1"); } ## dans une application particulière, le cookie "blink" est traité ## côté client ; il ne nous intéresse pas, on le nettoie set req.http.Cookie = regsuball(req.http.Cookie, "(^|; ) *(blink)=[^;]+;? *", "\1"); ## si le cookie résultant est vide, le supprimer if (req.http.Cookie == "") { remove req.http.Cookie; } ## si on est dans un repertoire statique ignorer totalement ## les cookies (ici, les répertoires SPIP & Drupal + les images ## css, scripts, etc.) ## (le ?\d+ final est un éventuel timestamp) if (req.url ~ "^[^?]*\.(css|js|jpg|jpeg|gif|png|ico|txt|mp3)(\?\d+)?$" || req.url ~ "^/(local|IMG|extensions|plugins|static)/") { remove req.http.Cookie; } } ## fin de la section COOKIE ## -- X-FORWARDED-FOR -- ## ## Ajouter un entête X-Forwarded-For: IP ## en le concaténant avec un éventuel entête déjà existant ## if (req.http.x-forwarded-for) { set req.http.X-Forwarded-For = req.http.X-Forwarded-For ", " client.ip; } else { set req.http.X-Forwarded-For = client.ip; } ## -- GZIP -- ## unifier les accept-encoding: accepte gzip ou pas ; on ne gere pas deflate ## (notamment : FF annonce "gzip, deflate" et Safari "gzip,deflate" !) if (req.http.Accept-Encoding) { if (req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; #} elsif (req.http.Accept-Encoding ~ "deflate") { # set req.http.Accept-Encoding = "deflate"; } else { remove req.http.Accept-Encoding; } } ## -- RANGE -- ## Varnish ne doit pas gérer pas les requêtes de contenu partiel ; ## on les passe directement au backend ## cf. http://forum.developers.facebook.net/viewtopic.php?id=68440#p253346 if (req.http.Range) { return(pipe); } ## -- TEST 503 -- ## cf. ci-dessus le backend "guru" qui ne mène nulle part ## se teste via le navigateur sur http://urldusite.tld/_-_-I-m-a-guru ## permet d'afficher l'erreur définie en bas de ce fichier ## le nom zen vient de l'erreur par défaut de Varnish : "guru meditation" if (req.url == "/_-_-I-m-a-guru") { set req.backend = guru; } ## -- DIVERS -- ## certain robot fou demande host:127.0.0.1, on le jette immédiatement if (req.http.host == "127.0.0.1") { error 500 "Unknown virtual host."; } } ## -- FETCH -- ## Cette fonction est appelée à chaque retour du backend vers varnish. ## sub vcl_fetch { ## -- REDIRECTION -- ## supprimer le port (:8080) envoyé par le backend lors d'une redirection ## car on veut rediriger vers le port public :80 if (beresp.http.Location) { set beresp.http.Location = regsub(beresp.http.Location, "^(\w+://[^/]+):\d+", "\1"); } ## -- TTL: DUREE DE CACHE -- ## ## C'est la durée de vie de la page dans le cache ; au-delà de cette durée, ## elle ne pourra être servie au client que dans le scénario de "grace". ## ## Différents cas : ## -1 la ressource signale X-Varnish-TTL: 20s ## (c'est ce que fait le plugin pour SPIP) ## elle annonce à varnish que son script lui signalera plus tard, ## par un entete X-Varnish-Purge, quand le moment sera venu de ## rafraichir la page. Dans ce cas de figure on peut donc la mettre ## en cache pour la durée indiquée (si elle est > 0) ## -2a la ressource est statique, on la cache un certain temps raisonnable ## (sauf si un autre entete indique qu'elle n'est pas cacheable) ## -2b la ressource est dynamique, on ne la cache pas ## L'entête X-VARNISH-TTL permet au backend de définir le ttl du cache ## code inspiré de: http://open.blogs.nytimes.com/2010/09/15/using-varnish-so-news-doesnt-break-your-server/ ## http://www.lovelysystems.com/configuring-varnish-to-use-custom-http-headers/ ## ## (n'utilise pas X-SPIP-Cache car, sur SPIP standard, ça tuerait les stats) ## if (beresp.http.X-VARNISH-TTL) { C{ char *ttl; ttl = VRT_GetHdr(sp, HDR_BERESP, "\016X-VARNISH-TTL:"); VRT_l_beresp_ttl(sp, atoi(ttl)); }C remove beresp.http.X-VARNISH-TTL; } ## sinon se baser sur la logique habituelle de varnish (Expires, etc) ; ## en ajoutant une règle pour les fichiers dont on sait avec certitude ## qu'ils sont statiques : les images etc else { ## ne cacher que les css, js, jpg, gif, png, etc. ## le (?\d+) est un éventuel timestamp ## à noter : si apache est bien configuré, cette ligne est inutile if (req.url ~ "\.(css|js|jpg|jpeg|gif|png|ico|txt|mp3)(\?\d+)?$" || req.url ~ "^/(local|IMG|extensions|plugins|static)/") { set beresp.ttl = 600s; set beresp.http.Cache-Control = "max-age=600"; set beresp.http.Vary = "Accept-Encoding"; } ## ne pas cacher une ressource qui ne precise pas d'entete de cache else { if ( (!beresp.http.Cache-Control && !beresp.http.Expires) || beresp.http.Cache-Control ~ "no-cache" || beresp.http.Cache-Control ~ "private" ) { set beresp.cacheable = false; } #else { # set beresp.cacheable = false; # remove beresp.http.Cache-Control; #} } } ## ne pas conserver une ressource servie vieille aux robots if (beresp.http.X-Varnish-Stale) { set beresp.cacheable = false; #remove beresp.http.X-Varnish-Stale; } ## -- INVALIDATIONS -- ## ## On a vu ci-dessus qu'une page pouvait entrer en cache si elle s'annonçait ## via X-Varnish-Message-OK ## ## Si à l'inverse le backend veut invalider le cache, il suffit ## qu'il envoie un entête X-Varnish-Purge ## if (beresp.http.X-Varnish-Purge) { purge("req.http.host == " req.http.host); remove beresp.http.X-Varnish-Purge; set beresp.cacheable = false; } ## -- VAR_MODE -- ## Cette section gère les invalidations via le bouton d'admin ## si on demande un var_mode=recalcul on va par principe tout purger ## pour ne pas subir de cache secondaire, par exemple dans local/ ## lorsqu'on modifie des CSS ou des images calculées ## En revanche un var_mode=calcul est plus léger if (req.url ~ "[?&]var_mode=(recalcul|images)") { purge ("req.http.host == " req.http.host); set beresp.cacheable = false; } ## si on demande un var_mode=calcul on va purger uniquement la page ## demandee, sans son var_mode elsif (req.url ~ "[?&]var_mode=calcul") { purge ("req.http.host == " req.http.host " && req.url == " regsuball(req.url,"[&?]var_mode=.*$", "")); set beresp.cacheable = false; } ## -- GRACE -- ## Si la réponse est cacheable, on peut la conserver pour un maximum d'1h ## au cas où on aurait une panne (maximum des "grace" définies dans RECV) ## http://varnish-cache.org/trac/wiki/VCLExampleGrace set beresp.grace = 1h; ## -- RANGE -- ## seuls les gros fichiers (sons, videos) sont susceptibles de valoir ## un range ; on n'annonce donc le range que pour ceux-la, et on desactive ## l'entete if (beresp.http.Accept-Ranges && beresp.http.content-type !~ "(image|audio|video)/") { remove beresp.http.Accept-Ranges; } ## -- ETAG -- ## corrige un bug d'apache qui donne le même Etag aux représentations ## gzip et non-gzip d'un même fichier... if (beresp.http.content-encoding == "gzip" && beresp.http.etag) { set beresp.http.Etag = regsub(beresp.http.etag, ".$", "-gzip\0"); } ## -- ACTION=CRON -- ## inutile de solliciter la page action=cron de SPIP plus d'1 fois par 5s ## (à noter : avec les stats en js cette action disparaît) if (req.url ~ "\?action=cron$") { set beresp.ttl = 5s; set beresp.cacheable = true; } } ## -- HASH -- ## ## Cette fonction établit le nom du cache en fonction des caractéristiques ## de la requête sub vcl_hash { set req.hash += req.url; if (req.http.host) { set req.hash += req.http.host; } else { set req.hash += server.ip; } return (hash); } ## -- HIT -- ## ## Cette fonction est appelée quand une page est trouvée dans le cache ## de Varnish ; on ajoute une logique pour que "force-reload", sur un ## navigateur correct, n'utilise pas le cache : il conduit jusqu'au backend ## et met à jour le cache sub vcl_hit { # non cacheable, on passe if (!obj.cacheable) { return (pass); } # force-refresh will update the cache # http://www.varnish-cache.org/trac/wiki/VCLExampleEnableForceRefresh if (req.http.Cache-Control ~ "no-cache") { # Ignore requests via proxy caches, IE users and badly behaved crawlers # like msnbot that send no-cache with every request. if (! (req.http.Via || req.http.User-Agent ~ "bot|MSIE")) { set obj.ttl = 0s; return (restart); } } # standard response: use the cached version return (deliver); } ## -- DELIVER -- ## ## Cette fonction est appelée à l'envoi final du fichier, sauf (pass) ## ## On met le champ Age dans X-Varnish-Age sinon ça fait râler redbot.org ## On supprime Accept-Ranges de tous les fichiers sauf les images/sons/vidéos ## sub vcl_deliver { { set resp.http.X-Varnish-Age = resp.http.age; remove resp.http.age; if (resp.http.content-type !~ "(image|audio|video)/") { remove resp.http.accept-ranges; } } } ## -- ERROR -- ## ## Cette fonction est appelée en cas d'erreur, par exemple ## lorsque l'objet n'est pas en cache et que le backend est ## en panne (erreur 503). ## ## On peut la déclencher volontairement, pour la tester, via l'URL "guru" ## sub vcl_error { set obj.http.Content-Type = "text/html; charset=utf-8"; synthetic {" <html><head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>"} obj.status " " obj.response {"</title> <style type="text/css"> body { background: #689ab3; color: #333; margin: 0; font-size:1.3em; font-family: georgia, serif; } div { margin: 30px 0 0 0; background: #ffffff; opacity: 0.6; width: 650px; padding: 20px 20px 23px 23px; } p { margin: 0.5em 0 0.5em 0; } p.en { margin: 0 0 0.5em 0; } p.fin { margin: 0.5em 0 0 0; } p.message { font-size: 1.5em; margin: 0 0 0.5em 0; } h1 { font-size: 2em; margin: 0 0 0.5em 0; font-weight:normal; display:none; } </style> </head><body> <div> <p class="message">Le service est momentanément indisponible.<br /> Veuillez réessayer un peu plus tard. </p> <p class="en">The service is currently unavailable. Please try again later. </p> <p class="fin"><small>Erreur "} obj.status {" | XID: "} req.xid {"</small></p> </div> </body></html> "}; return (deliver); }</textarea></div></form> <p>Comme on le voit c'est un <i>gros</i> fichier… on pourra en suivre le développement dans le répertoire du plugin.</p> <p> </p> <p>Dans le prochain article j'indiquerai comment procéder pour terminer l'installation.</p></div> Installer Varnish http://zzz.rezo.net/Installer-Varnish.html http://zzz.rezo.net/Installer-Varnish.html 2011-03-13T21:33:39Z text/html fr Fil Web <p>Pour commencer, nous allons installer Varnish sur un port secondaire (6081), et laisser le port 80 à Apache. Une fois que ça tournera correctement, et que la configuration sera satisfaisante, il sera temps d'inverser. On va d'abord chercher les sources au format tgz : http://www.varnish-cache.org/releases/varnish-cache-2.1.5, et on compile. # wget http://repo.varnish-cache.org/source/varnish-2.1.5.tar.gz # tar -xzf varnish-2.1.5.tar.gz # cd varnish-2.1.5 # ./configure # make # sudo make (...)</p> - <a href="http://zzz.rezo.net/-Varnish-.html" rel="directory">Varnish</a> / <a href="http://zzz.rezo.net/+-Web-+.html" rel="tag">Web</a> <div class='rss_chapo'><p>Pour commencer, nous allons installer Varnish sur un port secondaire (6081), et laisser le port 80 à Apache. Une fois que ça tournera correctement, et que la configuration sera satisfaisante, il sera temps d'inverser.</p></div> <div class='rss_texte'><p>On va d'abord chercher les sources au format tgz : <a href="http://www.varnish-cache.org/releases/varnish-cache-2.1.5" class='spip_url spip_out auto' rel='nofollow external'>http://www.varnish-cache.org/releases/varnish-cache-2.1.5</a>, et on compile.</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code># wget http://repo.varnish-cache.org/source/varnish-2.1.5.tar.gz<br /> # tar -xzf varnish-2.1.5.tar.gz<br /> # cd varnish-2.1.5<br /> # ./configure<br /> # make<br /> # sudo make install</code></div> <p>Cela fait, le démon <code class='spip_code' dir='ltr'>varnishd</code> est installé dans <code class='spip_code' dir='ltr'>/usr/local/sbin/</code> et les scripts d'administration se trouvent dans <code class='spip_code' dir='ltr'>/usr/local/bin/varnishadm</code>.</p> <p>On commence à éditer <code class='spip_code' dir='ltr'>/etc/varnish/default.conf</code> :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code> backend default {<br /> .host = "127.0.0.1";<br /> .port = "80";<br /> }</code></div> <p>On lance ensuite le démon à la main :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code># /usr/local/sbin/varnishd -f /etc/varnish/default.vcl -a127.0.0.1:6081 -S /etc/varnish/secret -Tlocalhost:6082 -s malloc,100M</code></div> <p>(Ici, avec <code class='spip_code' dir='ltr'>-s malloc,100M</code> on affecte 100Mo de <span class="caps">RAM</span> à Varnish ; au passage en production, on pourra lui attribuer 1Go ou même plus. Attention, si on n'utilise pas <code class='spip_code' dir='ltr'>malloc</code>, on se retrouve facilement à remplir son disque dur, dans des fichiers situés dans les répertoires <code class='spip_code' dir='ltr'>/usr/local/var/varnish/*</code>.)</p> <p>Désormais <code class='spip_code' dir='ltr'>varnishd</code> écoute le port 6081, et va chercher les ressources demandées sur le port 80, où se trouve Apache.</p> <p>Sur Debian, on va créer un fichier de configuration pour le démarrage du démon. Ce fichier se trouve dans <code class='spip_code' dir='ltr'>/etc/default/varnish</code></p> <form action='' method='get'><div> <input type='hidden' name='exec' value='' /> <textarea readonly='readonly' cols='40' rows='69' class='spip_cadre' dir='ltr'># Should we start varnishd at boot? Set to "yes" to enable. START=yes # Maximum number of open files (for ulimit -n) NFILES=131072 # Maximum locked memory size (for ulimit -l) # Used for locking the shared memory log in memory. If you increase log size, # you need to increase this number as well MEMLOCK=82000 # Default varnish instance name is the local nodename. Can be overridden with # the -n switch, to have more instances on a single server. INSTANCE=$(uname -n) # Main configuration file. You probably want to change it :) VARNISH_VCL_CONF=/etc/varnish/default.vcl # Default address and port to bind to # Blank address means all IPv4 and IPv6 interfaces, otherwise specify # a host name, an IPv4 dotted quad, or an IPv6 address in brackets. VARNISH_LISTEN_ADDRESS= VARNISH_LISTEN_PORT=6081 # Telnet admin interface listen address and port VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 VARNISH_ADMIN_LISTEN_PORT=6082 # The minimum number of worker threads to start VARNISH_MIN_THREADS=200 # The Maximum number of worker threads to start VARNISH_MAX_THREADS=1000 # Idle timeout for worker threads VARNISH_THREAD_TIMEOUT=120 # Cache file size: in bytes, optionally using k / M / G / T suffix, # or in percentage of available disk space using the % suffix. VARNISH_STORAGE_SIZE=512M # File containing administration secret VARNISH_SECRET_FILE=/etc/varnish/secret # Backend storage specification VARNISH_STORAGE="malloc,${VARNISH_STORAGE_SIZE}" # Default TTL used when the backend does not specify one VARNISH_TTL=120 # DAEMON_OPTS is used by the init script. If you add or remove options, make # sure you update this section, too. DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \ -f ${VARNISH_VCL_CONF} \ -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \ -t ${VARNISH_TTL} \ -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \ -S ${VARNISH_SECRET_FILE} \ -s ${VARNISH_STORAGE} \ -p http_range_support=yes"</textarea></div></form> <p>Et on l'appelle avec la commande <code class='spip_code' dir='ltr'>/etc/init.d/varnish start</code>.</p> <p>Varnish est installé.</p> <p>On peut voir nos pages à l'adresse http://<span class="caps">URLDUSITE</span>:6081/</p> <p>Dans les entêtes on observe quelque chose du genre :<br class='manualbr' /><code class='spip_code' dir='ltr'>X-Varnish: 1234</code><br class='manualbr' />ou <br class='manualbr' /><code class='spip_code' dir='ltr'>X-Varnish: 4567 1234</code></p> <p>Dans le premier cas, Varnish nous informe qu'il s'agit du 1234e hit qu'il a reçu, et qu'il est allé chercher la ressource sur le backend. Dans le second, il s'agit du 4567e hit, et c'est la ressource qu'il a mise en cache lors du 1234e hit qui a été servie directement, sans appel au backend.</p> <p>Notre configuration ouvre un port d'administration (localhost:6082), protégé par un secret écrit dans le fichier <code class='spip_code' dir='ltr'>/etc/varnish/secret</code><br class='autobr' /> On peut dès lors appeler le script d'administration avec la commande<br class='manualbr' /><code class='spip_code' dir='ltr'>varnishadm -T localhost:6082 -S /etc/varnish/secret</code></p> <p>C'est de là qu'on va piloter les fichiers de configuration.</p> <p>Pour se faciliter la vie, au moins lors de la mise au point de la configuration, on va adapter ce script <a href="http://kristianlyng.wordpress.com/2009/02/18/easy-reloading-of-varnish-vcl/" class='spip_url spip_out auto' rel='nofollow external'>http://kristianlyng.wordpress.com/2009/02/18/easy-reloading-of-varnish-vcl/</a> et le sauvegarder dans <code class='spip_code' dir='ltr'>/usr/local/bin/varnishreload</code>.</p> <form action='' method='get'><div> <input type='hidden' name='exec' value='' /> <textarea readonly='readonly' cols='40' rows='24' class='spip_cadre' dir='ltr'>#!/bin/bash # Reload a varnish config # Author: Kristian Lyngstol FILE="/etc/varnish/default.vcl" # Hostname and management port # (defined in /etc/default/varnish or on startup) HOSTPORT="localhost:6082" SECRET=" -S /etc/varnish/secret" NOW=`date +%s` HASH=`md5sum -b $FILE | awk '{print $1}'` error() { echo 1>&2 "Failed to reload $FILE." exit 1 } varnishadm -T $HOSTPORT $SECRET vcl.load $HASH $FILE #|| error varnishadm -T $HOSTPORT $SECRET vcl.use $HASH || error echo Current configs: varnishadm -T $HOSTPORT $SECRET vcl.list</textarea></div></form> <p>Dès lors on recharge la configuration <code class='spip_code' dir='ltr'>/etc/varnish/default.vcl</code> après chaque modification du fichier via la commande :<br class='manualbr' /><code class='spip_code' dir='ltr'># varnishreload</code></p> <p>Dans un prochain article nous verrons comment structurer ce fichier de configuration de manière à l'optimiser pour des sites sous <span class="caps">SPIP</span>.</p></div> À quoi sert Varnish ? http://zzz.rezo.net/A-quoi-sert-Varnish.html http://zzz.rezo.net/A-quoi-sert-Varnish.html 2011-03-11T21:55:36Z text/html fr Fil Web <p>Utilisé par des sites parmi les plus importants de la planète, Varnish est un ingrédient essentiel d'une bonne cuisine de serveur Web. Tout responsable de site Internet connaît le dilemme : quand il n'y a personne pour le visiter, le site marche très bien. Dès qu'il a du succès, il plante ! La difficulté s'appelle l'effet slashdot, du nom d'un webzine qui, lorsqu'il référence un site, y envoie tellement de visiteurs que le site s'effondre sous le poids des visites. Pour essayer de contrer ce problème, (...)</p> - <a href="http://zzz.rezo.net/-Varnish-.html" rel="directory">Varnish</a> / <a href="http://zzz.rezo.net/+-Web-+.html" rel="tag">Web</a> <div class='rss_chapo'><p>Utilisé par des sites parmi les plus importants de la planète, Varnish est un ingrédient essentiel d'une bonne cuisine de serveur Web.</p></div> <div class='rss_texte'><p>Tout responsable de site Internet connaît le dilemme : quand il n'y a personne pour le visiter, le site marche très bien. Dès qu'il a du succès, il plante ! La difficulté s'appelle <i>l'effet slashdot,</i> du nom d'un webzine qui, lorsqu'il référence un site, y envoie tellement de visiteurs que le site s'effondre sous le poids des visites.</p> <p>Pour essayer de contrer ce problème, plusieurs parades ont été inventées : des « caches » plus ou moins « statiques » permettent au serveur Apache de ne pas lancer de script <span class="caps">PHP</span> pour calculer la même page pour chaque visiteur. Des répartiteurs de charge (load balancers) permettent d'aiguiller les visiteurs vers plusieurs machines physiques, etc.</p> <p>L'approche de Varnish (un logiciel libre disponible sur <a href='http://www.varnish-cache.org/' class='spip_url spip_out auto' rel='nofollow external'>www.varnish-cache.org</a>) est celle d'un « proxy inverse » : c'est un serveur qui écoute les requêtes en provenance des clients, et les transmet au serveur Web applicatif proprement dit (Apache). Au passage, s'il voit que plusieurs visiteurs sollicitent la même ressource, il la demande une seule fois et la transmet ensuite à tous les visiteurs en même temps ; et s'il est autorisé à mémoriser une réponse, il ne la demande plus au serveur, pour un temps donné.</p> <p>Varnish peut être configuré pour, en fonction de certains paramètres (<span class="caps">URL</span> de la ressource demandée, présence de tel cookie chez le visiteur, adresse <span class="caps">IP</span> du visiteur, etc.), demander la ressource à différents serveurs applicatifs, que dans son jargon il appelle « backends ».</p> <p>Voici une petite vidéo qu'a publié la société qui s'est construite pour développer Varnish.</p> <iframe title="YouTube video player" width="496" height="302" src="http://www.youtube.com/embed/eAbamezUOjs" frameborder="0" allowfullscreen></iframe> <p>En bonus, quand Apache est planté, Varnish peut fournir la ressource demandée si elle est en cache, ou à l'inverse renvoyer une page informative au visiteur. C'est ce qui m'est arrivé tout à l'heure... Visiblement ça a plu à certains utilisateurs, qui exigent maintenant de savoir où est passée la si jolie page d'erreur (photo de baroug) !</p> <p><span class='spip_document_56 spip_documents spip_documents_center'> <img src='http://zzz.rezo.net/local/cache-vignettes/L500xH241/503-344bd.jpg' width='500' height='241' alt="" style='height:241px;width:500px;' /></span></p> <p>Dans de prochains articles, j'indiquerai comment installer et configurer Varnish pour en tirer le maximum avec <span class="caps">SPIP</span>.</p></div> Utiliser CouchDB avec SPIP http://zzz.rezo.net/Utiliser-CouchDB-avec-SPIP.html http://zzz.rezo.net/Utiliser-CouchDB-avec-SPIP.html 2011-01-08T14:10:13Z text/html fr Fil Web <p>CouchDB est un gestionnaire de base de données orienté documents, faisant partie du mouvement NoSQL : au lieu d'être ordonnée en lignes et en colonnes, la base est constituée d'une collection de documents au format JSON. On l'interroge par des requêtes HTTP. Ci-dessous, un exemple d'utilisation avec SPIP. HTTP et JSON : la boucle (DATA) de SPIP peut nativement parler à CouchDB. Comme exemple d'application, voici un squelette permettant d'afficher les « câbles » diplomatiques américains révélés par (...)</p> - <a href="http://zzz.rezo.net/-SPIP-.html" rel="directory">SPIP</a> / <a href="http://zzz.rezo.net/+-Web-+.html" rel="tag">Web</a> <div class='rss_chapo'><p>CouchDB est un gestionnaire de base de données orienté documents, faisant partie du mouvement <a href="http://fr.wikipedia.org/wiki/NoSQL" class='spip_glossaire' rel='external'>NoSQL</a> : au lieu d'être ordonnée en lignes et en colonnes, la base est constituée d'une collection de documents au format <span class="caps">JSON</span>. On l'interroge par des requêtes <span class="caps">HTTP</span>. Ci-dessous, un exemple d'utilisation avec <span class="caps">SPIP</span>.</p></div> <div class='rss_texte'><p><span class="caps">HTTP</span> et <span class="caps">JSON</span> : la boucle <code class='spip_code' dir='ltr'>(DATA)</code> de <span class="caps">SPIP</span> peut nativement parler à CouchDB. Comme exemple d'application, voici un squelette permettant d'afficher les « câbles » diplomatiques américains révélés par Wikileaks.</p> <p>(Pour en savoir plus sur CouchDB : <a href="http://couchdb.apache.org/" class='spip_url spip_out auto' rel='nofollow external'>http://couchdb.apache.org/</a>)</p> <h3 class='h3 spip'>La base de données</h3> <p>Le 6 décembre 2010, Benoît Chesneau <a href="https://twitter.com/#!/benoitc/status/11735512788246529" class='spip_out' rel='external'>annonçait</a> qu'il mettait les cablegate à disposition dans une base CouchDB :</p> <blockquote class="spip"> <p>You can now replicate cables in your couchdb via https <a href="https://upondata.com/cablesgate" class='spip_url spip_out auto' rel='nofollow external'>https://upondata.com/cablesgate</a> , more mirroring soon. #cablesgate #wikileaks</p> </blockquote> <p>On peut explorer cette base de données en utilisant la superbe interface Futon, associée à CouchDB : <a href="https://upondata.com/_utils/" class='spip_url spip_out' rel='external'>https://upondata.com/_utils/</a></p> <dl class='spip_document_55 spip_documents spip_documents_center'> <dt><img src='http://zzz.rezo.net/local/cache-vignettes/L500xH195/Futon-7f401.png' width='500' height='195' alt='PNG - 66.3 ko' style='height:195px;width:500px;' /></dt> <dt class='crayon document-titre-55 spip_doc_titre' style='width:350px;'><strong>Futon</strong></dt> </dl> <p>Sous CouchDB, la liste des documents disponibles se trouve derrière une adresse du type <code class='spip_code' dir='ltr'>URL_BASE_DONNEES/_all_docs</code>, et les résultats sont renvoyés sous forme d'un tableau au format <span class="caps">JSON</span>, dont l'élément <code class='spip_code' dir='ltr'>rows</code> contient les résultats.</p> <p>Une simple boucle permet de vérifier rapidement le contenu de cette base :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code><BOUCLE_liste(DATA)<br /> {source json, https://upondata.com/cablesgate/_all_docs}<br /> {datapath rows}<br /> {pagination 10}<br /> ><br /> [(#VALEUR|print)<br />]<br /> </BOUCLE_liste></code></div> <p>(On a ajouté la pagination car la base contient déjà plus de 1500 documents).</p> <p>Résultat :</p> <blockquote class="spip"> <p><small> 00HARARE5461, 00HARARE5461, 1-ab2f3b839699e38a0ade9a69580d3807<br /> 00HARARE6677, 00HARARE6677, 1-ff69b744322ed2ad40684a3049438a76<br /> 01PRETORIA1173, 01PRETORIA1173, 1-17ae5eba0e6fa54f756e11c33db3c12c<br /> 01VATICAN1261, 01VATICAN1261, 1-5b2bb5179171b8fdb6cf5c49e70f7efc<br /> 01VATICAN3507, 01VATICAN3507, 1-cf8f30b56ae3b022a9a13c18e9861fdf<br /> 02BRASILIA4227, 02BRASILIA4227, 1-618545c581de8c36034e69125ab91b91<br /> 02ROME1196, 02ROME1196, 1-c3886574e19883f1710941c5306f58c8<br /> 02VATICAN819, 02VATICAN819, 1-118b2bb09f1aeb02771368f88ec03439<br /> 03ABUDHABI2641, 03ABUDHABI2641, 1-9253471e5f4f776c89032acb245cab44<br /> 03BRASILIA3122, 03BRASILIA3122, 1-03f664271441db15b2a72730af841c11 </small></p> </blockquote> <p>Ces valeurs sont la clé, l'identifiant (dans ce cas, égal à la clé), et le numéro de révision de chaque document.</p> <p>Pour aller chercher un document particulier il suffit de solliciter l'<span class="caps">URL</span> correspondant à son identifiant : par exemple <a href="https://upondata.com/cablesgate/00HARARE5461" class='spip_url spip_out' rel='external'>https://upondata.com/cablesgate/00H...</a> ; le document s'affiche alors au format <span class="caps">JSON</span>.</p> <p>Une deuxième boucle <code class='spip_code' dir='ltr'>(DATA)</code> permet d'afficher proprement les champs du document :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code><BOUCLE_cable(DATA)<br /> {source json, https://upondata.com/cablesgate/00HARARE5461}<br /> ><br /> [<dt>#CLE</dt><br /> <dd><kbd>(#VALEUR|print)</kbd></dd>]<br /> </BOUCLE_cable></code></div> <p>Résultat :</p> <blockquote class="spip"> <dl> <dt>_id</dt> <dd><kbd>00HARARE5461</kbd></dd> <dt>_rev</dt> <dd><kbd>1-ab2f3b839699e38a0ade9a69580d3807</kbd></dd> <dt>origin</dt> <dd><kbd>CONFIDENTIAL</kbd></dd> <dt>date_time</dt> <dd><kbd>2000-09-27 14:02</kbd></dd> <dt>body</dt> <dd><kbd>C O N F I D E N T I A L SECTION 01 OF 02 HARARE 005461 SIPDIS NSC FOR SENIOR AFRICA DIRECTOR GAYLE SMITH LONDON FOR CHARLES GURNEY PARIS FOR BISA WILLIAMS PASS USTR FOR ROSA WHITAKER EO 12958 DECL : 09/21/10 TAGS PGOV, PINS, ZI, MDC, ZANU-PF (...)</kbd></dd> <dt>classification</dt> <dd><kbd>2010-12-18 21:09</kbd></dd> <dt>header</dt> <dd><kbd>This record is a partial extract of the original cable. The full text of the original cable is not available. (...)</kbd></dd> <dt>refererence_id</dt> <dd><kbd>00HARARE5461</kbd></dd> </dl> </blockquote> <p><i>Remarque : </i> à l'inverse des boucles standard de <span class="caps">SPIP</span>, basées sur <span class="caps">SQL</span>, on voit donc qu'il faut ici appeler des services différents pour obtenir soit un document, soit une liste de documents.</p> <p>Ajoutons maintenant quelques bidouilles décoratives :<br />— pagination<br />— passage de l'identifiant du câble par la variable <code class='spip_code' dir='ltr'>#ID</code><br />— utilisation du critère <code class='spip_code' dir='ltr'>{si #ID}</code> pour ne lancer la <code class='spip_code' dir='ltr'><BOUCLE_cable ...></code> qu'en présence d'un identifiant<br />— gestion des sauts de ligne, marqués dans le champ <code class='spip_code' dir='ltr'>body</code> par la séquence <code class='spip_code' dir='ltr'>&#x000A;</code></p> <p>Et nous obtenons, en deux boucles, une première version de notre application :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code><B_liste><br /> [<p class="pagination">(#PAGINATION)</p>]<br /> <ul><br /> <BOUCLE_liste(DATA)<br /> {source json, https://upondata.com/cablesgate/_all_docs}<br /> {datapath rows}<br /> {pagination 10}<br /> ><br /> <li><a href="[(#SELF|parametre_url{id,#VALEUR{id}})]"<br /> >#VALEUR{id}</a></li><br /> </BOUCLE_liste><br /> </ul><br /> </B_liste><br /> <br /> <B_cable><br /> <h2>#ID</h2><br /> <BOUCLE_cable(DATA)<br /> {source json, https://upondata.com/cablesgate/#ID}<br /> {si #ID}<br /> ><br /> [<dt>#CLE</dt><br /> <dd><kbd>(#VALEUR|print|replace{&#x000A;,<br />})</kbd></dd>]<br /> </BOUCLE_cable></code></div> <h3 class='h3 spip'>Trier par date, afficher le sujet</h3> <p>Pour aller plus loin, on veut pouvoir afficher notre liste de documents non pas dans l'ordre de stockage dans la base de données, mais selon leur date de publication (donnée dans le champ <code class='spip_code' dir='ltr'>classification</code> de la base de Benoît... on dirait qu'il s'est un peu emmêlé les pinceaux dans ses nommages...) ; on veut aussi afficher à côté le sujet du câble, qu'il va falloir extraire du champ <code class='spip_code' dir='ltr'>body</code> de chaque document.</p> <p>Pour cela, il faut ajouter une vue à la base de données. Comme celle-ci est gérée par Benoît Chesneau, nous n'y avons pas accès en écriture, et ne pouvons donc rien y ajouter. Nous allons donc créer une base CouchDB nous appartenant, dans laquelle on va recopier (« replicate » en langage CouchDB) celle de Benoît, puis ajouter notre vue.</p> <p>Deux méthodes :<br />— soit on installe CouchDB sur notre serveur <a href="http://wiki.apache.org/couchdb/Installation" class='spip_url spip_out' rel='external'>http://wiki.apache.org/couchdb/Inst...</a><br />— soit on crée un compte hébergé sur <a href='http://www.couchone.com/' class='spip_url spip_out' rel='external'>www.couchone.com</a></p> <p>Dans les deux cas, l'interface Futon permet de naviguer facilement dans les données. Une fois notre base créée, on utilise le menu Replicator pour lui dire de recopier la base source <code class='spip_code' dir='ltr'>https://upondata.com/cablesgate</code> dans la nôtre.</p> <dl class='spip_document_53 spip_documents spip_documents_center'> <dt><img src='http://zzz.rezo.net/local/cache-vignettes/L500xH114/replicator-84b12.png' width='500' height='114' alt='PNG - 29.9 ko' style='height:114px;width:500px;' /></dt> <dt class='crayon document-titre-53 spip_doc_titre' style='width:350px;'><strong>Replicator</strong></dt> </dl> <p>Nous ajoutons ensuite une vue (<i>view</i>) :</p> <dl class='spip_document_54 spip_documents spip_documents_center'> <dt><img src='http://zzz.rezo.net/local/cache-vignettes/L500xH193/view-61b29.png' width='500' height='193' alt='PNG - 43.5 ko' style='height:193px;width:500px;' /></dt> <dt class='crayon document-titre-54 spip_doc_titre' style='width:350px;'><strong>View</strong></dt> </dl> <p>Voici le code de notre vue ; c'est un <span class="caps">JSON</span> décrivant une fonction <code class='spip_code' dir='ltr'>map</code> écrite en javascript.</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>{<br /> "classification": {<br /> "map": "function (doc) {<br /> if (doc.body && (doc.subject = doc.body.match(/SUBJECT:(.*?)&#x000A;&#x000A;/))) {<br /> doc.subject = doc.subject[1].substr(0,300);<br /> }<br /> else {<br /> doc.subject = 'Untitled';<br /> }<br /> emit(doc.classification, {<br /> date_time:doc.date_time,<br /> subject:doc.subject,<br /> origin:doc.origin||null<br /> });<br /> }"<br /> }<br /> }</code></div> <p>Comme on l'a vu avec la boucle ci-dessus, chaque document contient un champ <code class='spip_code' dir='ltr'>classification</code> avec la date de mise en ligne du document.</p> <p>Notre fonction <code class='spip_code' dir='ltr'>map:</code> va donc émettre, pour chaque document, une clé correspondant à cette valeur <code class='spip_code' dir='ltr'>doc.classification</code>, ce qui permettra de trier les résultats selon cette valeur. On émet aussi, en valeur, un sujet extrait à coup d'expression rationnelle du <code class='spip_code' dir='ltr'>doc.body</code> (quand c'est possible), ainsi que les champs <code class='spip_code' dir='ltr'>date_time</code> et <code class='spip_code' dir='ltr'>origin</code> du document.</p> <p>Dès lors, si on appelle l'<span class="caps">URL</span> <code class='spip_code' dir='ltr'>/_design/sort/_view/classification</code> sur notre base CouchDB, on obtient la liste des câbles triés par date de mise en ligne, ainsi que leur sujet et niveau de classification.</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>{<br /> "id":"04ANKARA348",<br /> "key":"2010-11-28 18:06",<br /> "value":{<br /> "date_time":"2004-01-20 12:12",<br /> "subject":"Untitled",<br /> "origin":"CONFIDENTIAL"<br /> }<br /> },<br /> {<br /> "id":"04ANKARA7211",<br /> "key":"2010-11-28 18:06",<br /> "value":{<br /> "date_time":"2004-12-30 05:05",<br /> "subject":"Untitled",<br /> "origin":"SECRET"<br /> }<br /> },<br /> {<br /> "id":"05ABUDHABI2178",<br /> "key":"2010-11-28 18:06",<br /> "value":{<br /> "date_time":"2005-05-16 09:09",<br /> "subject":"Untitled",<br /> "origin":"SECRET"<br /> }<br /> },<br /> {<br /> "id":"05ANKARA1730",<br /> "key":"2010-11-28 18:06",<br /> "value":{<br /> "date_time":"2005-03-25 09:09",<br /> "subject":" TURKEY ADRIFT",<br /> "origin":"CONFIDENTIAL"<br /> }<br /> },<br /> ...</code></div> <p>Pour les obtenir dans l'ordre inverse (les plus récents en premier), on utilise l'<span class="caps">URL</span> <code class='spip_code' dir='ltr'>/_design/sort/_view/classification?descending=true</code>.</p> <h3 class='h3 spip'>Notre application complète</h3> <p>Voici au final le squelette de notre application complète. Ici, on a installé CouchDB en local, l'<span class="caps">URL</span> de notre base est <code class='spip_code' dir='ltr'>http://127.0.0.1:5984/cablegate</code></p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>#SET{base,http://127.0.0.1:5984/cablegate}<br /> <br /> <B_liste><br /> [<p class="pagination">(#PAGINATION)</p>]<br /> <ul><br /> <BOUCLE_liste(DATA)<br /> {source json, #GET{base}/_design/sort/_view/classification?descending=true}<br /> {datapath rows}<br /> {pagination 5}<br /> ><br /> <li><a href="[(#SELF|parametre_url{id,#VALEUR{id}})]"<br /> >#VALEUR{id}</a><br /><br /> <small>#VALEUR{value/subject}<br /><br /> [(#VALEUR{value/date_time})] | #VALEUR{value/origin}<br /> </small><br /> </li><br /> </BOUCLE_liste><br /> </ul><br /> </B_liste><br /> <br /> <B_cable><br /> <h2>#ID</h2><br /> <BOUCLE_cable(DATA)<br /> {source json, #GET{base}/#ID}<br /> {si #ID}<br /> ><br /> [<dt>#CLE</dt><br /> <dd><kbd>(#VALEUR|print|replace{&#x000A;,<br />})</kbd></dd>]<br /> </BOUCLE_cable></code></div> <p>Résultat :</p> <blockquote class="spip"> <p class="pagination"> <span class="on">0</span> | 5 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | ...</p> <ul> <li>09BRASILIA1239<br /> <small> HANDLING VISA REQUEST FROM BRAZILIAN INVOLVED IN THE 1969 KIDNAPPING OF THE U.S. <br /> 2009-10-15 17:05 | SECRET//NOFORN</small> </li> <li>04BRASILIA2803<br /> <small>Untitled<br /> 2004-11-12 16:04 | UNCLASSIFIED//FOR OFFICIAL USE ONLY</small> </li> <li>10SANTIAGO25<br /> <small> Meet Chile's President-Elect, Sebastian Pinera<br /> 2010-01-22 20:08 | CONFIDENTIAL</small> </li> <li>09SANTIAGO867<br /> <small> CHILE: Conservatives Beat Back Skeleton in Pinera's Closet<br /> 2009-10-09 15:03 | CONFIDENTIAL</small> </li> <li>08SANTIAGO249<br /> <small> CHILE'S "NEXT PRESIDENT" WILL PROPOSE A "NEW&#x000A;DEAL": A TAD EARLY FOR COMPARISONS TO FDR<br /> 2008-03-17 14:02 | CONFIDENTIAL</small> </li> </ul> <h2>04BRASILIA2803</h2> <dt>_id</dt> <dd><kbd>04BRASILIA2803</kbd></dd> <dt>_rev</dt> <dd><kbd>1-385f6e7e62f2249fb1877e04b9819021</kbd></dd> <dt>origin</dt> <dd><kbd>UNCLASSIFIED//FOR OFFICIAL USE ONLY</kbd></dd> <dt>date_time</dt> <dd><kbd>2004-11-12 16:04</kbd></dd> <dt>body</dt> <dd><kbd>UNCLAS BRASILIA 002803 <br /><br />SIPDIS <br /><br />SENSITIVE <br /><br />PORT-AU-PRINCE FOR AMB. FOLEY <br /><br />E.O. 12958 : N/A <br />TAGS : PREL PGOV BR HA POL MIL <br /><br /> ¶ 1. (SBU) On November 9, Brazilian Federal Deputy Maninha paid a courtesy call on Ambassador Danilovich. Maninha is the current president of COPA (Confederation of the Parliaments of the Americas), and this week she...</kbd></dd> <dt>classification</dt> <dd><kbd>2010-12-28 00:12</kbd></dd> <dt>header</dt> <dd><kbd>This record is a partial extract of the original cable. The full text of the original cable is not available.</kbd></dd> <dt>refererence_id</dt> <dd><kbd>04BRASILIA2803</kbd></dd> </blockquote> <p>La démo est visible ici : <a href="http://zzz.rezo.net/cablegate/" class='spip_url spip_out'>http://zzz.rezo.net/cablegate/</a>.</p> <h3 class='h3 spip'>* * *</h3> <p>J'espère que cet exemple vous aura donné envie de jouer avec <a href='http://www.spip.net/' class='spip_out' rel='external'><span class="caps">SPIP</span></a> et <a href="http://couchdb.apache.org/" class='spip_out' rel='external'>CouchDB</a>. N'hésitez pas à utiliser le forum ci-dessous pour partager vos expériences.</p></div> Plugin Flattr pour SPIP http://zzz.rezo.net/Plugin-Flattr-pour-SPIP.html http://zzz.rezo.net/Plugin-Flattr-pour-SPIP.html 2010-09-01T16:20:46Z text/html fr Fil Web <p>Comme promis dans l'article Flattr-ies et Kurbettes, voici un plugin facilitant l'intégration dans SPIP du système de microdons Flattr. Téléchargement Le plugin est développé sur SPIP-Zone, disponible via la commande svn co svn ://zone.spip.org/spip-zone/_plugins_/flattr/ On trouvera aussi le plugin sous forme de ZIP à l'adresse Version courante : 0.2 Configuration Ce plugin se configure avec CFG ; on y indique le UserID du compte Flattr qui recevra les microdons. On peut aussi préciser le (...)</p> - <a href="http://zzz.rezo.net/-SPIP-.html" rel="directory">SPIP</a> / <a href="http://zzz.rezo.net/+-Web-+.html" rel="tag">Web</a> <img class='spip_logos' alt="" align="right" src='http://zzz.rezo.net/local/cache-vignettes/L20xH20/arton66-5bbd5.png' width='20' height='20' style='height:20px;width:20px;' /> <div class='rss_chapo'><p>Comme promis dans l'article <a href='http://zzz.rezo.net/Flattr-ies-et-Kurbettes.html' class='spip_in'>Flattr-ies et Kurbettes</a>, voici un plugin facilitant l'intégration dans <span class="caps">SPIP</span> du système de microdons Flattr.</p></div> <div class='rss_texte'><h3 class='h3 spip'>Téléchargement</h3> <p>Le plugin est développé sur <span class="caps">SPIP</span>-Zone, disponible via la commande</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>svn co svn://zone.spip.org/spip-zone/_plugins_/flattr/</code></div> <p>On trouvera aussi le plugin sous forme de <span class="caps">ZIP</span> à l'adresse <a href="http://files.spip.org/spip-zone/flattr.zip" class='spip_url spip_out' rel='external'>http://files.spip.org/spip-zone/fla...</a></p> <p><i>Version courante : 0.2</i></p> <h3 class='h3 spip'>Configuration</h3> <p>Ce plugin se configure avec <span class="caps">CFG</span> ; on y indique le UserID du compte Flattr qui recevra les microdons. On peut aussi préciser le type de contenus qu'on propose sur le site, dans la nomenclature de Flattr : text, images, video, audio, software...</p> <h3 class='h3 spip'>Intégration</h3> <p>Pour l'intégrer à son site <span class="caps">SPIP</span>, on utilise un modèle <code class='spip_code' dir='ltr'>article_flattr.html</code> ; ce modèle peut s'intégrer :<br />— au cas par cas, en saisissant dans le corps ou le post-scriptum d'un article un contenu du type <code class='spip_code' dir='ltr'><article66|flattr></code> ;<br />— dans un squelette (par exemple <code class='spip_code' dir='ltr'>extra/article.html</code> en y indiquant <code class='spip_code' dir='ltr'>#MODELE{article_flattr,id_article}</code>.</p> <p>Un autre modèle permet de flattr la page d'accueil du site : <code class='spip_code' dir='ltr'><site|flattr></code> ou <code class='spip_code' dir='ltr'>#MODELE{site_flattr}</code>.</p> <p><strong>Note sur le javascript.</strong> Le bouton standard que propose Flattr ne convient pas, car tel un mouchard il envoie chaque visiteur de votre site sur le site Flattr.com ; en termes de privacy c'est assez inacceptable. Nous avons donc dans ce plugin un <span class="caps">JS</span> un peu plus élaboré, qui ne contacte Flattr.com que lorsque l'utilisateur appuie sur le bouton. Le <span class="caps">JS</span> principal est servi par votre site ; vous pouvez, si vous mettez le bouton partout, l'intégrer dans votre <code class='spip_code' dir='ltr'>inc-head</code> ; dans le cas contraire, il sera chargé à la demande en fonction du besoin, lors du survol du bouton.</p> <h3 class='h3 spip'>Paramétrage</h3> <p>Les paramètres par défaut du bouton sont :<br />— title : titre de l'article.<br />— description : descriptif de l'article, coupé à 1000 car. <br />— uid : User <span class="caps">ID</span> configuré dans le <span class="caps">CFG</span><br />— hidden : true ou false (<span class="caps">CFG</span>)<br />— button : default<br />— tags : mots-clés de l'article<br />— category : text (ou autre, défini dans <span class="caps">CFG</span>)</p> <p>Il est possible de modifier ces paramètres en les passant directement au modèle, ainsi par exemple si l'article 67 représente une vidéo, on indiquera :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code><article67|flattr|category=video></code></div> <p>Si un article correspond à une flatterie pour un autre auteur que celui défini dans le <span class="caps">CFG</span>, on passera son <code class='spip_code' dir='ltr'>uid</code> au modèle :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code><article67|flattr|uid=2106></code></div> <p>Idem pour les autres paramètres.</p> <p>A noter : si vous ne créez pas vos ‘things' à la main depuis l'interface de Flattr, ils sont créés lors du premier microdon effectué dessus à partir de votre site. Dès lors qu'un article (à une certaine <span class="caps">URL</span>) a été créé dans Flattr, ses paramètres sont figés ; vous pouvez encore les éditer, mais uniquement à partir de votre dashboard sur le site Flattr.</p> <h3 class='h3 spip'>Démo</h3> <p>Le bouton est en action ici-même :</p> <p><code class='spip_code' dir='ltr'><article66|flattr|category=software></code><br class='autobr' /> <a href='http://zzz.rezo.net/Plugin-Flattr-pour-SPIP.html' class="spip_modele">Plugin Flattr pour SPIP</a></p> <p><code class='spip_code' dir='ltr'><site|flattr></code></p></div> Présentation de Textwheel http://zzz.rezo.net/Presentation-de-Textwheel.html http://zzz.rezo.net/Presentation-de-Textwheel.html 2010-08-15T14:53:04Z text/html fr Cerdic, Fil Logiciels libres Web <p>Textwheel — littéralement, « la roue du texte » — est un projet visant à simplifier l'écriture de règles de transformation d'un texte d'un format vers un autre. Quand on s'intéresse aux systèmes de publication sur Internet, on a la forte impression que chacun réinvente la roue de son côté, refaisant pour chaque composant du logiciel sa propre implémentation. Textwheel s'attaque à l'un de ces composants : la transformation d'un texte « brut » en texte présentable à l'écran. Par exemple, sous SPIP, on (...)</p> - <a href="http://zzz.rezo.net/-SPIP-.html" rel="directory">SPIP</a> / <a href="http://zzz.rezo.net/+-Logiciels-libres-+.html" rel="tag">Logiciels libres</a>, <a href="http://zzz.rezo.net/+-Web-+.html" rel="tag">Web</a> <div class='rss_chapo'><p>Textwheel — littéralement, « la roue du texte » — est un projet visant à simplifier l'écriture de règles de transformation d'un texte d'un format vers un autre.</p></div> <div class='rss_texte'><p>Quand on s'intéresse aux systèmes de publication sur Internet, on a la forte impression que chacun réinvente la roue de son côté, refaisant pour chaque composant du logiciel sa propre implémentation.</p> <p>Textwheel s'attaque à l'un de ces composants : la transformation d'un texte « brut » en texte présentable à l'écran.</p> <p>Par exemple, sous <span class="caps">SPIP</span>, on transforme :<br class='manualbr' /><code class='spip_code' dir='ltr'>{Hello} {{World}}</code><br class='manualbr' />en :<br class='manualbr' /><code class='spip_code' dir='ltr'><i>Hello</i> <strong>World</strong></code></p> <p>Sous Textile, on transforme :<br class='manualbr' /><code class='spip_code' dir='ltr'>_Hello_ *World*</code><br class='manualbr' />en :<br class='manualbr' /><code class='spip_code' dir='ltr'><em>Hello</em> <strong>World</strong></code></p> <p>En BBCode, on aura :<br class='manualbr' /><code class='spip_code' dir='ltr'>[i]Hello[/i] [b]World[/b]</code></p> <p>L'ennui jusqu'ici c'est que chaque logiciel (gestion de contenu, gestion de forums) est livré avec ses propres raccourcis, dans sa propre implémentation. Il n'y a donc ni standard, ni possibilité d'échanger, ni possibilité de modifier ses raccourcis. Textwheel est une proposition visant à répondre à ces soucis d'interopérabilité.</p> <p>Le principe : avec Textwheel, plutôt que de coder une fonction qui effectue ces règles de transformation, on les décrit dans un fichier de configuration (ex : <a href="http://github.com/Cerdic/textwheel/blob/master/wheels/spip/spip.yaml" class='spip_out' rel='external'><code class='spip_code' dir='ltr'>spip.yaml</code></a>), au format très simple (<a href="http://zzz.rezo.net/Je-suis-fan-de-YAML.html" class='spip_out'><span class="caps">YAML</span></a>). Textwheel se chargera d'appliquer ces règles.</p> <p>Ainsi, Textwheel sépare la création des « raccourcis d'édition » de leur implémentation technique.</p> <p>Avec Textwheel, les raccourcis de <span class="caps">SPIP</span> se <i>programment</i> donc ainsi :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>strong:<br /> match: [ "{{", "}}" ]<br /> replace: [ "<strong>", "</strong>" ]<br /> italics:<br /> match: [ "{", "}" ]<br /> replace: [ "<i>", "</i>" ]</code></div> <p>Ceux de Textile :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>strong:<br /> match: "/\*(\w*)\*/U"<br /> replace: "<strong>\1</strong>"<br /> italics:<br /> match: "/_(\w*)_/U"<br /> replace: "<em>\1</em>"</code></div> <p>et le BBCode :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>strong:<br /> match: [ "[b]", "[/b]" ]<br /> replace: [ "<strong>", "</strong>" ]<br /> italics:<br /> match: [ "[i]", "[/i]" ]<br /> replace: [ "<i>", "</i>" ]</code></div> <p>On voit qu'il est dès lors très facile d'ajouter les raccourcis BBCode ou Textile dans <span class="caps">SPIP</span>, ou l'inverse, en manipulant des fichiers de configuration. Bien entendu les cas plus complexes (callbacks, expressions rationnelles) sont prévus.</p> <h3 class='h3 spip'> Avantages de Textwheel </h3> <p>L'interopérabilité entre logiciels n'est pas le seul avantage.</p> <p><img src='http://zzz.rezo.net/local/cache-vignettes/L8xH11/puce-32883.gif' width='8' height='11' class='puce' alt="-" style='height:11px;width:8px;' /> <strong>Extensibilité.</strong> Il est plus aisé pour un utilisateur de manipuler un fichier de configuration au format établi, que de se plonger dans des modifications de code qui peuvent sauter à chaque mise à jour.</p> <p><img src='http://zzz.rezo.net/local/cache-vignettes/L8xH11/puce-32883.gif' width='8' height='11' class='puce' alt="-" style='height:11px;width:8px;' /> <strong>Traitements.</strong> Dès lors que les raccourcis sont codés de manière descriptive, et non pas fonctionnelle, il est possible de leur faire subir des traitements qui ne se limitent pas à les appliquer à un texte. On peut par exemple les appliquer à la chaîne sur l'ensemble des textes d'une base de données, et voir lesquels sont utilisés, combien de fois, à quels textes... et à quelle vitesse.</p> <p><img src='http://zzz.rezo.net/local/cache-vignettes/L8xH11/puce-32883.gif' width='8' height='11' class='puce' alt="-" style='height:11px;width:8px;' /> <strong>Rapidité.</strong> Ce qui permet de détecter des règles mal programmées, inutiles, trop lentes ou pas efficaces. En appliquant cette méthodologie aux raccourcis de <span class="caps">SPIP</span>, nous avons pu en quelques <i>jours</i> diviser par deux le temps de calcul des textes (sur certaines bases de texte d'usage réel).</p> <p><img src='http://zzz.rezo.net/local/cache-vignettes/L8xH11/puce-32883.gif' width='8' height='11' class='puce' alt="-" style='height:11px;width:8px;' /> <strong>Compilation.</strong> Une autre sortie possible pour un fichier de raccourcis, c'est une compilation sous forme de code dans un langage arbitraire (par exemple : <span class="caps">PHP</span>, python, ruby, javascript, C...). Cette approche devrait permettre à terme de retrouver les mêmes raccourcis sous différents logiciels, quel que soit leur langage de programmation, et aussi bien côté serveur (<span class="caps">PHP</span>, python) que client (javascript).</p> <p><img src='http://zzz.rezo.net/local/cache-vignettes/L8xH11/puce-32883.gif' width='8' height='11' class='puce' alt="-" style='height:11px;width:8px;' /> <strong>Tests unitaires.</strong> Jusqu'ici les raccourcis avaient tendance à « casser » dès lors qu'on mettait les mains dans le code, et il était bien difficile, lorsqu'on constatait un bug, de voir à quel niveau des traitements le résultat devenait non conforme. Maintenant que notre moteur peut comparer, pour chaque règle, le résultat obtenu avec sa valeur attendue, un jeu de tests peut non seulement nous dire si quelque chose a changé, mais nous dire aussi précisément quoi.</p> <p><img src='http://zzz.rezo.net/local/cache-vignettes/L8xH11/puce-32883.gif' width='8' height='11' class='puce' alt="-" style='height:11px;width:8px;' /> <strong>Évolutivité.</strong> Cette approche devrait permettre de redynamiser le travail sur les raccourcis (introduction de nouveaux raccourcis, suppression de raccourcis obsolètes, amélioration de raccourcis mal foutus...). Car on peut imaginer construire un outil qui permettra de signaler le cas échéant au webmestre qui met à jour son site qu'il aura, par exemple, deux articles à vérifier (et lesquels) suite à une amélioration du code. Outil qui sera basé sur de simples fichiers <span class="caps">YAML</span>.</p> <h3 class='h3 spip'> Télécharger </h3> <p>Le projet est développé, en ce moment, via git et sur github.com ; on avance en parallèle sur le moteur (<a href="http://github.com/Cerdic/textwheel/tree/master/engine/" class='spip_url spip_out' rel='external'>http://github.com/Cerdic/textwheel/...</a>) et sur le plugin <span class="caps">SPIP</span> (<a href="http://github.com/Cerdic/textwheel/" class='spip_url spip_out' rel='external'>http://github.com/Cerdic/textwheel/</a>).</p> <p>Pour télécharger ce dernier par svn, utiliser la commande suivante :</p> <div style='text-align: left;' class='spip_code' dir='ltr'><code>svn checkout http://svn.github.com/Cerdic/textwheel.git/ plugins/textwheel/</code></div> <p>Le plugin pour <span class="caps">SPIP</span> donne une page <code class='spip_code' dir='ltr'>?exec=tw</code> dans l'espace privé qui permet de voir ce qui change entre textwheel et la fonction <code class='spip_code' dir='ltr'>propre()</code> classique de <span class="caps">SPIP</span> : les quelques textes où le rendu n'est pas exactement identique sont signalés, ainsi que le temps passé dans chaque <i>rule</i>, et le temps total des calculs.</p> <h3 class='h3 spip'> Participer </h3> <p>Si cette rapide présentation vous a alléché, sachez que toutes les participations sont les bienvenues.</p> <p>Le projet est, pour démarrer, codé en anglais et en <span class="caps">PHP</span>. Il offre d'ores et déjà des spécifications en version 0.1, une implémentation en <span class="caps">PHP</span>, et un plugin pour <span class="caps">SPIP</span> qui remplace le moteur historique de <span class="caps">SPIP</span> par cette nouvelle approche.</p> <p>Nous n'en sommes qu'au début. Il y a beaucoup à faire sur ce projet, qu'il s'agisse d'améliorer les specs, de contribuer de la documentation, d'établir des cas tests, de coder des implémentations dans d'autres langages (ruby, javascript), etc.</p> <p>Une communauté de développeurs se met en place sur la mailing-list textwheel@rezo.net ; <span class="caps">URL</span> : <a href="http://listes.rezo.net/mailman/listinfo/textwheel" class='spip_url spip_out auto' rel='nofollow external'>http://listes.rezo.net/mailman/listinfo/textwheel</a></p> <p>A bientôt !</p></div> Bloquer les mouchards avec Ghostery http://zzz.rezo.net/Bloquer-les-mouchards-avec.html http://zzz.rezo.net/Bloquer-les-mouchards-avec.html 2010-05-20T21:26:12Z text/html fr Fil Web Publicité <p>Mon billet pour Bloquer les mouchards de Facebook a eu pas mal de succès, signe que l'internaute commence à en avoir assez d'être pisté dans chaque recoin du Web. Y a-t-il d'autres solutions que mon bricolage ? Ghostery Ghostery propose une extension pour Firefox qui détecte, affiche et élimine les mouchards du Web. Merci à cy_altern qui, dans le forum, a signalé cette solution. Il s'agit d'un plugin à vocation didactique car, quand on l'active, il ne fait qu'afficher, dans une petite fenêtre en (...)</p> - <a href="http://zzz.rezo.net/-Scripts-.html" rel="directory">Scripts</a> / <a href="http://zzz.rezo.net/+-Web-+.html" rel="tag">Web</a>, <a href="http://zzz.rezo.net/+-Publicite-+.html" rel="tag">Publicité</a> <div class='rss_chapo'><p>Mon billet pour <a href='http://zzz.rezo.net/Bloquer-les-mouchards-de-Facebook.html' class='spip_in'>Bloquer les mouchards de Facebook</a> a eu pas mal de succès, signe que l'internaute commence à en avoir assez d'être pisté dans chaque recoin du Web. Y a-t-il d'autres solutions que mon bricolage ?</p></div> <div class='rss_texte'><h3 class='h3 spip'>Ghostery</h3> <p><span class='spip_document_44 spip_documents spip_documents_left' style='float:left; width:326px;'> <img src='http://zzz.rezo.net/local/cache-vignettes/L326xH185/messina-0fc56.png' width='326' height='185' alt="" style='height:185px;width:326px;' /></span> Ghostery propose une <strong>extension pour Firefox</strong> qui détecte, affiche et élimine les mouchards du Web. Merci à cy_altern qui, dans le <a href='http://zzz.rezo.net/Bloquer-les-mouchards-de-Facebook.html#forum236' class='spip_in'>forum</a>, a signalé cette solution.</p> <p><span class='spip_document_45 spip_documents spip_documents_right' style='float:right; width:288px;'> <img src='http://zzz.rezo.net/local/cache-vignettes/L288xH174/zzz-c54f1.png' width='288' height='174' alt="" style='height:174px;width:288px;' /></span> Il s'agit d'un plugin à vocation didactique car, quand on l'active, il ne fait qu'afficher, dans une petite fenêtre en haut à droite de la page Web, la liste des mouchards détectés dans la page. Il n'est pas rare d'en voir 1, 2 ou 3 à chaque page, avec les mêmes qui reviennent sans arrêt : Google, Facebook, Xiti, DoubleClick, etc.</p> <p><span class='spip_document_46 spip_documents spip_documents_left' style='float:left; width:242px;'> <img src='http://zzz.rezo.net/local/cache-vignettes/L242xH187/libe-8a463.png' width='242' height='187' alt="" style='height:187px;width:242px;' /></span> L'interface permet de bloquer un à un ces réseaux de traqueurs et de « pub comportementale ». En allant dans les préférences de l'extension, on peut aussi les bloquer tous en un seul clic.</p> <p>Pour reprendre ensuite une navigation normale, il suffit de désactiver l'affichage de la liste. Seul un petit fantôme bleu en bas de la page permet de temps à autre de savourer le nombre de mouchards qui restent à la porte.</p> <p><span class='spip_document_47 spip_documents spip_documents_center'> <img src='http://zzz.rezo.net/local/cache-vignettes/L287xH285/menu-b6a81.png' width='287' height='285' alt="" style='height:285px;width:287px;' /></span></p> <p>Ghostery est, bizarrement, édité par la société <i>Better Advertising</i> (sic), qui conseille aussi les réseaux de publicitaires dans leur gestion des questions de <i>privacy.</i> Le plugin permet, pour chaque mouchard, d'aller consulter une page décrivant le réseau et de consulter sa politique de confidentialité, de façon à améliorer la <i>« confiance »</i> des internautes dans la pub (re-sic).</p> <p><span class='spip_document_48 spip_documents spip_documents_center'> <img src='http://zzz.rezo.net/local/cache-vignettes/L500xH285/Capture_d_ecran_2010-05-20_a_23-13-26-461c7.png' width='500' height='285' alt="" style='height:285px;width:500px;' /></span></p> <p><strong>À noter :</strong> Ghostery ne fonctionne pour l'instant que pour Firefox ; sa version pour Internet Explorer ne bloque qu'une partie des mouchards, et sa version pour Chrome ne fait que les détecter (pas de blocage).</p></div>