<?php
#=
/****************************************************************************
Copyright 2002-2004, Daniel Deycard, Jacques Messines, Alain Pomirol
(CATICE Académie de Bordeaux)

This file is part of GiBii/Melia.
GiBii/Melia is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

GiBii/Melia is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GiBii/Melia; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
****************************************************************************/

/*
Le backup sauvegarde les tables en remplaçant les valeurs inconnues des liens
par leurs opposées.
Voici le début de la table eleves stocké par le backup :
        [eleves]
        12="nom='machin',...,compte_id=-14,classe_id=-4
        17="nom='mioche',...,compte_id=-18,classe_id=-7
Pendant la restauration, des tableaux de correspondance ancien id/nouvel id sont
construits en mémoire. Ainsi, pour la table eleves, les 2 lignes ci-dessus
seront restaurées par les instructions :
    INSERT INTO eleves SET nom='machin',...,compte_id=-14,classe_id=-4,etab_id=8
    INSERT INTO eleves SET nom='mioche',...,compte_id=-18,classe_id=-7,etab_id=8
et, si les INSERT donnent les eleve_id respectifs 145 et 146, le tableau
$eleve_id subira parallèlement les affectations :
        $eleve_id[12]=145 et $eleve_id[17]=146

Une fois que les lignes du backup sont écrites dans la base, toutes les
références sont résolues grâce aux tableaux $eleve_id, $classe_id, $compte_id,...
Ainsi, le restore de la table classes permettra de créer un tableau $classe_id
qui permettre de résoudre les liens inconnus dans ta table eleves notamment.

Il faudra donc effectuer une deuxième passe qui remplacera les anciennes
références par les nouvelles trouvées dans les tableaux. Cela signifie qu'il
faudra remplacer
        compte_id=-14,classe_id=-4
par les nouvelles valeurs :
        compte_id=$compte_id[14],classe_id=$classe_id[4]

Pour automatiser ce traitement pour toutes les tables, un tableau-guide sera
utilisé pour le backup et le restore (voir programme ci-dessous et fichier
inclus guide.inc.php).
*/

function sql_addslashes($a_string) {
$a_string = str_replace('\\', '\\\\', $a_string);  // '\
$a_string = str_replace('\'', '\\\'', $a_string);
return $a_string;
}

function bon_crlf() {
$the_crlf = "\n";
if (!isset($GLOBALS['HTTP_USER_AGENT']))
    if (!empty($GLOBALS['HTTP_SERVER_VARS']) && isset($GLOBALS['HTTP_SERVER_VARS']['HTTP_USER_AGENT']))
        $GLOBALS['HTTP_USER_AGENT'] = $GLOBALS['HTTP_SERVER_VARS']['HTTP_USER_AGENT'];
    else $GLOBALS['HTTP_USER_AGENT'] = @getenv('HTTP_USER_AGENT');
// Chercher "win"
if (!empty($GLOBALS['HTTP_USER_AGENT'])
    && ereg('[^(]*\((.*)\)[^)]*', $GLOBALS['HTTP_USER_AGENT'], $regs))
    if (eregi('Win', $regs[1])) $the_crlf = "\r\n";
return $the_crlf;
}


function printstream($sql) {
global $dump_buffer,$crlf;
$dump_buffer.=$sql.$crlf;
//print $sql.'<br />';
}

// Chercher les champs entiers
function champs_entiers($ressource) {
for ($j = 0; $j < mysql_num_fields($ressource); $j++) {
    //$field_set[$j] = mysql_field_name($result, $j);
    $type          = mysql_field_type($ressource, $j);
    $field_num[$j]=($type == 'tinyint' || $type == 'smallint' ||
                    $type == 'mediumint' || $type == 'int' ||
                    $type == 'bigint'  ||$type == 'timestamp');
}
return $field_num;
}

/*non utilisée
function recup_valeurs($row,$field_count,$field_num) {
global $search,$replace;
for ($j = 0; $j < $field_count; $j++) {
    if (!isset($row[$j])) $values[]= 'NULL';
    else if (!empty($row[$j]))
            if ($field_num[$j]) $values[]= $row[$j];
            else $values[]= "'".str_replace($search, $replace, sql_addslashes($row[$j]))."'";
         else $values[]= "''";
} // for
return $values;
}
*/

//==============================================================================
function sauvertable($table1) {
global $etab_id,$guide,$db;

if (!table_dans_base($table1,$db)) return false; //cas des nouvelles tables créées à la volée

@set_time_limit(1200);
$condwhere="etab_id=$etab_id";

$nomid=getguide($table1,'cle');          //clé primaire autonumber éventuelle (eleve_id)
$yesetab=getguide($table1,'etab')==1;

//il faut récupérer les enregistrements propres à l'étab. Quand etab_id fait
//  partie des champs de la table, pas de problème. Sinon, il faut l'obtenir
//  par jointure avec un champ permettant d'accéder à etab_id (eleve_id ou prof_id) :
if ($yesetab) {
    $from=$table1;
    $where="etab_id=$etab_id";
	}
elseif ($table1=='etablissements') {
	$from='etablissements';
	$where=$condwhere;
	}
else {
	$from=getguide($table1,'from');
	$where=getguide($table1,'where').$etab_id; //$where se termine par =
	}

$result = query("SELECT $table1.* FROM $from WHERE $where");
if (!$result) return false;

$isfieldnumeric=champs_entiers($result); //tableau de booléens (champs de type entier)
$fieldcount=mysql_num_fields($result);
$fieldnames=array();
for ($i=0; $i<$fieldcount; $i++) $fieldnames[$i]=mysql_field_name($result,$i);

printstream("");
printstream("");
printstream("[$table1]");
printstream("");

$iligneini=0;
while ($row = mysql_fetch_array($result)) {  //écrire un enreg de la table
    $contenu='';
    if ($nomid=='') {
        $numero=$iligneini.'=';
        $iligneini++;
        }
    else $numero=$row[$nomid].'=';
    for ($i=0; $i<$fieldcount; $i++) {
        $nomchamp=$fieldnames[$i];
        if ($nomchamp==$nomid) continue;    //champ autoinc donc non explicite
        if (!isset($row[$i]))
            $value='NULL';                             //à mettre en 1° pour comptes (eleve_id et prof_id pas tous 2 affectés))
        elseif ($nomchamp=='etab_id')
            continue;                       //pas écrit au backup : sera ajouté au restore grâce à la table $guide
        elseif ($isfieldnumeric[$i])
            $value=$row[$i];                //celle-ci est fixe
        elseif (empty($row[$i]))
            $value="''";
        else $value="'".addslashes($row[$i])."'";
        $contenu.=urlencode($nomchamp.'='.$value).',';
    }
    $contenu=substr($contenu,0,-1);         //enlever la dernière virgule
    //print $contenu;print "<br />";
    printstream($numero.'"'.$contenu.'"');  // urlencode pour les caractères non numériques : 4="nom%3D%27Machin%27%2C..."

}//while
return true;
}//function

//##############################################################################

function creer_backup($zip,$fermewin) {
global
   $db,$crlf,$dump_buffer,$MODULE,
   $VERSION_GIBII,$DATE_GIBII,$PAS_SAUVE_LOCAL, $HIDEDATA, $SITE_GIBII,
   $etab_theme,$etab_id,$etab_rne,$etab_nom,$etab_rne,$etab_adresse,
   $etab_codepostal,$etab_ville,
   $sess_ip,$sess_machinecliente,
   $guide;

$beginhtml="<html><head>
            <title>Sauvegarde des données de l'établissement</title>
            <link rel=\"stylesheet\" href=\"../themes/$etab_theme/b2i.css\">
            </head><body class=\"arialadmin\">\n";
$endhtml="</body></html>\n";

/*
$search  = array("\x0a","\x0d","\x1a");
$replace = array("\\n","\\r","\Z");
*/
/* Parmi les tables à sauvegarder, il y a :
   - les tables primaires : celles qui ont un champ etab_id. Tous les
     enregistrements ayant la bonne valeur pour ce etab_id sont à enregistrer ;
     il s'agit de eleves, etablissements, libelles_perso, profs, classes,
     comptes,
   - les tables secondaires : elles sont liées à une principale par un champ
     commun (entre parenthèses). Il s'agit de demandes et resultats (eleve_id),
     ainsi que reponses, lpi et lien_profs_classes (prof_id).
     Certaines tables principales n'ont pas de tables secondaires : le tableau
     qu'elles pointent est vide. Celles qui ont des tables secondaires pointent
     un tableau dont les clés sont les champs de liaison avec la table principale
     et les noms des tableaux secondaires relatifs à ces champs de liaison.
*/

$dump_buffer = '';
$crlf=bon_crlf();
if (empty($etab_rne)) $prefixe=$etab_id;
else $prefixe=$etab_rne;

if (function_exists("apache_get_version"))
	$vapache=@apache_get_version();
else $vapache='non trouvée';

$fichier=$prefixe."_".$db."_".date("Ymj").'.sql';
if ($zip!="non") $fichier.='.'.$zip;

$dump_buffer   .= '; Backup pour '.$MODULE.' version '.$VERSION_GIBII.' du '.$DATE_GIBII. $crlf
               .  '; révision du 5 mai 2007' . $crlf
               .  '; CATICE Rectorat de Bordeaux' . $crlf
               .  '; Daniel Deycard - Jacques Messines - Jean-Marie Treins' . $crlf
               .  '; décembre 2001 - mai 2007'. $crlf
               .  ';' . $crlf;
$dump_buffer   .= $crlf
               .  '; Créé le       : ' . date('j F Y, H:i ') . $crlf
               .  '; IP            : ' . $sess_ip . $crlf
               .  '; nom machine   : ' . $sess_machinecliente. $crlf 
               .  '; Version Apache: ' . $vapache. $crlf
               .  '; Version PHP   : ' . phpversion() . $crlf
               .  '; Version MySQL : ' . mysql_get_server_info().', sur '. mysql_get_host_info() . $crlf
               .  '; Version '		   . $MODULE.' : ' . $VERSION_GIBII . $crlf
               .  '; Base          : ' . $db . $crlf
               .  '; Etablissement : ' . $etab_nom. $crlf
               .  '; RNE           : ' . $etab_rne. $crlf
               .  '; Adresse       : ' . $etab_adresse.", - ". $etab_codepostal." -  ". $etab_ville.". ".$crlf.$crlf;

//Ajouté à partir de la version 4.6.1 (fausse table spéciale pour contrôles)
$dump_buffer   .= $crlf
			   .'[#]'.$crlf
			   .'module='.$MODULE.$crlf
			   .'version='.$VERSION_GIBII.$crlf
			   .'site='.$SITE_GIBII.$crlf	
			   .'etab_id='.$etab_id.$crlf.$crlf;
//fin ajout

foreach($guide as $nomtable => $params) {
    sauvertable($nomtable);
	}

$cs=substr(md5($dump_buffer),0,6);
$fichier=$cs.'_'.$fichier;

// "Affichage" (envoi) du contenu
// en principe (!) il ne peut y avoir d'erreur due à la compression :
// les cas de fonction inexistante ont été filtrés au niveau du formulaire
$erreur=false;
if ($zip == 'bz2') {
    if (@function_exists('bzcompress'))
        $envoi=bzcompress($dump_buffer);
    else $erreur=true;
	}
elseif ($zip == 'gz') {
    if (@function_exists('gzencode'))
        $envoi=gzencode($dump_buffer);
    else $erreur=true;
	}
else $envoi=$dump_buffer;

if ($erreur) {
    print $beginhtml;
    print "Problème pour compresser la sauvegarde.<br />\n";
    print "La version de PHP ne supporte pas les fichiers $zip.<br />\n";
    retour('../backup/back_choix.php');
    print $endhtml;
    exit();
}

// choix actuel : "sauvegarde sur serveur" OU "exclusif récupération en local"
//============================================================================
if ($PAS_SAUVE_LOCAL) {
    //sauvegarde sur serveur
    $nomfic="$HIDEDATA/$etab_rne/backup/".$fichier;
    $merreur="";
    if ($fp=fopen(creertousrep($nomfic),"w")) {
        $nboctets=fputs($fp,$envoi);
        if (!$nboctets) $merreur="d'écriture";
        fclose($fp);
    }
    else $merreur="d'ouverture en écriture";
    print $beginhtml;
    print "<p style=\"text-align:center\">";
    if ($merreur) {
        print "Problème $merreur du fichier $nomfic sur le serveur.<br />";
        print "Signalez-le au super-administrateur.";
    }
    else {
        print "Sauvegarde effectuée dans le fichier $fichier du serveur.";
    }
    print "<br /><br /></p>";
    if ($fermewin) {
        //appel depuis l'incorporation d'individus : fermer la popup
        retour("javascript:window.close()");
    }
    else {
        //appel depuis le menu backup : retour à admin_bas/php
        retour('../admin/admin_bas.php');
    }
    print $endhtml;
}
else {
    prepare_download($fichier); //en-têtes permettant d'effectuer un download
    print $envoi;               //en fait c'est un download
}

} //function creer_backup
?>