/** * Retreive an instance of the encoder as a singleton. * New instances are never ever needed since it's monostatic. * @return Message_Encoder */ public static function instance() { if (self::$instance === null) { self::$instance = new Swift_Message_Encoder(); } return self::$instance; }
/** * Build the list of attributes for appending to the given header * This is RFC 2231 & 2047 compliant. * A HUGE thanks to Joaquim Homrighausen for heaps of help, advice * and testing to get this working rock solid. * @param string The header built without attributes * @param string The lowercase name of the header * @return string * @throws Swift_Message_MimeException If no such header exists or there are no attributes */ function buildAttributes($header_line, $header_name) { Swift_ClassLoader::load("Swift_Message_Encoder"); $encoder =& Swift_Message_Encoder::instance(); $lines = explode($this->LE, $header_line); $used_len = strlen($lines[count($lines) - 1]); $lines = null; $ret = ""; foreach ($this->attributes[$header_name] as $attribute => $att_value) { if ($att_value === null) { continue; } // 70 to account for LWSP, CRLF, quotes and a semi-colon // + length of attribute // + 4 for a 2 digit number and 2 asterisks $avail_len = 70 - (strlen($attribute) + 4); $encoded = $encoder->rfc2047Encode($att_value, $this->charset, $this->language, $avail_len, $this->LE); $lines = explode($this->LE, $encoded); foreach ($lines as $i => $line) { //Add quotes if needed (RFC 2045) if (preg_match("~[\\s\";,<>\\(\\)@:\\\\/\\[\\]\\?=]~", $line)) { $lines[$i] = '"' . $line . '"'; } } $encoded = implode($this->LE, $lines); //If we can fit this entire attribute onto the same line as the header then do it! if (strlen($encoded) + $used_len + strlen($attribute) + 4 < 74) { if (strpos($encoded, "'") !== false) { $attribute .= "*"; } $append = "; " . $attribute . "=" . $encoded; $ret .= $append; $used_len += strlen($append); } else { $ret .= ";"; if (count($lines) > 1) { $loop = false; $add_asterisk = false; foreach ($lines as $i => $line) { $att_copy = $attribute; //Because it's multi-line it needs asterisks with decimal indices $att_copy .= "*" . $i; if ($add_asterisk || strpos($encoded, "'") !== false) { $att_copy .= "*"; //And if it's got a ' then it needs another asterisk $add_asterisk = true; } $append = ""; if ($loop) { $append .= ";"; } $append .= $this->LE . " " . $att_copy . "=" . $line; $ret .= $append; $used_len = strlen($append) + 1; $loop = true; } } else { if (strpos($encoded, "'") !== false) { $attribute .= "*"; } $append = $this->LE . " " . $attribute . "=" . $encoded; $used_len = strlen($append) + 1; $ret .= $append; } } $lines = null; } return $ret; }
/** * Send a message to any number of recipients * @param Swift_Message The message to send. This does not need to (and shouldn't really) have any of the recipient headers set. * @param mixed The recipients to send to. Can be a string, Swift_Address or Swift_RecipientList. Note that all addresses apart from Bcc recipients will appear in the message headers * @param mixed The address to send the message from. Can either be a string or an instance of Swift_Address. * @return int The number of successful recipients * @throws Swift_ConnectionException If sending fails for any reason. */ function send(&$message, $recipients, $from) { Swift_ClassLoader::load("Swift_Message_Encoder"); $encoder =& Swift_Message_Encoder::instance(); if (!is_a($message, "Swift_Message")) { trigger_error("Swift::send expects parameter 1 to be instance of Swift_Message."); return; } if (is_string($recipients) && preg_match("/^" . $encoder->CHEAP_ADDRESS_RE . "\$/", $recipients)) { $recipients =& new Swift_Address($recipients); } elseif (!is_a($recipients, "Swift_AddressContainer")) { trigger_error("The recipients parameter must either be a valid string email address, " . "an instance of Swift_RecipientList or an instance of Swift_Address."); return; } if (is_string($from) && preg_match("/^" . $encoder->CHEAP_ADDRESS_RE . "\$/", $from)) { $from =& new Swift_Address($from); } elseif (!is_a($from, "Swift_Address")) { trigger_error("The sender parameter must either be a valid string email address or " . "an instance of Swift_Address."); return; } $log =& Swift_LogContainer::getLog(); if (!$message->getEncoding() && !$this->connection->hasExtension("8BITMIME")) { $message->setEncoding("QP", true, true); } $list =& $recipients; if (is_a($recipients, "Swift_Address")) { $list =& new Swift_RecipientList(); $list->addTo($recipients); } Swift_ClassLoader::load("Swift_Events_SendEvent"); $send_event =& new Swift_Events_SendEvent($message, $list, $from, 0); $this->notifyListeners($send_event, "BeforeSendListener"); $to = $cc = array(); if (!($has_from = $message->getFrom())) { $message->setFrom($from); } if (!($has_return_path = $message->getReturnPath())) { $message->setReturnPath($from->build(true)); } if (!($has_reply_to = $message->getReplyTo())) { $message->setReplyTo($from); } if (!($has_message_id = $message->getId())) { $message->generateId(); } $this->command("MAIL FROM: " . $message->getReturnPath(true), 250); $failed = 0; $sent = 0; $tmp_sent = 0; $it =& $list->getIterator("to"); while ($it->hasNext()) { $it->next(); $address = $it->getValue(); $to[] = $address->build(); $e = null; Swift_Errors::expect($e, "Swift_BadResponseException"); $this->command("RCPT TO: " . $address->build(true), 250); if (!$e) { $tmp_sent++; Swift_Errors::clear("Swift_BadResponseException"); } else { $failed++; $send_event->addFailedRecipient($address->getAddress()); if ($log->hasLevel(SWIFT_LOG_FAILURES)) { $log->addfailedRecipient($address->getAddress()); } } } $it =& $list->getIterator("cc"); while ($it->hasNext()) { $it->next(); $address = $it->getValue(); $cc[] = $address->build(); $e = null; Swift_Errors::expect($e, "Swift_BadResponseException"); $this->command("RCPT TO: " . $address->build(true), 250); if (!$e) { $tmp_sent++; Swift_Errors::clear("Swift_BadResponseException"); } else { $failed++; $send_event->addFailedRecipient($address->getAddress()); if ($log->hasLevel(SWIFT_LOG_FAILURES)) { $log->addfailedRecipient($address->getAddress()); } } } if ($failed == count($to) + count($cc)) { $this->reset(); $this->notifyListeners($send_event, "SendListener"); return 0; } if (!($has_to = $message->getTo()) && !empty($to)) { $message->setTo($to); } if (!($has_cc = $message->getCc()) && !empty($cc)) { $message->setCc($cc); } $this->command("DATA", 354); $data =& $message->build(); while (false !== ($bytes = $data->read())) { $this->command($bytes, -1); } if ($log->hasLevel(SWIFT_LOG_NETWORK)) { $log->add("<MESSAGE DATA>", SWIFT_LOG_COMMAND); } Swift_Errors::expect($e, "Swift_BadResponseException"); $this->command("\r\n.", 250); if (!$e) { $sent += $tmp_sent; Swift_Errors::clear("Swift_BadResponseException"); } else { $failed += $tmp_sent; } $tmp_sent = 0; $has_bcc = $message->getBcc(); $it =& $list->getIterator("bcc"); while ($it->hasNext()) { $it->next(); $address = $it->getValue(); if (!$has_bcc) { $message->setBcc($address->build()); } $e = null; Swift_Errors::expect($e, "Swift_BadResponseException"); if (!$e) { $this->command("MAIL FROM: " . $message->getReturnPath(true), 250); } if (!$e) { $this->command("RCPT TO: " . $address->build(true), 250); } if (!$e) { $this->command("DATA", 354); } if (!$e) { $data =& $message->build(); while (false !== ($bytes = $data->read())) { $this->command($bytes, -1); } if ($log->hasLevel(SWIFT_LOG_NETWORK)) { $log->add("<MESSAGE DATA>", SWIFT_LOG_COMMAND); } $this->command("\r\n.", 250); } if (!$e) { $sent++; Swift_Errors::clear("Swift_BadResponseException"); } else { $failed++; $send_event->addFailedRecipient($address->getAddress()); if ($log->hasLevel(SWIFT_LOG_FAILURES)) { $log->addfailedRecipient($address->getAddress()); } $this->reset(); } } $total = count($to) + count($cc) + count($list->getBcc()); $send_event->setNumSent($sent); $this->notifyListeners($send_event, "SendListener"); if (!$has_return_path) { $message->setReturnPath(""); } if (!$has_from) { $message->setFrom(""); } if (!$has_to) { $message->setTo(""); } if (!$has_reply_to) { $message->setReplyTo(null); } if (!$has_cc) { $message->setCc(null); } if (!$has_bcc) { $message->setBcc(null); } if (!$has_message_id) { $message->setId(null); } if ($log->hasLevel(SWIFT_LOG_NETWORK)) { $log->add("Message sent to " . $sent . "/" . $total . " recipients", SWIFT_LOG_NORMAL); } return $sent; }
/** * Execute needed logic prior to compilation */ public function preBuild() { $data = $this->getData(); if (!($enc = $this->getEncoding())) { $this->setEncoding("8bit"); } if ($this->getCharset() === null && !$this->numChildren()) { Swift_ClassLoader::load("Swift_Message_Encoder"); if (is_string($data) && Swift_Message_Encoder::instance()->isUTF8($data)) { $this->setCharset("utf-8"); } elseif (is_string($data) && Swift_Message_Encoder::instance()->is7BitAscii($data)) { $this->setCharset("us-ascii"); if (!$enc) { $this->setEncoding("7bit"); } } else { $this->setCharset("iso-8859-1"); } } elseif ($this->numChildren()) { if (!$this->getData()) { $this->setData($this->getMimeWarning()); $this->setLineWrap(76); } if ($this->getCharset() !== null) { $this->setCharset(null); } if ($this->isFlowed()) { $this->setFlowed(false); } $this->setEncoding("7bit"); } }
/** * FUNCTION: _sendMail * * Proccesses all headers and attachments ready for sending. * * @access private */ function _sendMail() { $message = new Swift_Message($this->subject); if (empty($this->sendto) and (empty($this->body) and empty($this->htmlbody))) { vlibMimeMailError::raiseError('VM_ERROR_CANNOT_SEND', FATAL); } // Attachments for ($index = 0; $index < sizeof($this->attachments); $index++) { $message->attach(new Swift_Message_Attachment(new Swift_File($this->attachments[$index]), $this->attachments[$index], $this->mimetypes[$index])); } // ReplyTo if exists if (!empty($this->replyToEmail)) { $message->setReplyTo(new Swift_Address($this->replyToEmail, $this->replyToName)); } // attach body if exist if (!empty($this->body)) { if (empty($this->htmlbody) and sizeof($this->attachments) == 0) { $message->setData($this->body); Swift_ClassLoader::load('Swift_Message_Encoder'); if (Swift_Message_Encoder::instance()->isUTF8($this->body)) { $message->setCharset('utf-8'); } else { $message->setCharset('iso-8859-1'); } } else { $message->attach(new Swift_Message_Part($this->body, 'text/plain')); } } // attach HTML body if exist if (!empty($this->htmlbody)) { $message->attach(new Swift_Message_Part($this->htmlbody, 'text/html')); } return $this->swift->send($message, $this->swift_recipients, new Swift_Address($this->fromEmail, $this->fromName)); }
/** * Pre-compilation logic */ public function preBuild() { if (!($enc = $this->getEncoding())) { $this->setEncoding("8bit"); } $data = $this->getData(); if ($this->getCharset() === null && !$this->numChildren()) { if (is_string($data) && Swift_Message_Encoder::instance()->isUTF8($data)) { $this->setCharset("utf-8"); } elseif (is_string($data) && Swift_Message_Encoder::instance()->is7BitAscii($data)) { $this->setCharset("us-ascii"); if (!$enc) { $this->setEncoding("7bit"); } } else { $this->setCharset("iso-8859-1"); } } elseif ($this->numChildren()) { $this->setCharset(null); $this->setEncoding("7bit"); } }
/** * Constructor * @param Swift_Connection The connection to use * @param string The domain name of this server (not the SMTP server) */ function EasySwift(&$connection, $domain = null) { if (!is_a($connection, "Swift_Connection") && !is_a($connection, "SimpleMock")) { trigger_error("EasySwift constructor parameter 1 must be instance of Swift_Connection."); return; } Swift_Errors::expect($e, "Swift_ConnectionException"); if (!$e) { $this->swift =& new Swift($connection, $domain, SWIFT_ENABLE_LOGGING); } Swift_ClassLoader::load("Swift_Plugin_EasySwiftResponseTracker"); if (!$e) { $this->swift->attachPlugin(new Swift_Plugin_EasySwiftResponseTracker($this), "_ResponseTracker"); } if ($e) { $this->failed = true; $this->setError("The connection failed to start. An exception was thrown:<br />" . $e->getMessage()); } Swift_Errors::clear("Swift_ConnectionException"); $this->newMessage(); $this->newRecipientList(); $this->encoder =& Swift_Message_Encoder::instance(); }
/** * Get the data in the format suitable for sending * @return Swift_Cache_OutputStream * @throws Swift_FileException If the file stream given cannot be read * @throws Swift_Message_MimeException If some required headers have been forcefully removed */ public function buildData() { Swift_ClassLoader::load("Swift_Message_Encoder"); Swift_ClassLoader::load("Swift_Cache_JointOutputStream"); if (!empty($this->children)) { if ($this->boundary === null) { $this->boundary = self::generateBoundary(); } $this->headers->setAttribute("Content-Type", "boundary", $this->boundary); $this->cache->clear("append"); foreach ($this->children as $part) { $this->cache->write("append", $this->LE . "--" . $this->boundary . $this->LE); $part_stream = $part->build(); while (false !== ($bytes = $part_stream->read())) { $this->cache->write("append", $bytes); } } $this->cache->write("append", $this->LE . "--" . $this->boundary . "--" . $this->LE); } $joint_os = new Swift_Cache_JointOutputStream(); //Try using a cached version to save some cycles (at the expense of memory) //if ($this->cache !== null) return $this->cache . $append; if ($this->cache->has("body")) { $joint_os->addStream($this->cache->getOutputStream("body")); $joint_os->addStream($this->cache->getOutputStream("append")); return $joint_os; } $is_file = $this->getData() instanceof Swift_File; switch ($this->getEncoding()) { case "quoted-printable": if ($is_file) { $qp_os = Swift_Message_Encoder::instance()->QPEncodeFile($this->getData(), 76, $this->LE); while (false !== ($bytes = $qp_os->read())) { $this->cache->write("body", $bytes); } } else { $this->cache->write("body", Swift_Message_Encoder::instance()->QPEncode($this->getData(), 76, 0, false, $this->LE)); } break; case "base64": if ($is_file) { $b64_os = Swift_Message_Encoder::instance()->base64EncodeFile($this->getData(), 76, $this->LE); while (false !== ($bytes = $b64_os->read())) { $this->cache->write("body", $bytes); } } else { $this->cache->write("body", Swift_Message_Encoder::instance()->base64Encode($this->getData(), 76, 0, false, $this->LE)); } break; case "binary": if ($is_file) { $data = $this->getData(); while (false !== ($bytes = $data->read(8192))) { $this->cache->write("body", $bytes); } } else { $this->cache->write("body", $this->getData()); } break; case "7bit": if ($is_file) { $os = Swift_Message_Encoder::instance()->encode7BitFile($this->getData(), $this->wrap, $this->LE); while (false !== ($bytes = $os->read())) { $this->cache->write("body", $bytes); } } else { $this->cache->write("body", Swift_Message_Encoder::instance()->encode7Bit($this->getData(), $this->wrap, $this->LE)); } break; case "8bit": default: if ($is_file) { $os = Swift_Message_Encoder::instance()->encode8BitFile($this->getData(), $this->wrap, $this->LE); while (false !== ($bytes = $os->read())) { $this->cache->write("body", $bytes); } } else { $this->cache->write("body", Swift_Message_Encoder::instance()->encode8Bit($this->getData(), $this->wrap, $this->LE)); } break; } $joint_os->addStream($this->cache->getOutputStream("body")); $joint_os->addStream($this->cache->getOutputStream("append")); return $joint_os; }
/** * Detecting UTF8 automatically is useful so we want to be able to do this. */ public function testUTF8Detection() { $iso88591 = file_get_contents(TestConfiguration::FILES_PATH . "/encodings/iso-8859-1.txt"); $this->assertFalse(Swift_Message_Encoder::instance()->isUTF8($iso88591)); $utf8 = file_get_contents(TestConfiguration::FILES_PATH . "/encodings/utf-8.txt"); $this->assertTrue(Swift_Message_Encoder::instance()->isUTF8($utf8)); }
/** * Set the encoding format to be used on the body of the document * @param string The encoding type used * @param boolean If this encoding format should be used recursively. Note, this only takes effect if no encoding is set in the children. * @param boolean If the encoding should only be applied when the string is not ascii. */ function setEncoding($encoding, $recursive = false, $non_ascii = false) { $this->cache->clear("body"); switch (strtolower($encoding)) { case "q": case "qp": case "quoted-printable": $encoding = "quoted-printable"; break; case "b": case "base64": $encoding = "base64"; break; case "7bit": case "8bit": case "binary": $encoding = strtolower($encoding); break; } $data =& $this->getData(); if ($non_ascii && is_string($data) && !$this->_encoder->is7BitAscii($data)) { $this->headers->set("Content-Transfer-Encoding", $encoding); } elseif (!$non_ascii || !is_string($data)) { $this->headers->set("Content-Transfer-Encoding", $encoding); } if ($recursive) { foreach ($this->children as $id => $child) { if (!$child->getEncoding()) { $this->children[$id]->setEncoding($encoding, $recursive, $non_ascii); } } } }