uawdijnntqw1x1x1
IP : 216.73.217.6
Hostname : webm002.cluster111.gra.hosting.ovh.net
Kernel : Linux webm002.cluster111.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64
Disable Function : _dyuweyrj4,_dyuweyrj4r,dl
OS : Linux
PATH:
/
home
/
atelierpru
/
provence
/
6bf95
/
..
/
tmp
/
..
/
52177
/
base.tar
/
/
index.php000066600000000002152442520540006363 0ustar00X connect_sql.php000066600000040224152442520540007576 0ustar00<?php /***************************************************************************\ * SPIP, Systeme de publication pour l'internet * * * * Copyright (c) 2001-2019 * * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * \***************************************************************************/ /** * Utilitaires indispensables autour des serveurs SQL * * @package SPIP\Core\SQL **/ if (!defined('_ECRIRE_INC_VERSION')) { return; } require_once _ROOT_RESTREINT . 'base/objets.php'; /** * Connexion à un serveur de base de données * * On charge le fichier `config/$serveur` (`$serveur='connect'` pour le principal) * qui est censé initaliser la connexion en appelant la fonction `spip_connect_db` * laquelle met dans la globale `db_ok` la description de la connexion. * * On la mémorise dans un tableau pour permettre plusieurs serveurs. * * À l'installation, il faut simuler l'existence de ce fichier. * * @uses spip_connect_main() * * @param string $serveur Nom du connecteur * @param string $version Version de l'API SQL * @return bool|array * - false si la connexion a échouée, * - tableau décrivant la connexion sinon **/ function spip_connect($serveur = '', $version = '') { $serveur = !is_string($serveur) ? '' : strtolower($serveur); $index = $serveur ? $serveur : 0; if (!$version) { $version = $GLOBALS['spip_sql_version']; } if (isset($GLOBALS['connexions'][$index][$version])) { return $GLOBALS['connexions'][$index]; } include_spip('base/abstract_sql'); $install = (_request('exec') == 'install'); // Premiere connexion ? if (!($old = isset($GLOBALS['connexions'][$index]))) { $f = (!preg_match('/^[\w\.]*$/', $serveur)) ? '' // nom de serveur mal ecrit : ($serveur ? (_DIR_CONNECT . $serveur . '.php') // serveur externe : (_FILE_CONNECT ? _FILE_CONNECT // serveur principal ok : ($install ? _FILE_CONNECT_TMP // init du serveur principal : ''))); // installation pas faite unset($GLOBALS['db_ok']); unset($GLOBALS['spip_connect_version']); if ($f) { if (is_readable($f)) { include($f); } elseif ($serveur and !$install) { // chercher une declaration de serveur dans le path // qui pourra un jour servir a declarer des bases sqlite // par des plugins. Et sert aussi aux boucles POUR. find_in_path("$serveur.php", 'connect/', true); } } if (!isset($GLOBALS['db_ok'])) { // fera mieux la prochaine fois if ($install) { return false; } if ($f and is_readable($f)) { spip_log("spip_connect: fichier de connexion '$f' OK.", _LOG_INFO_IMPORTANTE); } else { spip_log("spip_connect: fichier de connexion '$f' non trouve", _LOG_INFO_IMPORTANTE); } spip_log("spip_connect: echec connexion ou serveur $index mal defini dans '$f'.", _LOG_HS); // ne plus reessayer si ce n'est pas l'install return $GLOBALS['connexions'][$index] = false; } $GLOBALS['connexions'][$index] = $GLOBALS['db_ok']; } // si la connexion a deja ete tentee mais a echoue, le dire! if (!$GLOBALS['connexions'][$index]) { return false; } // la connexion a reussi ou etait deja faite. // chargement de la version du jeu de fonctions // si pas dans le fichier par defaut $type = $GLOBALS['db_ok']['type']; $jeu = 'spip_' . $type . '_functions_' . $version; if (!isset($GLOBALS[$jeu])) { if (!find_in_path($type . '_' . $version . '.php', 'req/', true)) { spip_log("spip_connect: serveur $index version '$version' non defini pour '$type'", _LOG_HS); // ne plus reessayer return $GLOBALS['connexions'][$index][$version] = array(); } } $GLOBALS['connexions'][$index][$version] = $GLOBALS[$jeu]; if ($old) { return $GLOBALS['connexions'][$index]; } $GLOBALS['connexions'][$index]['spip_connect_version'] = isset($GLOBALS['spip_connect_version']) ? $GLOBALS['spip_connect_version'] : 0; // initialisation de l'alphabet utilise dans les connexions SQL // si l'installation l'a determine. // Celui du serveur principal l'impose aux serveurs secondaires // s'ils le connaissent if (!$serveur) { $charset = spip_connect_main($GLOBALS[$jeu], $GLOBALS['db_ok']['charset']); if (!$charset) { unset($GLOBALS['connexions'][$index]); spip_log("spip_connect: absence de charset", _LOG_AVERTISSEMENT); return false; } } else { if ($GLOBALS['db_ok']['charset']) { $charset = $GLOBALS['db_ok']['charset']; } // spip_meta n'existe pas toujours dans la base // C'est le cas d'un dump sqlite par exemple elseif ($GLOBALS['connexions'][$index]['spip_connect_version'] and sql_showtable('spip_meta', true, $serveur) and $r = sql_getfetsel('valeur', 'spip_meta', "nom='charset_sql_connexion'", '', '', '', '', $serveur) ) { $charset = $r; } else { $charset = -1; } } if ($charset != -1) { $f = $GLOBALS[$jeu]['set_charset']; if (function_exists($f)) { $f($charset, $serveur); } } return $GLOBALS['connexions'][$index]; } /** * Log la dernière erreur SQL présente sur la connexion indiquée * * @param string $serveur Nom du connecteur de bdd utilisé **/ function spip_sql_erreur($serveur = '') { $connexion = spip_connect($serveur); $e = sql_errno($serveur); $t = (isset($connexion['type']) ? $connexion['type'] : 'sql'); $m = "Erreur $e de $t: " . sql_error($serveur) . "\nin " . sql_error_backtrace() . "\n" . trim($connexion['last']); $f = $t . $serveur; spip_log($m, $f . '.' . _LOG_ERREUR); } /** * Retourne le nom de la fonction adaptée de l'API SQL en fonction du type de serveur * * Cette fonction ne doit être appelée qu'à travers la fonction sql_serveur * définie dans base/abstract_sql * * Elle existe en tant que gestionnaire de versions, * connue seulement des convertisseurs automatiques * * @param string $version Numéro de version de l'API SQL * @param string $ins Instruction de l'API souhaitée, tel que 'allfetsel' * @param string $serveur Nom du connecteur * @param bool $cont true pour continuer même si le serveur SQL ou l'instruction est indisponible * @return array|bool|string * - string : nom de la fonction à utiliser, * - false : si la connexion a échouée * - array : description de la connexion, si l'instruction sql est indisponible pour cette connexion **/ function spip_connect_sql($version, $ins = '', $serveur = '', $cont = false) { $desc = spip_connect($serveur, $version); if (function_exists($f = @$desc[$version][$ins])) { return $f; } if ($cont) { return $desc; } if ($ins) { spip_log("Le serveur '$serveur' version $version n'a pas '$ins'", _LOG_ERREUR); } include_spip('inc/minipres'); echo minipres(_T('info_travaux_titre'), _T('titre_probleme_technique'), array('status' => 503)); exit; } /** * Fonction appelée par le fichier connecteur de base de données * crée dans `config/` à l'installation. * * Il contient un appel direct à cette fonction avec comme arguments * les identifants de connexion. * * Si la connexion reussit, la globale `db_ok` mémorise sa description. * C'est un tableau également retourné en valeur, pour les appels * lors de l'installation. * * @param string $host Adresse du serveur de base de données * @param string $port Port utilisé pour la connexion * @param string $login Identifiant de connexion à la base de données * @param string $pass Mot de passe pour cet identifiant * @param string $db Nom de la base de données à utiliser * @param string $type Type de base de données tel que 'mysql', 'sqlite3' (cf ecrire/req/) * @param string $prefixe Préfixe des tables SPIP * @param string $auth Type d'authentification (cas si 'ldap') * @param string $charset Charset de la connexion SQL (optionnel) * @return array Description de la connexion */ function spip_connect_db( $host, $port, $login, $pass, $db = '', $type = 'mysql', $prefixe = '', $auth = '', $charset = '' ) { // temps avant nouvelle tentative de connexion // suite a une connection echouee if (!defined('_CONNECT_RETRY_DELAY')) { define('_CONNECT_RETRY_DELAY', 30); } $f = ""; // un fichier de identifiant par combinaison (type,host,port,db) // pour ne pas declarer tout indisponible d'un coup // si en cours d'installation ou si db=@test@ on ne pose rien // car c'est un test de connexion if (!defined('_ECRIRE_INSTALL') and $db !== "@test@") { $f = _DIR_TMP . $type . '.' . substr(md5($host . $port . $db), 0, 8) . '.out'; } elseif ($db == '@test@') { $db = ''; } if ($f and @file_exists($f) and (time() - @filemtime($f) < _CONNECT_RETRY_DELAY) ) { spip_log("Echec : $f recent. Pas de tentative de connexion", _LOG_HS); return; } if (!$prefixe) { $prefixe = isset($GLOBALS['table_prefix']) ? $GLOBALS['table_prefix'] : $db; } $h = charger_fonction($type, 'req', true); if (!$h) { spip_log("les requetes $type ne sont pas fournies", _LOG_HS); return; } if ($g = $h($host, $port, $login, $pass, $db, $prefixe)) { if (!is_array($auth)) { // compatibilite version 0.7 initiale $g['ldap'] = $auth; $auth = array('ldap' => $auth); } $g['authentification'] = $auth; $g['type'] = $type; $g['charset'] = $charset; return $GLOBALS['db_ok'] = $g; } // En cas d'indisponibilite du serveur, eviter de le bombarder if ($f) { @touch($f); spip_log("Echec connexion serveur $type : host[$host] port[$port] login[$login] base[$db]", $type . '.' . _LOG_HS); } } /** * Première connexion au serveur principal de base de données * * Retourner le charset donnée par la table principale * mais vérifier que le fichier de connexion n'est pas trop vieux * * @note * Version courante = 0.8 * * - La version 0.8 indique un charset de connexion comme 9e arg * - La version 0.7 indique un serveur d'authentification comme 8e arg * - La version 0.6 indique le prefixe comme 7e arg * - La version 0.5 indique le serveur comme 6e arg * * La version 0.0 (non numerotée) doit être refaite par un admin. * Les autres fonctionnent toujours, même si : * * - la version 0.1 est moins performante que la 0.2 * - la 0.2 fait un include_ecrire('inc_db_mysql.php3'). * * @param array $connexion Description de la connexion * @param string $charset_sql_connexion charset de connexion fourni dans l'appal a spip_connect_db * @return string|bool|int * - false si pas de charset connu pour la connexion * - -1 charset non renseigné * - nom du charset sinon **/ function spip_connect_main($connexion, $charset_sql_connexion = '') { if ($GLOBALS['spip_connect_version'] < 0.1 and _DIR_RESTREINT) { include_spip('inc/headers'); redirige_url_ecrire('upgrade', 'reinstall=oui'); } if (!($f = $connexion['select'])) { return false; } // si le charset est fourni, l'utiliser if ($charset_sql_connexion) { return $charset_sql_connexion; } // sinon on regarde la table spip_meta // en cas d'erreur select retourne la requette (is_string=true donc) if (!$r = $f('valeur', 'spip_meta', "nom='charset_sql_connexion'") or is_string($r) ) { return false; } if (!($f = $connexion['fetch'])) { return false; } $r = $f($r); return ($r['valeur'] ? $r['valeur'] : -1); } /** * Connection à LDAP * * Fonction présente pour compatibilité * * @deprecated Utiliser l'authentification LDAP de auth/ldap * @uses auth_ldap_connect() * * @param string $serveur Nom du connecteur * @return array */ function spip_connect_ldap($serveur = '') { include_spip('auth/ldap'); return auth_ldap_connect($serveur); } /** * Échappement d'une valeur sous forme de chaîne PHP * * Échappe une valeur (num, string, array) pour en faire une chaîne pour PHP. * Un `array(1,'a',"a'")` renvoie la chaine `"'1','a','a\''"` * * @note * L'usage comme échappement SQL est déprécié, à remplacer par sql_quote(). * * @param num|string|array $a Valeur à échapper * @return string Valeur échappée. **/ function _q($a) { return (is_numeric($a)) ? strval($a) : (!is_array($a) ? ("'" . addslashes($a) . "'") : join(",", array_map('_q', $a))); } /** * Récupérer le nom de la table de jointure `xxxx` sur l'objet `yyyy` * * @deprecated * Utiliser l'API editer_liens ou les tables de liaisons spip_xx_liens * ou spip_yy_liens selon. * * @param string $x Table de destination * @param string $y Objet source * @return array|string * - array : Description de la table de jointure si connue * - chaîne vide si non trouvé. **/ function table_jointure($x, $y) { $trouver_table = charger_fonction('trouver_table', 'base'); $xdesc = $trouver_table(table_objet($x)); $ydesc = $trouver_table(table_objet($y)); $ix = @$xdesc['key']["PRIMARY KEY"]; $iy = @$ydesc['key']["PRIMARY KEY"]; if ($table = $ydesc['tables_jointures'][$ix]) { return $table; } if ($table = $xdesc['tables_jointures'][$iy]) { return $table; } return ''; } /** * Echapper les textes entre ' ' ou " " d'une requête SQL * avant son pre-traitement * * On renvoi la query sans textes et les textes séparés, dans * leur ordre d'apparition dans la query * * @see query_reinjecte_textes() * * @param string $query * @return array */ function query_echappe_textes($query) { static $codeEchappements = array("''" => "\x1@##@\x1", "\'" => "\x2@##@\x2", "\\\"" => "\x3@##@\x3"); $query = str_replace(array_keys($codeEchappements), array_values($codeEchappements), $query); if (preg_match_all("/((['])[^']*(\\2))|(([\"])[^\"]*(\\5))/S", $query, $textes)) { $textes = reset($textes); // indice 0 du match switch (count($textes)) { case 0: $replace = array(); break; case 1: $replace = array('%1$s'); break; case 2: $replace = array('%1$s', '%2$s'); break; case 3: $replace = array('%1$s', '%2$s', '%3$s'); break; case 4: $replace = array('%1$s', '%2$s', '%3$s', '%4$s'); break; case 5: $replace = array('%1$s', '%2$s', '%3$s', '%4$s', '%5$s'); break; default: $replace = range(1, count($textes)); $replace = '%' . implode('$s,%', $replace) . '$s'; $replace = explode(',', $replace); break; } $query = str_replace($textes, $replace, $query); } else { $textes = array(); } return array($query, $textes); } /** * Réinjecter les textes d'une requete SQL à leur place initiale, * après traitement de la requête * * @see query_echappe_textes() * * @param string $query * @param array $textes * @return string */ function query_reinjecte_textes($query, $textes) { static $codeEchappements = array("''" => "\x1@##@\x1", "\'" => "\x2@##@\x2", "\\\"" => "\x3@##@\x3"); # debug de la substitution #if (($c1=substr_count($query,"%"))!=($c2=count($textes))){ # spip_log("$c1 ::". $query,"tradquery"._LOG_ERREUR); # spip_log("$c2 ::". var_export($textes,1),"tradquery"._LOG_ERREUR); # spip_log("ini ::". $qi,"tradquery"._LOG_ERREUR); #} switch (count($textes)) { case 0: break; case 1: $query = sprintf($query, $textes[0]); break; case 2: $query = sprintf($query, $textes[0], $textes[1]); break; case 3: $query = sprintf($query, $textes[0], $textes[1], $textes[2]); break; case 4: $query = sprintf($query, $textes[0], $textes[1], $textes[2], $textes[3]); break; case 5: $query = sprintf($query, $textes[0], $textes[1], $textes[2], $textes[3], $textes[4]); break; default: array_unshift($textes, $query); $query = call_user_func_array('sprintf', $textes); break; } $query = str_replace(array_values($codeEchappements), array_keys($codeEchappements), $query); return $query; } /** * Exécute une requête sur le serveur SQL * * @see sql_query() * @deprecated Pour compatibilité. Utiliser `sql_query()` ou l'API `sql_*`. * * @param string $query Texte de la requête * @param string $serveur Nom du connecteur pour la base de données * @return bool|mixed * - false si on ne peut pas exécuter la requête * - indéfini sinon. **/ function spip_query($query, $serveur = '') { $f = spip_connect_sql($GLOBALS['spip_sql_version'], 'query', $serveur, true); return function_exists($f) ? $f($query, $serveur) : false; } dump.php000066600000063577152442520540006253 0ustar00<?php /***************************************************************************\ * SPIP, Systeme de publication pour l'internet * * * * Copyright (c) 2001-2019 * * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * \***************************************************************************/ /** * Fonctions de base pour la sauvegarde * * Boîte à outil commune, sans préjuger de la méthode de sauvegarde */ if (!defined('_ECRIRE_INC_VERSION')) { return; } define('_VERSION_ARCHIVE', '1.3'); include_spip('base/serial'); include_spip('base/auxiliaires'); include_spip('public/interfaces'); // pour table_jointures // NB: Ce fichier peut ajouter des tables (old-style) // donc il faut l'inclure "en globals" if ($f = find_in_path('mes_fonctions.php')) { global $dossier_squelettes; @include_once(_ROOT_CWD . $f); } if (@is_readable(_CACHE_PLUGINS_FCT)) { // chargement optimise precompile include_once(_CACHE_PLUGINS_FCT); } /** * Retourne un nom de meta pour une rubrique et l'auteur connecté. * * Ce nom servira pour le stockage dans un fichier temporaire des informations * sérialisées sur le statut de l'export. * * @param int $rub * @return string **/ function base_dump_meta_name($rub) { return $meta = "status_dump_{$rub}_" . abs($GLOBALS['visiteur_session']['id_auteur']); } /** * Crée un répertoire recevant la sauvegarde de la base de données * et retourne son chemin. * * @note * Utilisé uniquement dans l'ancienne sauvegarde XML (plugin dump_xml) * À supprimer ? * * @param string $meta * @return string **/ function base_dump_dir($meta) { include_spip('inc/documents'); // determine upload va aussi initialiser l'index "restreint" $maindir = determine_upload(); if (!$GLOBALS['visiteur_session']['restreint']) { $maindir = _DIR_DUMP; } $dir = sous_repertoire($maindir, $meta); return $dir; } /** * Lister toutes les tables d'un serveur * en excluant eventuellement une liste fournie * * @param string $serveur * @param array $tables * @param array $exclude * @param bool $affiche_vrai_prefixe * @return array */ function base_lister_toutes_tables( $serveur = '', $tables = array(), $exclude = array(), $affiche_vrai_prefixe = false ) { spip_connect($serveur); $connexion = $GLOBALS['connexions'][$serveur ? $serveur : 0]; $prefixe = $connexion['prefixe']; $p = '/^' . $prefixe . '/'; $res = $tables; foreach (sql_alltable(null, $serveur) as $t) { if (preg_match($p, $t)) { $t1 = preg_replace($p, 'spip', $t); if (!in_array($t1, $tables) and !in_array($t1, $exclude)) { $res[] = ($affiche_vrai_prefixe ? $t : $t1); } } } sort($res); return $res; } /** * Retrouver le prefixe des tables * * @param string $serveur * @return string */ function base_prefixe_tables($serveur = '') { spip_connect($serveur); $connexion = $GLOBALS['connexions'][$serveur ? $serveur : 0]; $prefixe = $connexion['prefixe']; return $prefixe; } /** * Fabrique la liste a cocher des tables a traiter (copie, delete, sauvegarde) * * @param string $name * @param array $tables * @param array $exclude * @param array|null $post * @param string $serveur * @return array */ function base_saisie_tables($name, $tables, $exclude = array(), $post = null, $serveur = '') { include_spip('inc/filtres'); $res = array(); foreach ($tables as $k => $t) { // par defaut tout est coche sauf les tables dans $exclude if (is_null($post)) { $check = (in_array($t, $exclude) ? false : true); } // mais si on a poste une selection, la reprendre else { $check = in_array($t, $post); } $res[$k] = "<input type='checkbox' value='$t' name='$name" . "[]' id='$name$k'" . ($check ? " checked='checked'" : '') . "/>\n" . "<label for='$name$k'>$t</label>" . " (" . sinon(singulier_ou_pluriel(sql_countsel($t, '', '', '', $serveur), 'dump:une_donnee', 'dump:nb_donnees'), _T('dump:aucune_donnee')) . ")"; } return $res; } /** * Lister les tables non exportables par defaut * (liste completable par le pipeline lister_tables_noexport * * @staticvar array $EXPORT_tables_noexport * @return array */ function lister_tables_noexport() { // par defaut tout est exporte sauf les tables ci-dessous static $EXPORT_tables_noexport = null; if (!is_null($EXPORT_tables_noexport)) { return $EXPORT_tables_noexport; } $EXPORT_tables_noexport = array( 'spip_caches', // plugin invalideur 'spip_resultats', // resultats de recherche ... c'est un cache ! 'spip_test', // c'est un test ! #'spip_referers', #'spip_referers_articles', #'spip_visites', #'spip_visites_articles', #'spip_versions', #'spip_versions_fragments' ); $EXPORT_tables_noexport = pipeline('lister_tables_noexport', $EXPORT_tables_noexport); return $EXPORT_tables_noexport; } /** * Lister les tables non importables par defaut * (liste completable par le pipeline lister_tables_noimport * * @staticvar array $IMPORT_tables_noimport * @return array */ function lister_tables_noimport() { static $IMPORT_tables_noimport = null; if (!is_null($IMPORT_tables_noimport)) { return $IMPORT_tables_noimport; } $IMPORT_tables_noimport = array(); // par defaut tout est importe sauf les tables ci-dessous // possibiliter de definir cela tables via la meta // compatibilite if (isset($GLOBALS['meta']['IMPORT_tables_noimport'])) { $IMPORT_tables_noimport = unserialize($GLOBALS['meta']['IMPORT_tables_noimport']); if (!is_array($IMPORT_tables_noimport)) { include_spip('inc/meta'); effacer_meta('IMPORT_tables_noimport'); } } $IMPORT_tables_noimport = pipeline('lister_tables_noimport', $IMPORT_tables_noimport); return $IMPORT_tables_noimport; } /** * Lister les tables a ne pas effacer * (liste completable par le pipeline lister_tables_noerase * * @staticvar array $IMPORT_tables_noerase * @return array */ function lister_tables_noerase() { static $IMPORT_tables_noerase = null; if (!is_null($IMPORT_tables_noerase)) { return $IMPORT_tables_noerase; } $IMPORT_tables_noerase = array( 'spip_meta', // par defaut on ne vide pas les stats, car elles ne figurent pas dans les dump // et le cas echeant, un bouton dans l'admin permet de les vider a la main... 'spip_referers', 'spip_referers_articles', 'spip_visites', 'spip_visites_articles' ); $IMPORT_tables_noerase = pipeline('lister_tables_noerase', $IMPORT_tables_noerase); return $IMPORT_tables_noerase; } /** * construction de la liste des tables pour le dump : * toutes les tables principales * + toutes les tables auxiliaires hors relations * + les tables relations dont les deux tables liees sont dans la liste * * @param array $exclude_tables * @return array */ function base_liste_table_for_dump($exclude_tables = array()) { $tables_for_dump = array(); $tables_pointees = array(); $tables = array(); $tables_principales = $GLOBALS['tables_principales']; $tables_auxiliaires = $GLOBALS['tables_auxiliaires']; $tables_jointures = $GLOBALS['tables_jointures']; if (include_spip('base/objets') and function_exists('lister_tables_objets_sql') ) { $tables = lister_tables_objets_sql(); foreach ($tables as $t => $infos) { if ($infos['principale'] and !isset($tables_principales[$t])) { $tables_principales[$t] = true; } if (!$infos['principale'] and !isset($tables_auxiliaires[$t])) { $tables_auxiliaires[$t] = true; } if (count($infos['tables_jointures'])) { $tables_jointures[$t] = array_merge(isset($tables_jointures[$t]) ? $tables_jointures[$t] : array(), $infos['tables_jointures']); } } } // on construit un index des tables de liens // pour les ajouter SI les deux tables qu'ils connectent sont sauvegardees $tables_for_link = array(); foreach ($tables_jointures as $table => $liste_relations) { if (is_array($liste_relations)) { $nom = $table; if (!isset($tables_auxiliaires[$nom]) && !isset($tables_principales[$nom])) { $nom = "spip_$table"; } if (isset($tables_auxiliaires[$nom]) || isset($tables_principales[$nom])) { foreach ($liste_relations as $link_table) { if (isset($tables_auxiliaires[$link_table])/*||isset($tables_principales[$link_table])*/) { $tables_for_link[$link_table][] = $nom; } else { if (isset($tables_auxiliaires["spip_$link_table"])/*||isset($tables_principales["spip_$link_table"])*/) { $tables_for_link["spip_$link_table"][] = $nom; } } } } } } $liste_tables = array_merge(array_keys($tables_principales), array_keys($tables_auxiliaires), array_keys($tables)); foreach ($liste_tables as $table) { // $name = preg_replace("{^spip_}","",$table); if (!isset($tables_pointees[$table]) && !in_array($table, $exclude_tables) && !isset($tables_for_link[$table]) ) { $tables_for_dump[] = $table; $tables_pointees[$table] = 1; } } foreach ($tables_for_link as $link_table => $liste) { $connecte = true; foreach ($liste as $connect_table) { if (!in_array($connect_table, $tables_for_dump)) { $connecte = false; } } if ($connecte) # on ajoute les liaisons en premier # si une restauration est interrompue, # cela se verra mieux si il manque des objets # que des liens { array_unshift($tables_for_dump, $link_table); } } return array($tables_for_dump, $tables_for_link); } /** * Vider les tables de la base de destination * pour la copie dans une base * * peut etre utilise pour l'import depuis xml, * ou la copie de base a base (mysql<->sqlite par exemple) * * @param array $tables * @param array $exclure_tables * @param string $serveur */ function base_vider_tables_destination_copie($tables, $exclure_tables = array(), $serveur = '') { $trouver_table = charger_fonction('trouver_table', 'base'); spip_log('Vider ' . count($tables) . " tables sur serveur '$serveur' : " . join(', ', $tables), 'base.' . _LOG_INFO_IMPORTANTE); foreach ($tables as $table) { if (!in_array($table, $exclure_tables)) { // sur le serveur principal, il ne faut pas supprimer l'auteur loge ! if (($table != 'spip_auteurs') or $serveur != '') { // regarder si il y a au moins un champ impt='non' $desc = $trouver_table($table, $serveur); if (isset($desc['field']['impt'])) { sql_delete($table, "impt='oui'", $serveur); } else { sql_delete($table, "", $serveur); } } } } // sur le serveur principal, il ne faut pas supprimer l'auteur loge ! // Bidouille pour garder l'acces admin actuel pendant toute la restauration if ($serveur == '' and in_array('spip_auteurs', $tables) and !in_array('spip_auteurs', $exclure_tables) ) { base_conserver_copieur(true, $serveur); sql_delete("spip_auteurs", "id_auteur>0", $serveur); } } /** * Conserver le copieur si besoin * * @param bool $move * @param string $serveur * @return void */ function base_conserver_copieur($move = true, $serveur = '') { // s'asurer qu'on a pas deja fait la manip ! if ($GLOBALS['visiteur_session']['id_auteur'] > 0 and sql_countsel("spip_auteurs", "id_auteur>0")) { spip_log('Conserver copieur dans id_auteur=' . $GLOBALS['visiteur_session']['id_auteur'] . " pour le serveur '$serveur'", 'dump.' . _LOG_INFO_IMPORTANTE); sql_delete("spip_auteurs", "id_auteur<0", $serveur); if ($move) { sql_updateq('spip_auteurs', array('id_auteur' => -$GLOBALS['visiteur_session']['id_auteur']), "id_auteur=" . intval($GLOBALS['visiteur_session']['id_auteur']), array(), $serveur); } else { $row = sql_fetsel('*', 'spip_auteurs', 'id_auteur=' . $GLOBALS['visiteur_session']['id_auteur'], '', '', '', '', $serveur); $row['id_auteur'] = -$GLOBALS['visiteur_session']['id_auteur']; sql_insertq('spip_auteurs', $row, array(), $serveur); } } } /** * Effacement de la bidouille ci-dessus * Toutefois si la table des auteurs ne contient plus qu'elle * c'est que la copie etait incomplete et on restaure le compte * pour garder la connection au site * * (mais il doit pas etre bien beau * et ca ne marche que si l'id_auteur est sur moins de 3 chiffres) * * @param string $serveur */ function base_detruire_copieur_si_besoin($serveur = '') { // rien a faire si ce n'est pas le serveur principal ! if ($serveur == '') { if (sql_countsel("spip_auteurs", "id_auteur>0")) { spip_log("Detruire copieur id_auteur<0 pour le serveur '$serveur'", 'dump.' . _LOG_INFO_IMPORTANTE); sql_delete("spip_auteurs", "id_auteur<0", $serveur); } else { spip_log("Restaurer copieur id_auteur<0 pour le serveur '$serveur' (aucun autre auteur en base)", 'dump.' . _LOG_INFO_IMPORTANTE); sql_update('spip_auteurs', array('id_auteur' => '-id_auteur'), "id_auteur<0"); } } else { spip_log("Pas de destruction copieur sur serveur '$serveur'", 'dump.' . _LOG_INFO_IMPORTANTE); } } /** * Preparer la table dans la base de destination : * la droper si elle existe (sauf si auteurs ou meta sur le serveur principal) * la creer si necessaire, ou ajouter simplement les champs manquants * * @param string $table * @param array $desc * @param string $serveur_dest * @param bool $init * @return array */ function base_preparer_table_dest($table, $desc, $serveur_dest, $init = false) { $upgrade = false; // si la table existe et qu'on est a l'init, la dropper if ($desc_dest = sql_showtable($table, true, $serveur_dest) and $init) { if ($serveur_dest == '' and in_array($table, array('spip_meta', 'spip_auteurs'))) { // ne pas dropper auteurs et meta sur le serveur principal // faire un simple upgrade a la place // pour ajouter les champs manquants $upgrade = true; // coherence avec le drop sur les autres tables base_vider_tables_destination_copie(array($table), array(), $serveur_dest); if ($table == 'spip_meta') { // virer les version base qui vont venir avec l'import sql_delete($table, "nom like '%_base_version'", $serveur_dest); // hum casse la base si pas version_installee a l'import ... sql_delete($table, "nom='version_installee'", $serveur_dest); } } else { sql_drop_table($table, '', $serveur_dest); spip_log("drop table '$table' sur serveur '$serveur_dest'", 'dump.' . _LOG_INFO_IMPORTANTE); } $desc_dest = false; } // si la table n'existe pas dans la destination, la creer a l'identique ! if (!$desc_dest) { spip_log("creation '$table' sur serveur '$serveur_dest'", 'dump.' . _LOG_INFO_IMPORTANTE); include_spip('base/create'); creer_ou_upgrader_table($table, $desc, 'auto', $upgrade, $serveur_dest); $desc_dest = sql_showtable($table, true, $serveur_dest); } if (!$desc_dest) { spip_log("Erreur creation '$table' sur serveur '$serveur_dest'" . var_export($desc, 1), 'dump.' . _LOG_ERREUR); } return $desc_dest; } /** * Copier de base a base * * @param string $status_file * nom avec chemin complet du fichier ou est stocke le status courant * @param array $tables * liste des tables a copier * @param string $serveur_source * @param string $serveur_dest * @param array $options * parametres optionnels sous forme de tableau : * param string $callback_progression * fonction a appeler pour afficher la progression, avec les arguments (compteur,total,table) * param int $max_time * limite de temps au dela de laquelle sortir de la fonction proprement (de la forme time()+15) * param bool $drop_source * vider les tables sources apres copie * param array $no_erase_dest * liste des tables a ne pas vider systematiquement (ne seront videes que si existent dans la base source) * param array $where * liste optionnelle de condition where de selection des donnees pour chaque table * param string $racine_fonctions_dest * racine utilisee pour charger_fonction() des operations elementaires sur la base de destination. * Permet de deleguer vers une autre voie de communication. * Par defaut on utilise 'base', ce qui route vers les fonctions de ce fichier. Concerne : * - vider_tables_destination_copie * - preparer_table_dest * - detruire_copieur_si_besoin * - inserer_copie * param array $fonction_base_inserer * fonction d'insertion en base. Par defaut "inserer_copie" qui fait un insertq a l'identique. * Attention, la fonction appelee est prefixee par $racine_fonctions_dest via un charger_fonction() * Peut etre personalisee pour filtrer, renumeroter.... * param array $desc_tables_dest * description des tables de destination a utiliser de preference a la description de la table source * param int data_pool * nombre de ko de donnees a envoyer d'un coup en insertion dans la table cible (par defaut 1) * permet des envois groupes pour plus de rapidite, notamment si l'insertion est distante * * @return bool */ function base_copier_tables($status_file, $tables, $serveur_source, $serveur_dest, $options = array()) { $callback_progression = isset($options['callback_progression']) ? $options['callback_progression'] : ''; $max_time = isset($options['max_time']) ? $options['max_time'] : 0; $drop_source = isset($options['drop_source']) ? $options['drop_source'] : false; $no_erase_dest = isset($options['no_erase_dest']) ? $options['no_erase_dest'] : array(); $where = isset($options['where']) ? $options['where'] : array(); $fonction_base_inserer = isset($options['fonction_base_inserer']) ? $options['fonction_base_inserer'] : 'inserer_copie'; $desc_tables_dest = isset($options['desc_tables_dest']) ? $options['desc_tables_dest'] : array(); $racine_fonctions = (isset($options['racine_fonctions_dest']) ? $options['racine_fonctions_dest'] : 'base'); $data_pool = (isset($options['data_pool']) ? $options['data_pool'] : 50 * 1024); spip_log("Copier " . count($tables) . " tables de '$serveur_source' vers '$serveur_dest'", 'dump.' . _LOG_INFO_IMPORTANTE); if (!$inserer_copie = charger_fonction($fonction_base_inserer, $racine_fonctions, true)) { spip_log("Fonction '{$racine_fonctions}_$fonction_base_inserer' inconnue. Abandon", 'dump.' . _LOG_INFO_IMPORTANTE); return true; // echec mais on a fini, donc true } if (!$preparer_table_dest = charger_fonction('preparer_table_dest', $racine_fonctions, true)) { spip_log("Fonction '{$racine_fonctions}_$preparer_table_dest' inconnue. Abandon", 'dump.' . _LOG_INFO_IMPORTANTE); return true; // echec mais on a fini, donc true } if (!lire_fichier($status_file, $status) or !$status = unserialize($status) ) { $status = array(); } $status['etape'] = 'basecopie'; // puis relister les tables a importer // et les vider si besoin, au moment du premier passage ici $initialisation_copie = (!isset($status["dump_status_copie"])) ? 0 : $status["dump_status_copie"]; // si init pas encore faite, vider les tables du serveur destination if (!$initialisation_copie) { if (!$vider_tables_destination_copie = charger_fonction('vider_tables_destination_copie', $racine_fonctions, true) ) { spip_log("Fonction '{$racine_fonctions}_vider_tables_destination_copie' inconnue. Abandon", 'dump.' . _LOG_INFO_IMPORTANTE); return true; // echec mais on a fini, donc true } $vider_tables_destination_copie($tables, $no_erase_dest, $serveur_dest); $status["dump_status_copie"] = 'ok'; ecrire_fichier($status_file, serialize($status)); } // les tables auteurs et meta doivent etre copiees en dernier ! if (in_array('spip_auteurs', $tables)) { $tables = array_diff($tables, array('spip_auteurs')); $tables[] = 'spip_auteurs'; } if (in_array('spip_meta', $tables)) { $tables = array_diff($tables, array('spip_meta')); $tables[] = 'spip_meta'; } spip_log("Tables a copier :" . implode(", ", $tables), 'dump.' . _LOG_INFO); $trouver_table = charger_fonction('trouver_table', 'base'); foreach ($tables as $table) { // si table commence par spip_ c'est une table SPIP, renommer le prefixe si besoin // sinon chercher la vraie table $desc_source = false; if (strncmp($table, "spip_", 5) == 0) { $desc_source = $trouver_table(preg_replace(",^spip_,", "", $table), $serveur_source, true); } if (!$desc_source or !isset($desc_source['exist']) or !$desc_source['exist']) { $desc_source = $trouver_table($table, $serveur_source, false); } // verifier que la table est presente dans la base source if ($desc_source) { // $status['tables_copiees'][$table] contient l'avancement // de la copie pour la $table : 0 a N et -N quand elle est finie (-1 si vide et finie...) if (!isset($status['tables_copiees'][$table])) { $status['tables_copiees'][$table] = 0; } if (is_numeric($status['tables_copiees'][$table]) and $status['tables_copiees'][$table] >= 0 and $desc_dest = $preparer_table_dest( $table, isset($desc_tables_dest[$table]) ? $desc_tables_dest[$table] : $desc_source, $serveur_dest, $status['tables_copiees'][$table] == 0) ) { if ($callback_progression) { $callback_progression($status['tables_copiees'][$table], 0, $table); } while (true) { $n = intval($status['tables_copiees'][$table]); // on copie par lot de 400 $res = sql_select('*', $table, isset($where[$table]) ? $where[$table] : '', '', '', "$n,400", '', $serveur_source); while ($row = sql_fetch($res, $serveur_source)) { $rows = array($row); // lire un groupe de donnees si demande en option // (permet un envoi par lot vers la destination) if ($data_pool > 0) { $s = strlen(serialize($row)); while ($s < $data_pool and $row = sql_fetch($res, $serveur_source)) { $s += strlen(serialize($row)); $rows[] = $row; } } // si l'enregistrement est deja en base, ca fera un echec ou un doublon // mais si ca renvoie false c'est une erreur fatale => abandon if ($inserer_copie($table, $rows, $desc_dest, $serveur_dest) === false) { // forcer la sortie, charge a l'appelant de gerer l'echec spip_log("Erreur fatale dans $inserer_copie table $table", "dump" . _LOG_ERREUR); $status['errors'][] = "Erreur fatale lors de la copie de la table $table"; ecrire_fichier($status_file, serialize($status)); // copie finie return true; } $status['tables_copiees'][$table] += count($rows); if ($max_time and time() > $max_time) { break; } } if ($n == $status['tables_copiees'][$table]) { break; } spip_log("recopie $table " . $status['tables_copiees'][$table], 'dump.' . _LOG_INFO_IMPORTANTE); if ($callback_progression) { $callback_progression($status['tables_copiees'][$table], 0, $table); } ecrire_fichier($status_file, serialize($status)); if ($max_time and time() > $max_time) { return false; } // on a pas fini, mais le temps imparti est ecoule } if ($drop_source) { sql_drop_table($table, '', $serveur_source); spip_log("drop $table sur serveur source '$serveur_source'", 'dump.' . _LOG_INFO_IMPORTANTE); } $status['tables_copiees'][$table] = ($status['tables_copiees'][$table] ? -$status['tables_copiees'][$table] : "zero"); ecrire_fichier($status_file, serialize($status)); spip_log("tables_recopiees " . implode(',', array_keys($status['tables_copiees'])), 'dump.' . _LOG_INFO); if ($callback_progression) { $callback_progression($status['tables_copiees'][$table], $status['tables_copiees'][$table], $table); } } else { if ($status['tables_copiees'][$table] < 0) { spip_log("Table $table deja copiee : " . $status['tables_copiees'][$table], "dump." . _LOG_INFO); } if ($callback_progression) { $callback_progression(0, $status['tables_copiees'][$table], "$table" . ((is_numeric($status['tables_copiees'][$table]) and $status['tables_copiees'][$table] >= 0) ? "[Echec]" : "")); } } } else { $status['errors'][] = "Impossible de lire la description de la table $table"; ecrire_fichier($status_file, serialize($status)); spip_log("Impossible de lire la description de la table $table", "dump." . _LOG_ERREUR); } } // si le nombre de tables envoyees n'est pas egal au nombre de tables demandees // abandonner if (count($status['tables_copiees']) < count($tables)) { spip_log("Nombre de tables copiees incorrect : " . count($status['tables_copiees']) . "/" . count($tables), "dump." . _LOG_ERREUR); $status['errors'][] = "Nombre de tables copiees incorrect : " . count($status['tables_copiees']) . "/" . count($tables); ecrire_fichier($status_file, serialize($status)); } if ($detruire_copieur_si_besoin = charger_fonction('detruire_copieur_si_besoin', $racine_fonctions, true)) { $detruire_copieur_si_besoin($serveur_dest); } else { spip_log("Fonction '{$racine_fonctions}_detruire_copieur_si_besoin' inconnue.", 'dump.' . _LOG_INFO_IMPORTANTE); } // OK, copie complete return true; } /** * fonction d'insertion en base lors de la copie de base a base * * @param string $table * @param array $rows * @param array $desc_dest * @param string $serveur_dest * @return int/bool */ function base_inserer_copie($table, $rows, $desc_dest, $serveur_dest) { // verifier le nombre d'insertion $nb1 = sql_countsel($table, '', '', '', $serveur_dest); // si l'enregistrement est deja en base, ca fera un echec ou un doublon $r = sql_insertq_multi($table, $rows, $desc_dest, $serveur_dest); $nb = sql_countsel($table, '', '', '', $serveur_dest); if ($nb - $nb1 < count($rows)) { spip_log("base_inserer_copie : " . ($nb - $nb1) . " insertions au lieu de " . count($rows) . ". On retente 1 par 1", "dump" . _LOG_INFO_IMPORTANTE); foreach ($rows as $row) { // si l'enregistrement est deja en base, ca fera un echec ou un doublon $r = sql_insertq($table, $row, $desc_dest, $serveur_dest); } // on reverifie le total $r = 0; $nb = sql_countsel($table, '', '', '', $serveur_dest); if ($nb - $nb1 < count($rows)) { spip_log("base_inserer_copie : " . ($nb - $nb1) . " insertions au lieu de " . count($rows) . " apres insertion 1 par 1", "dump" . _LOG_ERREUR); $r = false; } } return $r; } trouver_table.php000066600000015337152442520540010152 0ustar00<?php /***************************************************************************\ * SPIP, Systeme de publication pour l'internet * * * * Copyright (c) 2001-2019 * * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * \***************************************************************************/ /** * Gestion de l'obtention des descriptions de tables SQL * * @package SPIP\Core\SQL\Tables **/ if (!defined('_ECRIRE_INC_VERSION')) { return; } include_spip('base/objets'); /** * Retourne la description d'une table SQL * * Cela sert notamment au moment de la compilation des boucles, critères et balise. * * Les champs et clés de la tables sont retrouvés prioritairement via le * gestionnaire de base de données. Les descriptions sont complétées, * pour les tables éditoriales, des informations déclarées ou construites * par la déclaration des objets éditoriaux. * * @example * $trouver_table = charger_fonction('trouver_table', 'base'); * $desc = $trouver_table('spip_groupes_mots'); * * Cette fonction intervient à la compilation, mais aussi pour la balise * contextuelle EXPOSE ou certains critères. * * L'ensemble des descriptions de table d'un serveur est stocké dans un * fichier cache/sql_desc.txt par soucis de performance. Un appel * avec $nom vide est une demande explicite de vidange de ce cache * * @see lister_tables_objets_sql() * * @api * @param string $nom * Nom de la table * Vide '' demande de vider le cache des discriptions * @param string $serveur * Nom du connecteur * @param bool $table_spip * Indique s'il faut transformer le préfixe de table * @return array|bool * false si table introuvable * tableau de description de la table sinon, en particulier : * - field : tableau des colonnes SQL et leur description (comme dans serial.php ou objets.php) * - key : tableau des KEY (comme dans serial.php ou objets.php) * - table et table_sql : nom de la table (avec spip_ en préfixe) * - id_table : nom SPIP de la table (type de boucle) * le compilateur produit FROM $r['table'] AS $r['id_table'] * - Toutes les autres informations des objets éditoriaux si la table est l'un d'eux. * * **/ function base_trouver_table_dist($nom, $serveur = '', $table_spip = true) { static $nom_cache_desc_sql = array(); if (!spip_connect($serveur) or !preg_match('/^[a-zA-Z0-9._-]*/', $nom) ) { return null; } $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0]; $objets_sql = lister_tables_objets_sql("::md5"); // le nom du cache depend du serveur mais aussi du nom de la db et du prefixe // ce qui permet une auto invalidation en cas de modif manuelle du fichier // de connexion, et tout risque d'ambiguite if (!isset($nom_cache_desc_sql[$serveur][$objets_sql])) { $nom_cache_desc_sql[$serveur][$objets_sql] = _DIR_CACHE . 'sql_desc_' . ($serveur ? "{$serveur}_" : "") . substr(md5($connexion['db'] . ":" . $connexion['prefixe'] . ":$objets_sql"), 0, 8) . '.txt'; // nouveau nom de cache = nouvelle version en memoire unset($connexion['tables']); } // un appel avec $nom vide est une demande explicite de vidange du cache des descriptions if (!$nom) { spip_unlink($nom_cache_desc_sql[$serveur][$objets_sql]); $connexion['tables'] = array(); return null; } $nom_sql = $nom; if (preg_match('/\.(.*)$/', $nom, $s)) { $nom_sql = $s[1]; } else { $nom_sql = $nom; } $fdesc = $desc = ''; $connexion = &$GLOBALS['connexions'][$serveur ? $serveur : 0]; // base sous SPIP: gerer les abreviations explicites des noms de table if ($connexion['spip_connect_version']) { if ($table_spip and isset($GLOBALS['table_des_tables'][$nom])) { $nom = $GLOBALS['table_des_tables'][$nom]; $nom_sql = 'spip_' . $nom; } } // si c'est la premiere table qu'on cherche // et si on est pas explicitement en recalcul // on essaye de recharger le cache des decriptions de ce serveur // dans le fichier cache if (!isset($connexion['tables'][$nom_sql]) and defined('_VAR_MODE') and _VAR_MODE !== 'recalcul' and (!isset($connexion['tables']) or !$connexion['tables']) ) { if (lire_fichier($nom_cache_desc_sql[$serveur][$objets_sql], $desc_cache) and $desc_cache = unserialize($desc_cache) ) { $connexion['tables'] = $desc_cache; } } if ($table_spip and !isset($connexion['tables'][$nom_sql])) { if (isset($GLOBALS['tables_principales'][$nom_sql])) { $fdesc = $GLOBALS['tables_principales'][$nom_sql]; } // meme si pas d'abreviation declaree, trouver la table spip_$nom // si c'est une table principale, // puisqu'on le fait aussi pour les tables auxiliaires elseif ($nom_sql == $nom and isset($GLOBALS['tables_principales']['spip_' . $nom])) { $nom_sql = 'spip_' . $nom; $fdesc = &$GLOBALS['tables_principales'][$nom_sql]; } elseif (isset($GLOBALS['tables_auxiliaires'][$n = $nom]) or isset($GLOBALS['tables_auxiliaires'][$n = 'spip_' . $nom]) ) { $nom_sql = $n; $fdesc = &$GLOBALS['tables_auxiliaires'][$n]; } # table locale a cote de SPIP, comme non SPIP: } if (!isset($connexion['tables'][$nom_sql])) { // La *vraie* base a la priorite $desc = sql_showtable($nom_sql, $table_spip, $serveur); if (!$desc or !$desc['field']) { if (!$fdesc) { spip_log("trouver_table: table inconnue '$serveur' '$nom'", _LOG_INFO_IMPORTANTE); return null; } // on ne sait pas lire la structure de la table : // on retombe sur la description donnee dans les fichiers spip $desc = $fdesc; $desc['exist'] = false; } else { $desc['exist'] = true; } $desc['table'] = $desc['table_sql'] = $nom_sql; $desc['connexion'] = $serveur; // charger les infos declarees pour cette table // en lui passant les infos connues // $desc est prioritaire pour la description de la table $desc = array_merge(lister_tables_objets_sql($nom_sql, $desc), $desc); // si tables_objets_sql est bien fini d'init, on peut cacher $connexion['tables'][$nom_sql] = $desc; $res = &$connexion['tables'][$nom_sql]; // une nouvelle table a ete decrite // mettons donc a jour le cache des descriptions de ce serveur if (is_writeable(_DIR_CACHE)) { ecrire_fichier($nom_cache_desc_sql[$serveur][$objets_sql], serialize($connexion['tables']), true); } } else { $res = &$connexion['tables'][$nom_sql]; } // toujours retourner $nom dans id_table $res['id_table'] = $nom; return $res; } auxiliaires.php000066600000002024152442520540007601 0ustar00<?php /***************************************************************************\ * SPIP, Systeme de publication pour l'internet * * * * Copyright (c) 2001-2019 * * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * \***************************************************************************/ /** * Déclare la liste des tables auxiliaires * * @todo * Nettoyages à faire dans le core : on ne devrait plus appeler * Ce fichier mais directement base/objets si nécessaire * * @package SPIP\Core\SQL\Tables **/ if (!defined('_ECRIRE_INC_VERSION')) { return; } include_spip('base/objets'); lister_tables_objets_sql(); objets.php000066600000114761152442520540006564 0ustar00<?php /***************************************************************************\ * SPIP, Systeme de publication pour l'internet * * * * Copyright (c) 2001-2019 * * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * \***************************************************************************/ /** * Fonctions relatives aux objets éditoriaux et SQL * * @package SPIP\Core\SQL\Tables **/ if (!defined('_ECRIRE_INC_VERSION')) { return; } /** * Merge dans un tableau une de ses clés avec une valeur * * @param array $table * Tableau dont on veut compléter une clé * @param string $index * Clé du tableau que l'on souhaite compléter * @param array $valeur * Sous tableau à merger dans la clé. * @return void **/ function array_set_merge(&$table, $index, $valeur) { if (!isset($table[$index])) { $table[$index] = $valeur; } else { $table[$index] = array_merge($table[$index], $valeur); } } /** * Lister les infos de toutes les tables sql declarées * * Si un argument est fourni, on ne renvoie que les infos de cette table. * Elle est auto-declarée si inconnue jusqu'alors. * * @api * @param string $table_sql * table_sql demandee explicitement * @param array $desc * description connue de la table sql demandee * @return array|bool */ function lister_tables_objets_sql($table_sql = null, $desc = array()) { static $deja_la = false; static $infos_tables = null; static $md5 = null; static $plugin_hash = null; // plugins hash connu ? non si _CACHE_PLUGINS_OPT est pas encore chargé. $_PLUGINS_HASH = defined('_PLUGINS_HASH') ? _PLUGINS_HASH : '!_CACHE_PLUGINS_OPT'; // prealablement recuperer les tables_principales if (is_null($infos_tables) or $plugin_hash !== $_PLUGINS_HASH) { // pas de reentrance (cas base/serial) if ($deja_la) { spip_log('Re-entrance anormale sur lister_tables_objets_sql : ' . var_export(debug_backtrace(), true), _LOG_CRITIQUE); return ($table_sql === '::md5' ? $md5 : array()); } $deja_la = true; $plugin_hash = $_PLUGINS_HASH; // avant de lancer les pipelines // recuperer les declarations explicites ancienne mode // qui servent a completer declarer_tables_objets_sql base_serial($GLOBALS['tables_principales']); base_auxiliaires($GLOBALS['tables_auxiliaires']); $infos_tables = array( 'spip_articles' => array( 'page' => 'article', 'texte_retour' => 'icone_retour_article', 'texte_modifier' => 'icone_modifier_article', 'texte_creer' => 'icone_ecrire_article', 'texte_objets' => 'public:articles', 'texte_objet' => 'public:article', 'texte_signale_edition' => 'texte_travail_article', 'info_aucun_objet' => 'info_aucun_article', 'info_1_objet' => 'info_1_article', 'info_nb_objets' => 'info_nb_articles', 'texte_logo_objet' => 'logo_article', 'texte_langue_objet' => 'titre_langue_article', 'texte_definir_comme_traduction_objet' => 'trad_lier', 'titre' => 'titre, lang', 'date' => 'date', 'principale' => 'oui', 'introduction_longueur' => '500', 'champs_editables' => array( 'surtitre', 'titre', 'soustitre', 'descriptif', 'nom_site', 'url_site', 'chapo', 'texte', 'ps', 'virtuel' ), 'champs_versionnes' => array( 'id_rubrique', 'surtitre', 'titre', 'soustitre', 'jointure_auteurs', 'descriptif', 'nom_site', 'url_site', 'chapo', 'texte', 'ps' ), 'field' => array( 'id_article' => 'bigint(21) NOT NULL', 'surtitre' => "text DEFAULT '' NOT NULL", 'titre' => "text DEFAULT '' NOT NULL", 'soustitre' => "text DEFAULT '' NOT NULL", 'id_rubrique' => "bigint(21) DEFAULT '0' NOT NULL", 'descriptif' => "text DEFAULT '' NOT NULL", 'chapo' => "mediumtext DEFAULT '' NOT NULL", 'texte' => "longtext DEFAULT '' NOT NULL", 'ps' => "mediumtext DEFAULT '' NOT NULL", 'date' => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL", 'statut' => "varchar(10) DEFAULT '0' NOT NULL", 'id_secteur' => "bigint(21) DEFAULT '0' NOT NULL", 'maj' => 'TIMESTAMP', 'export' => "VARCHAR(10) DEFAULT 'oui'", 'date_redac' => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL", 'visites' => "integer DEFAULT '0' NOT NULL", 'referers' => "integer DEFAULT '0' NOT NULL", 'popularite' => "DOUBLE DEFAULT '0' NOT NULL", 'accepter_forum' => "CHAR(3) DEFAULT '' NOT NULL", 'date_modif' => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL", 'lang' => "VARCHAR(10) DEFAULT '' NOT NULL", 'langue_choisie' => "VARCHAR(3) DEFAULT 'non'", 'id_trad' => "bigint(21) DEFAULT '0' NOT NULL", 'nom_site' => "tinytext DEFAULT '' NOT NULL", 'url_site' => "text DEFAULT '' NOT NULL", 'virtuel' => "text DEFAULT '' NOT NULL", ), 'key' => array( 'PRIMARY KEY' => 'id_article', 'KEY id_rubrique' => 'id_rubrique', 'KEY id_secteur' => 'id_secteur', 'KEY id_trad' => 'id_trad', 'KEY lang' => 'lang', 'KEY statut' => 'statut, date', ), 'join' => array( 'id_article' => 'id_article', 'id_rubrique' => 'id_rubrique' ), 'rechercher_champs' => array( 'surtitre' => 5, 'titre' => 8, 'soustitre' => 5, 'chapo' => 3, 'texte' => 1, 'ps' => 1, 'nom_site' => 1, 'url_site' => 1, 'descriptif' => 4 ), 'rechercher_jointures' => array( 'auteur' => array('nom' => 10), ), 'statut' => array( array( 'champ' => 'statut', 'publie' => 'publie', 'previsu' => 'publie,prop,prepa/auteur', 'post_date' => 'date', 'exception' => array('statut', 'tout') ) ), 'statut_titres' => array( 'prepa' => 'info_article_redaction', 'prop' => 'info_article_propose', 'publie' => 'info_article_publie', 'refuse' => 'info_article_refuse', 'poubelle' => 'info_article_supprime' ), 'statut_textes_instituer' => array( 'prepa' => 'texte_statut_en_cours_redaction', 'prop' => 'texte_statut_propose_evaluation', 'publie' => 'texte_statut_publie', 'refuse' => 'texte_statut_refuse', 'poubelle' => 'texte_statut_poubelle', ), 'texte_changer_statut' => 'texte_article_statut', 'aide_changer_statut' => 'artstatut', 'tables_jointures' => array( 'profondeur' => 'rubriques', #'id_auteur' => 'auteurs_liens' // declaration generique plus bas ), ), 'spip_auteurs' => array( 'page' => 'auteur', 'texte_retour' => 'icone_retour', 'texte_ajouter' => 'titre_ajouter_un_auteur', 'texte_modifier' => 'admin_modifier_auteur', 'texte_objets' => 'icone_auteurs', 'texte_objet' => 'public:auteur', 'info_aucun_objet' => 'info_aucun_auteur', 'info_1_objet' => 'info_1_auteur', 'info_nb_objets' => 'info_nb_auteurs', 'texte_logo_objet' => 'logo_auteur', 'texte_creer_associer' => 'creer_et_associer_un_auteur', 'titre' => "nom AS titre, '' AS lang", 'date' => 'date', 'principale' => 'oui', 'champs_editables' => array('nom', 'email', 'bio', 'nom_site', 'url_site', 'imessage', 'pgp'), 'champs_versionnes' => array('nom', 'bio', 'email', 'nom_site', 'url_site', 'login'), 'field' => array( 'id_auteur' => 'bigint(21) NOT NULL', 'nom' => "text DEFAULT '' NOT NULL", 'bio' => "text DEFAULT '' NOT NULL", 'email' => "tinytext DEFAULT '' NOT NULL", 'nom_site' => "tinytext DEFAULT '' NOT NULL", 'url_site' => "text DEFAULT '' NOT NULL", 'login' => 'VARCHAR(255) BINARY', 'pass' => "tinytext DEFAULT '' NOT NULL", 'low_sec' => "tinytext DEFAULT '' NOT NULL", 'statut' => "varchar(255) DEFAULT '0' NOT NULL", 'webmestre' => "varchar(3) DEFAULT 'non' NOT NULL", 'maj' => 'TIMESTAMP', 'pgp' => "TEXT DEFAULT '' NOT NULL", 'htpass' => "tinytext DEFAULT '' NOT NULL", 'en_ligne' => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL", 'alea_actuel' => 'tinytext', 'alea_futur' => 'tinytext', 'prefs' => 'text', 'cookie_oubli' => 'tinytext', 'source' => "VARCHAR(10) DEFAULT 'spip' NOT NULL", 'lang' => "VARCHAR(10) DEFAULT '' NOT NULL" ), 'key' => array( 'PRIMARY KEY' => 'id_auteur', 'KEY login' => 'login', 'KEY statut' => 'statut', 'KEY en_ligne' => 'en_ligne', ), 'join' => array( 'id_auteur' => 'id_auteur', 'login' => 'login' ), 'rechercher_champs' => array( 'nom' => 5, 'bio' => 1, 'email' => 1, 'nom_site' => 1, 'url_site' => 1, 'login' => 1 ), // 2 conditions pour les auteurs : statut!=poubelle, // et avoir des articles publies 'statut' => array( array( 'champ' => 'statut', 'publie' => '!5poubelle', 'previsu' => '!5poubelle', 'exception' => 'statut' ), array( 'champ' => array( array('spip_auteurs_liens', 'id_auteur'), array( 'spip_articles', array('id_objet', 'id_article', 'objet', 'article') ), 'statut' ), 'publie' => 'publie', 'previsu' => '!', 'post_date' => 'date', 'exception' => array('statut', 'lien', 'tout') ), ), 'statut_images' => array( 'auteur-6forum-16.png', '0minirezo' => 'auteur-0minirezo-16.png', '1comite' => 'auteur-1comite-16.png', '6forum' => 'auteur-6forum-16.png', '5poubelle' => 'auteur-5poubelle-16.png', 'nouveau' => '' ), 'statut_titres' => array( 'titre_image_visiteur', '0minirezo' => 'titre_image_administrateur', '1comite' => 'titre_image_redacteur_02', '6forum' => 'titre_image_visiteur', '5poubelle' => 'titre_image_auteur_supprime', ), 'tables_jointures' => array(#'auteurs_liens' // declaration generique plus bas ), ), 'spip_rubriques' => array( 'page' => 'rubrique', 'url_voir' => 'rubrique', 'url_edit' => 'rubrique_edit', 'texte_retour' => 'icone_retour', 'texte_objets' => 'public:rubriques', 'texte_objet' => 'public:rubrique', 'texte_modifier' => 'icone_modifier_rubrique', 'texte_creer' => 'icone_creer_rubrique', 'texte_ajouter' => 'titre_ajouter_une_rubrique', 'texte_creer_associer' => 'creer_et_associer_une_rubrique', 'info_aucun_objet' => 'info_aucun_rubrique', 'info_1_objet' => 'info_1_rubrique', 'info_nb_objets' => 'info_nb_rubriques', 'texte_logo_objet' => 'logo_rubrique', 'texte_langue_objet' => 'titre_langue_rubrique', 'texte_definir_comme_traduction_objet' => 'texte_definir_comme_traduction_rubrique', 'titre' => 'titre, lang', 'date' => 'date', 'principale' => 'oui', 'introduction_longueur' => '600', 'champs_editables' => array('titre', 'texte', 'descriptif', 'extra'), 'champs_versionnes' => array('titre', 'descriptif', 'texte'), 'field' => array( 'id_rubrique' => 'bigint(21) NOT NULL', 'id_parent' => "bigint(21) DEFAULT '0' NOT NULL", 'titre' => "text DEFAULT '' NOT NULL", 'descriptif' => "text DEFAULT '' NOT NULL", 'texte' => "longtext DEFAULT '' NOT NULL", 'id_secteur' => "bigint(21) DEFAULT '0' NOT NULL", 'maj' => 'TIMESTAMP', 'statut' => "varchar(10) DEFAULT '0' NOT NULL", 'date' => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL", 'lang' => "VARCHAR(10) DEFAULT '' NOT NULL", 'langue_choisie' => "VARCHAR(3) DEFAULT 'non'", 'statut_tmp' => "varchar(10) DEFAULT '0' NOT NULL", 'date_tmp' => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL", 'profondeur' => "smallint(5) DEFAULT '0' NOT NULL" ), 'key' => array( 'PRIMARY KEY' => 'id_rubrique', 'KEY lang' => 'lang', 'KEY id_parent' => 'id_parent', ), 'rechercher_champs' => array( 'titre' => 8, 'descriptif' => 5, 'texte' => 1 ), 'statut' => array( array( 'champ' => 'statut', 'publie' => 'publie', 'previsu' => '!', 'exception' => array('statut', 'tout') ), ), 'tables_jointures' => array(#'id_auteur' => 'auteurs_liens' // declaration generique plus bas ), ), // toutes les tables ont le droit a une jointure sur les auteurs array('tables_jointures' => array('id_auteur' => 'auteurs_liens')) ); // avant d'appeller les pipeline qui peuvent generer une reentrance a l'install // initialiser la signature $md5 = md5(serialize($infos_tables)); $GLOBALS['tables_principales'] = pipeline('declarer_tables_principales', $GLOBALS['tables_principales']); $GLOBALS['tables_auxiliaires'] = pipeline('declarer_tables_auxiliaires', $GLOBALS['tables_auxiliaires']); $infos_tables = pipeline('declarer_tables_objets_sql', $infos_tables); // completer les informations manquantes ou implicites $all = array(); foreach (array_keys($infos_tables) as $t) { // les cles numeriques servent a declarer // les proprietes applicables a tous les objets // on les mets de cote if (is_numeric($t)) { $all = array_merge_recursive($all, $infos_tables[$t]); unset($infos_tables[$t]); } else { $infos_tables[$t] = renseigner_table_objet_sql($t, $infos_tables[$t]); } } // repercuter les proprietes generales communes a tous les objets foreach (array_keys($infos_tables) as $t) { foreach ($all as $i => $v) { if (in_array($i, array('tables_jointures', 'champs_versionnes'))) { $add = $all[$i]; // eviter les doublons de declaration de table jointure (ex des mots sur auteurs) // pour les declarations generiques avec cles numeriques if ($i == 'tables_jointures' and isset($infos_tables[$t][$i]) and count($infos_tables[$t][$i])) { $doublons = array_intersect($infos_tables[$t][$i], $add); foreach ($doublons as $d) { if (is_numeric(array_search($d, $infos_tables[$t][$i])) and is_numeric($k = array_search($d, $add)) ) { unset($add[$k]); } } } $infos_tables[$t][$i] = array_merge(isset($infos_tables[$t][$i]) ? $infos_tables[$t][$i] : array(), $add); } else { $infos_tables[$t][$i] = array_merge_recursive( isset($infos_tables[$t][$i]) ? $infos_tables[$t][$i] : array(), $all[$i] ); } } } // completer les tables principales et auxiliaires // avec celles declarees uniquement dans declarer_table_objets_sql // pour assurer la compat en transition foreach ($infos_tables as $table => $infos) { $principale_ou_auxiliaire = ($infos['principale'] ? 'tables_principales' : 'tables_auxiliaires'); // memoriser des champs eventuels declares par des plugins dans le pipeline tables_xxx // qui a ete appelle avant $mem = (isset($GLOBALS[$principale_ou_auxiliaire][$table]) ? $GLOBALS[$principale_ou_auxiliaire][$table] : array()); // l'ajouter au tableau $GLOBALS[$principale_ou_auxiliaire][$table] = array(); if (isset($infos['field']) and isset($infos['key'])) { foreach (array('field', 'key', 'join') as $k) { if (isset($infos_tables[$table][$k])) { $GLOBALS[$principale_ou_auxiliaire][$table][$k] = &$infos_tables[$table][$k]; } } } else { // ici on ne renvoie que les declarations, donc RIEN // pour avoir la vrai description en base, il faut passer par trouver_table $GLOBALS[$principale_ou_auxiliaire][$table] = array(); } if (count($mem)) { foreach (array_keys($mem) as $k) { if (isset($GLOBALS[$principale_ou_auxiliaire][$table][$k])) { $GLOBALS[$principale_ou_auxiliaire][$table][$k] = array_merge( $GLOBALS[$principale_ou_auxiliaire][$table][$k], $mem[$k] ); } else { $GLOBALS[$principale_ou_auxiliaire][$table][$k] = $mem[$k]; } } } } // recuperer les interfaces (table_titre, table_date) // on ne le fait que dans un second temps pour que table_objet soit fonctionnel // dans le pipeline de declarer_tables_interfaces include_spip('public/interfaces'); foreach (array_keys($infos_tables) as $t) { $infos_tables[$t] = renseigner_table_objet_interfaces($t, $infos_tables[$t]); } $deja_la = false; // signature $md5 = md5(serialize($infos_tables)); } if ($table_sql === '::md5') { return $md5; } if ($table_sql and !isset($infos_tables[$table_sql])) { #$desc = renseigner_table_objet_sql($table_sql,$desc); $desc = renseigner_table_objet_interfaces($table_sql, $desc); return $desc; } if ($table_sql) { return isset($infos_tables[$table_sql]) ? $infos_tables[$table_sql] : array(); } return $infos_tables; } /** * Déclare les tables principales du Core * * Tables principales, hors objets éditoriaux. * * @param array $tables_principales * Description des tables principales déjà déclarées * @return void **/ function base_serial(&$tables_principales) { $spip_jobs = array( 'id_job' => 'bigint(21) NOT NULL', 'descriptif' => "text DEFAULT '' NOT NULL", 'fonction' => 'varchar(255) NOT NULL', //nom de la fonction 'args' => "longblob DEFAULT '' NOT NULL", // arguments 'md5args' => "char(32) NOT NULL default ''", // signature des arguments 'inclure' => 'varchar(255) NOT NULL', // fichier a inclure ou path/ pour charger_fonction 'priorite' => 'smallint(6) NOT NULL default 0', 'date' => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL", // date au plus tot 'status' => 'tinyint NOT NULL default 1', ); $spip_jobs_key = array( 'PRIMARY KEY' => 'id_job', 'KEY date' => 'date', 'KEY status' => 'status', ); /// Attention: mes_fonctions peut avoir deja defini cette variable /// il faut donc rajouter, mais pas reinitialiser $tables_principales['spip_jobs'] = array('field' => &$spip_jobs, 'key' => &$spip_jobs_key); } /** * Déclare les tables auxiliaires du Core * * @param array $tables_auxiliaires * Description des tables auxiliaires déjà déclarées * @return void **/ function base_auxiliaires(&$tables_auxiliaires) { $spip_resultats = array( 'recherche' => "char(16) DEFAULT '' NOT NULL", 'id' => 'INT UNSIGNED NOT NULL', 'points' => "INT UNSIGNED DEFAULT '0' NOT NULL", 'table_objet' => "varchar(30) DEFAULT '' NOT NULL", 'serveur' => "char(16) DEFAULT '' NOT NULL", // hash md5 partiel du serveur de base ('' pour le serveur principal) 'maj' => 'TIMESTAMP' ); $spip_resultats_key = array(// pas de cle ni index, ca fait des insertions plus rapides et les requetes jointes utilisees en recheche ne sont pas plus lentes ... ); $spip_auteurs_liens = array( 'id_auteur' => "bigint(21) DEFAULT '0' NOT NULL", 'id_objet' => "bigint(21) DEFAULT '0' NOT NULL", 'objet' => "VARCHAR (25) DEFAULT '' NOT NULL", 'vu' => "VARCHAR(6) DEFAULT 'non' NOT NULL" ); $spip_auteurs_liens_key = array( 'PRIMARY KEY' => 'id_auteur,id_objet,objet', 'KEY id_auteur' => 'id_auteur', 'KEY id_objet' => 'id_objet', 'KEY objet' => 'objet', ); $spip_meta = array( 'nom' => 'VARCHAR (255) NOT NULL', 'valeur' => "text DEFAULT ''", 'impt' => "ENUM('non', 'oui') DEFAULT 'oui' NOT NULL", 'maj' => 'TIMESTAMP' ); $spip_meta_key = array( 'PRIMARY KEY' => 'nom' ); $spip_jobs_liens = array( 'id_job' => "bigint(21) DEFAULT '0' NOT NULL", 'id_objet' => "bigint(21) DEFAULT '0' NOT NULL", 'objet' => "VARCHAR (25) DEFAULT '' NOT NULL", ); $spip_jobs_liens_key = array( 'PRIMARY KEY' => 'id_job,id_objet,objet', 'KEY id_job' => 'id_job' ); $tables_auxiliaires['spip_auteurs_liens'] = array( 'field' => &$spip_auteurs_liens, 'key' => &$spip_auteurs_liens_key ); $tables_auxiliaires['spip_meta'] = array( 'field' => &$spip_meta, 'key' => &$spip_meta_key ); $tables_auxiliaires['spip_resultats'] = array( 'field' => &$spip_resultats, 'key' => &$spip_resultats_key ); $tables_auxiliaires['spip_jobs_liens'] = array( 'field' => &$spip_jobs_liens, 'key' => &$spip_jobs_liens_key ); } /** * Auto remplissage des informations non explicites * sur un objet d'une table sql * * - table_objet * - table_objet_surnoms * - type * - type_surnoms * - url_voir * - url_edit * - icone_objet * * - texte_retour * - texte_modifier * - texte_creer * - texte_creer_associer * - texte_ajouter * - texte_objets * - texte_objet * * - info_aucun_objet * - info_1_objet * - info_nb_objets * * - texte_logo_objet * - texte_langue_objet * - texte_definir_comme_traduction_objet * * - principale * - champs_contenu : utlisé pour générer l'affichage par défaut du contenu * - editable * - champs_editables : utilisé pour prendre en compte le post lors de l'édition * * - champs_versionnes * * L'objet doit définir de lui même ces champs pour gérer des statuts : * - statut * - statut_images * - statut_titres * - statut_textes_instituer * - texte_changer_statut * - aide_changer_statut * * - modeles : permet de declarer les modeles associes a cet objet * * Les infos non renseignées sont auto-déduites par conventions * ou laissées vides * * @param string $table_sql * @param array $infos * @return array */ function renseigner_table_objet_sql($table_sql, &$infos) { if (!isset($infos['type'])) { // si on arrive de base/trouver_table, on a la cle primaire : // s'en servir pour extrapoler le type if (isset($infos['key']['PRIMARY KEY'])) { $primary = $infos['key']['PRIMARY KEY']; $primary = explode(',', $primary); $primary = reset($primary); $infos['type'] = preg_replace(',^spip_|^id_|s$,', '', $primary); } else { $infos['type'] = preg_replace(',^spip_|s$,', '', $table_sql); } } if (!isset($infos['type_surnoms'])) { $infos['type_surnoms'] = array(); } if (!isset($infos['table_objet'])) { $infos['table_objet'] = preg_replace(',^spip_,', '', $table_sql); } if (!isset($infos['table_objet_surnoms'])) { $infos['table_objet_surnoms'] = array(); } if (!isset($infos['principale'])) { $infos['principale'] = (isset($GLOBALS['tables_principales'][$table_sql]) ? 'oui' : false); } // normaliser pour pouvoir tester en php $infos['principale']? // et dans une boucle {principale=oui} $infos['principale'] = (($infos['principale'] and $infos['principale'] != 'non') ? 'oui' : false); // declarer et normaliser pour pouvoir tester en php $infos['editable']? // et dans une boucle {editable=oui} if (!isset($infos['editable'])) { $infos['editable'] = 'oui'; } $infos['editable'] = (($infos['editable'] and $infos['editable'] != 'non') ? 'oui' : false); // les urls publiques sont par defaut page=type pour les tables principales, et rien pour les autres // seules les exceptions sont donc a declarer if (!isset($infos['page'])) { $infos['page'] = ($infos['principale'] ? $infos['type'] : ''); } if (!isset($infos['url_voir'])) { $infos['url_voir'] = $infos['type']; } if (!isset($infos['url_edit'])) { $infos['url_edit'] = $infos['url_voir'] . ($infos['editable'] ? '_edit' : ''); } if (!isset($infos['icone_objet'])) { $infos['icone_objet'] = $infos['type']; } // chaines de langue // par defaut : objet:icone_xxx_objet if (!isset($infos['texte_retour'])) { $infos['texte_retour'] = 'icone_retour'; } if (!isset($infos['texte_modifier'])) { $infos['texte_modifier'] = $infos['type'] . ':' . 'icone_modifier_' . $infos['type']; } if (!isset($infos['texte_creer'])) { $infos['texte_creer'] = $infos['type'] . ':' . 'icone_creer_' . $infos['type']; } if (!isset($infos['texte_creer_associer'])) { $infos['texte_creer_associer'] = $infos['type'] . ':' . 'texte_creer_associer_' . $infos['type']; } if (!isset($infos['texte_ajouter'])) { // Ajouter un X $infos['texte_ajouter'] = $infos['type'] . ':' . 'texte_ajouter_' . $infos['type']; } if (!isset($infos['texte_objets'])) { $infos['texte_objets'] = $infos['type'] . ':' . 'titre_' . $infos['table_objet']; } if (!isset($infos['texte_objet'])) { $infos['texte_objet'] = $infos['type'] . ':' . 'titre_' . $infos['type']; } if (!isset($infos['texte_logo_objet'])) { // objet:titre_logo_objet "Logo de ce X" $infos['texte_logo_objet'] = $infos['type'] . ':' . 'titre_logo_' . $infos['type']; } if (!isset($infos['texte_langue_objet'])) { // objet:texte_langue_objet "Langue de ce X" $infos['texte_langue_objet'] = $infos['type'] . ':' . 'titre_langue_' . $infos['type']; } if (!isset($infos['texte_definir_comme_traduction_objet'])) { // "Ce X est une traduction du X numéro :" $infos['texte_definir_comme_traduction_objet'] = $infos['type'] . ':' . 'texte_definir_comme_traduction_' . $infos['type']; } // objet:info_aucun_objet if (!isset($infos['info_aucun_objet'])) { $infos['info_aucun_objet'] = $infos['type'] . ':' . 'info_aucun_' . $infos['type']; } // objet:info_1_objet if (!isset($infos['info_1_objet'])) { $infos['info_1_objet'] = $infos['type'] . ':' . 'info_1_' . $infos['type']; } // objet:info_nb_objets if (!isset($infos['info_nb_objets'])) { $infos['info_nb_objets'] = $infos['type'] . ':' . 'info_nb_' . $infos['table_objet']; } if (!isset($infos['champs_editables'])) { $infos['champs_editables'] = array(); } if (!isset($infos['champs_versionnes'])) { $infos['champs_versionnes'] = array(); } if (!isset($infos['rechercher_champs'])) { $infos['rechercher_champs'] = array(); } if (!isset($infos['rechercher_jointures'])) { $infos['rechercher_jointures'] = array(); } if (!isset($infos['modeles'])) { $infos['modeles'] = array($infos['type']); } return $infos; } /** * Renseigner les infos d'interface compilateur pour les tables objets * complete la declaration precedente * * titre * date * statut * tables_jointures * * @param $table_sql * @param $infos * @return array */ function renseigner_table_objet_interfaces($table_sql, &$infos) { if (!isset($infos['titre'])) { if (isset($infos['table_objet']) and isset($GLOBALS['table_titre'][$infos['table_objet']])) { $infos['titre'] = $GLOBALS['table_titre'][$infos['table_objet']]; } else { $infos['titre'] = ((isset($infos['field']['titre'])) ? 'titre,' : "'' as titre,"); $infos['titre'] .= ((isset($infos['field']['lang'])) ? 'lang' : "'' as lang"); } } if (!isset($infos['date'])) { if (isset($infos['table_objet']) and isset($GLOBALS['table_date'][$infos['table_objet']])) { $infos['date'] = $GLOBALS['table_date'][$infos['table_objet']]; } else { $infos['date'] = ((isset($infos['field']['date'])) ? 'date' : ''); } } if (!isset($infos['statut'])) { $infos['statut'] = isset($GLOBALS['table_statut'][$table_sql]) ? $GLOBALS['table_statut'][$table_sql] : ''; } if (!isset($infos['tables_jointures'])) { $infos['tables_jointures'] = array(); } if (isset($GLOBALS['tables_jointures'][$table_sql])) { $infos['tables_jointures'] = array_merge($infos['tables_jointures'], $GLOBALS['tables_jointures'][$table_sql]); } return $infos; } /** * Retourne la liste des tables principales et leurs descriptions * * @api * @return array * Liste et descriptions des tables principales **/ function lister_tables_principales() { static $done = false; if (!$done or !count($GLOBALS['tables_principales'])) { lister_tables_objets_sql(); $done = true; } return $GLOBALS['tables_principales']; } /** * Retourne la liste des tables auxiliaires et leurs descriptions * * @api * @return array * Liste et descriptions des tables auxiliaires **/ function lister_tables_auxiliaires() { static $done = false; if (!$done or !count($GLOBALS['tables_auxiliaires'])) { lister_tables_objets_sql(); $done = true; } return $GLOBALS['tables_auxiliaires']; } /** * Recenser les surnoms de table_objet * * @return array */ function lister_tables_objets_surnoms() { static $surnoms = null; static $md5 = null; if (!$surnoms or $md5 != lister_tables_objets_sql('::md5') ) { // passer dans un pipeline qui permet aux plugins de declarer leurs exceptions // pour compatibilite, car il faut dorenavent utiliser // declarer_table_objets_sql $surnoms = pipeline( 'declarer_tables_objets_surnoms', array( # pour les modeles # a enlever ? 'doc' => 'documents', 'img' => 'documents', 'emb' => 'documents', ) ); $infos_tables = lister_tables_objets_sql(); foreach ($infos_tables as $t => $infos) { // cas de base type=>table // et preg_replace(',^spip_|^id_|s$,',table)=>table if ($infos['table_objet']) { // securite, si la fonction est appelee trop tot, c'est vide // optimisations pour table_objet //$surnoms[$infos['type']] = $infos['table_objet']; $surnoms[preg_replace(',^spip_|^id_|s$,', '', $infos['table_objet'])] = $infos['table_objet']; $surnoms[preg_replace(',^spip_|^id_|s$,', '', $infos['type'])] = $infos['table_objet']; if (is_array($infos['table_objet_surnoms']) and count($infos['table_objet_surnoms'])) { foreach ($infos['table_objet_surnoms'] as $surnom) { $surnoms[$surnom] = $infos['table_objet']; } } } } $md5 = lister_tables_objets_sql('::md5'); } return $surnoms; } /** * Recenser les surnoms de table_objet * * @return array */ function lister_types_surnoms() { static $surnoms = null; static $md5 = null; if (!$surnoms or $md5 != lister_tables_objets_sql('::md5') ) { // passer dans un pipeline qui permet aux plugins de declarer leurs exceptions // pour compatibilite, car il faut dorenavent utiliser // declarer_table_objets_sql $surnoms = pipeline('declarer_type_surnoms', array('racine-site' => 'site')); $infos_tables = lister_tables_objets_sql(); foreach ($infos_tables as $t => $infos) { if ($infos['type']) { // securite, si la fonction est appelee trop tot, c'est vide // optimisations pour objet_type //$surnoms[$infos['type']] = $infos['type']; $surnoms[preg_replace(',^spip_|^id_|s$,', '', $infos['table_objet'])] = $infos['type']; $surnoms[preg_replace(',^spip_|^id_|s$,', '', $infos['type'])] = $infos['type']; // surnoms declares if (is_array($infos['type_surnoms']) and count($infos['type_surnoms'])) { foreach ($infos['type_surnoms'] as $surnom) { $surnoms[$surnom] = $infos['type']; } } } } $md5 = lister_tables_objets_sql('::md5'); } return $surnoms; } /** * Retourne la liste des tables SQL qui concernent SPIP * * Cette liste n'est calculée qu'une fois par serveur pour l'ensemble du hit * * @param string $serveur * Nom du fichier de connexion à la base de données * @return array * Couples (nom de la table SQL => même nom, sans 'spip_' devant) **/ function lister_tables_spip($serveur = '') { static $tables = array(); if (!isset($tables[$serveur])) { $tables[$serveur] = array(); if (!function_exists('sql_alltable')) { include_spip('base/abstract_sql'); } $ts = sql_alltable(null, $serveur); // toutes les tables "spip_" (ou prefixe perso) $connexion = $GLOBALS['connexions'][$serveur ? $serveur : 0]; $spip = $connexion['prefixe'] . '_'; foreach ($ts as $t) { $t = substr($t, strlen($spip)); $tables[$serveur]["spip_$t"] = $t; } } return $tables[$serveur]; } /** * Retourne la liste des tables SQL, Spip ou autres * * Cette liste n'est calculée qu'une fois par serveur pour l'ensemble du hit * * @param string $serveur * Nom du fichier de connexion à la base de données * @return array * Couples (nom de la table SQL => même nom) **/ function lister_toutes_tables($serveur){ static $tables = array(); if (!isset($tables[$serveur])){ $tables[$serveur] = array(); if (!function_exists("sql_alltable")) include_spip("base/abstract_sql"); $ts = sql_alltable('%',$serveur); // toutes les tables foreach ($ts as $t){ $tables[$serveur][$t] = $t; } } return $tables[$serveur]; } /** * Retrouve le nom d'objet à partir de la table * * - spip_articles -> articles * - id_article -> articles * - article -> articles * * @api * @param string $type * Nom de la table SQL (le plus souvent) * Tolère un nom de clé primaire. * @param string $serveur * Nom du connecteur * @return string * Nom de l'objet **/ function table_objet($type, $serveur = '') { $surnoms = lister_tables_objets_surnoms(); $type = preg_replace(',^spip_|^id_|s$,', '', $type); if (!$type) { return; } if (isset($surnoms[$type])) { return $surnoms[$type]; } if ($serveur !== false) { $t = lister_tables_spip($serveur); $trouver_table = charger_fonction('trouver_table', 'base'); $typetrim = rtrim($type, 's') . 's'; if ((isset($t[$typetrim]) or in_array($typetrim, $t)) and ($desc = $trouver_table(rtrim($type, 's') . 's', $serveur)) ) { return $desc['id_table']; } elseif ((isset($t[$type]) or in_array($type, $t)) and ($desc = $trouver_table($type, $serveur)) ) { return $desc['id_table']; } spip_log('table_objet(' . $type . ') calculee sans verification'); #spip_log(debug_backtrace(),'db'); } return rtrim($type, 's') . 's'; # cas historique ne devant plus servir, sauf si $serveur=false } /** * Retrouve la table sql à partir de l'objet ou du type * * - articles -> spip_articles * - article -> spip_articles * - id_article -> spip_articles * * @api * @param string $type * Nom ou type de l'objet * Tolère un nom de clé primaire. * @param string $serveur * Nom du connecteur * @return string * Nom de la table SQL **/ function table_objet_sql($type, $serveur = '') { $nom = table_objet($type, $serveur); if (!isset($GLOBALS['table_des_tables']['articles'])) { // eviter de multiples inclusions include_spip('public/interfaces'); } if (isset($GLOBALS['table_des_tables'][$nom])) { $nom = $GLOBALS['table_des_tables'][$nom]; $nom = "spip_$nom"; } else { $infos_tables = lister_tables_objets_sql(); if (isset($infos_tables["spip_$nom"])) { $nom = "spip_$nom"; } elseif ($serveur !== false) { $t = lister_tables_spip($serveur); if (isset($t[$nom]) or in_array($nom, $t)) { $trouver_table = charger_fonction('trouver_table', 'base'); if ($desc = $trouver_table($nom, $serveur)) { return $desc['table_sql']; } } } } return $nom; } /** * Retrouve la clé primaire à partir du nom d'objet ou de table * * - articles -> id_article * - article -> id_article * - spip_articles -> id_article * * @api * @param string $type * Nom de la table SQL ou de l'objet * @param string $serveur * Nom du connecteur * @return string * Nom de la clé primaire **/ function id_table_objet($type, $serveur = '') { static $trouver_table = null; $type = objet_type($type, $serveur); if (!$type) { return; } $t = table_objet($type); if (!$trouver_table) { $trouver_table = charger_fonction('trouver_table', 'base'); } $ts = lister_tables_spip($serveur); if ( in_array($t, $ts) or in_array($t, lister_toutes_tables($serveur)) ){ $desc = $trouver_table($t, $serveur); if (isset($desc['key']['PRIMARY KEY'])) { return $desc['key']['PRIMARY KEY']; } if (!$desc or isset($desc['field']["id_$type"])) { return "id_$type"; } // sinon renvoyer le premier champ de la table... $keys = array_keys($desc['field']); return array_shift($keys); } return "id_$type"; } /** * Retrouve le type d'objet à partir du nom d'objet ou de table * * - articles -> article * - spip_articles -> article * - id_article -> article * * @api * @param string $table_objet * Nom de l'objet ou de la table SQL * @param string $serveur * Nom du connecteur * @return string * Type de l'objet **/ function objet_type($table_objet, $serveur = '') { if (!$table_objet) { return; } $surnoms = lister_types_surnoms(); // scenario de base // le type est decline a partir du nom de la table en enlevant le prefixe eventuel // et la marque du pluriel // on accepte id_xx en entree aussi $type = preg_replace(',^spip_|^id_|s$,', '', $table_objet); if (isset($surnoms[$type])) { return $surnoms[$type]; } // securite : eliminer les caracteres non \w $type = preg_replace(',[^\w-],', '', $type); // si le type redonne bien la table c'est bon // oui si table_objet ressemblait deja a un type if ($type == $table_objet or (table_objet($type, $serveur) == $table_objet) or (table_objet_sql($type, $serveur) == $table_objet) ) { return $type; } // si on ne veut pas chercher en base if ($serveur === false) { return $type; } // sinon on passe par la cle primaire id_xx pour trouver le type // car le s a la fin est incertain // notamment en cas de pluriel derogatoire // id_jeu/spip_jeux id_journal/spip_journaux qui necessitent tout deux // une declaration jeu => jeux, journal => journaux // dans le pipeline declarer_tables_objets_surnoms $trouver_table = charger_fonction('trouver_table', 'base'); $ts = lister_tables_spip($serveur); $desc = false; if (in_array($table_objet, $ts)) { $desc = $trouver_table($table_objet); } if (!$desc and in_array($table_objet = table_objet($type, $serveur), $ts)) { $desc = $trouver_table($table_objet, $serveur); } // si le type est declare : bingo ! if ($desc and isset($desc['type'])) { return $desc['type']; } // on a fait ce qu'on a pu return $type; } /** * Determininer si un objet est publie ou non * * On se base pour cela sur sa declaration de statut * pour des cas particuliers non declarables, on permet de fournir une fonction * base_xxxx_test_si_publie qui sera appele par la fonction * * @param string $objet * @param int $id_objet * @param string $serveur * @return bool */ function objet_test_si_publie($objet, $id_objet, $serveur = '') { // voir si une fonction est definie pour faire le boulot // elle a la priorite dans ce cas if ($f = charger_fonction($objet . '_test_si_publie', 'base', true)) { return $f($objet, $id_objet, $serveur); } // sinon on se fie a la declaration de l'objet si presente $id_table = $table_objet = table_objet($objet); $id_table_objet = id_table_objet($objet, $serveur); $trouver_table = charger_fonction('trouver_table', 'base'); if ($desc = $trouver_table($table_objet, $serveur) and isset($desc['statut']) and $desc['statut'] ) { $boucle = new Boucle(); $boucle->show = $desc; $boucle->nom = 'objet_test_si_publie'; $boucle->id_boucle = $id_table; $boucle->id_table = $id_table; $boucle->sql_serveur = $serveur; $boucle->select[] = $id_table_objet; $boucle->from[$table_objet] = table_objet_sql($objet, $serveur); $boucle->where[] = $id_table . '.' . $id_table_objet . '=' . intval($id_objet); include_spip('public/compiler'); include_spip('public/composer'); instituer_boucle($boucle, false, true); $res = calculer_select( $boucle->select, $boucle->from, $boucle->from_type, $boucle->where, $boucle->join, $boucle->group, $boucle->order, $boucle->limit, $boucle->having, $table_objet, $id_table, $serveur ); if (sql_fetch($res)) { return true; } return false; } // si pas d'info statut ni de fonction : l'objet est publie return true; } serial.php000066600000002024152442520540006541 0ustar00<?php /***************************************************************************\ * SPIP, Systeme de publication pour l'internet * * * * Copyright (c) 2001-2019 * * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * \***************************************************************************/ /** * Déclare la liste des tables principales * * @todo * Nettoyages à faire dans le core : on ne devrait plus appeler * Ce fichier mais directement base/objets si nécessaire * * @package SPIP\Core\SQL\Tables **/ if (!defined('_ECRIRE_INC_VERSION')) { return; } include_spip('base/objets'); lister_tables_objets_sql(); upgrade.php000066600000044656152442520540006732 0ustar00<?php /***************************************************************************\ * SPIP, Systeme de publication pour l'internet * * * * Copyright (c) 2001-2019 * * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * \***************************************************************************/ /** * Mise à jour de la base de données * * @package SPIP\Core\SQL\Upgrade */ if (!defined('_ECRIRE_INC_VERSION')) { return; } /** * Programme de mise à jour des tables SQL lors d'un changement de version. * * L'entrée dans cette fonction est reservée aux mises à jour de SPIP coeur. * * Marche aussi pour les plugins en appelant directement la fonction `maj_plugin` * Pour que ceux-ci profitent aussi de la reprise sur interruption, * ils doivent simplement indiquer leur numero de version installée dans une meta * et fournir le tableau `$maj` à la fonction `maj_plugin`. * La reprise sur timeout se fait alors par la page admin_plugin et jamais par ici. * * @uses creer_base() * @uses maj_base() * @uses auth_synchroniser_distant() * * @param string $titre * @param string $reprise Inutilisé * @return void */ function base_upgrade_dist($titre = '', $reprise = '') { if (!$titre) { return; } // anti-testeur automatique if ($GLOBALS['spip_version_base'] != $GLOBALS['meta']['version_installee']) { if (!is_numeric(_request('reinstall'))) { include_spip('base/create'); spip_log('recree les tables eventuellement disparues', 'maj.' . _LOG_INFO_IMPORTANTE); creer_base(); } // quand on rentre par ici, c'est toujours une mise a jour de SPIP // lancement de l'upgrade SPIP $res = maj_base(); if ($res) { // on arrete tout ici ! exit; } } spip_log('Fin de mise a jour SQL. Debut m-a-j acces et config', 'maj.' . _LOG_INFO_IMPORTANTE); // supprimer quelques fichiers temporaires qui peuvent se retrouver invalides @spip_unlink(_CACHE_RUBRIQUES); @spip_unlink(_CACHE_PIPELINES); @spip_unlink(_CACHE_PLUGINS_PATH); @spip_unlink(_CACHE_PLUGINS_OPT); @spip_unlink(_CACHE_PLUGINS_FCT); @spip_unlink(_CACHE_CHEMIN); @spip_unlink(_DIR_TMP . 'plugin_xml_cache.gz'); include_spip('inc/auth'); auth_synchroniser_distant(); $config = charger_fonction('config', 'inc'); $config(); } /** * Mise à jour de base de SPIP * * Exécute toutes les fonctions de mises à jour de SPIP nécessaires, * en fonction de la meta `version_installee` indiquant le numéro de * schéma actuel de la base de données. * * Les fonctions de mises à jour se trouvent dans `ecrire/maj/` * * @uses upgrade_test() * @uses maj_while() * * @param int $version_cible * @param string $redirect * @return array|bool */ function maj_base($version_cible = 0, $redirect = '') { $version_installee = @$GLOBALS['meta']['version_installee']; // // Si version nulle ou inexistante, c'est une nouvelle installation // => 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 '<p>' . _T('avis_operation_echec') . ' ' . join(' ', $res) . '</p>'; } } } } /** * 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 "<div style='text-align: left'>\n"; if (ob_get_level()) { ob_flush(); } flush(); $done = true; } if (!defined('_UPGRADE_TIME_OUT')) { /** * 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 '<br />'; } 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 " <span title='$i'>.</span>"; 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)) ); } abstract_sql.php000066600000175745152442520540007771 0ustar00<?php /* *************************************************************************\ * SPIP, Systeme de publication pour l'internet * * * * Copyright (c) 2001-2019 * * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * \***************************************************************************/ /** * Definition de l'API SQL * * Ce fichier definit la couche d'abstraction entre SPIP et ses serveurs SQL. * Cette version 1 est un ensemble de fonctions ecrites rapidement * pour generaliser le code strictement MySQL de SPIP <= 1.9.2 * Des retouches sont a prevoir apres l'experience des premiers portages. * Les symboles sql_* (constantes et nom de fonctions) sont reserves * a cette interface, sans quoi le gestionnaire de version dysfonctionnera. * * @package SPIP\Core\SQL\API * @version 1 */ if (!defined('_ECRIRE_INC_VERSION')) { return; } /** Version de l'API SQL */ define('sql_ABSTRACT_VERSION', 1); include_spip('base/connect_sql'); /** * Retourne la pile de fonctions utilisée lors de la précence d'une erreur SQL * * @note * Ignore les fonctions `include_once`, `include_spip`, `find_in_path` * @param bool $compil_info * - false : Retourne un texte présentant les fonctions utilisées * - true : retourne un tableau indiquant un contexte de compilation à l'origine de la requête, * utile pour présenter une erreur au débuggueur via `erreur_squelette()` * @return array|string * contexte de l'erreur **/ function sql_error_backtrace($compil_info = false) { $trace = debug_backtrace(); $caller = array_shift($trace); while (count($trace) and (empty($trace[0]['file']) or $trace[0]['file'] === $caller['file'] or $trace[0]['file'] === __FILE__)) { array_shift($trace); } if ($compil_info) { $contexte_compil = array( $trace[0]['file'],// sourcefile '', //nom (isset($trace[1]) ? $trace[1]['function'] . "(){\n" : '') . $trace[0]['function'] . "();" . (isset($trace[1]) ? "\n}" : ''), //id_boucle $trace[0]['line'], // ligne $GLOBALS['spip_lang'], // lang ); return $contexte_compil; } $message = count($trace) ? $trace[0]['file'] . " L" . $trace[0]['line'] : ""; $f = array(); while (count($trace) and $t = array_shift($trace)) { if (in_array($t['function'], array('include_once', 'include_spip', 'find_in_path'))) { break; } $f[] = $t['function']; } if (count($f)) { $message .= " [" . implode("(),", $f) . "()]"; } return $message; } /** * Charge le serveur de base de donnees * * Fonction principale. Elle charge l'interface au serveur de base de donnees * via la fonction spip_connect_version qui etablira la connexion au besoin. * Elle retourne la fonction produisant la requete SQL demandee * Erreur fatale si la fonctionnalite est absente sauf si le 3e arg <> false * * @internal Cette fonction de base est appelee par les autres fonctions sql_* * @param string $ins_sql * Instruction de l'API SQL demandee (insertq, update, select...) * @param string $serveur * Nom du connecteur ('' pour celui par defaut a l'installation de SPIP) * @param bool $continue * true pour ne pas generer d'erreur si le serveur SQL ne dispose pas de la fonction demandee * @return string|array * Nom de la fonction a appeler pour l'instruction demandee pour le type de serveur SQL correspondant au fichier de connexion. * Si l'instruction demandee n'existe pas, retourne la liste de toutes les instructions du serveur SQL avec $continue a true. * **/ function sql_serveur($ins_sql = '', $serveur = '', $continue = false) { static $sql_serveur = array(); if (!isset($sql_serveur[$serveur][$ins_sql])) { $f = spip_connect_sql(sql_ABSTRACT_VERSION, $ins_sql, $serveur, $continue); if (!is_string($f) or !$f) { return $f; } $sql_serveur[$serveur][$ins_sql] = $f; } return $sql_serveur[$serveur][$ins_sql]; } /** * Demande si un charset est disponible * * Demande si un charset (tel que utf-8) est disponible * sur le gestionnaire de base de données de la connexion utilisée * * @api * @see sql_set_charset() pour utiliser un charset * * @param string $charset * Le charset souhaité * @param string $serveur * Le nom du connecteur * @param bool $option * Inutilise * @return string|bool * Retourne le nom du charset si effectivement trouvé, sinon false. **/ function sql_get_charset($charset, $serveur = '', $option = true) { // le nom http du charset differe parfois du nom SQL utf-8 ==> utf8 etc. $desc = sql_serveur('', $serveur, true, true); $desc = $desc[sql_ABSTRACT_VERSION]; $c = $desc['charsets'][$charset]; if ($c) { if (function_exists($f = @$desc['get_charset'])) { if ($f($c, $serveur, $option !== false)) { return $c; } } } spip_log("SPIP ne connait pas les Charsets disponibles sur le serveur $serveur. Le serveur choisira seul.", _LOG_AVERTISSEMENT); return false; } /** * Regler le codage de connexion * * Affecte un charset (tel que utf-8) sur la connexion utilisee * avec le gestionnaire de base de donnees * * @api * @see sql_get_charset() pour tester l'utilisation d'un charset * * @param string $charset * Le charset souhaite * @param string $serveur * Le nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * - true pour executer la requete. * - continue pour ne pas echouer en cas de serveur sql indisponible. * * @return bool * Retourne true si elle reussie. **/ function sql_set_charset($charset, $serveur = '', $option = true) { $f = sql_serveur('set_charset', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } return $f($charset, $serveur, $option !== false); } /** * Effectue une requête de selection * * Fonction de selection (SELECT), retournant la ressource interrogeable par sql_fetch. * * @api * @see sql_fetch() Pour boucler sur les resultats de cette fonction * * @param array|string $select * Liste des champs a recuperer (Select) * @param array|string $from * Tables a consulter (From) * @param array|string $where * Conditions a remplir (Where) * @param array|string $groupby * Critere de regroupement (Group by) * @param array|string $orderby * Tableau de classement (Order By) * @param string $limit * Critere de limite (Limit) * @param array $having * Tableau des des post-conditions a remplir (Having) * @param string $serveur * Le serveur sollicite (pour retrouver la connexion) * @param bool|string $option * Peut avoir 3 valeurs : * * - false -> ne pas l'exécuter mais la retourner, * - continue -> ne pas echouer en cas de serveur sql indisponible, * - true|array -> executer la requête. * Le cas array est, pour une requete produite par le compilateur, * un tableau donnnant le contexte afin d'indiquer le lieu de l'erreur au besoin * * * @return mixed * Ressource SQL * * - Ressource SQL pour sql_fetch, si la requete est correcte * - false en cas d'erreur * - Chaine contenant la requete avec $option=false * * Retourne false en cas d'erreur, apres l'avoir denoncee. * Les portages doivent retourner la requete elle-meme en cas d'erreur, * afin de disposer du texte brut. * **/ function sql_select( $select = array(), $from = array(), $where = array(), $groupby = array(), $orderby = array(), $limit = '', $having = array(), $serveur = '', $option = true ) { $f = sql_serveur('select', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $debug = (defined('_VAR_MODE') and _VAR_MODE == 'debug'); if (($option !== false) and !$debug) { $res = $f($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, is_array($option) ? true : $option); } else { $query = $f($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, false); if (!$option) { return $query; } // le debug, c'est pour ce qui a ete produit par le compilateur if (isset($GLOBALS['debug']['aucasou'])) { list($table, $id, ) = $GLOBALS['debug']['aucasou']; $nom = $GLOBALS['debug_objets']['courant'] . $id; $GLOBALS['debug_objets']['requete'][$nom] = $query; } $res = $f($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, true); } // en cas d'erreur if (!is_string($res)) { return $res; } // denoncer l'erreur SQL dans sa version brute spip_sql_erreur($serveur); // idem dans sa version squelette (prefixe des tables non substitue) $contexte_compil = sql_error_backtrace(true); erreur_squelette(array(sql_errno($serveur), sql_error($serveur), $res), $contexte_compil); return false; } /** * Recupere la syntaxe de la requete select sans l'executer * * Passe simplement $option a false au lieu de true * sans obliger a renseigner tous les arguments de sql_select. * Les autres parametres sont identiques. * * @api * @uses sql_select() * * @param array|string $select * Liste des champs a recuperer (Select) * @param array|string $from * Tables a consulter (From) * @param array|string $where * Conditions a remplir (Where) * @param array|string $groupby * Critere de regroupement (Group by) * @param array|string $orderby * Tableau de classement (Order By) * @param string $limit * Critere de limite (Limit) * @param array $having * Tableau des des post-conditions a remplir (Having) * @param string $serveur * Le serveur sollicite (pour retrouver la connexion) * * @return mixed * Chaine contenant la requete * ou false en cas d'erreur * **/ function sql_get_select( $select = array(), $from = array(), $where = array(), $groupby = array(), $orderby = array(), $limit = '', $having = array(), $serveur = '' ) { return sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, false); } /** * Retourne le nombre de lignes d'une sélection * * Ramène seulement et tout de suite le nombre de lignes * Pas de colonne ni de tri à donner donc. * * @api * @see sql_count() * @example * ``` * if (sql_countsel('spip_mots_liens', array( * "objet=".sql_quote('article'), * "id_article=".sql_quote($id_article)) > 0) { * // ... * } * ``` * * @param array|string $from * Tables a consulter (From) * @param array|string $where * Conditions a remplir (Where) * @param array|string $groupby * Critere de regroupement (Group by) * @param array $having * Tableau des des post-conditions a remplir (Having) * @param string $serveur * Le serveur sollicite (pour retrouver la connexion) * @param bool|string $option * Peut avoir 3 valeurs : * * - false -> ne pas l'executer mais la retourner, * - continue -> ne pas echouer en cas de serveur sql indisponible, * - true -> executer la requete. * * @return int|bool * - Nombre de lignes de resultat * - ou false en cas d'erreur * **/ function sql_countsel( $from = array(), $where = array(), $groupby = array(), $having = array(), $serveur = '', $option = true ) { $f = sql_serveur('countsel', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($from, $where, $groupby, $having, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Modifie la structure de la base de données * * Effectue une opération ALTER. * * @example * ``` * sql_alter('DROP COLUMN supprimer'); * ``` * * @api * @param string $q * La requête à exécuter (sans la préceder de 'ALTER ') * @param string $serveur * Le serveur sollicite (pour retrouver la connexion) * @param bool|string $option * Peut avoir 2 valeurs : * * - true : exécuter la requete * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return mixed * 2 possibilités : * * - Incertain en cas d'exécution correcte de la requête * - false en cas de serveur indiponible ou d'erreur * * Ce retour n'est pas pertinent pour savoir si l'opération est correctement réalisée. **/ function sql_alter($q, $serveur = '', $option = true) { $f = sql_serveur('alter', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($q, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Retourne un enregistrement d'une selection * * Retourne un resultat d'une ressource obtenue avec sql_select() * * @api * @param mixed $res * Ressource retournee par sql_select() * @param string $serveur * Le nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * - true -> executer la requete * - continue -> ne pas echouer en cas de serveur sql indisponible * * @return array * Tableau de cles (colonnes SQL ou alias) / valeurs (valeurs dans la colonne de la table ou calculee) * presentant une ligne de resultat d'une selection */ function sql_fetch($res, $serveur = '', $option = true) { $f = sql_serveur('fetch', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } return $f($res, null, $serveur, $option !== false); } /** * Retourne tous les enregistrements d'une selection * * Retourne tous les resultats d'une ressource obtenue avec sql_select() * dans un tableau * * @api * @param mixed $res * Ressource retournee par sql_select() * @param string $serveur * Le nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * - true -> executer la requete * - continue -> ne pas echouer en cas de serveur sql indisponible * * @return array * Tableau contenant les enregistrements. * Chaque entree du tableau est un autre tableau * de cles (colonnes SQL ou alias) / valeurs (valeurs dans la colonne de la table ou calculee) * presentant une ligne de resultat d'une selection */ function sql_fetch_all($res, $serveur = '', $option = true) { $rows = array(); if (!$res) { return $rows; } $f = sql_serveur('fetch', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return array(); } while ($r = $f($res, null, $serveur, $option !== false)) { $rows[] = $r; } sql_free($res, $serveur); return $rows; } /** * Déplace le pointeur d'une ressource de sélection * * Deplace le pointeur sur un numéro de ligne précisé * sur une ressource issue de sql_select, afin que * le prochain sql_fetch récupère cette ligne. * * @api * @see sql_skip() Pour sauter des enregistrements * * @param mixed $res * Ressource issue de sql_select * @param int $row_number * Numero de ligne sur laquelle placer le pointeur * @param string $serveur * Le nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * - true -> executer la requete * - continue -> ne pas echouer en cas de serveur sql indisponible * * @return bool * Operation effectuée (true), sinon false. **/ function sql_seek($res, $row_number, $serveur = '', $option = true) { $f = sql_serveur('seek', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($res, $row_number, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Liste des bases de donnees accessibles * * Retourne un tableau du nom de toutes les bases de donnees * accessibles avec les permissions de l'utilisateur SQL * de cette connexion. * Attention on n'a pas toujours les droits ! * * @api * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * - true -> executer la requete * - continue -> ne pas echouer en cas de serveur sql indisponible * * @return array|bool * Tableau contenant chaque nom de base de donnees. * False en cas d'erreur. **/ function sql_listdbs($serveur = '', $option = true) { $f = sql_serveur('listdbs', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($serveur); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Demande d'utiliser d'une base de donnees * * @api * @param string $nom * Nom de la base a utiliser * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * * - true -> executer la requete * - continue -> ne pas echouer en cas de serveur sql indisponible * * @return bool|string * - True ou nom de la base en cas de success. * - False en cas d'erreur. **/ function sql_selectdb($nom, $serveur = '', $option = true) { $f = sql_serveur('selectdb', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($nom, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Retourne le nombre de lignes d’une ressource de sélection obtenue * avec `sql_select()` * * @api * @see sql_select() * @see sql_countsel() * * @param Ressource $res * Ressource SQL * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * * - true -> executer la requete * - continue -> ne pas echouer en cas de serveur sql indisponible * @return bool|string * - int Nombre de lignes, * - false en cas d'erreur. **/ function sql_count($res, $serveur = '', $option = true) { $f = sql_serveur('count', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($res, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Libère une ressource de résultat * * Indique au gestionnaire SQL de libérer de sa mémoire la ressoucre de * résultat indiquée car on n'a plus besoin de l'utiliser. * * @param Ressource|Object $res * Ressource de résultat * @param string $serveur * Nom de la connexion * @param bool|string $option * Peut avoir 2 valeurs : * * - true -> exécuter la requete * - continue -> ne pas échouer en cas de serveur SQL indisponible * @return bool * True si réussi */ function sql_free($res, $serveur = '', $option = true) { $f = sql_serveur('free', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } return $f($res); } /** * Insère une ligne dans une table * * @see sql_insertq() * @see sql_quote() * @note * Cette fonction ne garantit pas une portabilité totale, * et n'est là que pour faciliter des migrations de vieux scripts. * Préférer sql_insertq. * * @param string $table * Nom de la table SQL * @param string $noms * Liste des colonnes impactées, * @param string $valeurs * Liste des valeurs, * @param array $desc * Tableau de description des colonnes de la table SQL utilisée * (il sera calculé si nécessaire s'il n'est pas transmis). * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * * @return bool|string * - int|true identifiant de l'élément inséré (si possible), ou true, si réussite * - Texte de la requête si demandé, * - False en cas d'erreur. **/ function sql_insert($table, $noms, $valeurs, $desc = array(), $serveur = '', $option = true) { $f = sql_serveur('insert', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $noms, $valeurs, $desc, $serveur, $option !== false); if ($r === false or $r === null) { spip_sql_erreur($serveur); $r = false; } return $r; } /** * Insère une ligne dans une table * * Protègera chaque valeur comme sql_quote. * * @api * @see sql_insert() * @see sql_insertq_multi() * @see sql_quote() * @see objet_inserer() * @example * ``` * $titre = _request('titre'); * $id = sql_insertq('spip_rubriques', array('titre' => $titre)); * ``` * * @param string $table * Nom de la table SQL * @param array $couples * Tableau (nom => valeur) * @param array $desc * Tableau de description des colonnes de la table SQL utilisée * (il sera calculé si nécessaire s'il n'est pas transmis). * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * * @return bool|string * - int|true identifiant de l'élément inséré (si possible), ou true, si réussite * - Texte de la requête si demandé, * - False en cas d'erreur. **/ function sql_insertq($table, $couples = array(), $desc = array(), $serveur = '', $option = true) { $f = sql_serveur('insertq', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $couples, $desc, $serveur, $option !== false); if ($r === false or $r === null) { spip_sql_erreur($serveur); $r = false; } return $r; } /** * Insère plusieurs lignes d'un coup dans une table * * Insère en une opération plusieurs éléments au schéma identique * dans une table de la base de données. Lorsque les portages le permettent, * ils utilisent une seule requête SQL pour réaliser l’ajout. * * @api * @see sql_insertq() * * @param string $table * Nom de la table SQL * @param array $couples * Tableau de tableaux associatifs (nom => valeur) * @param array $desc * Tableau de description des colonnes de la table SQL utilisée * (il sera calculé si nécessaire s'il n'est pas transmis). * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * * @return bool|string * - True en cas de succès, * - Texte de la requête si demandé, * - False en cas d'erreur. **/ function sql_insertq_multi($table, $couples = array(), $desc = array(), $serveur = '', $option = true) { $f = sql_serveur('insertq_multi', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $couples, $desc, $serveur, $option !== false); if ($r === false or $r === null) { spip_sql_erreur($serveur); $r = false; } return $r; } /** * Met à jour des enregistrements d'une table SQL * * Les valeurs ne sont pas échappées, ce qui permet de modifier une colonne * en utilisant la valeur d'une autre colonne ou une expression SQL. * * Il faut alors protéger avec sql_quote() manuellement les valeurs qui * en ont besoin. * * Dans les autres cas, préférer sql_updateq(). * * @api * @see sql_updateq() * * @param string $table * Nom de la table * @param array $exp * Couples (colonne => valeur) * @param string|array $where * Conditions a remplir (Where) * @param array $desc * Tableau de description des colonnes de la table SQL utilisée * (il sera calculé si nécessaire s'il n'est pas transmis). * @param string $serveur * Nom de la connexion * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return array|bool|string * - string : texte de la requête si demandé * - true si la requête a réussie, false sinon * - array Tableau décrivant la requête et son temps d'exécution si var_profile est actif */ function sql_update($table, $exp, $where = '', $desc = array(), $serveur = '', $option = true) { $f = sql_serveur('update', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $exp, $where, $desc, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Met à jour du contenu d’une table SQL * * Le contenu transmis à la fonction est protégé automatiquement * comme sql_quote(). * * @api * @see sql_quote() * @see sql_update() * @example * ``` * sql_updateq('table', array('colonne' => $valeur), 'id_table=' . intval($id_table)); * sql_updateq("spip_auteurs", array("statut" => '6forum'), "id_auteur=$id_auteur") ; * ``` * @note * sql_update() est presque toujours appelée sur des constantes ou des dates * Cette fonction (sql_updateq) est donc plus utile que la précédente, * d'autant qu'elle permet de gerer les différences de représentation des constantes. * * @param string $table * Nom de la table SQL * @param array $exp * Couples (colonne => valeur) * @param array|string $where * Conditions à vérifier * @param array $desc * Tableau de description des colonnes de la table SQL utilisée * (il sera calculé si nécessaire s'il n'est pas transmis). * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return bool|string * - true si réussite * - Texte de la requête si demandé, * - False en cas d'erreur. **/ function sql_updateq($table, $exp, $where = '', $desc = array(), $serveur = '', $option = true) { $f = sql_serveur('updateq', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $exp, $where, $desc, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Supprime des enregistrements d'une table * * @example * ``` * sql_delete('spip_articles', 'id_article='.sql_quote($id_article)); * ``` * * @api * @param string $table * Nom de la table SQL * @param string|array $where * Conditions à vérifier * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * * @return bool|string * - int : nombre de suppressions réalisées, * - Texte de la requête si demandé, * - False en cas d'erreur. **/ function sql_delete($table, $where = '', $serveur = '', $option = true) { $f = sql_serveur('delete', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $where, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Insère où met à jour une entrée d’une table SQL * * La clé ou les cles primaires doivent être présentes dans les données insérés. * La fonction effectue une protection automatique des données. * * Préférez sql_insertq() et sql_updateq(). * * @see sql_insertq() * @see sql_updateq() * * @param string $table * Nom de la table SQL * @param array $couples * Couples colonne / valeur à modifier, * @param array $desc * Tableau de description des colonnes de la table SQL utilisée * (il sera calculé si nécessaire s'il n'est pas transmis). * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * * @return bool|string * - true si réussite * - Texte de la requête si demandé, * - False en cas d'erreur. **/ function sql_replace($table, $couples, $desc = array(), $serveur = '', $option = true) { $f = sql_serveur('replace', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $couples, $desc, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Insère où met à jour des entrées d’une table SQL * * La clé ou les cles primaires doivent être présentes dans les données insérés. * La fonction effectue une protection automatique des données. * * Préférez sql_insertq_multi() et sql_updateq(). * * @see sql_insertq_multi() * @see sql_updateq() * @see sql_replace() * * @param string $table * Nom de la table SQL * @param array $tab_couples * Tableau de tableau (colonne / valeur à modifier), * @param array $desc * Tableau de description des colonnes de la table SQL utilisée * (il sera calculé si nécessaire s'il n'est pas transmis). * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * * @return bool|string * - true si réussite * - Texte de la requête si demandé, * - False en cas d'erreur. **/ function sql_replace_multi($table, $tab_couples, $desc = array(), $serveur = '', $option = true) { $f = sql_serveur('replace_multi', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $tab_couples, $desc, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Supprime une table SQL (structure et données) * * @api * @see sql_create() * @see sql_drop_view() * * @param string $table * Nom de la table * @param string $exist * true pour ajouter un test sur l'existence de la table, false sinon * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return bool|string * - True en cas de succès, * - Texte de la requête si demandé, * - False en cas d'erreur. **/ function sql_drop_table($table, $exist = '', $serveur = '', $option = true) { $f = sql_serveur('drop_table', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $exist, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Supprime une vue SQL * * @api * @see sql_create_view() * @see sql_drop_table() * * @param string $table Nom de la vue SQL * @param string $exist True pour ajouter un test d'existence avant de supprimer * @param string $serveur Nom de la connexion * @param bool $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return bool|string * - string Texte de la requête si demandé * - true si la requête a réussie, false sinon */ function sql_drop_view($table, $exist = '', $serveur = '', $option = true) { $f = sql_serveur('drop_view', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $exist, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Retourne une ressource de la liste des tables de la base de données * * @api * @see sql_alltable() * * @param string $spip * Filtre sur tables retournées * - NULL : retourne les tables SPIP uniquement (tables préfixées avec le préfixe de la connexion) * - '%' : retourne toutes les tables de la base * @param string $serveur * Le nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * - false -> ne pas l'executer mais la retourner, * - continue -> ne pas echouer en cas de serveur sql indisponible, * - true -> executer la requete. * @return ressource * Ressource à utiliser avec sql_fetch() **/ function sql_showbase($spip = null, $serveur = '', $option = true) { $f = sql_serveur('showbase', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } // la globale n'est remplie qu'apres l'appel de sql_serveur. if ($spip == null) { $connexion = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0]; $spip = $connexion['prefixe'] . '\_%'; } return $f($spip, $serveur, $option !== false); } /** * Retourne la liste des tables SQL * * @api * @uses sql_showbase() * @param string $spip * Filtre sur tables retournées * - NULL : retourne les tables SPIP uniquement (tables préfixées avec le préfixe de la connexion) * - '%' : retourne toutes les tables de la base * @param string $serveur * Le nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * - false -> ne pas l'executer mais la retourner, * - continue -> ne pas echouer en cas de serveur sql indisponible, * - true -> executer la requete. * @return array * Liste des tables SQL **/ function sql_alltable($spip = null, $serveur = '', $option = true) { $q = sql_showbase($spip, $serveur, $option); $r = array(); if ($q) { while ($t = sql_fetch($q, $serveur)) { $r[] = array_shift($t); } } return $r; } /** * Retourne la liste (et description) des colonnes et key d’une table SQL * * @note * Dans la plupart des situations, il vaut mieux utiliser directement * la fonction trouver_table() qui possède un cache. * * @api * @see base_trouver_table_dist() * * @param string $table * Nom de la table SQL * @param bool $table_spip * true pour remplacer automatiquement « spip » par le vrai préfixe de table * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - 'continue' : ne pas échouer en cas de serveur SQL indisponible, * - true : exécuter la requete. * @return bool|array * - false en cas d'echec * - sinon array : Tableau avec * - 'field' => array(colonne => description) * - 'key' => array(type => key) * - 'join' => array() // jointures, si déclarées. **/ function sql_showtable($table, $table_spip = false, $serveur = '', $option = true) { $f = sql_serveur('showtable', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } // la globale n'est remplie qu'apres l'appel de sql_serveur. if ($table_spip) { $connexion = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0]; $prefixe = $connexion['prefixe']; $vraie_table = prefixer_table_spip($table, $prefixe); } else { $vraie_table = $table; } $f = $f($vraie_table, $serveur, $option !== false); if (!$f) { return array(); } if (isset($GLOBALS['tables_principales'][$table]['join'])) { $f['join'] = $GLOBALS['tables_principales'][$table]['join']; } elseif (isset($GLOBALS['tables_auxiliaires'][$table]['join'])) { $f['join'] = $GLOBALS['tables_auxiliaires'][$table]['join']; } return $f; } /** * Crée une table dans la base de données * * @api * @example * ``` * sql_create("spip_tables", * array( * "id_table" => "bigint(20) NOT NULL default '0'", * "colonne1"=> "varchar(3) NOT NULL default 'oui'", * "colonne2"=> "text NOT NULL default ''" * ), * array( * 'PRIMARY KEY' => "id_table", * 'KEY colonne1' => "colonne1" * ) * ); * ``` * * @param string $nom * Nom de la table * @param array $champs * Couples (colonne => description) * @param array $cles * Clé (nomdelaclef => champ) * @param bool $autoinc * Si un champ est clef primaire est numérique alors la propriété * d’autoincrémentation sera ajoutée * @param bool $temporary * true pour créer une table temporaire (au sens SQL) * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - 'continue' : ne pas échouer en cas de serveur SQL indisponible, * - true : exécuter la requete. * @return bool * true si succès, false en cas d'echec **/ function sql_create( $nom, $champs, $cles = array(), $autoinc = false, $temporary = false, $serveur = '', $option = true ) { $f = sql_serveur('create', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($nom, $champs, $cles, $autoinc, $temporary, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Crée une base de données * * @api * @param string $nom Nom de la base (sans l'extension de fichier si gestionnaire SQLite) * @param string $serveur Nom de la connexion * @param bool $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return bool true si la base est créee. **/ function sql_create_base($nom, $serveur = '', $option = true) { $f = sql_serveur('create_base', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($nom, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Crée une vue SQL * * @api * @see sql_drop_view() * @see sql_create() * @see sql_get_select() Pour obtenir le texte de la requête SELECT pour créer la vue. * * @param string $nom * Nom de la vue * @param string $select_query * Une requête SELECT, idéalement crée avec `sql_get_select(...)` * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return bool|string * - true si succès, * - texte de la requête si demandé * - false en cas d'échec. **/ function sql_create_view($nom, $select_query, $serveur = '', $option = true) { $f = sql_serveur('create_view', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($nom, $select_query, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Retourne l'instruction SQL pour obtenir le texte d'un champ contenant * une balise `<multi>` dans la langue indiquée * * Cette sélection est mise dans l'alias `multi` (instruction AS multi). * * @example * ``` * $t = sql_multi('chapo', 'fr'); * ``` * @api * @param string $sel * Colonne ayant le texte * @param string $lang * Langue à extraire * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return string * Texte de sélection pour la requête */ function sql_multi($sel, $lang, $serveur = '', $option = true) { $f = sql_serveur('multi', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } return $f($sel, $lang); } /** * Retourne la dernière erreur connue * * @api * @param string $serveur * Nom du connecteur * @return bool|string * Description de l'erreur * False si le serveur est indisponible */ function sql_error($serveur = '') { $f = sql_serveur('error', $serveur, 'continue'); if (!is_string($f) or !$f) { return false; } return $f('query inconnue', $serveur); } /** * Retourne le numéro de la derniere erreur connue * * @api * @param string $serveur * Nom du connecteur * @return bool|int * Numéro de l'erreur * False si le serveur est indisponible */ function sql_errno($serveur = '') { $f = sql_serveur('errno', $serveur, 'continue'); if (!is_string($f) or !$f) { return false; } return $f($serveur); } /** * Retourne une explication de requête (Explain) SQL * * @api * @param string $q Texte de la requête * @param string $serveur Nom de la connexion * @param bool $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return array Tableau de l'explication */ function sql_explain($q, $serveur = '', $option = true) { $f = sql_serveur('explain', $serveur, 'continue'); if (!is_string($f) or !$f) { return false; } $r = $f($q, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Optimise une table SQL * * @api * @param string $table Nom de la table * @param string $serveur Nom de la connexion * @param bool $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return bool Toujours true */ function sql_optimize($table, $serveur = '', $option = true) { $f = sql_serveur('optimize', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Répare une table SQL * * @api * @param string $table Nom de la table SQL * @param string $serveur Nom de la connexion * @param bool $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return bool|string * - string Texte de la requête si demandée, * - true si la requête a réussie, false sinon */ function sql_repair($table, $serveur = '', $option = true) { $f = sql_serveur('repair', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($table, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Exécute une requête SQL * * Fonction la plus générale ... et la moins portable * À n'utiliser qu'en dernière extrémité * * @api * @param string $ins Requête * @param string $serveur Nom de la connexion * @param bool $option * Peut avoir 3 valeurs : * * - false : ne pas l'exécuter mais la retourner, * - true : exécuter la requête * - 'continue' : ne pas échouer en cas de serveur sql indisponible * @return array|resource|string|bool * - string : Texte de la requête si on ne l'exécute pas * - ressource|bool : Si requête exécutée * - array : Tableau décrivant requête et temps d'exécution si var_profile actif pour tracer. */ function sql_query($ins, $serveur = '', $option = true) { $f = sql_serveur('query', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } $r = $f($ins, $serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } /** * Retourne la première ligne d'une sélection * * Retourne la première ligne de résultat d'une sélection * comme si l'on appelait successivement `sql_select()` puis `sql_fetch()` * * @example * ``` * $art = sql_fetsel(array('id_rubrique','id_secteur'), 'spip_articles', 'id_article='.sql_quote($id_article)); * $id_rubrique = $art['id_rubrique']; * ``` * * @api * @uses sql_select() * @uses sql_fetch() * @see sql_getfetsel() * * @param array|string $select * Liste des champs a recuperer (Select) * @param array|string $from * Tables a consulter (From) * @param array|string $where * Conditions a remplir (Where) * @param array|string $groupby * Critere de regroupement (Group by) * @param array|string $orderby * Tableau de classement (Order By) * @param string $limit * Critere de limite (Limit) * @param array $having * Tableau des des post-conditions a remplir (Having) * @param string $serveur * Le serveur sollicite (pour retrouver la connexion) * @param bool|string $option * Peut avoir 3 valeurs : * - true -> executer la requete. * - continue -> ne pas echouer en cas de serveur sql indisponible. * - false -> ne pas l'executer mais la retourner. * * @return array * Tableau de la premiere ligne de resultat de la selection tel que * `array('id_rubrique' => 1, 'id_secteur' => 2)` * **/ function sql_fetsel( $select = array(), $from = array(), $where = array(), $groupby = array(), $orderby = array(), $limit = '', $having = array(), $serveur = '', $option = true ) { $q = sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, $option); if ($option === false) { return $q; } if (!$q) { return array(); } $r = sql_fetch($q, $serveur, $option); sql_free($q, $serveur, $option); return $r; } /** * Retourne le tableau de toutes les lignes d'une selection * * Retourne toutes les lignes de resultat d'une selection * comme si l'on appelait successivement sql_select() puis while(sql_fetch()) * * @example * ``` * $rubs = sql_allfetsel('id_rubrique', 'spip_articles', 'id_secteur='.sql_quote($id_secteur)); * // $rubs = array(array('id_rubrique'=>1), array('id_rubrique'=>3, ...) * ``` * * @api * @uses sql_select() * @uses sql_fetch() * * @param array|string $select * Liste des champs a recuperer (Select) * @param array|string $from * Tables a consulter (From) * @param array|string $where * Conditions a remplir (Where) * @param array|string $groupby * Critere de regroupement (Group by) * @param array|string $orderby * Tableau de classement (Order By) * @param string $limit * Critere de limite (Limit) * @param array $having * Tableau des des post-conditions a remplir (Having) * @param string $serveur * Le serveur sollicite (pour retrouver la connexion) * @param bool|string $option * Peut avoir 3 valeurs : * - true -> executer la requete. * - continue -> ne pas echouer en cas de serveur sql indisponible. * - false -> ne pas l'executer mais la retourner. * * @return array * Tableau de toutes les lignes de resultat de la selection * Chaque entree contient un tableau des elements demandees dans le SELECT. * {@example * ``` * array( * array('id_rubrique' => 1, 'id_secteur' => 2) * array('id_rubrique' => 4, 'id_secteur' => 2) * ... * ) * ``` * } * **/ function sql_allfetsel( $select = array(), $from = array(), $where = array(), $groupby = array(), $orderby = array(), $limit = '', $having = array(), $serveur = '', $option = true ) { $q = sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, $option); if ($option === false) { return $q; } return sql_fetch_all($q, $serveur, $option); } /** * Retourne un unique champ d'une selection * * Retourne dans la premiere ligne de resultat d'une selection * un unique champ demande * * @example * ``` * $id_rubrique = sql_getfetsel('id_rubrique', 'spip_articles', 'id_article='.sql_quote($id_article)); * ``` * * @api * @uses sql_fetsel() * * @param array|string $select * Liste des champs à récupérer (Select) * @param array|string $from * Tables à consulter (From) * @param array|string $where * Conditions à remplir (Where) * @param array|string $groupby * Critère de regroupement (Group by) * @param array|string $orderby * Tableau de classement (Order By) * @param string $limit * Critère de limite (Limit) * @param array $having * Tableau des des post-conditions à remplir (Having) * @param string $serveur * Le serveur sollicité (pour retrouver la connexion) * @param bool|string $option * Peut avoir 3 valeurs : * * - true -> executer la requete. * - continue -> ne pas echouer en cas de serveur sql indisponible. * - false -> ne pas l'executer mais la retourner. * * @return mixed * Contenu de l'unique valeur demandee du premier enregistrement retourne * ou NULL si la requete ne retourne aucun enregistrement * **/ function sql_getfetsel( $select, $from = array(), $where = array(), $groupby = array(), $orderby = array(), $limit = '', $having = array(), $serveur = '', $option = true ) { if (preg_match('/\s+as\s+(\w+)$/i', $select, $c)) { $id = $c[1]; } elseif (!preg_match('/\W/', $select)) { $id = $select; } else { $id = 'n'; $select .= ' AS n'; } $r = sql_fetsel($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur, $option); if ($option === false) { return $r; } if (!$r) { return null; } return $r[$id]; } /** * Retourne le numero de version du serveur SQL * * @api * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * - true pour executer la requete. * - continue pour ne pas echouer en cas de serveur sql indisponible. * * @return string * Numero de version du serveur SQL **/ function sql_version($serveur = '', $option = true) { $row = sql_fetsel("version() AS n", '', '', '', '', '', '', $serveur); return ($row['n']); } /** * Informe si le moteur SQL prefere utiliser des transactions * * Cette fonction experimentale est pour l'instant presente pour accelerer certaines * insertions multiples en SQLite, en les encadrant d'une transaction. * SQLite ne cree alors qu'un verrou pour l'ensemble des insertions * et non un pour chaque, ce qui accelere grandement le processus. * Evidemment, si une des insertions echoue, rien ne sera enregistre. * Pour ne pas perturber les autres moteurs, cette fonction permet * de verifier que le moteur prefere utiliser des transactions dans ce cas. * * @example * ``` * if (sql_preferer_transaction()) { * sql_demarrer_transaction(); * } * ``` * * @api * @see sql_demarrer_transaction() * @see sql_terminer_transaction() * * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * - true pour executer la requete. * - continue pour ne pas echouer en cas de serveur sql indisponible. * * @return bool * Le serveur SQL prefere t'il des transactions pour les insertions multiples ? **/ function sql_preferer_transaction($serveur = '', $option = true) { $f = sql_serveur('preferer_transaction', $serveur, 'continue'); if (!is_string($f) or !$f) { return false; } $r = $f($serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } ; /** * Démarre une transaction * * @api * @see sql_terminer_transaction() Pour cloturer la transaction * * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - true pour executer la requete. * - continue pour ne pas echouer en cas de serveur sql indisponible. * - false pour obtenir le code de la requete * * @return bool * true si la transaction est demarree * false en cas d'erreur **/ function sql_demarrer_transaction($serveur = '', $option = true) { $f = sql_serveur('demarrer_transaction', $serveur, 'continue'); if (!is_string($f) or !$f) { return false; } $r = $f($serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } ; /** * Termine une transaction * * @api * @see sql_demarrer_transaction() Pour demarrer une transaction * * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 3 valeurs : * * - true pour executer la requete. * - continue pour ne pas echouer en cas de serveur sql indisponible. * - false pour obtenir le code de la requete * * @return bool * true si la transaction est demarree * false en cas d'erreur **/ function sql_terminer_transaction($serveur = '', $option = true) { $f = sql_serveur('terminer_transaction', $serveur, 'continue'); if (!is_string($f) or !$f) { return false; } $r = $f($serveur, $option !== false); if ($r === false) { spip_sql_erreur($serveur); } return $r; } ; /** * Prépare une chaine hexadécimale * * Prend une chaîne sur l'aphabet hexa * et retourne sa représentation numérique attendue par le serveur SQL. * Par exemple : FF ==> 0xFF en MySQL mais x'FF' en PG * * @api * @param string $val * Chaine hexadécimale * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * * - true pour exécuter la demande. * - 'continue' pour ne pas échouer en cas de serveur SQL indisponible. * @return string * Valeur hexadécimale attendue par le serveur SQL **/ function sql_hex($val, $serveur = '', $option = true) { $f = sql_serveur('hex', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } return $f($val); } /** * Echapper du contenu * * Echappe du contenu selon ce qu'attend le type de serveur SQL * et en fonction du type de contenu. * * Permet entre autres de se protéger d'injections SQL. * * Cette fonction est automatiquement appelée par les fonctions `sql_*q` * tel que `sql_instertq` ou `sql_updateq` * * @api * @param string $val * Chaine à echapper * @param string $serveur * Nom du connecteur * @param string $type * Peut contenir une declaration de type de champ SQL. * Exemple : `int NOT NULL` qui sert alors aussi à calculer le type d'échappement * @return string * La chaine echappee **/ function sql_quote($val, $serveur = '', $type = '') { $f = sql_serveur('quote', $serveur, true); if (!is_string($f) or !$f) { $f = '_q'; } return $f($val, $type); } /** * Tester si une date est proche de la valeur d'un champ * * @api * @param string $champ * Nom du champ a tester * @param int $interval * Valeur de l'intervalle : -1, 4, ... * @param string $unite * Utité utilisée (DAY, MONTH, YEAR, ...) * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * * - true pour exécuter la demande. * - 'continue' pour ne pas échouer en cas de serveur SQL indisponible. * @return string|bool * - string : Expression SQL * - false si le serveur SQL est indisponible **/ function sql_date_proche($champ, $interval, $unite, $serveur = '', $option = true) { $f = sql_serveur('date_proche', $serveur, true); if (!is_string($f) or !$f) { return false; } return $f($champ, $interval, $unite); } /** * Retourne une expression IN pour le gestionnaire de base de données * * Retourne un code à insérer dans une requête SQL pour récupérer * les éléments d'une colonne qui appartiennent à une liste donnée * * @example * `sql_in('id_rubrique', array(3,4,5))` * retourne approximativement «id_rubrique IN (3,4,5)» selon ce qu'attend * le gestionnaire de base de donnée du connecteur en cours. * * @api * @param string $val * Colonne SQL sur laquelle appliquer le test * @param string|array $valeurs * Liste des valeurs possibles (séparés par des virgules si string) * @param string $not * - '' sélectionne les éléments correspondant aux valeurs * - 'NOT' inverse en sélectionnant les éléments ne correspondant pas aux valeurs * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * * - continue -> ne pas echouer en cas de serveur sql indisponible * - true ou false -> retourne l'expression * @return string * Expression de requête SQL **/ function sql_in($val, $valeurs, $not = '', $serveur = '', $option = true) { if (is_array($valeurs)) { $f = sql_serveur('quote', $serveur, true); if (!is_string($f) or !$f) { return false; } $valeurs = join(',', array_map($f, array_unique($valeurs))); } elseif (isset($valeurs[0]) and $valeurs[0] === ',') { $valeurs = substr($valeurs, 1); } if (!strlen(trim($valeurs))) { return ($not ? "0=0" : '0=1'); } $f = sql_serveur('in', $serveur, $option === 'continue' or $option === false); if (!is_string($f) or !$f) { return false; } return $f($val, $valeurs, $not, $serveur, $option !== false); } /** * Retourne une expression IN pour le gestionnaire de base de données * à partir d'une sélection de données * * Sélectionne les données (comme sql_select()) et prépare avec l'expression IN * * @see sql_select() * @see sql_in() * @note * Penser à dire dans la description du serveur * s'il accepte les requêtes imbriquées afin d'optimiser ca * * @api * @param string $in * Colonne SQL sur laquelle appliquer le test * @param array|string $select * Liste des champs à récupérer (Select). * La donnée extraite est le premier élément de la sélection. * @param array|string $from * Tables a consulter (From) * @param array|string $where * Conditions a remplir (Where) * @param array|string $groupby * Critere de regroupement (Group by) * @param array|string $orderby * Tableau de classement (Order By) * @param string $limit * Critere de limite (Limit) * @param array $having * Tableau des des post-conditions a remplir (Having) * @param string $serveur * Nom du connecteur * @return string * Expression de requête SQL **/ function sql_in_select( $in, $select, $from = array(), $where = array(), $groupby = array(), $orderby = array(), $limit = '', $having = array(), $serveur = '' ) { $liste = array(); $res = sql_select($select, $from, $where, $groupby, $orderby, $limit, $having, $serveur); while ($r = sql_fetch($res)) { $liste[] = array_shift($r); } sql_free($res); return sql_in($in, $liste); } /** * Implémentation sécurisée du saut en avant. * * Ne dépend pas de la disponibilité de la fonction `sql_seek()`. * Ne fait rien pour une valeur négative ou nulle de `$saut`. * Retourne la position après le saut * * @see sql_seek() * * @param resource $res * Ressource issue d'une selection sql_select * @param int $pos * position courante * @param int $saut * saut demande * @param int $count * position maximale * (nombre de resultat de la requete OU position qu'on ne veut pas depasser) * @param string $serveur * Nom du connecteur * @param bool|string $option * Peut avoir 2 valeurs : * - true -> executer la requete * - continue -> ne pas echouer en cas de serveur sql indisponible * * @return int * Position apres le saut. */ function sql_skip($res, $pos, $saut, $count, $serveur = '', $option = true) { // pas de saut en arriere qu'on ne sait pas faire sans sql_seek if (($saut = intval($saut)) <= 0) { return $pos; } $seek = $pos + $saut; // si le saut fait depasser le maxi, on libere la resource // et on sort if ($seek >= $count) { sql_free($res, $serveur, $option); return $count; } if (sql_seek($res, $seek)) { $pos = $seek; } else { while ($pos < $seek and sql_fetch($res, $serveur, $option)) { $pos++; } } return $pos; } /** * Teste qu'une description de champ SQL est de type entier * * @api * @see sql_test_date() pour tester les champs de date * * @param string $type * Description de la colonne SQL * @param string $serveur * Nom du connecteur * @param bool $option * Inutilisé * @return bool * True si le champ est de type entier */ function sql_test_int($type, $serveur = '', $option = true) { return preg_match('/^(TINYINT|SMALLINT|MEDIUMINT|INT|INTEGER|BIGINT)/i', trim($type)); } /** * Teste qu'une description de champ SQL est de type entier * * @api * @see sql_test_int() pour tester les champs d'entiers * * @param string $type * Description de la colonne SQL * @param string $serveur * Nom du connecteur * @param bool $option * Inutilisé * @return bool * True si le champ est de type entier */ function sql_test_date($type, $serveur = '', $option = true) { return preg_match('/^(DATE|DATETIME|TIMESTAMP|TIME)/i', trim($type)); } /** * Formate une date * * Formater une date Y-m-d H:i:s sans passer par mktime * qui ne sait pas gerer les dates < 1970 * * @api * @param int $annee Annee * @param int $mois Numero du mois * @param int $jour Numero du jour dans le mois * @param int $h Heures * @param int $m Minutes * @param int $s Secondes * @param string $serveur * Le serveur sollicite (pour retrouver la connexion) * @return string * La date formatee */ function sql_format_date($annee = 0, $mois = 0, $jour = 0, $h = 0, $m = 0, $s = 0, $serveur = '') { $annee = sprintf("%04s", $annee); $mois = sprintf("%02s", $mois); if ($annee == "0000") { $mois = 0; } if ($mois == "00") { $jour = 0; } return sprintf("%04u", $annee) . '-' . sprintf("%02u", $mois) . '-' . sprintf("%02u", $jour) . ' ' . sprintf("%02u", $h) . ':' . sprintf("%02u", $m) . ':' . sprintf("%02u", $s); } /** * Retourne la description de la table SQL * * Retrouve la description de la table SQL en privilegiant * la structure reelle de la base de donnees. * En absence, ce qui arrive lors de l'installation, la fonction * s'appuie sur la declaration des tables SQL principales ou auxiliaires. * * @internal Cette fonction devrait disparaître * * @param string $nom * Nom de la table dont on souhait la description * @param string $serveur * Nom du connecteur * @return array|bool * Description de la table ou false si elle n'est pas trouvee ou declaree. **/ function description_table($nom, $serveur = '') { static $trouver_table; /* toujours utiliser trouver_table qui renverra la description theorique car sinon on va se comporter differement selon que la table est declaree ou non */ if (!$trouver_table) { $trouver_table = charger_fonction('trouver_table', 'base'); } if ($desc = $trouver_table($nom, $serveur)) { return $desc; } // sauf a l'installation : include_spip('base/serial'); if (isset($GLOBALS['tables_principales'][$nom])) { return $GLOBALS['tables_principales'][$nom]; } include_spip('base/auxiliaires'); if (isset($GLOBALS['tables_auxiliaires'][$nom])) { return $GLOBALS['tables_auxiliaires'][$nom]; } return false; } /** * Corrige le nom d’une table SQL en utilisant le bon préfixe * * Ie: si prefixe 'dev', retournera, pour la table 'spip_articles' : 'dev_articles'. * * @param string $table * @param string $prefixe * @return string Table sql éventuellement renommée */ function prefixer_table_spip($table, $prefixe) { if ($prefixe) { $table = preg_replace('/^spip_/', $prefixe . '_', $table); } return $table; }create.php000066600000014440152442520540006532 0ustar00<?php /***************************************************************************\ * SPIP, Systeme de publication pour l'internet * * * * Copyright (c) 2001-2019 * * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * \***************************************************************************/ /** * Création ou mise à jour des tables * * @package SPIP\Core\Installation **/ if (!defined('_ECRIRE_INC_VERSION')) { return; } include_spip('inc/acces'); include_spip('base/objets'); include_spip('base/typedoc'); include_spip('base/abstract_sql'); /** * Determiner le flag autoinc pour une table * en fonction de si c'est une table principale * * @param string $table * @param array $desc * @return bool */ function base_determine_autoinc($table, $desc = array()) { if ($t = lister_tables_principales() and isset($t[$table])) { $autoinc = true; } elseif ($t = lister_tables_auxiliaires() and isset($t[$table])) { $autoinc = false; } else { // essayer de faire au mieux ! $autoinc = (isset($desc['key']['PRIMARY KEY']) and strpos($desc['key']['PRIMARY KEY'], ',') === false and strpos($desc['field'][$desc['key']['PRIMARY KEY']], 'default') === false); } return $autoinc; } /** * Créer une table, * ou ajouter les champs manquants si elle existe déjà * * @param string $table * @param array $desc * @param bool|string $autoinc * 'auto' pour detecter automatiquement si le champ doit etre autoinc ou non * en fonction de la table * @param bool $upgrade * @param string $serveur * @return void */ function creer_ou_upgrader_table($table, $desc, $autoinc, $upgrade = false, $serveur = '') { #spip_log("creer_ou_upgrader_table table=$table autoinc=$autoinc upgrade=$upgrade","dbinstall"._LOG_INFO_IMPORTANTE); $sql_desc = $upgrade ? sql_showtable($table, true, $serveur) : false; #if (!$sql_desc) $sql_desc = false; #spip_log("table=$table sql_desc:$sql_desc","dbinstall"._LOG_INFO_IMPORTANTE); if (!$sql_desc) { if ($autoinc === 'auto') { $autoinc = base_determine_autoinc($table, $desc); } #spip_log("sql_create $table autoinc=$autoinc","dbinstall"._LOG_INFO_IMPORTANTE); sql_create($table, $desc['field'], $desc['key'], $autoinc, false, $serveur); // verifier la bonne installation de la table (php-fpm es-tu la ?) $sql_desc = sql_showtable($table, true, $serveur); #if (!$sql_desc) $sql_desc = false; #spip_log("Resultat table=$table sql_desc:$sql_desc","dbinstall"._LOG_INFO_IMPORTANTE); if (!$sql_desc) { // on retente avec un sleep ? sleep(1); sql_create($table, $desc['field'], $desc['key'], $autoinc, false, $serveur); $sql_desc = sql_showtable($table, true, $serveur); #if (!$sql_desc) $sql_desc = false; #spip_log("Resultat table=$table sql_desc:$sql_desc","dbinstall"._LOG_INFO_IMPORTANTE); if (!$sql_desc) { spip_log("Echec creation table $table", "maj" . _LOG_CRITIQUE); } } } else { #spip_log("sql_alter $table ... (on s'en fiche)","dbinstall"._LOG_INFO_IMPORTANTE); // ajouter les champs manquants // on ne supprime jamais les champs, car c'est dangereux // c'est toujours a faire manuellement $last = ''; foreach ($desc['field'] as $field => $type) { if (!isset($sql_desc['field'][$field])) { sql_alter("TABLE $table ADD $field $type" . ($last ? " AFTER $last" : ""), $serveur); } $last = $field; } foreach ($desc['key'] as $key => $type) { // Ne pas oublier les cas des cles non nommees dans la declaration et qui sont retournees // par le showtable sous la forme d'un index de tableau "KEY $type" et non "KEY" if (!isset($sql_desc['key'][$key]) and !isset($sql_desc['key']["$key $type"])) { sql_alter("TABLE $table ADD $key ($type)", $serveur); } $last = $field; } } } /** * Creer ou mettre à jour un ensemble de tables * en fonction du flag `$up` * * @uses creer_ou_upgrader_table() * * @param array $tables_inc * tables avec autoincrement sur la cle primaire * @param $tables_noinc * tables sans autoincrement sur la cle primaire * @param bool|array $up * upgrader (true) ou creer (false) * si un tableau de table est fournie, seules l'intersection de ces tables * et des $tables_inc / $tables_noinc seront traitees * @param string $serveur * serveur sql * @return void */ function alterer_base($tables_inc, $tables_noinc, $up = false, $serveur = '') { if ($up === false) { $old = false; $up = array(); } else { $old = true; if (!is_array($up)) { $up = array($up); } } foreach ($tables_inc as $k => $v) { if (!$old or in_array($k, $up)) { creer_ou_upgrader_table($k, $v, true, $old, $serveur); } } foreach ($tables_noinc as $k => $v) { if (!$old or in_array($k, $up)) { creer_ou_upgrader_table($k, $v, false, $old, $serveur); } } } /** * Créer une base de données * à partir des tables principales et auxiliaires * * Lorsque de nouvelles tables ont été déclarées, cette fonction crée les tables manquantes. * mais ne crée pas des champs manquant d'une table déjà présente. * Pour cela, c’est `maj_tables()` qu’il faut appeler. * * @api * @see maj_tables() * @uses alterer_base() * * @param string $serveur * @return void */ function creer_base($serveur = '') { // Note: les mises a jour reexecutent ce code pour s'assurer // de la conformite de la base // pas de panique sur "already exists" et "duplicate entry" donc. alterer_base( lister_tables_principales(), lister_tables_auxiliaires(), false, $serveur ); } /** * Mettre à jour une liste de tables * * Fonction facilitatrice utilisée pour les maj de base * dans les plugins. * * Elle permet de créer les champs manquants d'une table déjà présente. * * @api * @see creer_base() * @uses alterer_base() * * @param array $upgrade_tables * @param string $serveur * @return void */ function maj_tables($upgrade_tables = array(), $serveur = '') { alterer_base( lister_tables_principales(), lister_tables_auxiliaires(), $upgrade_tables, $serveur ); } delete_all.php000066600000003305152442520540007357 0ustar00<?php /***************************************************************************\ * SPIP, Systeme de publication pour l'internet * * * * Copyright (c) 2001-2019 * * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * \***************************************************************************/ /** * Gestion d'affichage de la page de destruction des tables de SPIP * * @package SPIP\Core\Base */ if (!defined('_ECRIRE_INC_VERSION')) { return; } /** * Destruction des tables SQL de SPIP * * La liste des tables à supprimer est à poster sur le nom (tableau) `delete` * * @pipeline_appel delete_tables * @param string $titre Inutilisé **/ function base_delete_all_dist($titre) { $delete = _request('delete'); $res = array(); if (is_array($delete)) { foreach ($delete as $table) { if (sql_drop_table($table)) { $res[] = $table; } else { spip_log("SPIP n'a pas pu detruire $table.", _LOG_ERREUR); } } // un pipeline pour detruire les tables installees par les plugins pipeline('delete_tables', ''); spip_unlink(_FILE_CONNECT); spip_unlink(_FILE_CHMOD); spip_unlink(_FILE_META); spip_unlink(_ACCESS_FILE_NAME); spip_unlink(_CACHE_RUBRIQUES); } $d = count($delete); $r = count($res); spip_log("Tables detruites: $r sur $d: " . join(', ', $res), _LOG_INFO_IMPORTANTE); } repair.php000066600000012036152442520540006550 0ustar00<?php /***************************************************************************\ * SPIP, Systeme de publication pour l'internet * * * * Copyright (c) 2001-2019 * * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * \***************************************************************************/ /** * Réparation de la base de données * * @package SPIP\Core\SQL\Reparation */ if (!defined('_ECRIRE_INC_VERSION')) { return; } /** * Action de réparation de la base de données * * Tente de réparer les tables, recalcule les héritages et secteurs * de rubriques. Affiche les erreurs s'il y en a eu. * * @pipeline_appel base_admin_repair * @uses admin_repair_tables() * @uses calculer_rubriques() * @uses propager_les_secteurs() * * @param string $titre Inutilisé * @param string $reprise Inutilisé **/ function base_repair_dist($titre = '', $reprise = '') { $res = admin_repair_tables(); if (!$res) { $res = "<div class='error'>" . _T('avis_erreur_mysql') . ' ' . sql_errno() . ': ' . sql_error() . "</div>\n"; } else { include_spip('inc/rubriques'); calculer_rubriques(); propager_les_secteurs(); } include_spip('inc/minipres'); $res .= pipeline('base_admin_repair', $res); echo minipres(_T('texte_tentative_recuperation'), $res . generer_form_ecrire('accueil', '', '', _T('public:accueil_site'))); } /** * Réparer les documents stockés dans des faux répertoires .plat * * @deprecated Les fichiers .plat ne sont plus utilisés. Cette fonction n'est plus appelée depuis r14292 * @todo À supprimer ou déplacer dans le plugin Medias. * * @return string Description des changements de chemins des documents **/ function admin_repair_plat() { spip_log("verification des documents joints", _LOG_INFO_IMPORTANTE); $out = ""; $repertoire = array(); include_spip('inc/getdocument'); $res = sql_select('*', 'spip_documents', "fichier REGEXP CONCAT('^',extension,'[^/\]') AND distant='non'"); while ($row = sql_fetch($res)) { $ext = $row['extension']; if (!$ext) { spip_log("document sans extension: " . $row['id_document'], _LOG_INFO_IMPORTANTE); continue; } if (!isset($repertoire[$ext])) { if (@file_exists($plat = _DIR_IMG . $ext . ".plat")) { spip_unlink($plat); } $repertoire[$ext] = creer_repertoire_documents($ext); if (preg_match(',_$,', $repertoire[$ext])) { $repertoire[$ext] = false; } } if ($d = $repertoire[$ext]) { $d = substr($d, strlen(_DIR_IMG)); $src = $row['fichier']; $dest = $d . substr($src, strlen($d)); if (@copy(_DIR_IMG . $src, _DIR_IMG . $dest) and file_exists(_DIR_IMG . $dest) ) { sql_updateq('spip_documents', array('fichier' => $dest), 'id_document=' . intval($row['id_document'])); spip_unlink(_DIR_IMG . $src); $out .= "$src => $dest<br />"; } } } return $out; } /** * Exécute une réparation de la base de données * * Crée les tables et les champs manquants. * Applique sur les tables un REPAIR en SQL (si le serveur SQL l'accepte). * * @return string * Code HTML expliquant les actions réalisées **/ function admin_repair_tables() { $repair = sql_repair('repair', null, 'continue'); // recreer les tables manquantes eventuelles include_spip('base/create'); creer_base(); $connexion = $GLOBALS['connexions'][0]; $prefixe = $connexion['prefixe']; $rows = array(); if ($res1 = sql_showbase()) { while ($r = sql_fetch($res1)) { $rows[] = $r; } sql_free($res1); } $res = ""; if (count($rows)) { while ($r = array_shift($rows)) { $tab = array_shift($r); $class = ""; $m = "<strong>$tab</strong> "; spip_log("Repare $tab", _LOG_INFO_IMPORTANTE); // supprimer la meta avant de lancer la reparation // car le repair peut etre long ; on ne veut pas boucler effacer_meta('admin_repair'); if ($repair) { $result_repair = sql_repair($tab); if (!$result_repair) { return false; } } // essayer de maj la table (creation de champs manquants) maj_tables($tab); $count = sql_countsel($tab); if ($count > 1) { $m .= "(" . _T('texte_compte_elements', array('count' => $count)) . ")\n"; } else { if ($count == 1) { $m .= "(" . _T('texte_compte_element', array('count' => $count)) . ")\n"; } else { $m .= "(" . _T('texte_vide') . ")\n"; } } if ($result_repair and $msg = join(" ", (is_resource($result_repair) or is_object($result_repair)) ? sql_fetch($result_repair) : $result_repair) . ' ' and strpos($msg, ' OK ') === false ) { $class = " class='notice'"; $m .= "<br /><tt>" . spip_htmlentities($msg) . "</tt>\n"; } else { $m .= " " . _T('texte_table_ok'); } $res .= "<div$class>$m</div>"; } } return $res; }
/home/atelierpru/provence/6bf95/../tmp/../52177/base.tar