Compare commits

...

20 Commits
master ... v1

Author SHA1 Message Date
Maïeul Rouquette 0eb7c0bec0 chargé les v php 5 pour php 5 et plus 5 years ago
spip.franck@lien-d-amis.net 9eb570e019 Contrib est en https, donc j'ajoute le "s", plus divers broutilles 6 years ago
real3t@gmail.com 376d4c20b7 Éviter cette erreur : Strict standards: Non-static method Facteur::html2text() should not be called statically 6 years ago
spip.franck@lien-d-amis.net c9944f2edb Ce n'est plus spip-contrib, mais contrib.spip 8 years ago
yffic@lefourneau.com f3888c7cb5 Et ne pas proposer d'utiliser la version 5.2.1 de phpMailer qui n'apporte pas grand chose à part de nouveaux bugs 11 years ago
yffic@lefourneau.com 475cd1cf98 Redéfinir dans la classe Facteur, les fonctions Send, AddAttachment, AddReplyTo, AddBCC, AddCC, de la classe PhpMailer de cette façon : 11 years ago
yffic@lefourneau.com ff44dc813e - Si échec lors du test d'envoi, le message d'erreur n'est plus affiché : indiquer d'aller consulter le fichier log 11 years ago
cedric@yterium.com 8804391518 Faire passer le test de mail du facteur par inc_envoyer_mail 11 years ago
cedric@yterium.com 9fe01388bf coquille 11 years ago
cedric@yterium.com 72faee6276 coquille 11 years ago
arnaud@arnaudcordier.org c551d47f5c Après corrections de bugs et changement de la configuration par défaut: changement de version. 11 years ago
arnaud@arnaudcordier.org fe9c95b25b Gestion plus fine des warning quand le HTML de la lettre est mal formé, on se contente de loguer le problème dans facteur.log 11 years ago
arnaud@arnaudcordier.org 0ba363ab0f Gestion plus fine des erreurs d'interprétation de la feuille de style, on arrête pas le processus mais on se contente de loguer l'erreur dans facteur.log 11 years ago
arnaud@arnaudcordier.org 33d50ce819 Ne pas activer la fonction de conversion des CSS en ligne par défaut 11 years ago
real3t@gmail.com 196f265cab Il manquait 2 pseudo class : before et after 11 years ago
yffic@lefourneau.com 1e231893ab Log du type d'erreur si échec d'envoi 11 years ago
arnaud@arnaudcordier.org 8e8e889196 Ajout d'une nouvelle fonctionnalité, donc incrément du y de la version. 11 years ago
arnaud@arnaudcordier.org 69e9afad46 Ajout de la class inlineStyle (https://github.com/christiaan/InlineStyle) et intégration de celle-ci. 11 years ago
rastapopoulos@spip.org 89e907cf59 Modifs bidons pour refaire les ZIPs. 11 years ago
cedric@yterium.com b06ee80ba2 branchons la v1.x actuelle 11 years ago
  1. 11
      .gitattributes
  2. 2
      base/facteur.php
  3. 313
      classes/facteur.php
  4. 42
      erreurs et exceptions.txt
  5. 83
      facteur_fonctions.php
  6. 344
      formulaires/configurer_facteur.php
  7. 11
      inc/envoyer_mail.php
  8. 1133
      inline-style/CSSQuery.php
  9. 235
      inline-style/InlineStyle.php
  10. 100
      inline-style/InlineStyleTest.php
  11. 20
      inline-style/MIT-LICENCE
  12. 64
      inline-style/README.markdown
  13. 11
      inline-style/testfiles/external.css
  14. 23
      inline-style/testfiles/test.html
  15. 10
      inline-style/testfiles/testApplyExtractedStylesheet.html
  16. 24
      inline-style/testfiles/testApplyStylesheet.html
  17. 24
      inline-style/testfiles/testGetHTML.html
  18. 14
      lang/facteur_de.php
  19. 147
      lang/facteur_fr.php
  20. 6
      plugin.xml

11
.gitattributes vendored

@ -6,6 +6,7 @@ emails/inc-bas.html -text
emails/inc-haut.html -text
emails/test_email_html.html -text
emails/test_email_texte.html -text
/erreurs[!!-~]et[!!-~]exceptions.txt -text
exec/facteur.php -text
/facteur_fonctions.php -text
/facteur_ieconfig_metas.php -text
@ -14,6 +15,16 @@ formulaires/configurer_facteur.php -text
inc/envoyer_mail.php -text
inc/facteur_autorisations.php -text
inc/facteur_classes.php -text
inline-style/CSSQuery.php -text
inline-style/InlineStyle.php -text
inline-style/InlineStyleTest.php -text
inline-style/MIT-LICENCE -text
inline-style/README.markdown -text
inline-style/testfiles/external.css -text
inline-style/testfiles/test.html -text
inline-style/testfiles/testApplyExtractedStylesheet.html -text
inline-style/testfiles/testApplyStylesheet.html -text
inline-style/testfiles/testGetHTML.html -text
lang/facteur_de.php -text
lang/facteur_en.php -text
lang/facteur_fr.php -text

2
base/facteur.php

@ -49,7 +49,7 @@ function facteur_upgrade($nom_meta_base_version, $version_cible){
ecrire_meta('facteur_smtp_secure', 'non');
ecrire_meta('facteur_smtp_sender', '');
ecrire_meta('facteur_filtre_images', 1);
ecrire_meta('facteur_filtre_css', 1);
ecrire_meta('facteur_filtre_css', '');
ecrire_meta('facteur_filtre_iso_8859', 1);
ecrire_meta('facteur_adresse_envoi', 'non');
}

313
classes/facteur.php

@ -12,7 +12,7 @@ include_spip('inc/charsets');
include_spip('inc/filtres');
if (!class_exists('PHPMailer')) {
if (intval(phpversion()) == 5) {
if (intval(phpversion()) >= 5) {
include_spip('phpmailer-php5/class.phpmailer');
include_spip('phpmailer-php5/class.smtp');
} else {
@ -26,6 +26,9 @@ class Facteur extends PHPMailer {
function Facteur($email, $objet, $message_html, $message_texte) {
if (defined('_FACTEUR_DEBUG_SMTP')) {
$this->SMTPDebug = _FACTEUR_DEBUG_SMTP ;
}
if ($GLOBALS['meta']['facteur_adresse_envoi'] == 'oui'
AND $GLOBALS['meta']['facteur_adresse_envoi_email'])
$this->From = $GLOBALS['meta']['facteur_adresse_envoi_email'];
@ -45,11 +48,13 @@ class Facteur extends PHPMailer {
//Pour un envoi multiple de mail, $email doit être un tableau avec les adresses.
if (is_array($email)) {
foreach ($email as $cle => $adresseMail) {
$this->AddAddress($adresseMail);
if (!$this->AddAddress($adresseMail))
spip_log("Erreur AddAddress $adresseMail : ".print_r($this->ErrorInfo,true),'facteur');
}
}
else
$this->AddAddress($email);
if (!$this->AddAddress($email))
spip_log("Erreur AddAddress $email : ".print_r($this->ErrorInfo,true),'facteur');
if (!empty($GLOBALS['meta']['facteur_smtp_sender'])) {
$this->Sender = $GLOBALS['meta']['facteur_smtp_sender'];
@ -117,87 +122,7 @@ class Facteur extends PHPMailer {
* @return string Retourne un texte brut formaté correctement
*/
function html2text($html){
// On remplace tous les sauts de lignes par un espace
$html = str_replace("\n", ' ', $html);
// Supprimer tous les liens internes
$texte = preg_replace("/\<a href=['\"]#(.*?)['\"][^>]*>(.*?)<\/a>/ims", "\\2", $html);
// Supprime feuille style
$texte = preg_replace(";<style[^>]*>[^<]*</style>;i", "", $texte);
// Remplace tous les liens
$texte = preg_replace("/\<a[^>]*href=['\"](.*?)['\"][^>]*>(.*?)<\/a>/ims", "\\2 (\\1)", $texte);
// Les titres
$texte = preg_replace(";<h1[^>]*>;i", "\n= ", $texte);
$texte = str_replace("</h1>", " =\n\n", $texte);
$texte = preg_replace(";<h2[^>]*>;i", "\n== ", $texte);
$texte = str_replace("</h2>", " ==\n\n", $texte);
$texte = preg_replace(";<h3[^>]*>;i", "\n=== ", $texte);
$texte = str_replace("</h3>", " ===\n\n", $texte);
// Une fin de liste
$texte = preg_replace(";</(u|o)l>;i", "\n\n", $texte);
// Une saut de ligne *après* le paragraphe
$texte = preg_replace(";<p[^>]*>;i", "\n", $texte);
$texte = preg_replace(";</p>;i", "\n\n", $texte);
// Les sauts de ligne interne
$texte = preg_replace(";<br[^>]*>;i", "\n", $texte);
//$texte = str_replace('<br /><img class=\'spip_puce\' src=\'puce.gif\' alt=\'-\' border=\'0\'>', "\n".'-', $texte);
$texte = preg_replace (';<li[^>]*>;i', "\n".'- ', $texte);
// accentuation du gras
// <b>texte</b> -> **texte**
$texte = preg_replace (';<b[^>]*>;i','**' ,$texte);
$texte = str_replace ('</b>','**' ,$texte);
// accentuation du gras
// <strong>texte</strong> -> **texte**
$texte = preg_replace (';<strong[^>]*>;i','**' ,$texte);
$texte = str_replace ('</strong>','**' ,$texte);
// accentuation de l'italique
// <em>texte</em> -> *texte*
$texte = preg_replace (';<em[^>]*>;i','/' ,$texte);
$texte = str_replace ('</em>','*' ,$texte);
// accentuation de l'italique
// <i>texte</i> -> *texte*
$texte = preg_replace (';<i[^>]*>;i','/' ,$texte);
$texte = str_replace ('</i>','*' ,$texte);
$texte = str_replace('&oelig;', 'oe', $texte);
$texte = str_replace("&nbsp;", " ", $texte);
$texte = filtrer_entites($texte);
// On supprime toutes les balises restantes
$texte = supprimer_tags($texte);
$texte = str_replace("\x0B", "", $texte);
$texte = str_replace("\t", "", $texte) ;
$texte = preg_replace(";[ ]{3,};", "", $texte);
// espace en debut de ligne
$texte = preg_replace("/(\r\n|\n|\r)[ ]+/", "\n", $texte);
//marche po
// Bring down number of empty lines to 4 max
$texte = preg_replace("/(\r\n|\n|\r){3,}/m", "\n\n", $texte);
//saut de lignes en debut de texte
$texte = preg_replace("/^(\r\n|\n|\r)*/", "\n\n", $texte);
//saut de lignes en debut ou fin de texte
$texte = preg_replace("/(\r\n|\n|\r)*$/", "\n\n", $texte);
// Faire des lignes de 75 caracteres maximum
//$texte = wordwrap($texte);
return $texte;
return facteur_mail_html2text($html);
}
/**
@ -268,172 +193,22 @@ class Facteur extends PHPMailer {
}
}
function ConvertirStylesEnligne() {
/*
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");
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.
include_spip('inline-style/InlineStyle');
include_spip('inline-style/CSSQuery');
.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.
*/
// 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", $this->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";
$this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->Body);
$styles[6][$i]=1; // mark as injected inline
}
}
}
// 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";
$this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->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";
$this->Body = preg_replace_callback ($pattern, 'facteur_addstyle' , $this->Body);
$styles[6][$i]=1; // mark as injected inline
}
}
/* 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", $this->Body)==0) {
$this->Body = preg_replace ("/(<body[^>]*>)/i", "\n\$1\n".'<style type="text/css">'."\n<!--\n-->\n</style>\n", $this->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." }";
$this->Body = preg_replace ("!(<body[^>]*>\s*<style[^>]*>\s*<\!\-\-[^>]*)"."(\s*\-\->\s*</style>)!si", "\$1".$declaration."\n\$2", $this->Body);
$styles[6][$i]= 2; // mark as moved to <style> section in <body>
}
libxml_use_internal_errors(true); // supprime les warnings d'un HTML mal formé
$bodyStyleenLigne = new InlineStyle(charset2unicode($this->Body,'utf-8')); // inlineStyle préfère l'unicode
foreach (libxml_get_errors() as $error) {
spip_log("Erreur dans la lecture du HTML de la lettre: ".$error->message." ligne ".$error->line,'facteur');
}
libxml_clear_errors();
libxml_use_internal_errors(false);
// remove stylesheet declaration(s) from <head> section (comment following line out if not wanted)
//$this->Body = preg_replace ("!(<head>.*)<style type.*</style>(.*</head>)!si", "\$1\$2" , $this->Body);
// check what styles have been injected
# print_r($styles);
$bodyStyleenLigne->applyStylesheet($bodyStyleenLigne->extractStylesheets());
$this->Body = $bodyStyleenLigne->getHTML();
}
function safe_utf8_decode($text,$mode='texte_brut') {
if (!is_utf8($text))
return ($text);
@ -486,6 +261,56 @@ class Facteur extends PHPMailer {
$this->Body = strtr($this->Body, $cor);
}
public function Send() {
ob_start();
$retour = parent::Send();
$error = ob_get_contents();
ob_end_clean();
if( !empty($error) ) {
spip_log("Erreur Facteur->Send : $error",'facteur.err');
}
return $retour;
}
public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
ob_start();
$retour = parent::AddAttachment($path, $name, $encoding, $type);
$error = ob_get_contents();
ob_end_clean();
if( !empty($error) ) {
spip_log("Erreur Facteur->AddAttachment : $error",'facteur.err');
}
return $retour;
}
public function AddReplyTo($address, $name = '') {
ob_start();
$retour = parent::AddReplyTo($address, $name);
$error = ob_get_contents();
ob_end_clean();
if( !empty($error) ) {
spip_log("Erreur Facteur->AddReplyTo : $error",'facteur.err');
}
return $retour;
}
public function AddBCC($address, $name = '') {
ob_start();
$retour = parent::AddBCC($address, $name);
$error = ob_get_contents();
ob_end_clean();
if( !empty($error) ) {
spip_log("Erreur Facteur->AddBCC : $error",'facteur.err');
}
return $retour;
}
public function AddCC($address, $name = '') {
ob_start();
$retour = parent::AddCC($address, $name);
$error = ob_get_contents();
ob_end_clean();
if( !empty($error) ) {
spip_log("Erreur Facteur->AddCC : $error",'facteur.err');
}
return $retour;
}
}
?>

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

83
facteur_fonctions.php

@ -59,5 +59,86 @@ function facteur_addstyle($matches) {
return "<".$matches[1].$attributes.$matches[3].">";
}
function facteur_mail_html2text($html){
// On remplace tous les sauts de lignes par un espace
$html = str_replace("\n", ' ', $html);
?>
// Supprimer tous les liens internes
$texte = preg_replace("/\<a href=['\"]#(.*?)['\"][^>]*>(.*?)<\/a>/ims", "\\2", $html);
// Supprime feuille style
$texte = preg_replace(";<style[^>]*>[^<]*</style>;i", "", $texte);
// Remplace tous les liens
$texte = preg_replace("/\<a[^>]*href=['\"](.*?)['\"][^>]*>(.*?)<\/a>/ims", "\\2 (\\1)", $texte);
// Les titres
$texte = preg_replace(";<h1[^>]*>;i", "\n= ", $texte);
$texte = str_replace("</h1>", " =\n\n", $texte);
$texte = preg_replace(";<h2[^>]*>;i", "\n== ", $texte);
$texte = str_replace("</h2>", " ==\n\n", $texte);
$texte = preg_replace(";<h3[^>]*>;i", "\n=== ", $texte);
$texte = str_replace("</h3>", " ===\n\n", $texte);
// Une fin de liste
$texte = preg_replace(";</(u|o)l>;i", "\n\n", $texte);
// Une saut de ligne *après* le paragraphe
$texte = preg_replace(";<p[^>]*>;i", "\n", $texte);
$texte = preg_replace(";</p>;i", "\n\n", $texte);
// Les sauts de ligne interne
$texte = preg_replace(";<br[^>]*>;i", "\n", $texte);
//$texte = str_replace('<br /><img class=\'spip_puce\' src=\'puce.gif\' alt=\'-\' border=\'0\'>', "\n".'-', $texte);
$texte = preg_replace (';<li[^>]*>;i', "\n".'- ', $texte);
// accentuation du gras
// <b>texte</b> -> **texte**
$texte = preg_replace (';<b[^>]*>;i','**' ,$texte);
$texte = str_replace ('</b>','**' ,$texte);
// accentuation du gras
// <strong>texte</strong> -> **texte**
$texte = preg_replace (';<strong[^>]*>;i','**' ,$texte);
$texte = str_replace ('</strong>','**' ,$texte);
// accentuation de l'italique
// <em>texte</em> -> *texte*
$texte = preg_replace (';<em[^>]*>;i','/' ,$texte);
$texte = str_replace ('</em>','*' ,$texte);
// accentuation de l'italique
// <i>texte</i> -> *texte*
$texte = preg_replace (';<i[^>]*>;i','/' ,$texte);
$texte = str_replace ('</i>','*' ,$texte);
$texte = str_replace('&oelig;', 'oe', $texte);
$texte = str_replace("&nbsp;", " ", $texte);
$texte = filtrer_entites($texte);
// On supprime toutes les balises restantes
$texte = supprimer_tags($texte);
$texte = str_replace("\x0B", "", $texte);
$texte = str_replace("\t", "", $texte) ;
$texte = preg_replace(";[ ]{3,};", "", $texte);
// espace en debut de ligne
$texte = preg_replace("/(\r\n|\n|\r)[ ]+/", "\n", $texte);
//marche po
// Bring down number of empty lines to 4 max
$texte = preg_replace("/(\r\n|\n|\r){3,}/m", "\n\n", $texte);
//saut de lignes en debut de texte
$texte = preg_replace("/^(\r\n|\n|\r)*/", "\n\n", $texte);
//saut de lignes en debut ou fin de texte
$texte = preg_replace("/(\r\n|\n|\r)*$/", "\n\n", $texte);
// Faire des lignes de 75 caracteres maximum
//$texte = wordwrap($texte);
return $texte;
}

344
formulaires/configurer_facteur.php

@ -1,173 +1,173 @@
<?php
/*
* Plugin Facteur
* (c) 2009-2010 Collectif SPIP
* Distribue sous licence GPL
*
*/
if (!defined("_ECRIRE_INC_VERSION")) return;
function formulaires_configurer_facteur_charger_dist(){
$valeurs = array(
'facteur_adresse_envoi' => $GLOBALS['meta']['facteur_adresse_envoi'],
'facteur_adresse_envoi_nom' => $GLOBALS['meta']['facteur_adresse_envoi_nom'],
'facteur_adresse_envoi_email' => $GLOBALS['meta']['facteur_adresse_envoi_email'],
'facteur_smtp' => $GLOBALS['meta']['facteur_smtp'],
'facteur_smtp_host' => $GLOBALS['meta']['facteur_smtp_host'],
'facteur_smtp_port' => $GLOBALS['meta']['facteur_smtp_port']?$GLOBALS['meta']['facteur_smtp_port']:'25',
'facteur_smtp_auth' => $GLOBALS['meta']['facteur_smtp_auth'],
'facteur_smtp_username' => $GLOBALS['meta']['facteur_smtp_username'],
'facteur_smtp_password' => $GLOBALS['meta']['facteur_smtp_password'],
'facteur_smtp_secure' => $GLOBALS['meta']['facteur_smtp_secure'],
'facteur_smtp_sender' => $GLOBALS['meta']['facteur_smtp_sender'],
'facteur_filtre_images' => $GLOBALS['meta']['facteur_filtre_images'],
'facteur_filtre_css' => $GLOBALS['meta']['facteur_filtre_css'],
'facteur_filtre_iso_8859' => $GLOBALS['meta']['facteur_filtre_iso_8859'],
'_enable_smtp_secure' => (intval(phpversion()) == 5)?' ':'',
'facteur_cc' => $GLOBALS['meta']['facteur_cc'],
'facteur_bcc' => $GLOBALS['meta']['facteur_bcc'],
'tester' => '',
);
return $valeurs;
}
function formulaires_configurer_facteur_verifier_dist(){
$erreurs = array();
if ($email = _request('facteur_adresse_envoi_email')
AND !email_valide($email)) {
$erreurs['facteur_adresse_envoi_email'] = _T('form_email_non_valide');
set_request('facteur_adresse_envoi','oui');
}
if (_request('facteur_smtp')=='oui'){
if (!($h=_request('facteur_smtp_host')))
$erreurs['facteur_smtp_host'] = _T('info_obligatoire');
else {
$regexp_ip_valide = '#^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$#';
// Source : http://www.d-sites.com/2008/10/09/regex-ipv4-et-ipv6/
if (!preg_match($regexp_ip_valide,$h)){ // ce n'est pas une IP
if(!preg_match(';^([^.\s/?:]+[.]){0,2}[^.\s/?:]+$;',$h)
OR gethostbyname($h)==$h)
$erreurs['facteur_smtp_host'] = _T('facteur:erreur_invalid_host');
}
else {
if (gethostbyaddr($h)==$h)
$erreurs['facteur_smtp_host'] = _T('facteur:erreur_invalid_host');
}
}
if (!($p=_request('facteur_smtp_port')))
$erreurs['facteur_smtp_port'] = _T('info_obligatoire');
elseif(!preg_match(';^[0-9]+$;',$p) OR !intval($p))
$erreurs['facteur_smtp_port'] = _T('facteur:erreur_invalid_port');
if (!_request('facteur_smtp_auth'))
$erreurs['facteur_smtp_auth'] = _T('info_obligatoire');
if (_request('facteur_smtp_auth')=='oui'){
if (!_request('facteur_smtp_username'))
$erreurs['facteur_smtp_username'] = _T('info_obligatoire');
if (!_request('facteur_smtp_password'))
$erreurs['facteur_smtp_password'] = _T('info_obligatoire');
}
}
if ($emailcc = _request('facteur_cc')
AND !email_valide($emailcc)) {
$erreurs['facteur_cc'] = _T('form_email_non_valide');
}
if ($emailbcc = _request('facteur_bcc')
AND !email_valide($emailbcc)) {
$erreurs['facteur_bcc'] = _T('form_email_non_valide');
}
if(count($erreurs)>0){
$erreurs['message_erreur'] = _T('facteur:erreur_generale');
}
return $erreurs;
}
function formulaires_configurer_facteur_traiter_dist(){
include_spip('inc/meta');
$facteur_adresse_envoi = _request('facteur_adresse_envoi');
ecrire_meta('facteur_adresse_envoi', ($facteur_adresse_envoi=='oui')?'oui':'non');
$facteur_adresse_envoi_nom = _request('facteur_adresse_envoi_nom');
ecrire_meta('facteur_adresse_envoi_nom', $facteur_adresse_envoi_nom?$facteur_adresse_envoi_nom:'');
$facteur_adresse_envoi_email = _request('facteur_adresse_envoi_email');
ecrire_meta('facteur_adresse_envoi_email', $facteur_adresse_envoi_email?$facteur_adresse_envoi_email:'');
$facteur_smtp = _request('facteur_smtp');
ecrire_meta('facteur_smtp', ($facteur_smtp=='oui')?'oui':'non');
$facteur_smtp_host = _request('facteur_smtp_host');
ecrire_meta('facteur_smtp_host', $facteur_smtp_host?$facteur_smtp_host:'');
$facteur_smtp_port = _request('facteur_smtp_port');
ecrire_meta('facteur_smtp_port', strlen($facteur_smtp_port)?intval($facteur_smtp_port):'');
$facteur_smtp_auth = _request('facteur_smtp_auth');
ecrire_meta('facteur_smtp_auth', ($facteur_smtp_auth=='oui')?'oui':'non');
$facteur_smtp_username = _request('facteur_smtp_username');
ecrire_meta('facteur_smtp_username', $facteur_smtp_username);
$facteur_smtp_password = _request('facteur_smtp_password');
ecrire_meta('facteur_smtp_password', $facteur_smtp_password);
if (intval(phpversion()) == 5) {
$facteur_smtp_secure = _request('facteur_smtp_secure');
ecrire_meta('facteur_smtp_secure', in_array($facteur_smtp_secure,array('non','ssl','tls'))?$facteur_smtp_secure:'non');
}
$facteur_smtp_sender = _request('facteur_smtp_sender');
ecrire_meta('facteur_smtp_sender', $facteur_smtp_sender);
ecrire_meta('facteur_filtre_images', intval(_request('facteur_filtre_images')));
ecrire_meta('facteur_filtre_css', intval(_request('facteur_filtre_css')));
ecrire_meta('facteur_filtre_iso_8859', intval(_request('facteur_filtre_iso_8859')));
$facteur_cc = _request('facteur_cc');
ecrire_meta('facteur_cc', $facteur_cc?$facteur_cc:'');
$facteur_bcc = _request('facteur_bcc');
ecrire_meta('facteur_bcc', $facteur_bcc?$facteur_bcc:'');
$res = array('message_ok'=>_T('facteur:config_info_enregistree'));
// faut-il envoyer un message de test ?
if (_request('tester')){
if ($GLOBALS['meta']['facteur_adresse_envoi'] == 'oui'
AND $GLOBALS['meta']['facteur_adresse_envoi_email'])
$destinataire = $GLOBALS['meta']['facteur_adresse_envoi_email'];
else
$destinataire = $GLOBALS['meta']['email_webmaster'];
if (($e=facteur_envoyer_mail_test($destinataire,_T('facteur:corps_email_de_test')))===true){
// OK
$res = array('message_ok'=>_T('facteur:email_test_envoye'));
}
else {
// erreur
$res = array('message_erreur'=>_T('facteur:erreur')." $e");
}
}
return $res;
}
function facteur_envoyer_mail_test($destinataire,$titre){
include_spip('classes/facteur');
$message_html = recuperer_fond('emails/test_email_html', array());
$message_texte = recuperer_fond('emails/test_email_texte', array());
$facteur = new Facteur($destinataire, $titre, $message_html, $message_texte);
if (!$facteur->Send())
return $test->ErrorInfo;
else
return true;
}
<?php
/*
* Plugin Facteur
* (c) 2009-2010 Collectif SPIP
* Distribue sous licence GPL
*
*/
if (!defined("_ECRIRE_INC_VERSION")) return;
function formulaires_configurer_facteur_charger_dist(){
$valeurs = array(
'facteur_adresse_envoi' => $GLOBALS['meta']['facteur_adresse_envoi'],
'facteur_adresse_envoi_nom' => $GLOBALS['meta']['facteur_adresse_envoi_nom'],
'facteur_adresse_envoi_email' => $GLOBALS['meta']['facteur_adresse_envoi_email'],
'facteur_smtp' => $GLOBALS['meta']['facteur_smtp'],
'facteur_smtp_host' => $GLOBALS['meta']['facteur_smtp_host'],
'facteur_smtp_port' => $GLOBALS['meta']['facteur_smtp_port']?$GLOBALS['meta']['facteur_smtp_port']:'25',
'facteur_smtp_auth' => $GLOBALS['meta']['facteur_smtp_auth'],
'facteur_smtp_username' => $GLOBALS['meta']['facteur_smtp_username'],
'facteur_smtp_password' => $GLOBALS['meta']['facteur_smtp_password'],
'facteur_smtp_secure' => $GLOBALS['meta']['facteur_smtp_secure'],
'facteur_smtp_sender' => $GLOBALS['meta']['facteur_smtp_sender'],
'facteur_filtre_images' => $GLOBALS['meta']['facteur_filtre_images'],
'facteur_filtre_css' => $GLOBALS['meta']['facteur_filtre_css'],
'facteur_filtre_iso_8859' => $GLOBALS['meta']['facteur_filtre_iso_8859'],
'_enable_smtp_secure' => (intval(phpversion()) == 5)?' ':'',
'facteur_cc' => $GLOBALS['meta']['facteur_cc'],
'facteur_bcc' => $GLOBALS['meta']['facteur_bcc'],
'tester' => '',
);
return $valeurs;
}
function formulaires_configurer_facteur_verifier_dist(){
$erreurs = array();
if ($email = _request('facteur_adresse_envoi_email')
AND !email_valide($email)) {
$erreurs['facteur_adresse_envoi_email'] = _T('form_email_non_valide');
set_request('facteur_adresse_envoi','oui');
}
if (_request('facteur_smtp')=='oui'){
if (!($h=_request('facteur_smtp_host')))
$erreurs['facteur_smtp_host'] = _T('info_obligatoire');
else {
$regexp_ip_valide = '#^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$#';
// Source : http://www.d-sites.com/2008/10/09/regex-ipv4-et-ipv6/
if (!preg_match($regexp_ip_valide,$h)){ // ce n'est pas une IP
if(!preg_match(';^([^.\s/?:]+[.]){0,2}[^.\s/?:]+$;',$h)
OR gethostbyname($h)==$h)
$erreurs['facteur_smtp_host'] = _T('facteur:erreur_invalid_host');
}
else {
if (gethostbyaddr($h)==$h)
$erreurs['facteur_smtp_host'] = _T('facteur:erreur_invalid_host');
}
}
if (!($p=_request('facteur_smtp_port')))
$erreurs['facteur_smtp_port'] = _T('info_obligatoire');
elseif(!preg_match(';^[0-9]+$;',$p) OR !intval($p))
$erreurs['facteur_smtp_port'] = _T('facteur:erreur_invalid_port');
if (!_request('facteur_smtp_auth'))
$erreurs['facteur_smtp_auth'] = _T('info_obligatoire');
if (_request('facteur_smtp_auth')=='oui'){
if (!_request('facteur_smtp_username'))
$erreurs['facteur_smtp_username'] = _T('info_obligatoire');
if (!_request('facteur_smtp_password'))
$erreurs['facteur_smtp_password'] = _T('info_obligatoire');
}
}
if ($emailcc = _request('facteur_cc')
AND !email_valide($emailcc)) {
$erreurs['facteur_cc'] = _T('form_email_non_valide');
}
if ($emailbcc = _request('facteur_bcc')
AND !email_valide($emailbcc)) {
$erreurs['facteur_bcc'] = _T('form_email_non_valide');
}
if(count($erreurs)>0){
$erreurs['message_erreur'] = _T('facteur:erreur_generale');
}
return $erreurs;
}
function formulaires_configurer_facteur_traiter_dist(){
include_spip('inc/meta');
$facteur_adresse_envoi = _request('facteur_adresse_envoi');
ecrire_meta('facteur_adresse_envoi', ($facteur_adresse_envoi=='oui')?'oui':'non');
$facteur_adresse_envoi_nom = _request('facteur_adresse_envoi_nom');
ecrire_meta('facteur_adresse_envoi_nom', $facteur_adresse_envoi_nom?$facteur_adresse_envoi_nom:'');
$facteur_adresse_envoi_email = _request('facteur_adresse_envoi_email');
ecrire_meta('facteur_adresse_envoi_email', $facteur_adresse_envoi_email?$facteur_adresse_envoi_email:'');
$facteur_smtp = _request('facteur_smtp');
ecrire_meta('facteur_smtp', ($facteur_smtp=='oui')?'oui':'non');
$facteur_smtp_host = _request('facteur_smtp_host');
ecrire_meta('facteur_smtp_host', $facteur_smtp_host?$facteur_smtp_host:'');
$facteur_smtp_port = _request('facteur_smtp_port');
ecrire_meta('facteur_smtp_port', strlen($facteur_smtp_port)?intval($facteur_smtp_port):'');
$facteur_smtp_auth = _request('facteur_smtp_auth');
ecrire_meta('facteur_smtp_auth', ($facteur_smtp_auth=='oui')?'oui':'non');
$facteur_smtp_username = _request('facteur_smtp_username');
ecrire_meta('facteur_smtp_username', $facteur_smtp_username);
$facteur_smtp_password = _request('facteur_smtp_password');
ecrire_meta('facteur_smtp_password', $facteur_smtp_password);
if (intval(phpversion()) == 5) {
$facteur_smtp_secure = _request('facteur_smtp_secure');
ecrire_meta('facteur_smtp_secure', in_array($facteur_smtp_secure,array('non','ssl','tls'))?$facteur_smtp_secure:'non');
}
$facteur_smtp_sender = _request('facteur_smtp_sender');
ecrire_meta('facteur_smtp_sender', $facteur_smtp_sender);
ecrire_meta('facteur_filtre_images', intval(_request('facteur_filtre_images')));
ecrire_meta('facteur_filtre_css', intval(_request('facteur_filtre_css')));
ecrire_meta('facteur_filtre_iso_8859', intval(_request('facteur_filtre_iso_8859')));
$facteur_cc = _request('facteur_cc');
ecrire_meta('facteur_cc', $facteur_cc?$facteur_cc:'');
$facteur_bcc = _request('facteur_bcc');
ecrire_meta('facteur_bcc', $facteur_bcc?$facteur_bcc:'');
$res = array('message_ok'=>_T('facteur:config_info_enregistree'));
// faut-il envoyer un message de test ?
if (_request('tester')){
if ($GLOBALS['meta']['facteur_adresse_envoi'] == 'oui'
AND $GLOBALS['meta']['facteur_adresse_envoi_email'])
$destinataire = $GLOBALS['meta']['facteur_adresse_envoi_email'];
else
$destinataire = $GLOBALS['meta']['email_webmaster'];
if ((facteur_envoyer_mail_test($destinataire,_T('facteur:corps_email_de_test')))===true){
// OK
$res = array('message_ok'=>_T('facteur:email_test_envoye'));
}
else {
// erreur
$res = array('message_erreur'=>_T('facteur:erreur')._T('facteur:erreur_dans_log'));
}
}
return $res;
}
function facteur_envoyer_mail_test($destinataire,$titre){
include_spip('classes/facteur');
$message_html = recuperer_fond('emails/test_email_html', array());
$message_texte = recuperer_fond('emails/test_email_texte', array());
// passer par envoyer_mail pour bien passer par les pipeline et avoir tous les logs
$envoyer_mail = charger_fonction('envoyer_mail','inc');
$retour = $envoyer_mail($destinataire, $titre, array('html'=>$message_html,'texte'=>$message_texte));
return $retour?true:false;
}
?>

11
inc/envoyer_mail.php

@ -163,9 +163,14 @@ function inc_envoyer_mail($destinataire, $sujet, $corps, $from = "", $headers =
$head = $facteur->CreateHeader();
// Et c'est parti on envoie enfin
spip_log("mail via facteur\n$head"."Destinataire: \n$destinataire\n",'mail');
spip_log("mail\n$head"."Destinataire: \n$destinataire\n",'facteur');
return $facteur->Send();
spip_log("mail via facteur\n$head"."Destinataire:".print_r($destinataire,true),'mail');
spip_log("mail\n$head"."Destinataire:".print_r($destinataire,true),'facteur');
$retour = $facteur->Send();
if (!$retour)
spip_log("Erreur Envoi mail via Facteur : ".print_r($facteur->ErrorInfo,true),'facteur');
return $retour ;
}
// Juste pour déclarer le pipeline

1133
inline-style/CSSQuery.php

File diff suppressed because it is too large Load Diff

235
inline-style/InlineStyle.php

@ -0,0 +1,235 @@
<?php
/*
* InlineStyle MIT License
*
* Copyright (c) 2010 Christiaan Baartse
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Parses a html file and applies all embedded and external stylesheets inline
*
* @author Christiaan Baartse <christiaan@baartse.nl>
* @copyright 2010 Christiaan Baartse
*/
class InlineStyle
{
/**
* @var DOMDocument the HTML as DOMDocument
*/
protected $_dom;
/**
* @var CSSQuery instance to use css based selectors on our DOMDocument
*/
protected $_cssquery;
/**
* Prepare all the necessary objects
*
* @param string $html
*/
public function __construct($html) {
if(!class_exists("CSSQuery")) {
throw new Exception(
"InlineStyle needs the CSSQuery class");
}
$html = (string) $html;
$this->_dom = new DOMDocument();
if(file_exists($html)) {
$this->_dom->loadHTMLFile($html);
}
else {
$this->_dom->loadHTML($html);
}
$this->_cssquery = new CSSQuery($this->_dom);
}
/**
* Applies one or more stylesheets to the current document
*
* @param string $stylesheet
* @return InlineStyle self
*/
public function applyStylesheet($stylesheet) {
$stylesheet = (array) $stylesheet;
foreach($stylesheet as $ss) {
foreach($this->parseStylesheet($ss) as $arr) {
list($selector, $style) = $arr;
try {
$this->applyRule($selector, $style);
}
catch(Exception $e) { // ne pas casser sur un sélecteur inconnu ou une erreur dans le CSS
spip_log("Erreur dans la transcription des styles en ligne: ".$e->getMessage(),'facteur');
}
}
}
return $this;
}
/**
* Applies a style rule on the document
* @param string $selector
* @param string $style
* @return InlineStyle self
*/
public function applyRule($selector, $style) {
$selector = trim(trim($selector), ",");
if($selector) {
$nodes = array();
foreach(explode(",", $selector) as $sel) {
if(false === stripos($sel, ":hover") &&
false === stripos($sel, ":active") &&
false === stripos($sel, ":visited")) {
$nodes = array_merge($nodes, $this->_cssquery->query($sel));
}
}
$style = $this->_styleToArray($style);
foreach($nodes as $node) {
$current = $node->hasAttribute("style") ?
$this->_styleToArray($node->getAttribute("style")) :
array();
$current = $this->_mergeStyles($current, $style);
$st = array();
foreach($current as $prop => $val) {
$st[] = "{$prop}:{$val}";
}
$node->setAttribute("style", implode(";", $st));
}
}
return $this;
}
/**
* Returns the DOMDocument as html
*
* @return string the HTML
*/
public function getHTML()
{
return $this->_dom->saveHTML();
}
/**
* Recursively extracts the stylesheet nodes from the DOMNode
* @param DOMNode $node leave empty to extract from the whole document
* @return array the extracted stylesheets
*/
public function extractStylesheets(DOMNode $node = null, $base = "")
{
if(null === $node) {
$node = $this->_dom;
}
$stylesheets = array();
if(strtolower($node->nodeName) === "style") {
$stylesheets[] = $node->nodeValue;
$node->parentNode->removeChild($node);
}
else if(strtolower($node->nodeName) === "link") {
if($node->hasAttribute("href")) {
$href = $node->getAttribute("href");
if($base && false === strpos($href, "://")) {
$href = "{$base}/{$href}";
}
$ext = @file_get_contents($href);
if($ext) {
$stylesheets[] = $ext;
$node->parentNode->removeChild($node);
}
}
}
if($node->hasChildNodes()) {
foreach($node->childNodes as $child) {
$stylesheets = array_merge($stylesheets,
$this->extractStylesheets($child, $base));
}
}
return $stylesheets;
}
/**
* Parses a stylesheet to selectors and properties
* @param string $stylesheet
* @return array
*/
public function parseStylesheet($stylesheet) {
$parsed = array();
$stylesheet = $this->_stripStylesheet($stylesheet);
$stylesheet = trim(trim($stylesheet), "}");
foreach(explode("}", $stylesheet) as $rule) {
list($selector, $style) = explode("{", $rule, 2);
$parsed[] = array(trim($selector), trim(trim($style), ";"));
}
return $parsed;
}
/**
* Parses style properties to a array which can be merged by mergeStyles()
* @param string $style
* @return array
*/
protected function _styleToArray($style) {
$styles = array();
$style = trim(trim($style), ";");
if($style) {
foreach(explode(";",$style) as $props) {
$props = trim(trim($props), ";");
list($prop, $val) = explode(":", $props);
$styles[$prop] = $val;
}
}
return $styles;
}
/**
* Merges two sets of style properties taking !important into account
* @param array $styleA
* @param array $styleB
* @return array
*/
protected function _mergeStyles(array $styleA, array $styleB) {
foreach($styleB as $prop => $val) {
if(!isset($styleA[$prop]) ||
substr(str_replace(" ", "", strtolower($styleA[$prop])), -10) !==
"!important") {
$styleA[$prop] = $val;
}
}
return $styleA;
}
protected function _stripStylesheet($s)
{
$s = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!','', $s);
$s = str_replace(array("\r\n","\r","\n","\t",' ',' ',' '),'',$s);
$s = str_replace('{ ', '{', $s);
$s = str_replace(' }', '}', $s);
$s = str_replace('; ', ';', $s);
return $s;
}
}

100
inline-style/InlineStyleTest.php

@ -0,0 +1,100 @@
<?php
require_once 'PHPUnit/Framework.php';
require_once 'CSSQuery.php';
require_once 'InlineStyle.php';
/**
* Test class for InlineStyle.
* Generated by PHPUnit on 2010-03-10 at 21:52:44.
*/
class InlineStyleTest extends PHPUnit_Framework_TestCase
{
/**
* @var InlineStyle
*/
protected $object;
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp()
{
$this->object = new InlineStyle("testfiles/test.html");
}
/**
* Tears down the fixture, for example, closes a network connection.
* This method is called after a test is executed.
*/
protected function tearDown()
{
unset($this->object);
}
public function testGetHTML()
{
$this->assertEquals($this->object->getHTML(),
file_get_contents("testfiles/testGetHTML.html"));
}
public function testApplyStyleSheet()
{
$this->object->applyStyleSheet("p:not(.p2) { color: red }");
$this->assertEquals($this->object->getHTML(),
file_get_contents("testfiles/testApplyStylesheet.html"));
}
public function testApplyRule()
{
$this->object->applyRule("p:not(.p2)", "color: red");
$this->assertEquals($this->object->getHTML(),
file_get_contents("testfiles/testApplyStylesheet.html"));
}
public function testExtractStylesheets()
{
$stylesheets = $this->object->extractStylesheets(null, "testfiles");
$this->assertEquals($stylesheets, array(
'p{
margin:0;
padding:0 0 10px 0;
background-image: url("someimage.jpg");
}
a:hover{
color:Red;
}
p:hover{
color:blue;
}
',
'
h1{
color:yellow
}
p {
color:yellow !important;
}
p {
color:blue
}
',
));
}
public function testApplyExtractedStylesheet()
{
$stylesheets = $this->object->extractStylesheets(null, "testfiles");
$this->object->applyStylesheet($stylesheets);
$this->assertEquals($this->object->getHTML(),
file_get_contents("testfiles/testApplyExtractedStylesheet.html"));
}
public function testParseStyleSheet()
{
$parsed = $this->object->parseStylesheet("p:not(.p2) { color: red }");
$this->assertEquals($parsed, array(array("p:not(.p2)", "color: red")));
}
}

20
inline-style/MIT-LICENCE

@ -0,0 +1,20 @@
Copyright (c) 2010 Christiaan Baartse
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

64
inline-style/README.markdown

@ -0,0 +1,64 @@
InlineStyle
===========
InlineStyle provides an easy way to apply embedded and external stylesheets
directly as inline styles on the HTML tags. This is especially targetted at mail
clients which mostly dont support stylesheets but do support the style attribute
for HTML tags.
Usage
-----
First include both InlineStyle.php and CSSQuery.php.
Then create a new InlineStyle object from either a HTML string or HTML file.
$htmldoc = new InlineStyle("testfiles/test.html");
or
$htmldoc = new InlineStyle(file_get_contents("http://github.com"));
### Apply the embedded and external stylesheets
First we'll have to extract the stylesheets from the document and then we have
to apply them.
$htmldoc->applyStylesheet($htmldoc->extractStylesheets());
The second param is the base url that is used to parse the links to external
stylesheets.
$htmldoc->applyStylesheet($htmldoc->extractStylesheets(null, "http://github.com"));
### Applying additional stylesheets
This class can also be used to apply a given css template to each processed HTML
file.
$htmldoc->applyStylesheet(file_get_contents("testfiles/external.css"));
License
-------
InlineStyle MIT License
Copyright (c) 2010 Christiaan Baartse
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

11
inline-style/testfiles/external.css

@ -0,0 +1,11 @@
p{
margin:0;
padding:0 0 10px 0;
background-image: url("someimage.jpg");
}
a:hover{
color:Red;
}
p:hover{
color:blue;
}

23
inline-style/testfiles/test.html

@ -0,0 +1,23 @@
<html>
<head>
<title>Example</title>
<link rel="stylesheet" href="external.css" />
</head>
<body>
<style type="text/css">
h1{
color:yellow
}
p {
color:yellow !important;
}
p {
color:blue
}
</style>
<h1>An example title</h1>
<p>Paragraph 1</p>
<p class="p2">Paragraph 2</p>
<br>
</body>
</html>

10
inline-style/testfiles/testApplyExtractedStylesheet.html

@ -0,0 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head><title>Example</title></head>
<body>
<h1 style="color:yellow">An example title</h1>
<p style='margin:0;padding:0 0 10px 0;background-image: url("someimage.jpg");color:yellow !important'>Paragraph 1</p>
<p class="p2" style='margin:0;padding:0 0 10px 0;background-image: url("someimage.jpg");color:yellow !important'>Paragraph 2</p>
<br>
</body>
</html>

24
inline-style/testfiles/testApplyStylesheet.html

@ -0,0 +1,24 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>Example</title>
<link rel="stylesheet" href="external.css">
</head>
<body>
<style type="text/css">
h1{
color:yellow
}
p {
color:yellow !important;
}
p {
color:blue
}
</style>
<h1>An example title</h1>
<p style="color: red">Paragraph 1</p>
<p class="p2">Paragraph 2</p>
<br>
</body>
</html>

24
inline-style/testfiles/testGetHTML.html

@ -0,0 +1,24 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>Example</title>
<link rel="stylesheet" href="external.css">
</head>
<body>
<style type="text/css">
h1{
color:yellow
}
p {
color:yellow !important;
}
p {
color:blue
}
</style>
<h1>An example title</h1>
<p>Paragraph 1</p>
<p class="p2">Paragraph 2</p>
<br>
</body>
</html>

14
lang/facteur_de.php

@ -5,9 +5,9 @@ if (!defined("_ECRIRE_INC_VERSION")) return;
$GLOBALS[$GLOBALS['idx_lang']] = array(
// C
'config_info_enregistree' => 'Die Konfiguration des Briedtr&#228;gers wurde gespeichert',
'config_info_enregistree' => 'Die Konfiguration des Briedträgers wurde gespeichert',
'configuration_adresse_envoi' => 'Absendeadresse einstellen',
'configuration_facteur' => 'Brieftr&#228;ger',
'configuration_facteur' => 'Briefträger',
'configuration_mailer' => 'Konfiguration des Mailers',
'configuration_smtp' => 'Auswahl der Versandmethode',
'configuration_smtp_descriptif' => 'Im Zweifel hier die mail() Funktion von PHP eintragen.',
@ -24,24 +24,24 @@ $GLOBALS[$GLOBALS['idx_lang']] = array(
// F
'facteur_adresse_envoi_email' => 'E-Mail :',
'facteur_adresse_envoi_nom' => 'Name:',
'facteur_filtre_accents' => 'Sonderzeichen in HTML-Entit&#228;ten umwandeln (z.B. f&#252;r Hotmail).',
'facteur_filtre_css' => 'Stile zwischen &lt;head&gt; und &lt;/head&gt; zu "inline" Stilen umwandeln, sinnvoll f&#252;r Webmail die interne Stile externen vorzieht.',
'facteur_filtre_accents' => 'Sonderzeichen in HTML-Entitäten umwandeln (z.B. für Hotmail).',
'facteur_filtre_css' => 'Stile zwischen <head> und </head> zu "inline" Stilen umwandeln, sinnvoll für Webmail die interne Stile externen vorzieht.',
'facteur_filtre_iso_8859' => 'Nach ISO-8859-1 umwandeln',
'facteur_filtre_images' => 'Verlinkte Bilder in E-Mail einbetten',
'facteur_filtres' => 'Filter',
'facteur_filtres_descriptif' => 'Beim Versand k&#246;nnen mehrere Filter eingesetzt werden.',
'facteur_filtres_descriptif' => 'Beim Versand können mehrere Filter eingesetzt werden.',
'facteur_smtp_auth' => 'Autorisierung erforderlich:',
'facteur_smtp_auth_oui' => 'ja',
'facteur_smtp_auth_non' => 'nein',
'facteur_smtp_host' => 'Server:',
'facteur_smtp_password' => 'Passwort:',
'facteur_smtp_port' => 'Port:',
'facteur_smtp_secure' => 'Verschl&#252;sselte Verbindung:',
'facteur_smtp_secure' => 'Verschlüsselte Verbindung:',
'facteur_smtp_secure_non' => 'nein',
'facteur_smtp_secure_ssl' => 'SSL',
'facteur_smtp_secure_tls' => 'TLS',
'facteur_smtp_sender' => 'Fehlercodes (optional)',
'facteur_smtp_sender_descriptif' => 'Legt im Kopf der Mail die Empf&#228;ngeradresse f&#252;r Fehlermeldungen fest (bzw. den Return-Path), bestimmt ebenfalls die Absenderadresse bei Versand per SMTP.',
'facteur_smtp_sender_descriptif' => 'Legt im Kopf der Mail die Empfängeradresse für Fehlermeldungen fest (bzw. den Return-Path), bestimmt ebenfalls die Absenderadresse bei Versand per SMTP.',
'facteur_smtp_username' => 'Benutzername:',
// N