Comme je le soulignais hier, Internet Explorer permet de définir et de modifier les favicons définis dans les favoris tandis que Firefox ne le permet pas par défaut. Au moment de l'enregistrement du lien, Firefox récupère le favicon spécifié dans la balise <link> du code HTML et il n'est plus possible de le modifier par la suite.
Étant donné que je traine mes favoris depuis longtemps (n'étant pas encore abonné à un service comme Delicious, je me suis promis d'ouvrir un compte d'ici la fin de mes vacances...), j'avais gardé Last.fm dans mes favoris de Firefox et à ce moment, le site ne proposait probablement pas encore de favicon. Maintenant que le site offre une icône, je n'avais pas d'autre solution que de supprimer le favori et l'ajouter à nouveau pour la récupérer. Mais je Je me doutais bien qu'il y aurait une extension pour le faire facilement : Favicon Picker 3.
Après avoir installé l'extension, on peut changer l'icône d'un lien en cliquant dessus avec le bouton droit de la souris et choisir "Properties". Ensuite, il suffit de cliquer "Browse" et de sélectionner une image sur son poste de travail ou de coller un lien web vers une image (jpg, gif, png, bmp ou ico). Dans mon cas, j'ai récupéré dans le code source de la page la valeur du href dans la balise <link rel="icon" href="http://cdn.last.fm/flatness/favicon.2.ico" /> et coller l'URL dans l'espace réservé au nom du fichier.
En utilisant le code source de Last.fm comme exemple, le hasard m'a fait découvrir une chose intéressante sur laquelle j'aimerais attirer votre attention. Sous la balise <head> se trouve une autre icône spécifiée explicitement pour le iPhone / iPod Touch :
<link rel="apple-touch-icon" href="http://cdn.last.fm/flatness/apple-touch-icon.png" />
Devinez un peu à quoi ça sert ? Il semblerait que ça soit pour ajouter une icône sur le tableau de bord de l'appareil. On s'en reparle bientôt...
L'idée du favicon vient d'Internet Explorer qui permettait d'associer une icône à un favori (bookmark), d'où il tire son nom. Au départ, comme l'icône associée était une extension .ico placée à la racine du site, c'est devenu le format par défaut que la plupart des fureteurs ont adopté, bien que le PNG et GIF soit acceptés par certains fureteurs.
Pour en créer un de base, il faudra d'abord faire une image de dimension 16 x 16 pixels. Pour y arriver, on peut utiliser Photoshop, GIMP ou un service web gratuit pour créer un favicon (il suffit de fournir une image et on nous renvoie un .ico). Dans mon cas, je procéderai avec GIMP pour Windows (GNU Image Manipulation Program).
- Créer un gabarit de format carré et de taille normale pour pouvoir créer l'image (pour un meilleur contrôle du résultat final, mieux vaut créer un gabarit de format 16 x 16 et l'agrandir en utilisant la touche "+" du clavier numérique)
- Créer l'image
- Réduire le format à 16 x 16 pixels (Menu Image / Échelle et taille de l'image, entrer les dimensions et cliquer sur le bouton Échelle)
- Dans le menu Fichier, sélectionner "Enregistrer sous" et choisir "Windows Icon Format" dans le panneau "Sélectionner le type de fichier (selon l'extension)"
- Enregister
- Déposer le fichier .ico à la racine du site (le fichier peut se trouver n'importe où en réalité, il suffira de spécifier le chemin relatif ou absolu)
- Créer le lien sur les pages comme ceci :
<link rel="shortcut icon" href="favicon.ico">
Si on ne voit pas le favicon après l'avoir placé ou remplacé sur un site, c'est soit que :
- le nom de la ressource comporte une erreur
- il faut vider la cache du fureteur ou dans certains cas le redémarrer
- le format ou les dimensions ne sont pas compatibles
- Internet Explorer reconnait par défaut le favicon s'il est placé à la racine du site et s'il porte le nom favicon.ico
- pour Firefox, l'option des favicons peut être désactivée. Dans ce cas, on peut le réactiver en entrant about:config dans la barre d'adresse, ensuite utiliser le filtre pour trouver la propriété browser.chrome.favicons et changer sa valeur pour true
script.aculo.us est une librairie JavaScript d'effets visuels qui repose sur la base de prototype, un peu comme si elle agissait comme une extension du framework. Il faut donc inclure les deux librairies pour pouvoir commencer à créer des effets. En téléchargeant le fichier zip contenant scriptaculous, une version de prototype est incluse dans le répertoire /lib/ mais comme j'utilise généralement prototype dans la plupart de mes projets, j'ai tendance à utiliser une version indépendante plutôt que la version fournie dans le fichier compressé.
Lors de l'inclusion des librairies, il faudra tenir compte que scriptaculous est dépendant de prototype, donc celui-ci devra apparaître en premier pour que scriptaculous puisse être reconnu correctement. Si les scripts sont inversés ou si la version de prototype est trop vieille, un message d'erreur indiquera "uncaught exception: script.aculo.us requires the Prototype JavaScript framework >= 1.6.0".
<script type="text/javascript" src="/js/prototype/1.6.0.3/prototype-1.6.0.3.js"></script>
<script type="text/javascript" src="/js/scriptaculous/1.8.2/src/scriptaculous.js"></script>
À partir de ce moment, on peut créer des effets. Contrairement à la documentation de scriptaculous qui utilise les attributs d'événements (onclick="fonction"), je préfère extraire le code JS des balises HTML pour initialiser les événements en utilisant prototype (les deux méthodes fonctionnent bien, c'est une préférence au niveau de la structure).
Pour introduire les effets, je commencerai simplement avec l'affichage et le masquage d'un élément. Si on se rappele bien, l'objet Element de prototype.js offre deux méthodes pour y arriver : show() et hide(). Cependant, l'utilisation de ces méthodes n'offre que deux états à l'objet (affiché ou pas) et on note qu'il n'y a aucune transition dans le changement d'état. C'est ici que scriptaculous vient ajouter un peu d'effets pour rendre le visuel plus intéressant :
1. Toggle
Inverse automatiquement l'état de la fenêtre en utilisant l'effet "Appear", "Slide" ou "Blind".
Event.observe('btnToogle', 'click', function() {
Effect.toggle('box1', 'Slide');
} );
2. Appear
Permet de faire apparaître ou disparaitre un élément en faisant varier l'opacité.
Event.observe('btnShow', 'click', function() {
$('box1').appear({ from: 0, to: 1 });
} );
Event.observe('btnHide', 'click', function() {
$('box1').appear({ from: 1, to: 0 }); }
);
3. Slide
Permet de faire apparaître ou disparaitre un élément horizontalement comme un store de fenêtre (imaginez que le contenu de l'élément s'enroule dans le store).
Event.observe('btnSlideUp', 'click', function() {
Effect.SlideUp('box1');
} );
Event.observe('btnSlideDown', 'click', function() {
Effect.SlideDown('box1');
} );
4. Blind
Semblable à l'effet "Slide" sauf que le contenu ne se déplace pas, c'est le conteneur qui semble se déplacer.
Event.observe('btnBlindUp', 'click', function() {
Effect.BlindUp('box1');
} );
Event.observe('btnBlindDown', 'click', function() {
Effect.BlindDown('box1');
} );
5. switchOff
Permet de faire disparaitre un élément un peu comme lorsqu'on éteint un poste de téléviseur.
Event.observe('btnSwitchOff', 'click', function() {
$('box1').switchOff();
} );
Ce n'est qu'un bref aperçu de que ce scriptaculous propose. On peut paramétrer les effets pour contrôler le jeu de transition, combiner des effets ensemble et modifier dynamiquement les propriétés CSS d'un élément.
Sinon, un autre volet de scriptaculous que j'introduirai prochainement est le "drag and drop" qui permet de faire des fenêtres flottantes, déplacer les éléments sur une page, etc (un peu comme Facebook ou Blogspot font pour configurer la mise en page). Maintenant, amusez-vous à explorer les possibilités!
Quand un vrai génie apparaît en ce bas monde, on le peut reconnaître à ce signe que les imbéciles sont tous ligués contre lui.
Incroyable mais vrai. Hier, j'allais à un petit souper des fêtes chez des amis et à ma grande surprise, qu'est-ce que je vois sur le dos de Monsieur Jeune Padawan en personne ? Un t-shirt "Personal Soundtrack" provenant de Think Geek !
Mon rêve qui s'est matérialisé! Jamais je n'aurais pensé que ce chandail était sorti pour vrai car il faisait parti de la gamme de produits du dernier "April Fool's Day" de Think Geek.
Si quelqu'un vous pose une question à laquelle Google pourrait répondre, cherchez la réponse et envoyez lui le résultat à l'aide du site Let Me Google That For You.
Vous voyez, ce n'était pas si compliqué !
Comme chaque année, chaque réunion de famille devient propice à une discussion de hockey, suivi d'une séance de questions/réponses au geek de service. Parce que comme tout le monde le sait, quand on travaille en informatique, on connait tout de la technologie...
Au menu cette année :
- faire un bref exposé à "mononcle" pour expliquer ce qu'est le HD en vue des achats du boxing day
- dresser un tableau comparatif de NHL 09 sur les consoles PS2 et PS3 avec le cousin
- expliquer comment brancher une routeur sans fil
- initier grand-mère aux plaisirs du iPod touch
- décevoir quelqu'un parce que je n'ai pas su répondre à une question technique sur les GPS
- aider un ami en détresse parce que son ordinateur ne détectait plus le Master Boot Record (MBR)
L'extension que tous les développeurs web devraient installer est sans contredit Firebug. J'hésitais à en parler car ça me semblait trop évident que tout le monde l'aie déjà. Si vous ne le connaissez pas encore, c'est certainement la première qu'il vous faut installer. Firebug permet d'explorer le DOM, modifier et déboguer le code HTML, JavaScript et le CSS en temps réel sur vos projets ou sur des pages que vous visitez. C'est tellement pratique que ça devient dur de s'en passer.
Une fois installé, on peut accéder à Firebug en cliquant sur l'insecte qui se trouve en bas à droite dans la barre de statut. Le premier onglet présente une console qui est utilisée pour faire afficher différents messages : erreurs JavaScript, requêtes AJAX, requêtes GET et POST, etc.
Au moment du développement, on peut aussi avoir accès à cette console. Par exemple, pour déboguer du code JavaScript, j'avais souvent tendance à faire afficher une trace des variables ou faire un suivi sur une structure de contrôle en utilisant alert(). Avec Firebug, on peut prendre avantage de la console pour y faire afficher nos messages de trace sans avoir à fermer continuellement des fenêtres popup. Pour ce faire, on peut utiliser l'objet JavaScript "console" de Firebug :
<script type="text/javascript">
console.log("trace 1");
</script>
L'objet console possède aussi une fonction de profilage (console.profile()) qui permet de mesurer la performance de certaines actions.
Une autre fonction utile se trouve sous l'onglet NET (network) qui permet de suivre le temps de chargement et la taille des ressources utilisées sur une page (images, scripts, etc). C'est ainsi qu'on verra que www.google.ca ne charge que 3 ressources en 235 millisecondes tandis que www.yahoo.ca en utilise 22 qui se chargent en 1,29 seconde (le sommaire est indiqué à la dernière ligne).
Il est aussi possible de modifier le code HTML d'une page à partir de Firebug. Et c'est assez simple :
- Rendez-vous sur la page d'accueil de Google
- Ouvrez Firebug et cliquez sur le bouton Inspect
- En survolant les éléments de la page, cliquez sur le bouton "Google Search" (en passant par-dessus, il sera encadré et le click correspondra à sélectionner l'élément à inspecter plutôt qu'à soumettre le formulaire)
- Dans Firebug, sous l'onglet HTML, on remarquera que le code du bouton est surligné en bleu
- En cliquant sur le bouton Edit, le code du bouton sera isolé et on pourra utiliser l'onglet HTML pour modifier le code. Par exemple, modifiez la valeur de l'attribut "title" pour le texte de votre choix
- On pourra voir en temps réel le rendu de la page changer selon nos modifications
Et ce n'est qu'une partie des possibilités offertes par Firebug. Comme cette extension indispensable n'est offerte que sur Firefox, on pourra trouver du support pour Safari, Opera ou Internet Explorer en utilisant Firebug Lite, une version en JavaScript qu'il suffit d'inclure à sa page pour pouvoir bénéficier des fonctionnalités de base.
J'ai reçu un DVD contenant des fichiers vidéo au format .rmvb (RealMedia Variable Bitrate) et je dois dire que je n'avais vraiment aucune envie d'installer RealPlayer pour pouvoir les visionner. Il y a quelque chose dans ce lecteur multimédia que je déteste ou du moins, je suis toujours resté avec une mauvaise impression sur ce logiciel. Ma première expérience doit remonter autour de 1997 ou 1998 et je crois me souvenir qu'il fallait s'enregistrer, que la publicité était envahissante, qu'il y avait une tonne de gadgets inutiles, que pour télécharger des extraits audio, on devait ouvrir le fichier .ram et y extraire l'URL du fichier .ra et que je ne pouvais pas faire jouer les extraits avec mon lecteur audio préféré en raison du format propriétaire. C'est pour ces raisons que je m'étais vite tourné vers le format mp3.
Mais avec ce DVD en main, j'étais curieux de voir ce qu'on m'envoyait. J'ai cherché une alternative, une façon d'installer un CODEC (coder-decoder), pour me permettre de lire les fichiers. Et j'ai découvert RealAlternative, un substitut pour Windows qui installe les codecs et en option le lecteur multimédia Media Player Classic (peu gourmand en mémoire vive et compatible avec de nombreux formats).
Pour ce qui est de RealPlayer, je ne suis pas déçu d'en être débarassé...
C'est la première journée de mes vacances de Noël, une grosse tempête de neige est tombée sur le Québec et je dois aller pelleter pour dégager ma voiture (en fait, je me croise les doigts et j'espère que mon voisin qui a une voiture identique à la mienne se soit trompé et qu'il ait commencé le travail à ma place...). Aussi, Cyberpresse annonce que cette fois-ci, la neige ne sera pas ramassée avant la semaine prochaine puisque les travailleurs de la ville prennent congé durant le temps des fêtes. Est-ce qu'on peut s'inspirer de Toronto et appeler l'armée en renfort ?
Bon, j'ai le sentiment d'amorcer mes vacances du bon pied : paresse totale. Mais comme je me suis mis au défi d'écrire un article par jour, je crois qu'il est temps de sortir mon atout et jouer la carte du Lorem Ipsum.
Donc voici mon entrée pour aujourd'hui :
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in nunc ac sem posuere aliquam. Aenean sodales pede id nibh. Integer id lectus a tortor adipiscing vestibulum. Duis ut felis. Aenean nulla. Vestibulum sagittis varius turpis. Aliquam imperdiet. Aenean sapien leo, porttitor et, sollicitudin eget, rutrum eu, quam. Fusce egestas ante eu eros. Aenean porttitor ante eu dui. Nunc ac tellus. Duis erat lectus, dictum et, bibendum ac, elementum et, enim. Proin consectetur elit vel lectus. Donec congue ultrices felis. Nulla vehicula hendrerit velit. Aliquam porta dui a tellus. Phasellus accumsan feugiat tortor. Duis ligula dui, tincidunt eget, aliquam eget, ullamcorper adipiscing, nisi. Praesent eros turpis, egestas at, accumsan eget, dignissim eget, tortor. Sed ut erat.
Si vous ne connaissez pas Lorem Ipsum, sachez qu'il s'agit de faux-texte utilisé en imprimerie ou en intégration web pour remplir une page de contenu et donner un aperçu de la mise en page. Plusieurs logiciels d'édition permettent de générer du texte générique en latin et s'il n'y en a pas, des extensions sont souvent disponibles. Dans mon cas, j'ai généré mon texte par le web avec le générateur de latin Lipsum.
La compétence, comme la vérité, beauté, et les verres de contact, est dans l'oeil du spectateur.
Il y a une fonction de PostgreSQL très peu documentée et pourtant très pratique qui se nomme generate_series(). Il s'agit d'une fonction qui permet de générer des séries de nombres entiers, un peu à la manière d'une boucle "for" où on indique la valeur de départ, la valeur maximale et de façon optionnelle le saut (step) entre chaque itération (1 par défaut).
Par exemple, pour obtenir 5 enregistrements (rows) allant de 1 à 5 :
SELECT * FROM generate_series(1,5)
--------------------------------------------------------
1
2
3
4
5
On peut aussi obtenir un jeu de résultats en utilisant un saut, positif ou négatif, qui sera passé comme troisième argument (optionnel, la valeur par défaut est +1) :
-- obtenir 0, 10, 20, 30, ... 90, 100
SELECT * FROM generate_series(0, 100, 10)
Dans mon cas, j'y ai trouvé une utilité lorsque j'ai eu à programmer un calendrier d'événements s'échelonant sur plusieurs jours, où la modélisation des dates n'était pas normalisée dans la base de données. Pour exposer l'idée de façon simpliste, on définira une table et un événement, par exemple la Conférence PHP Québec 2009, qui aura lieu du 4 au 6 mars 2009 (durée de 3 jours).
-- création de la table
CREATE TABLE events
(
pk_event integer serial,
eventname character varying(100),
start_date date,
nb_days integer
)
-- Insertion de l'événement (ici, la séquence sera auto-incrémentée et aura la valeur 1)
INSERT INTO events (eventname, start_date, nb_days)
VALUES ('Conférence PHP Québec 2009', '2009-03-04', 3);
Si on souhaite obtenir une liste calculée des trois dates, on pourra exécuter une requête SQL semblable à celle-ci :
SELECT start_date + generate_series(0, nb_days-1) as event_date
FROM events
WHERE pk_event = 1;
Résultat :
2009-03-04
2009-03-05
2009-03-06
C'est un peu comme si on disait en pseudo-code :
nb_days_max = (nb_days - 1) // 2
date = start_date; // '2008-03-04'
for (days = 0 ; days <= nb_days_max ; days++ ) {
// days = 0, 1, 2
echo (date + days);
}
Dans cette requête, j'utilise le champ "start_date" de l'événement comme valeur de départ, à laquelle j'ajoute un des nombres de la série générée qui correspond au nombre de jours. Comme l'événement débute le 4 mars et que cette date est déjà définie dans la base de données, on aura qu'à ajouter 0 à la date initiale pour la conserver telle quelle (première valeur de la série). La dernière date sera calculée en ajoutant 2 jours à la date initiale lors de la dernière itération de generate_series.
En fouillant un peu, je me suis aperçu qu'il n'existait pas d'implémentation native pour d'autres types de bases de données mais j'ai trouvé des scripts de définitions de fonctions similaires pour SQL Server et Oracle.
Une autre utilisation pratique de generate_series() serait de pouvoir effectuer des requêtes sur les listes de codes de statut HTTP ou de tout type de classement inspiré de la classification numérique de Dewey.
La langue française est difficile à maîtriser et moi-même je ne peux prétendre en être un expert. Mais je suis fier de ma langue et j'essaie le plus possible d'utiliser la meilleure qualité possible. Durant mes études, plusieurs de mes collègues programmeurs croyaient que les cours de français n'allaient pas être une nécessité dans une carrière en informatique. Pourtant, dès qu'on est appelé à participer à la rédaction d'un document d'analyse ou à rédiger du texte s'affichant sur un site web, on est responsable de la qualité de notre propre travail et ça devient vite tributaire de la crédibilité de l'entreprise.
Par exemple, lorsque je regarde un formulaire web où les libellés sont en français, une erreur courante que je remarque est une mention indiquant que "les champs avec des astérix sont obligatoires".
Mettons les choses au clair. Lui, c'est Astérix, le personnage populaire des bandes dessinées. Son nom est dérivé du mot "Astérisque", dont le symbole est *. Voilà, qu'on se le tienne pour dit.
A-S-T-E-R-I-S-Q-U-E
En informatique, un astérisque a plusieurs utilités :
- une convention indiquant un champ requis dans un formulaire
- permet de sélectionner toutes les colonnes d'une table dans une requête SQL
- un pointeur en C
- le symbole généralement utilisé pour faire une multiplication
- un caractère de remplacement (aussi nommé wildcard)
- dans une regexp, indique la répétition (0 ou plus) du pattern qui le précède
Cette semaine, j'ai terminé la lecture de la version française du livre "The Art of the Steal" (L'art de la fraude) de Frank Abagnale, ce célèbre fraudeur américain dont l'histoire fut relatée dans le film Catch Me If You Can. Le livre, sorti originalement en 2001, m'intéressait car j'étais curieux de lire ce qu'il avait à dire sur ce qui touche à Internet.
Dans le chapitre 8 ("L'arnaqueur internaute"), il raconte une anecdote sur sa seule expérience d'achat sur le web, alors qu'il acheta sur eBay une guitare pour l'anniversaire de son fils. Voulant payer à l'aide de PayPal, il explique avoir tout juste eu le temps d'entrer son numéro de carte de crédit mais qu'il se rétracta, annula la transaction et préféra payer le vendeur par chèque certifié. Il fut ensuite victime de fraude et son numéro de carte MasterCard fut utilisé pour faire d'autres achats par Internet. Selon lui, le simple fait d'avoir saisi son numéro de carte dans le formulaire le rendit vulnérable en moins d'une minute.
En me fiant à mon expérience personnelle sur ces sites, j'ai été étonné de lire son histoire et je la trouvais pratiquement invraisemblable. Il faut dire qu'au moment de ces faits, PayPal n'avait pas encore été acquis par eBay, donc ça revenait à effectuer le paiement de façon indépendante sur le site d'un tiers parti. J'imagine qu'il devait s'agir soit d'une faille de sécurité importante, soit qu'il fut victime de "phishing" ou de sa méconnaissance du système. Depuis son acquisition par eBay en octobre 2002, un gros travail a été fait afin d'intégrer adéquatement le service de paiement lié à PayPal. Aujourd'hui, c'est sans aucun doute la façon la plus sécuritaire de payer un article acheté sur eBay, principalement en raison des protections offertes.
Il reste que c'est quand même surprenant de voir qu'un fraudeur repenti se fasse frauder à son tour. De mon côté, j'ai eu la chance d'avoir une expérience positive et je me suis toujours senti en sécurité face aux transactions électroniques. À deux reprises, un vendeur ne m'a pas envoyé l'article commandé et un d'eux a même poussé l'audace jusqu'à fermer son compte immédiatement après la transaction (je crois que c'était le même vendeur car je tentais d'acheter le même article que la première fois). Il m'a suffit de signaler le cas à PayPal et si le vendeur ne fait pas suite à ma demande à l'intérieur de 10 jours, PayPal me rembourse automatiquement.
Comme le livre date d'environ 8 ans, on peut croire qu'il y a eu du progrès dans la détection de la fraude et dans la sécurité reliée à ces services. Dans mon cas, ça fait longtemps que je n'ai plus de crainte à acheter sur eBay, tant que je peux payer avec PayPal. J'ai d'autant plus confiance depuis que j'ai lu le chapitre consacré à PayPal, dans le livre Founders at Work, qui explique comment fonctionne son système de détection de la fraude (basé sur des statistiques et probabilités). Dans le fond, celui qui court le plus gros risque aujourd'hui est le vendeur...
Dans un monde idéal, ce serait merveilleux si on pouvait être la seule personne à avoir accès au développement d'un site web. On pourrait alors simplement conserver une copie du projet sur notre disque dur et lorsque des changements surviennent, on aurait qu'à les transférer sur le serveur, sans se soucier de savoir si on possède la version la plus récente. Or, la réalité nous démontre que c'est rarement le cas : nombreux sont les clients qui souhaitent avoir la liberté de faire des modifications mineures au contenu statique de leur site, de façon autonome.
C'est pourquoi à chaque fois que je travaille sur un projet web existant, je vérifie si le client possède un accès FTP et j'essaie de déterminer si une plateforme de publication comme Contribute est configurée. Si c'est le cas, on doit s'assurer de récupérer le fichier en ligne, y faire ses modifications et le renvoyer. Évidemment, le client doit suivre la même procédure, sans quoi il écrasera nos changements... et Dieu sait que c'est le genre de chose qu'on programmeur déteste (levez la main ceux à qui c'est jamais arrivé!). Bref, mieux vaut avoir une bonne communication pour éviter d'écraser mutuellement les plus récentes modifications apportées.
En tant que développeur, si on utilise l'éditeur Dreamweaver, son système de vérouillage pourra être activé (check in / check out) et permettra d'éviter le pire puisqu'un seul utilisateur à la fois est autorisé à apporter des modifications. Lorsqu'un fichier est en train d'être modifié par Contribute ou Dreamweaver, le logiciel envoie sur le serveur un fichier .LCK ("lock") qui indique le nom de la personne qui réserve la ressource. Si quelqu'un d'autre tente d'ouvrir le fichier, le logiciel vérifie d'abord si le fichier en question n'est pas vérouillé en recherchant le fichier .LCK sur le serveur distant. Ce mécanisme est transparent et l'explorateur de fichiers / FTP de DW ne les affichera pas (en mode "remote").
Une petite astuce pour savoir si un site utilise Contribute : on trouvera un répertoire nommé "_mm" à la racine du site (www.nom-du-site-web.com/_mm). Ce répertoire est automatiquement créé lorsqu'un site est configuré pour être utilisé avec Contribute. Il contient un fichier nommé contribute.xml où sont décrites différentes propriétés, dont le mot de passe (encrypté) pour autoriser la connexion. Ce répertoire aussi n'est pas visible à partir de Dreamweaver donc pour le voir, on devra se connecter par FTP ou entrer l'URL où se trouve le répertoire _mm dans un fureteur.
La procédure est différente si on utilise tout autre logiciel. Si notre éditeur est autre chose que Dreamweaver ou si on utilise un client FTP indépendant, il vaudra mieux mettre les choses au clair avant de faire les mises à jour. Si on voit des fichiers .LCK sur le serveur, cela indique que des changement sont encore en suspens par un utilisateur et que la version en ligne n'est peut-être pas la plus récente. Dans certains cas (de mauvaise utilisation), le fichier .LCK demeure sur le serveur alors qu'on en a plus besoin. On pourra le supprimer par FTP pour libérer l'accès à la ressource.
Requête SQL pour obtenir un enregistrement au hasard
Ça m'arrive souvent qu'un client me demande de faire afficher un élément aléatoire dans une page web. Que ce soit pour placer une publicité, mettre un produit en vedette ou pour faire afficher une rubrique "saviez-vous que", c'est le genre de fonctionnalité qui revient constamment et qui permet de mettre un peu de dynamisme dans l'affichage.
De plus, c'est très facile à faire lorsque le contenu est dynamique et géré par un CMS puisqu'on trouve normalement une référence sur les enregistrements dans la base de données. Voici une façon simple d'obtenir un enregistrement aléatoire à partir d'une requête SQL sur trois types de bases de données différentes.
PostgreSQL
Pour obtenir un enregistrement au hasard, on utilisera la fonction mathématique random() qui permet de générer un nombre flotant de 0 à 1. Comme chaque enregistrement se verra associé à un nombre aléatoire, on pourra le classer en ordre et restreindre le nombre de résultats retournés en utilisant la clause LIMIT.
SELECT *SQL Server
FROM table
WHERE condition
ORDER BY random()
LIMIT 1
Du côté de SQL Server, on pourra arriver au même résultat en utilisant la fonction newid(), qui crée un identificateur unique (de type uniqueidentifier) souvent nommé GUID (Globally Unique Identifier) ou UUID (Universally Unique Identifier). Ici, l'équivalent de LIMIT est le mot réservé TOP placé en début de requête.
SELECT TOP 1 *SQL Server possède une fonction rand() pour obtenir un float entre 0 et 1, mais elle est appelée une seule fois à l'intérieur de la requête, donnant toujours le même résultat et rendant impossible l'effet "aléatoire". C'est pourquoi on doit utiliser la fonction newid() qui est non-déterministe, c'est-à-dire qu'elle retournera une valeur différente pour chaque enregistrement (pour visualiser ce qui se passe, placez le dans la liste des colonnes du SELECT *, rand(), newid()...).
FROM table
WHERE condition
ORDER BY newid()
MySQL
Même si j'ai utilisé moins souvent MySQL dans mes projets, j'ai pu obtenir le même comportement avec la fonction rand(), équivalente au random() de PostgreSQL.
SELECT *
FROM table
WHERE condition
ORDER BY rand()
LIMIT 1
Lors d'une analyse de projet, j'ai du chercher une solution de traduction automatique pour du contenu web. Certains produits étaient intéressants mais aucun n'était vraiment satisfaisant à 100%. À vrai dire, la traduction était approximative et le français était généralement massacrée.
Par exemple, le produit qui me semblait le plus évolué était Systran. Il fallait donc le mettre à l'épreuve. Je l'ai mis au défi de traduire en français la phrase désormais classique "bill is a great fan of mark messier". Le résultat fut lamentable mais rigolo : "la facture est un grand ventilateur de marque plus malpropre".
Pour le plaisir, je me suis tourné vers d'autres sites de traduction en ligne dont Google Translate et Babel Fish. Ce dernier étant propulsé par Systran, le résultat fut le même.
De son côté, Google a abandonné Systran il y a un peu plus d'un an pour implanter son propre moteur de traduction. Ce qui est intéressant, c'est qu'il permet aux utilisateurs de proposer de meilleures traductions si celles proposées ne sont pas exactes.
Le résultat de Google est celui qui s'approche le plus de la traduction attendue mais il n'est pas tout à fait au point. Il proposera comme traduction "projet de loi est un grand fan de la marque Messier" et fera un pas de plus dans la bonne direction si on utilise les lettres capitales des noms propres : "Le projet de loi est un grand fan de Mark Messier" (seul le prénom Bill n'est pas reconnu, même si on y ajoute "My friend" devant).
À titre d'information, Mark Messier est un joueur de hockey retraité qui a connu ses derniers moments de gloire en faisant des publicités pour les croustilles Lay's.
Lorsque je suis à court de designer et que j'ai besoin d'utiliser des icônes dans un site ou une application web, je me tourne souvent vers la librairie des icônes Fam Fam Fam.
Offerte gratuitement par le développeur web Mark James, cette librairie compte environ 1000 icônes PNG de qualité (16 x 16 pixels). La librairie générale (silk) en compte 700, à laquelle s'ajoute celle des drapeaux (247 pays), dont les fichiers sont nommés selon les codes ISO.
Le format PNG (Portable Network Graphics) est l'idéal pour les icônes puisqu'il est le successeur du format GIF (Graphics Interchange Format), qui lui conserve principalement la propriété de transparence que le JPG ne peut avoir, tout en offrant un plus grand éventail de couleurs. Ainsi, on passera de 256 (8 bits) à 16 millions (24 bits) de couleurs, qui, contrairement au JPG, pourra se fondre à la couleur de fond sur laquelle l'icône est placée.
Encore une fois, le support dans Internet Explorer 5 et 6 est déficient mais est rendu correctement depuis la version 7. Pour une question de "back compatibility", il faudra faire un bug fix pour être compatible avec les versions antérieures (autrement, les éléments transparents ne seront pas pris en compte). Plusieurs méthodes sont disponibles sur le web, il suffit de rechercher "correct png javascript" ou mieux, iepngfix.htc.
Samedi prochain, ce sera le party de Noël, juste avant des vacances bien méritées. Après avoir passé toute l'année à programmer, c'est maintenant l'heure de se dégourdir un peu.
Voici ma sélection de chorégraphies à apprendre pour épater la galerie et faire lever le party :
Avec ça, fini les anti-dépresseurs.
Vive Internet.
Il m'est arrivé à quelques reprises, dont une fois cette semaine, à devoir superposer un élément HTML par dessus un Flash. En fait, pour être un peu plus précis, ce que je vais expliquer est un problème fréquent avec les menus DHTML qui comportent des portions qui doivent s'afficher par-dessus un élément Flash mais qui passent plutôt au dessous (donnant l'impression de disparaître).
En fait, ce n'est pas une question ici de modifier le z-index car il n'aura pas d'effet sur la superposition des éléments. La solution est plutôt d'ajouter une valeur de transparence à l'attribut wmode de l'objet Flash :
<object type="application/x-shockwave-flash" ...>
<param name="wmode" value="transparent" />
...
</object>
Ainsi qu'à la balise <embed> :
<embed src="" ... wmode="transparent"></embed>
Si la fonction AC_FL_RunContent est utilisée (pour contourner l'activation du Flash imposé par Internet Explorer), on aurait du aussi ajouter ceci à la liste des arguments de l'appel :
AC_FL_RunContent(..., 'wmode', 'transparent' );
Cependant, il faut noter que l'appel à la fonction AC_FL_RunContent devrait maintenant être optionnel puique Microsoft avait annoncé qu'il abolirait l'activation des composants Flash dès avril 2008. Comme les utilisateurs d'Internet Explorer sont encore nombreux, cette modification pourra s'avérer utile pour les utilisateurs qui n'ont pas mis à jour leur fureteur.
À l'origine, Flash était développé par l'entreprise FutureWave Software et l'application se nommait FutureSplash Animator. En 1996, Macromedia acheta la compagnie et renomma le produit Flash 1.0 (un hybride du nom Future Splash ?).
On connait la suite. Macromedia passa aux mains d'Adobe en 2005.
C'est une bonne pratique de détacher les événements JavaScript placés directement sur un élément HTML en les regroupant à la place sous la balise <head>.
Un exemple :
<input type="button" id="btnSubmit" value="OK" onClick="myFunction" />
Pour attacher la fonction dans la balise HEAD, on doit attendre que le DOM (Document Object Model) soit chargé, autrement, il ne trouvera pas l'élément puisqu'il n'existe pas encore.
En utilisant la librairie prototype.js, on pouvait généralement le faire comme ceci :
Event.observe(window, 'load', function() {
/* initialisation suite au chargement de la page */
Event.observe('btnSubmit', 'click', myFunction);
});
Depuis la version 1.6, il est possible de remplacer cet appel par :Event.observe(document, 'dom:loaded', function() {Qui est aussi équivalent à :
/* initialisation suite au chargement du DOM */
Event.observe('btnSubmit', 'click', myFunction);
});
document.observe("dom:loaded", function() {Ainsi, le code HTML est plus "propre", mieux structuré et surtout plus facile à lire. Ce qui me fait penser que ça fait pratiquement un an que la librairie prototype.js n'a pas évolué. Qu'est-ce qui se passe ?
/* initialisation */
Event.observe('btnSubmit', 'click', myFunction);
});
Configurer son routeur sans fil pour travailler à distance
Tempête de neige sur Montréal... Pourquoi ne pas travailler de la maison ? Un coup d'oeil par la fenêtre... Je ne demande pas mieux. Dans mon cas, il suffit que je me connecte par VPN (Virtual Private Network) sur le réseau du bureau, pour ensuite accéder à mon poste de travail à distance (qui doit être ouvert) en utilisant Remote Desktop (je lance toujours l'application par le menu Start / Run / mstsc). Mais ce matin, un petit problème est apparu.
Comme j'ai installé un routeur la semaine dernière pour pouvoir m'amuser avec mon iPod touch, il semblerait que mon réseau local entre maintenant en conflit avec le réseau au travail. Je peux me connecter au VPN, mais plus rien n'est accessible. Ce qui m'indique que le problème est relié au routeur est que si je le retire de ma configuration, tout fonctionne correctement. Il me faudra donc modifier la configuration du routeur pour qu'il soit heureux.
D'abord, je dois dire que je ne suis pas très doué en ce qui concerne la réseautique. Par contre, je suis débrouillard et je réussis généralement à faire ce dont j'ai besoin. Je possède un routeur D-Link DIR-615 que j'accède par mon fureteur à l'adresse 192.168.0.1 pour le configurer. Une fois connecté en administrateur, je me rends à l'onglet Setup et je choisis Network Settings dans le menu de gauche. À ce que j'ai lu, je peux changer le default gateway (router IP address) pour l'adresse IP 10.0.0.1 (lorsque ce sera enregistré, on pourra retourner à la console de gestion du routeur par cette adresse plutôt que par 192.168.0.1). Une fois redémarré, je suis capable d'accéder normalement à Internet, le VPN et le Remote Desktop.
Je ne sais pas s'il s'agit de la meilleure solution mais ça fonctionne. Si quelqu'un a une meilleure alternative, merci de la partager avec moi.
La plupart des programmeurs PHP que je connais utilisent les fonctions PHP var_dump() et print_r() pour effectuer la trace des variables pendant le débogage. Voici un petit aide-mémoire qui résume les fonctions à utiliser au besoin.
Pour un array donné :
$arrTest = array('a', 'b', 'c');
var_dump
var_dump($arrTest);
Résultat :
array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> string(1) "c" }
- Accepte une ou plusieurs variables en entrée
- Dans le cas de notre array, il retournera le type et la valeur de chaque clé dans une forme lisible
- Récursif, pour afficher la structure complète de l'objet
print_r($arrTest);
Résultat :
Array ( [0] => a [1] => b [2] => c )
- Accepte une seule variable en entrée
- Retourne la valeur de chaque clé, sans le type
- Accepte un deuxième argument (booléen) pour indiquer si on veut retourner le résultat dans une variable plutôt que de l'afficher. Par exemple : $result = print_r($arrTest, true);
Il existe une troisième façon intéressante et pratique, soit var_export, qui s'appele aussi avec un ou deux arguments.
var_export($arrTest);
ou
$result = var_export($arrTest, true);
Résultat :
array ( 0 => 'a', 1 => 'b', 2 => 'c', )
- Accepte une seule variable en entrée
- Retourne la valeur de chaque clé, sans le type
- Contrairement aux deux autres, le résultat est du code PHP valide
Comme ce que contient $result est une chaîne de caractère représentant un array PHP valide, on pourrait l'enregistrer et le récupérer plus tard en appelant la fonction eval() :
eval('$arrRecuperation = ' . $result . ';');
Ainsi, la variable $arrRecuperation est un array à nouveau.
Pour du débogage avancé (pour les tâches plus coriaces!), je vous recommande de jeter un oeil aux puissants outils fournis avec Zend Studio (breakpoints, stacks, introspection de variables, etc).
Pour Noël, faites un heureux. Offrez à votre programmeur préféré le livre PHP 5 Objects, Patterns, and Practice (1ère édition, 2004), disponible sur eBay pour la modique somme de 700$ canadiens (550$ US). Et oui, vous avez bien lu, le vendeur est nul autre que Best Bargain Books. Ironie ?
Faites vite, seulement 8 copies disponibles !
Pour les autres qui ne peuvent se payer ce luxe en temps de récession, Amazon offre la deuxième édition pour seulement 35$...
Lorsqu'on télécharge un fichier, on remarque parfois dans la liste une clé md5 ou un fichier avec l'extension .md5. Un MD5 (Message-Digest Algorithm 5) est une fonction d'encryption à 128 bits qui donne comme résultat un hash de 32 caractères en notation hexadécimale. Ce résultat peut être utilisé pour effectuer une validation que le fichier téléchargé a été transféré correctement et que l'intégrité des données est respectée.
C'est une technique généralement utilisée sur Linux mais on peut la reproduire sans trop de problème sous Windows en utilisant UnxUtils. En installant cet outil, on aura accès à plusieurs des commandes disponibles sous Linux dont md5sum.
Si on regarde la page de téléchargement de PHP, on remarquera que sous chaque lien se trouve une clé md5. Il s'agit du résultat attendu lorsqu'on exécute la commande md5sum sur le fichier téléchargé. Dans le cas du fichier php-5.2.6.tar.bz2, le résultat devrait être le suivant : 7380ffecebd95c6edb317ef861229ebd.
La commande md5sum php-5.2.6.tar.bz2 affichera le checksum du fichier (plusieurs fichiers peuvent être passés comme arguments et chacun aura son propre hash) :
7380ffecebd95c6edb317ef861229ebd *php-5.2.6.tar.bz2
On pourra le comparer manuellement à ce qui est inscrit sur le site. Mieux, si un fichier .md5 est déjà disponible en téléchargement, on pourra faire la comparaison directement. S'il n'est pas présent, on pourra le créer, simplement en ajoutant à un fichier texte une ligne pour chaque fichier, composée de la clé md5 attendue, suivie du nom de fichier correspondant (comme le résultat plus haut).
On terminera la vérification à l'aide du fichier .md5 qui utilisera le nom de chaque fichier indiqué pour vérifier sa clé :
md5sum -c result.md5
php-5.2.6.tar.bz2: OK
Dans ce cas-ci, tout est conforme. Si un fichier avait été altéré lors de la transmission, ce serait indiqué FAILED. La commande md5sum peut être utile lorsqu'on télécharge des images ISO de CD ou de DVD, par exemple une distribution Linux. Elle permet de vérifier que le contenu n'est pas corrompu avant de le graver sur un média.
Mise à jour, 2008-12-08
Les noms de fichiers des exemples de cet article ont été modifiés pour utiliser la version 5.2.6 de PHP plutôt que la plus récente version 5.2.7 en raison d'un bogue de sécurité. Pour l'instant, l'utilisation de la version 5.2.6 est recommandée en attendant la sortie de PHP 5.2.8.
En cette période d'instabilité économique, on apprend que 71 000 emplois ont été perdus au Canada, au mois de novembre seulement (et plus de 500 000 aux États-Unis). Moins d'emplois se traduira inmanquablement par une diminution des revenus dans les coffres de l'état, donc moins d'investissements, tant dans les infrastructures que dans les programmes sociaux.
On devra donc s'attendre à ce que les gouvernements fassent des compressions budgétaires un peu partout pour pouvoir arriver. Si on y réfléchit bien, combien d'argent pourraient-ils économiser s'ils troquaient uniquement la suite Microsoft Office pour son rival gratuit OpenOffice ? En se basant sur les prix de vente affichés sur le site de Microsoft, on peut certainement figurer de quel ordre pourrait se chiffrer les économies pour la fonction publique.
Il existe probablement une entente commerciale à plus ou moins long terme avec le géant Microsoft mais lorsqu'elle sera échue, peut-on s'attendre à ce que les gouvernements révisent leur position ? Ce point a été soulevé en juillet dernier par l'organisme FACIL qui estime que le gouvernement dépense annuellement 80 millions de dollars pour des licenses de Windows. Le débat a déjà eu lieu et personnellement, je ne crois pas que se tourner vers un système d'exploitation comme Linux puisse se traduire par des économies substancielles. Mais il faudrait au moins considérer l'adoption de la suite bureautique OpenOffice.
Plusieurs pays ont déjà fait le saut au logiciel libre mais le Québec sembre prendre du retard à cet effet. Peut-être est-ce le moment approprié pour forcer un changement ? Et qui sait, pourquoi ne pas adopter la même approche dans les Cegeps, universités et les bibliothèques ?
Après avoir complètement réinitialisé mon iPod touch (1ère génération, de 8 Go d'espace de stockage), je l'ai branché à iTunes pour pouvoir mettre à jour le firmware et espérer pouvoir installer les applications gratuites offertes dans leur boutique (tout à fait légalement, sans jailbreak). Après avoir télécharger quelques applications intéressantes, je me suis rendu compte que plusieurs demandaient à être installées sur un firmware 2.0 ou plus. Comme la seulement mise à jour disponible pour mon appareil était la version 1.1.5 (améliorations de base), je devais soit jailbreaker mon iPod, soit payer la mise à jour à la version 2.2 proposée par iTunes.
Il y a environ un an, lorsque j'avais jailbreaké mon iPod pour la première fois, je devais d'abord restaurer le iPod avec un firmware précis et j'avais réussi à en trouver un sans trop de problème sur Google. Encore une fois, j'ai procédé de la même façon et j'ai découvert un site où on peut télécharger les firmwares pour iPod. J'ai sélectionné dans la liste "iPod touch 1G (2.2/5G77)" et j'ai téléchargé le fichier .ipsw d'environ 250 Mo.
Une fois en possession de ce fichier, j'ai branché mon iPod touch et j'ai ouvert iTunes 8. Dans la liste de droite, j'ai sélectionné mon appareil pour faire apparaître l'onglet "Summary". Dans cet écran, j'ai cliqué sur le bouton "Restore" tout en gardant enfoncée la touche "shift" de mon clavier. Cette combinaison permet d'ouvrir une fenêtre qui donne la possibilité de choisir le fichier .ipsw à partir duquel effectuer la restauration ou la mise à jour plutôt que d'utiliser celui par défaut. Une fois sélectionné, tout se fait automatiquement, il suffit d'être patient.
Lorsque le processus s'est terminé, j'ai retrouvé mon iPod comme un neuf, avec les applications du iPod touch 2ème génération dont Google Maps, Stocks, Weather, Mail, la possibilité de déplacer les icônes et surtout, j'ai pu installer énormément d'applications gratuites provenant du iTunes store.
Je me retrouve donc avec un jeu de batterie, un autre de air hockey, la pinte de bière Carling, Tap Tap Revenge (inspiré du jeu Guitar Hero), un traducteur, un jeu de darts, le fameux sabre laser de Star Wars et beaucoup d'autres trucs, souvent inutiles qui ne servent qu'à impressionner les amis (surtout ceux qui n'ont pas encore de iPod touch ou iPhone).
Pour la prochaine étape, je me demande si ça vaudrait la peine de jailbreaker le tout avec QuickPwn ?
Vous vous souvenez de la vieille blague du téléchargement de l'Internet ?
Bien que l'idée soit farfelue (évidemment), voilà qu'on peut maintenant télécharger l'encyclopédie Wikipedia pour en faire une archive sur DVD. Mieux, vous pouvez toujours installer une copie complète sur votre iPod touch / iPhone, en installant l'application Encyclopedia, moyennant 2.2 Go d'espace et 8$. Comme ils le disent si bien, c'est peu demandé pour avoir au bout des doigts la somme de toutes les connaissances humaines!
En fouillant un peu, j'ai aussi découvert un autre projet dans le même genre sur Sourceforge, gratuit et fonctionnant sur les anciens types de iPod : Encyclopodia.
Malheureusement, le gros défaut ici est que l'encyclopédie est créée à partir d'un dump (copie fixée dans le temps) de la base de données de Wikipedia, donc l'information n'est pas mise à jour automatiquement. Ça en fait donc une solution idéale pour le iPod mais sans intérêt pour le iPhone. Du moins, à moins de vouloir gaspiller beaucoup dl'espace disque, aussi bien y accéder normalement par Safari.
Ce soir, j'ai réinitialisé mon iPod touch (1ère génération de 8 Go) car j'avais fait plusieurs tests récemment, entre autre en testant deux façons différentes de le "jailbreaker" avec le firmware original (JailbreakMe et ZiPhone). Comme j'avais installé de nombreuses applications pour explorer ses nouvelles capacités, il ne restait plus beaucoup de place pour la musique et les vidéos. Un petit ménage s'imposait.
Parmis les applications que j'ai testé, il y avait un lecteur de eBooks et un émulateur de jeux NES. Dans les deux cas, les applications s'installaient facilement, mais les PDF et les ROMS devaient être déposés dans l'appareil par S-FTP/SSH car contrairement aux fichiers mp3, on ne peut pas les ajouter par iTunes.
Pour y arriver, on doit d'abord ouvrir une connexion sans fil avec le iPod jailbreaké (autrement, la connexion est refusée). Il faudra ensuite obtenir l'adresse IP qu'utilise l'appareil :
- Ouvrir l'icône Settings
- Sélectionner Wi-Fi
- Repérer la connexion utilisée (celle avec un crochet)
- Entrer dans la configuration de cette connexion par la flèche bleue à droite
- Noter ce qui est indiqué à IP Address (192.168.0.x)
- Type : SFTP - SSH File Transfert Protocol
- Entrez comme hôte l'adresse IP utilisée par le iPod
- Par défaut, l'appareil utilise root comme nom d'utilisateur et alpine comme mot de passe
Pour faire suite au Startup Camp de jeudi dernier, je reviens cette semaine avec le livre Founders at Work. Ce bouquin est constitué d'une collection d'entrevues effectuées par Jessica Levingston (mariée depuis 2008 à Paul Graham) qui s'est entretenue avec une trentaine de fondateurs d'entreprises informatiques dont plusieurs sont devenues les leaders dans leur domaine.
Loin d'être technique, on explorera plutôt leur histoire à travers diverses anecdotes qui nous permettra de mieux comprendre les opportunités qui se sont offertes à eux, le contexte dans lequel les idées sont nées, les compromis à faire et les défis qu'ils avaient à relever, y compris au niveau du financement (VCs et Angels).
On lira par exemple l'histoire du succès de PayPal (vendu 1.5 milliards à eBay en 2002), la naissance d'un des premiers web-mail nommé Hotmail (acquis par Microsoft en 1997 pour 400 millions) ou encore un chapitre incontournable où Paul Graham (Y Combinator) parle de ViaWeb, un service permettant de construire une boutique de vente en ligne... devenu par la suite le Yahoo! Store. Ce type est un vrai passionné et c'est toujours intéressant de voir ce qu'il a à dire.
Sinon, le chapitre le plus impressionnant est probablement celui où Steve Wozniak, le co-fondateur et génie technique derrière Apple, parle de la conception révolutionnaire de ses premiers ordinateurs en faisant le maximum avec le moins de puces possible.
Tout ça, en passant par Firefox, Adobe, Research in Motion (fabriquant du BlackBerry), Gmail, Craiglist, Flickr, la plateforme Blogger (où je suis publié), Lotus, VisiCalc (ancêtre du tableur Excel), Hot or Not (précurseur du site québécois Do You Look Good ?), le site Internet Archive, Alexa (maintenant propriété d'Amazon), le déploiement de Ruby on Rails par 37 Signals, et bien plus.
Une source d'information inspirant le succès que tous les entrepreneurs en informatique devraient lire.
La documentation officielle de PHP indique que les balises de fermeture (?>) sont optionnelles. Depuis la sortie de Zend Framework, le standard de formatage exige que ces balises soient omises pour les pages qui ne contiennent que du code PHP (par exemple la définition d'une classe).
Lorsqu'on utilise les instructions (include|require)(_once)? pour attacher une librairie, PHP copie dans le script principal le contenu du fichier avant d'exécuter le tout. Dans ces cas-ci, l'idée de ne pas fermer les balises PHP permet d'éviter que des sauts de lignes ou des espaces, souvent positionnés à la fin des fichiers inclus (après le tag de fermeture), se retrouvent imprimés en sortie dans le script principal. Par la suite, lorsqu'on voudra employer l'instruction header() pour faire une redirection ou encore pour faire du output buffering, cela provoquera la fameuse erreur "headers already sent".
Or, certaines personnes prétendent qu'une balise ouverte devrait toujours pouvoir être fermée et que c'est la responsabilité du programmeur de formater convenablement le code de ses librairies. D'autres, dont les concepteurs du Zend Framework, de Zend Studio, et plus particulièrement du Zend Engine sur lequel repose PHP, croient le contraire.
Simple préférence ou bonnes pratiques de programmation ?
Quoi qu'il en soit, l'éditeur Zend Studio for Eclipse 6 permet de tirer profit du formatage automatique du code (Menu Windows / Preferences / PHP / Formatter) et de le configurer pour utiliser les conventions PHP ou celles du Zend Framework. Et pourtant, même en spécifiant celles de ZF pour créer une nouvelle classe, j'ai remarqué que la balise de fermeture de PHP est automatiquement créée. Comme si c'était voulu...