[TASK] Correct DBAL ux_* class mapping in migrations file
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_formmail.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains a class for formmail
29 *
30 * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj
31 *
32 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
33 */
34 /**
35 * Formmail class, used by the TYPO3 "cms" extension (default frontend) to send email forms.
36 *
37 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
38 * @package TYPO3
39 * @subpackage t3lib
40 * @see tslib_fe::sendFormmail(), t3lib/formmail.php
41 */
42 class t3lib_formmail {
43
44 protected $reserved_names = 'recipient,recipient_copy,auto_respond_msg,auto_respond_checksum,redirect,subject,attachment,from_email,from_name,replyto_email,replyto_name,organisation,priority,html_enabled,quoted_printable,submit_x,submit_y';
45
46 // Collection of suspicious header data, used for logging
47 protected $dirtyHeaders = array();
48
49 protected $characterSet;
50
51 protected $subject;
52
53 protected $fromName;
54
55 protected $replyToName;
56
57 protected $organisation;
58
59 protected $fromAddress;
60
61 protected $replyToAddress;
62
63 protected $priority;
64
65 protected $autoRespondMessage;
66
67 protected $encoding = 'quoted-printable';
68
69 /**
70 * @var \TYPO3\CMS\Core\Mail\MailMessage
71 */
72 protected $mailMessage;
73
74 protected $recipient;
75
76 protected $plainContent = '';
77
78 /**
79 * @var array Files to clean up at the end (attachments)
80 */
81 protected $temporaryFiles = array();
82
83 /**
84 * Start function
85 * This class is able to generate a mail in formmail-style from the data in $V
86 * Fields:
87 *
88 * [recipient]: email-adress of the one to receive the mail. If array, then all values are expected to be recipients
89 * [attachment]: ....
90 *
91 * [subject]: The subject of the mail
92 * [from_email]: Sender email. If not set, [email] is used
93 * [from_name]: Sender name. If not set, [name] is used
94 * [replyto_email]: Reply-to email. If not set [from_email] is used
95 * [replyto_name]: Reply-to name. If not set [from_name] is used
96 * [organisation]: Organization (header)
97 * [priority]: Priority, 1-5, default 3
98 * [html_enabled]: If mail is sent as html
99 * [use_base64]: If set, base64 encoding will be used instead of quoted-printable
100 *
101 * @param array $valueList Contains values for the field names listed above (with slashes removed if from POST input)
102 * @param boolean $base64 Whether to base64 encode the mail content
103 * @return void
104 * @todo Define visibility
105 */
106 public function start($valueList, $base64 = FALSE) {
107 $this->mailMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Mail\\MailMessage');
108 if ($GLOBALS['TSFE']->config['config']['formMailCharset']) {
109 // Respect formMailCharset if it was set
110 $this->characterSet = $GLOBALS['TSFE']->csConvObj->parse_charset($GLOBALS['TSFE']->config['config']['formMailCharset']);
111 } elseif ($GLOBALS['TSFE']->metaCharset != $GLOBALS['TSFE']->renderCharset) {
112 // Use metaCharset for mail if different from renderCharset
113 $this->characterSet = $GLOBALS['TSFE']->metaCharset;
114 } else {
115 // Otherwise use renderCharset as default
116 $this->characterSet = $GLOBALS['TSFE']->renderCharset;
117 }
118 if ($base64 || $valueList['use_base64']) {
119 $this->encoding = 'base64';
120 }
121 if (isset($valueList['recipient'])) {
122 // Convert form data from renderCharset to mail charset
123 $this->subject = $valueList['subject'] ? $valueList['subject'] : 'Formmail on ' . \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('HTTP_HOST');
124 $this->subject = $this->sanitizeHeaderString($this->subject);
125 $this->fromName = $valueList['from_name'] ? $valueList['from_name'] : ($valueList['name'] ? $valueList['name'] : '');
126 $this->fromName = $this->sanitizeHeaderString($this->fromName);
127 $this->replyToName = $valueList['replyto_name'] ? $valueList['replyto_name'] : $this->fromName;
128 $this->replyToName = $this->sanitizeHeaderString($this->replyToName);
129 $this->organisation = $valueList['organisation'] ? $valueList['organisation'] : '';
130 $this->organisation = $this->sanitizeHeaderString($this->organisation);
131 $this->fromAddress = $valueList['from_email'] ? $valueList['from_email'] : ($valueList['email'] ? $valueList['email'] : '');
132 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::validEmail($this->fromAddress)) {
133 $this->fromAddress = \TYPO3\CMS\Core\Utility\MailUtility::getSystemFromAddress();
134 $this->fromName = \TYPO3\CMS\Core\Utility\MailUtility::getSystemFromName();
135 }
136 $this->replyToAddress = $valueList['replyto_email'] ? $valueList['replyto_email'] : $this->fromAddress;
137 $this->priority = $valueList['priority'] ? \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($valueList['priority'], 1, 5) : 3;
138 // Auto responder
139 $this->autoRespondMessage = trim($valueList['auto_respond_msg']) && $this->fromAddress ? trim($valueList['auto_respond_msg']) : '';
140 if ($this->autoRespondMessage !== '') {
141 // Check if the value of the auto responder message has been modified with evil intentions
142 $autoRespondChecksum = $valueList['auto_respond_checksum'];
143 $correctHmacChecksum = \TYPO3\CMS\Core\Utility\GeneralUtility::hmac($this->autoRespondMessage);
144 if ($autoRespondChecksum !== $correctHmacChecksum) {
145 \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog('Possible misuse of t3lib_formmail auto respond method. Subject: ' . $valueList['subject'], 'Core', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_ERROR);
146 return;
147 } else {
148 $this->autoRespondMessage = $this->sanitizeHeaderString($this->autoRespondMessage);
149 }
150 }
151 $plainTextContent = '';
152 $htmlContent = '<table border="0" cellpadding="2" cellspacing="2">';
153 // Runs through $V and generates the mail
154 if (is_array($valueList)) {
155 foreach ($valueList as $key => $val) {
156 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::inList($this->reserved_names, $key)) {
157 $space = strlen($val) > 60 ? LF : '';
158 $val = is_array($val) ? implode($val, LF) : $val;
159 // Convert form data from renderCharset to mail charset (HTML may use entities)
160 $plainTextValue = $val;
161 $HtmlValue = htmlspecialchars($val);
162 $plainTextContent .= ((((strtoupper($key) . ': ') . $space) . $plainTextValue) . LF) . $space;
163 $htmlContent .= ((('<tr><td bgcolor="#eeeeee"><font face="Verdana" size="1"><strong>' . strtoupper($key)) . '</strong></font></td><td bgcolor="#eeeeee"><font face="Verdana" size="1">') . nl2br($HtmlValue)) . '&nbsp;</font></td></tr>';
164 }
165 }
166 }
167 $htmlContent .= '</table>';
168 $this->plainContent = $plainTextContent;
169 if ($valueList['html_enabled']) {
170 $this->mailMessage->setBody($htmlContent, 'text/html', $this->characterSet);
171 $this->mailMessage->addPart($plainTextContent, 'text/plain', $this->characterSet);
172 } else {
173 $this->mailMessage->setBody($plainTextContent, 'text/plain', $this->characterSet);
174 }
175 for ($a = 0; $a < 10; $a++) {
176 $variableName = 'attachment' . ($a ? $a : '');
177 if (!isset($_FILES[$variableName])) {
178 continue;
179 }
180 if (!is_uploaded_file($_FILES[$variableName]['tmp_name'])) {
181 \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog(((('Possible abuse of t3lib_formmail: temporary file "' . $_FILES[$variableName]['tmp_name']) . '" ("') . $_FILES[$variableName]['name']) . '") was not an uploaded file.', 'Core', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_ERROR);
182 }
183 if ($_FILES[$variableName]['tmp_name']['error'] !== UPLOAD_ERR_OK) {
184 \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog((((('Error in uploaded file in t3lib_formmail: temporary file "' . $_FILES[$variableName]['tmp_name']) . '" ("') . $_FILES[$variableName]['name']) . '") Error code: ') . $_FILES[$variableName]['tmp_name']['error'], 'Core', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_ERROR);
185 }
186 $theFile = \TYPO3\CMS\Core\Utility\GeneralUtility::upload_to_tempfile($_FILES[$variableName]['tmp_name']);
187 $theName = $_FILES[$variableName]['name'];
188 if ($theFile && file_exists($theFile)) {
189 if (filesize($theFile) < $GLOBALS['TYPO3_CONF_VARS']['FE']['formmailMaxAttachmentSize']) {
190 $this->mailMessage->attach(Swift_Attachment::fromPath($theFile)->setFilename($theName));
191 }
192 }
193 $this->temporaryFiles[] = $theFile;
194 }
195 $from = $this->fromName ? array($this->fromAddress => $this->fromName) : array($this->fromAddress);
196 $this->recipient = $this->parseAddresses($valueList['recipient']);
197 $this->mailMessage->setSubject($this->subject)->setFrom($from)->setTo($this->recipient)->setPriority($this->priority);
198 $replyTo = $this->replyToName ? array($this->replyToAddress => $this->replyToName) : array($this->replyToAddress);
199 $this->mailMessage->setReplyTo($replyTo);
200 $this->mailMessage->getHeaders()->addTextHeader('Organization', $this->organisation);
201 if ($valueList['recipient_copy']) {
202 $this->mailMessage->setCc($this->parseAddresses($valueList['recipient_copy']));
203 }
204 $this->mailMessage->setCharset($this->characterSet);
205 // Ignore target encoding. This is handled automatically by Swift Mailer and overriding the defaults
206 // is not worth the trouble
207 // Log dirty header lines
208 if ($this->dirtyHeaders) {
209 \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog('Possible misuse of t3lib_formmail: see TYPO3 devLog', 'Core', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_ERROR);
210 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['enable_DLOG']) {
211 \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('t3lib_formmail: ' . \TYPO3\CMS\Core\Utility\GeneralUtility::arrayToLogString($this->dirtyHeaders, '', 200), 'Core', 3);
212 }
213 }
214 }
215 }
216
217 /**
218 * Checks string for suspicious characters
219 *
220 * @param string $string String to check
221 * @return string Valid or empty string
222 */
223 protected function sanitizeHeaderString($string) {
224 $pattern = '/[\\r\\n\\f\\e]/';
225 if (preg_match($pattern, $string) > 0) {
226 $this->dirtyHeaders[] = $string;
227 $string = '';
228 }
229 return $string;
230 }
231
232 /**
233 * Parses mailbox headers and turns them into an array.
234 *
235 * Mailbox headers are a comma separated list of 'name <email@example.org' combinations or plain email addresses (or a mix
236 * of these).
237 * The resulting array has key-value pairs where the key is either a number (no display name in the mailbox header) and the
238 * value is the email address, or the key is the email address and the value is the display name.
239 *
240 * @param string $rawAddresses Comma separated list of email addresses (optionally with display name)
241 * @return array Parsed list of addresses.
242 */
243 protected function parseAddresses($rawAddresses = '') {
244 /** @var $addressParser \TYPO3\CMS\Core\Mail\Rfc822AddressesParser */
245 $addressParser = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Mail\\Rfc822AddressesParser', $rawAddresses);
246 $addresses = $addressParser->parseAddressList();
247 $addressList = array();
248 foreach ($addresses as $address) {
249 if ($address->personal) {
250 // Item with name found ( name <email@example.org> )
251 $addressList[($address->mailbox . '@') . $address->host] = $address->personal;
252 } else {
253 // Item without name found ( email@example.org )
254 $addressList[] = ($address->mailbox . '@') . $address->host;
255 }
256 }
257 return $addressList;
258 }
259
260 /**
261 * Sends the actual mail and handles autorespond message
262 *
263 * @return boolean
264 */
265 public function sendTheMail() {
266 // Sending the mail requires the recipient and message to be set.
267 if (!$this->mailMessage->getTo() || !trim($this->mailMessage->getBody())) {
268 return FALSE;
269 }
270 $this->mailMessage->send();
271 // Auto response
272 if ($this->autoRespondMessage) {
273 $theParts = explode('/', $this->autoRespondMessage, 2);
274 $theParts[0] = str_replace('###SUBJECT###', $this->subject, $theParts[0]);
275 $theParts[1] = str_replace('/', LF, $theParts[1]);
276 $theParts[1] = str_replace('###MESSAGE###', $this->plainContent, $theParts[1]);
277 /** @var $autoRespondMail \TYPO3\CMS\Core\Mail\MailMessage */
278 $autoRespondMail = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Mail\\MailMessage');
279 $autoRespondMail->setTo($this->fromAddress)->setSubject($theParts[0])->setFrom($this->recipient)->setBody($theParts[1]);
280 $autoRespondMail->send();
281 }
282 return $this->mailMessage->isSent();
283 }
284
285 /**
286 * Do some cleanup at the end (deleting attachment files)
287 */
288 public function __destruct() {
289 foreach ($this->temporaryFiles as $file) {
290 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isAllowedAbsPath($file) && \TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($file, PATH_site . 'typo3temp/upload_temp_')) {
291 \TYPO3\CMS\Core\Utility\GeneralUtility::unlink_tempfile($file);
292 }
293 }
294 }
295
296 }
297
298 ?>