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

vendredi 31 décembre 2010

J'ai passé mon cours de programmation avec une note finale de 2%

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

Pour la dernière journée de l'année 2010, je termine en force avec une déclaration surprenante. Cherchez l'erreur... C'est étonnant mais vrai. C'est qu'en regroupant nos affaires pour paqueter des boîtes, j'ai retrouvé un bulletin indiquant mes notes finales datant de l'époque de mes études collégiales. Lors de mon cours de Programmation II, ma note finale fût [roulement de tambour] de 2%. Et pourtant, j'ai passé le cours avec succès.

Ma mémoire avait enfouilli ce fait et je me suis rappelé la circonstance en voyant le bulletin. À l'époque, j'étais plus marginal que la moyenne, plus loquace que la majorité des étudiants timides en informatique. Pourtant, je ne me mêlais pas beaucoup avec les autres étudiants de mon programme, préférant la compagnie d'amis qui étudiaient dans d'autres départements et passant une bonne partie de mon temps à la radio étudiante.

Dès les premières semaines de classe, l'enseignante m'avait peut-être jugé trop rapidement et de la façon qu'elle s'adressait à moi donnait l'impression qu'elle cherchait le moyen de m'humilier devant les autres ou de me remettre à ma place (au cours de programmation I en langage C, j'avais terminé la session avec une note finale de 93% alors que la moyenne était de 45%). J'assimilais vite les notions sans être un "ti-Joe connaissant". Sans blague, contrairement à plusieurs, mon initiation à l'informatique s'est fait sur le tard, alors que j'avais 15 ans! J'avais tout à apprendre.

Comme elle revenait sans cesse sur les notions de la session précédente, je n'apprenais rien de nouveau et j'avais le sentiment de perdre mon temps à chaque fois qu'elle imposait une pause à l'ensemble du groupe pour réexpliquer un concept à une minorité d'étudiants plutôt que de le faire après la classe. Durant ces moments, je poursuivais par moi-même mon exploration pour continuer à progresser et ça lui déplaisait, au point de me rappeler à l'ordre.

Lorsqu'elle me posait des questions ou me demandait d'aller faire une démonstration devant la classe, je ne tombais pas dans ses pièges. Je sentais que c'était frustrant pour elle et elle avait la fâcheuse tendance à parler à ses étudiants en les infantilisant. Merde, on n'était plus à la petite école! Et elle s'acharnait sur moi comme pour me rappeler que c'était elle qui détenait le savoir dans la classe et que nous, simples étudiants, lui devions une soumission et dévotion totales.

J'ai préféré abandonner le cours pour le rependre à la session suivante avec un autre enseignant plutôt que de poursuivre avec un professeur qui faisait la grosse tête et qui ne m'avait pas en estime. Au point où c'était rendu, c'était rédiproque. Qu'on se comprenne bien, j'ai obtenu 2% parce que le seul travail pratique comptabilisé valait 2 points dans la note finale.

La session suivante, la meilleure vengence a été d'obtenir une note finale de 87% en plus de m'impliquer dans du tutorat pour aider les étudiants en difficulté jusqu'à la fin de mes études.

Pour la postérité, j'ai numérisé et rassemblé les notes ici. Dans l'ordre : code du cours, nom du cours, note finale obtenue, moyenne du groupe et crédits.



Après toutes ces années, cet épisode anodin de ma vie m'a prouvé que j'avais probablement fait le meilleur choix. Autrement, j'aurais peut-être opté pour un cheminement différent, dans un tout autre domaine d'études. Donc un petit pied de nez qui a fait du bien se remémorer. Allez, je vous laisse là-dessus. Je range ce bout de papier dans la boîte sinon je ne finirai jamais.


Tags: Programmation

mercredi 29 décembre 2010

Piège JavaScript avec undefined et les closures

Publié par Infinite Loop, à 11 h 34 1 commentaire

Vous avez fort probablement déjà utilisé la propriété undefined en JavaScript pour vérifier si une variable a été assignée ou pas ? Considérez simplement l'exemple suivant qui déclare ce genre de fonction :

var app = new Object();
var x = '';
var y;

app.isDefined = function(value){
return value !== undefined;
}

console.log( app.isDefined(x) ? 'defined' : 'undefined' );
console.log( app.isDefined(y) ? 'defined' : 'undefined' );
Logiquement, vous vous attendez à ce que la variable x soit définie alors que y ne le soit pas. Si oui, vous avez raison, c'est tout à fait le comportement attendu. Mais qu'arriverait-t-il si on définissait volontairement une variable undefined dans ce script ou involontairement lors de l'inclusion d'une librairie externe ? Le concept de closure viendrait introduire une vulnérabilité :
var app = new Object();
var x = '';
var y;

var undefined = 18; // oups...

app.isDefined = function(value){
return value !== undefined;
}

console.log( app.isDefined(x) ? 'defined' : 'undefined' );
console.log( app.isDefined(y) ? 'defined' : 'undefined' );
Dans ce cas-ci, les deux appels retourneraient 'defined'.

L'idéal serait de ne jamais se fier à la propriété undefined, à moins de la redéclarer à l'intérieur de la fonction qui compte l'utiliser :
var undefined = 18; // ok

app.isDefined = function(value){
// sans danger pour le undefined dans la portée globale
var undefined;
return value !== undefined;
}
Ainsi, on évitera les mauvaises surprises reliées à ce genre de pratique.


Tags: JavaScript

mardi 28 décembre 2010

Mauvaise traduction double

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

On est présentement en mode "on vide les armoires" et on a trouvé ce vaporisateur pour souliers de cuir de marque Emu Polishes (beau site en passant) qui, vraisemblabment, est supposé préserver l'apparelence des vêtements.



En anglais, le mot "apparel" fait référence à un vêtement. Pourtant, on sent la volonté du traducteur de vouloir parler d'apparence alors qu'il a fusionné les deux termes. S'il avait demandé un coup de pouce à Google Translate, il aurait su que "keeps apparel looking new longer" se traduit par "garde des vêtements à la recherche de nouveaux plus". Si Google le dit...


Tags: Pancartes et écriteaux

lundi 27 décembre 2010

Connexion VPN avec rdesktop d'Ubuntu à Windows

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

Honte à moi, j'ai flanché. Oui, je l'avoue, je me suis connecté à mon ordinateur du boulot sans aucune raison valable pendant les vacances de Noël. À vrai dire, c'est que je voulais configurer sous Linux (Ubuntu) la connexion VPN à mon PC Windows et trouver une alternative à Remote Desktop. J'y suis allé à tâtons et ça a fonctionné malgré mes connaissances limitées en réseautique.

Pour se connecter par VPN (virtual private network) au réseau Windows, la première chose à faire est d'installer PPTP (Point-to-Point Tunneling Protocol). Si ce n'est pas fait, ouvrez un terminal et lancez la ligne de commande suivante :

sudo apt-get install network-manager-pptp

Une fois que ce sera fait, vous pouvez redémarrer le daemon NetworkManager et l'applet NetworkManager Applet. J'ai trouvé ces lignes qui sont supposées faire le travail :

killall nm-applet
sudo /etc/init.d/dbus restart
nm-applet --sm-disable

Normalement, ces instructions devraient suffire pour réinitialiser le tout sans avoir à redémarrer mais j'ai rencontré un problème avec la commande sudo /etc/init.d/dbus restart. J'ai perdu l'environnement graphique et l'écran est devenu noir pendant assez longtemps pour que je me dise qu'il vaudrait mieux redémarrer. Après le reboot, l'icône du NetworkManager Applet était réapparu avec les options de connexions VPN.



Justement, sur l'autre ordinateur (laptop), cet icône avait disparu sur le profil Ubuntu de ma copine. Dorénavant, je saurai que je pourrai le réactiver avec :

nm-applet --sm-disable

Maintenant, on est prêt à configurer la connexion. Dans le menu de l'applet :

  • VPN Connections / Configure VPN / Onglet VPN / Bouton Add.
  • Choose a VPN Connection Type : Point-to-Point Tunneling Protocol (PPTP) / Create
  • Donnez un nom à la connexion (par exemple, le nom de l'entreprise).
  • Indiquez l'adresse IP du Gateway (votre administrateur réseau vous la fournira).
  • Entrez votre nom d'utilisateur, mot de passe et le domaine du réseau. Cliquez sur le bouton Advanced.
  • Décochez PAP et cochez Use Point-to-Point encryption, Allow stateful encryption et Send PPP echo packets. Cliquez OK.


Allez ensuite sous l'onglet IPV4 Settings
  • Choisissez Automatic VPN
  • Après avoir cliqué sur le bouton Routes, entrez les informations pour :
  • Address : adresse IP de la machine où vous voulez vous connecter
  • Netmask du réseau (par exemple : 255.255.255.0)
  • Gateway : le gateway du réseau ou adresse IP du routeur
  • Metric : 1
  • Cliquez sur OK, ensuite Apply
Vous devriez être en mesure de vous connecter au VPN en sélectionnant son nom dans le menu de l'applet. Si un message indique que la connexion a échouée, vérifiez la configuration et votre login pour vous assurer qu'ils sont corrects. Sinon, un redémarrage peut s'avérer nécessaire.

Maintenant que j'ai accès au réseau distant de mon boulot, comment accéder à mon PC avec un logiciel alternatif à Remote Desktop (mstsc) ? Sous Linux, on peut utiliser rdesktop à lancer à partir d'un terminal.

sudo apt-get install rdesktop

Une fois installé, appelez le programme, toujours par le terminal (configuration minimale) :

rdesktop adresse-ip -d domaine -u utilisateur -p mot-de-passe

Où :
  • l'adresse IP doit être celle du poste sur lequel vous désirez vous connecter. Pour la trouver (parce qu'on ne la spécifie pas explicitement par Remote Desktop de Windows), je me suis connecté comme à l'habitude au VPN et à Remote Desktop. Une fois sur mon poste, j'ai lancé la commande ipconfig pour faire afficher l'IP. Je l'ai ensuite notée pour la substituer dans cette commande.
  • -d est pour spécifier le domaine. Vous devriez le connaître, sinon demandez à votre sysadmin.
  • -u pour indiquer le nom d'utilisateur (optionnel).
  • -p pour indiquer le mot de passe (optionnel si vous préférez l'entrer dans la fenêtre de login Windows).


La fenêtre étant petite, j'ai recommencé en utilisant l'option -f pour l'afficher en mode plein écran (fullscreen). Ce n'est qu'ensuite que j'ai remarqué qu'on pouvait basculer entre le mode plein écran et une fenêtre en appuyant sur CTRL+ALT-ENTER.


Tags: Linux

dimanche 26 décembre 2010

Jouer un wav avec PlaySound et contrôler le volume

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

Récemment, par intérêt personnel, j'ai commencé à explorer les différentes façons de faire sortir du son d'un ordinateur par programmation C++. Comme point de départ, j'ai testé la sortie de son par le haut-parleur et j'ai joué avec les fréquences pour composer une mélodie simpliste. L'étape suivante devait naturellement être celle où j'allais faire jouer un fichier wav et dans l'ordre logique des choses, je m'attaquerai éventuellement au format mp3.

Avant toute chose, j'avais besoin de lier une librairie pour le son à mon projet dans l'éditeur Bloodshed C++. La fonction PlaySound(), nécessaire à la lecture d'un wav, se trouve dans libwinmm.a. Je l'ai localisée dans mon installation Windows dans le répertoire de librairies fournies avec l'éditeur dans C:\Dev-Cpp\lib\libwinmm.a.

Pour l'ajouter, rendez-vous dans le menu Project / Project Options / Parameters / Add Library or Object et ajoutez le chemin vers le fichier libwinmm.a.



Dans le répertoire du projet, j'ai ajouté 2 fichiers wav à des fins de tests et j'ai écrit le code suivant:

#include <windows.h>
#include <stdio.h>

using namespace std;

int main(int argc, char *argv[]){

MMRESULT result;
result = waveOutSetVolume(NULL, 0x3000);

if(MMSYSERR_NOERROR == result){
// ils jouent un après l'autre, pas simultanément

printf("Debut de son1.wav\n");
PlaySound("son1.wav", NULL, SND_FILENAME);
printf("cette ligne sera ecrite apres\n");

printf("Debut de son2.wav\n");
PlaySound("son2.wav", NULL, SND_FILENAME|SND_ASYNC);
printf("cette ligne sera ecrite pendant que son2.wav joue, l'execution du code se poursuit...\n");
}

system("PAUSE");
return EXIT_SUCCESS;
}
Quelques explications :
  • il faut inclure windows.h en entête en plus de lier libwinmm.a. Sinon, stdio.h ne sert qu'à l'utilisation de la fonction printf() pour suivre la trace.
  • comme paramètre à la fonction waveOutSetVolume(), le niveau de volume doit être une valeur hexadécimale située entre 0x0000 (silence) à 0xFFFF (plein volume).
  • on peut aussi balancer le volume entre le canal gauche et droit, la valeur 0xFFFF0000 indiquant que le son ne sortira que du côté droit, alors que 0x0000FFFF sera uniquement pour le gauche. Dans le DWORD, les 4 premiers caractères sont pour le canal droit et les 4 suivants sont pour le gauche (0xDDDDGGGG).
  • j'en ai profité pour illustrer la différence entre la façon de jouer les 2 fichiers. La première instruction PlaySound attendra que la lecture du wav soit terminée pour exécuter la ligne suivante alors que la deuxième instruction, qui utilise le flag SND_ASYNC, permet de poursuivre l'exécution pendant que le wav joue.
  • il est possible de le combiner avec le flag SND_LOOP pour le jouer en boucle.


Tags: Programmation

Citation no. 113 sur le Père Noël

Publié par Infinite Loop, à 13 h 18 0 commentaire

Il y a quatre âges dans la vie de l'homme:

  1. celui où il croit au Père Noël
  2. celui où il ne croit plus au Père Noël
  3. celui où il est le Père Noël
  4. celui où il ressemble au Père Noël
- Anonyme


Tags: Citations

jeudi 23 décembre 2010

Meilleurs voeux pour Noël

Publié par Infinite Loop, à 11 h 36 1 commentaire

Pendant que Beau Dommage accroche un sourire au visage des concitoyens en entonnant à la radio la fameuse chanson 23 décembre : Joyeux Noël, Monsieur Côté, salut ti-cul, on se r'verra, le 7 janvier... on sent qu'il y a de la fébrilité dans l'air dans le monde politique.

Où est-ce que je veux en venir avec ça ? C'est que les statistiques de mon blogue montrent que quelqu'un au Parlement du Canada (Canadian House Of Commons) a recherché ce matin les termes "Chanson mangeux de marde" pour aboutir sur mon billet top 4 des chansons pour envoyer promener quelqu'un.

Cliquez pour agrandir :



Ça vole bas à Ottawa. Et ça sent les élections en 2011.

Mais à qui était destiné cet hymne grossier ? La session parlementaire étant terminée, qui donc fait du zèle dans les bureaux gouvernementaux plutôt que d'être en vacances ? Ma bulle vient d'éclater, moi qui croyait que la politique n'était composée que de parfaits gentlemen...

Malgré tout, joyeuses fêtes à tous!


Tags: Curiosités, Musique

mercredi 22 décembre 2010

Illusion d'optique animée

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

Admirez le travail. Si quelqu'un a une idée de quelle façon ils s'y prennent pour déconstruire l'image originale qui rend possible l'animation, je serais intéressé à l'apprendre. Un genre de reverse engineering ? Quel est le truc ?


Tags: Curiosités

lundi 20 décembre 2010

Hackers, heroes of the computer revolution

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

Je ne pensais pas terminer la lecture du bouquin Hackers avant les fêtes mais voilà, dès que je m'y suis plongé, je l'ai littéralement dévoré­. Trop rapidement à mon goût tellement c'est devenu un livre coup de coeur. Bien qu'il ne soit pas très récent (écrit originalement en 1984 et réédité en 2010 par O'Reilly à l'occasion de son 25ème anniversaire de publication), son contenu a su traverser le temps puisqu'il dépeint l'histoire et la culture du hacker, son évolution de 1950 jusqu'au début des années 80, le tout raconté de manière passionnante par Steven Levy (Wired). Une incursion dans cet univers mal connu était nécessaire pour démystifier la vraie nature du hacker.

Le terme "hacker", avouons le, a perdu ses lettres de noblesse avec le temps. La connotation négative qui lui est aujourd'hui associée n'a plus rien à voir avec les fondements originaux. Depuis son adoption par la culture populaire, plusieurs ont dénaturé son sens premier en s'autoproclamant hacker. Initialement, le hacker faisait son travail par pure passion, sans aucune attente de notoriété ou récompense financière. Avec le temps, il s'est adapté aux lois du marché pour devenir entrepreneur. Et c'est exactement là que la confrontation s'amorce.

Cette culture a vu le jour au Massachusetts Institute of Technology (MIT) à la fin des années 50, où des passionnés passaient la majorité de leur temps (y compris la nuit) à construire et améliorer collectivement les systèmes informatiques et en partageant ouvertement leurs connaissances. Et contrairement à ce qu'on pourrait le croire, ils suivaient (parfois sans le savoir) les règles d'éthique du hacker. Les zones d'exploration consistaient d'abord en les machines commerciales onéreuses comme le TX-0, le PDP1 et le PDP6. Mais d'autres avaient comme vision de rendre l'ordinateur accessible à tous et c'est dans les clubs informatiques comme le Homebrew Computer Club en Californie que des passionnés nouveau genre s'échangeaient les idées de concepts et astuces techniques, le tout sur une base volontaire. Et c'est d'ailleurs là que Steve Wozniak a amorcé la révolution en introduisant un nouveau genre de machine avec ce qui allait devenir une entreprise bien connue : Apple (voir à ce sujet l'excellent film Pirates of Silicon Valley).

Au fil de la lecture, on suit l'évolution de plusieurs acteurs de la révolution informatique (avec l'avènement de l'ordinateur personnel), des plus puristes (Greenblatt, Wozniak, Stallman) jusqu'à d'autres, qui ont connu le succès avec leur flair pour les bonnes affaires (Williams, Osborne, Gates, Zuckerberg). Ces deux derniers font une très brève apparition dans le texte, surtout le fondateur de Facebook qui n'a droit qu'à quelques lignes (et c'est tant mieux) dans un épilogue ajouté pour 2010.

Bien entendu, ce type de récit ne s'adresse pas à tout le monde mais c'est suffisamment bien vulgarisé pour qu'un néophyte y trouve son compte (c'est un récit donc rien de trop technique). Assurément, les passionnés d'informatique et les développeurs risquent d'y trouver une bonne source d'inspiration.

Je vous avertis tout de suite, si vous l'aviez lu à l'époque, cette nouvelle édition a peu de nouveau à se mettre sous la dent. Autrement, rendez-vous chez votre librairie (virtuel ou non) pour vous le procurer.

Une fois que vous l'aurez fait, voici d'autres suggestions de lecture secondaires :

  • Pour les plus geeks d'entre-vous, regardez du côté de The Soul of a New Machine de Tracy Kidder (conception d'un ordinateur 32 bits chez Data General sur une période d'un an)
  • JPod de Douglas Coupland, destiné au grand public, une immersion dans le monde des programmeurs avec quelques clichés selon la perception d'un observateur qui regarde de l'extérieur


Tags: Livres

dimanche 19 décembre 2010

Script PHP pour obtenir la liste de tous ses statuts Twitter

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

J'ai appris récemment qu'on pouvait changer la pagination pour visualiser la liste de nos statuts sur Twitter en ajoutant manuellement le paramètre ?page=n à la suite de l'URL (http://twitter.com/code18?page=2).

Bien sûr, la liste des status de notre timeline peut être obtenue à partir de l'API. Et si j'essayais de les récupérer sans passer par l'API, juste pour le plaisir d'essayer de les extraire pour en faire un backup pour mes archives personnelles ? Après tout, mes premiers pas sur Twitter datent de mars 2009 et j'ai publié au-delà de 1300 "gazouillis" jusqu'à maintenant.

C'est certain que je rencontrerai des contraintes par rapport à l'API (qu'il est plus prudent d'utiliser en plus de bénéficier de support et d'assurer la compatibilité). D'abord, mon script sera dépendant de la structure du code advenant qu'elle change dans le futur (HTML ou CSS appliqué). Ensuite, je devrai me contenter des statuts qui sont publics parce que ma méthode ne s'authentifiera pas au service Twitter.

Je me mets donc au travail avec comme base les éléments suivants :

  • la fonction file_get_contents() servira à récupérer le code HTML d'une page distante selon l'URL passé en paramètre
  • la librairie Zend_Dom_Query du Zend Framework sera utilisée pour les sélecteurs du DOM
Le script :
require_once('Zend/Dom/Query.php');

header('Content-Type: text/html; charset=utf8');

DEFINE('ACCOUNT', 'code18');
DEFINE('STATUS_PER_PAGE', 20);

$html = file_get_contents('http://twitter.com/' . ACCOUNT);

// obtenir le nombre de tweets total affiché à titre informatif sur la page
$dom = new Zend_Dom_Query($html);
$nodes = $dom->query('#update_count');

$nbUpdates = 0;
foreach($nodes as $node){
// retirer la virgule, le séparateur de milliers en anglais
$nbUpdates = (int)str_replace(',', '', $node->textContent);
}

# calcul du nombre de pages total
$nbPages = ceil($nbUpdates / STATUS_PER_PAGE);

# timeout du script selon le volume de données (2 secondes par tweet)
set_time_limit(2 * STATUS_PER_PAGE * $nbPages);

$buffer = "";

// récupérer les statuts une page à la fois
for($page=1 ; $page<=$nbPages; $page++){
$html = file_get_contents('http://twitter.com/' . ACCOUNT . '?page=' . $page);
$dom = new Zend_Dom_Query($html);

$listLI = $dom->query('#timeline li');

// pour chaque statut qui se trouve dans le LI
foreach($listLI as $li){
$doc = new DOMDocument();
$doc->appendChild($doc->importNode($li, true));
$elem = new Zend_Dom_Query( $doc->saveHTML() );
$listSpan = $elem->query('.published');
$listStatus = $elem->query('.entry-content');

// obtenir la date de publication du tweet
$dateValue = '';
foreach($listSpan as $date){
$dateValue = $date->getAttribute('data');
// attention, ne tient pas compte du fuseau horaire
$dateValue = preg_replace("/^\{time:'(.*)'\}$/", '$1', $dateValue);
}

// obtenir le texte du statut
$text = '';
foreach($listStatus as $status){
$text = $status->textContent;
}

$buffer .= $dateValue . ' | ' . $text . "\n";
}
}

// écrire le tout dans un fichier
$file = 'c:\tweets-' . ACCOUNT . '.txt';
// ou
// $file = '/home/code18/tweets-' . ACCOUNT . '.txt';

$fh = fopen($file, 'w');
fwrite($fh, $buffer, strlen($buffer));
fclose($fh);

echo 'Done';
Le résultat : un fichier texte de 163 kb comprenant la totalité de mes tweets depuis près de 2 ans.



Enfin, ça fonctionne mais il ne faudrait pas trop s'y fier si on veut construire quelque chose de solide. Aussi, je me rends compte que mes premiers tweets n'étaient vraiment pas pertinents et ça s'est heureusement amélioré avec le temps.


Tags: PHP, Zend Framework

Citation no. 112 sur le bonheur

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

C'est important le bonheur, parce que si t'as pas le bonheur, t'es-pas-heuREUX !

- Yvon Deschamps, humoriste


Tags: Citations

samedi 18 décembre 2010

Récupérer le contenu d'un fichier UIF en le convertissant en ISO

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

Encore une fois, on m'a fait parvenir un fichier d'un format obscur dont l'extension est .UIF (Universal Image Format). Il s'agit d'une image de DVD créée à partir de l'application commerciale MagicISO pour Windows. Mon défi aujourd'hui : comment extraire son contenu à partir de Linux sans avoir à installer MagicISO et le faire rouler sous Wine ?

Le tour de passe-passe que j'ai trouvé consiste d'abord à convertir le fichier UIF au format ISO pour ensuite monter le système de fichier pour les extraire. Voici comment j'ai procédé sous la distribution Ubuntu de Linux.

D'abord, j'ai téléchargé la source d'un programme de conversion nommé UIF2ISO. J'ai créé un répertoire pour y déposer la source et j'y ai décompressé le contenu du fichier zip :

mkdir uif2iso
cp uif2iso.zip uif2iso/uif2iso.zip
cd uif2iso/
unzip uif2iso.zip

Depuis le répertoire des sources (src), j'ai appelé make :

cd src
make

Une erreur s'est affichée : uif2iso.c:29: fatal error: zlib.h: No such file or directory. Avant de poursuivre plus loin, j'ai installé zlib :

sudo apt-get install zlib1g zlib1g-dev libssl-dev build-essential

Si des erreurs se produisent (comme ça a été le cas pour moi) et qu'un message s'affiche indiquant qu'il ne trouve pas les fichiers sur le repository, faites ceci pour mettre à jour la liste des sources :

sudo apt-get update

Ensuite, on peut installer correctement zlib (sudo apt-get install zlib...) et lancer la procédure de make et make install :

make
sudo make install

Voilà, le programme uif2iso est prêt à être utilisé. En retournant dans le répertoire où se trouve le fichier UIF, je l'ai converti en ISO par une simple commande :

uif2iso fichier.uif fichier.iso

Une fois le processus terminé, j'ai monté le système de fichier du .ISO pour en extraire le contenu :

mkdir /mnt/iso
sudo mount -o loop /home/code18/Desktop/repertoire/fichier.iso /mnt/iso

Pour les consulter, je me suis rendu au répertoire où était monté le système de fichier (par le terminal, mais j'aurais pu y aller par l'interface graphique) :

cd /mnt/iso

Et j'ai copié copie tous les fichiers vers ma clé USB qui se trouvait montée dans /media/KINGSTON :

cp * /media/KINGSTON

Et finalement, on démonte le tout pour que ça reste propre :

sudo umount /mnt/iso

Mission accomplie.


Tags: Linux

jeudi 16 décembre 2010

Je n'ai jamais vu ce personnage dans Zelda

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

En cherchant sur eBay un t-shirt du jeu Zelda, j'ai découvert un nouveau personnage que je n'avais jamais remarqué auparavant...

Hey, c'est le rappeur 50 Rupees !



Le t-shirt The Legend Of Zelda, Ocarina Of Time est offert par le marchand st_darwood. Ce qui est inquiétant, c'est qu'il y en a déjà 3 de vendus. J'imagine déjà la surprise quand les acheteurs ouvriront leurs colis...


Tags: Curiosités

Évaluer des conditions multiples dans une instruction IF

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

Dans du code source, une instruction IF est quelque chose qu'on comprend généralement assez facilement. Elle comprend une ou plusieurs conditions qui, une fois évaluées, permettent de savoir si on doit ou non exécuter le code subséquent.

À partir de cet exemple qui récupère un enregistrement de la base de données :

$record = $connection->query('SELECT * FROM employee_sales WHERE employee = 18');

/*
Imaginez la structure obtenue :

$record = array(
'active' => true,
'salary' => 40000,
'weeklySales' => 1200,
'weeklyAverage' => 1000,
'hours' => 35
);
*/
Je suis convaincu que vous êtes déjà tombé sur du code dont la condition du if ressemblait à ça (peut-être l'avez-vous écrite vous-même ?) :
if($record['active'] && ($record['salary'] / ($record['hours'] * 52) > 20) && ($record['weeklySales'] >= $record['weeklyAverage']) && ((($record['weeklySales'] - $record['weeklyAverage'])  * 52) > (0.25 * $record['salary']) ) ){
// mérite un bonus!
}
Vous trouvez ça difficile à comprendre ? Je suis d'accord. J'ai vraiment fait exprès pour rendre ça compliqué pour rien, uniquement pour illustrer mon propos. Sur le coup, le programmeur qui écrit le code dans ce style a probablement eu le souçi de minimiser le nombre de lignes au détriment de la compréhension pour le prochain programmeur qui héritera du projet (ou vous-même, 1 an plus tard).

Quand c'est à moi que ça arrive, j'ai l'habitude de reformater le code avant même d'essayer de le comprendre. C'est plus simple à lire et ça évite de faire des erreurs de syntaxe lors de l'édition.

Pour une question de clareté et de lisibilité, certains pourront opter pour un formatage qui liste une condition par ligne :
if( $record['active']
&& ($record['salary'] / ($record['hours'] * 52) > 20)
&& ($record['weeklySales'] >= $record['weeklyAverage'])
&& ((($record['weeklySales'] - $record['weeklyAverage']) * 52) > (0.25 * $record['salary']) )
){
// mérite un bonus!
}
C'est déjà plus clair.

Sinon, une solution alternative serait de créer une liste des conditions dans un array. Comme toutes les conditions seraient évaluées individuellement à true ou false, on obtiendrait un array du type : array(true, true, true, false) dans lequel on n'aurait qu'à s'assurer qu'il n'y a aucune valeur fausse.
$conditions = array(
$record['active'],
($record['salary'] / ($record['hours'] * 52) > 20),
($record['weeklySales'] >= $record['weeklyAverage']),
((($record['weeklySales'] - $record['weeklyAverage']) * 52) > (0.25 * $record['salary']) )
);

if( !in_array(false, $conditions) ){
// mérite un bonus!
}
Qui plus est, un autre avantage est de laisser de l'espace pour pouvoir ajouter un commentaire à la suite de chaque condition. Juste pour préserver la bonne humeur du programmeur qui reprendra le flambeau de votre projet dans un avenir proche.


Tags: PHP, Programmation

mercredi 15 décembre 2010

Redirections HTTP, JavaScript et Refresh

Publié par Infinite Loop, à 21 h 48 8 commentaires

Rediriger l'utilisateur vers une autre page est une action courante dans le développement web. Pour les newbies, je vous ai préparé un petit résumé de quelques techniques possibles.

Redirection HTTP (par PHP)

La plus simple, à condition d'avoir accès à un langage de programmation dynamique (sinon, voir les possibilités avec .htaccess sur Apache).

# Permanente
header('Location: http://code18.blogspot.com/', true, 301);
exit;

# Temporaire
header('Location: http://code18.blogspot.com/', true, 302);
exit;
La redirection est immédiate et permet autant la redirection permanente que temporaire. Par contre, cette technique ne permet pas la redirection différée.

Par JavaScript

Ici, l'instuction clé est l'utilisation de window.location = url; pour une redirection immédiate. Combiné à un timer et la fonction setInterval qui rappelle continuellement la fonction à intervalles réguliers (1000 millisecondes), on pourra rediriger à une autre page ou un autre domaine après avoir attendu un nombre x de secondes (redirection différée).
var seconds = 5;
var redirect = 'http://code18.blogspot.com/';
var timer;

$j = jQuery.noConflict();
$j(document).ready(function(){
timer = setInterval("countdown()", 1000);
});

function countdown(){
seconds--;
if(seconds == 0){
clearInterval(timer);
window.location = redirect;
}
}
Si JavaScript n'est pas activé dans le navigateur, vous êtes foutu.

Meta tag refresh

Celle-là, on y pense moins souvent mais elle fonctionne même si JavaScript n'est pas activé. Il permet de rafraîchir la page à intervalle régulier et permet de placer un URL qui peut être différent de celui de la page courante. À placer en entête de page, à l'intérieur de la balise <head>.
<meta http-equiv="refresh" content="5;url=http://code18.blogspot.com/">
Si le nombre de secondes indiqué est 0, la redirection sera immédiate.

J'ai récemment utilisé cette technique pour montrer sur un splash page un message expliquant au visiteur que le site sera déménagé vers un nouveau domaine dans les semaines à venir. Après avoir attendu quelques secondes, le visiteur était redirigé vers le nouveau site.

Le défaut de cette technique est qu'elle ne pourra jamais être aussi efficace qu'une redirection HTTP car contrairement à cette dernière, c'est impossible de spécifier s'il s'agit d'une redirection permanente pour les engins de recherche.


Tags: HTML, JavaScript, PHP

mardi 14 décembre 2010

Nouvelle balise Datalist en HTML5

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

Lors de mes récentes expérimentations HTML5, j'ai eu l'occasion de tester la nouvelle balise <datalist> qui permet de définir des choix à associer à un <input type="text"> standard. En effet, on avait l'habitude d'utiliser une balise <select> avec une série de <option> pour obtenir ce résultat. La nouveauté du datalist HTML5 permet de créer une extension à un input pour en faire un hybride entre le champ de saisie et le selectbox.



Exemple de code :

<input type="text" list="listeDesProvinces">
<datalist id="listeDesProvinces">
<option label="Ontario" value="ON">
<option label="Québec" value="QC">
<option label="Nouvelle-Écosse" value="NS">
<option label="Nouveau-Brunswick" value="NB">
<option label="Manitoba" value="MB"></option>
<option label="Colombie-Britannique" value="BC">
<option label="Ile-du-Prince-Edouard" value="PE">
<option label="Saskatchewan" value="SK">
<option label="Alberta" value="AB">
<option label="Terre-Neuve-et-Labrador" value="NL">
<option label="Territoires du Nord-Ouest" value="NT">
<option label="Yukon" value="YT">
<option label="Nunavut" value="NU">
</datalist>
Dans la balise input, la valeur de l'attribut "list" indique l'ID de l'élément datalist à lui associer pour obtenir la liste des choix.

Un point intéressant est que les valeurs d'un datalist peuvent être partagées entre différents éléments dans la page. Ce qui l'est moins, c'est qu'il n'est pas tout à fait prêt à être intégré dans un projet car il ne fonctionne que sous Opera. Chrome, Safari et Firefox ont échoué le test.


Tags: HTML

lundi 13 décembre 2010

Machine de Rube Goldberg

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

Je l'ai mentionné hier sur mon compte Twitter et pour ceux qui ne me suivent pas (encore), je diffuse ici ce vidéoclip coup de coeur vraiment génial pour la pièce This Too Shall Pass du groupe OK Go.

Même si je n'ai pas accroché sur leur musique, je dois saluer la superbe réalisation de l'équipe technique qui a mis en scène une machine à la Rube Goldberg, telle que vous l'avez probablement déjà remarquée dans des films comme Back To The Future, Edward aux mains d'argent ou les Goonies, sans pourtant en connaître l'origine.



Assurez-vous aussi de jeter un oeil au plan interactif qui détaille point par point les différentes étapes du parcours et poursuivez en allant visionner les extraits vidéos du top 10 de l'utilisation d'une machine à la Rube Goldberg au cinéma, selon Gizmodo.


Tags: Le coin du geek, Musique

dimanche 12 décembre 2010

Excusez-moi, avez-vous l'heure ?

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

La convention veut qu'en société, on utilise une base 60 pour calculer le temps : 60 secondes dans une minute, 60 minutes dans une heure. Pour le geek en vous, mieux vaut se démarquer de la masse en utilisant la notation binaire pour connaître l'heure courante.

Sous un système Linux, cette commande vous permettra de suivre en temps réel l'heure actuelle en mode binaire (avec un décalage d'une seconde) :

watch -n 1 'echo "obase=2;`date +%s`" | bc'



Où :

  • La commande watch est utilisée pour appeler périodiquement un programme (selon le nombre de secondes indiqué au paramètre -n)
  • obase pour indiquer qu'en sortie (output base), ce sera de la base 2 (binaire)
  • bc est un langage de calculatrice à précision arbitraire
Autrement, si vous désirez posséder un objet physique, je vous recommande le LED Binary Clock vendu par ThinkGeek ou encore une de ces montres : ici ou ici.


Tags: Linux

Citation no. 111 sur la créativité

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

Tu peux seulement faire certaines choses avec tes mains mais avec ton esprit, c'est illimité.

- Conseil de Kalman Seinfeld à son fils Jerry


Tags: Citations

samedi 11 décembre 2010

Épitaphe insultante

Publié par Infinite Loop, à 16 h 00 0 commentaire

Le nom de John Laird McCaffrey, ça vous dit quelque chose ? Ce type est décédé le 14 août 1995 à l'âge de 54 ans et repose au Cimetière Notre-Dame-des-Neiges, sur le Mont-Royal à Montréal.

Sur sa pierre tombale se trouve ce poème :

John

Free your body and soul
Unfold your powerful wings
Climb up the highest mountains
Kick your feet up in the air
You may now live forever
Or return to this Earth
Unless you feel good where you are!

Missed by your friends

Voici la photo :



Si vous lisez uniquement la première lettre de chaque vers, vous lirez : FUCK YOU. Message caché ou coincidence ?

Selon la recherche de défunt du site du cimetière Notre-Dame-Des-Neiges, cette nouvelle célébrité se trouve dans la section C, lot 01369.


Tags: Curiosités, Humour, Montréal

mercredi 8 décembre 2010

Flashback en 1981 avec Softporn Adventure

Publié par Infinite Loop, à 22 h 04 1 commentaire

Ma lecture du livre Hackers de Steven Levy tirant à sa fin, je voulais partager une des bonnes anecdotes relatant la sortie d'un jeu vidéo sorti en 1981 (l'année de ma naissance), soit Softporn Adventure. Conçu pour Apple II, uniquement en mode texte, sa publication avait été refusée par quelques compagnies qui disaient privilégier la famille comme public cible.

De son côté, Ken Williams, le fondateur de On-Line Systems (Sierra), accepta, croyant qu'il pourrait tirer profit de la controverse et de la publicité gratuit en publiant le jeu. En effet, sa stratégie lui a permis de doubler ses profits. Pour concevoir la publicité, Ken a eu l'idée de présenter trois femmes nues dans un spa, où un serveur leur offre des verres. En arrière-plan se trouve un ordinateur Apple (non mais quel concept!).

Aussi curieux que cela puisse paraître, on retrouve dans la photo :

  • la responsable de la comptabilité de la compagnie
  • la femme de Bob Davis (un des programmeurs)
  • le serveur, trouvé dans un steak house local (The Broken Bit)
  • Roberta Williams (la femme de Ken et co-fondatrice de Sierra Online)


Il aurait suffit à Ken d'arriver dans les locaux de la compagnie et de poser ouvertement la question : qui veut venir chez moi pour prendre des photos nus dans le spa ? Les volontaires se sont fait connaître.

Anecdote tirée de Hackers, chapitre 17 (Summer Camp), page 350. Et oui, ce jeu a bel et bien servi d'inspiration à Larry Leisure Suit.


Tags: Vieilles publicités

mardi 7 décembre 2010

Image de webcam en ASCII art sur Linux

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

Au moment d'écrire ces lignes, je suis devant la télévision à regarder le match de hockey avec mon laptop sur les genoux. C'est un bon moment pour explorer la distribution Ubuntu qui a joyeusement remplacé Windows Vista qui était installé sur mon portable HP au moment de l'achat. Tout ça juste pour le plaisir de découvrir l'étendue des possibilités qu'offrent les outils de ce système d'exploitation.

J'avais le goût de vous saluer avec la webcam en mettant à l'essai une ligne de commande qui permet de capturer l'image par la webcam et de la convertir en vidéo ASCII.



Yeah, un thumb up !

Si mplayer n'est pas installé, faites-le en lançant la commande suivante dans un terminal :

sudo apt-get install mplayer

Une fois que c'est fait, vous pourrez essayez le petit truc avec cette commande :

mplayer -tv driver=v4l2:gain=1:width=640:height=480:device=/dev/video0:fps=10:outfmt=rgb16 -vo aa tv://

Sur ce, bonne fin de match :-)


Tags: Linux

lundi 6 décembre 2010

Comme le fondateur de WikiLeaks, je vire parano

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

Comme WikiLeaks compte déjà 208 sites mirroirs pour se protéger de la censure, il est temps que je fasse une copie de sauvegarde de la totalité de mon blogue avant qu'un malheur arrive. Eh oui, à l'image de la télésérie Virginie, je me base aussi sur l'actualité pour rédiger mon contenu. Patience, ça tire à sa fin! Pas mon blogue, Virginie!

Alors, comment on s'y prend pour aspirer la totalité d'un site ? Avec la commande GNU Wget sur Linux bien sûr! Essentiellement, la commande suivante devrait suffire à récupérer les pages HTML de mon blogue :

wget -r http://code18.blogspot.com

Mais Wget compte tellement d'options puissantes que la tentation est grande de les utiliser :

wget -r -p --random-wait robots-off -U mozilla -P code18 http://code18.blogspot.com/

-r : récursif
-p : télécharge tout ce qui est dépendant de la page pour l'afficher correctement
--random-wait : attend un nombre aléatoire de secondes entre les requêtes pour éviter d'être "black listé"
robots-off : pour qu'il ne suive pas les directives dans robots.txt
-U : pour indiquer le nom du user-agent qui sera envoyé au serveur HTTP
-P : pour indiquer, selon le répertoire courant d'où la commande est appelée, dans quel répertoire on enregistrera le contenu aspiré

Le hic, c'est que les images n'ont pas suivies car j'ai remarqué qu'elles sont hébergées sur un serveur différent, soit 4.bp.blogspot.com. On recommence en appliquant quelques modifications.

wget -r -p --random-wait robots-off -U mozilla -P code18 http://code18.blogspot.com/ -H -D code18.blogspot.com,4.bp.blogspot.com

-H permet d'étendre la récupération récursivement sur différents hôtes
-D suivi d'une liste de domaines séparés par des virgules permet de restreindre la récupération à ces domaines

Maintenant ça fonctionne. Pour faire une copie de sauvegarde des images, Wget crée sur mon poste un répertoire 4.bp.blogspot.com et l'alimente en créant l'arborescence complète avec une série de répertoires aux noms bizarres.

Et si j'avais voulu juste les images, toutes au même endroit (1 répertoire unique) ?

wget -r -p -nd --random-wait robots-off -U mozilla -P images -A jpg,jpeg,gif,png http://code18.blogspot.com/ -H -D code18.blogspot.com,4.bp.blogspot.com

-nd (no directories) pour que tous les fichiers s'enregistrent dans le répertoire indiqué sous l'option -P (images)
-A pour spécifier les extensions à conserver

Puissant, n'est-ce pas ? Je disais au début du billet que cette commande est pour Linux mais les utilisateurs de Windows ne seront pas en peine puisqu'il existe aussi une adaptation de Wget pour Windows si vous souhaitez vous amusez aussi.

En conclusion, avant d'avoir l'idée folle de télécharger la totalité de Wikipedia avec cet outil pratique, jetez plutôt un coup d'oeil à leur section Télécharger la base de données...


Tags: Linux

dimanche 5 décembre 2010

Preuve de l'existence des extraterrestres

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

Ma copine et moi venons de terminer le souper. Durant notre repas, ma douce moitié m'a fait remarquer que si les femmes viennent de Vénus et que les hommes viennent de Mars, l'espèce humaine est sans doute apparue sur la planète Terre par déportation.

Et moi de répondre : ce qui prouve qu'il existe des formes de vies ailleurs dans l'Univers que sur la Terre. Dès lors, l'institut SETI peut cesser ses activités.

CQFD


Tags: Lois et principes

Citation no. 110 sur Internet

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

L'Internet subira un effondrement catastrophique en 1996.

- Robert Metcalfe (inventeur de Ethernet)

En 1997, il a littéralement ravalé ses mots en mangeant sa feuille de papier en face d'un auditoire lors de la 6ème édition du International World Wide Web Conference.


Tags: Citations

samedi 4 décembre 2010

Démarrer Firefox en mode plein écran par une ligne de commande

Publié par Infinite Loop, à 09 h 15 6 commentaires

Nous étions en réunion pour faire du brainstorming sur la façon de concevoir les interfaces d'une application web quand le designer est venu présenter le fruit de son travail. Il déplorait que les exigences du système fassent qu'il y ait tellement de boutons et de contrôles que ça occupait beaucoup d'espace à l'écran et que le contenu pertinent à consulter se voyait relégué vers le bas, ce qui nécessitait l'utilisation de la barre de défilement pour y accéder.

Après que le groupe eut sorti quelques idées sur la façon de réorganiser le tout (nous sommes arrivés à d'excellentes solutions), j'ai fait remarquer qu'on aurait pu tirer parti des fonctionnalités du fureteur en maximisant l'espace visible disponible en basculant en mode plein écran (F11 sous Firefox, IE, Chrome et Opera. Safari ?). Une fois les barres d'outils cachées (menu, navigation, favoris, onglets, barre de statut, barre des tâches Windows), on obtient une zone visible additionnelle non négligeable dans le contexte d'une application dont le fonctionnement n'a pas les mêmes objectifs que la visite d'un site web.

Une autre avantage est qu'on peut se permettre de travailler dans un environnement contrôlé et suggérer aux utilisateurs d'utiliser tel type et telle version de fureteur pour offrir la meilleure expérience et bénéficier des caractéristiques particulières de l'outil (considérez par exemple les extensions).

Je me suis ensuite posé la question à savoir s'il était possible de préparer un raccourci de bureau pour les gestionnaires qui travailleront tous les jours avec l'application web pour qu'ils puissent double cliquer sur l'icône et la démarrer en se rendant automatiquement au bon URL en mode plein écran.

En regardant les options de ligne de commande de Firefox, la seule chose qui ne peut être faite est d'appeler le mode fullscreen en l'activant au démarrage, uniquement que pour cet URL. Il faut absoluement appuyer sur la touche F11. Je me suis alors tourné vers l'entrepôt d'extensions de Mozilla pour y dénicher quelque chose de bon mais sans succès. C'est pourtant sur le site d'un développeur indépendant que j'ai trouvé la solution : l'extension Autohide.

J'ai fait fi de la mention "Use Autohide at your own risk!" et du fait que le développeur s'entête à ne pas vouloir soumettre son extension à addons.mozilla.org (voir question 1 de la FAQ) et je l'ai installée malgré tout. Comme LifeHacker a déjà suggéré Autohide en tant que "download of the day" dans le passé, ça m'a rassuré. Et ça fonctionne bien.

Autohide permet de configurer quelles portions du fureteur on veut cacher ou voir lorsqu'on bascule en mode plein écran. Si on cache tout (sauf la barre de défilement qui ne peut disparaître), j'ai figuré qu'on pouvait récupérer environ 150 pixels horizontalement. Et le plus important, c'est qu'il ajoute à la ligne de commande l'option -fullscreen qui prend effet lorsqu'on démarre pour la première fois le fureteur (malheureusement, ça ne fonctionnera pas si une fenêtre de FF est déjà ouverte).

Après avoir récupéré le chemin de l'exécutable de Firefox sur ma machine, j'ai créé un raccourci sur mon bureau et j'ai indiqué comme cible la valeur suivante :

"C:\Program Files\Mozilla Firefox\firefox.exe" -new-window "http://code18.blogspot.com" -fullscreen

Où :

  • on indique le chemin de firefox.exe
  • on spécifie qu'on veut ouvrir une nouvelle fenêtre avec -new-window
  • l'URL à charger
  • on souhaite entrer en mode fullscreen (celui proposé par Autohide)
Ce n'est pas parfait mais c'est une piste de solution qui pourrait parfois être envisageable.


Tags: Extensions Firefox

vendredi 3 décembre 2010

Contourner la limitation de la fonction unnest sous Postgres

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

Vous vous souvenez quand j'ai parlé de la fonction unnest() pour Postgres (native à 8.4 et aussi implémentée pour les versions antérieures) ? Elle m'est souvent pratique dans mes projets mais comporte une limitation importante : elle ne traite pas les arrays à deux dimensions. Voici comment j'ai réussi à contourner le problème pour transformer un array Postgres en recordset par une requête SQL.

Disons que j'obtiens des données d'une table sous la forme d'un array qui compte à chaque indice un array associatif représentant un enregistrement :

$rs = array(
array('id' => 10, 'name' => 'Godspeed you black emperor', 'date' => '2003-05-01'),
array('id' => 20, 'name' => 'Arcade Fire', 'date' => '2010-09-04'),
array('id' => 30, 'name' => 'Thee Silver Mount Zion', 'date' => '2011-01-12')
);
La fonction unnest() ne permet pas de la traiter correctement les arrays à plusieurs dimensions. J'ai donc écrit une fonction PHP qui permet de convertir un array tel que décrit plus haut en une chaîne de caractères correspondant à la notation d'un array PostgreSQL.
function convertToPgArray($arrayCollection){
$records = array();
foreach($arrayCollection as $array){
foreach($array as $idx => $value){
$array[$idx] = '"' . $value . '"';
}
$records[] = '{' . implode(', ', $array) . '}';
}
return '{ ' . implode(',', $records) . ' }';
}
L'appel à la fonction retournera ceci :
$pgArray = convertToPostgresArray($rs);
echo $pgArray;

/*
{
{"10", "Godspeed you black emperor", "2003-05-01"},
{"20", "Arcade Fire", "2010-09-04"},
{"30", "Thee Silver Mount Zion", "2011-01-12"}
}
*/
Ce qui nous permet par la suite d'utiliser cette valeur comme paramètre de la requête SQL ou d'une fonction Postgres. Le truc est que les éléments de l'array doivent être du même type (tous des integers, des varchars, des dates, etc). C'est exactement pour cette raison que la fonction PHP convertit toutes les valeurs en tant que varchar. Après le traitement, on utilisera un "cast" (avec l'opérateur ::) pour convertir chaque valeur dans son type original.

La structure spécifique de la requête SQL qui convertira la chaîne en enregistrements prend cette forme :
SELECT sub[idx][1]::integer as id, sub[idx][2]::varchar as name, sub[idx][3]::date as important_date
FROM (SELECT 'PLACEHOLDER'::varchar[] as sub) as tmp
CROSS JOIN generate_series(1, array_upper('PLACEHOLDER'::varchar[], 1) ) as idx
J'utilise la fonction generate_series() pour obtenir une liste des indices selon la première dimensions de l'array (autrement dit, combien d'enregistrements) à laquelle je crée une jointure. Dans les espaces réservés où j'ai inscrit "PLACEHOLDER", remplacez-les par la valeur de $pgArray pour construire une requête SQL valide :
$sql = "
SELECT sub[idx][1]::integer as id, sub[idx][2]::varchar as name, sub[idx][3]::date as important_date
FROM (SELECT 'PLACEHOLDER'::varchar[] as sub) as tmp
CROSS JOIN generate_series(1, array_upper('PLACEHOLDER'::varchar[], 1) ) as idx
";

$sqlToExecute = str_replace('PLACEHOLDER', $pgArray, $sql);

echo $sqlToExecute;

/*
SELECT sub[idx][1]::integer as id, sub[idx][2]::varchar as name, sub[idx][3]::date as important_date
FROM (SELECT '{ {"10", "Godspeed you black emperor", "2003-05-01"},{"20", "Arcade Fire", "2010-09-04"},{"30", "Thee Silver Mount Zion", "2011-01-12"} }'::varchar[] as sub) as tmp
CROSS JOIN generate_series(1, array_upper('{ {"10", "Godspeed you black emperor", "2003-05-01"},{"20", "Arcade Fire", "2010-09-04"},{"30", "Thee Silver Mount Zion", "2011-01-12"} }'::varchar[], 1) ) as idx
*/
Une fois la requête exécutée, vous obtiendrez un jeu d'enregistrements :


Tags: PHP, PostgreSQL

jeudi 2 décembre 2010

La magie du contexte dans jQuery

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

Question : après avoir utilisé un sélecteur jQuery qui nous retourne l'élément du DOM HTML, comment peut-on effectuer une sélection supplémentaire sur la portion du code HTML référencée par le sélecteur ?

Pour y répondre, la meilleure façon est d'avoir un exemple de code. En commençant par un div comme conteneur où se trouvent un lien et un paragraphe :

<div id="mainDiv">
<a href="http://code18.blogspot.com">Code 18</a>
<p>Lorem ipsum... cette portion <span>n'est pas en gras</span></p>
</div>
En sélectionnant le div principal par son ID, on peut assigner ce qui est retourné à une variable qui contient le code HTML du div ainsi que son contenu. Toujours en utilisant un sélecteur comme premier paramètre, on indiquera la variable du résultat précédent comme contexte, c'est-à-dire comme deuxième argument (optionnel) : $j(sélecteur, contexte).

On pourra alors aller chercher la balise <a> qui se trouve à l'intérieur du <div> et changer l'URL et le texte du lien par programmation.

Enfin, on ira extraire la balise <p> et on cherchera ensuite par un autre sélecteur le <span> qui se trouve imbriqué dans le paragraphe pour y appliquer le style gras (et du même coup changer le sens de la phrase).
$j = jQuery.noConflict();

$j(document).ready(function(){
if( confirm('Voulez-vous effectuer le changement ?') ){
var div = $j('#mainDiv');
$j('a', div).attr('href', 'http://www.google.com').html('Google');

var p = $j('p', div);
$j('span', p).attr('style', 'font-weight:bold').html('est en gras');
}
});
Dans cet exemple, le popup de confirmation est là que pour vous laisser le temps de voir s'appliquer les changements avant/après.


Tags: JavaScript

mercredi 1 décembre 2010

Trier les éléments du DOM avec TinySort pour jQuery

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

J'ai souvent développé des interfaces qui permettaient de transférer des items sélectionnés d'une liste à une autre. Chaque fois, le même problème se posait : les éléments apparaissaient à l'écran suivant l'ordre du transfert plutôt que dans l'ordre logique, par exemple selon un tri alphabétique. Et chaque fois, je devais coder une fonction de tri spécifique, faute d'avoir accès à une fonction générique configurable.

Hier soir, je me suis mis à chercher un plugin qui pouvait trier les éléments du DOM. J'ai fait l'essai du plugin jQuery TinySort (version 1.0.4) et dans le cas de mon interface, tout a fonctionné du premier coup (chaque fois que je sélectionnais une date dans un calendrier, la valeur de la date s'ajoutait à une liste que je réordonnais avec TinySort pour conserver l'ordre chronologique à l'écran). L'avantage principal de ce type de tri est de pouvoir manipuler les éléments du DOM sans avoir à rafraîchir la page.

Ensuite, j'ai constaté que ce plugin pouvait aussi s'avérer utile pour trier le contenu d'une table, par colonnes, sans refaire de requête SQL à la base de données ou d'appel AJAX (les données ne sont pas rafraîchies, seulement déplacées). J'ai créé ce petit exemple fonctionnel pour vous.

Prenez la table HTML suivante, statique ou générée dynamiquement :

<table id="myTableId">
<thead>
<tr id="tableHeader">
<th><a id="headerId" href="javascript:;">ID</a></th>
<th><a id="headerDate" href="javascript:;">Date</a></th>
<th><a id="headerCity" href="javascript:;">Ville</a></th>
</tr>
</thead>
<tbody>
<tr>
<td class="id">1</td>
<td class="date">2010-11-30</td>
<td class="city">Montréal</td>
</tr>
<tr>
<td class="id">2</td>
<td class="date">2010-11-17</td>
<td class="city">Toronto</td>
</tr>
<tr>
<td class="id">3</td>
<td class="date">2011-12-25</td>
<td class="city">Calgary</td>
</tr>
<tr>
<td class="id">4</td>
<td class="date">2010-10-05</td>
<td class="city">Vancouver</td>
</tr>
<tr>
<td class="id">5</td>
<td class="date">2009-01-19</td>
<td class="city">Ottawa</td>
</tr>
</tbody>
</table>
Incluez à votre page jQuery et le plugin TinySort :
<script type="text/javascript" src="/js/jquery-1.4.min.js"></script>
<script type="text/javascript" src="/js/jquery.tinysort.min.js"></script>
Et initialisez les liens en entête du tableau pour leur attacher un événement onClick qui permettra le tri ascendant (du plus petit au plus grand) selon la valeur qui se trouve dans la cellule portant le nom de la classe :
$j = jQuery.noConflict();

$j(document).ready(function(){
$j('#tableHeader a').click(
function(){
var sortBy = '';
switch($j(this).get(0).id){
case 'headerId' : sortBy = '.id'; break;
case 'headerDate' : sortBy = '.date'; break;
case 'headerCity' : sortBy = '.city'; break;
}
$j('table#myTableId tr').tsort('td' + sortBy, { 'order': 'asc' } );
}
);
});
L'idée de mettre une classe à chaque cellule me plaît moins mais c'est ce qui permet le tri des éléments sans trop se casser la tête. Notez que vous pouvez trier par le contenu texte de l'élément, par texte de l'élément enfant et par la valeur d'un attribut d'une balise (par exemple, le "value" d'un input). D'autres exemples pertinents de tri se trouvent dans la documentation, dont une façon alternative de trier des tables.


Tags: JavaScript

mardi 30 novembre 2010

Des arbres en 3D dans Google Earth 6

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

La 6ème édition du logiciel Google Earth est sortie hier. Parmi les nouveautés, la multinationale de Mountain View a ajouté une option impressionnante qui permet de visualiser les arbres en 3D selon un procédé de détection automatique par satellite (évidemment, c'est une simulation). 80 millions d'arbres virtuels auraient été plantés, représentant environ 40 espèces différentes (voir cet article intéressant à ce sujet).

Ici, une vue de la ville de New York à partir de Central Park.



Jusqu'à maintenant, seules quelques villes américaines et autres endroits spécifiques dans le monde bénéficient de cet nouvelle fonctionnalité (il faut croire que les villes de Montréal et Québec viendront beaucoup, beaucoup plus tard).

Pour activer l'option, rendez-vous dans le panneau Layers et cochez 3D Buildings ainsi que Trees.


Tags: Coffre à outils

dimanche 28 novembre 2010

Tracer une zone circulaire sur une carte Google

Publié par Infinite Loop, à 11 h 30 1 commentaire

Le restaurant qui prépare votre poutine préférée offre la livraison dans un rayon restreint de 3 kilomètres ? Vous voulez illustrer graphiquement la zone sur une carte Google ? Voici comment faire.

Tout d'abord, si c'est votre première expérience avec Google Maps, référez-vous à mon billet qui explique comment intégrer une carte Google à son site (en obtenant une clé d'API gratuite).

Incluez un conteneur HTML pour la carte en indiquant un ID unique qui pourra être utilisé dans la programmation JavaScript :

<div id="map" style="width:800px;height:600px"></div>
Ensuite, déclarez la carte, les coordonnées du point central du cercle et indiquez le rayon. À l'aide de votre ami jQuery, appelez la fonction principale au chargement de la page (sinon, faites-le dans l'événement onLoad de la balise body).

Le code JavaScript :
var map;
var center = new GLatLng(45.563234,-73.65614);
var radius = 3; // km

$(document).ready(loadMap);

function loadMap() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map"));
map.enableScrollWheelZoom();
map.setCenter(center, 13); // 13 = niveau de zoom

var centerMarker = new GMarker(map.getCenter());
map.addOverlay(centerMarker);

var points = new Array();

// rayon de la Terre = 6378.8 km
var d = radius/6378.8;

// radians
var lat1 = (Math.PI/180)* center.lat();
var lng1 = (Math.PI/180)* center.lng();

var bounds = new GLatLngBounds();

// calculer les 360 points du cercle
for(var i=0 ; i<=360 ; i++ ){
var tc = (Math.PI/180)*i;
var y = Math.asin(Math.sin(lat1)*Math.cos(d)+Math.cos(lat1)*Math.sin(d)*Math.cos(tc));
var dlng = Math.atan2(Math.sin(tc)*Math.sin(d)*Math.cos(lat1),Math.cos(d)-Math.sin(lat1)*Math.sin(y));
var x = ((lng1-dlng+Math.PI) % (2*Math.PI)) - Math.PI ;
var point = new GLatLng(parseFloat(y*(180/Math.PI)),parseFloat(x*(180/Math.PI)));

points.push(point);
bounds.extend(point);
}

if (d < 1.5678565720686044) {
circle = new GPolygon(points, '#ACACAC', 2, 1, '#ACACAC', 0.25);
}
else {
circle = new GPolygon(points, '#ACACAC', 2, 1);
}

map.addOverlay(circle);
map.setZoom(map.getBoundsZoomLevel(bounds));
}
}
La seule difficulté réside dans le fait qu'on doit utiliser un polygone et calculer avec une formule mathématique chaque point du cercle (1 par degré). Le résultat obtenu est réussi:



Pour en revenir au restaurant que je mentionnais, je ne connais pas vraiment l'étendue de leur zone de livraison. La plupart du temps, je prends mes commandes en take-out. Avec 10% d'escompte au comptoir, essayez la grosse poutine Mistinguette (frites, viande fumée, sauce à la viande, le tout gratiné). Pendant la préparation, allez faire un tour au dépanneur juste à côté et découvrez leur belle sélection de bières de microbrasseries québécoises. Hum... l'heure du lunch approche...


Tags: JavaScript

Citation no. 109 sur Facebook

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

Facebook, c'est comme la prison. Vous y perdez du temps, écrivez sur les murs et vous faites poker par des inconnus.

- Anonyme


Tags: Citations

vendredi 26 novembre 2010

Instrument de musique fabriqué avec des tuyaux

Publié par Infinite Loop, à 06 h 57 1 commentaire

Dans la catégorie des instruments de musique atypiques, ce gars en a inventé un plutôt original à l'aide de tuyaux en PVC. Il nous offre une performance stupéfiante en interprétant un medley d'extraits connus, de Rondo Alla Turca de Mozart, en passant par Lady Gaga et Ozzy Osbourne, le thème de Mario Bros et The Final Countdown en duo à la fin (et plusieurs autres). Incroyablement original et créatif.


Tags: Musique

jeudi 25 novembre 2010

Disque dur DeLorean USB de BTTF

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

Noël arrive dans exactement un mois. J'ai découvert aujourd'hui LE cadeau par excellence que j'aimerais recevoir en tant que geek assumé : un disque dur en modèle réduit de la DeLorean du film Back To The Future.


Spécifications techniques :

  • Disque dur Seagate de 500 GB
  • Échelle 1:18
  • Réacteur Mr Fusion!
  • 250$, payable par PayPal
  • Très, très geek (idéal pour faire des jaloux au bureau)
Sinon, la boutique Imaginaire.com de Ste-Foy (Québec) offre une réplique du convecteur temporel pour 349.99$. Ça serait de toute beauté dans une Yaris...

Mais bon, comme je n'ai pas été très sage cette année, je me contenterais d'un kit de modèle à coller ou encore d'un die cast (je sais, je n'ai toujours pas décroché de cette voiture mythique)... Autrement, il y a toujours le modèle de maquette en carton, mais je me vois mal placer mon disque dur dedans.


Tags: Curiosités

mercredi 24 novembre 2010

Les programmeurs mélangent l'Halloween et Noël

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

Demain, nous serons le 25 novembre, à 1 mois du compte à rebours de l'arrivée de la fête de Noël. Pour l'occasion, sur le thème du numéro 25, je vous offre cette petite devinette.

Savez-vous pourquoi les programmeurs ne font pas la différence entre l'Halloween et Noël ? Parce que Oct 31 == Dec 25.

Besoin d'explications ? Vous devez savoir que pour le commun des mortels, l'abréviation "Oct 31" équivaut au 31 octobre alors que "Dec 25" représente la date du 25 décembre. Pour quelqu'un de familier avec la programmation et les mathématiques, la signification est tout autre.

Le programmeur lira Oct 31 en tant que "valeur octale 31" et Dec 25 comme étant la "valeur décimale 25". Alors que le système décimal utilise la base 10, le système octal utilise une base 8.

Base 10 : 2 dizaines (2 x 10) + 5 unités = 25
Base 8 : 3 octets (1 octet = 8 bits, 8 x 3 = 24) + 1 bit = 25


Tags: Mathématique, Programmation, Saviez-vous que

mardi 23 novembre 2010

Top 5 des sites complètement inutiles

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

J'ai enfin trouvé un nouveau site inutile pour pouvoir créer mon top 5 des sites les plus inutiles. Je vous les présente donc, pas nécessairement dans l'ordre d'impertinence. Je vous laisserai en juger par vous-même.

Le blogue ultime de la productivité
Pour le meilleur conseil sur la productivité, on vous signale que vous devriez plutôt être en train de travailler.




Devrait-on utiliser des tables pour faire la mise en page HTML ?
Le site shouldiusetablesforlayout.com fournira une réponse claire à quiconque mettrait en doute cette vérité absolue.



Benoit Brunet
Oui, c'est un fait, le commentateur est maladroit dans ses descriptions de matchs de hockey. Un "hater" a pris les choses en main en s'appropriant le nom de domaine benoitbrunet.com pour résumer en quelques mots ce que les fans n'osaient pas dire tout haut.

Je tiens à dire que je ne partage pas nécessairement l'opinion de Habs or Die qui est derrière cette initiative. Comme disait Stéphane Richer : Y a pas juste le hockey dans la vie !

Perdu sur l'Internet ?
Pas de panique, ce site va vous aider à vous y retrouver. Le point concret sur une situation très problématique.


Une mention honorable puisqu'il fût créé en 1996 et obtient un remarquable Page Rank de 5 !

Nom de domaine trop long
Faut vraiment être con pour avoir une adresse internet aussi longue. 58 caractères, excluant le .com. Qui dit mieux ?


Avec tout ça, c'est quand même surprenant que personne n'ait encore acheté le nom de domaine answertolifetheuniverseandeverything.com pour y placer un 42 géant (disponible selon register.com). À qui la chance ?


Tags: Humour

lundi 22 novembre 2010

Désolé, vous ne savez pas compter

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

J'ai visité un vieux blogue à l'abandon et j'y ai trouvé une énigme intéressante que je reprends ici afin que vous tentiez à votre tour de la résoudre.

  • Observez l'image ci-dessous et comptez le nombre d'individus
  • Attendez qu'elle s'anime et comptez à nouveau


Source : Math à Jakarta


Quel est votre résultat ? 12 ? 13 ? Sauriez-vous expliquer l'astuce ?

Sans vous énerver qu'il disait...


Tags: Curiosités, Mathématique

dimanche 21 novembre 2010

Comment démarrer une vidéo YouTube à un temps spécifique

Publié par Infinite Loop, à 09 h 17 2 commentaires

La documentation de YouTube est claire à ce sujet. On peut utiliser le paramètre start pour indiquer à quelle seconde on souhaite faire démarrer le clip vidéo.

Pour l'intégrer au code HTML, on l'ajoutera comme paramètre GET, par exemple pour se positionner directement à la reprise au ralenti de l'impressionnant but du joueur de hockey Alexander Burmistrov. On indiquera la 38ème seconde comme temps de départ, que le service YouTube nous assure d'être valide avec une précision de +/- 2 secondes. Pour un temps au-delà de 60 secondes, il faudra effectuer le calcul (par exemple, 2 minutes et 5 secondes = 60*2+5 = 125).

<object width="640" height="385">
<param name="movie"
value="http://www.youtube.com/v/YxiJRx7F_5I?start=38">
</param>
<embed src="http://www.youtube.com/v/YxiJRx7F_5I?start=38"
type="application/x-shockwave-flash"
width="640"
height="385">
</embed>
</object>
Autrement, on pourra aussi utiliser une ancre pour positionner le début de la lecture au moment voulu en utilisant une notation indiquant l'heure (h), la minute (m) et la seconde (s). Dans le cas d'un long métrage comme The House On Haunted Hill (durée d'une heure et 14 minutes), on pourra référer à un passage précis en indiquant le temps sous cette forme dans le paramètre GET nommé "t" qu'on viendra ajouter à la fin de l'URL. Pour 1 heure, 10 minutes et 5 secondes : t=1h10m5s.

http://www.youtube.com/watch?v=NXPjWk5IZ-g&t=1h10m5s

YouTube Time, un petit outil web est disponible pour vous aider. Contrairement à mon exemple, il ne tient pas compte des heures. Il faut donc les convertir en minutes.


Tags: Intégration

Citation no. 108 sur le programmeur

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

A programmer is a device for turning energy drinks into rants about bad coding.

- @kwirq (Nolan Woods) sur Twitter


Tags: Citations, Programmation

samedi 20 novembre 2010

Clé USB à écran de 16 pouces

Publié par Infinite Loop, à 10 h 17 2 commentaires

Vous l'avez probablement vu sur FailQc plus tôt cette semaine. C'est maintenant le temps de vous rappeler que c'est ce matin que vous devez vous rendre chez Bureau en gros pour profiter du spécial "lève-tôt du samedi" pour vous procurer une clé USB Kingston avec un écran de 16 pouces (au lieu de capacité de 16 Go), au prix spécial de 9,99$.

Publié en première page de la circulaire web et papier, il semblerait que cette erreur ait échappé à la personne en charge de la révision. Quelqu'un, quelque part n'a pas fait son boulot correctement.

Si vous êtes employé de Bureau en gros, je serais curieux de savoir combien de clients vous ont fait la remarque et s'il y en a qui ont insisté pour avoir le modèle avec l'écran...

Selon les succursales, les magasins ouvrent à 9h ou 10h le samedi.


Tags: Curiosités

Mike Patton ressemble tout à fait à Johnny Depp

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

Une simple constatation qui plaira sans doute à la gente féminine et qui concerne le chanteur Mike Patton qui nous a donné d'excellents albums avec les formations Faith No more, Mr. Bungle, Fantômas et Tomahawk. Ne trouvez-vous pas qu'il ressemble étrangement à l'acteur Johnny Depp ?

À gauche, Mike Patton, à droite, Johnny Depp.



On dirait même que son sosie suit les mêmes modes au fil du temps.



Il ne faut surtout pas les confondre. L'un fait des films pour Disney, l'autre ne s'adresse surtout pas aux enfants. La preuve, l'excellente prestation de la pièce Urlo Negro (le cri de l'homme noir) de l'album Mondo Cane, sorti plus tôt cette année :



Lo sai che cosa hai fatto ? A me !
Savez-vous ce que vous avez fait ? Pour moi !

Vous trouverez une traduction italien-anglais des paroles de l'album Mondo Cane.


Tags: Musique

vendredi 19 novembre 2010

L'éthique des hackers

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

En 1984, Steven Levy (magazine Wired) énonçait les règles d'éthique des hackers dans son livre Hackers: Heroes of the Computer Revolution (chapitre 2, édition 25ème anniversaire).

Veuillez en prendre connaissance si ce n'est pas déjà fait.

  1. L'accès aux ordinateurs et tout ce qui pourrait vous apprendre quelque chose sur la façon dont le monde fonctionne, devrait être illimité et total. N'hésitez pas à vous retrousser les manches pour surmonter des difficultés
  2. Toutes les informations doivent être libres
  3. Méfiez vous de l'autorité. Faites la promotion de la décentralisation
  4. Les pirates devraient être jugés par leurs piratage, pas par des faux critères tels que les diplômes, l'âge, la race, ou leur position
  5. Vous pouvez créer de l'art et la beauté sur un ordinateur
  6. L'informatique peut améliorer votre vie
Maintenant, posez-vous la question pourquoi vous faites votre job. Tout simplement inspirant.


Tags: Livres, Lois et principes

mercredi 17 novembre 2010

Piège avec un URL en paramètre GET

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

Voici un piège sur lequel vous risquez de tomber si vous comptez passer un URL comme valeur dans la query string (peu importe le langage de programmation utilisé, ça ne s'applique pas exclusivement au PHP). Considérant un URL comme le suivant :

http://tests.localhost/script.php?active=1&redirect=http://www.google.com/page.php?q=test&limit=10

Vous remarquerez que parmi les paramètres passés dans la query string, il existe plusieurs clés dont "active" et "redirect". On note aussi que la valeur de la clé redirect est elle-même un URL. Donc l'URL complet compte deux "?" en plus des clés supplémentaires "q" et "limit". On pourrait s'attendre à ce que la valeur de la clé redirect soit "http://www.google.com/page.php?q=test&limit=10". Pourtant non.

echo $_GET['redirect']; // http://www.google.com/page.php?q=test
Aussi, la dernière combinaison de clé/valeur est manquante. Pourquoi ? Simplement parce que c'est une clé additionnelle qui est considérée comme partie intégrante de l'URL principal (pas de la valeur du paramètre redirect) et qui est séparée du reste avec le symbole "&". La paire q=test est complètement ignorée parce qu'elle fait partie de la deuxième combinaison :

?(active=1)&(redirect=http://www.google.com/page.php?q=test)&(limit=10)
echo $_GET['active']; // 1
echo $_GET['redirect']; // http://www.google.com/page.php?q=test
echo $_GET['limit']; // 10
Même la fonction parse_url() n'est pas d'un grand secours pour le décortiquer :
$url = 'http://tests.localhost/script.php?active=1&redirect=http://www.google.com/page.php?q=test&limit=10';

$urlParts = parse_url($url);
print_r($urlParts);
Array
(
[scheme] => http
[host] => tests.localhost
[path] => /script.php
[query] => active=1&redirect=http://www.google.com/page.php?q=test&limit=10
)
Pour contourner ce genre de problème, on devra préalablement transformer la valeur du paramètre redirect avec une fonction comme urlencode(). Le fichier script.php pourra ensuite extraire la valeur de la clé redirect en effectuant quelques manipulations et en décodant la valeur avant de faire la redirection.
$urlParam = urlencode('http://www.google.com/page.php?q=test&limit=10');
$url = 'http://tests.localhost/script.php?active=1&redirect=' . $urlParam;
$parts = parse_url($url);
$pairs = explode('&', $parts['query']);

$keys = array();
foreach($pairs as $pair){
list($key, $value) = explode('=', $pair);
$keys[$key] = $value;
}

header('Location: ' . urldecode($keys['redirect']) );
exit;
Certaines personnes pourraient avoir tendance à vouloir utiliser base64_encode() et base64_decode() pour encoder la valeur de l'URL passée en paramètre. Je ne vous recommande pas car vous risquez d'avoir un problème au moment de faire le split sur le caractère "=" (une chaîne encodée en base64 peut comprendre le caractère = dans le résultat).


Tags: PHP, Programmation

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 (55)
    • 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)
        • J'ai passé mon cours de programmation avec une not...
        • Piège JavaScript avec undefined et les closures
        • Mauvaise traduction double
        • Connexion VPN avec rdesktop d'Ubuntu à Windows
        • Jouer un wav avec PlaySound et contrôler le volume
        • Citation no. 113 sur le Père Noël
        • Meilleurs voeux pour Noël
        • Illusion d'optique animée
        • Hackers, heroes of the computer revolution
        • Script PHP pour obtenir la liste de tous ses statu...
        • Citation no. 112 sur le bonheur
        • Récupérer le contenu d'un fichier UIF en le conver...
        • Je n'ai jamais vu ce personnage dans Zelda
        • Évaluer des conditions multiples dans une instruct...
        • Redirections HTTP, JavaScript et Refresh
        • Nouvelle balise Datalist en HTML5
        • Machine de Rube Goldberg
        • Excusez-moi, avez-vous l'heure ?
        • Citation no. 111 sur la créativité
        • Épitaphe insultante
        • Flashback en 1981 avec Softporn Adventure
        • Image de webcam en ASCII art sur Linux
        • Comme le fondateur de WikiLeaks, je vire parano
        • Preuve de l'existence des extraterrestres
        • Citation no. 110 sur Internet
        • Démarrer Firefox en mode plein écran par une ligne...
        • Contourner la limitation de la fonction unnest sou...
        • La magie du contexte dans jQuery
        • Trier les éléments du DOM avec TinySort pour jQuery
      • ►  novembre 2010 (28)
        • Des arbres en 3D dans Google Earth 6
        • Tracer une zone circulaire sur une carte Google
        • Citation no. 109 sur Facebook
        • Instrument de musique fabriqué avec des tuyaux
        • Disque dur DeLorean USB de BTTF
        • Les programmeurs mélangent l'Halloween et Noël
        • Top 5 des sites complètement inutiles
        • Désolé, vous ne savez pas compter
        • Comment démarrer une vidéo YouTube à un temps spéc...
        • Citation no. 108 sur le programmeur
        • Clé USB à écran de 16 pouces
        • Mike Patton ressemble tout à fait à Johnny Depp
        • L'éthique des hackers
        • Piège avec un URL en paramètre GET
      • ►  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 (429)
      • ►  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 (36)
      • ►  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