PageRenderTime 49ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/spip/ecrire/inc/editer.php

https://github.com/eyeswebcrea/espace-couture-sittler.fr
PHP | 408 lines | 294 code | 52 blank | 62 comment | 48 complexity | 7305fb0da573eec8bfbf503c95d87fd7 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('base/abstract_sql');
  13. // http://doc.spip.org/@formulaires_editer_objet_traiter
  14. function formulaires_editer_objet_traiter($type, $id='new', $id_parent=0, $lier_trad=0, $retour='', $config_fonc='articles_edit_config', $row=array(), $hidden=''){
  15. $res = array();
  16. $action_editer = charger_fonction("editer_$type",'action');
  17. list($id,$err) = $action_editer($id);
  18. $id_table_objet = id_table_objet($type);
  19. $res[$id_table_objet] = $id;
  20. if ($err OR !$id){
  21. $res['message_erreur'] = ($err?$err:_T('erreur'));
  22. }
  23. else{
  24. $res['message_ok'] = ""; // il faudrait faire mieux que cela !
  25. if ($retour)
  26. $res['redirect'] = parametre_url($retour,$id_table_objet,$id);
  27. }
  28. return $res;
  29. }
  30. // http://doc.spip.org/@formulaires_editer_objet_verifier
  31. function formulaires_editer_objet_verifier($type,$id='new', $oblis = array()){
  32. $erreurs = array();
  33. if (intval($id)) {
  34. $conflits = controler_contenu($type,$id);
  35. if (count($conflits)) {
  36. foreach($conflits as $champ=>$conflit){
  37. $erreurs[$champ] .= _T("alerte_modif_info_concourante")."<br /><textarea readonly='readonly' class='forml'>".$conflit['base']."</textarea>";
  38. }
  39. }
  40. }
  41. foreach($oblis as $obli){
  42. if (!_request($obli))
  43. $erreurs[$obli] .= _T("info_obligatoire");
  44. }
  45. return $erreurs;
  46. }
  47. // http://doc.spip.org/@formulaires_editer_objet_charger
  48. function formulaires_editer_objet_charger($type, $id='new', $id_parent=0, $lier_trad=0, $retour='', $config_fonc='articles_edit_config', $row=array(), $hidden=''){
  49. $table_objet = table_objet($type);
  50. $table_objet_sql = table_objet_sql($type);
  51. $id_table_objet = id_table_objet($type);
  52. $new = !is_numeric($id);
  53. // Appel direct dans un squelette
  54. if (!$row) {
  55. if (!$new OR $lier_trad) {
  56. if ($select = charger_fonction($type."_select",'inc',true))
  57. $row = $select($id, $id_parent, $lier_trad);
  58. else $row = sql_fetsel('*',$table_objet_sql,$id_table_objet."=".intval($id));
  59. if (!$new)
  60. $md5 = controles_md5($row);
  61. }
  62. if (!$row) {
  63. $trouver_table = charger_fonction('trouver_table','base');
  64. if ($desc = $trouver_table($table_objet))
  65. foreach($desc['field'] as $k=>$v) $row[$k]='';
  66. }
  67. }
  68. // Gaffe: sans ceci, on ecrase systematiquement l'article d'origine
  69. // (et donc: pas de lien de traduction)
  70. $id = ($new OR $lier_trad)
  71. ? 'oui'
  72. : $row[$id_table_objet];
  73. $row[$id_table_objet] = $id;
  74. $contexte = $row;
  75. if ($id_parent && (!isset($contexte['id_parent']) OR $new))
  76. $contexte['id_parent']=$id_parent;
  77. if ($config_fonc)
  78. $contexte['config'] = $config = $config_fonc($contexte);
  79. $att_text = " class='textarea' "
  80. . " rows='"
  81. . ($config['lignes'] +15)
  82. . "' cols='40'";
  83. list($contexte['texte'],$contexte['_texte_trop_long']) = editer_texte_recolle($contexte['texte'],$att_text);
  84. // on veut conserver la langue de l'interface ;
  85. // on passe cette donnee sous un autre nom, au cas ou le squelette
  86. // voudrait l'exploiter
  87. if (isset($contexte['lang'])) {
  88. $contexte['langue'] = $contexte['lang'];
  89. unset($contexte['lang']);
  90. }
  91. $contexte['_hidden'] = "<input type='hidden' name='editer_$type' value='oui' />\n" .
  92. (!$lier_trad ? '' :
  93. ("\n<input type='hidden' name='lier_trad' value='" .
  94. $lier_trad .
  95. "' />" .
  96. "\n<input type='hidden' name='changer_lang' value='" .
  97. $config['langue'] .
  98. "' />"))
  99. . $hidden
  100. . $md5;
  101. if (isset($contexte['extra']))
  102. $contexte['extra'] = unserialize($contexte['extra']);
  103. // preciser que le formulaire doit passer dans un pipeline
  104. $contexte['_pipeline'] = array('editer_contenu_objet',array('type'=>$type,'id'=>$id));
  105. // preciser que le formulaire doit etre securise auteur/action
  106. // n'est plus utile lorsque l'action accepte l'id en argument direct
  107. // on le garde pour compat
  108. $contexte['_action'] = array("editer_$type",$id);
  109. return $contexte;
  110. }
  111. //
  112. // Gestion des textes trop longs (limitation brouteurs)
  113. // utile pour les textes > 32ko
  114. // http://doc.spip.org/@coupe_trop_long
  115. function coupe_trop_long($texte){
  116. $aider = charger_fonction('aider', 'inc');
  117. if (strlen($texte) > 28*1024) {
  118. $texte = str_replace("\r\n","\n",$texte);
  119. $pos = strpos($texte, "\n\n", 28*1024); // coupe para > 28 ko
  120. if ($pos > 0 and $pos < 32 * 1024) {
  121. $debut = substr($texte, 0, $pos)."\n\n<!--SPIP-->\n";
  122. $suite = substr($texte, $pos + 2);
  123. } else {
  124. $pos = strpos($texte, " ", 28*1024); // sinon coupe espace
  125. if (!($pos > 0 and $pos < 32 * 1024)) {
  126. $pos = 28*1024; // au pire (pas d'espace trouv'e)
  127. $decalage = 0; // si y'a pas d'espace, il ne faut pas perdre le caract`ere
  128. } else {
  129. $decalage = 1;
  130. }
  131. $debut = substr($texte,0,$pos + $decalage); // Il faut conserver l'espace s'il y en a un
  132. $suite = substr($texte,$pos + $decalage);
  133. }
  134. return (array($debut,$suite));
  135. }
  136. else
  137. return (array($texte,''));
  138. }
  139. // http://doc.spip.org/@editer_texte_recolle
  140. function editer_texte_recolle($texte, $att_text)
  141. {
  142. if ((strlen($texte)<29*1024)
  143. OR (include_spip('inc/layer') AND ($GLOBALS['browser_name']!="MSIE")) )
  144. return array($texte,"");
  145. include_spip('inc/barre');
  146. $textes_supplement = "<br /><span style='color: red'>"._T('info_texte_long')."</span>\n";
  147. $nombre = 0;
  148. while (strlen($texte)>29*1024) {
  149. $nombre ++;
  150. list($texte1,$texte) = coupe_trop_long($texte);
  151. $textes_supplement .= "<br />" .
  152. "<textarea id='texte$nombre' name='texte_plus[$nombre]'$att_text>$texte1</textarea>\n";
  153. }
  154. return array($texte,$textes_supplement);
  155. }
  156. // Produit la liste des md5 d'un tableau de donnees, sous forme
  157. // de inputs html
  158. // http://doc.spip.org/@controles_md5
  159. function controles_md5($data, $prefixe='ctr_', $format='html'){
  160. if (!is_array($data))
  161. return false;
  162. $ctr = array();
  163. foreach ($data as $key => $val) {
  164. $m = md5($val);
  165. $k = $prefixe.$key;
  166. switch ($format) {
  167. case 'html':
  168. $ctr[$k] = "<input type='hidden' value='$m' name='$k' />";
  169. break;
  170. default:
  171. $ctr[$k] = $m;
  172. break;
  173. }
  174. }
  175. if ($format == 'html')
  176. return "\n\n<!-- controles md5 -->\n".join("\n", $ctr)."\n\n";
  177. else
  178. return $ctr;
  179. }
  180. // http://doc.spip.org/@controler_contenu
  181. function controler_contenu($type, $id, $options=array(), $c=false, $serveur='') {
  182. include_spip('inc/filtres');
  183. $table_objet = table_objet($type);
  184. $spip_table_objet = table_objet_sql($type);
  185. $id_table_objet = id_table_objet($type);
  186. $trouver_table = charger_fonction('trouver_table', 'base');
  187. $desc = $trouver_table($table_objet, $serveur);
  188. // Appels incomplets (sans $c)
  189. if (!is_array($c)) {
  190. foreach($desc['field'] as $champ=>$ignore)
  191. if(_request($champ))
  192. $c[$champ] = _request($champ);
  193. }
  194. // Securite : certaines variables ne sont jamais acceptees ici
  195. // car elles ne relevent pas de autoriser(article, modifier) ;
  196. // il faut passer par instituer_XX()
  197. // TODO: faut-il passer ces variables interdites
  198. // dans un fichier de description separe ?
  199. unset($c['statut']);
  200. unset($c['id_parent']);
  201. unset($c['id_rubrique']);
  202. unset($c['id_secteur']);
  203. // Gerer les champs non vides
  204. if (is_array($options['nonvide']))
  205. foreach ($options['nonvide'] as $champ => $sinon)
  206. if ($c[$champ] === '')
  207. $c[$champ] = $sinon;
  208. // N'accepter que les champs qui existent
  209. // TODO: ici aussi on peut valider les contenus
  210. // en fonction du type
  211. $champs = array();
  212. foreach($desc['field'] as $champ => $ignore)
  213. if (isset($c[$champ]))
  214. $champs[$champ] = $c[$champ];
  215. // Nettoyer les valeurs
  216. $champs = array_map('corriger_caracteres', $champs);
  217. // Envoyer aux plugins
  218. $champs = pipeline('pre_edition',
  219. array(
  220. 'args' => array(
  221. 'table' => $spip_table_objet, // compatibilite
  222. 'table_objet' => $table_objet,
  223. 'spip_table_objet' => $spip_table_objet,
  224. 'type' =>$type,
  225. 'id_objet' => $id,
  226. 'champs' => $options['champs'],
  227. 'action' => 'controler'
  228. ),
  229. 'data' => $champs
  230. )
  231. );
  232. if (!$champs) return array();
  233. // Verifier si les mises a jour sont pertinentes, datees, en conflit etc
  234. $conflits = controler_md5($champs, $_POST, $type, $id, $serveur, $options['prefix']?$options['prefix']:'ctr_');
  235. return $conflits;
  236. }
  237. // Controle la liste des md5 envoyes, supprime les inchanges,
  238. // signale les modifies depuis telle date
  239. // http://doc.spip.org/@controler_md5
  240. function controler_md5(&$champs, $ctr, $type, $id, $serveur, $prefix = 'ctr_') {
  241. $table_objet = table_objet($type);
  242. $spip_table_objet = table_objet_sql($type);
  243. $id_table_objet = id_table_objet($type);
  244. // Controle des MD5 envoyes
  245. // On elimine les donnees non modifiees par le formulaire (mais
  246. // potentiellement modifiees entre temps par un autre utilisateur)
  247. foreach ($champs as $key => $val) {
  248. if ($m = $ctr[$prefix.$key]) {
  249. if ($m == md5($val))
  250. unset ($champs[$key]);
  251. }
  252. }
  253. if (!$champs) return array();
  254. // On veut savoir si notre modif va avoir un impact
  255. // par rapport aux donnees contenues dans la base
  256. // (qui peuvent etre differentes de celles ayant servi a calculer le ctr)
  257. $s = sql_fetsel(array_keys($champs), $spip_table_objet, "$id_table_objet=$id", $serveur);
  258. $intact = true;
  259. foreach ($champs as $ch => $val)
  260. $intact &= ($s[$ch] == $val);
  261. if ($intact) return array();
  262. // Detection de conflits :
  263. // On verifie si notre modif ne provient pas d'un formulaire
  264. // genere a partir de donnees modifiees dans l'intervalle ; ici
  265. // on compare a ce qui est dans la base, et on bloque en cas
  266. // de conflit.
  267. $ctrh = $ctrq = $conflits = array();
  268. foreach (array_keys($champs) as $key) {
  269. if ($m = $ctr[$prefix.$key]) {
  270. $ctrh[$key] = $m;
  271. $ctrq[] = $key;
  272. }
  273. }
  274. if ($ctrq) {
  275. $ctrq = sql_fetsel($ctrq, $spip_table_objet, "$id_table_objet=$id", $serveur);
  276. foreach ($ctrh as $key => $m) {
  277. if ($m != md5($ctrq[$key])
  278. AND $champs[$key] !== $ctrq[$key]) {
  279. $conflits[$key] = array(
  280. 'base' => $ctrq[$key],
  281. 'post' => $champs[$key]
  282. );
  283. unset($champs[$key]); # stocker quand meme les modifs ?
  284. }
  285. }
  286. }
  287. return $conflits;
  288. }
  289. // http://doc.spip.org/@display_conflit_champ
  290. function display_conflit_champ($x) {
  291. if (strstr($x, "\n") OR strlen($x)>80)
  292. return "<textarea style='width:99%; height:10em;'>".entites_html($x)."</textarea>\n";
  293. else
  294. return "<input type='text' size='40' style='width:99%' value=\"".entites_html($x)."\" />\n";
  295. }
  296. // http://doc.spip.org/@signaler_conflits_edition
  297. function signaler_conflits_edition($conflits, $redirect='') {
  298. include_spip('inc/minipres');
  299. include_spip('inc/revisions');
  300. include_spip('inc/suivi_versions');
  301. include_spip('inc/diff');
  302. foreach ($conflits as $champ=>$a) {
  303. // probleme de stockage ou conflit d'edition ?
  304. $base = isset($a['save']) ? $a['save'] : $a['base'];
  305. $diff = new Diff(new DiffTexte);
  306. $n = preparer_diff($a['post']);
  307. $o = preparer_diff($base);
  308. $d = propre_diff(
  309. afficher_para_modifies(afficher_diff($diff->comparer($n,$o))));
  310. $titre = isset($a['save']) ? _L('Echec lors de l\'enregistrement du champ @champ@', array('champ' => $champ)) : $champ;
  311. $diffs[] = "<h2>$titre</h2>\n"
  312. . "<h3>"._T('info_conflit_edition_differences')."</h3>\n"
  313. . "<div style='max-height:8em; overflow: auto; width:99%;'>".$d."</div>\n"
  314. . "<h4>"._T('info_conflit_edition_votre_version')."</h4>"
  315. . display_conflit_champ($a['post'])
  316. . "<h4>"._T('info_conflit_edition_version_enregistree')."</h4>"
  317. . display_conflit_champ($base);
  318. }
  319. if ($redirect) {
  320. $id = uniqid(rand());
  321. $redirect = "<form action='$redirect' method='get'
  322. id='$id'
  323. style='float:".$GLOBALS['spip_lang_right']."; margin-top:2em;'>\n"
  324. .form_hidden($redirect)
  325. ."<input type='submit' value='"._T('icone_retour')."' />
  326. </form>\n";
  327. // pour les documents, on est probablement en ajax : il faut ajaxer
  328. if (_AJAX)
  329. $redirect .= '<script type="text/javascript">'
  330. .'setTimeout(function(){$("#'.$id.'")
  331. .ajaxForm({target:$("#'.$id.'").parent()});
  332. }, 200);'
  333. ."</script>\n";
  334. }
  335. echo minipres(
  336. _T('titre_conflit_edition'),
  337. '<style>
  338. .diff-para-deplace { background: #e8e8ff; }
  339. .diff-para-ajoute { background: #d0ffc0; color: #000; }
  340. .diff-para-supprime { background: #ffd0c0; color: #904040; text-decoration: line-through; }
  341. .diff-deplace { background: #e8e8ff; }
  342. .diff-ajoute { background: #d0ffc0; }
  343. .diff-supprime { background: #ffd0c0; color: #802020; text-decoration: line-through; }
  344. .diff-para-deplace .diff-ajoute { background: #b8ffb8; border: 1px solid #808080; }
  345. .diff-para-deplace .diff-supprime { background: #ffb8b8; border: 1px solid #808080; }
  346. .diff-para-deplace .diff-deplace { background: #b8b8ff; border: 1px solid #808080; }
  347. </style>'
  348. .'<p>'._T('info_conflit_edition_avis_non_sauvegarde').'</p>'
  349. .'<p>'._T('texte_conflit_edition_correction').'</p>'
  350. ."<div style='text-align:".$GLOBALS['spip_lang_left'].";'>"
  351. . join("\n",$diffs)
  352. ."</div>\n"
  353. . $redirect
  354. );
  355. }
  356. ?>