CI的Loader类导致使用phpmailer发送收件人和抄送人不断的增加

为啥要介绍CI的loader?

在一次使用群发邮件的功能时,引用了第三方的发送邮件的类,phpmailer,在使用时出现收件人和发件人在不断增加,然后就去了解了一下CI的loader源码

使用phpmailer的方法

    /**
     * 发送邮件
     * @param $to
     * @param string $name
     * @param $subject
     * @param $content
     * @param bool $bcc
     * @param array $ccto
     * @param string $reply_to
     * @return bool
     */
    function sendEmail($to, $name = '', $subject, $content, $bcc = FALSE, $ccto = array(), $reply_to='')
    {
        $CI = &get_instance();
        $CI->load->add_package_path(APPPATH . 'third_party/phpmailer/');
        $CI->load->library('phpmailer');
        $CI->load->config('mail');
        $CI->phpmailer->CharSet = $CI->config->item('charset'); // sets charset
        $CI->phpmailer->AddReplyTo($reply_to, 'Synbio Technologies');
        $CI->phpmailer->IsSMTP(); // telling the class to use SMTP
        $CI->phpmailer->SMTPDebug = $CI->config->item('smtp_debug');    // enables SMTP debug information (for testing)
        $CI->phpmailer->SMTPAuth = $CI->config->item('smtp_auth');        // enable SMTP authentication
        $CI->phpmailer->SMTPSecure = $CI->config->item('smtp_secure');       // sets the prefix to the servier
        $CI->phpmailer->Host = $CI->config->item('smtp_host');      // sets GMAIL as the SMTP server
        $CI->phpmailer->Port = $CI->config->item('smtp_port');         // set the SMTP port for the GMAIL server
        $CI->phpmailer->Username = $CI->config->item('smtp_username');  // GMAIL username
        $CI->phpmailer->Password = $CI->config->item('smtp_password');      // GMAIL password

        $CI->phpmailer->SetFrom($CI->config->item('smtp_username'), 'Synbio Technologies');

        $CI->phpmailer->Subject = $subject;

        $CI->phpmailer->MsgHTML($content);

        if($ccto)
        {
            if ($bcc)
            {
                if(is_array($ccto)){
                    foreach ($ccto as $value){
                        $CI->phpmailer->AddBCC($value, $value);
                    }
                }else{
                    $CI->phpmailer->AddBCC($ccto, $ccto);
                }
            }
            else
            {
                if(is_array($ccto)){
                    foreach ($ccto as $value){
                        $CI->phpmailer->AddCC($value, $value);
                    }
                }else{
                    $CI->phpmailer->AddCC($ccto, $ccto);
                }
            }

        }

        if ($bcc && empty($ccto)) {
            if(is_array($to)){
                foreach ($to as $key => $value){
                    $CI->phpmailer->AddBCC($value, (@$name[$key] ? @$name[$key] : $value));
                }
            }else{
                $CI->phpmailer->AddBCC($to, ($name ? $name : $to));
            }
        } else {
            if(is_array($to)){
                foreach ($to as $key => $value){
                    $CI->phpmailer->AddAddress($value, (@$name[$key] ? @$name[$key] : $value));
                }
            }else{
                $CI->phpmailer->AddAddress($to, ($name ? $name : $to));
            }
        }

//       attachment
        if(count($attachment) > 0)
        {
            foreach($attachment as $value)
            {
               $CI->phpmailer->AddAttachment($value);
           }
        }
        if (!$CI->phpmailer->Send()) {
            $CI->phpmailer->ClearAddresses();
            $CI->phpmailer->ClearCCs();
            return FALSE;
        } else {
            $CI->phpmailer->ClearAddresses();
            $CI->phpmailer->ClearCCs();
            return TRUE;
        }
    }

注意方法结尾部分的代码

 $CI->phpmailer->ClearAddresses();
 $CI->phpmailer->ClearCCs();

原来是没有这两行代码的,后面我在介绍这两行代码

了解对象在函数中的方式,是传值还是按引用?

这里我就不过多解释了,是引用方式
这里就解释了为什么上面代码群发邮件时会导致收件人和抄送人会增加的原因

$CI->phpmailer->AddAddress($to, ($name ? $name : $to));
 $CI->phpmailer->AddCC($ccto, $ccto);

如何解决这个问题

首先我想到的是能不能再使用完phpmailer对象是,释放掉这个对象unset(CI->phpmailer),CI是单例模式,在加载完使用的类之后,使用属性的方式将加载的类作为CI的一个属性,在释放$CI->phpmailer这个属性之后,我就发现多次调用上面发送sendEmail的方法时会报错:

ERROR - 2020-01-07 02:08:45 --> Severity: Warning --> Creating default object from empty value 
ERROR - 2020-01-07 02:08:45 --> Severity: error --> Exception: Call to undefined method stdClass::AddReplyTo() 

这是上面原因呢?

这就讲到CI的loader类了,CI的loader在加载时使用的是include_once所以在加载一次之后不会重复加载,所以就不能讲phpmailer作为CI的属性再次添加到CI的超级对象中,所以就报错,我们来看下源码:

$CI = &get_instance();
$CI->load->add_package_path(APPPATH . 'third_party/phpmailer/');
$CI->load->library('phpmailer');
$CI->load->config('mail');

这是我上述的方法,看下CI的loader源码:

protected function _ci_load_library($class, $params = NULL, $object_name = NULL)
    {
        // Get the class name, and while we're at it trim any slashes.
        // The directory path can be included as part of the class name,
        // but we don't want a leading slash
        $class = str_replace('.php', '', trim($class, '/'));

        // Was the path included with the class name?
        // We look for a slash to determine this
        if (($last_slash = strrpos($class, '/')) !== FALSE)
        {
            // Extract the path
            $subdir = substr($class, 0, ++$last_slash);

            // Get the filename from the path
            $class = substr($class, $last_slash);
        }
        else
        {
            $subdir = '';
        }

        $class = ucfirst($class);

        // Is this a stock library? There are a few special conditions if so ...
        if (file_exists(BASEPATH.'libraries/'.$subdir.$class.'.php'))
        {
            return $this->_ci_load_stock_library($class, $subdir, $params, $object_name);
        }

        // Let's search for the requested library file and load it.
        foreach ($this->_ci_library_paths as $path)
        {
            // BASEPATH has already been checked for
            if ($path === BASEPATH)
            {
                continue;
            }

            $filepath = $path.'libraries/'.$subdir.$class.'.php';

            // Safety: Was the class already loaded by a previous call?
            if (class_exists($class, FALSE))
            {
                // Before we deem this to be a duplicate request, let's see
                // if a custom object name is being supplied. If so, we'll
                // return a new instance of the object
                if ($object_name !== NULL)
                {
                    $CI =& get_instance();
                    if ( ! isset($CI->$object_name))
                    {
                        return $this->_ci_init_library($class, '', $params, $object_name);
                    }
                }

                log_message('debug', $class.' class already loaded. Second attempt ignored.');
                return;
            }
            // Does the file exist? No? Bummer...
            elseif ( ! file_exists($filepath))
            {
                continue;
            }

            include_once($filepath);
            return $this->_ci_init_library($class, '', $params, $object_name);
        }

        // One last attempt. Maybe the library is in a subdirectory, but it wasn't specified?
        if ($subdir === '')
        {
            return $this->_ci_load_library($class.'/'.$class, $params, $object_name);
        }

        // If we got this far we were unable to find the requested class.
        log_message('error', 'Unable to load the requested class: '.$class);
        show_error('Unable to load the requested class: '.$class);
    }

代码中明确指定了include_once一次,在PHP程序中代码都是依次执行的,不管循环多少次,只要前面加载过后面就不会再次加载了。

如何解决发送邮件的收件人和抄送人增加的问题呢

其实在phpmailer中已经给我们方法了

  public function ClearAddresses() {
    foreach($this->to as $to) {
      unset($this->all_recipients[strtolower($to[0])]);
    }
    $this->to = array();
  }
  public function ClearCCs() {
    foreach($this->cc as $cc) {
      unset($this->all_recipients[strtolower($cc[0])]);
    }
    $this->cc = array();
  }

  public function ClearBCCs() {
    foreach($this->bcc as $bcc) {
      unset($this->all_recipients[strtolower($bcc[0])]);
    }
    $this->bcc = array();
  }
  public function ClearReplyTos() {
    $this->ReplyTo = array();
  }

这几个方法在循环发送邮件的时候时候使用就不需要通过unset对象的方法来进行初始化了。所以在程序依次执行时,循环发送邮件调用phpmailer的方法是不需要释法phpmailer这个对象,通过使用他的方法进行收件人和抄送密送等初始化就可以了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容