mail : Add folding

git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@5472 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
2019-09-11 12:35:07 +00:00
parent e72c0a849e
commit 39e47d70c6

109
mail.php
View File

@@ -33,6 +33,7 @@ class mail
* returns
*/
private function printSections ()
// {{{
{
foreach ($this->sections as $sectionID=>$vals)
{
@@ -66,22 +67,26 @@ class mail
echo ")\n\n";
}
}
// }}}
/** Add a new section
* @param array $param The parameters to store
* @return the sectionID
*/
private function sectionAdd ($param)
// {{{
{
$sectionID = md5 (microtime(true).rand());
$this->sections[$sectionID] = $param;
return $sectionID;
}
// }}}
/** Add a new section with the default parameters
* @return array The sectionID stored with the default parameters
*/
private function sectionAddDefault ()
// {{{
{
return $this->sectionAdd (
array ("_headerBodySeparator"=>$this->headerBodySeparator,
@@ -91,6 +96,7 @@ class mail
"_contentEML"=>"",
"_contentUTF"=>""));
}
// }}}
/** Del an existing section
* If there is one child, and the section was multiple, remove it and
@@ -98,6 +104,7 @@ class mail
* @param string $sectionID The section to delete
*/
private function sectionDel ($sectionID)
// {{{
{
// TODO !
}
@@ -107,6 +114,7 @@ class mail
* @param string $sectionIDchild The sectionID of the child to add
*/
private function sectionAddChild ($sectionIDParent, $sectionIDchild)
// {{{
{
if (! array_key_exists ($sectionIDParent, $this->sections))
throw new \Exception (dgettext ("domframework",
@@ -114,12 +122,14 @@ class mail
$this->sections[$sectionIDParent]["_partsIDchild"][] = $sectionIDchild;
$this->sections[$sectionIDchild]["_parentID"] = $sectionIDParent;
}
// }}}
/** Add a newChild to an existing section at the beginning of the list
* @param string $sectionIDParent The parent modified by adding a child
* @param string $sectionIDchild The sectionID of the child to add
*/
private function sectionAddChildFirst ($sectionIDParent, $sectionIDchild)
// {{{
{
if (! array_key_exists ($sectionIDParent, $this->sections))
throw new \Exception (dgettext ("domframework",
@@ -128,24 +138,28 @@ class mail
$sectionIDchild);
$this->sections[$sectionIDchild]["_parentID"] = $sectionIDParent;
}
// }}}
/** Remove all the defined Childs in the section. Do not remove really the
* childs !
* @param string $sectionID the section to clean
*/
private function sectionDelChilds ($sectionID)
// {{{
{
if (! array_key_exists ($sectionID, $this->sections))
throw new \Exception (dgettext ("domframework",
"Section not found"), 404);
unset ($this->sections[$sectionID]["_partsIDchild"]);
}
// }}}
/** Update the content of an existing section
* @param string $sectionID The section to modify
* @param array $param The parameters to update
*/
private function sectionUpdate ($sectionID, $param)
// {{{
{
if (! array_key_exists ($sectionID, $this->sections))
throw new \Exception (dgettext ("domframework", "Section not found"),
@@ -158,19 +172,23 @@ class mail
$this->sections[$sectionID][$key] = $val;
}
}
// }}}
/** Get the list of sections ID
* @return array the defined sectionsID
*/
private function sectionList ()
// {{{
{
return array_keys ($this->sections);
}
// }}}
/** Get the section ID List with parents ID
* @return array the defined sectionsID with the parent ID as value
*/
private function sectionListParent ()
// {{{
{
$res = array ();
foreach ($this->sections as $sectionID=>$content)
@@ -182,23 +200,27 @@ class mail
}
return $res;
}
// }}}
/** Return the content array of the section
* @param string $sectionID The section ID to get
* @return array The content of the section
*/
private function sectionGet ($sectionID)
// {{{
{
if (! array_key_exists ($sectionID, $this->sections))
throw new \Exception (dgettext ("domframework",
"Section not found"), 404);
return $this->sections[$sectionID];
}
// }}}
/** Get the section ID of the main part
* @return bool|string the section ID of the main part or FALSE if not found
*/
public function sectionMainID ()
// {{{
{
foreach ($this->sectionListParent () as $sectionID=>$parentID)
{
@@ -207,11 +229,13 @@ class mail
}
return false;
}
// }}}
/** Refresh the _headersEML from the _headersArray
* @param string $sectionID the section to refresh
*/
private function sectionRefreshHeadersEML ($sectionID)
// {{{
{
$section = $this->sectionGet ($sectionID);
$headersEML = "";
@@ -223,12 +247,14 @@ class mail
}
$this->sections[$sectionID]["_headersEML"] = $headersEML;
}
// }}}
/** Read the complete mail to analyze
* Destroy all the previous definitions of mail
* @param string $content The complete mail to read
*/
public function readMail ($content)
// {{{
{
$this->sections = array ();
$this->completeEmailEML = $content;
@@ -236,6 +262,7 @@ class mail
if ($partinfo !== null)
$this->readMailContentRecurse ($partinfo);
}
// }}}
/** Read the content of the mail and allow the content to be also multipart.
* Then the method is recursively called to generate the sections
@@ -243,6 +270,7 @@ class mail
* @param string|null $sectionIDParent The parent sectionID to link with
*/
private function readMailContentRecurse ($partinfo, $sectionIDParent=false)
// {{{
{
if (key_exists ("_contentType", $partinfo) &&
substr ($partinfo["_contentType"], 0, 10) === "multipart/")
@@ -300,12 +328,14 @@ class mail
$sectionIDParent = $this->sectionAdd ($partinfo);
}
}
// }}}
/** Return the data for a part of the mail
* @param string $content The content of the mail to parse
* @return array The data content in the mail
*/
private function parseMessagePart ($content)
// {{{
{
// Get the HeaderBodySeparator
$pos = strpos ($content, "\r\n\r\n");
@@ -428,10 +458,12 @@ class mail
$res["Content-ID"] = $contentID;
return $res;
}
// }}}
/** The constuctor verify if the external libraries are available
*/
public function __construct ()
// {{{
{
if (! function_exists ("finfo_buffer"))
throw new \Exception (dgettext ("domframework",
@@ -446,6 +478,7 @@ class mail
$this->addHeader ("From", $user["name"]."@".php_uname('n'));
$this->addHeader ("MIME-Version", "1.0");
}
// }}}
/** Define a HTML body. If the HTML body already exists, overwrite it
* If there is an text body, manage the boundary in alternative mode
@@ -455,6 +488,7 @@ class mail
*/
public function setBodyHTML ($htmlContent, $charset="utf-8",
$encoding="quoted-printable")
// {{{
{
// Look if there is an existing section with text (main or
// multipart/alternative)
@@ -550,6 +584,7 @@ class mail
$this->sectionUpdate ($sectionIDtoChange, $part);
$this->createMailEML ();
}
// }}}
/** Add a Text body. If the text body already exists, overwrite it
* If there is an HTML body, manage the boundary in alternative mode
@@ -559,6 +594,7 @@ class mail
*/
public function setBodyText ($textContent, $charset="utf-8",
$encoding="quoted-printable")
// {{{
{
// Look if there is an existing section with text (main or
// multipart/alternative)
@@ -636,6 +672,7 @@ class mail
$this->sectionUpdate ($sectionIDtoChange, $part);
$this->createMailEML ();
}
// }}}
/** Return the HTML body if exists in UTF-8. If the body is not in UTF-8, it
* is converted
@@ -644,6 +681,7 @@ class mail
* no HTML part in the mail
*/
public function getBodyHTML ()
// {{{
{
$sectionList = $this->sectionList ();
$sectionIDtoChange = "";
@@ -662,6 +700,7 @@ class mail
}
return false;
}
// }}}
/** Get the text body if exists in UTF-8. If the body is not in UTF-8, it is
* converted
@@ -670,6 +709,7 @@ class mail
* no Text part in the mail
*/
public function getBodyText ()
// {{{
{
$sectionList = $this->sectionList ();
$sectionIDtoChange = "";
@@ -688,6 +728,7 @@ class mail
}
return false;
}
// }}}
/** Move the sections where the parent is defined to $oldParentID to the
* $newParentID.
@@ -697,6 +738,7 @@ class mail
* @param string|null $oldParentID The oldParent to look for
*/
private function moveChilds ($newParentID, $oldParentID=false)
// {{{
{
if ($newParentID === $oldParentID)
throw new \Exception ("moveChilds : old and new ParentID are the same",
@@ -756,6 +798,7 @@ class mail
}
}
}
// }}}
/** Add an attachment to the mail.
* The allowed encodings are "quoted-printable" or "base64"
@@ -769,6 +812,7 @@ class mail
*/
public function addAttachment ($name, $fileContent, $encoding="base64",
$inline=false)
// {{{
{
if ($this->getBodyHTML() === false && $inline !== false)
$this->setBodyHTML ("No HTML provided by inline file added");
@@ -851,6 +895,7 @@ class mail
if ($inline === true)
return substr ($contentID, 1, -1);
}
// }}}
/** Add an inline attachment to the mail.
* The allowed encodings are "quoted-printable" or "base64"
@@ -863,9 +908,11 @@ class mail
* @return string The content ID created
*/
public function addAttachmentInline ($name, $fileContent, $encoding="base64")
// {{{
{
return $this->addAttachment ($name, $fileContent, $encoding, true);
}
// }}}
/** Get an attachment of the mail
* @param integer $number the number of attach to get starting to 0
@@ -873,6 +920,7 @@ class mail
* @return the content of the attachment. Can be binary
*/
public function getAttachment ($number, $inline = false)
// {{{
{
$attachmentIDs = $this->getAttachmentID ($inline);
if (! array_key_exists ($number, $attachmentIDs))
@@ -883,6 +931,7 @@ class mail
$part["_headersArray"]);
return $this->encodingDecode ($part["_contentEML"], $encoding);
}
// }}}
/** Get the attachment details
* @param integer $number the number of attach to get starting to 0
@@ -890,6 +939,7 @@ class mail
* @return array containing the information of the attachment
*/
public function getAttachmentDetails ($number, $inline = false)
// {{{
{
$attachmentIDs = $this->getAttachmentID ($inline);
if (! array_key_exists ($number, $attachmentIDs))
@@ -911,6 +961,7 @@ class mail
}
return $res;
}
// }}}
/** Return the list of the sectionID containing a attachment. Contains the
* inline attachments too.
@@ -918,6 +969,7 @@ class mail
* @return array The sectionIDs
*/
private function getAttachmentID ($inline = false)
// {{{
{
$res = array ();
foreach ($this->sections as $sectionID=>$section)
@@ -946,12 +998,14 @@ class mail
}
return $res;
}
// }}}
/** Add a To: header. If it already exists, add a new recipient
* @param string $toMail The mail to add
* @param string|null $toName The name of the recipient
*/
public function addTo ($toMail, $toName = "")
// {{{
{
if (strspn ($toName, "abcdefghijklmnopqrstuvwxyz".
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".
@@ -967,20 +1021,24 @@ class mail
else
$this->setHeader ("To", $toField);
}
// }}}
/** Get the To Header as it is written in the mail
* @return string The To Header defined in the mail
*/
public function getTo ()
// {{{
{
return $this->getHeader ("To");
}
// }}}
/** Add a From: header. If it already exists, overwrite the existing one
* @param string $fromMail The from Mail to define
* @param string|null $fromName The from Name to define
*/
public function setFrom ($fromMail, $fromName= "")
// {{{
{
if (strspn ($fromName, "abcdefghijklmnopqrstuvwxyz".
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".
@@ -991,19 +1049,23 @@ class mail
$fromName .= " ";
$this->setHeader ("From", "$fromName<$fromMail>");
}
// }}}
/** Return the From header as it is written in the mail
* @return string The From Header defined in the mail
*/
public function getFrom ()
// {{{
{
return $this->getHeader ("From");
}
// }}}
/** Return the From header converted to array with mail and name keys
* @return array The From details
*/
public function getFromArray ()
// {{{
{
$from = $this->getHeader ("From");
$res = array ();
@@ -1011,49 +1073,59 @@ class mail
$from = $this->convertPeopleToArray ($from);
return reset ($from);
}
// }}}
/** Set the subject
* @param string $subject In UTF8
*/
public function setSubject ($subject)
// {{{
{
$this->setHeader ("Subject",
$this->encodeHeaders ("Subject", $subject,
"quoted-printable"));
}
// }}}
/** Set the Date
* @param string $date In RFC 2822 format
*/
public function setDate ($date)
// {{{
{
// TODO : Check if the date format is valid
$this->setHeader ("Date", $date);
}
// }}}
/** Set the Date
* @param string $timestamp In Timestamp format
*/
public function setDateTimestamp ($timestamp)
// {{{
{
// TODO : Check if the timestamp is valid
$this->setHeader ("Date", date ("r", $timestamp));
}
// }}}
/** Get the Date header if defined.
* Return false if not defined
* @return string|bool The date Header if defined or false if not defined
*/
public function getDate ()
// {{{
{
return $this->getHeader ("Date");
}
// }}}
/** Return the Date header (if defined) in timestamp
* Return false if not defined
* @return integer|bool The date Header if defined or false if not defined
*/
public function getDateTimestamp ()
// {{{
{
$datetimestamp = false;
$date = rtrim ($this->getDate ());
@@ -1069,6 +1141,7 @@ class mail
}
return $dateTimestamp;
}
// }}}
/** Set a generic header
* @param string $header The name of the Header (without colon)
@@ -1076,6 +1149,7 @@ class mail
* @param string|null $sectionID The section to modify. If null, use the main
*/
public function setHeader ($header, $value, $sectionID=null)
// {{{
{
if (substr ($value, -1) !== "\n" &&
substr ($value, -1) !== "\r" &&
@@ -1118,6 +1192,7 @@ class mail
$this->sections[$sectionMainID]["_headersEML"] = $_headerEML;
$this->createMailEML ();
}
// }}}
/** Add a generic header
* @param string $header The name of the Header (without colon)
@@ -1125,6 +1200,7 @@ class mail
* @param string|null $sectionID The section to modify. If null, use the main
*/
public function addHeader ($header, $value, $sectionID=null)
// {{{
{
if (substr ($value, -1) !== "\n" &&
substr ($value, -1) !== "\r" &&
@@ -1170,12 +1246,14 @@ class mail
}
$this->createMailEML ();
}
// }}}
/** Delete a specific header
* @param string $header The header to remove
* @param string|null $sectionID The section to modify. If null, use the main
*/
public function delHeader ($header, $sectionID=null)
// {{{
{
if ($sectionID === null)
{
@@ -1213,6 +1291,7 @@ class mail
$this->sections[$sectionMainID]["_headersEML"] = $_headerEML;
$this->createMailEML ();
}
// }}}
/** Get a generic header
* If there is multiple headers with the same name, return the first
@@ -1221,6 +1300,7 @@ class mail
* @return string|bool the literal value or false if it doesn't exist
*/
public function getHeader ($header, $headers=null)
// {{{
{
if ($headers === null)
{
@@ -1240,6 +1320,7 @@ class mail
}
return false;
}
// }}}
/** Get a generic header with removing the carriage return
* If there is multiple headers with the same name, return the first
@@ -1248,6 +1329,7 @@ class mail
* @return string|bool the literal value or false if it doesn't exist
*/
public function getHeaderValue ($header, $headers=null)
// {{{
{
if ($headers === null)
{
@@ -1272,10 +1354,12 @@ class mail
}
return false;
}
// }}}
/** Create the complete mail structure
*/
public function createMailEML ()
// {{{
{
$complete = "";
$this->recurse = 0;
@@ -1292,11 +1376,13 @@ class mail
}
$this->completeEmailEML = $complete;
}
// }}}
/** Recursive email EML creation for childs
* @param array $parent The parent array
*/
private function createMailEMLSub ($parent)
// {{{
{
$this->recurse++;
if ($this->recurse > 120)
@@ -1322,17 +1408,20 @@ class mail
$complete .= "--".$parent["_boundary"]."--".$parent["_boundaryCR"];
return $complete;
}
// }}}
/** Return the complete mail
* @return string The complete mail
*/
public function getMail ()
// {{{
{
if (trim ($this->getBodyHTML()) === "No HTML provided by inline file added")
throw new \Exception ("No HTML provided by inline file added", 500);
return $this->completeEmailEML;
}
// }}}
/** Return an array with the details of the mail :
* the number of attachments, the from, to, subject in UTF-8, if there is
@@ -1340,6 +1429,7 @@ class mail
* @return array The details of the mail
*/
public function getDetails ()
// {{{
{
$bodyTextExists = false;
$bodyHTMLExists = false;
@@ -1381,11 +1471,13 @@ class mail
$subject = $this->decodeHeaders ("Subject", $this->getHeader ("Subject"));
return get_defined_vars();
}
// }}}
/** Create a boundary
* @return string the textual boundary
*/
private function getBoundary ()
// {{{
{
$data = openssl_random_pseudo_bytes (16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0010
@@ -1393,11 +1485,13 @@ class mail
return "-----".vsprintf ('%s%s%s%s%s%s%s%s',
str_split (bin2hex ($data), 4));
}
// }}}
/** Create a messageID
* @return string the textual MessageID
*/
public function provideMessageID ()
// {{{
{
$data = openssl_random_pseudo_bytes (16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0010
@@ -1406,6 +1500,7 @@ class mail
str_split (bin2hex ($data), 4))."@".
php_uname('n').">";
}
// }}}
/** Convert the content to correct encoding.
* The allowed encodings are "quoted-printable" or "base64" or "flowed"
@@ -1415,6 +1510,7 @@ class mail
* @return string the content encoded by $encoding
*/
private function encodingEncode ($content, $encoding)
// {{{
{
if ($encoding === "quoted-printable")
{
@@ -1434,6 +1530,7 @@ class mail
dgettext ("domframework",
"Invalid encoding provided to encodingEncode : %s"), $encoding), 500);
}
// }}}
/** Decode the content with correct encoding.
* The allowed encodings are "quoted-printable" or "base64" or "8bit"
@@ -1442,6 +1539,7 @@ class mail
* @return the content decoded by $encoding
*/
private function encodingDecode ($content, $encoding)
// {{{
{
if ($encoding === "quoted-printable")
return quoted_printable_decode ($content);
@@ -1453,6 +1551,7 @@ class mail
dgettext ("domframework",
"Invalid encoding provided to encodingDecode : '%s'"), $encoding), 500);
}
// }}}
/** Encode a string to be compliant with MIME (used in headers)
* @param string $header The header to be used. Will not be returned, but the
@@ -1463,6 +1562,7 @@ class mail
* @return string the content encoded by $encoding
*/
private function encodeHeaders ($header, $content, $encoding)
// {{{
{
$prefs = array ("input-charset" => "utf-8",
"output-charset" => "utf-8");
@@ -1476,6 +1576,7 @@ class mail
return substr (iconv_mime_encode ($header, $content, $prefs),
strlen ($header)+2);
}
// }}}
/** Convert the header to text
* @param string $header The header to decode
@@ -1483,10 +1584,12 @@ class mail
* @return string the header converted
*/
private function decodeHeaders ($header, $content)
// {{{
{
return substr (iconv_mime_decode ("$header: $content", 0, "utf-8"),
strlen ($header)+2);
}
// }}}
/** Encode a header string not starting on first column. The number of chars
* need to be skipped is passed as argument. The function will correctely
@@ -1498,6 +1601,7 @@ class mail
* @return string the content encoded by $encoding
*/
private function encodeHeaderStringWithPosition ($content, $encoding, $blanks)
// {{{
{
$prefs = array ("input-charset" => "utf-8",
"output-charset" => "utf-8");
@@ -1512,6 +1616,7 @@ class mail
$prefs),
$blanks+2);
}
// }}}
/** Convert a From/To string to array. Manage multiple recipients
* Ex. : toto toto <toto@toto.com>, titi <titi@titi.com>
@@ -1521,6 +1626,7 @@ class mail
* @return array The array with the converted data
*/
public function convertPeopleToArray ($data)
// {{{
{
$elements = explode (",", $data);
$res = array ();
@@ -1542,12 +1648,14 @@ class mail
}
return $res;
}
// }}}
/** Analyze the Content-Type line and return an array with the values
* @param string $contentType The content Type to analyze
* @return array The analyzed Content-Type
*/
public function contentTypeAnalyze ($contentType)
// {{{
{
$contentType = preg_replace ("#[\r\n]+[ \t]+#", " ", $contentType);
$elements = explode (";", $contentType);
@@ -1566,4 +1674,5 @@ class mail
}
return $res;
}
// }}}
}