我有一个包含 20,000 个电子邮件地址的数据库,并且还在不断增加。我一次发送 100 封电子邮件,然后使用 CURL php 访问同一页面,但该页面仍然获得最大执行超时。我在共享(Hostgator)服务器上运行这个 php 脚本。我应该怎么做才能消除这个问题?
我正在通过以下方式执行此脚本:
exec("php-cli file.php > testoutput.php 2>&1 & echo $!", $output)
您可以在数据库中添加一列(或辅助表),并将所有地址标记为最初“待处理”。
然后你的脚本可以:
- SELECT the number of worked addresses and total addresses
- display a progress bar
- SELECT the lowest 100, or 50, or N addresses yet to be worked
- send the emails and mark them worked
- issue a javascript to refresh itself.
然后客户端将看到一个进度条不断前进的页面,并且永远不会超时(只要“N”足够小)。
您也可以在 AJAX 中执行此操作,但这可能有点矫枉过正。
此外,您可以使用一些技巧(如果您还没有这样做的话)来加速操作。一种可能性是将多个地址“合并”为密件抄送:,如果电子邮件正文相同;这样一来,您就可以在一次通话中传递多条消息。注意不要超过任何密件抄送:限制您的 ISP 可能强制执行的内容。此策略在 ISP 端使用更多资源,因此请与他们核实。
另一种可能性(可以一起使用)是发送按域排序的电子邮件。如果可能,多台邮件服务器会尝试在一个连接中将电子邮件发送到同一台服务器,以节省资源和时间。如果您将一组电子邮件全部发送到同一个域,则可以使服务器更轻松。
在最后一种情况下,您会SELECT
发送这样的电子邮件:
SELECT * FROM addresses
WHERE (worked=0 AND active = 1)
ORDER BY SUBSTRING_INDEX(email, '@', -1)
LIMIT 20;
然后(使用 mysql 函数的示例 - PDO 更好),
while($tuple = mysql_fetch_assoc($exec))
{
if (send_mail_to(...))
$sent[] = $tuple['id'];
else $failed[] = $tuple['id'];
}
// Now mark both SENT and FAILED as worked
$sentm = implode(',', $sent);
$failm = implode(',', $failed);
// UPDATE addresses SET worked = 1 WHERE id IN ($sentm,$failm);
// UPDATE addresses SET active = 0 WHERE id IN ($failm);
如果您在 PHP 会话中保存了开始时间,您甚至可以显示一个漂亮的带仪表板的栏,例如
+--------------------+
|######## |
+--------------------+
40% processed
38% delivered
2% failed
Expected time remaining 5 min 17"
PHP 的时间限制可以通过 PHP 的set_time_limit()
函数移除:
set_time_limit(0);
但是,这只会解决由于 PHP 本身注意到该进程花费了太长时间而导致长时间运行的进程死亡的问题。虽然这是一个重要的步骤,但您还应该预测长时间运行的流程中的其他类型的故障,将工作分成更小的批次,并确保您的代码的结构允许在不重新运行的情况下恢复流程整件事情。