PageRenderTime 68ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/ecrire/inc/filtres.php

https://github.com/denisbz/SPIP
PHP | 1580 lines | 1132 code | 164 blank | 284 comment | 216 complexity | 58fee47c76d8b1aaf9c35647c80172a5 MD5 | raw file
  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. include_spip('base/objets');
  15. include_spip('public/parametrer'); // charger les fichiers fonctions
  16. /**
  17. * Charger un filtre depuis le php :
  18. * - on inclue tous les fichiers fonctions des plugins et du skel
  19. * - on appelle chercher_filtre
  20. *
  21. * @param string $fonc
  22. * @param string $default
  23. * @return string
  24. */
  25. function charger_filtre($fonc, $default='filtre_identite_dist') {
  26. include_spip('public/parametrer'); // inclure les fichiers fonctions
  27. return chercher_filtre($fonc, $default);
  28. }
  29. function filtre_identite_dist($texte){return $texte;}
  30. /**
  31. * http://doc.spip.org/@chercher_filtre
  32. *
  33. * @param string $fonc
  34. * @param null $default
  35. * @return string
  36. */
  37. function chercher_filtre($fonc, $default=NULL) {
  38. if (!$fonc) return $default;
  39. // Cas des types mime, sans confondre avec les appels de fonction de classe
  40. // Foo::Bar
  41. // qui peuvent etre avec un namespace : space\Foo::Bar
  42. if (preg_match(',^[\w]+/,',$fonc)){
  43. $nom = preg_replace(',\W,','_', $fonc);
  44. $f = chercher_filtre($nom);
  45. // cas du sous-type MIME sans filtre associe, passer au type:
  46. // si filtre_text_plain pas defini, passe a filtre_text
  47. if (!$f AND $nom!==$fonc)
  48. $f = chercher_filtre(preg_replace(',\W.*$,','', $fonc));
  49. return $f;
  50. }
  51. foreach (
  52. array('filtre_'.$fonc, 'filtre_'.$fonc.'_dist', $fonc) as $f){
  53. if (is_string($g = $GLOBALS['spip_matrice'][$f]))
  54. find_in_path($g,'', true);
  55. if (function_exists($f)
  56. OR (preg_match("/^(\w*)::(\w*)$/", $f, $regs)
  57. AND is_callable(array($regs[1], $regs[2]))
  58. )) {
  59. return $f;
  60. }
  61. }
  62. return $default;
  63. }
  64. // http://doc.spip.org/@appliquer_filtre
  65. function appliquer_filtre($arg, $filtre) {
  66. $f = chercher_filtre($filtre);
  67. if (!$f)
  68. return ''; // ou faut-il retourner $arg inchange == filtre_identite?
  69. $args = func_get_args();
  70. array_shift($args); // enlever $arg
  71. array_shift($args); // enlever $filtre
  72. array_unshift($args, $arg); // remettre $arg
  73. return call_user_func_array($f,$args);
  74. }
  75. // http://doc.spip.org/@spip_version
  76. function spip_version() {
  77. $version = $GLOBALS['spip_version_affichee'];
  78. if ($svn_revision = version_svn_courante(_DIR_RACINE))
  79. $version .= ($svn_revision<0 ? ' SVN':'').' ['.abs($svn_revision).']';
  80. return $version;
  81. }
  82. //
  83. // Mention de la revision SVN courante de l'espace restreint standard
  84. // (numero non garanti pour l'espace public et en cas de mutualisation)
  85. // on est negatif si on est sur .svn, et positif si on utilise svn.revision
  86. // http://doc.spip.org/@version_svn_courante
  87. function version_svn_courante($dir) {
  88. if (!$dir) $dir = '.';
  89. // version installee par paquet ZIP
  90. if (lire_fichier($dir.'/svn.revision', $c)
  91. AND preg_match(',Revision: (\d+),', $c, $d))
  92. return intval($d[1]);
  93. // version installee par SVN
  94. if (lire_fichier($dir . '/.svn/entries', $c)
  95. AND (
  96. (preg_match_all(
  97. ',committed-rev="([0-9]+)",', $c, $r1, PREG_PATTERN_ORDER)
  98. AND $v = max($r1[1])
  99. )
  100. OR
  101. (preg_match(',^\d.*dir[\r\n]+(\d+),ms', $c, $r1) # svn >= 1.4
  102. AND $v = $r1[1]
  103. )))
  104. return -$v;
  105. // Bug ou paquet fait main
  106. return 0;
  107. }
  108. // La matrice est necessaire pour ne filtrer _que_ des fonctions definies dans filtres_images
  109. // et laisser passer les fonctions personnelles baptisees image_...
  110. $GLOBALS['spip_matrice']['image_graver'] = true;//'inc/filtres_images_mini.php';
  111. $GLOBALS['spip_matrice']['image_select'] = true;//'inc/filtres_images_mini.php';
  112. $GLOBALS['spip_matrice']['image_reduire'] = true;//'inc/filtres_images_mini.php';
  113. $GLOBALS['spip_matrice']['image_reduire_par'] = true;//'inc/filtres_images_mini.php';
  114. $GLOBALS['spip_matrice']['image_passe_partout'] = true;//'inc/filtres_images_mini.php';
  115. $GLOBALS['spip_matrice']['couleur_html_to_hex'] = 'inc/filtres_images_mini.php';
  116. $GLOBALS['spip_matrice']['couleur_foncer'] = 'inc/filtres_images_mini.php';
  117. $GLOBALS['spip_matrice']['couleur_eclaircir'] = 'inc/filtres_images_mini.php';
  118. // ou pour inclure un script au moment ou l'on cherche le filtre
  119. $GLOBALS['spip_matrice']['filtre_image_dist'] = 'inc/filtres_mime.php';
  120. $GLOBALS['spip_matrice']['filtre_audio_dist'] = 'inc/filtres_mime.php';
  121. $GLOBALS['spip_matrice']['filtre_video_dist'] = 'inc/filtres_mime.php';
  122. $GLOBALS['spip_matrice']['filtre_application_dist'] = 'inc/filtres_mime.php';
  123. $GLOBALS['spip_matrice']['filtre_message_dist'] = 'inc/filtres_mime.php';
  124. $GLOBALS['spip_matrice']['filtre_multipart_dist'] = 'inc/filtres_mime.php';
  125. $GLOBALS['spip_matrice']['filtre_text_dist'] = 'inc/filtres_mime.php';
  126. $GLOBALS['spip_matrice']['filtre_text_csv_dist'] = 'inc/filtres_mime.php';
  127. $GLOBALS['spip_matrice']['filtre_text_html_dist'] = 'inc/filtres_mime.php';
  128. $GLOBALS['spip_matrice']['filtre_audio_x_pn_realaudio'] = 'inc/filtres_mime.php';
  129. // charge les fonctions graphiques et applique celle demandee
  130. // http://doc.spip.org/@filtrer
  131. function filtrer($filtre) {
  132. if (is_string($f = $GLOBALS['spip_matrice'][$filtre])){
  133. find_in_path($f,'', true);
  134. $GLOBALS['spip_matrice'][$filtre] = true;
  135. }
  136. $tous = func_get_args();
  137. if (substr($filtre,0,6)=='image_' && $GLOBALS['spip_matrice'][$filtre])
  138. return image_filtrer($tous);
  139. elseif($f = chercher_filtre($filtre)) {
  140. array_shift($tous);
  141. return call_user_func_array($f, $tous);
  142. }
  143. else {
  144. // le filtre n'existe pas, on provoque une erreur
  145. $msg = array('zbug_erreur_filtre', array('filtre'=>texte_script($filtre)));
  146. erreur_squelette($msg);
  147. return '';
  148. }
  149. }
  150. // fonction generique d'entree des filtres images
  151. // accepte en entree un texte complet, un img-log (produit par #LOGO_XX),
  152. // un tag <img ...> complet, ou encore un nom de fichier *local* (passer
  153. // le filtre |copie_locale si on veut l'appliquer a un document)
  154. // applique le filtre demande a chacune des occurrences
  155. // http://doc.spip.org/@image_filtrer
  156. function image_filtrer($args){
  157. $filtre = array_shift($args); # enlever $filtre
  158. $texte = array_shift($args);
  159. if (!strlen($texte)) return;
  160. find_in_path('filtres_images_mini.php','inc/', true);
  161. statut_effacer_images_temporaires(true); // activer la suppression des images temporaires car le compilo finit la chaine par un image_graver
  162. // Cas du nom de fichier local
  163. if ( strpos(substr($texte,strlen(_DIR_RACINE)),'..')===FALSE
  164. AND !preg_match(',^/|[<>]|\s,S', $texte)
  165. AND (
  166. file_exists(preg_replace(',[?].*$,','',$texte))
  167. OR preg_match(';^(\w{3,7}://);', $texte)
  168. )) {
  169. array_unshift($args,"<img src='$texte' />");
  170. $res = call_user_func_array($filtre, $args);
  171. statut_effacer_images_temporaires(false); // desactiver pour les appels hors compilo
  172. return $res;
  173. }
  174. // Cas general : trier toutes les images, avec eventuellement leur <span>
  175. if (preg_match_all(
  176. ',(<([a-z]+) [^<>]*spip_documents[^<>]*>)?\s*(<img\s.*>),UimsS',
  177. $texte, $tags, PREG_SET_ORDER)) {
  178. foreach ($tags as $tag) {
  179. $class = extraire_attribut($tag[3],'class');
  180. if (!$class || (strpos($class,'no_image_filtrer')===FALSE)){
  181. array_unshift($args,$tag[3]);
  182. if ($reduit = call_user_func_array($filtre, $args)) {
  183. // En cas de span spip_documents, modifier le style=...width:
  184. if($tag[1]){
  185. $w = extraire_attribut($reduit, 'width');
  186. if (!$w AND preg_match(",width:\s*(\d+)px,S",extraire_attribut($reduit,'style'),$regs))
  187. $w = $regs[1];
  188. if ($w AND ($style = extraire_attribut($tag[1], 'style'))){
  189. $style = preg_replace(",width:\s*\d+px,S", "width:${w}px", $style);
  190. $replace = inserer_attribut($tag[1], 'style', $style);
  191. $texte = str_replace($tag[1], $replace, $texte);
  192. }
  193. }
  194. // traiter aussi un eventuel mouseover
  195. if ($mouseover = extraire_attribut($reduit,'onmouseover')){
  196. if (preg_match(",this[.]src=['\"]([^'\"]+)['\"],ims", $mouseover, $match)){
  197. $srcover = $match[1];
  198. array_shift($args);
  199. array_unshift($args,"<img src='".$match[1]."' />");
  200. $srcover_filter = call_user_func_array($filtre, $args);
  201. $srcover_filter = extraire_attribut($srcover_filter,'src');
  202. $reduit = str_replace($srcover,$srcover_filter,$reduit);
  203. }
  204. }
  205. $texte = str_replace($tag[3], $reduit, $texte);
  206. }
  207. array_shift($args);
  208. }
  209. }
  210. }
  211. statut_effacer_images_temporaires(false); // desactiver pour les appels hors compilo
  212. return $texte;
  213. }
  214. //
  215. // Retourner taille d'une image
  216. // pour les filtres |largeur et |hauteur
  217. //
  218. // http://doc.spip.org/@taille_image
  219. function taille_image($img) {
  220. static $largeur_img =array(), $hauteur_img= array();
  221. $srcWidth = 0;
  222. $srcHeight = 0;
  223. $logo = extraire_attribut($img,'src');
  224. if (!$logo) $logo = $img;
  225. else {
  226. $srcWidth = extraire_attribut($img,'width');
  227. $srcHeight = extraire_attribut($img,'height');
  228. }
  229. // ne jamais operer directement sur une image distante pour des raisons de perfo
  230. // la copie locale a toutes les chances d'etre la ou de resservir
  231. if (preg_match(';^(\w{3,7}://);', $logo)){
  232. include_spip('inc/distant');
  233. $fichier = copie_locale($logo);
  234. $logo = $fichier ? _DIR_RACINE . $fichier : $logo;
  235. }
  236. if (($p=strpos($logo,'?'))!==FALSE)
  237. $logo=substr($logo,0,$p);
  238. $srcsize = false;
  239. if (isset($largeur_img[$logo]))
  240. $srcWidth = $largeur_img[$logo];
  241. if (isset($hauteur_img[$logo]))
  242. $srcHeight = $hauteur_img[$logo];
  243. if (!$srcWidth OR !$srcHeight){
  244. if ($srcsize = @getimagesize($logo)){
  245. if (!$srcWidth) $largeur_img[$logo] = $srcWidth = $srcsize[0];
  246. if (!$srcHeight) $hauteur_img[$logo] = $srcHeight = $srcsize[1];
  247. }
  248. // $logo peut etre une reference a une image temporaire dont a n'a que le log .src
  249. // on s'y refere, l'image sera reconstruite en temps utile si necessaire
  250. elseif(@file_exists($f = "$logo.src")
  251. AND lire_fichier($f,$valeurs)
  252. AND $valeurs=unserialize($valeurs)) {
  253. if (!$srcWidth) $largeur_img[$logo] = $srcWidth = $valeurs["largeur_dest"];
  254. if (!$srcHeight) $hauteur_img[$logo] = $srcHeight = $valeurs["hauteur_dest"];
  255. }
  256. }
  257. return array($srcHeight, $srcWidth);
  258. }
  259. // http://doc.spip.org/@largeur
  260. function largeur($img) {
  261. if (!$img) return;
  262. list ($h,$l) = taille_image($img);
  263. return $l;
  264. }
  265. // http://doc.spip.org/@hauteur
  266. function hauteur($img) {
  267. if (!$img) return;
  268. list ($h,$l) = taille_image($img);
  269. return $h;
  270. }
  271. // Echappement des entites HTML avec correction des entites "brutes"
  272. // (generees par les butineurs lorsqu'on rentre des caracteres n'appartenant
  273. // pas au charset de la page [iso-8859-1 par defaut])
  274. //
  275. // Attention on limite cette correction aux caracteres "hauts" (en fait > 99
  276. // pour aller plus vite que le > 127 qui serait logique), de maniere a
  277. // preserver des echappements de caracteres "bas" (par exemple [ ou ")
  278. // et au cas particulier de &amp; qui devient &amp;amp; dans les url
  279. // http://doc.spip.org/@corriger_entites_html
  280. function corriger_entites_html($texte) {
  281. if (strpos($texte,'&amp;') === false) return $texte;
  282. return preg_replace(',&amp;(#[0-9][0-9][0-9]+;|amp;),iS', '&\1', $texte);
  283. }
  284. // idem mais corriger aussi les &amp;eacute; en &eacute;
  285. // http://doc.spip.org/@corriger_toutes_entites_html
  286. function corriger_toutes_entites_html($texte) {
  287. if (strpos($texte,'&amp;') === false) return $texte;
  288. return preg_replace(',&amp;(#?[a-z0-9]+;),iS', '&\1', $texte);
  289. }
  290. // http://doc.spip.org/@proteger_amp
  291. function proteger_amp($texte){
  292. return str_replace('&','&amp;',$texte);
  293. }
  294. // http://doc.spip.org/@entites_html
  295. function entites_html($texte, $tout=false) {
  296. if (!is_string($texte) OR !$texte
  297. OR strpbrk($texte, "&\"'<>")==false
  298. ) return $texte;
  299. include_spip('inc/texte');
  300. $texte = htmlspecialchars(echappe_retour(echappe_html($texte,'',true),'','proteger_amp'),ENT_QUOTES);
  301. if ($tout)
  302. return corriger_toutes_entites_html($texte);
  303. else
  304. return corriger_entites_html($texte);
  305. }
  306. // Transformer les &eacute; dans le charset local
  307. // http://doc.spip.org/@filtrer_entites
  308. function filtrer_entites($texte) {
  309. if (strpos($texte,'&') === false) return $texte;
  310. // filtrer
  311. $texte = html2unicode($texte);
  312. // remettre le tout dans le charset cible
  313. return unicode2charset($texte);
  314. }
  315. // caracteres de controle - http://www.w3.org/TR/REC-xml/#charsets
  316. // http://doc.spip.org/@supprimer_caracteres_illegaux
  317. function supprimer_caracteres_illegaux($texte) {
  318. 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";
  319. static $to = null;
  320. if (is_array($texte)) {
  321. return array_map('corriger_caracteres_windows', $texte);
  322. }
  323. if (!$to) $to = str_repeat('-', strlen($from));
  324. return strtr($texte, $from, $to);
  325. }
  326. // Supprimer caracteres windows et les caracteres de controle ILLEGAUX
  327. // http://doc.spip.org/@corriger_caracteres
  328. function corriger_caracteres ($texte) {
  329. $texte = corriger_caracteres_windows($texte);
  330. $texte = supprimer_caracteres_illegaux($texte);
  331. return $texte;
  332. }
  333. // Encode du HTML pour transmission XML
  334. // http://doc.spip.org/@texte_backend
  335. function texte_backend($texte) {
  336. static $apostrophe = array("&#8217;", "'"); # n'allouer qu'une fois
  337. // si on a des liens ou des images, les passer en absolu
  338. $texte = liens_absolus($texte);
  339. // echapper les tags &gt; &lt;
  340. $texte = preg_replace(',&(gt|lt);,S', '&amp;\1;', $texte);
  341. // importer les &eacute;
  342. $texte = filtrer_entites($texte);
  343. // " -> &quot; et tout ce genre de choses
  344. $u = $GLOBALS['meta']['pcre_u'];
  345. $texte = str_replace("&nbsp;", " ", $texte);
  346. $texte = preg_replace('/\s{2,}/S'.$u, " ", $texte);
  347. $texte = entites_html($texte);
  348. // verifier le charset
  349. $texte = charset2unicode($texte);
  350. // Caracteres problematiques en iso-latin 1
  351. if ($GLOBALS['meta']['charset'] == 'iso-8859-1') {
  352. $texte = str_replace(chr(156), '&#156;', $texte);
  353. $texte = str_replace(chr(140), '&#140;', $texte);
  354. $texte = str_replace(chr(159), '&#159;', $texte);
  355. }
  356. // l'apostrophe curly pose probleme a certains lecteure de RSS
  357. // et le caractere apostrophe alourdit les squelettes avec PHP
  358. // ==> on les remplace par l'entite HTML
  359. return str_replace($apostrophe, "'", $texte);
  360. }
  361. // Comme ci-dessus, mais avec addslashes final pour squelettes avec PHP (rss)
  362. function texte_backendq($texte) {
  363. return addslashes(texte_backend($texte));
  364. }
  365. // Enleve le numero des titres numerotes ("1. Titre" -> "Titre")
  366. // http://doc.spip.org/@supprimer_numero
  367. function supprimer_numero($texte) {
  368. return preg_replace(
  369. ",^[[:space:]]*([0-9]+)([.)]|".chr(194).'?'.chr(176).")[[:space:]]+,S",
  370. "", $texte);
  371. }
  372. // et la fonction inverse
  373. // http://doc.spip.org/@recuperer_numero
  374. function recuperer_numero($texte) {
  375. if (preg_match(
  376. ",^[[:space:]]*([0-9]+)([.)]|".chr(194).'?'.chr(176).")[[:space:]]+,S",
  377. $texte, $regs))
  378. return intval($regs[1]);
  379. else
  380. return '';
  381. }
  382. // Suppression basique et brutale de tous les <...>
  383. // http://doc.spip.org/@supprimer_tags
  384. function supprimer_tags($texte, $rempl = "") {
  385. $texte = preg_replace(",<[^>]*>,US", $rempl, $texte);
  386. // ne pas oublier un < final non ferme
  387. // mais qui peut aussi etre un simple signe plus petit que
  388. $texte = str_replace('<', ' ', $texte);
  389. return $texte;
  390. }
  391. // Convertit les <...> en la version lisible en HTML
  392. // http://doc.spip.org/@echapper_tags
  393. function echapper_tags($texte, $rempl = "") {
  394. $texte = preg_replace("/<([^>]*)>/", "&lt;\\1&gt;", $texte);
  395. return $texte;
  396. }
  397. // Convertit un texte HTML en texte brut
  398. // http://doc.spip.org/@textebrut
  399. function textebrut($texte) {
  400. $u = $GLOBALS['meta']['pcre_u'];
  401. $texte = preg_replace('/\s+/S'.$u, " ", $texte);
  402. $texte = preg_replace("/<(p|br)( [^>]*)?".">/iS", "\n\n", $texte);
  403. $texte = preg_replace("/^\n+/", "", $texte);
  404. $texte = preg_replace("/\n+$/", "", $texte);
  405. $texte = preg_replace("/\n +/", "\n", $texte);
  406. $texte = supprimer_tags($texte);
  407. $texte = preg_replace("/(&nbsp;| )+/S", " ", $texte);
  408. // nettoyer l'apostrophe curly qui pose probleme a certains rss-readers, lecteurs de mail...
  409. $texte = str_replace("&#8217;","'",$texte);
  410. return $texte;
  411. }
  412. // Remplace les liens SPIP en liens ouvrant dans une nouvelle fenetre (target=blank)
  413. // http://doc.spip.org/@liens_ouvrants
  414. function liens_ouvrants ($texte) {
  415. return preg_replace(",<a ([^>]*https?://[^>]*class=[\"']spip_(out|url)\b[^>]+)>,",
  416. "<a \\1 target=\"_blank\">", $texte);
  417. }
  418. // Transformer les sauts de paragraphe en simples passages a la ligne
  419. // http://doc.spip.org/@PtoBR
  420. function PtoBR($texte){
  421. $u = $GLOBALS['meta']['pcre_u'];
  422. $texte = preg_replace("@</p>@iS", "\n", $texte);
  423. $texte = preg_replace("@<p\b.*>@UiS", "<br />", $texte);
  424. $texte = preg_replace("@^\s*<br />@S".$u, "", $texte);
  425. return $texte;
  426. }
  427. /**
  428. * lignes_longues assure qu'un texte ne vas pas deborder d'un bloc
  429. * par la faute d'un mot trop long (souvent des URLs)
  430. * Ne devrait plus etre utilise et fait directement en CSS par un style
  431. * word-wrap:break-word;
  432. * cf http://www.alsacreations.com/tuto/lire/1038-gerer-debordement-contenu-css.html
  433. *
  434. * Pour assurer la compatibilite du filtre, on encapsule le contenu par
  435. * un div ou span portant ce style inline.
  436. *
  437. * http://doc.spip.org/@lignes_longues
  438. *
  439. * @param string $texte
  440. * @return string
  441. */
  442. function lignes_longues($texte) {
  443. if (!strlen(trim($texte))) return $texte;
  444. include_spip('inc/texte');
  445. $tag = preg_match(',</?('._BALISES_BLOCS.')[>[:space:]],iS', $texte) ?
  446. 'div' : 'span';
  447. return "<$tag style='word-wrap:break-word;'>$texte</$tag>";
  448. }
  449. // Majuscules y compris accents, en HTML
  450. // http://doc.spip.org/@majuscules
  451. function majuscules($texte) {
  452. if (!strlen($texte)) return '';
  453. // Cas du turc
  454. if ($GLOBALS['spip_lang'] == 'tr') {
  455. # remplacer hors des tags et des entites
  456. if (preg_match_all(',<[^<>]+>|&[^;]+;,S', $texte, $regs, PREG_SET_ORDER))
  457. foreach ($regs as $n => $match)
  458. $texte = str_replace($match[0], "@@SPIP_TURC$n@@", $texte);
  459. $texte = str_replace('i', '&#304;', $texte);
  460. if ($regs)
  461. foreach ($regs as $n => $match)
  462. $texte = str_replace("@@SPIP_TURC$n@@", $match[0], $texte);
  463. }
  464. // Cas general
  465. return "<span style='text-transform: uppercase;'>$texte</span>";
  466. }
  467. // "127.4 ko" ou "3.1 Mo"
  468. // http://doc.spip.org/@taille_en_octets
  469. function taille_en_octets ($taille) {
  470. if ($taille < 1024) {$taille = _T('taille_octets', array('taille' => $taille));}
  471. else if ($taille < 1024*1024) {
  472. $taille = _T('taille_ko', array('taille' => ((floor($taille / 102.4))/10)));
  473. } else {
  474. $taille = _T('taille_mo', array('taille' => ((floor(($taille / 1024) / 102.4))/10)));
  475. }
  476. return $taille;
  477. }
  478. // Rend une chaine utilisable sans dommage comme attribut HTML
  479. // http://doc.spip.org/@attribut_html
  480. function attribut_html($texte,$textebrut = true) {
  481. $u = $GLOBALS['meta']['pcre_u'];
  482. if ($textebrut)
  483. $texte = preg_replace(array(",\n,",",\s(?=\s),msS".$u),array(" ",""),textebrut($texte));
  484. $texte = texte_backend($texte);
  485. $texte = str_replace(array("'",'"'),array('&#039;', '&#034;'), $texte);
  486. return preg_replace(array("/&(amp;|#38;)/","/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/"),array("&","&#38;") , $texte);
  487. }
  488. // Vider les url nulles comme 'http://' ou 'mailto:'
  489. // et leur appliquer un htmlspecialchars() + gerer les &amp;
  490. // http://doc.spip.org/@vider_url
  491. function vider_url($url, $entites = true) {
  492. # un message pour abs_url
  493. $GLOBALS['mode_abs_url'] = 'url';
  494. $url = trim($url);
  495. if (preg_match(",^(http:?/?/?|mailto:?)$,iS", $url))
  496. return '';
  497. if ($entites) $url = entites_html($url);
  498. return $url;
  499. }
  500. // Extraire une date de n'importe quel champ (a completer...)
  501. // http://doc.spip.org/@extraire_date
  502. function extraire_date($texte) {
  503. // format = 2001-08
  504. if (preg_match(",([1-2][0-9]{3})[^0-9]*(1[0-2]|0?[1-9]),",$texte,$regs))
  505. return $regs[1]."-".sprintf("%02d", $regs[2])."-01";
  506. }
  507. // Maquiller une adresse e-mail
  508. // http://doc.spip.org/@antispam
  509. function antispam($texte) {
  510. include_spip('inc/acces');
  511. $masque = creer_pass_aleatoire(3);
  512. return preg_replace("/@/", " $masque ", $texte);
  513. }
  514. // http://doc.spip.org/@securiser_acces
  515. function securiser_acces($id_auteur, $cle, $dir, $op='', $args='')
  516. {
  517. include_spip('inc/acces');
  518. if ($op) $dir .= " $op $args";
  519. return verifier_low_sec($id_auteur, $cle, $dir);
  520. }
  521. // sinon{texte, rien} : affiche "rien" si la chaine est vide,
  522. // affiche la chaine si non vide ;
  523. // attention c'est compile directement dans inc/references
  524. // http://doc.spip.org/@sinon
  525. function sinon ($texte, $sinon='') {
  526. if ($texte OR (!is_array($texte) AND strlen($texte)))
  527. return $texte;
  528. else
  529. return $sinon;
  530. }
  531. // |choixsivide{vide,pasvide} affiche pasvide si la chaine n'est pas vide...
  532. // http://doc.spip.org/@choixsivide
  533. function choixsivide($a, $vide, $pasvide) {
  534. return $a ? $pasvide : $vide;
  535. }
  536. // |choixsiegal{aquoi,oui,non} affiche oui si la chaine est egal a aquoi ...
  537. // http://doc.spip.org/@choixsiegal
  538. function choixsiegal($a1,$a2,$v,$f) {
  539. return ($a1 == $a2) ? $v : $f;
  540. }
  541. //
  542. // Date, heure, saisons
  543. //
  544. // on normalise la date, si elle vient du contexte (public/parametrer.php), on force le jour
  545. // http://doc.spip.org/@normaliser_date
  546. function normaliser_date($date, $forcer_jour = false) {
  547. $date = vider_date($date);
  548. if ($date) {
  549. if (preg_match("/^[0-9]{8,10}$/", $date))
  550. $date = date("Y-m-d H:i:s", $date);
  551. if (preg_match("#^([12][0-9]{3})([-/]00)?( [-0-9:]+)?$#", $date, $regs))
  552. $date = $regs[1]."-00-00".$regs[3];
  553. else if (preg_match("#^([12][0-9]{3}[-/][01]?[0-9])([-/]00)?( [-0-9:]+)?$#", $date, $regs))
  554. $date = preg_replace("@/@","-",$regs[1])."-00".$regs[3];
  555. else
  556. $date = date("Y-m-d H:i:s", strtotime($date));
  557. if ($forcer_jour)
  558. $date = str_replace('-00', '-01', $date);
  559. }
  560. return $date;
  561. }
  562. // http://doc.spip.org/@vider_date
  563. function vider_date($letexte) {
  564. if (strncmp("0000-00-00", $letexte,10)==0) return '';
  565. if (strncmp("0001-01-01", $letexte,10)==0) return '';
  566. if (strncmp("1970-01-01", $letexte,10)==0) return ''; // eviter le bug GMT-1
  567. return $letexte;
  568. }
  569. // http://doc.spip.org/@recup_heure
  570. function recup_heure($date){
  571. static $d = array(0,0,0);
  572. if (!preg_match('#([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})#', $date, $r))
  573. return $d;
  574. array_shift($r);
  575. return $r;
  576. }
  577. // http://doc.spip.org/@heures
  578. function heures($numdate) {
  579. $date_array = recup_heure($numdate);
  580. if ($date_array)
  581. list($heures, $minutes, $secondes) = $date_array;
  582. return $heures;
  583. }
  584. // http://doc.spip.org/@minutes
  585. function minutes($numdate) {
  586. $date_array = recup_heure($numdate);
  587. if ($date_array)
  588. list($heures, $minutes, $secondes) = $date_array;
  589. return $minutes;
  590. }
  591. // http://doc.spip.org/@secondes
  592. function secondes($numdate) {
  593. $date_array = recup_heure($numdate);
  594. if ($date_array)
  595. list($heures,$minutes,$secondes) = $date_array;
  596. return $secondes;
  597. }
  598. // http://doc.spip.org/@heures_minutes
  599. function heures_minutes($numdate) {
  600. return _T('date_fmt_heures_minutes', array('h'=> heures($numdate), 'm'=> minutes($numdate)));
  601. }
  602. // http://doc.spip.org/@recup_date
  603. function recup_date($numdate, $forcer_jour = true){
  604. if (!$numdate) return '';
  605. $heures = $minutes = $secondes = 0;
  606. if (preg_match('#([0-9]{1,2})/([0-9]{1,2})/([0-9]{4}|[0-9]{1,2})#', $numdate, $regs)) {
  607. $jour = $regs[1];
  608. $mois = $regs[2];
  609. $annee = $regs[3];
  610. if ($annee < 90){
  611. $annee = 2000 + $annee;
  612. } elseif ($annee<100) {
  613. $annee = 1900 + $annee ;
  614. }
  615. list($heures, $minutes, $secondes) = recup_heure($numdate);
  616. }
  617. elseif (preg_match('#([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})#',$numdate, $regs)) {
  618. $annee = $regs[1];
  619. $mois = $regs[2];
  620. $jour = $regs[3];
  621. list($heures, $minutes, $secondes) = recup_heure($numdate);
  622. }
  623. elseif (preg_match('#([0-9]{4})-([0-9]{2})#', $numdate, $regs)){
  624. $annee = $regs[1];
  625. $mois = $regs[2];
  626. $jour ='';
  627. list($heures, $minutes, $secondes) = recup_heure($numdate);
  628. }
  629. elseif (preg_match('#^([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})$#', $numdate, $regs)){
  630. $annee = $regs[1];
  631. $mois = $regs[2];
  632. $jour = $regs[3];
  633. $heures = $regs[4];
  634. $minutes = $regs[5];
  635. $secondes = $regs[6];
  636. } else $annee = $mois = $jour ='';
  637. if ($annee > 4000) $annee -= 9000;
  638. if (substr($jour, 0, 1) == '0') $jour = substr($jour, 1);
  639. if ($forcer_jour AND $jour == '0') $jour = '1';
  640. if ($forcer_jour AND $mois == '0') $mois = '1';
  641. if ($annee OR $mois OR $jour OR $heures OR $minutes OR $secondes)
  642. return array($annee, $mois, $jour, $heures, $minutes, $secondes);
  643. }
  644. // une date pour l'interface : utilise date_relative si le decalage
  645. // avec time() est de moins de douze heures, sinon la date complete
  646. // http://doc.spip.org/@date_interface
  647. function date_interface($date, $decalage_maxi = 43200/* 12*3600 */) {
  648. return sinon(
  649. date_relative($date, $decalage_maxi),
  650. affdate_heure($date)
  651. );
  652. }
  653. // http://doc.spip.org/@date_relative
  654. function date_relative($date, $decalage_maxi=0,$ref_date=null) {
  655. if (is_null($ref_date))
  656. $ref_time = time();
  657. else
  658. $ref_time = strtotime($ref_date);
  659. if (!$date) return;
  660. $decal = date("U",$ref_time) - date("U", strtotime($date));
  661. if ($decalage_maxi AND ($decal > $decalage_maxi OR $decal < 0))
  662. return '';
  663. if ($decal < 0) {
  664. $il_y_a = "date_dans";
  665. $decal = -1 * $decal;
  666. } else {
  667. $il_y_a = "date_il_y_a";
  668. }
  669. if ($decal > 3600 * 24 * 30 * 6)
  670. return affdate_court($date);
  671. if ($decal > 3600 * 24 * 30) {
  672. $mois = floor ($decal / (3600 * 24 * 30));
  673. if ($mois < 2)
  674. $delai = "$mois "._T("date_un_mois");
  675. else
  676. $delai = "$mois "._T("date_mois");
  677. }
  678. else if ($decal > 3600 * 24 * 7) {
  679. $semaines = floor ($decal / (3600 * 24 * 7));
  680. if ($semaines < 2)
  681. $delai = "$semaines "._T("date_une_semaine");
  682. else
  683. $delai = "$semaines "._T("date_semaines");
  684. }
  685. else if ($decal > 3600 * 24) {
  686. $jours = floor ($decal / (3600 * 24));
  687. if ($jours < 2)
  688. return $il_y_a=="date_dans"?_T("date_demain"):_T("date_hier");
  689. else
  690. $delai = "$jours "._T("date_jours");
  691. }
  692. else if ($decal >= 3600) {
  693. $heures = floor ($decal / 3600);
  694. if ($heures < 2)
  695. $delai = "$heures "._T("date_une_heure");
  696. else
  697. $delai = "$heures "._T("date_heures");
  698. }
  699. else if ($decal >= 60) {
  700. $minutes = floor($decal / 60);
  701. if ($minutes < 2)
  702. $delai = "$minutes "._T("date_une_minute");
  703. else
  704. $delai = "$minutes "._T("date_minutes");
  705. } else {
  706. $secondes = ceil($decal);
  707. if ($secondes < 2)
  708. $delai = "$secondes "._T("date_une_seconde");
  709. else
  710. $delai = "$secondes "._T("date_secondes");
  711. }
  712. return _T($il_y_a, array("delai"=> $delai));
  713. }
  714. // http://doc.spip.org/@date_relativecourt
  715. function date_relativecourt($date, $decalage_maxi=0) {
  716. if (!$date) return;
  717. $decal = date("U",strtotime(date('Y-m-d'))-strtotime(date('Y-m-d',strtotime($date))));
  718. if ($decalage_maxi AND ($decal > $decalage_maxi OR $decal < 0))
  719. return '';
  720. if ($decal < -24*3600) {
  721. $retour = date_relative($date, $decalage_maxi);
  722. }
  723. elseif ($decal < 0) {
  724. $retour = _T("date_demain");
  725. }
  726. else if ($decal < (3600 * 24) ) {
  727. $retour = _T("date_aujourdhui");
  728. }
  729. else if ($decal < (3600 * 24 *2) ) {
  730. $retour = _T("date_hier");
  731. }
  732. else {
  733. $retour = date_relative($date, $decalage_maxi);
  734. }
  735. return $retour;
  736. }
  737. /**
  738. * Formatage humain de la date $numdate selon le format $vue
  739. * http://doc.spip.org/@affdate_base
  740. *
  741. * @param $numdate
  742. * @param $vue
  743. * @param array $options
  744. * param : 'abbr' ou 'initiale' permet d'afficher les jours au format court ou initiale
  745. * annee_courante : permet de definir l'annee de reference pour l'affichage des dates courtes
  746. * @return mixed|string
  747. */
  748. function affdate_base($numdate, $vue, $options = array()) {
  749. if (is_string($options))
  750. $options = array('param'=>$options);
  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. $saison = '';
  779. if ($mois > 0){
  780. $saison = 1;
  781. if (($mois == 3 AND $jour >= 21) OR $mois > 3) $saison = 2;
  782. if (($mois == 6 AND $jour >= 21) OR $mois > 6) $saison = 3;
  783. if (($mois == 9 AND $jour >= 21) OR $mois > 9) $saison = 4;
  784. if (($mois == 12 AND $jour >= 21) OR $mois > 12) $saison = 1;
  785. }
  786. return $saison?_T('date_saison_'.$saison):'';
  787. case 'court':
  788. if ($avjc) return $annee;
  789. $a = ((isset($options['annee_courante']) AND $options['annee_courante'])?$options['annee_courante']:date('Y'));
  790. if ($annee < ($a - 100) OR $annee > ($a + 100)) return $annee;
  791. if ($annee != $a) return _T('date_fmt_mois_annee', array ('mois'=>$mois, 'nommois'=>ucfirst($nommois), 'annee'=>$annee));
  792. return _T('date_fmt_jour_mois', array ('jourmois'=>$jourmois, 'jour'=>$jour, 'mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee));
  793. case 'jourcourt':
  794. if ($avjc) return $annee;
  795. $a = ((isset($options['annee_courante']) AND $options['annee_courante'])?$options['annee_courante']:date('Y'));
  796. if ($annee < ($a - 100) OR $annee > ($a + 100)) return $annee;
  797. if ($annee != $a) return _T('date_fmt_jour_mois_annee', array ('jourmois'=>$jourmois, 'jour'=>$jour, 'mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee));
  798. return _T('date_fmt_jour_mois', array ('jourmois'=>$jourmois, 'jour'=>$jour, 'mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee));
  799. case 'entier':
  800. if ($avjc) return $annee;
  801. if ($jour)
  802. return _T('date_fmt_jour_mois_annee', array ('jourmois'=>$jourmois, 'jour'=>$jour, 'mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee));
  803. elseif ($mois)
  804. return trim(_T('date_fmt_mois_annee', array ('mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee)));
  805. else
  806. return $annee;
  807. case 'nom_mois':
  808. return $nommois;
  809. case 'mois':
  810. return sprintf("%02s",$mois);
  811. case 'jour':
  812. return $jour;
  813. case 'journum':
  814. return $journum;
  815. case 'nom_jour':
  816. if (!$mois OR !$njour)
  817. return '';
  818. $nom = mktime(1,1,1,$mois,$njour,$annee);
  819. $nom = 1+date('w',$nom);
  820. $param = ((isset($options['param']) AND $options['param']) ? '_'.$options['param'] : '');
  821. return _T('date_jour_'.$nom.$param);
  822. case 'mois_annee':
  823. if ($avjc) return $annee;
  824. return trim(_T('date_fmt_mois_annee', array('mois'=>$mois, 'nommois'=>$nommois, 'annee'=>$annee)));
  825. case 'annee':
  826. return $annee;
  827. // Cas d'une vue non definie : retomber sur le format
  828. // de date propose par http://www.php.net/date
  829. default:
  830. return date($vue, strtotime($numdate));
  831. }
  832. }
  833. // http://doc.spip.org/@nom_jour
  834. function nom_jour($numdate, $forme = '') {
  835. if(!($forme == 'abbr' OR $forme == 'initiale')) $forme = '';
  836. return affdate_base($numdate, 'nom_jour', $forme);
  837. }
  838. // http://doc.spip.org/@jour
  839. function jour($numdate) {
  840. return affdate_base($numdate, 'jour');
  841. }
  842. // http://doc.spip.org/@journum
  843. function journum($numdate) {
  844. return affdate_base($numdate, 'journum');
  845. }
  846. // http://doc.spip.org/@mois
  847. function mois($numdate) {
  848. return affdate_base($numdate, 'mois');
  849. }
  850. // http://doc.spip.org/@nom_mois
  851. function nom_mois($numdate) {
  852. return affdate_base($numdate, 'nom_mois');
  853. }
  854. // http://doc.spip.org/@annee
  855. function annee($numdate) {
  856. return affdate_base($numdate, 'annee');
  857. }
  858. // http://doc.spip.org/@saison
  859. function saison($numdate) {
  860. return affdate_base($numdate, 'saison');
  861. }
  862. // http://doc.spip.org/@affdate
  863. function affdate($numdate, $format='entier') {
  864. return affdate_base($numdate, $format);
  865. }
  866. // http://doc.spip.org/@affdate_court
  867. function affdate_court($numdate, $annee_courante=null) {
  868. return affdate_base($numdate, 'court', array('annee_courante'=>$annee_courante));
  869. }
  870. // http://doc.spip.org/@affdate_jourcourt
  871. function affdate_jourcourt($numdate, $annee_courante=null) {
  872. return affdate_base($numdate, 'jourcourt', array('annee_courante'=>$annee_courante));
  873. }
  874. // http://doc.spip.org/@affdate_mois_annee
  875. function affdate_mois_annee($numdate) {
  876. return affdate_base($numdate, 'mois_annee');
  877. }
  878. // http://doc.spip.org/@affdate_heure
  879. function affdate_heure($numdate) {
  880. $date_array = recup_date($numdate);
  881. if (!$date_array) return;
  882. list($annee, $mois, $jour, $heures, $minutes, $sec)= $date_array;
  883. return _T('date_fmt_jour_heure', array('jour' => affdate($numdate), 'heure' => _T('date_fmt_heures_minutes', array('h'=> $heures, 'm'=> $minutes))));
  884. }
  885. /**
  886. * Afficher de facon textuelle les dates de debut et fin en fonction des cas
  887. * - Lundi 20 fevrier a 18h
  888. * - Le 20 fevrier de 18h a 20h
  889. * - Du 20 au 23 fevrier
  890. * - du 20 fevrier au 30 mars
  891. * - du 20 fevrier 2007 au 30 mars 2008
  892. * $horaire='oui' ou true permet d'afficher l'horaire, toute autre valeur n'indique que le jour
  893. * $forme peut contenir une ou plusieurs valeurs parmi
  894. * - abbr (afficher le nom des jours en abbrege)
  895. * - hcal (generer une date au format hcal)
  896. * - annee (forcer l'affichage de l'annee)
  897. *
  898. * @param string $date_debut
  899. * @param string $date_fin
  900. * @param string $horaire
  901. * @param string $forme
  902. * @return string
  903. */
  904. function affdate_debut_fin($date_debut, $date_fin, $horaire = 'oui', $forme=''){
  905. $abbr = '';
  906. if (strpos($forme,'abbr')!==false) $abbr = 'abbr';
  907. $affdate = "affdate_jourcourt";
  908. if (strpos($forme,'annee')!==false) $affdate = 'affdate';
  909. $dtstart = $dtend = $dtabbr = "";
  910. if (strpos($forme,'hcal')!==false) {
  911. $dtstart = "<abbr class='dtstart' title='".date_iso($date_debut)."'>";
  912. $dtend = "<abbr class='dtend' title='".date_iso($date_fin)."'>";
  913. $dtabbr = "</abbr>";
  914. }
  915. $date_debut = strtotime($date_debut);
  916. $date_fin = strtotime($date_fin);
  917. $d = date("Y-m-d", $date_debut);
  918. $f = date("Y-m-d", $date_fin);
  919. $h = ($horaire==='oui' OR $horaire===true);
  920. $hd = _T('date_fmt_heures_minutes_court', array('h'=> date("H",$date_debut), 'm'=> date("i",$date_debut)));
  921. $hf = _T('date_fmt_heures_minutes_court', array('h'=> date("H",$date_fin), 'm'=> date("i",$date_fin)));
  922. $au = " " . strtolower(_T('date_fmt_periode_to')) . " ";
  923. $du = _T('date_fmt_periode_from') . " ";
  924. if ($d==$f)
  925. { // meme jour
  926. $s = ucfirst(nom_jour($d,$abbr))." ".$affdate($d);
  927. if ($h)
  928. if ($hd!=$hf)
  929. $s .= " $hd";
  930. else
  931. $s = _T('date_fmt_jour_heure',array('jour'=>$s,'heure'=>$hd));
  932. $s = "$dtstart$s$dtabbr";
  933. if ($h AND $hd!=$hf) $s .= "-$dtend$hf$dtabbr";
  934. }
  935. else if ((date("Y-m",$date_debut))==date("Y-m",$date_fin))
  936. { // meme annee et mois, jours differents
  937. if ($h){
  938. $s = $du . $dtstart . affdate_jourcourt($d,date("Y",$date_debut)) . " $hd" . $dtabbr;
  939. $s .= $au . $dtend . $affdate($f);
  940. if ($hd!=$hf) $s .= " $hf";
  941. $s .= $dtabbr;
  942. }
  943. else {
  944. $s = $du . $dtstart . jour($d) . $dtabbr;
  945. $s .= $au . $dtend . $affdate($f) . $dtabbr;
  946. }
  947. }
  948. else if ((date("Y",$date_debut))==date("Y",$date_fin))
  949. { // meme annee, mois et jours differents
  950. $s = $du . $dtstart . affdate_jourcourt($d,date("Y",$date_debut));
  951. if ($h) $s .= " $hd";
  952. $s .= $dtabbr . $au . $dtend . $affdate($f);
  953. if ($h) $s .= " $hf";
  954. $s .= $dtabbr;
  955. }
  956. else
  957. { // tout different
  958. $s = $du . $dtstart . affdate($d);
  959. if ($h)
  960. $s .= " ($hd)";
  961. $s .= $dtabbr . $au . $dtend. affdate($f);
  962. if ($h)
  963. $s .= " ($hf)";
  964. $s .= $dtabbr;
  965. }
  966. return $s;
  967. }
  968. /**
  969. * Alignements en HTML (Old-style, preferer CSS)
  970. * Cette fonction ne cree pas de paragraphe
  971. *
  972. * http://doc.spip.org/@aligner
  973. *
  974. * @param $letexte
  975. * @param string $justif
  976. * @return string
  977. */
  978. function aligner($letexte, $justif='') {
  979. $letexte = trim($letexte);
  980. if (!strlen($letexte)) return '';
  981. // Paragrapher rapidement
  982. $letexte = "<div style='text-align:$justif'>"
  983. . $letexte
  984. ."</div>";
  985. return $letexte;
  986. }
  987. // http://doc.spip.org/@justifier
  988. function justifier($letexte) { return aligner($letexte,'justify');}
  989. // http://doc.spip.org/@aligner_droite
  990. function aligner_droite($letexte) { return aligner($letexte,'right');}
  991. // http://doc.spip.org/@aligner_gauche
  992. function aligner_gauche($letexte) {return aligner($letexte,'left');}
  993. // http://doc.spip.org/@centrer
  994. function centrer($letexte) {return aligner($letexte,'center');}
  995. // http://doc.spip.org/@style_align
  996. function style_align($bof) {
  997. global $spip_lang_left;
  998. return "text-align: $spip_lang_left";
  999. }
  1000. //
  1001. // Export iCal
  1002. //
  1003. // http://doc.spip.org/@filtrer_ical
  1004. function filtrer_ical($texte) {
  1005. #include_spip('inc/charsets');
  1006. $texte = html2unicode($texte);
  1007. $texte = unicode2charset(charset2unicode($texte, $GLOBALS['meta']['charset'], 1), 'utf-8');
  1008. $texte = preg_replace("/\n/", " ", $texte);
  1009. $texte = preg_replace("/,/", "\,", $texte);
  1010. return $texte;
  1011. }
  1012. // http://doc.spip.org/@date_ical
  1013. function date_ical($date, $addminutes = 0) {
  1014. list($heures, $minutes, $secondes) = recup_heure($date);
  1015. list($annee, $mois, $jour) = recup_date($date);
  1016. return date("Ymd\THis",
  1017. mktime($heures, $minutes+$addminutes,$secondes,$mois,$jour,$annee));
  1018. }
  1019. // date_iso retourne la date au format "RFC 3339" / "ISO 8601"
  1020. // voir http://www.php.net/manual/fr/ref.datetime.php#datetime.constants
  1021. // http://doc.spip.org/@date_iso
  1022. function date_iso($date_heure) {
  1023. list($annee, $mois, $jour) = recup_date($date_heure);
  1024. list($heures, $minutes, $secondes) = recup_heure($date_heure);
  1025. $time = @mktime($heures, $minutes, $secondes, $mois, $jour, $annee);
  1026. return gmdate('Y-m-d\TH:i:s\Z', $time);
  1027. }
  1028. // date_822 retourne la date au format "RFC 822"
  1029. // utilise pour <pubdate> dans certains feeds RSS
  1030. // http://doc.spip.org/@date_822
  1031. function date_822($date_heure) {
  1032. list($annee, $mois, $jour) = recup_date($date_heure);
  1033. list($heures, $minutes, $secondes) = recup_heure($date_heure);
  1034. $time = mktime($heures, $minutes, $secondes, $mois, $jour, $annee);
  1035. return date('r', $time);
  1036. }
  1037. // http://doc.spip.org/@date_anneemoisjour
  1038. function date_anneemoisjour($d) {
  1039. if (!$d) $d = date("Y-m-d");
  1040. return substr($d, 0, 4) . substr($d, 5, 2) .substr($d, 8, 2);
  1041. }
  1042. // http://doc.spip.org/@date_anneemois
  1043. function date_anneemois($d) {
  1044. if (!$d) $d = date("Y-m-d");
  1045. return substr($d, 0, 4) . substr($d, 5, 2);
  1046. }
  1047. // http://doc.spip.org/@date_debut_semaine
  1048. function date_debut_semaine($annee, $mois, $jour) {
  1049. $w_day = date("w", mktime(0,0,0,$mois, $jour, $annee));
  1050. if ($w_day == 0) $w_day = 7; // Gaffe: le dimanche est zero
  1051. $debut = $jour-$w_day+1;
  1052. return date("Ymd", mktime(0,0,0,$mois,$debut,$annee));
  1053. }
  1054. // http://doc.spip.org/@date_fin_semaine
  1055. function date_fin_semaine($annee, $mois, $jour) {
  1056. $w_day = date("w", mktime(0,0,0,$mois, $jour, $annee));
  1057. if ($w_day == 0) $w_day = 7; // Gaffe: le dimanche est zero
  1058. $debut = $jour-$w_day+1;
  1059. return date("Ymd", mktime(0,0,0,$mois,$debut+6,$annee));
  1060. }
  1061. //
  1062. // Recuperation de donnees dans le champ extra
  1063. // Ce filtre n'a de sens qu'avec la balise #EXTRA
  1064. //
  1065. // http://doc.spip.org/@extra
  1066. function extra($letexte, $champ) {
  1067. $champs = unserialize($letexte);
  1068. return $champs[$champ];
  1069. }
  1070. // postautobr : transforme les sauts de ligne en _
  1071. // http://doc.spip.org/@post_autobr
  1072. function post_autobr($texte, $delim="\n_ ") {
  1073. if (!function_exists('echappe_html'))
  1074. include_spip('inc/texte_mini');
  1075. $texte = str_replace("\r\n", "\r", $texte);
  1076. $texte = str_replace("\r", "\n", $texte);
  1077. if (preg_match(",\n+$,", $texte, $fin))
  1078. $texte = substr($texte, 0, -strlen($fin = $fin[0]));
  1079. else
  1080. $fin = '';
  1081. $texte = echappe_html($texte, '', true);
  1082. // echapper les modeles
  1083. if (strpos($texte,"<")!==false){
  1084. include_spip('inc/lien');
  1085. if (defined('_PREG_MODELE')){
  1086. $preg_modeles = "@"._PREG_MODELE."@imsS";
  1087. $texte = echappe_html($texte, '', true, $preg_modeles);
  1088. }
  1089. }
  1090. $debut = '';
  1091. $suite = $texte;
  1092. while ($t = strpos('-'.$suite, "\n", 1)) {
  1093. $debut .= substr($suite, 0, $t-1);
  1094. $suite = substr($suite, $t);
  1095. $car = substr($suite, 0, 1);
  1096. if (($car<>'-') AND ($car<>'_') AND ($car<>"\n") AND ($car<>"|") AND ($car<>"}")
  1097. AND !preg_match(',^\s*(\n|</?(quote|div)|$),S',($suite))
  1098. AND !preg_match(',</?(quote|div)> *$,iS', $debut)) {
  1099. $debut .= $delim;
  1100. } else
  1101. $debut .= "\n";
  1102. if (preg_match(",^\n+,", $suite, $regs)) {
  1103. $debut.=$regs[0];
  1104. $suite = substr($suite, strlen($regs[0]));
  1105. }
  1106. }
  1107. $texte = $debut.$suite;
  1108. $texte = echappe_retour($texte);
  1109. return $texte.$fin;
  1110. }
  1111. define('_EXTRAIRE_MULTI', "@<multi>(.*?)</multi>@sS");
  1112. // Extraire et transformer les blocs multi ; on indique la langue courante
  1113. // pour ne pas mettre de span@lang=fr si on est deja en fr
  1114. // http://doc.spip.org/@extraire_multi
  1115. function extraire_multi($letexte, $lang=null, $echappe_span=false) {
  1116. if (preg_match_all(_EXTRAIRE_MULTI, $letexte, $regs, PREG_SET_ORDER)) {
  1117. if (!$lang) $lang = $GLOBALS['spip_lang'];
  1118. foreach ($regs as $reg) {
  1119. // chercher la version de la langue courante
  1120. $trads = extraire_trads($reg[1]);
  1121. if ($l = approcher_langue($trads, $lang)) {
  1122. $trad = $trads[$l];
  1123. } else {
  1124. include_spip('inc/texte');
  1125. // langue absente, prendre la premiere dispo
  1126. // mais typographier le texte selon les regles de celle-ci
  1127. // Attention aux blocs multi sur plusieurs lignes
  1128. $l = key($trads);
  1129. $trad = $trads[$l];
  1130. $typographie = charger_fonction(lang_typo($l), 'typographie');
  1131. $trad = $typographie($trad);
  1132. include_spip('inc/texte');
  1133. // Tester si on echappe en span ou en div
  1134. // il ne faut pas echapper en div si propre produit un seul paragraphe
  1135. $trad_propre = preg_replace(",(^<p[^>]*>|</p>$),Uims","",propre($trad));
  1136. $mode = preg_match(',</?('._BALISES_BLOCS.')[>[:space:]],iS', $trad_propre) ? 'div' : 'span';
  1137. $trad = code_echappement($trad, 'multi', false, $mode);
  1138. $trad = str_replace("'", '"', inserer_attribut($trad, 'lang', $l));
  1139. if (lang_dir($l) !== lang_dir($lang))
  1140. $trad = str_replace("'", '"', inserer_attribut($trad, 'dir', lang_dir($l)));
  1141. if (!$echappe_span)
  1142. $trad = echappe_retour($trad, 'multi');
  1143. }
  1144. $letexte = str_replace($reg[0], $trad, $letexte);
  1145. }
  1146. }
  1147. return $letexte;
  1148. }
  1149. // convertit le contenu d'une balise multi en un tableau
  1150. // http://doc.spip.org/@extraire_trad
  1151. function extraire_trads($bloc) {
  1152. $lang = '';
  1153. // ce reg fait planter l'analyse multi s'il y a de l'{italique} dans le champ
  1154. // while (preg_match("/^(.*?)[{\[]([a-z_]+)[}\]]/siS", $bloc, $regs)) {
  1155. while (preg_match("/^(.*?)[\[]([a-z_]+)[\]]/siS", $bloc, $regs)) {
  1156. $texte = trim($regs[1]);
  1157. if ($texte OR $lang)
  1158. $trads[$lang] = $texte;
  1159. $bloc = substr($bloc, strlen($regs[0]));
  1160. $lang = $regs[2];
  1161. }
  1162. $trads[$lang] = $bloc;
  1163. return $trads;
  1164. }
  1165. //
  1166. // Ce filtre retourne la donnee si c'est la premiere fois qu'il la voit ;
  1167. // possibilite de gerer differentes "familles" de donnees |unique{famille}
  1168. # |unique{famille,1} affiche le nombre d'elements affiches (preferer toutefois #TOTAL_UNIQUE)
  1169. # ameliorations possibles :
  1170. # 1) si la donnee est grosse, mettre son md5 comme cle
  1171. # 2) purger $mem quand on change de squelette (sinon bug inclusions)
  1172. //
  1173. // http://www.spip.net/@unique
  1174. // http://doc.spip.org/@unique
  1175. function unique($donnee, $famille='', $cpt = false) {
  1176. static $mem;
  1177. // permettre de vider la pile et de la restaurer
  1178. // pour le calcul de introduction...
  1179. if ($famille=='_spip_raz_'){
  1180. $tmp = $mem;
  1181. $mem = array();
  1182. return $tmp;
  1183. } elseif ($famille=='_spip_set_'){
  1184. $mem = $donnee;
  1185. return;
  1186. }
  1187. if ($cpt)
  1188. return count($mem[$famille]);
  1189. if (!($mem[$famille][$donnee]++))
  1190. return $donnee;
  1191. }
  1192. //
  1193. // Filtre |alterner
  1194. //
  1195. // Exemple [(#COMPTEUR_BOUCLE|alterner{'bleu','vert','rouge'})]
  1196. //
  1197. // http://doc.spip.org/@alterner
  1198. function alterner($i) {
  1199. // recuperer les arguments (attention fonctions un peu space)
  1200. $num = func_num_args();
  1201. $args = func_get_args();
  1202. if($num == 2 && is_array($args[1])) {
  1203. $args = $args[1];
  1204. array_unshift($args,'');
  1205. $num = count($args);
  1206. }
  1207. // renvoyer le i-ieme argument, modulo le nombre d'arguments
  1208. return $args[(intval($i)-1)%($num-1)+1];
  1209. }
  1210. // recuperer un attribut d'une balise html
  1211. // ($complet demande de retourner $r)
  1212. // la regexp est mortelle : cf. tests/filtres/extraire_attribut.php
  1213. // Si on a passe un tableau de balises, renvoyer un tableau de resultats
  1214. // (dans ce cas l'option $complet n'est pas disponible)
  1215. // http://doc.spip.org/@extraire_attribut
  1216. function extraire_attribut($balise, $attribut, $complet = false) {
  1217. if (is_array($balise)) {
  1218. array_walk($balise,
  1219. create_function('&$a,$key,$t',
  1220. '$a = extraire_attribut($a,$t);'
  1221. ),
  1222. $attribut);
  1223. return $balise;
  1224. }
  1225. if (preg_match(
  1226. ',(^.*?<(?:(?>\s*)(?>[\w:.-]+)(?>(?:=(?:"[^"]*"|\'[^\']*\'|[^\'"]\S*))?))*?)(\s+'
  1227. .$attribut
  1228. .'(?:=\s*("[^"]*"|\'[^\']*\'|[^\'"]\S*))?)()([^>]*>.*),isS',
  1229. $balise, $r)) {
  1230. if ($r[3][0] == '"' || $r[3][0] == "'") {
  1231. $r[4] = substr($r[3], 1, -1);
  1232. $r[3] = $r[3][0];
  1233. } elseif ($r[3]!=='') {
  1234. $r[4] = $r[3];
  1235. $r[3] = '';
  1236. } else {
  1237. $r[4] = trim($r[2]);
  1238. }
  1239. $att = filtrer_entites(str_replace("&#39;", "'", $r[4]));
  1240. }
  1241. else
  1242. $att = NULL;
  1243. if ($complet)
  1244. return array($att, $r);
  1245. else
  1246. return $att;
  1247. }
  1248. // modifier (ou inserer) un attribut html dans une balise
  1249. // http://doc.spip.org/@inserer_attribut
  1250. function inserer_attribut($balise, $attribut, $val, $proteger=true, $vider=false) {
  1251. // preparer l'attribut
  1252. // supprimer les &nbsp; etc mais pas les balises html
  1253. // qui ont un sens dans un attribut value d'un input
  1254. if ($proteger) $val = attribut_html($val,false);
  1255. // echapper les ' pour eviter tout bug
  1256. $val = str_replace("'", "&#039;", $val);
  1257. if ($vider AND strlen($val)==0)
  1258. $insert = '';
  1259. else
  1260. $insert = " $attribut='$val'";
  1261. list($old, $r) = extraire_attribut($balise, $attribut, true);
  1262. if ($old !== NULL) {
  1263. // Remplacer l'ancien attribut du meme nom
  1264. $balise = $r[1].$insert.$r[5];
  1265. }
  1266. else {
  1267. // preferer une balise " />" (comme <img />)
  1268. if (preg_match(',/>,', $balise))
  1269. $balise = preg_replace(",\s?/>,S", $insert." />", $balise, 1);
  1270. // sinon une balise <a ...> ... </a>
  1271. else
  1272. $balise = preg_replace(",\s?>,S", $insert.">", $balise, 1);
  1273. }
  1274. return $balise;
  1275. }
  1276. // http://doc.spip.org/@vider_attribut
  1277. function vider_attribut ($balise, $attribut) {
  1278. return inserer_attribut($balise, $attribut, '', false, true);
  1279. }
  1280. /**
  1281. * Un filtre pour determiner le nom du satut des inscrits
  1282. * @param void $dummy
  1283. * @param string $mode
  1284. * @return string
  1285. */
  1286. function tester_config($dummy, $mode='') {
  1287. include_spip('action/inscrire_auteur');
  1288. return tester_statut_inscription($mode);
  1289. }
  1290. //
  1291. // Quelques fonctions de calcul arithmetique
  1292. //
  1293. // http://doc.spip.org/@plus
  1294. function plus($a,$b) {
  1295. return $a+$b;
  1296. }
  1297. // http://doc.spip.org/@moins
  1298. function moins($a,$b) {
  1299. return $a-$b;
  1300. }
  1301. // http://doc.spip.org/@mult
  1302. function mult($a,$b) {
  1303. return $a*$b;
  1304. }
  1305. // http://doc.spip.org/@div
  1306. function div($a,$b) {
  1307. return $b?$a/$b:0;
  1308. }
  1309. // http://doc.spip.org/@modulo
  1310. function modulo($nb, $mod, $add=0) {
  1311. return ($mod?$nb%$mod:0)+$add;
  1312. }
  1313. // Verifier la conformite d'une ou plusieurs adresses email
  1314. // retourne false ou la normalisation de la derniere adresse donnee
  1315. // http://doc.spip.org/@email_valide
  1316. function email_valide($adresses) {
  1317. // eviter d'injecter n'importe quoi dans preg_match
  1318. if (!is_string($adresses))
  1319. return false;
  1320. // Si c'est un spammeur autant arreter tout de suite
  1321. if (preg_match(",[\n\r].*(MIME|multipart|Content-),i", $adresses)) {
  1322. spip_log("Tentative d'injection de mail : $adresses");
  1323. return false;
  1324. }
  1325. foreach (explode(',', $adresses) as $v) {
  1326. // nettoyer certains formats
  1327. // "Marie Toto <Marie@toto.com>"
  1328. $adresse = trim(preg_replace(",^[^<>\"]*<([^<>\"]+)>$,i", "\\1", $v));
  1329. // RFC 822
  1330. if (!preg_match('#^[^()<>@,;:\\"/[:space:]]+(@([-_0-9a-z]+\.)*[-_0-9a-z]+)$#i', $adresse))
  1331. return false;
  1332. }
  1333. return $adresse;
  1334. }
  1335. // http://doc.spip.org/@afficher_enclosures
  1336. function afficher_enclosures($tags) {
  1337. $s = array();
  1338. foreach (extraire_balises($tags, 'a') as $tag) {
  1339. if (extraire_attribut($tag, 'rel') == 'enclosure'
  1340. AND $t = extraire_attribut($tag, 'href')) {
  1341. $s[] = preg_replace(',>[^<]+</a>,S',
  1342. '>'
  1343. .http_img_pack('attachment-16.png', $t,
  1344. 'title="'.attribut_html($t).'"')
  1345. .'</a>', $tag);
  1346. }
  1347. }
  1348. return join('&nbsp;', $s);
  1349. }
  1350. // http://doc.spip.org/@afficher_tags
  1351. function afficher_tags($tags, $rels='tag,directory') {
  1352. $s = array();
  1353. foreach (extraire_balises($tags, 'a') as $tag) {
  1354. $rel = extraire_attribut($tag, 'rel');
  1355. if (strstr(",$rels,", ",$rel,"))
  1356. $s[] = $tag;
  1357. }
  1358. return join(', ', $s);
  1359. }
  1360. // Passe un <enclosure url="fichier" length="5588242" type="audio/mpeg"/>
  1361. // au format microformat <a rel="enclosure" href="fichier" ...>fichier</a>
  1362. // attention length="zz" devient title="zz", pour rester conforme
  1363. // http://doc.spip.org/@enclosure2microformat
  1364. function enclosure2microformat($e) {
  1365. if (!$url = filtrer_entites(extraire_attribut($e, 'url')))
  1366. $url = filtrer_entites(extraire_attribut($e, 'href'));
  1367. $type = extraire_attribut($e, 'type');
  1368. $length = extraire_attribut($e, 'length');
  1369. $fichier = basename($url);
  1370. return '<a rel="enclosure"'
  1371. . ($url? ' href="'.htmlspecialchars($url).'"' : '')
  1372. . ($type? ' type="'.htmlspecialchars($type).'"' : '')
  1373. . ($length? ' title="'.htmlspecialchars($length).'"' : '')
  1374. . '>'.$fichier.'</a>';
  1375. }
  1376. // La fonction inverse
  1377. // http://doc.spip.org/@microformat2enclosure
  1378. function microformat2enclosure($tags) {
  1379. $enclosures = array();
  1380. foreach (extraire_balises($tags, 'a') as $e)
  1381. if (extraire_attribut($e, 'rel') == 'enclosure') {
  1382. $url = filtrer_entites(extraire_attribut($e, 'href'));
  1383. $type = extraire_attribut($e, 'type');
  1384. if (!$length = intval(extraire_attribut($e, 'title')))
  1385. $length = intval(extraire_attribut($e, 'length')); # vieux data
  1386. $fichier = basename($url);
  1387. $enclosures[] = '<enclosure'
  1388. . ($url? ' url="'.htmlspecialchars($u