skip to main | skip to sidebar
Code 18
Manuel du savoir-faire à l'usage des geeks et des curieux
RSS
  • Accueil
  • Le web au Québec
  • Liens
  • Twitter
  • Facebook
  • À propos

mardi 31 mars 2009

Étui pour ordinateur portatif

Publié par Infinite Loop, à 20 h 52 0 commentaire

Une question de gros bon sens...

S'il y a une chose qui me choque dans le monde des produits électroniques et informatiques, c'est qu'à chaque fois qu'on se procure un nouveau gadget, on veut protéger notre investissement et on se sent obligé d'acheter un étui ou un protecteur quelconque. Et c'est justement là le problème car les entreprises savent qu'on dépense une petite fortune pour ces appareils alors c'est naturel pour le consommateur de vouloir en prendre soin pour en bénéficier le plus longtemps possible. Sans compter que de nos jours, les produits sont munis d'une garantie de base d'un an, sauf si on achète les plans de protections prolongées (une autre arnaque).

Il y a quelques années, j'étais propriétaire d'un Palm Tungsten. Comme c'était un appareil fragile, j'avais acheté un étui conçu spécialement pour ce modèle. Et il fallait inmanquablement se munir de pellicules protectrices pour protéger l'écran des éraflures dûes à l'usure. Quand j'ai eu mon premier iPod, je me souviens avoir acheté un iSkin en silicone pour environ 25 ou 30$. Quand je l'ai changé pour un iPod Touch, je me suis procuré un étui en cuir (40$). Si ma mémoire est bonne, une seule pelicule protectrice pour l'écran se détaillait 10$ (et dire que l'écran est supposé être insensible aux égratignures). Bref, c'est sans compter un autre étui pour la caméra numérique et plus récemment, lorsque j'ai acheté mon ordinateur portatif, il fallait me magasiner un étui convenable.

Je n'avais jamais vraiment été informé sur la valeur de tels étuis mais je ne fûs pas très surpris d'apprendre qu'ils se détaillaient entre 50 et 100$ chez les Future Shop et Best Buy de ce monde. Le seul étui que je trouvais correct et qui soutenait le portable de façon stable à l'intérieur coûtait 70$ (contrairement aux autres qui retenaient l'ordinateur par une bande velcro dans un compartiment trop grand). C'est pourquoi je me pose la question : jusqu'à quel point est-ce qu'on peut dépenser pour des accessoires de protection ?

Ne voulant pas encourager les gros détaillants à nous arnaquer davantage, j'ai cherché pour une solution alternative. Après en avoir glissé un mot à ma copine, ça n'a pas pris de temps qu'elle me parla d'une boutique qu'elle connaissait, un centre de liquidation situé sur la rue Chabanel dans le nord de Montréal.

Dans cette petite boutique familiale qui s'appelle Moura Cuir, où on y trouve des valises, sacs à dos, portefeuilles, sacs à main et accessoires, j'y ai déniché un étui pour ordinateur portatif de bonne qualité pour à peine 25$ (taxes incluses ou sans taxe ?). Pour une fois que le prix n'est pas exagéré, je crois que ça vaut la peine d'être dit et encouragé. Voici l'adresse :

Centre de liquidation Moura Cuir
220 Chabanel Ouest
Montréal, Québec
514-384-3906


Tags: Liens

lundi 30 mars 2009

Pagination des résultats sous SQL Server

Publié par Infinite Loop, à 20 h 05 0 commentaire

Pour effectuer une requête SQL paginée, PostgreSQL possède les clauses LIMIT et OFFSET tandis que MySQL utilise la syntaxe LIMIT x,y. Étonnamment, Microsoft SQL Server n'avait pas d'équivalent, jusqu'à l'arrivée de la version MSSQL 2005 et plus récemment la 2008.

Ces dernières versions ont introduit une nouvelle approche pour construire la requête, qui ne ressemble en rien à ce que PgSQL ou MySQL font. La magie s'opère grâce à la fonction row_number(), qui permet de numéroter séquentiellement les résultats d'une requête. À titre d'exemple, imaginez qu'on définisse préalablement une sous-requête qui liste des villes. On utilisera le mot clé OVER pour associer un numéro de 1 à n, en suivant l'ordre spécifié par le champ noté entre parenthèses (dans mon exemple, alphabétique selon le nom de la ville). Une fois la sous-requête définie, il ne restera qu'à l'utiliser dans un autre SELECT et utiliser la référence à l'indice idx attribué par row_number() pour trancher les résultats selon le nombre d'enregistrements par page voulu.

WITH subquery AS
(
SELECT *, row_number() OVER (ORDER BY city_name) as idx
FROM dbo.table_cities
)
SELECT *
FROM subquery
WHERE idx BETWEEN 50 AND 100;
Personnellement, je suis d'accord que c'est pratique et que ça constitue un gros pas en avant pour SQL Server, mais c'est beaucoup moins élégant que ce que propose ses concurrents. OK, je sais que ça fera plaisir à plusieurs de l'entendre : Microsoft a copié sa solution sur Oracle :-)

Précédemment, que devait-on faire lorsqu'on utilisait MSDE (Desktop Engine) ou SQL Server 2000 ? Il fallait simplement user d'imagination. Mais on peut gagner beaucoup à apprendre quel genre de mécanisme permettait d'arriver à paginer des résultats.

On pouvait créer une requête avec des sous-requêtes imbriquées mais ma solution favorite était d'utiliser du Transact-SQL (T-SQL) à l'intérieur d'une procédure stockée. À l'aide d'une table temporaire ou une variable table qui contient une colonne integer avec IDENTITY(1,1) - qui débute par 1 (seed) et qui s'incrémente de 1 à chaque appel, on insère les résultats de la requête de base et un numéro incrémentiel unique est attribué à chaque enregistrement, ce qui nous permet ensuite d'extraire la page.
CREATE PROCEDURE 
@page INT,
@resultsPerPage INT
AS
DECLARE
@tempResults TABLE (
idx INT IDENTITY(1,1),
field1 INT,
field2 VARCHAR(100),
field3 BIT,
...
)
DECLARE
@idxFirst INT,
@idxLast INT

-- assigner un numéro de ligne automatiquement
INSERT INTO @tempResults (field1, field2, field3)
SELECT field1, field2, field3 FROM dbo.my_table
WHERE condition1 = x
AND condition2 = y
ORDER BY field2

-- pagination
/*
Selon ce calcul, si on compte 50 résultats par page
Page 1 : 1 à 50
Page 2 : 51 à 100
*/
SET @idxFirst = (@page - 1) * @resultsPerPage + 1
SET @idxLast = @idxFirst + @resultsPerPage - 1

-- retourner la page
SELECT * FROM @tempResults
WHERE idx BETWEEN @idxFirst AND @idxLast
GO
Vous devrez par la suite vous assurer que le numéro de page n'est pas négatif, que la page demandée n'excède pas le nombre de résultats, que votre table de base ne possède pas trop d'enregistrements, ce qui entraînerait une perte de performance. De quoi se faire aller les méninges un peu. À bien y penser, row_number() n'est pas si mal.


Tags: SQL Server

dimanche 29 mars 2009

Calendrier jQuery UI

Publié par Infinite Loop, à 13 h 11 2 commentaires

Je viens de m'amuser pour la première fois avec jQuery User Interface. C'est vraiment du beau boulot! En allant de l'animation, aux effets, en plus d'ajouter les widgets et les thèmes, il y a de quoi s'amuser et créer des interfaces attrayantes en un tour de main.

Parmi les widgets disponibles, il y a :

  • l'accordéon
  • un sélectionneur de date (calendrier)
  • une boîte de dialogue (modale)
  • une barre de progression
  • un curseur de défilement
  • les onglets
Contrairement à d'autres librairies JavaScript, il faut avouer que les démos et les exemples sont bien documentés et faciles à réaliser.

Pour ma part, j'ai fait mes premières expériences avec le calendrier qui permet à l'utilisateur de sélectionner une date facilement, tout simplement parce que c'est le type de contrôle que j'utilise régulièrement dans mes formulaires. J'ai été surpris de voir à quel point celui de jQuery UI est complet. D'abord, il s'initialise facilement, il suit les règles esthétiques d'un thème qui peut se marier agréablement avec les autres contrôles et il est très flexible. Je publie ici le résultat commenté de mon premier test.

Après avoir sélectionné les options, le thème et téléchargé le tout, j'ai pris tous les fichiers et je les ai placés dans mon projet à cet emplacement : /js/jquery-ui.

Dans ma page web, j'ai chargé les librairies :
  • d'abord jQuery
  • ensuite le noyau UI et le datepicker
  • l'internationalisation, pour afficher le contrôle dans la langue de notre choix
<script type="text/javascript" src="/js/jquery-ui/js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/js/jquery-ui/development-bundle/ui/ui.core.js"></script>
<script type="text/javascript" src="/js/jquery-ui/development-bundle/ui/ui.datepicker.js"></script>
Ensuite le thème de base en CSS :
<link type="text/css" href="/js/jquery-ui/development-bundle/themes/base/ui.all.css" rel="Stylesheet" />
Dans le HTML, j'ai crée un formulaire et j'y ai ajouté un champ texte, par exemple pour inscrire une date de naissance :

<input type="text" id="birthdate" />

Pour contrôler la grosseur du calendrier, j'ai dû ajuster le CSS pour réduire ses dimensions. Comme le reste du texte de ma page en était affecté, j'ai forcé la taille du texte dans différentes balises.
<style type="text/css">
body {
font-size: 62.5%;
}

// voir plus loin
#inlineCalendar {
font-size: 62.5%;
}

div, p {
font-size: 12px;
font-family: arial;
}
</style>
Pour initialiser le datepicker, j'ai créé un objet JS qui définit le format de date international (ISO 8601) du type "2008-03-29". Comme vous le verrez plus loin, d'autres options pourront être ajoutées.
var dp_config =  { dateFormat: 'yy-mm-dd' };
J'initialise le contrôle pour afficher le datepicker lorsque le champ qui possède l'ID "birthdate" recevra le focus.
function initialize() {
$('#birthdate').datepicker(dp_config);
}

$(document).ready( initialize );
Configurer le calendrier en français

Par défaut, le calendrier s'affiche en anglais. Quelques petites modifications sont nécessaires pour le configurer en français (ou tout autre langue désirée, le répertoire d'internationalisation, i18n, semble contenir environ 40 langues prédéfinies).
// charger le fichier d'internationalisation global
<script type="text/javascript" src="/js/jquery-ui/development-bundle/ui/i18n/jquery-ui-i18n.js"></script>

// ou mieux, charger seulement la langue française
<script type="text/javascript" src="/js/jquery-ui/development-bundle/ui/i18n/ui.datepicker-fr.js"></script>
Dans l'objet dp_config, on pourra aussi redéfinir les entêtes de colonnes pour les noms de jours pour passer d'une abréviation de deux lettres à une seule :
var dp_config =
{
dateFormat: 'yy-mm-dd',
dayNamesMin: ['D', 'L', 'M', 'M', 'J', 'V', 'S']
};
Dans la fonction d'initialisation, j'ai appelé la fonction setDefaults() pour paramétrer deux éléments de langue :
  • showMonthAfterYear : false, pour afficher "mars 2009" au lieu de "2009 mars"
  • $.datepicker.regional['fr'] pour indiquer à i18n de charger le package de langue français
function initialize() {
$.datepicker.setDefaults($.extend({showMonthAfterYear: false}, $.datepicker.regional['fr']));
$('#birthdate').datepicker(dp_config);
}
Avec ceci, mon calendrier / datepicker était 100% fonctionnel en français.

Un peu plus d'options

En lisant la documentation, d'autres ajouts intéressants sont possibles, que j'ai placé dans dp_config (cet objet ne fait pas parti de la suite jQuery, c'est une façon que j'ai de structurer mon code pour qu'il soit plus lisible). Comme pour dateFormat et dayNamesMin, il faut ajoute une ligne à la fin pour chaque option désirée (clé/valeur, séparée par une virgule, sauf le dernier) :
  • Permettre de changer de mois et/ou d'année. Comme c'est un champ pour saisir la date de naissance, on spécifiera yearRange pour permettre au calendrier de reculer 100 ans en arrière et 0 année en avant (année courante) :

    changeMonth: true,
    changeYear: true,
    yearRange: '-100:+0'

  • Afficher deux mois consécutifs (ou plusieurs), comme le font les sites de voyage :

    numberOfMonths: 2

  • Affichage des boutons pour revenir au mois courant et pour forcer la fermeture du datepicker :

    showButtonPanel: true

  • Ajouter un effet graphique d'animation à l'affichage du calendrier :

    showAnim: 'fadeIn'

  • Afficher le calendrier inline dans le HTML. Il suffit de créer une balise DIV dans le HTML et attacher le calendrier au DIV plutôt qu'au champ du formulaire dans la fonction initialize().

    $('#divInlineCalendar').datepicker(dp_config);


Tags: JavaScript

Citation no. 23 sur l'ambidextrie

Publié par Infinite Loop, à 08 h 11 0 commentaire

Je donnerais mon bras droit pour être ambidextre

- Brian W. Kernighan


Tags: Citations

samedi 28 mars 2009

Poster son statut Twitter avec PHP

Publié par Infinite Loop, à 10 h 32 4 commentaires

Pour moi, en dépit de la popularité du service de micro-blogging Twitter, c'est encore resté au stade de curiosité. Peut-être parce que j'ai le verbe facile et que j'ai de la difficulté à être contraint à 140 caractères! Non, sans blague, on est habitué à ce genre de fonctionnalité, que ce soit dans le statut MSN (Share a quick message), dans celui de Facebook ou dans les SMS (160 caractères), donc je comprends l'engouement des gens à vouloir résumer leur pensée en une courte phrase.

Alors que la demande est grandissante, les utilisateurs veulent pouvoir intégrer le contenu à partir d'une interface unique. Qu'en est-il si on veut faire en sorte de poster un message vers Twitter à partir de notre propre application ?

En utilisant cUrl (à supposer qu'il est installé), on sait qu'on peut appeler la commande par le shell pour s'authentifier et poster le statut:

curl http://twitter.com/statuses/update.xml -u username:password -d status="message"

Sachant cela, rien ne nous empêcherait de lancer la commande PHP shell_exec(), mais pour des raisons de sécurité, les administrateurs réseaux ne sont jamais très friand à débloquer ce type d'appel. Souvent, le mieux qu'ils puissent faire est d'autoriser l'exécution de certains programmes, en les spécifiants comme sudoers.

$result = shell_exec('curl http://twitter.com/statuses/update.xml -u username:password -d status="message"');

Donc il est préférable d'utiliser la librairie cUrl et d'instancier l'appel à l'API REST directement par PHP:

// url qui pointe vers l'action update, en xml ou json
$api_url = 'http://twitter.com/statuses/update.xml';

// l'information de votre compte
$username = 'usr';
$password = 'pwd';

// le message
$args = array( 'status' => 'Mon premier statut par curl');

// initialiser une session cUrl
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $api_url);

curl_setopt($ch, CURLOPT_HEADER, True);
curl_setopt($ch, CURLOPT_NOBODY, False);

curl_setopt($ch, CURLOPT_POST, True);
curl_setopt($ch, CURLOPT_POSTFIELDS, $args);

// information de login
curl_setopt($ch, CURLOPT_USERPWD, $username.':'.$password );

// en secondes
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

// pour éviter l'erreur HTTP 417 - Expectation Failed
$headers = array('Expect:', 'X-Twitter-Client: ', 'X-Twitter-Client-Version: ', 'X-Twitter-Client-URL: ');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

// envoyer le message
$response = curl_exec($ch);
$info = curl_getinfo($ch);

curl_close($ch);
Une fois l'envoi terminé, on récupère l'information retournée dans une variable et on peut regarder le statut par le code HTTP reçu:
if( intval( $info['http_code'] ) == 200 )
echo 'Message envoyé';
else
echo 'Erreur HTTP ' . $info['http_code'];
Notez que si vous faites des tests et que vous avez du mal à vous authentifier, votre compte sera bloqué temporairement et provoquera une erreur 401. Vous devrez patienter un certain temps pour qu'il soit dévérrouillé.


Tags: PHP

vendredi 27 mars 2009

Informatique du film Jurassic Park

Publié par Infinite Loop, à 20 h 36 0 commentaire

Vous vous souvenez du film Jurassic Park, lancé sur nos écrans en 1993 ? Ça faisait un bout de temps que je voulais en parler car le film présente quelques petites curiosités informatiques que je n'avais pas réellement noté à l'époque, mais qui sont appropriées pour cette chronique quotidienne.

Dans ce film, ce n'était pas tant les dinosaures qui m'avaient impressionné. Non, la magie se retrouvait d'abord dans les Jeeps qui possédaient des systèmes de CD-Rom interactifs! Rien de moins. Et que dire du personnage de Lex Murphy, la fillette qui connaissait Unix et qui a su restaurer le programme pour assurer le bon fonctionnement du parc d'attraction. Un vrai jeu d'enfant...

Sinon j'aimerais attirer votre attention sur un détail qui ne défile que pendant quelques secondes : quand Dennis Nedry, l'informaticien crasseux, lance le programme de sabotage. J'ai dû effectuer une saisie d'écran au ralenti pour montrer ce qui est affiché à l'écran. Cliquez sur l'image ci-dessous pour la voir en plus grand format.


Qu'est-ce que vous remarquez dans le code source ?

  • Des commentaires (#)
  • Le décompilateur de ressources Macintosh (Derez)
  • Une expression régulière à évaluer
  • Une commande checkout pour du contrôle de source
On pourrait presque y croire, non ?

En fouillant un peu, j'ai trouvé ceci dans le trivia d'IMDB (que je traduis approximativement) :

Le logiciel du parc est écrit en Pascal; un programme est clairement visible en gros plan dans l'un des moniteurs du système UNIX. L'interface graphique reconnue comme étant UNIX était en réalité un navigateur de fichiers fictif en 3D de Silicon Graphics. En réponse au film, une véritable application a été écrite (NDLR: elle se nommait FSN). Le numéro de version du système d'exploitation Unix de SG était 4.0.5 que l'on peut voir dans un des shell.

J'ai réussi à mettre la main sur une copie inspirée du Silicon Graphics 3D File System Navigator, qui se nomme FSV pour Linux / Unix. Requiert au minimum OpenGL 1.1 ou les librairies Mesa3D. Ma curiosité a été assouvie pour aujourd'hui.


Tags: Curiosités

jeudi 26 mars 2009

XML valide pour RSS

Publié par Infinite Loop, à 22 h 43 0 commentaire

Aujourd'hui, j'ai eu à récupérer un flux RSS externe et à l'intégrer sur le site web d'un de nos clients. Évidemment, c'était en supposant que le RSS soit formatté correctement...

La difficulté que j'ai rencontré était que des caractères illégaux s'étaient glissés dans le texte, en particulier le symbole "&", qui n'est pas considéré valide, tout comme les balises HTML. N'ayant pas le contrôle sur le flux en question, je cherchais un moyen de contourner le problème, à la plus grande satisfaction de mon client.

Pour y remédier, je me suis simplement arrangé pour entourer le texte de sections CDATA, qui font en sorte que les caractères spéciaux et le code HTML provenant d'un éditeur de texte riche (gras, italique, etc.) ne soient pas analysés et validés en tant que structure du document XML.

D'abord, j'ai lancé une commande cUrl pour capturer les résultats situés sur le site distant. Ensuite, j'ai effectué une série de remplacement pour insérer les sections CDATA (Character Data) aux bons endroits. Le texte compris dans une section CDATA doit toujours être placé entre les marqueurs <![CDATA[ et se ]]-->.

Ce que j'ai fait pouvait ressembler à ceci :

// url du RSS
$url = 'http://www.site.com/rss-avec-syntaxe-invalide.php';

// initialiser une session cUrl
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);

//
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

// obtenir le contenu
$xml = curl_exec($ch);

// effectuer les remplacements
// j'aurais aussi bien pu le faire par RegExp
$xml = str_replace("<title>", "<title><![CDATA[", $xml);
$xml = str_replace("</title>", "]]></title>", $xml);

$xml = str_replace("<description>", "<description><![CDATA[", $xml);
$xml = str_replace("</description>", "]]></description>", $xml);

curl_close($ch);

// afficher le flux dans ma page PHP
echo $xml;
Une fois les sections insérées, le RSS a pu s'afficher correctement, tant dans Internet Explorer que dans Firefox. Contrairement à ce dernier, IE 7 reconnaissait l'erreur mais n'effectuait pas la correction, se contentant de lancer un message de syntaxe invalide :

Internet Explorer ne peut pas afficher ce flux
Ce flux contient des erreurs de code.
Aucun espace blanc n'est autorisé à cet emplacement.


Tags: Intégration, PHP

mercredi 25 mars 2009

Gadgets électroniques et informatiques

Publié par Infinite Loop, à 20 h 29 0 commentaire

Vous devez certainement connaître ThinkGeek, la boutique de prédilection pour trouver des curiosités en tout genre qui plaira aux geeks ?

Et bien j'en ai découvert une autre récemment, un peu moins originale mais où les prix sont ridiculement bas. Je dois cette trouvaille à mon père, bien qu'il ne soit pas très techno, dès qu'il l'a vu, il a immédiatement su que ça me plairait. Naturellement, plutôt que de me transférer le courriel, il a jugé bon de l'imprimer et de me le remettre en personne. Comme quoi il est bien ancré dans ses habitudes!

Ce fournisseur de gadgets se nomme DealExtreme et il a pignon sur rue quelque part à Hong Kong. Leur site compte des milliers d'articles, en passant par l'informatique, l'électronique, des accessoires rares et curiosités diverses. Chaque fiche possède une description, des photos et vidéos des utilisateurs, des critiques en plusieurs points (pour et contre), ce qui me laisse croire que la qualité des produits est somme toute respectable.

Il n'y a qu'à cet endroit où on peut trouver :

  • un porte-clés en sabre laser lumineux à 1,83$
  • des étuis pour Nintendo DS Lite ou pour PSP à moins de 1,50$
  • un câble USB pour iPod à 2,48$
  • une souris optique à doigt
  • des housses de protection pour ordinateurs portables entre 5$ et 10$
  • des accessoires de tours de magie
  • des farces et attrapes
  • des adaptateurs de manettes de jeux vidéos
Contrairement à eBay, où les vendeurs asiatiques ont tendance à annoncer des bas prix et des frais de livraison exorbitants, DealExtreme offre la livraison standard gratuite sur tous les achats (peu importe le prix), acheminés dans un délai approximatif de 2 semaines. Assurez-vous de jeter un oeil à ce bric-à-brac. Pour ma part, je viens de passer une commande à l'instant.


Tags: Le coin du geek

mardi 24 mars 2009

Redéfinition de classe PHP

Publié par Infinite Loop, à 19 h 31 0 commentaire

Avez-vous déjà rencontré l'erreur PHP suivante ?

Fatal error: Cannot redeclare class test in path.php on line 2

C'est le genre de message qui apparaît lorsqu'on tente d'inclure deux fois le même fichier avec include() ou require().

require('myClass.php');
require('myClass.php');
Heureusement, on peut facilement corriger le tout en utilisant require_once() pour éviter la redéfinition.
require_once('myClass.php');
require_once('myClass.php');
Dans bon nombre de projet, ce n'est pas rare qu'une librairie contienne des dépendances ou qu'elles en incluent d'autres. C'est exactement ce qu'on fait dans nos projets : on inclut des librairies externes et nos propres librairies. Si on déclare une nouvelle classe dans un projet, c'est possible qu'un autre fichier en contienne une du même nom. Et nous n'avons pas le contrôle sur la façon que choisissent les autres développeurs pour les nommer. Le message d'erreur est assez explicite pour indiquer la redéfinition d'une classe, mais comment savoir où se trouve la première déclaration ?

Un truc très simple pour déboguer : il suffit de déclarer une classe vide du même nom et placer cette déclaration avant tous les includes de notre projet. En faisant cela, notre classe deviendra la principale (la première déclarée) et celle cachée dans les profondeurs d'une librairie sera considérée comme celle redéfinie. Le message d'erreur permettra de connaître l'emplacement exact de la classe externe et nous pourrons ensuite décider des meilleures actions à prendre.
// forcer une déclaration vide
class test {}

require_once('external.library.with.test.class.php');
require_once('my.test.class.php');
Fatal error: Cannot redeclare class test in path\external\library\test.php on line 2

Dans d'autres circonstances, ça peut parfois être pratique d'avoir un aperçu de toutes les classes déclarées dans un projet en les listant comme ceci :
echo '<pre>';
print_r(get_declared_classes());
echo '</pre>';
De la même façon, on pourra obtenir la liste de tous les fichiers inclus dans notre projet, incluant leur chemin complet :
echo '<pre>';
print_r(get_included_files());
echo '</pre>';


Tags: PHP

lundi 23 mars 2009

Origines du Hello World

Publié par Infinite Loop, à 19 h 25 0 commentaire

Saviez-vous que le premier exemple de programme "Hello World" avait été écrit vers 1974 par le canadien Brian Kernighan, un guru Unix et du langage C ? Alors qu'il travaillait pour Bell Labs, il rédigea un tutoriel où il y faisait référence. Une tradition était née.

Un programme Hello World est habituellement constitué d'un nombre minimal de lignes de code pour faire afficher le message et il sert généralement d'introduction lorsqu'on apprend un langage. En un coup d'oeil, le programmeur peut reconnaître la structure et la syntaxe à utiliser.

Parmi ses réalisations, Brian Kernighan a co-écrit le langage AWK, il a été co-auteur de la célèbre bible The C Programming Language et c'est à lui qu'on doit le nom du système d'exploitation Unix.

Pour aiguiser votre curiosité, jetez un oeil à une collection de programmes Hello World écrits dans plus de 400 langages!


Tags: Saviez-vous que

dimanche 22 mars 2009

Diaporama de photos en JavaScript, partie 2

Publié par Infinite Loop, à 11 h 04 0 commentaire

Hier, j'ai démontré comment on pouvait programmer un diaporama de base pour afficher des photos. Bien que le code était fonctionnel, sa structure laissait à désirer. Avant de lire cette deuxième partie, je vous suggère de lire l'introduction du sujet, vous pourrez mieux comparer les améliorations apportées pour transformer le code en orientée objet. J'introduirai aussi le concept des closures JavaScript (fermetures), qui sont nécessaires à la réalisation de cet exercice.

La première amélioration apportée sera d'ajouter deux boutons pour pouvoir démarrer et arrêter le défilement des photos :

<input type="button" id="btnStart" value="Démarrer" />
<input type="button" id="btnEnd" value="Terminer" />
Contrairement à l'exemple précédent, comme le diaporama ne débutera pas automatiquement, on voudra cacher la photo et sa vignette jusqu'à ce que le bouton soit cliqué. Nous allons placer les balises <img> et <span> dans un conteneur que nous allons cacher au chargement de la page.
<div id="slideshow">
<p><img id="pictureHolder" src=""></p>
<span id="counter"></span>
</div>
Avec Prototype (mais on aurait aussi pu prendre jQuery), on appelle un fonction d'initialisation qui attache les événements aux deux boutons.
document.observe('dom:loaded', initialize );

function initialize() {
initSlideshow();
Event.observe('btnStart', 'click', showSlideshow );
Event.observe('btnEnd', 'click', hideSlideshow );
}
On définit les méthodes et on inclut les appels à un objet "s" encore inexistant, qui sera l'objet slideshow, instancié globalement.
function initSlideshow() {
hideSlideshow();
}

function showSlideshow() {
$('slideshow').show();
s.start();
}

function hideSlideshow() {
$('slideshow').hide();
s.end();
}
Jusqu'ici, nous n'avons pas encore couvert la refonte orientée objet de notre slideshow. Par contre, on sait qu'on voudra obtenir un code semblable à ceci, où le constructeur (new Slideshow) prendra comme attributs :
  • l'ID du conteneur d'image <img>
  • l'ID du compteur, la vignette <span>
  • le chemin du répertoire où sont placées les images
  • un array qui contient la liste des images
var path = 'images/vacances/';
var pics = new Array(
'001.jpg',
'002.jpg',
'003.jpg',
'004.jpg',
'005.jpg',
'006.jpg',
'007.jpg',
'008.jpg',
'009.jpg',
'010.jpg'
);

var s = new Slideshow('pictureHolder', 'counter', path, pics);
s.showLengthInSeconds(1);

// et plus tard, contrôler le défilement
s.start();
s.end();
Pour commencer, il faut définir l'objet :
function Slideshow(pImageId, pCounterId, pPath, pPicsArray) {
var _self = this; // closure :-)

this.holderId = pImageId;
this.counterId = pCounterId;
this.path = pPath;
this.pics = pPicsArray;
this.appearLength;
this.currentPicture = 0;

this.timerDisplay;
this.timerChange;

// pour le moment, j'assume qu'il y a au moins une photo
this.totalPictures = this.pics.length;
}
Ici, on utilise le mot clé "this" pour attacher des propriétés à l'objet Slideshow. Les variables sont initialisées aux valeurs par défaut et selon les paramètres reçus.

La première ligne sert à créer une fermeture (closure), c'est-à-dire une référence sur l'objet actuel Slideshow. Comme notre objet contiendra des fonctions, si nous essayons d'utiliser "this" à l'intérieur, ce sera le "this" de la portée (scope) de la fonction, et non pas le "this" de notre objet. En créant une référence dans une variable dès le départ, nous serons en mesure de faire la distinction entre la portée locale de la fonction et globale de l'objet.

À l'intérieur de Slideshow(), on attachera des fonctions anonymes (leur définition ne contient pas de nom, on les appellera par le nom associé à l'objet)
this.showLengthInSeconds = function(sec) {
_self.appearLength = sec;
}

this.start = function() {
_self.loadPicture();
}

this.loadPicture = function() {
// remarquez l'utilisation de _self
$(_self.holderId).src = _self.path + _self.pics[_self.currentPicture];
_self.showCounter();

Effect.Appear(_self.holderId, { duration:1, from:0.0, to:1.0 });

_self.displayFor(_self.appearLength);
}

this.showCounter = function() {
$(_self.counterId).update( (_self.currentPicture + 1) + ' / ' + _self.totalPictures + ' - ' + _self.pics[_self.currentPicture]);
}

this.displayFor = function(sec) {
// utilisation du closure pour faire le callback
_self.timerDisplay =
setTimeout(
function() { _self.changePicture(); },
sec * 1000
);
}

this.changePicture = function() {
_self.currentPicture++;
if (_self.currentPicture == _self.totalPictures )
_self.currentPicture = 0;

Effect.Fade(_self.holderId, { duration:1, from:1.0, to:0.0 });
_self.waitFadeOutEnds(1); // 1 sec, according to duration
}

this.waitFadeOutEnds = function(sec) {
// setTimeout s'attend à recevoir des millisecondes, donc paramètre secondes * 1000
_self.timerChange =
setTimeout(
function() { _self.loadPicture(); },
sec * 1000
);
}

this.end = function() {
clearTimeout( _self.timerDisplay );
clearTimeout( _self.timerChange );
}
En conclusion, il y a trois notions importantes à retenir pour réussir à faire fonctionner le tout sans problème. Elles se retrouvent dans les fonctions displayFor() et waitFadeOutEnd() :
  • l'utilisation de setTimeout pour faire un appel à une fonction à un intervalle régulier
  • conserver une référence sur le timerID (_self.timerDisplay et _self.timerChange). Ceci nous permettra de stopper le callback, donc d'arrêter le diaporama
  • l'utilisation du closure _self pour appeler la fonction à l'intérieur d'une fonction anonyme, plutôt que d'utiliser setTimeout avec le code en texte
Comme les fonctions appartiennent à l'objet, il n'y a plus de risque de collision entre des noms de fonctions utilisés : deux objets peuvent avoir une fonction du même nom. De plus, on peut sans problème instancier plusieurs objets du même type, chose qui aurait été difficile avec l'exemple de la partie 1.


Tags: JavaScript

Citation no. 22 sur la simplicité

Publié par Infinite Loop, à 09 h 53 0 commentaire

La simplicité est la sophistication suprême.

- Léonard de Vinci


Tags: Citations

samedi 21 mars 2009

Diaporama de photos en JavaScript, partie 1

Publié par Infinite Loop, à 10 h 58 0 commentaire

Ce matin, pendant que ma blonde dormait, j'ai fait un petit exercice pour créer un diaporama de photos simple en JavaScript, où les images défilent automatiquement. En moins d'une heure, j'ai réalisé deux versions, une utilisant des méthodes standards procédurales, et l'autre, que je présenterai demain, qui est plus orientée objet et qui introduit les fermetures. J'ai écrit ce code pour le plaisir, alors je ne prétends pas qu'il soit parfait et je ne serais certainement pas prêt à le mettre tel quel en production sans l'avoir préalablement paufiné. Comme tout ce que je présente ici, l'objectif est surtout de présenter le concept et de voir les applications possibles.

Pour atteindre mon but, j'ai utilisé la librairie Prototype pour simplifier les appels document.getElementById par $() et Script.aculo.us pour ajouter un effet de transition dans le chargement des images. Le reste est du JS pur. Je peux aussi dire que je l'ai testé uniquement sous Firefox 3 et Internet Explorer 7.

Pour commencer, j'ai défini un conteneur HTML pour la photo et un autre pour le compteur d'images qui apparaîtra au dessous. L'objectif est simplement de créer une boucle qui chargera alternativement les images d'une liste selon un intervalle régulier. La balise <img> servira à recevoir l'image en changeant dynamiquement son attribut source. Le compteur indiquera le numéro de l'image courante et le nombre d'images au total.

<p><img id="picture" src=""></p>
<span id="detail"></span>
On définit en JavaScript le chemin où se trouvent les images et une variable array liste tous les fichiers.
var path = 'images/vacances/';
var pics = new Array(
'001.jpg',
'002.jpg',
'003.jpg',
'004.jpg',
'005.jpg',
'006.jpg',
'007.jpg',
'008.jpg',
'009.jpg',
'010.jpg'
);
On initialise des variables pour indiquer l'image courante (l'indice dans la liste), le nombre total de photos et le temps d'affichage de chacune d'elles.
var currentPicture = 0;
var totalPictures = pics.length;
var showImageSeconds = 4;
Au chargement de la page, je démarre le slideshow en utilisant la notation de Prototype. Ensuite, je charge la première photo en appelant la méthode LoadPicture.
document.observe('dom:loaded', startSlideShow );

function startSlideShow() {
LoadPicture();
}
Dans le conteneur d'image <img>, on remplace la source par le chemin de la première image dans l'array. On met à jour le compteur avec les valeurs courantes en utilisant update() de Prototype, mais on aurait pu le faire aussi bien avec InnerHTML. On fait apparaître l'image avec l'effet Appear de Scriptaculous (qui est l'inverse de Fade) qui dure une seconde. On affiche ensuite l'image quelques secondes selon la variable définie plus haut.
function LoadPicture() {
$('picture').src = path + pics[currentPicture];

// compteur
$('detail').update( (currentPicture + 1) + ' / ' + totalPictures);

Effect.Appear('picture', { duration:1, from:0.0, to:1.0 });
Display(showImageSeconds);
}
Pour afficher l'image un certain temps, j'appelle setTimeout qui me permet d'effectuer une pause avant de montrer la suivante. Lorsque le temps se sera écoulé, la fonction ChangePicture sera appelée.
function Display(sec) {
setTimeout("ChangePicture()", sec * 1000);
}
Lors du changement de photo, on vérifie si l'indice est le dernier de la liste. Si c'est le cas, on revient au début pour afficher la première photo. Un petit effet la fait disparaître et comme on veut voir la transition correctement, on doit attendre une seconde. Le temps de l'effet est spécifié dans la propriété duration alors on fait coïncider l'appel de Wait() pour attendre que l'effet soit terminé avant de changer d'image.
function ChangePicture() {
currentPicture++;
// si c'est la dernière
if (currentPicture == totalPictures )
currentPicture = 0;

Effect.Fade('picture', { duration:1, from:1.0, to:0.0 });
Wait(1);
}
Lorsque l'effet est terminé, on charge la photo suivante.
function Wait(sec) {
setTimeout("LoadPicture()", sec * 1000);
}
En exécutant le code, on devrait voir les images défiler en boucle une à une. Le problème avec ce genre de code procédural, c'est que ça ne forme pas un tout, il n'y a pas d'unité qui relie les variables et fonctions entre elles. Demain, je présenterai une refonte du code en version orientée objet et j'expliquerai le concept des fermetures JavaScript (closures) pour pouvoir créer un objet Slideshow mieux structuré, plus facile à comprendre et à maintenir.


Tags: JavaScript

vendredi 20 mars 2009

Sortie officielle de Internet Explorer 8

Publié par Infinite Loop, à 08 h 56 0 commentaire

Eh oui, Microsoft a enfin lancé officiellement la dernière mouture de son fureteur populaire, Internet Explorer 8. On y propose maintenant une sécurité accrue (protection contre les logiciels malveillants), une confidentialité améliorée, la navigation privée InPrivate, les web slices (abonnement à des portions de site), etc.

L'innovation la plus intéressante est certainement les accélérateurs qui permettent de souligner un bout de texte avec la souris et de lancer une action sur ce terme en utilisant un service en ligne.

Oh, mais attendez! Firefox possédait déjà un plugin du même genre : Select-n-Go by Cleeki.

Malgré tout, je dois avouer être plutôt enthousiaste car je vois dans ce lancement une bonne nouvelle : on s'éloigne de plus en plus d'IE 6 et des maux de têtes qu'il occasionne. Espérons que les utilisateurs effectueront la mise à jour.

En conclusion
En ce 20 mars 2008, je déclare que IE8 est certainement le meilleur fureteur depuis Netscape 5... Et vous, quels sont vos pronostics ?


Tags: Extensions Firefox

jeudi 19 mars 2009

Convertir l'encodage d'une page avec Dreamweaver

Publié par Infinite Loop, à 20 h 11 3 commentaires

Avec les années, j'ai pris l'habitude de développer mes projets web en utilisant l'encodage de caractères UTF-8. Non seulement les pages web sont enregistrées au format Unicode, mais les fichiers JavaScript et la base de données le sont aussi.

Avec le temps, j'ai ajouté des scripts à ma librairie principale de code et je ne me suis pas posé de question puisqu'ils étaient tous au standard Unicode. Jusqu'à ce que j'aie à effectuer une refonte et un refactoring d'un vieux projet encodé en ISO-8859-1 que je voulais migrer en UTF-8... Ouf! Je comptais bien améliorer le code en utilisant Prototype ou jQuery, un peu de Ajax et ce en espérant ne pas rencontrer de conflits d'encodage. Mon problème principal a été au niveau des textes statiques, où les caractères accentués étaient tous intégrés en utilisant les entités HTML (é pour é). Alors comment pouvoir convertir automatiquement tous ces caractères spéciaux dans les pages de mon projet pour qu'ils respectent la norme Unicode ?

Que ce soit pour convertir du format ISO à UTF-8 ou le contraire, Adobe Dreamweaver offre la possibilité de le faire d'un seul coup. Contrairement à d'autres éditeurs qui ne permettent d'enregistrer que sous un autre type d'encodage, Dreamweaver va un peu plus loin et convertit les entités d'un format à un autre.

Pour convertir une page existante :

  • Menu Modify
  • Page Properties
  • Title / Encoding
  • Choisir le nouveau format (par exemple Europe Occidentale ou UTF-8)
Non seulement la page sera enregistrée avec le nouvel encodage, mais DW remplacera aussi automatiquement la valeur du charset dans le meta tag :

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

On pourra aussi spécifier l'encodage à utiliser lors de la création des nouveaux documents :
  • Menu Edit
  • Preferences
  • New Document
  • Default encoding
  • Choisir dans la liste déroulante "Europe Occidentale" ou "UTF-8"
Au meilleur de mes connaissances (et de ma mémoire), ce type de conversion est possible depuis au moins Dreamweaver 8 jusqu'à la plus récente CS4.


Tags: Intégration

mercredi 18 mars 2009

Comparaison de texte PostgreSQL

Publié par Infinite Loop, à 19 h 38 1 commentaire

La base de données PostgreSQL offre plusieurs opérateurs utiles pour effectuer des comparaisons.

Opérateur =
Pour comparer de façon exacte deux chaînes de caractères :

SELECT * FROM table WHERE field = 'code18'

LIKE
Le mot réservé LIKE est standard dans le monde des bases de données. Il permet de vérifier si le texte comparé respecte partiellement un pattern :

commence par : WHERE title LIKE 'code%'
se termine par : WHERE title LIKE '%18'
contient : WHERE title LIKE '%code%'

ILIKE
Semblable à LIKE, ILIKE permet de faire la même comparaison mais en ne tenant pas compte de la casse (case insensitive) :

WHERE title LIKE '%CoDe%' -- ne trouvera pas "code18"
WHERE title ILIKE '%CoDe%' -- le trouvera

SIMILAR TO
Permet d'utiliser un pattern qui combine, comme pour LIKE, les wildcards _ (n'importe quel caractère unique) et % (n'importe quoi) :

WHERE encoding SIMILAR TO '[a-zA-Z0-9]%'
WHERE encoding SIMILAR TO '%utf-(8|16)%'

Ici, '%utf-*(8|16)%' est équivalent à '%utf-%(8|16)%'.

Expression régulière POSIX
Ou encore utiliser des expressions régulières. Un opérateur équivalent existe au pour case insensitive (~*) :

WHERE song_title ~ '^[0-9]+'

Résultats :
99 Luftballoons - Nena
3ème avertissement - Miriodor
100,000 People - Philip Glass

Accent Insensitive ?
Malheureusement, malgré la version 8.3 de PostgreSQL, il n'y a toujours aucune trace d'une recherche insensible aux accents. On peut certainement partenir à quelque chose en convertissant le texte avec to_ascii() mais avec certains encodages comme UTF-8, ce n'est pas supporté correctement. Un workaroung possible serait de créer une fonction qui remplace les accents pour pouvoir effectuer la comparaison. Aujourd'hui, Thom Brown a proposé sur la liste de diffusion de Postgre une fonction appelée unaccent_string :

CREATE OR REPLACE FUNCTION unaccent_string(text)
RETURNS text AS $$
my ($input_string) = @_;
$input_string =~ s/[âãäåaaa]/a;
$input_string =~ s/[ÁÂÃÄÅAAA]/A;
$input_string =~ s/[èééêëeeeee]/e;
$input_string =~ s/[EEEEE]/E;
$input_string =~ s/[ìíîïìiii]/i;
$input_string =~ s/[ÌÍÎÏÌIII]/I;
$input_string =~ s/[óôõöooo]/o;
$input_string =~ s/[ÒÓÔÕÖOOO]/O;
$input_string =~ s/[ùúûüuuuu]/u;
$input_string =~ s/[ÙÚÛÜUUUU]/U;
return $input_string;
$$ LANGUAGE plperl;

Appel :
WHERE unaccent_string(address) ILIKE unaccent_string('Montréal')

Finalement, une piste de solution viendra peut-être éventuellement dans une version ultérieure avec Text Search Configuration.


Tags: PostgreSQL

mardi 17 mars 2009

Lister les fichiers d'un répertoire en PHP

Publié par Infinite Loop, à 20 h 37 1 commentaire

Dans les beaux jours de PHP 4, si on voulait parcourir et lister le contenu d'un répertoire, on devait s'y prendre comme ceci :

$directory = '/path/to/files';

if ($handle = opendir( $directory )) {
while ($file = readdir($handle)) {
if ($file != '.' && $file != '..') {
echo $file;
}
}
closedir($handle);
}
On peut encore utiliser cette bonne vieille méthode, mais PHP 5 a introduit dans son SPL la classe DirectoryIterator qui est beaucoup plus facile à comprendre. Voici le même bout de code traduit à la façon PHP 5.
$iter = new DirectoryIterator( $directory );
foreach($iter as $file ) {
if ( !$file->isDot() ) {
echo $file->getFilename();
}
}
L'objet $file possède plusieurs méthodes pour nous simplifier la vie, comme par exemple getPath, getPathName, getSize, isDir, isFile, isDot, isExecutable, isReadable et isWritable.

En revanche, si le répertoire contient d'autres dossiers à parcourir, il suffit d'utiliser la classe RecursiveDirectoryIterator.
$iter = new RecursiveDirectoryIterator( $directory );
foreach (new RecursiveIteratorIterator($iter) as $file) {
echo $file->getPath() . ' [' . $file->getFilename() . ']';
}
Dans les deux derniers cas, on peut parcourir la liste à l'aide d'un foreach puisque les deux classes implémentent l'interface Iterator, un pattern populaire.


Tags: PHP

lundi 16 mars 2009

Pages 404 originales

Publié par Infinite Loop, à 21 h 08 0 commentaire

Ce midi, j'ai commandé un livre en ligne et je suis tombé par hasard sur la page 404 d'Amazon.ca et l'image Kailey Kitty.

Par définition, une page 404 correspond à la réponse HTTP pour indiquer que la page demandée est introuvable. C'est généralement le genre de page qui ne mérite aucune attention de la part des visiteurs car elle n'affiche qu'un simple "404 Not Found".

Cependant, le web étant un endroit où tout est possible, certains se sont amusés à rendre la chose plus amusante.

Voici deux galeries d'images de pages 404 très originales publiées par Smashing Magazine :

  • 404 error pages - reloaded
  • 404 error pages - one more time


Tags: Curiosités

dimanche 15 mars 2009

Erreur curieuse en PHP : Paamayim Nekudotayim

Publié par Infinite Loop, à 11 h 18 2 commentaires

Avez-vous déjà rencontré l'erreur T_PAAMAYIM_NEKUDOTAYIM ? Drôle de nom n'est-ce pas ? Cette constante PHP est utilisée pour définir l'opérateur de résolution de portée "::" (scope resolution operator), comme par exemple dans le cas suivant :

Classe::element
"Parse error: parse error, expecting 'T_PAAMAYIM_NEKUDOTAYIM' in ..."

Évidemment, quand on rencontre ce type d'erreur, le nom n'est pas très explicite et il faut fouiller pour comprendre le message. Il faut savoir qu'en hébreux, Paamayim veut dire "double / twice" et Nekudotaim est "colon", donc on fait référence à l'opérateur ::. En remontant plus loin dans l'histoire du développement, on découvre que Andi Gutmans and Zeev Suraski, les créateurs du Zend Engine de PHP et Zend Technologies, sont israéliens et ont étudié au Technion Israel Institute of Technology. D'ailleurs, le nom Zend est vient de la fusion de leurs prénoms : ZEev et aNDi.

Ça explique certaines choses. Mais pourquoi ne pas avoir standardisé les noms en anglais et avoir conservé celle-ci ? En fait, la question est aussi de savoir s'il existe d'autres noms curieux utilisés dans les entrailles du code source C. Alors cherchons les!

Sur la page de téléchargement de PHP, j'ai téléchargé le code source complet, php-5.2.9.tar.gz, soit l'archive stable la plus récente. Après l'avoir extraite, je me suis débrouillé pour utiliser une combinaison des commandes grep et sed pour effectuer les recherches.

D'abord, j'ai voulu obtenir la liste des fichiers et leurs lignes où on trouvait des constantes dont le nom débutait par T_. J'ai utilisé grep avec les options de recherches récursives (-r) dans les sous-répertoires et j'ai spécifié la recherche de mots complets (-w). Ensuite, j'ai défini une simple expression régulière et j'ai envoyé le résultat dans un fichier :

grep -r -w ^.*\bT_.*\b php-5.2.9 > all_lines_with_t_.txt

À partir du résultat, j'ai lancé la commande sed pour extraire les constantes trouvées. J'ai utilisé une regexp (-e), la substitution (s/old/new/) et la capture de pattern (\1).

sed 's/^.*\(\bT_\w*\b\).*$/\1/' all_lines_with_t_.txt > all_t.txt

Finalement j'ai effectué un tri avec filtre unique (sort -u) sur le fichier pour ne conserver qu'une seule occurence de chaque constante. Si vous êtes sous Windows, faites attention car il y a une autre fonction sort native. Assurez-vous d'utiliser celle Unix (Cygwin ou UnxUtils).

sort -u all_t.txt > sorted.txt

En jetant un coup d'oeil au fichier final, on peut noter 137 constantes différentes mais la seule qui porte un nom bizarre est T_PAAMAYIM_NEKUDOTAYIM. Ok, j'avoue que je ne sais pas encore ce que T_MX et T_FMT_AMPM veulent dire mais ce sont certainement des abréviations.

Qu'est-ce que ça représenterait de changer toutes ces constantes par un nom plus explicite ? J'imaginais pouvoir y arriver en le remplaçant par T_DOUBLE_COLON mais cette constante existe déjà dans un autre contexte. Alors pourquoi ne pas utiliser T_SRO ou T_SCOPE_RESOLUTION_OP ?

Pour trouver toutes les occurences de la constante dans l'ensemble du code source :

grep -r -w T_PAAMAYIM_NEKUDOTAYIM php-5.2.9 > paamayim_occurences.txt

Seulement 66 occurences trouvées. Ça devrait pouvoir se remplacer facilement.


Tags: Curiosités, PHP

Citation no. 21 sur les mots de passe

Publié par Infinite Loop, à 09 h 19 0 commentaire

Les mots de passe sont comme les sous-vêtements : on devrait les changer souvent, ne pas les exposer en public et ne jamais les donner à des étrangers.

- Le gros bon sens


Tags: Citations

samedi 14 mars 2009

Manipuler une archive TAR compressée (gzip)

Publié par Infinite Loop, à 08 h 41 0 commentaire

L'autre jour, j'ai démontré comment manipuler les archives tarball à partir d'une ligne de commande mais le sujet était loin d'être complet si je n'abordais pas la question de la compression, l'idée étant de réduire au maximum la taille de l'archive en utilisant un algorithme de compression comme gzip ou bzip2.

Par exemple, en téléchargeant le code source php-5.2.9.tar.gz (12 Mo), on remarque que le fichier porte l'extension .tar .gz, ce qui est une convention pour indiquer que que le tarball est compressé en utilisant gzip.

Avant de pouvoir extraire l'archive, la première étape consistera à la décompresser :

gunzip -c php-5.2.9.tar.gz > unzipped.tar

-c permet de contrôler la sortie pour pouvoir ensuite l'envoyer dans un nouveau fichier que je nomme unzipped.tar. Autrement, si -c et > ne sont pas spécifiés, l'archive sera décompressée et écrasera le fichier original.

Ensuite, on pourra l'extraire l'archive unzipped.tar (70 Mo) :

tar -xf unzipped.tar

Patientez un moment car l'archive contient plus de 10000 fichiers.

On peut aussi combiner les deux commandes une à la suite de l'autre :

gunzip < php-5.2.9.tar.gz | tar xf -

Remarquez le symbole - à la fin.


Tags: Coffre à outils

vendredi 13 mars 2009

Une histoire de pixel brûlé

Publié par Infinite Loop, à 19 h 21 0 commentaire

Dimanche dernier, j'ai fait l'achat d'un ordinateur portatif Toshiba Satellite chez Future Shop. Les caractéristiques semblaient intéressantes :

  • écran de 15,4 po
  • disque dur de 250 Go
  • 3 Go de mémoire vive
  • processeur Intel à double coeur cadencé à 2,16 GHz
  • caméra numérique
  • graveur DVD double couche
  • lecteur de cartes
  • système d'exploitation bilingue
  • une garantie d'un an du fabricant
  • le tout pour 700$ (avant taxes)
En me voyant magasiner, un vendeur s'approcha et me proposa de faire l'acquisition du même modèle en boîte ouverte, c'est-à-dire un produit neuf qu'un client a retourné, au même prix qu'une boîte emballée, mais il bonifia son offre en ajoutant gratuitement une garantie prolongée de deux ans d'une valeur de 159,99$, en plus de m'offrir des accessoires à moitié prix (souris et sac de transport). Si j'étais intéressé, je pouvais ajouter une troisième année de garantie pour seulement 30$ (valeur totale de 259,99$).

En y réfléchissant un peu, ce n'était pas un gros risque, d'autant plus que la garantie couvrait les produits citrons. Je lui ai donc demandé l'autorisation de vérifier son fonctionnement avant de prendre une décision. À première vue, l'esthétique de l'ordinateur était impeccable et il y avait même certains autocollants de protection originaux. Il démarrait sans problème et tout semblait dans l'ordre. Jusqu'à ce que je remarque dans le haut de l'écran une marque qui était dissimulée sous des traces de doigts. J'ai essayé de le montrer au vendeur mais même en tentant de l'essuyer, il semblait incapable de voir la même chose que moi.

J'ai pris une chance et j'ai décidé d'acheter le portable quand même. De toute façon, le vendeur disait que si je remarquais quelque chose après l'achat et que je n'étais pas satisfait, je pouvais le retourner dans les 14 jours. En cas de problème, l'appareil serait réparé et en cas de trois retours, il serait échangé contre un produit neuf équivalent.

Arrivé chez moi, j'ai eu le réflexe de mettre un fond d'écran uni pour détecter plus facilement les pixels brûlés. Sans surprise, ce que j'avais cru voir était bel et bien un pixel éteint. Une autre déception a été que l'ordinateur était supposé avoir été réinitialisé comme s'il sortait de l'usine. Or, le système d'exploitation était en français et il n'y avait aucun moyen de revenir en arrière et d'installer le OS en anglais. C'est un détail qui m'agace car comme mes applications sont anglaises, si je les utilise sur un OS en français, certains menus et options sont affichés dans les deux langues en même temps. L'utiliser en anglais a aussi l'avantage de trouver plus facilement de documentation et d'aide sans avoir besoin de traduire les termes.

Pour Windows, l'explication que j'ai trouvé est qu'en usine, une partition a été réservée pour contenir les deux versions du système d'exploitation. Lors de la première ouverture de l'ordinateur, on doit choisir la langue à installer et la partition se supprime automatiquement par la suite. Et comme Windows est pré-installé, le portable ne vient pas avec le CD d'installation.

En y réfléchissant, j'ai eu le raisonnement suivant :
  • Dans le cas des boîtes ouvertes, combien de fois un produit peut-il être retourné au magasin et revendu à la clientèle ?
  • Combien de clients ont eu entre les mains ce même ordinateur ?
  • Il paraît qu'un pixel brûlé se répare. Mais si l'appareil est neuf et qu'il a déjà des problèmes, est-ce un défaut de fabrication ? Quelles autres surprises m'attendent ? Devrais-je l'apporter à chaque fois pour le faire réparer et attendre parfois plusieurs semaines pour le recevoir ?
  • Selon les termes de la garantie, suite à un échange, la garantie se termine automatiquement. Est-ce qu'un pixel peut justifier la défectuosité que couvre la garantie ? Après tout, ce n'est que de l'affichage...
  • Si je profite de la garantie après avoir été quelques jours en possession du portable, j'aurais payé 30$ supplémentaires pour rien pour ajouter une troisième année de garantie. À ce prix-là, j'aurais été mieux d'en acheter un neuf.
  • Comme on m'a donné la garantie, sa valeur est soustraite de la valeur de l'ordinateur. Donc le coût du laptop diminue à 440$ (surprise!). En cas d'échange, c'est la valeur que j'aurais eu pour en choisir un nouveau. Et à ce prix, les portables se font rares, sont peu puissants et de moindre qualité.
  • Je me suis souvenu que mes achats portés à ma carte Visa m'offre gratuitement de doubler la garantie de réparation du fabricant jusqu'à concurrence d'une année supplémentaire.
  • Enfin, le meilleur choix est certainement le retour et le remboursement de la marchandise. Surtout pour avoir l'esprit tranquille.
Au retour, on m'a fait passer au comptoir informatique. Le technicien chargé de la vérification du matériel s'est assuré qu'aucun accessoire n'était manquant et que le produit n'était pas endommagé, même s'il n'a jamais démarré l'ordinateur. Pour ma part, je n'avais rien à me reprocher car je l'avais utilisé que pour le vérifier et il était dans le même état que lorsque je l'avais reçu. Mais bon, j'aurais pu tomber sur un employé qui fait du zèle...

Au final, je n'ai eu aucun problème à me faire rembourser mais malheureusement, quelqu'un d'autre sera pris avec ce défaut...


Tags: Le coin du geek

jeudi 12 mars 2009

Il n'y a pas d'Easter Eggs dans ce programme

Publié par Infinite Loop, à 19 h 54 0 commentaire

Dans certaines distributions Linux comme Ubuntu et Kubuntu, il y a une commande nommée "apt-get" et une autre qui porte le nom "aptitude" qui permettent d'installer les packetages et ses dépendances.

On obtiendra le résultat suivant si on lance cette commande :

~$ apt-get moo

        (__)
(oo)
/------\/
/ | ||
* /\---/\
~~ ~~

...."Have you mooed today?"...
Alternativement, si on lance aptitude avec l'argument -v (pour afficher des informations supplémentaires) :

~$ aptitude -v moo

Il nous répondra :
There really are no Easter Eggs in this program.

~$ aptitude -vv moo

Didn't I already tell you that there are no Easter Eggs in this program?

Un oeuf de pâque pour dire qu'il n'y en a pas ?


Tags: Easter Eggs

mercredi 11 mars 2009

Adresse de courriel temporaire jetable

Publié par Infinite Loop, à 18 h 42 3 commentaires

Avec la popularité des services de profilage sur le web, les sites demandent constamment aux visiteurs de s'inscrire pour pouvoir visualiser du contenu. Que ce soit pour participer à un forum de discussion ou s'abonner à un site de référence quelconque, une fois qu'on a fourni notre courriel, on finit tôt ou tard par recevoir du spam de leur part. Dans mon cas, ce que je déteste le plus est de devoir laisser mon adresse courriel pour pouvoir télécharger la démo d'une application où le lien de téléchargement est transmis par courriel. On ne sait jamais dans quelles mains se retrouve nos informations.

À chaque fois que j'ai un doute sur la crédibilité d'un service, je m'arrange pour founir une adresse courriel temporaire (jetable) à partir d'un des services ci-dessous. Ainsi, je n'ai plus à me soucier d'être importuné dans le futur par des publicités de toutes sortes que je n'ai pas sollicité. Par contre, s'il s'agit d'une entreprise reconnue ou si le produit / service m'intéresse vraiment, je me permets de laisser ma véritable adresse. C'est surtout une question de précaution contre les sites douteux.

Voici quelques variantes de services gratuits :

  • No Spam For Us
  • SpamBox : permet de créer un alias actif jusqu'à un an qui redirige les courriels vers votre adresse courriel
  • Halto Spam : crée un alias sur son adresse courriel pour une durée de 7 jours
  • Mailinator : j'aime bien leur domaine alternatif "@thisisnotmyrealemail.com"
  • 10 minute mail : un autre bon service temporaire
  • Anonym Box : durée de 12 heures
  • MailCatch


Tags: Coffre à outils

Bande dessinée sur la sécurité informatique

Publié par Infinite Loop, à 14 h 11 0 commentaire

L'entreprise CoSoSys a créé une bande dessinée en 6 langues (dont français et anglais) pour sensibiliser le public à la sécurité informatique. Excellente initiative!

Endpoint Security Adventures - Comic Series


Tags: Sécurité

mardi 10 mars 2009

Populer un formulaire automatiquement

Publié par Infinite Loop, à 18 h 43 1 commentaire

Dans l'univers de la programmation web, une des actions les plus fréquentes est de remplir un formulaire pour tester l'envoi des données et les enregistrer dans une base de données. Pour nous faciliter la vie, voici deux extensions Firefox qui permettent de remplir un formulaire automatiquement.

Web Developer Toolbar
Dans Web Developer Toolbar, on peut utiliser une option pour remplir automatiquement les champs d'un formulaire. WDT extraira le nom de chaque champ et utilisera le texte pour populer la valeur.

Ici, le texte saisi sera "firstname" :

<input type="text" id="firstname" name="firstname" value="" />
Si l'input porte un nom qui contient le terme "email", il remplira ce champ avec une adresse courriel (par défaut example@example.com). Vous pourrez personnaliser le courriel avec le vôtre en accédant au menu Options / Options / Miscellaneous / Encadré Forms.

Selenium IDE
L'autre possibilité, beaucoup plus flexible, est d'utiliser l'extension Selenium, de loin une de mes préférées. Selenium possède une nette avance sur WDT : on peut enregistrer nos actions sur un formulaire, l'information exacte saisie, les événements déclenchés, etc, et créer un test case / test suite. Par exemple, on pourra facilement remplir les différents champs du formulaire avec les valeurs désirées, effectuer des choix dans des listes déroulantes, lancer des appels Ajax, cocher des cases, cliquer sur des contrôles et soumettre le formulaire, tout ça d'un seul coup.

Avouez que c'est génial et que ça peut nous faire sauver beaucoup de temps. Donc, moins de temps à remplir des formulaires et à tester et plus de temps à passer sur ce que l'on aime vraiment : programmer.

Pour bien démarrer avec Selenium, installez l'extension et démarrez la à partir du menu Tools / Selenium IDE. Une fois lancée, repérez le bouton rouge dans le coin supérieur droit : c'est le bouton qui vous permettra de démarrer l'enregistrement des actions.

D'abord, rendez-vous sur le formulaire de votre choix.
  • Entrez l'URL du formulaire dans la case Base URL
  • Créez un nouveau Test Case et donnez lui un nom (clic droit de la souris / Properties)
  • Démarrer l'enregistrement en cliquant sur le bouton rouge
  • Dans le formulaire, saisissez l'information normalement
  • Soumettez le formulaire
  • Cliquez à nouveau sur le bouton rouge pour terminer l'enregistrement des actions
  • Ouvrez un nouvel onglet dans Firefox et accédez à nouveau au formulaire vierge
  • Exécutez l'ensemble des actions en cliquant sur le bouton Play Current Test Case
  • Admirez l'automatisation
Si le formulaire fait des appels Ajax, comme c'est asynchrone, on ne sait pas exactement à quel moment la réponse nous parviendra, c'est préférable de procéder à une exécution lente du test case. Ajustez la vitesse en utilisant la barre coulissante (slider) de Fast à Slow (coin supérieur gauche).

N'oubliez pas d'enregistrer vos tests pour une utilisation future. Mieux encore, vous pouvez exporter automatiquement vos tests pour PHPUnit. Menu File / Export Test Case As / PHP Selenium RC (Java, C#, Perl, Python et Ruby aussi disponibles).


Tags: Coffre à outils, Extensions Firefox

lundi 9 mars 2009

Interface countable en PHP

Publié par Infinite Loop, à 19 h 44 0 commentaire

En PHP, l'interface interne la plus simple à implémenter est sans aucun doute countable, qui est fournie de façon native avec la SPL (Standard PHP Library). Comme son nom l'indique, une classe qui implémente l'interface countable doit pouvoir être en mesure de compter ses items qui la compose.

Cette interface est simple car elle ne nécessite que l'implémentation de la méthode count(). Autrement dit, la classe que vous créez doit simplement posséder une fonction count() qui retourne le nombre d'éléments.

À la base, on sait qu'on peut compter les éléments d'une liste (array) :

echo count($arr);
En utilisant un exemple tiré du site php.net, on voit que la représentation interne des données pourrait simplement être un entier statique :
class myCounter implements Countable {
public function count() {
static $count = 0;
return ++$count;
}
}
En définissant une autre classe pour gérer une liste d'épicerie, on pourrait conserver la liste de n'importe quelle façon. Ici, j'ai utilisé un array pour la représentation interne mais ça aurait pu être n'importe quoi.
class GroceryList Implements Countable {
private $someData;

public function __construct() {
$this->someData = array();
}

public function add($pItem, $pQty) {
$this->someData[] = array('name' => $pItem, 'qty' => $pQty);
}

public function count() {
$count = 0;
foreach($this->someData as $item) {
$count += $item['qty'];
}
return $count;
}
}
Si je n'avais pas mis "Implements Countable" dans la définition de ma classe, count() n'aurait pas pu déterminer le nombre d'items dans la liste interne et aurait retourné 1 (1 étant l'objet lui-même. Sa méthode count() ne serait pas appelée). Dans ce cas, j'aurais pu utiliser $gl->count(); pour obtenir le bon nombre. Question de standardiser les objets qui se comptent, on est mieux d'implémenter countable.
// type 1
$list = array(1,2,3,4,5);

// type 2
$counter = new myCounter;

count($counter); // 1
count($counter); // 2
count($counter); // 3

// type 3
$gl = new GroceryList();

$gl->add('Hamburger buns', 12);
$gl->add('Ground beef', 2);
$gl->add('Relish', 1);
$gl->add('Ketchup', 1);
$gl->add('Mustard', 1);

// créer une liste qui contient différents objets qui peuvent se compter :
$countables = array();
$countables[] = $gl;
$countables[] = $list;
$countables[] = $counter;

foreach ($countables as $cnt) {
echo count($cnt);
}
Dans l'exemple ci-dessus, tous les objets peuvent être comptés, ce qui permet de boucler sur tous les types d'objets qui se comptent (array, myCounter, GroceryList) puisque la méthode count() et commune et uniforme.


Tags: PHP

dimanche 8 mars 2009

Conteneurs HTML à coins ronds

Publié par Infinite Loop, à 21 h 11 0 commentaire

C'est reconnu qu'un programmeur qui effectue de l'intégration fera généralement un travail douteux. On doit se l'avouer, pour la plupart, nous n'avons pas l'oeil. C'est pourquoi j'apprécie les librairies graphiques qui me simplifient la vie comme script.aculo.us et Open Rico. Dans le cas de Rico, l'avantage que j'en tire est de pouvoir générer des conteneurs à coins ronds (rounded corners) en quelques lignes de code, et par programmation, pour mon plus grand bonheur.

On doit d'abord charger sa librairie principale (rico.js) et la dépendance à prototype.js. Ensuite, on chargera dynamiquement l'extension "Corner" et on appliquera la transformation sur les conteneurs désirés en utilisant les ID.

<script src="js/prototype/1.6.0.3/prototype-1.6.0.3-min.js"></script>
<script src="js/rico2/src/rico.js" type="text/javascript"></script>
<script type='text/javascript'>
Rico.loadModule('Corner');
Rico.onLoad( function() {
Rico.Corner.round('conteneur1');
});
</script>
La fonction round() peut aussi recevoir des paramètres optionnels qui indiquent le type de coins à utiliser, la couleur de la bordure (s'il y a lieu) et quels coins on doit arrondir.

On y ajoute un peu de CSS pour rendre le tout joli. En plus de définir une classe "card" qui représente le conteneur principal, j'en crée une deuxième qui me permettra d'avoir un meilleur contrôle sur le détail que contiendra le conteneur.
body {
font-family: verdana;
font-size:12px;
}

div.card {
background-color: #cecece;
float:left;
margin:0;
padding:0;
width:400px;
min-height:150px;
height:150px;
}

div.card-detail {
height:100%;
}
Un exemple de conteneur qui sera transformé :
<div id="conteneur1" class="card">
<div class="card-detail">
</div>
</div>
Quelques recommandations :
  • attention de ne pas appeler round() deux fois sur le même item...
  • faites gaffe avec les bordures et l'application des classes CSS avec Internet Explorer. Ça peut être désastreux.
  • sous IE, assurez-vous d'appliquer la bordure à l'aide des options Rico et pas avec le CSS. Autrement, le CSS risque d'être appliqué au rectangle et la bordure pourrait sembler brisée dans les coins
  • encore avec IE 7, le seul truc que j'ai trouvé pour pouvoir spécifier la hauteur du conteneur comme il faut a été de mettre un conteneur à l'intérieur du conteneur principal avec une hauteur de 100% (comme l'exemple ci-dessous) et un min height au div principal.
Tout comme script.aculo.us, Rico possède aussi des fonctionnalités de drag and drop et des effets graphiques mais la transformation en coins ronds avec Rico est la seule portion que j'utilise en complément pour le moment.


Tags: Intégration, JavaScript

Citation no. 20 sur les consommateurs mécontents

Publié par Infinite Loop, à 09 h 41 0 commentaire

Your most unhappy customers are your greatest source of learning.

- Bill Gates


Tags: Citations

samedi 7 mars 2009

Conférence PHP Québec 2009 - Jour 3

Publié par Infinite Loop, à 09 h 40 1 commentaire

Dernière journée de la conférence PHP. Au programme, plusieurs sessions intéressants :

  • Building PHP Powered Android Applications (téléphones mobiles).
  • Growing a Development Team While Building a Huge App at 500 miles/hour (avec Owen Byrne, co-fondateur de Digg, maintenant avec TravelPod Labs, qui appartient à TripAdvisor). J'adore sa biographie sur Twitter : The person who "built digg for $1000 @ $10/hour".
  • Git et le renouveau du contrôle de versions. Une alternative intéressante à Subversion.
  • K.I.S.S. (Keep It Simple, Stupid). Trop souvent négligé.
  • Laboratoire sécurité : audit de code PHP en deux parties.
  • La clinique de Regex d'Andrei. Un tour complet de la puissance des expressions régulières. J'espère que sa présentation sera disponible en téléchargement sur le site de PHPQuébec.
  • PHP Worst Practices (il y avait aussi une autre session nommée Bonnes pratiques en un clin d'oeil).
  • PHP 5, Ajax avec jQuery et JSON.
Durant l'heure du dîner, il y avait à nos tables des ballons et les instructions pour pouvoir se pratiquer à construire un éléphant (comme les petits caniches dans les fêtes pour enfants). Pour ceux moins familiers avec l'univers PHP, l'éléPHPant est souvent illustré en tant que mascotte du langage. À la fin du repas, les organisateurs tiraient au hasard 5 participants qui devaient se présenter à l'avant pour reproduire l'éléphant en moins de 5 minutes. Le gagnant se méritait un iPod touch. La gagnante a réalisé son oeuvre à l'intérieur de quelques secondes seulement. Il faut croire qu'elle a été clown dans une autre vie!

La journée s'est terminée par une session commune dans la salle principale où Chris Shiflett a fait une présentation sur le design axé sur la sécurité. C'était léger et peu technique (tant mieux) mais ses exemples étaient introduits par des jeux de photos et de vidéo qui illustraient ses propos. Si vous n'avez pas entendu parler de l'exploit de Twitter "Don't Click", je vous réfère vers son blogue pour en savoir plus.

Pour clôturer la conférence, il y a eu un petit tirage d'une dizaine de prix de présence : livres, peluches elePHPant, laisser-passer pour la conférence PHP Québec 2010, etc. Les intéressés pouvaient ensuite aller faire la fête aux 3 Brasseurs et en profiter pour regarder sur écran géant le match (détaite) du Canadiens. Et ce matin, ceux qui avaient encore de l'énergie pouvaient participer à la sortie annuelle à la cabane à sucre. C'est exactement pour cette raison que je suis présentement chez moi :-)


Tags: PHP

vendredi 6 mars 2009

Manipuler une archive TAR

Publié par Infinite Loop, à 07 h 15 0 commentaire

La semaine dernière, en téléchargeant un tarball (.tar) de Smarty, j'ai eu l'idée d'aborder le sujet des archives. Trop souvent, les utilisateurs se tournent vers les interfaces graphiques pour réaliser le travail à leur place alors que pourtant, ça se résume en une seule ligne à exécuter par l'invite. Je ne peux pas en vouloir à monsieur et madame tout le monde, mais les développeurs et les gens qui travaillent dans les technologies de l'information (TI) devraient être en mesure de pouvoir faire cette opération alternative.

Pour commencer, un tarball représente un fichier d'archive qui contient plusieurs fichiers réunis ensemble (comme un zip) et qui peut être décompressé pour récupérer les fichiers originaux. Son nom provient de Tape ARchive puisque qu'il a toujours été utilisé pour des fins de distribution et d'archivage.

Extraire le contenu d'une archive TAR
En prenant pour exemple l'archive Smarty-2.6.22.tar, voici la ligne de commande la plus simpliste à exécuter pour extraire les fichiers :

tar -xf Smarty-2.6.22.tar

où l'option -x indique qu'on veut extraire l'archive et -f (combiné -xf) spécifie le nom de l'archive à traiter. On voit parfois l'utilisation de -v (-xvf) pour lister les fichiers au moment de l'extraction.

Créer une archive TAR
En prenant pour acquis que l'archive Smarty ait été extraite dans un répertoire du même nom que le tarball original, on pourrait réutiliser les fichiers du répertoire pour créer un nouveau tarball.

tar -cf Smarty-new.tar Smarty-2.6.22/

où l'option -c indique qu'on veut créer une archive et -f est encore présent pour spécifier le nom du fichier. On indique ensuite le nom du répertoire source.

Plutôt que d'utiliser un répertoire, on peut aussi spécifier les fichiers individuellement :

tar -cf archive.tar fichier1 fichier2 fichier3

Lister les fichiers à l'intérieur d'un TAR
En tout temps, on pourrait vouloir consulter le contenu d'un tarball. Avant de l'extraire, on peut utiliser une autre commande qui listera simplement le contenu :

tar -tf archive.tar

On utilisera l'option -t pour indiquer qu'on souhaite connaître la liste des fichiers de l'archive et encore une fois -f pour spécifier le nom du fichier à observer.


Tags: Coffre à outils

jeudi 5 mars 2009

Conférence PHP Québec 2009 - Jour 2

Publié par Infinite Loop, à 22 h 09 0 commentaire

Pour cette deuxième journée à la conférence PHP Québec, la journée a débuté un peu plus tard que la veille, soit à 8h30. 30 minutes de sommeil bien appréciées, d'autant plus qu'avec le salon emploi qui se tenait en fin de journée, ça s'annonçait une grosse journée.

Depuis le début, je comptais bien assister à la session "PHP 5.3" par Johannes Schlüter, un développeur de Sun qui travaille sur le projet MySQL mais qui est aussi parmi les responsables de la version 5.3 de PHP. J'avais déjà lu un peu sur les nouvelles fonctionnalités intégrées (support unicode, namespaces, closures, etc.) et c'était intéressant d'écouter ce qu'avait à dire un acteur de premier plan impliqué dans son développement.

En guise d'entrée avant le dîner, John Coggeshall a fait une présentation (Beyond the Browser) pour expliquer que le web fait du sur place depuis plusieurs années en raison du fureteur. Son discours suggérait que le web se dirigera vers l'ajout de vues différentes parmi lesquelles le fureteur ferait (entre autre) parti. Il a aussi noté les lacunes des applications web qui s'exécutent à travers un fureteur et qui ne peuvent intégrer de support matériel, comme par exemple la possibilité d'utiliser des lecteurs de codes barres, imprimantes, etc. Ce sera vraisemblablement le prochain gros défi.

Au menu midi, le repas était encore une fois excellent mais je n'ai pas eu l'embarras du choix pour le dessert... Un peu oublié la veille, le mot s'est passé et tout le monde en a profité avant qu'il n'en reste plus.

Pour occuper mon après-midi, j'ai choisi de participer à l'atelier Design Patterns. Plusieurs provenaient de ceux répertoriés par la Gang of Four (Gof) : 5 modèles de conception de création (Factory, Abstract Factory, Builder, Prototype et Singleton), 7 de structure (Adapter, Bridge, etc.) tandis que le conférencier en a aussi présenté quelque uns d'architecture d'entreprise de Martin Fowler (Active Record, DAO, Lazy Load, MVC, Front Controller, 2 step view). D'ailleurs, ses livres ainsi que Design Patterns sont certainement des lectures fortement recommandées. Mais tenez-vous en à la version originale, nous dit-on; la version française est horrible!

Pour terminer la journée, j'ai fait un peu de réseautage social durant le 5 à 7, en sirotant un verre, sans vraiment porter attention aux chasseurs de têtes et aux kiosques des employeurs... quoi que la présence de membres des Forces Armées Canadiennes m'a intrigué un bout de temps. Mais rassurez-vous, j'ai su résister à la tentation d'aller les voir. Pour les autres entreprises, de jolies demoiselles étaient présentes pour rencontrer les candidats à l'emploi. Chose certaine, c'est un bon truc pour attirer un public majoritairement masculin.


Tags: PHP

mercredi 4 mars 2009

Conférence PHP Québec 2009 - Jour 1

Publié par Infinite Loop, à 19 h 45 0 commentaire

Je me suis levé de bonne heure ce matin car je devais me préparer pour aller à la place Bonaventure (Montréal) pour assister à la conférence PHP Québec 2009. Comme je n'avais pas pu y être la dernière fois, j'attendais ce moment avec hâte.

À l'arrivée, on devait procéder à l'inscription où on nous remettait notre badge ainsi qu'une serviette de cuirette qui contenait un bloc-note, un stylo, un DVD vidéo de 6 heures sur les sessions de la conférence de 2003, un surligneur miniature à l'effigie d'un commanditaire, une copie de l'application SQL Anywhere 11 Web Edition for Windows et une publicité en format signet / carte d'affaire pour une entreprise qui embauche dans le domaine du divertissement pour adulte sur le web (franchement original! d'autant plus que cette compagnie est un commanditaire de l'événement).

En ouverture, on a eu droit à une introduction par le co-auteur de PHP, Zeev Suraski, qui a expliqué pour quelles raisons PHP était gagnant (Why PHP Wins). Malheureusement, on a appris que Sara Golemon (Yahoo!) n'avait pu être présente pour des raisons de santé et que ses interventions allaient être remplacées. Ensuite, au programme de la journée, il y avait plusieurs sessions qui se déroulaient simultanément, alors chaque participant devait faire un choix selon ce qui l'intéressait. Pour ma part, j'avais un intérêt dans la plupart des sessions, sauf celles où étaient abordées les CMS (Joomla, Typo3, ImpressCMS). Le choix n'a pas été facile.

Évidemment, ça serait difficile de résumer les présentations mais pour cette première journée, j'ai pu m'initier à 5 sujets très différents les uns des autres tous reliés au PHP. Le niveau de difficulté variait selon le sujet abordé mais j'en suis sorti satisfait car j'y ai appris quelque chose à chaque fois. Aussi, à chaque conférence, un livre était tiré dans l'assistance. Dans le domaine du curieux, paraît-il qu'un employé de Google donnait une présentation et qu'elle était incompréhensible tellement le niveau de complexité était élevé. On est geek ou on ne l'est pas!

Un autre truc comique que j'ai noté, à chaque fois qu'un conférencier posait la question à savoir qui travaillait sur Windows, personne n'osait lever sa main... Mais en même temps, la proportion de gens qui avait apporté leur ordinateur portatif roulant sur Ubuntu était assez grande.

Avec ce que j'ai vu jusqu'à maintenant, je suis convaincu que les 500$ (prévente) demandés pour assister à cette conférence de 3 jours sont bien investis (et ce n'est pas cher). Les conférenciers proviennent d'un peu partout à travers le monde et apportent vraiment un plus dans leurs messages. C'est vraiment stimulant de savoir qu'on peut amener les choses à un autre niveau et qu'il y a tant à découvrir.

Demain, il y aura un salon emploi d'organisé. Même si je ne suis pas à la recherche de travail, je compte bien y faire un tour puisqu'on nous a remis deux billets pour obtenir une consommation gratuite. J'y ferai honneur :-)


Tags: PHP

mardi 3 mars 2009

Analyser et configurer les paramètres GET et POST

Publié par Infinite Loop, à 19 h 11 0 commentaire

Lorsque vous testez vos pages web dynamiques, est-ce que ça vous modifiez directement les paramètres de la query string dans la barre d'adresse du fureteur ? Quand vous postez un formulaire, devez-vous rafraîchir la page et la soumettre à nouveau ? Il est temps de changer vos habitudes. Grâce à une petite extension Firefox qui se nomme UrlParams, vous pourrez automatiquement lire, séparer et modifier les paramètres GET et POST.

À tout moment, ouvrez le panneau en utilisant la combinaison des touches CTRL+ALT+U (sinon il se trouve dans View / Sidebar). Vous verrez alors apparaître deux sections qui récupèrent les paramètres GET (page.php?q=test) et POST. Chaque paramètre sera séparé en deux champs, soit la clé (q) et la valeur (test), les deux étant modifiables pour regénérer une requête HTTP. Très simplement, il est possible d'ajouter une combinaison en utilisant l'icône "+" alors qu'en décochant une des clés, vous la désactiverez. Il ne restera qu'à cliquer sur le bouton "Submit" pour relancer la requête.

Vous pourrez ainsi tester la réception des champs d'un formulaire sans même en utiliser un. Cet outil est un atout quand on veut tester une requête Ajax puisque la page dynamique doit recevoir certains paramètres pour en retourner un objet Json ou XML. On peut même faire en sorte de transformer l'ensemble des paramètres reçus pour convertir une requête GET en POST (et vice versa). Simple et pratique.

Sur une note différente, demain est le début de la conférence PHP Québec à laquelle j'assisterai. Je vous donnerai un petit compte rendu de mes découvertes.


Tags: Extensions Firefox

lundi 2 mars 2009

Protéger son code PHP avec Zend Guard

Publié par Infinite Loop, à 18 h 39 1 commentaire

Récemment, j'ai commencé à évaluer les options possibles pour protéger la propriété intellectuelle dans les librairies PHP distribuées, plus particulièrement dans les applications web. Évidemment, on n'a pas à avoir de souci quand on héberge les projets sur nos propres serveurs mais il vient un temps où certains clients souhaitent déménager leur projet chez un autre hébergeur et c'est là qu'on sent la nécessité de protéger certaines portions critiques contre les gens mal intentionnés (vol de code, espionnage industriel, ingénierie inversée / reverse engineering). On met des efforts pendant des mois, parfois des années à développer et paufiner des mécanismes et des processus intelligents, il est normal de vouloir protéger notre savoir. Comme PHP est un langage interprété (non compilé), et que le code peut être lu et décortiqué facilement par des programmeurs, on est aussi bien de leur compliquer la vie un peu!

Lors de mes recherches, j'ai retenu deux possibilités : Zend Guard (basé sur la notoriété de Zend, c'est celui que j'ai testé) et IonCube (efficace et un peu moins cher).

Zend Guard, successeur de Zend Encoder, permet de prendre un projet, le sélectionner dans son ensemble ou en partie et de convertir les instructions PHP en un code intermédiaire illisible par un être humain normalement constitué. Ce code, obfusqué et encodé, pourra ensuite être lu, compris et exécuté par Zend Optimizer, un gratuiciel qui doit être installé sur le serveur qui héberge le projet.

Pour appliquer simplement la protection à un projet, suivez les instructions suivantes :

  • Menu File / New / Zend Guard Project
  • Entrez le nom du projet et le chemin où les fichiers de configuration seront conservés
  • Indiquez le nom du produit (comme s'il s'agissait d'une application web) et la version
  • Spécifiez l'emplacement où vous voulez déposer les fichiers une fois encodés
  • À l'étape suivante, choisissez le répertoire où sont placés les fichiers sources PHP (racine)
  • Pour des fins de tests, terminez en utilisant les options par défaut
Imaginez que vous avez un projet très simpliste, composé d'un fichier index.php à la racine, qui utilise une librairie placée dans le répertoire "lib". On pourrait vouloir protéger exclusivement le contenu de lib et laisser tel quel le fichier d'index puisqu'il ne contient que les appels à la librairie.

Dans la fenêtre Guard Explorer (normalement à gauche, elle ressemble à un explorateur de fichiers) :
  • Sélectionner les fichiers et répertoires à exclure, ouvrez le menu contextuel avec le bouton droit de la souris et choisissez l'option "Exclude resource"
  • En ouvrant le menu contextuel sur le nom du projet (racine de l'explorateur de fichiers), cliquez sur "Encode Project"
La version d'essai de Zend Guard permet d'encoder les fichiers pendant 14 jours sans qu'ils soient totalement optimisés. Les licences d'utilisation sont quant à elles valides pour 3 jours. L'avantage des licences est de pouvoir installer l'application web que vous avez développé chez un partenaire, un client, etc., et de pouvoir générer des clés d'utilisation valides pour une période de temps de votre choix (limitée ou permanente). À échéance, l'utilisateur devra la renouveller pour que l'application continue de fonctionner.

Dans le répertoire que vous avez spécifié plus tôt, vous retrouverez les fichiers encodés. Vous pourrez vérifier que les fichiers choisis ont bien été transformés en les ouvrant avec votre éditeur préféré. Vous ne devriez plus reconnaître les portions PHP. Ceux exclus demeureront intacts.

Pour terminer, il ne restera qu'à transférer les fichiers sur le serveur en utilisant un client FTP. À l'exécution du code, si vous voyez apparaître une erreur du type "Fatal error: Unable to read xxx bytes in chemin-du-fichier on line 0", c'est que vous n'avez pas transféré les fichiers encodés dans le bon mode. Forcez votre client FTP à utiliser le mode binaire (par exemple dans Filezilla : Menu Transfert / Mode de transfert / Binaire).


Tags: PHP

dimanche 1 mars 2009

Hébergement PHP gratuit

Publié par Infinite Loop, à 19 h 19 0 commentaire

Bonne nouvelle pour tous les développeurs PHP qui ont besoin d'un espace d'hébergement comme laboratoire pour expérimenter différents modules et techniques, le service 000webhost.com peut vous fournir tout cela gratuitement (d'où leur nom 0.00$).

Voici leur offre:

  • 1500 Mo d'espace disque
  • 100 Go de bande passante
  • Possibilité d'y attacher votre nom de domaine
  • PHP 5.2.x (mail, cUrl, GD2, fopen, sockets, PEAR, et plus)
  • MySQL
  • cPanel
  • Accès FTP
  • Support pour Zend Optimizer et IonCube
  • Pop3
  • Cron jobs
  • Activation instantanée
  • Aucune publicité de leur part (vous pouvez ajouter les vôtres)
  • 100% gratuit
Faites passer le mot, profitez-en mais n'en abusez pas.


Tags: PHP

Citation no. 19 sur la consommation d'alcool

Publié par Infinite Loop, à 09 h 03 0 commentaire

Verre vide je te plains, verre plein je te vide !

- Ivrogne optimiste


Tags: Citations

Messages plus récents Messages plus anciens Accueil
S'abonner à : Messages (Atom)
    Suivre @code18 sur Twitter

    Catégories

    • Apache (21)
    • Citations (167)
    • Club Vidéo (24)
    • Coffre à outils (56)
    • CSS (8)
    • Curiosités (117)
    • Design Pattern (2)
    • Drupal (8)
    • Easter Eggs (22)
    • Extensions Firefox (20)
    • GIMP (7)
    • Histoire (21)
    • HTML (32)
    • Humour (57)
    • Intégration (34)
    • iPod (12)
    • JavaScript (110)
    • Jeu de combat (6)
    • Le coin du geek (128)
    • Liens (12)
    • Linux (56)
    • Livres (78)
    • Lois et principes (46)
    • Marché des saveurs (26)
    • Mathématique (18)
    • Mobile (5)
    • Montréal (32)
    • Musique (112)
    • Pancartes et écriteaux (16)
    • Perl (8)
    • Pérou (1)
    • PHP (130)
    • PostgreSQL (44)
    • Programmation (105)
    • Saviez-vous que (55)
    • Sécurité (22)
    • SEO (5)
    • SQL Server (22)
    • Vieilles publicités (6)
    • Virtualisation (8)
    • Voyages (1)
    • Zend Framework (26)

    Divers

    Archives

    • ►  2015 (6)
      • ►  août 2015 (1)
      • ►  juillet 2015 (1)
      • ►  février 2015 (3)
      • ►  janvier 2015 (1)
    • ►  2014 (8)
      • ►  décembre 2014 (1)
      • ►  novembre 2014 (1)
      • ►  octobre 2014 (1)
      • ►  août 2014 (2)
      • ►  juillet 2014 (2)
      • ►  janvier 2014 (1)
    • ►  2013 (53)
      • ►  décembre 2013 (2)
      • ►  novembre 2013 (1)
      • ►  octobre 2013 (3)
      • ►  septembre 2013 (2)
      • ►  août 2013 (5)
      • ►  juillet 2013 (3)
      • ►  juin 2013 (5)
      • ►  mai 2013 (3)
      • ►  avril 2013 (7)
      • ►  mars 2013 (7)
      • ►  février 2013 (11)
      • ►  janvier 2013 (4)
    • ►  2012 (105)
      • ►  décembre 2012 (8)
      • ►  novembre 2012 (5)
      • ►  octobre 2012 (4)
      • ►  septembre 2012 (1)
      • ►  août 2012 (8)
      • ►  juillet 2012 (7)
      • ►  juin 2012 (7)
      • ►  mai 2012 (10)
      • ►  avril 2012 (13)
      • ►  mars 2012 (15)
      • ►  février 2012 (15)
      • ►  janvier 2012 (12)
    • ►  2011 (146)
      • ►  décembre 2011 (14)
      • ►  novembre 2011 (11)
      • ►  octobre 2011 (12)
      • ►  septembre 2011 (13)
      • ►  août 2011 (15)
      • ►  juillet 2011 (17)
      • ►  juin 2011 (18)
      • ►  mai 2011 (15)
      • ►  avril 2011 (9)
      • ►  mars 2011 (7)
      • ►  février 2011 (3)
      • ►  janvier 2011 (12)
    • ►  2010 (398)
      • ►  décembre 2010 (29)
      • ►  novembre 2010 (28)
      • ►  octobre 2010 (32)
      • ►  septembre 2010 (34)
      • ►  août 2010 (22)
      • ►  juillet 2010 (35)
      • ►  juin 2010 (42)
      • ►  mai 2010 (36)
      • ►  avril 2010 (37)
      • ►  mars 2010 (34)
      • ►  février 2010 (32)
      • ►  janvier 2010 (37)
    • ▼  2009 (430)
      • ►  décembre 2009 (32)
      • ►  novembre 2009 (34)
      • ►  octobre 2009 (33)
      • ►  septembre 2009 (37)
      • ►  août 2009 (37)
      • ►  juillet 2009 (39)
      • ►  juin 2009 (38)
      • ►  mai 2009 (37)
      • ►  avril 2009 (35)
      • ▼  mars 2009 (37)
        • Étui pour ordinateur portatif
        • Pagination des résultats sous SQL Server
        • Calendrier jQuery UI
        • Citation no. 23 sur l'ambidextrie
        • Poster son statut Twitter avec PHP
        • Informatique du film Jurassic Park
        • XML valide pour RSS
        • Gadgets électroniques et informatiques
        • Redéfinition de classe PHP
        • Origines du Hello World
        • Diaporama de photos en JavaScript, partie 2
        • Citation no. 22 sur la simplicité
        • Diaporama de photos en JavaScript, partie 1
        • Sortie officielle de Internet Explorer 8
        • Convertir l'encodage d'une page avec Dreamweaver
        • Comparaison de texte PostgreSQL
        • Lister les fichiers d'un répertoire en PHP
        • Pages 404 originales
        • Erreur curieuse en PHP : Paamayim Nekudotayim
        • Citation no. 21 sur les mots de passe
        • Manipuler une archive TAR compressée (gzip)
        • Une histoire de pixel brûlé
        • Il n'y a pas d'Easter Eggs dans ce programme
        • Adresse de courriel temporaire jetable
        • Bande dessinée sur la sécurité informatique
        • Populer un formulaire automatiquement
        • Interface countable en PHP
        • Conteneurs HTML à coins ronds
        • Citation no. 20 sur les consommateurs mécontents
        • Conférence PHP Québec 2009 - Jour 3
        • Manipuler une archive TAR
        • Conférence PHP Québec 2009 - Jour 2
        • Conférence PHP Québec 2009 - Jour 1
        • Analyser et configurer les paramètres GET et POST
        • Protéger son code PHP avec Zend Guard
        • Hébergement PHP gratuit
        • Citation no. 19 sur la consommation d'alcool
      • ►  février 2009 (32)
      • ►  janvier 2009 (39)
    • ►  2008 (84)
      • ►  décembre 2008 (34)
      • ►  novembre 2008 (39)
      • ►  octobre 2008 (11)

    Abonnés

Copyright © All Rights Reserved. Code 18 | Converted into Blogger Templates by Theme Craft