Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

jsarnowski / jsarnowski/blocksy-companion-pro   php

Repository URL to install this package:

Version: 1.8.76 

/ includes / managers / class-fs-clone-manager.php

<?php
    /**
     * @package   Freemius
     * @copyright Copyright (c) 2015, Freemius, Inc.
     * @license   https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
     * @author    Leo Fajardo (@leorw)
     * @since     2.5.0
     */

    if ( ! defined( 'ABSPATH' ) ) {
        exit;
    }

    /**
     * Manages the detection of clones and provides the logged-in WordPress user with options for manually resolving them.
     *
     * @since 2.5.0
     *
     * @property int    $clone_identification_timestamp
     * @property int    $temporary_duplicate_mode_selection_timestamp
     * @property int    $temporary_duplicate_notice_shown_timestamp
     * @property string $request_handler_id
     * @property int    $request_handler_timestamp
     * @property int    $request_handler_retries_count
     * @property bool   $hide_manual_resolution
     * @property array  $new_blog_install_map
     */
    class FS_Clone_Manager {
        /**
         * @var FS_Option_Manager
         */
        private $_storage;
        /**
         * @var FS_Option_Manager
         */
        private $_network_storage;
        /**
         * @var FS_Admin_Notices
         */
        private $_notices;
        /**
         * @var FS_Logger
         */
        protected $_logger;

        /**
         * @var int 3 minutes
         */
        const CLONE_RESOLUTION_MAX_EXECUTION_TIME = 180;
        /**
         * @var int
         */
        const CLONE_RESOLUTION_MAX_RETRIES = 3;
        /**
         * @var int
         */
        const TEMPORARY_DUPLICATE_PERIOD = WP_FS__TIME_WEEK_IN_SEC * 2;
        /**
         * @var string
         */
        const OPTION_NAME = 'clone_resolution';
        /**
         * @var string
         */
        const OPTION_MANAGER_NAME = 'clone_management';
        /**
         * @var string
         */
        const OPTION_TEMPORARY_DUPLICATE = 'temporary_duplicate';
        /**
         * @var string
         */
        const OPTION_LONG_TERM_DUPLICATE = 'long_term_duplicate';
        /**
         * @var string
         */
        const OPTION_NEW_HOME = 'new_home';

        #--------------------------------------------------------------------------------
        #region Singleton
        #--------------------------------------------------------------------------------

        /**
         * @var FS_Clone_Manager
         */
        private static $_instance;

        /**
         * @return FS_Clone_Manager
         */
        static function instance() {
            if ( ! isset( self::$_instance ) ) {
                self::$_instance = new self();
            }

            return self::$_instance;
        }

        #endregion

        private function __construct() {
            $this->_storage         = FS_Option_Manager::get_manager( WP_FS___OPTION_PREFIX . self::OPTION_MANAGER_NAME, true );
            $this->_network_storage = FS_Option_Manager::get_manager( WP_FS___OPTION_PREFIX . self::OPTION_MANAGER_NAME, true, true );

            $this->maybe_migrate_options();

            $this->_notices = FS_Admin_Notices::instance( 'global_clone_resolution_notices', '', '', true );
            $this->_logger  = FS_Logger::get_logger( WP_FS__SLUG . '_' . '_clone_manager', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
        }

        /**
         * Migrate clone resolution options from 2.5.0 array-based structure, to a new flat structure.
         *
         * The reason this logic is not in a separate migration script is that we want to be 100% sure data is migrated before any execution of clone logic.
         *
         * @todo Delete this one in the future.
         */
        private function maybe_migrate_options() {
            $storages = array(
                $this->_storage,
                $this->_network_storage
            );

            foreach ( $storages as $storage ) {
                $clone_data = $storage->get_option( self::OPTION_NAME );
                if ( is_array( $clone_data ) && ! empty( $clone_data ) ) {
                    foreach ( $clone_data as $key => $val ) {
                        if ( ! is_null( $val ) ) {
                            $storage->set_option( $key, $val );
                        }
                    }

                    $storage->unset_option( self::OPTION_NAME, true );
                }
            }
        }

        /**
         * @author Leo Fajardo (@leorw)
         * @since 2.5.0
         */
        function _init() {
            if ( is_admin() ) {
                if ( Freemius::is_admin_post() ) {
                    add_action( 'admin_post_fs_clone_resolution', array( $this, '_handle_clone_resolution' ) );
                }

                if ( Freemius::is_ajax() ) {
                    Freemius::add_ajax_action_static( 'handle_clone_resolution', array( $this, '_clone_resolution_action_ajax_handler' ) );
                } else {
                    if (
                        empty( $this->get_clone_identification_timestamp() ) &&
                        (
                            ! fs_is_network_admin() ||
                            ! ( $this->is_clone_resolution_options_notice_shown() || $this->is_temporary_duplicate_notice_shown() )
                        )
                    ) {
                        $this->hide_clone_admin_notices();
                    } else if ( ! Freemius::is_cron() && ! Freemius::is_admin_post() ) {
                        $this->try_resolve_clone_automatically();
                        $this->maybe_show_clone_admin_notice();

                        add_action( 'admin_footer', array( $this, '_add_clone_resolution_javascript' ) );
                    }
                }
            }
        }

        /**
         * Retrieves the timestamp that was stored when a clone was identified.
         *
         * @return int|null
         */
        function get_clone_identification_timestamp() {
            return $this->get_option( 'clone_identification_timestamp', true );
        }

        /**
         * @author Leo Fajardo (@leorw)
         * @since 2.5.1
         *
         * @param string $sdk_last_version
         */
        function maybe_update_clone_resolution_support_flag( $sdk_last_version ) {
            if ( null !== $this->hide_manual_resolution ) {
                return;
            }

            $this->hide_manual_resolution = (
                ! empty( $sdk_last_version ) &&
                version_compare( $sdk_last_version, '2.5.0', '<' )
            );
        }

        /**
         * Stores the time when a clone was identified.
         */
        function store_clone_identification_timestamp() {
            $this->clone_identification_timestamp = time();
        }

        /**
         * Retrieves the timestamp for the temporary duplicate mode's expiration.
         *
         * @return int
         */
        function get_temporary_duplicate_expiration_timestamp() {
            $temporary_duplicate_mode_start_timestamp = $this->was_temporary_duplicate_mode_selected() ?
                $this->temporary_duplicate_mode_selection_timestamp :
                $this->get_clone_identification_timestamp();

            return ( $temporary_duplicate_mode_start_timestamp + self::TEMPORARY_DUPLICATE_PERIOD );
        }

        /**
         * Determines if the SDK should handle clones. The SDK handles clones only up to 3 times with 3 min interval.
         *
         * @return bool
         */
        private function should_handle_clones() {
            if ( ! isset( $this->request_handler_timestamp ) ) {
                return true;
            }

            if ( $this->request_handler_retries_count >= self::CLONE_RESOLUTION_MAX_RETRIES ) {
                return false;
            }

            // Give the logic that handles clones enough time to finish (it is given 3 minutes for now).
            return ( time() > ( $this->request_handler_timestamp + self::CLONE_RESOLUTION_MAX_EXECUTION_TIME ) );
        }

        /**
         * @author Leo Fajardo (@leorw)
         * @since 2.5.1
         *
         * @return bool
         */
        function should_hide_manual_resolution() {
            return ( true === $this->hide_manual_resolution );
        }

        /**
         * Executes the clones handler logic if it should be executed, i.e., based on the return value of the should_handle_clones() method.
         *
         * @author Leo Fajardo (@leorw)
         * @since 2.5.0
         */
        function maybe_run_clone_resolution() {
            if ( ! $this->should_handle_clones() ) {
                return;
            }

            $this->request_handler_retries_count = isset( $this->request_handler_retries_count ) ?
                ( $this->request_handler_retries_count + 1 ) :
                1;

            $this->request_handler_timestamp = time();

            $handler_id               = ( rand() . microtime() );
            $this->request_handler_id = $handler_id;

            // Add cookies to trigger request with the same user access permissions.
            $cookies = array();
            foreach ( $_COOKIE as $name => $value ) {
                $cookies[] = new WP_Http_Cookie( array(
                    'name'  => $name,
                    'value' => $value,
                ) );
            }

            wp_remote_post(
                admin_url( 'admin-post.php' ),
                array(
                    'method'    => 'POST',
                    'body'      => array(
                        'action'     => 'fs_clone_resolution',
                        'handler_id' => $handler_id,
                    ),
                    'timeout'   => 0.01,
                    'blocking'  => false,
                    'sslverify' => false,
                    'cookies'   => $cookies,
                )
            );
        }

        /**
         * Executes the clones handler logic.
         *
         * @author Leo Fajardo (@leorw)
         * @since 2.5.0
         */
        function _handle_clone_resolution() {
            $handler_id = fs_request_get( 'handler_id' );

            if ( empty( $handler_id ) ) {
                return;
            }

            if (
                ! isset( $this->request_handler_id ) ||
                $this->request_handler_id !== $handler_id
            ) {
                return;
            }

            if ( ! $this->try_automatic_resolution() ) {
                $this->clear_temporary_duplicate_notice_shown_timestamp();
            }
        }

        #--------------------------------------------------------------------------------
        #region Automatic Clone Resolution
        #--------------------------------------------------------------------------------

        /**
         * @var array All installs cache.
         */
        private $all_installs;

        /**
         * Checks if a given instance's install is a clone of another subsite in the network.
         *
         * @author Vova Feldman (@svovaf)
         *
         * @return FS_Site
         */
        private function find_network_subsite_clone_install( Freemius $instance ) {
            if ( ! is_multisite() ) {
                // Not a multi-site network.
                return null;
            }

            if ( ! isset( $this->all_installs ) ) {
                $this->all_installs = Freemius::get_all_modules_sites();
            }

            // Check if there's another blog that has the same site.
            $module_type          = $instance->get_module_type();
            $sites_by_module_type = ! empty( $this->all_installs[ $module_type ] ) ?
                $this->all_installs[ $module_type ] :
                array();

            $slug          = $instance->get_slug();
Loading ...