1342 lines
44 KiB
PHP
1342 lines
44 KiB
PHP
<?php
|
|
// File name: mail.inc.php
|
|
// Description: PHP class to compose an RFC 822 e-mail message
|
|
// Date: 2002-06-29
|
|
// Author: imacat <imacat@pristine.com.tw>
|
|
// Copyright: Copyright (C) 2002-2009 Pristine Communications
|
|
|
|
// Set the include path
|
|
if (!defined("INCPATH_SET")) {
|
|
require_once dirname(__FILE__) . "/incpath.inc.php";
|
|
}
|
|
// Referenced subroutines
|
|
require_once "monica/cgiemu.inc.php";
|
|
require_once "monica/curtime.inc.php";
|
|
require_once "monica/errhndl.inc.php";
|
|
require_once "monica/geoip.inc.php";
|
|
require_once "monica/getlang.inc.php";
|
|
require_once "monica/guest.inc.php";
|
|
require_once "monica/https.inc.php";
|
|
require_once "monica/lninfo.inc.php";
|
|
require_once "monica/login.inc.php";
|
|
require_once "monica/md5.inc.php";
|
|
require_once "monica/mimeenc.inc.php";
|
|
require_once "monica/mimetype.inc.php";
|
|
require_once "monica/rfc1521.inc.php";
|
|
require_once "monica/rfc822.inc.php";
|
|
require_once "monica/server.inc.php";
|
|
require_once "monica/unicode.inc.php";
|
|
require_once "monica/upload.inc.php";
|
|
require_once "monica/xfileio.inc.php";
|
|
|
|
// References:
|
|
// RFC 821 SIMPLE MAIL TRANSFER PROTOCOL
|
|
// RFC 822 STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES
|
|
// RFC 1521 MIME (Multipurpose Internet Mail Extensions) Part One: Mechanisms for Specifying and Describing the Format of Internet Message Bodies
|
|
// RFC 1766 Tags for the Identification of Languages
|
|
// RFC 1806 Communicating Presentation Information in Internet Messages: The Content-Disposition Header
|
|
// RFC 1864 The Content-MD5 Header Field
|
|
// RFC 2183 Communicating Presentation Information in Internet Messages: The Content-Disposition Header Field
|
|
// RFC 2369 The Use of URLs as Meta-Syntax for Core Mail List Commands and their Transport through Message Header Fields
|
|
// RFC 2919 List-Id: A Structured Field and Namespace for the Identification of Mailing Lists
|
|
|
|
// Mail: An RFC-822 e-mail message
|
|
// 2005-05-06: All input information must be in UTF-8
|
|
class Mail
|
|
{
|
|
protected $_body = null;
|
|
protected $_parts = array();
|
|
protected $_charset = null;
|
|
protected $_modified = false;
|
|
protected $_output = null;
|
|
protected $_attaches = array();
|
|
|
|
// RFC 821 headers/properties
|
|
protected $_mail_from = null;
|
|
protected $_rcpt_to = null;
|
|
// RFC 822 headers/properties
|
|
protected $_from = null;
|
|
protected $_subject = null;
|
|
protected $_sender = null;
|
|
protected $_to = null;
|
|
protected $_cc = null;
|
|
protected $_bcc = null;
|
|
protected $_reply_to = null;
|
|
// RFC 1521 MIME headers/properties
|
|
protected $_type = "text/plain";
|
|
protected $_id = null;
|
|
// RFC 1766 Content-Language
|
|
protected $_lang = null;
|
|
// RFC 1806/2183 Content-Disposition
|
|
protected $_disposition = null;
|
|
protected $_filename = null;
|
|
protected $_filemtime = null;
|
|
protected $_filesize = null;
|
|
// RFC 1864 Content-MD5
|
|
protected $_md5 = false;
|
|
// RFC 2387 MIME multipart/related headers/properties
|
|
protected $_related_type = null;
|
|
protected $_related_start = null;
|
|
// RFC 2369/2919 Mailing Lists headers/properties
|
|
protected $_list_id = null;
|
|
protected $_list_help = null;
|
|
protected $_list_subscribe = null;
|
|
protected $_list_unsubscribe = null;
|
|
protected $_list_post = null;
|
|
protected $_list_owner = null;
|
|
protected $_list_archive = null;
|
|
// Non-standard headers
|
|
protected $_errors_to = null;
|
|
protected $_precedence = null;
|
|
protected $_mailer = "Monica mail.inc.php http://www.pristine.com.tw/";
|
|
protected $_any_header = array();
|
|
|
|
protected $_boundary_len = 32;
|
|
|
|
// __construct: Initialize the e-mail message
|
|
function __construct()
|
|
{
|
|
// Nothing to initialize
|
|
}
|
|
|
|
// RFC 821 headers/properties
|
|
// mail_from: Set/retrieve the MAIL FROM: sender
|
|
function mail_from($email = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_mail_from = $email;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_mail_from;
|
|
}
|
|
// rcpt_to: Set/retrieve the RCPT TO: recipients (to be used in send())
|
|
function rcpt_to($email = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
// Reset it
|
|
if (is_null($email)) {
|
|
$this->_rcpt_to = null;
|
|
// Add it
|
|
} else {
|
|
if (!is_array($this->_rcpt_to)) {
|
|
$this->_rcpt_to = array();
|
|
}
|
|
if (!in_array($email, $this->_rcpt_to)) {
|
|
$this->_rcpt_to[] = $email;
|
|
}
|
|
}
|
|
}
|
|
return is_null($this->_rcpt_to)? null:
|
|
implode(",", $this->_rcpt_to);
|
|
}
|
|
|
|
// RFC 822 headers/properties
|
|
// from: Set/retrieve the From: header
|
|
function from($email = null, $name = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_add_addr($this->_from, $email, $name);
|
|
}
|
|
return $this->_ret_addrs($this->_from);
|
|
}
|
|
// subject: Set/retrieve the subject
|
|
function subject($subject = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_subject = $subject;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_subject;
|
|
}
|
|
// sender: Set/retrieve the Sender: header
|
|
function sender($email = null, $name = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_set_addr($this->_sender, $email, $name);
|
|
}
|
|
return $this->_ret_addr($this->_sender);
|
|
}
|
|
// to: Set/retrieve the To: header
|
|
function to($email = null, $name = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_add_addr($this->_to, $email, $name);
|
|
}
|
|
return $this->_ret_addrs($this->_to);
|
|
}
|
|
// cc: Set/retrieve the Cc: header
|
|
function cc($email = null, $name = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_add_addr($this->_cc, $email, $name);
|
|
}
|
|
return $this->_ret_addrs($this->_cc);
|
|
}
|
|
// bcc: Set/retrieve the Bcc: header
|
|
function bcc($email = null, $name = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_add_addr($this->_bcc, $email, $name);
|
|
}
|
|
return $this->_ret_addrs($this->_bcc);
|
|
}
|
|
// reply_to: Set/retrieve the Reply-To: header
|
|
function reply_to($email = null, $name = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_add_addr($this->_reply_to, $email, $name);
|
|
}
|
|
return $this->_ret_addrs($this->_reply_to);
|
|
}
|
|
|
|
// RFC 1521 MIME headers/properties
|
|
// charset: Set/retrieve the desired character set
|
|
// Note that this is the desired character set. The input information
|
|
// should still in UTF-8
|
|
function charset($charset = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_charset = $charset;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_charset;
|
|
}
|
|
// type: Set/retrieve the MIME content type
|
|
function type($type = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_type = $type;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_type;
|
|
}
|
|
// id: Set/retrieve the content ID.
|
|
function id($id = true)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
// Set a content ID.
|
|
if ($id) {
|
|
if (is_null($this->_id)) {
|
|
$this->_id = $this->_new_msgid();
|
|
$this->_modified = true;
|
|
}
|
|
// Unset the content ID.
|
|
} else {
|
|
if (!is_null($this->_id)) {
|
|
$this->_id = null;
|
|
$this->_modified = true;
|
|
}
|
|
}
|
|
}
|
|
return $this->_id;
|
|
}
|
|
|
|
// RFC 1766 Content-Language
|
|
// lang: Set/retrieve the language
|
|
function lang($lang = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
// Reset it
|
|
if (is_null($lang)) {
|
|
$this->_lang = null;
|
|
// Add it
|
|
} else {
|
|
if (!is_array($this->_lang)) {
|
|
$this->_lang = array();
|
|
}
|
|
$this->_lang[] = $lang;
|
|
}
|
|
$this->_modified = true;
|
|
}
|
|
if (is_null($this->_lang)) {
|
|
return null;
|
|
} else {
|
|
$langs = array();
|
|
for ($i = 0; $i < count($this->_lang); $i++) {
|
|
$langs[] = ln($this->_lang[$i], LN_NAME);
|
|
}
|
|
return implode(", ", $this->_lang);
|
|
}
|
|
}
|
|
|
|
// RFC 1806/2183 Content-Disposition
|
|
// disposition: Set/retrieve the MIME content disposition
|
|
// "inline" or "attachment"
|
|
function disposition($disposition = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
if (is_null($disposition)) {
|
|
$this->_disposition = null;
|
|
} else {
|
|
switch ($disposition) {
|
|
case "inline":
|
|
case "attachment":
|
|
$this->_disposition = $disposition;
|
|
break;
|
|
default:
|
|
trigger_error("bad content disposition $disposition", E_USER_ERROR);
|
|
break;
|
|
}
|
|
}
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_disposition;
|
|
}
|
|
// filename: Set/retrieve the MIME content disposition filename
|
|
function filename($filename = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_filename = $filename;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_filename;
|
|
}
|
|
// filemtime: Set/retrieve the MIME content disposition modification time
|
|
function filemtime($mtime = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_filemtime = $mtime;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_filemtime;
|
|
}
|
|
// filesize: Set/retrieve the MIME content disposition size
|
|
function filesize($size = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_filesize = $size;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_filesize;
|
|
}
|
|
|
|
// RFC 1864 Content-MD5
|
|
// md5: Set/retrieve the MD5 digest flag
|
|
function md5($md5 = true)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_md5 = $md5? true: false;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_md5;
|
|
}
|
|
|
|
// RFC 2387 MIME multipart/related headers/properties
|
|
// related_type: Set/retrieve the multipart/related type
|
|
function related_type($reltype = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_related_type = $reltype;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_related_type;
|
|
}
|
|
// related_start: Set/retrieve the multipart/related start
|
|
function related_start($relstart = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_related_start = $relstart;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_related_start;
|
|
}
|
|
|
|
// RFC 2369/2919 Mailing Lists headers/properties
|
|
// list_id: Set/retrieve the list ID.
|
|
function list_id($id = null, $phrase = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
// Reset it
|
|
if (is_null($id)) {
|
|
$this->_list_id = null;
|
|
// Set it
|
|
} else {
|
|
$this->_list_id = array(
|
|
"id" => $id,
|
|
"phrase" => $phrase,
|
|
);
|
|
}
|
|
$this->_modified = true;
|
|
}
|
|
if (is_null($this->_list_id)) {
|
|
return null;
|
|
}
|
|
$ret = "<" . $this->_list_id["id"] . ">";
|
|
if (!is_null($this->_list_id["phrase"])) {
|
|
$phrase = $this->_list_id["phrase"];
|
|
if (rfc822_phrase_need_quoting($phrase)) {
|
|
$phrase = "\"" . addslashes($phrase) . "\"";
|
|
}
|
|
$ret = "$phrase $ret";
|
|
}
|
|
return $ret;
|
|
}
|
|
// list_help: Set/retrieve the list help address
|
|
function list_help($url = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_add_list_url($this->_list_help, $url);
|
|
}
|
|
return $this->_ret_list_urls($this->_list_help);
|
|
}
|
|
// list_subscribe: Set/retrieve the list subscribe address
|
|
function list_subscribe($url = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_add_list_url($this->_list_subscribe, $url);
|
|
}
|
|
return $this->_ret_list_urls($this->_list_subscribe);
|
|
}
|
|
// list_unsubscribe: Set/retrieve the list unsubscribe address
|
|
function list_unsubscribe($url = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_add_list_url($this->_list_unsubscribe, $url);
|
|
}
|
|
return $this->_ret_list_urls($this->_list_unsubscribe);
|
|
}
|
|
// list_post: Set/retrieve the list post address
|
|
// False means "List-Post: NO"
|
|
function list_post($url = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
if ($url === false) {
|
|
$this->_list_post = false;
|
|
} else {
|
|
$this->_add_list_url($this->_list_post, $url);
|
|
}
|
|
}
|
|
if ($this->_list_post === false) {
|
|
return "NO";
|
|
} else {
|
|
return $this->_ret_list_urls($this->_list_post);
|
|
}
|
|
}
|
|
// list_owner: Set/retrieve the list owner address
|
|
function list_owner($url = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_add_list_url($this->_list_owner, $url);
|
|
}
|
|
return $this->_ret_list_urls($this->_list_owner);
|
|
}
|
|
// list_archive: Set/retrieve the list archive address
|
|
function list_archive($url = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_add_list_url($this->_list_archive, $url);
|
|
}
|
|
return $this->_ret_list_urls($this->_list_archive);
|
|
}
|
|
|
|
// Non-standard headers
|
|
// errors_to: Set/retrieve the Errors-To: header
|
|
function errors_to($email = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
if (is_null($email)) {
|
|
$this->_errors_to = null;
|
|
} else {
|
|
if (!is_array($this->_errors_to)) {
|
|
$this->_errors_to = array();
|
|
}
|
|
$this->_errors_to[] = $email;
|
|
}
|
|
$this->_modified = true;
|
|
}
|
|
return is_null($this->_errors_to)? null:
|
|
implode(", ", $this->_errors_to);
|
|
}
|
|
// precedence: Set/retrieve the precedence, mentioned in RFC 2076
|
|
// "bulk" or "first-class"
|
|
function precedence($precedence = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
if (is_null($precedence)) {
|
|
$this->_precedence = null;
|
|
} else {
|
|
switch ($precedence) {
|
|
case "bulk":
|
|
case "first-class":
|
|
$this->_precedence = $precedence;
|
|
break;
|
|
default:
|
|
trigger_error("bad precedence $precedence", E_USER_ERROR);
|
|
break;
|
|
}
|
|
}
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_precedence;
|
|
}
|
|
|
|
// mailer: Set/retrieve the mailer
|
|
function mailer($mailer = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_mailer = $mailer;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_mailer;
|
|
}
|
|
|
|
// any_header: Set/retrieve any header
|
|
function any_header($name, $value = null)
|
|
{
|
|
// Find the index of that header
|
|
unset($ndx);
|
|
for ($i = 0; $i < count($this->_any_header); $i++) {
|
|
if ($this->_any_header[$i]["name"] = $name) {
|
|
$ndx = $i;
|
|
break;
|
|
}
|
|
}
|
|
// Set the value
|
|
if (func_num_args() > 1) {
|
|
if (isset($ndx)) {
|
|
$this->_any_header[$ndx]["value"] = $value;
|
|
} else {
|
|
// Only add a non-null value
|
|
if (!is_null($value)) {
|
|
$this->_any_header[] = array(
|
|
"name" => $name,
|
|
"value" => $value,
|
|
);
|
|
}
|
|
}
|
|
$this->_modified = true;
|
|
return $value;
|
|
// Retrieve the value
|
|
} else {
|
|
if (isset($ndx)) {
|
|
return $this->_any_header[$ndx]["value"];
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
// body: Set/retrieve the body
|
|
function body($body = null)
|
|
{
|
|
if (func_num_args() > 0) {
|
|
$this->_body = $body;
|
|
$this->_modified = true;
|
|
}
|
|
return $this->_body;
|
|
}
|
|
|
|
// addpart: Add an MIME part
|
|
// $mail is a Mail object
|
|
function addpart($mail)
|
|
{
|
|
if (is_null($mail)) {
|
|
$this->_parts = array();
|
|
} else {
|
|
$this->_parts[] = $mail;
|
|
}
|
|
$this->_modified = true;
|
|
return $mail;
|
|
}
|
|
|
|
// from_file: Set the mail from a file
|
|
function from_file($file)
|
|
{
|
|
$this->_type = check_mime_type($file);
|
|
$this->_body = xfread($file);
|
|
$this->_modified = true;
|
|
return;
|
|
}
|
|
|
|
// as_attach: Set the mail as an attachment
|
|
function as_attach($file, $filename = null)
|
|
{
|
|
$this->_type = check_mime_type($file);
|
|
$this->_disposition = "attachment";
|
|
$this->_filename = !is_null($filename)? $filename:
|
|
basename($file);
|
|
$this->_filemtime = filemtime($file);
|
|
$this->_filesize = filesize($file);
|
|
$this->_body = xfread($file);
|
|
$this->_modified = true;
|
|
return $this->_body;
|
|
}
|
|
|
|
// as_attach_upload: Set the an attachment from $_SESSION
|
|
function as_attach_upload($sn)
|
|
{
|
|
$FILES =& file_deposit();
|
|
$file =& $FILES[$sn];
|
|
$this->_charset = getlang(LN_CHARSET);
|
|
$this->_type = $file["type"];
|
|
$this->_disposition = "attachment";
|
|
$this->_filename = $file["name"];
|
|
$this->_filesize = $file["size"];
|
|
$this->_body = $file["content"];
|
|
$this->_modified = true;
|
|
return $this->_body;
|
|
}
|
|
|
|
// add_attach: Add an attachment
|
|
function add_attach($file, $filename = null)
|
|
{
|
|
if (is_null($file)) {
|
|
$this->_attaches = array();
|
|
} else {
|
|
// Create the attachment
|
|
$attach = new Mail();
|
|
$attach->as_attach($file, $filename);
|
|
$this->_attaches[] = $attach;
|
|
}
|
|
$this->_modified = true;
|
|
return;
|
|
}
|
|
|
|
// add_attach_upload: Add an attachment from $_SESSION
|
|
function add_attach_upload($sn)
|
|
{
|
|
if (is_null($sn)) {
|
|
$this->_attaches = array();
|
|
} else {
|
|
// Create the attachment
|
|
$attach = new Mail();
|
|
$attach->as_attach_upload($sn);
|
|
$this->_attaches[] = $attach;
|
|
}
|
|
$this->_modified = true;
|
|
return;
|
|
}
|
|
|
|
// output: Output the mail message
|
|
function output($is_full_msg = true)
|
|
{
|
|
// Output before
|
|
if (!is_null($this->_output) && !$this->_modified) {
|
|
return $this->_output;
|
|
}
|
|
// Preserve the original timeout
|
|
$timeout = ini_get("max_execution_time");
|
|
ini_set("max_execution_time", 0);
|
|
|
|
// Set the attachment
|
|
$mail = $this->_get_attached_mail();
|
|
|
|
// Check the message
|
|
if ($is_full_msg) {
|
|
$mail->_check();
|
|
}
|
|
|
|
// Set the mail body
|
|
// Set the body first, since we need to know Content-Transfer-Encoding
|
|
// and MIME multipart boundary first
|
|
$body = "";
|
|
unset($content_transfer_encoding);
|
|
// A single content
|
|
if ( is_null($mail->_type)
|
|
|| substr($mail->_type, 0, 10) != "multipart/") {
|
|
if (!is_null($mail->_body)) {
|
|
$body = $mail->_body;
|
|
// A text message
|
|
if (substr($mail->_type, 0, 5) == "text/") {
|
|
// Convert to the desired character set
|
|
// This piece of code shall be refined
|
|
if ( $mail->_type == "text/plain"
|
|
&& !is_usascii_printable($body)
|
|
&& !is_null($this->_charset)
|
|
&& $this->_charset != "UTF-8") {
|
|
$body = iconv("UTF-8", $this->_charset, $body);
|
|
}
|
|
$body = str_replace("\r\n", "\n", $body);
|
|
$body = str_replace("\n", "\r\n", $body);
|
|
if ($mail->_md5) {
|
|
$md5 = md5_base64($body);
|
|
}
|
|
// Not in US-ASCII, containing long lines, or MD5 is in use
|
|
if ( !is_usascii_printable_text($body)
|
|
|| preg_match("/[^\r\n]{76}/", $body)
|
|
|| $mail->_md5) {
|
|
$body = qpencode($body);
|
|
$content_transfer_encoding = "quoted-printable";
|
|
}
|
|
|
|
// A piece of RFC-822 e-mail message
|
|
} elseif (substr($mail->_type, 0, 8) == "message/") {
|
|
// Do nothing
|
|
|
|
// A piece of binary data
|
|
} else {
|
|
if ($mail->_md5) {
|
|
$md5 = md5_base64($body);
|
|
}
|
|
$body = base64_encode($body);
|
|
$body = preg_replace("/(.{76})/", "$1\r\n", $body);
|
|
$content_transfer_encoding = "base64";
|
|
}
|
|
}
|
|
|
|
// A multipart MIME content
|
|
} else {
|
|
$parts = array();
|
|
for ($i = 0; $i < count($mail->_parts); $i++) {
|
|
$parts[] = $mail->_parts[$i]->output(false);
|
|
}
|
|
$everything = implode("", $parts);
|
|
// Create a boundary
|
|
do {
|
|
$boundary = "=_";
|
|
while (strlen($boundary) < $mail->_boundary_len) {
|
|
switch (mt_rand(0, 2)) {
|
|
case 0:
|
|
$boundary .= chr(mt_rand(0, 9) + ord("0"));
|
|
break;
|
|
case 1:
|
|
$boundary .= chr(mt_rand(0, 25) + ord("A"));
|
|
break;
|
|
case 2:
|
|
$boundary .= chr(mt_rand(0, 25) + ord("a"));
|
|
break;
|
|
}
|
|
}
|
|
} while (strpos($everything, $boundary) !== false);
|
|
// Add the boundary
|
|
for ($i = 0; $i < count($parts); $i++) {
|
|
$parts[$i] = "--$boundary\r\n" . $parts[$i] . "\r\n";
|
|
}
|
|
// Compose the body
|
|
$body = implode("", $parts) . "--$boundary--\r\n";
|
|
}
|
|
// Ensure a CRLF is in the end
|
|
if (substr($body, -2) != "\r\n") {
|
|
$body .= "\r\n";
|
|
}
|
|
|
|
$headers = array();
|
|
|
|
// RFC 822 headers
|
|
// RFC-822 suggests the header order as:
|
|
// "Return-Path", "Received", "Date", "From", "Subject", "Sender",
|
|
// "To", "cc", etc.
|
|
// We do not set the Received: header. It is added before mail is sent.
|
|
// Set the Date: header
|
|
if ($is_full_msg) {
|
|
$headers[] = "Date: " . date("r", NOW) . "\r\n";
|
|
}
|
|
// Set the From: header
|
|
if (!is_null($mail->_from)) {
|
|
$headers[] = "From: " . $mail->_out_addrs($mail->_from) . "\r\n";
|
|
} elseif ($is_full_msg) {
|
|
$pwent = posix_getpwuid(posix_geteuid());
|
|
$addr = array(
|
|
"name" => $pwent["gecos"],
|
|
"email" => $pwent["name"] . "@" . fqdn(),
|
|
);
|
|
$headers[] = "From: " . $mail->_out_addr($addr) . "\r\n";
|
|
}
|
|
// Set the Subject: header
|
|
if (!is_null($mail->_subject)) {
|
|
$subject = $this->_subject;
|
|
$subject = b64hdr_encode($subject, $this->_charset);
|
|
$headers[] = "Subject: $subject\r\n";
|
|
}
|
|
// Set the Sender: header
|
|
if (!is_null($mail->_sender)) {
|
|
$need = false;
|
|
// Multiple From:
|
|
if (count($mail->_from) > 1) {
|
|
$need = true;
|
|
// Different than the only From:
|
|
} elseif ( $mail->_from[0]["email"] !== $mail->_sender["email"]
|
|
|| $mail->_from[0]["name"] !== $mail->_sender["name"]) {
|
|
$need = true;
|
|
}
|
|
if ($need) {
|
|
$headers[] = "Sender: " . $mail->_out_addr($mail->_sender) . "\r\n";
|
|
}
|
|
}
|
|
// Set the To: header
|
|
if (!is_null($mail->_to)) {
|
|
$headers[] = "To: " . $mail->_out_addrs($mail->_to) . "\r\n";
|
|
}
|
|
// Set the Cc: header
|
|
if (!is_null($mail->_cc)) {
|
|
$headers[] = "Cc: " . $mail->_out_addrs($mail->_cc) . "\r\n";
|
|
}
|
|
// Set the Bcc: header
|
|
if (!is_null($mail->_bcc)) {
|
|
$headers[] = "Bcc: " . $mail->_out_addrs($mail->_bcc) . "\r\n";
|
|
}
|
|
// Destination must exist (by RFC 822 4.1)
|
|
/* if ( $is_full_msg
|
|
&& is_null($mail->_to)
|
|
&& is_null($mail->_cc)
|
|
&& is_null($mail->_bcc)) {
|
|
$headers[] = "Bcc: \r\n";
|
|
} */
|
|
// Set the Reply-To: header
|
|
if (!is_null($mail->_reply_to)) {
|
|
$headers[] = "Reply-To: " . $mail->_out_addrs($mail->_reply_to) . "\r\n";
|
|
}
|
|
// Set the Message-ID: header
|
|
if ($is_full_msg) {
|
|
$id = !is_null($mail->_id)? $mail->_id: $mail->_new_msgid();
|
|
$headers[] = "Message-ID: <$id>\r\n";
|
|
}
|
|
|
|
// RFC 1521 MIME headers
|
|
// Set the MIME-Version: header
|
|
if ($is_full_msg && !is_null($mail->_type)) {
|
|
$headers[] = "MIME-Version: 1.0\r\n";
|
|
}
|
|
// Set the Content-Type: header
|
|
if (!is_null($mail->_type)) {
|
|
$type = $mail->_type;
|
|
if (substr($type, 0, 5) == "text/" && !is_null($mail->_charset)) {
|
|
$type .= "; charset=" . $mail->_charset;
|
|
}
|
|
// Attachment filename -- deprecated
|
|
/* if (!is_null($mail->_filename)) {
|
|
$filename = $mail->_filename;
|
|
$filename = b64hdr_encode($filename, $this->_charset);
|
|
if (rfc1521_value_need_quoting($filename)) {
|
|
$filename = "\"" . addslashes($filename) . "\"";
|
|
}
|
|
$type .= ";\r\n name=$filename";
|
|
} */
|
|
if (substr($type, 0, 10) == "multipart/") {
|
|
// Add type and start parameter to multipart/related
|
|
if ($type == "multipart/related") {
|
|
$reltype = $mail->_related_type;
|
|
if (is_null($reltype)) {
|
|
$reltype = $mail->_parts[0]->type();
|
|
}
|
|
$type .= ";\r\n type=\"$reltype\"";
|
|
// "start" parameter is broken in most e-mail client (??? why?)
|
|
/* $relstart = $mail->_related_start;
|
|
if (is_null($relstart)) {
|
|
$relstart = $mail->_parts[0]->id(true);
|
|
}
|
|
$type .= ";\r\n start=\"$relstart\""; */
|
|
}
|
|
$type .= ";\r\n boundary=\"$boundary\"";
|
|
}
|
|
$headers[] = "Content-Type: $type\r\n";
|
|
}
|
|
// Set the Content-ID: header
|
|
// Do not generate Content-ID for complete messages. Complete
|
|
// messages has Message-ID instead.
|
|
if (!$is_full_msg && !is_null($mail->_id)) {
|
|
$headers[] = "Content-ID: <" . $mail->_id . ">\r\n";
|
|
}
|
|
// Set the Content-Transfer-Encoding: header
|
|
if (isset($content_transfer_encoding)) {
|
|
$headers[] = "Content-Transfer-Encoding: $content_transfer_encoding\r\n";
|
|
}
|
|
|
|
// RFC 1766 Content-Language
|
|
if (!is_null($mail->_lang)) {
|
|
$langs = array();
|
|
for ($i = 0; $i < count($mail->_lang); $i++) {
|
|
$langs[] = ln($mail->_lang[$i], LN_NAME);
|
|
}
|
|
$headers[] = "Content-Language: " . implode(", ", $langs) . "\r\n";
|
|
}
|
|
|
|
// RFC 1806/2183 Content-Disposition
|
|
if (!is_null($mail->_disposition)) {
|
|
$disposition = $mail->_disposition;
|
|
if (!is_null($mail->_filename)) {
|
|
$filename = $mail->_filename;
|
|
// Note: Eudora cannot handle encoded MIME parameter values
|
|
$filename = b64hdr_encode($filename, $this->_charset);
|
|
if (rfc1521_value_need_quoting($filename)) {
|
|
$filename = "\"" . addslashes($filename) . "\"";
|
|
}
|
|
$disposition .= ";\r\n filename=$filename";
|
|
}
|
|
if (!is_null($mail->_filemtime)) {
|
|
$disposition .= ";\r\n modification-date=\""
|
|
. date("r", $mail->_filemtime) . "\"";
|
|
}
|
|
if (!is_null($mail->_filesize)) {
|
|
$disposition .= ";\r\n size=" . $mail->_filesize;
|
|
}
|
|
$headers[] = "Content-Disposition: $disposition\r\n";
|
|
}
|
|
// RFC 1864 Content-MD5
|
|
if ($mail->_md5) {
|
|
$headers[] = "Content-MD5: $md5\r\n";
|
|
}
|
|
|
|
// RFC 2369/2919 Mailing Lists headers
|
|
// Set the List-ID: header
|
|
if (!is_null($mail->_list_id)) {
|
|
$list_id = "<" . $mail->_list_id["id"] . ">";
|
|
if (!is_null($mail->_list_id["phrase"])) {
|
|
$phrase = $mail->_list_id["phrase"];
|
|
if (rfc822_phrase_need_quoting($phrase)) {
|
|
$phrase = "\"" . addslashes($phrase) . "\"";
|
|
}
|
|
$phrase = b64hdr_encode($phrase, $this->_charset);
|
|
$list_id = "$phrase $list_id";
|
|
}
|
|
$headers[] = "List-ID: $list_id\r\n";
|
|
}
|
|
// Set the List-Help: header
|
|
if (!is_null($mail->_list_help)) {
|
|
$headers[] = "List-Help: "
|
|
. $mail->_out_list_urls($mail->_list_help) . "\r\n";
|
|
}
|
|
// Set the List-Subscribe: header
|
|
if (!is_null($mail->_list_subscribe)) {
|
|
$headers[] = "List-Subscribe: "
|
|
. $mail->_out_list_urls($mail->_list_subscribe) . "\r\n";
|
|
}
|
|
// Set the List-Unsubscribe: header
|
|
if (!is_null($mail->_list_unsubscribe)) {
|
|
$headers[] = "List-Unsubscribe: "
|
|
. $mail->_out_list_urls($mail->_list_unsubscribe) . "\r\n";
|
|
}
|
|
// Set the List-Post: header
|
|
if (!is_null($mail->_list_post)) {
|
|
$list_post = ($mail->_list_post !== false)?
|
|
$mail->_out_list_urls($mail->_list_post): "NO";
|
|
$headers[] = "List-Post: $list_post\r\n";
|
|
}
|
|
// Set the List-Owner: header
|
|
if (!is_null($mail->_list_owner)) {
|
|
$headers[] = "List-Owner: "
|
|
. $mail->_out_list_urls($mail->_list_owner) . "\r\n";
|
|
}
|
|
// Set the List-Archive: header
|
|
if (!is_null($mail->_list_archive)) {
|
|
$headers[] = "List-Archive: "
|
|
. $mail->_out_list_urls($mail->_list_archive) . "\r\n";
|
|
}
|
|
|
|
// Set the Errors-To: header
|
|
if ($is_full_msg && !is_null($mail->_errors_to)) {
|
|
$headers[] = "Errors-To: " . implode(", ", $mail->_errors_to) . "\r\n";
|
|
}
|
|
|
|
// Set the Precedence: header
|
|
if ($is_full_msg && !is_null($mail->_precedence)) {
|
|
$headers[] = "Precedence: " . $mail->_precedence . "\r\n";
|
|
}
|
|
|
|
// Set the X-Mailer: header
|
|
if ($is_full_msg && !is_null($mail->_mailer)) {
|
|
$headers[] = "X-Mailer: " . $mail->_mailer . "\r\n";
|
|
}
|
|
|
|
// Compose it
|
|
$this->_output = implode("", $headers) . "\r\n" . $body;
|
|
$this->_modified = false;
|
|
// Restore the timeout
|
|
ini_set("max_execution_time", $timeout);
|
|
return $this->_output;
|
|
}
|
|
|
|
// send: Send the mail message
|
|
function send()
|
|
{
|
|
// Send the mail with sendmail
|
|
return $this->_send_with_sendmail();
|
|
}
|
|
|
|
// gsend: Send the mail message if the user is not a guest
|
|
function gsend()
|
|
{
|
|
if (!is_guest()) {
|
|
return $this->send();
|
|
}
|
|
}
|
|
|
|
// _new_msgid: Obtain a new message ID.
|
|
function _new_msgid()
|
|
{
|
|
static $MSGIDS = array();
|
|
// Epoch time and minisecond
|
|
list($msec, $sec) = explode(" ", microtime());
|
|
settype($sec, "integer");
|
|
$msec *= 1000000;
|
|
settype($msec, "integer");
|
|
// A random serial number
|
|
do {
|
|
$sn = mt_rand(0, 9999);
|
|
} while (in_array($sn, $MSGIDS));
|
|
$MSGIDS[] = $sn;
|
|
// Compose it
|
|
return sprintf("%10d.%06d.%05d.%04d.monica@%s",
|
|
$sec, $msec, getmypid(), $sn, fqdn());
|
|
}
|
|
|
|
// _get_attached_mail: Get the mail with its attachment
|
|
// Actually, this will convert the mail to multipart/mixed
|
|
// and add the attachments
|
|
function _get_attached_mail()
|
|
{
|
|
// Make a copy of myself
|
|
$mail = $this;
|
|
|
|
// Return myself if there is no attachment
|
|
if (count($mail->_attaches) == 0) {
|
|
return $mail;
|
|
}
|
|
|
|
// Not multipart/mixed -- convert to multipart/mixed
|
|
if (is_null($mail->_type) || $mail->_type != "multipart/mixed") {
|
|
// Pass the content to the body part
|
|
$body = new Mail();
|
|
$body->_charset = $mail->_charset;
|
|
$body->_type = $mail->_type;
|
|
$body->_id = $mail->_id;
|
|
$body->_lang = $mail->_lang;
|
|
$body->_md5 = $mail->_md5;
|
|
// Set the body
|
|
// The origin is multipart/xxx
|
|
if (!is_null($mail->_type) && substr($mail->_type, 0, 10) == "multipart/") {
|
|
$body->_parts = $mail->_parts;
|
|
} else {
|
|
$body->_body = $mail->_body;
|
|
}
|
|
// Reset these values
|
|
$mail->_parts = array();
|
|
$mail->_body = null;
|
|
$mail->_type = "multipart/mixed";
|
|
$mail->_id = null;
|
|
$mail->_lang = null;
|
|
$mail->_md5 = false;
|
|
$mail->addpart($body);
|
|
}
|
|
|
|
// Add each attachment
|
|
foreach ($mail->_attaches as $attach) {
|
|
$mail->addpart($attach);
|
|
}
|
|
|
|
return $mail;
|
|
}
|
|
|
|
// _set_addr: Set an address
|
|
function _set_addr(&$addr, $email, $name)
|
|
{
|
|
// Reset it
|
|
if (is_null($email)) {
|
|
$addr = null;
|
|
// Set it
|
|
} else {
|
|
$addr = array(
|
|
"name" => $name,
|
|
"email" => $email,
|
|
);
|
|
}
|
|
$this->_modified = true;
|
|
}
|
|
// _add_addr: Add an address to an address list
|
|
function _add_addr(&$list, $email, $name)
|
|
{
|
|
// Reset it
|
|
if (is_null($email)) {
|
|
$list = null;
|
|
// Add it
|
|
} else {
|
|
if (!is_array($list)) {
|
|
$list = array();
|
|
}
|
|
$list[] = array(
|
|
"name" => $name,
|
|
"email" => $email,
|
|
);
|
|
}
|
|
$this->_modified = true;
|
|
}
|
|
|
|
// _ret_addr: Return an address
|
|
function _ret_addr($addr)
|
|
{
|
|
if (is_null($addr)) {
|
|
return null;
|
|
} elseif (is_null($addr["name"])) {
|
|
return $addr["email"];
|
|
} else {
|
|
$name = $addr["name"];
|
|
if (rfc822_phrase_need_quoting($name)) {
|
|
$name = "\"" . addslashes($name) . "\"";
|
|
}
|
|
return sprintf("%s <%s>", $name, $addr["email"]);
|
|
}
|
|
}
|
|
// _ret_addrs: Return a list of addresses
|
|
function _ret_addrs(&$list)
|
|
{
|
|
if (is_null($list)) {
|
|
return null;
|
|
} else {
|
|
$addrs = array();
|
|
for ($i = 0; $i < count($list); $i++) {
|
|
$addrs[] = $this->_ret_addr($list[$i]);
|
|
}
|
|
return implode(", ", $addrs);
|
|
}
|
|
}
|
|
|
|
// _out_addr: Output an address
|
|
function _out_addr($addr)
|
|
{
|
|
$out = $addr["email"];
|
|
if (!is_null($addr["name"])) {
|
|
$name = $addr["name"];
|
|
if (rfc822_phrase_need_quoting($name)) {
|
|
$name = "\"" . addslashes($name) . "\"";
|
|
}
|
|
$name = b64hdr_encode($name, $this->_charset);
|
|
$out = "$name <$out>";
|
|
}
|
|
return $out;
|
|
}
|
|
// _out_addrs: Output a list of addresses
|
|
function _out_addrs(&$list)
|
|
{
|
|
$addrs = array();
|
|
for ($i = 0; $i < count($list); $i++) {
|
|
$addrs[] = $this->_out_addr($list[$i]);
|
|
}
|
|
return implode(",\r\n ", $addrs);
|
|
}
|
|
|
|
// _add_list_url: Add a list URL to a list URL list
|
|
function _add_list_url(&$list, $url)
|
|
{
|
|
// Reset it
|
|
if (is_null($url)) {
|
|
$list = null;
|
|
// Add it
|
|
} else {
|
|
if (!is_array($list)) {
|
|
$list = array();
|
|
}
|
|
$list[] = $url;
|
|
}
|
|
$this->_modified = true;
|
|
}
|
|
// _ret_list_urls: Return a list of list URLs
|
|
function _ret_list_urls(&$list)
|
|
{
|
|
if (is_null($list)) {
|
|
return null;
|
|
} else {
|
|
$urls = array();
|
|
for ($i = 0; $i < count($list); $i++) {
|
|
$urls[] = "<" . $list[$i] . ">";
|
|
}
|
|
return implode(", ", $urls);
|
|
}
|
|
}
|
|
// _out_list_urls: Output a list of list URLs
|
|
function _out_list_urls(&$list)
|
|
{
|
|
$urls = array();
|
|
for ($i = 0; $i < count($list); $i++) {
|
|
$urls[] = "<" . $list[$i] . ">";
|
|
}
|
|
return implode(",\r\n ", $urls);
|
|
}
|
|
// _out_trace: Output the trace information (the Received: header)
|
|
// See RFC 2821 4.4 Trace Information
|
|
function _out_trace()
|
|
{
|
|
// The trace information
|
|
$trace_info = array();
|
|
|
|
// From-domain
|
|
$from_tcpinfo_domain = gethostbyaddr($_SERVER["REMOTE_ADDR"]);
|
|
if ($from_tcpinfo_domain == $_SERVER["REMOTE_ADDR"]) {
|
|
$from_tcpinfo_domain = null;
|
|
}
|
|
if (is_null($from_tcpinfo_domain)) {
|
|
$from_tcp_info = sprintf("[%s]", $_SERVER["REMOTE_ADDR"]);
|
|
} else {
|
|
$from_tcp_info = sprintf("%s [%s]",
|
|
$from_tcpinfo_domain, $_SERVER["REMOTE_ADDR"]);
|
|
}
|
|
$trace_info[] = "from webclient ($from_tcp_info)";
|
|
|
|
// The invoking user, as a from comment
|
|
if (is_null(get_login_sn())) {
|
|
$from_comment = "invoked by anonymous web user"
|
|
. " country " . geoiplookup();
|
|
} else {
|
|
$from_comment = "invoked by web user " . get_login_id()
|
|
. " S/N " . get_login_sn()
|
|
. " country " . geoiplookup();
|
|
}
|
|
$trace_info[] = "($from_comment)";
|
|
|
|
// By-domain
|
|
// Apache implementation
|
|
if (is_apache()) {
|
|
$by_address_literal = $_SERVER["SERVER_ADDR"];
|
|
// Microsoft IIS implementation
|
|
} elseif (is_iis()) {
|
|
$by_address_literal = $_SERVER["LOCAL_ADDR"];
|
|
// Else, do DNS query
|
|
} else {
|
|
$by_address_literal = gethostbyname($_SERVER["SERVER_NAME"]);
|
|
}
|
|
if (array_key_exists("HTTP_HOST", $_SERVER)) {
|
|
$by_domain = preg_replace("/:\d+$/", "", $_SERVER["HTTP_HOST"]);
|
|
} else {
|
|
$by_domain = $by_address_literal;
|
|
}
|
|
$by_tcpinfo_domain = gethostbyaddr($by_address_literal);
|
|
if ($by_tcpinfo_domain == $by_address_literal) {
|
|
$by_tcpinfo_domain = null;
|
|
}
|
|
if (is_null($by_tcpinfo_domain)) {
|
|
$by_tcp_info = sprintf("[%s]", $by_address_literal);
|
|
} else {
|
|
$by_tcp_info = sprintf("%s [%s]",
|
|
$by_tcpinfo_domain, $by_address_literal);
|
|
}
|
|
$trace_info[] = sprintf("by %s (%s)", $by_domain, $by_tcp_info);
|
|
|
|
// VIA Link and WITH Protocol
|
|
$trace_info[] = "via TCP with HTTP";
|
|
|
|
// For recipients
|
|
$rcpts = $this->_get_rcpts();
|
|
if (count($rcpts) > 0) {
|
|
for ($i = 0; $i < count($rcpts); $i++) {
|
|
$rcpts[$i] = "<" . $rcpts[$i] . ">";
|
|
}
|
|
$trace_info[] = "for " . implode(" ", $rcpts);
|
|
}
|
|
|
|
return sprintf("Received: %s ;\r\n\t%s\r\n",
|
|
implode("\r\n\t", $trace_info), date("r", NOW));
|
|
}
|
|
|
|
// _check: Check if it is ready to be output
|
|
// Refer to RFC 822
|
|
function _check()
|
|
{
|
|
// When no valid From: exists, default to the current user of the running process
|
|
// Check if a valid Sender: exists with multiple From:
|
|
if ( !is_null($this->_from)
|
|
&& count($this->_from) > 1
|
|
&& is_null($this->_sender)) {
|
|
trigger_error("Multiple From: without a valid Sender: (RFC-822)", E_USER_ERROR);
|
|
}
|
|
// Check if valid contents exist
|
|
if ( !is_null($this->_type)
|
|
&& substr($this->_type, 0, 10) == "multipart/"
|
|
&& count($this->_parts) == 0) {
|
|
trigger_error("MIME Multipart without any valid part", E_USER_ERROR);
|
|
}
|
|
}
|
|
|
|
// _get_sender: Obtain the sender
|
|
function _get_sender($fallback = false)
|
|
{
|
|
// MAIL FROM: specified
|
|
if (!is_null($this->_mail_from)) {
|
|
return $this->_mail_from;
|
|
// Sender specified
|
|
} elseif (!is_null($this->_sender)) {
|
|
return $this->_sender["email"];
|
|
// Obtain the sender from From:
|
|
} elseif (!is_null($this->_from)) {
|
|
return $this->_from[0]["email"];
|
|
// Nothing left
|
|
} elseif (!$fallback) {
|
|
return null;
|
|
// Use the current user
|
|
} else {
|
|
$pwent = posix_getpwuid(posix_geteuid());
|
|
return $pwent["name"] . "@" . fqdn();
|
|
}
|
|
}
|
|
|
|
// _get_rcpts: Collect the recipients list
|
|
function _get_rcpts()
|
|
{
|
|
// Recipients specified
|
|
if (!is_null($this->_rcpt_to)) {
|
|
return $this->_rcpt_to;
|
|
}
|
|
|
|
// Obtain the recipients from To:, Cc: and Bcc:
|
|
$rcpts = array();
|
|
for ($i = 0; $i < count($this->_to); $i++) {
|
|
if (!in_array($this->_to[$i]["email"], $rcpts)) {
|
|
$rcpts[] = $this->_to[$i]["email"];
|
|
}
|
|
}
|
|
for ($i = 0; $i < count($this->_cc); $i++) {
|
|
if (!in_array($this->_cc[$i]["email"], $rcpts)) {
|
|
$rcpts[] = $this->_cc[$i]["email"];
|
|
}
|
|
}
|
|
for ($i = 0; $i < count($this->_bcc); $i++) {
|
|
if (!in_array($this->_bcc[$i]["email"], $rcpts)) {
|
|
$rcpts[] = $this->_bcc[$i]["email"];
|
|
}
|
|
}
|
|
return $rcpts;
|
|
}
|
|
|
|
// _send_with_sendmail: Send the mail with Sendmail
|
|
function _send_with_sendmail()
|
|
{
|
|
// Obtain the sender
|
|
$sender = $this->_get_sender();
|
|
// Collect the Recipients list
|
|
$rcpts = $this->_get_rcpts();
|
|
// No recipients found
|
|
if (count($rcpts) == 0) {
|
|
trigger_error("No recipients found", E_USER_ERROR);
|
|
}
|
|
|
|
// Send with Sendmail
|
|
$sendmail = array("/usr/sbin/sendmail", "-odb");
|
|
if (!is_null($sender)) {
|
|
$sendmail = array_merge($sendmail, array("-f", $sender));
|
|
}
|
|
$sendmail = array_merge($sendmail, $rcpts);
|
|
$mail = $this->_out_trace() . $this->output();
|
|
// Sendmail must escape "." on a line. See RFC 821 SMTP 4.5.2
|
|
$mail = preg_replace("/^(\.+)\r$/m", ".$1", $mail);
|
|
return gxruncmd($sendmail, $mail);
|
|
}
|
|
}
|
|
|
|
// b64hdr_encode: Encode a piece of header text with Base-64
|
|
// Refer to RFC-1522 4.1
|
|
function b64hdr_encode($text, $charset)
|
|
{
|
|
// US-ASCII printable -- no need to encode it
|
|
if (is_usascii_printable($text)) {
|
|
return $text;
|
|
}
|
|
// No desired character set available
|
|
if (is_null($charset)) {
|
|
return $text;
|
|
}
|
|
// Desired character set not UTF-8
|
|
if ($charset != "UTF-8") {
|
|
// Try to convert into the desired character set
|
|
$GLOBALS["php_errormsg"] = null;
|
|
set_error_handler("null_error_handler");
|
|
$converted = iconv("UTF-8", $charset, $text);
|
|
restore_error_handler();
|
|
// Conversion OK -- in the desired character set
|
|
if (is_null($GLOBALS["php_errormsg"])) {
|
|
return "=?$charset?B?" . base64_encode($converted) . "?=";
|
|
}
|
|
}
|
|
// Else -- send in UTF-8
|
|
return "=?UTF-8?B?" . base64_encode($text) . "?=";
|
|
}
|
|
|
|
?>
|