ne pas passer par le processus de mise a jour. // De meme en cas de version superieure: ca devait etre un test, // il y a eu le message d'avertissement il doit savoir ce qu'il fait // // version_installee = 1.702; quand on a besoin de forcer une MAJ spip_log( "Version anterieure: $version_installee. Courante: " . $GLOBALS['spip_version_base'], 'maj.' . _LOG_INFO_IMPORTANTE ); if (!$version_installee or ($GLOBALS['spip_version_base'] < $version_installee)) { sql_replace( 'spip_meta', array( 'nom' => 'version_installee', 'valeur' => $GLOBALS['spip_version_base'], 'impt' => 'non' ) ); return false; } if (!upgrade_test()) { return true; } $cible = ($version_cible ? $version_cible : $GLOBALS['spip_version_base']); if ($version_installee <= 1.926) { $n = floor($version_installee * 10); while ($n < 19) { $nom = sprintf('v%03d', $n); $f = charger_fonction($nom, 'maj', true); if ($f) { spip_log("$f repercute les modifications de la version " . ($n / 10), 'maj.' . _LOG_INFO_IMPORTANTE); $f($version_installee, $GLOBALS['spip_version_base']); } else { spip_log("pas de fonction pour la maj $n $nom", 'maj.' . _LOG_INFO_IMPORTANTE); } $n++; } include_spip('maj/v019_pre193'); v019_pre193($version_installee, $version_cible); } if ($version_installee < 2000) { if ($version_installee < 2) { $version_installee = $version_installee * 1000; } include_spip('maj/v019'); } if ($cible < 2) { $cible = $cible * 1000; } include_spip('maj/svn10000'); ksort($GLOBALS['maj']); $res = maj_while($version_installee, $cible, $GLOBALS['maj'], 'version_installee', 'meta', $redirect, true); if ($res) { if (!is_array($res)) { spip_log("Pb d'acces SQL a la mise a jour", 'maj.' . _LOG_INFO_ERREUR); } else { echo _T('avis_operation_echec') . ' ' . join(' ', $res); echo install_fin_html(); } } return $res; } /** * Mise à jour d'un plugin de SPIP * * Fonction appelée par la fonction de mise à jour d'un plugin. * On lui fournit un tableau de fonctions élementaires * dont l'indice est la version. * * @uses maj_while() * * @param string $nom_meta_base_version * Nom de la meta informant de la version du schéma de données du plugin installé dans SPIP * @param string $version_cible * Version du schéma de données dans le plugin (déclaré dans paquet.xml) * @param array $maj * Tableau d'actions à faire à l'installation (clé `create`) et pour chaque * version intermédiaire entre la version actuelle du schéma du plugin dans SPIP * et la version du schéma déclaré dans le plugin (ex. clé `1.1.0`). * * Chaque valeur est un tableau contenant une liste de fonctions à exécuter, * cette liste étant elle-même un tableau avec premier paramètre le nom de la fonction * et les suivant les paramètres à lui passer * * Exemple : * * ``` * array( * 'create' => array( * array('maj_tables', array('spip_rubriques', 'spip_articles')), * array('creer_base)), * '1.1.0' => array( * array('sql_alter', 'TABLE spip_articles ADD INDEX truc (truc)')) * ) * ``` * @param string $table_meta * Nom de la table meta (sans le prefixe spip_) dans laquelle trouver la meta $nom_meta_base_version * @return void */ function maj_plugin($nom_meta_base_version, $version_cible, $maj, $table_meta = 'meta') { if ($table_meta !== 'meta') { lire_metas($table_meta); } $current_version = null; if ((!isset($GLOBALS[$table_meta][$nom_meta_base_version])) || (!spip_version_compare($current_version = $GLOBALS[$table_meta][$nom_meta_base_version], $version_cible, '=')) ) { // $maj['create'] contient les directives propres a la premiere creation de base // c'est une operation derogatoire qui fait aboutir directement dans la version_cible if (isset($maj['create'])) { if (!isset($GLOBALS[$table_meta][$nom_meta_base_version])) { // installation : on ne fait que l'operation create $maj = array('init' => $maj['create']); // et on lui ajoute un appel a inc/config // pour creer les metas par defaut $config = charger_fonction('config', 'inc'); $maj[$version_cible] = array(array($config)); } // dans tous les cas enlever cet index du tableau unset($maj['create']); } // si init, deja dans le bon ordre if (!isset($maj['init'])) { include_spip('inc/plugin'); // pour spip_version_compare uksort($maj, 'spip_version_compare'); } // la redirection se fait par defaut sur la page d'administration des plugins // sauf lorsque nous sommes sur l'installation de SPIP // ou define _REDIRECT_MAJ_PLUGIN $redirect = (defined('_REDIRECT_MAJ_PLUGIN') ? _REDIRECT_MAJ_PLUGIN : generer_url_ecrire('admin_plugin')); if (defined('_ECRIRE_INSTALL')) { $redirect = parametre_url(generer_url_ecrire('install'), 'etape', _request('etape')); } $res = maj_while($current_version, $version_cible, $maj, $nom_meta_base_version, $table_meta, $redirect); if ($res) { if (!is_array($res)) { spip_log("Pb d'acces SQL a la mise a jour", 'maj.' . _LOG_INFO_ERREUR); } else { echo '

' . _T('avis_operation_echec') . ' ' . join(' ', $res) . '

'; } } } } /** * Relancer le hit de mise à jour avant timeout * * si pas de redirect fourni, on redirige vers `exec=upgrade` pour finir * ce qui doit être une mise à jour SPIP * * @uses redirige_formulaire() * * @param string $meta * @param string $table * @param string $redirect * @return void */ function relance_maj($meta, $table, $redirect = '') { include_spip('inc/headers'); if (!$redirect) { // recuperer la valeur installee en cours // on la tronque numeriquement, elle ne sert pas reellement // sauf pour verifier que ce n'est pas oui ou non // sinon is_numeric va echouer sur un numero de version 1.2.3 $installee = intval($GLOBALS[$table][$meta]); $redirect = generer_url_ecrire('upgrade', "reinstall=$installee&meta=$meta&table=$table", true); } echo redirige_formulaire($redirect); exit(); } /** * Initialiser la page pour l'affichage des progrès de l'upgrade * uniquement si la page n'a pas déjà été initilalisée * * @param string $installee * @param string $meta * @param string $table * @return void */ function maj_debut_page($installee, $meta, $table) { static $done = false; if ($done) { return; } include_spip('inc/minipres'); @ini_set('zlib.output_compression', '0'); // pour permettre l'affichage au fur et a mesure $timeout = _UPGRADE_TIME_OUT * 2; $titre = _T('titre_page_upgrade'); $balise_img = charger_filtre('balise_img'); $titre .= $balise_img(chemin_image('searching.gif')); echo(install_debut_html($titre)); // script de rechargement auto sur timeout $redirect = generer_url_ecrire('upgrade', "reinstall=$installee&meta=$meta&table=$table", true); echo http_script("window.setTimeout('location.href=\"" . $redirect . "\";'," . ($timeout * 1000) . ')'); echo "
\n"; if (ob_get_level()) { ob_flush(); } flush(); $done = true; } /** * Durée en secondes pour relancer les scripts de mises à jour, x secondes * avant que la durée d'exécution du script provoque un timeout * * @var int **/ define('_UPGRADE_TIME_OUT', 20); /** * Gestion des mises à jour de SPIP et des plugins * * À partir des versions > 1.926 (i.e SPIP > 1.9.2), cette fonction gere les MAJ. * * Se relancer soi-même pour éviter l'interruption pendant une operation SQL * (qu'on espère pas trop longue chacune) évidemment en ecrivant dans la meta * à quel numero on en est. * * Cette fonction peut servir aux plugins qui doivent donner comme arguments : * * 1. le numero de version courant (numéro de version 1.2.3 ou entier) * 2. le numero de version à atteindre (numéro de version 1.2.3 ou entier) * 3. le tableau des instructions de mise à jour à exécuter * Pour profiter du mécanisme de reprise sur interruption il faut de plus * 4. le nom de la meta permettant de retrouver tout ca * 5. la table des meta ou elle se trouve (`$table_prefix . '_meta'` par défaut) * (cf début de fichier) * * les fonctions `sql_xx` appelées lors des mises à jour sont supposées * atomiques et ne sont pas relancées en cas de timeout, mais les fonctions * spécifiques sont relancées jusqu'à ce qu'elles finissent. * Elles doivent donc s'assurer de progresser à chaque reprise. * * @uses maj_debut_page() * @uses serie_alter() * @uses relance_maj() * * @param string $installee * @param string $cible * @param array $maj * @param string $meta * @param string $table * @param string $redirect * @param bool $debut_page * @return array * - tableau (étape, sous-étape) en cas d'échec, * - tableau vide sinon. */ function maj_while($installee, $cible, $maj, $meta = '', $table = 'meta', $redirect = '', $debut_page = false) { # inclusions pour que les procedures d'upgrade disposent des fonctions de base include_spip('base/create'); include_spip('base/abstract_sql'); $trouver_table = charger_fonction('trouver_table', 'base'); include_spip('inc/plugin'); // pour spip_version_compare $n = 0; $time = time(); if (!defined('_TIME_OUT')) { /** * Définir le timeout qui peut-être utilisé dans les fonctions * de mises à jour qui durent trop longtemps * * À utiliser tel que : `if (time() >= _TIME_OUT)` * * @var int */ define('_TIME_OUT', $time + _UPGRADE_TIME_OUT); } reset($maj); while (list($v, ) = each($maj)) { // si une maj pour cette version if ($v == 'init' or (spip_version_compare($v, $installee, '>') and spip_version_compare($v, $cible, '<=')) ) { if ($debut_page) { maj_debut_page($v, $meta, $table); } echo "MAJ $v"; $etape = serie_alter($v, $maj[$v], $meta, $table, $redirect); $trouver_table(''); // vider le cache des descriptions de table # echec sur une etape en cours ? # on sort if ($etape) { return array($v, $etape); } $n = time() - $time; spip_log("$table $meta: $v en $n secondes", 'maj.' . _LOG_INFO_IMPORTANTE); if ($meta) { ecrire_meta($meta, $installee = $v, 'oui', $table); } echo '
'; } if (time() >= _TIME_OUT) { relance_maj($meta, $table, $redirect); } } $trouver_table(''); // vider le cache des descriptions de table // indispensable pour les chgt de versions qui n'ecrivent pas en base // tant pis pour la redondance eventuelle avec ci-dessus if ($meta) { ecrire_meta($meta, $cible, 'oui', $table); } spip_log("MAJ terminee. $meta: $installee", 'maj.' . _LOG_INFO_IMPORTANTE); return array(); } /** * Appliquer une serie de changements qui risquent de partir en timeout * * Alter crée une copie temporaire d'une table, c'est lourd. * * @uses relance_maj() * * @param string $serie * numero de version upgrade * @param array $q * tableau des operations pour cette version * @param string $meta * nom de la meta qui contient le numero de version * @param string $table * nom de la table meta * @param string $redirect * url de redirection en cas d'interruption * @return int */ function serie_alter($serie, $q = array(), $meta = '', $table = 'meta', $redirect = '') { $meta2 = $meta . '_maj_' . $serie; $etape = intval(@$GLOBALS[$table][$meta2]); foreach ($q as $i => $r) { if ($i >= $etape) { $msg = "maj $table $meta2 etape $i"; if (is_array($r) and function_exists($f = array_shift($r)) ) { // note: $r (arguments de la fonction $f) peut avoir des données tabulaires spip_log("$msg: $f " . @join(',', $r), 'maj.' . _LOG_INFO_IMPORTANTE); // pour les fonctions atomiques sql_xx // on enregistre le meta avant de lancer la fonction, // de maniere a eviter de boucler sur timeout // mais pour les fonctions complexes, // il faut les rejouer jusqu'a achevement. // C'est a elle d'assurer qu'elles progressent a chaque rappel if (strncmp($f, 'sql_', 4) == 0) { ecrire_meta($meta2, $i + 1, 'non', $table); } echo " ."; call_user_func_array($f, $r); // si temps imparti depasse, on relance sans ecrire en meta // car on est peut etre sorti sur timeout si c'est une fonction longue if (time() >= _TIME_OUT) { relance_maj($meta, $table, $redirect); } ecrire_meta($meta2, $i + 1, 'non', $table); spip_log("$meta2: ok", 'maj.' . _LOG_INFO_IMPORTANTE); } else { if (!is_array($r)) { spip_log("maj $i format incorrect", 'maj.' . _LOG_ERREUR); } else { spip_log("maj $i fonction $f non definie", 'maj.' . _LOG_ERREUR); } // en cas d'erreur serieuse, on s'arrete // mais on permet de passer par dessus en rechargeant la page. return $i + 1; } } } effacer_meta($meta2, $table); return 0; } /** * Mise à jour des types MIME de documents * * Fonction utilisé par les vieilles mises à jour de SPIP, à appeler dans * le tableau `$maj` quand on rajoute des types MIME. Remplacé actuellement * par le plugin Medias. * * @deprecated Utiliser directement `creer_base_types_doc()` du plugin Medias * @example * ``` * $GLOBALS['maj'][1953] = array(array('upgrade_types_documents')); * * ``` * @uses creer_base_types_doc() * **/ function upgrade_types_documents() { if (include_spip('base/medias') and function_exists('creer_base_types_doc') ) { creer_base_types_doc(); } } /** * Vérifie qu'il est possible d'ajouter une colonne à une table SQL * * @return bool True si possible. **/ function upgrade_test() { sql_drop_table('spip_test', true); sql_create('spip_test', array('a' => 'int')); sql_alter('TABLE spip_test ADD b INT'); sql_insertq('spip_test', array('b' => 1), array('field' => array('b' => 'int'))); $result = sql_select('b', 'spip_test'); // ne pas garder le resultat de la requete sinon sqlite3 // ne peut pas supprimer la table spip_test lors du sql_alter qui suit // car cette table serait alors 'verouillee' $result = $result ? true : false; sql_alter('TABLE spip_test DROP b'); return $result; } /** * Mise à jour des versions de SPIP < 1.926 * * @deprecated Utiliser `maj_plugin()` ou la globale `maj` pour le core. * @see maj_plugin() * @see maj_base() * * @param float $version * @param bool $test * @return void **/ function maj_version($version, $test = true) { if ($test) { if ($version >= 1.922) { ecrire_meta('version_installee', $version, 'oui'); } else { // on le fait manuellement, car ecrire_meta utilise le champs impt qui est absent sur les vieilles versions $GLOBALS['meta']['version_installee'] = $version; sql_updateq('spip_meta', array('valeur' => $version), 'nom=' . sql_quote('version_installee')); } spip_log("mise a jour de la base en $version", 'maj.' . _LOG_INFO_IMPORTANTE); } else { echo _T('alerte_maj_impossible', array('version' => $version)); exit; } } /** * Teste de mise à jour des versions de SPIP < 1.926 * * @deprecated Utiliser `maj_plugin()` ou la globale `maj` pour le core. * @see maj_plugin() * @see maj_base() * * @param float $version * @param float $version_installee * @param int $version_cible * @return bool true si la mise à jour doit se réaliser **/ function upgrade_vers($version, $version_installee, $version_cible = 0) { return ($version_installee < $version and (($version_cible >= $version) or ($version_cible == 0)) ); }