近日在对charsen的修改版上进行了再次的修改与调整,对原版的qee v3 做了更多的bug修改,目前经过测试基本可以使用,虽然还有一些坑,但是代码量始终只有那么一点,填补起来应该很方便,加上qee-v3确实有些技术知识点可供学习..
因为 qee-v3 只给出了一些极简单的库支持,而邮件功能在项目开发过程中又是不可或缺的部分,所以就集成了swiftmailer, 这个库在国外的知名度蛮高的,在性能上比phpmailer要好不少,尤其是对大附件的支持上.唯独的缺陷就是中文文档太少,为了方便使用,故对其做了如下封装....
如果非要对这个封装代码起个名字,那就叫做 qser-mailer 吧
先给出一个如何使用的demo,个人感觉还是比较方便和简单的
<?php
namespace qser\app\actions;
use qeephp\mvc\BaseAction;
use qeephp\Config;
use qeephp\tools\Logger;
use qeephp\storage\mysql\DataSource;
use qeephp\storage\Meta;
use qser\app\models\Post;
use qser\libraries\Validator;
use qser\libraries\PinyinLib;
class IndexAction extends BaseAction
{
/**
* @var mysql\DataSource
*/
private $_ds;
private $_handle;
function execute()
{
try{
$post5 = Post::find_one(5);
}
catch( \Exception $ex )
{
Logger::instance('test')->fatal($ex);
}
Logger::instance('test')->debug($post5);
dump('indexAction',PinyinLib::topinyin("我爱北京天门"));
///dump($this->app);
// $value = 7;
// $result = Validator::validateBatch($value, array(array('is_int'),array('between', 2, 6)));
// var_dump($result);
$this->view(array('action' => 'a', __DIR__));
$email = array('vb@qq.com');
$content = $this->result;
$this->app->tool('mail')->mailer->send(function($message) use($email,$content)
{
$text = $content->execute();
$message->to($email)->subject('qeev3 测试邮件');
$message->setBody($text, 0 ? 'text/plain' : 'text/html');
$message->attachData($text,'runtest',array('as' => $message->encodeAttachmentName('啥都好说')));
$message->attach(MYAPP_SRC_PATH . '/tmp/tests.log',array('as' => $message->encodeAttachmentName('尼玛')));
});
// dump($this->app->tool('mail')->mailer , $email);
//
//dump( $post5 );
/*
$sql = 'show tables';
$result = $this->_ds->execute($sql);
dump($result,$sql); // out resource
$result = $this->_ds->find_one('post',null);
dump($result,'post_one');
$result = $this->_ds->find('post',null)->fetch();
dump($result,'fetch');
$result = $this->_ds->find('post',null)->sort('post_id DESC')->fetch();
dump($result,'fetch by sort');
*/
//$result = $this->_ds->find('post',null)->fetch_all();
// dump($result,'fetch_all');
//
//$meta = new Meta('qser\\app\\models\\Revision');
//$meta = array();
// dump( $meta ,'meta');
}
protected function __before_execute()
{
// init resource
// $this->_ds = new DataSource( Config::get('storage.domains.default') );
// $this->_ds->connect();
// $this->_ds->set_logger(Logger::instance('test'));
// $this->_handle = $this->_ds->handle();
// $this->_ds->execute('SET AUTOCOMMIT=0');
// $this->_ds->execute('START TRANSACTION');
// foreach (self::post_recordset() as $post)
// {
// $this->_ds->insert('qser_posts', $post);
// }
// $this->_ds->execute('COMMIT');
// $this->_ds->execute('SET AUTOCOMMIT=1');
return true;
}
// test func
static function post_recordset($begin_post_id = 31)
{
static $authors = array('dualface', 'liaoyulei', 'lownr', 'dox', 'quietlife');
$recordset = array();
for ($post_id = $begin_post_id; $post_id < $begin_post_id + 10; $post_id++)
{
$author = $authors[mt_rand(0, count($authors) - 1)];
$recordset[$post_id] = array(
'post_id' => $post_id,
'title' => 'post ' . $post_id,
'author' => $author,
'click_count' => mt_rand(1, 999),
);
}
return $recordset;
}
static function revisions_recordset($begin_post_id = 1)
{
$recordset = array();
$created = time();
for ($post_id = $begin_post_id; $post_id < $begin_post_id + 5; $post_id++)
{
$num_rev = mt_rand(1, 5);
for ($i = 0; $i < $num_rev; $i++)
{
$recordset[] = array(
'post_id' => $post_id,
'body' => sprintf('post %u rev %u', $post_id, $i),
'created' => $created,
);
}
}
return $recordset;
}
}
测试的结果蛮好,如图所示,中文附件名字也能正常显示,灰常给力是不是
------------------------------------------------------------
所有代码如下所示:
<?php namespace qser\app\tools;
use qeephp\mvc\App;
use qser\libraries\Mail\Mailer;
class MailTool
{
/**
* 当前请求
*
* @var Mailer
*/
public $mailer;
/**
* Create a new Mailer instance.
*
* @param App $app
* @param array $config
*/
public function __construct(App $app, array $config) {
$this->mailer = new Mailer($config);
}
}
<?php
namespace qser\libraries\Mail;
if (!defined('SWIFT_INIT_LOADED')) {
require ROOT_PATH . '/packages/swiftmailer/lib/swift_init.php';
}
use Swift_Mailer;
use Swift_Message;
use qeephp\tools\Logger;
use qser\libraries\Mail\Provider;
class Mailer
{
/**
* The Swift Mailer instance.
*
* @var \Swift_Mailer
*/
protected $swift;
/**
* The global from address and name.
*
* @var array
*/
protected $from;
/**
* The log writer instance.
*
* @var ILogger
*/
protected $logger;
/**
* Indicates if the actual sending is disabled.
*
* @var bool
*/
protected $pretending = false;
/**
* Array of failed recipients.
*
* @var array
*/
protected $failedRecipients = array();
/**
* Create a new Mailer instance.
*
* @param array $config
* @return void
*/
public function __construct(array $config)
{
$this->swift = Provider::registerSwiftMailer($config);
$logger = val($config, 'logger' , false);
if ($logger)
{
$this->setLogger(Logger::instance($logger));
}
$from = val($config, 'from' , false);
if (is_array($from) && isset($from['address']))
{
$this->alwaysFrom($from['address'], $from['name']);
}
// Here we will determine if the mailer should be in "pretend" mode for this
// environment, which will simply write out e-mail to the logs instead of
// sending it over the web, which is useful for local dev environments.
$pretend = val($config, 'pretend' , false);
$this->pretend($pretend);
}
/**
* Set the global from address and name.
*
* @param string $address
* @param string $name
* @return void
*/
public function alwaysFrom($address, $name = null)
{
$this->from = compact('address', 'name');
}
/**
* Send a new message.
*
* @param callback $callback
* @return int
*/
public function send($callback)
{
$message = $this->createMessage();
$data['message'] = $message;
if ($callback && is_callable($callback))
{
call_user_func($callback,$message);
}
else
{
throw new \InvalidArgumentException('Invalid mail send callback.');
}
$message = $message->getSwiftMessage();
return $this->sendSwiftMessage($message);
}
/**
* Send a Swift Message instance.
*
* @param \Swift_Message $message
* @return int
*/
protected function sendSwiftMessage($message)
{
if ( !$this->pretending)
{
return $this->swift->send($message, $this->failedRecipients);
}
elseif (isset($this->logger))
{
$this->logMessage($message);
return 1;
}
}
/**
* Log that a message was sent.
*
* @param \Swift_Message $message
* @return void
*/
protected function logMessage($message)
{
$emails = implode(', ', array_keys((array) $message->getTo()));
$this->logger->info("Pretending to mail message to: {$emails}");
}
/**
* Create a new message instance.
*
* @return Message
*/
protected function createMessage()
{
$message = new Message(new Swift_Message);
// If a global from address has been specified we will set it on every message
// instances so the developer does not have to repeat themselves every time
// they create a new message. We will just go ahead and push the address.
if (isset($this->from['address']))
{
$message->from($this->from['address'], $this->from['name']);
}
return $message;
}
/**
* Tell the mailer to not really send messages.
*
* @param bool $value
* @return void
*/
public function pretend($value = true)
{
$this->pretending = $value;
}
/**
* Get the Swift Mailer instance.
*
* @return \Swift_Mailer
*/
public function getSwiftMailer()
{
return $this->swift;
}
/**
* Get the array of failed recipients.
*
* @return array
*/
public function failures()
{
return $this->failedRecipients;
}
/**
* Set the log writer instance.
*
* @param Logger $logger
*/
public function setLogger(Logger $logger)
{
$this->logger = $logger;
}
}
<?php namespace qser\libraries\Mail;
use Swift_Mailer;
use Swift_SmtpTransport as SmtpTransport;
use Swift_MailTransport as MailTransport;
use Swift_SendmailTransport as SendmailTransport;
class Provider
{
/**
* Register the Swift Mailer instance.
*
* @return \Swift_Mailer
*/
public static function registerSwiftMailer($config)
{
$self = new static();
return new Swift_Mailer( $self->registerSwiftTransport($config) );
}
/**
* Register the Swift Transport instance.
*
* @param array $config
* @return void
*
* @throws \InvalidArgumentException
*/
protected function registerSwiftTransport($config)
{
switch ($config['driver'])
{
case 'smtp':
return $this->registerSmtpTransport($config);
case 'sendmail':
return $this->registerSendmailTransport($config);
case 'mail':
return $this->registerMailTransport($config);
default:
throw new \InvalidArgumentException('Invalid mail driver.');
}
}
/**
* Register the SMTP Swift Transport instance.
*
* @param array $config
* @return void
*/
protected function registerSmtpTransport($config)
{
// The Swift SMTP transport instance will allow us to use any SMTP backend
// for delivering mail such as Sendgrid, Amazon SMS, or a custom server
// a developer has available. We will just pass this configured host.
$transport = SmtpTransport::newInstance($config['host'], $config['port']);
if (!empty($config['encryption']))
{
$transport->setEncryption($config['encryption']);
}
// Once we have the transport we will check for the presence of a username
// and password. If we have it we will set the credentials on the Swift
// transporter instance so that we'll properly authenticate delivery.
if (!empty($config['username']))
{
$transport->setUsername($config['username']);
$transport->setPassword($config['password']);
}
return $transport;
}
/**
* Register the Sendmail Swift Transport instance.
*
* @param array $config
* @return void
*/
protected function registerSendmailTransport($config)
{
return SendmailTransport::newInstance($config['sendmail']);
}
/**
* Register the Mail Swift Transport instance.
*
* @param array $config
* @return void
*/
protected function registerMailTransport($config)
{
return MailTransport::newInstance();
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array('mailer', 'swift.mailer', 'swift.transport');
}
}
<?php namespace qser\libraries\Mail;
use Swift_Image;
use Swift_Attachment;
class Message {
/**
* The Swift Message instance.
*
* @var \Swift_Message
*/
protected $swift;
/**
* Create a new message instance.
*
* @param \Swift_Message $swift
* @return void
*/
public function __construct($swift)
{
$this->swift = $swift;
}
/**
* Add a "from" address to the message.
*
* @param string $address
* @param string $name
* @return \qser\libraries\Mail\Message
*/
public function from($address, $name = null)
{
$this->swift->setFrom($address, $name);
return $this;
}
/**
* Set the "sender" of the message.
*
* @param string $address
* @param string $name
* @return \qser\libraries\Mail\Message
*/
public function sender($address, $name = null)
{
$this->swift->setSender($address, $name);
return $this;
}
/**
* Set the "return path" of the message.
*
* @param string $address
* @return \qser\libraries\Mail\Message
*/
public function returnPath($address)
{
$this->swift->setReturnPath($address);
return $this;
}
/**
* Add a recipient to the message.
*
* @param string|array $address
* @param string $name
* @return \qser\libraries\Mail\Message
*/
public function to($address, $name = null)
{
return $this->addAddresses($address, $name, 'To');
}
/**
* Add a carbon copy to the message.
*
* @param string $address
* @param string $name
* @return \qser\libraries\Mail\Message
*/
public function cc($address, $name = null)
{
return $this->addAddresses($address, $name, 'Cc');
}
/**
* Add a blind carbon copy to the message.
*
* @param string $address
* @param string $name
* @return \qser\libraries\Mail\Message
*/
public function bcc($address, $name = null)
{
return $this->addAddresses($address, $name, 'Bcc');
}
/**
* Add a reply to address to the message.
*
* @param string $address
* @param string $name
* @return \qser\libraries\Mail\Message
*/
public function replyTo($address, $name = null)
{
return $this->addAddresses($address, $name, 'ReplyTo');
}
/**
* Add a recipient to the message.
*
* @param string|array $address
* @param string $name
* @param string $type
* @return \qser\libraries\Mail\Message
*/
protected function addAddresses($address, $name, $type)
{
if (is_array($address))
{
$this->swift->{"set{$type}"}($address, $name);
}
else
{
$this->swift->{"add{$type}"}($address, $name);
}
return $this;
}
/**
* Set the subject of the message.
*
* @param string $subject
* @return \qser\libraries\Mail\Message
*/
public function subject($subject)
{
$this->swift->setSubject($subject);
return $this;
}
/**
* Set the message priority level.
*
* @param int $level
* @return \qser\libraries\Mail\Message
*/
public function priority($level)
{
$this->swift->setPriority($level);
return $this;
}
/**
* 编码附件名称(可用于显示中文附件名)
*
* @param string $file
*
* @return string
*/
public function encodeAttachmentName($name)
{
return "=?UTF-8?B?" . base64_encode($name) . "?=";
}
/**
* Attach a file to the message.
*
* @param string $file
* @param array $options
* @return \qser\libraries\Mail\Message
*/
public function attach($file, array $options = array())
{
$attachment = $this->createAttachmentFromPath($file);
return $this->prepAttachment($attachment, $options);
}
/**
* Create a Swift Attachment instance.
*
* @param string $file
* @return \Swift_Attachment
*/
protected function createAttachmentFromPath($file)
{
return Swift_Attachment::fromPath($file);
}
/**
* Attach in-memory data as an attachment.
*
* @param string $data
* @param string $name
* @param array $options
* @return \qser\libraries\Mail\Message
*/
public function attachData($data, $name, array $options = array())
{
$attachment = $this->createAttachmentFromData($data, $name);
return $this->prepAttachment($attachment, $options);
}
/**
* Create a Swift Attachment instance from data.
*
* @param string $data
* @param string $name
* @return \Swift_Attachment
*/
protected function createAttachmentFromData($data, $name)
{
return Swift_Attachment::newInstance($data, $name);
}
/**
* Embed a file in the message and get the CID.
*
* @param string $file
* @return string
*/
public function embed($file)
{
return $this->swift->embed(Swift_Image::fromPath($file));
}
/**
* Embed in-memory data in the message and get the CID.
*
* @param string $data
* @param string $name
* @param string $contentType
* @return string
*/
public function embedData($data, $name, $contentType = null)
{
$image = Swift_Image::newInstance($data, $name, $contentType);
return $this->swift->embed($image);
}
/**
* Prepare and attach the given attachment.
*
* @param \Swift_Attachment $attachment
* @param array $options
* @return \qser\libraries\Mail\Message
*/
protected function prepAttachment($attachment, $options = array())
{
// First we will check for a MIME type on the message, which instructs the
// mail client on what type of attachment the file is so that it may be
// downloaded correctly by the user. The MIME option is not required.
if (isset($options['mime']))
{
$attachment->setContentType($options['mime']);
}
// If an alternative name was given as an option, we will set that on this
// attachment so that it will be downloaded with the desired names from
// the developer, otherwise the default file names will get assigned.
if (isset($options['as']))
{
$attachment->setFilename($options['as']);
}
$this->swift->attach($attachment);
return $this;
}
/**
* Get the underlying Swift Message instance.
*
* @return \Swift_Message
*/
public function getSwiftMessage()
{
return $this->swift;
}
/**
* Dynamically pass missing methods to the Swift instance.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
$callable = array($this->swift, $method);
return call_user_func_array($callable, $parameters);
}
}
-------- 配置信息如下所示
写道
# Tools 设置
'app.tools' => array(
# mail 工具配置
'mail' => array(
'class' => 'qser\\app\\tools\\MailTool',
'driver' => 'smtp', #Supported: "smtp", "mail", "sendmail"
'host' => 'smtp.qq.com',
'port' => 4650,
'encryption' => 'ssl',
'username' => "noreply@sese.cn",
'password' =>"qwaszyss",
'pretend' => false,#启用此选项,邮件不会真正发送,而是写到日志文件中
'logger' => 'test', #使用日志对象
'from' => array('address' => 'noreply@sese.cn', 'name' => '易结网'),
),
),