14 10 2007
You've designed and implemented a nice web site. How do you prevent the client editors from messing up your nice HTML? An easy solution by Roger Johansson of 456 Berea Street.
12 05 2007
Un boulot tentant : Senior Python Engineer chez Churchill Navigation.
Je suis persuadé qu'ils ont raison :
We believe a programmer in the top 5% is 10 times as (or more) productive than an average programmer. So we don't hire average, or even above average, programmers.
Le rapport de productivité peut même atteindre 50 à 100 selon Tom DeMarco. Étonnamment (ou pas, c'est dur à avaler quand on est un average programmer), l'opinion est peu répandue. Je le constate tous les jours.
05 03 2007
Are you annoyed with telemarketers? Download this script [PDF 646ko] and disorient your opponent by mirroring his/her own technique!
19 02 2006
J'ai testé bon nombre de méthodes pour ajouter des rollovers aux images — y compris le code omniprésent de DreamWeaver. J'utilisais depuis longtemps le script soopa-rollovers de youngpup.net. Problème : il impose l'utilisation d'attributs qui n'existent pas dans les normes, et les pages ne valident1 plus.
La méthode la plus en vogue actuellement est le rollover en CSS, qui ne nécessite pas de javascript ni d'image séparée pour le rollover. C'est parfait pour les menus, mais infernal pour le rollover « accidentel » : ça impose de modifier le CSS à chaque fois.
Mon dernier choix est d'utiliser l'attribut class. Ça respecte la lettre de la norme — mais probablement pas son esprit. Enfin, le XHTML est valide.
Le marquage est simple ; on ajoute hover:rollover.gif à la classe, par exemple :
<img src="/images/download.gif" class="button hover:/images/download_ro.gif" />
Le code comporte trois fonctions. La première recherche les images avec une classe hover: et affecte les fonctions rolloverOn et rolloverOff aux événements onmouseover et onmouseout.
function rolloverSetup() { var img for (var i = 0; (img = document.images[i]); i++) { if (img.getAttribute) { iclass = img.className; isrc = img.getAttribute("src"); if (iclass != null && iclass.indexOf("hover:") >= 0 && isrc != null && isrc != "") { ihover = iclass.slice(iclass.indexOf("hover:") + 6); if (ihover.indexOf(" ") > 0) ihover = ihover.slice(0, ihover.indexOf(" ")) if (ihover != "") { img.hover = new Image(); img.hover.org = img.src; img.hover.src = ihover; img.onmouseover = rolloverOn img.onmouseout = rolloverOff } } } } }
On va récupérer la classe (l.7) ; si elle contient hover:, on récupère le nom de l'image (l.10-12). On mémorise l'image d'origine (l.15) et la nouvelle (l.16) [en la préchargeant pendant qu'on y est]. Finalement on affecte les fonctions qui changent l'image aux événements onmouseover et onmouseout
1. J'assume le néologisme grammatical.
17 02 2006
Robots shouldn't index RSS feeds. So I added the path to robots.txt:
Check your robots.txt syntax with one of the online validators, for example Robots.txt Checker.
I also wrote a syntax color highlighter module for GeSHi. (The mind boggles, the “language” counts... two instructions.)
15 02 2006
Following Sony's idiotic initiative, installing a rootkit on your PC if you listen to Céline Dion — but why would you? — somebody coined this new phrase. The original sentence :
In addition to corrupting the disc structure, Alpha-DVD pulls a Sony on you and installs software you really don't want to have installed.
12 02 2006
Configuration basée sur un vieil article de John Coggeshall.
Voici l'implémentation finale. Nous avons deux serveurs Apache. Le premier qui fait office de proxy est en version 1.3.34 avec PHP 4 en module statique ; le second en version 2.2.0 avec PHP 5 en module dynamique.
Phase 1 :
Recompiler Apache 1 avec mod_proxy (ajouter l'option --enable-module=proxy à la configuration).
Phase 2 :
Installer un second serveur Apache sur un autre port, par exemple le 8085. J'ai choisi Apache 2.2.0 et PHP 5.1.2. Voici le script — il suppose que les sources au format tar.bz2 soient préalablement téléchargés dans le répertoire de travail SOFT_DIR.
#!/bin/sh
SOFT_DIR=/home/xtian/src HTTPD=httpd-2.2.0 PHP=php-5.1.2
# Install Apache cd $SOFT_DIR rm -rf $HTTPD echo Extracting $HTTPD tar jxf $HTTPD.tar.bz2 cd $HTTPD ./configure \ --prefix=/usr/local/apache2 \ --enable-module=so \ --enable-rewrite \ --with-mpm=prefork \ --with-port=8085 make && make install
# Install PHP cd $SOFT_DIR rm -rf $PHP echo Extracting $PHP tar jxf $PHP.tar.bz2 cd $PHP ./configure \ --prefix=/usr/local/php5 \ --sysconfdir=/etc/php5 \ --disable-short-tags \ --with-apxs2=/usr/local/apache2/bin/apxs \ --with-config-file-path=/etc/php5 \ --with-freetype-dir \ --disable-magic-quotes \ --enable-ftp \ --with-gettext \ --with-gd \ --with-mbstring \ --with-mysql \ --with-openssl \ --with-pdo-mysql \ --with-pear \ --with-png \ --with-zlib make && make install
Phase 3 :
Configurer les deux serveurs. L'ancien :
<VirtualHost *:80> ServerName xtian.goelette.info DocumentRoot /home/xtian/goelette.info ProxyPass / http://xtian.goelette.info:8085/ ProxyPassReverse / http://xtian.goelette.info:8085/ </VirtualHost>
Le nouveau serveur écoute le port 8085 en local ; pas sur 127.0.0.1 mais sur l'adresse IP publique. La configuration de l'hôte virtuel est transférée dans le nouveau fichier de configuration, par exemple /usr/local/apache2/conf/extra/httpd-vhosts.conf
Listen 213.186.56.126:8085 LoadModule php5_module modules/libphp5.so NameVirtualHost *:8085
<VirtualHost localhost:8085> ServerName xtian.goelette.info DocumentRoot /home/xtian/goelette.info php_flag magic_quotes_gpc off CustomLog /home/xtian/goelette.info/logs/access.log combined </VirtualHost>
Dernière étape
Lancer/relancer les serveurs :
/usr/local/apache2/bin/apachectl start /usr/local/apache/bin/apachectl graceful
11 02 2006
L'idée du CGI étant décidément peu plaisante, je me suis plongé dans la documentation Apache. J'y ai découvert la directive ProxyPreserveHost, qui fait exactement ce que je veux, mais n'est malheureusement pas disponible pour Apache 1.3.
Par contre, la lecture du paragraphe éclaire la directive ProxyPass. Le second serveur utilise le nom d'hôte spécifié dans la directive — si on met 127.0.0.1, HTTP_HOST vaudra 127.0.0.1:8085.
Il est donc possible d'installer autant d'hôtes virtuels que l'on souhaite. Il reste un seul inconvénient, HTTP_HOST apparaît comme xtian.goelette.info:8085, une variable HTTP_X_FORWARDED_HOST apparaît avec le serveur d'origine, xtian.goelette.info. Heureusement, la variable SERVER_NAME ne comporte pas le port.
11 02 2006
Il n'est pas possible de charger les modules PHP 4 et PHP 5 simultanément dans Apache, que ce soit en statique (compilé avec Apache [./configure --activate-module=src/modules/php4/libphp4.a]) ou en dynamique (chargé dans la configuration [LoadModule php5_module modules/libphp5.so]).
Il y a plusieurs solutions au problème :
- Utiliser une autre machine
- Utiliser une autre adresse IP sur la même machine avec un second serveur Apache
- Utiliser un autre port sur la même machine avec un second serveur Apache
- Conserver PHP 4 en module et appeler PHP 5 en CGI
- Rediriger les requêtes vers un second serveur Apache
La solution 1 présente l'avantage de la simplicité, ainsi que de l'absence totale de risques pour les applications existantes. Les inconvénients sont le coût, doublé, la maintenance (patches de sécurité, upgrades) sur deux serveurs. La solution 2 est similaire, avec un coût moindre.
La solution 3 ne coûte rien, mais elle ne convient guère que pour des serveurs de développement — et encore ! Non seulement http://www.example.com:81/ risque d'être mal compris, mais en plus les ports non standard seront quasi certainement bloqués par les firewalls.
Dans le cas du CGI, les variables d'environnement sont différentes selon le fonctionnement de PHP en module ou en CGI. Dans le cas de $_ENV elles sont tellement imprévisibles que le manuel renonce à les lister !
Pour ces raisons, je me suis orienté vers la dernière idée. Elle n'est pas nouvelle et a été proposée par John Coggeshall dans un vieil article.
Je saute à la conclusion avant de détailler l'installation. La technique est simple et rapide à mettre en œuvre, mais elle présente plusieurs inconvénients :
- On ne peut rediriger qu'un seul virtual host sur un port. Impossible d'avoir deux sites en PHP5…
- Le serveur qui exécute le PHP est bien entendu le second. Ainsi, $_SERVER['HOST'] vaut (par exemple) 127.0.0.1:8085. À suivre.
Continue reading "PHP4 et PHP5 sur le même serveur, premier essai"
01 12 2005
Enjoy December to the full, with 24 ways to impress your (geek) friends. It starts with an easy Ajax project with Prototype.
24 11 2005
Check the upgrading guide then download the code.
It didn't last long… Version 5.1.1 was released on the 28th. The links are still valid though.
13 11 2005
osCommerce MS2 uses HTML 4.01 Transitional. MS3 will use XHTML 1.0. The exact doctypes are actually:
For an in-depth explanation of doctypes, check this very good article from A List Apart.
We're not alone in using XHTML; I won't go through the reasons of the choice, as so much has already be written on the subject. The New York Public Library Style Guide is a simple introduction.
Rules for XHTML are slightly different:
- Tags must be closed and must not overlap (<p><b>osCommerce</p> is wrong</b>);
- Element names must be lower case (eg <INPUT type="text" onClick="check()"> must be written <input type="text" onclick="check()">);
- End tags are required (eg <p> needs a closing </p>);
- Attribute values must be quoted (<td rowspan="3">);
- Attribute-value pairs must be written in full (eg selected="selected");
- Empty elements must either have an end tag or the start tag must end with /> (eg <br />)
- Plus some other minor stuff.
As quite a lot of HTML in osCommerce is build by PHP we must go through the HTML and the PHP code both. All pages will validate.
03 11 2005
Garvin Hicking rightly pointed out that allow_url_fopen would not be enabled on all servers. He suggested I use PEAR HTTP_Request. I took the opportunity to upgrade my PEAR packages and install HTTP_Request. Then I saw that it was already available in s9y libs. Sigh.
I changed the function to use HTTP_Request, but I left the fopen method in, as I believe the performance will be better. So here's the modified function:
/* * Query returns "Rank_1:1:4" as a string */ function getrank ($url) { $url = 'info:'. $url; $ch = $this-> GoogleCH($this-> strord($url)); $url = "http://www.google.com/search"; $url.= "?client=navclient-auto&ch=6$ch&features=Rank&q="; $url.= urlencode($url); if (ini_get('allow_url_fopen')) { $data = file_get_contents($url, 128); } else { require_once S9Y_PEAR_PATH . 'HTTP/Request.php'; $req =& new HTTP_Request ($url); if (!PEAR:: isError($req-> sendRequest())) { $data = $req-> getResponseBody(); } } $rankarray = explode (':', $data); return $rankarray[2]; }
serendipity_plugin_pagerank-0.3.zip
02 11 2005
This class provides HTTP Basic authentication. Try it here as user test with password pass.
It will be useful if you want to share the same protection system for a bunch of documents in a directory and a specific page located elsewhere. At the top of your page, include the following code; the constructor needs the path to the .htpasswd file:
include('./apacheAuthBasic.php'); $auth = new apacheAuthBasic('./.htpasswd'); $auth->checkAuthorized();
checkAuthorized() checks the user and password match. If they don't, it sends a request for authentication:
function checkAuthorized () { if (! $this-> okPasswd($this-> htpasswd)) { header('WWW-Authenticate: Basic realm="' . $this-> realm . '"'); header('HTTP/1.0 401 Unauthorized'); echo $this-> message; die(); } }
As you can guess, okPasswd() compares the encrypted password stored in .htpasswd with the clear password from the browser. To do this, it first encrypts the clear password with makePasswd(). Ancillary function makeHtpasswd() returns the user:password combination in a suitable format for .htpasswd.
Download: apacheAuthBasic.zip.
Note: this code is compatible with the default CRYPT encryption. The MD5 encryption is more complex and is not supported.
30 10 2005
I've started integrating
CSS layout 3 with the template system. I transfered the positioning definitions only. The fancy parts, such as background colors and borders, were only used to outline the various bits and pieces. We don't want LemonChiffon and GoldenRod colors in the default layout, we'll just keep it haze grey & underway.
The combined design constraints also require redefining the DIVs . Specifically, we add a sub-block containing both the center and left column. This is no problem, as the template system combines HTML and CSS.
The design comes in nicely, and is slightly different from MS2, as all columns are “liquid”; that is the left and right column will get wider if you enlarge your browser. They were fixed at 125px in MS2.
Commited to my branch 30 minutes ago.
26 10 2005
As I planned, I wrote a plugin to monitor Google PageRank for arbitrary URLs.
You can display the PageRanks for a configurable number of pages. It's also possible to display the PR of the current page. You can see how it looks in the right column.
Continue reading "A Serendipity plugin to monitor Google PageRanks"
23 10 2005
Je commence une petite expérience. Je viens de déclarer sur Google l'adresse d'un site non référencé. (S'il est déjà référencé, ça ne sert à rien.) Je m'intéresse au délai entre la déclaration et l'apparition dans l'index.
Comment savoir si un site est référencé dans Google ?
Il suffit de demander à Google ! Il y a un grand nombre de mots-clefs disponibles pour affiner la recherche, dont site.
Site: restreint la recherche au domaine que vous spécifiez, et ce de manière plus ou moins fine.
L'astuce est simple : en cherchant site:goelette.net sans ajouter de mot-clef, vous aurez la liste de toutes les pages indexées pour le domaine. Si aucun document n'est référencé, c'est que le domaine n'est pas indexé.
Note : comme d'habitude, le signe moins - devant le mot-clef inverse la requête. Par exemple ibm -site:ibm.com renvoie la liste des pages qui parlent d'IBM, sauf les pages d'ibm.com. (Il y a des meilleurs moyens d'avoir la liste des pages qui pointent sur votre site. J'en parlerai un autre jour.)
Comment déclarer un site ?
Rendez-vous sur http://www.google.fr/addurl/?continue=/addurl , collez l'adresse de la page d'accueil du site dans la case URL. Si vous arrivez à lire le mot déformé dans la boîte, recopiez-le dans la case suivante, ça ne peut pas faire de mal.
Suivi
le 28 novembre au soir, rien chez Google. Il est maintenant certain que le site ne sera pas référencé. En l'occurence, il est réalisé dans une frame avec une redirection chez Free. Le résultat n'est guère surprenant.
23 10 2005
The third CSS layout is online. You can find the previous ones here and here. This will be the final mockup. The next layout is for real!
This layout is liquid, as the first. But this time, the left and right columns are fluid as well (their width was fixed in layout 1). The most obvious difference is the footer, which is now at the bottom of the page (it was at the bottom of the center column in layout 1).
The header is absolutely positioned, as usual. The rest of the page goes into a container DIV. But this time, we're using a trick in the HTML markup itself. as the "pageContent" DIV is still coming first in the page: an additional container encloses the left column and center column both.
The way the DIVs are floated left and right might seem strange, but it's actually simple:
- The right column is floated right.
- The additional container holding the left and center columns is floated left;
- Inside this container, the left column is floated left, and the center column is floated right (so it ends up in the middle).
That's it! CSS is easy!
22 10 2005
Aujourd'hui le PageRank de la page d'accueil est passé de 0 à 4 ! Les pages intérieures sont à 3.
J'ai raté la Google Dance. Le PageRank de la page d'accueil de Goélette est remonté à 6 après quelques mois à 5.
J'envisage d'écrire un plugin Serendipity pour surveiller ça plus facilement. C'est fait.
|