Migrer de PHP 5 à PHP 7.4 quand on utilise une base de données MySQL

Au mois de juin, je me suis attaquée à un problème qui traînait depuis plusieurs années. Je ne pouvais plus développer mon site Web sur mon ordinateur parce que la nouvelle version de l’environnement de serveur local MAMP que j’avais installée ne me permettait plus d’afficher les pages de mon site sur l’hôte local (localhost:8888/).

J’ai vérifié mon code dans PHP Code Checker pour sa conformité avec la syntaxe de PHP 7.3. Elles étaient listées là, les coupables, des fonctions PHP obsolètes:

  • mysql_error()
  • mysql_num_rows()
  • mysql_query()

J’ai trouvé l’information nécessaire (en français!) pour remplacer ces fonctions dans le Manuel PHP, vers lequel pointe le PHP Code Checker.

J’ai réussi à afficher quelques pages sur l’hôte local, puis je suis passée à d’autres activités de recherche plus stimulantes que de mettre à jour du code PHP. J’ai été forcée de m’y replonger d’urgence au début du mois de septembre quand j’ai temporairement brisé mon site Web en poussant ce nouveau code incomplètement mis à jour sur le serveur qui l’héberge.

Crisis avertedUne fois la panique passée, j’ai réalisé que je n’avais pas à réussir à tout migrer sur le champ: je pouvais patcher  le problème temporairement en faisant appel sur certaines pages à l’ancienne version du code en même temps que d’autres utilisaient la nouvelle. Ainsi, sur les pages que je n’avais pas encore réussi à migrer, j’ai passé l’ancienne version d’un fichier (beforecontents_old.php) comme argument dans l’instruction include plutôt que la nouvelle, qui forçait l’utilisation de PHP 7 d’un bout à l’autre du code générant la page.

J’ai utilisé cette patch sur 9 fichiers que j’ai finalement mis à jour mardi dernier. Pour le bénéfice de toutes les programmeuses et programmeurs qui seraient pris à mettre à jour du code vieux de 10 ans, voici comment j’y suis parvenue. Comme je l’explique à la fin, le simple fait de décrire ce que je fais m’aider à dénouer des problèmes.

Migrer les fonctions

Dans certains cas, c’est aussi simple que d’ajouter un «i» au nom de la fonction obsolète:

Fonction obsolète Nouvelle fonction
mysql_close() mysqli_close()
mysql_connect() mysqli_connect()
mysql_fetch_assoc() mysqli_fetch_assoc()
mysql_fetch_field() mysqli_fetch_field()
mysql_num_fields() mysqli_num_fields()
mysql_num_rows() mysqli_num_rows()

Par contre, dans beaucoup de cas, il fallait ajouter des paramètres ou en changer l’ordre.

Fonction obsolète Nouvelle fonction
mysql_insert_id(); mysqli_insert_id($db_server);
mysql_query($query); mysqli_query($db_server, $query);
mysql_real_escape_string($_POST[$var]); mysqli_real_escape_string($db_server, $_POST[$var]);
mysql_select_db($db_database, $db_server) mysqli_select_db($db_server, $db_database)
mysql_set_charset('[nom du jeu de caractères]'); mysqli_set_charset($db_server, '[nom du jeu de caractères]');

$query
est une chaîne de caractères représentant une requête SQL sans le point-virgule à la fin.
p. ex. "SELECT * FROM editions"
$db_server
est retourné par la fonction qui ouvre la connexion à un serveur MySQL (mysqli_connect()).
p. ex. mysqli_connect($db_hostname, $db_username, $db_password)
$_POST[$var]
est la valeur passée par un script, par exemple dans la page de recherche.
[nom du jeu de caractères]
p. ex. utf8.

Le plus compliqué pour moi a été de trouver comment remplacer mysql_result(). Au final, après avoir procédé en deux lignes, j’ai réalisé que je pouvais les combiner. Le résultat n’est pas compliqué:

Fonction obsolète Nouvelle fonction
mysql_result($result,$i,'[nom du champ]'); mysqli_fetch_assoc($result)['[nom du champ]'];
mysql_result($result,$i,0); mysqli_fetch_row($result)[0];

$result
contient le résultat d’une requête SQL.
$i
est une valeur incrémentée à chaque itération d’une boucle for pour passer à travers toutes les rangées du résultat de la requête SQL.
[nom du champ]
est le nom du champ de la base de données dont on souhaite extraire la valeur.
0
est la position du champ de la base de données dont on souhaite extraire la valeur (c’est donc le premier champ).

Mais dans un fichier, c’était plus compliqué.

Ajouter un paramètre dans les fonctions maison

Ça c’est ce que j’avais réussi à faire en juin et en septembre. Mardi dernier, après 30 minutes à me replonger dans les fichiers que je n’avais pas réussi à mettre à jour, j’ai réalisé que je n’arrivais plus à faire de requêtes SQL à l’intérieur des fonctions que j’avais définies moi-même. J’ai aussi compris que les nouvelles fonctions exigeaient maintenant un paramètre que je ne passais pas dans ces fonctions maison.

Ainsi, dans view_authors.php, j’avais défini function displayAuthors($query). La fonction permet de déterminer comment les résultats de la requête $query seront affichés. Toutefois, tel qu’expliqué ci-dessus, mysql_query($query); est devenu mysqli_query($db_server, $query);. Il faut donc passer le paramètre $db_server aussi dans la fonction.

La fonction devient donc function displayAuthors($db_server, $query) et les displayAuthors("SELECT... qui y font appel dans le code doivent être remplacés par des displayAuthors($db_server, "SELECT....

J’ai compris ça étape par étape en écrivant un courriel à Demian Katz, qui avait offert de m’aider si j’avais besoin d’aide avec cette migration PHP. Je n’ai finalement pas eu à l’envoyer, preuve qu’en documentant ses raisonnements on les fait avancer.

Remplacer mysql_result lorsque chaque champ est une rangée

J’ai un fichier .php que j’utilise pour visualiser toutes les tables associées à une édition précise. Chaque table de la base de données est présentée dans un tableau HTML et ses champs, plutôt que d’être présentés en colonnes, forment les rangées. Ainsi, les tables qui contiennent principalement des nombres (editions, volumes et issues) sont affichées de façon plus compacte.

Le HTML n’est pas conçu pour peupler un tableau une colonne à la fois: c’est une rangée (<tr> pour table row) à la fois. Ainsi, comme je ne pouvais plus utiliser mysql_result pour transposer la matrice si on veut, j’ai dû placer les résultats de la requête SQL dans un tableau multidimensionnel (des tableaux imbriqués dans un tableau) à l’aide d’une nouvelle boucle for introduite avant celle qui génère les rangées du tableau HTML.

$columns = mysqli_num_rows($result);

unset($values);
for ($i = 0; $i < $columns; $i++)
{
$values[] = mysqli_fetch_row($result);
}

La fonction mysql_result est donc au final remplacée par une valeur extraite de ce tableau PHP multidimensionnel, soit $values[$j][$i], où $j et $i représentent les deux valeurs incrémentées à chaque itération de deux boucles for imbriquées l’une dans l’autre.

Retour sur la liste de tâches

Mon code PHP est donc maintenant à jour, ✓!

Ça me permet de continuer avec l’ajout des clés étrangères dans l’ensemble des tables de ma base de données en développant sur mon serveur local. Avant de pouvoir mettre cette base de données mise à jour en ligne, toutefois, je vais devoir demander à mon gentil hébergeur Quentin Auvray de mettre à jour son serveur, comme j’ai documenté dans mon dernier billet.

Sur la liste des choses à faire en programmation, il y a donc:

  • mettre à jour le reste des fichiers PHP du site Web;
  • continuer la recherche sur les applications de programmation (API) dont je pourrai me servir pour trouver automatiquement les (potentielles) numérisations de penny bloods (billet déjà en cours de rédaction!);
  • ajouter les clés étrangères aux 45 (!) autres tables de la base de données (et en profiter pour commencer à les documenter!);
  • optimiser le code PHP du site Web en utilisant des jointures (JOIN) dans mes requêtes SQL.

Et c’est sans compter la recherche d’exemples d’interfaces compatibles avec les mobiles élégantes desquelles je voudrai m’inspirer pour la refonte du site.

Présentation la semaine prochaine!

Je vais commencer avec l’ajout des clés étrangères parce que la structure de ma base de données sera l’objet de ma présentation au Five College Book History Seminar la semaine prochaine, le mercredi 28 octobre:

The Nightmare Before Christmas; or The Trials and Rewards of Building a Database

(Il faut bien souligner l’Halloween!)

Viendrez-vous? C’est de 17 à 18 heures, heure de l’Est (22 à 23 heures en Europe), sur Zoom. L’inscription est gratuite mais obligatoire pour avoir le lien.


You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Search OpenEdition Search

You will be redirected to OpenEdition Search