[SPIP] ~maj v3.0.14-->v3.0.17
[ptitvelo/web/www.git] / www / ecrire / inc / filtres.php
index f1c2fc5..39fe12e 100644 (file)
@@ -3,7 +3,7 @@
 /***************************************************************************\
  *  SPIP, Systeme de publication pour l'internet                           *
  *                                                                         *
- *  Copyright (c) 2001-2012                                                *
+ *  Copyright (c) 2001-2014                                                *
  *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
  *                                                                         *
  *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
@@ -189,6 +189,39 @@ function filtrer($filtre) {
        }
 }
 
+/*
+ *
+ * [(#CALCUL|set{toto})] enregistre le résultat de #CALCUL
+ *           dans la variable toto et renvoie vide
+ *
+ * [(#CALCUL|set{toto,1})] enregistre le résultat de #CALCUL
+ *           dans la variable toto et renvoie la valeur
+ *
+ */
+function filtre_set(&$Pile, $val, $key, $continue = null) {
+       $Pile['vars'][$key] = $val;
+       return $continue ? $val : '';
+}
+
+/*
+ * [(#TRUC|debug{avant}|calcul|debug{apres}|etc)] affiche
+ *   la valeur de #TRUC avant et après le calcul
+ */
+function filtre_debug($val, $key=null) {
+       $debug = (
+               is_null($key) ? '' :  (var_export($key,true)." = ")
+       ) . var_export($val, true);
+
+       include_spip('inc/autoriser');
+       if (autoriser('webmestre'))
+               echo "<div class='spip_debug'>\n",$debug,"</div>\n";
+
+       spip_log($debug, 'debug');
+
+       return $val;
+}
+
+
 // fonction generique d'entree des filtres images
 // accepte en entree un texte complet, un img-log (produit par #LOGO_XX),
 // un tag <img ...> complet, ou encore un nom de fichier *local* (passer
@@ -363,7 +396,8 @@ function entites_html($texte, $tout=false, $quote=true) {
        OR strpbrk($texte, "&\"'<>")==false
        ) return $texte;
        include_spip('inc/texte');
-       $texte = htmlspecialchars(echappe_retour(echappe_html($texte,'',true),'','proteger_amp'),$quote?ENT_QUOTES:(ENT_COMPAT|ENT_HTML401));
+       $flags = !defined('PHP_VERSION_ID') OR PHP_VERSION_ID < 50400 ? ENT_COMPAT : ENT_COMPAT|ENT_HTML401;
+       $texte = spip_htmlspecialchars(echappe_retour(echappe_html($texte, '', true), '', 'proteger_amp'), $quote?ENT_QUOTES:$flags);
        if ($tout)
                return corriger_toutes_entites_html($texte);
        else
@@ -377,7 +411,12 @@ function filtrer_entites($texte) {
        // filtrer
        $texte = html2unicode($texte);
        // remettre le tout dans le charset cible
-       return unicode2charset($texte);
+       $texte = unicode2charset($texte);
+       // cas particulier des " et ' qu'il faut filtrer aussi
+       // (on le faisait deja avec un &quot;)
+       if (strpos($texte,"&#")!==false)
+               $texte = str_replace(array("&#039;","&#39;","&#034;","&#34;"), array("'","'",'"','"'), $texte);
+       return $texte;
 }
 
 // caracteres de controle - http://www.w3.org/TR/REC-xml/#charsets
@@ -430,6 +469,8 @@ function texte_backend($texte) {
        $texte = preg_replace('/\s{2,}/S'.$u, " ", $texte);
        // ne pas echapper les sinqle quotes car certains outils de syndication gerent mal
        $texte = entites_html($texte, false, false);
+       // mais bien echapper les double quotes !
+       $texte = str_replace('"','&#034;',$texte);
 
        // verifier le charset
        $texte = charset2unicode($texte);
@@ -467,7 +508,7 @@ function recuperer_numero($texte) {
        if (preg_match(
        ",^[[:space:]]*([0-9]+)([.)]|".chr(194).'?'.chr(176).")[[:space:]]+,S",
        $texte, $regs))
-               return intval($regs[1]);
+               return strval($regs[1]);
        else
                return '';
 }
@@ -512,6 +553,29 @@ function liens_ouvrants ($texte) {
                "<a \\1 target=\"_blank\">", $texte);
 }
 
+/**
+ * Ajouter un attribut rel="nofollow" sur tous les liens d'un texte
+ * @param string $texte
+ * @return string
+ */
+function liens_nofollow($texte) {
+       if (stripos($texte,"<a")===false)
+               return $texte;
+
+       if (preg_match_all(",<a\b[^>]*>,UimsS",$texte, $regs, PREG_PATTERN_ORDER)){
+               foreach($regs[0] as $a){
+                       $rel = extraire_attribut($a,"rel");
+                       if (strpos($rel,"nofollow")===false){
+                               $rel = "nofollow" . ($rel?" $rel":"");
+                               $anofollow = inserer_attribut($a,"rel",$rel);
+                               $texte = str_replace($a,$anofollow,$texte);
+                       }
+               }
+       }
+
+       return $texte;
+}
+
 // Transformer les sauts de paragraphe en simples passages a la ligne
 // http://doc.spip.org/@PtoBR
 function PtoBR($texte){
@@ -604,14 +668,9 @@ function attribut_html($texte,$textebrut = true) {
 function vider_url($url, $entites = true) {
        # un message pour abs_url
        $GLOBALS['mode_abs_url'] = 'url';
-
        $url = trim($url);
-       if (preg_match(",^(http:?/?/?|mailto:?)$,iS", $url))
-               return '';
-
-       if ($entites) $url = entites_html($url);
-
-       return $url;
+       $r = ",^(?:" . _PROTOCOLES_STD . '):?/?/?$,iS';
+       return preg_match($r, $url) ? '': ($entites ? entites_html($url) : $url);
 }
 
 // Extraire une date de n'importe quel champ (a completer...)
@@ -948,6 +1007,7 @@ function affdate_base($numdate, $vue, $options = array()) {
 
        switch ($vue) {
        case 'saison':
+       case 'saison_annee':
                $saison = '';
                if ($mois > 0){
                        $saison = 1;
@@ -956,7 +1016,10 @@ function affdate_base($numdate, $vue, $options = array()) {
                        if (($mois == 9 AND $jour >= 21) OR $mois > 9) $saison = 4;
                        if (($mois == 12 AND $jour >= 21) OR $mois > 12) $saison = 1;
                }
-               return $saison?_T('date_saison_'.$saison):'';
+               if($vue == 'saison')
+                       return $saison?_T('date_saison_'.$saison):'';
+               else
+                       return $saison?trim(_T('date_fmt_saison_annee', array('saison'=>_T('date_saison_'.$saison), 'annee'=>$annee))) :'';
 
        case 'court':
                if ($avjc) return $annee;
@@ -1056,6 +1119,11 @@ function saison($numdate) {
        return affdate_base($numdate, 'saison');
 }
 
+// http://doc.spip.org/@saison_annee
+function saison_annee($numdate) {
+       return affdate_base($numdate, 'saison_annee');
+}
+
 // http://doc.spip.org/@affdate
 function affdate($numdate, $format='entier') {
        return affdate_base($numdate, $format);
@@ -1102,6 +1170,10 @@ function affdate_heure($numdate) {
  * @param string $date_fin
  * @param string $horaire
  * @param string $forme
+ *   abbr pour afficher le nom du jour en abbrege (Dim. au lieu de Dimanche)
+ *   annee pour forcer l'affichage de l'annee courante
+ *   jour pour forcer l'affichage du nom du jour
+ *   hcal pour pour avoir un markup microformat abbr
  * @return string
  */
 function affdate_debut_fin($date_debut, $date_fin, $horaire = 'oui', $forme=''){
@@ -1139,14 +1211,14 @@ function affdate_debut_fin($date_debut, $date_fin, $horaire = 'oui', $forme=''){
                        }else{
                                // Le <abbr...>lundi 20 fevrier de 18h00</abbr> a <abbr...>20h00</abbr>
                                if($dtabbr && $dtstart && $dtend)
-                                       $s = spip_ucfirst(_T('date_fmt_jour_heure_debut_fin_abbr',array('jour'=>$s,'heure_debut'=>$hd,'heure_fin'=>$hf,'dtstart'=>$dtstart,'dtend'=>$dtend,'dtabbr'=>$dtabbr)));
+                                       $s = _T('date_fmt_jour_heure_debut_fin_abbr',array('jour'=>spip_ucfirst($s),'heure_debut'=>$hd,'heure_fin'=>$hf,'dtstart'=>$dtstart,'dtend'=>$dtend,'dtabbr'=>$dtabbr));
                                // Le lundi 20 fevrier de 18h00 a 20h00
                                else
                                        $s = spip_ucfirst(_T('date_fmt_jour_heure_debut_fin',array('jour'=>$s,'heure_debut'=>$hd,'heure_fin'=>$hf)));
                        }
                }else{
                        if($dtabbr && $dtstart)
-                               $s = $dtstart.spip_ucfirst($s).$dabbr;
+                               $s = $dtstart.spip_ucfirst($s).$dtabbr;
                        else
                                $s = spip_ucfirst($s);
                }
@@ -1156,7 +1228,7 @@ function affdate_debut_fin($date_debut, $date_fin, $horaire = 'oui', $forme=''){
                if(!$h)
                        $date_debut = jour($d);
                else
-                       $date_debut = $affdate($d);
+                       $date_debut = affdate_jourcourt($d,date("Y",$date_fin));
                $date_fin = $affdate($f);
                if($jour){
                        $nomjour_debut = nom_jour($d,$abbr);
@@ -1174,13 +1246,13 @@ function affdate_debut_fin($date_debut, $date_fin, $horaire = 'oui', $forme=''){
                $s = _T('date_fmt_periode',array('date_debut' => $date_debut,'date_fin'=>$date_fin));
        }
        else {
-               $date_debut = affdate($d);
-               $date_fin = affdate($f);
+               $date_debut = affdate_jourcourt($d,date("Y",$date_fin));
+               $date_fin = $affdate($f);
                if($jour){
                        $nomjour_debut = nom_jour($d,$abbr);
-                       $date_debut = _T('date_fmt_jour_periode',array('nomjour'=>$nomjour_debut,'jour' => $date_debut));
+                       $date_debut = _T('date_fmt_jour',array('nomjour'=>$nomjour_debut,'jour' => $date_debut));
                        $nomjour_fin = nom_jour($f,$abbr);
-                       $date_fin = _T('date_fmt_jour_periode',array('nomjour'=>$nomjour_fin,'jour' => $date_fin));
+                       $date_fin = _T('date_fmt_jour',array('nomjour'=>$nomjour_fin,'jour' => $date_fin));
                }
                if ($h){
                        $date_debut = _T('date_fmt_jour_heure',array('jour'=>$date_debut,'heure'=>$hd)); 
@@ -1421,6 +1493,11 @@ function extraire_trads($bloc) {
        return $trads;
 }
 
+// Calculer l'initiale d'un nom
+function initiale($nom){
+       return spip_substr(trim(strtoupper(extraire_multi($nom))),0,1);
+}
+
 //
 // Ce filtre retourne la donnee si c'est la premiere fois qu'il la voit ;
 // possibilite de gerer differentes "familles" de donnees |unique{famille}
@@ -1510,7 +1587,10 @@ function extraire_attribut($balise, $attribut, $complet = false) {
                } else {
                        $r[4] = trim($r[2]); 
                }
-               $att = filtrer_entites(str_replace("&#39;", "'", $r[4]));
+               $att = $r[4];
+               if (strpos($att,"&#")!==false)
+                       $att = str_replace(array("&#039;","&#39;","&#034;","&#34;"), array("'","'",'"','"'), $att);
+               $att = filtrer_entites($att);
        }
        else
                $att = NULL;
@@ -1573,15 +1653,13 @@ function vider_attribut ($balise, $attribut) {
 /**
  * Un filtre pour determiner le nom du satut des inscrits
  *
- * @deprecated a virer en 3.1
- *
  * @param void|int $id
  * @param string $mode
  * @return string
  */
 function tester_config($id, $mode='') {
-       include_spip('inc/autoriser');
-       return autoriser('inscrireauteur', $mode, $id) ? $mode : '';
+       include_spip('action/inscrire_auteur');
+       return tester_statut_inscription($mode, $id);
 }
 
 //
@@ -1609,6 +1687,34 @@ function modulo($nb, $mod, $add=0) {
 }
 
 
+/**
+ * Vérifie qu'un nom (d'auteur) ne comporte pas d'autres tags que <multi>
+ * et ceux volontairement spécifiés dans la constante
+ *
+ * @param string $nom
+ *      Nom (signature) proposé
+ * @return bool
+ *      - false si pas conforme,
+ *      - true sinon
+**/
+function nom_acceptable($nom) {
+       if (!is_string($nom)) {
+               return false;
+       }
+       if (!defined('_TAGS_NOM_AUTEUR')) define('_TAGS_NOM_AUTEUR','');
+       $tags_acceptes = array_unique(explode(',', 'multi,' . _TAGS_NOM_AUTEUR));
+       foreach($tags_acceptes as $tag) {
+               if (strlen($tag)) {
+                       $remp1[] = '<'.trim($tag).'>';
+                       $remp1[] = '</'.trim($tag).'>';
+                       $remp2[] = '\x60'.trim($tag).'\x61';
+                       $remp2[] = '\x60/'.trim($tag).'\x61';
+               }
+       }       
+       $v_nom = str_replace($remp2, $remp1, supprimer_tags(str_replace($remp1, $remp2, $nom)));
+       return str_replace('&lt;', '<', $v_nom) == $nom;
+}
+
 // Verifier la conformite d'une ou plusieurs adresses email
 //  retourne false ou la  normalisation de la derniere adresse donnee
 // http://doc.spip.org/@email_valide
@@ -1674,9 +1780,9 @@ function enclosure2microformat($e) {
        }
        $fichier = basename($url);
        return '<a rel="enclosure"'
-               . ($url? ' href="'.htmlspecialchars($url).'"' : '')
-               . ($type? ' type="'.htmlspecialchars($type).'"' : '')
-               . ($length? ' title="'.htmlspecialchars($length).'"' : '')
+               . ($url? ' href="'.spip_htmlspecialchars($url).'"' : '')
+               . ($type? ' type="'.spip_htmlspecialchars($type).'"' : '')
+               . ($length? ' title="'.spip_htmlspecialchars($length).'"' : '')
                . '>'.$fichier.'</a>';
 }
 // La fonction inverse
@@ -1691,8 +1797,8 @@ function microformat2enclosure($tags) {
                        $length = intval(extraire_attribut($e, 'length')); # vieux data
                $fichier = basename($url);
                $enclosures[] = '<enclosure'
-                       . ($url? ' url="'.htmlspecialchars($url).'"' : '')
-                       . ($type? ' type="'.htmlspecialchars($type).'"' : '')
+                       . ($url? ' url="'.spip_htmlspecialchars($url).'"' : '')
+                       . ($type? ' type="'.spip_htmlspecialchars($type).'"' : '')
                        . ($length? ' length="'.$length.'"' : '')
                        . ' />';
        }
@@ -2211,16 +2317,17 @@ function concat(){
 
 
 // http://doc.spip.org/@charge_scripts
-function charge_scripts($scripts) {
-  $flux = "";
-  $args = is_array($scripts)?$scripts:explode("|",$scripts);
-  foreach($args as $script) {
-    if(preg_match(",^\w+$,",$script)) {
-      $path = find_in_path("javascript/$script.js");
-      if($path) $flux .= spip_file_get_contents($path);
-    }
-  }
-  return $flux;
+// http://doc.spip.org/@charge_scripts
+function charge_scripts($files, $script = true) {
+       $flux = "";
+       foreach(is_array($files)?$files:explode("|",$files) as $file) {
+               if (!is_string($file)) continue;
+               if ($script)
+                       $file = preg_match(",^\w+$,",$file) ? "javascript/$file.js" : '';
+               if ($file) $path = find_in_path($file);
+               if ($path) $flux .= spip_file_get_contents($path);
+       }
+       return $flux;
 }
 
 
@@ -2874,6 +2981,7 @@ function generer_info_entite($id_objet, $type_objet, $info, $etoile=""){
        if (!$etoile
                AND is_array($traitement)
          AND (isset($traitement[$table_sql]) OR isset($traitement[0]))){
+               include_spip('inc/texte');
                $traitement = $traitement[isset($traitement[$table_sql]) ? $table_sql : 0];
                $traitement = str_replace('%s', "'".texte_script($info_generee)."'", $traitement);
                // FIXME: $connect et $Pile[0] font souvent partie des traitements.
@@ -2904,20 +3012,54 @@ function wrap($texte,$wrap) {
 }
 
 
-// afficher proprement n'importe quoi
-// en cas de table profonde, l'option $join ne s'applique qu'au plus haut niveau
-// c'est VOULU !  Exemple : [(#VALEUR|print{<hr />})] va afficher de gros blocs
-// separes par des lignes, avec a l'interieur des trucs separes par des virgules
-function filtre_print_dist($u, $join=', ') {
-       if (is_string($u))
-               return typo($u);
-
-       if (is_array($u))
-               return join($join, array_map('filtre_print_dist', $u));
+/**
+ * afficher proprement n'importe quoi
+ * On affiche in fine un pseudo-yaml qui premet de lire humainement les tableaux et de s'y reperer
+ *
+ * Les textes sont retournes avec simplement mise en forme typo
+ *
+ * le $join sert a separer les items d'un tableau, c'est en general un \n ou <br /> selon si on fait du html ou du texte
+ * les tableaux-listes (qui n'ont que des cles numeriques), sont affiches sous forme de liste separee par des virgules :
+ * c'est VOULU !
+ *
+ * @param $u
+ * @param string $join
+ * @param int $indent
+ * @return array|mixed|string
+ */
+function filtre_print_dist($u, $join="<br />", $indent=0) {
+       if (is_string($u)){
+               $u = typo($u);
+               return $u;
+       }
 
+       // caster $u en array si besoin
        if (is_object($u))
-               return join($join, array_map('filtre_print_dist', (array) $u));
+               $u = (array) $u;
+
+       if (is_array($u)){
+               $out = "";
+               // toutes les cles sont numeriques ?
+               // et aucun enfant n'est un tableau
+               // liste simple separee par des virgules
+               $numeric_keys = array_map('is_numeric',array_keys($u));
+               $array_values = array_map('is_array',$u);
+               $object_values = array_map('is_object',$u);
+               if (array_sum($numeric_keys)==count($numeric_keys)
+                 AND !array_sum($array_values)
+                 AND !array_sum($object_values)){
+                       return join(", ", array_map('filtre_print_dist', $u));
+               }
+
+               // sinon on passe a la ligne et on indente
+               $i_str = str_pad("",$indent," ");
+               foreach($u as $k => $v){
+                       $out .= $join . $i_str . "$k: " . filtre_print_dist($v,$join,$indent+2);
+               }
+               return $out;
+       }
 
+       // on sait pas quoi faire...
        return $u;
 }
 
@@ -3061,7 +3203,7 @@ function produire_fond_statique($fond, $contexte=array(), $options = array(), $c
  * @return string
  */
 function timestamp($fichier){
-       if (!$fichier) return $fichier;
+       if (!$fichier OR !file_exists($fichier)) return $fichier;
        $m = filemtime($fichier);
        return "$fichier?$m";
 }