|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2010-2011 Jigal van Hemert <jigal@xs4all.nl> 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00027 00028 /** 00029 * Hook subscriber for using Swift Mailer with the t3lib_utility_mail function 00030 * 00031 * $Id$ 00032 * 00033 * @author Jigal van Hemert <jigal@xs4all.nl> 00034 * @package TYPO3 00035 * @subpackage t3lib 00036 */ 00037 class t3lib_mail_SwiftMailerAdapter implements t3lib_mail_MailerAdapter { 00038 00039 /** @var $mailer t3lib_mail_Mailer */ 00040 protected $mailer; 00041 00042 /** @var $message Swift_Message */ 00043 protected $message; 00044 00045 /** @var $messageHeaders Swift_Mime_HeaderSet */ 00046 protected $messageHeaders; 00047 00048 /** @var string */ 00049 protected $boundary = ''; 00050 00051 /** 00052 * Constructor 00053 * 00054 * @return void 00055 */ 00056 public function __construct() { 00057 // create mailer object 00058 $this->mailer = t3lib_div::makeInstance('t3lib_mail_Mailer'); 00059 // create message object 00060 $this->message = Swift_Message::newInstance(); 00061 } 00062 00063 /** 00064 * Parses parts of the mail message and sends it with the Swift Mailer functions 00065 * 00066 * @param string $to Email address to send the message to 00067 * @param string $subject Subject of mail message 00068 * @param string $messageBody Raw body (may be multipart) 00069 * @param array $additionalHeaders Additional mail headers 00070 * @param array $additionalParameters Extra parameters for the mail() command 00071 * @param bool $fakeSending If set fake sending a mail 00072 * @throws t3lib_exception 00073 * @return bool 00074 */ 00075 public function mail($to, $subject, $messageBody, $additionalHeaders = NULL, $additionalParameters = NULL, $fakeSending = FALSE) { 00076 00077 // report success for fake sending 00078 if ($fakeSending === TRUE) { 00079 return TRUE; 00080 } 00081 $this->message->setSubject($subject); 00082 // handle recipients 00083 $toAddresses = $this->parseAddresses($to); 00084 $this->message->setTo($toAddresses); 00085 // handle additional headers 00086 $headers = t3lib_div::trimExplode(LF, $additionalHeaders, TRUE); 00087 $this->messageHeaders = $this->message->getHeaders(); 00088 foreach ($headers as $header) { 00089 list($headerName, $headerValue) = t3lib_div::trimExplode(':', $header, FALSE, 2); 00090 $this->setHeader($headerName, $headerValue); 00091 } 00092 // handle additional parameters (force return path) 00093 if (preg_match('/-f\s*(\S*?)/', $additionalParameters, $matches)) { 00094 $this->message->setReturnPath($this->unescapeShellArguments($matches[1])); 00095 } 00096 // handle from: 00097 $this->fixSender(); 00098 // handle message body 00099 $this->setBody($messageBody); 00100 // send mail 00101 $result = $this->mailer->send($this->message); 00102 00103 // report success/failure 00104 return (bool) $result; 00105 } 00106 00107 /** 00108 * Tries to undo the action by escapeshellarg() 00109 * 00110 * @param $escapedString String escaped by escapeshellarg() 00111 * @return string String with escapeshellarg() action undone as best as possible 00112 */ 00113 protected function unescapeShellArguments($escapedString) { 00114 if (TYPO3_OS === 'WIN') { 00115 // on Windows double quotes are used and % signs are replaced by spaces 00116 if (preg_match('/^"([^"]*)"$/', trim($escapedString), $matches)) { 00117 $result = str_replace('\"', '"', $matches[1]); 00118 // % signs are replaced with spaces, so they can't be recovered 00119 } 00120 } else { 00121 // on Unix-like systems single quotes are escaped 00122 if (preg_match('/^\'([^' . preg_quote('\'') . ']*)\'$/', trim($escapedString), $matches)) { 00123 $result = str_replace('\\\'', '\'', $matches[1]); 00124 } 00125 } 00126 return $result; 00127 } 00128 00129 /** 00130 * Handles setting and replacing of mail headers 00131 * 00132 * @param $headerName Name of header 00133 * @param $headerValue Value of header 00134 * @return void 00135 */ 00136 protected function setHeader($headerName, $headerValue) { 00137 // check for boundary in headers 00138 if (preg_match('/^boundary="(.*)"$/', $headerName, $matches) > 0) { 00139 $this->boundary = $matches[1]; 00140 return; 00141 } 00142 // process other, real headers 00143 if ($this->messageHeaders->has($headerName)) { 00144 $header = $this->messageHeaders->get($headerName); 00145 $headerType = $header->getFieldType(); 00146 switch ($headerType) { 00147 case Swift_Mime_Header::TYPE_TEXT: 00148 $header->setValue($headerValue); 00149 break; 00150 case Swift_Mime_Header::TYPE_PARAMETERIZED: 00151 $header->setValue(rtrim($headerValue, ';')); 00152 break; 00153 case Swift_Mime_Header::TYPE_MAILBOX: 00154 $addressList = $this->parseAddresses($headerValue); 00155 if (count($addressList) > 0) { 00156 $header->setNameAddresses($addressList); 00157 } 00158 break; 00159 case Swift_Mime_Header::TYPE_DATE: 00160 $header->setTimeStamp(strtotime($headerValue)); 00161 break; 00162 case Swift_Mime_Header::TYPE_ID: 00163 // remove '<' and '>' from ID headers 00164 $header->setId(trim($headerValue, '<>')); 00165 break; 00166 case Swift_Mime_Header::TYPE_PATH: 00167 $header->setAddress($headerValue); 00168 break; 00169 } 00170 // change value 00171 } else { 00172 switch ($headerName) { 00173 // mailbox headers 00174 case 'From': 00175 case 'To': 00176 case 'Cc': 00177 case 'Bcc': 00178 case 'Reply-To': 00179 case 'Sender': 00180 $addressList = $this->parseAddresses($headerValue); 00181 if (count($addressList) > 0) { 00182 $this->messageHeaders->addMailboxHeader($headerName, $addressList); 00183 } 00184 break; 00185 // date headers 00186 case 'Date': 00187 $this->messageHeaders->addDateHeader($headerName, strtotime($headerValue)); 00188 break; 00189 // ID headers 00190 case 'Message-ID': 00191 // remove '<' and '>' from ID headers 00192 $this->messageHeaders->addIdHeader($headerName, trim($headerValue, '<>')); 00193 // path headers 00194 case 'Return-Path': 00195 $this->messageHeaders->addPathHeader($headerName, $headerValue); 00196 break; 00197 // parameterized headers 00198 case 'Content-Type': 00199 case 'Content-Disposition': 00200 $this->messageHeaders->addParameterizedHeader($headerName, rtrim($headerValue, ';')); 00201 break; 00202 // text headers 00203 default: 00204 $this->messageHeaders->addTextheader($headerName, $headerValue); 00205 break; 00206 } 00207 } 00208 } 00209 00210 /** 00211 * Sets body of mail message. Handles multi-part and single part messages. Encoded body parts are decoded prior to adding 00212 * them to the message object. 00213 * 00214 * @param string $body Raw body, may be multi-part 00215 * @return void 00216 */ 00217 protected function setBody($body) { 00218 if ($this->boundary) { 00219 // handle multi-part 00220 $bodyParts = preg_split('/--' . preg_quote($this->boundary) . '(--)?/m', $body, NULL, PREG_SPLIT_NO_EMPTY); 00221 foreach ($bodyParts as $bodyPart) { 00222 // skip empty parts 00223 if (trim($bodyPart) == '') { 00224 continue; 00225 } 00226 // keep leading white space when exploding the text 00227 $lines = explode(LF, $bodyPart); 00228 // set defaults for this part 00229 $encoding = ''; 00230 $charset = 'utf-8'; 00231 $contentType = 'text/plain'; 00232 // skip intro messages 00233 if (trim($lines[0]) == 'This is a multi-part message in MIME format.') { 00234 continue; 00235 } 00236 // first line is empty leftover from splitting 00237 array_shift($lines); 00238 while (count($lines) > 0) { 00239 $line = array_shift($lines); 00240 if (preg_match('/^content-type:(.*);( charset=(.*))?$/i', $line, $matches)) { 00241 $contentType = trim($matches[1]); 00242 if ($matches[2]) { 00243 $charset = trim($matches[3]); 00244 } 00245 } else if (preg_match('/^content-transfer-encoding:(.*)$/i', $line, $matches)) { 00246 $encoding = trim($matches[1]); 00247 } else if (strlen(trim($line)) == 0) { 00248 // empty line before actual content of this part 00249 break; 00250 } 00251 } 00252 // use rest of part as body, but reverse encoding first 00253 $bodyPart = $this->decode(implode(LF, $lines), $encoding); 00254 $this->message->addPart($bodyPart, $contentType, $charset); 00255 } 00256 } else { 00257 // Handle single body 00258 // The headers have already been set, so use header information 00259 $contentType = $this->message->getContentType(); 00260 $charset = $this->message->getCharset(); 00261 $encoding = $this->message->getEncoder()->getName(); 00262 // reverse encoding and set body 00263 $rawBody = $this->decode($body, $encoding); 00264 $this->message->setBody($rawBody, $contentType, $charset); 00265 } 00266 } 00267 00268 /** 00269 * Reverts encoding of body text 00270 * 00271 * @param string $text Body text to be decoded 00272 * @param string $encoding Encoding type to be reverted 00273 * @return string Decoded message body 00274 */ 00275 protected function decode($text, $encoding) { 00276 $result = $text; 00277 switch ($encoding) { 00278 case 'quoted-printable': 00279 $result = quoted_printable_decode($text); 00280 break; 00281 case 'base64': 00282 $result = base64_decode($text); 00283 break; 00284 } 00285 return $result; 00286 } 00287 00288 /** 00289 * Parses mailbox headers and turns them into an array. 00290 * 00291 * Mailbox headers are a comma separated list of 'name <email@example.org' combinations or plain email addresses (or a mix 00292 * of these). 00293 * The resulting array has key-value pairs where the key is either a number (no display name in the mailbox header) and the 00294 * value is the email address, or the key is the email address and the value is the display name. 00295 * 00296 * @param string $rawAddresses Comma separated list of email addresses (optionally with display name) 00297 * @return array Parsed list of addresses. 00298 */ 00299 protected function parseAddresses($rawAddresses = '') { 00300 /** @var $addressParser t3lib_mail_Rfc822AddressesParser */ 00301 $addressParser = t3lib_div::makeInstance('t3lib_mail_Rfc822AddressesParser', $rawAddresses); 00302 $addresses = $addressParser->parseAddressList(); 00303 $addressList = array(); 00304 foreach ($addresses as $address) { 00305 if ($address->personal) { 00306 // item with name found ( name <email@example.org> ) 00307 $addressList[$address->mailbox . '@' . $address->host] = $address->personal; 00308 } else { 00309 // item without name found ( email@example.org ) 00310 $addressList[] = $address->mailbox . '@' . $address->host; 00311 } 00312 } 00313 return $addressList; 00314 } 00315 00316 /** 00317 * Makes sure there is a correct sender set. 00318 * 00319 * If there is no from header the returnpath will be used. If that also fails a fake address will be used to make sure 00320 * Swift Mailer will be able to send the message. Some SMTP server will not accept mail messages without a valid sender. 00321 * 00322 * @return void 00323 */ 00324 protected function fixSender() { 00325 $from = $this->message->getFrom(); 00326 if (count($from) > 0) { 00327 reset($from); 00328 list($fromAddress, $fromName) = each($from); 00329 } else { 00330 $fromAddress = $this->message->getReturnPath(); 00331 $fromName = $fromAddress; 00332 } 00333 if (strlen($fromAddress) == 0) { 00334 $fromAddress = 'no-reply@example.org'; 00335 $fromName = 'TYPO3 CMS'; 00336 } 00337 $this->message->setFrom(array($fromAddress => $fromName)); 00338 } 00339 } 00340 ?>
1.8.0