From 0ad0379285e76bf7b4ba794dbdec501f244c31e2 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Mon, 11 May 2009 17:13:56 +0000 Subject: [PATCH] =?UTF-8?q?Add:=20possibilit=E9=20d'uploader=20une=20image?= =?UTF-8?q?=20et=20de=20l'envoyer=20dans=20un=20mailing=20(finalis=E9=20et?= =?UTF-8?q?=20fonctionnel)=20Add:=20modification=20classe=20smtps.php=20po?= =?UTF-8?q?ur=20l'envoi=20d'images?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/comm/mailing/fiche.php | 4 +- htdocs/includes/smtps/SMTPs.php | 80 ++++++++++- htdocs/lib/CMailFile.class.php | 244 +++++++++++++++++++++++++++++--- 3 files changed, 300 insertions(+), 28 deletions(-) diff --git a/htdocs/comm/mailing/fiche.php b/htdocs/comm/mailing/fiche.php index 38c7926d1b0..d1629161a9f 100644 --- a/htdocs/comm/mailing/fiche.php +++ b/htdocs/comm/mailing/fiche.php @@ -490,7 +490,7 @@ if ($_GET["action"] == 'create') if ($conf->fckeditor->enabled && $conf->global->FCKEDITOR_ENABLE_MAILING) { require_once(DOL_DOCUMENT_ROOT."/lib/doleditor.class.php"); - $doleditor=new DolEditor('body','',320,'dolibarr_mailings','',true,false); + $doleditor=new DolEditor('body','',320,'dolibarr_mailings','',true,true); $doleditor->Create(); } else @@ -762,7 +762,7 @@ else if ($conf->fckeditor->enabled && $conf->global->FCKEDITOR_ENABLE_MAILING) { require_once(DOL_DOCUMENT_ROOT."/lib/doleditor.class.php"); - $doleditor=new DolEditor('body',$mil->body,320,'dolibarr_mailings','',true,false); + $doleditor=new DolEditor('body',$mil->body,320,'dolibarr_mailings','',true,true); $doleditor->Create(); } else diff --git a/htdocs/includes/smtps/SMTPs.php b/htdocs/includes/smtps/SMTPs.php index 76cd7e8ffac..c2bdabe7b81 100644 --- a/htdocs/includes/smtps/SMTPs.php +++ b/htdocs/includes/smtps/SMTPs.php @@ -1941,7 +1941,7 @@ class SMTPs // What type[s] of content do we have $_types = array_keys ( $this->_msgContent ); - + // How many content types do we have $keyCount = count ( $_types ); @@ -1970,6 +1970,20 @@ class SMTPs // If we have more than ONE, we use the multi-part format else if( $keyCount > 1 ) { + // DOL_CHANGE LDR + foreach ($_types as $type) + { + if ($type == 'image') + { + $content = 'Content-Type: multipart/related;' . "\r\n"; + } + else + { + $content = 'Content-Type: multipart/mixed;' . "\r\n"; + } + } + // END DOL_CHANGE LDR + // Since this is an actual multi-part message // We need to define a content message Boundary // NOTE: This was 'multipart/alternative', but Windows based @@ -1977,7 +1991,10 @@ class SMTPs /* * @TODO Investigate "nested" boundary message parts */ - $content = 'Content-Type: multipart/mixed;' . "\r\n" + // DOL_CHANGE LDR + //$content = 'Content-Type: multipart/mixed;' . "\r\n" + $content = $content + // END DOL_CHANGE LDR . ' boundary="' . $this->_getBoundary() . '"' . "\r\n" . "\r\n" . 'This is a multi-part message in MIME format.' . "\r\n"; @@ -2004,12 +2021,33 @@ class SMTPs . $_data['data'] . "\r\n"; } } + // DOL_CHANGE LDR + else if ( $type == 'image' ) + { + // loop through all images + foreach ( $_content as $_image => $_data ) + { + + $content .= "\r\n--" . $this->_getBoundary() . "\r\n" + . 'Content-Type: ' . $_data['mimeType'] . '; name="' . $_data['imageName'] . '"' . "\r\n" + . 'Content-Transfer-Encoding: base64' . "\r\n" + . 'Content-Disposition: inline; filename="' . $_data['imageName'] . '"' . "\r\n" + . 'Content-ID: <' . $_data['cid'] . '> ' . "\r\n"; + + if ( $this->getMD5flag() ) + $content .= 'Content-MD5: ' . $_data['md5'] . "\r\n"; + + $content .= "\r\n" + . $_data['data'] . "\r\n"; + } + } + // END DOL_CHANGE LDR else { $content .= "\r\n--" . $this->_getBoundary() . "\r\n" . 'Content-Type: ' . $_content['mimeType'] . '; ' . 'charset="' . $this->getCharSet() . '"'; - $content .= ( $type == 'html') ? '; name="HTML Part"' : ''; + //$content .= ( $type == 'html') ? '; name="HTML Part"' : ''; $content .= "\r\n"; $content .= 'Content-Transfer-Encoding: '; $content .= ( $type == 'html') ? 'quoted-printable' : $this->getTransEncodeType(); @@ -2021,7 +2059,8 @@ class SMTPs $content .= 'Content-MD5: ' . $_content['md5'] . "\r\n"; $content .= "\r\n" - . $_content['data'] . "\r\n"; + . $_content['data'] . "\r\n" + . "\r\n--" . $this->_getBoundary() . "\r\n"; } } @@ -2065,6 +2104,35 @@ class SMTPs $this->_msgContent['attachment'][$strFileName]['md5'] = md5($strContent); } } + + + // DOL_CHANGE LDR + /** + * Method public void setImage( string ) + * + * Image attachments are added to the content array as sub-arrays, + * allowing for multiple images for each outbound email + * + * @param string $strContent Image data to attach to message + * @param string $strImageName Image Name to give to attachment + * @param string $strMimeType Image Mime Type of attachment + * @return void + * + */ + function setImage ( $strContent, $strImageName = 'unknown', $strMimeType = 'unknown', $strImageCid = 'unknown' ) + { + if ( $strContent ) + { + $this->_msgContent['image'][$strImageName]['mimeType'] = $strMimeType; + $this->_msgContent['image'][$strImageName]['imageName'] = $strImageName; + $this->_msgContent['image'][$strImageName]['cid'] = $strImageCid; + $this->_msgContent['image'][$strImageName]['data'] = $strContent; + + if ( $this->getMD5flag() ) + $this->_msgContent['image'][$strFileName]['md5'] = md5($strContent); + } + } + // END DOL_CHANGE LDR /** * Method public void setSensitivity( string ) @@ -2435,6 +2503,10 @@ class SMTPs /** * $Log$ + * Revision 1.3 2009/05/11 17:13:57 hregis + * Add: possibilité d'uploader une image et de l'envoyer dans un mailing (finalisé et fonctionnel) + * Add: modification classe smtps.php pour l'envoi d'images + * * Revision 1.2 2009/02/09 00:04:35 eldy * Added support for SMTPS protocol * diff --git a/htdocs/lib/CMailFile.class.php b/htdocs/lib/CMailFile.class.php index b57305997b1..1f0b8b78e07 100644 --- a/htdocs/lib/CMailFile.class.php +++ b/htdocs/lib/CMailFile.class.php @@ -53,6 +53,20 @@ class CMailFile var $error=''; var $smtps; // Contains SMTPs object (if this method is used) + + var $html; + var $image_boundary; + var $atleastoneimage=0; + var $html_images=array(); + var $images_encoded=array(); + var $image_types = array('gif' => 'image/gif', + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'bmp' => 'image/bmp', + 'png' => 'image/png', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff'); /** @@ -74,6 +88,10 @@ class CMailFile $addr_cc="",$addr_bcc="",$deliveryreceipt=0,$msgishtml=0,$errors_to='') { global $conf; + + // Evite caractere bizarre avec les accents + $subject = utf8_decode($subject); + $from = utf8_decode($from); // If ending method not defined if (empty($conf->global->MAIN_MAIL_SENDMODE)) $conf->global->MAIN_MAIL_SENDMODE='mail'; @@ -85,13 +103,32 @@ class CMailFile if ($msgishtml == -1) { $this->msgishtml = 0; - if (dol_textishtml($msg,1)) $this->msgishtml = 1; + if (dol_textishtml($msg)) $this->msgishtml = 1; } else { $this->msgishtml = $msgishtml; } + // Detect images + if ($this->msgishtml) + { + $this->html = $msg; + $findimg = $this->findHtmlImages($conf->fckeditor->dir_output); + // Define if there is at least one file + if ($findimg) + { + foreach ($this->html_images as $i => $val) + { + if ($this->html_images[$i]) + { + $this->atleastoneimage=1; + dol_syslog("CMailFile::CMailfile: html_images[$i]['name']=".$this->html_images[$i]['name'], LOG_DEBUG); + } + } + } + } + // Define if there is at least one file foreach ($filename_list as $i => $val) { @@ -132,10 +169,17 @@ class CMailFile $smtp_headers = $this->write_smtpheaders(); // En-tete suite dans $mime_headers - if ($this->atleastonefile) + if ($this->atleastonefile || $this->atleastoneimage) { $mime_headers = $this->write_mimeheaders($filename_list, $mimefilename_list); } + + // On encode les images + if ($this->atleastoneimage) + { + $images_encoded = $this->write_images($this->images_encoded); + $msg = $this->html; + } // Corps message dans $text_body $text_body = $this->write_body($msg, $filename_list); @@ -148,7 +192,7 @@ class CMailFile // On defini $this->headers et $this->message $this->headers = $smtp_headers . $mime_headers; - $this->message = $text_body . $text_encoded; + $this->message = $text_body . $images_encoded . $text_encoded; // On nettoie le header pour qu'il ne se termine pas par un retour chariot. // Ceci evite aussi les lignes vides en fin qui peuvent etre interpretees @@ -166,9 +210,33 @@ class CMailFile $smtps->setSubject($subject); $smtps->setTO($to); $smtps->setFrom($from); + if ($this->atleastoneimage) + { + $msg = $this->html; + /* + $out=''; + // Check if html header already in message + $htmlalreadyinmsg=0; + if (eregi('^[ \t]*html)) $htmlalreadyinmsg=1; + + if (! $htmlalreadyinmsg) $out .= ""; + $out.= $this->html; + if (! $htmlalreadyinmsg) $out .= ""; + $msg = $out; + */ + } + if ($this->msgishtml) $smtps->setBodyContent($msg,'html'); else $smtps->setBodyContent($msg,'plain'); + if ($this->atleastoneimage) + { + foreach ($this->images_encoded as $img) + { + $smtps->setImage($img['image_encoded'],$img['name'],$img['content_type'],$img['cid']); + } + } + if ($this->atleastonefile) { foreach ($filename_list as $i => $val) @@ -414,17 +482,22 @@ class CMailFile if (isset($this->deliveryreceipt) && $this->deliveryreceipt == 1) $out .= "Disposition-Notification-To: ".getValidAddress($this->addr_from,2).$this->eol; //$out .= "X-Priority: 3".$this->eol; - $out .= "X-Mailer: Dolibarr version " . DOL_VERSION ." (using php mail)".$this->eol; - $out .= "MIME-Version: 1.0".$this->eol; - - if ($this->msgishtml) + $out.= "X-Mailer: Dolibarr version " . DOL_VERSION ." (using php mail)".$this->eol; + $out.= "MIME-Version: 1.0".$this->eol; + + if ($this->atleastoneimage) { - if (! $this->atleastonefile) $out.= "Content-Type: text/html; charset=".$conf->file->character_set_client.$this->eol; + if (! $this->atleastonefile) $out.= "Content-Type: multipart/related; boundary=\"".$this->mime_boundary."\"".$this->eol; + $out.= "Content-Transfer-Encoding: 8bit".$this->eol; + } + else if ($this->msgishtml) + { + if (! $this->atleastonefile) $out.= "Content-Type: text/html; boundary=\"".$this->mime_boundary."\"".$this->eol; $out.= "Content-Transfer-Encoding: 8bit".$this->eol; } else { - if (! $this->atleastonefile) $out.= "Content-Type: text/plain; charset=".$conf->file->character_set_client.$this->eol; + if (! $this->atleastonefile) $out.= "Content-Type: text/plain; boundary=\"".$this->mime_boundary."\"".$this->eol; $out.= "Content-Transfer-Encoding: 8bit".$this->eol; } @@ -442,19 +515,24 @@ class CMailFile { $mimedone=0; $out = ""; - for ($i = 0; $i < count($filename_list); $i++) + + if ($filename_list) { - if ($filename_list[$i]) + for ($i = 0; $i < count($filename_list); $i++) { - if (! $mimedone) + if ($filename_list[$i]) { - $out.= "Content-Type: multipart/related; boundary=\"".$this->mime_boundary."\"".$this->eol; - $mimedone=1; + if (! $mimedone) + { + $out.= "Content-Type: multipart/mixed; boundary=\"".$this->mime_boundary."\"".$this->eol; + $mimedone=1; + } + if ($mimefilename_list[$i]) $filename_list[$i] = $mimefilename_list[$i]; + $out.= "X-attachments: $filename_list[$i]".$this->eol; } - if ($mimefilename_list[$i]) $filename_list[$i] = $mimefilename_list[$i]; - $out.= "X-attachments: $filename_list[$i]".$this->eol; } } + //$out.= $this->eol; dol_syslog("CMailFile::write_mimeheaders mime_header=\n".$out, LOG_DEBUG); return $out; @@ -471,15 +549,16 @@ class CMailFile $out=''; - if ($this->atleastonefile) + if ($this->atleastonefile || $this->atleastoneimage) { - $out.= "--" . $this->mime_boundary . $this->eol; if ($this->msgishtml) { + $out.= "--" . $this->mime_boundary . $this->eol; $out.= "Content-Type: text/html; charset=".$conf->file->character_set_client.$this->eol; } else { + $out.= "--" . $this->mime_boundary . $this->eol; $out.= "Content-Type: text/plain; charset=".$conf->file->character_set_client.$this->eol; } $out.= $this->eol; @@ -493,12 +572,17 @@ class CMailFile if (! $htmlalreadyinmsg) $out .= ""; $out.= $msgtext; if (! $htmlalreadyinmsg) $out .= ""; + if ($this->atleastonefile || $this->atleastoneimage) + { + $out.= $this->eol . "--" . $this->mime_boundary . $this->eol; + } } else { $out.= $msgtext; + $out.= $this->eol . "--" . $this->mime_boundary . $this->eol; } - $out.= $this->eol; + return $out; } @@ -531,7 +615,7 @@ class CMailFile $out.= $this->eol; $out.= $encoded; $out.= $this->eol; - // $out.= $this->eol; + //$out.= $this->eol; } else { @@ -541,7 +625,8 @@ class CMailFile } // Fin de tous les attachements - $out = $out . "--" . $this->mime_boundary . "--" . $this->eol; + $out.= "--" . $this->mime_boundary . "--" . $this->eol; + return $out; } @@ -611,6 +696,121 @@ class CMailFile return $_retVal; } + + /** + \brief Recherche la presence d'images dans le message html + \param images_dir Emplacement des images + \return int >0 if OK, <0 if KO + */ + function findHtmlImages($images_dir) + { + // Build the list of image extensions + $extensions = array_keys($this->image_types); + + preg_match_all('/(?:"|\')([^"\']+\.('.implode('|', $extensions).'))(?:"|\')/Ui', $this->html, $matches); + + if ($matches) + { + $i=0; + foreach ($matches[1] as $full) + { + eregi('file=([A-Za-z0-9_\-\/]+[.]?[A-Za-z0-9]+)?$',$full,$regs); + $img = $regs[1]; + + if (file_exists($images_dir.'/'.$img)) + { + // Image path + $src = preg_quote($full); + + // Image name + $this->html_images[$i]["name"] = $img; + + // Content type + $ext = preg_replace('#^.*\.(\w{3,4})$#e', 'strtolower("$1")', $img); + $this->html_images[$i]["content_type"] = $this->image_types[$ext]; + + // cid + $this->html_images[$i]["cid"] = md5(uniqid(time())); + + $this->html = preg_replace("#src=\"$src\"|src='$src'#", "src=\"cid:".$this->html_images[$i]["cid"]."\"", $this->html); + } + $i++; + } + + if (!empty($this->html_images)) + { + // If duplicate images are embedded, they may show up as attachments, so remove them. + //$html_images = array_unique($this->html_images); + //sort($html_images); + $i=0; + + foreach ($this->html_images as $img) + { + if ($image = file_get_contents($images_dir.'/'.$img["name"])) + { + // On garde que le nom de l'image + eregi('([A-Za-z0-9_-]+[.]?[A-Za-z0-9]+)?$',$img["name"],$regs); + $imgName = $regs[1]; + + $this->images_encoded[$i]['name'] = $imgName; + $this->images_encoded[$i]['content_type'] = $img["content_type"]; + $this->images_encoded[$i]['cid'] = $img["cid"]; + + // Encodage de l'image + $this->images_encoded[$i]["image_encoded"] = chunk_split(base64_encode($image), 68, $this->eol); + } + $i++; + } + } + else + { + return -1; + } + + return 1; + } + else + { + return 0; + } + } + + /** + \brief Permet d'attacher une image + \param images_list Tableau + \return out Chaine images encodees + */ + function write_images($images_list) + { + $out = ''; + + if ($images_list) + { + foreach ($images_list as $img) + { + dol_syslog("CMailFile::write_images: i=$i"); + + $out.= "--" . $this->mime_boundary . $this->eol; + $out.= "Content-Type: " . $img["content_type"] . "; name=\"".$img["name"]."\"".$this->eol; + $out.= "Content-Transfer-Encoding: base64".$this->eol; + $out.= "Content-Disposition: inline; filename=\"".$img["name"]."\"".$this->eol; + $out.= "Content-ID: <".$img["cid"].">".$this->eol; + $out.= $this->eol; + $out.= $img["image_encoded"]; + $out.= $this->eol; + } + } + else + { + return 0; + } + + // Fin de tous les attachements + $out.= "--" . $this->mime_boundary . "--" . $this->eol; + + return $out; + } + } @@ -634,7 +834,7 @@ function getValidAddress($adresses,$format) { if (eregi('^(.*)<(.*)>$',trim($val),$regs)) { - $name = trim($regs[1]); + $name = trim(utf8_decode($regs[1])); $email = trim($regs[2]); } else