[TASK] FAL: Hard-coded flexform on storage creation
[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 * @TODO: Deprecate this class
42 */
43 class t3lib_formmail {
44
45 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';
46
47 // Collection of suspicious header data, used for logging
48 protected $dirtyHeaders = array();
49
50 protected $characterSet;
51
52 protected $subject;
53
54 protected $fromName;
55
56 protected $replyToName;
57
58 protected $organisation;
59
60 protected $fromAddress;
61
62 protected $replyToAddress;
63
64 protected $priority;
65
66 protected $autoRespondMessage;
67
68 protected $encoding = 'quoted-printable';
69
70 /**
71 * @var \TYPO3\CMS\Core\Mail\MailMessage
72 */
73 protected $mailMessage;
74
75 protected $recipient;
76
77 protected $plainContent = '';
78
79 /**
80 * @var array Files to clean up at the end (attachments)
81 */
82 protected $temporaryFiles = array();
83
84 /**
85 * Start function
86 * This class is able to generate a mail in formmail-style from the data in $V
87 * Fields:
88 *
89 * [recipient]: email-adress of the one to receive the mail. If array, then all values are expected to be recipients
90 * [attachment]: ....
91 *
92 * [subject]: The subject of the mail
93 * [from_email]: Sender email. If not set, [email] is used
94 * [from_name]: Sender name. If not set, [name] is used
95 * [replyto_email]: Reply-to email. If not set [from_email] is used
96 * [replyto_name]: Reply-to name. If not set [from_name] is used
97 * [organisation]: Organization (header)
98 * [priority]: Priority, 1-5, default 3
99 * [html_enabled]: If mail is sent as html
100 * [use_base64]: If set, base64 encoding will be used instead of quoted-printable
101 *
102 * @param array $valueList Contains values for the field names listed above (with slashes removed if from POST input)
103 * @param boolean $base64 Whether to base64 encode the mail content
104 * @return void
105 * @todo Define visibility
106 */
107 public function start($valueList, $base64 = FALSE) {
108 $this->mailMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Mail\\MailMessage');
109 if ($GLOBALS['TSFE']->config['config']['formMailCharset']) {
110 // Respect formMailCharset if it was set
111 $this->characterSet = $GLOBALS['TSFE']->csConvObj->parse_charset($GLOBALS['TSFE']->config['config']['formMailCharset']);
112 } elseif ($GLOBALS['TSFE']->metaCharset != $GLOBALS['TSFE']->renderCharset) {
113 // Use metaCharset for mail if different from renderCharset
114 $this->characterSet = $GLOBALS['TSFE']->metaCharset;
115 } else {
116 // Otherwise use renderCharset as default
117 $this->characterSet = $GLOBALS['TSFE']->renderCharset;
118 }
119 if ($base64 || $valueList['use_base64']) {
120 $this->encoding = 'base64';
121 }
122 if (isset($valueList['recipient'])) {
123 // Convert form data from renderCharset to mail charset
124 $this->subject = $valueList['subject'] ? $valueList['subject'] : 'Formmail on ' . \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('HTTP_HOST');
125 $this->subject = $this->sanitizeHeaderString($this->subject);
126 $this->fromName = $valueList['from_name'] ? $valueList['from_name'] : ($valueList['name'] ? $valueList['name'] : '');
127 $this->fromName = $this->sanitizeHeaderString($this->fromName);
128 $this->replyToName = $valueList['replyto_name'] ? $valueList['replyto_name'] : $this->fromName;
129 $this->replyToName = $this->sanitizeHeaderString($this->replyToName);
130 $this->organisation = $valueList['organisation'] ? $valueList['organisation'] : '';
131 $this->organisation = $this->sanitizeHeaderString($this->organisation);
132 $this->fromAddress = $valueList['from_email'] ? $valueList['from_email'] : ($valueList['email'] ? $valueList['email'] : '');
133 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::validEmail($this->fromAddress)) {
134 $this->fromAddress = \TYPO3\CMS\Core\Utility\MailUtility::getSystemFromAddress();
135 $this->fromName = \TYPO3\CMS\Core\Utility\MailUtility::getSystemFromName();
136 }
137 $this->replyToAddress = $valueList['replyto_email'] ? $valueList['replyto_email'] : $this->fromAddress;
138 $this->priority = $valueList['priority'] ? \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($valueList['priority'], 1, 5) : 3;
139 // Auto responder
140 $this->autoRespondMessage = trim($valueList['auto_respond_msg']) && $this->fromAddress ? trim($valueList['auto_respond_msg']) : '';
141 if ($this->autoRespondMessage !== '') {
142 // Check if the value of the auto responder message has been modified with evil intentions
143 $autoRespondChecksum = $valueList['auto_respond_checksum'];
144 $correctHmacChecksum = \TYPO3\CMS\Core\Utility\GeneralUtility::hmac($this->autoRespondMessage);
145 if ($autoRespondChecksum !== $correctHmacChecksum) {
146 \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);
147 return;
148 } else {
149 $this->autoRespondMessage = $this->sanitizeHeaderString($this->autoRespondMessage);
150 }
151 }
152 $plainTextContent = '';
153 $htmlContent = '<table border="0" cellpadding="2" cellspacing="2">';
154 // Runs through $V and generates the mail
155 if (is_array($valueList)) {
156 foreach ($valueList as $key => $val) {
157 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::inList($this->reserved_names, $key)) {
158 $space = strlen($val) > 60 ? LF : '';
159 $val = is_array($val) ? implode($val, LF) : $val;
160 // Convert form data from renderCharset to mail charset (HTML may use entities)
161 $plainTextValue = $val;
162 $HtmlValue = htmlspecialchars($val);
163 $plainTextContent .= strtoupper($key) . ': ' . $space . $plainTextValue . LF . $space;
164 $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>';
165 }
166 }
167 }
168 $htmlContent .= '</table>';
169 $this->plainContent = $plainTextContent;
170 if ($valueList['html_enabled']) {
171 $this->mailMessage->setBody($htmlContent, 'text/html', $this->characterSet);
172 $this->mailMessage->addPart($plainTextContent, 'text/plain', $this->characterSet);
173 } else {
174 $this->mailMessage->setBody($plainTextContent, 'text/plain', $this->characterSet);
175 }
176 for ($a = 0; $a < 10; $a++) {
177 $variableName = 'attachment' . ($a ? $a : '');
178 if (!isset($_FILES[$variableName])) {
179 continue;
180 }
181 if (!is_uploaded_file($_FILES[$variableName]['tmp_name'])) {
182 \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);
183 }
184 if ($_FILES[$variableName]['tmp_name']['error'] !== UPLOAD_ERR_OK) {
185 \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);
186 }
187 $theFile = \TYPO3\CMS\Core\Utility\GeneralUtility::upload_to_tempfile($_FILES[$variableName]['tmp_name']);
188 $theName = $_FILES[$variableName]['name'];
189 if ($theFile && file_exists($theFile)) {
190 if (filesize($theFile) < $GLOBALS['TYPO3_CONF_VARS']['FE']['formmailMaxAttachmentSize']) {
191 $this->mailMessage->attach(Swift_Attachment::fromPath($theFile)->setFilename($theName));
192 }
193 }
194 $this->temporaryFiles[] = $theFile;
195 }
196 $from = $this->fromName ? array($this->fromAddress => $this->fromName) : array($this->fromAddress);
197 $this->recipient = $this->parseAddresses($valueList['recipient']);
198 $this->mailMessage->setSubject($this->subject)->setFrom($from)->setTo($this->recipient)->setPriority($this->priority);
199 $replyTo = $this->replyToName ? array($this->replyToAddress => $this->replyToName) : array($this->replyToAddress);
200 $this->mailMessage->setReplyTo($replyTo);
201 $this->mailMessage->getHeaders()->addTextHeader('Organization', $this->organisation);
202 if ($valueList['recipient_copy']) {
203 $this->mailMessage->setCc($this->parseAddresses($valueList['recipient_copy']));
204 }
205 $this->mailMessage->setCharset($this->characterSet);
206 // Ignore target encoding. This is handled automatically by Swift Mailer and overriding the defaults
207 // is not worth the trouble
208 // Log dirty header lines
209 if ($this->dirtyHeaders) {
210 \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog('Possible misuse of t3lib_formmail: see TYPO3 devLog', 'Core', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_ERROR);
211 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['enable_DLOG']) {
212 \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('t3lib_formmail: ' . \TYPO3\CMS\Core\Utility\GeneralUtility::arrayToLogString($this->dirtyHeaders, '', 200), 'Core', 3);
213 }
214 }
215 }
216 }
217
218 /**
219 * Checks string for suspicious characters
220 *
221 * @param string $string String to check
222 * @return string Valid or empty string
223 */
224 protected function sanitizeHeaderString($string) {
225 $pattern = '/[\\r\\n\\f\\e]/';
226 if (preg_match($pattern, $string) > 0) {
227 $this->dirtyHeaders[] = $string;
228 $string = '';
229 }
230 return $string;
231 }
232
233 /**
234 * Parses mailbox headers and turns them into an array.
235 *
236 * Mailbox headers are a comma separated list of 'name <email@example.org' combinations or plain email addresses (or a mix
237 * of these).
238 * The resulting array has key-value pairs where the key is either a number (no display name in the mailbox header) and the
239 * value is the email address, or the key is the email address and the value is the display name.
240 *
241 * @param string $rawAddresses Comma separated list of email addresses (optionally with display name)
242 * @return array Parsed list of addresses.
243 */
244 protected function parseAddresses($rawAddresses = '') {
245 /** @var $addressParser \TYPO3\CMS\Core\Mail\Rfc822AddressesParser */
246 $addressParser = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Mail\\Rfc822AddressesParser', $rawAddresses);
247 $addresses = $addressParser->parseAddressList();
248 $addressList = array();
249 foreach ($addresses as $address) {
250 if ($address->personal) {
251 // Item with name found ( name <email@example.org> )
252 $addressList[$address->mailbox . '@' . $address->host] = $address->personal;
253 } else {
254 // Item without name found ( email@example.org )
255 $addressList[] = $address->mailbox . '@' . $address->host;
256 }
257 }
258 return $addressList;
259 }
260
261 /**
262 * Sends the actual mail and handles autorespond message
263 *
264 * @return boolean
265 */
266 public function sendTheMail() {
267 // Sending the mail requires the recipient and message to be set.
268 if (!$this->mailMessage->getTo() || !trim($this->mailMessage->getBody())) {
269 return FALSE;
270 }
271 $this->mailMessage->send();
272 // Auto response
273 if ($this->autoRespondMessage) {
274 $theParts = explode('/', $this->autoRespondMessage, 2);
275 $theParts[0] = str_replace('###SUBJECT###', $this->subject, $theParts[0]);
276 $theParts[1] = str_replace('/', LF, $theParts[1]);
277 $theParts[1] = str_replace('###MESSAGE###', $this->plainContent, $theParts[1]);
278 /** @var $autoRespondMail \TYPO3\CMS\Core\Mail\MailMessage */
279 $autoRespondMail = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Mail\\MailMessage');
280 $autoRespondMail->setTo($this->fromAddress)->setSubject($theParts[0])->setFrom($this->recipient)->setBody($theParts[1]);
281 $autoRespondMail->send();
282 }
283 return $this->mailMessage->isSent();
284 }
285
286 /**
287 * Do some cleanup at the end (deleting attachment files)
288 */
289 public function __destruct() {
290 foreach ($this->temporaryFiles as $file) {
291 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isAllowedAbsPath($file) && \TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($file, PATH_site . 'typo3temp/upload_temp_')) {
292 \TYPO3\CMS\Core\Utility\GeneralUtility::unlink_tempfile($file);
293 }
294 }
295 }
296
297 }
298
299 ?>