newsletters
[ class tree: newsletters ] [ index: newsletters ] [ all elements ]

Source for file BitNewsletterMailer.php

Documentation is available at BitNewsletterMailer.php

  1. <?php
  2. /**
  3.  * $Header$
  4.  *
  5.  * @copyright (c) 2004 bitweaver.org
  6.  *  All Rights Reserved. See below for details and a complete list of authors.
  7.  *  Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See http://www.gnu.org/copyleft/lesser.html for details
  8.  *
  9.  *  $Id$
  10.  *
  11.  *  Class that handles editions of newsletters
  12.  * @package newsletters
  13.  *
  14.  * @date created 2005/12/08
  15.  *
  16.  * @author spiderr <spider@steelsun.com>
  17.  *
  18.  * @version $Revision$
  19.  */
  20.  
  21. /**
  22.  * required setup
  23.  */
  24. require_once( NEWSLETTERS_PKG_PATH.'BitNewsletter.php' );
  25. require_once( UTIL_PKG_PATH.'phpmailer/class.phpmailer.php' );
  26.  
  27. /**
  28.  * @package newsletters
  29.  */
  30.     // Set default variables for all new objects
  31.     var $From;
  32.     var $FromName;
  33.     var $Host;
  34.     var $Mailer;                         // Alternative to IsSMTP()
  35.     var $WordWrap;
  36.     function BitNewsletterMailer () {
  37.         global $gBitDb, $gBitSystem, $gBitLanguage;
  38.         $this->mDb = $gBitDb;
  39.     }
  40.  
  41.     // Replace the default error_handler
  42.     function error_handler( $msg ) {
  43.         global $gBitDb;
  44.         bit_error_handler( NULL, NULL, NULL, "FULFILLMENT ERROR: MISSSING PDF for ORDER $pOrderId CID ".$prod->mInfo['related_content_id'], $pdfInfo['pdf_file'], '', $prod->mDb );
  45.         print("My Site Error");
  46.         print("Description:");
  47.         printf("%s", $msg);
  48.         exit;
  49.     }
  50.  
  51.     function isRecipientQueued( $pRecipientMixed, $pContentId ) {
  52.         if( BitBase::verifyId( $pRecipientMixed ) ) {
  53.             $lookupCol = 'user_id';
  54.         } else {
  55.             $lookupCol = 'email';
  56.         }
  57.         return( $this->mDb->getOne( "SELECT COUNT(*) FROM `".BIT_DB_PREFIX."mail_queue` WHERE `content_id`=? AND `$lookupCol`=?", array( $pContentId, $pRecipientMixed ) ) );
  58.     }
  59.  
  60.     function queueRecipients( $pContentId, $pNewsletterContentId, $pRecipients, $pRequeue=FALSE ) {
  61.         $ret = 0;
  62.         if( !empty( $pRecipients ) && BitBase::verifyId( $pContentId ) ) {
  63.             $queueTime = time();
  64.             foreach( array_keys( $pRecipients ) AS $email ) {
  65.                 $unsub = $this->getUnsubscription( $email, $pNewsletterContentId );
  66.                 $lookup = !empty( $pRecipients[$email]['user_id'] ) ? $pRecipients[$email]['user_id'] : $email;
  67.                 if( empty( $unsub ) && !$this->isRecipientQueued( $lookup, $pContentId ) ) {
  68.                     $insertHash['mail_queue_id'] = $this->mDb->GenID( 'mail_queue_id' );
  69.                     $insertHash['email'] = $email;
  70.                     if( !empty( $pRecipients[$email]['user_id'] ) ) {
  71.                         $insertHash['user_id'] = $pRecipients[$email]['user_id'];
  72.                     }
  73.                     $insertHash['content_id'] = $pContentId;
  74.                     $insertHash['nl_content_id'] = $pNewsletterContentId;
  75.                     $insertHash['queue_date'] = $queueTime;
  76.                     $this->mDb->associateInsert( BIT_DB_PREFIX.'mail_queue', $insertHash );
  77.                     $ret++;
  78.                 } elseif( empty( $unsub ) && $pRequeue ) {
  79.                     $bindVars = array( $queueTime, $pContentId );
  80.                     if( !empty( $pRecipients[$email]['user_id'] ) ) {
  81.                         $lookupCol = 'user_id';
  82.                         $bindVars[] = $pRecipients[$email]['user_id'];
  83.                     } else {
  84.                         $lookupCol = 'email';
  85.                         $bindVars[]  = $email;
  86.                     }
  87.                     $rs = $this->mDb->query( "UPDATE `".BIT_DB_PREFIX."mail_queue` SET `queue_date`=?, `begin_date`=NULL, `sent_date`=NULL, `last_read_date`=NULL, `mail_error`=NULL, `hits`=0 WHERE `content_id`=? AND `$lookupCol`=?", array( $bindVars ) );
  88.                     $ret++;
  89.                 }
  90.             }
  91.         }
  92.         return $ret;
  93.     }
  94.  
  95.  
  96.     function tendQueue() {
  97.         $this->mDb->StartTrans();
  98.         $query = "SELECT *
  99.                   FROM `".BIT_DB_PREFIX."mail_queue` mq
  100.                   WHERE `sent_date` IS NULL AND `mail_error` IS NULL
  101.                   ORDER BY `queue_date`,`user_id`,`email` ".$this->mDb->SQLForUpdate();
  102.         if( $rs = $this->mDb->query( $query, NULL ) ) {
  103.             while( $pick = $rs->fetchRow() ) {
  104.                 $this->sendQueue( $pick );
  105.                 $this->mDb->CompleteTrans();
  106.                 $this->mDb->StartTrans();
  107.             }
  108.         }
  109.         $this->mDb->CompleteTrans();
  110.     }
  111.  
  112.     function sendQueue( $pQueueMixed ) {
  113.         global $gBitSmarty, $gBitSystem, $gBitLanguage;
  114.         static $body = array();
  115.         if( is_array( $pQueueMixed ) ) {
  116.             $pick = $pQueueMixed;
  117.         } elseif( is_numeric( $pQueueMixed ) ) {
  118.             $pick = $this->mDb->GetRow( "SELECT * FROM `".BIT_DB_PREFIX."mail_queue` mq WHERE `mail_queue_id` = ? ".$this->mDb->SQLForUpdate(), array( $pQueueMixed ) );
  119.         }
  120.  
  121.         if( !empty( $pick ) ) {    
  122.             $startTime = microtime( TRUE );
  123.             $this->mDb->query( "UPDATE `".BIT_DB_PREFIX."mail_queue` SET `begin_date`=? WHERE `mail_queue_id` = ? ", array( time(), $pick['mail_queue_id'] ) );
  124.             if( !empty( $pick['user_id'] ) ) {
  125.                 $userHash = $this->mDb->getRow( "SELECT * FROM `".BIT_DB_PREFIX."users_users` WHERE `user_id`=?", array( $pick['user_id'] ) );
  126.                 $pick['full_name'] = BitUser::getDisplayName( FALSE, $userHash );
  127.             } else {
  128.                 $pick['full_name'] = NULL;
  129.             }
  130.             if( !isset( $body[$pick['content_id']] ) ) {
  131.                 $gBitSmarty->assign( 'sending', TRUE );
  132.                 // We only support sending of newsletters currently
  133.                 $content = new BitNewsletterEdition( NULL, $pick['content_id'] );
  134.                 if( $content->load() ) {
  135.                     $body[$pick['content_id']]['body'] = $content->render();
  136.                     $body[$pick['content_id']]['subject'] = $content->getTitle();
  137.                     $body[$pick['content_id']]['reply_to'] = $content->getField( 'reply_to', $gBitSystem->getConfig( 'site_sender_email', $_SERVER['SERVER_ADMIN'] ) );
  138.                     $body[$pick['content_id']]['object'] = $content;
  139.                 } else {
  140.                     bit_error_log( $this->mErrors );
  141.                 }
  142. //                $content[$pick['content_id']] = LibertyBase::getLibertyObject();
  143.             }
  144.  
  145.             print "[ $pick[mail_queue_id] ] $pick[content_id] TO: $pick[email]\t";
  146.             $unsub = $this->getUnsubscription( $pick['email'], $pick['nl_content_id'] );
  147.             if( !empty( $unsub ) ) {
  148.                 print " SKIPPED (unsubscribed) <br/>\n";
  149.                 $this->mDb->query( "DELETE FROM `".BIT_DB_PREFIX."mail_queue` WHERE `mail_queue_id`=?", array( $pick['mail_queue_id'] ) );
  150.             } elseif( !empty( $body[$pick['content_id']] ) ) {
  151.                 $pick['url_code'] = md5( $pick['content_id'].$pick['email'].$pick['queue_date'] );
  152.                 $unsub = '';
  153.                 if( $body[$pick['content_id']]['object']->mNewsletter->getField('unsub_msg') ) {
  154.                     $gBitSmarty->assign( 'url_code', $pick['url_code'] );
  155.                 }
  156.                 $gBitSystem->preDisplay('');
  157.                 $gBitSmarty->assign( 'sending', TRUE );
  158.                 $gBitSmarty->assign( 'unsubMessage', $unsub );
  159.                 $gBitSmarty->assign( 'trackCode', $pick['url_code'] );
  160.                 $gBitSmarty->assign( 'mid', 'bitpackage:newsletters/view_edition.tpl' );
  161.                 $htmlBody = $gBitSmarty->fetch( 'bitpackage:newsletters/mail_edition.tpl' );
  162.                 $htmlBody = bit_add_clickthrough( $htmlBody, $pick['url_code'] );
  163.  
  164.                 $mailer = new PHPMailer();
  165.                 if( $gBitSystem->getConfig( 'bitmailer_errors_to' ) ) {
  166.                     $mailer->Sender = $gBitSystem->getConfig( 'bitmailer_errors_to' );
  167.                     $mailer->addCustomHeader( "Errors-To: ".$gBitSystem->getConfig( 'bitmailer_errors_to' ) );
  168.                 }
  169.                 $mailer->From     = $gBitSystem->getConfig( 'bitmailer_sender_email', $gBitSystem->getConfig( 'site_sender_email', $_SERVER['SERVER_ADMIN'] ) );
  170.                 $mailer->FromName = $gBitSystem->getConfig( 'bitmailer_from', $gBitSystem->getConfig( 'site_title' ) );
  171.                 $mailer->Host     = $gBitSystem->getConfig( 'bitmailer_servers', $gBitSystem->getConfig( 'kernel_server_name', '127.0.0.1' ) );
  172.                 $mailer->Mailer   = $gBitSystem->getConfig( 'bitmailer_protocol', 'smtp' ); // Alternative to IsSMTP()
  173.                 $mailer->CharSet  = 'UTF-8';
  174.                 if( $gBitSystem->getConfig( 'bitmailer_smtp_username' ) ) {
  175.                     $mailer->SMTPAuth = TRUE;
  176.                     $mailer->Username = $gBitSystem->getConfig( 'bitmailer_smtp_username' );
  177.                 }
  178.                 if( $gBitSystem->getConfig( 'bitmailer_smtp_password' ) ) {
  179.                     $mailer->Password = $gBitSystem->getConfig( 'bitmailer_smtp_password' );
  180.                 }
  181.                 $mailer->WordWrap = $gBitSystem->getConfig( 'bitmailer_word_wrap', 75 );
  182.                 if( !$mailer->SetLanguage( $gBitLanguage->getLanguage(), UTIL_PKG_PATH.'phpmailer/language/' ) ) {
  183.                     $mailer->SetLanguage( 'en' );
  184.                 }
  185.                 $mailer->ClearReplyTos();
  186.                 $mailer->AddReplyTo( $body[$pick['content_id']]['reply_to'], $gBitSystem->getConfig( 'bitmailer_from' ) );
  187.                 $mailer->Body    = $htmlBody;
  188.                 $mailer->Subject = $body[$pick['content_id']]['subject'];
  189.                 $mailer->IsHTML( TRUE );
  190.                 $mailer->AltBody = '';
  191.                 $mailer->AddAddress( $pick['email'], $pick["full_name"] );
  192.                 if( $mailer->Send() ) {
  193.                     print " SENT ".round( microtime( TRUE ) - $startTime, 2)." secs<br/>\n"; flush();
  194.                     $updateQuery = "UPDATE `".BIT_DB_PREFIX."mail_queue` SET `sent_date`=?,`url_code`=?  WHERE `content_id`=? AND `email`=?";
  195.                     $this->mDb->query( $updateQuery, array( time(), $pick['url_code'], $pick['content_id'], $pick['email'] ) );
  196.                 } else {
  197.                     $updateQuery = "UPDATE `".BIT_DB_PREFIX."mail_queue` SET `mail_error`=?,`sent_date`=?  WHERE `content_id`=? AND `email`=?";
  198.                     $this->mDb->query( $updateQuery, array( $mailer->ErrorInfo, time(), $pick['content_id'], $pick['email'] ) );
  199.                     $pick['error'] = $mailer->ErrorInfo;
  200.                     $this->logError( $pick );
  201.                 }
  202.             }
  203.         }
  204.     }
  205.  
  206.     function trackMail( $pUrlCode ) {
  207.         global $gBitDb;
  208.         $query = "UPDATE `".BIT_DB_PREFIX."mail_queue` SET `hits`=`hits`+1, `last_read_date`=?, `last_read_ip`=? WHERE `url_code`=? ";
  209.         $gBitDb->query( $query, array( time(), $_SERVER['REMOTE_ADDR'], $pUrlCode ) );
  210.     }
  211.  
  212.     function logError( $pInfo ) {
  213.         if( !empty( $pInfo['url_code'] ) && !$this->mDb->getOne( "SELECT `url_code` FROM `".BIT_DB_PREFIX."mail_errors` WHERE `url_code`=?", array( $pInfo['url_code'] ) ) ) {
  214.             $store['url_code'] = $pInfo['url_code'];
  215.             $store['user_id'] = !empty( $pInfo['user_id'] ) ? $pInfo['user_id'] : NULL;
  216.             $store['content_id'] = !empty( $pInfo['content_id'] ) ? $pInfo['content_id'] : NULL;
  217.             $store['email'] = !empty( $pInfo['email'] ) ? $pInfo['email'] : NULL;
  218.             $store['error_message'] = $pInfo['error'];
  219.             $store['error_date'] = time();
  220.             $this->mDb->associateInsert( BIT_DB_PREFIX."mail_errors", $store );
  221.         }
  222.         print "ERROR: ".$pInfo['error']."\n";
  223.     }
  224.  
  225.     // Looks up the code from the url to determine if the unsubscribe URL is valid.
  226.     // Can be statically called
  227.     function lookupSubscription( $pLookup ) {
  228.         global $gBitDb;
  229.         $ret = NULL;
  230.         if( is_array( $pLookup ) ) {
  231.             $query = "SELECT mq.*, lc.title, tct.*, uu.`real_name`, uu.`login`, uu.`email` FROM `".BIT_DB_PREFIX."mail_queue` mq
  232.                         INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON( mq.`content_id`=lc.`content_id` )
  233.                         INNER JOIN `".BIT_DB_PREFIX."liberty_content_types` tct ON( tct.`content_type_guid`=lc.`content_type_guid` )
  234.                         LEFT OUTER JOIN `".BIT_DB_PREFIX."users_users` uu ON( mq.`user_id`=uu.`user_id` )
  235.                       WHERE mq.`".key( $pLookup )."`=? ";
  236.             $ret = $gBitDb->getRow( $query, array( current( $pLookup ) ) );
  237.         }
  238.         return( $ret );
  239.     }
  240.  
  241.     // Accepts a single row has containing the column of mail_subscriptions as the key to lookup the unsubscription info
  242.     // Can be statically called
  243.     function getUnsubscriptions( $pMixed ) {
  244.         global $gBitDb;
  245.         $ret = NULL;
  246.         if( is_array( $pMixed ) ) {
  247.             $col = key( $pMixed );
  248.             $bindVars[] = current( $pMixed );
  249.             $query = "SELECT ms.`content_id` AS `hash_key`, ms.*, uu.*, lc.title
  250.                       FROM `".BIT_DB_PREFIX."mail_subscriptions` ms
  251.                         LEFT OUTER JOIN `".BIT_DB_PREFIX."users_users` uu ON( ms.`user_id`=uu.`user_id` )
  252.                         LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON( ms.`content_id`=lc.`content_id` )
  253.                       WHERE ms.`$col`=? ";
  254.             $ret = $gBitDb->getAssoc( $query, $bindVars );
  255.         }
  256.         return( $ret );
  257.     }
  258.  
  259.     function getUnsubscription( $pEmail, $pNewsletterContentId ) {
  260.         global $gBitDb;
  261.         return $gBitDb->getRow( "SELECT * FROM `".BIT_DB_PREFIX."mail_subscriptions` ms LEFT JOIN `".BIT_DB_PREFIX."users_users` uu ON (uu.`user_id`=ms.`user_id`) WHERE (ms.`content_id`=? OR `unsubscribe_all`='y') AND (ms.`email`=? OR uu.`email`=?)", array( $pNewsletterContentId, $pEmail, $pEmail ) );
  262.     }
  263.  
  264.     function storeSubscriptions( $pSubHash ) {
  265.         global $gBitSystem, $gBitDb;
  266.         $ret = FALSE;
  267.         $query = "delete from `".BIT_DB_PREFIX."mail_subscriptions` where `".key( $pSubHash['sub_lookup'] )."`=?";
  268.         $result = $gBitDb->query($query, array( current( $pSubHash['sub_lookup'] ) ) );
  269.         $ret = TRUE;
  270.         if( !empty( $pSubHash['unsub_content'] ) ) {
  271.             foreach( $pSubHash['unsub_content'] as $conId ) {
  272.                 $storeHash = array();
  273.                 $storeHash['content_id'] = $conId;
  274.                 $storeHash['unsubscribe_all'] = !empty( $pSubHash['unsubscribe_all'] ) ? 'y' : NULL;
  275.                 $storeHash['unsubscribe_date'] = time();
  276.                 $storeHash[key( $pSubHash['sub_lookup'] )] = current( $pSubHash['sub_lookup'] );
  277.                 if( !empty( $pSubHash['response_content_id'] ) ) {
  278.                     $storeHash['response_content_id'] = $pSubHash['response_content_id'];
  279.                 }
  280.                 $gBitDb->associateInsert( BIT_DB_PREFIX."mail_subscriptions", $storeHash );
  281.             }
  282.         } elseif( !empty( $pSubHash['unsubscribe_all'] ) ) {
  283.             // unsub all with no reference content_id
  284.             $storeHash = array();
  285.             $storeHash['unsubscribe_all'] = !empty( $pSubHash['unsubscribe_all'] ) ? 'y' : NULL;
  286.             $storeHash['unsubscribe_date'] = time();
  287.             $storeHash[key( $pSubHash['sub_lookup'] )] = current( $pSubHash['sub_lookup'] );
  288.             if( !empty( $pSubHash['response_content_id'] ) ) {
  289.                 $storeHash['response_content_id'] = $pSubHash['response_content_id'];
  290.             }
  291.             $gBitDb->associateInsert( BIT_DB_PREFIX."mail_subscriptions", $storeHash );
  292.         }
  293.         return $ret;
  294.     }
  295.  
  296.     function getQueue( &$pListHash ) {
  297.         $ret = array();
  298.         
  299.         LibertyContent::prepGetList( $pListHash );
  300.         
  301.         $query = "SELECT mq.`mail_queue_id` AS `hash_key`, mq.*, lc.`title`, lc2.`title` AS newsletter_title
  302.                   FROM `".BIT_DB_PREFIX."mail_queue` mq 
  303.                     INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (lc.content_id=mq.content_id)
  304.                     LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_content` lc2 ON (lc2.content_id=mq.nl_content_id)
  305.                   WHERE begin_date IS NULL 
  306.                   ORDER BY queue_date";
  307.         if( $rs = $this->mDb->query( $query ) ) {
  308.             $ret = $rs->getAssoc();
  309.         }
  310.         
  311.         return $ret;
  312.     }
  313.  
  314.     function expungeQueueRow( $pQueueId ) {
  315.         if( BitBase::verifyId( $pQueueId ) ) {
  316.             $this->mDb->query( "DELETE FROM `".BIT_DB_PREFIX."mail_queue` WHERE `mail_queue_id`=?", array( $pQueueId ) );
  317.         }
  318.     }
  319.  
  320.     function storeClickthrough( $pUrlCode ) {
  321.         global $gBitDb;
  322.  
  323.         $uri = substr( preg_replace( '/[&\?]?ct=[a-z0-9]{32}/', '', 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'] ), 0, 250 );
  324.         $query = "SELECT mc.`clicks`, mq.`content_id`, mq.`user_id`, mc.`clicked_url` FROM `".BIT_DB_PREFIX."mail_queue` mq
  325.                     LEFT JOIN `".BIT_DB_PREFIX."mail_clickthrough` mc ON (mq.`user_id`=mc.`user_id` AND mq.`content_id`=mc.`content_id` AND mc.`clicked_url`=?)
  326.                   WHERE `url_code`=?";
  327.         if( $row = $gBitDb->getRow( $query, array( $uri, $pUrlCode ) ) ) {
  328.             if( $row['clicked_url'] ) {
  329.                 $gBitDb->query( "UPDATE `".BIT_DB_PREFIX."mail_clickthrough` SET `clicks`=`clicks`+1 WHERE  `user_id`=? AND `content_id`=? AND `clicked_url`=? ", array( $row['user_id'], $row['content_id'], $row['clicked_url'] ) );
  330.             } else {
  331.                 $row['clicks'] = 1;
  332.                 $row['clicked_url'] = $uri;
  333.                 $gBitDb->associateInsert( BIT_DB_PREFIX.'mail_clickthrough', $row );
  334.             }
  335.         }
  336.     }
  337. }
  338.  
  339. // This will insert a ticket on all template URL's that have GET parameters.
  340. function bit_add_clickthrough( $pSource, $pUrlCode ) {
  341.     global $gBitUser, $gUrlCode;
  342.  
  343.     $gUrlCode = $pUrlCode;
  344.  
  345.     $pcre = '%href[\s]*=[\s]*["\']*((http|https)://[^\s"\']+?)(.*)%sU';
  346.  
  347.     $ret = preg_replace_callback( $pcre, 'process_clickthrough_match', $pSource    );
  348.  
  349.     return $ret;
  350.  
  351. }
  352.  
  353.  
  354. function process_clickthrough_match( $matches ) {
  355.     global $gUrlCode;
  356.     $ret = $matches[0];
  357.     if( strpos( $matches[0], '?' ) ) {
  358.         $ret .= '&amp;ct='.$gUrlCode;
  359.     } else {
  360.         $ret .= '?ct='.$gUrlCode;
  361.     }
  362.     return $ret; 
  363. }
  364.  
  365. ?>

Documentation generated on Wed, 29 Jul 2015 13:55:56 +0000 by phpDocumentor 1.5.0-lsces