如何在执行长时间运行的PHP脚本时解决执行超时错误?

时间:2012-09-28 09:08:15

标签: php curl

我有一个包含20,000个电子邮件地址的数据库并且不断增加。我正在发送电子邮件100一次,然后使用CURL php打同一页,但页面仍然有最大的执行时间。我在共享(Hostgator)服务器上运行此php脚本。我该怎么做才能消除这个问题?

我正在通过以下方式执行此脚本:

exec("php-cli file.php > testoutput.php 2>&1 & echo $!", $output)

2 个答案:

答案 0 :(得分:1)

您可以在数据库中添加列(或辅助表),并将所有地址标记为最初“待处理”。

然后你的脚本可以:

- 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"

答案 1 :(得分:0)

PHP的时间限制可以通过PHP的set_time_limit()函数删除:

set_time_limit(0);

然而,这只能解决由于PHP本身注意到该过程花费太长时间而导致长时间运行的进程死亡的问题。虽然这是一个重要的步骤,但您还应该通过将工作分成更小的批次并确保您的代整件事。