HervéRenault.fr

Logo de WordPress Logo de MariaDB

Migrer une base de données WordPress sans casser les données sérialisées

Migrer une base de données WordPress, c'est facile avec une simple commande sed. Le problème, c'est que WordPress lui-même, et encore plus les extensions, stockent des données sérialisées en PHP dans une ou plusieurs tables. Et quand on remplace une donnée sérialisée sous la forme s:14:https://URL1/ par s:14:https://URL2-plus-longue/ ça ne colle plus parce que l'URL 2 est plus longue, elle fait plus que 14 caractères, donc PHP jette la donnée au moment de désérialiser.

Mon script

C'est un script simple qui ne fonctionnera pas dans tous les cas de figure(*) mais qui me convient bien pour le moment.

(*) Par exemple si on remplace http://URL1 par http://URL1b, ça va donner http://URL1bb

Chaque fois qu'il trouve une occurence de ce qui ressemble à une chaîne sérialisée, il remplace URL1 par URL2 dans cette occurence en mettant à jour la longueur de cette chaîne.

Il faut lui envoyer un dump Mysql sur l'entrée standard et on récupère le dump mis à jour en sortie, du style
zcat mon_dump.mysql.gz | php mon_script.php URL1 URL2 > dump_modifié.mysql

<?php

while (($ligne = fgets(STDIN)) !== false) {

    $ligne = preg_replace_callback(
        '#s:(\d+):\\\"('.$argv[1].'.*?)\\\"#',
        function ($match) {
            global $argv;

            $match[2] = preg_replace("#${argv[1]}#", "${argv[2]}", $match[2]);

            return 's:'.mb_strlen($match[2]).':\"'.$match[2].'\"';
        },
        $ligne
    );

    // il n'y a pas que du sérialisé dans la base, aussi de simples chaines
    $ligne = preg_replace("#${argv[1]}#", "${argv[2]}", $ligne);

    echo $ligne;
}

Il existe un script assez connu qui fait la même chose mais il gère plusieurs CMS, plusieurs bases de données, il est assez complexe et ça ne m'amuse pas de comprendre tout ce qu'il fait.