[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / plugins-dist / dump / inc / dump.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2016 *
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 /**
14 * API permettant la manipulation des sauvegardes
15 *
16 * @package SPIP\Dump\API
17 */
18
19 if (!defined('_ECRIRE_INC_VERSION')) {
20 return;
21 }
22
23
24 /**
25 * Répertoire de sauvegarde
26 *
27 * Crée et retourne le chemin du répertoire de sauvegarde
28 *
29 * @see _DIR_DUMP
30 *
31 * @return string
32 */
33 function dump_repertoire() {
34 $repertoire = _DIR_DUMP;
35 if (!@file_exists($repertoire)
36 and !$repertoire = sous_repertoire(_DIR_DUMP, '', false, true)
37 ) {
38 $repertoire = preg_replace(',' . _DIR_TMP . ',', '', _DIR_DUMP);
39 $repertoire = sous_repertoire(_DIR_TMP, $repertoire);
40 }
41
42 return $repertoire;
43 }
44
45
46 /**
47 * Nom du fichier de sauvegarde
48 *
49 * la fourniture de l'extension permet de vérifier que le nom n'existe pas déjà.
50 *
51 * @param string $dir Chemin de stockage du fichier
52 * @param string $extension Extension du fichier de sauvegarde
53 * @return string
54 */
55 function dump_nom_fichier($dir, $extension = 'sqlite') {
56 include_spip('inc/texte');
57 $site = 'spip';
58 if (isset($GLOBALS['meta']['nom_site'])) {
59 $site = typo($GLOBALS['meta']['nom_site']); // extraire_multi
60 $site = couper(translitteration(trim($site)), 30, '');
61 $site = preg_replace(array(',\W,is', ',_(?=_),', ',_$,'), array('_', '', ''), $site);
62 }
63
64 $site .= '_' . date('Ymd');
65
66 $nom = $site;
67 $cpt = 0;
68 while (file_exists($dir . $nom . ".$extension")) {
69 $nom = $site . sprintf('_%03d', ++$cpt);
70 }
71
72 return $nom . ".$extension";
73 }
74
75 /**
76 * Détermine le type de serveur de sauvegarde,
77 * sqlite2 ou sqlite3
78 *
79 * @return string
80 */
81 function dump_type_serveur() {
82
83 // chercher si sqlite2 ou 3 est disponible
84 include_spip('req/sqlite3');
85 if (spip_versions_sqlite3()) {
86 return 'sqlite3';
87 }
88
89 include_spip('req/sqlite2');
90 if (spip_versions_sqlite2()) {
91 return 'sqlite2';
92 }
93
94 return '';
95 }
96
97 /**
98 * Conteneur pour les arguments de la connexion
99 *
100 * Si on passe $args, les arguments de la connexion sont memorisés.
101 * Renvoie toujours les derniers arguments memorisés.
102 *
103 * @staticvar array $connect_args Pour stocker le premier conteneur
104 * @param array $args
105 * @return array
106 */
107 function dump_serveur($args = null) {
108 static $connect_args = null;
109 if ($args) {
110 $connect_args = $args;
111 }
112
113 return $connect_args;
114 }
115
116 function dump_connect_args($archive) {
117 if (!$type_serveur = dump_type_serveur()) {
118 return null;
119 }
120
121 return array(dirname($archive), '', '', '', basename($archive, '.sqlite'), $type_serveur, 'spip');
122 }
123
124 /**
125 * Initialiser un dump
126 *
127 * @param string $status_file Fichier contenant les informations serialisees sur le statut de l'export
128 * @param string $archive Nom de l'archive (stockee dans le fichier de statut)
129 * @param array $tables Liste des tables a exporter (autocaculee par defaut)
130 * @param array $where Condition sur l'export
131 * @param string $action Pour differencier la sauvegarde de l'import
132 * @return bool/string
133 */
134 function dump_init($status_file, $archive, $tables = null, $where = array(), $action = 'sauvegarde') {
135 $status_file = _DIR_TMP . basename($status_file) . '.txt';
136
137 if (lire_fichier($status_file, $status)
138 and $status = unserialize($status)
139 and $status['etape'] !== 'fini'
140 and filemtime($status_file) >= time() - 120
141 ) {
142 // si le fichier status est trop vieux c'est un abandon
143 return _T('dump:erreur_' . $action . '_deja_en_cours');
144 }
145
146 if (!$type_serveur = dump_type_serveur()) {
147 return _T('dump:erreur_sqlite_indisponible');
148 }
149
150 if (!$tables) {
151 list($tables, ) = base_liste_table_for_dump(lister_tables_noexport());
152 }
153 $status = array('tables' => $tables, 'where' => $where, 'archive' => $archive);
154
155 $status['connect'] = dump_connect_args($archive);
156 dump_serveur($status['connect']);
157 if (!spip_connect('dump')) {
158 return _T('dump:erreur_creation_base_sqlite');
159 }
160
161 // la constante sert a verifier qu'on utilise bien le connect/dump du plugin,
162 // et pas une base externe homonyme
163 if (!defined('_DUMP_SERVEUR_OK')) {
164 return _T('erreur_connect_dump', array('dump' => 'dump'));
165 }
166
167 $status['etape'] = 'init';
168
169 if (!ecrire_fichier($status_file, serialize($status))) {
170 return _T('dump:avis_probleme_ecriture_fichier', array('fichier' => $status_file));
171 }
172
173 return true;
174 }
175
176 /**
177 * Afficher l'avancement de la copie
178 *
179 * @staticvar int $etape Nombre de fois ou on est passe dans cette foncion
180 * @param <type> $courant Flag pour indiquer si c'est la table sur laquelle on travaille actuellement
181 * @param <type> $total Nombre total de tables
182 * @param <type> $table Nom de la table
183 */
184 function dump_afficher_progres($courant, $total, $table) {
185 static $etape = 1;
186 if (unique($table)) {
187 if ($total < 0 or !is_numeric($total)) {
188 echo '<br /><strong>' . $etape . '. ' . "</strong>$table ";
189 } else {
190 echo '<br /><strong>' . $etape . '. ' . "$table</strong> " . ($courant ? " <i>($courant)</i> " : '');
191 }
192 $etape++;
193 }
194 if (is_numeric($total) and $total >= 0) {
195 echo '. ';
196 } else {
197 echo '(' . (-intval($total)) . ')';
198 }
199 flush();
200 }
201
202 /**
203 * Écrire le js pour relancer la procédure de dump
204 *
205 * @param string $redirect URL de la prochaine etape du dump
206 * @return string Code HTML de redirection
207 */
208 function dump_relance($redirect) {
209 // si Javascript est dispo, anticiper le Time-out
210 return "<script language=\"JavaScript\" type=\"text/javascript\">window.setTimeout('location.href=\"$redirect\";',300);</script>\n";
211 }
212
213
214 /**
215 * Marquer la procédure de dump comme finie
216 *
217 * @param string $status_file
218 * Fichier qui mémorise les infos utiles concernant la sauvegarde en cours
219 * @param string $action
220 * Type d'action supplémentaire à réaliser :
221 *
222 * - restaurer : supprimer la structure qui était stockée dans le dump
223 * - 'auvegarder : stocker dans le dump la structure de la base source
224 */
225 function dump_end($status_file, $action = '') {
226 $status_file = _DIR_TMP . basename($status_file) . '.txt';
227 if (!lire_fichier($status_file, $status)
228 or !$status = unserialize($status)
229 ) {
230 return;
231 }
232
233 switch ($action) {
234 case 'restaurer':
235 // supprimer la structure qui etait stockee dans le dump
236 sql_delete('spip_meta', "nom='dump_structure_temp'");
237 break;
238 case 'sauvegarder':
239 // stocker dans le dump la structure de la base source
240 $structure = array();
241 foreach ($status['tables_copiees'] as $t => $n) {
242 $structure[$t] = sql_showtable($t, true);
243 }
244 dump_serveur($status['connect']);
245 spip_connect('dump');
246 // si spip_meta n'a pas ete backup elle n'est pas dans le dump, il faut la creer pour y stocker cette meta
247 if (!sql_showtable('spip_meta', true, 'dump')) {
248 $desc = sql_showtable('spip_meta', true);
249 sql_create('spip_meta', $desc['field'], $desc['key'], false, false, 'dump');
250 }
251 sql_delete('spip_meta', "nom='dump_structure_temp'", 'dump'); #enlever une vieille structure deja la, au cas ou
252 sql_insertq(
253 'spip_meta',
254 array('nom' => 'dump_structure_temp', 'valeur' => serialize($structure), 'impt' => 'non'),
255 array(),
256 'dump'
257 );
258 break;
259 }
260
261 $status['etape'] = 'fini';
262 ecrire_fichier($status_file, serialize($status));
263 }
264
265 /**
266 * Lister les fichiers de sauvegarde existant dans un repertoire
267 * trie par nom, date ou taille
268 *
269 * @param string $dir Repertoire de sauvegarde
270 * @param string $tri Tri pour recuperer les fichiers
271 * @param string $extension Extension des fichiers de sauvegarde
272 * @param int $limit Nombre max de fichiers listes
273 * @return array
274 */
275 function dump_lister_sauvegardes($dir, $tri = 'nom', $extension = 'sqlite', $limit = 100) {
276 $liste_dump = preg_files($dir, '\.' . $extension . '$', $limit, false);
277
278 $n = strlen($dir);
279 $tn = $tl = $tt = $td = array();
280 foreach ($liste_dump as $fichier) {
281 $d = filemtime($fichier);
282 $t = filesize($fichier);
283 $fichier = substr($fichier, $n);
284 $tl[] = array('fichier' => $fichier, 'taille' => $t, 'date' => $d);
285 $td[] = $d;
286 $tt[] = $t;
287 $tn[] = $fichier;
288 }
289 if ($tri == 'taille') {
290 array_multisort($tt, SORT_ASC, $tl);
291 } elseif ($tri == 'date') {
292 array_multisort($td, SORT_ASC, $tl);
293 } else {
294 array_multisort($tn, SORT_ASC, $tl);
295 }
296
297 return $tl;
298 }
299
300 /**
301 * Extraire le statut contenu dans un fichier
302 *
303 * @param $status_file Nom du fichier stocke dans _DIR_TMP
304 * @return array
305 */
306 function dump_lire_status($status_file) {
307 $status_file = _DIR_TMP . basename($status_file) . '.txt';
308 if (!lire_fichier($status_file, $status)
309 or !$status = unserialize($status)
310 ) {
311 return '';
312 }
313
314 return $status;
315 }
316
317 /**
318 * Verifier qu'un sauvegarde est finie
319 *
320 * @param $status_file Nom du fichier stocke dans _DIR_TMP
321 * @return string Chaine non vide s'il reste des choses a faire
322 */
323 function dump_verifie_sauvegarde_finie($status_file) {
324 if (!$status = dump_lire_status($status_file)
325 or $status['etape'] !== 'fini'
326 ) {
327 return '';
328 }
329
330 return ' ';
331 }
332
333 /**
334 * Recuperer le nom du fichier d'archivage qui est memorise dans le fichier de statut
335 *
336 * @param $status_file Nom du fichier stocke dans _DIR_TMP
337 * @return string Nom ou chaine vide si on a un probleme
338 */
339 function dump_nom_sauvegarde($status_file) {
340 if (!$status = dump_lire_status($status_file)
341 or !file_exists($f = $status['archive'] . '.sqlite')
342 ) {
343 return '';
344 }
345
346 return $f;
347 }
348
349 /**
350 * Recuperer la taille du fichier de sauvegarde
351 *
352 * @param $status_file Nom du fichier stocke dans _DIR_TMP
353 * @return string/int Taille ou Chaine vide en cas de probleme
354 */
355 function dump_taille_sauvegarde($status_file) {
356 if (!$f = dump_nom_sauvegarde($status_file)
357 or !$s = filesize($f)
358 ) {
359 return '';
360 }
361
362 return $s;
363 }
364
365 /**
366 * Recuperer la date de derniere modification du fichier de sauvegarde
367 *
368 * @param $status_file Nom du fichier stocke dans _DIR_TMP
369 * @return string/int Date ou Chaine vide en cas de probleme
370 */
371 function dump_date_sauvegarde($status_file) {
372 if (!$f = dump_nom_sauvegarde($status_file)
373 or !$d = filemtime($f)
374 ) {
375 return '';
376 }
377
378 return date('Y-m-d', $d);
379 }