/formtools/modules/swift_mailer/php4/Swift/Plugin/Decorator.php

https://bitbucket.org/lihorne/tedxuw · PHP · 258 lines · 154 code · 8 blank · 96 comment · 18 complexity · a480e902978e43e808163b4cae7dafd4 MD5 · raw file

  1. <?php
  2. /**
  3. * Swift Mailer Message Decorating Plugin.
  4. * Please read the LICENSE file
  5. * @author Chris Corbyn <chris@w3style.co.uk>
  6. * @package Swift_Plugin
  7. * @subpackage Decorator
  8. * @license GNU Lesser General Public License
  9. */
  10. require_once dirname(__FILE__) . "/../ClassLoader.php";
  11. Swift_ClassLoader::load("Swift_Plugin_Decorator_Replacements");
  12. /**
  13. * Swift Decorator Plugin.
  14. * Allows messages to be slightly different for each recipient.
  15. * @package Swift_Plugin
  16. * @subpackage Decorator
  17. * @author Chris Corbyn <chris@w3style.co.uk>
  18. */
  19. class Swift_Plugin_Decorator extends Swift_Events_Listener
  20. {
  21. /**
  22. * The replacements object.
  23. * @var Swift_Plugin_Decorator_Replacements
  24. */
  25. var $replacements;
  26. /**
  27. * Temporary storage so we can restore changes we make.
  28. * @var array
  29. */
  30. var $store;
  31. /**
  32. * A list of allowed mime types to replace bodies for.
  33. * @var array
  34. */
  35. var $permittedTypes = array("text/plain" => 1, "text/html" => 1);
  36. /**
  37. * True if values in the headers can be replaced
  38. * @var boolean
  39. */
  40. var $permittedInHeaders = true;
  41. /**
  42. * Ctor.
  43. * @param mixed Replacements as a 2-d array or Swift_Plugin_Decorator_Replacements instance.
  44. */
  45. function Swift_Plugin_Decorator($replacements=null)
  46. {
  47. $this->setReplacements($replacements);
  48. }
  49. /**
  50. * Enable of disable the ability to replace values in the headers
  51. * @param boolean
  52. */
  53. function setPermittedInHeaders($bool)
  54. {
  55. $this->permittedInHeaders = (bool) $bool;
  56. }
  57. /**
  58. * Check if replacements in headers are allowed.
  59. * @return boolean
  60. */
  61. function getPermittedInHeaders()
  62. {
  63. return $this->permittedInHeaders;
  64. }
  65. /**
  66. * Add a mime type to the list of permitted type to replace values in the body.
  67. * @param string The mime type (e.g. text/plain)
  68. */
  69. function addPermittedType($type)
  70. {
  71. $type = strtolower($type);
  72. $this->permittedTypes[$type] = 1;
  73. }
  74. /**
  75. * Remove the ability to replace values in the body of the given mime type
  76. * @param string The mime type
  77. */
  78. function removePermittedType($type)
  79. {
  80. unset($this->permittedTypes[$type]);
  81. }
  82. /**
  83. * Get the list of mime types for which the body can be changed.
  84. * @return array
  85. */
  86. function getPermittedTypes()
  87. {
  88. return array_keys($this->permittedTypes);
  89. }
  90. /**
  91. * Check if the body can be replaced in the given mime type.
  92. * @param string The mime type
  93. * @return boolean
  94. */
  95. function isPermittedType($type)
  96. {
  97. return array_key_exists(strtolower($type), $this->permittedTypes);
  98. }
  99. /**
  100. * Called just before Swift sends a message.
  101. * We perform operations on the message here.
  102. * @param Swift_Events_SendEvent The event object for sending a message
  103. */
  104. function beforeSendPerformed(&$e)
  105. {
  106. $message =& $e->getMessage();
  107. $this->recursiveRestore($message, $this->store);
  108. $recipients =& $e->getRecipients();
  109. $to = array_keys($recipients->getTo());
  110. if (count($to) > 0) $to = $to[0];
  111. else return;
  112. $replacements = (array)$this->replacements->getReplacementsFor($to);
  113. $this->store = array(
  114. "headers" => array(),
  115. "body" => false,
  116. "children" => array()
  117. );
  118. $this->recursiveReplace($message, $replacements, $this->store);
  119. }
  120. /**
  121. * Replace strings in the message searching through all the allowed sub-parts.
  122. * @param Swift_Message_Mime The message (or part)
  123. * @param array The list of replacements
  124. * @param array The array to cache original values into where needed
  125. */
  126. function recursiveReplace(&$mime, $replacements, &$store)
  127. {
  128. //Check headers
  129. if ($this->getPermittedInHeaders())
  130. {
  131. foreach ($mime->headers->getList() as $name => $value)
  132. {
  133. if (is_string($value) && ($replaced = $this->replace($replacements, $value)) != $value)
  134. {
  135. $mime->headers->set($name, $replaced);
  136. $store["headers"][$name] = array();
  137. $store["headers"][$name]["value"] = $value;
  138. $store["headers"][$name]["attributes"] = array();
  139. }
  140. foreach ($mime->headers->listAttributes($name) as $att_name => $att_value)
  141. {
  142. if (is_string($att_value)
  143. && ($att_replaced = $this->replace($replacements, $att_value)) != $att_value)
  144. {
  145. if (!isset($store["headers"][$name]))
  146. {
  147. $store["headers"][$name] = array("value" => false, "attributes" => array());
  148. }
  149. $mime->headers->setAttribute($name, $att_name, $att_replaced);
  150. $store["headers"][$name]["attributes"][$att_name] = $att_value;
  151. }
  152. }
  153. }
  154. }
  155. //Check body
  156. $body = $mime->getData();
  157. if ($this->isPermittedType($mime->getContentType())
  158. && is_string($body) && ($replaced = $this->replace($replacements, $body)) != $body)
  159. {
  160. $mime->setData($replaced);
  161. $store["body"] = $body;
  162. }
  163. //Check sub-parts
  164. foreach ($mime->listChildren() as $id)
  165. {
  166. $store["children"][$id] = array(
  167. "headers" => array(),
  168. "body" => false,
  169. "children" => array()
  170. );
  171. $child =& $mime->getChild($id);
  172. $this->recursiveReplace($child, $replacements, $store["children"][$id]);
  173. }
  174. }
  175. /**
  176. * Perform a str_replace() over the given value.
  177. * @param array The list of replacements as (search => replacement)
  178. * @param string The string to replace
  179. * @return string
  180. */
  181. function replace($replacements, $value)
  182. {
  183. return str_replace(array_keys($replacements), array_values($replacements), $value);
  184. }
  185. /**
  186. * Put the original values back in the message after it was modified before sending.
  187. * @param Swift_Message_Mime The message (or part)
  188. * @param array The location of the stored values
  189. */
  190. function recursiveRestore(&$mime, &$store)
  191. {
  192. if (empty($store)) //3.3.3 bugfix
  193. {
  194. return;
  195. }
  196. //Restore headers
  197. foreach ($store["headers"] as $name => $array)
  198. {
  199. if ($array["value"] !== false) $mime->headers->set($name, $array["value"]);
  200. foreach ($array["attributes"] as $att_name => $att_value)
  201. {
  202. $mime->headers->setAttribute($name, $att_name, $att_value);
  203. }
  204. }
  205. //Restore body
  206. if ($store["body"] !== false)
  207. {
  208. $mime->setData($store["body"]);
  209. }
  210. //Restore children
  211. foreach ($store["children"] as $id => $child_store)
  212. {
  213. $child =& $mime->getChild($id);
  214. $this->recursiveRestore($child, $child_store);
  215. }
  216. }
  217. /**
  218. * Set the replacements as a 2-d array or an instance of Swift_Plugin_Decorator_Replacements.
  219. * @param mixed Array or Swift_Plugin_Decorator_Replacements
  220. */
  221. function setReplacements(&$replacements)
  222. {
  223. if ($replacements === null)
  224. {
  225. $r = array();
  226. $this->replacements =& new Swift_Plugin_Decorator_Replacements($r);
  227. }
  228. elseif (is_array($replacements))
  229. {
  230. $this->replacements =& new Swift_Plugin_Decorator_Replacements($replacements);
  231. }
  232. elseif (is_a($replacements, "Swift_Plugin_Decorator_Replacements"))
  233. {
  234. $this->replacements =& $replacements;
  235. }
  236. else
  237. {
  238. trigger_error(
  239. "Decorator replacements must be array or instance of Swift_Plugin_Decorator_Replacements.");
  240. }
  241. }
  242. /**
  243. * Get the replacements object.
  244. * @return Swift_Plugin_Decorator_Replacements
  245. */
  246. function &getReplacements()
  247. {
  248. return $this->replacements;
  249. }
  250. }