Add PHPMailerEnhanced class

master
Julien Rosset 2 years ago
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…
Cancel
Save