[spip-dev] Bug et Patch

Dans la fonction propre du fichier inc_texte.php3, la
boucle "Echappement pour texte brut et appels HREF",
s'effectue avec la fonction eregi (expression régulière
insensible à la case), mais à l'intérieur de la boucle,
il y a un appel à la fonction split, avec la même
expression régulière. Or la fonction split est sensible
à la case.

Le résultat est une boucle infinie et un timeout dans
des articles qui contenaient des "<a" en minuscule.

Pour corriger, il faut remplacer la ligne 493:

$zetexte = split($regexp_echap,$letexte,2);

par les lignes:

$pos_regexp = strpos($letexte, $regs[0]);
$zetexte[0] = substr($letexte, 0, $pos_regexp);
$zetexte[1] = substr($letexte, $pos_regexp + strlen($regs[0]));

Cordialement

Michaël

En fait c'est le eregi() qu'il faut changer en ereg(), -- cf. fonction
typo() juste au-dessus. Je fais la modif dans la version 1.0.3 ; merci.

@ Michaël Parienti (parienti@parienti.org) :

Dans la fonction propre du fichier inc_texte.php3, la
boucle "Echappement pour texte brut et appels HREF",
s'effectue avec la fonction eregi (expression régulière

-- Fil

J'aimais bien l'idée de pouvoir utiliser HTML ou html,
indifférement en majuscule et en miniscule, voir même
en mélangeant les deux!

Mais c'est peut être tordu comme comportement...

Michaël

@ Michaël Parienti (parienti@parienti.org) :

> > Dans la fonction propre du fichier inc_texte.php3, la
> > boucle "Echappement pour texte brut et appels HREF",
> > s'effectue avec la fonction eregi (expression régulière

J'aimais bien l'idée de pouvoir utiliser HTML ou html,
indifférement en majuscule et en miniscule, voir même
en mélangeant les deux!

Mais c'est peut être tordu comme comportement...

non non, mais la bonne solution est d'introduire un autre marqueur
interdisant la coupe, et de convertir <HTML> (et <html>) en ce marqueur, un
peu en amont. Il faut trouver un marqueur interne qui

- 1/ ne soit pas utilisé par ailleurs

- 2/ soit facile à parser (parce que parser <HTML>xxxxx</HTML> c'est
    pas de la tarte :
    <HTML>([^<]|<[^/]|</[^H]|</H[^T])*</HTML>

    Je m'explique : le problème est qu'on veut prendre le MINIMUM de texte,
    au cas où il y ait deux séquences successives. Or PHP ne fait pas
    les expressions régulières "non gourmandes"...

Est-ce qu'on peut prendre <x> ?

    l'expression deviendrait :
    <x>([^<]|<[^/]|</[^x]|</x[^>])*</x>

Pour faire plus simple et/ou plus lisible, il faut reprogrammer en strpos(),
mais là je plaide non-capable !

-- Fil

Est-ce que la boucle suivante répondrait à tes besoins:

$preserve_start_tag = "<spip_preverse>";
$preserve_end_tag = "</spip_preverse>";
$size_preserve_start_tag = strlen($preserve_start_tag);
$size_preserve_end_tag = strlen($preserve_end_tag);

while ($preserve_start_pos = strpos(strtolower($letexte), $preserve_start_tag)) {
    $preserve_end_pos = strpos(strtolower($letexte), $preserve_end_tag);
    if ( !$preserve_end_pos ) {
        $preserve_end_pos = strlen($letexte);
    }
    $compt_sources++;
    $zesources[$compt_sources] = substr($letexte,
                                        $preserve_start_pos + $size_preserve_start_tag,
                                        $preserve_end_pos - ($preserve_start_pos + $size_preserve_start_tag) );
    $letexte = substr($letexte, 0, $preserve_start_pos)."<SOURCE$compt_sources>".substr($letexte, $preserve_end_pos + $size_preserve_end_tag );
}

?

Je n'utilise pas d'expression régulière. j'ai pris un tag
<spip_preserve>, mais on peut le changer facilement, et
prendre un tag plus simple pour l'utilisateur.

De plus, dans la tableau $zesource j'ai enlevé les tags.

Michaël

Pas tout à fait. Car si strpos() vaut 0, ça peut être parce que la chaîne
commence au premier caractère. d'où bugs en cascade. If faut tester un
truc du genre is_num(strpos())...

En plus tu compliques inutilement en ayant un start-tag et un end-tag. Fais
juste "<".$tag_preserve et "</".$tag_preserve ?

@ Michaël Parienti (parienti@parienti.org) :

Est-ce que la boucle suivante répondrait à tes besoins:

-- Fil

Fil wrote:

Pas tout à fait. Car si strpos() vaut 0, ça peut être parce que la chaîne
commence au premier caractère. d'où bugs en cascade. If faut tester un
truc du genre is_num(strpos())...

Ce qui donne quelque chose comme cela:

$preserve_tag = "spip_preverse";
$preserve_start_tag = "<".$preserve_tag.">";
$preserve_end_tag = "</".$preserve_tag.">";
$size_preserve_start_tag = strlen($preserve_start_tag);
$size_preserve_end_tag = strlen($preserve_end_tag);

while ($preserve_start_pos = strpos("_".strtolower($letexte),
$preserve_start_tag)) {
    $preserve_end_pos = strpos(strtolower($letexte), $preserve_end_tag);
    if ( !$preserve_end_pos ) {
        $preserve_end_pos = strlen($letexte);
    }
    $compt_sources++;
    $zesources[$compt_sources] = substr($letexte,
                                        $preserve_start_pos +
$size_preserve_start_tag,
                                        $preserve_end_pos -
($preserve_start_pos + $size_preserve_start_tag) );
    $letexte = substr($letexte, 0,
$preserve_start_pos)."<SOURCE$compt_sources>".substr($letexte,
$preserve_end_pos + $size_preserve_end_tag );
}

Il n'y plus qu'une seule variable, qui soit "variable"; il
s'agit de $preserve_tag. Toutes les autres variables sont
déduites de celle-là.

la bug du strpos est résolu en ajoutant un caractère devant
la chaine que l'on recherche. Ce qui fait que si la chaine
recherchée est présente au tout début, elle sera en position
1 et pas en position 0.

Dans le deuxième strpos, le tag fermant se trouve après le
tag ouvrant. Donc il ne sera jamais en position 0. (sinon,
le document est mal formé, ce qui se traduit par la
"préservation" de tout le texte après le tag fermant.)

Michaêl

ps: je n'ai pas testé ce bout de code, parce qu'au moment
    où je réponds, je n'en ai pas les moyens

Hello,

J'ai amélioré les connexions à MySQL dans la 1.0.3. Dans
l'espace public, ça ne se connecte plus que si nécessaire.
Il y a donc beaucoup d'accès qui ne donnent plus lieu
à aucune connexion MySQL, ce qui soulage d'autant plus
la base de données. Ainsi, les rubriques, brèves, sommaires
en cache. Les articles en cache déclenchent toujours une
connexion, mais uniquement à la fin pour les stats : la
connexion est ouverte pendant un temps très réduit.

Pour ça, il a fallu que je bidouille un peu avec les
variables meta. Un inc_meta_cache.php3 est généré
automatiquement dans le répertoire ecrire, de façon
à avoir directement les valeurs de la table spip_meta
sous forme de tableau PHP depuis l'espace public.
A cet effet, une nouvelle fonction ecrire_metas() doit
être appelée à chaque fois que ce fichier doit être
recalculé (il est aussi recalculé toutes les 24 heures,
au cas où).

D'autre part, j'ai également réduit la charge en
terme de include() dans inc-public : la plupart des
fichiers inclus le sont seulement si besoin est.
Ce qui fait que dans le cas minimal, inc-public
n'inclut que ecrire/inc_version, et ne dérange pas
le serveur MySQL. Par contre, il y a toujours un
gros bout de code qui n'a rien à faire dans
inc-public, et qui concerne la gestion des pétitions
et de l'inscription des rédacteurs. J'invite l'auteur
dudit code à y remédier ;)))

(NB : j'ai supprimé le message d'erreur dans l'espace
public, quand la base de données est injoignable...)

Il y a pas mal de fichier modifiés, il vaut mieux donc
tout reprendre.... (snif CVS ;-)))

a+

Antoine.

Salut,

Content de voir que Michael plonge dans le code de SPIP.

Cependant, j'attire votre attention sur l'un des développements prévus de SPIP, qui doit interdire d'ajouter trop de souplesse à SPIP: il s'agit de la possibilité (future) d'échanger des articles directement (et automatiquement) de site à site (du peer to peer de contenu, hé hé).

En effet, comme on a finalement retenu, dans SPIP, le choix d'une structure de base de données figée (c'est-à-dire qu'on n'a pas la possibilité d'ajouter des champs spécifiques à un article) - choix d'abord motivé par la simplicité de l'interface que cela permettait-, il est prévu de tirer avantage de cette limitation: à partir du moment où tous les articles de tous les sites sous SPIP ont la même structure, il devient très facile d'échanger ces articles d'un site à l'autre. Parce que le titre sera toujours le titre, et le texte sera toujours le texte.

Du coup, si on peut se permettre de modifier localement (i.e. sur son propre site) la façon dont les balises (raccourcis) de mise en page sont utilisées (ajouter des espaces avant/après les intertitres, etc.), il est impératif que tout le monde utilise les mêmes balises. Donc: si c'est <HTML>, alors c'est <HTML> pour tout le monde. Sinon, lors de l'échange, c'est rapé. (Bien entendu, on pourrait imaginer exporter des sortes de description des comportements de ces balises, sauf que (1) ça induit généralement d'exporter carrément des sources PHP, et pas seulement des descriptions de CSS ou de HTML; (2) risque de conflits entre pseudo-balises identiques (par exemple, il semblerait logique d'utiliser les doubles-crochets pour un [[nouveau raccourci]], mais si 2 sites les utilisent pour des comportements différents, on est marrons).

Donc : oui pour pouvoir modifier localement le comportement d'affichage d'une balise SPIP (dans la limite où ce comportement est similaire au comportement général); mais non on ne doit pas laisser la liberté de créer ses propres balises "facilement", sauf à nous interdire ensuite ce grand pas pour l'humanité que sera l'échange d'articles de site à site :slight_smile:

Amicalement,
ARNO*

J'ai amélioré les connexions à MySQL dans la 1.0.3. Dans
l'espace public, ça ne se connecte plus que si nécessaire.

Yop, épatant!

Y'a un autre truc qu'on pourrait modifier pour améliorer, c'est la mise à jour de la syndication. L'appel aux sites syndiqués (mise à jour de spip_syndic_articles) se fait à chaque recalcul d'une page. Ce qui est beaucoup trop et interdit notamment d'afficher trop d'articles syndiqués sur une même page (dans uZine, j'ai remplacé l'affichage des articles syndiqués par secteur par les articles uniquement par rubrique).

Il suffirait d'ajouter un champ MAJ dans spip_syndic, incrémenté à chaque mise-à-jour des articles syndiqués correspondants, et de n'effectuer la mise à jour que, par exemple, toutes les 3 heures (tiens, on pourrait ajouter/retirer aléatoirement dans un intervalle de 1 heure autour de la véritable mise à jour pour interdire que les mises à jours de plusieurs sites syndiqués se synchronisent).

Mais bon, Antoine, comme t'es en train de bosser dessus, je préfère pas toucher. Tu veux t'en occuper, ou bien tu me donnes une plage horaire pendant laquelle je peux intervenir pour saloper ton code? :-))

Amicalement,
ARNO*

ARNO* wrote:

Yop, épatant!

Ceci dit, ce serait bien si Fil (par exemple) pouvait faire
un test pour voir si on y gagne... Je ne suis pas un pro du
Wget.

Il suffirait d'ajouter un champ MAJ dans spip_syndic, incrémenté à
chaque mise-à-jour des articles syndiqués correspondants, et de
n'effectuer la mise à jour que, par exemple, toutes les 3 heures
(tiens, on pourrait ajouter/retirer aléatoirement dans un intervalle
de 1 heure autour de la véritable mise à jour pour interdire que les
mises à jours de plusieurs sites syndiqués se synchronisent).

Oui par exemple. A ce moment-là, ajoute un champ "maj" de type
"TIMESTAMP" comme dans les autres tables, histoire que le tout
soit régulier.

Mais bon, Antoine, comme t'es en train de bosser dessus, je préfère
pas toucher.

Non j'ai fini. Tu peux y aller (bosser, pas saloper le code :-)).
Je te conseille fortement de déporter tout le code relatif à la
syndication dans un ecrire/inc_syndic.php3.

a+

Antoine.

Le but de la manoeuvre est bien d'avoir un comportement
similaire dans toutes les versions de spip. Il s'agit
juste de choisir si on garde la balise html, ou si on
choisit une autre balise pour tagger le texte qui sera
pas traiter par spip.

Personnelement j'en préférerais une autre, mais au final
c'est à vous de décider

Sur ce, moi je n'aurais pas accès à Internet pendant
quelques jours. Si le bout de code que j'ai écris vous
convient tel quel (au nom de la balise pres), vous
pouvez l'intégrer tout de suite dans spip. Je ne vois
pas, sur ce morceau très spécifique, ce que je pourrais
faire de plus.

Cordialement

@ Antoine Pitrou (pitrou@free.fr) :

un test pour voir si on y gagne... Je ne suis pas un pro du
Wget.

Je fais deux tests :
    time wget -r -np -R gif,jpg -q $URL
    cette commande "aspire" toute l'arborescence (dans notre cas 600 petits
articles SPIP) et affiche le temps total. Je le fais d'abord avec un cache
vide, puis une seconde fois (tout est alors en cache) (résultat = temps
total)

    /usr/sbin/ab -n 100 -c 10 $URL
    "stresse" le serveur en lui demandant 100 fois le même article SPIP (en
CACHE donc, forcément), 10 accès en parallèle. (résultat = temps moyen
d'envoi de la page)

    /usr/sbin/ab -n 100 -c 1 $URL
    même chose mais sans stresser le serveur (un fichier à la fois)

ancienne version

Léger bug dans la toute dernière 1.0.3:
Warning: Failed opening 'ecrire/inc_meta_cache.php3' for inclusion
(include_path='') in /var/www/spip_en/inc-public.php3 on line 392

-- Fil

@ Fil (fil@rezo.net) :

Léger bug dans la toute dernière 1.0.3:
Warning: Failed opening 'ecrire/inc_meta_cache.php3' for inclusion
(include_path='') in /var/www/spip_en/inc-public.php3 on line 392

(Un aller-retour dans "configuration précise" résoud le problème, mais il
vaudrait sans doute mieux faire un if (file_exists... avant

-- Fil

Fil wrote:

(Un aller-retour dans "configuration précise" résoud le problème, mais il
vaudrait sans doute mieux faire un if (file_exists... avant

Oui, j'ai oublié.... Bon, je le rajoute aujourd'hui.

Fil wrote:

(Un aller-retour dans "configuration précise" résoud le problème, mais il
vaudrait sans doute mieux faire un if (file_exists... avant

C'est fait.

Tetraminuscule modif dans inc-public : si le $delais est égal
à 0, le fichier cache est effacé à la fin de l'utilisation.
C'est au cas où certaines pages sont entièrement dynamiques.
Par exemple, dans uzine, la majorité des fichiers cache sont
des forum.php3, qui ne servent en général qu'une seule fois...

a+

Antoine.

Hello,

Va falloir commencer à parler de l'internationalisation
(i18n en abrégé). Donc discuter un peu de comment on
va faire... ? Première chose, la plus importante :
traduire l'interface SPIP (avec le problème des textes
en .gif qu'il va falloir résoudre, ou non, spécifiquement).

A priori, je propose qu'il y ait un répertoire ecrire/lang
qui contienne un (plusieurs ?) include php3 centralisant
les chaînes utilisées sous forme de variables ou constantes.

A titre d'exemple :

- phpNuke utilise un fichier unique language/lang-XXX.php3
(XXX = english, french...) contenant des lignes du style :

define("_PRINTER","Format imprimable");
define("_FRIEND","Envoyer cet article &agrave; un(e) ami(e)");
define("_SEARCH","Recherche");
define("_LOGIN"," Identification ");
define("_WRITES","a &eacute;crit :");
define("_POSTEDON","Post&eacute; le");
define("_NICKNAME","Surnom/Pseudo");
define("_PASSWORD","Mot de Passe");
[...]

- phpMyAdmin fait un peu le même genre de choses mais utilise
des variables globales et non des constantes. Extrait de
french.inc.php3 :

$strAPrimaryKey = "Une clé primaire a été ajoutée sur";
$strAccessDenied = "Accès refusé";
$strAction = "Action";
$strAddNewField = "Ajouter un champ";
$strAddSearchConditions = "Critères de recherche (pour l'énoncé \"where\"):";
$strAnIndex = "Un index a été ajouté sur ";

Si on utilise des variables globales, elles seront
appelées par $GLOBALS['nom_variable']. Si on utilise
des constantes, elles sont appelées simplement par
leur nom, y compris dans les fonctions : c'est donc
peut-être plus simple et plus lisible. Par contre
le fichier inclus est moins lisible (define au lieu
d'affectations de variables).

Pour remplacer les textes par les noms de variables
correspondants : je pense que ce serait mieux d'avoir
un système d'internationalisation assisté. J'ai
commencé un machin (*) qui va chercher les chaînes d'un
fichier PHP et en extrait ce qui ressemble à du
langage naturel. Ca marche pas trop mal, y a assez peu
de déchets. Ensuite le programmeur pourrait avoir
une interface pour choisir quelle chaîne ou sous-chaîne
internationaliser, et le script ferait le boulot
d'écrire la définition dans le include et de remplacer
la chaîne par l'appel de variable/constante dans le
script original.

(*) http://rezo.net/spip-dev/devel/i18n.php3

Pour la traduction, il suffirait simplement de prendre
un fichier langue, de le recopier sous un autre nom
et de taper les chaînes. Il peut également y avoir
une interface pour le faire : recopier les chaînes
d'un fichier à l'autre, et afficher un formulaire
pour les modifier.

Enfin, pour la sélection de la langue, on peut utiliser
la configuration du navigateur : normalement la variable
$HTTP_ACCEPT_LANGUAGE en PHP. Peut-être aussi donner
la possibilité de changer le réglage automatique (avec
un cookie ?).

Pour l'internationalisation, quoiqu'il en soit de la
méthode utilisée, va falloir rationaliser certains
bouts de code. Notamment du type :

  if ($articles_soustitre == "non") {
    echo "<INPUT TYPE='radio' NAME='articles_soustitre' VALUE='oui' id='articles_soustitre_on'>";
    echo " <label for='articles_soustitre_on'>Oui</label> ";
    echo " &nbsp; <INPUT TYPE='radio' NAME='articles_soustitre' VALUE='non' CHECKED id='articles_soustitre_off'>";
    echo " <B><label for='articles_soustitre_off'>Non</label></B> ";
  }
  else {
    echo "<INPUT TYPE='radio' NAME='articles_soustitre' VALUE='oui' CHECKED id='articles_soustitre_on'>";
    echo " <B><label for='articles_soustitre_on'>Oui</label></B> ";
    echo " &nbsp; <INPUT TYPE='radio' NAME='articles_soustitre' VALUE='non' id='articles_soustitre_off'>";
    echo " <label for='articles_soustitre_off'>Non</label> ";
  }

Non seulement la même chaîne est systématiquement en
double, mais en plus cela doit rester la même chaîne :
il est illogique que la case change d'intitulé une
fois sélectionnée. Donc avant d'internationaliser,
il faut s'arranger pour que la chaîne soit en simple
exemplaire (pourquoi pas faire une fonction qui
se charge en fonction des paramètres de sélectionner
la seule case qui doive l'être ?).

Alors, qu'est-ce qu'on fait ?

a+

Antoine.

Hello,

Va falloir commencer à parler de l'internationalisation (i18n en
abrégé).

De l'interface, du soft, du site et des docs ... :wink:

le problème des textes en .gif qu'il va falloir résoudre, ou non,
spécifiquement

Les textes en images sont à éviter tant que possible, mais on peut
imaginer une partie "génération d'images i18n" dans l'admin qui
exploiterait des templates d'images et la lib GD ...

A priori, je propose qu'il y ait un répertoire ecrire/lang qui
contienne un (plusieurs ?) include php3 centralisant les chaînes
utilisées sous forme de variables ou constantes.

C'est à mon avis le bon choix, enfin disons que c'est ce que je fais
toujours ... :wink:

- phpNuke utilise un fichier unique language/lang-XXX.php3
(XXX = english, french...) contenant des lignes du style :
define("_PRINTER","Format imprimable");
[...]

Tiens, c'était un tableau indexé sur les textes en anglais avant, ils
ont au moins amélioré ça ... :slight_smile:

Si on utilise des variables globales, elles seront appelées par
$GLOBALS['nom_variable'].

Et c'est la galère, notamment dans les fonctions ...

le fichier inclus est moins lisible (define au lieu d'affectations
de variables).

En quoi est-ce moins lisible ? Le tout est d'indenter le code comme il
faut ...

un système d'internationalisation assisté. J'ai commencé un machin

Qui est balaise, bravo !!! :slight_smile:

Enfin, pour la sélection de la langue, on peut utiliser la
configuration du navigateur

Non, il FAUT utiliser la config du client ...

Peut-être aussi donner la possibilité de changer le réglage
automatique (avec un cookie ?).

Je propose que mon code de phpLang
(PHP Heaven) soit intégré à SPIP, il
gère la config du client, la liste des langues dispos, et le choix
d'une langue alternative avec cookie. C'est en oeuvre sur phpHeaven si
vous voulez tester ...

echo " <label for='articles_soustitre_on'>Oui</label> ";

Il faudrait peut-être pondre un code respectant les règles du XHTML,
avec des valeurs d'attributs délimitées par ", non ?

En plus, là, ce n'est pas optimisé pour PHP, vu qu'il parse toute
chaine délimitée par " mais pas celles délimitées par '. Il faudrait
donc avoir :

echo ' <label for="articles_soustitre_on">Oui</label> ';

Mes 2 centimes ...

Nicolas.