Commit 13d8213d authored by Carsten  Rose's avatar Carsten Rose
Browse files

#5133 / sendmail: subject and body html entity decode: Introduce options for...

#5133 / sendmail: subject and body html entity decode: Introduce options for 'subject' and 'body' to switch on/off HTML encoding / decoding
parent f79128d4
......@@ -3415,9 +3415,14 @@ Type: sendmail
* *sendMailXId* - Will be copied to the mailLog record. Helps to setup specific logfile queries.
* *sendMailXId2* - Will be copied to the mailLog record. Helps to setup specific logfile queries.
* *sendMailXId3* - Will be copied to the mailLog record. Helps to setup specific logfile queries.
* *sendMailSubjectHtmlEntity* - **encode|decode|none** - the mail subject will htmlspecialchar() encoded / decoded (default) or none (untouched).
Please register or sign in to reply
* *sendMailBodyHtmlEntity* - **encode|decode|none** - the mail body will htmlspecialchar() encoded, decoded (default) or none (untouched).
* To use values of the submitted form, use the STORE_FORM. E.g. `{{name:F:allbut}}`
* To use the `id` of a new created or already existing primary record, use the STORE_RECORD. E.g. `{{id:R}}`.
* By default, QFQ stores values 'htmlspecialchars()' encoded. If such values have to send by email, the html entities are
unwanted. Therefore the default setting for 'subject' und 'body' is to decode the values via 'htmlspecialchars_decode()'.
If this is not wished, it can be turned off by `sendMailSubjectHtmlEntity=none` and/or `sendMailBodyHtmlEntity=none`.
* For debugging, please check `REDIRECT_ALL_MAIL_TO`_.
......@@ -5431,17 +5436,18 @@ Send text emails. Every mail will be logged in the table `mailLog`. Attachments
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
| b | Body |**Body**: Message | yes |
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
| h | Header |**Custom Header**: Separate multiple header with \r\n | |
| h | Mail header |**Custom mail header**: Separate multiple header with \r\n | |
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
| F | Attach file |**Attachment**: File to attach to the mail. Repeatable. | |
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
| u | Attach created PDF of a given URL |**Attachment**: Convert the given URL to a PDF and attach it the mail. Repeatable. | |
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
| U | Attach created PDF of a given T3 URL |**Attachment**: Convert the given URL to a PDF and attach it the mail. Repeatable. | |
| p | Attach created PDF of a given T3 URL |**Attachment**: Convert the given URL to a PDF and attach it the mail. Repeatable. | |
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
| d | Filename of the attachment |**Attachment**: Useful for URL to PDF converted attachments. Repeatable. | |
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
| M | Merge multiple F|p|u|U| together |**Attachment**: All given 'F|p|u|U' concatenated to one attachment. Repeatable. | |
| C | Concat multiple F|p|u| together |**Attachment**: All following (until the next 'C') 'F|p|u' concatenated to one attachment. | |
| | | Repeatable. | |
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
| A | flagAutoSubmit 'on' / 'off' |If 'on' (default), add mail header 'Auto-Submitted: auto-send' - suppress OoO replies | |
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
......@@ -5453,6 +5459,14 @@ Send text emails. Every mail will be logged in the table `mailLog`. Attachments
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
| z | xId3 |Will be copied to the mailLog record. Helps to setup specific logfile queries | |
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
| e | encode|decode|none |**Subject**: will be htmlspecialchar() encoded, decoded (default) or none (untouched) | |
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
| E | encode|decode|none |**Body**: will be htmlspecialchar() encoded, decoded (default) or none (untouched). | |
+----------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+
* **e|E**: By default, QFQ stores values 'htmlspecialchars()' encoded. If such values have to send by email, the html entities are
unwanted. Therefore the default setting for 'subject' und 'body' is to decode the values via 'htmlspecialchars_decode()'.
If this is not wished, it can be turned off by `e=none` and/or `E=none`.
**Minimal Example**
......
......@@ -609,7 +609,8 @@ abstract class AbstractBuildForm {
}
if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR) {
$value = htmlspecialchars_decode($value, ENT_QUOTES);
// $value = htmlspecialchars_decode($value, ENT_QUOTES);
$value = Support::htmlEntityEncodeDecode(MODE_DECODE, $value);
}
// Typically: $htmlElementNameIdZero = true
......
......@@ -878,6 +878,8 @@ const FE_SENDMAIL_GR_ID = 'sendMailGrId'; // gr_id: used to classify mail log en
const FE_SENDMAIL_X_ID = 'sendMailXId'; // x_id: used to classify mail log entries ind table mailLog
const FE_SENDMAIL_X_ID2 = 'sendMailXId2'; // x_id: used to classify mail log entries ind table mailLog
const FE_SENDMAIL_X_ID3 = 'sendMailXId3'; // x_id: used to classify mail log entries ind table mailLog
const FE_SENDMAIL_SUBJECT_HTML_ENTITY = 'sendMailSubjectHtmlEntity'; // encode|decode >> DECODE, ENCODE
const FE_SENDMAIL_BODY_HTML_ENTITY = 'sendMailBodyHtmlEntity'; // encode | decode >> DECODE, ENCODE
const FE_SENDMAIL_ATTACHMENT = 'sendMailAttachment'; // x_id: used to classify mail log entries in table mailLog
const FE_AUTOFOCUS = 'autofocus'; // value: <none>|0|1 , <none>==1, this element becomes the focus during form load.
const FE_RETYPE = 'retype'; // value: <none>|0|1 , <none>==1, this element becomes the focus during form load.
......@@ -982,6 +984,10 @@ const FE_TYPE_PILL = 'pill';
const FE_HTML_ID = 'htmlId'; // Will be dynamically computed during runtime.
const MODE_ENCODE = 'encode';
const MODE_DECODE = 'decode';
const MODE_NONE = 'none';
const HTML_DELIMITER_NAME = '-';
const HTML_DELIMITER_ID = HTML_DELIMITER_NAME;
......@@ -1083,6 +1089,8 @@ const SENDMAIL_TOKEN_ATTACHMENT_FILE_DEPRECATED = 'a'; // since 5.12.17
const SENDMAIL_TOKEN_HEADER = 'h';
const SENDMAIL_TOKEN_X_ID2 = 'y';
const SENDMAIL_TOKEN_X_ID3 = 'z';
const SENDMAIL_TOKEN_SUBJECT_HTML_ENTITY = 'e';
const SENDMAIL_TOKEN_BODY_HTML_ENTITY = 'E';
const SENDMAIL_TOKEN_SRC = 'S';
const SENDMAIL_TOKEN_CONCAT = 'C';
......
......@@ -1013,4 +1013,28 @@ class Support {
return $data;
}
/**
* @param $mode
* @param $data
* @return string
* @throws UserFormException
*/
public static function htmlEntityEncodeDecode($mode, $data) {
switch ($mode) {
case MODE_ENCODE:
$data = htmlspecialchars($data, ENT_QUOTES);
break;
case MODE_DECODE:
$data = htmlspecialchars_decode($data, ENT_QUOTES);
break;
case MODE_NONE:
break;
default:
throw new UserFormException('Unknown mode=' . $mode, ERROR_UNKNOWN_MODE);
}
return $data;
}
}
\ No newline at end of file
......@@ -10,6 +10,7 @@ require_once(__DIR__ . '/../store/Store.php');
require_once(__DIR__ . '/../report/Download.php');
require_once(__DIR__ . '/../helper/Sanitize.php');
require_once(__DIR__ . '/../helper/HelperFile.php');
require_once(__DIR__ . '/../helper/Support.php');
class SendMail {
......@@ -65,12 +66,31 @@ class SendMail {
$mailConfig[SENDMAIL_TOKEN_RECEIVER_BCC] = '';
}
$mailConfig = $this->setDefault($mailConfig);
$logAttachments = $this->sendEmail($mailConfig);
$this->mailLog($mailConfig, $logAttachments);
}
/**
* @param array $mailConfig
* @return array
*/
private function setDefault(array $mailConfig) {
if (empty($mailConfig[SENDMAIL_TOKEN_FLAG_AUTO_SUBMIT]) || $mailConfig[SENDMAIL_TOKEN_FLAG_AUTO_SUBMIT] === '') {
$mailConfig[SENDMAIL_TOKEN_FLAG_AUTO_SUBMIT] = 'on';
}
$logAttachments = $this->sendEmail($mailConfig);
$this->mailLog($mailConfig, $logAttachments);
if (empty($mailConfig[SENDMAIL_TOKEN_SUBJECT_HTML_ENTITY]) || $mailConfig[SENDMAIL_TOKEN_SUBJECT_HTML_ENTITY] !== MODE_ENCODE) {
$mailConfig[SENDMAIL_TOKEN_SUBJECT_HTML_ENTITY] = MODE_DECODE;
}
if (empty($mailConfig[SENDMAIL_TOKEN_BODY_HTML_ENTITY]) || $mailConfig[SENDMAIL_TOKEN_BODY_HTML_ENTITY] !== MODE_ENCODE) {
$mailConfig[SENDMAIL_TOKEN_BODY_HTML_ENTITY] = MODE_DECODE;
}
return $mailConfig;
}
/**
......@@ -88,11 +108,15 @@ class SendMail {
$attachments = array();
$cmdAttachments = '';
$mailConfig[SENDMAIL_TOKEN_SUBJECT] = Support::htmlEntityEncodeDecode($mailConfig[SENDMAIL_TOKEN_SUBJECT_HTML_ENTITY], $mailConfig[SENDMAIL_TOKEN_SUBJECT]);
$mailConfig[SENDMAIL_TOKEN_BODY] = Support::htmlEntityEncodeDecode($mailConfig[SENDMAIL_TOKEN_BODY_HTML_ENTITY], $mailConfig[SENDMAIL_TOKEN_BODY]);
foreach ($mailConfig as $key => $value) {
if (is_array($value)) {
continue;
}
$mailConfig[$key] = Support::escapeDoubleTick($value);
// $mailConfig[$key] = addslashes($value);
}
$args[] = '-f "' . $mailConfig[SENDMAIL_TOKEN_SENDER] . '"';
......@@ -113,6 +137,7 @@ class SendMail {
}
if (!empty($mailConfig[SENDMAIL_TOKEN_SUBJECT])) {
// The subject needs to be encoded to UTF-8 separately - https://stackoverflow.com/questions/4389676/email-from-php-has-broken-subject-header-encoding/27648245#27648245
$preferences = ["scheme" => "Q", "input-charset" => "UTF-8", "output-charset" => "UTF-8"];
$encodedSubject = iconv_mime_encode("Subject", $mailConfig[SENDMAIL_TOKEN_SUBJECT], $preferences);
......@@ -122,6 +147,7 @@ class SendMail {
}
if (!empty($mailConfig[SENDMAIL_TOKEN_BODY])) {
$args[] = '-m "' . $mailConfig[SENDMAIL_TOKEN_BODY] . '"';;
}
......@@ -179,6 +205,7 @@ class SendMail {
return $cmdAttachments;
}
/**
* Creates a new MailLog Record based on $mailArr / $header.
*
......
......@@ -241,7 +241,8 @@ class FillStoreForm {
if ($val !== '') {
$val = Sanitize::sanitize($val, $formElement[FE_CHECK_TYPE], $formElement[FE_CHECK_PATTERN], SANITIZE_EXCEPTION);
if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR) {
$val = htmlspecialchars($val, ENT_QUOTES);
// $val = htmlspecialchars($val, ENT_QUOTES);
$val = Support::htmlEntityEncodeDecode(MODE_ENCODE, $val);
}
}
$newValues[$formElement[FE_NAME]] = $val;
......
......@@ -566,6 +566,43 @@ class SupportTest extends \PHPUnit_Framework_TestCase {
$this->assertEquals('Hello World', Support::unWrapTag('<p>', '<p>Hello World</p>'));
}
public function testHtmlEntityEncodeDecode() {
$this->assertEquals('', Support::htmlEntityEncodeDecode(MODE_NONE, ''));
$this->assertEquals('test', Support::htmlEntityEncodeDecode(MODE_NONE, 'test'));
$this->assertEquals('te"st', Support::htmlEntityEncodeDecode(MODE_NONE, 'te"st'));
$this->assertEquals("te'st", Support::htmlEntityEncodeDecode(MODE_NONE, "te'st"));
$this->assertEquals("te's\\'t", Support::htmlEntityEncodeDecode(MODE_NONE, "te's\\'t"));
$this->assertEquals("te & st", Support::htmlEntityEncodeDecode(MODE_NONE, "te & st"));
$this->assertEquals("te & &amp; st", Support::htmlEntityEncodeDecode(MODE_NONE, "te & &amp; st"));
$this->assertEquals("te < st", Support::htmlEntityEncodeDecode(MODE_NONE, "te < st"));
$this->assertEquals("te > st", Support::htmlEntityEncodeDecode(MODE_NONE, "te > st"));
$this->assertEquals("te &lt; st", Support::htmlEntityEncodeDecode(MODE_NONE, "te &lt; st"));
$this->assertEquals("te &gt; st", Support::htmlEntityEncodeDecode(MODE_NONE, "te &gt; st"));
$this->assertEquals('', Support::htmlEntityEncodeDecode(MODE_ENCODE, ''));
$this->assertEquals('test', Support::htmlEntityEncodeDecode(MODE_ENCODE, 'test'));
$this->assertEquals('te&quot;st', Support::htmlEntityEncodeDecode(MODE_ENCODE, 'te"st'));
$this->assertEquals('te&#039;st', Support::htmlEntityEncodeDecode(MODE_ENCODE, "te'st"));
$this->assertEquals('te&#039;s\&#039;t', Support::htmlEntityEncodeDecode(MODE_ENCODE, "te's\\'t"));
$this->assertEquals('te &amp; st', Support::htmlEntityEncodeDecode(MODE_ENCODE, "te & st"));
$this->assertEquals('te &amp; &amp;amp; st', Support::htmlEntityEncodeDecode(MODE_ENCODE, "te & &amp; st"));
$this->assertEquals("te &lt; st", Support::htmlEntityEncodeDecode(MODE_ENCODE, "te < st"));
$this->assertEquals("te &gt; st", Support::htmlEntityEncodeDecode(MODE_ENCODE, "te > st"));
$this->assertEquals("te &amp;lt; st", Support::htmlEntityEncodeDecode(MODE_ENCODE, "te &lt; st"));
$this->assertEquals("te &amp;gt; st", Support::htmlEntityEncodeDecode(MODE_ENCODE, "te &gt; st"));
$this->assertEquals('', Support::htmlEntityEncodeDecode(MODE_DECODE, ''));
$this->assertEquals('test', Support::htmlEntityEncodeDecode(MODE_DECODE, 'test'));
$this->assertEquals('te"st', Support::htmlEntityEncodeDecode(MODE_DECODE, 'te"st'));
$this->assertEquals("te'st", Support::htmlEntityEncodeDecode(MODE_DECODE, "te'st"));
$this->assertEquals("te's\\'t", Support::htmlEntityEncodeDecode(MODE_DECODE, "te's\\'t"));
$this->assertEquals('te & st', Support::htmlEntityEncodeDecode(MODE_DECODE, "te & st"));
$this->assertEquals('te & & st', Support::htmlEntityEncodeDecode(MODE_DECODE, "te & &amp; st"));
$this->assertEquals("te < st", Support::htmlEntityEncodeDecode(MODE_DECODE, "te &lt; st"));
$this->assertEquals("te > st", Support::htmlEntityEncodeDecode(MODE_DECODE, "te &gt; st"));
}
protected function setUp() {
parent::setUp();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment