From 23516c7b57d9f40c36d518d40688b56bdb3af411 Mon Sep 17 00:00:00 2001 From: Dominique Fournier Date: Fri, 29 Apr 2016 14:47:12 +0000 Subject: [PATCH] * mail : the mail creator. Allow to create complete mails easily $mail = new mail (); $mail->setFrom ("sender@example.com","Sender Example Com"); $mail->addTo ("recipient1@example.com","Recipient1 Example Com"); $mail->addTo ("recipient2@example.com","Recipient2 Example Com"); $mail->setBodyText ("Content of TextBody part"); $mail->addAttachment ("file0.text", "File content"); $contentID1 = $mail->addAttachmentInline ("file2.jpg", "qcqscqs"); $mail->setBodyHTML ("

Content of HTMLBody part with inline

"); echo $mail->getMail (); git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@2709 bf3deb0d-5f1a-0410-827f-c0cc1f45334c --- Tests/mailTest.php | 136 +++++++++ mail.php | 678 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 814 insertions(+) create mode 100644 Tests/mailTest.php create mode 100644 mail.php diff --git a/Tests/mailTest.php b/Tests/mailTest.php new file mode 100644 index 0000000..aef8eb7 --- /dev/null +++ b/Tests/mailTest.php @@ -0,0 +1,136 @@ + */ + +/** Test the mail.php file */ +class test_mail extends PHPUnit_Framework_TestCase +{ + public function test_setBodyText1 () + { + $mail = new mail (); + $mail->setBodyText ("TEST"); + $res = $mail->getMail (); + $this->assertRegExp ("#TEST\r\n$#", $res); + } + + public function test_setBodyHTML1 () + { + $mail = new mail (); + $mail->setBodyHTML ("TEST"); + $res = $mail->getMail (); + $this->assertRegExp ("#^\r\nTEST\r$#m", $res); + } + + public function test_setGetBodyText1 () + { + $mail = new mail (); + $mail->setBodyText ("TEST"); + $res = $mail->getBodyText (); + $this->assertSame ("TEST", $res); + } + + public function test_setGetBodyHtml1 () + { + $mail = new mail (); + $mail->setBodyHtml ("TEST"); + $res = $mail->getBodyHtml (); + $this->assertSame ("TEST", $res); + } + + public function test_setFrom1 () + { + $mail = new mail (); + $mail->setFrom ("test@example.com", "Test Exa1mple Com"); + $res = $mail->getFrom (); + $this->assertSame ("Test Exa1mple Com \r\n", $res); + } + + public function test_addTo1 () + { + $mail = new mail (); + $mail->addTo ("test@example.com", "Test Exa1mple Com"); + $res = $mail->getTo (); + $this->assertSame ("Test Exa1mple Com \r\n", $res); + } + + public function test_addTo2 () + { + $mail = new mail (); + $mail->addTo ("test@example.com", "Test Exa1mple Com"); + $res = $mail->getMail (); + $this->assertRegexp ("#^To: Test Exa1mple Com \r$#m", $res); + } + + public function test_setDateTimestamp1 () + { + $mail = new mail (); + $time = time (); + $mail->setDateTimestamp ($time); + $res = $mail->getDateTimestamp (); + $this->assertSame ($res, $time); + } + + public function test_setDateTimestamp2 () + { + $mail = new mail (); + $time = time (); + $mail->setDateTimestamp ($time); + $res = $mail->getMail (); + $this->assertRegexp ("#^Date: ".preg_quote (date ("r", $time))."\r$#m", $res); + } + + public function test_convertPeopleToArray1 () + { + $mail = new mail (); + $res = $mail->convertPeopleToArray ("toto toto "); + $this->assertSame ($res, array (array ("name"=>"toto toto", + "mail"=>"toto@toto.com"))); + } + + public function test_convertPeopleToArray2 () + { + $mail = new mail (); + $res = $mail->convertPeopleToArray (""); + $this->assertSame ($res, array (array ("name"=>"", + "mail"=>"toto@toto.com"))); + } + + public function test_convertPeopleToArray3 () + { + $mail = new mail (); + $res = $mail->convertPeopleToArray ("toto@toto.com,titi@titi.com"); + $this->assertSame ($res, array (array ("name" => "", + "mail" => "toto@toto.com"), + array ("name" => "", + "mail" => "titi@titi.com"))); + } + + public function test_convertPeopleToArray4 () + { + $mail = new mail (); + $res = $mail->convertPeopleToArray ("toto@toto.com"); + $this->assertSame ($res, array (array ("name"=>"", + "mail"=>"toto@toto.com"))); + } + + public function test_convertPeopleToArray5 () + { + $mail = new mail (); + $res = $mail->convertPeopleToArray (" , "); + $this->assertSame ($res, array (array ("name" => "", + "mail" => "toto@toto.com"), + array ("name" => "", + "mail" => "titi@titi.com"))); + } + + public function test_convertPeopleToArray6 () + { + $mail = new mail (); + $res = $mail->convertPeopleToArray ("ToTo , "); + $this->assertSame ($res, array (array ("name" => "ToTo", + "mail" => "toto@toto.com"), + array ("name" => "", + "mail" => "titi@titi.com"))); + } +} diff --git a/mail.php b/mail.php new file mode 100644 index 0000000..0d836f6 --- /dev/null +++ b/mail.php @@ -0,0 +1,678 @@ + */ + +/** Manage the mail content */ +class mail +{ + /** The differents parts of the mail. Will be added to multipart/mixed + */ + private $parts = array (); + + /** The inline parts of HTML body. Will be added to multipart/related + */ + private $inlineParts = array (); + + /** The displayed part of the mail (the body) in TEXT and/or HTML. + * This is the alternative part of MIME mails + * Will be added to multipart/alternative + */ + private $bodyContent = array (); + + /** The EML part of the body (with the boundaries if needed) + * Contain the Text and/or HTML part of the body. For HTML, contain the + * inline parts too + */ + private $bodyContentEML = ""; + + /** The Headers of the Body in an array form. Will be appended to the mail + * headers if there is no multipart/alternative, or keep in the mail in case + * of multipart/alternative + */ + private $bodyHeaders = array (); + + /** The main headers of the mail + */ + private $headers = array (); + + /** Private the separator between the headers and the mail. Should be + * \r\n on a line, but special crafted mails may use something else + */ + private $headerBodySeparator = "\r\n"; + + /** The constuctor verify if the external libraries are available + */ + public function __construct () + { + if (! function_exists ("finfo_buffer")) + throw new \Exception (_("Missing FileInfo PHP Extension"), 500); + if (! function_exists ("openssl_random_pseudo_bytes")) + throw new \Exception (_("Missing OpenSSL PHP Extension"), 500); + // Define default headers + $this->setHeader ("Date", date ("r")); + $this->setHeader ("Message-ID", $this->getMessageID ()); + $user = posix_getpwuid (posix_geteuid()); + $this->setHeader ("From", $user["name"]."@".php_uname('n')); + $this->setHeader ("MIME-Version", "1.0"); + } + + /** Get the textual mail provided and use it as default + * @param $textualMail The complete mail to read + */ + public function readMail ($textualMail) + { + // TBD + } + + /** Define a HTML body. If the HTML body already exists, overwrite it + * If there is an text body, manage the boundary in alternative mode + * @param $htmlContent in UTF-8 + * @param $charset to be stored in the mail + * @param $encoding the encoding in the mail + */ + public function setBodyHTML ($htmlContent, $charset="utf-8", + $encoding="quoted-printable") + { + $oldPart = end ($this->bodyContent); + if (count ($oldPart) && + substr ($oldPart["Content-Type"], 0, 9) === "text/html") + { + // There is already a html body. Remove it to create a new one + array_pop ($this->bodyContent); + } + $htmlContent = iconv ("utf-8", $charset, $htmlContent); + $part["_charset"] = $charset; + $part["_content"] = $this->encodingEncode ($htmlContent, $encoding); + $part["Content-Type"] = "text/html; charset=$charset"; + $part["Content-Transfer-Encoding"] = $encoding; + // Order the HTML after the text if exists + array_push ($this->bodyContent, $part); + $this->createBodyEML (); + } + + /** Add a Text body. If the text body already exists, overwrite it + * If there is an HTML body, manage the boundary in alternative mode + * @param $textContent in UTF-8 + * @param $charset to be stored in the mail + * @param $encoding the encoding in the mail + */ + public function setBodyText ($textContent, $charset="utf-8", + $encoding="quoted-printable") + { + if (isset ($this->bodyContent[0]) && + substr ($this->bodyContent[0]["Content-Type"], 0, 10) === "text/plain") + { + // There is already a text body. Remove it to create a new one + unset ($this->bodyContent[0]); + } + $textContent = iconv ("utf-8", $charset, $textContent); + $part["_charset"] = $charset; + $part["Content-Type"] = "text/plain; charset=$charset"; + $part["Content-Transfer-Encoding"] = $encoding; + $part["_content"] = $this->encodingEncode ($textContent, $encoding); + // Order the text before the html if exists + array_unshift ($this->bodyContent, $part); + $this->createBodyEML (); + } + + /** Return the HTML body if exists in UTF-8. If the body is not in UTF-8, it + * is converted + * Return false if it doesn't exists + */ + public function getBodyHTML () + { + foreach ($this->bodyContent as $part) + { + if (substr ($part["Content-Type"], 0, 9) === "text/html") + { + $body = $this->encodingDecode ($part["_content"], + $part["Content-Transfer-Encoding"]); + return iconv ($part["_charset"], "UTF-8", $body); + } + } + return false; + } + + /** Get the text body if exists in UTF-8. If the body is not in UTF-8, it is + * converted + * Return false if it doesn't exists + */ + public function getBodyText () + { + foreach ($this->bodyContent as $part) + { + if (substr ($part["Content-Type"], 0, 10) === "text/plain") + { + $body = $this->encodingDecode ($part["_content"], + $part["Content-Transfer-Encoding"]); + return iconv ($part["_charset"], "UTF-8", $body); + } + } + return false; + } + + /** Add an attachment to the mail. + * The allowed encodings are "quoted-printable" or "base64" + */ + public function addAttachment ($name, $fileContent, $encoding="base64") + { + $finfo = new \finfo(FILEINFO_MIME); + $mimetype = $finfo->buffer($fileContent); + $part["Content-Type"] = "$mimetype; name=$name\r\n"; + $part["Content-Disposition"] = "attachment; filename=$name\r\n"; + $part["Content-Transfer-Encoding"] = "$encoding\r\n"; + $part["_name"] = $name; + $part["_content"] = $this->encodingEncode ($fileContent, $encoding); + $part["_mimetype"] = $mimetype; + $part["_sizeReal"] = strlen ($fileContent); + array_push ($this->parts, $part); + } + + /** Add an inline attachment to the mail. + * The allowed encodings are "quoted-printable" or "base64" + * Return the Content-ID needed to be used in HTML page like : + * + */ + public function addAttachmentInline ($name, $fileContent, $encoding="base64") + { + $finfo = new \finfo(FILEINFO_MIME); + $mimetype = $finfo->buffer($fileContent); + $part["Content-Type"] = "$mimetype; name=$name\r\n"; + $contentID = $this->getMessageID (); + $part["Content-ID"] = "$contentID\r\n"; + $part["Content-Disposition"] = "inline; filename=$name\r\n"; + $part["Content-Transfer-Encoding"] = "$encoding\r\n"; + $part["_name"] = $name; + $part["_content"] = $this->encodingEncode ($fileContent, $encoding); + $part["_mimetype"] = $mimetype; + $part["_sizeReal"] = strlen ($fileContent); + array_push ($this->inlineParts, $part); + $this->createBodyEML (); + return substr ($contentID, 1, -1); + } + + /** Get an attachment of the mail + * @param $number the number of attach to get starting to 0 + * @return the content of the attachment. Can be binary + */ + public function getAttachment ($number) + { + if (! array_key_exists ($number, $this->parts)) + throw new \Exception (_("Attachment not found"), 404); + $part = $this->parts[$number]; + return $this->encodingDecode ($part["_content"], + $part["Content-Transfer-Encoding"]); + } + + /** Get the attachment details + * @param $number the number of attach to get starting to 0 + * @return array containing the information of the attachment + */ + public function getAttachmentDetails ($number) + { + if (! array_key_exists ($number, $this->parts)) + throw new \Exception (sprintf (_("Attachment '%d' not found"), $number), + 404); + $part = $this->parts[$number]; + $res = array (); + foreach ($part as $key=>$val) + { + if ($key{0} === "_" && $key !== "_content") + $res[substr ($key, 1)] = $val; + } + return $res; + } + + /** Add a To: header. If it already exists, add a new recipient*/ + public function addTo ($toMail, $toName) + { + if (strspn ($toName, "abcdefghijklmnopqrstuvwxyz". + "ABCDEFGHIJKLMNOPQRSTUVWXYZ". + "0123456789 -_") !== strlen ($toName)) + $toName = $this->encodeHeaders ("From", $toName, + "quoted-printable"); + $toField = "$toName <$toMail>"; + if (array_key_exists ("To", $this->headers)) + $this->setHeader ("To", $this->getHeaderValue ("To").",\r\n $toField"); + else + $this->setHeader ("To", $toField); + } + + /** Get the To Header as it is written in the mail */ + public function getTo () + { + return $this->headers["To"]; + } + + /** Add a From: header. If it already exists, overwrite the existing one*/ + public function setFrom ($fromMail, $fromName) + { + if (strspn ($fromName, "abcdefghijklmnopqrstuvwxyz". + "ABCDEFGHIJKLMNOPQRSTUVWXYZ". + "0123456789 -_") !== strlen ($fromName)) + $fromName = $this->encodeHeaders ("From", $fromName, + "quoted-printable"); + $this->setHeader ("From", "$fromName <$fromMail>"); + } + + /** Return the From header as it is written in the mail */ + public function getFrom () + { + return $this->headers["From"]; + } + + /** Return the From header converted to array with mail and name keys */ + public function getFromArray () + { + $res = array (); + $from = $this->decodeHeaders ("From", $this->headers["From"]); + return reset ($this->convertPeopleToArray ($from)); + } + + /** Set the Date + * @param $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 $date In Timestamp format + */ + public function setDateTimestamp ($timestamp) + { + // TODO : Check if the timestamp is valid + $this->setHeader ("Date", date ("r", $timestamp)); + } + + /** Return the Date header if defined. + Return false if not defined */ + public function getDate () + { + return $this->getHeader ("Date"); + } + + /** Return the Date header (if defined) in timestamp + * Return false if not defined */ + public function getDateTimestamp () + { + $datetimestamp = false; + $date = rtrim ($this->getDate ()); + if ($date !== false) + { + $dateTimestamp = DateTime::createFromFormat (DateTime::RFC2822, + $date); + if ($dateTimestamp === false) + $dateTimestamp = DateTime::createFromFormat (DateTime::RFC822, + $date); + if ($dateTimestamp !== false) + $dateTimestamp = $dateTimestamp->getTimestamp(); + } + return $dateTimestamp; + } + + /** Set a generic header + * @param $header The name of the Header (without colon) + * @param $value The value the store. The format must be correct ! + */ + public function setHeader ($header, $value) + { + if (substr ($value, -1) !== "\n" && + substr ($value, -1) !== "\r" && + substr ($value, -2) !== "\r\n") + $value .= "\r\n"; + $this->headers[$header] = $value; + } + + /** Delete a specific header + * @param $header The header to remove + */ + public function delHeader ($header) + { + unset ($this->headers[$header]); + } + + /** Get a generic header + * @param $header The header to get + * @return the literal value or false if it doesn't exist + */ + public function getHeader ($header) + { + if (! isset ($this->headers[$header])) + return false; + return $this->headers[$header]; + } + + /** Get a generic header with removing the carraige return + *@param $header The header to get + * @return the literal value or false if it doesn't exist + */ + public function getHeaderValue ($header) + { + if (! isset ($this->headers[$header])) + return false; + if (substr ($this->headers[$header], -1) !== "\n" && + substr ($this->headers[$header], -1) !== "\r") + return substr ($this->headers[$header], 0, -1); + return substr ($this->headers[$header], 0, -2); + } + + /** Create the Body EML part for HTML + * @param $bodyContentHTML the $this->part corresponding to HTML Body + * @return the EML part for HTML with multipart/related if needed + */ + public function createBodyEMLHTML ($bodyContentHTML) + { + $html = ""; + if (count ($this->inlineParts)) + { + $inlineBoundary = $this->getBoundary (); + $html .= "Content-Type: multipart/related;\r\n". + " boundary=\"$inlineBoundary\"\r\n\r\n"; + $html .= "--$inlineBoundary\r\n"; + } + foreach ($bodyContentHTML as $key=>$val) + { + if ($key{0} === "_") continue; + $html .= "$key: $val\r\n"; + } + $html .= "\r\n".$bodyContentHTML["_content"]."\r\n"; + foreach ($this->inlineParts as $part) + { + $html .= "--$inlineBoundary\r\n"; + foreach ($part as $key=>$val) + { + if ($key{0} === "_") continue; + $html .= "$key: $val"; + } + $html .= "\r\n".$part["_content"]."\r\n"; + } + if (count ($this->inlineParts)) + { + $html .= "--$inlineBoundary--\r\n"; + } + return $html; + } + + /** Create the Body EML part + */ + public function createBodyEML () + { + // Create the alternative/part body for TEXT/HTML part + $bodyContent = ""; + $bodyHeaders = array (); + $body = ""; + // TODO : Check if the mail contain only attached file + if (count ($this->bodyContent) === 0) + throw new \Exception (_("No content in the mail"), 406); + elseif (count ($this->bodyContent) === 2) + { + // Text + HTML available : manage the alternative part + $boundary = $this->getBoundary (); + $bodyHeaders["Content-Type"] = "multipart/alternative;\r\n". + " boundary=\"$boundary\"\r\n"; + // Store the Text part + $bodyContent .= "--$boundary\r\n"; + foreach ($this->bodyContent[0] as $key=>$val) + { + if ($key{0} === "_") continue; + $bodyContent .= "$key: $val\r\n"; + } + $bodyContent .= "\r\n".$this->bodyContent[0]["_content"]."\r\n"; + + // Store the HTML part + $bodyContent .= "--$boundary\r\n"; + $bodyContent .= $this->createBodyEMLHTML ($this->bodyContent[1]); + $bodyContent .= "--$boundary--\r\n"; + } + else + { + // Text or HTML but not both + $part = reset ($this->bodyContent); + if (substr ($part["Content-Type"], 0, 10) === "text/plain") + { + // Only TEXT part + foreach ($part as $key=>$val) + { + if ($key{0} === "_") + $bodyContent = "$val\r\n"; + else + $bodyHeaders[$key] = "$val\r\n"; + } + $body .= $bodyContent; + } + elseif (substr ($part["Content-Type"], 0, 9) === "text/html") + { + // Only HTML part + foreach ($part as $key=>$val) + { + if ($key{0} === "_") + $bodyContent = "$val\r\n"; + else + $bodyHeaders[$key] = "$val\r\n"; + } + $body .= $this->createBodyEMLHTML ($part); + } + else + throw new \Exception (_("No text/plain nor text/html available"), + 500); + } + + $this->bodyContentEML = $bodyContent; + $this->bodyHeaders = $bodyHeaders; + } + + /** Return the complete mail + */ + public function getMail () + { + $complete = ""; + if (count ($this->parts) === 0) + { + // No attached files available : manage the body in text and/or html + foreach ($this->headers as $key=>$val) + { + $complete .= "$key: $val"; + } + foreach ($this->bodyHeaders as $key=>$val) + { + $complete .= "$key: $val"; + } + $complete .= $this->headerBodySeparator; + $complete .= $this->bodyContentEML; + } + else + { + // Attached files available : the main Content-Type is multipart/mixed; + $boundary = $this->getBoundary (); + $this->headers["Content-Type"] = "multipart/mixed;\r\n". + " boundary=\"$boundary\"\r\n"; + foreach ($this->headers as $key=>$val) + { + $complete .= "$key: $val"; + } + $complete .= $this->headerBodySeparator; + if ($this->bodyContentEML !== "") + { + $complete .= "--$boundary\r\n"; + foreach ($this->bodyHeaders as $key=>$val) + { + $complete .= "$key: $val"; + } + $complete .= $this->headerBodySeparator; + $complete .= $this->bodyContentEML; + } + foreach ($this->parts as $part) + { + $complete .= "--$boundary\r\n"; + foreach ($part as $key=>$val) + { + if ($key{0} === "_") continue; + $complete .= "$key: $val"; + } + $complete .= $this->headerBodySeparator; + $complete .= $part["_content"]; + } + $complete .= "--$boundary--\r\n"; + } + return $complete; + } + + /** Return an array with the details of the mail : + * the number of attachments, the from, to, subject in UTF-8, if there is + * a text and/or html body + * @return array + */ + public function getDetails () + { + $attachmentNb = count ($this->parts); + for ($i = 0 ; $i < count ($this->parts) ; $i ++) + $attachmentDetails[$i] = $this->getAttachmentDetails($i); + unset ($i); + $bodyTextExists = (isset ($this->bodyContent[0]) && + substr ($this->bodyContent[0]["Content-Type"], 0, 10) === "text/plain")? + true: false; + $oldPart = end ($this->bodyContent); + $bodyHtmlExists = (count ($oldPart) && + substr ($oldPart["Content-Type"], 0, 9) === "text/html")? + true:false; + unset ($oldPart); + $size = strlen ($this->getMail()); + $from = $this->getHeader ("From"); + if ($from !== false) + { + $fromArray = $this->convertPeopleToArray ( + $this->decodeHeaders ("From", $from)); + } + $to = $this->getHeader ("To"); + if ($to !== false) + { + $toArray = $this->convertPeopleToArray ( + $this->decodeHeaders ("To", $to)); + } + $date = $this->getDate (); + $dateTimestamp = $this->getDateTimestamp (); + return get_defined_vars(); + } + + /** Create a boundary + * @return the textual boundary + */ + private function getBoundary () + { + $data = openssl_random_pseudo_bytes (16); + $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0010 + $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10 + return "-----=_".vsprintf ('%s%s-%s-%s-%s-%s%s%s', + str_split (bin2hex ($data), 4)); + } + + /** Create a messageID + * @return the textual MessageID + */ + private function getMessageID () + { + $data = openssl_random_pseudo_bytes (16); + $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0010 + $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10 + return "<".vsprintf ('%s%s-%s-%s-%s-%s%s%s', + str_split (bin2hex ($data), 4))."@". + php_uname('n').">"; + } + + /** Convert the content to correct encoding. + * The allowed encodings are "quoted-printable" or "base64" + * Cut the long lines to 76 chars with the correct separator + * @return the content encoded by $encoding + */ + private function encodingEncode ($content, $encoding) + { + if ($encoding === "quoted-printable") + { + $tmp = quoted_printable_encode ($content); + return $tmp; + } + elseif ($encoding === "base64") + { + $tmp = base64_encode ($content); + return chunk_split ($tmp); + } + throw new \Exception (_("Invalid encoding provided to encodingEncode"), + 500); + } + + /** Decode the content with correct encoding. + * The allowed encodings are "quoted-printable" or "base64" + * @return the content decoded by $encoding + */ + private function encodingDecode ($content, $encoding) + { + if ($encoding === "quoted-printable") + return quoted_printable_decode ($content); + elseif ($encoding === "base64") + return base64_decode ($content); + throw new \Exception (_("Invalid encoding provided to encodingDecode"), + 500); + } + + /** Encode a string to be compliant with MIME (used in headers) + * @param $header The header to be used. Will not be returned, but the length + * of the result will be adapted to it + * @param $content The content to encode + * @param $encoding The encoding to use. + * The allowed encodings are "quoted-printable" or "base64" + * @return the content encoded by $encoding + */ + private function encodeHeaders ($header, $content, $encoding) + { + $prefs = array ("input-charset" => "utf-8", + "output-charset" => "utf-8"); + if ($encoding === "quoted-printable") + $prefs["scheme"] = "Q"; + elseif ($encoding === "base64") + $prefs["scheme"] = "B"; + else + throw new \Exception (_("Invalid encoding provided to encodeHeaders"), + 500); + return substr (iconv_mime_encode ($header, $content, $prefs), + strlen ($header)+2); + } + + /** Convert the header to text */ + private function decodeHeaders ($header, $content) + { + return substr (iconv_mime_decode ("$header: $content"), + strlen ($header)+2); + } + + /** Convert a From/To string to array. Manage multiple recipients + * Ex. : toto toto , titi + array (array ("name"=>"toto toto", "mail"=>"toto@toto.com"), + array ("name"=>"titi", "mail"=>"titi@titi.com")) + */ + public function convertPeopleToArray ($data) + { + $elements = explode (",", $data); + $res = array (); + foreach ($elements as $element) + { + @list ($name, $mail) = explode ("<", $element); + if ($mail === null) + { + $mail = $name; + $name = ""; + } + else + { + $name = trim ($name); + $mail = substr (trim ($mail), 0, -1); + } + $array = array ("name"=>$name, "mail"=>$mail); + $res[] = $array; + } + return $res; + } +}