Catégorie : développement

Tout ce qui concerne le développement en général, que ce soit des choses générales, ou des choses bien précises. Cela va de la gestion de projet à la recherche du fonctionnement de pointeurs en C.

Librairie Apr : tutoriel : aval officiel de l'auteur

J’ai eu l’aval officiel de l’auteur pour tout traduire et mettre en ligne sur mon site :
Voilà ce que j’ai demandé :

You’ve done a really really really good work with your apr tutorials.
I’d like to help the community by translating it in French and making it available in my site.
Example : (Exemple de document traduit)
May I go on or should I stop ?

Voilà sa réponse reçue au moment même où je fais cet article :

Hi, Olivier Pons,
Surely, you can go on.
It is my pleasure.
When you let me know the exact (I mean, a kind of permanent) URL, I will put the link on my site.
Thank you very much.
– INOUE Seiichiro

Pour information : regardez le tutoriel au complet, en Anglais, ici.
Vous trouverez tout ce tutoriel séparé en plusieurs pages ici.

Librairie Apr : tutoriel : mp-sample.c

Note

Regardez le tutoriel au complet, en Anglais, ici.
Vous trouverez tout ce tutoriel séparé en plusieurs pages ici.
Ce fichier est l’exemple le plus simple pour mettre en oeuvre les fonctions apr_xx
Il vient d’ici.

/**
 * apr tutorial sample code
 * http://dev.ariel-networks.com/apr/
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <apr_general.h>
#include <apr_pools.h>

#define MEM_ALLOC_SIZE		1024

/**
 * exemple de pool mémoire
 * @remark Vérif. des erreurs omise
 */
int main(int argc, const char *argv[])
{
    apr_status_t rv;
    apr_pool_t *mp;
    char *buf1;
    char *buf2;

    /* initialisation par processus (per-process) */
    rv = apr_initialize();
    if (rv != APR_SUCCESS) {
        assert(0);
        return -1;
    }

    /* créer un pool mémoire. */
    apr_pool_create(&mp, NULL);

    /* allouer de la mémoire via le pool */
    buf1 = apr_palloc(mp, MEM_ALLOC_SIZE);
    buf2 = apr_palloc(mp, MEM_ALLOC_SIZE);

    /* détruire le pool mémoire
      (ce qui était alloué au dessus sera
      automatiquement libéré) */
    apr_pool_destroy(mp);

    apr_terminate();
    return 0;
}

Librairie Apr : tutoriels 1 et 2

1. Disponibilité du tutoriel au complet

Regardez le tutoriel au complet, en Anglais, ici.
Vous trouverez tout ce tutoriel séparé en plusieurs pages ici.

2. Un squelette de code pour libapr

Je pense que c’est une bonne idée d’écrire un « squelette de code » au début, lorsque vous commencez à apprendre une nouvelle librairie ou un nouveau framework. Un ‘squelette de code’ est le plus petit morceau de code possible que vous pouvez compiler et exécuter (malgré le fait qu’il ne fasse rien de vraiment utile).
Heureusement, le squelette de code que l’on va faire pour la libapr est beaucoup plus simple que la plupart des frameworks modernes. Voyons apr-skeleton.c. On appelle apr_initialize() pour ouvrir la librairie, et apr_terminate() pour la fermer. C’est tout. Comme vous pouvez l’imaginer, le code ne fait rien du tout.
libapr n’est pas une librairie de type framework. Pour être plus précis, libapr ne vous aide pas du tout à concevoir la structure de votre code programme. Il y a des avantages et des inconvénients. L’avantage le plus important est que l’utilisation de libapr est très facile à utiliser et à intégrer dans du code existant. L’inconvénient principal est que vous devez concevoir la structure complète du code lorsque vous utilisez libapr.
Ici, nous avons tout de même quelques règles et style concernant libapr :

  • la règle de nommage est très simple et claire ;
  • les types de données opaques sont souvent utilisés (p.ex. les types incomplets) ;
  • la plupart des retours de fonctions sont apr_status_t et si besoin est, certaines variables en paramètre sont aussi des arguments résultats ;
  • règles de pool mémoire.

On peut voir les styles et les règles directement par cet exemple :

/* extrait de mp-sample.c */
apr_status_t rv;
apr_pool_t *mp;
rv = apr_pool_create(&mp, NULL);

Voici l’explication du code : ici ne regardez que la notation. Vous voyez le préfixe apr_. Ce dernier indique que le symbole fait partie de l’espace de nommage de la librairie libapr. Le suffixe _t précise que le nom concerné est un type.
apr_pool_t est un type opaque. Cela signifie que la structure de ce type n’est pas publique. En utilisant une terminologie de style OO (Object Oriented), toutes les variables membres sont privées. Vous ne pouvez pas y accéder directement. Vous ne pouvez pas les voir dans les fichiers « .h » non plus. La seule chose que vous puissiez faire pour ce type est d’appeler une API qui l’utilise, telle que apr_foo_bar() par exemple. Plus important encore, vous ne pouvez créer une instance de ce type dynamiquement. Vous êtes obligé de passer par une fonction d’allocation de la librairie. Seule libapr sait comment construire et détruire ce genre d’objets.
Comme vous pouvez le voir, le type de retour de la fonction apr_pool_create() est apr_status_t. apr_status_t est soit un code indiquant un status soir un code d’erreur. apr_status_t is est utilisé couramment en tant que type de valeur de retour par la plupart des fonctions de l’APIs. De la même façon, on peut recevoir des résultats de fonction via des arguments. De tels arguments sont appelés arguments-résultat. Il y a beaucoup d’arguments-résultat dans le monde de la libapr.
En général, si vous voyez le type apr_foo_t, vous verrez des fonctions apr_foo_bar(), qui ont un lien avec le type apr_foo_t. Le code qui suit est un pseudo code courant :

/* pseudo code of libapr. Vérif. des erreur omise */

apr_status_t rv;
apr_foo_t *foo;

/* créer un objet @foo selon @args : */
rv = apr_foo_create(&foo, args...);

/* faire quelque chose avec @foo : */
rv = apr_foo_do_something(foo, args...); /*  */

/* détruire l'objet @foo. */
apr_foo_destroy(foo);

/* NB : Parfois la destruction d'un objet est
   faite implicitement lorsque le pool mémoire
   associé est détruit. */

WordPress : comment faire si on déplace tout

C’est valable pour WordPress 2.5.1. Je ne sais pas pour les autres versions.
Lorsque vous voulez tout déplacer d’un répertoire vers un autre, et que vous ne voulez rien perdre de vos articles, c’est plutôt simple. Soit vous faites la modification avant de déplacer le répertoire, dans votre outil d’administration, soit vous… êtes dans le pétrin.
Mais plus maintenant !
Le principe est de modifier toute la configuration de votre WordPress par la nouvelle.
Voilà le cas typique : j’ai déplacé tout de :

http://olivier.pons.free.fr/wordpress/

vers :

http://olivier.pons.free.fr/

Solution : il vous faut ouvrir le fichier

wp-includes/functions.php

et aller à la fonction

wp_load_alloptions()

Juste après cette ligne :

$wpdb->suppress_errors($suppress);

vous y ajoutez l’affichage de toutes vos options :

echo "<pre style=\"text-align:left\">".var_export($alloptions_db,true)."</pre>";

Puis vous retournez sur votre blog et vous rafraichissez. Vous allez voir toute une série d’options apparaitre.

Cherchez lesquelles ont une valeur qui contient l’ancien répertoire.
Il vous faut transformer ces options sous cette forme :

  $wpdb->update($wpdb->options,
    array( 'option_value' => 'valeur nouvelle adresse' ),
    array( 'option_name'  => 'nom de l'option', 'autoload' => 'yes'));

et coller cela à la place de votre ligne qui affiche les variables (« echo … ») que je vous ai dit de mettre en début d’article.
Par exemple, mes deux options à appliquer étaient celles-ci :

  $wpdb->update($wpdb->options,
    array( 'option_value' => 'http://olivier.pons.free.fr' ),
    array( 'option_name'  => 'siteurl', 'autoload' => 'yes'));
  $wpdb->update($wpdb->options,
    array( 'option_value' => 'http://olivier.pons.free.fr' ),
    array( 'option_name'  => 'home', 'autoload' => 'yes'));

Ensuite, vous rafraichissez votre page, et hop, tout est écrit en base de données.

Après vérification que tout fonctionne, il ne vous reste plus qu’à supprimer toutes les lignes

$wpdb->update()

qui ne servent plus à rien.

Zeemoz – dev : entrées terminées

Ca y est maintenant on peut entrer tout ça sans problème, ça fonctionne :

0 => marseille
1 => Marseille
2 => MARSEILLE
3 => abbeville st lucien
4 => abbeville saint lucien
5 => abbeville-saint-lucien
6 => aix en provence entre 200000 et 500000 euros
7 => aix en provence
8 => entre 200000 et 500000 euros
9 => 13 entre 200000 et 500000 euros
10 => 13013 entre 200000 et 500000 euros
11 => 13013 entre 200000 et 500000euros
12 => 13013 entre 200000 et 500000
13 => loyer entre 200000 et 500000
14 => prix entre 200000 et 500000

Je crois que je vais recommencer à être un peu fatigué. Bonne fin de nuit à tout le monde…

MySQL : astuces pour quelques ordres de base

Voici quelques astuces dont je me sers souvent, pour ne pas avoir à systématiquement les rechercher, je m’en suis fait une copie dans un petit champ texte :

  1. Création d’une base de données
    CREATE DATABASE z DEFAULT CHARACTER SET utf8;
  2. Initialisation d’une variable via une requête :
    SELECT @MON_ID:= ID FROM matable WHERE CHAMP='champ_recherche';
    puis on se ressert de cette variable pour faire une insertion en base de données :
    INSERT INTO autre_table (ID_CLE_EXTERNE, DESCRIPTION, DOCUMENT) VALUES
    (@MON_ID, 'valeur1', './valeur2');
  3. Relancer le service MySQL
    1. service mysqld stop
    2. attendre une trentaine de secondes afin que le cache soit vidé et que toutes les allocations mémoires soient correctement libérées
    3. service mysqld start
  4. Convertir une table en utf8 :
    Très important : si vous tapez ce qui suit avec pour objectif de convertir la table et les données cela ne fonctionnera pas :
    ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
    Ce n’est qu’en utilisant les ordres suivants que la conversion sera faite par MySQL !
    ALTER TABLE t1 CHANGE c1 c1 BLOB;
    ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;
  5. Renommer un champ :
    Ici, je renomme la clé primaire « ID » et je la passe en minuscules (« id« ) :
    ALTER TABLE ville CHANGE ID id int(11) NOT NULL auto_increment;
  6. Modification des AUTO_INC
    Pour changer la valeur d’un auto_inc (‘réinitialiser la valeur’, comme on le dit dans MySQL ici) :
    ALTER TABLE tbl_name AUTO_INCREMENT = N
  7. Créer un utilisateur pour une base de données (la manière sale)
    Important : d’abord sans le ‘.*’ sinon ça ne fonctionne pas, et puis refaire avec le '.*'.
    Très important : ici on autorise tout à l’utilisateur qui va être crée. C’est donc une méthode rapide mais de bourrin et ce n’est pas la bonne méthode si vous voulez faire un utilisateur proprement, destiné à exister pour longtemps. Dans ce cas il faut faire quelque chose de plus précis afin de ne pas tout lui autoriser.
    GRANT ALL PRIVILEGES ON basededonnees
    TO ‘nomutilisateur’@’192.168.2.16’
    IDENTIFIED BY ‘motdepasse’;
    GRANT ALL PRIVILEGES ON basededonnees.*
    TO ‘nomutilisateur’@’192.168.2.16’
    IDENTIFIED BY ‘motdepasse’;

Zeemoz : berkeleydb : linké avec la librairie !

J’ai trouvé comment linker les exemples de berkeley DB avec la librairie :
Lors de la compilation, l’utilitaire de lien (ld) va chercher les toutes dernières librairies qu’il connait et les lie à l’executable. Seulement, quand il ne connait pas les librairies, il faut les ajouter.
L’opération est simple : il faut lire le fichier
/etc/ld.so.conf
Sur une distro Debian, il ne contient que cette ligne : include /etc/ld.so.conf.d/*.conf
C’est donc dans le répertoire /etc/ld.so.conf.d/ qu’il nous faut créer un fichier avec un nom explicite, qui spécifie où le linker doit aussi aller chercher les librairies.
Dans mon cas j’ai crée un fichier nommé /etc/ld.so.conf.d/db.4.5.conf dans lequel j’ai mis :
# creation olivier pons 2 mai 2007
/home/sources/db-4.5.20/build_unix/.libs
Ensuite, il suffit juste de dire au linker de recharger son cache :
ldconfig
Pour plus d’infos : man ldconfig !

Dix règles d'or pour les filtres de sortie.

Le contenu en Anglais non traduit se trouve ici.

Voilà les règles que doivent suivre à la lettre les filtres de sortie :

  1. Les filtres de sortie ne devraient pas passer de brigades vides le long de la chaine de sortie, mais devraient être tolérantes sur l’arrivée de brigades vides.
  2. Les filtres de sortie doivent passer tous les seaux de métadonnées (metadata buckets) le long de la chaine de sortie ; les seaux de vidages (FLUSH buckets) devraient être respectés en passant tous les seaux en attentes le long de la chaine de sortie.
  3. Les filtres de sortie devraient ignorer tous les seaux qui suivent un seaux de fin de fichier (EOS buckets).
  4. Les filtres de sortie doivent traiter une quantité fixe de données, à la fois, afin de s’assurer que la consommation mémoire n’est pas proportionelle à la taille du contenu qui est filtré.
  5. Les filtres de sortie devraient ignorer les types de seaux, et doivent être capables de traiter des seaux de type inconnu.
  6. Après avoir appelé ap_pass_brigade pour faire suivre une brigade le long de la chaine de filtres, les filtres de sortie devraient appeler apr_brigade_cleanup pour s’assurer que la brigade est vide avant de s’en resservir ; les filtres ne devraient jamais utiliser apr_brigade_destroy pour « détruire » des brigades.
  7. Les filtres de sortie doivent mettre de côté les seaux qui sont destinés à être gardés plus longtemps que la durée du filtrage.
  8. Les filtres de sortie ne doivent pas ignorer la valeur de retour de ap_pass_brigade, et doivent renvoyer les erreurs appropriées en retour, à la chaine de filtres.
  9. Les filtres de sortie doivent seulement créer un nombre fixe de brigades de seaux pour chaque réponse, plutôt que une par invocation.
  10. Les filtres de sortie devraient en tout premier lieu essayer des lectures non bloquantes sur chaque seau, et envoyer un buffer de vidage (FLUSH bucket) le long de la chaine de filtres si la lecture doit être faite à nouveau, et de manière bloquante, avant de recommencer une lecture bloquante.

Sachant que la règle 9 n’est pas très claire pour moi, je vous la relivre en Anglais :
Output filters must only create a fixed number of bucket brigades for each response, rather than one per invocation.

Apache : notes pour les filtres

Voilà ce que j’ai mis longtemps à comprendre :

Lorsqu’un client envoie quelque chose à httpd, le serveur Web commence à créer des seaux qu’il remplit au fur et à mesure : et quand un seau est plein, il en remplit un autre etc jusqu’à ce qu’il ait un nombre de seaux suffisants. Ces seaux sont rangés dans une brigade. Une brigade de seaux. Une bucket brigade, en Anglais. Et là, il les fait passer au premier filtre qu’il a sur sa liste. Ce filtre peut à son tour, ajouter d’autres seaux, en enlever, ou même, tout supprimer et créer toute une série d’autres seaux. Toujours est-il que quand on développe un filtre, il faut toujours avoir en tête plusieurs choses :

  • Il va toujours y avoir une série de seaux qu’il va falloir parcourir, ce ne sera jamais un seul seau simple et seul. La boucle de parcours sera toujours de la forme :
    /* on demande à lire une série de seaux : */
    rv = ap_get_brigade(f->next, bb, AP_MODE_READBYTES, APR_BLOCK_READ, readbytes);
    /* si erreur, la gérer, sinon boucle pour lire seau après seau : */
    for (b = APR_BRIGADE_FIRST(bb);
         b != APR_BRIGADE_SENTINEL(bb);
         b = nextb) {
        nextb = APR_BUCKET_NEXT(b);
        ...
        traitement de ce qu'on a reçu
        ...
    }
  • Le serveur Apache gère une chaine de filtres, qui se suivent dans un ordre qu’il est impossible à connaitre du point de vue d’un filtre. En résumé, on ne sait jamais, quand on programme un filtre, quels sont les filtres qui ont été appelés avant le nôtre, ou quels sont les filtres le seront après. Bon ok. Il y a quand même une possibilité de dire grossièrement où on veut que le filtre soit, dans la chaine. En réalité il est possible de préciser l’un cinq niveaux grossiers parmi :
    1. APR_HOOK_REALLY_FIRST
    2. APR_HOOK_FIRST
    3. APR_HOOK_MIDDLE
    4. APR_HOOK_LAST
    5. APR_HOOK_REALLY_LAST

    Revenons à notre brigade, pleine de seaux, mais dont on ne sait pas exactement ce qu’elle contient, mais on le suppose. Lorsque celle-ci arrive et que notre filtre est appelé, on ne sait que grossièrement où est placé le filtre dans la chaine, donc il se peut que la brigade arrive avec des données en plus qui proviennent d’autres filtres mais qui ne nous concernent pas (entre autres des données personnelles qui vont d’un filtre à l’autre, des méta-données, en Anglais METADATA). C’est pour cela qu’il faut toujours s’assurer que ce ne sont pas des métadonnées qui ne nous concernent pas : c’est la macro APR_BUCKET_IS_METADATA :
    /* on demande à lire une série de seaux : */
    rv = ap_get_brigade(f->next, bb, AP_MODE_READBYTES, APR_BLOCK_READ, readbytes);
    /* si erreur, la gérer, sinon boucle pour lire seau après seau : */
    for (b = APR_BRIGADE_FIRST(bb);
         b != APR_BRIGADE_SENTINEL(bb);
         b = nextb) {
        nextb = APR_BUCKET_NEXT(b);
        if ( ! APR_BUCKET_IS_METADATA(b) ) {
            ...
            traitement de ce qu'on a reçu
            ...
        }
    }

Zeemoz : créer un nouveau module C pour Apache

Aller dans le répertoire des sources, et taper :

/opt/httpd-2.2.4/bin/apxs -g -n modulenouveau

Il va créer un répertoire ./modulenouveau et à l’intérieur les fichiers Makefile et mod_modulenouveau.c, qui contient le squelette du code tel qu’attendu par Apache.
Ensuite il ne reste qu’à remplir.
Pour le script d’installation, il n’y a qu’à copier /usr/bin/modsearch_install.sh en modmodulenouveau_install.sh et modifier uniquement les variables $SOURCES et $MOD.