【问题标题】:How can I prevent PHP from executing code multiple times?如何防止 PHP 多次执行代码?
【发布时间】:2012-03-18 18:04:08
【问题描述】:

我有一个带有按计划执行的备份脚本的 WordPress 插件。问题是,如果有人连续多次点击该页面,它可以多次执行备份脚本。关于如何防止多次处决有什么想法吗?

global $bwpsoptions;

        if ( get_transient( 'bit51_bwps_backup' ) === false ) {

            set_transient( 'bit51_bwps_backup', '1', 300 );

            if ( $bwpsoptions['backup_enabled'] == 1 ) {

                $nextbackup = $bwpsoptions['backup_next']; //get next schedule
                $lastbackup = $bwpsoptions['backup_last']; //get last backup

                switch ( $bwpsoptions['backup_interval'] ) { //schedule backup at appropriate time
                    case '0':
                        $next = 60 * 60 * $bwpsoptions['backup_time'];
                        break;
                    case '1':
                        $next = 60 * 60 * 24 * $bwpsoptions['backup_time'];
                        break;
                    case '2':
                        $next = 60 * 60 * 24 * 7  * $bwpsoptions['backup_time'];
                        break;
                }

                if ( ( $lastbackup == '' || $nextbackup < time() ) && get_transient( 'bit51_bwps_backup' ) === false ) {

                    $bwpsoptions['backup_last'] = time();

                    if ( $lastbackup == '' ) {

                        $bwpsoptions['backup_next'] = ( time() + $next );

                    } else {

                        $bwpsoptions['backup_next'] = ( $lastbackup + $next );

                    }


                    update_option( $this->primarysettings, $bwpsoptions );

                    $this->execute_backup(); //execute backup

                }

            }

        }

【问题讨论】:

  • 在数据库中设置一个字段表示时间,并计算,如果上次运行脚本的时间与当前时间的差值大于t,则不运行脚本。
  • 你在哪里填充$bwpsoptions?如果它不是来自外部来源,如数据库、文件、会话等,那么它将在下一页加载时被遗忘。

标签: php wordpress


【解决方案1】:
  • 在代码开头创建一个文件。
  • 代码运行完毕后删除文件。
  • 在代码的开头确保该文件在运行前不存在。

有点像 linux 中的 apt-get lock。

【讨论】:

  • 请求此脚本的速度有多快?
【解决方案2】:

如果您的网站非常繁忙并且基本的锁定机制无法正常工作(我个人无法想象,但哦,好吧!),您可以尝试使用 PHP 会话的垃圾收集器的解决方案。

只需随机选择一个介于 0 和 10 之间的数字,如果数字为 0,则进行备份。如果现在有 10 个用户几乎同时调用您的备份脚本,统计上只有一个用户会实际执行备份。

define("BACKUP_PROBABILITY", 10);
if (mt_rand(0, BACKUP_PROBABILITY) == 0)
    doBackup();

如果您的网站频繁访问,您可以增加最大值(10 个)。

如果在这 10 次访问中没有人获得 0,那么接下来的 10 名访问者将获得机会。

您当然需要某种锁定机制,而且您仍然有可能(尽管不合理)最终获得超过一个甚至 10 个备份。

我在 PHP 中发现了这个关于互斥体(锁)的问题。可能会有所帮助:PHP mutual exclusion (mutex)

【讨论】:

    【解决方案3】:

    将上次备份的日期/时间存储在服务器上的某个外部文件或数据库中,并检查该值!

    【讨论】:

    • 为什么不在单独的页面上有这个备份脚本?并在满足条件时调用开始/包含页面!
    • @ChrisWiegman,A 是“服务器上的外部文件或进入数据库”。如果您在 D/B 中使用 batchQ 行/表,您将不会遇到此问题。只需更新 time=requested_time 的备份时间戳行上的时间。如果此更新执行的受影响行 == 1,则此进程会执行备份,否则其他进程会击败它。
    【解决方案4】:

    我假设这个备份的东西在某处进行备份。

    所以检查最新备份的元数据,如果过去的创建时间不够远,就不要备份。

    我认为这不是 cron 作业有充分的理由吗?

    【讨论】:

    • 是的,这不是一项 cron 工作,因为太多人无法处理它。我必须在实际 cron 作业不可用且 wp-cron 不够灵活的环境中使用它。
    猜你喜欢
    • 2014-12-18
    • 2013-03-11
    • 1970-01-01
    • 1970-01-01
    • 2018-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    相关资源
    最近更新 更多