PageRenderTime 63ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/spip/ecrire/inc/import.php

https://github.com/eyeswebcrea/espace-couture-sittler.fr
PHP | 501 lines | 373 code | 47 blank | 81 comment | 64 complexity | 78c3c4722d199f03ed2b40be64583833 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2011 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. if (!defined('_ECRIRE_INC_VERSION')) return;
  12. include_spip('inc/presentation');
  13. include_spip('inc/acces');
  14. include_spip('base/abstract_sql');
  15. // Retourne la premiere balise XML figurant dans le buffet de la sauvegarde
  16. // et avance dans ce buffet jusqu'au '>' de cette balise.
  17. // Si le 2e argument (passe par reference) est non vide
  18. // ce qui precede cette balise y est mis.
  19. // Les balises commencant par <! sont ignorees
  20. // $abs_pos est globale pour pouvoir etre reinitialisee a la meta
  21. // restauration_status en cas d'interruption sur TimeOut.
  22. // Evite au maximum les recopies
  23. // http://doc.spip.org/@xml_fetch_tag
  24. function xml_fetch_tag($f, &$before, $_fread='fread', $skip='!') {
  25. global $abs_pos;
  26. static $buf='';
  27. static $ent = array('&gt;','&lt;','&amp;');
  28. static $brut = array('>','<','&');
  29. while (($b=strpos($buf,'<'))===false) {
  30. if (!($x = $_fread($f, 1024))) return '';
  31. if ($before)
  32. $buf .= $x;
  33. else {
  34. if (_DEBUG_IMPORT)
  35. $GLOBALS['debug_import_avant'] .= $buf;
  36. $abs_pos += strlen($buf);
  37. $buf = $x;
  38. }
  39. }
  40. if ($before) $before = str_replace($ent,$brut,substr($buf,0,$b));
  41. # else { spip_log("position: $abs_pos" . substr($buf,0,12));flush();}
  42. // $b pour ignorer un > de raccourci Spip avant un < de balise XML
  43. while (($e=strpos($buf,'>', $b))===false) {
  44. if (!($x = $_fread($f, 1024))) return '';
  45. $buf .= $x;
  46. }
  47. if ($buf[++$b]!=$skip) {
  48. if (_DEBUG_IMPORT){
  49. $GLOBALS['debug_import_avant'] .= substr($buf,0,$e+1);
  50. $GLOBALS['debug_import_avant'] = substr($GLOBALS['debug_import_avant'],-1024);
  51. }
  52. $tag = substr($buf, $b, $e-$b);
  53. $buf = substr($buf,++$e);
  54. if (_DEBUG_IMPORT)
  55. $GLOBALS['debug_import_apres'] = $buf;
  56. $abs_pos += $e;
  57. return $tag;
  58. }
  59. if (_DEBUG_IMPORT)
  60. $GLOBALS['debug_import_avant'] .= substr($buf,0,$e+1);
  61. $buf = substr($buf,++$e);
  62. if (_DEBUG_IMPORT)
  63. $GLOBALS['debug_import_apres'] = $buf;
  64. $abs_pos += $e;
  65. return xml_fetch_tag($f,$before,$_fread,$skip);
  66. }
  67. // http://doc.spip.org/@xml_parse_tag
  68. function xml_parse_tag($t) {
  69. preg_match(',^([\w[?!%.;:-]*),s', $t, $res);
  70. $t = substr($t,strlen($res[0]));
  71. $res[1] = array();
  72. // pourquoi on ne peut pas mettre \3 entre crochets ?
  73. if (preg_match_all(',\s*(--.*?--)?\s*([^=]*)\s*=\s*([\'"])([^"]*)\3,sS', $t, $m, PREG_SET_ORDER)) {
  74. foreach($m as $r) $res[1][$r[2]] = $r[4];
  75. }
  76. return $res;
  77. }
  78. /**
  79. * Lire l'entete du fichier importe
  80. * Balise ouvrante:
  81. * 'SPIP' si fait par spip, nom de la base source si fait par phpmyadmin
  82. *
  83. * @param resource $f
  84. * @param string $gz
  85. * @return array
  86. */
  87. function import_debut($f, $gz='fread') {
  88. // Pour les anciennes archives, indiquer le charset par defaut:
  89. $charset = 'iso-8859-1';
  90. // les + recentes l'ont en debut de ce fichier
  91. $flag_phpmyadmin = false;
  92. $b = false;
  93. while ($t = xml_fetch_tag($f, $b, $gz, '')) {
  94. $r = xml_parse_tag($t);
  95. if ($r[0] == '?xml' AND $r[1]['encoding'])
  96. $charset = strtolower($r[1]['encoding']);
  97. elseif ($r[0] == "SPIP") {$r[2] = $charset; return $r;}
  98. if (($r[0] == "!--") && (preg_match(",phpmyadmin\sxml\sdump,is",$r[1]))){
  99. // c'est un dump xml phpmyadmin
  100. // on interprete le commentaire pour recuperer la version de phpmydadmin
  101. $version = preg_replace(",(.*?)version\s*([0-9a-z\.\-]*)\s(.*),is","\\2",$r[1]);
  102. $flag_phpmyadmin = true;
  103. }
  104. if (($r[0] != "!--") && ($flag_phpmyadmin == true)){
  105. $r[1] = array('version_archive'=>"phpmyadmin::$version");
  106. $r[2] = $charset;
  107. return $r;
  108. }
  109. }
  110. }
  111. // on conserve ce tableau pour faire des translations
  112. // de table eventuelles
  113. $tables_trans = array(
  114. );
  115. // http://doc.spip.org/@import_init_tables
  116. function import_init_tables($request){
  117. global $connect_id_auteur;
  118. // commencer par verifier les meta et le champ impt=non
  119. $config = charger_fonction('config','inc');
  120. $config();
  121. // grand menage
  122. // on vide toutes les tables dont la restauration est demandee
  123. list($tables,) = base_liste_table_for_dump(lister_tables_noerase());
  124. spip_log(count($tables) . " tables effacees " . join(', ', $tables),'import');
  125. foreach($tables as $table){
  126. // regarder si il y a au moins un champ impt='non'
  127. if (($table!='spip_auteurs')){
  128. $desc = description_table($table);
  129. if (isset($desc['field']['impt']))
  130. sql_delete($table, "impt='oui'");
  131. else
  132. sql_delete($table);
  133. }
  134. }
  135. // Bidouille pour garder l'acces admin actuel pendant toute la restauration
  136. sql_delete("spip_auteurs", "id_auteur=0");
  137. sql_updateq('spip_auteurs', array('id_auteur'=>0, 'extra'=>$connect_id_auteur), "id_auteur=$connect_id_auteur");
  138. sql_delete("spip_auteurs", "id_auteur!=0");
  139. // retourner la liste des tables a importer, pas celle des tables videes !
  140. return import_table_choix($request);
  141. }
  142. // Effacement de la bidouille ci-dessus
  143. // Toutefois si la table des auteurs ne contient plus qu'elle
  144. // c'est que la sauvegarde etait incomplete et on restaure le compte
  145. // pour garder la connection au site (mais il doit pas etre bien beau)
  146. // http://doc.spip.org/@detruit_restaurateur
  147. function detruit_restaurateur()
  148. {
  149. if (sql_countsel("spip_auteurs", "id_auteur<>0"))
  150. sql_delete("spip_auteurs", "id_auteur=0");
  151. else {
  152. sql_update('spip_auteurs', array('id_auteur'=>'extra'), "id_auteur=0");
  153. }
  154. }
  155. // http://doc.spip.org/@import_tables
  156. function import_tables($request, $archive) {
  157. global $import_ok, $abs_pos, $affiche_progression_pourcent;
  158. // regarder si on est pas en train d'importer dans une copie des tables
  159. if (isset($GLOBALS['meta']['restauration_table_prefix'])) {
  160. $charger = charger_fonction('charger','maj/vieille_base');
  161. $charger($GLOBALS['meta']['vieille_version_installee']);
  162. $GLOBALS['serveur_vieille_base'] = 0;
  163. $prefix = $GLOBALS['connexions'][$GLOBALS['serveur_vieille_base']]['prefixe'];
  164. $GLOBALS['connexions'][$GLOBALS['serveur_vieille_base']]['prefixe'] = $GLOBALS['meta']['restauration_table_prefix'];
  165. // verifier qu'une table meta existe bien
  166. // sinon c'est une restauration anterieure echouee
  167. if (!sql_getfetsel('valeur','spip_meta','','','','0,1')){
  168. $GLOBALS['connexions'][$GLOBALS['serveur_vieille_base']]['prefixe'] = $prefix;
  169. return;
  170. }
  171. // recharger les metas
  172. lire_metas();
  173. }
  174. $abs_pos = (!isset($GLOBALS['meta']["restauration_status"])) ? 0 :
  175. $GLOBALS['meta']["restauration_status"];
  176. // au premier appel destruction des tables a restaurer
  177. // ou initialisation de la table des translations,
  178. // mais pas lors d'une reprise.
  179. if ($request['insertion']=='on') {
  180. include_spip('inc/import_insere');
  181. $request['init'] = (!$abs_pos) ? 'insere_1_init' : 'insere_1bis_init';
  182. $request['boucle'] = 'import_insere';
  183. } elseif ($request['insertion']=='passe2') {
  184. $request['init'] = 'insere_2_init';
  185. $request['boucle'] = 'import_translate';
  186. } else {
  187. $request['init'] = (!$abs_pos) ? 'import_init_tables' : 'import_table_choix';
  188. $request['boucle'] = 'import_replace';
  189. }
  190. if (strncmp(".gz", substr($archive,-3),3)==0) {
  191. $size = false;
  192. $taille = taille_en_octets($abs_pos);
  193. $file = gzopen($archive, 'rb');
  194. $gz = 'gzread';
  195. } else {
  196. $size = @filesize($archive);
  197. $taille = @floor(100 * $abs_pos / $size)." %";
  198. $file = fopen($archive, 'rb');
  199. $gz = 'fread';
  200. }
  201. if ($abs_pos==0) {
  202. list($tag, $atts, $charset) = import_debut($file, $gz);
  203. // improbable: fichier correct avant debut_admin et plus apres
  204. if (!$tag) return !($import_ok = true);
  205. $version_archive = import_init_meta($tag, $atts, $charset, $request);
  206. } else {
  207. $version_archive = $GLOBALS['meta']['restauration_version_archive'];
  208. $atts = unserialize($GLOBALS['meta']['restauration_attributs_archive']);
  209. spip_log("Reprise de l'importation interrompue en $abs_pos");
  210. $_fseek = ($gz=='gzread') ? 'gzseek' : 'fseek';
  211. $_fseek($file, $abs_pos);
  212. }
  213. // placer la connexion sql dans le bon charset
  214. if (isset($GLOBALS['meta']['restauration_charset_sql_connexion']))
  215. sql_set_charset($GLOBALS['meta']['restauration_charset_sql_connexion']);
  216. if (!defined('_DEBUG_IMPORT')) define('_DEBUG_IMPORT', false);
  217. if (_DEBUG_IMPORT)
  218. ecrire_fichier(_DIR_TMP."debug_import.log","#####".date('Y-m-d H:i:s')."\n",false,false);
  219. $fimport = import_charge_version($version_archive);
  220. if ($request['insertion'] !== 'passe2')
  221. import_affiche_javascript($taille);
  222. if (function_exists('ob_flush')) @ob_flush();
  223. flush();
  224. $oldtable ='';
  225. $cpt = 0;
  226. $pos = $abs_pos;
  227. // BOUCLE principale qui tourne en rond jusqu'a le fin du fichier
  228. while ($table = $fimport($file, $request, $gz, $atts)) {
  229. // memoriser pour pouvoir reprendre en cas d'interrupt,
  230. // mais pas d'ecriture sur fichier, ca ralentit trop
  231. ecrire_meta("restauration_status", "$abs_pos",'non');
  232. if ($oldtable != $table) {
  233. if (_DEBUG_IMPORT){
  234. ecrire_fichier(_DIR_TMP."debug_import.log","----\n".$GLOBALS['debug_import_avant']."\n<<<<\n$table\n>>>>\n".$GLOBALS['debug_import_apres']."\n----\n",false,false);
  235. }
  236. if ($oldtable) spip_log("$cpt entrees","import");
  237. spip_log("Analyse de $table (commence en $pos)","import");
  238. affiche_progression_javascript($abs_pos,$size,$table);
  239. $oldtable = $table;
  240. $cpt = 0;
  241. $pos = $abs_pos;
  242. }
  243. $cpt++;
  244. }
  245. spip_log("$cpt entrees","import");
  246. spip_log("fin de l'archive, statut: " .($import_ok ? 'ok' : 'alert'),"import");
  247. if (!$import_ok)
  248. return _T('avis_archive_invalide') . ' ' .
  249. _T('taille_octets', array('taille' => $pos)) ;
  250. if ($GLOBALS['spip_version_base'] != (str_replace(',','.',$GLOBALS['meta']['version_installee']))){
  251. // il FAUT recharger les bonnes desc serial/aux avant ...
  252. include_spip('base/serial');
  253. $GLOBALS['tables_principales']=array();
  254. base_serial($GLOBALS['tables_principales']);
  255. include_spip('base/auxiliaires');
  256. $GLOBALS['tables_auxiliaires']=array();
  257. base_auxiliaires($GLOBALS['tables_auxiliaires']);
  258. $GLOBALS['tables_jointures']=array();
  259. include_spip('public/interfaces');
  260. declarer_interfaces();
  261. include_spip('base/upgrade');
  262. maj_base(); // upgrade jusqu'a la version courante
  263. }
  264. // regarder si on est pas en train d'importer dans une copie des tables
  265. if (isset($GLOBALS['meta']['restauration_table_prefix_source'])){
  266. $prefixe_source = $GLOBALS['meta']['restauration_table_prefix_source'];
  267. $GLOBALS['connexions']['-1'] = $GLOBALS['connexions'][0];
  268. // rebasculer le serveur sur les bonnes tables pour finir proprement
  269. $GLOBALS['connexions'][0]['prefixe'] = $prefixe_source;
  270. // et relire les meta de la bonne base
  271. lire_metas();
  272. $tables_recopiees = isset($GLOBALS['meta']['restauration_recopie_tables'])?unserialize($GLOBALS['meta']['restauration_recopie_tables']):array();
  273. spip_log("charge tables_recopiees ".serialize($tables_recopiees),'dbdump');
  274. // recopier les tables l'une sur l'autre
  275. // il FAUT recharger les bonnes desc serial/aux avant ...
  276. include_spip('base/serial');
  277. $GLOBALS['tables_principales']=array();
  278. base_serial($GLOBALS['tables_principales']);
  279. include_spip('base/auxiliaires');
  280. $GLOBALS['tables_auxiliaires']=array();
  281. base_auxiliaires($GLOBALS['tables_auxiliaires']);
  282. $GLOBALS['tables_jointures']=array();
  283. include_spip('public/interfaces');
  284. declarer_interfaces();
  285. // puis relister les tables a importer
  286. // et les vider si besoin, au moment du premier passage ici
  287. // (et seulement si ce n'est pas une fusion, comment le dit-on ?)
  288. $initialisation_copie = (!isset($GLOBALS['meta']["restauration_status_copie"])) ? 0 :
  289. $GLOBALS['meta']["restauration_status_copie"];
  290. if (!$initialisation_copie) {
  291. // vide les tables qui le necessitent
  292. $tables = import_init_tables($request);
  293. ecrire_meta("restauration_status_copie", "ok",'non');
  294. }
  295. else
  296. // la liste des tables a recopier
  297. $tables = import_table_choix($request);
  298. # var_dump($tables);die();
  299. spip_log("tables a copier :".implode(", ",$tables),'dbdump');
  300. if (in_array('spip_auteurs',$tables)){
  301. $tables = array_diff($tables,array('spip_auteurs'));
  302. $tables[] = 'spip_auteurs';
  303. }
  304. if (in_array('spip_meta',$tables)){
  305. $tables = array_diff($tables,array('spip_meta'));
  306. $tables[] = 'spip_meta';
  307. }
  308. sql_drop_table('spip_test','','-1');
  309. foreach ($tables as $table){
  310. if (sql_showtable($table,true,-1)){
  311. if (!isset($tables_recopiees[$table])) $tables_recopiees[$table] = 0;
  312. if ($tables_recopiees[$table]!==-1){
  313. affiche_progression_javascript(0,0,$table);
  314. while (true) {
  315. $n = intval($tables_recopiees[$table]);
  316. $res = sql_select('*',$table,'','','',"$n,400",'','-1');
  317. while ($row = sql_fetch($res,'-1')){
  318. array_walk($row,'sql_quote');
  319. sql_replace($table,$row);
  320. $tables_recopiees[$table]++;
  321. }
  322. if ($n == $tables_recopiees[$table])
  323. break;
  324. spip_log("recopie $table ".$tables_recopiees[$table],'dbdump');
  325. affiche_progression_javascript($tables_recopiees[$table],0,$table);
  326. ecrire_meta('restauration_recopie_tables',serialize($tables_recopiees));
  327. }
  328. sql_drop_table($table,'','-1');
  329. spip_log("drop $table",'dbdump');
  330. $tables_recopiees[$table]=-1;
  331. ecrire_meta('restauration_recopie_tables',serialize($tables_recopiees));
  332. spip_log("tables_recopiees ".serialize($tables_recopiees),'dbdump');
  333. }
  334. }
  335. }
  336. }
  337. // recharger les metas
  338. lire_metas();
  339. #die();
  340. return '' ;
  341. }
  342. // http://doc.spip.org/@import_init_meta
  343. function import_init_meta($tag, $atts, $charset, $request)
  344. {
  345. $version_archive = $atts['version_archive'];
  346. $version_base = $atts['version_base'];
  347. $insert = $request['insertion'] ;
  348. $old = (!$insert
  349. && version_compare($version_base,$GLOBALS['spip_version_base'],'<')
  350. && !isset($GLOBALS['meta']['restauration_table_prefix']));
  351. if ($old) {
  352. // creer une base avec les tables dans l'ancienne version
  353. // et changer de contexte
  354. $creer_base_anterieure = charger_fonction('create','maj/vieille_base');
  355. $creer_base_anterieure($version_base);
  356. }
  357. if ($old OR $insert) {
  358. $init = $request['init'];
  359. spip_log("import_init_meta lance $init","import");
  360. $init($request);
  361. }
  362. ecrire_meta('restauration_attributs_archive', serialize($atts),'non');
  363. ecrire_meta('restauration_version_archive', $version_archive,'non');
  364. ecrire_meta('restauration_tag_archive', $tag,'non');
  365. // trouver le charset de la connexion sql qu'il faut utiliser pour la restauration
  366. // ou si le charset de la base est iso-xx
  367. // (on ne peut garder une connexion utf dans ce cas)
  368. // on laisse sql gerer la conversion de charset !
  369. if (isset($GLOBALS['meta']['charset_sql_connexion'])
  370. OR (strncmp($charset,'iso-',4)==0)
  371. ){
  372. include_spip('base/abstract_sql');
  373. if ($sql_char = sql_get_charset($charset)){
  374. $sql_char = $sql_char['charset'];
  375. ecrire_meta('restauration_charset_sql_connexion',$sql_char);
  376. }
  377. else {
  378. // faire la conversion de charset en php :(
  379. effacer_meta('restauration_charset_sql_connexion'); # precaution
  380. spip_log("charset de restauration inconnu de sql : $charset");
  381. if ($insert)
  382. ecrire_meta('charset_insertion', $charset,'non');
  383. else ecrire_meta('charset_restauration', $charset,'non');
  384. }
  385. }
  386. $i = $insert ? ("insertion $insert") : '';
  387. spip_log("Debut de l'importation (charset: $charset, format: $version_archive) $i");
  388. return $version_archive;
  389. }
  390. // http://doc.spip.org/@import_affiche_javascript
  391. function import_affiche_javascript($taille)
  392. {
  393. $max_time = ini_get('max_execution_time')*1000;
  394. $t = _T('info_recharger_page');
  395. $t = "
  396. <input type='text' size='10' name='taille' id='taille' value='$taille' />
  397. <input type='text' class='forml' name='recharge' id='recharge' value='$t' />";
  398. echo debut_boite_alerte(),
  399. "<span style='color: black;' class='verdana1 spip_large'><b>", _T('info_base_restauration'), "</b></span>",
  400. generer_form_ecrire('', $t, " style='text-align: center' name='progression' id='progression' method='get' "),
  401. fin_boite_alerte();
  402. }
  403. // http://doc.spip.org/@affiche_progression_javascript
  404. function affiche_progression_javascript($abs_pos,$size, $table="") {
  405. include_spip('inc/charsets');
  406. echo "\n<script type='text/javascript'><!--\n";
  407. if ($abs_pos == '100 %') {
  408. echo "document.progression.taille.value='$abs_pos';\n";
  409. if ($x = $GLOBALS['erreur_restauration']) {
  410. echo "document.progression.recharge.value='".str_replace("'", "\\'", unicode_to_javascript(html2unicode(_T('avis_erreur').": $x")))." ';\n";
  411. }
  412. else {
  413. echo "document.progression.recharge.value='".str_replace("'", "\\'", unicode_to_javascript(html2unicode(_T('info_fini'))))."';\n";
  414. echo "window.setTimeout('location.href=\"".self()."\";',0);";
  415. }
  416. }
  417. else {
  418. if (trim($table))
  419. echo "document.progression.recharge.value='$table';\n";
  420. if (!$size)
  421. $taille = preg_replace("/&nbsp;/", " ", taille_en_octets($abs_pos));
  422. else
  423. $taille = floor(100 * $abs_pos / $size)." %";
  424. echo "document.progression.taille.value='$taille';\n";
  425. }
  426. echo "\n--></script>\n";
  427. if (function_exists('ob_flush')) @ob_flush();
  428. flush();
  429. }
  430. // http://doc.spip.org/@import_table_choix
  431. function import_table_choix($request){
  432. spip_log("noimport:".implode(',',lister_tables_noimport()),'noimport');
  433. list($tables,) = base_liste_table_for_dump(lister_tables_noimport());
  434. spip_log("liste:".implode(',',$tables),'noimport');
  435. return $tables;
  436. }
  437. ?>