Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Pour migrer des fonctions regex en fonctions pcre automatiquement.

23 réponses
Avatar
Jean-Francois Ortolo
Bonjour

J'ai l'honneur ( excusez du peu ;) ) de présenter une solution de
migration semi automatique, des fonctions de type regex: split(),
ereg(), eregi(), ereg_replace(), et eregi_replace(), vers leurs
équivalents de type pcre : preg_split(), preg_match(), et preg_replace().

En effet, ces fonctiosn regex, disparaîtront à la version PHP 6, et
il est donc souhaitable de pouvoir migrer ses sites vers les nouvelles
fonctions.

Compte tenu du fait que celà intéresse avant tout les programmeurs
php, j'espère que le modérateur va laisser passer ce message, bien que
ses outils relèvent plutôt de la programmation Shell et Awk. ;(


Cette solution se compose d'un script en Bourne Shell migration.sh, à
placer dans la racine du site web à migrer, et d'un script awk
filtre.awk à placer aussi dans la racine du site à migrer.

Voici le code des ces deux scripts :

D'abord, migration.sh

La variable dir_init doit être alimentée avec le répertoire dans
lequel est installé ce script ( répertoire racine du site web ).

Ce script est censé être lancé à partir du compte root.

La variable perm doit être alimentée avec le propriétaire et groupe
des scripts php à migrer.

Excusez-moi du fait que ces instructions sont sous forme de
citations, j'ai la flemme d'enlever manuellement les débuts de lignes.


> #!/bin/sh
>
> # Propriétaire et groupe
> # des scripts *.php
> perm="root:root"
>
> # Variables de configuration, c'est le répertoire de départ.
> dir_init="/var/www/html/php"
>
> # Et le script awk de filtre.
> filtre_awk=${dir_init}"/filtre.awk"
>
> # On calcule le répertoire absolu courant.
> # Quand le paramètre n'est pas présent,
> # c'est le répertoire de départ, sinon
> # c'est le paramètre du script.
> if [ $# -eq 0 ]; then
> dir=${dir_init}
> else
> dir=$1
> fi
>
> # Positionnement dans le répertoire courant.
> cd ${dir}
>
> # On parcourt le répertoire courant en sélectionnant
> # tous les scripts php.
> for i in `ls *.php 2>/dev/null`; do
> if [ -f $i ]; then
> file=${dir}"/"${i}
> file2=${dir}"/super_new_"${i}".txt"
>
> # Traitement du script *.php,
> # là on se contente d'afficher son nom
> # avec son chemin absolu.
> #
> echo ${file} > /root/tmp2.txt
> echo ${file2} >> /root/tmp2.txt
> echo "" >> /root/tmp2.txt
>
> awk -f ${filtre_awk} -- ${file} 1>${file2} 2>>/root/tmp2.txt
>
> chown $perm ${file2}
> chmod 777 ${file2}
>
> t1=`ls -l ${file} | awk '{ print $5; }'`
> t2=`ls -l ${file2} | awk '{ print $5; }'`
>
> if [ ${t1} -ne ${t2} ]; then
> cat /root/tmp2.txt >> /root/tmp.txt
> fi
> fi
> done
>
> # On lit tous les sous-répertoires du répertoire courant,
> # et on relance le même script, avec ces sous-répertoires
> # comme paramètre, pour que ces processus fils
> # se positionnent sur ces sous-répertoires.
> #
> for j in `ls -d * 2>/dev/null`; do
> if [ -d $j ]; then
>
> # Calcul du sous-répertoire absolu.
> direct=${dir}"/"${j}
>
> ${dir_init}/migration.sh ${direct}
> fi
> done
>
> # A la fin du script, on remonte vers le répertoire
> # père.
> cd ..
>
> exit 0


Ensuite, voici le code du script filtre.awk :


> function change(param)
> {
> p=split(param, tableau, "");
>
> drapeau=0;
> n=0;
>
> for(i=1; i<=p; i++)
> {
> t=tableau[i];
>
> if(drapeau!=0)
> {
> if(n==0)
> {
> if(t=="\\")
> {
> n++;
> }
> else
> {
> if(t==s)
> {
> chaine=chaine "/" s;
> break;
> }
> else
> chaine=chaine t;
> }
> }
> else
> {
> if(t=="\\")
> n++;
> else
> {
> d="";
> for(k=1; k<=n; k++)
> d=d "\\";
>
> chaine=chaine d;
>
> q=n;
> if(((2*int(q/2.0))==n)&&(t==s))
> {
> chaine=chaine "/" s;
> break;
> }
> else
> chaine=chaine t;
>
> n=0;
> }
> }
>
> }
> else
> {
> if((t=="'")||(t=="\""))
> {
> drapeau=1;
> s=t;
> chaine=t "/";
> }
> # Début de chr(nombre)
> # ou de variable masque.
> else if((t=="c")||(t=="$"))
> {
> chaine=t;
> break;
> }
> }
> }
>
> i++;
>
> for(; i<=p; i++)
> {
> t=tableau[i];
> chaine=chaine t;
> }
>
> return(chaine);
> }
> function change_i(param)
> {
> p=split(param, tableau, "");
>
> drapeau=0;
> n=0;
>
> for(i=1; i<=p; i++)
> {
> t=tableau[i];
>
> if(drapeau!=0)
> {
> if(n==0)
> {
> if(t=="\\")
> {
> n++;
> }
> else
> {
> if(t==s)
> {
> chaine=chaine "/i" s;
> break;
> }
> else
> chaine=chaine t;
> }
> }
> else
> {
> if(t=="\\")
> n++;
> else
> {
> d="";
> for(k=1; k<=n; k++)
> d=d "\\";
>
> chaine=chaine d;
>
> q=n;
> if(((2*int(q/2.0))==n)&&(t==s))
> {
> chaine=chaine "/i" s;
> break;
> }
> else
> chaine=chaine t;
>
> n=0;
> }
> }
>
> }
> else
> {
> if((t=="'")||(t=="\""))
> {
> drapeau=1;
> s=t;
> chaine=t "/";
> }
> # Début de chr(nombre)
> # ou de variable masque.
> else if((t=="c")||(t=="$"))
> {
> chaine=t;
> break;
> }
> }
> }
>
> i++;
>
> for(; i<=p; i++)
> {
> t=tableau[i];
> chaine=chaine t;
> }
>
> return(chaine);
> }
> {
> line=$0;
> line2=$0;
>
> if(line ~ /=[ \t]*split[ ]*\(/)
> {
> r=split(line, tableau, /=[ \t]*split[ ]*\(/);
>
> for(l=1; l<=r; l++)
> {
> u=tableau[l];
>
> if(l==1)
> line=u;
> else
> {
> line=line "= preg_split(";
> v=change(u);
> line=line v;
> }
> }
> }
>
> if(line ~ /eregi[ ]*\(/)
> {
> split(line, tableau, /eregi[ ]*\(/);
>
> for(l=1; l<=r; l++)
> {
> u=tableau[l];
>
> if(l==1)
> line=u;
> else
> {
> line=line "preg_match(";
> v=change_i(u);
> line=line v;
> }
> }
> }
>
> if(line ~ /ereg[ ]*\(/)
> {
> split(line, tableau, /ereg[ ]*\(/);
>
> for(l=1; l<=r; l++)
> {
> u=tableau[l];
>
> if(l==1)
> line=u;
> else
> {
> line=line "preg_match(";
> v=change(u);
> line=line v;
> }
> }
> }
>
> if(line ~ /eregi_replace[ ]*\(/)
> {
> split(line, tableau, /eregi_replace[ ]*\(/);
>
> for(l=1; l<=r; l++)
> {
> u=tableau[l];
>
> if(l==1)
> line=u;
> else
> {
> line=line "preg_replace(";
> v=change_i(u);
> line=line v;
> }
> }
> }
>
> if(line ~ /ereg_replace[ ]*\(/)
> {
> split(line, tableau, /ereg_replace[ ]*\(/);
>
> for(l=1; l<=r; l++)
> {
> u=tableau[l];
>
> if(l==1)
> line=u;
> else
> {
> line=line "preg_replace(";
> v=change(u);
> line=line v;
> }
> }
> }
>
> printf ("%s\n", line);
>
> if(line!=line2)
> {
> print "D'abord:" line2 " Ensuite:" line > "/dev/stderr"
> }
> }


A la fin de la migration, vous avez le fichier de logs /root/tmp.txt
qui contient les chemins absolus des scripts php avant et après
migration, ainsi que les lignes des fonctions migrées.

Ce fichier ne contient que les scripts modifiés, pas les scripts
inchangés.

Pour arranger le formattage, je suggère de séparer ce fichier de
logs, en deux fichiers indexé de 1 à n, n étant le nombre de fichiers
modifiés.

Pour celà :

cat tmp.txt | awk 'BEGIN{ i=0; j=0; }{ if(length($0)<5) { i++; j++;
if(j==1) print i; } else if ($0 !~ /Ensuite/) { j=0; print $0; } }' >
fichiers.txt


cat tmp.txt | awk 'BEGIN{ i=0; j=0; }{ if(length($0)<5) { i++; j++;
if(j==1) print i; } else if ($0 ~ /Ensuite/) { j=0; print $0; } }' | awk
'{ for(i=2; i<=NF; i++) if($i != "Ensuite:") printf("%s ", $i); else
printf(" "); printf("\n"); }' > fonctions.txt


Ensuite, vous aurez dans fichiers.txt la liste indexés de 1 à n des
chemins absolus des fichiers sources et cibles par paires, et dans
fonctions.txt la liste indexée des fonctions avant et après migration,
par groupes de fonctions pour chaque fichiers modifiés.

Dans les deux cas, l'index va de 1 à n, et n a la même valeur dans
les deux cas.

Il faut obligatoirement vérifier dans le fichier fonctions.txt qu'il
n'y a pas d'erreur lors de la migration des fonctions.

Théoriquement la seule erreur peut résulter du fait que l'expression
rationnelle est contenue dans une variable php ( commençant par $ le
caractère dollar ). Dans ce cas évidemment, il n'y a pas d'autre
solution que d'éditer manuellement le fichier cible correspondant ( de
même index dans le fichiers fichiers.txt ), pour modifier cette variable
php qui sert d'expression rationnelle.


Comme conclusion, je serais intéressé à ce que vous m'indiquiez les
erreurs de programmation éventuelles que vous voyez, car je suis en
train de faire cette migration sur mon ordinateur, pour mon site
www.pronostics-courses.fr versions locale et remote, ainsi que pour le
site www.lescourses.com, mon site partenaire, que j'ai copié sur mon
ordinateur. ;) Celà me permettrait de diminuer le risque d'erreurs.

Je suis aussi intéressé par vos remarques et suggestions, compte tenu
du fait que cette topique de migration automatisée de fonctions regex
vers des fonctions pcre, avait été abordée il y de celà quelques
semaines ou mois.

Bien à vous.

Amicalement.

Jean-François Ortolo

--
Visitez le site http://www.pronostics-courses.fr/
donnant des Statistiques, Pronostics et Historiques graphiques
très élaborés.

Les Statistiques sont calculées d'après une base de données
allant du 1er Janvier 2000 jusqu'à très récemment.

3 réponses

1 2 3
Avatar
Jean-Francois Ortolo
Le 14/01/2010 21:39, Christophe Bachmann a écrit :

L'euro n'apparaît pas dans le jeu iso-8859-1 (latin 1) mais dans le
iso-8859-15 (latin 9) auquel cas il est disponible par <AltGr>+E ou
<Ctrl>+<Alt>+E (au moins sous windows)

Voir http://www.cs.tut.fi/~jkorpela/latin9.html (en anglais)




Bonsoir Monsieur

Effectivement, sous vi j'arrive à faire apparaître le signe euro en
faisant <AltGr>+E, que E soit minuscule ou majuscule.

Donc il semble que le mode latin utilisé soit latin9, bien que le
fichier /etc/vimrc mentionne seulement latin.

Il est vrai que c'est moi qui ait fait la manip de configurer ce
fichier en mode latin, alors que par défaut il est en mode utf8.

Merci beaucoup de votre réponse, je vais maintenant essayer de faire
apparaître un signe euro sur ce Thunderbird version 3.0 sous Linux
Fedora 11 64 bits.

Attention... € C'est gagné !

Remerci beaucoup pour votre réponse.

Bien à vous.

Amicalement.

Jean-François Ortolo

--
Visitez le site http://www.pronostics-courses.fr/
donnant des Statistiques, Pronostics et Historiques graphiques
très élaborés.

Les Statistiques sont calculées d'après une base de données
allant du 1er Janvier 2000 jusqu'à très récemment.
Avatar
Jean-Francois Ortolo
Bonjour

Je vais bientôt passer à l'étape suivante : Migration des fonctions
mysql_*() , vers l'interface objet PDO d'accès à MySQL.

Pour celà, j'ai besoin d'une information sur php, php 6 en particulier.

Supposons une classe ( mettons de type MyPDO extends PDO ),
instanciée en objet $conn donnant la référence avec laquelle on
construit les requêtes ( $conn->query($sql) , $conn->exec($sql) ).

Les connexions à MySQL se font mettons avec la fonction aconnect(),
l'objet ( la variable ) $conn, la fonction aconnect() est définie dans
un script script_connexion.php inclus au début des scripts php, et
contient l'instruction classique de connexion à MySQL façon PDO. ( $conn
= new MyPDO( etc... ); , avec classique traitement d'erreur.

Cette fonction aconnect(void), instancifie donc l'objet $conn, qui
est global, et est utilisé dans les scripts, simplement en le déclarant
global.

On a donc :

<?php
include("script_connexion.php");

global($conn;

aconnect();

... Et à ce moment-là, l'objet $conn sera-t-il effectivement
disponible pour des requêtes genre $conn->query($sql) ou
$conn->exec($sql) ?

C'est ma première question.


Ma deuxième question, c'est de savoir si l'objet $conn, instancifié
dans le corps du script php ( aconnect(); ) sera aussi disponible dans
une fonction ou $conn est délaré global ?

Par exemple :

<?php
include("script_connexion.php");

global $conn;

aconnect();

function example() {

global $conn;

Ma question : $conn sera-t-il disponible pour des requêtes
de type $conn->query($sql) ou $conn->exec($sql) ?



}

Enfin, ma dernière question, c'est de savoir si c'est aussi le cas (
$conn disponible pour des requêtes ) si la fonction example() est
déclarée avant le déclenchement de aconnect(); , mais que la fonction
aconnect() est déclenchée avant l'appel à la fonction example()?

Merci beaucoup de vos réponses, je reconnais que mes questions sont
surtout relatifs à la portée des variables globales, et à la
Programmation Orientée Objet sous php, mais j'espère que le modérateur
va laisser passer mon message...

Bien à vous.

Amicalement.

Jean-François Ortolo

--
Visitez le site http://www.pronostics-courses.fr/
donnant des Statistiques, Pronostics et Historiques graphiques
très élaborés.

Les Statistiques sont calculées d'après une base de données
allant du 1er Janvier 2000 jusqu'à très récemment.
Avatar
Jean-Francois Ortolo
Bonjour

J'ai la réponse à ma question.

Bien à vous.

Amicalement.

Jean-François Ortolo

--
Visitez le site http://www.pronostics-courses.fr/
donnant des Statistiques, Pronostics et Historiques graphiques
très élaborés.

Les Statistiques sont calculées d'après une base de données
allant du 1er Janvier 2000 jusqu'à très récemment.
1 2 3