260 lines
7.5 KiB
PHP
Executable File
260 lines
7.5 KiB
PHP
Executable File
<?php
|
|
|
|
/**
|
|
* Swift Mailer Message Decorating Plugin.
|
|
* Please read the LICENSE file
|
|
* @author Chris Corbyn <chris@w3style.co.uk>
|
|
* @package Swift_Plugin
|
|
* @subpackage Decorator
|
|
* @license GNU Lesser General Public License
|
|
*/
|
|
|
|
require_once dirname(__FILE__) . "/../ClassLoader.php";
|
|
Swift_ClassLoader::load("Swift_Events_BeforeSendListener");
|
|
Swift_ClassLoader::load("Swift_Plugin_Decorator_Replacements");
|
|
|
|
/**
|
|
* Swift Decorator Plugin.
|
|
* Allows messages to be slightly different for each recipient.
|
|
* @package Swift_Plugin
|
|
* @subpackage Decorator
|
|
* @author Chris Corbyn <chris@w3style.co.uk>
|
|
*/
|
|
class Swift_Plugin_Decorator implements Swift_Events_BeforeSendListener
|
|
{
|
|
/**
|
|
* The replacements object.
|
|
* @var Swift_Plugin_Decorator_Replacements
|
|
*/
|
|
protected $replacements;
|
|
/**
|
|
* Temporary storage so we can restore changes we make.
|
|
* @var array
|
|
*/
|
|
protected $store;
|
|
/**
|
|
* A list of allowed mime types to replace bodies for.
|
|
* @var array
|
|
*/
|
|
protected $permittedTypes = array("text/plain" => 1, "text/html" => 1);
|
|
/**
|
|
* True if values in the headers can be replaced
|
|
* @var boolean
|
|
*/
|
|
protected $permittedInHeaders = true;
|
|
|
|
/**
|
|
* Ctor.
|
|
* @param mixed Replacements as a 2-d array or Swift_Plugin_Decorator_Replacements instance.
|
|
*/
|
|
public function __construct($replacements=null)
|
|
{
|
|
$this->setReplacements($replacements);
|
|
}
|
|
/**
|
|
* Enable of disable the ability to replace values in the headers
|
|
* @param boolean
|
|
*/
|
|
public function setPermittedInHeaders($bool)
|
|
{
|
|
$this->permittedInHeaders = (bool) $bool;
|
|
}
|
|
/**
|
|
* Check if replacements in headers are allowed.
|
|
* @return boolean
|
|
*/
|
|
public function getPermittedInHeaders()
|
|
{
|
|
return $this->permittedInHeaders;
|
|
}
|
|
/**
|
|
* Add a mime type to the list of permitted type to replace values in the body.
|
|
* @param string The mime type (e.g. text/plain)
|
|
*/
|
|
public function addPermittedType($type)
|
|
{
|
|
$type = strtolower($type);
|
|
$this->permittedTypes[$type] = 1;
|
|
}
|
|
/**
|
|
* Remove the ability to replace values in the body of the given mime type
|
|
* @param string The mime type
|
|
*/
|
|
public function removePermittedType($type)
|
|
{
|
|
unset($this->permittedTypes[$type]);
|
|
}
|
|
/**
|
|
* Get the list of mime types for which the body can be changed.
|
|
* @return array
|
|
*/
|
|
public function getPermittedTypes()
|
|
{
|
|
return array_keys($this->permittedTypes);
|
|
}
|
|
/**
|
|
* Check if the body can be replaced in the given mime type.
|
|
* @param string The mime type
|
|
* @return boolean
|
|
*/
|
|
public function isPermittedType($type)
|
|
{
|
|
return array_key_exists(strtolower($type), $this->permittedTypes);
|
|
}
|
|
/**
|
|
* Called just before Swift sends a message.
|
|
* We perform operations on the message here.
|
|
* @param Swift_Events_SendEvent The event object for sending a message
|
|
*/
|
|
public function beforeSendPerformed(Swift_Events_SendEvent $e)
|
|
{
|
|
$message = $e->getMessage();
|
|
$this->recursiveRestore($message, $this->store); //3.3.3 bugfix
|
|
|
|
$recipients = $e->getRecipients();
|
|
$to = array_keys($recipients->getTo());
|
|
if (count($to) > 0) $to = $to[0];
|
|
else return;
|
|
|
|
$replacements = (array)$this->replacements->getReplacementsFor($to);
|
|
|
|
$this->store = array(
|
|
"headers" => array(),
|
|
"body" => false,
|
|
"children" => array()
|
|
);
|
|
$this->recursiveReplace($message, $replacements, $this->store);
|
|
}
|
|
/**
|
|
* Replace strings in the message searching through all the allowed sub-parts.
|
|
* @param Swift_Message_Mime The message (or part)
|
|
* @param array The list of replacements
|
|
* @param array The array to cache original values into where needed
|
|
*/
|
|
protected function recursiveReplace(Swift_Message_Mime $mime, $replacements, &$store)
|
|
{
|
|
//Check headers
|
|
if ($this->getPermittedInHeaders())
|
|
{
|
|
foreach ($mime->headers->getList() as $name => $value)
|
|
{
|
|
if (is_string($value) && ($replaced = $this->replace($replacements, $value)) != $value)
|
|
{
|
|
$mime->headers->set($name, $replaced);
|
|
$store["headers"][$name] = array();
|
|
$store["headers"][$name]["value"] = $value;
|
|
$store["headers"][$name]["attributes"] = array();
|
|
}
|
|
foreach ($mime->headers->listAttributes($name) as $att_name => $att_value)
|
|
{
|
|
if (is_string($att_value)
|
|
&& ($att_replaced = $this->replace($replacements, $att_value)) != $att_value)
|
|
{
|
|
if (!isset($store["headers"][$name]))
|
|
{
|
|
$store["headers"][$name] = array("value" => false, "attributes" => array());
|
|
}
|
|
$mime->headers->setAttribute($name, $att_name, $att_replaced);
|
|
$store["headers"][$name]["attributes"][$att_name] = $att_value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Check body
|
|
$body = $mime->getData();
|
|
if ($this->isPermittedType($mime->getContentType())
|
|
&& is_string($body) && ($replaced = $this->replace($replacements, $body)) != $body)
|
|
{
|
|
$mime->setData($replaced);
|
|
$store["body"] = $body;
|
|
}
|
|
//Check sub-parts
|
|
foreach ($mime->listChildren() as $id)
|
|
{
|
|
$store["children"][$id] = array(
|
|
"headers" => array(),
|
|
"body" => false,
|
|
"children" => array()
|
|
);
|
|
$child = $mime->getChild($id);
|
|
$this->recursiveReplace($child, $replacements, $store["children"][$id]);
|
|
}
|
|
}
|
|
/**
|
|
* Perform a str_replace() over the given value.
|
|
* @param array The list of replacements as (search => replacement)
|
|
* @param string The string to replace
|
|
* @return string
|
|
*/
|
|
protected function replace($replacements, $value)
|
|
{
|
|
return str_replace(array_keys($replacements), array_values($replacements), $value);
|
|
}
|
|
/**
|
|
* Put the original values back in the message after it was modified before sending.
|
|
* @param Swift_Message_Mime The message (or part)
|
|
* @param array The location of the stored values
|
|
*/
|
|
protected function recursiveRestore(Swift_Message_Mime $mime, &$store)
|
|
{
|
|
if (empty($store)) //3.3.3 bugfix
|
|
{
|
|
return;
|
|
}
|
|
|
|
//Restore headers
|
|
foreach ($store["headers"] as $name => $array)
|
|
{
|
|
if ($array["value"] !== false) $mime->headers->set($name, $array["value"]);
|
|
foreach ($array["attributes"] as $att_name => $att_value)
|
|
{
|
|
$mime->headers->setAttribute($name, $att_name, $att_value);
|
|
}
|
|
}
|
|
//Restore body
|
|
if ($store["body"] !== false)
|
|
{
|
|
$mime->setData($store["body"]);
|
|
}
|
|
//Restore children
|
|
foreach ($store["children"] as $id => $child_store)
|
|
{
|
|
$child = $mime->getChild($id);
|
|
$this->recursiveRestore($child, $child_store);
|
|
}
|
|
}
|
|
/**
|
|
* Set the replacements as a 2-d array or an instance of Swift_Plugin_Decorator_Replacements.
|
|
* @param mixed Array or Swift_Plugin_Decorator_Replacements
|
|
*/
|
|
public function setReplacements($replacements)
|
|
{
|
|
if ($replacements === null)
|
|
{
|
|
$r = array();
|
|
$this->replacements = new Swift_Plugin_Decorator_Replacements($r);
|
|
}
|
|
elseif (is_array($replacements))
|
|
{
|
|
$this->replacements = new Swift_Plugin_Decorator_Replacements($replacements);
|
|
}
|
|
elseif ($replacements instanceof Swift_Plugin_Decorator_Replacements)
|
|
{
|
|
$this->replacements = $replacements;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception(
|
|
"Decorator replacements must be array or instance of Swift_Plugin_Decorator_Replacements.");
|
|
}
|
|
}
|
|
/**
|
|
* Get the replacements object.
|
|
* @return Swift_Plugin_Decorator_Replacements
|
|
*/
|
|
public function getReplacements()
|
|
{
|
|
return $this->replacements;
|
|
}
|
|
}
|