Compare commits

..

1 Commits
master ... v3

Author SHA1 Message Date
cedric@yterium.com 2cd14ef716 Archivons la branche v3 3 years ago
  1. 116
      .gitattributes
  2. 15
      .gitignore
  3. 462
      classes/facteur.php
  4. 27
      composer.json
  5. 0
      emails/css.html
  6. 0
      emails/inc-bas.html
  7. 0
      emails/inc-haut.html
  8. 14
      emails/test_email_html.html
  9. 8
      emails/test_email_texte.html
  10. 42
      erreurs et exceptions.txt
  11. 12
      facteur-64.svg
  12. 98
      facteur_administrations.php
  13. 441
      facteur_fonctions.php
  14. 6
      facteur_ieconfig_metas.php
  15. 33
      facteur_pipelines.php
  16. 336
      formulaires/configurer_facteur.html
  17. 323
      formulaires/configurer_facteur.php
  18. 4
      formulaires/inc-config-facteur-mailer-mail.html
  19. 71
      formulaires/inc-config-facteur-mailer-smtp.html
  20. 71
      formulaires/tester_facteur.html
  21. 183
      formulaires/tester_facteur.php
  22. 628
      inc/Facteur/FacteurMail.php
  23. 68
      inc/Facteur/FacteurSMTP.php
  24. 439
      inc/envoyer_mail.php
  25. 620
      inc/facteur.php
  26. 16
      inc/facteur_classes.php
  27. 224
      inc/facteur_convertir_styles_inline.php
  28. 52
      inc/facteur_envoyer_alerte_fail.php
  29. 113
      inc/facteur_mail_html2text.php
  30. 65
      inc/facteur_mail_wrap_to_html.php
  31. 47
      lang/facteur.xml
  32. 22
      lang/facteur_de.php
  33. 21
      lang/facteur_en.php
  34. 6
      lang/facteur_eo.php
  35. 4
      lang/facteur_es.php
  36. 4
      lang/facteur_fa.php
  37. 23
      lang/facteur_fr.php
  38. 21
      lang/facteur_fr_tu.php
  39. 66
      lang/facteur_it.php
  40. 19
      lang/facteur_ja.php
  41. 28
      lang/facteur_nl.php
  42. 4
      lang/facteur_oc_ni_mis.php
  43. 83
      lang/facteur_pt.php
  44. 6
      lang/facteur_pt_br.php
  45. 100
      lang/facteur_ru.php
  46. 4
      lang/facteur_sk.php
  47. 101
      lang/facteur_uk.php
  48. 20
      lang/paquet-facteur.xml
  49. 0
      lang/paquet-facteur_de.php
  50. 2
      lang/paquet-facteur_fr.php
  51. 4
      lang/paquet-facteur_it.php
  52. 16
      lang/paquet-facteur_pt.php
  53. 16
      lang/paquet-facteur_uk.php
  54. 46
      lib/PHPMailer-6/COMMITMENT
  55. 227
      lib/PHPMailer-6/README.md
  56. 37
      lib/PHPMailer-6/SECURITY.md
  57. 1
      lib/PHPMailer-6/VERSION
  58. 71
      lib/PHPMailer-6/composer.json
  59. 26
      lib/PHPMailer-6/language/phpmailer.lang-af.php
  60. 29
      lib/PHPMailer-6/language/phpmailer.lang-da.php
  61. 38
      lib/PHPMailer-6/language/phpmailer.lang-fr.php
  62. 27
      lib/PHPMailer-6/language/phpmailer.lang-hi.php
  63. 27
      lib/PHPMailer-6/language/phpmailer.lang-hy.php
  64. 31
      lib/PHPMailer-6/language/phpmailer.lang-id.php
  65. 27
      lib/PHPMailer-6/language/phpmailer.lang-mg.php
  66. 28
      lib/PHPMailer-6/language/phpmailer.lang-sr_latn.php
  67. 28
      lib/PHPMailer-6/language/phpmailer.lang-tl.php
  68. 40
      lib/PHPMailer-6/src/Exception.php
  69. 139
      lib/PHPMailer-6/src/OAuth.php
  70. 5040
      lib/PHPMailer-6/src/PHPMailer.php
  71. 462
      lib/PHPMailer-6/src/POP3.php
  72. 50
      paquet.xml
  73. 14
      phpcs.xml.dist
  74. 0
      phpmailer-php5/LICENSE
  75. 33
      phpmailer-php5/PHPMailerAutoload.php
  76. 1
      phpmailer-php5/VERSION
  77. 4061
      phpmailer-php5/class.phpmailer.php
  78. 197
      phpmailer-php5/class.phpmaileroauth.php
  79. 77
      phpmailer-php5/class.phpmaileroauthgoogle.php
  80. 407
      phpmailer-php5/class.pop3.php
  81. 941
      phpmailer-php5/class.smtp.php
  82. 61
      phpmailer-php5/composer.json
  83. 3593
      phpmailer-php5/composer.lock
  84. 148
      phpmailer-php5/extras/EasyPeasyICS.php
  85. 17
      phpmailer-php5/extras/README.md
  86. 1159
      phpmailer-php5/extras/htmlfilter.php
  87. 185
      phpmailer-php5/extras/ntlm_sasl_client.php
  88. 162
      phpmailer-php5/get_oauth_token.php
  89. 0
      phpmailer-php5/language/phpmailer.lang-am.php
  90. 6
      phpmailer-php5/language/phpmailer.lang-ar.php
  91. 1
      phpmailer-php5/language/phpmailer.lang-az.php
  92. 5
      phpmailer-php5/language/phpmailer.lang-ba.php
  93. 1
      phpmailer-php5/language/phpmailer.lang-be.php
  94. 1
      phpmailer-php5/language/phpmailer.lang-bg.php
  95. 1
      phpmailer-php5/language/phpmailer.lang-ca.php
  96. 1
      phpmailer-php5/language/phpmailer.lang-ch.php
  97. 3
      phpmailer-php5/language/phpmailer.lang-cs.php
  98. 26
      phpmailer-php5/language/phpmailer.lang-da.php
  99. 3
      phpmailer-php5/language/phpmailer.lang-de.php
  100. 1
      phpmailer-php5/language/phpmailer.lang-el.php
  101. Some files were not shown because too many files have changed in this diff Show More

116
.gitattributes vendored

@ -0,0 +1,116 @@
* text=auto !eol
classes/facteur.php -text
emails/css.html -text
emails/inc-bas.html -text
emails/inc-button.html -text
emails/inc-haut.html -text
emails/test_email_html.html -text
emails/test_email_texte.html -text
emails/texte.html -text
/erreurs[!!-~]et[!!-~]exceptions.txt -text
/facteur_administrations.php -text
/facteur_fonctions.php -text
/facteur_ieconfig_metas.php -text
/facteur_pipelines.php -text
formulaires/configurer_facteur.html -text
formulaires/configurer_facteur.php -text
inc/envoyer_mail.php -text
inc/facteur_classes.php -text
lang/facteur.xml -text
lang/facteur_de.php -text
lang/facteur_en.php -text
lang/facteur_eo.php -text
lang/facteur_es.php -text
lang/facteur_fa.php -text
lang/facteur_fr.php -text
lang/facteur_fr_tu.php -text
lang/facteur_it.php -text
lang/facteur_ja.php -text
lang/facteur_nl.php -text
lang/facteur_oc_ni_mis.php -text
lang/facteur_pt_br.php -text
lang/facteur_sk.php -text
lang/paquet-facteur.xml -text
lang/paquet-facteur_de.php -text
lang/paquet-facteur_en.php -text
lang/paquet-facteur_eo.php -text
lang/paquet-facteur_es.php -text
lang/paquet-facteur_fr.php -text
lang/paquet-facteur_fr_tu.php -text
lang/paquet-facteur_it.php -text
lang/paquet-facteur_ja.php -text
lang/paquet-facteur_nl.php -text
lang/paquet-facteur_pt_br.php -text
lang/paquet-facteur_ru.php -text
lang/paquet-facteur_sk.php -text
lib/markdownify/LICENSE_LGPL.txt -text
lib/markdownify/markdownify.php -text
lib/markdownify/markdownify_extra.php -text
lib/markdownify/parsehtml/parsehtml.php -text
/paquet.xml -text
phpmailer-php5/LICENSE -text
phpmailer-php5/PHPMailerAutoload.php -text
phpmailer-php5/VERSION -text
phpmailer-php5/class.phpmailer.php -text
phpmailer-php5/class.phpmaileroauth.php -text
phpmailer-php5/class.phpmaileroauthgoogle.php -text
phpmailer-php5/class.pop3.php -text
phpmailer-php5/class.smtp.php -text
phpmailer-php5/composer.json -text
phpmailer-php5/composer.lock -text
phpmailer-php5/extras/EasyPeasyICS.php -text
phpmailer-php5/extras/README.md -text
phpmailer-php5/extras/htmlfilter.php -text
phpmailer-php5/extras/ntlm_sasl_client.php -text
phpmailer-php5/get_oauth_token.php -text
phpmailer-php5/language/phpmailer.lang-am.php -text
phpmailer-php5/language/phpmailer.lang-ar.php -text
phpmailer-php5/language/phpmailer.lang-az.php -text
phpmailer-php5/language/phpmailer.lang-ba.php -text
phpmailer-php5/language/phpmailer.lang-be.php -text
phpmailer-php5/language/phpmailer.lang-bg.php -text
phpmailer-php5/language/phpmailer.lang-ca.php -text
phpmailer-php5/language/phpmailer.lang-ch.php -text
phpmailer-php5/language/phpmailer.lang-cs.php -text
phpmailer-php5/language/phpmailer.lang-da.php -text
phpmailer-php5/language/phpmailer.lang-de.php -text
phpmailer-php5/language/phpmailer.lang-el.php -text
phpmailer-php5/language/phpmailer.lang-eo.php -text
phpmailer-php5/language/phpmailer.lang-es.php -text
phpmailer-php5/language/phpmailer.lang-et.php -text
phpmailer-php5/language/phpmailer.lang-fa.php -text
phpmailer-php5/language/phpmailer.lang-fi.php -text
phpmailer-php5/language/phpmailer.lang-fo.php -text
phpmailer-php5/language/phpmailer.lang-fr.php -text
phpmailer-php5/language/phpmailer.lang-gl.php -text
phpmailer-php5/language/phpmailer.lang-he.php -text
phpmailer-php5/language/phpmailer.lang-hr.php -text
phpmailer-php5/language/phpmailer.lang-hu.php -text
phpmailer-php5/language/phpmailer.lang-id.php -text
phpmailer-php5/language/phpmailer.lang-it.php -text
phpmailer-php5/language/phpmailer.lang-ja.php -text svneol=unset#application/octet-stream
phpmailer-php5/language/phpmailer.lang-ka.php -text
phpmailer-php5/language/phpmailer.lang-ko.php -text
phpmailer-php5/language/phpmailer.lang-lt.php -text
phpmailer-php5/language/phpmailer.lang-lv.php -text
phpmailer-php5/language/phpmailer.lang-ms.php -text
phpmailer-php5/language/phpmailer.lang-nb.php -text
phpmailer-php5/language/phpmailer.lang-nl.php -text
phpmailer-php5/language/phpmailer.lang-pl.php -text
phpmailer-php5/language/phpmailer.lang-pt.php -text
phpmailer-php5/language/phpmailer.lang-pt_br.php -text
phpmailer-php5/language/phpmailer.lang-ro.php -text
phpmailer-php5/language/phpmailer.lang-rs.php -text
phpmailer-php5/language/phpmailer.lang-ru.php -text
phpmailer-php5/language/phpmailer.lang-sk.php -text
phpmailer-php5/language/phpmailer.lang-sl.php -text
phpmailer-php5/language/phpmailer.lang-sv.php -text
phpmailer-php5/language/phpmailer.lang-tr.php -text
phpmailer-php5/language/phpmailer.lang-uk.php -text
phpmailer-php5/language/phpmailer.lang-vi.php -text
phpmailer-php5/language/phpmailer.lang-zh.php -text
phpmailer-php5/language/phpmailer.lang-zh_cn.php -text
prive/squelettes/contenu/configurer_facteur.html -text
prive/themes/spip/images/facteur-16.png -text
prive/themes/spip/images/facteur-24.png -text
prive/themes/spip/images/facteur-32.png -text

15
.gitignore vendored

@ -1,15 +0,0 @@
/vendor/
/composer.phar
/composer.lock
/phpcs.xml
/phpstan.neon
/.php_cs.cache
/.php_cs.txt
/.phpunit.cache
/phpunit.xml
/var
!/var/tmp/file.unknown
!/var/tmp/test.zip
!/var/tmp/tar/test.tar
!/var/tmp/tgz/test.tar.gz
/rector.php

462
classes/facteur.php

@ -0,0 +1,462 @@
<?php
/*
* Plugin Facteur 2
* (c) 2009-2011 Collectif SPIP
* Distribue sous licence GPL
*
*/
if (!defined("_ECRIRE_INC_VERSION")) return;
include_spip('inc/charsets');
include_spip('inc/texte');
include_spip('inc/filtres');
if (!class_exists('PHPMailer')) {
include_spip('phpmailer-php5/class.phpmailer');
include_spip('phpmailer-php5/class.smtp');
}
include_spip('facteur_fonctions');
/**
* Wrapper de spip_log pour par PHPMailer
* @param $message
* @param $level
*/
function facteur_log_debug($message,$level){
spip_log("$level: ".trim($message),"facteur"._LOG_DEBUG);
}
class Facteur 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 = '';
/**
* @param $email
* @param $objet
* @param $message_html
* @param $message_texte
* @param array $options
*
*/
public function __construct($email, $objet, $message_html, $message_texte, $options = array()) {
// On récupère toutes les options par défaut depuis le formulaire de config
$defaut = array();
foreach (array(
'adresse_envoi', 'adresse_envoi_email', 'adresse_envoi_nom', 'forcer_from',
'cc', 'bcc',
'smtp', 'smtp_host', 'smtp_port', 'smtp_auth',
'smtp_username', 'smtp_password', 'smtp_secure', 'smtp_sender', 'smtp_tls_allow_self_signed',
'filtre_images', 'filtre_iso_8859',
) as $config) {
$defaut[$config] = isset($GLOBALS['meta']["facteur_$config"]) ? $GLOBALS['meta']["facteur_$config"] : '';
}
// On fusionne les options avec d'éventuelles surcharges lors de l'appel
$options = array_merge($defaut, $options);
// 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 = "facteur_log_debug";
// 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 (
$options['adresse_envoi'] == 'oui'
and $options['adresse_envoi_email']
) {
$this->From = $options['adresse_envoi_email'];
}
else {
$this->From = (isset($GLOBALS['meta']["email_envoi"]) AND $GLOBALS['meta']["email_envoi"]) ?
$GLOBALS['meta']["email_envoi"]
: $GLOBALS['meta']['email_webmaster'];
}
// Si plusieurs emails dans le from, pas de Name !
if (strpos($this->From,",") === false) {
if (
$options['adresse_envoi'] == 'oui'
and $options['adresse_envoi_nom']
) {
$this->FromName = $options['adresse_envoi_nom'];
}
// Par défaut, l'envoyeur est le nom du site
else {
$this->FromName = strip_tags(extraire_multi($GLOBALS['meta']['nom_site']));
}
}
// 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 ($options['forcer_from']=='oui'){
$this->ForceFrom = $this->From;
$this->ForceFromName = $this->FromName;
}
$this->CharSet = "utf-8";
$this->Mailer = 'mail';
$this->Subject = unicode_to_utf_8(charset2unicode($objet,$GLOBALS['meta']['charset']));
//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)) {
spip_log("Erreur AddAddress $adresseMail : ".print_r($this->ErrorInfo, true), 'facteur.'._LOG_ERREUR);
}
}
}
elseif (!$this->AddAddress($email)) {
spip_log("Erreur AddAddress $email : ".print_r($this->ErrorInfo, true), 'facteur.'._LOG_ERREUR);
}
// 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']);
}
}
// Si on envoie avec un SMTP explicite
if (isset($options['smtp']) AND $options['smtp'] == 'oui') {
$this->Mailer = 'smtp';
$this->Host = $options['smtp_host'];
$this->Port = $options['smtp_port'];
// SMTP authentifié
if ($options['smtp_auth'] == 'oui') {
$this->SMTPAuth = true;
$this->Username = $options['smtp_username'];
$this->Password = $options['smtp_password'];
}
else {
$this->SMTPAuth = false;
}
if ($options['smtp_secure'] == 'ssl') {
$this->SMTPSecure = 'ssl';
}
if ($options['smtp_secure'] == 'tls') {
$this->SMTPSecure = 'tls';
}
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;
}
// S'il y a un contenu HTML
if (!empty($message_html)) {
$message_html = unicode_to_utf_8(charset2unicode($message_html, $GLOBALS['meta']['charset']));
$this->Body = $message_html;
$this->IsHTML(true);
if ($options['filtre_images']) {
$this->JoindreImagesHTML();
}
$this->UrlsAbsolues();
}
// S'il y a un contenu texte brut
if (!empty($message_texte)) {
$message_texte = unicode_to_utf_8(charset2unicode($message_texte, $GLOBALS['meta']['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 ($options['filtre_iso_8859']) {
$this->ConvertirUtf8VersIso8859();
}
}
/**
* @param bool $exceptions
*/
public function SetExceptions($exceptions){
$this->exceptions = ($exceptions?true:false);
}
/**
* Transforme du HTML en texte brut, mais proprement
* utilise le filtre facteur_mail_html2text
* @uses facteur_mail_html2text()
*
* @param string $html Le HTML à transformer
* @param bool $advanced Inutilisé
* @return string Retourne un texte brut formaté correctement
*/
public function html2text($html, $advanced = false){
return facteur_mail_html2text($html);
}
/**
* Compat ascendante, obsolete
* @deprecated
*/
public function ConvertirStylesEnligne() {
$this->Body = facteur_convertir_styles_inline($this->Body);
}
/**
* Transformer les urls des liens et des images en url absolues
* sans toucher aux images embarquees de la forme "cid:..."
*/
protected function UrlsAbsolues($base=null){
include_spip('inc/filtres_mini');
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], $base);
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], $base);
if ($abs <> $lien[3])
$this->Body = str_replace($lien[0], $lien[1].$abs.$lien[4], $this->Body);
}
}
}
}
/**
* Embed les images HTML dans l'email
*/
protected function JoindreImagesHTML() {
$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'
);
$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];
if ($src AND strncmp($src,$adresse_site,strlen($adresse_site))==0)
$src = _DIR_RACINE . substr($src,strlen($adresse_site));
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 safe_utf8_decode($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('&#8217;',"'",$text);
}
else {
if ($mode == 'texte_brut') {
$text = str_replace('’',"'",$text);
}
$text = unicode2charset(utf_8_to_unicode($text),'iso-8859-1');
return str_replace('&#8217;',"'",$text);
}
}
/**
* Convertir tout le mail utf en isotruc
*/
protected function ConvertirUtf8VersIso8859() {
$this->CharSet = 'iso-8859-1';
$this->Body = str_ireplace('charset=utf-8', 'charset=iso-8859-1', $this->Body);
$this->Body = $this->safe_utf8_decode($this->Body,'html');
$this->AltBody = $this->safe_utf8_decode($this->AltBody);
$this->Subject = $this->safe_utf8_decode($this->Subject);
$this->FromName = $this->safe_utf8_decode($this->FromName);
}
/**
* Convertir les accents du body en entites html
*/
protected function ConvertirAccents() {
// tableau à compléter au fur et à mesure
$cor = array(
'à' => '&agrave;',
'â' => '&acirc;',
'ä' => '&auml;',
'ç' => '&ccedil;',
'é' => '&eacute;',
'è' => '&egrave;',
'ê' => '&ecirc;',
'ë' => '&euml;',
'î' => '&icirc;',
'ï' => '&iuml;',
'ò' => '&ograve;',
'ô' => '&ocirc;',
'ö' => '&ouml;',
'ù' => '&ugrave;',
'û' => '&ucirc;',
'œ' => '&oelig;',
'€' => '&euro;'
);
$this->Body = strtr($this->Body, $cor);
}
/**
* 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) {
spip_log((is_array($function)?implode('::',$function):$function)."() : ".$exc->getMessage(),'facteur.'._LOG_ERREUR);
$this->exceptions = $exceptions;
if ($this->exceptions) {
throw $exc;
}
return false;
}
if ($this->ErrorInfo){
spip_log((is_array($function)?implode('::',$function):$function)."() : ".$this->ErrorInfo,'facteur.'._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 phpmailerException
*/
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);
}
}

27
composer.json

@ -1,27 +0,0 @@
{
"autoload": {
"psr-4": {
"SPIP\\Facteur\\": "inc/Facteur/"
}
},
"autoload-dev": {
},
"require": {
"php": "^7.4 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"spip/coding-standards": "^1.2",
"phpstan/phpstan": "^1.4",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.1",
"rector/rector": "^0.12.13"
},
"config": {
"platform": {
"php": "7.4.27"
},
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}

0
emails/css.html

0
emails/inc-bas.html

0
emails/inc-haut.html

14
emails/test_email_html.html

@ -4,7 +4,7 @@
<p><:facteur:version_html:></p>
<BOUCLE_art(ARTICLES){id_article}>
<BOUCLE_art(ARTICLES){texte==<img}{0,1}>
[(#TEXTE|image_reduire{550,0})]
<hr />
[(#NOTES|image_reduire{550,0})]
@ -16,20 +16,12 @@
</BOUCLE_art2>
<//B_art>
<BOUCLE_image(DOCUMENTS){extension IN jpg,png,gif}{0,1}{statut==.*}{brise=0}{largeur>300}{par taille}>
<BOUCLE_image(DOCUMENTS){extension IN jpg,png,gif}{0,1}>
[(#MODELE{img}|image_reduire{550,0})]
</BOUCLE_image>
<BOUCLE_pdf(DOCUMENTS){extension=pdf}{0,1}{statut==.*}{brise=0}>
<BOUCLE_pdf(DOCUMENTS){extension=pdf}{0,1}>
[(#MODELE{doc}|image_reduire{550,0})]
</BOUCLE_pdf>
[(#ENV{piece_jointe}|oui)
<div>
<h3><:medias:titre_documents_joints:></h3>
[(#ENV{piece_jointe/chemin}|basename|unique{basename})][ - (#ENV{piece_jointe/nom}|unique{basename})]
</div>
]
</body>
#FILTRE{liens_absolus}
#FILTRE{facteur_email_wrap_to_html}

8
emails/test_email_texte.html

@ -3,16 +3,10 @@
<:facteur:version_texte:>
<BOUCLE_art(ARTICLES){id_article}>
<BOUCLE_art(ARTICLES){texte==<img}{0,1}>
[(#TEXTE|textebrut)]
</BOUCLE_art>
<BOUCLE_art2(ARTICLES){0,1}>
[(#TEXTE|textebrut)]
</BOUCLE_art2>
<//B_art>
[(#ENV{piece_jointe}|oui)
### <:medias:titre_documents_joints:>
[(#ENV{piece_jointe/chemin}|basename|unique{basename})][ - (#ENV{piece_jointe/nom}|unique{basename})]
]

42
erreurs et exceptions.txt

@ -0,0 +1,42 @@
Avril 2012
Yffic
Petit point sur la gestion des erreurs et les exceptions de phpMailer 5. "Parce que c'est pénible de ne pas savoir pourquoi ça ne marche pas"
Constat :
- Les problèmes de connexion smtp ne sont pas affichées dans l'interface privée de SPIP après un test d'envoi via la page de config de Facteur. On a juste le message "Erreur: consultez le fichier log pour plus de détails" dans un cadre rouge.
- Dans formulaires/configurer_facteur.php, facteur_envoyer_mail_test() renvoie true/false. Donc on n'a pas accès aux messages d'erreurs de phpMailer dans l'espace privé.
- La gestion des exceptions via la classe phpmailerException n'est pas activée par défaut dans phpMailer (Cf le constructeur). Elle sert surtout à faire remonter les messages d'erreur.
- Après avoir activé la gestion des exceptions et le mode debug de la classe smtp (qui ne fait que des echo), on peut remarquer que les messages d'erreurs affichés par les exceptions dans phpMailer ne reprennent pas les vraies causes d'erreurs relevées dans la classe smtp. Si par exemple, on n'active pas ssl dans php, le debug "echo" affiche "SMTP -> ERROR: Failed to connect to server: Unable to find the socket transport "ssl" - did you forget to enable it when you configured PHP?", mais l'exception se contente d'un "SMTP Error: Could not connect to SMTP host" dans le fichier log. C'est quand même dommage de ne pas avoir accès au premier message d'erreur.
- Voir aussi :
http://code.google.com/a/apache-extras.org/p/phpmailer/issues/detail?id=50
http://code.google.com/a/apache-extras.org/p/phpmailer/issues/detail?id=5
En attendant une éventuelle amélioration de phpMailer, on peut :
- Upgrader phpMailer 5.2.1. J'ai testé, ca ne change rien au niveau de la gestion des messages d'erreur, mais ça corrige d'autres trucs.
05/04/12 : Un cas foireux avec la version 5.2.1 : Si comme hôte on met un serveur ssl (ssl0.ovh.net), mais qu'on ne coche pas ssl au dessous, lors d'un test d'envoi, la roue Ajax tourne en rond indéfiniment... Pas de retour, aucune trace meme avec de simples echo... Je pense que ca tourne en rond au niveau de la fonction feof de get_lines. Cf les Notes de http://php.net/manual/fr/function.feof.php... Il n'est pas donc pas si urgent d'upgrader...
- Redéfinir dans la classe Facteur, les fonctions Send, AddAttachment, AddReplyTo, AddBCC, AddCC, de la classe PhpMailer de cette façon :
public function Send() {
ob_start();
parent::Send();
$error = ob_get_contents();
ob_end_clean();
if( !empty($error) ) {
spip_log("Erreur Facteur->Send : $error",'facteur.err');
}
}
Avec une constante pour activer ce mode et rajouter au début du constructeur de Facteur :
if (defined('_FACTEUR_DEBUG_SMTP')) {
$this->SMTPDebug = _FACTEUR_DEBUG_SMTP ;
}
Ajouter la ligne qui suit dans mes_options.php permet donc de retrouver les erreurs dans le fichier facteur.err.log.
define('_FACTEUR_DEBUG_SMTP','5'); // Le niveau peut varier de 1 à 5, 5 affichant tout le dialogue lors de la connexion smtp avec le serveur

12
facteur-64.svg

@ -1,12 +0,0 @@
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
<path d="M384.7 342.8H437a30.2 30.2 0 0030.2-30.3v-3.7a30.2 30.2 0 00-30.2-30.3h-52.3z" fill="#f3e3e3"/>
<path d="M306 512H206a97.2 97.2 0 01-97.2-97.2v-185a97.2 97.2 0 0197.2-97.2h100a97.2 97.2 0 0197.2 97.2v185A97.2 97.2 0 01306 512z" fill="#f3e3e3"/>
<path d="M127.3 342.8H75a30.2 30.2 0 01-30.2-30.3v-3.7A30.2 30.2 0 0175 278.5h52.3v64.3z" fill="#f3e3e3"/>
<path d="M363.7 266.3H148.2a53 53 0 01-53-53v-21.4h321.6v21.4a53 53 0 01-53 53z" fill="#E895B7"/>
<path d="M304 0h-96A112.8 112.8 0 0095.2 112.8v79h321.6v-79C416.8 50.5 366.3 0 304 0z" fill="#F43737"/>
<g fill="#555">
<path d="M424.6 262.2h-15v-8c8-10.7 12.7-24 12.7-38.4V121C422.3 54.3 368 0 301.2 0h-90.4A121.3 121.3 0 0089.7 121.1v94.7c0 14.4 4.7 27.8 12.7 38.5v8h-15a45.3 45.3 0 000 90.4h15v47c0 62 50.3 112.3 112.2 112.3h82.8c61.9 0 112.2-50.3 112.2-112.2v-47.1h15a45.3 45.3 0 000-90.5zm-322.2 60.5h-15a15.2 15.2 0 010-30.5h15v30.5zm277.2 77a82.3 82.3 0 01-82.2 82.3h-82.8a82.3 82.3 0 01-82.2-82.2v-123c7 2.5 14.4 3.9 22.1 3.9h203c7.7 0 15.2-1.4 22.1-4zm12.7-184a35 35 0 01-34.9 35H154.5a35 35 0 01-34.8-35v-5h272.6zm0-35H119.7V121A91.3 91.3 0 01210.8 30h90.4a91.3 91.3 0 0191.1 91.1v59.5zm32.3 142h-15v-30.5h15a15.2 15.2 0 010 30.5z"/>
<path d="M306.3 397a15 15 0 00-20.3 6.3 33.8 33.8 0 01-60 0 15 15 0 00-26.6 14 63.7 63.7 0 00113.2 0 15 15 0 00-6.3-20.3z"/>
<path fill="#fff" d="M 286.135 143.566 C 280.466 120.887 256.872 123.265 253.123 107.993 C 250.471 97.202 257.695 88.972 268.486 86.229 C 275.753 84.42 283.425 86.777 288.422 92.356 L 288.513 92.447 L 288.97 92.996 L 289.245 93.361 L 289.519 93.819 L 289.61 93.91 C 290.616 95.19 291.165 96.105 291.988 95.922 C 292.72 95.739 293.085 94.093 293.268 92.904 C 297.087 62.926 269.531 38.506 240.229 45.9 C 217.244 51.788 203.265 75.06 208.862 98.117 C 216.452 129.117 245.624 134.33 261.445 142.194 C 270.371 146.374 271.425 158.648 263.343 164.288 C 262.023 165.209 260.542 165.873 258.975 166.245 L 258.793 166.245 L 258.152 166.428 C 256.781 166.794 256.415 166.611 256.415 167.16 C 256.415 167.525 257.329 167.983 257.878 168.257 C 272.892 174.319 288.838 161.854 286.58 145.821 C 286.473 145.062 286.325 144.31 286.135 143.566 Z" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

98
facteur_administrations.php

@ -1,10 +1,9 @@
<?php
/**
* Plugin Facteur 4
* (c) 2009-2019 Collectif SPIP
/*
* Plugin Facteur 2
* (c) 2009-2011 Collectif SPIP
* Distribue sous licence GPL
*
* @package SPIP\Facteur\Administrations
*/
if (!defined('_ECRIRE_INC_VERSION')) {
@ -14,73 +13,35 @@ if (!defined('_ECRIRE_INC_VERSION')) {
function facteur_upgrade($nom_meta_base_version, $version_cible) {
$maj = array();
include_spip('inc/config');
$maj['create'] = array(
array('ecrire_config','facteur/mailer', 'mail'),
array('ecrire_config','facteur/smtp_auth', 'non'),
array('ecrire_config','facteur/smtp_secure', 'non'),
array('ecrire_config','facteur/smtp_sender', ''),
array('ecrire_config','facteur/filtre_images', 0),
array('ecrire_config','facteur/filtre_css', 0),
array('ecrire_config','facteur/filtre_iso_8859', 0),
array('ecrire_config','facteur/adresse_envoi', 'non'),
array('ecrire_meta','facteur_smtp', 'non'),
array('ecrire_meta','facteur_smtp_auth', 'non'),
array('ecrire_meta','facteur_smtp_secure', 'non'),
array('ecrire_meta','facteur_smtp_sender', ''),
array('ecrire_meta','facteur_filtre_images', 1),
array('ecrire_meta','facteur_filtre_css', 0),
array('ecrire_meta','facteur_filtre_iso_8859', 0),
array('ecrire_meta','facteur_adresse_envoi', 'non'),
array('facteur_vieil_upgrade'),
);
$maj['2.0.0'] = array(
array('facteur_migre_metas_to_config'),
);
include_spip('base/upgrade');
maj_plugin($nom_meta_base_version, $version_cible, $maj);
}
/**
* Migrer les N metas en une seule meta facteur que l'on accede via les fonctions lire_config/ecrire_config
*/
function facteur_migre_metas_to_config(){
include_spip('inc/config');
// ne pas migrer 2 fois
if (!isset($GLOBALS['meta']["facteur"]) or !@unserialize($GLOBALS['meta']["facteur"])) {
foreach (array(
'adresse_envoi', 'adresse_envoi_email', 'adresse_envoi_nom', 'forcer_from',
'cc', 'bcc',
'mailer',
'smtp_host', 'smtp_port', 'smtp_auth',
'smtp_username', 'smtp_password', 'smtp_secure', 'smtp_sender', 'smtp_tls_allow_self_signed',
'filtre_images', 'filtre_iso_8859',
) as $config) {
if (isset($GLOBALS['meta']["facteur_$config"])) {
ecrire_config("facteur/$config", $GLOBALS['meta']["facteur_$config"]);
effacer_meta("facteur_$config");
}
}
}
if (isset($GLOBALS['meta']["facteur_smtp"])) {
if (!lire_config("facteur/mailer",'')) {
ecrire_config("facteur/mailer", $GLOBALS['meta']["facteur_smtp"] === 'oui' ? 'smtp' : 'mail');
}
effacer_meta('facteur_smtp');
}
}
/**
* migration depuis tres ancienne version du plugin spip_notifications, a la main
*/
function facteur_vieil_upgrade() {
// migration depuis tres ancienne version, a la main
if (isset($GLOBALS['meta']['spip_notifications_version'])) {
ecrire_config('facteur/mailer', ($GLOBALS['meta']['spip_notifications_smtp'] === 'oui') ? 'smtp' : 'mail');
ecrire_config('facteur/smtp_auth', $GLOBALS['meta']['spip_notifications_smtp_auth']);
ecrire_config('facteur/smtp_secure', $GLOBALS['meta']['spip_notifications_smtp_secure']);
ecrire_config('facteur/smtp_sender', $GLOBALS['meta']['spip_notifications_smtp_sender']);
ecrire_config('facteur/filtre_images', $GLOBALS['meta']['spip_notifications_filtre_images']);
ecrire_config('facteur/filtre_css', $GLOBALS['meta']['spip_notifications_filtre_css']);
ecrire_config('facteur/filtre_iso_8859', $GLOBALS['meta']['spip_notifications_filtre_iso_8859']);
ecrire_config('facteur/adresse_envoi', $GLOBALS['meta']['spip_notifications_adresse_envoi']);
ecrire_config('facteur/adresse_envoi_nom', $GLOBALS['meta']['spip_notifications_adresse_envoi_nom']);
ecrire_config('facteur/adresse_envoi_email', $GLOBALS['meta']['spip_notifications_adresse_envoi_email']);
ecrire_meta('facteur_smtp', $GLOBALS['meta']['spip_notifications_smtp']);
ecrire_meta('facteur_smtp_auth', $GLOBALS['meta']['spip_notifications_smtp_auth']);
ecrire_meta('facteur_smtp_secure', $GLOBALS['meta']['spip_notifications_smtp_secure']);
ecrire_meta('facteur_smtp_sender', $GLOBALS['meta']['spip_notifications_smtp_sender']);
ecrire_meta('facteur_filtre_images', $GLOBALS['meta']['spip_notifications_filtre_images']);
ecrire_meta('facteur_filtre_css', $GLOBALS['meta']['spip_notifications_filtre_css']);
ecrire_meta('facteur_filtre_iso_8859', $GLOBALS['meta']['spip_notifications_filtre_iso_8859']);
ecrire_meta('facteur_adresse_envoi', $GLOBALS['meta']['spip_notifications_adresse_envoi']);
ecrire_meta('facteur_adresse_envoi_nom', $GLOBALS['meta']['spip_notifications_adresse_envoi_nom']);
ecrire_meta('facteur_adresse_envoi_email', $GLOBALS['meta']['spip_notifications_adresse_envoi_email']);
// supprimer l'ancien nommage
effacer_meta('spip_notifications_smtp');
effacer_meta('spip_notifications_smtp_auth');
@ -101,6 +62,19 @@ function facteur_vieil_upgrade() {
function facteur_vider_tables($nom_meta_base_version) {
effacer_meta('facteur');
// cfg la dessus, ca serait mieux !
effacer_meta('facteur_version');
effacer_meta('facteur_smtp');
effacer_meta('facteur_smtp_auth');
effacer_meta('facteur_smtp_secure');
effacer_meta('facteur_smtp_sender');
effacer_meta('facteur_filtre_images');
effacer_meta('facteur_filtre_css');
effacer_meta('facteur_filtre_iso_8859');
effacer_meta('facteur_adresse_envoi');
effacer_meta('facteur_adresse_envoi_nom');
effacer_meta('facteur_adresse_envoi_email');
effacer_meta('facteur_cc');
effacer_meta('facteur_bcc');
effacer_meta($nom_meta_base_version);
}

441
facteur_fonctions.php

@ -1,128 +1,407 @@
<?php
/**
* Plugin Facteur 4
* (c) 2009-2019 Collectif SPIP
/*
* Plugin Facteur 2
* (c) 2009-2011 Collectif SPIP
* Distribue sous licence GPL
*
* @package SPIP\Facteur\Fonctions
*/
if (!defined("_ECRIRE_INC_VERSION")) return;
function facteur_affiche_password_masque($pass){
$l = strlen($pass);
if ($l<=8){
return str_pad('',$l,'*');
}
$e = intval(ceil($l/10));
$mid = str_pad('',$l-2*$e,'*');
if (strlen($mid)>8){
$mid = '***...***';
}
return substr($pass,0,$e) . $mid . substr($pass,-$e);
}
/**
* Afficher partiellement un mot de passe que l'on ne veut pas rendre lisible par un champ hidden
* @param string $passe
* @param bool $afficher_partiellement
* @param int|null $portion_pourcent
* Transformer un mail texte ou HTML simplifie en mail HTML complet avec le wrapper emails/texte.html
* Si le mail est un mail texte :
* la premiere ligne est le sujet
* le reste est le corps du mail
*
* Si le mail est un mail HTML simplifie :
* le sujet est entre <title></title>
* le corps est entre <body></body>
* une eventuelle intro peut etre fournie entre <intro></intro>
*
* @param string $texte_ou_html
* @return string
*/
function facteur_affiche_password_masque($passe, $afficher_partiellement = false, $portion_pourcent = null) {
if (function_exists('spip_affiche_mot_de_passe_masque')) {
return spip_affiche_mot_de_passe_masque($passe, $afficher_partiellement, $portion_pourcent);
}
$l = strlen($passe);
function facteur_email_wrap_to_html($texte_ou_html){
$texte_ou_html = trim($texte_ou_html);
// attention : si pas de contenu on renvoi du vide aussi (mail vide = mail vide)
if (!strlen(trim($texte_ou_html))) {
return $texte_ou_html;
}
$contexte = array('sujet' => '', 'texte' => '', 'intro' => '');
if ($l<=8 or !$afficher_partiellement){
if (!$l) {
return ''; // montrer qu'il y a pas de mot de passe si il y en a pas
// tester si le mail est en html (simplifie)
if (substr($texte_ou_html, 0, 1) == '<'
and substr($texte_ou_html,-1,1) == '>'
and stripos($texte_ou_html, '</body>') !== false) {
// dans ce cas on ruse un peu : extraire le sujet du title
$sujet = '';
if (preg_match(",<title>(.*)</title>,Uims", $texte_ou_html, $m)) {
$contexte['sujet'] = $m[1];
$texte_ou_html = preg_replace(",<title>(.*)</title>,Uims", '', $texte_ou_html, 1);
$texte_ou_html = trim($texte_ou_html);
}
if (preg_match(",<intro>(.*)</intro>,Uims", $texte_ou_html, $m)){
$contexte['intro'] = $m[1];
$texte_ou_html = preg_replace(",<intro>(.*)</intro>,Uims", '', $texte_ou_html, 1);
$texte_ou_html = trim($texte_ou_html);
}
return str_pad('',$afficher_partiellement ? $l : 16,'*');
$contexte['html'] = preg_replace(",</?body>,ims", '', $texte_ou_html);
}
else {
// la premiere ligne est toujours le sujet
$texte_ou_html = explode("\n", $texte_ou_html);
$contexte['sujet'] = trim(array_shift($texte_ou_html));
$contexte['texte'] = trim(implode("\n", $texte_ou_html));
}
// attention : si pas de contenu on renvoi du vide aussi (mail vide = mail vide)
if (!strlen(trim(implode('', $contexte)))) {
return '';
}
return recuperer_fond('emails/texte', $contexte);
}
/*
Written by Eric Dols - edols@auditavenue.com
You may freely use or modify this, provided
you leave credits to the original coder.
Feedback about (un)successfull uses, bugs and improvements done
are much appreciated, but don't expect actual support.
PURPOSE OF THIS FUNCTION
It is designed to process html emails relying
on a css stylesheet placed in the <head> for layout in
order to enhance compatibility with email clients,
including webmail services.
Provided you use minimal css, you can keep styling separate
from the content in your email template, and let this function
"inject" those styles inline in your email html tags on-the-fly,
just before sending.
Technically, it grabs the style declarations found in the
<head> section and inserts each declaration inline,
inside the corresponding html tags in the email message.
Supports both HTML and XHTML markup seamlessly. Thus
tolerant to email message writers using non-xhtml tag,
even when template is xhtml compliant (e.g. they would
add <img ...> instead of a xhtml compliant <img ... />).
NEW 10 dec. 2003:
- code revised, including a few regexp bugs fixed.
- multiple class for a tag are now allowed <p class="firstclass secondclass">
- all unsupported css styles are now moved to the body section (not just a:hover etc...)
USE
Add this function to a function library include, like "inline.inc"
and include it near the beginning of your php page:
require ("inline.inc");
if (is_null($portion_pourcent)) {
if (!defined('_SPIP_AFFICHE_MOT_DE_PASSE_MASQUE_PERCENT')) {
define('_SPIP_AFFICHE_MOT_DE_PASSE_MASQUE_PERCENT', 20); // 20%
load the html source of message into a variable
like $html_source and process it using:
$html_source = sheet2inline($html_source)
STYLE DEFINITIONS SUPPORTED
TAG { ... }
TAG1, TAG2, ... { ... }
TAG.class { ... }
.class { ...)
TAG:pseudo { ... }
CSS definitions may be freely formatted (spaces, tabs, linefeeds...),
they are converted to oneliners before inserting them inline in the html tags.
.class definitions are processed AFTER tag definitions,
thus appended inline after any existing tag styling to
preserve the normal css priority behavior.
Existing style="..." attributes in tags are NOT stripped. However they MUST
be with double quotes. If not, an addtional style="..." attribute will be added
KNOWN LIMITATIONS
- style info should be placed in <head> section. I believe
it shouldnt be too hard to modify to point to an external
stylesheet instead.
- no support (yet?):
* chains like P UL LI { .... } or P UL LI.class { .... }
* #divname p { ... } and <tag id="...">
* a:hover, a:visited {...} multiple class:pseudo
They require a significantly more complicated processing likely
based on stylesheet and document trees parsing.
Many email clients don't handle more than what is supported
by this script anyway.
- pseudo-classes like a:hover {...} can't be inserted inline
in the html tags: they are moved to a <style> declaration in
the <body> instead. This is a limitation from html, not this script.
- It is still up to you to check if target email clients render
your css styled templates correctly, especially webmail services
like Hotmail, in which the email becomes a sub-part of an html page,
with styles already in place.
*/
function facteur_convertir_styles_inline($body){
// variables to be accessed in the callback sub-function too
global $styledefinition, $styletag, $styleclass;
// Let's first load the stylesheet information in a $styles array using a regexp
preg_match_all ( "/^[ \t]*([.]?)([\w, #]+)([.:])?(\S*)\s+{([^}]+)}/mi", $body , $styles);
/*
$styles[1] = . or '' => .class or tag (empty)
$styles[2] = name of class or tag(s)
$styles[3] = : . or '' => followed by pseudo-element, class separator or nothing (empty)
$styles[4] = name of pseudo-element after a tag, if any
$styles[5] = the style definition itself, i.e. what's between the { }
*/
// Now loop through the styles found and act accordingly;
// process TAG {...} & TAG1, TAG2,... {...} definitions only first by order of appearance
foreach ($styles[1] as $i => $type) {
if ($type=="" && $styles[3][$i]=="") {
$styledefinition = trim($styles[5][$i]);
$styletag = preg_replace("/ *, */", "|", trim($styles[2][$i])); //echo $styletag."<br />";
$styleclass = "";
// process TAG {...} and TAG1, TAG2 {...} but not TAG1 TAG2 {...} or #divname styles
if (!preg_match("/ /", $styletag) && !preg_match("/#/", $styletag)) {
$pattern = "!<(".$styletag.")([^>]*(?= /)|[^>]*)( /)?>!mi";
$body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
$styles[6][$i]=1; // mark as injected inline
}
}
$portion_pourcent = _SPIP_AFFICHE_MOT_DE_PASSE_MASQUE_PERCENT;
}
if ($portion_pourcent >= 100) {
return $passe;
// append additional .CLASS {...} and TAG.CLASS {...} styling by order of appearance
// important to do so after TAG {...} definitions, so that class attributes override TAG styles when needed
foreach ($styles[1] as $i => $type) {
if ($type!="." && $styles[3][$i]=="." ) { // class definition for a specific tag
$styledefinition = trim($styles[5][$i]);
$styletag = trim($styles[2][$i]);
$styleclass = trim($styles[4][$i]);
$pattern = "!<(".$styletag.")([^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*(?= /)|[^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*)( />)?>!mi";
$body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
$styles[6][$i]=1; // mark as injected inline
}
elseif ($type=="." && $styles[3][$i]=="" ) { // general class definition for any tag
$styledefinition = trim($styles[5][$i]);
$styletag = "";
$styleclass = trim($styles[2][$i]);
$pattern = "!<(\w+)([^>]* class\=['\"]".$styleclass."['\"][^>]*(?= /)|[^>]* class\=['\"]".$styleclass."['\"][^>]*)( />)?>!mi";
$body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
$styles[6][$i]=1; // mark as injected inline
}
}
$e = intval(ceil($l * $portion_pourcent / 100 / 2));
$e = max($e, 0);
$mid = str_pad('',$l-2*$e,'*');
if ($e>0 and strlen($mid)>8){
$mid = '***...***';
/* move all style declarations that weren't injected from <head> to a <body> <style> section,
including but not limited to:
- pseudo-classes like a:hover {...} as they can't be set inline
- declaration chains like UL LI {...}
- #divname {...}. These are not supported by email clients like Mac/Entourage anyway, it seems. */
foreach ($styles[1] as $i => $type) {
if ($styles[6][$i]=="") {
// add a <style type="text/css"> section after <body> if there's isn't one yet
if (preg_match ("!<body[^>]*>\s*<style!mi", $body)==0) {
$body = preg_replace ("/(<body[^>]*>)/i", "\n\$1\n".'<style type="text/css">'."\n<!--\n-->\n</style>\n", $body);
}
// append a copy of the pseudo-element declaration to that body style section
$styledefinition = trim($styles[5][$i]);
$styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition ); // convert style definition to a one-liner (optional)
$declaration = $styles[1][$i].trim($styles[2][$i]).$styles[3][$i].trim($styles[4][$i])." { ".$styledefinition." }";
$body = preg_replace ("!(<body[^>]*>\s*<style[^>]*>\s*<\!\-\-[^>]*)"."(\s*\-\->\s*</style>)!si", "\$1".$declaration."\n\$2", $body);
$styles[6][$i]= 2; // mark as moved to <style> section in <body>
}
}
return substr($passe,0,$e) . $mid . ($e > 0 ? substr($passe,-$e) : '');
// remove stylesheet declaration(s) from <head> section (comment following line out if not wanted)
//$body = preg_replace ("!(<head>.*)<style type.*</style>(.*</head>)!si", "\$1\$2" , $body);
// check what styles have been injected
# print_r($styles);
return $body;
}
/**
* Un filtre pour transformer les retour ligne texte en br si besoin (si pas autobr actif)
* facteur_addstyle
* @author Eric Dols
*
* @param string $texte
* @param $matches
* @return string
*/
function facteur_nl2br_si_pas_autobr($texte){
if (_AUTOBR) return $texte;
include_spip("inc/filtres");
$texte = post_autobr($texte);
return $texte;
}
function facteur_addstyle($matches) {
// $matches[1]=tag, $matches[2]=tag attributes (if any), $matches[3]=xhtml closing (if any)
// variables values set in calling function
global $styledefinition, $styletag, $styleclass;
/**
* @see inc_facteur_mail_wrap_to_html_dist
*
* @param string $texte_ou_html
* @return string
*/
function facteur_email_wrap_to_html($texte_ou_html){
// convert the style definition to a one-liner
$styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition );
// convert all double-quotes to single-quotes
$styledefinition = preg_replace ('/"/','\'', $styledefinition );
$facteur_mail_wrap_to_html = charger_fonction('facteur_mail_wrap_to_html', 'inc');
return $facteur_mail_wrap_to_html($texte_ou_html);
if (preg_match ("/style\=/i", $matches[2])) {
// add styles to existing style attribute if any already in the tag
$pattern = "!(.* style\=)[\"]([^\"]*)[\"](.*)!mi";
$replacement = "\$1".'"'."\$2 ".$styledefinition.'"'."\$3";
$attributes = preg_replace ($pattern, $replacement , $matches[2]);
} else {
// otherwise add new style attribute to tag (none was present)
$attributes = $matches[2].' style="'.$styledefinition.'"';
}
if ($styleclass!="") {
// if we were injecting a class style, remove the now useless class attribute from the html tag
// Single class in tag case (class="classname"): remove class attribute altogether
$pattern = "!(.*) class\=['\"]".$styleclass."['\"](.*)!mi";
$replacement = "\$1\$2";
$attributes = preg_replace ( $pattern, $replacement, $attributes);
// Multiple classes in tag case (class="classname anotherclass..."): remove class name from class attribute.
// classes are injected inline and removed by order of appearance in <head> stylesheet
// exact same behavior as where last declared class attributes in <style> take over (IE6 tested only)
$pattern = "!(.* class\=['\"][^\"]*)(".$styleclass." | ".$styleclass.")([^\"]*['\"].*)!mi";
$replacement = "\$1\$3";
$attributes = preg_replace ( $pattern, $replacement, $attributes);
}
return "<".$matches[1].$attributes.$matches[3].">";
}
/**
* voir inc/facteur_convertir_styles_inline
* Un filtre pour transformer les retour ligne texte en br si besoin (si pas autobr actif)
*
* @param string $body
* @param string $texte
* @return string
*/
function facteur_convertir_styles_inline($body){
$facteur_convertir_styles_inline = charger_fonction('facteur_convertir_styles_inline', 'inc');
return $facteur_convertir_styles_inline($body);
function facteur_nl2br_si_pas_autobr($texte){
if (_AUTOBR) return $texte;
include_spip("inc/filtres");
$texte = post_autobr($texte);
return $texte;
}
/**
* voir inc/facteur_mail_html2text
* Transformer un mail HTML en mail Texte proprement :
* - les tableaux de mise en page sont utilis<EFBFBD>s pour structurer le mail texte
* - le reste du HTML est markdownifie car c'est un format texte lisible et conventionnel
*
* @param string $html
* @return string
*/
function facteur_mail_html2text($html){
// nettoyer les balises de mise en page html
$html = preg_replace(",</(td|th)>,Uims","<br/>",$html);
$html = preg_replace(",</(table)>,Uims","@@@hr@@@",$html);
$html = preg_replace(",</?(html|body|table|td|th|tbody|thead|center|article|section|span)[^>]*>,Uims","\n\n",$html);
$facteur_mail_html2text = charger_fonction('facteur_mail_html2text', 'inc');
return $facteur_mail_html2text($html);
}
// commentaires html et conditionnels
$html = preg_replace(",<!--.*-->,Uims","\n",$html);
$html = preg_replace(",<!\[.*\]>,Uims","\n",$html);
$html = preg_replace(",<(/?)(div|tr|caption)([^>]*>),Uims","<\\1p>",$html);
$html = preg_replace(",(<p>\s*)+,ims","<p>",$html);
$html = preg_replace(",<br/?>\s*</p>,ims","</p>",$html);
$html = preg_replace(",</p>\s*<br/?>,ims","</p>",$html);
$html = preg_replace(",(</p>\s*(@@@hr@@@)?\s*)+,ims","</p>\\2",$html);
$html = preg_replace(",(<p>\s*</p>),ims","",$html);
/**
* Insertion dans le pipeline formulaire_fond (SPIP)
*
* On indique dans le formulaire de configuration de l'identité du site
* que facteur surchargera l'email configuré ici pour envoyer les emails
*
* @param array $flux
* Le contexte du pipeline
* @return array $flux
* Le contexte du pipeline modifé
*/
function facteur_formulaire_fond($flux) {
if ($flux['args']['form'] == 'configurer_identite'
and include_spip('inc/config')
and lire_config('facteur/adresse_envoi') === 'oui'
and strlen($email = lire_config('facteur/adresse_envoi_email', '')) ) {
$url = generer_url_ecrire('configurer_facteur');
$ajout = '<p class="notice" style="margin-top:0">'._T('facteur:message_identite_email', array('url' => $url, 'email' => $email)).'</p>';
if (preg_match(",<(div|li) [^>]*class=[\"']editer editer_email_webmaster.*>,Uims", $flux['data'], $match)) {
$p = strpos($flux['data'], (string) $match[0]);
$p = strpos($flux['data'], "<input", $p);
$p = strpos($flux['data'], "</".$match[1], $p);
$flux['data'] = substr_replace($flux['data'], $ajout, $p, 0);
// succession @@@hr@@@<hr> et <hr>@@@hr@@@
$html = preg_replace(",@@@hr@@@\s*(<[^>]*>\s*)?<hr[^>]*>,ims","@@@hr@@@\n",$html);
$html = preg_replace(",<hr[^>]*>\s*(<[^>]*>\s*)?@@@hr@@@,ims","\n@@@hr@@@",$html);
$html = preg_replace(",<textarea[^>]*spip_cadre[^>]*>(.*)</textarea>,Uims","<code>\n\\1\n</code>",$html);
// vider le contenu de qqunes :
$html = preg_replace(",<head[^>]*>.*</head>,Uims","\n",$html);
// Liens :
// Nettoyage des liens des notes de bas de page
$html = preg_replace("@<a href=\"#n(b|h)[0-9]+-[0-9]+\" name=\"n(b|h)[0-9]+-[0-9]+\" class=\"spip_note\">([0-9]+)</a>@", "\\3", $html);
// Supprimer tous les liens internes
$html = preg_replace("/\<a href=['\"]#(.*?)['\"][^>]*>(.*?)<\/a>/ims","\\2", $html);
// Remplace tous les liens
preg_match_all("/\<a href=['\"](.*?)['\"][^>]*>(.*?)<\/a>/ims", $html,$matches,PREG_SET_ORDER);
$prelinks = $postlinks = array();
if (!function_exists('url_absolue'))
include_spip('inc/filtres');
foreach ($matches as $k => $match){
$link = "@@@link$k@@@";
$url = str_replace("&amp;","&",$match[1]);
if ($match[2]==$match[1] OR $match[2]==$url){
// si le texte est l'url :
$prelinks[$match[0]] = "$link";
}
else {
// texte + url
$prelinks[$match[0]] = $match[2] . " ($link)";
}
// passer l'url en absolu dans le texte sinon elle n'est pas clicable ni utilisable
$postlinks[$link] = url_absolue($url);
}
return $flux;
$html = str_replace(array_keys($prelinks), array_values($prelinks),$html);
// les images par leur alt ?
// au moins les puces
$html = preg_replace(',<img\s[^>]*alt="-"[^>]*>,Uims','-',$html);
// les autres
$html = preg_replace(',<img\s[^>]*alt=[\'"]([^\'"]*)[\'"][^>]*>,Uims',"\\1",$html);
// on vire celles sans alt
$html = preg_replace(",</?(img)[^>]*>,Uims","\n",$html);
// espaces
$html = str_replace("&nbsp;"," ",$html);
$html = preg_replace(",<p>\s+,ims","<p>",$html);
#return $html;
include_spip("lib/markdownify/markdownify");
$parser = new Markdownify('inline',false,false);
$texte = $parser->parseString($html);
$texte = str_replace(array_keys($postlinks), array_values($postlinks),$texte);
// trim et sauts de ligne en trop ou pas assez
$texte = trim($texte);
$texte = str_replace("<br />\n","\n",$texte);
$texte = preg_replace(",(@@@hr@@@\s*)+\Z,ims","",$texte);
$texte = preg_replace(",(@@@hr@@@\s*\n)+,ims","\n\n\n".str_pad("-",75,"-")."\n\n\n",$texte);
$texte = preg_replace(",(\n#+\s),ims","\n\n\\1",$texte);
$texte = preg_replace(",(\n\s*)(\n\s*)+(\n)+,ims","\n\n\n",$texte);
// <p> et </p> restants
$texte = str_replace(array("<p>","</p>"),array("",""),$texte);
// entites restantes ? (dans du code...)
include_spip('inc/charsets');
$texte = unicode2charset($texte);
$texte = str_replace(array('&#039;', '&#034;'),array("'",'"'), $texte);
// Faire des lignes de 75 caracteres maximum
return trim(wordwrap($texte));
}

6
facteur_ieconfig_metas.php

@ -1,7 +1,7 @@
<?php
/**
* Plugin Facteur 4
* (c) 2009-2019 Collectif SPIP
* Plugin Facteur 2
* (c) 2009-2011 Collectif SPIP
* Distribue sous licence GPL
*
*/
@ -13,6 +13,6 @@ if (!defined('_ECRIRE_INC_VERSION')) {
function facteur_ieconfig_metas($table) {
$table['facteur']['titre'] = _T('facteur:configuration_facteur');
$table['facteur']['icone'] = 'facteur-16.png';
$table['facteur']['metas_brutes'] = 'facteur_adresse_envoi,facteur_adresse_envoi_nom,facteur_adresse_envoi_email,facteur_mailer,facteur_smtp_host,facteur_smtp_port,facteur_smtp_auth,facteur_smtp_username,facteur_smtp_password,facteur_smtp_secure,facteur_smtp_sender,facteur_filtre_images,facteur_filtre_css,facteur_filtre_iso_8859';
$table['facteur']['metas_brutes'] = 'facteur_adresse_envoi,facteur_adresse_envoi_nom,facteur_adresse_envoi_email,facteur_smtp,facteur_smtp_host,facteur_smtp_port,facteur_smtp_auth,facteur_smtp_username,facteur_smtp_password,facteur_smtp_secure,facteur_smtp_sender,facteur_filtre_images,facteur_filtre_css,facteur_filtre_iso_8859';
return $table;
}

33
facteur_pipelines.php

@ -0,0 +1,33 @@
<?php
/**
* Plugin Facteur
* (c) 2009-2013 Collectif SPIP
* Distribue sous licence GPL
*
* @package SPIP\Facteur\Pipelines
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Insertion dans le pipeline recuperer_fond (SPIP)
*
* On indique dans le formulaire de configuration de l'identité du site
* que facteur surchargera l'email configuré ici pour envoyer les emails
*
* @param array $flux
* Le contexte du pipeline
* @return array $flux
* Le contexte du pipeline modifé
*/
function facteur_formulaire_fond($flux) {
if (($flux['args']['form'] == 'configurer_identite')
&& (isset($GLOBALS['meta']['facteur_adresse_envoi']) && $GLOBALS['meta']['facteur_adresse_envoi'] == 'oui')
&& (isset($GLOBALS['meta']['facteur_adresse_envoi_email']) && strlen($GLOBALS['meta']['facteur_adresse_envoi_email']) > 0)) {
$ajout = '<p class="notice">'._T('facteur:message_identite_email').'</p>';
$flux['data'] = preg_replace(",(<li [^>]*class=[\"']editer editer_email_webmaster.*>)(.*<label),Uims", "\\1".$ajout."\\2", $flux['data'], 1);
}
return $flux;
}

336
formulaires/configurer_facteur.html

@ -1,141 +1,231 @@
<div class="formulaire_spip formulaire_configurer formulaire_#FORM">
<h3 class="titrem"><:facteur:titre_configurer_facteur:></h3>
[<div class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</div>]
[<div class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</div>]
[<div class="notice">(#ENV*{_message_warning})</div>]
[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
[(#ENV{tester,''}|et{#ENV*{message_erreur}|non})
<iframe style='width:95%;height:500px;margin:10px;' src='#URL_PAGE{emails/test_email_html,var_mode=calcul}'></iframe>
]
<form method="post" action="#ENV{action}"><div>
#ACTION_FORMULAIRE{#ENV{action}}
<fieldset>
<legend><:facteur:configuration_adresse_envoi:></legend>
<div class="editer-groupe">
<div class="editer pleine_largeur editer_adresse_envoi [ (#ENV**{erreurs}|table_valeur{adresse_envoi}|oui)erreur]">
[<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{adresse_envoi})</span>]
<div class="choix">
<input type="radio" name="adresse_envoi" class="radio" value="non" id="adresse_envoi_non"[(#ENV{adresse_envoi,'non'}|=={non}|oui)checked="checked"]/>
<label for="adresse_envoi_non"><:facteur:utiliser_reglages_site{from=#ENV{_from_defaut}}:></label>
<div class="suite editer-groupe"[(#ENV{adresse_envoi,'non'}|=={non}|non)style='display:none;']>
<div class="editer editer_from_defaut_nom">
<label for="from_defaut_nom"><:facteur:facteur_adresse_envoi_nom:></label>
<input type="text" disabled="disabled" class="text" value="#ENV**{_from_defaut_nom}" id="from_defaut_nom" />
<ul class="editer-groupe">
<li class="fieldset">
<fieldset>
<legend><:facteur:configuration_adresse_envoi:></legend>
<ul class="editer-groupe">
<li class="editer editer_facteur_adresse_envoi [ (#ENV**{erreurs}|table_valeur{facteur_adresse_envoi}|oui)erreur]">
[<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_adresse_envoi})</span>]
<div class="choix">
<input type="radio" name="facteur_adresse_envoi" class="radio" value="non" id="facteur_adresse_envoi_non"[(#ENV{facteur_adresse_envoi,'non'}|=={non}|oui)checked="checked"]/>
<label for="facteur_adresse_envoi_non"><:facteur:utiliser_reglages_site{from=#ENV{_from_defaut}}:></label>
</div>
<div class="editer editer_from_defaut_email">
<label for="from_defaut_email"><:facteur:facteur_adresse_envoi_email:></label>
<input type="text" disabled="disabled" class="text" value="#ENV**{_from_defaut_email}" id="from_defaut_email" />
<div class="choix">
<input type="radio" name="facteur_adresse_envoi" class="radio" value="oui" id="facteur_adresse_envoi_oui"[(#ENV{facteur_adresse_envoi,'non'}|=={oui}|oui)checked="checked"]/>
<label for="facteur_adresse_envoi_oui"><:facteur:personnaliser:></label>
</div>
</div>
</div>
<div class="choix">
<input type="radio" name="adresse_envoi" class="radio" value="oui" id="adresse_envoi_oui"[(#ENV{adresse_envoi,'non'}|=={oui}|oui)checked="checked"]/>
<label for="adresse_envoi_oui"><:facteur:personnaliser:></label>