1b9f24b3a0e97c331918cd9e9a3ceb7513146e19
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2014 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
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 \***************************************************************************/
14 * Fonctions utilitaires du plugin révisions
18 if (!defined("_ECRIRE_INC_VERSION")) return;
20 $GLOBALS['agregation_versions'] = 10;
22 /** Intervalle de temps (en seconde) separant deux révisions par un même auteur */
23 define('_INTERVALLE_REVISIONS', 600);
25 // http://code.spip.net/@separer_paras
26 function separer_paras($texte, $paras = "") {
27 if (!$paras) $paras = array();
28 while (preg_match("/(\r\n?){2,}|\n{2,}/", $texte, $regs)) {
29 $p = strpos($texte, $regs[0]) +
strlen($regs[0]);
30 $paras[] = substr($texte, 0, $p);
31 $texte = substr($texte, $p);
33 if ($texte) $paras[] = $texte;
37 // http://code.spip.net/@replace_fragment
38 function replace_fragment($id_objet,$objet, $version_min, $version_max, $id_fragment, $fragment) {
39 $fragment = serialize($fragment);
42 // pour le portage en PG il faut l'equivalente au mysql_escape_string
43 // et deporter son appel dans les fonctions d'abstraction.
44 if (function_exists('gzcompress')
45 AND $GLOBALS['connexions'][0]['type'] == 'mysql') {
46 $s = gzcompress($fragment);
47 if (strlen($s) < strlen($fragment)) {
48 # spip_log("gain gz: ".intval(100 - 100 * strlen($s) / strlen($fragment)));
54 // Attention a echapper $fragment, binaire potentiellement gz
56 'id_objet' => intval($id_objet),
58 'id_fragment' => intval($id_fragment),
59 'version_min' => intval($version_min),
60 'version_max' => intval($version_max),
61 'compress' => $compress,
62 'fragment' => $fragment);
65 // http://code.spip.net/@envoi_replace_fragments
66 function envoi_replace_fragments($replaces) {
67 $desc = $GLOBALS['tables_auxiliaires']['spip_versions_fragments'];
68 foreach($replaces as $r)
69 sql_replace('spip_versions_fragments', $r, $desc);
73 // http://code.spip.net/@envoi_delete_fragments
74 function envoi_delete_fragments($id_objet,$objet, $deletes) {
75 if (count($deletes)) {
76 sql_delete("spip_versions_fragments", "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND ((". join(") OR (", $deletes)."))");
82 // Ajouter les fragments de la derniere version (tableau associatif id_fragment => texte)
84 // http://code.spip.net/@ajouter_fragments
85 function ajouter_fragments($id_objet,$objet, $id_version, $fragments) {
86 global $agregation_versions;
89 foreach ($fragments as $id_fragment => $texte) {
91 // Recuperer la version la plus recente
92 $row = sql_fetsel("compress, fragment, version_min, version_max", "spip_versions_fragments", "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND id_fragment=$id_fragment AND version_min<=$id_version", "", "version_min DESC", "1");
95 $fragment = $row['fragment'];
96 $version_min = $row['version_min'];
97 if ($row['compress'] > 0) $fragment = @gzuncompress
($fragment);
98 $fragment = unserialize($fragment);
99 if (is_array($fragment)) {
100 unset($fragment[$id_version]);
101 // Si le fragment n'est pas trop gros, prolonger celui-ci
102 $nouveau = count($fragment) >= $agregation_versions
103 && strlen($row['fragment']) > 1000;
107 $fragment = array($id_version => $texte);
108 $version_min = $id_version;
111 // Ne pas dupliquer les fragments non modifies
113 for ($i = $id_version - 1; $i >= $version_min; $i--) {
114 if (isset($fragment[$i])) {
115 $modif = ($fragment[$i] != $texte);
119 if ($modif) $fragment[$id_version] = $texte;
122 // Preparer l'enregistrement du fragment
123 $replaces[] = replace_fragment($id_objet,$objet, $version_min, $id_version, $id_fragment, $fragment);
126 envoi_replace_fragments($replaces);
130 // Supprimer tous les fragments d'un objet lies a un intervalle de versions
131 // (essaie d'eviter une trop grande fragmentation)
133 // http://code.spip.net/@supprimer_fragments
134 function supprimer_fragments($id_objet,$objet, $version_debut, $version_fin) {
135 global $agregation_versions;
140 // D'abord, vider les fragments inutiles
141 sql_delete("spip_versions_fragments", "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND version_min>=$version_debut AND version_max<=$version_fin");
143 // Fragments chevauchant l'ensemble de l'intervalle, s'ils existent
144 $result = sql_select("id_fragment, compress, fragment, version_min, version_max", "spip_versions_fragments", "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND version_min<$version_debut AND version_max>$version_fin");
146 while ($row = sql_fetch($result)) {
147 $id_fragment = $row['id_fragment'];
148 $fragment = $row['fragment'];
149 if ($row['compress'] > 0) $fragment = gzuncompress($fragment);
150 $fragment = unserialize($fragment);
151 for ($i = $version_fin; $i >= $version_debut; $i--) {
152 if (isset($fragment[$i])) {
153 // Recopier le dernier fragment si implicite
154 if (!isset($fragment[$version_fin +
1]))
155 $fragment[$version_fin +
1] = $fragment[$i];
156 unset($fragment[$i]);
160 $replaces[] = replace_fragment($id_objet,$objet,
161 $row['version_min'], $row['version_max'], $id_fragment, $fragment);
164 // Fragments chevauchant le debut de l'intervalle, s'ils existent
165 $result = sql_select("id_fragment, compress, fragment, version_min, version_max", "spip_versions_fragments", "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND version_min<$version_debut AND version_max>=$version_debut AND version_max<=$version_fin");
167 $deb_fragment = array();
168 while ($row = sql_fetch($result)) {
169 $id_fragment = $row['id_fragment'];
170 $fragment = $row['fragment'];
171 $version_min = $row['version_min'];
172 $version_max = $row['version_max'];
173 if ($row['compress'] > 0) $fragment = gzuncompress($fragment);
174 $fragment = unserialize($fragment);
175 for ($i = $version_debut; $i <= $version_max; $i++
) {
176 if (isset($fragment[$i])) unset($fragment[$i]);
179 // Stocker temporairement le fragment pour agregation
180 $deb_fragment[$id_fragment] = $fragment;
181 // Ajuster l'intervalle des versions
182 $deb_version_min[$id_fragment] = $version_min;
183 $deb_version_max[$id_fragment] = $version_debut - 1;
186 // Fragments chevauchant la fin de l'intervalle, s'ils existent
187 $result = sql_select("id_fragment, compress, fragment, version_min, version_max", "spip_versions_fragments", "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND version_max>$version_fin AND version_min>=$version_debut AND version_min<=$version_fin");
189 while ($row = sql_fetch($result)) {
190 $id_fragment = $row['id_fragment'];
191 $fragment = $row['fragment'];
192 $version_min = $row['version_min'];
193 $version_max = $row['version_max'];
194 if ($row['compress'] > 0) $fragment = gzuncompress($fragment);
195 $fragment = unserialize($fragment);
196 for ($i = $version_fin; $i >= $version_min; $i--) {
197 if (isset($fragment[$i])) {
198 // Recopier le dernier fragment si implicite
199 if (!isset($fragment[$version_fin +
1]))
200 $fragment[$version_fin +
1] = $fragment[$i];
201 unset($fragment[$i]);
205 // Virer l'ancien enregistrement (la cle primaire va changer)
206 $deletes[] = "id_fragment=$id_fragment AND version_min=$version_min";
207 // Essayer l'agregation
209 if (isset($deb_fragment[$id_fragment])) {
210 $agreger = (count($deb_fragment[$id_fragment]) +
count($fragment) <= $agregation_versions);
212 $fragment = $deb_fragment[$id_fragment] +
$fragment;
213 $version_min = $deb_version_min[$id_fragment];
216 $replaces[] = replace_fragment($id_objet,$objet,
217 $deb_version_min[$id_fragment], $deb_version_max[$id_fragment],
218 $id_fragment, $deb_fragment[$id_fragment]);
220 unset($deb_fragment[$id_fragment]);
223 // Ajuster l'intervalle des versions
224 $version_min = $version_fin +
1;
226 $replaces[] = replace_fragment($id_objet, $objet, $version_min, $version_max, $id_fragment, $fragment);
229 // Ajouter fragments restants
230 if (is_array($deb_fragment) && count($deb_fragment) > 0) {
231 foreach ($deb_fragment as $id_fragment => $fragment) {
232 $replaces[] = replace_fragment($id_objet,$objet,
233 $deb_version_min[$id_fragment], $deb_version_max[$id_fragment],
234 $id_fragment, $deb_fragment[$id_fragment]);
238 envoi_replace_fragments($replaces);
239 envoi_delete_fragments($id_objet,$objet, $deletes);
243 // Recuperer les fragments d'une version donnee
244 // renvoie un tableau associatif (id_fragment => texte)
246 // http://code.spip.net/@recuperer_fragments
247 function recuperer_fragments($id_objet,$objet, $id_version) {
248 $fragments = array();
250 if ($id_version == 0) return array();
252 $result = sql_select("id_fragment, version_min, version_max, compress, fragment", "spip_versions_fragments", "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND version_min<=$id_version AND version_max>=$id_version");
254 while ($row = sql_fetch($result)) {
255 $id_fragment = $row['id_fragment'];
256 $version_min = $row['version_min'];
257 $fragment = $row['fragment'];
258 if ($row['compress'] > 0){
259 $fragment_ = @gzuncompress
($fragment);
260 if (strlen($fragment) && $fragment_===false)
261 $fragment=serialize(array($row['version_max']=>"["._T('forum_titre_erreur').$id_fragment."]"));
263 $fragment = $fragment_;
265 $fragment_ = unserialize($fragment);
266 if (strlen($fragment) && $fragment_===false)
267 $fragment=array($row['version_max']=>"["._T('forum_titre_erreur').$id_fragment."]");
269 $fragment = $fragment_;
270 for ($i = $id_version; $i >= $version_min; $i--) {
271 if (isset($fragment[$i])) {
273 ## hack destine a sauver les archives des sites iso-8859-1
274 ## convertis en utf-8 (les archives ne sont pas converties
275 ## mais ce code va les nettoyer ; pour les autres charsets
276 ## la situation n'est pas meilleure ni pire qu'avant)
277 if ($GLOBALS['meta']['charset'] == 'utf-8'
278 AND include_spip('inc/charsets')
279 AND !is_utf8($fragment[$i])) {
280 $fragment[$i] = importer_charset($fragment[$i], 'iso-8859-1');
283 $fragments[$id_fragment] = $fragment[$i];
293 // Apparier des paragraphes deux a deux entre une version originale
294 // et une version modifiee
296 // http://code.spip.net/@apparier_paras
297 function apparier_paras($src, $dest, $flou = true) {
303 $md1 = $md2 = array();
304 $gz_min1 = $gz_min2 = array();
305 $gz_trans1 = $gz_trans2 = array();
308 // Nettoyage de la ponctuation pour faciliter l'appariement
309 foreach($src as $key => $val) {
310 $t1[$key] = strval(preg_replace("/[[:punct:][:space:]]+/", " ", $val));
312 foreach($dest as $key => $val) {
313 $t2[$key] = strval(preg_replace("/[[:punct:][:space:]]+/", " ", $val));
316 // Premiere passe : chercher les correspondance exactes
317 foreach($t1 as $key => $val) $md1[$key] = md5($val);
318 foreach($t2 as $key => $val) $md2[md5($val)][$key] = $key;
319 foreach($md1 as $key1 => $h) {
320 if (isset($md2[$h])) {
321 $key2 = reset($md2[$h]);
322 if (isset($t1[$key1]) AND isset($t2[$key2]) AND $t1[$key1] == $t2[$key2]) {
323 $src_dest[$key1] = $key2;
324 $dest_src[$key2] = $key1;
327 unset($md2[$h][$key2]);
333 // Deuxieme passe : recherche de correlation par test de compressibilite
334 foreach($t1 as $key => $val) {
335 $l1[$key] = strlen(gzcompress($val));
337 foreach($t2 as $key => $val) {
338 $l2[$key] = strlen(gzcompress($val));
340 foreach($t1 as $key1 => $s1) {
341 foreach($t2 as $key2 => $s2) {
342 $r = strlen(gzcompress($s1.$s2));
343 $taux = 1.0 * $r / ($l1[$key1] +
$l2[$key2]);
344 if (!isset($gz_min1[$key1]) ||
!$gz_min1[$key1] ||
$gz_min1[$key1] > $taux) {
345 $gz_min1[$key1] = $taux;
346 $gz_trans1[$key1] = $key2;
348 if (!isset($gz_min2[$key2]) ||
!$gz_min2[$key2] ||
$gz_min2[$key2] > $taux) {
349 $gz_min2[$key2] = $taux;
350 $gz_trans2[$key2] = $key1;
355 // Depouiller les resultats de la deuxieme passe :
356 // ne retenir que les correlations reciproques
357 foreach($gz_trans1 as $key1 => $key2) {
358 if ($gz_trans2[$key2] == $key1 && $gz_min1[$key1] < 0.9) {
359 $src_dest[$key1] = $key2;
360 $dest_src[$key2] = $key1;
365 // Retourner les mappings
366 return array($src_dest, $dest_src);
370 // Recuperer les champs d'une version donnee
372 // http://code.spip.net/@recuperer_version
373 function recuperer_version($id_objet,$objet, $id_version) {
375 $champs = sql_getfetsel("champs", "spip_versions", "id_objet=" . intval($id_objet) . " AND objet=".sql_quote($objet)." AND id_version=" . intval($id_version));
376 if (!$champs OR !is_array($champs = unserialize($champs)))
378 else return reconstuire_version($champs,
379 recuperer_fragments($id_objet,$objet, $id_version));
382 // http://code.spip.net/@reconstuire_version
383 function reconstuire_version($champs, $fragments, $res=array()) {
386 if (!$msg) $msg = _T('forum_titre_erreur');
388 foreach ($champs as $nom => $code) {
389 if (!isset($res[$nom])) {
391 foreach (array_filter(explode(' ', $code)) as $id) {
392 $t .= isset($fragments[$id])
402 // http://code.spip.net/@supprimer_versions
403 function supprimer_versions($id_objet,$objet, $version_min, $version_max) {
404 sql_delete("spip_versions", "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND id_version>=$version_min AND id_version<=$version_max");
406 supprimer_fragments($id_objet,$objet, $version_min, $version_max);
410 // Ajouter une version a un objet
412 // http://code.spip.net/@ajouter_version
413 function ajouter_version($id_objet,$objet, $champs, $titre_version = "", $id_auteur) {
414 $paras = $paras_old = $paras_champ = $fragments = array();
416 // Attention a une edition anonyme (type wiki): id_auteur n'est pas
417 // definie, on enregistre alors le numero IP
418 $str_auteur = intval($id_auteur) ?
intval($id_auteur) : $GLOBALS['ip'];
419 // si pas de titre dans cette version, la marquer 'non' permanente,
420 // et elle pourra etre fusionnee avec une revision ulterieure dans un delai < _INTERVALLE_REVISIONS
421 // permet de fusionner plusieurs editions consecutives champs par champs avec les crayons
422 $permanent = empty($titre_version) ?
'non' : '';
424 // Detruire les tentatives d'archivages non abouties en 1 heure
425 sql_delete('spip_versions', "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND id_version <= 0 AND date < DATE_SUB(".sql_quote(date('Y-m-d H:i:s')).", INTERVAL "._INTERVALLE_REVISIONS
." SECOND)");
427 // Signaler qu'on opere en mettant un numero de version negatif
428 // distinctif (pour eviter la violation d'unicite)
429 // et un titre contenant en fait le moment de l'insertion
430 list($ms, $sec) = explode(' ', microtime());
431 $date = $sec . substr($ms,1,4); // SQL ne ramene que 4 chiffres significatifs apres la virgule pour 0.0+titre_version
432 $datediff = ($sec - mktime(0,0,0,9,1,2007)) * 1000000 +
substr($ms,2, strlen($ms)-4);
434 $valeurs = array('id_objet' => $id_objet,
436 'id_version' => (0 - $datediff),
437 'date' => date('Y-m-d H:i:s'),
438 'id_auteur' => $str_auteur, // varchar ici!
439 'titre_version' => $date);
440 sql_insertq('spip_versions', $valeurs);
442 // Eviter les validations entremelees en s'endormant s'il existe
443 // une version <0 plus recente mais pas plus vieille que 10s
444 // Une <0 encore plus vieille est une operation avortee,
445 // on passe outre (vaut mieux archiver mal que pas du tout).
447 // 0. mettre le delai a 30
448 // 1. decommenter le premier sleep(15)
449 // 2. enregistrer une modif
450 // 3. recommenter le premier sleep(15), decommenter le second.
451 // 4. enregistrer une autre modif dans les 15 secondes
454 while (sql_countsel('spip_versions', "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND id_version < 0 AND 0.0+titre_version < $date AND titre_version<>".sql_quote($date,'','text')." AND 0.0+titre_version > $delai")) {
455 spip_log("version $objet $id_objet :insertion en cours avant $date ($delai)");
459 # sleep(15); spip_log("sortie $sec $delai");
460 // Determiner le numero du prochain fragment
461 $next = sql_fetsel("id_fragment", "spip_versions_fragments", "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet), "", "id_fragment DESC", "1");
465 // Examiner la derniere version
466 $row = sql_fetsel("id_version, champs, id_auteur, date, permanent", "spip_versions", "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND id_version > 0", '', "id_version DESC", "1"); // le champ id_auteur est un varchar dans cette table
469 $id_version = $row['id_version'];
470 $paras_old = recuperer_fragments($id_objet,$objet, $id_version);
471 $champs_old = $row['champs'];
472 if ($row['id_auteur']!= $str_auteur
473 OR $row['permanent']!='non'
474 OR strtotime($row['date']) < (time()-_INTERVALLE_REVISIONS
)) {
475 spip_log(strtotime($row['date']), 'revisions');
476 spip_log(time(), 'revisions');
477 spip_log(_INTERVALLE_REVISIONS
, 'revisions');
480 // version precedente recente, on va la mettre a jour
481 // avec les nouveaux arrivants si presents
483 $champs = reconstuire_version(unserialize($champs_old), $paras_old, $champs);
489 spip_log($str_auteur, 'revisions');
490 spip_log($row, 'revisions');
491 spip_log($id_version, 'revisions');
493 $next = !$next ?
1 : ($next['id_fragment'] +
1);
495 // Generer les nouveaux fragments
497 foreach ($champs as $nom => $texte) {
498 $codes[$nom] = array();
499 $paras = separer_paras($texte, $paras);
500 $paras_champ[$nom] = count($paras);
503 // Apparier les fragments de maniere optimale
506 // Tables d'appariement dans les deux sens
507 list(,$trans) = apparier_paras($paras_old, $paras);
511 // eviter une notice PHP au tout debut de la boucle
512 // on ajoute ''=>0 en debut de tableau.
513 $paras_champ = array($nom=>0) +
$paras_champ;
515 for ($i = 0; $i < $n; $i++
) {
516 while ($i >= $paras_champ[$nom]) list($nom, ) = each($champs);
517 // Lier au fragment existant si possible, sinon creer un nouveau fragment
518 $id_fragment = isset($trans[$i]) ?
$trans[$i] : $next++
;
519 $codes[$nom][] = $id_fragment;
520 $fragments[$id_fragment] = $paras[$i];
523 foreach ($champs as $nom => $t) {
524 $codes[$nom] = join(' ', $codes[$nom]);
525 # avec la ligne qui suit, un champ qu'on vide ne s'enregistre pas
526 # if (!strlen($codes[$nom])) unset($codes[$nom]);
529 // Enregistrer les modifications
530 ajouter_fragments($id_objet,$objet, $id_version, $fragments);
532 // Si l'insertion ne servait que de verrou,
533 // la detruire apres mise a jour de l'ancienne entree,
534 // sinon la mise a jour efface en fait le verrou.
537 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_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND id_version < 0 AND titre_version='$date'");
539 sql_updateq('spip_versions', array('date'=>date('Y-m-d H:i:s'), 'champs'=>serialize($codes), 'permanent'=>$permanent, 'titre_version'=> $titre_version), "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND id_version=$id_version");
541 sql_delete("spip_versions", "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND id_version < 0 AND titre_version ='$date'");
543 spip_log($onlylock . "memorise la version $id_version de l'objet $objet $id_objet $titre_version");
548 // les textes "diff" ne peuvent pas passer dans propre directement,
549 // car ils contiennent des <span> et <div> parfois mal places
550 // http://code.spip.net/@propre_diff
551 function propre_diff($texte) {
553 $span_diff = array();
554 if (preg_match_all(',<(/)?(span|div) (class|rem)="diff-[^>]*>,', $texte, $regs, PREG_SET_ORDER
)) {
555 $regs = array_slice($regs,0,500); #limiter la casse s'il y en a trop
556 foreach ($regs as $c => $reg) {
557 $texte = str_replace($reg[0], '@@@SPIP_DIFF'.$c.'@@@', $texte);
561 // [ ...<span diff> -> lien ]
562 // < tag <span diff> >
563 $texte = preg_replace(',<([^>]*?@@@SPIP_DIFF[0-9]+@@@),',
566 # attention ici astuce seulement deux @@ finals car on doit eviter
567 # deux patterns a suivre, afin de pouvoir prendre [ mais eviter [[
568 $texte = preg_replace(',(^|[^[])[[]([^[\]]*@@@SPIP_DIFF[0-9]+@@),',
569 '\1[\2', $texte);
571 // desactiver TeX & toujours-paragrapher
572 $tex = $GLOBALS['traiter_math'];
573 $GLOBALS['traiter_math'] = '';
574 $mem = $GLOBALS['toujours_paragrapher'];
575 $GLOBALS['toujours_paragrapher'] = false;
577 $texte = propre($texte);
580 $GLOBALS['traiter_math'] = $tex;
581 $GLOBALS['toujours_paragrapher'] = $mem;
583 // un blockquote mal ferme peut gener l'affichage, et title plante safari
584 $texte = preg_replace(',<(/?(blockquote|title)[^>]*)>,i', '<\1>', $texte);
586 // Dans les <cadre> c'est un peu plus complique
587 if (preg_match_all(',<textarea (.*)</textarea>,Uims', $texte, $area, PREG_SET_ORDER
)) {
588 foreach ($area as $reg) {
589 $remplace = preg_replace(',@@@SPIP_DIFF[0-9]+@@@,', '**', $reg[0]);
590 if ($remplace <> $reg[0])
591 $texte = str_replace($reg[0], $remplace, $texte);
595 // replacer les valeurs des <span> et <div> diff-
597 foreach ($regs as $c => $reg) {
598 $bal = (!$reg[1]) ?
$reg[0] : "</$reg[2]>";
599 $texte = str_replace('@@@SPIP_DIFF'.$c.'@@@', $bal, $texte);
600 $GLOBALS['les_notes'] = str_replace('@@@SPIP_DIFF'.$c.'@@@', $bal, $GLOBALS['les_notes']);
604 // quand le dernier tag est ouvrant le refermer ...
606 if (!$reg[1] AND $reg[2]) $texte.="</$reg[2]>";
608 // et interdire_scripts !
609 $texte = interdire_scripts($texte);
616 * Liste les champs versionnés d'une table objet.
618 * @param string $table
619 * Nom complet de sa table sql. Exemple 'spip_articles'
621 * Liste des champs versionnés
623 function liste_champs_versionnes($table) {
624 $liste_objets_versionnees = is_array(unserialize($GLOBALS['meta']['objets_versions'])) ?
unserialize($GLOBALS['meta']['objets_versions']) : array();
626 if (!in_array($table,$liste_objets_versionnees))
629 include_spip('base/objets');
630 if ($infos=lister_tables_objets_sql($table)
631 AND isset($infos['champs_versionnes']))
632 return $infos['champs_versionnes'];
638 * Lorsqu'un champ versionée est une jointure, récuperer tous les liens
639 * et les mettre sous forme de liste énumérée
641 * @param string $objet
642 * @param string $id_objet
643 * @param string $jointure
646 function recuperer_valeur_champ_jointure($objet,$id_objet,$jointure){
647 $objet_joint = objet_type($jointure);
648 include_spip('action/editer_liens');
650 if (objet_associable($objet_joint)) {
651 $liens = objet_trouver_liens(array($objet_joint=>'*'),array($objet=>$id_objet));
652 foreach($liens as $l)
653 $v[] = $l[$objet_joint];
655 elseif(objet_associable($objet)) {
656 $liens = objet_trouver_liens(array($objet=>$id_objet),array($objet_joint=>'*'));
657 foreach($liens as $l)
661 return implode(",",$v);
665 * Créer la première révision d'un objet si nécessaire
667 * À faire notamment si on vient d'activer l'extension et qu'on fait une modif
668 * sur un objet qui était déjà en base, mais non versionné
670 * La fonction renvoie le numéro de la dernière version de l'objet,
671 * et 0 si pas de version pour cet objet
673 * @param string $table
674 * @param string $objet
675 * @param int $id_objet
676 * @param array $champs
677 * @param int $id_auteur
680 function verifier_premiere_revision($table,$objet,$id_objet,$champs=null, $id_auteur=0){
682 $id_table_objet = id_table_objet($objet);
684 $champs = liste_champs_versionnes($table);
688 if (!$id_version = sql_getfetsel('id_version','spip_versions',"id_objet=".intval($id_objet)." AND objet=".sql_quote($objet),'','id_version DESC','0,1')) {
689 // recuperer toutes les valeurs actuelles des champs
691 $originaux = sql_fetsel("*", $table, "$id_table_objet=".intval($id_objet));
693 foreach($champs as $v){
694 if (isset($originaux[$v])){
695 $champs_originaux[$v] = $originaux[$v];
697 else if(strncmp($v,'jointure_',9)==0) {
698 $champs_originaux[$v] = recuperer_valeur_champ_jointure($objet,$id_objet,substr($v,9));
700 if (isset($champs_originaux[$v]) AND strlen($originaux[$v]))
704 // Si un champ est non vide,
705 // il faut creer une premiere revision
707 $trouver_table = charger_fonction('trouver_table','base');
708 $desc = $trouver_table($table);
710 // "trouver" une date raisonnable pour la version initiale
713 foreach(array('date_modif','maj') as $d){
714 if (!$date_modif AND isset($originaux[$d]) AND $t=strtotime($d))
715 $date_modif = date("Y-m-d H:i:s", $t);
718 AND isset($desc['date'])
719 AND isset($originaux[$desc['date']])) {
720 $date_modif = $originaux[$desc['date']];
722 elseif (!$date_modif)
723 $date_modif = date("Y-m-d H:i:s", time()-7200);
725 if ($id_version = ajouter_version($id_objet, $objet, $champs_originaux, _T('revisions:version_initiale'), $id_auteur))
726 sql_updateq('spip_versions', array('date' => $date_modif), "id_objet=".intval($id_objet)." AND objet=".sql_quote($objet)." AND id_version=$id_version");