Seditio Source
Root |
./othercms/ips_4.3.4/applications/core/sources/BulkMail/Bulkmailer.php
<?php
/**
 * @brief        Bulkmail central library
 * @author        <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
 * @copyright    (c) Invision Power Services, Inc.
 * @license        https://www.invisioncommunity.com/legal/standards/
 * @package        Invision Community
 * @since        25 Jun 2013
 */

namespace IPS\core\BulkMail;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
   
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * Bulk mail central library
 */
class _Bulkmailer extends \IPS\Patterns\ActiveRecord
{
   
/**
     * @brief    Database Table
     */
   
public static $databaseTable = 'core_bulk_mail';

   
/**
     * @brief    [ActiveRecord] Database Prefix
     */
   
public static $databasePrefix = 'mail_';

   
/**
     * @brief    Multiton Store
     */
   
protected static $multitons;
   
   
/**
     * @brief    Flag to denote just getting the count only.
     */
   
const GET_COUNT_ONLY = 1;
   
   
/**
     * Get the mail options
     *
     * @return    array
     */
   
public function get__options()
    {
        if ( !isset(
$this->_data['opts'] ) )
        {
            return array();
        }
       
        return
json_decode( $this->_data['opts'], TRUE );
    }

   
/**
     * Set the mail options
     *
     * @param    array    $value    Mail options
     * @return    vpid
     */
   
public function set__options( $value )
    {
       
$this->opts    = json_encode( $value );
    }

   
/**
     * Send the bulk mail.  Determines if bulk mail should be sent via a task or immediately and dispatches appropriately.
     *
     * @return    NULL|int
     * @throws    \Exception
     */
   
public function send()
    {
       
/* Work out how many to do */
       
$classToUse = \IPS\Email::classToUse( \IPS\Email::TYPE_BULK );
       
$limit    = array( $this->offset, $classToUse::MAX_EMAILS_PER_GO );
       
       
/* Get recipients */
       
$results = $this->getQuery( $limit );

       
/* If there are no recipients we must be done */
       
if( !count( $results ) )
        {
           
$this->active    = 0;
           
$this->offset    = 0;
           
$this->save();

            return
NULL;
        }
       
       
/* Convert $results into an array with replacement tags */
       
$recipients = array();
        foreach (
$results as $memberData )
        {
           
$member = \IPS\Member::constructFromData( $memberData );
           
           
$vars = array();
            foreach (
$this->returnTagValues( 2, $member ) as $k => $v )
            {
               
$vars[ mb_substr( $k, 1, -1 ) ] = $v;
            }
           
           
$recipients[ $member->language()->_id ][ $memberData['email'] ] = $vars;
        }
               
       
/* Convert member-specific {{tag}} into *|tag|* and global {{tag}} into the value */
       
$content = $this->_data['content'];
        foreach (
$this->returnTagValues( 1 ) as $k => $v )
        {
           
$content = str_replace( $k, $v, $content );
        }
        foreach(
array_keys( static::getTags() ) as $k )
        {
            if (
mb_strpos( $content, $k ) !== FALSE )
            {
               
$content = str_replace( $k, '*|' . str_replace( array( '{', '}' ), '', $k ) . '|*', $content );
            }
        }
                               
       
/* Send it */
       
$email = \IPS\Email::buildFromContent( $this->_data['subject'], \IPS\Email::staticParseTextForEmail( $content, \IPS\Lang::load( \IPS\Lang::defaultLanguage() ) ), NULL, \IPS\Email::TYPE_BULK )
            ->
setUnsubscribe( 'core', 'unsubscribeBulk' );
       
$sent = 0;
        foreach (
$recipients as $languageId => $_recipients )
        {
           
$sent += $email->mergeAndSend( $_recipients, NULL, NULL, array( 'List-Unsubscribe' => '<*|unsubscribe_url|*>' ), \IPS\Lang::load( $languageId ) );
        }
       
       
/* Update bulk mail record */
       
if( $sent === 0 )
        {
           
$this->active    = 0;
           
$this->updated    = time();
           
$this->offset     = 0;
           
$this->save();
        }
        else
        {
           
$this->updated    = time();
           
$this->offset    = ( $this->offset + $classToUse::MAX_EMAILS_PER_GO );
           
$this->sentto    = ( $this->sentto + $sent );
           
$this->save();
        }

       
/* Return the number to increase the offset by (not necessarily the number of users the email was sent to, but still the amount we need to increase the offset by) */
       
return $classToUse::MAX_EMAILS_PER_GO;
    }

   
/**
     * Retrieve the query to fetch members based on our filters
     *
     * @param    array|int    $option        A constant to fetch counts only or an array with the limit to apply to the query
     * @return    \IPS\Db\Select
     */
   
public function getQuery( $option=NULL )
    {
       
/* Compile where */
       
$where = array();
       
$where[] = array( "core_members.allow_admin_mails=1" );
       
$where[] = array( "core_members.temp_ban=0" );
       
$where[] = array( "core_members.email!=''" );
       
$where[] = array( '( ! ' . \IPS\Db::i()->bitwiseWhere( \IPS\Member::$bitOptions['members_bitoptions'], 'bw_is_spammer' ) . ' )' );

        foreach ( \
IPS\Application::allExtensions( 'core', 'MemberFilter', FALSE, 'core' ) as $key => $extension )
        {
            if(
method_exists( $extension, 'getQueryWhereClause' ) AND $extension->availableIn( 'bulkmail' ) )
            {
               
/* Grab our fields and add to the form */
               
if( !empty( $this->_options[ $key ] ) )
                {
                    if(
$_where = $extension->getQueryWhereClause( $this->_options[ $key ] ) )
                    {
                        if (
is_string( $_where ) )
                        {
                           
$_where = array( $_where );
                        }
                       
                       
$where    = array_merge( $where, $_where );
                    }
                }
            }
        }
       
       
/* Compile query */
       
$select = ( $option !== static::GET_COUNT_ONLY ) ? 'core_members.member_id AS my_member_id, core_members.*' : 'COUNT(DISTINCT core_members.member_id)';
       
$limit = is_array( $option ) ? $option : NULL;
       
$query = \IPS\Db::i()->select( $select, 'core_members', $where, ( $option !== static::GET_COUNT_ONLY ) ? 'core_members.member_id' : NULL, $limit, NULL, NULL, \IPS\Db::SELECT_DISTINCT );
       
       
/* Run callbacks */
       
foreach ( \IPS\Application::allExtensions( 'core', 'MemberFilter', FALSE, 'core' ) as $key => $extension )
        {
            if(
method_exists( $extension, 'queryCallback' ) AND $extension->availableIn( 'bulkmail' ) )
            {
               
/* Grab our fields and add to the form */
               
if( !empty( $this->_options[ $key ] ) )
                {
                   
$data = $this->_options[ $key ];
                   
$extension->queryCallback( $data, $query );
                }
            }
        }

        return
$query;
    }

   
/**
     * Return tag values
     *
     * @param    int                    $type    0=All, 1=Global, 2=Member-specific
     * @param    NULL|\IPS\Member    $member    Member object if $type is 0 or 2
     * @return    array
     */
   
public function returnTagValues( $type, $member=NULL )
    {
       
$tags    = array();

       
/* Do we want global tags? */
       
if( $type === 0 OR $type === 1 )
        {
           
$mostOnline = json_decode( \IPS\Settings::i()->most_online, TRUE );

           
$tags['{suite_name}']        = \IPS\Settings::i()->board_name;
           
$tags['{suite_url}']        = \IPS\Settings::i()->base_url;
           
$tags['{busy_time}']        = \IPS\DateTime::ts( ( $mostOnline['time'] ) ? $mostOnline['time'] : time() )->localeDate();
           
$tags['{busy_count}']        = $mostOnline['count'];
           
           
/* Only bother querying if we need the value */
           
if( mb_strpos( $this->_data['content'], '{reg_total}' ) !== FALSE )
            {
               
$tags['{reg_total}']        = \IPS\Db::i()->select( 'count(*)', 'core_members', 'member_id > 0' )->first();
            }
        }

       
/* Do we want member tags? */
       
if( $type === 0 OR $type === 2 )
        {
           
$tags['{member_id}']            = $member->member_id;
           
$tags['{member_email}']            = $member->email;
           
$tags['{member_name}']            = $member->name;
           
$tags['{member_url}']            = $member->url();
           
$tags['{member_joined}']        = $member->joined->localeDate();
           
$tags['{member_last_visit}']    = \IPS\DateTime::ts( $member->last_visit )->localeDate();
           
$tags['{member_posts}']            = $member->member_posts;
           
$tags['{unsubscribe_url}']        = (string) \IPS\Http\Url::internal( 'app=core&module=system&controller=unsubscribe', 'front', 'unsubscribe' )->setQueryString( array(
               
'email'    => $member->email,
               
'key'    => md5( $member->email . ':' . $member->members_pass_hash )
            ) );
           
$tags['{unsubscribe_key}']        = md5( $member->email . ':' . $member->members_pass_hash );
        }

       
/* Now retrieve tags via any bulk mail extensions.  We only want them to return an array of tags to perform formatting, but
            $body is passed in case a particular tag is computationally expensive so that the extension may "sniff" for it and elect
            not to perform the computation if it is not used. */
       
foreach ( \IPS\Application::allExtensions( 'core', 'BulkMail', TRUE, 'core' ) as $key => $extension )
        {
            if(
method_exists( $extension, 'returnTagValues' ) )
            {
               
$tags    = array_merge( $tags, $extension->returnTagValues( $this->_data['content'], $type, $member ) );
            }
        }

        return
$tags;
    }

   
/**
     * Retrieve the tags that can be used in bulk mails
     *
     * @return    array     An array of tags in foramt of 'tag' => 'explanation text'
     */
   
public static function getTags()
    {
       
/* Default tags */
       
$tags    = array(
           
'{member_id}'            => \IPS\Member::loggedIn()->language()->addToStack('bmtag_member_id'),
           
'{member_name}'            => \IPS\Member::loggedIn()->language()->addToStack('bmtag_member_name'),
           
'{member_url}'            => \IPS\Member::loggedIn()->language()->addToStack('bmtag_member_profileurl'),
           
'{member_joined}'        => \IPS\Member::loggedIn()->language()->addToStack('bmtag_member_joined'),
           
'{member_last_visit}'    => \IPS\Member::loggedIn()->language()->addToStack('bmtag_member_last_visit'),
           
'{member_posts}'        => \IPS\Member::loggedIn()->language()->addToStack('bmtag_member_posts'),
           
'{reg_total}'            => \IPS\Member::loggedIn()->language()->addToStack('bmtag_reg_total'),
           
'{suite_name}'            => \IPS\Member::loggedIn()->language()->addToStack('bmtag_suite_name'),
           
'{suite_url}'            => \IPS\Member::loggedIn()->language()->addToStack('bmtag_suite_url'),
           
'{busy_count}'            => \IPS\Member::loggedIn()->language()->addToStack('bmtag_busy_count'),
           
'{busy_time}'            => \IPS\Member::loggedIn()->language()->addToStack('bmtag_busy_time'),
        );

       
/* Now grab tags from any bulk mail extensions */
       
foreach ( \IPS\Application::allExtensions( 'core', 'BulkMail', TRUE, 'core' ) as $key => $extension )
        {
            if(
method_exists( $extension, 'getTags' ) )
            {
               
$tags    = array_merge( $tags, $extension->getTags() );
            }
        }

        return
$tags;
    }
   
   
/**
     * Delete Record
     *
     * @return    void
     */
   
public function delete()
    {
       
/* Unclaim Attachments */
       
\IPS\File::unclaimAttachments( 'core_Admin', $this->id, NULL, 'bulkmail' );
       
       
/* Make sure any queue rows are removed */
       
foreach( \IPS\Db::i()->select( '*', 'core_queue', array( "`key`=?", 'Bulkmail' ) ) AS $task )
        {
           
$data = json_decode( $task['data'], TRUE );
           
            if ( isset(
$data['mail_id'] ) AND $data['mail_id'] == $this->id )
            {
                \
IPS\Db::i()->delete( 'core_queue', array( "id=?", $task['id'] ) );
            }
        }
       
       
parent::delete();
    }
}