[couverture de Linux Magazine 73]

Perles de Mongueurs (14)

Article publié dans Linux Magazine 73, juin 2005.

[+ del.icio.us] [+ Developers Zone] [+ Bookmarks.fr] [Digg this] [+ My Yahoo!]

Testez Google Suggest chez vous !

Vous connaissez Google Suggest[1] ? Ou CPAN Suggest[2] ? Vous voudriez l'utiliser pour le tester ? Alors, lisez ce qui suit, mais attention, le code JavaScript de ac.js n'est pas libre de droits, car sous évident copyright de Google.

Un nom a été donné[3] récemment à cette technique : Ajax, contraction de Asynchronous JavaScript + XML. Pour résumer, le but de l'utilisation de méthodes de développement web de type Ajax est de mettre à jour des morceaux de pages HTML sans pour autant recharger l'intégralité de la page. Cela permet de réduire d'autant la bande passante utilisée, plutôt que de faire recharger une page à chaque mise à jour. Ça permet aussi de faire des requêtes dynamiquement à un serveur HTTP pour pré-renseigner des champs de saisie, de façon à améliorer l'ergonomie d'une application web. On peut même réaliser des formulaires dont les champs sont validés au fur et à mesure de leur saisie, comme pour une application classique.

Dans notre cas, ça va nous servir à remplir un champ devant contenir une adresse mail à partir de la frappe d'un nom, sans pour autant ouvrir un annuaire dans un autre onglet du navigateur.

Mais faisons fi des explications du fonctionnement, détaillées[4] par ailleurs, sachez simplement que le tout se base sur une invention de Microsoft (via un ActiveX, XMLHTTP), reprise par Mozilla, qui a le doux nom de XMLHttpRequest. Cette fonction JavaScript permet de mettre en œuvre un client HTTP (le XML n'est pas obligatoire, mais peut être géré) asynchrone dans la page. Pourquoi asynchrone ? Parce que s'il ne l'était pas, vous ne pourriez continuer à taper sur le clavier en espérant une réaction à la frappe d'un caractère avant que la dernière réaction ne se soit terminée.

Passons maintenant à la pratique, et à ce qu'il faut préparer côté serveur pour que ça fonctionne.

Nous aurons besoin d'un formulaire dont un champ devra être completé, un serveur web gérant les CGI, d'un peu de Perl, et du fichier ac.js récupéré sur Google[5], que nous allons modifier comme suit :

  perl -pi.orig -e 's!(\"/*)complete(/*\")!$1cgi-bin$2!g' ac.js

Cela permettra de joindre notre CGI sous le chemin /cgi-bin/ de notre serveur web.

Notre but sera de rechercher de remplir le champ par une adresse mail alors que nous tapons un uid. La source de données sera un annuaire LDAP.

Le formulaire devra comporter un champ texte comme suit :

    <form method="get" name=monform action="http://localhost/cgi-bin/test.cgi">
        <label for="nom">Nom&nbsp;:</label>
        <input type="text" name="nom" autocomplete=off size=50 value="*"/>
        <input type="submit" name="submit" id="submit"/>
    </form>

Ce formulaire porte un nom (monform), et le champ qui nous intéresse est nom. L'action test.cgi est là pour vérifier que le tout fonctionne correctement.

Il nous faut aussi invoquer le script de Google. Pour ça, trois lignes à ajouter après (pour que les objets du DOM soient chargés dans JavaScript) le formulaire :

    <SCRIPT src="ac.js"></SCRIPT>
    <SCRIPT> InstallAC( document.monform, document.monform.nom,
        document.monform.submit, "ldap.pl", "en"); </SCRIPT>

En gros, cela installe l'auto-complétion JavaScript sur le champ monform.nom.

Vient ensuite le script Perl (ldap.pl) pour nourrir l'ensemble :

  #!/usr/bin/perl -w
  use strict;
  use Net::LDAP;
  use CGI qw(:standard);

  my $mesg;

  my $ldap = Net::LDAP->new("localhost", port => 389, version => 3)
     or die "erreur LDAP: Can't contact master ldap server ($@)";

  $mesg = $ldap->bind( "cn=Manager,dc=example,dc=com", password => 'secret' );
  $mesg->code && die $mesg->error;

  print << "EOF";
  Content-Type: text/javascript; charset=ISO-8859-1

  EOF

  my $name=param('qu');
  if (defined $name) { $name =~ s/\*//g; } else { exit 0; }

  $mesg = $ldap->search( base   => 'ou=People,dc=example,dc=com',
    scope  => 'sub', filter => "(uid=$name*)", attrs  => [ qw(uid mail) ] );
  $mesg->code && die $mesg->error;

  my (@a1, @a2, @a3);
  foreach my $entry ($mesg->all_entries) {
      if ($entry->get_value('mail')) {
          push @a1, $entry->get_value('uid');
          push @a2, $entry->get_value('mail');
      }
  }
  $ldap->unbind();
  @a3 = "0" x  scalar a1;

  print "sendRPCDone( frameElement, \"$name\",";
  print "new Array(\"", join('","', @a2), "\"), ";
  print "new Array(\"", join('","', @a1), "\"), ";
  print "new Array(\"", join('","', @a3), "\") );";

Passons la connexion à l'annuaire, déjà abordée dans ces colonnes. Remarquez l'utilisation du module CGI avec l'interface non-objet (qw(:standard)). Cela va nous permettre l'utilisation de la fonction param pour récupérer le champ qu demandé à notre CGI par ac.js.

Ce même script demande la création d'un appel à la fonction JavaScript sendRPCDone avec pour paramètre le nom de l'objet mis à jour et surtout deux tableaux avec les résultats. Un troisième tableau (non-vide) est demandé en paramètre sinon les résultats ne s'affichent pas. Notez au passage sa création utilisant l'opérateur multiplicateur en fonction du nombre d'éléments du tableau @a1.

Vous pourrez inverser les lignes contenant les join sur @a1 et @a2 suivant que l'élément recherché est le mail ou l'uid, l'autre étant affiché à titre indicatif.

Pour déboguer le tout, pensez à utiliser multitail qui est très pratique pour suivre à la fois l'access_log et l'error_log d'Apache.

Enfin, le code de Google n'est pas (encore ?) réentrant (il change régulièrement). Cela signifie que vous ne pourrez avoir sur un formulaire donné qu'un seul champ pour lequel la complétion pourra être activée.

(Jérôme Fenal, Paris.pm - <jfenal@free.fr>)

À vous !

Envoyez vos perles à perles@mongueurs.net, elles seront peut-être publiées dans un prochain numéro de Linux Magazine.

[IE7, par Dean Edwards] [Validation du HTML] [Validation du CSS]