c3806dc9c3cc7603fa252caed5ae39d351c21f77
[velocampus/web/www.git] / www / ecrire / inc / revisions.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2014 *
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 $GLOBALS['agregation_versions'] = 10;
16 define('_INTERVALLE_REVISIONS', 3600); // intervalle de temps separant deux revisions par un meme auteur
17
18 // http://doc.spip.org/@separer_paras
19 function separer_paras($texte, $paras = "") {
20 if (!$paras) $paras = array();
21 while (preg_match("/(\r\n?){2,}|\n{2,}/", $texte, $regs)) {
22 $p = strpos($texte, $regs[0]) + strlen($regs[0]);
23 $paras[] = substr($texte, 0, $p);
24 $texte = substr($texte, $p);
25 }
26 if ($texte) $paras[] = $texte;
27 return $paras;
28 }
29
30 // http://doc.spip.org/@replace_fragment
31 function replace_fragment($id_article, $version_min, $version_max, $id_fragment, $fragment) {
32 $fragment = serialize($fragment);
33 $compress = 0;
34
35 // pour le portage en PG il faut l'equivalente au mysql_escape_string
36 // et deporter son appel dans les fonctions d'abstraction.
37 if (function_exists('gzcompress')
38 AND $GLOBALS['connexions'][0]['type'] == 'mysql') {
39 $s = gzcompress($fragment);
40 if (strlen($s) < strlen($fragment)) {
41 # spip_log("gain gz: ".intval(100 - 100 * strlen($s) / strlen($fragment)));
42 $compress = 1;
43 $fragment = $s;
44 }
45 }
46
47 // Attention a echapper $fragment, binaire potentiellement gz
48 return array(
49 'id_article' => intval($id_article),
50 'id_fragment' => intval($id_fragment),
51 'version_min' => intval($version_min),
52 'version_max' => intval($version_max),
53 'compress' => $compress,
54 'fragment' => $fragment);
55 }
56
57 // http://doc.spip.org/@envoi_replace_fragments
58 function envoi_replace_fragments($replaces) {
59 $desc = $GLOBALS['tables_auxiliaires']['spip_versions_fragments'];
60 foreach($replaces as $r)
61 sql_replace('spip_versions_fragments', $r, $desc);
62 }
63
64
65 // http://doc.spip.org/@envoi_delete_fragments
66 function envoi_delete_fragments($id_article, $deletes) {
67 if (count($deletes)) {
68 sql_delete("spip_versions_fragments", "id_article=$id_article AND ((". join(") OR (", $deletes)."))");
69 }
70 }
71
72
73 //
74 // Ajouter les fragments de la derniere version (tableau associatif id_fragment => texte)
75 //
76 // http://doc.spip.org/@ajouter_fragments
77 function ajouter_fragments($id_article, $id_version, $fragments) {
78 global $agregation_versions;
79
80 $replaces = array();
81 foreach ($fragments as $id_fragment => $texte) {
82 $nouveau = true;
83 // Recuperer la version la plus recente
84 $row = sql_fetsel("compress, fragment, version_min, version_max", "spip_versions_fragments", "id_article=$id_article AND id_fragment=$id_fragment AND version_min<=$id_version", "", "version_min DESC", "1");
85
86 if ($row) {
87 $fragment = $row['fragment'];
88 $version_min = $row['version_min'];
89 if ($row['compress'] > 0) $fragment = @gzuncompress($fragment);
90 $fragment = unserialize($fragment);
91 if (is_array($fragment)) {
92 unset($fragment[$id_version]);
93 // Si le fragment n'est pas trop gros, prolonger celui-ci
94 $nouveau = count($fragment) >= $agregation_versions
95 && strlen($row['fragment']) > 1000;
96 }
97 }
98 if ($nouveau) {
99 $fragment = array($id_version => $texte);
100 $version_min = $id_version;
101 }
102 else {
103 // Ne pas dupliquer les fragments non modifies
104 $modif = true;
105 for ($i = $id_version - 1; $i >= $version_min; $i--) {
106 if (isset($fragment[$i])) {
107 $modif = ($fragment[$i] != $texte);
108 break;
109 }
110 }
111 if ($modif) $fragment[$id_version] = $texte;
112 }
113
114 // Preparer l'enregistrement du fragment
115 $replaces[] = replace_fragment($id_article, $version_min, $id_version, $id_fragment, $fragment);
116 }
117
118 envoi_replace_fragments($replaces);
119 }
120
121 //
122 // Supprimer tous les fragments d'un article lies a un intervalle de versions
123 // (essaie d'eviter une trop grande fragmentation)
124 //
125 // http://doc.spip.org/@supprimer_fragments
126 function supprimer_fragments($id_article, $version_debut, $version_fin) {
127 global $agregation_versions;
128
129 $replaces = array();
130 $deletes = array();
131
132 // D'abord, vider les fragments inutiles
133 sql_delete("spip_versions_fragments", "id_article=$id_article AND version_min>=$version_debut AND version_max<=$version_fin");
134
135
136 // Fragments chevauchant l'ensemble de l'intervalle, s'ils existent
137 $result = sql_select("id_fragment, compress, fragment, version_min, version_max", "spip_versions_fragments", "id_article=$id_article AND version_min<$version_debut AND version_max>$version_fin");
138
139 while ($row = sql_fetch($result)) {
140 $id_fragment = $row['id_fragment'];
141 $fragment = $row['fragment'];
142 if ($row['compress'] > 0) $fragment = gzuncompress($fragment);
143 $fragment = unserialize($fragment);
144 for ($i = $version_fin; $i >= $version_debut; $i--) {
145 if (isset($fragment[$i])) {
146 // Recopier le dernier fragment si implicite
147 if (!isset($fragment[$version_fin + 1]))
148 $fragment[$version_fin + 1] = $fragment[$i];
149 unset($fragment[$i]);
150 }
151 }
152
153 $replaces[] = replace_fragment($id_article,
154 $row['version_min'], $row['version_max'], $id_fragment, $fragment);
155 }
156
157 // Fragments chevauchant le debut de l'intervalle, s'ils existent
158 $result = sql_select("id_fragment, compress, fragment, version_min, version_max", "spip_versions_fragments", "id_article=$id_article AND version_min<$version_debut AND version_max>=$version_debut AND version_max<=$version_fin");
159
160 $deb_fragment = array();
161 while ($row = sql_fetch($result)) {
162 $id_fragment = $row['id_fragment'];
163 $fragment = $row['fragment'];
164 $version_min = $row['version_min'];
165 $version_max = $row['version_max'];
166 if ($row['compress'] > 0) $fragment = gzuncompress($fragment);
167 $fragment = unserialize($fragment);
168 for ($i = $version_debut; $i <= $version_max; $i++) {
169 if (isset($fragment[$i])) unset($fragment[$i]);
170 }
171
172 // Stocker temporairement le fragment pour agregation
173 $deb_fragment[$id_fragment] = $fragment;
174 // Ajuster l'intervalle des versions
175 $deb_version_min[$id_fragment] = $version_min;
176 $deb_version_max[$id_fragment] = $version_debut - 1;
177 }
178
179 // Fragments chevauchant la fin de l'intervalle, s'ils existent
180 $result = sql_select("id_fragment, compress, fragment, version_min, version_max", "spip_versions_fragments", "id_article=$id_article AND version_max>$version_fin AND version_min>=$version_debut AND version_min<=$version_fin");
181
182 while ($row = sql_fetch($result)) {
183 $id_fragment = $row['id_fragment'];
184 $fragment = $row['fragment'];
185 $version_min = $row['version_min'];
186 $version_max = $row['version_max'];
187 if ($row['compress'] > 0) $fragment = gzuncompress($fragment);
188 $fragment = unserialize($fragment);
189 for ($i = $version_fin; $i >= $version_min; $i--) {
190 if (isset($fragment[$i])) {
191 // Recopier le dernier fragment si implicite
192 if (!isset($fragment[$version_fin + 1]))
193 $fragment[$version_fin + 1] = $fragment[$i];
194 unset($fragment[$i]);
195 }
196 }
197
198 // Virer l'ancien enregistrement (la cle primaire va changer)
199 $deletes[] = "id_fragment=$id_fragment AND version_min=$version_min";
200 // Essayer l'agregation
201 $agreger = false;
202 if (isset($deb_fragment[$id_fragment])) {
203 $agreger = (count($deb_fragment[$id_fragment]) + count($fragment) <= $agregation_versions);
204 if ($agreger) {
205 $fragment = $deb_fragment[$id_fragment] + $fragment;
206 $version_min = $deb_version_min[$id_fragment];
207 }
208 else {
209 $replaces[] = replace_fragment($id_article,
210 $deb_version_min[$id_fragment], $deb_version_max[$id_fragment],
211 $id_fragment, $deb_fragment[$id_fragment]);
212 }
213 unset($deb_fragment[$id_fragment]);
214 }
215 if (!$agreger) {
216 // Ajuster l'intervalle des versions
217 $version_min = $version_fin + 1;
218 }
219 $replaces[] = replace_fragment($id_article, $version_min, $version_max, $id_fragment, $fragment);
220 }
221
222 // Ajouter fragments restants
223 if (is_array($deb_fragment) && count($deb_fragment) > 0) {
224 foreach ($deb_fragment as $id_fragment => $fragment) {
225 $replaces[] = replace_fragment($id_article,
226 $deb_version_min[$id_fragment], $deb_version_max[$id_fragment],
227 $id_fragment, $deb_fragment[$id_fragment]);
228 }
229 }
230
231 envoi_replace_fragments($replaces);
232 envoi_delete_fragments($id_article, $deletes);
233 }
234
235 //
236 // Recuperer les fragments d'une version donnee
237 // renvoie un tableau associatif (id_fragment => texte)
238 //
239 // http://doc.spip.org/@recuperer_fragments
240 function recuperer_fragments($id_article, $id_version) {
241 $fragments = array();
242
243 if ($id_version == 0) return array();
244
245 $result = sql_select("id_fragment, version_min, version_max, compress, fragment", "spip_versions_fragments", "id_article=$id_article AND version_min<=$id_version AND version_max>=$id_version");
246
247 while ($row = sql_fetch($result)) {
248 $id_fragment = $row['id_fragment'];
249 $version_min = $row['version_min'];
250 $fragment = $row['fragment'];
251 if ($row['compress'] > 0){
252 $fragment_ = @gzuncompress($fragment);
253 if (strlen($fragment) && $fragment_===false)
254 $fragment=serialize(array($row['version_max']=>"["._T('forum_titre_erreur').$id_fragment."]"));
255 else
256 $fragment = $fragment_;
257 }
258 $fragment_ = unserialize($fragment);
259 if (strlen($fragment) && $fragment_===false)
260 $fragment=array($row['version_max']=>"["._T('forum_titre_erreur').$id_fragment."]");
261 else
262 $fragment = $fragment_;
263 for ($i = $id_version; $i >= $version_min; $i--) {
264 if (isset($fragment[$i])) {
265
266 ## hack destine a sauver les archives des sites iso-8859-1
267 ## convertis en utf-8 (les archives ne sont pas converties
268 ## mais ce code va les nettoyer ; pour les autres charsets
269 ## la situation n'est pas meilleure ni pire qu'avant)
270 if ($GLOBALS['meta']['charset'] == 'utf-8'
271 AND include_spip('inc/charsets')
272 AND !is_utf8($fragment[$i])) {
273 $fragment[$i] = importer_charset($fragment[$i], 'iso-8859-1');
274 }
275
276 $fragments[$id_fragment] = $fragment[$i];
277 break;
278 }
279 }
280 }
281 return $fragments;
282 }
283
284
285 //
286 // Apparier des paragraphes deux a deux entre une version originale
287 // et une version modifiee
288 //
289 // http://doc.spip.org/@apparier_paras
290 function apparier_paras($src, $dest, $flou = true) {
291 $src_dest = array();
292 $dest_src = array();
293
294 $t1 = $t2 = array();
295
296 $md1 = $md2 = array();
297 $gz_min1 = $gz_min2 = array();
298 $gz_trans1 = $gz_trans2 = array();
299 $l1 = $l2 = array();
300
301 // Nettoyage de la ponctuation pour faciliter l'appariement
302 foreach($src as $key => $val) {
303 $t1[$key] = strval(preg_replace("/[[:punct:][:space:]]+/", " ", $val));
304 }
305 foreach($dest as $key => $val) {
306 $t2[$key] = strval(preg_replace("/[[:punct:][:space:]]+/", " ", $val));
307 }
308
309 // Premiere passe : chercher les correspondance exactes
310 foreach($t1 as $key => $val) $md1[$key] = md5($val);
311 foreach($t2 as $key => $val) $md2[md5($val)][$key] = $key;
312 foreach($md1 as $key1 => $h) {
313 if (isset($md2[$h])) {
314 $key2 = reset($md2[$h]);
315 if ($t1[$key1] == $t2[$key2]) {
316 $src_dest[$key1] = $key2;
317 $dest_src[$key2] = $key1;
318 unset($t1[$key1]);
319 unset($t2[$key2]);
320 unset($md2[$h][$key2]);
321 }
322 }
323 }
324
325 if ($flou) {
326 // Deuxieme passe : recherche de correlation par test de compressibilite
327 foreach($t1 as $key => $val) {
328 $l1[$key] = strlen(gzcompress($val));
329 }
330 foreach($t2 as $key => $val) {
331 $l2[$key] = strlen(gzcompress($val));
332 }
333 foreach($t1 as $key1 => $s1) {
334 foreach($t2 as $key2 => $s2) {
335 $r = strlen(gzcompress($s1.$s2));
336 $taux = 1.0 * $r / ($l1[$key1] + $l2[$key2]);
337 if (!$gz_min1[$key1] || $gz_min1[$key1] > $taux) {
338 $gz_min1[$key1] = $taux;
339 $gz_trans1[$key1] = $key2;
340 }
341 if (!$gz_min2[$key2] || $gz_min2[$key2] > $taux) {
342 $gz_min2[$key2] = $taux;
343 $gz_trans2[$key2] = $key1;
344 }
345 }
346 }
347
348 // Depouiller les resultats de la deuxieme passe :
349 // ne retenir que les correlations reciproques
350 foreach($gz_trans1 as $key1 => $key2) {
351 if ($gz_trans2[$key2] == $key1 && $gz_min1[$key1] < 0.9) {
352 $src_dest[$key1] = $key2;
353 $dest_src[$key2] = $key1;
354 }
355 }
356 }
357
358 // Retourner les mappings
359 return array($src_dest, $dest_src);
360 }
361
362 //
363 // Recuperer les champs d'une version donnee
364 //
365 // http://doc.spip.org/@recuperer_version
366 function recuperer_version($id_article, $id_version) {
367
368 $champs = sql_getfetsel("champs", "spip_versions", "id_article=" . intval($id_article) . " AND id_version=" . intval($id_version));
369 if (!$champs OR !is_array($champs = unserialize($champs)))
370 return array();
371 else return reconstuire_version($champs,
372 recuperer_fragments($id_article, $id_version));
373 }
374
375 // http://doc.spip.org/@reconstuire_version
376 function reconstuire_version($champs, $fragments, $res=array()) {
377
378 static $msg;
379 if (!$msg) $msg = _T('forum_titre_erreur');
380
381 foreach ($champs as $nom => $code) {
382 if (!isset($res[$nom])) {
383 $t = '';
384 foreach (array_filter(explode(' ', $code)) as $id) {
385 $t .= isset($fragments[$id])
386 ? $fragments[$id]
387 : "[$msg$id]";
388 }
389 $res[$nom] = $t;
390 }
391 }
392 return $res;
393 }
394
395 // http://doc.spip.org/@supprimer_versions
396 function supprimer_versions($id_article, $version_min, $version_max) {
397 sql_delete("spip_versions", "id_article=$id_article AND id_version>=$version_min AND id_version<=$version_max");
398
399 supprimer_fragments($id_article, $version_min, $version_max);
400 }
401
402 //
403 // Ajouter une version a un article
404 //
405 // http://doc.spip.org/@ajouter_version
406 function ajouter_version($id_article, $champs, $titre_version = "", $id_auteur) {
407 $paras = $paras_old = $paras_champ = $fragments = array();
408
409 // Attention a une edition anonyme (type wiki): id_auteur n'est pas
410 // definie, on enregistre alors le numero IP
411
412 $str_auteur = intval($id_auteur) ? intval($id_auteur) : $GLOBALS['ip'];
413 $permanent = empty($titre_version) ? 'non' : 'oui';
414
415 // Detruire les tentatives d'archivages non abouties en 1 heure
416
417 sql_delete('spip_versions', "id_article=$id_article AND id_version <= 0 AND date < DATE_SUB(".sql_quote(date('Y-m-d H:i:s')).", INTERVAL "._INTERVALLE_REVISIONS." SECOND)");
418
419 // Signaler qu'on opere en mettant un numero de version negatif
420 // distinctif (pour eviter la violation d'unicite)
421 // et un titre contenant en fait le moment de l'insertion
422
423 list($ms, $sec) = explode(' ', microtime());
424 $date = $sec . substr($ms,1,4); // SQL ne ramene que 4 chiffres significatifs apres la virgule pour 0.0+titre_version
425 $datediff = ($sec - mktime(0,0,0,9,1,2007)) * 1000000 + substr($ms,2, strlen($ms)-4);
426
427 $valeurs = array('id_article' => $id_article,
428 'id_version' => (0 - $datediff),
429 'date' => date('Y-m-d H:i:s'),
430 'id_auteur' => $str_auteur, // varchar ici!
431 'titre_version' => $date);
432
433 sql_insertq('spip_versions', $valeurs);
434
435 // Eviter les validations entremelees en s'endormant s'il existe
436 // une version <0 plus recente mais pas plus vieille que 10s
437 // Une <0 encore plus vieille est une operation avortee,
438 // on passe outre (vaut mieux archiver mal que pas du tout).
439 // Pour tester:
440 // 0. mettre le delai a 30
441 // 1. decommenter le premier sleep(15)
442 // 2. enregistrer une modif
443 // 3. recommenter le premier sleep(15), decommenter le second.
444 // 4. enregistrer une autre modif dans les 15 secondes
445 # sleep(15);
446 $delai = $sec-10;
447 while (sql_countsel('spip_versions', "id_article=$id_article AND id_version < 0 AND 0.0+titre_version < $date AND 0.0+titre_version > $delai")) {
448 spip_log("version $id_article :insertion en cours avant $date ($delai)");
449 sleep(1);
450 $delai++;
451 }
452 # sleep(15); spip_log("sortie $sec $delai");
453 // Determiner le numero du prochain fragment
454 $next = sql_fetsel("id_fragment", "spip_versions_fragments", "id_article=$id_article", "", "id_fragment DESC", "1");
455
456 $onlylock = '';
457
458 // Examiner la derniere version
459 $row = sql_fetsel("id_version, champs, id_auteur, date, permanent", "spip_versions", "id_article=$id_article AND id_version > 0", '', "id_version DESC", "1"); // le champ id_auteur est un varchar dans cette table
460
461 if ($row) {
462 $id_version = $row['id_version'];
463 $paras_old = recuperer_fragments($id_article, $id_version);
464 $champs_old = $row['champs'];
465 if ($row['id_auteur']!= $str_auteur
466 OR $row['permanent']=='oui'
467 OR strtotime($row['date']) < (time()-_INTERVALLE_REVISIONS)) {
468 $id_version++;
469
470 // version precedente recente, on va la mettre a jour
471 // avec les nouveaux arrivants si presents
472 } else {
473 $champs = reconstuire_version(unserialize($champs_old), $paras_old, $champs);
474 $onlylock = 're';
475 }
476 } else $id_version = 1;
477
478 $next = !$next ? 1 : ($next['id_fragment'] + 1);
479
480 // Generer les nouveaux fragments
481 $codes = array();
482 foreach ($champs as $nom => $texte) {
483 $codes[$nom] = array();
484 $paras = separer_paras($texte, $paras);
485 $paras_champ[$nom] = count($paras);
486 }
487
488 // Apparier les fragments de maniere optimale
489 $n = count($paras);
490 if ($n) {
491 // Tables d'appariement dans les deux sens
492 list(,$trans) = apparier_paras($paras_old, $paras);
493 reset($champs);
494 $nom = '';
495 for ($i = 0; $i < $n; $i++) {
496 while ($i >= $paras_champ[$nom]) list($nom, ) = each($champs);
497 // Lier au fragment existant si possible, sinon creer un nouveau fragment
498 $id_fragment = isset($trans[$i]) ? $trans[$i] : $next++;
499 $codes[$nom][] = $id_fragment;
500 $fragments[$id_fragment] = $paras[$i];
501 }
502 }
503 foreach ($champs as $nom => $t) {
504 $codes[$nom] = join(' ', $codes[$nom]);
505 # avec la ligne qui suit, un champ qu'on vide ne s'enregistre pas
506 # if (!strlen($codes[$nom])) unset($codes[$nom]);
507 }
508
509 // Enregistrer les modifications
510 ajouter_fragments($id_article, $id_version, $fragments);
511
512 sql_updateq("spip_articles", array("id_version" => $id_version), "id_article=$id_article");
513
514 // Si l'insertion ne servait que de verrou,
515 // la detruire apres mise a jour de l'ancienne entree,
516 // sinon la mise a jour efface en fait le verrou.
517
518 if (!$onlylock) {
519 sql_updateq('spip_versions', array('id_version'=>$id_version, 'date'=>date('Y-m-d H:i:s'), 'champs'=> serialize($codes), 'permanent'=>$permanent, 'titre_version'=> $titre_version), "id_article=$id_article AND id_version < 0 AND titre_version='$date'");
520 } else {
521 sql_updateq('spip_versions', array('date'=>date('Y-m-d H:i:s'), 'champs'=>serialize($codes), 'permanent'=>$permanent, 'titre_version'=> $titre_version), "id_article=$id_article AND id_version=$id_version");
522
523 sql_delete("spip_versions", "id_article=$id_article AND id_version < 0 AND titre_version ='$date'");
524 }
525 spip_log($onlylock . "memorise la version $id_version de l'article $id_article $titre_version");
526
527 return $id_version;
528 }
529
530 // les textes "diff" ne peuvent pas passer dans propre directement,
531 // car ils contiennent des <span> et <div> parfois mal places
532 // http://doc.spip.org/@propre_diff
533 function propre_diff($texte) {
534
535 $span_diff = array();
536 if (preg_match_all(',<(/)?(span|div) (class|rem)="diff-[^>]*>,', $texte, $regs, PREG_SET_ORDER)) {
537 foreach ($regs as $c => $reg) {
538 $texte = str_replace($reg[0], '@@@SPIP_DIFF'.$c.'@@@', $texte);
539 }
540 }
541
542 // [ ...<span diff> -> lien ]
543 // < tag <span diff> >
544 $texte = preg_replace(',<([^>]*?@@@SPIP_DIFF[0-9]+@@@),',
545 '&lt;\1', $texte);
546
547 # attention ici astuce seulement deux @@ finals car on doit eviter
548 # deux patterns a suivre, afin de pouvoir prendre [ mais eviter [[
549 $texte = preg_replace(',(^|[^[])[[]([^[\]]*@@@SPIP_DIFF[0-9]+@@),',
550 '\1&#91;\2', $texte);
551
552 // desactiver TeX & toujours-paragrapher
553 $tex = $GLOBALS['traiter_math'];
554 $GLOBALS['traiter_math'] = '';
555 $mem = $GLOBALS['toujours_paragrapher'];
556 $GLOBALS['toujours_paragrapher'] = false;
557
558 $texte = propre($texte);
559
560 // retablir
561 $GLOBALS['traiter_math'] = $tex;
562 $GLOBALS['toujours_paragrapher'] = $mem;
563
564 // un blockquote mal ferme peut gener l'affichage, et title plante safari
565 $texte = preg_replace(',<(/?(blockquote|title)[^>]*)>,i', '&lt;\1>', $texte);
566
567 // Dans les <cadre> c'est un peu plus complique
568 if (preg_match_all(',<textarea (.*)</textarea>,Uims', $texte, $area, PREG_SET_ORDER)) {
569 foreach ($area as $reg) {
570 $remplace = preg_replace(',@@@SPIP_DIFF[0-9]+@@@,', '**', $reg[0]);
571 if ($remplace <> $reg[0])
572 $texte = str_replace($reg[0], $remplace, $texte);
573 }
574 }
575
576 // replacer les valeurs des <span> et <div> diff-
577 if (is_array($regs))
578 foreach ($regs as $c => $reg) {
579 $bal = (!$reg[1]) ? $reg[0] : "</$reg[2]>";
580 $texte = str_replace('@@@SPIP_DIFF'.$c.'@@@', $bal, $texte);
581 $GLOBALS['les_notes'] = str_replace('@@@SPIP_DIFF'.$c.'@@@', $bal, $GLOBALS['les_notes']);
582 }
583
584
585 // quand le dernier tag est ouvrant le refermer ...
586 $reg = end($regs);
587 if (!$reg[1] AND $reg[2]) $texte.="</$reg[2]>";
588
589 return $texte;
590 }
591
592
593 // liste les champs versionnes d'un objet
594 // http://doc.spip.org/@liste_champs_versionnes
595 function liste_champs_versionnes($table) {
596 $champs = array();
597 switch ($table) {
598 case 'spip_articles':
599 $champs += array('id_rubrique', 'surtitre', 'titre', 'soustitre', 'j_mots', 'descriptif', 'nom_site', 'url_site', 'chapo', 'texte', 'ps');
600
601 // prendre en compte les champs extras2
602 if (function_exists($f = 'cextras_get_extras_match')
603 AND is_array($g = $f($table)))
604 foreach($g as $c)
605 $champs[] = $c->champ;
606
607 break;
608 # case 'spip_rubriques':
609 # $champs += array('titre', 'descriptif', 'texte');
610 # break;
611 default:
612 break;
613 }
614 return $champs;
615 }
616
617 // http://doc.spip.org/@enregistrer_premiere_revision
618 function enregistrer_premiere_revision($x) {
619
620 if ($GLOBALS['meta']["articles_versions"]=='oui'
621 AND $champs = liste_champs_versionnes($x['args']['table'])) {
622
623 $id_article = $x['args']['id_objet'];
624
625 if (!sql_countsel('spip_versions',"id_article=$id_article")) {
626 $originaux = sql_fetsel("*", 'spip_articles', "id_article=$id_article");
627 foreach($champs as $v)
628 if (isset($originaux[$v]))
629 $champs_originaux[$v] = $originaux[$v];
630
631 // Si le titre est vide, c'est qu'on vient de creer l'article
632 if ($champs_originaux['titre'] != '') {
633 $date_modif = $champs_originaux['date_modif'];
634 $date = $champs_originaux['date'];
635 unset ($champs_originaux['date_modif']);
636 unset ($champs_originaux['date']);
637 $id_version = ajouter_version($id_article, $champs_originaux, _T('version_initiale'), 0);
638 // Inventer une date raisonnable pour la version initiale
639 if ($date_modif>'1970-')
640 $date_modif = strtotime($date_modif);
641 else if ($date>'1970-')
642 $date_modif = strtotime($date);
643 else
644 $date_modif = time()-7200;
645 sql_updateq('spip_versions', array('date' => date("Y-m-d H:i:s", $date_modif)), "id_article=$id_article AND id_version=$id_version");
646 }
647 }
648 }
649 return $x;
650 }
651
652
653 // http://doc.spip.org/@enregistrer_nouvelle_revision
654 function enregistrer_nouvelle_revision($x) {
655 if ($GLOBALS['meta']["articles_versions"] != 'oui')
656 return $x;
657
658 // Regarder si au moins une des modifs est versionnable
659 $champs = array();
660 foreach (liste_champs_versionnes($x['args']['table']) as $key)
661 if (isset($x['data'][$key]))
662 $champs[$key] = $x['data'][$key];
663
664 // A moins qu'il ne s'agisse d'operation (ajout/suppr) sur les mots-cles?
665 if ($x['args']['operation'] == 'editer_mots'
666 AND $x['args']['table'] == 'spip_articles') {
667 include_spip('inc/texte');
668 $mots = array();
669 foreach(
670 sql_allfetsel('id_mot', 'spip_mots_articles',
671 'id_article='.sql_quote($x['args']['id_objet']))
672 as $mot)
673 $mots[] = "[->mot".$mot['id_mot']."]";
674 $champs['j_mots'] = join(' ', $mots);
675 }
676
677 if (count($champs))
678 ajouter_version($x['args']['id_objet'], $champs, '', $GLOBALS['visiteur_session']['id_auteur']);
679
680 return $x;
681 }
682
683 ?>