Valider 39ba7d7c rédigé par esj's avatar esj
Parcourir les fichiers

Nouvelle implémentation des sauvegardes partielles.

Auparavant, ces sauvegardes étaient construites lorsqu'un administrateur restreint déclenchait le script '''export_all''', et la sauvegarde contenait alors le contenu de toutes les rubriques qu'il administrait. Construire une sauvegarde pour une rubrique précise imposait donc de créer un pseudo-administrateur pour cette rubrique, de se connecter sous son identité et d'exécuter ce script.

A présent, ce script permet de spécifier un numéro de rubrique à sauvegarder,indépendamment des droits du demandeur. Ce procédé est plus pratique, et figure donc sur la même page que l'option de fusion pour l'opération inverse de restauration, à laquelle elle est naturellement rattachée. De plus, les dépendances sont calculées plus finement, ce qui évite de placer dans cette sauvegarde l'intégralité des tables annexes (tables des mots etc).

Pour le moment, cette sauvegarde ne fonctionne que pour une rubrique de secteur. Cette restriction devrait être levée bientôt.

A noter que cette nouvelle implémentation permet à plusieurs administrateurs de lancer chacun une sauvegarde en même temps. Même en cas de suspension des scripts, chacun d'eux reprendra là où il en était lorsque l'administrateur concerné le redéclenchera (en revanche un même administrateur ne peut toujours pas  lancer plusieurs sauvegardes simultanément, mais ce n'est pas gênant).
parent cfe6d4a1
Chargement en cours
Chargement en cours
Chargement en cours
Chargement en cours
+36 −31
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -12,45 +12,43 @@

if (!defined("_ECRIRE_INC_VERSION")) return;

include_spip('inc/meta');
include_spip('inc/export');
include_spip('inc/minipres');

// http://doc.spip.org/@action_export_all_dist
function action_export_all_dist()
{
	global $spip_lang_left,$spip_lang_right;
	
	$securiser_action = charger_fonction('securiser_action', 'inc');
	$arg = $securiser_action();

	// determine upload va aussi initialiser l'index "restreint"
	$dir = determine_upload();
	if (!$GLOBALS['auteur_session']['restreint'] AND file_exists(_DIR_DUMP))
		$dir = _DIR_DUMP;

	list($quoi, $gz, $archive) = split(',', $arg);
	@list($quoi, $gz, $archive, $rub) = split(',', $arg);
	$meta = 'status_dump_'  . $GLOBALS['auteur_session']['id_auteur'];
	$file =  export_subdir($rub) . $archive;

	$file =  $dir . $archive;

	include_spip('inc/meta');
	utiliser_langue_visiteur();
	if ($quoi =='start'){
		// creer l'en tete du fichier et retourner dans l'espace prive
		include_spip('inc/export');
		ecrire_fichier($file, export_entete(),false);
		ecrire_meta("status_dump", "$gz::$archive::1::0",'non');
		ecrire_meta($meta, "$gz::$archive::$rub::1::0",'non');
		ecrire_metas();
		include_spip('inc/headers');
		  // suite=1 ne sert qu'a distinguer cette redirection
		  // rub=$rub sert AUSSI a distinguer cette redirection
		  // d'avec l'appel initial sinon FireFox croit malin
		  // d'optimiser la redirection
		redirige_par_entete(generer_url_ecrire('export_all',"suite=1", true));
	}elseif ($quoi=='end'){
		redirige_par_entete(generer_url_ecrire('export_all',"rub=$rub", true));
	} elseif ($quoi=='end') export_all_fin($file, $meta);
}

function export_all_fin($file, $meta)
{
	global $spip_lang_left,$spip_lang_right;

	lire_metas();
		$tables_sauvegardees = isset($GLOBALS['meta']['status_dump_tables'])?unserialize($GLOBALS['meta']['status_dump_tables']):array();
		effacer_meta("status_dump");
		effacer_meta("status_dump_tables");
		effacer_meta("export_session_id");
	$metatable = $meta . '_tables';
	$tables_sauvegardees = isset($GLOBALS['meta'][$metatable])?unserialize($GLOBALS['meta'][$metatable]):array();
	effacer_meta($meta);
	effacer_meta($metatable);
	ecrire_metas();

	$size = @(!file_exists($file) ? 0 : filesize($file));
@@ -59,8 +57,16 @@ function action_export_all_dist()
		$corps = _T('avis_erreur_sauvegarde', array('type'=>'.', 'id_objet'=>'. .'));
	
	} else {
		$subdir = dirname($file);
		$dir = dirname($subdir);
		$nom = basename($file);
		if (@rename($file, $dir . '/' . $nom)) {
			spip_unlink($subdir);
			spip_log("$file renomme en $dir/$nom");
		}
	// ne pas effrayer inutilement: il peut y avoir moins de fichiers
	// qu'annonce' si certains etaient vides

		$n = _T('taille_octets', array('taille' => number_format($size, 0, ' ', ' ')));
		
		$corps = "<p style='text-align: $spip_lang_left'>".
@@ -88,5 +94,4 @@ function action_export_all_dist()
	echo minipres(_T('info_sauvegarde'), $corps);
	exit;
}
}
?>
+5 −0
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -107,6 +107,11 @@ function exec_admin_tech_dist()
	    "\n<input type='hidden' name='gz' id='gz' value='0' /></p>";
	}

	$res .= "\n<p><label for='id_rubrique'>" .
	    _L('Vous pouvez limiter la sauvegarde &agrave; la rubrique: ') .
	       "</label>" .
	    "\n<input name='id_rubrique' id='id_rubrique' size='5' /></p>";

	$res .= "\n<input type='hidden' name='reinstall' value='non' />";
 
	echo 
+54 −52
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -24,22 +24,12 @@ include_spip('inc/acces');
function exec_export_all_dist()
{
	global $connect_toutes_rubriques;
	$start = false;

	if ($connect_toutes_rubriques AND file_exists(_DIR_DUMP))
		$dir = _DIR_DUMP;
	else $dir = determine_upload();

	// creer un id de la session d'export qui sera utilise pour verifier qu'on a toujours la main
	// avant chaque ecriture de morceau
	// permet d'eviter les process concourants qui realisent le meme export
	@define('_EXPORT_SESSION_ID',creer_uniqid());
	ecrire_meta('export_session_id',_EXPORT_SESSION_ID,'non');
	
	// utiliser une version fraiche des metas (ie pas le cache)
	lire_metas();
	$rub = intval(_request('id_rubrique'));
	$meta = 'status_dump_'  . $GLOBALS['auteur_session']['id_auteur'];

	if (!isset($GLOBALS['meta']["status_dump"])) {
	if (!isset($GLOBALS['meta'][$meta])) {
		$gz = _request('gz') ? '.gz' : '';
		$archive = $gz 
		?  _request('znom_sauvegarde') 
@@ -49,15 +39,16 @@ function exec_export_all_dist()

		//  creer l'en tete du fichier a partir de l'espace public
		include_spip('inc/headers');
		redirige_par_entete(generer_action_auteur("export_all", "start,$gz,$archive", '', true));
		redirige_par_entete(generer_action_auteur("export_all", "start,$gz,$archive,$rub", '', true));
	} 

	list($gz, $archive, $etape_actuelle, $sous_etape) = 
	  explode("::",$GLOBALS['meta']["status_dump"]);

	$start = false;
	list($gz, $archive, $rub, $etape_actuelle, $sous_etape) = 
		explode("::",$GLOBALS['meta'][$meta]);
	$dir =  export_subdir($rub);
	$file = $dir . $archive;
	$metatable = $meta . '_tables';
	$redirect = generer_url_ecrire("export_all");
	$tables_sauvegardees = isset($GLOBALS['meta']['status_dump_tables'])?unserialize($GLOBALS['meta']['status_dump_tables']):array();

	if (!$etape_actuelle AND !$sous_etape) {
		$l = preg_files($file .  ".part_[0-9]+_[0-9]+");
@@ -67,24 +58,29 @@ function exec_export_all_dist()
		}
		$start = true; //  utilise pour faire un premier hit moitie moins long
		$tables_sauvegardees = array();
	}
	} else 	$tables_sauvegardees = isset($GLOBALS['meta'][$metatable])?unserialize($GLOBALS['meta'][$metatable]):array();

	list($tables_for_dump, $tables_for_link) = export_all_list_tables();
	list($tables_for_dump,) = export_all_list_tables();
	
	$all = count($tables_for_dump);
	// en mode partiel, commence par les articles pour savoir quelles
	// parties des tables s'y rattachant sont a sauvegarder
	if ($rub AND $t = array_search('spip_articles', $tables_for_dump)) {
		unset($tables_for_dump[$t]);
		array_unshift($tables_for_dump, 'spip_articles');
	}
	  
	// concatenation des fichiers crees a l'appel precedent
	ramasse_parties($dir, $archive);

	$all = count($tables_for_dump);
	if ($etape_actuelle > $all){ 
	  // l'appel precedent avait fini le boulot. mettre l'en-pied.
		ecrire_fichier($file, export_enpied(),false,false);
		include_spip('inc/headers');
		redirige_par_entete(generer_action_auteur("export_all","end,$gz,$archive",'',true));
		redirige_par_entete(generer_action_auteur("export_all","end,$gz,$archive,$rub",'',true));
	}

	include_spip('inc/minipres');
	echo install_debut_html(_T('info_sauvegarde') . " ($all)");
	echo_flush( install_debut_html(_T('info_sauvegarde') . " ($all)"));

	if (!($timeout = ini_get('max_execution_time')*1000));
	$timeout = 30000; // parions sur une valeur tellement courante ...
@@ -93,21 +89,19 @@ function exec_export_all_dist()
	// sinon grosse ecriture au 1er hit, puis gros rammassage au deuxieme avec petite ecriture,... ca oscille
	if ($start) $timeout = round($timeout/2);
	// script de rechargement auto sur timeout
	echo ("<script language=\"JavaScript\" type=\"text/javascript\">window.setTimeout('location.href=\"".$redirect."\";',$timeout);</script>\n");

	if (function_exists('ob_flush')) @ob_flush();
	flush();
	echo_flush("<script language=\"JavaScript\" type=\"text/javascript\">window.setTimeout('location.href=\"".$redirect."\";',$timeout);</script>\n");

	echo "<div style='text-align: left'>\n";
	echo_flush( "<div style='text-align: left'>\n");
	$etape = 1;

	// Les sauvegardes partielles prennent le temps d'indiquer les logos
	// Instancier une fois pour toutes, car on va boucler un max.
	// Completer jusqu'au secteur (sans prendre les soeurs) pour pouvoir
	// resituer dans l'arborescence
	if ($GLOBALS['connect_id_rubrique']) {
	// On ne complete par jusqu'au secteur
	// (il faudrait, sans prendre les soeurs, pour pouvoir
	// resituer dans l'arborescence)
	if ($rub) {
		$GLOBALS['chercher_logo'] = charger_fonction('chercher_logo', 'inc',true);
		$les_rubriques = complete_secteurs($GLOBALS['connect_id_rubrique']);
		$les_rubriques = complete_fils(array($rub));
	} else {
		$GLOBALS['chercher_logo'] = false;
		$les_rubriques = '';
@@ -116,29 +110,28 @@ function exec_export_all_dist()
	foreach($tables_for_dump as $table){
		if ($etape_actuelle <= $etape) {
		  $r = sql_countsel($table);
		  echo "\n<br /><strong>",$etape, '. ', $table,"</strong> ";
		  if (!$r) echo _T('texte_vide');
		  echo_flush( "\n<br /><strong>".$etape. '. '. $table."</strong> ");
		  if (!$r) echo_flush( _T('texte_vide'));
		  else
		    export_objets($table, $etape, $sous_etape,$dir, $archive, $gz, $r, $les_rubriques);
		  if (function_exists('ob_flush')) @ob_flush();
		  flush();
		    export_objets($table, $etape, $sous_etape,$dir, $archive, $gz, $r, $les_rubriques, $rub, $meta);
		  $sous_etape = 0;
		  // on utilise l'index comme ca c'est pas grave si on ecrit plusieurs fois la meme
		  $tables_sauvegardees[$table] = 1;
			ecrire_meta("status_dump_tables", serialize($tables_sauvegardees),'non');
		  ecrire_meta($metatable, serialize($tables_sauvegardees),'non');
		}
		$etape++;
		$status_dump = "$gz::$archive::" . $etape . "::0";
		$status_dump = "$gz::$archive::$rub::" . $etape . "::0";
	// on se contente d'une ecriture en base pour aller plus vite
	// a la relecture on en profitera pour mettre le cache a jour
		ecrire_meta("status_dump", $status_dump,'non');
		ecrire_meta($meta, $status_dump,'non');
	}
	echo "</div>\n";
	echo_flush( "</div>\n");
	// si Javascript est dispo, anticiper le Time-out
	echo ("<script language=\"JavaScript\" type=\"text/javascript\">window.setTimeout('location.href=\"$redirect\";',0);</script>\n");
	echo install_fin_html();
	echo_flush ("<script language=\"JavaScript\" type=\"text/javascript\">window.setTimeout('location.href=\"$redirect\";',0);</script>\n");
	echo_flush(install_fin_html());
}

/* A reutiliser
// http://doc.spip.org/@complete_secteurs
function complete_secteurs($les_rubriques)
{
@@ -155,11 +148,20 @@ function complete_secteurs($les_rubriques)
	}
	return $les_rubriques;
}
*/

function complete_fils($rubriques)
{
	$r = $rubriques;
	do {
		$q = spip_query("SELECT id_rubrique FROM spip_rubriques WHERE id_parent IN (".join(',',$r).")");
		$r = array();
		while ($row = sql_fetch($q)) {
			$r[]= $rubriques[] = $row['id_rubrique'];
		}
	} while ($r);


// http://doc.spip.org/@export_verifie_session
function export_verifie_session() {
	$row = sql_fetsel('valeur','spip_meta',("nom='export_session_id'"));
	if ($row['valeur']!=_EXPORT_SESSION_ID)
		die('la place est prise');
	return $rubriques;
}
?>
+53 −20
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -150,7 +150,7 @@ define('_EXTENSION_PARTIES', '.gz');
// et on memorise dans le serveur qu'on va passer a la table suivante.

// http://doc.spip.org/@export_objets
function export_objets($table, $etape, $cpt, $dir, $archive, $gz, $total, $les_rubriques) {
function export_objets($table, $etape, $cpt, $dir, $archive, $gz, $total, $les_rubriques, $rub, $meta) {
	global $tables_principales;

	$filetable = $dir . $archive . '.part_' . sprintf('%03d',$etape);
@@ -165,14 +165,12 @@ function export_objets($table, $etape, $cpt, $dir, $archive, $gz, $total, $les_r
		$string = build_while($debut, $table, $prim, $les_rubriques);
		$cpt++;
		$debut +=  _EXPORT_TRANCHES_LIMITE;
		$status_dump = "$gz::$archive::$etape::$cpt";
		$status_dump = "$gz::$archive::$rub::$etape::$cpt";

		// attention $string vide ne suffit pas a sortir
		// car les admins restreints peuvent parcourir
		// une portion de table vide pour eux.
		// car les sauvegardes partielles peuvent parcourir
		// une table dont la portion qui les concerne sera vide..
		if ($string) { 
			// verifier qu'on a encore la main, sinon mourir, un autre process a pris la suite
			export_verifie_session();
		// on ecrit dans un fichier generique
		// puis on le renomme pour avoir une operation atomique 
			ecrire_fichier ($temp = $filetable . '.temp' . _EXTENSION_PARTIES, $string);
@@ -183,11 +181,18 @@ function export_objets($table, $etape, $cpt, $dir, $archive, $gz, $total, $les_r
		}
		// on se contente d'une ecriture en base pour aller plus vite
		// a la relecture on en profitera pour mettre le cache a jour
		ecrire_meta("status_dump", $status_dump,'non');
		ecrire_meta($meta, $status_dump,'non');
		if ($debut >= $total) {break;}
		echo " $debut";
		/* pour tester la robustesse de la reprise sur interruption
		decommenter ce qui suit,  mais voir aussi echo_flush
		if ($cpt && 1) {
		  spip_log("force interrup $status_dump");
		  include_spip('inc/headers');
		  redirige_par_entete("./?exec=export_all&rub=$rub&x=$status_dump");
		  } */
		echo_flush(" $debut");
	}
	echo " $total."; 
	echo_flush(" $total."); 
	
	# on prefere ne pas faire le ramassage ici de peur d'etre interrompu par le timeout au mauvais moment
	# le ramassage aura lieu en debut de hit suivant, et ne sera normalement pas interrompu car le temps pour ramasser
@@ -195,6 +200,17 @@ function export_objets($table, $etape, $cpt, $dir, $archive, $gz, $total, $les_r
	// ramasse_parties($dir.$archive, $dir.$archive);
}

// Envoi immediat au client.
// Pour tester la robustesse ci-dessus, 
// commenter 3 lignes et decommenter la derniere (sinon le 302 ne marche pas)
function echo_flush($texte)
{
	echo $texte;
	if (function_exists('ob_flush')) @ob_flush();
	flush();
#	spip_log(str_replace('<','',$texte));
}

// Construit la version xml  des champs d'une table

// http://doc.spip.org/@build_while
@@ -230,19 +246,24 @@ function build_while($debut, $table, $prim, $les_rubriques) {

// http://doc.spip.org/@export_select
function export_select($row, $les_rubriques) {
	static $articles = array();

	if (isset($row['impt']) AND $row['impt'] !='oui') return false;
	if (!$les_rubriques) return true;
	// if (isset($row['id_auteur'])) return false; # pour les ignorer
	if (!isset($row['id_rubrique'])) {
		if (isset($row['id_article']))
			return autoriser('modifier','article',$row['id_article']);
		if (isset($row['id_breve']))
			return autoriser('modifier','breve',$row['id_breve']);
	// numero de rubrique present suffit, sauf pour les forums
	if (isset($row['id_rubrique']) AND $row['id_rubrique']) {
		if  (!in_array($row['id_rubrique'], $les_rubriques))
		  return false;
		$articles[$row['id_article']] = true;
		return true;
	}
	//  petitions, signatures et documents associes aux articles
	if (isset($row['id_article']) AND $row['id_article']) {
		return array_search($row['id_article'], $articles);
	}
	if (isset($row['id_article']) OR isset($row['id_breve']))
		return autoriser('publierdans','rubrique',$row['id_rubrique']);
	return isset($les_rubriques[$row['id_rubrique']]);

	// a la louche pour le reste, mais c'est a peu pres ca.
	return (isset($row['id_groupe']) OR isset($row['id_mot']) OR isset($row['mime_type']) OR isset($row['id_document']));
}

// Conversion texte -> xml (ajout d'entites)
@@ -251,6 +272,18 @@ function text_to_xml($string) {
	return str_replace(array('&','<','>'), array('&amp;','&lt;','&gt;'), $string);
}

// construit le repertoire ou preparer la sauvegarde
function export_subdir($rub)
{
	include_spip('inc/actions');
	// determine upload va aussi initialiser l'index "restreint"
	$dir = determine_upload();
	if (!$GLOBALS['auteur_session']['restreint'])
		$dir = _DIR_DUMP;
	$subdir = 'export_' . $GLOBALS['auteur_session']['id_auteur'] . '_' . intval($rub);
	return sous_repertoire($dir, $subdir);
}

// production de l'entete du fichier d'archive

// http://doc.spip.org/@export_entete
+7 −5
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -188,11 +188,13 @@ function supprimer_fichier($fichier, $lock=true) {
}
// Supprimer brutalement, si le fichier existe
// http://doc.spip.org/@spip_unlink
function spip_unlink($fichier) {
	if (is_dir($fichier))
		@rmdir($fichier);
	else 
		supprimer_fichier($fichier,false);
function spip_unlink($f) {
	if (!is_dir($f))
		supprimer_fichier($f,false);
	else {
		@unlink("$f/.ok");
		@rmdir($f);
	}
}

//