我有一个简单的类,有两个方法:添加和处理。
require_once('MailQueue.config.php');
require_once('class.phpmailer.subclass.php');
class MailQueue {
private $dbServer;
private $dbName;
private $dbUsername;
private $dbPassword;
private $mailLimit;
private $mailLimitTimeUnit;
private $db;
function __construct() {
global $CONFIG;
// Set database connection variables
$this->dbServer = $CONFIG['dbServer'];
$this->dbName = $CONFIG['dbName'];
$this->dbUsername = $CONFIG['dbUsername'];
$this->dbPassword = $CONFIG['dbPassword'];
// Set app settings
$this->mailLimit = $CONFIG['mailLimit'];
$this->mailLimitTimeUnit = $CONFIG['mailLimitTimeUnit'];
// Connect to database
$this->db = new mysqli($this->dbServer, $this->dbUsername, $this->dbPassword, $this->dbName);
if($this->db->connect_error) {
die("Error connecting to MailQueue.<br />".$this->db->connect_error);
}
}
function add($data) {
$sqls = "";
foreach($data as $d) {
$sqls .= "INSERT INTO mailqueue (".
"desiredSendTime, ".
"fromName, ".
"fromAddress, ".
"toName, ".
"toAddress, ".
"subject, ".
"bodyHtml ".
") VALUES (".
"'".$d['sendAt']."',".
"'".$d['fromName']."',".
"'".$d['fromAddress']."',".
"'".$d['toName']."',".
"'".$d['toAddress']."',".
"'".$d['subject']."',".
"'".$d['body']."'".
");";
}
$insertIds = Array();
if(!$this->db->multi_query($sqls)){
die("Error adding emails to mailqueue: (".$this->db->errno.") ".$this->db->error);
}
// fetch insert ids
do {
$insertIds[] = $this->db->insert_id;
} while($this->db->more_results() && $this->db->next_result());
return $insertIds;
}
function processQueue($numberOfMessages, $preferredEmailIds="") {
// Get number of emails already sent in this timeframe
// Do not check for the last timeUnit, but for the timeUnit we're currently in, e.g.
// if timeUnit = 'hour', count the processed emails in de current hour, not in the last 60 minutes.
switch($this->mailLimitTimeUnit) {
case 'year':
$startOfCurrentTimeframe = date('Y-01-01 00:00:00');
break;
case 'month':
$startOfCurrentTimeframe = date('Y-m-01 00:00:00');
break;
case 'day':
$startOfCurrentTimeframe = date('Y-m-d 00:00:00');
break;
case 'hour':
$startOfCurrentTimeframe = date('Y-m-d H:00:00');
break;
case 'minute':
$startOfCurrentTimeframe = date('Y-m-d H:i:00');
break;
default:
$startOfCurrentTimeframe = '';
}
if($startOfCurrentTimeframe != '') {
$successCounter = 0;
$sql = "SELECT ".
"COUNT(*) AS currentCount ".
"FROM ".
"mailqueue ".
"WHERE ".
"actualSendTime BETWEEN '".$startOfCurrentTimeframe."' AND NOW()";
if(!($stmt = $this->db->prepare($sql))) {
die("Prepare failed: (".$this->db->errno.") ".$this->db->error);
}
if(!($stmt->execute())) {
die("Execute failed: (".$stmt->errno.") ".$stmt->error);
}
$result = $stmt->get_result();
$row = $result->fetch_assoc();
$currentCount = $row['currentCount'];
$spaceLeft = $this->mailLimit - $currentCount;
// Don't exceed the mail limits!
if($spaceLeft < $numberOfMessages){
$numberOfMessages = $spaceLeft;
}
// In case of preferred emails, add an explicit filter to accomplish this
if($preferredEmailIds!=""){
$preferredEmailsOnly = "AND id IN (".implode(',', $preferredEmailIds).") ";
} else {
$preferredEmailsOnly = "";
}
// Process new emails
$sql = "SELECT ".
"* ".
"FROM ".
"mailqueue ".
"WHERE ".
"desiredSendTime < NOW() ".
"AND actualSendTime IS NULL ".
$preferredEmailsOnly.
"ORDER BY ".
"desiredSendTime, ".
"id ".
"LIMIT ?";
if(!($stmt = $this->db->prepare($sql))) {
die("Prepare failed: (".$this->db->errno.") ".$this->db->error);
}
if (!$stmt->bind_param("i", $numberOfMessages)){
die("Binding parameters failed: (".$stmt->errno.") ".$stmt->error);
}
if (!$stmt->execute()) {
die("Execute failed: (".$stmt->errno.") ".$stmt->error);
}
$result = $stmt->get_result();
if($result->num_rows > 0) {
$successCounter = 0;
$sqls = "";
while($row = $result->fetch_assoc()) {
$msg = new themedMailer();
$msg->From = $row['fromAddress'];
$msg->FromName = $row['fromName'];
$msg->Subject = $row['subject'];
$msg->Body = $row['bodyHtml'];
$msg->IsMail();
$msg->AddAddress($row['toAddress'], $row['toName']);
if($msg->Send()) {
$successCounter++;
// Save the time of sending to the email in the database
$sqls .= "UPDATE mailqueue SET actualSendTime = NOW() WHERE id = ".$row['id'].";";
} else {
die("Sending mail failed: ".$this->ErrorInfo);
}
}
// Update the sent emails
if(!$this->db->multi_query($sqls)){
die("Failed updating records for sent emails; these emails will be sent again because of this error.");
}
}
$stmt->close();
}
return $successCounter;
}
}
如果我使用单独的http请求来调用add
和process
函数,则它可以正常工作。 add
函数在表中添加了一些记录,process
函数处理来自同一表的一些记录(不一定是相同的记录)。
如果我尝试将两者合并以使process
处理由add
插入的记录,则process
函数根本找不到由{{1}插入的记录功能。一些代码解释了我一直在尝试的内容:
此代码可以正常工作:
HTTP请求1:
add
HTTP请求2:
ERROR_REPORTING(E_ALL);
require_once('../MailQueue.class.php');
$queue = new MailQueue();
$currentTime = date('YmdHis');
$data = Array();
$num = 2000;
for($i=1; $i<=$num; $i++) {
$data[$i] = Array();
$data[$i]['sendAt'] = date('Y-m-d H:i:s');
$data[$i]['fromName'] = 'John Doe';
$data[$i]['fromAddress'] = 'john@doe.com';
$data[$i]['toName'] = 'Jane Doe';
$data[$i]['toAddress'] = 'jane@doe.com';
$data[$i]['subject'] = 'Test message MailQueue '.$currentTime;
$data[$i]['body'] = 'Test message MailQueue '.$currentTime;
}
$queue->add($data);
echo "Added ".$num." new emails to be sent";
以下代码不起作用,因为ERROR_REPORTING(E_ALL);
require_once('../MailQueue.class.php');
$try = 50;
$queue = new MailQueue();
echo "Trying to send ".$try." emails.<br />";
$counter = $queue->processQueue($try);
echo "Sent ".$counter." emails.";
if($counter < $try) {
echo " Not all desired emails were sent, so the mail limit was probably reached. Please try again later.";
}
函数中的SELECT
查询不返回任何记录:
只有1个HTTP请求:
process
任何人都可以解释为什么组合这两个功能不起作用? Autocommit是1,我试图明确提交,但无济于事。