[SPIP] +2.1.12
[velocampus/web/www.git] / www / ecrire / inc / export.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2011 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 if (!defined('_ECRIRE_INC_VERSION')) return;
14
15 define('_EXPORT_TRANCHES_LIMITE', 200);
16 define('_EXTENSION_PARTIES', '.gz');
17
18 // http://doc.spip.org/@exec_export_all_args
19 function inc_export_dist($meta)
20 {
21 if (!isset($GLOBALS['meta'][$meta])) {
22 include_spip('inc/minipres');
23 echo minipres();
24 }
25 else {
26 $start = false;
27 list($gz, $archive, $rub, $tables_for_dump, $etape_actuelle, $sous_etape) =
28 unserialize($GLOBALS['meta'][$meta]);
29
30 // determine upload va aussi initialiser l'index "restreint"
31 $maindir = determine_upload();
32 if (!$GLOBALS['visiteur_session']['restreint'])
33 $maindir = _DIR_DUMP;
34 $dir = sous_repertoire($maindir, $meta);
35 $file = $dir . $archive;
36 $metatable = $meta . '_tables';
37
38 // Reperer une situation anormale (echec reprise sur interruption)
39 if (!$etape_actuelle AND !$sous_etape) {
40 $l = preg_files($file . ".part_[0-9]+_[0-9]+");
41 if ($l) {
42 spip_log("menage d'une sauvegarde inachevee: " . join(',', $l));
43 foreach($l as $dummy) spip_unlink($dummy);
44 }
45 $start = true; // utilise pour faire un premier hit moitie moins long
46 $tables_sauvegardees = array();
47 } else $tables_sauvegardees = isset($GLOBALS['meta'][$metatable])?unserialize($GLOBALS['meta'][$metatable]):array();
48
49 // concatenation des fichiers crees a l'appel precedent
50 ramasse_parties($dir, $archive);
51 $all = count($tables_for_dump);
52 if ($etape_actuelle > $all OR !$all){
53 return "end,$gz,$archive,$rub"; // c'est fini !
54 }
55
56 include_spip('inc/minipres');
57 @ini_set("zlib.output_compression","0"); // pour permettre l'affichage au fur et a mesure
58
59 echo ( install_debut_html(_T('info_sauvegarde') . " ($all)"));
60
61 if (!($timeout = ini_get('max_execution_time')*1000));
62 $timeout = 30000; // parions sur une valeur tellement courante ...
63 // le premier hit est moitie moins long car seulement une phase d'ecriture de morceaux
64 // sans ramassage
65 // sinon grosse ecriture au 1er hit, puis gros rammassage au deuxieme avec petite ecriture,... ca oscille
66 if ($start) $timeout = round($timeout/2);
67
68 // Les sauvegardes partielles prennent le temps d'indiquer les logos
69 // Instancier une fois pour toutes, car on va boucler un max.
70 // On complete jusqu'au secteur pour resituer dans l'arborescence)
71 if ($rub) {
72 $GLOBALS['chercher_logo'] = charger_fonction('chercher_logo', 'inc',true);
73 $les_rubriques = complete_fils(array($rub));
74 $les_meres = complete_secteurs(array($rub));
75 } else {
76 $GLOBALS['chercher_logo'] = false;
77 $les_rubriques = $les_meres = '';
78 }
79
80 // script de rechargement auto sur timeout
81 $redirect = generer_url_ecrire("export_all");
82 echo http_script("window.setTimeout('location.href=\"".$redirect."\";',$timeout)");
83
84 echo "<div style='text-align: left'>\n";
85 $etape = 1;
86 foreach($tables_for_dump as $table){
87 if ($etape_actuelle > $etape) {
88 // sauter les deja faits, mais rappeler qu'ils sont fait
89 echo ( "\n<br /><strong>".$etape. '. '."</strong>". $tables_sauvegardees[$table]);
90 }
91 else {
92 echo ( "\n<br /><strong>".$etape. '. '. $table."</strong> ");
93 $r = sql_countsel($table);
94 flush();
95 if (!$r) $r = ( _T('texte_vide'));
96 else {
97 $f = $dir . $archive . '.part_' . sprintf('%03d',$etape);
98 $r = export_objets($table, $sous_etape, $r, $f, $les_rubriques, $les_meres, $meta);
99 $r += $sous_etape*_EXPORT_TRANCHES_LIMITE;
100 // info pas fiable si interruption+partiel
101 if ($rub AND $etape_actuelle > 1) $r = ">= $r";
102 }
103 echo " $r";
104 flush();
105 $sous_etape = 0;
106 // on utilise l'index comme ca c'est pas grave si on ecrit plusieurs fois la meme
107 $tables_sauvegardees[$table] = "$table ($r)";
108 ecrire_meta($metatable, serialize($tables_sauvegardees),'non');
109 }
110 $etape++;
111 $v = serialize(array($gz, $archive, $rub, $tables_for_dump, $etape,$sous_etape));
112 ecrire_meta($meta, $v,'non');
113 }
114 echo ( "</div>\n");
115 // si Javascript est dispo, anticiper le Time-out
116 echo ("<script language=\"JavaScript\" type=\"text/javascript\">window.setTimeout('location.href=\"$redirect\";',0);</script>\n");
117 echo (install_fin_html());
118 flush();
119 }
120 }
121
122
123 // http://doc.spip.org/@complete_secteurs
124 function complete_secteurs($les_rubriques)
125 {
126 $res = array();
127 foreach($les_rubriques as $r) {
128 do {
129 $r = sql_getfetsel("id_parent", "spip_rubriques", "id_rubrique=$r");
130 if ($r) {
131 if ((isset($les_rubriques[$r])) OR isset($res[$r]))
132 $r = false;
133 else $res[$r] = $r;
134 }
135 } while ($r);
136 }
137 return $res;
138 }
139
140 // http://doc.spip.org/@complete_fils
141 function complete_fils($rubriques)
142 {
143 $r = $rubriques;
144 do {
145 $q = sql_select("id_rubrique", "spip_rubriques", "id_parent IN (".join(',',$r).")");
146 $r = array();
147 while ($row = sql_fetch($q)) {
148 $r[]= $rubriques[] = $row['id_rubrique'];
149 }
150 } while ($r);
151
152
153 return $rubriques;
154 }
155
156 // Concatenation des tranches
157 // Il faudrait ouvrir une seule fois le fichier, et d'abord sous un autre nom
158 // et sans detruire les tranches: au final renommage+destruction massive pour
159 // prevenir autant que possible un Time-out.
160
161 // http://doc.spip.org/@ramasse_parties
162 function ramasse_parties($dir, $archive)
163 {
164 $files = preg_files($dir . $archive . ".part_[0-9]+_[0-9]+[.gz]?");
165
166 $ok = true;
167 $files_o = array();
168 $but = $dir . $archive;
169 foreach($files as $f) {
170 $contenu = "";
171 if (lire_fichier ($f, $contenu)) {
172 if (!ecrire_fichier($but,$contenu,false,false))
173 { $ok = false; break;}
174 }
175 spip_unlink($f);
176 $files_o[]=$f;
177 }
178 return $ok ? $files_o : false;
179 }
180
181 //
182 // Exportation de table SQL au format xml
183 // La constante ci-dessus determine la taille des tranches,
184 // chaque tranche etant copiee immediatement dans un fichier
185 // et son numero memorisee dans le serveur SQL.
186 // En cas d'abandon sur Time-out, le travail pourra ainsi avancer.
187 // Au final, on regroupera les tranches en un seul fichier
188 // et on memorise dans le serveur qu'on va passer a la table suivante.
189 // on prefere ne pas faire le ramassage ici de peur d'etre interrompu
190 // par le timeout au mauvais moment
191 // le ramassage aura lieu en debut de hit suivant,
192 // et ne sera normalement pas interrompu car le temps pour ramasser
193 // est plus court que le temps pour creer les parties
194
195 // http://doc.spip.org/@export_objets
196 function export_objets($table, $cpt, $total, $filetable, $les_rubriques, $les_meres, $meta) {
197 global $tables_principales;
198
199 $temp = $filetable . '.temp' . _EXTENSION_PARTIES;
200 $prim = isset($tables_principales[$table])
201 ? $tables_principales[$table]['key']["PRIMARY KEY"]
202 : '';
203 $debut = $cpt * _EXPORT_TRANCHES_LIMITE;
204 $effectifs = 0;
205
206 while (1){ // on ne connait pas le nb de paquets d'avance
207
208 $cpt++;
209 $tranche = build_while($debut, $table, $prim, $les_rubriques, $les_meres);
210 // attention: vide ne suffit pas a sortir
211 // car les sauvegardes partielles peuvent parcourir
212 // une table dont la portion qui les concerne sera vide..
213 if ($tranche) {
214 // on ecrit dans un fichier generique
215 // puis on le renomme pour avoir une operation atomique
216 ecrire_fichier ($temp, join('', $tranche));
217 $f = $filetable . sprintf('_%04d',$cpt) . _EXTENSION_PARTIES;
218 // le fichier destination peut deja exister
219 // si on sort d'un timeout entre le rename et le ecrire_meta
220 if (file_exists($f)) spip_unlink($f);
221 rename($temp, $f);
222 $effectifs += count($tranche);
223 }
224 // incrementer le numero de sous-etape
225 // au cas ou une interruption interviendrait
226 $v = unserialize($GLOBALS['meta'][$meta]);
227 $v[5]++;
228 ecrire_meta($meta, serialize($v));
229 $debut += _EXPORT_TRANCHES_LIMITE;
230 if ($debut >= $total) {break;}
231 /* pour tester la robustesse de la reprise sur interruption
232 decommenter ce qui suit.
233 if ($cpt && 1) {
234 spip_log("force interrup $s");
235 include_spip('inc/headers');
236 redirige_par_entete("./?exec=export_all&rub=$rub&x=$s");
237 } /* */
238 echo(". ");
239 flush();
240 }
241
242 return $effectifs;
243 }
244
245
246 // Construit la version xml des champs d'une table
247
248 // http://doc.spip.org/@build_while
249 function build_while($debut, $table, $prim, $les_rubriques, $les_meres) {
250 global $chercher_logo ;
251
252 // sauver par ordre croissant les tables avec cles primaires simples
253 // sinon les sequences PG seront pertubees a la restauration
254 // (a ameliorer)
255 $result = sql_select('*', $table, '', '', $prim, "$debut," . _EXPORT_TRANCHES_LIMITE);
256
257 $res = array();
258 while ($row = sql_fetch($result)) {
259 if (export_select($row, $les_rubriques, $les_meres)) {
260 $attributs = "";
261 if ($chercher_logo) {
262 if ($logo = $chercher_logo($row[$prim], $prim, 'on'))
263 $attributs .= ' on="' . $logo[3] . '"';
264 if ($logo = $chercher_logo($row[$prim], $prim, 'off'))
265 $attributs .= ' off="' . $logo[3] . '"';
266 }
267
268 $string = "<$table$attributs>\n";
269 foreach ($row as $k => $v) {
270 $string .= "<$k>" . text_to_xml($v) . "</$k>\n";
271 }
272 $string .= "</$table>\n\n";
273 $res[]= $string;
274 }
275 }
276 sql_free($result);
277 return $res;
278 }
279
280 // dit si Row est exportable,
281 // en particulier quand on se restreint a certaines rubriques
282 // Attention, la table articles doit etre au debut
283 // et la table document_articles avant la table documents
284 // (faudrait blinder, c'est un bug potentiel)
285
286 // http://doc.spip.org/@export_select
287 function export_select($row, $les_rubriques, $les_meres) {
288 static $articles = array();
289 static $documents = array();
290
291 if (isset($row['impt']) AND $row['impt'] !='oui') return false;
292 if (!$les_rubriques) return true;
293
294 // numero de rubrique non determinant pour les forums (0 � 99%)
295 if (isset($row['id_rubrique']) AND $row['id_rubrique']) {
296 if (in_array($row['id_rubrique'], $les_rubriques)) {
297 if (isset($row['id_article']))
298 $articles[] = $row['id_article'];
299 if (isset($row['id_document']))
300 $documents[]=$row['id_document'];
301 return true;
302 }
303 if (!in_array($row['id_rubrique'], $les_meres))
304 return false;
305 // la rubrique, mais rien d'autre
306 return (!isset($row['id_article'])
307 AND !isset($row['id_mot'])
308 AND !isset($row['id_document'])
309 AND !isset($row['id_breve']));
310 }
311 // dependances d'articles (mots, petitions, signatures et documents)
312 if (isset($row['id_article']) AND $row['id_article']) {
313 if (in_array($row['id_article'], $articles)) {
314 if (isset($row['id_document']))
315 $documents[]= $row['id_document'];
316 return true;
317 }
318 return false;
319 }
320 if (isset($row['id_objet']) AND isset($row['objet'])) {
321 if ($row['objet'] == 'article') {
322 if (in_array($row['id_objet'], $articles)) {
323 if (isset($row['id_document']))
324 $documents[]= $row['id_document'];
325 return true;
326 }
327 return false;
328 }
329 if ($row['objet'] == 'rubrique') {
330 if (in_array($row['id_objet'], $les_rubriques)) {
331 if (isset($row['id_document']))
332 $documents[]=$row['id_document'];
333 return true;
334 }
335 return false;
336 }
337 }
338
339 if (isset($row['id_document']) AND $row['id_document']) {
340 return array_search($row['id_document'], $documents);
341 }
342 // a la louche pour le reste, mais c'est a peu pres ca.
343 return (isset($row['id_groupe']) OR isset($row['id_mot']) OR isset($row['mime_type']));
344 }
345
346 // Conversion texte -> xml (ajout d'entites)
347 // http://doc.spip.org/@text_to_xml
348 function text_to_xml($string) {
349 return str_replace(array('&','<','>'), array('&amp;','&lt;','&gt;'), $string);
350 }
351
352 ?>