/**
  * Builds and returns the generated mailing body HTML or plaintext.
  *
  * @param array $replacements An array of key/value pairs, where key is the string to replace with the value.
  * @return string The generated mailing body.
  */
 public function buildBody(array $replacements = null)
 {
     $templateHtml = $this->getTemplateContent();
     $editorHtml = $this->getEditorContent();
     $css = $this->getCSS();
     if (empty($templateHtml)) {
         throw new Exception('No valid template HTML was set.');
     }
     if (empty($editorHtml)) {
         throw new Exception('No valid editor content HTML was set.');
     }
     // we replace the editor tags with the content the user gave into the editor in the CMS
     $body = preg_replace('/<!-- editor -->.*?<!-- \\/editor -->/is', $editorHtml, $templateHtml);
     // we have to do this so we have entities in our body instead
     $body = mb_convert_encoding($body, 'HTML-ENTITIES', 'UTF-8');
     // add Google UTM parameters to all anchors
     $body = $this->processUTMParameters($body);
     $body = $this->processReplacements($body, $replacements);
     $body = $this->processCSS($body);
     // we parse the template CSS into the template, and re-build our body
     $body = $this->processCSS($body);
     // we will return plaintext if the user asked for it.
     if ($this->isPlaintext()) {
         $body = SpoonFilter::stripHTML($body);
     }
     return $body;
 }
    public function testStripHTML()
    {
        $html = '
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
	<title>Fork CMS</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>

<body>
	<p>
		<a href="http://www.spoon-library.com">Spoon Library</a>
	</p>
</body>
</html>';
        $this->assertEquals('Spoon Library', SpoonFilter::stripHTML($html));
        $this->assertEquals('<a href="http://www.spoon-library.com">Spoon Library</a>', SpoonFilter::stripHTML($html, '<a>'));
        $this->assertEquals('Spoon Library (http://www.spoon-library.com)', SpoonFilter::stripHTML($html, null, true));
    }
Example #3
0
 /**
  * Execute the action
  */
 public function execute()
 {
     parent::execute();
     // get parameters
     $mailingId = \SpoonFilter::getPostValue('mailing_id', null, '', 'int');
     $subject = \SpoonFilter::getPostValue('subject', null, '');
     $contentHTML = urldecode(\SpoonFilter::getPostValue('content_html', null, ''));
     $contentPlain = \SpoonFilter::getPostValue('content_plain', null, '');
     // validate mailing ID
     if ($mailingId == '') {
         $this->output(self::BAD_REQUEST, null, 'No mailing ID provided');
     } else {
         // get mailing record
         $this->mailing = BackendMailmotorModel::getMailing($mailingId);
         // check if record is empty
         if (empty($this->mailing)) {
             $this->output(self::BAD_REQUEST, null, BL::err('MailingDoesNotExist', $this->getModule()));
         } else {
             // validate subject
             if ($subject == '') {
                 $this->output(500, array('element' => 'subject', 'element_error' => BL::err('NoSubject', $this->getModule())), BL::err('FormError'));
             } else {
                 // set plain content
                 $contentPlain = empty($contentPlain) ? \SpoonFilter::stripHTML($contentHTML) : $contentPlain;
                 // add unsubscribe link
                 if (mb_strpos($contentPlain, '[unsubscribe]') === false) {
                     $contentPlain .= PHP_EOL . '[unsubscribe]';
                 }
                 // build data
                 $item['id'] = $this->mailing['id'];
                 $item['subject'] = $subject;
                 $item['content_plain'] = $contentPlain;
                 $item['content_html'] = $contentHTML;
                 $item['edited_on'] = date('Y-m-d H:i:s');
                 // update mailing in our database
                 BackendMailmotorModel::updateMailing($item);
                 /*
                     we should insert the draft into campaignmonitor here,
                     so we can use sendCampaignPreview in step 4.
                 */
                 $item['groups'] = $this->mailing['groups'];
                 $item['name'] = $this->mailing['name'];
                 $item['from_name'] = $this->mailing['from_name'];
                 $item['from_email'] = $this->mailing['from_email'];
                 $item['reply_to_email'] = $this->mailing['reply_to_email'];
                 try {
                     BackendMailmotorCMHelper::saveMailingDraft($item);
                 } catch (Exception $e) {
                     // CM did not receive a valid URL
                     if (strpos($e->getMessage(), 'HTML Content URL Required')) {
                         $message = BL::err('HTMLContentURLRequired', $this->getModule());
                     } elseif (strpos($e->getMessage(), 'Payment details required')) {
                         // no payment details were set for the CM client yet
                         $error = BL::err('PaymentDetailsRequired', $this->getModule());
                         $cmUsername = $this->get('fork.settings')->get($this->getModule(), 'cm_username');
                         $message = sprintf($error, $cmUsername);
                     } elseif (strpos($e->getMessage(), 'Duplicate Campaign Name')) {
                         // the campaign name already exists in CM
                         $message = BL::err('DuplicateCampaignName', $this->getModule());
                     } else {
                         // we received an unknown error
                         $message = $e->getMessage();
                     }
                     // stop the script and show our error
                     $this->output(500, null, $message);
                     return;
                 }
                 // trigger event
                 BackendModel::triggerEvent($this->getModule(), 'after_edit_mailing_step3', array('item' => $item));
                 // output
                 $this->output(self::OK, array('mailing_id' => $mailingId), BL::msg('MailingEdited', $this->getModule()));
                 return;
             }
         }
         // error
         $this->output(500, null, $message);
         return;
     }
 }
Example #4
0
 /**
  * Execute the action
  *
  * @return	void
  */
 public function execute()
 {
     // call parent, this will probably add some general CSS/JS or other required files
     parent::execute();
     // get parameters
     $mailingId = SpoonFilter::getPostValue('mailing_id', null, '', 'int');
     $subject = SpoonFilter::getPostValue('subject', null, '');
     $contentHTML = urldecode(SpoonFilter::getPostValue('content_html', null, ''));
     $contentPlain = SpoonFilter::getPostValue('content_plain', null, '');
     $fullContentHTML = SpoonFilter::getPostValue('full_content_html', null, '');
     // validate mailing ID
     if ($mailingId == '') {
         $this->output(self::BAD_REQUEST, null, 'No mailing ID provided');
     }
     // get mailing record
     $this->mailing = BackendMailmotorModel::getMailing($mailingId);
     // record is empty
     if (empty($this->mailing)) {
         $this->output(self::BAD_REQUEST, null, BL::err('MailingDoesNotExist', $this->getModule()));
     }
     // validate other fields
     if ($subject == '') {
         $this->output(900, array('element' => 'subject', 'element_error' => BL::err('NoSubject', $this->getModule())), BL::err('FormError'));
     }
     // set full HTML
     $HTML = $this->getEmailContent($this->mailing['template'], $contentHTML, $fullContentHTML);
     // set plain content
     $contentPlain = empty($contentPlain) ? SpoonFilter::stripHTML($HTML) : $contentPlain;
     // add unsubscribe link
     if (mb_strpos($contentPlain, '[unsubscribe]') === false) {
         $contentPlain .= PHP_EOL . '[unsubscribe]';
     }
     // build data
     $item['id'] = $this->mailing['id'];
     $item['subject'] = $subject;
     $item['content_plain'] = $contentPlain;
     $item['content_html'] = $contentHTML;
     $item['data'] = serialize(array('full_content_html' => $HTML));
     $item['edited_on'] = date('Y-m-d H:i:s');
     // update mailing
     BackendMailmotorModel::updateMailing($item);
     // trigger event
     BackendModel::triggerEvent($this->getModule(), 'after_edit_mailing_step3', array('item' => $item));
     // output
     $this->output(self::OK, array('mailing_id' => $mailingId), BL::msg('MailingEdited', $this->getModule()));
 }
Example #5
0
 /**
  * Builds the e-mail headers.
  */
 private function getHeaders()
 {
     // create boundaries
     $uniqueId = md5(uniqid(time()));
     $boundary = 'SEB1_' . $uniqueId;
     $secondBoundary = 'SEB2_' . $uniqueId;
     // if plain body is not set, we'll strip the HTML tags from the HTML body
     if (empty($this->content['plain'])) {
         $this->content['plain'] = SpoonFilter::stripHTML($this->content['html'], null, true);
     }
     // encode the content
     $this->content['html'] = $this->encodeContent($this->content['html']);
     $this->content['plain'] = $this->encodeContent($this->content['plain']);
     // build headers
     $this->addHeader('Date: ' . SpoonDate::getDate('r'));
     $this->addHeader('From: ' . $this->from['name'] . ' <' . $this->from['email'] . '>');
     // check mailmethod, some media don't need these (like mail())
     if ($this->method == 'smtp') {
         // set subject
         $this->addHeader('Subject: ' . $this->subject);
         // set general To: header. useful if you prefer to customize it
         if (!empty($this->to['name'])) {
             $this->addHeader('To: ' . $this->to['name'] . ' <' . $this->to['email'] . '>');
         } else {
             $this->addHeader('To: ' . $this->reformatRecipientString($this->recipients));
         }
     }
     // loop and add CCs to headers
     if (!empty($this->CC)) {
         $this->addHeader('cc: ' . $this->reformatRecipientString($this->CC));
     }
     // loop and add BCCs to headers
     if (!empty($this->BCC)) {
         $this->addHeader('bcc: ' . $this->reformatRecipientString($this->BCC));
     }
     // add Reply-To header to headers
     if (!empty($this->replyTo)) {
         $this->addHeader('Reply-To: ' . $this->reformatRecipientString($this->replyTo));
     }
     // if attachments are set, change the mail content type
     if (!empty($this->attachments)) {
         $this->contentType = 'multipart/mixed';
     }
     // continue the rest of the headers
     $this->addHeader('X-Priority: ' . $this->priority);
     $this->addHeader('X-Mailer: SpoonEmail (part of Spoon library - http://www.spoon-library.com)');
     $this->addHeader('MIME-Version: 1.0');
     $this->addHeader('Content-Type: ' . $this->contentType . '; charset="' . $this->charset . '"; boundary="' . $boundary . '"' . self::LF);
     $this->addHeader('Importance: normal');
     $this->addHeader('Priority: normal');
     $this->addHeader('This is a multi-part message in MIME format.' . self::LF);
     $this->addHeader('--' . $boundary);
     // attachments found
     if (!empty($this->attachments)) {
         // means we need a second boundary defined to send html/plain mails.
         $this->addHeader('Content-Type: multipart/alternative; boundary="' . $secondBoundary . '"' . self::LF);
         $this->addHeader('--' . $secondBoundary);
         $this->addHeader('Content-Type: text/plain; charset="' . $this->charset . '"');
         $this->addHeader('Content-Disposition: inline');
         $this->addHeader('Content-Transfer-Encoding: ' . $this->contentTransferEncoding . self::LF);
         $this->addHeader($this->content['plain'] . self::LF);
         $this->addHeader('--' . $secondBoundary);
         $this->addHeader('Content-Type: text/html; charset="' . $this->charset . '"');
         $this->addHeader('Content-Disposition: inline');
         $this->addHeader('Content-Transfer-Encoding: ' . $this->contentTransferEncoding . self::LF);
         $this->addHeader($this->content['html'] . self::LF);
         $this->addHeader('--' . $secondBoundary . '--');
     } else {
         // continue the rest of the headers
         $this->addHeader('Content-Type: text/plain; charset="' . $this->charset . '"');
         $this->addHeader('Content-Disposition: inline');
         $this->addHeader('Content-Transfer-Encoding: ' . $this->contentTransferEncoding . self::LF);
         $this->addHeader($this->content['plain'] . self::LF);
         $this->addHeader('--' . $boundary);
         $this->addHeader('Content-Type: text/html; charset="' . $this->charset . '"');
         $this->addHeader('Content-Disposition: inline');
         $this->addHeader('Content-Transfer-Encoding: ' . $this->contentTransferEncoding . self::LF);
         $this->addHeader($this->content['html'] . self::LF);
     }
     // attachments found
     if (!empty($this->attachments)) {
         // loop attachments
         foreach ($this->attachments as $attachment) {
             // set attachment headers
             $this->addHeader('--' . $boundary);
             $this->addHeader('Content-Type: ' . $attachment['type'] . '; name="' . $attachment['name'] . '"');
             $this->addHeader('Content-Transfer-Encoding: ' . $attachment['encoding']);
             $this->addHeader('Content-Disposition: ' . $attachment['disposition'] . '; filename="' . $attachment['name'] . '"' . self::LF);
             $this->addHeader($attachment['data'] . self::LF);
         }
     }
     // final boundary, closes the headers
     $this->headers .= '--' . $boundary . '--';
     // return headers string
     return $this->headers;
 }