1 | <?php |
---|
2 | |
---|
3 | |
---|
4 | if (intval(phpversion()) == 5) { |
---|
5 | include_spip('phpmailer-php5/class.phpmailer'); |
---|
6 | include_spip('phpmailer-php5/class.smtp'); |
---|
7 | } else { |
---|
8 | include_spip('phpmailer-php4/class.phpmailer'); |
---|
9 | include_spip('phpmailer-php4/class.smtp'); |
---|
10 | } |
---|
11 | include_spip('facteur_fonctions'); |
---|
12 | |
---|
13 | class Facteur extends PHPMailer { |
---|
14 | |
---|
15 | function Facteur($email, $objet, $message_html, $message_texte) { |
---|
16 | |
---|
17 | if ($GLOBALS['meta']['facteur_adresse_envoi'] == 'oui') { |
---|
18 | $this->From = $GLOBALS['meta']['facteur_adresse_envoi_email']; |
---|
19 | $this->FromName = $GLOBALS['meta']['facteur_adresse_envoi_nom']; |
---|
20 | } else { |
---|
21 | $this->From = $GLOBALS['meta']['email_webmaster']; |
---|
22 | $this->FromName = $GLOBALS['meta']['nom_site']; |
---|
23 | } |
---|
24 | |
---|
25 | $this->CharSet = $GLOBALS['meta']['charset']; |
---|
26 | $this->Mailer = 'mail'; |
---|
27 | $this->Subject = $objet; |
---|
28 | $this->AddAddress($email); |
---|
29 | |
---|
30 | if (isset($GLOBALS['meta']['facteur_smtp_sender'])) { |
---|
31 | $this->Sender = $GLOBALS['meta']['facteur_smtp_sender']; |
---|
32 | $this->AddCustomHeader("Errors-To: ".$this->Sender); |
---|
33 | } |
---|
34 | |
---|
35 | if (isset($GLOBALS['meta']['facteur_smtp']) AND $GLOBALS['meta']['facteur_smtp'] == 'oui') { |
---|
36 | $this->Mailer = 'smtp'; |
---|
37 | $this->Host = $GLOBALS['meta']['facteur_smtp_host']; |
---|
38 | $this->Port = $GLOBALS['meta']['facteur_smtp_port']; |
---|
39 | if ($GLOBALS['meta']['facteur_smtp_auth'] == 'oui') { |
---|
40 | $this->SMTPAuth = true; |
---|
41 | $this->Username = $GLOBALS['meta']['facteur_smtp_username']; |
---|
42 | $this->Password = $GLOBALS['meta']['facteur_smtp_password']; |
---|
43 | } else { |
---|
44 | $this->SMTPAuth = false; |
---|
45 | } |
---|
46 | if (intval(phpversion()) == 5) { |
---|
47 | if ($GLOBALS['meta']['facteur_smtp_secure'] == 'ssl') |
---|
48 | $this->SMTPSecure = 'ssl'; |
---|
49 | if ($GLOBALS['meta']['facteur_smtp_secure'] == 'tls') |
---|
50 | $this->SMTPSecure = 'tls'; |
---|
51 | } |
---|
52 | } |
---|
53 | |
---|
54 | if (!empty($message_html)) { |
---|
55 | $this->Body = $message_html; |
---|
56 | $this->IsHTML(true); |
---|
57 | if ($GLOBALS['meta']['facteur_filtre_css']) |
---|
58 | $this->ConvertirStylesEnligne(); |
---|
59 | if ($GLOBALS['meta']['facteur_filtre_images']) |
---|
60 | $this->JoindreImagesHTML(); |
---|
61 | } |
---|
62 | if (!empty($message_texte)) { |
---|
63 | if (!$this->Body) { |
---|
64 | $this->IsHTML(false); |
---|
65 | $this->Body = $message_texte; |
---|
66 | } else { |
---|
67 | $this->AltBody = $message_texte; |
---|
68 | } |
---|
69 | } |
---|
70 | |
---|
71 | if ($GLOBALS['meta']['facteur_filtre_iso_8859']) |
---|
72 | $this->ConvertirUtf8VersIso8859(); |
---|
73 | |
---|
74 | } |
---|
75 | |
---|
76 | |
---|
77 | function JoindreImagesHTML() { |
---|
78 | $image_types = array( |
---|
79 | 'gif' => 'image/gif', |
---|
80 | 'jpg' => 'image/jpeg', |
---|
81 | 'jpeg' => 'image/jpeg', |
---|
82 | 'jpe' => 'image/jpeg', |
---|
83 | 'bmp' => 'image/bmp', |
---|
84 | 'png' => 'image/png', |
---|
85 | 'tif' => 'image/tiff', |
---|
86 | 'tiff' => 'image/tiff', |
---|
87 | 'swf' => 'application/x-shockwave-flash' |
---|
88 | ); |
---|
89 | while (list($key,) = each($image_types)) |
---|
90 | $extensions[] = $key; |
---|
91 | |
---|
92 | preg_match_all('/"([^"]+\.('.implode('|', $extensions).'))"/Ui', $this->Body, $images); |
---|
93 | |
---|
94 | for ($i=0; $i<count($images[1]); $i++) { |
---|
95 | if (file_exists('../'.$images[1][$i])) { |
---|
96 | $html_images[] = '../'.$images[1][$i]; |
---|
97 | $this->Body = str_replace($images[1][$i], basename($images[1][$i]), $this->Body); |
---|
98 | } |
---|
99 | if (file_exists($images[1][$i])) { |
---|
100 | $html_images[] = $images[1][$i]; |
---|
101 | $this->Body = str_replace($images[1][$i], basename($images[1][$i]), $this->Body); |
---|
102 | } |
---|
103 | } |
---|
104 | |
---|
105 | $images = array(); |
---|
106 | preg_match_all("/'([^']+\.(".implode('|', $extensions)."))'/Ui", $this->Body, $images); |
---|
107 | |
---|
108 | for ($i=0; $i<count($images[1]); $i++) { |
---|
109 | if (file_exists('../'.$images[1][$i])) { |
---|
110 | $html_images[] = '../'.$images[1][$i]; |
---|
111 | $this->Body = str_replace($images[1][$i], basename($images[1][$i]), $this->Body); |
---|
112 | } |
---|
113 | if (file_exists($images[1][$i])) { |
---|
114 | $html_images[] = $images[1][$i]; |
---|
115 | $this->Body = str_replace($images[1][$i], basename($images[1][$i]), $this->Body); |
---|
116 | } |
---|
117 | } |
---|
118 | |
---|
119 | if (!empty($html_images)) { |
---|
120 | $html_images = array_unique($html_images); |
---|
121 | sort($html_images); |
---|
122 | for ($i=0; $i<count($html_images); $i++) { |
---|
123 | |
---|
124 | // Bug Fix: dans thunderbird, il faut etre strict avec le header envoy� avec l'image |
---|
125 | $bouts = explode(".", basename($html_images[$i])); |
---|
126 | $extension = strtolower(array_pop($bouts)); |
---|
127 | $header_extension = $image_types[$extension]; |
---|
128 | |
---|
129 | $cid = md5(uniqid(time())); |
---|
130 | $this->AddEmbeddedImage($html_images[$i], $cid, basename($html_images[$i]),'base64',$header_extension); |
---|
131 | $this->Body = str_replace(basename($html_images[$i]), "cid:$cid", $this->Body); |
---|
132 | } |
---|
133 | } |
---|
134 | } |
---|
135 | |
---|
136 | |
---|
137 | function ConvertirStylesEnligne() { |
---|
138 | /* |
---|
139 | |
---|
140 | Written by Eric Dols - edols@auditavenue.com |
---|
141 | |
---|
142 | You may freely use or modify this, provided |
---|
143 | you leave credits to the original coder. |
---|
144 | Feedback about (un)successfull uses, bugs and improvements done |
---|
145 | are much appreciated, but don't expect actual support. |
---|
146 | |
---|
147 | PURPOSE OF THIS FUNCTION |
---|
148 | It is designed to process html emails relying |
---|
149 | on a css stylesheet placed in the <head> for layout in |
---|
150 | order to enhance compatibility with email clients, |
---|
151 | including webmail services. |
---|
152 | Provided you use minimal css, you can keep styling separate |
---|
153 | from the content in your email template, and let this function |
---|
154 | "inject" those styles inline in your email html tags on-the-fly, |
---|
155 | just before sending. |
---|
156 | Technically, it grabs the style declarations found in the |
---|
157 | <head> section and inserts each declaration inline, |
---|
158 | inside the corresponding html tags in the email message. |
---|
159 | |
---|
160 | Supports both HTML and XHTML markup seamlessly. Thus |
---|
161 | tolerant to email message writers using non-xhtml tag, |
---|
162 | even when template is xhtml compliant (e.g. they would |
---|
163 | add <img ...> instead of a xhtml compliant <img ... />). |
---|
164 | |
---|
165 | NEW 10 dec. 2003: |
---|
166 | - code revised, including a few regexp bugs fixed. |
---|
167 | - multiple class for a tag are now allowed <p class="firstclass secondclass"> |
---|
168 | - all unsupported css styles are now moved to the body section (not just a:hover etc...) |
---|
169 | |
---|
170 | USE |
---|
171 | Add this function to a function library include, like "inline.inc" |
---|
172 | and include it near the beginning of your php page: |
---|
173 | require ("inline.inc"); |
---|
174 | |
---|
175 | load the html source of message into a variable |
---|
176 | like $html_source and process it using: |
---|
177 | $html_source = sheet2inline($html_source) |
---|
178 | |
---|
179 | |
---|
180 | STYLE DEFINITIONS SUPPORTED |
---|
181 | TAG { ... } |
---|
182 | TAG1, TAG2, ... { ... } |
---|
183 | TAG.class { ... } |
---|
184 | .class { ...) |
---|
185 | TAG:pseudo { ... } |
---|
186 | |
---|
187 | |
---|
188 | CSS definitions may be freely formatted (spaces, tabs, linefeeds...), |
---|
189 | they are converted to oneliners before inserting them inline in the html tags. |
---|
190 | |
---|
191 | .class definitions are processed AFTER tag definitions, |
---|
192 | thus appended inline after any existing tag styling to |
---|
193 | preserve the normal css priority behavior. |
---|
194 | |
---|
195 | Existing style="..." attributes in tags are NOT stripped. However they MUST |
---|
196 | be with double quotes. If not, an addtional style="..." attribute will be added |
---|
197 | |
---|
198 | |
---|
199 | KNOWN LIMITATIONS |
---|
200 | - style info should be placed in <head> section. I believe |
---|
201 | it shouldnt be too hard to modify to point to an external |
---|
202 | stylesheet instead. |
---|
203 | - no support (yet?): |
---|
204 | * chains like P UL LI { .... } or P UL LI.class { .... } |
---|
205 | * #divname p { ... } and <tag id="..."> |
---|
206 | * a:hover, a:visited {...} multiple class:pseudo |
---|
207 | They require a significantly more complicated processing likely |
---|
208 | based on stylesheet and document trees parsing. |
---|
209 | Many email clients don't handle more than what is supported |
---|
210 | by this script anyway. |
---|
211 | - pseudo-classes like a:hover {...} can't be inserted inline |
---|
212 | in the html tags: they are moved to a <style> declaration in |
---|
213 | the <body> instead. This is a limitation from html, not this script. |
---|
214 | - It is still up to you to check if target email clients render |
---|
215 | your css styled templates correctly, especially webmail services |
---|
216 | like Hotmail, in which the email becomes a sub-part of an html page, |
---|
217 | with styles already in place. |
---|
218 | */ |
---|
219 | |
---|
220 | // variables to be accessed in the callback sub-function too |
---|
221 | global $styledefinition, $styletag, $styleclass; |
---|
222 | |
---|
223 | // Let's first load the stylesheet information in a $styles array using a regexp |
---|
224 | preg_match_all ( "/^[ \t]*([.]?)([\w, #]+)([.:])?(\S*)\s+{([^}]+)}/mi", $this->Body , $styles); |
---|
225 | /* |
---|
226 | $styles[1] = . or '' => .class or tag (empty) |
---|
227 | $styles[2] = name of class or tag(s) |
---|
228 | $styles[3] = : . or '' => followed by pseudo-element, class separator or nothing (empty) |
---|
229 | $styles[4] = name of pseudo-element after a tag, if any |
---|
230 | $styles[5] = the style definition itself, i.e. what's between the { } |
---|
231 | */ |
---|
232 | |
---|
233 | // Now loop through the styles found and act accordingly; |
---|
234 | |
---|
235 | // process TAG {...} & TAG1, TAG2,... {...} definitions only first by order of appearance |
---|
236 | foreach ($styles[1] as $i => $type) { |
---|
237 | if ($type=="" && $styles[3][$i]=="") { |
---|
238 | $styledefinition = trim($styles[5][$i]); |
---|
239 | $styletag = preg_replace("/ *, */", "|", trim($styles[2][$i])); //echo $styletag."<br />"; |
---|
240 | $styleclass = ""; |
---|
241 | // process TAG {...} and TAG1, TAG2 {...} but not TAG1 TAG2 {...} or #divname styles |
---|
242 | if (!preg_match("/ /", $styletag) && !preg_match("/#/", $styletag)) { |
---|
243 | $pattern = "!<(".$styletag.")([^>]*(?= /)|[^>]*)( /)?>!mi"; |
---|
244 | $this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->Body); |
---|
245 | $styles[6][$i]=1; // mark as injected inline |
---|
246 | } |
---|
247 | } |
---|
248 | } |
---|
249 | |
---|
250 | // append additional .CLASS {...} and TAG.CLASS {...} styling by order of appearance |
---|
251 | // important to do so after TAG {...} definitions, so that class attributes override TAG styles when needed |
---|
252 | foreach ($styles[1] as $i => $type) { |
---|
253 | if ($type!="." && $styles[3][$i]=="." ) { // class definition for a specific tag |
---|
254 | $styledefinition = trim($styles[5][$i]); |
---|
255 | $styletag = trim($styles[2][$i]); |
---|
256 | $styleclass = trim($styles[4][$i]); |
---|
257 | $pattern = "!<(".$styletag.")([^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*(?= /)|[^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*)( />)?>!mi"; |
---|
258 | $this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->Body); |
---|
259 | $styles[6][$i]=1; // mark as injected inline |
---|
260 | |
---|
261 | } elseif ($type=="." && $styles[3][$i]=="" ) { // general class definition for any tag |
---|
262 | $styledefinition = trim($styles[5][$i]); |
---|
263 | $styletag = ""; |
---|
264 | $styleclass = trim($styles[2][$i]); |
---|
265 | $pattern = "!<(\w+)([^>]* class\=['\"]".$styleclass."['\"][^>]*(?= /)|[^>]* class\=['\"]".$styleclass."['\"][^>]*)( />)?>!mi"; |
---|
266 | $this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->Body); |
---|
267 | $styles[6][$i]=1; // mark as injected inline |
---|
268 | } |
---|
269 | } |
---|
270 | |
---|
271 | |
---|
272 | /* move all style declarations that weren't injected from <head> to a <body> <style> section, |
---|
273 | including but not limited to: |
---|
274 | - pseudo-classes like a:hover {...} as they can't be set inline |
---|
275 | - declaration chains like UL LI {...} |
---|
276 | - #divname {...}. These are not supported by email clients like Mac/Entourage anyway, it seems. */ |
---|
277 | foreach ($styles[1] as $i => $type) { |
---|
278 | if ($styles[6][$i]=="") { |
---|
279 | // add a <style type="text/css"> section after <body> if there's isn't one yet |
---|
280 | if (preg_match ("!<body[^>]*>\s*<style!mi", $this->Body)==0) { |
---|
281 | $this->Body = preg_replace ("/(<body[^>]*>)/i", "\n\$1\n".'<style type="text/css">'."\n<!--\n-->\n</style>\n", $this->Body); |
---|
282 | } |
---|
283 | // append a copy of the pseudo-element declaration to that body style section |
---|
284 | $styledefinition = trim($styles[5][$i]); |
---|
285 | $styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition ); // convert style definition to a one-liner (optional) |
---|
286 | $declaration = $styles[1][$i].trim($styles[2][$i]).$styles[3][$i].trim($styles[4][$i])." { ".$styledefinition." }"; |
---|
287 | $this->Body = preg_replace ("!(<body[^>]*>\s*<style[^>]*>\s*<\!\-\-[^>]*)"."(\s*\-\->\s*</style>)!si", "\$1".$declaration."\n\$2", $this->Body); |
---|
288 | $styles[6][$i]= 2; // mark as moved to <style> section in <body> |
---|
289 | } |
---|
290 | } |
---|
291 | |
---|
292 | // remove stylesheet declaration(s) from <head> section (comment following line out if not wanted) |
---|
293 | //$this->Body = preg_replace ("!(<head>.*)<style type.*</style>(.*</head>)!si", "\$1\$2" , $this->Body); |
---|
294 | |
---|
295 | // check what styles have been injected |
---|
296 | # print_r($styles); |
---|
297 | |
---|
298 | } |
---|
299 | |
---|
300 | |
---|
301 | function ConvertirUtf8VersIso8859() { |
---|
302 | $this->Body = str_replace('’',"'",$this->Body); |
---|
303 | $this->AltBody = str_replace('’',"'",$this->AltBody); |
---|
304 | $this->CharSet = 'iso-8859-1'; |
---|
305 | $this->Body = str_replace('charset=utf-8', 'charset=iso-8859-1', $this->Body); |
---|
306 | $this->Body = utf8_decode($this->Body); |
---|
307 | $this->AltBody = utf8_decode($this->AltBody); |
---|
308 | $this->Subject = utf8_decode($this->Subject); |
---|
309 | $this->FromName = utf8_decode($this->FromName); |
---|
310 | } |
---|
311 | |
---|
312 | function ConvertirAccents() { |
---|
313 | // tableau à compléter au fur et à mesure |
---|
314 | $cor = array( |
---|
315 | 'à' => 'à', |
---|
316 | 'â' => 'â', |
---|
317 | 'ä' => 'ä', |
---|
318 | 'ç' => 'ç', |
---|
319 | 'é' => 'é', |
---|
320 | 'è' => 'è', |
---|
321 | 'ê' => 'ê', |
---|
322 | 'ë' => 'ë', |
---|
323 | 'î' => 'î', |
---|
324 | 'ï' => 'ï', |
---|
325 | 'ò' => 'ò', |
---|
326 | 'ô' => 'ô', |
---|
327 | 'ö' => 'ö', |
---|
328 | 'ù' => 'ù', |
---|
329 | 'û' => 'û', |
---|
330 | 'œ' => 'œ', |
---|
331 | '€' => '€' |
---|
332 | ); |
---|
333 | |
---|
334 | $this->Body = strtr($this->Body, $cor); |
---|
335 | } |
---|
336 | |
---|
337 | } |
---|
338 | |
---|
339 | ?> |
---|