这个脚本包含 Pear::DB 数据库访问类。然后定义 mailouts 类,其中包含三个主要的静态函数:add、delete 和 get_all。add() 方法向队列中添加一个电子邮件,这个方法由前端使用。get_all() 方法从表中返回所有数据。delete() 方法删除一个电子邮件。
您可能会问,我为什么不只在脚本末尾调用 delete_all() 方法。不这么做有两个原因:如果在发送每个消息之后删除它,那么即使脚本在出现问题之后重新运行,消息也不可能发送两次;在批作业的启动和完成之间可能会添加新的消息。
下一步是编写一个简单的测试脚本,这个脚本将一个条目添加到队列中。
清单 3. mailout_test_add.php
<?phprequire '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
<?phprequire_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 表。
与 mailouts 表一样,这两个表也由 PHP 类包装,这个类称为 ProcessingItems。
清单 6. generic.php
<?phprequire_once('DB.php');class ProcessingItems{ public static function get_db() { ... } public static function delete( $id ) { $db = ProcessingItems::get_db(); $sth = $db->prepare( 'DELETE FROM processing_args WHERE item_id=?' ); $db->execute( $sth, $id ); $sth = $db->prepare( 'DELETE FROM processing_items WHERE id=?' ); $db->execute( $sth, $id ); return true; } public static function add( $function, $args ) { $db = ProcessingItems::get_db(); $sth = $db->prepare( 'INSERT INTO processing_items VALUES (null,?)' ); $db->execute( $sth, array( $function ) ); $res = $db->query( "SELECT last_insert_id()" ); $id = null; while( $res->fetchInto( $row ) ) { $id = $row[0]; } foreach( $args as $key => $value ) { $sth = $db->prepare( 'INSERT INTO processing_args VALUES (null,?,?,?)' ); $db->execute( $sth, array( $id, $key, $value ) ); } return true; } public static function get_all() { $db = ProcessingItems::get_db(); $res = $db->query( "SELECT * FROM processing_items" ); $rows = array(); while( $res->fetchInto( $row ) ) { $item = array(); $item['id'] = $row[0]; $item['function'] = $row[1]; $item['args'] = array(); $ares = $db->query( "SELECT key_name, value FROM processing_args WHERE item_id=?", $item['id'] ); while( $ares->fetchInto( $arow ) ) $item['args'][ $arow[0] ] = $arow[1]; $rows []= $item; } return $rows; }}?>
这个类包含三个重要的方法:add()、get_all() 和 delete()。与 mailouts 系统一样,前端使用 add(),处理引擎使用 get_all() 和 delete()。
清单 7 所示的测试脚本将一个条目添加到处理队列中。
清单 7. generic_test_add.php
<?phprequire_once 'generic.php';ProcessingItems::add( 'printvalue', array( 'value' => 'foo' ) );?>
在这个示例中,添加了一个对 printvalue 函数的调用,并将 value 参数设置为 foo。我使用 PHP 命令行解释器运行这个脚本,并将这个方法调用放进队列中。然后使用以下处理脚本运行这个方法。
清单 8. generic_process.php
<?phprequire_once 'generic.php';function printvalue( $args ) { echo 'Printing: '.$args['value']."\n";}foreach( ProcessingItems::get_all() as $item ) { call_user_func_array( $item['function'], array( $item['args'] ) ); ProcessingItems::delete( $item['id'] );}?>
文章整理:西部数码--专业提供域名注册、虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!




