PageRenderTime 37ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/spip/ecrire/inc/filtres.php

https://github.com/eyeswebcrea/espace-couture-sittler.fr
PHP | 2667 lines | 1962 code | 280 blank | 425 comment | 309 complexity | ce8c22ea3d09041a59539a675f5f3c13 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/charsets');
  13. include_spip('inc/filtres_mini');
  14. /**
  15. * Charger un filtre depuis le php :
  16. * - on inclue tous les fichiers fonctions des plugins et du skel
  17. * - on appelle chercher_filtre
  18. */
  19. function charger_filtre($fonc, $default=NULL) {
  20. include_spip('public/parametrer'); // inclure les fichiers fonctions
  21. return chercher_filtre($fonc, $default);
  22. }
  23. // http://adoc.spip.org/@chercher_filtre
  24. function chercher_filtre($fonc, $default=NULL) {
  25. // Cas MIME = type/subtype
  26. // sans confondre avec les appels de fonction de classe Foo::Bar
  27. // qui peuvent etre avec un namespace : space\Foo::Bar
  28. if (strpos($fonc, '/')){
  29. $f = preg_replace(',\W,','_', $fonc);
  30. if ($f = chercher_filtre($f)) return $f;
  31. // cas du sous-type MIME sans filtre associe, passer au type:
  32. // si filtre_text_plain pas defini, passe a filtre_text
  33. $fonc = preg_replace(',\W.*$,','', $fonc);
  34. }
  35. if (!$fonc) return $default;
  36. foreach (
  37. array('filtre_'.$fonc, 'filtre_'.$fonc.'_dist', $fonc) as $f){
  38. if (is_string($g = $GLOBALS['spip_matrice'][$f]))
  39. find_in_path($g,'', true);
  40. if (function_exists($f)
  41. OR (preg_match("/^(\w*)::(\w*)$/", $f, $regs)
  42. AND is_callable(array($regs[1], $regs[2]))
  43. )) {
  44. return $f;
  45. }
  46. }
  47. return $default;
  48. }
  49. // http://doc.spip.org/@appliquer_filtre
  50. function appliquer_filtre($arg, $filtre) {
  51. $f = chercher_filtre($filtre);
  52. if (!$f)
  53. return ''; // ou faut-il retourner $arg inchange == filtre_identite?
  54. $args = func_get_args();
  55. array_shift($args); // enlever $arg
  56. array_shift($args); // enlever $filtre
  57. array_unshift($args, $arg); // remettre $arg
  58. return call_user_func_array($f,$args);
  59. }
  60. // http://doc.spip.org/@spip_version
  61. function spip_version() {
  62. $version = $GLOBALS['spip_version_affichee'];
  63. if ($svn_revision = version_svn_courante(_DIR_RACINE))
  64. $version .= ($svn_revision<0 ? ' SVN':'').' ['.abs($svn_revision).']';
  65. return $version;
  66. }
  67. //
  68. // Mention de la revision SVN courante de l'espace restreint standard
  69. // (numero non garanti pour l'espace public et en cas de mutualisation)
  70. // on est negatif si on est sur .svn, et positif si on utilise svn.revision
  71. // http://doc.spip.org/@version_svn_courante
  72. function version_svn_courante($dir) {
  73. if (!$dir) $dir = '.';
  74. // version installee par paquet ZIP
  75. if (lire_fichier($dir.'/svn.revision', $c)
  76. AND preg_match(',Revision: (\d+),', $c, $d))
  77. return intval($d[1]);
  78. // version installee par SVN
  79. if (lire_fichier($dir . '/.svn/entries', $c)
  80. AND (
  81. (preg_match_all(
  82. ',committed-rev="([0-9]+)",', $c, $r1, PREG_PATTERN_ORDER)
  83. AND $v = max($r1[1])
  84. )
  85. OR
  86. (preg_match(',^\d.*dir[\r\n]+(\d+),ms', $c, $r1) # svn >= 1.4
  87. AND $v = $r1[1]
  88. )))
  89. return -$v;
  90. // Bug ou paquet fait main
  91. return 0;
  92. }
  93. // La matrice est necessaire pour ne filtrer _que_ des fonctions definies dans filtres_images
  94. // et laisser passer les fonctions personnelles baptisees image_...
  95. $GLOBALS['spip_matrice']['image_graver'] = 'inc/filtres_images_mini.php';
  96. $GLOBALS['spip_matrice']['image_select'] = 'inc/filtres_images_mini.php';
  97. $GLOBALS['spip_matrice']['image_reduire'] = 'inc/filtres_images_mini.php';
  98. $GLOBALS['spip_matrice']['image_reduire_par'] = 'inc/filtres_images_mini.php';
  99. $GLOBALS['spip_matrice']['image_passe_partout'] = 'inc/filtres_images_mini.php';
  100. $GLOBALS['spip_matrice']['couleur_html_to_hex'] = 'inc/filtres_images_mini.php';
  101. $GLOBALS['spip_matrice']['couleur_foncer'] = 'inc/filtres_images_mini.php';
  102. $GLOBALS['spip_matrice']['couleur_eclaircir'] = 'inc/filtres_images_mini.php';
  103. // ou pour inclure un script au moment ou l'on cherche le filtre
  104. $GLOBALS['spip_matrice']['filtre_image_dist'] = 'inc/filtres_mime.php';
  105. $GLOBALS['spip_matrice']['filtre_audio_dist'] = 'inc/filtres_mime.php';
  106. $GLOBALS['spip_matrice']['filtre_video_dist'] = 'inc/filtres_mime.php';
  107. $GLOBALS['spip_matrice']['filtre_application_dist'] = 'inc/filtres_mime.php';
  108. $GLOBALS['spip_matrice']['filtre_message_dist'] = 'inc/filtres_mime.php';
  109. $GLOBALS['spip_matrice']['filtre_multipart_dist'] = 'inc/filtres_mime.php';
  110. $GLOBALS['spip_matrice']['filtre_text_dist'] = 'inc/filtres_mime.php';
  111. $GLOBALS['spip_matrice']['filtre_text_csv_dist'] = 'inc/filtres_mime.php';
  112. $GLOBALS['spip_matrice']['filtre_text_html_dist'] = 'inc/filtres_mime.php';
  113. $GLOBALS['spip_matrice']['filtre_audio_x_pn_realaudio'] = 'inc/filtres_mime.php';
  114. // charge les fonctions graphiques et applique celle demandee
  115. // http://doc.spip.org/@filtrer
  116. function filtrer($filtre) {
  117. include_spip('public/parametrer'); // charger les fichiers fonctions
  118. if (is_string($f = $GLOBALS['spip_matrice'][$filtre]))
  119. find_in_path($f,'', true);
  120. $tous = func_get_args();
  121. if (substr($filtre,0,6)=='image_' && $GLOBALS['spip_matrice'][$filtre])
  122. return image_filtrer($tous);
  123. elseif($f = chercher_filtre($filtre)) {
  124. array_shift($tous);
  125. return call_user_func_array($f, $tous);
  126. }
  127. else {
  128. // le filtre n'existe pas, on provoque une erreur
  129. $msg = array('zbug_erreur_filtre', array('filtre'=>texte_script($filtre)));
  130. erreur_squelette($msg);
  131. return '';
  132. }
  133. }
  134. // fonction generique d'entree des filtres images
  135. // accepte en entree un texte complet, un img-log (produit par #LOGO_XX),
  136. // un tag <img ...> complet, ou encore un nom de fichier *local* (passer
  137. // le filtre |copie_locale si on veut l'appliquer a un document)
  138. // applique le filtre demande a chacune des occurrences
  139. // http://doc.spip.org/@image_filtrer
  140. function image_filtrer($args){
  141. $filtre = array_shift($args); # enlever $filtre
  142. $texte = array_shift($args);
  143. if (!strlen($texte)) return;
  144. find_in_path('filtres_images_mini.php','inc/', true);
  145. statut_effacer_images_temporaires(true); // activer la suppression des images temporaires car le compilo finit la chaine par un image_graver
  146. // Cas du nom de fichier local
  147. if ( strpos(substr($texte,strlen(_DIR_RACINE)),'..')===FALSE
  148. AND !preg_match(',^/|[<>]|\s,S', $texte)
  149. AND (
  150. file_exists(preg_replace(',[?].*$,','',$texte))
  151. OR preg_match(';^(\w{3,7}://);', $texte)
  152. )) {
  153. array_unshift($args,"<img src='$texte' />");
  154. $res = call_user_func_array($filtre, $args);
  155. statut_effacer_images_temporaires(false); // desactiver pour les appels hors compilo
  156. return $res;
  157. }
  158. // Cas general : trier toutes les images, avec eventuellement leur <span>
  159. if (preg_match_all(
  160. ',(<([a-z]+) [^<>]*spip_documents[^<>]*>)?\s*(<img\s.*>),UimsS',
  161. $texte, $tags, PREG_SET_ORDER)) {
  162. foreach ($tags as $tag) {
  163. $class = extraire_attribut($tag[3],'class');
  164. if (!$class || (strpos($class,'no_image_filtrer')===FALSE)){
  165. array_unshift($args,$tag[3]);
  166. if ($reduit = call_user_func_array($filtre, $args)) {
  167. // En cas de span spip_documents, modifier le style=...width:
  168. if($tag[1]){
  169. $w = extraire_attribut($reduit, 'width');
  170. if (!$w AND preg_match(",width:\s*(\d+)px,S",extraire_attribut($reduit,'style'),$regs))
  171. $w = $regs[1];
  172. if ($w AND ($style = extraire_attribut($tag[1], 'style'))){
  173. $style = preg_replace(",width:\s*\d+px,S", "width:${w}px", $style);
  174. $replace = inserer_attribut($tag[1], 'style', $style);
  175. $texte = str_replace($tag[1], $replace, $texte);
  176. }
  177. }
  178. // traiter aussi un eventuel mouseover
  179. if ($mouseover = extraire_attribut($reduit,'onmouseover')){
  180. if (preg_match(",this[.]src=['\"]([^'\"]+)['\"],ims", $mouseover, $match)){
  181. $srcover = $match[1];
  182. array_shift($args);
  183. array_unshift($args,"<img src='".$match[1]."' />");
  184. $srcover_filter = call_user_func_array($filtre, $args);
  185. $srcover_filter = extraire_attribut($srcover_filter,'src');
  186. $reduit = str_replace($srcover,$srcover_filter,$reduit);
  187. }
  188. }
  189. $texte = str_replace($tag[3], $reduit, $texte);
  190. }
  191. array_shift($args);
  192. }
  193. }
  194. }
  195. statut_effacer_images_temporaires(false); // desactiver pour les appels hors compilo
  196. return $texte;
  197. }
  198. // pour les feuilles de style CSS du prive
  199. function filtre_background_image_dist ($img, $couleur, $pos="") {
  200. if (!function_exists("imagecreatetruecolor")
  201. OR !include_spip('filtres/images_transforme')
  202. OR !function_exists('image_sepia')
  203. OR !function_exists('image_aplatir')
  204. )
  205. return "background-color: #$couleur;";
  206. return "background: url(".url_absolue(extraire_attribut(image_aplatir(image_sepia($img, $couleur),"gif","cccccc", 64, true), "src")).") $pos;";
  207. }
  208. //
  209. // Retourner taille d'une image
  210. // pour les filtres |largeur et |hauteur
  211. //
  212. // http://doc.spip.org/@taille_image
  213. function taille_image($img) {
  214. static $largeur_img =array(), $hauteur_img= array();
  215. $srcWidth = 0;
  216. $srcHeight = 0;
  217. $logo = extraire_attribut($img,'src');
  218. if (!$logo) $logo = $img;
  219. else {
  220. $srcWidth = extraire_attribut($img,'width');
  221. $srcHeight = extraire_attribut($img,'height');
  222. }
  223. // ne jamais operer directement sur une image distante pour des raisons de perfo
  224. // la copie locale a toutes les chances d'etre la ou de resservir
  225. if (preg_match(';^(\w{3,7}://);', $logo)){
  226. include_spip('inc/distant');
  227. $fichier = copie_locale($logo);
  228. $logo = $fichier ? _DIR_RACINE . $fichier : $logo;
  229. }
  230. if (($p=strpos($logo,'?'))!==FALSE)
  231. $logo=substr($logo,0,$p);
  232. $srcsize = false;
  233. if (isset($largeur_img[$logo]))
  234. $srcWidth = $largeur_img[$logo];
  235. if (isset($hauteur_img[$logo]))
  236. $srcHeight = $hauteur_img[$logo];
  237. if (!$srcWidth OR !$srcHeight){
  238. if ($srcsize = @getimagesize($logo)){
  239. if (!$srcWidth) $largeur_img[$logo] = $srcWidth = $srcsize[0];
  240. if (!$srcHeight) $hauteur_img[$logo] = $srcHeight = $srcsize[1];
  241. }
  242. // $logo peut etre une reference a une image temporaire dont a n'a que le log .src
  243. // on s'y refere, l'image sera reconstruite en temps utile si necessaire
  244. elseif(@file_exists($f = "$logo.src")
  245. AND lire_fichier($f,$valeurs)
  246. AND $valeurs=unserialize($valeurs)) {
  247. if (!$srcWidth) $largeur_img[$mem] = $srcWidth = $valeurs["largeur_dest"];
  248. if (!$srcHeight) $hauteur_img[$mem] = $srcHeight = $valeurs["hauteur_dest"];
  249. }
  250. }
  251. return array($srcHeight, $srcWidth);
  252. }
  253. // http://doc.spip.org/@largeur
  254. function largeur($img) {
  255. if (!$img) return;
  256. list ($h,$l) = taille_image($img);
  257. return $l;
  258. }
  259. // http://doc.spip.org/@hauteur
  260. function hauteur($img) {
  261. if (!$img) return;
  262. list ($h,$l) = taille_image($img);
  263. return $h;
  264. }
  265. // Echappement des entites HTML avec correction des entites "brutes"
  266. // (generees par les butineurs lorsqu'on rentre des caracteres n'appartenant
  267. // pas au charset de la page [iso-8859-1 par defaut])
  268. //
  269. // Attention on limite cette correction aux caracteres "hauts" (en fait > 99
  270. // pour aller plus vite que le > 127 qui serait logique), de maniere a
  271. // preserver des echappements de caracteres "bas" (par exemple [ ou ")
  272. // et au cas particulier de &amp; qui devient &amp;amp; dans les url
  273. // http://doc.spip.org/@corriger_entites_html
  274. function corriger_entites_html($texte) {
  275. if (strpos($texte,'&amp;') === false) return $texte;
  276. return preg_replace(',&amp;(#[0-9][0-9][0-9]+;|amp;),iS', '&\1', $texte);
  277. }
  278. // idem mais corriger aussi les &amp;eacute; en &eacute;
  279. // http://doc.spip.org/@corriger_toutes_entites_html
  280. function corriger_toutes_entites_html($texte) {
  281. if (strpos($texte,'&amp;') === false) return $texte;
  282. return preg_replace(',&amp;(#?[a-z0-9]+;),iS', '&\1', $texte);
  283. }
  284. // http://doc.spip.org/@proteger_amp
  285. function proteger_amp($texte){
  286. return str_replace('&','&amp;',$texte);
  287. }
  288. // http://doc.spip.org/@entites_html
  289. function entites_html($texte, $tout=false) {
  290. if (!is_string($texte) OR !$texte
  291. OR !preg_match(",[&\"'<>],S", $texte) # strpbrk($texte, "&\"'<>")!==false
  292. ) return $texte;
  293. include_spip('inc/texte');
  294. $texte = htmlspecialchars(echappe_retour(echappe_html($texte,'',true),'','proteger_amp'));
  295. if ($tout)
  296. return corriger_toutes_entites_html($texte);
  297. else
  298. return corriger_entites_html($texte);
  299. }
  300. // Transformer les &eacute; dans le charset local
  301. // http://doc.spip.org/@filtrer_entites
  302. function filtrer_entites($texte) {
  303. if (strpos($texte,'&') === false) return $texte;
  304. // filtrer
  305. $texte = html2unicode($texte);
  306. // remettre le tout dans le charset cible
  307. return unicode2charset($texte);
  308. }
  309. // caracteres de controle - http://www.w3.org/TR/REC-xml/#charsets
  310. // http://doc.spip.org/@supprimer_caracteres_illegaux
  311. function supprimer_caracteres_illegaux($texte) {
  312. static $from = "\x0\x1\x2\x3\x4\x5\x6\x7\x8\xB\xC\xE\xF\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
  313. static $to = null;
  314. if (is_array($texte)) {
  315. return array_map('supprimer_caracteres_illegaux', $texte);
  316. }
  317. if (!$to) $to = str_repeat('-', strlen($from));
  318. return strtr($texte, $from, $to);
  319. }
  320. // Supprimer caracteres windows et les caracteres de controle ILLEGAUX
  321. // http://doc.spip.org/@corriger_caracteres
  322. function corriger_caracteres ($texte) {
  323. $texte = corriger_caracteres_windows($texte);
  324. $texte = supprimer_caracteres_illegaux($texte);
  325. return $texte;
  326. }
  327. // Encode du HTML pour transmission XML
  328. // http://doc.spip.org/@texte_backend
  329. function texte_backend($texte) {
  330. static $apostrophe = array("&#8217;", "'"); # n'allouer qu'une fois
  331. // si on a des liens ou des images, les passer en absolu
  332. $texte = liens_absolus($texte);
  333. // echapper les tags &gt; &lt;
  334. $texte = preg_replace(',&(gt|lt);,S', '&amp;\1;', $texte);
  335. // importer les &eacute;
  336. $texte = filtrer_entites($texte);
  337. // " -> &quot; et tout ce genre de choses
  338. $u = $GLOBALS['meta']['pcre_u'];
  339. $texte = str_replace("&nbsp;", " ", $texte);
  340. $texte = preg_replace('/\s{2,}/S'.$u, " ", $texte);
  341. $texte = entites_html($texte);
  342. // verifier le charset
  343. $texte = charset2unicode($texte);
  344. // Caracteres problematiques en iso-latin 1
  345. if ($GLOBALS['meta']['charset'] == 'iso-8859-1') {
  346. $texte = str_replace(chr(156), '&#156;', $texte);
  347. $texte = str_replace(chr(140), '&#140;', $texte);
  348. $texte = str_replace(chr(159), '&#159;', $texte);
  349. }
  350. // l'apostrophe curly pose probleme a certains lecteure de RSS
  351. // et le caractere apostrophe alourdit les squelettes avec PHP
  352. // ==> on les remplace par l'entite HTML
  353. return str_replace($apostrophe, "'", $texte);
  354. }
  355. // Comme ci-dessus, mais avec addslashes final pour squelettes avec PHP (rss)
  356. function texte_backendq($texte) {
  357. return addslashes(texte_backend($texte));
  358. }
  359. // Enleve le numero des titres numerotes ("1. Titre" -> "Titre")
  360. // http://doc.spip.org/@supprimer_numero
  361. function supprimer_numero($texte) {
  362. return preg_replace(
  363. ",^[[:space:]]*([0-9]+)([.)]|".chr(194).'?'.chr(176).")[[:space:]]+,S",
  364. "", $texte);
  365. }
  366. // et la fonction inverse
  367. // http://doc.spip.org/@recuperer_numero
  368. function recuperer_numero($texte) {
  369. if (preg_match(
  370. ",^[[:space:]]*([0-9]+)([.)]|".chr(194).'?'.chr(176).")[[:space:]]+,S",
  371. $texte, $regs))
  372. return intval($regs[1]);
  373. else
  374. return '';
  375. }
  376. // Suppression basique et brutale de tous les <...>
  377. // http://doc.spip.org/@supprimer_tags
  378. function supprimer_tags($texte, $rempl = "") {
  379. $texte = preg_replace(",<[^>]*>,US", $rempl, $texte);
  380. // ne pas oublier un < final non ferme
  381. // mais qui peut aussi etre un simple signe plus petit que
  382. $texte = str_replace('<', ' ', $texte);
  383. return $texte;
  384. }
  385. // Convertit les <...> en la version lisible en HTML
  386. // http://doc.spip.org/@echapper_tags
  387. function echapper_tags($texte, $rempl = "") {
  388. $texte = preg_replace("/<([^>]*)>/", "&lt;\\1&gt;", $texte);
  389. return $texte;
  390. }
  391. // Convertit un texte HTML en texte brut
  392. // http://doc.spip.org/@textebrut
  393. function textebrut($texte) {
  394. $u = $GLOBALS['meta']['pcre_u'];
  395. $texte = preg_replace('/\s+/S'.$u, " ", $texte);
  396. $texte = preg_replace("/<(p|br)( [^>]*)?".">/iS", "\n\n", $texte);
  397. $texte = preg_replace("/^\n+/", "", $texte);
  398. $texte = preg_replace("/\n+$/", "", $texte);
  399. $texte = preg_replace("/\n +/", "\n", $texte);
  400. $texte = supprimer_tags($texte);
  401. $texte = preg_replace("/(&nbsp;| )+/S", " ", $texte);
  402. // nettoyer l'apostrophe curly qui pose probleme a certains rss-readers, lecteurs de mail...
  403. $texte = str_replace("&#8217;","'",$texte);
  404. return $texte;
  405. }
  406. // Remplace les liens SPIP en liens ouvrant dans une nouvelle fenetre (target=blank)
  407. // http://doc.spip.org/@liens_ouvrants
  408. function liens_ouvrants ($texte) {
  409. return preg_replace(",<a ([^>]*https?://[^>]*class=[\"']spip_(out|url)\b[^>]+)>,",
  410. "<a \\1 target=\"_blank\">", $texte);
  411. }
  412. // Transformer les sauts de paragraphe en simples passages a la ligne
  413. // http://doc.spip.org/@PtoBR
  414. function PtoBR($texte){
  415. $u = $GLOBALS['meta']['pcre_u'];
  416. $texte = preg_replace("@</p>@iS", "\n", $texte);
  417. $texte = preg_replace("@<p\b.*>@UiS", "<br />", $texte);
  418. $texte = preg_replace("@^\s*<br />@S".$u, "", $texte);
  419. return $texte;
  420. }
  421. // Couper les "mots" de plus de $l caracteres (souvent des URLs)
  422. // en mettant des espaces (par defaut, soft hyphen &#173: = &shy;)
  423. // http://doc.spip.org/@lignes_longues
  424. function lignes_longues($texte, $l = 70, $espace='&#173;') {
  425. if ($l<1) return $texte;
  426. if (!preg_match("/[\w,\/.]{".$l."}/UmsS", $texte))
  427. return $texte;
  428. // Passer en utf-8 pour ne pas avoir de coupes trop courtes avec les &#xxxx;
  429. // qui prennent 7 caracteres
  430. #include_spip('inc/charsets');
  431. $texte = str_replace("&nbsp;","<&nbsp>",$texte);
  432. $texte = html2unicode($texte, true);
  433. $texte = str_replace("<&nbsp>","&nbsp;",$texte);
  434. $texte = unicode_to_utf_8(charset2unicode(
  435. $texte, $GLOBALS['meta']['charset'], true));
  436. // echapper les tags (on ne veut pas casser les a href=...)
  437. $tags = array();
  438. if (preg_match_all('/<.+>|&(?:amp;)?#x?[0-9]+;|&(?:amp;)?[a-zA-Z1-4]{2,6};/UumsS', $texte, $t, PREG_SET_ORDER)) {
  439. foreach ($t as $n => $tag) {
  440. $tags[$n] = $tag[0];
  441. $texte = str_replace($tag[0], "<---$n--->", $texte);
  442. }
  443. }
  444. // casser les mots longs qui restent
  445. // note : on pourrait preferer couper sur les / , etc.
  446. if (preg_match_all("/[\w,\/.]{".$l."}/UmsS", $texte, $longs, PREG_SET_ORDER)) {
  447. foreach ($longs as $long) {
  448. $texte = str_replace($long[0], $long[0].$espace, $texte);
  449. }
  450. }
  451. // retablir les tags
  452. if (preg_match_all('/<---[\s0-9]+--->/UumsS', $texte, $t, PREG_SET_ORDER)) {
  453. foreach ($t as $tag) {
  454. $n = intval(preg_replace(',[^0-9]+,U','',$tag[0]));
  455. $texte = str_replace($tag[0], $tags[$n], $texte);
  456. }
  457. }
  458. return importer_charset($texte, 'utf-8');
  459. }
  460. // Majuscules y compris accents, en HTML
  461. // http://doc.spip.org/@majuscules
  462. function majuscules($texte) {
  463. if (!strlen($texte)) return '';
  464. // Cas du turc
  465. if ($GLOBALS['spip_lang'] == 'tr') {
  466. # remplacer hors des tags et des entites
  467. if (preg_match_all(',<[^<>]+>|&[^;]+;,S', $texte, $regs, PREG_SET_ORDER))
  468. foreach ($regs as $n => $match)
  469. $texte = str_replace($match[0], "@@SPIP_TURC$n@@", $texte);
  470. $texte = str_replace('i', '&#304;', $texte);
  471. if ($regs)
  472. foreach ($regs as $n => $match)
  473. $texte = str_replace("@@SPIP_TURC$n@@", $match[0], $texte);
  474. }
  475. // Cas general
  476. return "<span style='text-transform: uppercase;'>$texte</span>";
  477. }
  478. // "127.4 ko" ou "3.1 Mo"
  479. // http://doc.spip.org/@taille_en_octets
  480. function taille_en_octets ($taille) {
  481. if ($taille < 1024) {$taille = _T('taille_octets', array('taille' => $taille));}
  482. else if ($taille < 1024*1024) {
  483. $taille = _T('taille_ko', array('taille' => ((floor($taille / 102.4))/10)));
  484. } else {
  485. $taille = _T('taille_mo', array('taille' => ((floor(($taille / 1024) / 102.4))/10)));
  486. }
  487. return $taille;
  488. }
  489. // Rend une chaine utilisable sans dommage comme attribut HTML
  490. // http://doc.spip.org/@attribut_html
  491. function attribut_html($texte,$textebrut = true) {
  492. $u = $GLOBALS['meta']['pcre_u'];
  493. if ($textebrut)
  494. $texte = preg_replace(array(",\n,",",\s(?=\s),msS".$u),array(" ",""),textebrut($texte));
  495. $texte = texte_backend($texte);
  496. $texte = str_replace(array("'",'"'),array('&#39;', '&#34;'), $texte);
  497. return preg_replace(array("/&(amp;|#38;)/","/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/"),array("&","&#38;") , $texte);
  498. }
  499. // Vider les url nulles comme 'http://' ou 'mailto:'
  500. // et leur appliquer un htmlspecialchars() + gerer les &amp;
  501. // http://doc.spip.org/@vider_url
  502. function vider_url($url, $entites = true) {
  503. # un message pour abs_url
  504. $GLOBALS['mode_abs_url'] = 'url';
  505. $url = trim($url);
  506. if (preg_match(",^(http:?/?/?|mailto:?)$,iS", $url))
  507. return '';
  508. if ($entites) $url = entites_html($url);
  509. return $url;
  510. }
  511. // Extraire une date de n'importe quel champ (a completer...)
  512. // http://doc.spip.org/@extraire_date
  513. function extraire_date($texte) {
  514. // format = 2001-08
  515. if (preg_match(",([1-2][0-9]{3})[^0-9]*(1[0-2]|0?[1-9]),",$texte,$regs))
  516. return $regs[1]."-".sprintf("%02d", $regs[2])."-01";
  517. }
  518. // Maquiller une adresse e-mail
  519. // http://doc.spip.org/@antispam
  520. function antispam($texte) {
  521. include_spip('inc/acces');
  522. $masque = creer_pass_aleatoire(3);
  523. return preg_replace("/@/", " $masque ", $texte);
  524. }
  525. // http://doc.spip.org/@securiser_acces
  526. function securiser_acces($id_auteur, $cle, $dir, $op='', $args='')
  527. {
  528. include_spip('inc/acces');
  529. if ($op) $dir .= " $op $args";
  530. return verifier_low_sec($id_auteur, $cle, $dir);
  531. }
  532. // sinon{texte, rien} : affiche "rien" si la chaine est vide,
  533. // affiche la chaine si non vide ;
  534. // attention c'est compile directement dans inc/references
  535. // http://doc.spip.org/@sinon
  536. function sinon ($texte, $sinon='') {
  537. if ($texte OR (!is_array($texte) AND strlen($texte)))
  538. return $texte;
  539. else
  540. return $sinon;
  541. }
  542. // |choixsivide{vide,pasvide} affiche pasvide si la chaine n'est pas vide...
  543. // http://doc.spip.org/@choixsivide
  544. function choixsivide($a, $vide, $pasvide) {
  545. return $a ? $pasvide : $vide;
  546. }
  547. // |choixsiegal{aquoi,oui,non} affiche oui si la chaine est egal a aquoi ...
  548. // http://doc.spip.org/@choixsiegal
  549. function choixsiegal($a1,$a2,$v,$f) {
  550. return ($a1 == $a2) ? $v : $f;
  551. }
  552. //
  553. // Date, heure, saisons
  554. //
  555. // on normalise la date, si elle vient du contexte (public/parametrer.php), on force le jour
  556. // http://doc.spip.org/@normaliser_date
  557. function normaliser_date($date, $forcer_jour = false) {
  558. $date = vider_date($date);
  559. if ($date) {
  560. if (preg_match("/^[0-9]{8,10}$/", $date))
  561. $date = date("Y-m-d H:i:s", $date);
  562. if (preg_match("#^([12][0-9]{3})([-/]00)?( [-0-9:]+)?$#", $date, $regs))
  563. $date = $regs[1]."-00-00".$regs[3];
  564. else if (preg_match("#^([12][0-9]{3}[-/][01]?[0-9])([-/]00)?( [-0-9:]+)?$#", $date, $regs))
  565. $date = preg_replace("@/@","-",$regs[1])."-00".$regs[3];
  566. else
  567. $date = date("Y-m-d H:i:s", strtotime($date));
  568. if ($forcer_jour)
  569. $date = str_replace('-00', '-01', $date);
  570. }
  571. return $date;
  572. }
  573. // http://doc.spip.org/@vider_date
  574. function vider_date($letexte) {
  575. if (strncmp("0000-00-00", $letexte,10)==0) return '';
  576. if (strncmp("0001-01-01", $letexte,10)==0) return '';
  577. if (strncmp("1970-01-01", $letexte,10)==0) return ''; // eviter le bug GMT-1
  578. return $letexte;
  579. }
  580. // http://doc.spip.org/@recup_heure
  581. function recup_heure($date){
  582. static $d = array(0,0,0);
  583. if (!preg_match('#([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})#', $date, $r))
  584. return $d;
  585. array_shift($r);
  586. return $r;
  587. }
  588. // http://doc.spip.org/@heures
  589. function heures($numdate) {
  590. $date_array = recup_heure($numdate);
  591. if ($date_array)
  592. list($heures, $minutes, $secondes) = $date_array;
  593. return $heures;
  594. }
  595. // http://doc.spip.org/@minutes
  596. function minutes($numdate) {
  597. $date_array = recup_heure($numdate);
  598. if ($date_array)
  599. list($heures, $minutes, $secondes) = $date_array;
  600. return $minutes;
  601. }
  602. // http://doc.spip.org/@secondes
  603. function secondes($numdate) {
  604. $date_array = recup_heure($numdate);
  605. if ($date_array)
  606. list($heures,$minutes,$secondes) = $date_array;
  607. return $secondes;
  608. }
  609. // http://doc.spip.org/@heures_minutes
  610. function heures_minutes($numdate) {
  611. return _T('date_fmt_heures_minutes', array('h'=> heures($numdate), 'm'=> minutes($numdate)));
  612. }
  613. // http://doc.spip.org/@recup_date
  614. function recup_date($numdate, $forcer_jour = true){
  615. if (!$numdate) return '';
  616. $heures = $minutes = $secondes = 0;
  617. if (preg_match('#([0-9]{1,2})/([0-9]{1,2})/([0-9]{4}|[0-9]{1,2})#', $numdate, $regs)) {
  618. $jour = $regs[1];
  619. $mois = $regs[2];
  620. $annee = $regs[3];
  621. if ($annee < 90){
  622. $annee = 2000 + $annee;
  623. } elseif ($annee<100) {
  624. $annee = 1900 + $annee ;
  625. }
  626. list($heures, $minutes, $secondes) = recup_heure($numdate);
  627. }
  628. elseif (preg_match('#([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})#',$numdate, $regs)) {
  629. $annee = $regs[1];
  630. $mois = $regs[2];
  631. $jour = $regs[3];
  632. list($heures, $minutes, $secondes) = recup_heure($numdate);
  633. }
  634. elseif (preg_match('#([0-9]{4})-([0-9]{2})#', $numdate, $regs)){
  635. $annee = $regs[1];
  636. $mois = $regs[2];
  637. $jour ='';
  638. list($heures, $minutes, $secondes) = recup_heure($numdate);
  639. }
  640. elseif (preg_match('#^([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})$#', $numdate, $regs)){
  641. $annee = $regs[1];
  642. $mois = $regs[2];
  643. $jour = $regs[3];
  644. $heures = $regs[4];
  645. $minutes = $regs[5];
  646. $secondes = $regs[6];
  647. } else $annee = $mois = $jour ='';
  648. if ($annee > 4000) $annee -= 9000;
  649. if (substr($jour, 0, 1) == '0') $jour = substr($jour, 1);
  650. if ($forcer_jour AND $jour == '0') $jour = '1';
  651. if ($forcer_jour AND $mois == '0') $mois = '1';
  652. if ($annee OR $mois OR $jour OR $heures OR $minutes OR $secondes)
  653. return array($annee, $mois, $jour, $heures, $minutes, $secondes);
  654. }
  655. // une date pour l'interface : utilise date_relative si le decalage
  656. // avec time() est de moins de douze heures, sinon la date complete
  657. // http://doc.spip.org/@date_interface
  658. function date_interface($date, $decalage_maxi = 43200/* 12*3600 */) {
  659. return sinon(
  660. date_relative($date, $decalage_maxi),
  661. affdate_heure($date)
  662. );
  663. }
  664. // http://doc.spip.org/@date_relative
  665. function date_relative($date, $decalage_maxi=0,$ref_date=null) {
  666. if (is_null($ref_date))
  667. $ref_time = time();
  668. else
  669. $ref_time = strtotime($ref_date);
  670. if (!$date) return;
  671. $decal = date("U",$ref_time) - date("U", strtotime($date));
  672. if ($decalage_maxi AND ($decal > $decalage_maxi OR $decal < 0))
  673. return '';
  674. if ($decal < 0) {
  675. $il_y_a = "date_dans";
  676. $decal = -1 * $decal;
  677. } else {
  678. $il_y_a = "date_il_y_a";
  679. }
  680. if ($decal > 3600 * 24 * 30 * 6)
  681. return affdate_court($date);
  682. if ($decal > 3600 * 24 * 30) {
  683. $mois = floor ($decal / (3600 * 24 * 30));
  684. if ($mois < 2)
  685. $delai = "$mois "._T("date_un_mois");
  686. else
  687. $delai = "$mois "._T("date_mois");
  688. }
  689. else if ($decal > 3600 * 24 * 7) {
  690. $semaines = floor ($decal / (3600 * 24 * 7));
  691. if ($semaines < 2)
  692. $delai = "$semaines "._T("date_une_semaine");
  693. else
  694. $delai = "$semaines "._T("date_semaines");
  695. }
  696. else if ($decal > 3600 * 24) {
  697. $jours = floor ($decal / (3600 * 24));
  698. if ($jours < 2)
  699. return $il_y_a=="date_dans"?_T("date_demain"):_T("date_hier");
  700. else
  701. $delai = "$jours "._T("date_jours");
  702. }
  703. else if ($decal >= 3600) {
  704. $heures = floor ($decal / 3600);
  705. if ($heures < 2)
  706. $delai = "$heures "._T("date_une_heure");
  707. else
  708. $delai = "$heures "._T("date_heures");
  709. }
  710. else if ($decal >= 60) {
  711. $minutes = floor($decal / 60);
  712. if ($minutes < 2)
  713. $delai = "$minutes "._T("date_une_minute");
  714. else
  715. $delai = "$minutes "._T("date_minutes");
  716. } else {
  717. $secondes = ceil($decal);
  718. if ($secondes < 2)
  719. $delai = "$secondes "._T("date_une_seconde");
  720. else
  721. $delai = "$secondes "._T("date_secondes");
  722. }
  723. return _T($il_y_a, array("delai"=> $delai));
  724. }
  725. // http://doc.spip.org/@date_relativecourt
  726. function date_relativecourt($date, $decalage_maxi=0) {
  727. if (!$date) return;
  728. $decal = date("U",strtotime(date('Y-m-d'))-strtotime(date('Y-m-d',strtotime($date))));
  729. if ($decalage_maxi AND ($decal > $decalage_maxi OR $decal < 0))
  730. return '';
  731. if ($decal < -24*3600) {
  732. $retour = date_relative($date, $decalage_maxi);
  733. }
  734. elseif ($decal < 0) {
  735. $retour = _T("date_demain");
  736. }
  737. else if ($decal < (3600 * 24) ) {
  738. $retour = _T("date_aujourdhui");
  739. }
  740. else if ($decal < (3600 * 24 *2) ) {
  741. $retour = _T("date_hier");
  742. }
  743. else {
  744. $retour = date_relative($date, $decalage_maxi);
  745. }
  746. return $retour;
  747. }
  748. // http://doc.spip.org/@affdate_base
  749. function affdate_base($numdate, $vue, $param = '') {
  750. global $spip_lang;
  751. $date_array = recup_date($numdate, false);
  752. if (!$date_array) return;
  753. list($annee, $mois, $jour, $heures, $minutes, $secondes)= $date_array;
  754. // 1er, 21st, etc.
  755. $journum = $jour;
  756. if ($jour == 0) {
  757. $jour = '';
  758. } else {
  759. $njour = intval($jour);
  760. if ($jourth = _T('date_jnum'.$jour))
  761. $jour = $jourth;
  762. }
  763. $mois = intval($mois);
  764. if ($mois > 0 AND $mois < 13) {
  765. $nommois = _T('date_mois_'.$mois);
  766. if ($jour)
  767. $jourmois = _T('date_de_mois_'.$mois, array('j'=>$jour, 'nommois'=>$nommois));
  768. else
  769. $jourmois = $nommois;
  770. } else $nommois = '';
  771. if ($annee < 0) {
  772. $annee = -$annee." "._T('date_avant_jc');
  773. $avjc = true;
  774. }
  775. else $avjc = false;
  776. switch ($vue) {
  777. case 'saison':
  778. if ($mois > 0){
  779. $saison = 1;
  780. if (($mois == 3 AND $jour >= 21) OR $mois > 3) $saison = 2;
  781. if (($mois == 6 AND $jour >= 21) OR $mois > 6) $saison = 3;
  782. if (($mois == 9 AND $jour >= 21) OR $mois > 9) $saison = 4;
  783. if (($mois == 12 AND $jour >= 21) OR $mois > 12) $saison = 1;
  784. }
  785. return _T('date_saison_'.$saison);
  786. case 'court':
  787. if ($avjc) return $annee;
  788. $a = date('Y');
  789. if ($annee < ($a - 100) OR $annee > ($a + 100)) return $annee;
  790. if ($annee != $a) return _T('date_fmt_mois_annee', array ('mois'=>$mois, 'nommois'=>ucfirst($nommois), 'annee'=>$annee));
  791. return _T('date_fmt_jour_mois', array ('jourmois'=>$jourmois, 'jour'=>$jour, 'mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee));
  792. case 'jourcourt':
  793. if ($avjc) return $annee;
  794. $a = date('Y');
  795. if ($annee < ($a - 100) OR $annee > ($a + 100)) return $annee;
  796. if ($annee != $a) return _T('date_fmt_jour_mois_annee', array ('jourmois'=>$jourmois, 'jour'=>$jour, 'mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee));
  797. return _T('date_fmt_jour_mois', array ('jourmois'=>$jourmois, 'jour'=>$jour, 'mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee));
  798. case 'entier':
  799. if ($avjc) return $annee;
  800. if ($jour)
  801. return _T('date_fmt_jour_mois_annee', array ('jourmois'=>$jourmois, 'jour'=>$jour, 'mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee));
  802. elseif ($mois)
  803. return trim(_T('date_fmt_mois_annee', array ('mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee)));
  804. else
  805. return $annee;
  806. case 'nom_mois':
  807. return $nommois;
  808. case 'mois':
  809. return sprintf("%02s",$mois);
  810. case 'jour':
  811. return $jour;
  812. case 'journum':
  813. return $journum;
  814. case 'nom_jour':
  815. if (!$mois OR !$njour)
  816. return '';
  817. $nom = mktime(1,1,1,$mois,$njour,$annee);
  818. $nom = 1+date('w',$nom);
  819. $param = $param ? '_'.$param : '';
  820. return _T('date_jour_'.$nom.$param);
  821. case 'mois_annee':
  822. if ($avjc) return $annee;
  823. return trim(_T('date_fmt_mois_annee', array('mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee)));
  824. case 'annee':
  825. return $annee;
  826. // Cas d'une vue non definie : retomber sur le format
  827. // de date propose par http://www.php.net/date
  828. default:
  829. return date($vue, strtotime($numdate));
  830. }
  831. }
  832. // http://doc.spip.org/@nom_jour
  833. function nom_jour($numdate, $forme = '') {
  834. if(!($forme == 'abbr' OR $forme == 'initiale')) $forme = '';
  835. return affdate_base($numdate, 'nom_jour', $forme);
  836. }
  837. // http://doc.spip.org/@jour
  838. function jour($numdate) {
  839. return affdate_base($numdate, 'jour');
  840. }
  841. // http://doc.spip.org/@journum
  842. function journum($numdate) {
  843. return affdate_base($numdate, 'journum');
  844. }
  845. // http://doc.spip.org/@mois
  846. function mois($numdate) {
  847. return affdate_base($numdate, 'mois');
  848. }
  849. // http://doc.spip.org/@nom_mois
  850. function nom_mois($numdate) {
  851. return affdate_base($numdate, 'nom_mois');
  852. }
  853. // http://doc.spip.org/@annee
  854. function annee($numdate) {
  855. return affdate_base($numdate, 'annee');
  856. }
  857. // http://doc.spip.org/@saison
  858. function saison($numdate) {
  859. return affdate_base($numdate, 'saison');
  860. }
  861. // http://doc.spip.org/@affdate
  862. function affdate($numdate, $format='entier') {
  863. return affdate_base($numdate, $format);
  864. }
  865. // http://doc.spip.org/@affdate_court
  866. function affdate_court($numdate) {
  867. return affdate_base($numdate, 'court');
  868. }
  869. // http://doc.spip.org/@affdate_jourcourt
  870. function affdate_jourcourt($numdate) {
  871. return affdate_base($numdate, 'jourcourt');
  872. }
  873. // http://doc.spip.org/@affdate_mois_annee
  874. function affdate_mois_annee($numdate) {
  875. return affdate_base($numdate, 'mois_annee');
  876. }
  877. // http://doc.spip.org/@affdate_heure
  878. function affdate_heure($numdate) {
  879. $date_array = recup_date($numdate);
  880. if (!$date_array) return;
  881. list($annee, $mois, $jour, $heures, $minutes, $sec)= $date_array;
  882. return _T('date_fmt_jour_heure', array('jour' => affdate($numdate), 'heure' => _T('date_fmt_heures_minutes', array('h'=> $heures, 'm'=> $minutes))));
  883. }
  884. //
  885. // Alignements en HTML (Old-style, preferer CSS)
  886. //
  887. // Cette fonction cree le paragraphe s'il n'existe pas (texte sur un seul para)
  888. // http://doc.spip.org/@aligner
  889. function aligner($letexte, $justif='') {
  890. $letexte = trim($letexte);
  891. if (!strlen($letexte)) return '';
  892. // Paragrapher proprement
  893. $letexte = paragrapher($letexte, true);
  894. // Inserer les alignements
  895. if ($justif)
  896. $letexte = str_replace(
  897. '<p class="spip">', '<p class="spip" align="'.$justif.'">',
  898. $letexte);
  899. return $letexte;
  900. }
  901. // http://doc.spip.org/@justifier
  902. function justifier($letexte) {
  903. return aligner($letexte,'justify');
  904. }
  905. // http://doc.spip.org/@aligner_droite
  906. function aligner_droite($letexte) {
  907. return aligner($letexte,'right');
  908. }
  909. // http://doc.spip.org/@aligner_gauche
  910. function aligner_gauche($letexte) {
  911. return aligner($letexte,'left');
  912. }
  913. // http://doc.spip.org/@centrer
  914. function centrer($letexte) {
  915. return aligner($letexte,'center');
  916. }
  917. // http://doc.spip.org/@style_align
  918. function style_align($bof) {
  919. global $spip_lang_left;
  920. return "text-align: $spip_lang_left";
  921. }
  922. //
  923. // Export iCal
  924. //
  925. // http://doc.spip.org/@filtrer_ical
  926. function filtrer_ical($texte) {
  927. #include_spip('inc/charsets');
  928. $texte = html2unicode($texte);
  929. $texte = unicode2charset(charset2unicode($texte, $GLOBALS['meta']['charset'], 1), 'utf-8');
  930. $texte = preg_replace("/\n/", " ", $texte);
  931. $texte = preg_replace("/,/", "\,", $texte);
  932. return $texte;
  933. }
  934. // http://doc.spip.org/@date_ical
  935. function date_ical($date, $addminutes = 0) {
  936. list($heures, $minutes, $secondes) = recup_heure($date);
  937. list($annee, $mois, $jour) = recup_date($date);
  938. return date("Ymd\THis",
  939. mktime($heures, $minutes+$addminutes,$secondes,$mois,$jour,$annee));
  940. }
  941. // date_iso retourne la date au format "RFC 3339" / "ISO 8601"
  942. // voir http://www.php.net/manual/fr/ref.datetime.php#datetime.constants
  943. // http://doc.spip.org/@date_iso
  944. function date_iso($date_heure) {
  945. list($annee, $mois, $jour) = recup_date($date_heure);
  946. list($heures, $minutes, $secondes) = recup_heure($date_heure);
  947. $time = @mktime($heures, $minutes, $secondes, $mois, $jour, $annee);
  948. return gmdate('Y-m-d\TH:i:s\Z', $time);
  949. }
  950. // date_822 retourne la date au format "RFC 822"
  951. // utilise pour <pubdate> dans certains feeds RSS
  952. // http://doc.spip.org/@date_822
  953. function date_822($date_heure) {
  954. list($annee, $mois, $jour) = recup_date($date_heure);
  955. list($heures, $minutes, $secondes) = recup_heure($date_heure);
  956. $time = mktime($heures, $minutes, $secondes, $mois, $jour, $annee);
  957. return date('r', $time);
  958. }
  959. // http://doc.spip.org/@date_anneemoisjour
  960. function date_anneemoisjour($d) {
  961. if (!$d) $d = date("Y-m-d");
  962. return substr($d, 0, 4) . substr($d, 5, 2) .substr($d, 8, 2);
  963. }
  964. // http://doc.spip.org/@date_anneemois
  965. function date_anneemois($d) {
  966. if (!$d) $d = date("Y-m-d");
  967. return substr($d, 0, 4) . substr($d, 5, 2);
  968. }
  969. // http://doc.spip.org/@date_debut_semaine
  970. function date_debut_semaine($annee, $mois, $jour) {
  971. $w_day = date("w", mktime(0,0,0,$mois, $jour, $annee));
  972. if ($w_day == 0) $w_day = 7; // Gaffe: le dimanche est zero
  973. $debut = $jour-$w_day+1;
  974. return date("Ymd", mktime(0,0,0,$mois,$debut,$annee));
  975. }
  976. // http://doc.spip.org/@date_fin_semaine
  977. function date_fin_semaine($annee, $mois, $jour) {
  978. $w_day = date("w", mktime(0,0,0,$mois, $jour, $annee));
  979. if ($w_day == 0) $w_day = 7; // Gaffe: le dimanche est zero
  980. $debut = $jour-$w_day+1;
  981. return date("Ymd", mktime(0,0,0,$mois,$debut+6,$annee));
  982. }
  983. // http://doc.spip.org/@agenda_connu
  984. function agenda_connu($type)
  985. {
  986. return in_array($type, array('jour','mois','semaine','periode', 'trimestre')) ? ' ' : '';
  987. }
  988. // Cette fonction memorise dans un tableau indexe par son 5e arg
  989. // un evenement decrit par les 4 autres (date, descriptif, titre, URL).
  990. // Appellee avec une date nulle, elle renvoie le tableau construit.
  991. // l'indexation par le 5e arg autorise plusieurs calendriers dans une page
  992. // http://doc.spip.org/@agenda_memo
  993. function agenda_memo($date=0 , $descriptif='', $titre='', $url='', $cal='')
  994. {
  995. static $agenda = array();
  996. if (!$date) return $agenda;
  997. $idate = date_ical($date);
  998. $cal = trim($cal); // func_get_args (filtre alterner) rajoute \n !!!!
  999. $agenda[$cal][(date_anneemoisjour($date))][] = array(
  1000. 'CATEGORIES' => $cal,
  1001. 'DTSTART' => $idate,
  1002. 'DTEND' => $idate,
  1003. 'DESCRIPTION' => texte_script($descriptif),
  1004. 'SUMMARY' => texte_script($titre),
  1005. 'URL' => $url);
  1006. // toujours retourner vide pour qu'il ne se passe rien
  1007. return "";
  1008. }
  1009. // Cette fonction recoit:
  1010. // - un nombre d'evenements,
  1011. // - une chaine a afficher si ce nombre est nul,
  1012. // - un type de calendrier
  1013. // -- et une suite de noms N.
  1014. // Elle demande a la fonction precedente son tableau
  1015. // et affiche selon le type les elements indexes par N dans ce tableau.
  1016. // Si le suite de noms est vide, tout le tableau est pris
  1017. // Ces noms N sont aussi des classes CSS utilisees par http_calendrier_init
  1018. // Cette fonction recupere aussi par _request les parametres
  1019. // jour, mois, annee, echelle, partie_cal (a ameliorer)
  1020. // http://doc.spip.org/@agenda_affiche
  1021. function agenda_affiche($i)
  1022. {
  1023. $args = func_get_args();
  1024. // date (ou nombre d'evenements qu'on pourrait alors afficher)
  1025. $nb = array_shift($args);
  1026. $evt = array_shift($args);
  1027. $type = array_shift($args);
  1028. if ($nb) {
  1029. $agenda = agenda_memo(0);
  1030. $evt = array();
  1031. foreach (($args ? $args : array_keys($agenda)) as $k) {
  1032. if (is_array($agenda[$k]))
  1033. foreach($agenda[$k] as $d => $v) {
  1034. $evt[$d] = $evt[$d] ? (array_merge($evt[$d], $v)) : $v;
  1035. }
  1036. }
  1037. }
  1038. return agenda_periode($type, $nb, $evt);
  1039. }
  1040. function agenda_periode($type, $nb, $avec, $sans='')
  1041. {
  1042. include_spip('inc/agenda');
  1043. $start = agenda_controle();
  1044. if ($start<0) $start = time();
  1045. $mindate = date("Ymd", $start);
  1046. if ($type != 'periode')
  1047. $evt = array($sans, $avec);
  1048. else {
  1049. $min = substr($mindate,6,2);
  1050. $max = !(is_array($avec) AND $avec) ? time() : strtotime(max(array_keys($avec)));
  1051. $max = $min + (($max - $start) / (3600 * 24));
  1052. if ($max < 31) $max = 0;
  1053. $evt = array($sans, $avec, $min, $max);
  1054. $type = 'mois';
  1055. }
  1056. $ancre = _request('ancre');
  1057. $s = self('&') . (preg_match('/^[\w-]+$/', $ancre) ? "#$ancre" : '');
  1058. return http_calendrier_init($start, $type, _request('echelle'), _request('partie_cal'), $s, $evt);
  1059. }
  1060. // Controle la coherence des 3 nombres d'une date et retourne le temps Unix,
  1061. // sinon retourne un code d'erreur, toujours negatif
  1062. function agenda_controle($date='date', $jour='jour', $mois='mois', $annee='annee')
  1063. {
  1064. $jour = _request($jour);
  1065. $mois = _request($mois);
  1066. $annee = _request($annee);
  1067. if (!($jour||$mois||$anne)) {
  1068. if ($date = recup_date(_request($date))) {
  1069. list($annee, $mois, $jour ) = $date;
  1070. } else return -1;
  1071. }
  1072. if (!$d = mktime(0,0,0, $mois, $jour, $annee)) return -2;
  1073. if ($jour != date("d", $d)) return -3;
  1074. if ($mois != date("m", $d)) return -4;
  1075. if ($annee != date("Y", $d)) return -5;
  1076. return $d;
  1077. }
  1078. //
  1079. // Recuperation de donnees dans le champ extra
  1080. // Ce filtre n'a de sens qu'avec la balise #EXTRA
  1081. //
  1082. // http://doc.spip.org/@extra
  1083. function extra($letexte, $champ) {
  1084. $champs = unserialize($letexte);
  1085. return $champs[$champ];
  1086. }
  1087. // postautobr : transforme les sauts de ligne en _
  1088. // http://doc.spip.org/@post_autobr
  1089. function post_autobr($texte, $delim="\n_ ") {
  1090. $texte = str_replace("\r\n", "\r", $texte);
  1091. $texte = str_replace("\r", "\n", $texte);
  1092. if (preg_match(",\n+$,", $texte, $fin))
  1093. $texte = substr($texte, 0, -strlen($fin = $fin[0]));
  1094. else
  1095. $fin = '';
  1096. $texte = echappe_html($texte, '', true);
  1097. $debut = '';
  1098. $suite = $texte;
  1099. while ($t = strpos('-'.$suite, "\n", 1)) {
  1100. $debut .= substr($suite, 0, $t-1);
  1101. $suite = substr($suite, $t);
  1102. $car = substr($suite, 0, 1);
  1103. if (($car<>'-') AND ($car<>'_') AND ($car<>"\n") AND ($car<>"|") AND ($car<>"}")
  1104. AND !preg_match(',^\s*(\n|</?(quote|div)|$),S',($suite))
  1105. AND !preg_match(',</?(quote|div)> *$,iS', $debut)) {
  1106. $debut .= $delim;
  1107. } else
  1108. $debut .= "\n";
  1109. if (preg_match(",^\n+,", $suite, $regs)) {
  1110. $debut.=$regs[0];
  1111. $suite = substr($suite, strlen($regs[0]));
  1112. }
  1113. }
  1114. $texte = $debut.$suite;
  1115. $texte = echappe_retour($texte);
  1116. return $texte.$fin;
  1117. }
  1118. //
  1119. // Gestion des blocs multilingues
  1120. //
  1121. define('_EXTRAIRE_MULTI', "@<multi>(.*?)</multi>@sS");
  1122. // Extraire et transformer les blocs multi ; on indique la langue courante
  1123. // pour ne pas mettre de span@lang=fr si on est deja en fr
  1124. // http://doc.spip.org/@extraire_multi
  1125. function extraire_multi($letexte, $lang=null, $echappe_span=false) {
  1126. if (strpos($letexte, '<multi>') === false) return $letexte; // perf
  1127. if (preg_match_all(_EXTRAIRE_MULTI, $letexte, $regs, PREG_SET_ORDER)) {
  1128. if (!$lang) $lang = $GLOBALS['spip_lang'];
  1129. foreach ($regs as $reg) {
  1130. // chercher la version de la langue courante
  1131. $trads = extraire_trads($reg[1]);
  1132. if ($l = approcher_langue($trads, $lang)) {
  1133. $trad = $trads[$l];
  1134. } else {
  1135. include_spip('inc/texte');
  1136. // langue absente, prendre la premiere dispo
  1137. // mais typographier le texte selon les regles de celle-ci
  1138. // Attention aux blocs multi sur plusieurs lignes
  1139. $l = key($trads);
  1140. $trad = $trads[$l];
  1141. $typographie = charger_fonction(lang_typo($l), 'typographie');
  1142. $trad = traiter_retours_chariots($typographie($trad));
  1143. $trad = explode("\n", $trad);
  1144. foreach($trad as $i => $ligne) {
  1145. if (strlen($ligne)) {
  1146. $ligne = code_echappement($ligne, 'multi');
  1147. $ligne = str_replace("'", '"', inserer_attribut($ligne, 'lang', $l));
  1148. if (lang_dir($l) !== lang_dir($lang))
  1149. $ligne = str_replace("'", '"', inserer_attribut($ligne, 'dir', lang_dir($l)));
  1150. $trad[$i] = $ligne;
  1151. }
  1152. }
  1153. $trad = join("\n", $trad);
  1154. if (!$echappe_span)
  1155. $trad = echappe_retour($trad, 'multi');
  1156. }
  1157. $letexte = str_replace($reg[0], $trad, $letexte);
  1158. }
  1159. }
  1160. return $letexte;
  1161. }
  1162. //
  1163. // Selection dans un tableau dont les index sont des noms de langues
  1164. // de la valeur associee a la langue en cours
  1165. // si absente, retourne le premier
  1166. // remarque : on pourrait aussi appeler un service de traduction externe
  1167. // ou permettre de choisir une langue "plus proche",
  1168. // par exemple le francais pour l'espagnol, l'anglais pour l'allemand, etc.
  1169. function multi_trad ($trads, $lang='') {
  1170. $k = multi_trads($trads, $lang);
  1171. return $k ? $trads[$k] : array_shift($trads);
  1172. }
  1173. // idem, mais retourne l'index
  1174. function multi_trads ($trads, $lang='') {
  1175. if (!$lang) $lang = $GLOBALS['spip_lang'];
  1176. if (isset($trads[$lang])) {
  1177. return $lang;
  1178. } // cas des langues xx_yy
  1179. else if (preg_match(',^([a-z]+)_,', $lang, $regs) AND isset($trads[$regs[1]])) {
  1180. return $regs[1];
  1181. }
  1182. else return '';
  1183. }
  1184. // convertit le contenu d'une balise multi en un tableau
  1185. // http://doc.spip.org/@extraire_trad
  1186. function extraire_trads($bloc) {
  1187. $lang = '';
  1188. // ce reg fait planter l'analyse multi s'il y a de l'{italique} dans le champ
  1189. // while (preg_match("/^(.*?)[{\[]([a-z_]+)[}\]]/siS", $bloc, $regs)) {
  1190. while (preg_match("/^(.*?)[\[]([a-z_]+)[\]]/siS", $bloc, $regs)) {
  1191. $texte = trim($regs[1]);
  1192. if ($texte OR $lang)
  1193. $trads[$lang] = $texte;
  1194. $bloc = substr($bloc, strlen($regs[0]));
  1195. $lang = $regs[2];
  1196. }
  1197. $trads[$lang] = $bloc;
  1198. return $trads;
  1199. }
  1200. //
  1201. // Ce filtre retourne la donnee si c'est la premiere fois qu'il la voit ;
  1202. // possibilite de gerer differentes "familles" de donnees |unique{famille}
  1203. # |unique{famille,1} affiche le nombre d'elements affiches (preferer toutefois #TOTAL_UNIQUE)
  1204. # ameliorations possibles :
  1205. # 1) si la donnee est grosse, mettre son md5 comme cle
  1206. # 2) purger $mem quand on change de squelette (sinon bug inclusions)
  1207. //
  1208. // http://www.spip.net/@unique
  1209. // http://doc.spip.org/@unique
  1210. function unique($donnee, $famille='', $cpt = false) {
  1211. static $mem;
  1212. // permettre de vider la pile et de la restaurer
  1213. // pour le calcul de introduction...
  1214. if ($famille=='_spip_raz_'){
  1215. $tmp = $mem;
  1216. $mem = array();
  1217. return $tmp;
  1218. } elseif ($famille=='_spip_set_'){
  1219. $mem = $donnee;
  1220. return;
  1221. }
  1222. if ($cpt)
  1223. return count($mem[$famille]);
  1224. if (!($mem[$famille][$donnee]++))
  1225. return $donnee;
  1226. }
  1227. //
  1228. // Filtre |alterner
  1229. //
  1230. // Exemple [(#COMPTEUR_BOUCLE|alterner{'bleu','vert','rouge'})]
  1231. //
  1232. // http://doc.spip.org/@alterner
  1233. function alterner($i) {
  1234. // recuperer les arguments (attention fonctions un peu space)
  1235. $num = func_num_args();
  1236. $args = func_get_args();
  1237. if($num == 2 && is_array($args[1])) {
  1238. $args = $args[1];
  1239. array_unshift($args,'');
  1240. $num = count($args);
  1241. }
  1242. // renvoyer le i-ieme argument, modulo le nombre d'arguments
  1243. return $args[(intval($i)-1)%($num-1)+1];
  1244. }
  1245. // recuperer un attribut d'une balise html
  1246. // ($complet demande de retourner $r)
  1247. // la regexp est mortelle : cf. tests/filtres/extraire_attribut.php
  1248. // Si on a passe un tableau de balises, renvoyer un tableau de resultats
  1249. // (dans ce cas l'option $complet n'est pas disponible)
  1250. // http://doc.spip.org/@extraire_attribut
  1251. function extraire_attribut($balise, $attribut, $complet = false) {
  1252. if (is_array($balise)) {
  1253. array_walk($balise,
  1254. create_function('&$a,$key,$t',
  1255. '$a = extraire_attribut($a,$t);'
  1256. ),
  1257. $attribut);
  1258. return $balise;
  1259. }
  1260. if (preg_match(
  1261. ',(^.*?<(?:(?>\s*)(?>[\w:.-]+)(?>(?:=(?:"[^"]*"|\'[^\']*\'|[^\'"]\S*))?))*?)(\s+'
  1262. .$attribut
  1263. .'(?:=\s*("[^"]*"|\'[^\']*\'|[^\'"]\S*))?)()([^>]*>.*),isS',
  1264. $balise, $r)) {
  1265. if ($r[3][0] == '"' || $r[3][0] == "'") {
  1266. $r[4] = substr($r[3], 1, -1);
  1267. $r[3] = $r[3][0];
  1268. } elseif ($r[3]!=='') {
  1269. $r[4] = $r[3];
  1270. $r[3] = '';
  1271. } else {
  1272. $r[4] = trim($r[2]);
  1273. }
  1274. $att = filtrer_entites(str_replace("&#39;", "'", $r[4]));
  1275. }
  1276. else
  1277. $att = NULL;
  1278. if ($complet)
  1279. return array($att, $r);
  1280. else
  1281. return $att;
  1282. }
  1283. // modifier (ou inserer) un attribut html dans une balise
  1284. // http://doc.spip.org/@inserer_attribut
  1285. function inserer_attribut($balise, $attribut, $val, $proteger=true, $vider=false) {
  1286. // preparer l'attribut
  1287. // supprimer les &nbsp; etc mais pas les balises html
  1288. // qui ont un sens dans un attribut value d'un input
  1289. if ($proteger) $val = attribut_html($val,false);
  1290. // echapper les ' pour eviter tout bug
  1291. $val = str_replace("'", "&#39;", $val);
  1292. if ($vider AND strlen($val)==0)
  1293. $insert = '';
  1294. else
  1295. $insert = " $attribut='$val'";
  1296. list($old, $r) = extraire_attribut($balise, $attribut, true);
  1297. if ($old !== NULL) {
  1298. // Remplacer l'ancien attribut du meme nom
  1299. $balise = $r[1].$insert.$r[5];
  1300. }
  1301. else {
  1302. // preferer une balise " />" (comme <img />)
  1303. if (preg_match(',/>,', $balise))
  1304. $balise = preg_replace(",\s?/>,S", $insert." />", $balise, 1);
  1305. // sinon une balise <a ...> ... </a>
  1306. else
  1307. $balise = preg_replace(",\s?>,S", $insert.">", $balise, 1);
  1308. }
  1309. return $balise;
  1310. }
  1311. // http://doc.spip.org/@vider_attribut
  1312. function vider_attribut ($balise, $attribut) {
  1313. return inserer_attribut($balise, $attribut, '', false, true);
  1314. }
  1315. // Un filtre pour determiner le nom du mode des librement inscrits,
  1316. // a l'aide de la liste globale des statuts (tableau mode => nom du mode)
  1317. // Utile pour le formulaire d'inscription.
  1318. // Si un mode est fourni, verifier que la configuration l'accepte.
  1319. // Si mode inconnu laisser faire, c'est une extension non std
  1320. // mais verifier que la syntaxe est compatible avec SQL
  1321. // http://doc.spip.org/@tester_config
  1322. function tester_config($id, $mode='') {
  1323. $s = array_search($mode, $GLOBALS['liste_des_statuts']);
  1324. switch ($s) {
  1325. case 'info_redacteurs' :
  1326. return (($GLOBALS['meta']['accepter_inscriptions'] == 'oui') ? $mode : '');
  1327. case 'info_visiteurs' :
  1328. return (($GLOBALS['meta']['accepter_visiteurs'] == 'oui' OR $GLOBALS['meta']['forums_publics'] == 'abo') ? $mode : '');
  1329. default:
  1330. if ($mode AND $mode == addslashes($mode))
  1331. return $mode;
  1332. if ($GLOBALS['meta']["accepter_inscriptions"] == "oui")
  1333. return $GLOBALS['liste_des_statuts']['info_redacteurs'];
  1334. if ($GLOBALS['meta']["accepter_visiteurs"] == "oui")
  1335. return $GLOBALS['liste_des_statuts']['info_visiteurs'];
  1336. return '';
  1337. }
  1338. }
  1339. //
  1340. // Un filtre qui, etant donne un #PARAMETRES_FORUM, retourne un URL de suivi rss
  1341. // dudit forum
  1342. // Attention applique a un #PARAMETRES_FORUM complexe (id_article=x&id_forum=y)
  1343. // ca retourne un url de suivi du thread y (que le thread existe ou non)
  1344. // http://doc.spip.org/@url_rss_forum
  1345. function url_rss_forum($param) {
  1346. if (!preg_match(',.*(id_(\w*?))=([0-9]+),S', $param, $regs)) return '';
  1347. list(,$k,$t,$v) = $regs;
  1348. if ($t == 'forum') $k = 'id_' . ($t = 'thread');
  1349. return generer_url_public("rss_forum_$t", array($k => $v));
  1350. }
  1351. //
  1352. // Un filtre applique a #PARAMETRES_FORUM, qui donne l'adresse de la page
  1353. // de reponse
  1354. //
  1355. // http://doc.spip.org/@url_reponse_forum
  1356. function url_reponse_forum($parametres) {
  1357. if (!$parametres) return '';
  1358. return generer_url_public('forum', $parametres);
  1359. }
  1360. //
  1361. // Quelques fonctions de calcul arithmetique
  1362. //
  1363. // http://doc.spip.org/@plus
  1364. function plus($a,$b) {
  1365. return $a+$b;
  1366. }
  1367. // http://doc.spip.org/@moins
  1368. function moins($a,$b) {
  1369. return $a-$b;
  1370. }
  1371. // http://doc.spip.org/@mult
  1372. function mult($a,$b) {
  1373. return $a*$b;
  1374. }
  1375. // http://doc.spip.org/@div
  1376. function div($a,$b) {
  1377. return $b?$a/$b:0;
  1378. }
  1379. // http://doc.spip.org/@modulo
  1380. function modulo($nb, $mod, $add=0) {
  1381. return ($mod?$nb%$mod:0)+$add;
  1382. }
  1383. // Verifier la conformite d'une ou plusieurs adresses email
  1384. // retourne false ou la normalisation de la derniere adresse donnee
  1385. // http://doc.spip.org/@email_valide
  1386. function email_valide($adresses) {
  1387. // eviter d'injecter n'importe quoi dans preg_match
  1388. if (!is_string($adresses))
  1389. return false;
  1390. // Si c'est un spammeur autant arreter tout de suite
  1391. if (preg_match(",[\n\r].*(MIME|multipart|Content-),i", $adresses)) {
  1392. spip_log("Tentative d'injection de mail : $adresses");
  1393. return false;
  1394. }
  1395. foreach (explode(',', $adresses) as $v) {
  1396. // nettoyer certains formats
  1397. // "Marie Toto <Marie@toto.com>"
  1398. $adresse = trim(preg_replace(",^[^<>\"]*<([^<>\"]+)>$,i", "\\1", $v));
  1399. // RFC 822
  1400. if (!preg_match('#^[^()<>@,;:\\"/[:space:]]+(@([-_0-9a-z]+\.)*[-_0-9a-z]+)$#i', $adresse))
  1401. return false;
  1402. }
  1403. return $adresse;
  1404. }
  1405. // http://doc.spip.org/@afficher_enclosures
  1406. function afficher_enclosures($tags) {
  1407. $s = array();
  1408. foreach (extraire_balises($tags, 'a') as $tag) {
  1409. if (extraire_attribut($tag, 'rel') == 'enclosure'
  1410. AND $t = extraire_attribut($tag, 'href')) {
  1411. $s[] = preg_replace(',>[^<]+</a>,S',
  1412. '>'
  1413. .http_img_pack('attachment.gif', $t,
  1414. 'height="15" width="15" title="'.attribut_html($t).'"')
  1415. .'</a>', $tag);
  1416. }
  1417. }
  1418. return join('&nbsp;', $s);
  1419. }
  1420. // http://doc.spip.org/@afficher_tags
  1421. function afficher_tags($tags, $rels='tag,directory') {
  1422. $s = array();
  1423. foreach (extraire_balises($tags, 'a') as $tag) {
  1424. $rel = extraire_attribut($tag, 'rel');
  1425. if (strstr(",$rels,", ",$rel,"))
  1426. $s[] = $tag;
  1427. }
  1428. return join(', ', $s);
  1429. }
  1430. // Passe un <enclosure url="fichier" length="5588242" type="audio/mpeg"/>
  1431. // au format microformat <a rel="enclosure" href="fichier" ...>fichier</a>
  1432. // attention length="zz" devient title="zz", pour rester conforme
  1433. // http://doc.spip.org/@enclosure2microformat
  1434. function enclosure2microformat($e) {
  1435. if (!$url = filtrer_entites(extraire_attribut($e, 'url')))
  1436. $url = filtrer_entites(extraire_attribut($e, 'href'));
  1437. $type = extraire_attribut($e, 'type');
  1438. $length = extraire_attribut($e, 'length');
  1439. $fichier = basename($url);
  1440. return '<a rel="enclosure"'
  1441. . ($url? ' href="'.htmlspecialchars($url).'"' : '')
  1442. . ($type? ' type="'.htmlspecialchars($type).'"' : '')
  1443. . ($length? ' title="'.htmlspecialchars($length).'"' : '')
  1444. . '>'.$fichier.'</a>';
  1445. }
  1446. // La fonction inverse
  1447. // http://doc.spip.org/@microformat2enclosure
  1448. function microformat2enclosure($tags) {
  1449. $enclosures = array();
  1450. foreach (extraire_balises($tags, 'a') as $e)
  1451. if (extraire_attribut($e, 'rel') == 'enclosure') {
  1452. $url = filtrer_entites(extraire_attribut($e, 'href'));
  1453. $type = extraire_attribut($e, 'type');
  1454. if (!$length = intval(extraire_attribut($e, 'title')))
  1455. $length = intval(extraire_attribut($e, 'length')); # vieux data
  1456. $fichier = basename($url);
  1457. $enclosures[] = '<enclosure'
  1458. . ($url? ' url="'.htmlspecialchars($url).'"' : '')
  1459. . ($type? ' type="'.htmlspecialchars($type).'"' : '')
  1460. . ($length? ' length="'.$length.'"' : '')
  1461. . ' />';
  1462. }
  1463. return join("\n", $enclosures);
  1464. }
  1465. // Creer les elements ATOM <dc:subject> a partir des tags
  1466. // http://doc.spip.org/@tags2dcsubject
  1467. function tags2dcsubject($tags) {
  1468. $subjects = '';
  1469. foreach (extraire_balises($tags, 'a') as $e) {
  1470. if (extraire_attribut($e, rel) == 'tag') {
  1471. $subjects .= '<dc:subject>'
  1472. . texte_backend(textebrut($e))
  1473. . '</dc:subject>'."\n";
  1474. }
  1475. }
  1476. return $subjects;
  1477. }
  1478. // fabrique un bouton de type $t de Name $n, de Value $v et autres attributs $a
  1479. // http://doc.spip.org/@boutonne
  1480. function boutonne($t, $n, $v, $a='') {
  1481. return "\n<input type='$t'"
  1482. . (!$n ? '' : " name='$n'")
  1483. . " value=\"$v\" $a />";
  1484. }
  1485. // retourne la premiere balise du type demande
  1486. // ex: [(#DESCRIPTIF|extraire_balise{img})]
  1487. // Si on a passe un tableau de textes, renvoyer un tableau de resultats
  1488. // http://doc.spip.org/@extraire_balise
  1489. function extraire_balise($texte, $tag='a') {
  1490. if (is_array($texte)) {
  1491. array_walk($texte,
  1492. create_function('&$a,$key,$t', '$a = extraire_balise($a,$t);'),
  1493. $tag);
  1494. return $texte;
  1495. }
  1496. if (preg_match(
  1497. ",<$tag\b[^>]*(/>|>.*</$tag\b[^>]*>|>),UimsS",
  1498. $texte, $regs))
  1499. return $regs[0];
  1500. }
  1501. // extraire toutes les balises du type demande, sous forme de tableau
  1502. // Si on a passe un tableau de textes, renvoyer un tableau de resultats
  1503. // http://doc.spip.org/@extraire_balises
  1504. function extraire_balises($texte, $tag='a') {
  1505. if (is_array($texte)) {
  1506. array_walk($texte,
  1507. create_function('&$a,$key,$t', '$a = extraire_balises($a,$t);'),
  1508. $tag);
  1509. return $texte;
  1510. }
  1511. if (preg_match_all(
  1512. ",<${tag}\b[^>]*(/>|>.*</${tag}\b[^>]*>|>),UimsS",
  1513. $texte, $regs, PREG_PATTERN_ORDER))
  1514. return $regs[0];
  1515. else
  1516. return array();
  1517. }
  1518. // comme in_array mais renvoie son 3e arg si le 2er arg n'est pas un tableau
  1519. // prend ' ' comme representant de vrai et '' de faux
  1520. // http://doc.spip.org/@in_any
  1521. function in_any($val, $vals, $def='') {
  1522. return (!is_array($vals) ? $def : (in_array($val, $vals) ? ' ' : ''));
  1523. }
  1524. // valeur_numerique("3*2") => 6
  1525. // n'accepte que les *, + et - (a ameliorer si on l'utilise vraiment)
  1526. // http://doc.spip.org/@valeur_numerique
  1527. function valeur_numerique($expr) {
  1528. if (preg_match(',^[0-9]+(\s*[+*-]\s*[0-9]+)*$,S', trim($expr)))
  1529. eval("\$a = $expr;");
  1530. return intval($a);
  1531. }
  1532. // http://doc.spip.org/@regledetrois
  1533. function regledetrois($a,$b,$c)
  1534. {
  1535. return round($a*$b/$c);
  1536. }
  1537. // Fournit la suite de Input-Hidden correspondant aux parametres de
  1538. // l'URL donnee en argument, compatible avec les types_urls depuis [14447].
  1539. // cf. tests/filtres/form_hidden.html
  1540. // http://doc.spip.org/@form_hidden
  1541. function form_hidden($action) {
  1542. $fond = ''; // inutilise mais necessaire
  1543. $contexte = array();
  1544. if (
  1545. ($renommer = generer_url_entite() OR $renommer = charger_fonction('page','urls'))
  1546. AND $p = $renommer($action, $fond, $contexte)
  1547. AND $p[3]) {
  1548. $contexte = $p[0];
  1549. $contexte['page'] = $p[3];
  1550. $action = preg_replace('/([?]'.$p[3].'[^&=]*[0-9]+)(&|$)/', '?&', $action);
  1551. }
  1552. // on va remplir un tableau de valeurs en prenant bien soin de ne pas
  1553. // ecraser les elements de la forme mots[]=1&mots[]=2
  1554. $values = array();
  1555. // d'abord avec celles de l'url
  1556. if (false !== ($p = strpos($action, '?'))) {
  1557. foreach(preg_split('/&(amp;)?/S',substr($action,$p+1)) as $c){
  1558. list($var,$val) = explode('=', $c, 2);
  1559. if ($var) {
  1560. $val = rawurldecode($val);
  1561. $var = rawurldecode($var); // decoder les [] eventuels
  1562. if (preg_match(',\[\]$,S', $var))
  1563. $values[] = array($var, $val);
  1564. else if (!isset($values[$var]))
  1565. $values[$var] = array($var, $val);
  1566. }
  1567. }
  1568. }
  1569. // ensuite avec celles du contexte, sans doublonner !
  1570. foreach($contexte as $var=>$val)
  1571. if (preg_match(',\[\]$,S', $var))
  1572. $values[] = array($var, $val);
  1573. else if (!isset($values[$var]))
  1574. $values[$var] = array($var, $val);
  1575. // puis on rassemble le tout
  1576. $hidden = array();
  1577. foreach($values as $value) {
  1578. list($var,$val) = $value;
  1579. $hidden[] = '<input name="'
  1580. . entites_html($var)
  1581. .'"'
  1582. . (is_null($val)
  1583. ? ''
  1584. : ' value="'.str_replace("'","&#39;",entites_html($val)).'"'
  1585. )
  1586. . ' type="hidden" />';
  1587. }
  1588. return join("\n", $hidden);
  1589. }
  1590. // http://doc.spip.org/@filtre_bornes_pagination_dist
  1591. function filtre_bornes_pagination_dist($courante, $nombre, $max = 10) {
  1592. if($max<=0 OR $max>=$nombre)
  1593. return array(1, $nombre);
  1594. $premiere = max(1, $courante-floor(($max-1)/2));
  1595. $derniere = min($nombre, $premiere+$max-2);
  1596. $premiere = $derniere == $nombre ? $derniere-$max+1 : $premiere;
  1597. return array($premiere, $derniere);
  1598. }
  1599. // Ces trois fonctions permettent de simuler les filtres |reset et |end
  1600. // pour extraire la premiere ou la derniere valeur d'un tableau ; utile
  1601. // pour la pagination (mais peut-etre a refaire plus simplement)
  1602. // http://doc.spip.org/@filtre_valeur_tableau
  1603. function filtre_valeur_tableau($array, $index) {
  1604. if (!is_array($array)
  1605. OR !isset($array[$index]))
  1606. return null;
  1607. return $array[$index];
  1608. }
  1609. // http://doc.spip.org/@filtre_reset
  1610. function filtre_reset($array) {
  1611. return !is_array($array) ? null : reset($array);
  1612. }
  1613. // http://doc.spip.org/@filtre_end
  1614. function filtre_end($array) {
  1615. return !is_array($array) ? null : end($array);
  1616. }
  1617. // http://doc.spip.org/@filtre_push
  1618. function filtre_push($array, $val) {
  1619. if($array == '' OR !array_push($array, $val)) return '';
  1620. return $array;
  1621. }
  1622. // http://doc.spip.org/@filtre_find
  1623. function filtre_find($array, $val) {
  1624. return (is_array($array) AND in_array($val, $array));
  1625. }
  1626. //
  1627. // fonction standard de calcul de la balise #PAGINATION
  1628. // on peut la surcharger en definissant filtre_pagination dans mes_fonctions
  1629. //
  1630. // http://doc.spip.org/@filtre_pagination_dist
  1631. function filtre_pagination_dist($total, $nom, $position, $pas, $liste = true, $modele='', $connect='', $env=array()) {
  1632. static $ancres = array();
  1633. if ($pas<1) return '';
  1634. $ancre = 'pagination'.$nom; // #pagination_articles
  1635. $debut = 'debut'.$nom; // 'debut_articles'
  1636. // n'afficher l'ancre qu'une fois
  1637. if (!isset($ancres[$ancre]))
  1638. $bloc_ancre = $ancres[$ancre] = "<a name='$ancre' id='$ancre'></a>";
  1639. else $bloc_ancre = '';
  1640. // liste = false : on ne veut que l'ancre
  1641. if (!$liste)
  1642. return $ancres[$ancre];
  1643. $position = min($position,$total);
  1644. $pagination = array(
  1645. 'debut' => $debut,
  1646. 'url' => parametre_url(self(),'fragment',''), // nettoyer l'id ahah eventuel
  1647. 'total' => $total,
  1648. 'position' => intval($position),
  1649. 'pas' => $pas,
  1650. 'nombre_pages' => floor(($total-1)/$pas)+1,
  1651. 'page_courante' => floor(intval($position)/$pas)+1,
  1652. 'ancre' => $ancre,
  1653. 'bloc_ancre' => $bloc_ancre
  1654. );
  1655. if (is_array($env))
  1656. $pagination = array_merge($env,$pagination);
  1657. // Pas de pagination
  1658. if ($pagination['nombre_pages']<=1)
  1659. return '';
  1660. if ($modele) $modele = '_'.$modele;
  1661. return recuperer_fond("modeles/pagination$modele", $pagination, array('trim'=>true), $connect);
  1662. }
  1663. // passer les url relatives a la css d'origine en url absolues
  1664. // http://doc.spip.org/@urls_absolues_css
  1665. function urls_absolues_css($contenu, $source) {
  1666. $path = suivre_lien(url_absolue($source),'./');
  1667. $contenu = preg_replace_callback(
  1668. ",url\s*\(\s*['\"]?([^'\"/][^:]*)['\"]?\s*\),Uims",
  1669. create_function('$x',
  1670. 'return "url(\"".suivre_lien("'.$path.'",$x[1])."\")";'
  1671. ), $contenu);
  1672. // les directives filter ... progid:DXImageTransform.Microsoft.AlphaImageLoader(src=...,..)
  1673. // de IEx prennent des urls relatives a la page, et non a la css
  1674. // ne pas y toucher.
  1675. /*
  1676. $contenu = preg_replace_callback(
  1677. ";\(\s*src=['\"]?([^'\"/][^:]*)['\"]?\s*(,|\));Uims",
  1678. create_function('$x',
  1679. 'return "(src=\"".suivre_lien("'.$path.'",$x[1])."\"".$x[2];'
  1680. ), $contenu);
  1681. */
  1682. return $contenu;
  1683. }
  1684. // recuperere le chemin d'une css existante et :
  1685. // 1. regarde si une css inversee droite-gauche existe dans le meme repertoire
  1686. // 2. sinon la cree (ou la recree) dans _DIR_VAR/cache_css/
  1687. // SI on lui donne a manger une feuille nommee _rtl.css il va faire l'inverse
  1688. // http://doc.spip.org/@direction_css
  1689. function direction_css ($css, $voulue='') {
  1690. if (!preg_match(',(_rtl)?\.css$,i', $css, $r)) return $css;
  1691. // si on a precise le sens voulu en argument, le prendre en compte
  1692. if ($voulue = strtolower($voulue)) {
  1693. if ($voulue != 'rtl' AND $voulue != 'ltr')
  1694. $voulue = lang_dir($voulue);
  1695. }
  1696. else
  1697. $voulue = lang_dir();
  1698. $r = count($r) > 1;
  1699. $right = $r ? 'left' : 'right'; // 'right' de la css lue en entree
  1700. $dir = $r ? 'rtl' : 'ltr';
  1701. $ndir = $r ? 'ltr' : 'rtl';
  1702. if ($voulue == $dir)
  1703. return $css;
  1704. if (
  1705. // url absolue
  1706. preg_match(",^http:,i",$css)
  1707. // ou qui contient un ?
  1708. OR (($p=strpos($css,'?'))!==FALSE)) {
  1709. $distant = true;
  1710. $cssf = parse_url($css);
  1711. $cssf = $cssf['path'].($cssf['query']?"?".$cssf['query']:"");
  1712. $cssf = preg_replace(',[\W],', "_", $cssf);
  1713. }
  1714. else {
  1715. $distant = false;
  1716. $cssf = $css;
  1717. // 1. regarder d'abord si un fichier avec la bonne direction n'est pas aussi
  1718. //propose (rien a faire dans ce cas)
  1719. $f = preg_replace(',(_rtl)?\.css$,i', '_'.$ndir.'.css', $css);
  1720. if (@file_exists($f))
  1721. return $f;
  1722. }
  1723. // 2.
  1724. $dir_var = sous_repertoire (_DIR_VAR, 'cache-css');
  1725. $f = $dir_var
  1726. . preg_replace(',.*/(.*?)(_rtl)?\.css,', '\1', $cssf)
  1727. . '.' . substr(md5($cssf), 0,4) . '_' . $ndir . '.css';
  1728. // la css peut etre distante (url absolue !)
  1729. if ($distant){
  1730. include_spip('inc/distant');
  1731. $contenu = recuperer_page($css);
  1732. if (!$contenu) return $css;
  1733. }
  1734. else {
  1735. if ((@filemtime($f) > @filemtime($css))
  1736. AND ($GLOBALS['var_mode'] != 'recalcul'))
  1737. return $f;
  1738. if (!lire_fichier($css, $contenu))
  1739. return $css;
  1740. }
  1741. $contenu = str_replace(
  1742. array('right', 'left', '@@@@L E F T@@@@'),
  1743. array('@@@@L E F T@@@@', 'right', 'left'),
  1744. $contenu);
  1745. // reperer les @import auxquels il faut propager le direction_css
  1746. preg_match_all(",\@import\s*url\s*\(\s*['\"]?([^'\"/][^:]*)['\"]?\s*\),Uims",$contenu,$regs);
  1747. $src = array();$src_direction_css = array();$src_faux_abs=array();
  1748. $d = dirname($css);
  1749. foreach($regs[1] as $k=>$import_css){
  1750. $css_direction = direction_css("$d/$import_css",$voulue);
  1751. // si la css_direction est dans le meme path que la css d'origine, on tronque le path, elle sera passee en absolue
  1752. if (substr($css_direction,0,strlen($d)+1)=="$d/") $css_direction = substr($css_direction,strlen($d)+1);
  1753. // si la css_direction commence par $dir_var on la fait passer pour une absolue
  1754. elseif (substr($css_direction,0,strlen($dir_var))==$dir_var) {
  1755. $css_direction = substr($css_direction,strlen($dir_var));
  1756. $src_faux_abs["/@@@@@@/".$css_direction] = $css_direction;
  1757. $css_direction = "/@@@@@@/".$css_direction;
  1758. }
  1759. $src[] = $regs[0][$k];
  1760. $src_direction_css[] = str_replace($import_css,$css_direction,$regs[0][$k]);
  1761. }
  1762. $contenu = str_replace($src,$src_direction_css,$contenu);
  1763. $contenu = urls_absolues_css($contenu, $css);
  1764. // virer les fausses url absolues que l'on a mis dans les import
  1765. if (count($src_faux_abs))
  1766. $contenu = str_replace(array_keys($src_faux_abs),$src_faux_abs,$contenu);
  1767. if (!ecrire_fichier($f, $contenu))
  1768. return $css;
  1769. return $f;
  1770. }
  1771. // recuperere le chemin d'une css existante et :
  1772. // cree (ou recree) dans _DIR_VAR/cache_css/ une css dont les url relatives sont passees en url absolues
  1773. // http://doc.spip.org/@url_absolue_css
  1774. function url_absolue_css ($css) {
  1775. if (!preg_match(',\.css$,i', $css, $r)) return $css;
  1776. $url_absolue_css = url_absolue($css);
  1777. $f = basename($css,'.css');
  1778. $f = sous_repertoire (_DIR_VAR, 'cache-css')
  1779. . preg_replace(",(.*?)(_rtl|_ltr)?$,","\\1-urlabs-" . substr(md5("$css-urlabs"), 0,4) . "\\2",$f)
  1780. . '.css';
  1781. if ((@filemtime($f) > @filemtime($css))
  1782. AND ($GLOBALS['var_mode'] != 'recalcul'))
  1783. return $f;
  1784. if ($url_absolue_css==$css){
  1785. if (strncmp($GLOBALS['meta']['adresse_site'],$css,$l=strlen($GLOBALS['meta']['adresse_site']))!=0
  1786. OR !lire_fichier(_DIR_RACINE . substr($css,$l), $contenu)){
  1787. include_spip('inc/distant');
  1788. if (!$contenu = recuperer_page($css))
  1789. return $css;
  1790. }
  1791. }
  1792. elseif (!lire_fichier($css, $contenu))
  1793. return $css;
  1794. // passer les url relatives a la css d'origine en url absolues
  1795. $contenu = urls_absolues_css($contenu, $css);
  1796. // ecrire la css
  1797. if (!ecrire_fichier($f, $contenu))
  1798. return $css;
  1799. return $f;
  1800. }
  1801. // filtre table_valeur
  1802. // permet de recuperer la valeur d'un tableau pour une cle donnee
  1803. // prend en entree un tableau serialise ou non (ce qui permet d'enchainer le filtre)
  1804. // http://doc.spip.org/@table_valeur
  1805. function table_valeur($table,$cle,$defaut=''){
  1806. $table= is_string($table)?unserialize($table):$table;
  1807. $table= is_array($table)?$table:array();
  1808. return isset($table[$cle])?$table[$cle]:$defaut;
  1809. }
  1810. // filtre match pour faire des tests avec expression reguliere
  1811. // [(#TEXTE|match{^ceci$,Uims})]
  1812. // retourne le fragment de chaine qui "matche"
  1813. // il est possible de passer en 3eme argument optionnel le numero de parenthese capturante
  1814. // accepte egalement la syntaxe #TRUC|match{truc(...)$,1} ou le modificateur n'est pas passe en second argument
  1815. // http://doc.spip.org/@match
  1816. function match($texte, $expression, $modif="UimsS",$capte=0) {
  1817. if (intval($modif) AND $capte==0){
  1818. $capte = $modif;
  1819. $modif = "UimsS";
  1820. }
  1821. $expression=str_replace("\/","/",$expression);
  1822. $expression=str_replace("/","\/",$expression);
  1823. if (preg_match('/' . $expression . '/' . $modif,$texte, $r)) {
  1824. if (isset($r[$capte]))
  1825. return $r[$capte];
  1826. else
  1827. return true;
  1828. }
  1829. return false;
  1830. }
  1831. // filtre replace pour faire des operations avec expression reguliere
  1832. // [(#TEXTE|replace{^ceci$,cela,UimsS})]
  1833. // http://doc.spip.org/@replace
  1834. function replace($texte, $expression, $replace='', $modif="UimsS") {
  1835. $expression=str_replace("\/","/", $expression);
  1836. $expression=str_replace("/","\/",$expression);
  1837. return preg_replace('/' . $expression . '/' . $modif, $replace, $texte);
  1838. }
  1839. // cherche les documents numerotes dans un texte traite par propre()
  1840. // et affecte les doublons['documents']
  1841. // http://doc.spip.org/@traiter_doublons_documents
  1842. // http://doc.spip.org/@traiter_doublons_documents
  1843. function traiter_doublons_documents(&$doublons, $letexte) {
  1844. // Verifier dans le texte & les notes (pas beau, helas)
  1845. $t = $letexte.$GLOBALS['les_notes'];
  1846. if (strstr($t, 'spip_document_') // evite le preg_match_all si inutile
  1847. AND preg_match_all(
  1848. ',<[^>]+\sclass=["\']spip_document_([0-9]+)[\s"\'],imsS',
  1849. $t, $matches, PREG_PATTERN_ORDER))
  1850. $doublons['documents'] .= "," . join(',', $matches[1]);
  1851. return $letexte;
  1852. }
  1853. // filtre vide qui ne renvoie rien
  1854. // http://doc.spip.org/@vide
  1855. function vide($texte){
  1856. return "";
  1857. }
  1858. //
  1859. // Filtres pour le modele/emb (embed document)
  1860. //
  1861. // A partir d'un #ENV, retourne des <param ...>
  1862. // http://doc.spip.org/@env_to_params
  1863. function env_to_params ($texte, $ignore_params=array()) {
  1864. $ignore_params = array_merge (
  1865. array('id', 'lang', 'id_document', 'date', 'date_redac', 'align', 'fond', '', 'recurs', 'emb', 'dir_racine'),
  1866. $ignore_params);
  1867. $tableau = unserialize($texte);
  1868. $texte = "";
  1869. foreach ($tableau as $i => $j)
  1870. if (is_string($j) AND !in_array($i,$ignore_params))
  1871. $texte .= "<param name='".$i."'\n\tvalue='".$j."' />";
  1872. return $texte;
  1873. }
  1874. // A partir d'un #ENV, retourne des attributs
  1875. // http://doc.spip.org/@env_to_attributs
  1876. function env_to_attributs ($texte, $ignore_params=array()) {
  1877. $ignore_params = array_merge (
  1878. array('id', 'lang', 'id_document', 'date', 'date_redac', 'align', 'fond', '', 'recurs', 'emb', 'dir_racine'),
  1879. $ignore_params);
  1880. $tableau = unserialize($texte);
  1881. $texte = "";
  1882. foreach ($tableau as $i => $j)
  1883. if (is_string($j) AND !in_array($i,$ignore_params))
  1884. $texte .= $i."='".$j."' ";
  1885. return $texte;
  1886. }
  1887. // Inserer jQuery
  1888. // et au passage verifier qu'on ne doublonne pas #INSERT_HEAD
  1889. // http://doc.spip.org/@f_jQuery
  1890. function f_jQuery ($texte) {
  1891. static $doublon=0;
  1892. if ($doublon++) {
  1893. erreur_squelette(array('double_occurrence', array('balise' => "INSERT_HEAD")));
  1894. } else {
  1895. $x = '';
  1896. foreach (array_unique(pipeline('jquery_plugins',
  1897. array(
  1898. 'javascript/jquery.js',
  1899. 'javascript/jquery.form.js',
  1900. 'javascript/ajaxCallback.js',
  1901. 'javascript/jquery.cookie.js'
  1902. ))) as $script)
  1903. if ($script = find_in_path($script))
  1904. $x .= "\n<script src=\"$script\" type=\"text/javascript\"></script>\n";
  1905. $texte = $x.$texte;
  1906. }
  1907. return $texte;
  1908. }
  1909. /**
  1910. * fonction appelee par #INSERT_HEAD_CSS et #INSERT_HEAD pour la compatibilite
  1911. * @staticvar <type> $done
  1912. * @return <type>
  1913. */
  1914. function insert_head_css(){
  1915. static $done = false;
  1916. if ($done) return '';
  1917. $done = true;
  1918. return pipeline('insert_head_css','');
  1919. }
  1920. // Concatener des chaines
  1921. // #TEXTE|concat{texte1,texte2,...}
  1922. // http://doc.spip.org/@concat
  1923. function concat(){
  1924. $args = func_get_args();
  1925. return join('', $args);
  1926. }
  1927. // http://doc.spip.org/@charge_scripts
  1928. function charge_scripts($scripts) {
  1929. $flux = "";
  1930. $args = is_array($scripts)?$scripts:explode("|",$scripts);
  1931. foreach($args as $script) {
  1932. if(preg_match(",^\w+$,",$script)) {
  1933. $path = find_in_path("javascript/$script.js");
  1934. if($path) $flux .= spip_file_get_contents($path);
  1935. }
  1936. }
  1937. return $flux;
  1938. }
  1939. // produit une balise img avec un champ alt d'office si vide
  1940. // attention le htmlentities et la traduction doivent etre appliques avant.
  1941. // http://doc.spip.org/@http_wrapper
  1942. function http_wrapper($img){
  1943. if (strpos($img,'/')===FALSE) // on ne prefixe par _NOM_IMG_PACK que si c'est un nom de fichier sans chemin
  1944. $f = chemin_image($img);
  1945. else { // sinon, le path a ete fourni
  1946. $f = $img;
  1947. }
  1948. return $f;
  1949. }
  1950. // http://doc.spip.org/@http_img_pack
  1951. function http_img_pack($img, $alt, $atts='', $title='') {
  1952. $img = http_wrapper($img);
  1953. if (strpos($atts, 'width')===FALSE){
  1954. // utiliser directement l'info de taille presente dans le nom
  1955. if (preg_match(',-([0-9]+)[.](png|gif)$,',$img,$regs)){
  1956. $size = array(intval($regs[1]),intval($regs[1]));
  1957. }
  1958. else
  1959. $size = @getimagesize($img);
  1960. $atts.=" width='".$size[0]."' height='".$size[1]."'";
  1961. }
  1962. return "<img src='" . $img
  1963. . ("'\nalt=\"" .
  1964. str_replace('"','', textebrut($alt ? $alt : ($title ? $title : '')))
  1965. . '" ')
  1966. . ($title ? "title=\"$title\" " : '')
  1967. . $atts
  1968. . " />";
  1969. }
  1970. // http://doc.spip.org/@http_style_background
  1971. function http_style_background($img, $att='')
  1972. {
  1973. return " style='background: url(\"".http_wrapper($img)."\")" .
  1974. ($att ? (' ' . $att) : '') . ";'";
  1975. }
  1976. //[(#ENV*|unserialize|foreach)]
  1977. // http://doc.spip.org/@filtre_foreach_dist
  1978. function filtre_foreach_dist($balise_deserializee, $modele = 'foreach') {
  1979. $texte = '';
  1980. if(is_array($balise_deserializee))
  1981. foreach($balise_deserializee as $k => $v) {
  1982. $res = recuperer_fond('modeles/'.$modele,
  1983. array_merge(array('cle' => $k), (is_array($v) ? $v : array('valeur' => $v)))
  1984. );
  1985. $texte .= $res;
  1986. }
  1987. return $texte;
  1988. }
  1989. // renvoie la liste des plugins actifs du site
  1990. // si le premier parametre est un prefix de cette liste, renvoie vrai, faux sinon
  1991. // la valeur du second parametre si celui-ci renvoie a une information connue
  1992. // cf liste_plugin_actifs() pour connaitre les informations affichables
  1993. // appelee par la balise #PLUGIN
  1994. // http://doc.spip.org/@filtre_info_plugin_dist
  1995. function filtre_info_plugin_dist($plugin, $type_info) {
  1996. include_spip('inc/plugin');
  1997. $plugin = strtoupper($plugin);
  1998. $plugins_actifs = liste_plugin_actifs();
  1999. if (!$plugin)
  2000. return serialize(array_keys($plugins_actifs));
  2001. elseif (empty($plugins_actifs[$plugin]))
  2002. return '';
  2003. elseif ($type_info == 'est_actif')
  2004. return $plugins_actifs[$plugin] ? 1 : 0;
  2005. elseif (isset($plugins_actifs[$plugin][$type_info]))
  2006. return $plugins_actifs[$plugin][$type_info];
  2007. else {
  2008. $get_infos = charger_fonction('get_infos','plugins');
  2009. // On prend en compte les extensions
  2010. if (!is_dir($plugins_actifs[$plugin]['dir_type']))
  2011. $dir_plugins = constant($plugins_actifs[$plugin]['dir_type']);
  2012. else
  2013. $dir_plugins = $plugins_actifs[$plugin]['dir_type'];
  2014. if (!$infos = $get_infos($plugins_actifs[$plugin]['dir'], false, $dir_plugins))
  2015. return '';
  2016. if ($type_info == 'tout')
  2017. return $infos;
  2018. else
  2019. return strval($infos[$type_info]);
  2020. }
  2021. }
  2022. // http://doc.spip.org/@chercher_rubrique
  2023. function chercher_rubrique($msg,$id, $id_parent, $type, $id_secteur, $restreint,$actionable = false, $retour_sans_cadre=false){
  2024. global $spip_lang_right;
  2025. include_spip('inc/autoriser');
  2026. if (intval($id) && !autoriser('modifier', $type, $id))
  2027. return "";
  2028. if (!sql_countsel('spip_rubriques'))
  2029. return "";
  2030. $chercher_rubrique = charger_fonction('chercher_rubrique', 'inc');
  2031. $form = $chercher_rubrique($id_parent, $type, $restreint, ($type=='rubrique')?$id:0);
  2032. if ($id_parent == 0) $logo = "racine-site-24.gif";
  2033. elseif ($id_secteur == $id_parent) $logo = "secteur-24.gif";
  2034. else $logo = "rubrique-24.gif";
  2035. $confirm = "";
  2036. if ($type=='rubrique') {
  2037. // si c'est une rubrique-secteur contenant des breves, demander la
  2038. // confirmation du deplacement
  2039. $contient_breves = sql_countsel('spip_breves', "id_rubrique=$id");
  2040. if ($contient_breves > 0) {
  2041. $scb = ($contient_breves>1? 's':'');
  2042. $scb = _T('avis_deplacement_rubrique',
  2043. array('contient_breves' => $contient_breves,
  2044. 'scb' => $scb));
  2045. $confirm .= "\n<div class='confirmer_deplacement verdana2'><div class='choix'><input type='checkbox' name='confirme_deplace' value='oui' id='confirme-deplace' /><label for='confirme-deplace'>" . $scb . "</label></div></div>\n";
  2046. } else
  2047. $confirm .= "<input type='hidden' name='confirme_deplace' value='oui' />\n";
  2048. }
  2049. $form .= $confirm;
  2050. if ($actionable){
  2051. if (strpos($form,'<select')!==false) {
  2052. $form .= "<div style='text-align: $spip_lang_right;'>"
  2053. . '<input type="submit" value="'._T('bouton_choisir').'"/>'
  2054. . "</div>";
  2055. }
  2056. $form = "<input type='hidden' name='editer_$type' value='oui' />\n" . $form;
  2057. $form = generer_action_auteur("editer_$type", $id, self(), $form, " method='post' class='submit_plongeur'");
  2058. }
  2059. if ($retour_sans_cadre)
  2060. return $form;
  2061. include_spip('inc/presentation');
  2062. return debut_cadre_couleur($logo, true, "", $msg) . $form .fin_cadre_couleur(true);
  2063. }
  2064. // http://doc.spip.org/@puce_changement_statut
  2065. function puce_changement_statut($id_objet, $statut, $id_rubrique, $type, $ajax=false){
  2066. $puce_statut = charger_fonction('puce_statut','inc');
  2067. return $puce_statut($id_objet, $statut, $id_rubrique, $type, $ajax=false);
  2068. }
  2069. // Encoder un contexte pour l'ajax, le signer avec une cle, le crypter
  2070. // avec le secret du site, le gziper si possible...
  2071. // l'entree peut etre serialisee (le #ENV** des fonds ajax et ajax_stat)
  2072. // http://doc.spip.org/@encoder_contexte_ajax
  2073. function encoder_contexte_ajax($c,$form='', $emboite=NULL) {
  2074. if (is_string($c)
  2075. AND !is_null(@unserialize($c)))
  2076. $c = unserialize($c);
  2077. // supprimer les parametres debut_x
  2078. // pour que la pagination ajax ne soit pas plantee
  2079. // si on charge la page &debut_x=1 : car alors en cliquant sur l'item 0,
  2080. // le debut_x=0 n'existe pas, et on resterait sur 1
  2081. foreach ($c as $k => $v)
  2082. if (strpos($k,'debut_') === 0)
  2083. unset($c[$k]);
  2084. include_spip("inc/securiser_action");
  2085. $cle = calculer_cle_action($form.(is_array($c)?serialize($c):$c));
  2086. $c = serialize(array($c,$cle));
  2087. if ((defined('_CACHE_CONTEXTES_AJAX') AND _CACHE_CONTEXTES_AJAX)
  2088. AND $dir = sous_repertoire(_DIR_CACHE, 'contextes')) {
  2089. // stocker les contextes sur disque et ne passer qu'un hash dans l'url
  2090. $md5 = md5($c);
  2091. ecrire_fichier("$dir/c$md5",$c);
  2092. $c = $md5;
  2093. } else {
  2094. if (function_exists('gzdeflate') && function_exists('gzinflate'))
  2095. $c = gzdeflate($c);
  2096. $c = _xor($c);
  2097. $c = base64_encode($c);
  2098. }
  2099. if ($emboite === NULL) return $c;
  2100. return !trim($emboite) ? '' :
  2101. "<div class='ajaxbloc env-$c'>\n$emboite</div><!-- ajaxbloc -->\n";
  2102. }
  2103. // la procedure inverse de encoder_contexte_ajax()
  2104. // http://doc.spip.org/@decoder_contexte_ajax
  2105. function decoder_contexte_ajax($c,$form='') {
  2106. include_spip("inc/securiser_action");
  2107. if (( (defined('_CACHE_CONTEXTES_AJAX') AND _CACHE_CONTEXTES_AJAX) OR strlen($c)==32)
  2108. AND $dir = sous_repertoire(_DIR_CACHE, 'contextes')
  2109. AND lire_fichier("$dir/c$c",$contexte)) {
  2110. $c = $contexte;
  2111. } else {
  2112. $c = @base64_decode($c);
  2113. $c = _xor($c);
  2114. if (function_exists('gzdeflate') && function_exists('gzinflate'))
  2115. $c = @gzinflate($c);
  2116. }
  2117. list($env, $cle) = @unserialize($c);
  2118. if ($cle == calculer_cle_action($form.(is_array($env)?serialize($env):$env)))
  2119. return $env;
  2120. return false;
  2121. }
  2122. // encrypter/decrypter un message
  2123. // http://www.php.net/manual/fr/language.operators.bitwise.php#81358
  2124. // http://doc.spip.org/@_xor
  2125. function _xor($message, $key=null){
  2126. if (is_null($key)) {
  2127. include_spip("inc/securiser_action");
  2128. $key = pack("H*", calculer_cle_action('_xor'));
  2129. }
  2130. $keylen = strlen($key);
  2131. $messagelen = strlen($message);
  2132. for($i=0; $i<$messagelen; $i++)
  2133. $message[$i] = ~($message[$i]^$key[$i%$keylen]);
  2134. return $message;
  2135. }
  2136. /**
  2137. * une fonction pour generer des menus avec liens
  2138. * ou un <strong class='on'> non clicable lorsque l'item est selectionne
  2139. *
  2140. * @param string $url
  2141. * @param string $libelle
  2142. * le texte du lien
  2143. * @param bool $on
  2144. * etat expose (genere un strong) ou non (genere un lien)
  2145. * @param string $class
  2146. * @param string $title
  2147. * @param string $rel
  2148. * @param string $evt
  2149. * complement a la balise a pour gerer un evenement javascript, de la forme " onclick='...'"
  2150. * @return string
  2151. */
  2152. function lien_ou_expose($url,$libelle,$on=false,$class="",$title="",$rel="", $evt=''){
  2153. if ($on) {
  2154. $bal = "strong";
  2155. $att = "class='on'";
  2156. } else {
  2157. $bal = 'a';
  2158. $att = "href='$url'"
  2159. .($title?" title='".attribut_html($title)."'":'')
  2160. .($class?" class='".attribut_html($class)."'":'')
  2161. .($rel?" rel='".attribut_html($rel)."'":'')
  2162. .$evt;
  2163. }
  2164. return "<$bal $att>$libelle</$bal>";
  2165. }
  2166. /**
  2167. * une fonction pour generer une balise img a partir d'un nom de fichier
  2168. *
  2169. * @param string $img
  2170. * @param string $alt
  2171. * @param string $class
  2172. * @return string
  2173. */
  2174. function filtre_balise_img_dist($img,$alt="",$class=""){
  2175. $taille = taille_image($img);
  2176. list($hauteur,$largeur) = $taille;
  2177. if (!$hauteur OR !$largeur)
  2178. return "";
  2179. return
  2180. "<img src='$img' width='$largeur' height='$hauteur'"
  2181. ." alt='".attribut_html($alt)."'"
  2182. .($class?" class='".attribut_html($class)."'":'')
  2183. .' />';
  2184. }
  2185. /**
  2186. * Afficher un message "un truc"/"N trucs"
  2187. *
  2188. * @param int $nb
  2189. * @return string
  2190. */
  2191. function singulier_ou_pluriel($nb,$chaine_un,$chaine_plusieurs,$var='nb'){
  2192. if (!$nb=intval($nb)) return "";
  2193. if ($nb>1) return _T($chaine_plusieurs, array($var => $nb));
  2194. else return _T($chaine_un);
  2195. }
  2196. /**
  2197. * un filtre icone mappe sur icone_inline, qui cree une icone a gauche par defaut
  2198. * le code de icone_inline est grandement reproduit ici car les liens ajax portent simplement une class ajax
  2199. * lorsque les interfaces sont en squelette, alors que l'implementation d'ajax de des scripts php
  2200. * est plus complexe
  2201. *
  2202. * @param string $lien
  2203. * @param string $texte
  2204. * @param string $fond
  2205. * @param string $align
  2206. * @param string $fonction
  2207. * @return string
  2208. */
  2209. function filtre_icone_dist($lien, $texte, $fond, $align="", $fonction="", $class="",$javascript=""){
  2210. if ($icone_renommer = charger_fonction('icone_renommer','inc',true))
  2211. list($fond,$fonction) = $icone_renommer($fond,$fonction);
  2212. $align = $align?$align:$GLOBALS['spip_lang_left'];
  2213. global $spip_display;
  2214. if ($fonction == "del") {
  2215. $style = 'icone36 danger';
  2216. } else {
  2217. $style = 'icone36';
  2218. if (strlen($fonction) < 3) $fonction = "rien.gif";
  2219. }
  2220. $style .= " " . substr(basename($fond),0,-4);
  2221. if ($spip_display == 1){
  2222. $hauteur = 20;
  2223. $largeur = 100;
  2224. $title = $alt = "";
  2225. }
  2226. else if ($spip_display == 3){
  2227. $hauteur = 30;
  2228. $largeur = 30;
  2229. $title = "\ntitle=\"$texte\"";
  2230. $alt = $texte;
  2231. }
  2232. else {
  2233. $hauteur = 70;
  2234. $largeur = 100;
  2235. $title = '';
  2236. $alt = $texte;
  2237. }
  2238. $size = 24;
  2239. if (preg_match("/-([0-9]{1,3})[.](gif|png)$/i",$fond,$match))
  2240. $size = $match[1];
  2241. if ($spip_display != 1 AND $spip_display != 4){
  2242. if ($fonction != "rien.gif"){
  2243. $icone = http_img_pack($fonction, $alt, "$title width='$size' height='$size'\n" .
  2244. http_style_background($fond, "no-repeat center center"));
  2245. }
  2246. else {
  2247. $icone = http_img_pack($fond, $alt, "$title width='$size' height='$size'");
  2248. }
  2249. } else $icone = '';
  2250. // cas d'ajax_action_auteur: faut defaire le boulot
  2251. // (il faudrait fusionner avec le cas $javascript)
  2252. if (preg_match(",^<a\shref='([^']*)'([^>]*)>(.*)</a>$,i",$lien,$r))
  2253. list($x,$lien,$atts,$texte)= $r;
  2254. else $atts = '';
  2255. if ($align && $align!='center') $align = "float: $align; ";
  2256. $icone = "<a style='$align' class='$style $class'"
  2257. . $atts
  2258. . $javascript
  2259. . "\nhref='"
  2260. . $lien
  2261. . "'>"
  2262. . $icone
  2263. . (($spip_display == 3) ? '' : "<span>$texte</span>")
  2264. . "</a>\n";
  2265. if ($align <> 'center') return $icone;
  2266. $style = " style='text-align:center;'";
  2267. return "<div$style>$icone</div>";
  2268. }
  2269. /**
  2270. * filtre explode pour les squelettes permettant d'ecrire
  2271. * #GET{truc}|explode{-}
  2272. *
  2273. * @param strong $a
  2274. * @param string $b
  2275. * @return array
  2276. */
  2277. function filtre_explode_dist($a,$b){return explode($b,$a);}
  2278. /**
  2279. * filtre implode pour les squelettes permettant d'ecrire
  2280. * #GET{truc}|implode{-}
  2281. *
  2282. * @param array $a
  2283. * @param string $b
  2284. * @return string
  2285. */
  2286. function filtre_implode_dist($a,$b){return is_array($a)?implode($b,$a):$a;}
  2287. /*
  2288. * Deux verrues pour que le pipeline de revisions soit correct
  2289. * elles vont sauter quand ca passera en plugin
  2290. */
  2291. function premiere_revision($x) {
  2292. include_spip('inc/revisions');
  2293. return enregistrer_premiere_revision($x);
  2294. }
  2295. function nouvelle_revision($x) {
  2296. include_spip('inc/revisions');
  2297. return enregistrer_nouvelle_revision($x);
  2298. }
  2299. /**
  2300. * Generer un bouton_action
  2301. * utilise par #BOUTON_ACTION
  2302. *
  2303. * @param string $libelle
  2304. * @param string $url
  2305. * @param string $class
  2306. * @param string $confirm
  2307. * @param string $title
  2308. * @return string
  2309. */
  2310. function bouton_action($libelle, $url, $class="", $confirm="", $title=""){
  2311. $onclick = $confirm?" onclick='return confirm(\"" . attribut_html($confirm) . "\");'":"";
  2312. $title = $title ? " title='$title'" : "";
  2313. return "<form class='bouton_action_post $class' method='post' action='$url'><div>".form_hidden($url)
  2314. ."<button type='submit' class='submit'$title$onclick>$libelle</button></div></form>";
  2315. }
  2316. ?>