我需要管理经典数据库和大量 xls 文件之间的服务器上同步。
如果它们同步,我将通过数据库执行所有操作并且没有问题。
其中一些文件会定期添加到服务器,我需要同步它们。它们可能很少,但很长,有数十万行的顺序。
如果我发现新的,我就会开始同步过程。事实证明,同步过程的持续时间足够短,不会超过 PHP 在 1 个文件 30 秒后触发的最大执行时间。但是当我有更多文件时,它可能会超过它。
我无法覆盖 PHP 时间限制。
现在我有一个事务,如果上次文件同步失败则回滚。 并且必须重新加载页面,直到我看到同步失败/成功消息。 这可行,但一点也不太好。
选择:
- 使用 register_shutdown_function 打印页面的其余部分(可能吗?)并告诉重新加载
- 在接近时间限制时使用自定义脚本会发生同样的事情
- 有什么办法可以在后台完成同步吗?也许会通过以下方式注意到页面 也许是 Ajax ?
什么才是更合适的选择?还有第三种方法吗?
最佳答案
有一个很好的技巧可以绕过时间限制,但是如果操作不当,它可能会延迟您的服务器。基于这个脚本,我编写了纯 PHP CRON 替代方案。
您要做的就是使 HTTP 客户端断开连接,但保持脚本运行。这是最重要的 - 然后,脚本可以调用自身而不会卡在 istelf 上。
为此,发送 http header Content-Length 非常重要。
<?php
ignore_user_abort (true); //Tells PHP to ignore connection state
ob_start();
echo "Loop started\n";
$size = ob_get_length();
header("Content-Length: $size"); //Send exact output size to make sure client disconnects
header("Connection: close"); //Tells client to disconnect
ob_end_flush();
ob_flush();
flush(); //Clean all buffers
if(session_id()!="")
session_write_close(); //Close the session so that the user can use other scripts on the site
/*Here, the script runs even if client is connected*/
?>
现在,递归部分非常危险。您应该创建一个文件,告诉脚本它已经在运行以避免多线程。像这样:
if(file_exists("secure_key"))
exit;
else
file_put_contents("secure_key",time());
因为您说过您正在同步一些数据,所以您可能还需要一个文件(或MySql表)来存储有关同步过程的信息。这将可以通知用户有关请求进度的信息,也许可以使用 AJAX,就像您想要的那样。这将使整个应用程序看起来非常专业:)
您可能知道这一点,但如果您正在同步的是 FOR 或 WHILE 循环,则最好将开始时间保存在常量中,这样您就可以毫无问题地退出并保存:
define("STARTTIME",time()); //Right now
define("MAXTIME",ini_get('max_execution_time')); //Max execution time
define("SAFE_EXIT_TIME", 4); //4 seconds to save & quit
/*preparation*/
while(time()-(STARTTIME-SAFE_EXIT_TIME)<MAXTIME) {
/*Synchronize*/
}
unlink("secure_key"); //delete the antistuck file
get_headers(/*scriopt url*/); //call itself
exit; //quit
关于PHP持久脚本和最大执行时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14675828/