source: spip-zone/_plugins_/facteur/trunk/classes/facteur.php @ 54249

Last change on this file since 54249 was 54249, checked in by cedric@…, 8 years ago

cartouche
lien vers la bonne icone
modernisation du script d'upgrade
grostitre sur la page de configuration
ne pas inclure classes/facteur sur chaque calcul, les scripts qui ont besoin de mailer le font par cette inclusion
ou par inc/envoyer_mail

  • Property svn:executable set to *
File size: 18.1 KB
Line 
1<?php
2/*
3 * Plugin Facteur 2
4 * (c) 2009-2011 Collectif SPIP
5 * Distribue sous licence GPL
6 *
7 */
8
9if (!defined("_ECRIRE_INC_VERSION")) return;
10
11include_spip('inc/charsets');
12include_spip('inc/texte');
13include_spip('inc/filtres');
14
15if (!class_exists('PHPMailer')) {
16        include_spip('phpmailer-php5/class.phpmailer');
17        include_spip('phpmailer-php5/class.smtp');
18}
19
20include_spip('facteur_fonctions');
21
22class Facteur extends PHPMailer {
23
24        function Facteur($email, $objet, $message_html, $message_texte) {
25
26                if ($GLOBALS['meta']['facteur_adresse_envoi'] == 'oui'
27                  AND $GLOBALS['meta']['facteur_adresse_envoi_email'])
28                        $this->From = $GLOBALS['meta']['facteur_adresse_envoi_email'];
29                else
30                        $this->From = $GLOBALS['meta']['email_webmaster'];
31
32                if ($GLOBALS['meta']['facteur_adresse_envoi'] == 'oui'
33                  AND $GLOBALS['meta']['facteur_adresse_envoi_nom'])
34                        $this->FromName = $GLOBALS['meta']['facteur_adresse_envoi_nom'];
35                else
36                        $this->FromName = strip_tags(extraire_multi($GLOBALS['meta']['nom_site']));
37
38                $this->CharSet = "utf-8";
39                $this->Mailer = 'mail';
40                $this->Subject = unicode_to_utf_8(charset2unicode($objet,$GLOBALS['meta']['charset']));
41
42                //Pour un envoi multiple de mail, $email doit être un tableau avec les adresses.
43                if (is_array($email)) {
44                        foreach ($email as $cle => $adresseMail) {
45                                $this->AddAddress($adresseMail);
46                        }
47                }
48                else
49                        $this->AddAddress($email);
50
51                if (!empty($GLOBALS['meta']['facteur_smtp_sender'])) {
52                        $this->Sender = $GLOBALS['meta']['facteur_smtp_sender'];
53                        $this->AddCustomHeader("Errors-To: ".$this->Sender);
54                }
55
56                if (!empty($GLOBALS['meta']['facteur_cc'])) {
57                        $this->AddCC( $GLOBALS['meta']['facteur_cc'] );
58                }
59                if (!empty($GLOBALS['meta']['facteur_bcc'])) {
60                        $this->AddBCC( $GLOBALS['meta']['facteur_bcc'] );
61                }
62               
63                if (isset($GLOBALS['meta']['facteur_smtp']) AND $GLOBALS['meta']['facteur_smtp'] == 'oui') {
64                        $this->Mailer   = 'smtp';
65                        $this->Host     = $GLOBALS['meta']['facteur_smtp_host'];
66                        $this->Port     = $GLOBALS['meta']['facteur_smtp_port'];
67                        if ($GLOBALS['meta']['facteur_smtp_auth'] == 'oui') {
68                                $this->SMTPAuth = true;
69                                $this->Username = $GLOBALS['meta']['facteur_smtp_username'];
70                                $this->Password = $GLOBALS['meta']['facteur_smtp_password'];
71                        }
72                        else {
73                                $this->SMTPAuth = false;
74                        }
75                        if (intval(phpversion()) == 5) {
76                        if ($GLOBALS['meta']['facteur_smtp_secure'] == 'ssl')
77                                $this->SMTPSecure = 'ssl';
78                        if ($GLOBALS['meta']['facteur_smtp_secure'] == 'tls')
79                                $this->SMTPSecure = 'tls';
80                        }
81                }
82
83                if (!empty($message_html)) {
84                        $message_html = unicode_to_utf_8(charset2unicode($message_html,$GLOBALS['meta']['charset']));
85                        $this->Body = $message_html;
86                        $this->IsHTML(true);
87                        if ($GLOBALS['meta']['facteur_filtre_css'])
88                                $this->ConvertirStylesEnligne();
89                        if ($GLOBALS['meta']['facteur_filtre_images'])
90                                $this->JoindreImagesHTML();
91                        $this->UrlsAbsolues();
92                }
93                if (!empty($message_texte)) {
94                        $message_texte = unicode_to_utf_8(charset2unicode($message_texte,$GLOBALS['meta']['charset']));
95                        if (!$this->Body) {
96                                $this->IsHTML(false);
97                                $this->Body = $message_texte;
98                        }
99                        else {
100                                $this->AltBody = $message_texte;
101                        }
102                }
103
104                if ($GLOBALS['meta']['facteur_filtre_iso_8859'])
105                        $this->ConvertirUtf8VersIso8859();
106
107        }
108       
109        /*
110         * Transforme du HTML en texte brut, mais proprement, c'est-à-dire en essayant
111         * de garder les titrages, les listes, etc
112         *
113         * @param string $html Le HTML à transformer
114         * @return string Retourne un texte brut formaté correctement
115         */
116        function html2text($html){
117                // On remplace tous les sauts de lignes par un espace
118                $html = str_replace("\n", ' ', $html);
119               
120                // Supprimer tous les liens internes
121                $texte = preg_replace("/\<a href=['\"]#(.*?)['\"][^>]*>(.*?)<\/a>/ims", "\\2", $html);
122       
123                // Supprime feuille style
124                $texte = preg_replace(";<style[^>]*>[^<]*</style>;i", "", $texte);
125       
126                // Remplace tous les liens     
127                $texte = preg_replace("/\<a[^>]*href=['\"](.*?)['\"][^>]*>(.*?)<\/a>/ims", "\\2 (\\1)", $texte);
128       
129                // Les titres
130                $texte = preg_replace(";<h1[^>]*>;i", "\n= ", $texte);
131                $texte = str_replace("</h1>", " =\n\n", $texte);
132                $texte = preg_replace(";<h2[^>]*>;i", "\n== ", $texte);
133                $texte = str_replace("</h2>", " ==\n\n", $texte);
134                $texte = preg_replace(";<h3[^>]*>;i", "\n=== ", $texte);
135                $texte = str_replace("</h3>", " ===\n\n", $texte);
136               
137                // Une fin de liste
138                $texte = preg_replace(";</(u|o)l>;i", "\n\n", $texte);
139               
140                // Une saut de ligne *après* le paragraphe
141                $texte = preg_replace(";<p[^>]*>;i", "\n", $texte);
142                $texte = preg_replace(";</p>;i", "\n\n", $texte);
143                // Les sauts de ligne interne
144                $texte = preg_replace(";<br[^>]*>;i", "\n", $texte);
145       
146                //$texte = str_replace('<br /><img class=\'spip_puce\' src=\'puce.gif\' alt=\'-\' border=\'0\'>', "\n".'-', $texte);
147                $texte = preg_replace (';<li[^>]*>;i', "\n".'- ', $texte);
148       
149       
150                // accentuation du gras
151                // <b>texte</b> -> **texte**
152                $texte = preg_replace (';<b[^>]*>;i','**' ,$texte);
153                $texte = str_replace ('</b>','**' ,$texte);
154       
155                // accentuation du gras
156                // <strong>texte</strong> -> **texte**
157                $texte = preg_replace (';<strong[^>]*>;i','**' ,$texte);
158                $texte = str_replace ('</strong>','**' ,$texte);
159       
160       
161                // accentuation de l'italique
162                // <em>texte</em> -> *texte*
163                $texte = preg_replace (';<em[^>]*>;i','/' ,$texte);
164                $texte = str_replace ('</em>','*' ,$texte);
165               
166                // accentuation de l'italique
167                // <i>texte</i> -> *texte*
168                $texte = preg_replace (';<i[^>]*>;i','/' ,$texte);
169                $texte = str_replace ('</i>','*' ,$texte);
170       
171                $texte = str_replace('&oelig;', 'oe', $texte);
172                $texte = str_replace("&nbsp;", " ", $texte);
173                $texte = filtrer_entites($texte);
174       
175                // On supprime toutes les balises restantes
176                $texte = supprimer_tags($texte);
177       
178                $texte = str_replace("\x0B", "", $texte); 
179                $texte = str_replace("\t", "", $texte) ;
180                $texte = preg_replace(";[ ]{3,};", "", $texte);
181       
182                // espace en debut de ligne
183                $texte = preg_replace("/(\r\n|\n|\r)[ ]+/", "\n", $texte);
184       
185                //marche po
186                // Bring down number of empty lines to 4 max
187                $texte = preg_replace("/(\r\n|\n|\r){3,}/m", "\n\n", $texte);
188       
189                //saut de lignes en debut de texte
190                $texte = preg_replace("/^(\r\n|\n|\r)*/", "\n\n", $texte);
191                //saut de lignes en debut ou fin de texte
192                $texte = preg_replace("/(\r\n|\n|\r)*$/", "\n\n", $texte);
193       
194                // Faire des lignes de 75 caracteres maximum
195                //$texte = wordwrap($texte);
196       
197                return $texte;
198        }
199       
200        /**
201         * Transformer les urls des liens et des images en url absolues
202         * sans toucher aux images embarquees de la forme "cid:..."
203         */
204        function UrlsAbsolues(){
205                include_spip('inc/filtres_mini');
206                if (preg_match_all(',(<(a|link)[[:space:]]+[^<>]*href=["\']?)([^"\' ><[:space:]]+)([^<>]*>),imsS',
207                $this->Body, $liens, PREG_SET_ORDER)) {
208                        foreach ($liens as $lien) {
209                                if (strncmp($lien[3],"cid:",4)!==0){
210                                        $abs = url_absolue($lien[3], $base);
211                                        if ($abs <> $lien[3] and !preg_match('/^#/',$lien[3]))
212                                                $this->Body = str_replace($lien[0], $lien[1].$abs.$lien[4], $this->Body);
213                                }
214                        }
215                }
216                if (preg_match_all(',(<(img|script)[[:space:]]+[^<>]*src=["\']?)([^"\' ><[:space:]]+)([^<>]*>),imsS',
217                $this->Body, $liens, PREG_SET_ORDER)) {
218                        foreach ($liens as $lien) {
219                                if (strncmp($lien[3],"cid:",4)!==0){
220                                        $abs = url_absolue($lien[3], $base);
221                                        if ($abs <> $lien[3])
222                                                $this->Body = str_replace($lien[0], $lien[1].$abs.$lien[4], $this->Body);
223                                }
224                        }
225                }
226        }
227
228        function JoindreImagesHTML() {
229                $image_types = array(
230                                                        'gif'   => 'image/gif',
231                                                        'jpg'   => 'image/jpeg',
232                                                        'jpeg'  => 'image/jpeg',
233                                                        'jpe'   => 'image/jpeg',
234                                                        'bmp'   => 'image/bmp',
235                                                        'png'   => 'image/png',
236                                                        'tif'   => 'image/tiff',
237                                                        'tiff'  => 'image/tiff',
238                                                        'swf'   => 'application/x-shockwave-flash'
239                                                );
240                while (list($key,) = each($image_types))
241                        $extensions[] = $key;
242
243                preg_match_all('/["\'](([^"\']+)\.('.implode('|', $extensions).'))([?][^"\']+)?["\']/Ui', $this->Body, $images, PREG_SET_ORDER);
244
245                $html_images = array();
246                foreach($images as $im){
247                        if (!preg_match(",^[a-z0-9]+://,i",$im[1])
248                         AND ($src = $im[1].$im[4])
249                         AND (
250                              file_exists($f=$im[1]) // l'image a ete generee depuis le meme cote que l'envoi
251                              OR (_DIR_RACINE AND file_exists($f=_DIR_RACINE.$im[1])) // l'image a ete generee dans le public et on est dans le prive
252                              OR (!_DIR_RACINE AND strncmp($im[1],"../",3)==0 AND file_exists($f=substr($im[1],3))) // l'image a ete generee dans le prive et on est dans le public
253                             )
254                         AND !isset($html_images[$src])){
255
256                                $extension = strtolower($im[3]);
257                                $header_extension = $image_types[$extension];
258                                $cid = md5($f); // un id unique pour un meme fichier
259                                // l'ajouter si pas deja present (avec un autre ?...)
260                                if (!in_array($cid,$html_images))
261                                        $this->AddEmbeddedImage($f, $cid, basename($f),'base64',$header_extension);
262                                $this->Body = str_replace($src, "cid:$cid", $this->Body);
263                                $html_images[$src] = $cid; // marquer l'image comme traitee, inutile d'y revenir
264                        }
265                }
266        }
267
268
269        function ConvertirStylesEnligne() {
270                /*
271
272                Written by Eric Dols - edols@auditavenue.com
273
274                You may freely use or modify this, provided
275                you leave credits to the original coder.
276                Feedback about (un)successfull uses, bugs and improvements done
277                are much appreciated, but don't expect actual support.
278
279                PURPOSE OF THIS FUNCTION
280                        It is designed to process html emails relying
281                        on a css stylesheet placed in the <head> for layout in
282                        order to enhance compatibility with email clients,
283                        including webmail services.
284                        Provided you use minimal css, you can keep styling separate
285                        from the content in your email template, and let this function
286                        "inject" those styles inline in your email html tags on-the-fly,
287                        just before sending.
288                        Technically, it grabs the style declarations found in the
289                        <head> section and inserts each declaration inline,
290                        inside the corresponding html tags in the email message.
291
292                        Supports both HTML and XHTML markup seamlessly. Thus
293                        tolerant to email message writers using non-xhtml tag,
294                        even when template is xhtml compliant (e.g. they would
295                        add <img ...> instead of a xhtml compliant <img ... />).
296
297                NEW 10 dec. 2003:
298                        - code revised, including a few regexp bugs fixed.
299                        - multiple class for a tag are now allowed <p class="firstclass secondclass">
300                        - all unsupported css styles are now moved to the body section (not just a:hover etc...)
301
302                USE
303                        Add this function to a function library include, like "inline.inc"
304                        and include it near the beginning of your php page:
305                        require ("inline.inc");
306
307                        load the html source of message into a variable
308                        like $html_source and process it using:
309                        $html_source = sheet2inline($html_source)
310
311
312                STYLE DEFINITIONS SUPPORTED
313                        TAG { ... }
314                        TAG1, TAG2, ... { ... }
315                        TAG.class { ... }
316                        .class { ...)
317                        TAG:pseudo { ... }
318
319
320                        CSS definitions may be freely formatted (spaces, tabs, linefeeds...),
321                        they are converted to oneliners before inserting them inline in the html tags.
322
323                        .class definitions are processed AFTER tag definitions,
324                        thus appended inline after any existing tag styling to
325                        preserve the normal css priority behavior.
326
327                        Existing style="..." attributes in tags are NOT stripped. However they MUST
328                        be with double quotes. If not, an addtional style="..." attribute will be added
329
330
331                KNOWN LIMITATIONS
332                        - style info should be placed in <head> section. I believe
333                                it shouldnt be too hard to modify to point to an external
334                                stylesheet instead.
335                        - no support (yet?):
336                                * chains like P UL LI { .... } or P UL LI.class { .... }
337                                * #divname p { ... } and <tag id="...">
338                                * a:hover, a:visited {...} multiple class:pseudo
339                                They require a significantly more complicated processing likely
340                                based on stylesheet and document trees parsing.
341                                Many email clients don't handle more than what is supported
342                                by this script anyway.
343                        - pseudo-classes like a:hover {...} can't be inserted inline
344                                in the html tags: they are moved to a <style> declaration in
345                                the <body> instead. This is a limitation from html, not this script.
346                        - It is still up to you to check if target email clients render
347                                your css styled templates correctly, especially webmail services
348                                like Hotmail, in which the email becomes a sub-part of an html page,
349                                with styles already in place.
350                */
351
352                // variables to be accessed in the callback sub-function too
353                global $styledefinition, $styletag, $styleclass;
354
355                // Let's first load the stylesheet information in a $styles array using a regexp
356                preg_match_all ( "/^[ \t]*([.]?)([\w, #]+)([.:])?(\S*)\s+{([^}]+)}/mi", $this->Body , $styles);
357                /*
358                        $styles[1] = . or ''  => .class or tag (empty)
359                        $styles[2] = name of class or tag(s)
360                        $styles[3] = : . or '' => followed by pseudo-element, class separator or nothing (empty)
361                        $styles[4] = name of pseudo-element after a tag, if any
362                        $styles[5] = the style definition itself, i.e. what's between the { }
363                */
364
365                // Now loop through the styles found and act accordingly;
366
367                // process TAG {...} & TAG1, TAG2,... {...} definitions only first by order of appearance
368                foreach ($styles[1] as $i => $type) {
369                        if ($type=="" && $styles[3][$i]=="") {
370                                $styledefinition = trim($styles[5][$i]);
371                                $styletag = preg_replace("/ *, */", "|", trim($styles[2][$i])); //echo $styletag."<br />";
372                                $styleclass = "";
373                                // process TAG {...} and TAG1, TAG2 {...} but not TAG1 TAG2 {...} or #divname styles
374                                if (!preg_match("/ /", $styletag) && !preg_match("/#/", $styletag)) {
375                                        $pattern = "!<(".$styletag.")([^>]*(?= /)|[^>]*)( /)?>!mi";
376                                        $this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->Body);
377                                        $styles[6][$i]=1; // mark as injected inline
378                                }
379                        }
380                }
381
382                // append additional .CLASS {...} and TAG.CLASS {...} styling by order of appearance
383                // important to do so after TAG {...} definitions, so that class attributes override TAG styles when needed
384                foreach ($styles[1] as $i => $type) {
385                        if ($type!="." && $styles[3][$i]=="." ) {       // class definition for a specific tag
386                                $styledefinition = trim($styles[5][$i]);
387                                $styletag = trim($styles[2][$i]);
388                                $styleclass = trim($styles[4][$i]);
389                                $pattern = "!<(".$styletag.")([^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*(?= /)|[^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*)( />)?>!mi";
390                                $this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->Body);
391                                $styles[6][$i]=1; // mark as injected inline
392
393                        }
394                        elseif ($type=="." && $styles[3][$i]=="" ) {    // general class definition for any tag
395                                $styledefinition = trim($styles[5][$i]);
396                                $styletag = "";
397                                $styleclass = trim($styles[2][$i]);
398                                $pattern = "!<(\w+)([^>]* class\=['\"]".$styleclass."['\"][^>]*(?= /)|[^>]* class\=['\"]".$styleclass."['\"][^>]*)( />)?>!mi";
399                                $this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->Body);
400                                $styles[6][$i]=1; // mark as injected inline
401                        }
402                }
403
404
405                /* move all style declarations that weren't injected from <head> to a <body> <style> section,
406                         including but not limited to:
407                         - pseudo-classes like a:hover {...} as they can't be set inline
408                         - declaration chains like UL LI {...}
409                         - #divname {...}. These are not supported by email clients like Mac/Entourage anyway, it seems. */
410                foreach ($styles[1] as $i => $type) {
411                        if ($styles[6][$i]=="") {
412                                // add a <style type="text/css"> section after <body> if there's isn't one yet
413                                if (preg_match ("!<body[^>]*>\s*<style!mi", $this->Body)==0) {
414                                        $this->Body = preg_replace ("/(<body[^>]*>)/i", "\n\$1\n".'<style type="text/css">'."\n<!--\n-->\n</style>\n", $this->Body);
415                                }
416                                // append a copy of the pseudo-element declaration to that body style section
417                                $styledefinition = trim($styles[5][$i]);
418                                $styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition ); // convert style definition to a one-liner (optional)
419                                $declaration = $styles[1][$i].trim($styles[2][$i]).$styles[3][$i].trim($styles[4][$i])." { ".$styledefinition." }";
420                                $this->Body = preg_replace ("!(<body[^>]*>\s*<style[^>]*>\s*<\!\-\-[^>]*)"."(\s*\-\->\s*</style>)!si", "\$1".$declaration."\n\$2", $this->Body);
421                                $styles[6][$i]= 2; // mark as moved to <style> section in <body>
422                        }
423                }
424
425                // remove stylesheet declaration(s) from <head> section (comment following line out if not wanted)
426                //$this->Body = preg_replace ("!(<head>.*)<style type.*</style>(.*</head>)!si", "\$1\$2" , $this->Body);
427
428                // check what styles have been injected
429#                       print_r($styles);
430
431        }
432
433
434        function safe_utf8_decode($text,$mode='texte_brut') {
435                if (!is_utf8($text))
436                        return ($text);
437
438                if (function_exists('iconv') && $mode == 'texte_brut') {
439                        $text = str_replace('’',"'",$text);
440                        $text = iconv("UTF-8", "ISO-8859-1//TRANSLIT", $text);
441                        return str_replace('&#8217;',"'",$text);
442                }
443                else {
444                        if ($mode == 'texte_brut') {
445                                $text = str_replace('’',"'",$text);
446                        }
447                        $text = unicode2charset(utf_8_to_unicode($text),'iso-8859-1');
448                        return str_replace('&#8217;',"'",$text);
449                }
450        }
451
452        function ConvertirUtf8VersIso8859() {
453                $this->CharSet  = 'iso-8859-1';
454                $this->Body             = str_replace('charset=utf-8', 'charset=iso-8859-1', $this->Body);
455                $this->Body             = $this->safe_utf8_decode($this->Body,'html');
456                $this->AltBody  = $this->safe_utf8_decode($this->AltBody);
457                $this->Subject  = $this->safe_utf8_decode($this->Subject);
458                $this->FromName = $this->safe_utf8_decode($this->FromName);
459        }
460
461        function ConvertirAccents() {
462                // tableau à compléter au fur et à mesure
463                $cor = array(
464                                                'à' => '&agrave;',
465                                                'â' => '&acirc;',
466                                                'ä' => '&auml;',
467                                                'ç' => '&ccedil;',
468                                                'é' => '&eacute;',
469                                                'è' => '&egrave;',
470                                                'ê' => '&ecirc;',
471                                                'ë' => '&euml;',
472                                                'î' => '&icirc;',
473                                                'ï' => '&iuml;',
474                                                'ò' => '&ograve;',
475                                                'ô' => '&ocirc;',
476                                                'ö' => '&ouml;',
477                                                'ù' => '&ugrave;',
478                                                'û' => '&ucirc;',
479                                                'œ' => '&oelig;',
480                                                '€' => '&euro;'
481                                        );
482
483                $this->Body = strtr($this->Body, $cor);
484        }
485
486}
487
488?>
Note: See TracBrowser for help on using the repository browser.