Changeset 118855 in spip-zone


Ignore:
Timestamp:
Dec 2, 2019, 12:30:19 PM (7 days ago)
Author:
Cerdic
Message:

on deporte tous les gros filtres dans des fonctions surchargeables sur le meme modele, c'est plus simple a maintenir, lire, surcharger

Location:
_plugins_/facteur/trunk
Files:
3 added
2 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/facteur/trunk

    • Property subgit:lock:5a870185582ca35b2eb360fd507ce156b0d8c2c8 deleted
    • Property subgit:lock:00dd4501ded3fbc7b1b4c54a5a0a0364ab69d5da set to 2019-12-02T18:21:48.553
  • _plugins_/facteur/trunk/facteur_fonctions.php

    r118853 r118855  
    2424
    2525/**
    26  * Transformer un mail texte ou HTML simplifie en mail HTML complet avec le wrapper emails/texte.html
    27  * Si le mail est un mail texte :
    28  *   la premiere ligne est le sujet
    29  *   le reste est le corps du mail
    30  *
    31  * Si le mail est un mail HTML simplifie :
    32  *   le sujet est entre <title></title>
    33  *   le corps est entre <body></body>
    34  *   une eventuelle intro peut etre fournie entre <intro></intro>
    35  *
    36  * @param string $texte_ou_html
    37  * @return string
    38  */
    39 function facteur_email_wrap_to_html($texte_ou_html){
    40         $texte_ou_html = trim($texte_ou_html);
    41         // attention : si pas de contenu on renvoi du vide aussi (mail vide = mail vide)
    42         if (!strlen(trim($texte_ou_html))) {
    43         return $texte_ou_html;
    44     }
    45 
    46         $contexte = array('sujet' => '', 'texte' => '', 'intro' => '');
    47 
    48         // tester si le mail est en html (simplifie)
    49         if (substr($texte_ou_html, 0, 1) == '<'
    50           and substr($texte_ou_html,-1,1) == '>'
    51           and stripos($texte_ou_html, '</body>') !== false) {
    52 
    53                 // dans ce cas on ruse un peu : extraire le sujet du title
    54                 $sujet = '';
    55                 if (preg_match(",<title>(.*)</title>,Uims", $texte_ou_html, $m)) {
    56                         $contexte['sujet'] = $m[1];
    57                         $texte_ou_html = preg_replace(",<title>(.*)</title>,Uims", '', $texte_ou_html, 1);
    58                         $texte_ou_html = trim($texte_ou_html);
    59                 }
    60                 if (preg_match(",<intro>(.*)</intro>,Uims", $texte_ou_html, $m)){
    61                         $contexte['intro'] = $m[1];
    62                         $texte_ou_html = preg_replace(",<intro>(.*)</intro>,Uims", '', $texte_ou_html, 1);
    63                         $texte_ou_html = trim($texte_ou_html);
    64                 }
    65                 $contexte['html'] = preg_replace(",</?body>,ims", '', $texte_ou_html);
    66         }
    67         else {
    68                 // la premiere ligne est toujours le sujet
    69                 $texte_ou_html = explode("\n", $texte_ou_html);
    70                 $contexte['sujet'] = trim(array_shift($texte_ou_html));
    71                 $contexte['texte'] = trim(implode("\n", $texte_ou_html));
    72         }
    73 
    74         // attention : si pas de contenu on renvoi du vide aussi (mail vide = mail vide)
    75         if (!strlen(trim(implode('', $contexte)))) {
    76         return '';
    77     }
    78 
    79         return recuperer_fond('emails/texte', $contexte);
    80 }
    81 
    82         /*
    83 
    84         Written by Eric Dols - edols@auditavenue.com
    85 
    86         You may freely use or modify this, provided
    87         you leave credits to the original coder.
    88         Feedback about (un)successfull uses, bugs and improvements done
    89         are much appreciated, but don't expect actual support.
    90 
    91         PURPOSE OF THIS FUNCTION
    92                 It is designed to process html emails relying
    93                 on a css stylesheet placed in the <head> for layout in
    94                 order to enhance compatibility with email clients,
    95                 including webmail services.
    96                 Provided you use minimal css, you can keep styling separate
    97                 from the content in your email template, and let this function
    98                 "inject" those styles inline in your email html tags on-the-fly,
    99                 just before sending.
    100                 Technically, it grabs the style declarations found in the
    101                 <head> section and inserts each declaration inline,
    102                 inside the corresponding html tags in the email message.
    103 
    104                 Supports both HTML and XHTML markup seamlessly. Thus
    105                 tolerant to email message writers using non-xhtml tag,
    106                 even when template is xhtml compliant (e.g. they would
    107                 add <img ...> instead of a xhtml compliant <img ... />).
    108 
    109         NEW 10 dec. 2003:
    110                 - code revised, including a few regexp bugs fixed.
    111                 - multiple class for a tag are now allowed <p class="firstclass secondclass">
    112                 - all unsupported css styles are now moved to the body section (not just a:hover etc...)
    113 
    114         USE
    115                 Add this function to a function library include, like "inline.inc"
    116                 and include it near the beginning of your php page:
    117                 require ("inline.inc");
    118 
    119                 load the html source of message into a variable
    120                 like $html_source and process it using:
    121                 $html_source = sheet2inline($html_source)
    122 
    123 
    124         STYLE DEFINITIONS SUPPORTED
    125                 TAG { ... }
    126                 TAG1, TAG2, ... { ... }
    127                 TAG.class { ... }
    128                 .class { ...)
    129                 TAG:pseudo { ... }
    130 
    131 
    132                 CSS definitions may be freely formatted (spaces, tabs, linefeeds...),
    133                 they are converted to oneliners before inserting them inline in the html tags.
    134 
    135                 .class definitions are processed AFTER tag definitions,
    136                 thus appended inline after any existing tag styling to
    137                 preserve the normal css priority behavior.
    138 
    139                 Existing style="..." attributes in tags are NOT stripped. However they MUST
    140                 be with double quotes. If not, an addtional style="..." attribute will be added
    141 
    142 
    143         KNOWN LIMITATIONS
    144                 - style info should be placed in <head> section. I believe
    145                         it shouldnt be too hard to modify to point to an external
    146                         stylesheet instead.
    147                 - no support (yet?):
    148                         * chains like P UL LI { .... } or P UL LI.class { .... }
    149                         * #divname p { ... } and <tag id="...">
    150                         * a:hover, a:visited {...} multiple class:pseudo
    151                         They require a significantly more complicated processing likely
    152                         based on stylesheet and document trees parsing.
    153                         Many email clients don't handle more than what is supported
    154                         by this script anyway.
    155                 - pseudo-classes like a:hover {...} can't be inserted inline
    156                         in the html tags: they are moved to a <style> declaration in
    157                         the <body> instead. This is a limitation from html, not this script.
    158                 - It is still up to you to check if target email clients render
    159                         your css styled templates correctly, especially webmail services
    160                         like Hotmail, in which the email becomes a sub-part of an html page,
    161                         with styles already in place.
    162         */
    163 function facteur_convertir_styles_inline($body){
    164         // variables to be accessed in the callback sub-function too
    165         global $styledefinition, $styletag, $styleclass;
    166 
    167         // Let's first load the stylesheet information in a $styles array using a regexp
    168         preg_match_all ( "/^[ \t]*([.]?)([\w, #]+)([.:])?(\S*)\s+{([^}]+)}/mi", $body , $styles);
    169         /*
    170                 $styles[1] = . or ''  => .class or tag (empty)
    171                 $styles[2] = name of class or tag(s)
    172                 $styles[3] = : . or '' => followed by pseudo-element, class separator or nothing (empty)
    173                 $styles[4] = name of pseudo-element after a tag, if any
    174                 $styles[5] = the style definition itself, i.e. what's between the { }
    175         */
    176 
    177         // Now loop through the styles found and act accordingly;
    178 
    179         // process TAG {...} & TAG1, TAG2,... {...} definitions only first by order of appearance
    180         foreach ($styles[1] as $i => $type) {
    181                 if ($type=="" && $styles[3][$i]=="") {
    182                         $styledefinition = trim($styles[5][$i]);
    183                         $styletag = preg_replace("/ *, */", "|", trim($styles[2][$i])); //echo $styletag."<br />";
    184                         $styleclass = "";
    185                         // process TAG {...} and TAG1, TAG2 {...} but not TAG1 TAG2 {...} or #divname styles
    186                         if (!preg_match("/ /", $styletag) && !preg_match("/#/", $styletag)) {
    187                                 $pattern = "!<(".$styletag.")([^>]*(?= /)|[^>]*)( /)?>!mi";
    188                                 $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
    189                                 $styles[6][$i]=1; // mark as injected inline
    190                         }
    191                 }
    192         }
    193 
    194         // append additional .CLASS {...} and TAG.CLASS {...} styling by order of appearance
    195         // important to do so after TAG {...} definitions, so that class attributes override TAG styles when needed
    196         foreach ($styles[1] as $i => $type) {
    197                 if ($type!="." && $styles[3][$i]=="." ) {       // class definition for a specific tag
    198                         $styledefinition = trim($styles[5][$i]);
    199                         $styletag = trim($styles[2][$i]);
    200                         $styleclass = trim($styles[4][$i]);
    201                         $pattern = "!<(".$styletag.")([^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*(?= /)|[^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*)( />)?>!mi";
    202                         $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
    203                         $styles[6][$i]=1; // mark as injected inline
    204 
    205                 }
    206                 elseif ($type=="." && $styles[3][$i]=="" ) {    // general class definition for any tag
    207                         $styledefinition = trim($styles[5][$i]);
    208                         $styletag = "";
    209                         $styleclass = trim($styles[2][$i]);
    210                         $pattern = "!<(\w+)([^>]* class\=['\"]".$styleclass."['\"][^>]*(?= /)|[^>]* class\=['\"]".$styleclass."['\"][^>]*)( />)?>!mi";
    211                         $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
    212                         $styles[6][$i]=1; // mark as injected inline
    213                 }
    214         }
    215 
    216 
    217         /* move all style declarations that weren't injected from <head> to a <body> <style> section,
    218                  including but not limited to:
    219                  - pseudo-classes like a:hover {...} as they can't be set inline
    220                  - declaration chains like UL LI {...}
    221                  - #divname {...}. These are not supported by email clients like Mac/Entourage anyway, it seems. */
    222         foreach ($styles[1] as $i => $type) {
    223                 if ($styles[6][$i]=="") {
    224                         // add a <style type="text/css"> section after <body> if there's isn't one yet
    225                         if (preg_match ("!<body[^>]*>\s*<style!mi", $body)==0) {
    226                                 $body = preg_replace ("/(<body[^>]*>)/i", "\n\$1\n".'<style type="text/css">'."\n<!--\n-->\n</style>\n", $body);
    227                         }
    228                         // append a copy of the pseudo-element declaration to that body style section
    229                         $styledefinition = trim($styles[5][$i]);
    230                         $styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition ); // convert style definition to a one-liner (optional)
    231                         $declaration = $styles[1][$i].trim($styles[2][$i]).$styles[3][$i].trim($styles[4][$i])." { ".$styledefinition." }";
    232                         $body = preg_replace ("!(<body[^>]*>\s*<style[^>]*>\s*<\!\-\-[^>]*)"."(\s*\-\->\s*</style>)!si", "\$1".$declaration."\n\$2", $body);
    233                         $styles[6][$i]= 2; // mark as moved to <style> section in <body>
    234                 }
    235         }
    236 
    237         // remove stylesheet declaration(s) from <head> section (comment following line out if not wanted)
    238         //$body = preg_replace ("!(<head>.*)<style type.*</style>(.*</head>)!si", "\$1\$2" , $body);
    239 
    240         // check what styles have been injected
    241 #                       print_r($styles);
    242 
    243         return $body;
    244 }
    245 
    246 /**
    247  * facteur_addstyle
    248  * @author Eric Dols
    249  *
    250  * @param $matches
    251  * @return string
    252  */
    253 function facteur_addstyle($matches) {
    254 
    255         // $matches[1]=tag, $matches[2]=tag attributes (if any), $matches[3]=xhtml closing (if any)
    256 
    257         // variables values set in calling function
    258         global $styledefinition, $styletag, $styleclass;
    259 
    260         // convert the style definition to a one-liner
    261         $styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition );
    262         // convert all double-quotes to single-quotes
    263         $styledefinition = preg_replace ('/"/','\'', $styledefinition );
    264 
    265         if (preg_match ("/style\=/i", $matches[2])) {
    266                         // add styles to existing style attribute if any already in the tag
    267                         $pattern = "!(.* style\=)[\"]([^\"]*)[\"](.*)!mi";
    268                         $replacement = "\$1".'"'."\$2 ".$styledefinition.'"'."\$3";
    269                         $attributes = preg_replace ($pattern, $replacement , $matches[2]);
    270         } else {
    271                         // otherwise add new style attribute to tag (none was present)
    272                         $attributes = $matches[2].' style="'.$styledefinition.'"';
    273         }
    274 
    275         if ($styleclass!="") {
    276                 // if we were injecting a class style, remove the now useless class attribute from the html tag
    277 
    278                 // Single class in tag case (class="classname"): remove class attribute altogether
    279                 $pattern = "!(.*) class\=['\"]".$styleclass."['\"](.*)!mi";
    280                 $replacement = "\$1\$2";
    281                 $attributes = preg_replace ( $pattern, $replacement, $attributes);
    282 
    283                 // Multiple classes in tag case (class="classname anotherclass..."): remove class name from class attribute.
    284                 // classes are injected inline and removed by order of appearance in <head> stylesheet
    285                 // exact same behavior as where last declared class attributes in <style> take over (IE6 tested only)
    286                 $pattern = "!(.* class\=['\"][^\"]*)(".$styleclass." | ".$styleclass.")([^\"]*['\"].*)!mi";
    287                 $replacement = "\$1\$3";
    288                 $attributes = preg_replace ( $pattern, $replacement, $attributes);
    289 
    290         }
    291 
    292         return "<".$matches[1].$attributes.$matches[3].">";
    293 }
    294 
    295 /**
    29626 * Un filtre pour transformer les retour ligne texte en br si besoin (si pas autobr actif)
    29727 *
     
    30636}
    30737
     38
     39
    30840/**
    309  * Transformer un mail HTML en mail Texte proprement :
    310  * - les tableaux de mise en page sont utilisés pour structurer le mail texte
    311  * - le reste du HTML est markdownifie car c'est un format texte lisible et conventionnel
     41 * voir inc/facteur_mail_wrap_to_html
    31242 *
     43 * @param string $texte_ou_html
     44 * @return string
     45 */
     46function facteur_email_wrap_to_html($texte_ou_html){
     47
     48        $facteur_mail_wrap_to_html = charger_fonction('facteur_mail_wrap_to_html', 'inc');
     49        return $facteur_mail_wrap_to_html($texte_ou_html);
     50}
     51
     52/**
     53 * voir inc/facteur_convertir_styles_inline
     54 *
     55 * @param string $body
     56 * @return string
     57 */
     58function facteur_convertir_styles_inline($body){
     59
     60        $facteur_convertir_styles_inline = charger_fonction('facteur_convertir_styles_inline', 'inc');
     61        return $facteur_convertir_styles_inline($body);
     62}
     63
     64
     65/**
     66 * voir inc/facteur_mail_html2text
    31367 * @param string $html
    31468 * @return string
    31569 */
    31670function facteur_mail_html2text($html){
    317         // nettoyer les balises de mise en page html
    318         $html = preg_replace(",</(td|th)>,Uims","<br/>",$html);
    319         $html = preg_replace(",</(table)>,Uims","@@@hr@@@",$html);
    320         $html = preg_replace(",</?(html|body|table|td|th|tbody|thead|center|article|section|span)[^>]*>,Uims","\n\n",$html);
    32171
    322         // commentaires html et conditionnels
    323         $html = preg_replace(",<!--.*-->,Uims","\n",$html);
    324         $html = preg_replace(",<!\[.*\]>,Uims","\n",$html);
    325 
    326         $html = preg_replace(",<(/?)(div|tr|caption)([^>]*>),Uims","<\\1p>",$html);
    327         $html = preg_replace(",(<p>\s*)+,ims","<p>",$html);
    328         $html = preg_replace(",<br/?>\s*</p>,ims","</p>",$html);
    329         $html = preg_replace(",</p>\s*<br/?>,ims","</p>",$html);
    330         $html = preg_replace(",(</p>\s*(@@@hr@@@)?\s*)+,ims","</p>\\2",$html);
    331         $html = preg_replace(",(<p>\s*</p>),ims","",$html);
    332 
    333         // succession @@@hr@@@<hr> et <hr>@@@hr@@@
    334         $html = preg_replace(",@@@hr@@@\s*(<[^>]*>\s*)?<hr[^>]*>,ims","@@@hr@@@\n",$html);
    335         $html = preg_replace(",<hr[^>]*>\s*(<[^>]*>\s*)?@@@hr@@@,ims","\n@@@hr@@@",$html);
    336 
    337         $html = preg_replace(",<textarea[^>]*spip_cadre[^>]*>(.*)</textarea>,Uims","<code>\n\\1\n</code>",$html);
    338 
    339         // vider le contenu de qqunes :
    340         $html = preg_replace(",<head[^>]*>.*</head>,Uims","\n",$html);
    341 
    342         // Liens :
    343         // Nettoyage des liens des notes de bas de page
    344         $html = preg_replace("@<a href=\"#n(b|h)[0-9]+-[0-9]+\" name=\"n(b|h)[0-9]+-[0-9]+\" class=\"spip_note\">([0-9]+)</a>@", "\\3", $html);
    345         // Supprimer tous les liens internes
    346         $html = preg_replace("/\<a href=['\"]#(.*?)['\"][^>]*>(.*?)<\/a>/ims","\\2", $html);
    347         // Remplace tous les liens
    348         preg_match_all("/\<a href=['\"](.*?)['\"][^>]*>(.*?)<\/a>/ims", $html,$matches,PREG_SET_ORDER);
    349         $prelinks = $postlinks = array();
    350         if (!function_exists('url_absolue'))
    351                 include_spip('inc/filtres');
    352         foreach ($matches as $k => $match){
    353                 $link = "@@@link$k@@@";
    354                 $url = str_replace("&amp;","&",$match[1]);
    355                 if ($match[2]==$match[1] OR $match[2]==$url){
    356                         // si le texte est l'url :
    357                         $prelinks[$match[0]] = "$link";
    358                 }
    359                 else {
    360                         // texte + url
    361                         $prelinks[$match[0]] = $match[2] . " ($link)";
    362                 }
    363                 // passer l'url en absolu dans le texte sinon elle n'est pas clicable ni utilisable
    364                 $postlinks[$link] = url_absolue($url);
    365         }
    366         $html = str_replace(array_keys($prelinks), array_values($prelinks),$html);
    367 
    368         // les images par leur alt ?
    369         // au moins les puces
    370         $html = preg_replace(',<img\s[^>]*alt="-"[^>]*>,Uims','-',$html);
    371         // les autres
    372         $html = preg_replace(',<img\s[^>]*alt=[\'"]([^\'"]*)[\'"][^>]*>,Uims',"\\1",$html);
    373         // on vire celles sans alt
    374         $html = preg_replace(",</?(img)[^>]*>,Uims","\n",$html);
    375 
    376         // espaces
    377         $html = str_replace("&nbsp;"," ",$html);
    378         $html = preg_replace(",<p>\s+,ims","<p>",$html);
    379 
    380         #return $html;
    381         include_spip("lib/markdownify/markdownify");
    382         $parser = new Markdownify('inline',false,false);
    383         $texte = $parser->parseString($html);
    384 
    385         $texte = str_replace(array_keys($postlinks), array_values($postlinks),$texte);
    386 
    387 
    388         // trim et sauts de ligne en trop ou pas assez
    389         $texte = trim($texte);
    390         $texte = str_replace("<br />\n","\n",$texte);
    391         $texte = preg_replace(",(@@@hr@@@\s*)+\Z,ims","",$texte);
    392         $texte = preg_replace(",(@@@hr@@@\s*\n)+,ims","\n\n\n".str_pad("-",75,"-")."\n\n\n",$texte);
    393         $texte = preg_replace(",(\n#+\s),ims","\n\n\\1",$texte);
    394         $texte = preg_replace(",(\n\s*)(\n\s*)+(\n)+,ims","\n\n\n",$texte);
    395 
    396 
    397         // <p> et </p> restants
    398         $texte = str_replace(array("<p>","</p>"),array("",""),$texte);
    399 
    400         // entites restantes ? (dans du code...)
    401         include_spip('inc/charsets');
    402         $texte = unicode2charset($texte);
    403         $texte = str_replace(array('&#039;', '&#034;'),array("'",'"'), $texte);
    404 
    405 
    406         // Faire des lignes de 75 caracteres maximum
    407         return trim(wordwrap($texte));
     72        $facteur_mail_html2text = charger_fonction('facteur_mail_html2text', 'inc');
     73        return $facteur_mail_html2text($html);
    40874}
Note: See TracChangeset for help on using the changeset viewer.