Browse Source
L'ancienne classe Facteur est branchee sur FacteurSMTP qui se degrade en FacteurMail si pas de SMTP configure, pour assurer une continuite fonctionnelle des plugins qui utilisaient la classe Facteur directementsvn/root/tags/v4.0.3
5 changed files with 626 additions and 375 deletions
@ -0,0 +1,445 @@
|
||||
<?php |
||||
/** |
||||
* Plugin Facteur 4 |
||||
* (c) 2009-2019 Collectif SPIP |
||||
* Distribue sous licence GPL |
||||
* |
||||
* @package SPIP\Facteur\FacteurMail |
||||
*/ |
||||
|
||||
namespace SPIP\Facteur; |
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer; |
||||
use PHPMailer\PHPMailer\Exception; |
||||
|
||||
if (!defined("_ECRIRE_INC_VERSION")){ |
||||
return; |
||||
} |
||||
|
||||
include_spip('inc/charsets'); |
||||
include_spip('inc/texte'); |
||||
include_spip('inc/filtres'); |
||||
include_spip('facteur_fonctions'); |
||||
include_spip('lib/PHPMailer-6/autoload'); |
||||
|
||||
class FacteurMail extends PHPMailer { |
||||
/** |
||||
* From force si From pas dans le bon domaine |
||||
* @var string |
||||
*/ |
||||
public $ForceFrom = ''; |
||||
|
||||
/** |
||||
* FromName force si From pas dans le bon domaine |
||||
* @var string |
||||
*/ |
||||
public $ForceFromName = ''; |
||||
|
||||
/** |
||||
* Faut il embarquer dans le mail les images referencees ? |
||||
* @var bool |
||||
*/ |
||||
protected $embedReferencedImages = false; |
||||
|
||||
/** |
||||
* Faut il convertir le message en Isotruc (obsolete ?) |
||||
* @var bool |
||||
*/ |
||||
protected $convertMessageToIso8859 = false; |
||||
|
||||
/** |
||||
* Les URLs du site |
||||
* @var array |
||||
*/ |
||||
protected $urlsBase = array(); |
||||
|
||||
/** |
||||
* Wrapper de spip_log pour par PHPMailer |
||||
* @param $message |
||||
* @param $level |
||||
*/ |
||||
public static function logDebug($message, $level){ |
||||
spip_log("$level: " . trim($message), "facteur" . _LOG_DEBUG); |
||||
} |
||||
|
||||
protected function log($message, $level = null) { |
||||
$class = get_class($this); |
||||
if (empty($level)) { |
||||
$level = _LOG_INFO; |
||||
} |
||||
spip_log("$class: $message", "facteur" . $level); |
||||
} |
||||
|
||||
/** |
||||
* Facteur constructor. |
||||
* @param array $options |
||||
* @throws Exception |
||||
*/ |
||||
public function __construct($options = array()){ |
||||
// par defaut on log rien car tres verbeux |
||||
// on utilise facteur_log_debug qui filtre log SPIP en _LOG_DEBUG |
||||
$this->SMTPDebug = 0; |
||||
$this->Debugoutput = __NAMESPACE__ . '\FacteurMail::logDebug'; |
||||
// Il est possible d'avoir beaucoup plus de logs avec 2, 3 ou 4, ce qui logs les échanges complets avec le serveur |
||||
// utiliser avec un define('_MAX_LOG',1000); car sinon on est limite a 100 lignes par hit et phpMailer est tres verbeux |
||||
if (defined('_FACTEUR_DEBUG_SMTP')){ |
||||
$this->SMTPDebug = _FACTEUR_DEBUG_SMTP; |
||||
} |
||||
$this->exceptions = false; |
||||
if (!empty($options['exceptions'])) { |
||||
$this->exceptions = ($options['exceptions'] ? true : false); |
||||
} |
||||
|
||||
if (!empty($options['adresse_envoi_email'])){ |
||||
$this->From = $options['adresse_envoi_email']; |
||||
} |
||||
|
||||
// Si plusieurs emails dans le from, pas de Name ! |
||||
if (strpos($this->From, ",")===false){ |
||||
if (!empty($options['adresse_envoi_nom'])){ |
||||
$this->FromName = $options['adresse_envoi_nom']; |
||||
} |
||||
} |
||||
|
||||
// si forcer_from, on sauvegarde le From et FromName par defaut, qui seront utilises |
||||
// si From n'est pas dans le meme domaine |
||||
// (utiliser le facteur avec un service externe qui necessite la validation des domaines d'envoi) |
||||
if (isset($options['forcer_from']) and ($options['forcer_from'] === 'oui' or $options['forcer_from'] === true)){ |
||||
$this->ForceFrom = $this->From; |
||||
$this->ForceFromName = $this->FromName; |
||||
} |
||||
|
||||
$this->CharSet = "utf-8"; |
||||
$this->Mailer = 'mail'; |
||||
|
||||
// Retour des erreurs |
||||
if (!empty($options['smtp_sender'])){ |
||||
$this->Sender = $options['smtp_sender']; |
||||
$this->AddCustomHeader("Errors-To: " . $this->Sender); |
||||
} |
||||
|
||||
// Destinataires en copie, seulement s'il n'y a pas de destinataire de test |
||||
if (!defined('_TEST_EMAIL_DEST')){ |
||||
if (!empty($options['cc'])){ |
||||
$this->AddCC($options['cc']); |
||||
} |
||||
if (!empty($options['bcc'])){ |
||||
$this->AddBCC($options['bcc']); |
||||
} |
||||
} |
||||
|
||||
if (!empty($options['filtre_images']) and $options['filtre_images']) { |
||||
$this->embedReferencedImages = true; |
||||
} |
||||
|
||||
if (!empty($options['filtre_iso_8859']) and $options['filtre_iso_8859']) { |
||||
$this->convertMessageToIso8859 = true; |
||||
} |
||||
|
||||
if (!empty($options['adresses_site'])) { |
||||
$this->urlsBase = $options['adresses_site']; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Auto-configuration du mailer si besoin |
||||
* (rien a faire ici dans le cas par defaut) |
||||
* @return bool |
||||
*/ |
||||
public function configure(){ |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Definir l'objet du mail |
||||
* @param $objet |
||||
* @param $charset |
||||
*/ |
||||
public function setObjet($objet, $charset = null){ |
||||
if (is_null($charset)) { |
||||
$charset = $GLOBALS['meta']['charset']; |
||||
} |
||||
$this->Subject = unicode_to_utf_8(charset2unicode($objet, $charset)); |
||||
} |
||||
|
||||
/** |
||||
* Destinataire(s) du mail |
||||
* @param string | array $email |
||||
* @throws Exception |
||||
*/ |
||||
public function setDest($email) { |
||||
//Pour un envoi multiple de mail, $email doit être un tableau avec les adresses. |
||||
if (is_array($email)){ |
||||
foreach ($email as $cle => $adresseMail){ |
||||
if (!$this->AddAddress($adresseMail)){ |
||||
$this->log("Erreur AddAddress $adresseMail : " . print_r($this->ErrorInfo, true), _LOG_ERREUR); |
||||
} |
||||
} |
||||
} elseif (!$this->AddAddress($email)) { |
||||
$this->log("Erreur AddAddress $email : " . print_r($this->ErrorInfo, true), _LOG_ERREUR); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Definir le message, en HTML et/ou en texte (si seulement un message texte fourni |
||||
* @param string|null $message_html |
||||
* @param string $message_texte |
||||
* @param string $charset |
||||
* @throws Exception |
||||
*/ |
||||
public function setMessage($message_html, $message_texte = null, $charset = null) { |
||||
if (is_null($charset)) { |
||||
$charset = $GLOBALS['meta']['charset']; |
||||
} |
||||
|
||||
// S'il y a un contenu HTML |
||||
if (!empty($message_html)){ |
||||
$message_html = unicode_to_utf_8(charset2unicode($message_html, $charset)); |
||||
|
||||
$this->Body = $message_html; |
||||
$this->IsHTML(true); |
||||
if ($this->embedReferencedImages) { |
||||
$this->embedReferencedImages(); |
||||
} |
||||
|
||||
$this->urlsToAbsUrls(); |
||||
} |
||||
|
||||
// S'il y a un contenu texte brut |
||||
if (!empty($message_texte)){ |
||||
$message_texte = unicode_to_utf_8(charset2unicode($message_texte, $charset)); |
||||
|
||||
// Si pas de HTML on le remplace en tant que contenu principal |
||||
if (!$this->Body){ |
||||
$this->IsHTML(false); |
||||
$this->Body = $message_texte; |
||||
} // Sinon on met le texte brut en contenu alternatif |
||||
else { |
||||
$this->AltBody = $message_texte; |
||||
} |
||||
} |
||||
|
||||
if ($this->convertMessageToIso8859){ |
||||
$this->convertMessageFromUtf8ToIso8859(); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* @param bool $exceptions |
||||
*/ |
||||
public function setExceptions($exceptions){ |
||||
$this->exceptions = ($exceptions ? true : false); |
||||
} |
||||
|
||||
/** |
||||
* Transformer les urls des liens et des images en url absolues |
||||
* sans toucher aux images embarquees de la forme "cid:..." |
||||
* |
||||
* @param string|null $baseUrl |
||||
*/ |
||||
protected function urlsToAbsUrls($baseUrl = null){ |
||||
if (preg_match_all(',(<(a|link)[[:space:]]+[^<>]*href=["\']?)([^"\' ><[:space:]]+)([^<>]*>),imsS', |
||||
$this->Body, $liens, PREG_SET_ORDER)){ |
||||
foreach ($liens as $lien){ |
||||
if (strncmp($lien[3], "cid:", 4)!==0){ |
||||
$abs = url_absolue($lien[3], $baseUrl); |
||||
if ($abs<>$lien[3] and !preg_match('/^#/', $lien[3])){ |
||||
$this->Body = str_replace($lien[0], $lien[1] . $abs . $lien[4], $this->Body); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
if (preg_match_all(',(<(img|script)[[:space:]]+[^<>]*src=["\']?)([^"\' ><[:space:]]+)([^<>]*>),imsS', |
||||
$this->Body, $liens, PREG_SET_ORDER)){ |
||||
foreach ($liens as $lien){ |
||||
if (strncmp($lien[3], "cid:", 4)!==0){ |
||||
$abs = url_absolue($lien[3], $baseUrl); |
||||
if ($abs<>$lien[3]){ |
||||
$this->Body = str_replace($lien[0], $lien[1] . $abs . $lien[4], $this->Body); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Embed les images HTML dans l'email |
||||
* @throws Exception |
||||
*/ |
||||
protected function embedReferencedImages(){ |
||||
$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', |
||||
//'swf' => 'application/x-shockwave-flash' // on elever pour des raisons de securite et deprecie |
||||
); |
||||
|
||||
$src_found = array(); |
||||
$images_embeded = array(); |
||||
if (preg_match_all( |
||||
'/["\'](([^"\']+)\.(' . implode('|', array_keys($image_types)) . '))([?][^"\']+)?([#][^"\']+)?["\']/Uims', |
||||
$this->Body, $images, PREG_SET_ORDER)){ |
||||
|
||||
$adresse_site = $GLOBALS['meta']['adresse_site'] . '/'; |
||||
foreach ($images as $im){ |
||||
$im = array_pad($im, 6, null); |
||||
$src_orig = $im[1] . $im[4] . $im[5]; |
||||
|
||||
if (!isset($src_found[$src_orig])){ // deja remplace ? rien a faire (ie la meme image presente plusieurs fois) |
||||
// examiner le src et voir si embedable |
||||
$src = $im[1]; |
||||
foreach ($this->urlsBase as $base) { |
||||
if ($src AND strncmp($src, $base, strlen($base))==0){ |
||||
$src = _DIR_RACINE . substr($src, strlen($base)); |
||||
} |
||||
} |
||||
|
||||
if ($src |
||||
AND !preg_match(",^([a-z0-9]+:)?//,i", $src) |
||||
AND ( |
||||
file_exists($f = $src) // l'image a ete generee depuis le meme cote que l'envoi |
||||
OR (_DIR_RACINE AND file_exists($f = _DIR_RACINE . $src)) // l'image a ete generee dans le public et on est dans le prive |
||||
OR (!_DIR_RACINE AND file_exists($f = _DIR_RESTREINT . $src)) // l'image a ete generee dans le prive et on est dans le public |
||||
) |
||||
){ |
||||
if (!isset($images_embeded[$f])){ |
||||
$extension = strtolower($im[3]); |
||||
$header_extension = $image_types[$extension]; |
||||
$cid = md5($f); // un id unique pour un meme fichier |
||||
$images_embeded[$f] = $cid; // marquer l'image comme traitee, inutile d'y revenir |
||||
$this->AddEmbeddedImage($f, $cid, basename($f), 'base64', $header_extension); |
||||
} |
||||
|
||||
$this->Body = str_replace($src_orig, "cid:" . $images_embeded[$f], $this->Body); |
||||
$src_found[$src_orig] = $f; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Conversion safe d'un texte utf en isotruc |
||||
* @param string $text |
||||
* @param string $mode |
||||
* @return string |
||||
*/ |
||||
protected function safeUtf8Decode($text, $mode = 'texte_brut'){ |
||||
if (!is_utf8($text)){ |
||||
return ($text); |
||||
} |
||||
|
||||
if (function_exists('iconv') && $mode=='texte_brut'){ |
||||
$text = str_replace('?', "'", $text); |
||||
$text = iconv("UTF-8", "ISO-8859-1//TRANSLIT", $text); |
||||
return str_replace('’', "'", $text); |
||||
} else { |
||||
if ($mode=='texte_brut'){ |
||||
$text = str_replace('?', "'", $text); |
||||
} |
||||
$text = unicode2charset(utf_8_to_unicode($text), 'iso-8859-1'); |
||||
return str_replace('’', "'", $text); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Convertir tout le mail utf en isotruc |
||||
*/ |
||||
protected function convertMessageFromUtf8ToIso8859(){ |
||||
$this->CharSet = 'iso-8859-1'; |
||||
$this->Body = str_ireplace('charset=utf-8', 'charset=iso-8859-1', $this->Body); |
||||
$this->Body = $this->safeUtf8Decode($this->Body, 'html'); |
||||
$this->AltBody = $this->safeUtf8Decode($this->AltBody); |
||||
$this->Subject = $this->safeUtf8Decode($this->Subject); |
||||
$this->FromName = $this->safeUtf8Decode($this->FromName); |
||||
} |
||||
|
||||
/** |
||||
* Une fonction wrapper pour appeler une methode de phpMailer |
||||
* en recuperant l'erreur eventuelle, en la loguant via SPIP et en lancant une exception si demandee |
||||
* @param string $function |
||||
* @param array $args |
||||
* @return bool |
||||
* @throws phpmailerException |
||||
*/ |
||||
protected function callWrapper($function, $args){ |
||||
$exceptions = $this->exceptions; |
||||
$this->exceptions = true; |
||||
try { |
||||
$retour = call_user_func_array($function, $args); |
||||
$this->exceptions = $exceptions; |
||||
} catch (phpmailerException $exc) { |
||||
$this->log((is_array($function) ? implode('::', $function) : $function) . "() : " . $exc->getMessage(), _LOG_ERREUR); |
||||
$this->exceptions = $exceptions; |
||||
if ($this->exceptions){ |
||||
throw $exc; |
||||
} |
||||
return false; |
||||
} |
||||
if ($this->ErrorInfo){ |
||||
$this->log((is_array($function) ? implode('::', $function) : $function) . "() : " . $this->ErrorInfo, _LOG_ERREUR); |
||||
} |
||||
|
||||
return $retour; |
||||
} |
||||
|
||||
/* |
||||
* Appel des fonctions parents via le callWrapper qui se charge de loger les erreurs |
||||
*/ |
||||
|
||||
/** |
||||
* Avant le Send() on force le From si besoin |
||||
* |
||||
* @return bool |
||||
* @throws Exception |
||||
*/ |
||||
public function Send(){ |
||||
if ($this->ForceFrom |
||||
AND $this->From!==$this->ForceFrom){ |
||||
|
||||
$forcedomain = explode('@', $this->ForceFrom); |
||||
$forcedomain = end($forcedomain); |
||||
$domain = explode('@', $this->From); |
||||
$domain = end($domain); |
||||
|
||||
if ($domain!==$forcedomain){ |
||||
// le From passe en ReplyTo |
||||
$this->AddReplyTo($this->From, $this->FromName); |
||||
// on force le From |
||||
$this->From = $this->ForceFrom; |
||||
$this->FromName = $this->ForceFromName; |
||||
} |
||||
} |
||||
|
||||
$args = func_get_args(); |
||||
return $this->callWrapper(array('parent', 'Send'), $args); |
||||
} |
||||
|
||||
public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment'){ |
||||
$args = func_get_args(); |
||||
return $this->callWrapper(array('parent', 'AddAttachment'), $args); |
||||
} |
||||
|
||||
public function AddReplyTo($address, $name = ''){ |
||||
$args = func_get_args(); |
||||
return $this->callWrapper(array('parent', 'AddReplyTo'), $args); |
||||
} |
||||
|
||||
public function AddBCC($address, $name = ''){ |
||||
$args = func_get_args(); |
||||
return $this->callWrapper(array('parent', 'AddBCC'), $args); |
||||
} |
||||
|
||||
public function AddCC($address, $name = ''){ |
||||
$args = func_get_args(); |
||||
return $this->callWrapper(array('parent', 'AddCC'), $args); |
||||
} |
||||
} |
@ -0,0 +1,66 @@
|
||||
<?php |
||||
/** |
||||
* Plugin Facteur 4 |
||||
* (c) 2009-2019 Collectif SPIP |
||||
* Distribue sous licence GPL |
||||
* |
||||
* @package SPIP\Facteur\FacteurSMTP |
||||
*/ |
||||
|
||||
namespace SPIP\Facteur; |
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer; |
||||
use PHPMailer\PHPMailer\Exception; |
||||
|
||||
if (!defined("_ECRIRE_INC_VERSION")){ |
||||
return; |
||||
} |
||||
|
||||
include_spip('inc/Facteur/FacteurMail'); |
||||
|
||||
class FacteurSMTP extends FacteurMail { |
||||
|
||||
/** |
||||
* Facteur constructor. |
||||
* @param array $options |
||||
* @throws Exception |
||||
*/ |
||||
public function __construct($options = array()){ |
||||
parent::__construct($options); |
||||
|
||||
// il faut quand meme avoir un host et un port, sinon on reste sur le mailer par defaut |
||||
if (!empty($options['smtp_host']) and !empty($options['smtp_port'])){ |
||||
$this->Mailer = 'smtp'; |
||||
$this->Host = $options['smtp_host']; |
||||
$this->Port = $options['smtp_port']; |
||||
|
||||
// SMTP authentifié ? |
||||
$this->SMTPAuth = false; |
||||
if (isset($options['smtp_auth']) |
||||
and ($options['smtp_auth']==='oui' or $options['smtp_auth']===true) |
||||
and !empty($options['smtp_username']) |
||||
and !empty($options['smtp_password'])){ |
||||
$this->SMTPAuth = true; |
||||
$this->Username = $options['smtp_username']; |
||||
$this->Password = $options['smtp_password']; |
||||
} |
||||
|
||||
if (!empty($options['smtp_secure']) |
||||
and in_array($options['smtp_secure'], ['ssl', 'tls'])){ |
||||
$this->SMTPSecure = $options['smtp_secure']; |
||||
} |
||||
|
||||
if ($options['smtp_tls_allow_self_signed']=='oui'){ |
||||
$this->SMTPOptions = array( |
||||
'ssl' => array('allow_self_signed' => true) |
||||
); |
||||
} |
||||
|
||||
// Pour le moment on remet l'ancien fonctionnement : |
||||
// on ne doit pas tester les certificats si pas demandé explicitement avec l'option TLS ! |
||||
$this->SMTPAutoTLS = false; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,80 @@
|
||||
<?php |
||||
/** |
||||
* Plugin Facteur 4 |
||||
* (c) 2009-2019 Collectif SPIP |
||||
* Distribue sous licence GPL |
||||
* |
||||
* @package SPIP\Facteur\Inc\Facteur_factory |
||||
*/ |
||||
|
||||
|
||||
|
||||
/** |
||||
* Recuperer la config par defaut de Facteur, en s'assurant que les meta ont bien ete migrees |
||||
* @return array |
||||
*/ |
||||
function facteur_config_default() { |
||||
if (!function_exists('lire_config')) { |
||||
include_spip('inc/config'); |
||||
} |
||||
|
||||
// si jamais les meta sont pas migrees... le faire a l'arrache ! |
||||
if (isset($GLOBALS['meta']["facteur_smtp"])) { |
||||
include_spip('facteur_administrations'); |
||||
facteur_migre_metas_to_config(); |
||||
} |
||||
|
||||
$config = lire_config('facteur'); |
||||
|
||||
if ($config['adresse_envoi'] !== 'oui' or !$config['adresse_envoi_email'] |
||||
) { |
||||
$config['adresse_envoi'] = (isset($GLOBALS['meta']["email_envoi"]) AND $GLOBALS['meta']["email_envoi"]) ? |
||||
$GLOBALS['meta']["email_envoi"] |
||||
: $GLOBALS['meta']['email_webmaster']; |
||||
|
||||
if (!function_exists('extraire_multi')) { |
||||
include_spip('inc/filtres'); |
||||
} |
||||
$config['adresse_envoi_nom'] = strip_tags(extraire_multi($GLOBALS['meta']['nom_site'])); |
||||
} |
||||
|
||||
$config['adresses_site'] = array( |
||||
$GLOBALS['meta']['adresse_site'] . '/', |
||||
url_de_base(), |
||||
); |
||||
|
||||
return $config; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Generer le FacteurXXX selon la config par defaut/passee en options |
||||
* @param array $options |
||||
* @return \SPIP\Facteur\FacteurMail |
||||
* @throws \PHPMailer\PHPMailer\Exception |
||||
*/ |
||||
function facteur_factory($options = array()) { |
||||
|
||||
if (!is_array($options)) { |
||||
$options = array(); |
||||
} |
||||
$options = array_merge(facteur_config_default(), $options); |
||||
|
||||
$config_mailer = $options['mailer']; |
||||
|
||||
switch ($config_mailer) { |
||||
case 'smtp': |
||||
include_spip('inc/Facteur/FacteurSMTP'); |
||||
return new SPIP\Facteur\FacteurSMTP($options); |
||||
|
||||
case 'mailjet': |
||||
include_spip('inc/Facteur/FacteurMailjet'); |
||||
return new SPIP\Facteur\FacteurMailjet($options); |
||||
|
||||
case 'mail': |
||||
default: |
||||
include_spip('inc/Facteur/FacteurMail'); |
||||
return new SPIP\Facteur\FacteurMail($options); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue