这个模型首先需要 MySQL 模式。
清单 1. mailout.sql
DROP TABLE IF EXISTS mailouts; CREATE TABLE mailouts ( id MEDIUMINT NOT NULL AUTO_INCREMENT, from_address TEXT NOT NULL, to_address TEXT NOT NULL, subject TEXT NOT NULL, content TEXT NOT NULL, PRIMARY KEY ( id ) ); |
这个模式非常简单。每行中有一个 from 和一个 to 地址,以及电子邮件的主题和内容。
对数据库中的 mailouts 表进行处理的是 PHP mailouts 类。
清单 2. mailouts.php
<?php
require_once('DB.php');
class Mailouts
{
public static function get_db()
{
$dsn = 'mysql://root:@localhost/mailout';
$db =& DB::Connect( $dsn, array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
return $db;
}
public static function delete( $id )
{
$db = Mailouts::get_db();
$sth = $db->prepare( 'DELETE FROM mailouts WHERE id=?' );
$db->execute( $sth, $id );
return true;
}
public static function add( $from, $to, $subject, $content )
{
$db = Mailouts::get_db();
$sth = $db->prepare( 'INSERT INTO mailouts VALUES (null,?,?,?,?)' );
$db->execute( $sth, array( $from, $to, $subject, $content ) );
return true;
}
public static function get_all()
{
$db = Mailouts::get_db();
$res = $db->query( "SELECT * FROM mailouts" );
$rows = array();
while( $res->fetchInto( $row ) ) { $rows []= $row; }
return $rows;
}
}
?>
|
这个脚本包含 Pear::DB 数据库访问类。然后定义 mailouts 类,其中包含三个主要的静态函数:add、delete 和 get_all。add() 方法向队列中添加一个电子邮件,这个方法由前端使用。get_all() 方法从表中返回所有数据。delete() 方法删除一个电子邮件。
您可能会问,我为什么不只在脚本末尾调用 delete_all() 方法。不这么做有两个原因:如果在发送每个消息之后删除它,那么即使脚本在出现问题之后重新运行,消息也不可能发送两次;在批作业的启动和完成之间可能会添加新的消息。
下一步是编写一个简单的测试脚本,这个脚本将一个条目添加到队列中。
清单 3. mailout_test_add.php
<?php require 'mailout.php'; Mailouts::add( 'donotreply@mydomain.com', 'molly@nocompany.com.org', 'Test Subject', 'This is a test of the batch mail sendout' ); ?> |
在这个示例中,我添加一个 mailout,这个消息要发送给某公司的 Molly,其中包括主题 “Test Subject” 和电子邮件主体。可以在命令行上运行这个脚本:php mailout_test_add.php。
为了发送电子邮件,需要另一个脚本,这个脚本作为作业处理程序。
清单 4. mailout_send.php
<?php
require_once 'mailout.php';
function process( $from, $to, $subject, $email ) {
mail( $to, $subject, $email, "From: $from" );
}
$messages = Mailouts::get_all();
foreach( $messages as $msg ) {
process( $msg[1], $msg[2], $msg[3], $msg[4] );
Mailouts::delete( $msg[0] );
}
?>
|
这个脚本使用 get_all() 方法检索所有电子邮件消息,然后使用 PHP 的 mail() 方法逐一发送消息。在每次成功发送电子邮件之后,调用 delete() 方法从队列中删除对应的记录。
使用 cron 守护进程定期运行这个脚本。运行这个脚本的频率取决于您的应用程序的需要。
注意:PHP Extension and Application Repository(PEAR)存储库包含一个出色的 邮件队列系统 实现,可以免费下载。
更通用的方法
专门用来发送电子邮件的解决方案是很不错,但是是否有更通用的方法?我们需要能够发送电子邮件、生成报告或者执行其他耗费时间的处理,而不必在浏览器中等待处理完成。
为此,可以利用一个事实:PHP 是一种解释型语言。可以将 PHP 代码存储在数据库中的队列中,以后再执行它。这需要两个表,见清单 5。
清单 5. generic.sql
DROP TABLE IF EXISTS processing_items; CREATE TABLE processing_items ( id MEDIUMINT NOT NULL AUTO_INCREMENT, function TEXT NOT NULL, PRIMARY KEY ( id ) ); DROP TABLE IF EXISTS processing_args; CREATE TABLE processing_args ( id MEDIUMINT NOT NULL AUTO_INCREMENT, item_id MEDIUMINT NOT NULL, key_name TEXT NOT NULL, value TEXT NOT NULL, PRIMARY KEY ( id ) ); |
第一个表 processing_items 包含作业处理程序调用的函数。第二个表 processing_args 包含要发送给函数的参数,采用的形式是由键/值对组成的 hash 表。
![nixsky[www.nixsky.com]](/templets/images/toplogo.gif)

