[PLUGINS] ~maj globale
[lhc/web/www.git] / www / plugins / facteur / classes / facteur.php
index daedf1e..5a8decd 100755 (executable)
@@ -19,7 +19,28 @@ if (!class_exists('PHPMailer')) {
 \r
 include_spip('facteur_fonctions');\r
 \r
+/**\r
+ * Wrapper de spip_log pour par PHPMailer\r
+ * @param $message\r
+ * @param $level\r
+ */\r
+function facteur_log_debug($message,$level){\r
+       spip_log("$level: ".trim($message),"facteur"._LOG_DEBUG);\r
+}\r
+\r
+\r
 class Facteur extends PHPMailer {\r
+       /**\r
+        * From force si From pas dans le bon domaine\r
+        * @var string\r
+        */\r
+       public $ForceFrom = '';\r
+\r
+       /**\r
+        * FromName force si From pas dans le bon domaine\r
+        * @var string\r
+        */\r
+       public $ForceFromName = '';\r
 \r
        /**\r
         * @param $email\r
@@ -29,44 +50,65 @@ class Facteur extends PHPMailer {
         * @param array $options\r
         *\r
         */\r
-       function Facteur($email, $objet, $message_html, $message_texte, $options = array()) {\r
-               $defaut = array(\r
-                       'adresse_envoi' => $GLOBALS['meta']['facteur_adresse_envoi'],\r
-                       'adresse_envoi_email' => $GLOBALS['meta']['facteur_adresse_envoi_email'],\r
-                       'adresse_envoi_nom' => $GLOBALS['meta']['facteur_adresse_envoi_nom'],\r
-                       'cc' => $GLOBALS['meta']['facteur_cc'],\r
-                       'bcc' => $GLOBALS['meta']['facteur_bcc'],\r
-                       'smtp' => $GLOBALS['meta']['facteur_smtp'],\r
-                       'smtp_host' => $GLOBALS['meta']['facteur_smtp_host'],\r
-                       'smtp_port' => $GLOBALS['meta']['facteur_smtp_port'],\r
-                       'smtp_auth' => $GLOBALS['meta']['facteur_smtp_auth'],\r
-                       'smtp_username' => $GLOBALS['meta']['facteur_smtp_username'],\r
-                       'smtp_password' => $GLOBALS['meta']['facteur_smtp_password'],\r
-                       'smtp_secure' => $GLOBALS['meta']['facteur_smtp_secure'],\r
-                       'smtp_sender' => $GLOBALS['meta']['facteur_smtp_sender'],\r
-                       'filtre_images' => $GLOBALS['meta']['facteur_filtre_images'],\r
-                       'filtre_iso_8859' => $GLOBALS['meta']['facteur_filtre_iso_8859'],\r
-               );\r
+       public function __construct($email, $objet, $message_html, $message_texte, $options = array()) {\r
+               // On récupère toutes les options par défaut depuis le formulaire de config\r
+               $defaut = array();\r
+               foreach (array(\r
+                       'adresse_envoi', 'adresse_envoi_email', 'adresse_envoi_nom', 'forcer_from',\r
+                       'cc', 'bcc',\r
+                       'smtp', 'smtp_host', 'smtp_port', 'smtp_auth',\r
+                       'smtp_username', 'smtp_password', 'smtp_secure', 'smtp_sender',\r
+                       'filtre_images', 'filtre_iso_8859',\r
+               ) as $config) {\r
+                       $defaut[$config] = isset($GLOBALS['meta']["facteur_$config"]) ? $GLOBALS['meta']["facteur_$config"] : '';\r
+               }\r
+               // On fusionne les options avec d'éventuelles surcharges lors de l'appel\r
                $options = array_merge($defaut, $options);\r
 \r
+               // par defaut on log rien car tres verbeux\r
+               // on utilise facteur_log_debug qui filtre log SPIP en _LOG_DEBUG\r
+               $this->SMTPDebug = 0;\r
+               $this->Debugoutput = "facteur_log_debug";\r
+               // Il est possible d'avoir beaucoup plus de logs avec 2, 3 ou 4, ce qui logs les échanges complets avec le serveur\r
+               // utiliser avec un define('_MAX_LOG',1000); car sinon on est limite a 100 lignes par hit et phpMailer est tres verbeux\r
                if (defined('_FACTEUR_DEBUG_SMTP')) {\r
                        $this->SMTPDebug = _FACTEUR_DEBUG_SMTP ;\r
                }\r
-               if ($options['adresse_envoi'] == 'oui'\r
-                 AND $options['adresse_envoi_email'])\r
+               $this->exceptions = false;\r
+\r
+\r
+               if (\r
+                       $options['adresse_envoi'] == 'oui'\r
+                       and $options['adresse_envoi_email']\r
+               ) {\r
                        $this->From = $options['adresse_envoi_email'];\r
-               else\r
-                       $this->From = (isset($GLOBALS['meta']["email_envoi"]) AND $GLOBALS['meta']["email_envoi"])?\r
+               }\r
+               else {\r
+                       $this->From = (isset($GLOBALS['meta']["email_envoi"]) AND $GLOBALS['meta']["email_envoi"]) ?\r
                                $GLOBALS['meta']["email_envoi"]\r
-                               :$GLOBALS['meta']['email_webmaster'];\r
+                               : $GLOBALS['meta']['email_webmaster'];\r
+               }\r
 \r
                // Si plusieurs emails dans le from, pas de Name !\r
-               if (strpos($this->From,",")===false){\r
-                       if ($options['adresse_envoi'] == 'oui'\r
-                         AND $options['adresse_envoi_nom'])\r
+               if (strpos($this->From,",") === false) {\r
+                       if (\r
+                               $options['adresse_envoi'] == 'oui'\r
+                               and $options['adresse_envoi_nom']\r
+                       ) {\r
                                $this->FromName = $options['adresse_envoi_nom'];\r
-                       else\r
+                       }\r
+                       // Par défaut, l'envoyeur est le nom du site\r
+                       else {\r
                                $this->FromName = strip_tags(extraire_multi($GLOBALS['meta']['nom_site']));\r
+                       }\r
+               }\r
+\r
+               // si forcer_from, on sauvegarde le From et FromName par defaut, qui seront utilises\r
+               // si From n'est pas dans le meme domaine\r
+               // (utiliser le facteur avec un service externe qui necessite la validation des domaines d'envoi)\r
+               if ($options['forcer_from']=='oui'){\r
+                       $this->ForceFrom = $this->From;\r
+                       $this->ForceFromName = $this->FromName;\r
                }\r
 \r
                $this->CharSet = "utf-8";\r
@@ -76,32 +118,38 @@ class Facteur extends PHPMailer {
                //Pour un envoi multiple de mail, $email doit être un tableau avec les adresses.\r
                if (is_array($email)) {\r
                        foreach ($email as $cle => $adresseMail) {\r
-                               if (!$this->AddAddress($adresseMail))\r
-                                       spip_log("Erreur AddAddress $adresseMail : ".print_r($this->ErrorInfo,true),'facteur');\r
+                               if (!$this->AddAddress($adresseMail)) {\r
+                                       spip_log("Erreur AddAddress $adresseMail : ".print_r($this->ErrorInfo, true), 'facteur.'._LOG_ERREUR);\r
+                               }\r
                        }\r
                }\r
-               else\r
-                       if (!$this->AddAddress($email))\r
-                               spip_log("Erreur AddAddress $email : ".print_r($this->ErrorInfo,true),'facteur');\r
+               elseif (!$this->AddAddress($email)) {\r
+                       spip_log("Erreur AddAddress $email : ".print_r($this->ErrorInfo, true), 'facteur.'._LOG_ERREUR);\r
+               }\r
 \r
+               // Retour des erreurs\r
                if (!empty($options['smtp_sender'])) {\r
                        $this->Sender = $options['smtp_sender'];\r
                        $this->AddCustomHeader("Errors-To: ".$this->Sender);\r
                }\r
 \r
+               // Destinataires en copie, seulement s'il n'y a pas de destinataire de test\r
                if (!defined('_TEST_EMAIL_DEST')){\r
                        if (!empty($options['cc'])) {\r
-                               $this->AddCC( $options['cc'] );\r
+                               $this->AddCC($options['cc']);\r
                        }\r
                        if (!empty($options['bcc'])) {\r
-                               $this->AddBCC( $options['bcc'] );\r
+                               $this->AddBCC($options['bcc']);\r
                        }\r
                }\r
 \r
+               // Si on envoie avec un SMTP explicite\r
                if (isset($options['smtp']) AND $options['smtp'] == 'oui') {\r
                        $this->Mailer   = 'smtp';\r
                        $this->Host     = $options['smtp_host'];\r
                        $this->Port     = $options['smtp_port'];\r
+\r
+                       // SMTP authentifié\r
                        if ($options['smtp_auth'] == 'oui') {\r
                                $this->SMTPAuth = true;\r
                                $this->Username = $options['smtp_username'];\r
@@ -110,55 +158,85 @@ class Facteur extends PHPMailer {
                        else {\r
                                $this->SMTPAuth = false;\r
                        }\r
-                       if (intval(phpversion()) == 5) {\r
-                       if ($options['smtp_secure'] == 'ssl')\r
+\r
+                       if ($options['smtp_secure'] == 'ssl') {\r
                                $this->SMTPSecure = 'ssl';\r
-                       if ($options['smtp_secure'] == 'tls')\r
+                       }\r
+                       if ($options['smtp_secure'] == 'tls') {\r
                                $this->SMTPSecure = 'tls';\r
                        }\r
+\r
+                       // Pour le moment on remet l'ancien fonctionnement :\r
+                       // on ne doit pas tester les certificats si pas demandé explicitement avec l'option TLS !\r
+                       $this->SMTPAutoTLS = false;\r
                }\r
 \r
+               // S'il y a un contenu HTML\r
                if (!empty($message_html)) {\r
-                       $message_html = unicode_to_utf_8(charset2unicode($message_html,$GLOBALS['meta']['charset']));\r
+                       $message_html = unicode_to_utf_8(charset2unicode($message_html, $GLOBALS['meta']['charset']));\r
+\r
                        $this->Body = $message_html;\r
                        $this->IsHTML(true);\r
-                       if ($options['filtre_images'])\r
+                       if ($options['filtre_images']) {\r
                                $this->JoindreImagesHTML();\r
+                       }\r
+\r
                        $this->UrlsAbsolues();\r
                }\r
+\r
+               // S'il y a un contenu texte brut\r
                if (!empty($message_texte)) {\r
-                       $message_texte = unicode_to_utf_8(charset2unicode($message_texte,$GLOBALS['meta']['charset']));\r
+                       $message_texte = unicode_to_utf_8(charset2unicode($message_texte, $GLOBALS['meta']['charset']));\r
+\r
+                       // Si pas de HTML on le remplace en tant que contenu principal\r
                        if (!$this->Body) {\r
                                $this->IsHTML(false);\r
                                $this->Body = $message_texte;\r
                        }\r
+                       // Sinon on met le texte brut en contenu alternatif\r
                        else {\r
                                $this->AltBody = $message_texte;\r
                        }\r
                }\r
 \r
-               if ($options['filtre_iso_8859'])\r
+               if ($options['filtre_iso_8859']) {\r
                        $this->ConvertirUtf8VersIso8859();\r
+               }\r
+       }\r
 \r
+       /**\r
+        * @param bool $exceptions\r
+        */\r
+       public function SetExceptions($exceptions){\r
+               $this->exceptions = ($exceptions?true:false);\r
        }\r
-       \r
-       /*\r
+\r
+       /**\r
         * Transforme du HTML en texte brut, mais proprement\r
         * utilise le filtre facteur_mail_html2text\r
         * @uses facteur_mail_html2text()\r
         *\r
         * @param string $html Le HTML à transformer\r
+        * @param bool $advanced Inutilisé\r
         * @return string Retourne un texte brut formaté correctement\r
         */\r
-       function html2text($html){\r
+       public function html2text($html, $advanced = false){\r
                return facteur_mail_html2text($html);\r
        }\r
-       \r
+\r
+       /**\r
+        * Compat ascendante, obsolete\r
+        * @deprecated\r
+        */\r
+       public function ConvertirStylesEnligne() {\r
+               $this->Body = facteur_convertir_styles_inline($this->Body);\r
+       }\r
+\r
        /**\r
         * Transformer les urls des liens et des images en url absolues\r
         * sans toucher aux images embarquees de la forme "cid:..."\r
         */\r
-       function UrlsAbsolues($base=null){\r
+       protected function UrlsAbsolues($base=null){\r
                include_spip('inc/filtres_mini');\r
                if (preg_match_all(',(<(a|link)[[:space:]]+[^<>]*href=["\']?)([^"\' ><[:space:]]+)([^<>]*>),imsS',\r
                  $this->Body, $liens, PREG_SET_ORDER)) {\r
@@ -182,7 +260,10 @@ class Facteur extends PHPMailer {
                }\r
        }\r
 \r
-       function JoindreImagesHTML() {\r
+       /**\r
+        * Embed les images HTML dans l'email\r
+        */\r
+       protected function JoindreImagesHTML() {\r
                $image_types = array(\r
                                                        'gif'   => 'image/gif',\r
                                                        'jpg'   => 'image/jpeg',\r
@@ -202,6 +283,7 @@ class Facteur extends PHPMailer {
 \r
                        $adresse_site = $GLOBALS['meta']['adresse_site'].'/';\r
                        foreach($images as $im){\r
+                               $im = array_pad($im, 6, null);\r
                                $src_orig = $im[1].$im[4].$im[5];\r
                                if (!isset($src_found[$src_orig])){ // deja remplace ? rien a faire (ie la meme image presente plusieurs fois)\r
                                        // examiner le src et voir si embedable\r
@@ -234,14 +316,12 @@ class Facteur extends PHPMailer {
 \r
 \r
        /**\r
-        * Compat ascendante, obsolete\r
+        * Conversion safe d'un texte utf en isotruc\r
+        * @param string $text\r
+        * @param string $mode\r
+        * @return string\r
         */\r
-       function ConvertirStylesEnligne() {\r
-               $this->Body = facteur_convertir_styles_inline($this->Body);\r
-       }\r
-\r
-\r
-       function safe_utf8_decode($text,$mode='texte_brut') {\r
+       protected function safe_utf8_decode($text,$mode='texte_brut') {\r
                if (!is_utf8($text))\r
                        return ($text);\r
 \r
@@ -259,7 +339,10 @@ class Facteur extends PHPMailer {
                }\r
        }\r
 \r
-       function ConvertirUtf8VersIso8859() {\r
+       /**\r
+        * Convertir tout le mail utf en isotruc\r
+        */\r
+       protected function ConvertirUtf8VersIso8859() {\r
                $this->CharSet  = 'iso-8859-1';\r
                $this->Body             = str_ireplace('charset=utf-8', 'charset=iso-8859-1', $this->Body);\r
                $this->Body             = $this->safe_utf8_decode($this->Body,'html');\r
@@ -268,7 +351,10 @@ class Facteur extends PHPMailer {
                $this->FromName = $this->safe_utf8_decode($this->FromName);\r
        }\r
 \r
-       function ConvertirAccents() {\r
+       /**\r
+        * Convertir les accents du body en entites html\r
+        */\r
+       protected function ConvertirAccents() {\r
                // tableau à compléter au fur et à mesure\r
                $cor = array(\r
                                                'à' => '&agrave;',\r
@@ -292,56 +378,79 @@ class Facteur extends PHPMailer {
 \r
                $this->Body = strtr($this->Body, $cor);\r
        }\r
-       public function Send() {\r
-               ob_start();\r
-               $retour = parent::Send();\r
-               $error = ob_get_contents();\r
-               ob_end_clean();\r
-               if( !empty($error) ) {\r
-                       spip_log("Erreur Facteur->Send : $error",'facteur.err');\r
+\r
+\r
+       /**\r
+        * Une fonction wrapper pour appeler une methode de phpMailer\r
+        * en recuperant l'erreur eventuelle, en la loguant via SPIP et en lancant une exception si demandee\r
+        * @param string $function\r
+        * @param array $args\r
+        * @return bool\r
+        * @throws phpmailerException\r
+        */\r
+       protected function callWrapper($function,$args){\r
+               $exceptions = $this->exceptions;\r
+               $this->exceptions = true;\r
+               try {\r
+                       $retour = call_user_func_array($function,$args);\r
+                       $this->exceptions = $exceptions;\r
                }\r
+               catch (phpmailerException $exc) {\r
+                       spip_log((is_array($function)?implode('::',$function):$function)."() : ".$exc->getMessage(),'facteur.'._LOG_ERREUR);\r
+                       $this->exceptions = $exceptions;\r
+                       if ($this->exceptions) {\r
+                               throw $exc;\r
+                       }\r
+                       return false;\r
+               }\r
+               if ($this->ErrorInfo){\r
+                       spip_log($function."() : ".$this->ErrorInfo,'facteur.'._LOG_ERREUR);\r
+               }\r
+\r
                return $retour;\r
        }\r
-       public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {\r
-               ob_start();\r
-               $retour = parent::AddAttachment($path, $name, $encoding, $type);\r
-               $error = ob_get_contents();\r
-               ob_end_clean();\r
-               if( !empty($error) ) {\r
-                       spip_log("Erreur Facteur->AddAttachment : $error",'facteur.err');\r
+\r
+       /*\r
+        * Appel des fonctions parents via le callWrapper qui se charge de loger les erreurs\r
+        */\r
+\r
+       /**\r
+        * Avant le Send() on force le From si besoin\r
+        * @return bool\r
+        * @throws phpmailerException\r
+        */\r
+       public function Send() {\r
+               if ($this->ForceFrom\r
+                       AND $this->From!==$this->ForceFrom){\r
+                       $forcedomain = explode('@',$this->ForceFrom);\r
+                       $forcedomain = end($forcedomain);\r
+                       $domain = explode('@',$this->From);\r
+                       $domain = end($domain);\r
+                       if ($domain!==$forcedomain){\r
+                               // le From passe en ReplyTo\r
+                               $this->AddReplyTo($this->From,$this->FromName);\r
+                               // on force le From\r
+                               $this->From = $this->ForceFrom;\r
+                               $this->FromName = $this->ForceFromName;\r
+                       }\r
                }\r
-               return $retour;\r
+               $args = func_get_args();\r
+               return $this->callWrapper(array('parent','Send'),$args);\r
+       }\r
+       public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment') {\r
+               $args = func_get_args();\r
+               return $this->callWrapper(array('parent','AddAttachment'),$args);\r
        }\r
        public function AddReplyTo($address, $name = '') {\r
-               ob_start();\r
-               $retour = parent::AddReplyTo($address, $name);\r
-               $error = ob_get_contents();\r
-               ob_end_clean();\r
-               if( !empty($error) ) {\r
-                       spip_log("Erreur Facteur->AddReplyTo : $error",'facteur.err');\r
-               }\r
-               return $retour;\r
+               $args = func_get_args();\r
+               return $this->callWrapper(array('parent','AddReplyTo'),$args);\r
        }\r
        public function AddBCC($address, $name = '') {\r
-               ob_start();\r
-               $retour = parent::AddBCC($address, $name);\r
-               $error = ob_get_contents();\r
-               ob_end_clean();\r
-               if( !empty($error) ) {\r
-                       spip_log("Erreur Facteur->AddBCC : $error",'facteur.err');\r
-               }\r
-               return $retour;\r
+               $args = func_get_args();\r
+               return $this->callWrapper(array('parent','AddBCC'),$args);\r
        }\r
        public function AddCC($address, $name = '') {\r
-               ob_start();\r
-               $retour = parent::AddCC($address, $name);\r
-               $error = ob_get_contents();\r
-               ob_end_clean();\r
-               if( !empty($error) ) {\r
-                       spip_log("Erreur Facteur->AddCC : $error",'facteur.err');\r
-               }\r
-               return $retour;\r
+               $args = func_get_args();\r
+               return $this->callWrapper(array('parent','AddCC'),$args);\r
        }\r
 }\r
-\r
-?>\r