Add PHPMailerEnhanced class
parent
162dffa2f9
commit
13a5c33701
@ -0,0 +1,172 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace jrosset\PHPMailerEnhanced;
|
||||||
|
|
||||||
|
use PHPMailer\PHPMailer\Exception;
|
||||||
|
use PHPMailer\PHPMailer\PHPMailer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enhanced version of {@see PHPMailer}
|
||||||
|
*
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
class PHPMailerEnhanced extends PHPMailer {
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function __construct ($exceptions = true) {
|
||||||
|
parent::__construct($exceptions);
|
||||||
|
$this->CharSet = PHPMailer::CHARSET_UTF8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function setFrom ($address, $name = '', $auto = true): bool {
|
||||||
|
static::splitAddressName($address, $name);
|
||||||
|
return parent::setFrom($address, $name, $auto);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected function addAnAddress ($kind, $address, $name = ''): bool {
|
||||||
|
static::splitAddressName($address, $name);
|
||||||
|
return parent::addAnAddress($kind, $address, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casse une adresse contenant un nom
|
||||||
|
*
|
||||||
|
* @param string $address [in/out] L'adresse mail d'origine avec potentiellement un nom (format : "{name} <{email}>")
|
||||||
|
* @param string $name [in/out] Le nom de l'adresse
|
||||||
|
* @param boolean $replaceName Remplace le nom fourni si un trouvé dans l'adresse mail
|
||||||
|
*
|
||||||
|
* @return bool Est-ce qu'un nom a été trouvé dans l'adresse mail ?
|
||||||
|
*/
|
||||||
|
protected static function splitAddressName (string &$address, string &$name = '', bool $replaceName = true): bool {
|
||||||
|
if (preg_match('/^\\s*(?<name>[^<]+?)\s*<(?<address>[^>]+@[^>]+)>\\s*$/i', $address, $match) !== 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$address = $match['address'];
|
||||||
|
if ($replaceName && $name !== '') {
|
||||||
|
$name = $match['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process local files to embed then in mail
|
||||||
|
*
|
||||||
|
* <b>INFO:</b> automatically called by {@see static::send()}
|
||||||
|
*
|
||||||
|
* @param string $localDirectory Le répertoire des images (défaut = répertoire exécution actuel)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws Exception If failed to embed one of the files
|
||||||
|
*/
|
||||||
|
public function processFiles (string $localDirectory = '.'): void {
|
||||||
|
//region Ensure the trailing directory separator in local directory path
|
||||||
|
if (preg_match('#' . preg_quote(DIRECTORY_SEPARATOR, '#') . '$#', $localDirectory) !== 1) {
|
||||||
|
$localDirectory .= DIRECTORY_SEPARATOR;
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region Read the HTML mail body
|
||||||
|
switch ($this->ContentType) {
|
||||||
|
case PHPMailer::CONTENT_TYPE_TEXT_HTML:
|
||||||
|
// Mail in HTML directly → use body
|
||||||
|
$bodyProperty = 'Body';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PHPMailer::CONTENT_TYPE_PLAINTEXT:
|
||||||
|
// Mail NOT in HTML → try alternative body
|
||||||
|
$bodyProperty = 'AltBody';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$body = $this->$bodyProperty;
|
||||||
|
|
||||||
|
// If HTML body is empty, stop here
|
||||||
|
if (empty($body)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
//region Generate an unique “cid“ prefix
|
||||||
|
$cidNumber = 1;
|
||||||
|
do {
|
||||||
|
$cidPrefix = uniqid() . '_';
|
||||||
|
} while ($this->cidExists($cidPrefix . $cidNumber));
|
||||||
|
$embeddedImages = [];
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region Search all link (“src” or “href“ attribute)
|
||||||
|
$body = preg_replace_callback(
|
||||||
|
'#(?<=src="|href=")[^"]+(?=")#i',
|
||||||
|
function (array $match) use ($localDirectory, $cidPrefix, &$cidNumber, &$embeddedImages): string {
|
||||||
|
$link = $match[0];
|
||||||
|
|
||||||
|
//region Check the link has no protocol (http, cid, etc.) or it's “file”
|
||||||
|
if (preg_match('#^(?<protocol>[a-z][a-z\d+.-]*):(?<path>.+)$#i', $link, $match) === 1) {
|
||||||
|
if (($match['protocol'] ?? '') !== 'file') {
|
||||||
|
return $link;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$link = $match['path'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region Try to find a valid file
|
||||||
|
// Search a file relative to local directory
|
||||||
|
$path = $localDirectory . $link;
|
||||||
|
if (!file_exists($path) || !is_file($path) || !is_readable($path)) {
|
||||||
|
// Search an absolute file
|
||||||
|
$path = $link;
|
||||||
|
if (!file_exists($path) || !is_file($path) || !is_readable($path)) {
|
||||||
|
return $link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region Associate a “cid“ to the file
|
||||||
|
$cid = $cidPrefix . ($cidNumber++);
|
||||||
|
$embeddedImages[$cid] = $path;
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
return 'cid:' . $cid;
|
||||||
|
},
|
||||||
|
$body
|
||||||
|
);
|
||||||
|
//region Check there is at least one file to embed
|
||||||
|
if (count($embeddedImages) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region Write back the mail body
|
||||||
|
$this->$bodyProperty = $body;
|
||||||
|
//endregion
|
||||||
|
//region Embed the files in the mail
|
||||||
|
foreach ($embeddedImages as $cid => $path) {
|
||||||
|
$this->addEmbeddedImage($path, $cid);
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @param string $localDirectory Le répertoire des images embarquées
|
||||||
|
*
|
||||||
|
* @throws Exception If failed to embed one of the files
|
||||||
|
*/
|
||||||
|
public function send (string $localDirectory = '.'): bool {
|
||||||
|
$this->processFiles($localDirectory);
|
||||||
|
return parent::send();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue