Your IP : 216.73.216.171


Current Path : /home/ereika83/public_html/wp-content/plugins/snapshot/lib/Snapshot/Helper/
Upload File :
Current File : /home/ereika83/public_html/wp-content/plugins/snapshot/lib/Snapshot/Helper/Utility.php

<?php // phpcs:ignore
/**
 * Snapshot Utility class
 *
 * @since 2.5
 *
 * @package Snapshot
 * @subpackage Helper
 */

if ( ! class_exists( 'Snapshot_Helper_Utility' ) ) {

	class Snapshot_Helper_Utility {

		const MIN_VIABLE_EXEC_TIME = 30;

		/**
		 * Get the database name for multisites.
		 *
		 * @return string
		 */
		public static function get_db_name() {

			global $wpdb;

			$db_class = get_class( $wpdb );

			if ( "m_wpdb" === $db_class ) {

				$test_sql   = "SELECT ID FROM " . $wpdb->prefix . "posts LIMIT 1";
				$query_data = $wpdb->analyze_query( $test_sql );
				if ( isset( $query_data['dataset'] ) ) {

					global $db_servers;
					if ( isset( $db_servers[ $query_data['dataset'] ][0]['name'] ) ) {
						return $db_servers[ $query_data['dataset'] ][0]['name'];
					}
				}
			} else {
				return DB_NAME;
			}
		}


		/**
		 * Utility function to grab the array of database tables for the site. This function
		 * is multisite aware in that is only grabs tables within the site's table prefix
		 * for example if on a multisite install the table prefix is wp_2_ then all other
		 * tables 'wp_' and 'wp_x_' will be ignored.
		 *
		 * The functions builds a multi array. On node of the array [wp]  will be the
		 * core WP tables. Another node [non] will be tables within that site which
		 * are not core tables. This could be table created by other plugins.
		 *
		 * @since 1.0.0
		 * @see wp_upload_dir()
		 *
		 * @param int $blog_id
		 * @param int $site_id
		 *
		 * @return array $tables multi-dimensional array of tables.
		 */
		public static function get_database_tables( $blog_id = 0, $site_id = 1 ) {

			global $wpdb;

			if ( ( ! $blog_id ) || ( 0 === $blog_id ) ) {
				$blog_id = $wpdb->blogid;
			}

			if ( is_multisite() ) {
				$blog_tables = get_site_transient( 'snapshot-blog-tables-' . $blog_id );
				if ( $blog_tables ) {
					return $blog_tables;
				}
			}

			$tables           = array();
			$tables['global'] = array();
			$tables['wp']     = array();
			$tables['non']    = array();
			$tables['other']  = array();
			$tables['error']  = array();
			$tables_all       = array();

			$blog_prefixes         = array();
			$blog_prefixes_lengths = array();

			$old_blog_id = $wpdb->blogid;

			if ( ( $blog_id ) && ( $blog_id !== $wpdb->blogid ) ) {
				$wpdb->set_blog_id( $blog_id );
			}

			if ( is_multisite() ) {

				$db_name = self::get_db_name();
				if ( ! $db_name ) {
					$db_name = DB_NAME;
				}
				$wpdb_prefix = str_replace( '_', '\_', $wpdb->prefix );

				if ( $wpdb->prefix === $wpdb->base_prefix ) {
					// Under Multisite and when the prefix and base prefox match we assume this is the primary site.
					// For example the default base prefix is 'wp_' and for the primary site the tables all start as 'wp_???'
					// for secondary site the prefix will be something like 'wp_2_', 'wp_3_'. So on the primary site tables
					// we cannot simply look for all tables starting with 'wp_' because this will include all sites. So
					// we use some MySQL REGEX to exclude matches.
					/*
					$show_all_tables_sql = "SELECT table_name FROM information_schema.tables
											WHERE table_schema = '". $db_name ."'
											AND table_name LIKE '". $wpdb->prefix ."%'
											AND table_name NOT REGEXP '^". $wpdb_prefix ."[[:digit:]]+\_'";
					*/
					$table_placeholder = "^{$wpdb_prefix}[[:digit:]]+\_";
					$tables_all_rows = $wpdb->query( $wpdb->prepare( "SELECT table_name FROM information_schema.tables
									WHERE table_schema = %s
									AND table_name NOT REGEXP %s", $db_name, $table_placeholder ) );

				} else {
					$table_placeholder = "{$wpdb_prefix}";
					$tables_all_rows = $wpdb->query( $wpdb->prepare( "SELECT table_name FROM information_schema.tables
									WHERE table_schema = %s
									AND table_name LIKE %s", $db_name, $table_placeholder . '%' ) );
				}
			} else {
				$db_name     = DB_NAME;
				$wpdb_prefix = str_replace( '_', '\_', $wpdb->prefix );

				/*
						$show_all_tables_sql = "SELECT table_name FROM information_schema.tables
												WHERE table_schema = '". $db_name ."'
												AND table_name LIKE '". $wpdb_prefix ."%'";
				*/
				$tables_all_rows = $wpdb->query( $wpdb->prepare( "SELECT table_name FROM information_schema.tables
								WHERE table_schema = %s", $db_name ) );
			}

				if ( $tables_all_rows ) {
					foreach ( $wpdb->last_result as $table_set ) {
						foreach ( $table_set as $table_name ) {
							// Use of esc_sql() instead of $wpdb->prepare() because of backticks in query.
							$table_structure = $wpdb->query( esc_sql( "DESCRIBE `{$table_name}`; " ) );
							if ( empty( $table_structure ) ) {
								continue;
							}
							$tables_all[ $table_name ] = $table_name;
						}
					}
				}

			if ( count( $tables_all ) ) {

				// Get a list of all WordPress known tables for the selected blog_id
				$tables_wp = $wpdb->tables( 'all' );
				//echo "tables_wp<pre>"; print_r($tables_wp); echo "</pre>";

				// The 'non' tables are the difference between the all and wp table sets
				$tables['non'] = array_diff( $tables_all, $tables_wp );
				$tables['wp']  = array_intersect( $tables_all, $tables_wp );

				foreach ( $tables['non'] as $_idx => $table ) {
					if ( substr( $table, 0, 3 ) !== "wp_" ) {
						$tables['other'][ $_idx ] = $table;
						unset( $tables['non'][ $_idx ] );
					}
				}

				if ( is_multisite() ) {
					if ( ! is_main_site( $blog_id ) ) {
						if ( ( isset( $wpdb->global_tables ) ) && ( count( $wpdb->global_tables ) ) ) {
							foreach ( $wpdb->global_tables as $global_table ) {
								$table_name = $wpdb->base_prefix . $global_table;
								//echo "table_name[". $table_name ."]<br />";
								$tables['global'][ $table_name ] = $table_name;
							}
						}
					}
				}
				//echo "tables<pre>"; print_r($tables); echo "</pre>";
			}

			// Now for each set set want to strip off the table prefix from the name
			// so when they are displayed they take up less room.

			if ( isset( $tables['global'] ) ) {
				if ( count( $tables['global'] ) ) {
					ksort( $tables['global'] );
				}
			}

			if ( isset( $tables['wp'] ) ) {
				if ( count( $tables['wp'] ) ) {
					ksort( $tables['wp'] );
				}
			}

			if ( isset( $tables['non'] ) ) {
				if ( count( $tables['non'] ) ) {
					ksort( $tables['non'] );
				}
			}

			if ( isset( $tables['other'] ) ) {
				if ( count( $tables['other'] ) ) {
					ksort( $tables['other'] );
				}
			}

			//echo "tables<pre>"; print_r($tables); echo "</pre>";

			if ( $old_blog_id !== $wpdb->blogid ) {
				$wpdb->set_blog_id( $old_blog_id );
			}

			if ( is_multisite() ) {
				set_transient( 'snapshot-blog-tables-' . $blog_id, $tables, 300 );
			}

			return $tables;
		}

		/**
		 * @param $table_name
		 * @param int $blog_id
		 * @param int $site_id
		 *
		 * @return mixed
		 */
		public static function get_table_meta( $table_name, $blog_id = 0, $site_id = 1 ) {
			global $wpdb;

			if ( ( $blog_id ) && ( $blog_id !== $wpdb->blogid ) ) {
				$wpdb->set_blog_id( $blog_id );
			}

			if ( is_multisite() ) {
				$db_name = self::get_db_name();
				if ( ! $db_name ) {
					$db_name = DB_NAME;
				}
				$wpdb_prefix = str_replace( '_', '\_', $wpdb->prefix );
			} else {
				$db_name     = DB_NAME;
				$wpdb_prefix = str_replace( '_', '\_', $wpdb->prefix );
			}

			$result = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM information_schema.TABLES WHERE table_schema = %s AND table_name = %s", $db_name, $table_name ) );

			//echo "result<pre>"; print_r($result); echo "</pre>";
			return $result;
		}

		/**
		 * Utility function to determine all blogs under a Multisite install
		 *
		 * @since 1.0.2
		 *
		 * @param bool $show_counts_only
		 *
		 * @return array|bool|int|mixed
		 */
		public static function get_blogs( $show_counts_only = false ) {

			global $wpdb;

			$archived = '0';
			$spam = 0;
			$deleted = 0;

			if ( true === $show_counts_only ) {

				$result = $wpdb->get_row( $wpdb->prepare( "SELECT count(blog_id) as blogs_count FROM $wpdb->blogs WHERE archived = %s AND spam = %d AND deleted = %d", $archived, $spam, $deleted ) );
				if ( isset( $result->blogs_count ) ) {
					return $result->blogs_count;
				} else {
					return 0;
				}
			} else {
				$blogs = wp_cache_get( 'snapshot-blogs', 'snapshot-plugin' );
				if ( $blogs ) {
					return $blogs;
				}

				if ( ( is_multisite() ) && ( is_network_admin() ) ) {

					$blog_ids = $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE archived = %s AND spam = %d AND deleted = %d", $archived, $spam, $deleted ) );
					//echo "blog_ids<pre>"; print_r($blog_ids); echo "</pre>";
					if ( $blog_ids ) {
						$blogs = array();
						foreach ( $blog_ids as $blog_id ) {
							$blogs[ $blog_id ] = get_blog_details( $blog_id );
						}
						wp_cache_set( 'snapshot-blogs', $blogs, 'snapshot-plugin' );

						return $blogs;
					}
				}
			}
		}


		/**
		 * Utility function to generate an 8 character checksum for a filename. This is to make the filename unique.
		 *
		 * @since 1.0.2
		 *
		 * @param $file
		 *
		 * @return int|string
		 */
		public static function get_file_checksum( $file ) {

			$checksum = '';
			if ( function_exists( 'sha1_file' ) ) {
				$checksum = sha1_file( $file );
			} else {
				$checksum = rand( 8, 8 );
			}

			if ( ! $checksum ) {
				$checksum = "00000000";
			}

			if ( ( $checksum ) && ( strlen( $checksum ) > 8 ) ) {
				$checksum = substr( $checksum, 0, 8 );
			}

			return $checksum;
		}


		/**
		 * Get current blog site's theme (Works on single and multisite).
		 *
		 * Uses 'template' option for WP 3.4+ and 'current_theme' for older versions.
		 *
		 * @param int $blog_id
		 *
		 * @return mixed|void
		 */
		public static function get_current_theme( $blog_id = 0 ) {

			if ( is_multisite() ) {
				$current_theme = get_blog_option( $blog_id, 'template' );
				if ( empty ( $current_theme ) ) {
					$current_theme = get_blog_option( $blog_id, 'current_theme' );
				}
			} else {
				$current_theme = get_option( 'template' );
				if ( empty ( $current_theme ) ) {
					$current_theme = get_option( 'current_theme' );
				}
			}

			return $current_theme;
		}

		/**
		 * Utility function to get a list of allowed/active theme for the site.
		 *
		 * @since 1.0.0
		 *
		 * @param int $blog_id
		 *
		 * @return Array
		 */
		public static function get_blog_active_themes( $blog_id = 0 ) {

			// Get All themes in the system.
			$themes_all = wp_get_themes();

			/* The get_themes returns an unusable array. So we need to rework it to be able to
			   compare to the array returned from allowedthemes */
			foreach ( $themes_all as $themes_all_key => $themes_all_set ) {
				unset( $themes_all[ $themes_all_key ] );
				$themes_all[ $themes_all_set['Stylesheet'] ] = $themes_all_set['Name'];
			}

			if ( is_multisite() ) {

				//$allowed_themes = wpmu_get_blog_allowedthemes( $blog_id );
				$allowed_themes = WP_Theme::get_allowed_on_site( $blog_id );

				$themes_blog = get_blog_option( $blog_id, 'allowedthemes' );
				if ( ! $themes_blog ) {
					$themes_blog = array();
				}

				//$site_allowed_themes = get_site_allowed_themes();
				$site_allowed_themes = WP_Theme::get_allowed_on_network();
				if ( ! $site_allowed_themes ) {
					$site_allowed_themes = array();
				}

				$themes_blog = array_merge( $themes_blog, $site_allowed_themes );

				if ( ( isset( $themes_blog ) ) && ( isset( $themes_all ) ) ) {
					foreach ( $themes_all as $themes_all_key => $themes_all_name ) {
						if ( ! isset( $themes_blog[ $themes_all_key ] ) ) {
							unset( $themes_all[ $themes_all_key ] );
						}
					}
					//echo "themes_all<pre>"; print_r($themes_all); echo "</pre>";
					asort( $themes_all );

					return $themes_all;
				}

			} else {
				return $themes_all;
			}
		}

		/**
		 * Get the user's name.
		 *
		 * First try display_name, then user_nicename else user_login.
		 *
		 * @since 1.0.0
		 *
		 * @param $user_id
		 *
		 * @return string
		 */
		public static function get_user_name( $user_id ) {

			$user_name = get_the_author_meta( 'display_name', intval( $user_id ) );

			if ( ! $user_name ) {
				$user_name = get_the_author_meta( 'user_nicename', intval( $user_id ) );
			}

			if ( ! $user_name ) {
				$user_name = get_the_author_meta( 'user_login', intval( $user_id ) );
			}

			return $user_name;
		}

		/**
		 * Utility function to check if we can adjust the server PHP timeout
		 *
		 * @since 1.0.0
		 * @return bool
		 */
		public static function check_server_timeout() {
			$current_timeout = ini_get( 'max_execution_time' );
			$current_timeout = intval( $current_timeout );

			// If the max execution time is zero (means no timeout). We leave it.
			if ( 0 === $current_timeout ) {
				return true;
			}

			// Else we try to set the timeout to some other value. If success we are golden.
			$new_timeout = $current_timeout;
			@set_time_limit(0); //phpcs:ignore
			$new_timeout = ini_get( 'max_execution_time' );
			$new_timeout = intval( $new_timeout );

			if (0 === $new_timeout) {
				return true;
			}

			// Finally, if we cannot adjust the timeout and the current timeout is less than 30 seconds we throw a warning to the user.
			return $current_timeout > self::MIN_VIABLE_EXEC_TIME;
		}

		/**
		 * Utility function to build the display of a timestamp into the date time format.
		 *
		 * @since 1.0.0
		 *
		 * @param int $timestamp UNIX timestamp from time()
		 * @param string $format
		 *
		 * @return string
		 */
		public static function show_date_time( $timestamp, $format = '' ) {

			if ( ! $format ) {
				$format = get_option( 'date_format' );
				$format .= _x( ' @ ', 'date time sep', SNAPSHOT_I18N_DOMAIN );
				$format .= get_option( 'time_format' );
			}

			$gmt_offset = get_option( 'gmt_offset' ) ? get_option( 'gmt_offset' ) : 0;
			$timestamp  = $timestamp + ( $gmt_offset * 3600 );

			return date_i18n( $format, $timestamp );
		}

		/**
		 * Utility function to build the duration of a snapshots.
		 *
		 * @param $interval
		 * @param $interval_offset
		 *
		 * @return false|string
		 */
		public static function show_duration( $interval, $interval_offset ) {

			if ( ! empty( $interval ) && ! empty( $interval_offset ) ) {
				if ( isset( $interval_offset[ $interval ]['tm_wday'] ) ) {
					return date( 'l', strtotime( 'Sunday + ' . $interval_offset[ $interval ]['tm_wday'] . ' Days' ) );
				}
			}

			return '';
		}

		/**
		 * Utility function recursively scan a folder and build an array of it's contents
		 *
		 * @since 1.0.2
		 *
		 * @param string $base Where to start.
		 *
		 * @return array
		 */
		public static function scandir( $base = '' ) {
			if ( ! defined('SNAPSHOT_IGNORE_SYMLINKS') || SNAPSHOT_IGNORE_SYMLINKS === true) {
				if ( is_link ( $base ) )
					return array();
			}

			if ( ( ! $base ) || ( ! strlen( $base ) ) ) {
				return array();
			}

			if ( ! file_exists( $base ) ) {
				return array();
			}

			self::check_server_timeout();

			$result = scandir($base);
			$data = !empty($result) ? array_diff( $result, array( '.', '..' ) ) : array();

			$subs = array();
			foreach ( $data as $key => $value ) :
				if ( is_dir( $base . '/' . $value ) ) :
					unset( $data[ $key ] );
					$subs[] = self::scandir( $base . '/' . $value );
				elseif ( is_file( $base . '/' . $value ) ) :
					$data[ $key ] = $base . '/' . $value;
				endif;
			endforeach;

			if ( count( $subs ) ) {
				foreach ( $subs as $sub ) {
					$data = array_merge( $data, $sub );
				}
			}

			return $data;
		}

		/**
		 * Utility function to break up a given table rows into segments based on the Settings size for Segments.
		 *
		 * Given a database table with 80,000 rows and a segment size of 1000 the returned $table_set will
		 * be an array of nodes. Each node will contain information about the stating row and number of
		 * segment (itself). Also total rows and total segments for this table.
		 *
		 * @since 1.0.2
		 *
		 * @param $table_name
		 * @param int $segmentSize
		 * @param string $where
		 *
		 * @return array
		 */
		public static function get_table_segments( $table_name, $segmentSize = 1000, $where = '' ) {

			global $wpdb;

			$table_set               = array();
			$table_set['table_name'] = $table_name;
			$table_set['rows_total'] = 0;
			$table_set['segments']   = array();

			$segment_set = array();

			// Use of esc_sql() instead of $wpdb->prepare() because of backticks in query.
			$table_data = $wpdb->get_row( esc_sql( "SELECT count(*) as total_rows FROM `{$table_name}` {$where}; " ) );
			if ( ( isset( $table_data->total_rows ) ) && intval( $table_data->total_rows ) ) {

				$last_rows                 = 0;
				$segment_set['rows_start'] = 0;
				$segment_set['rows_end']   = 0;

				$total_rows              = intval( $table_data->total_rows );
				$table_set['rows_total'] = $total_rows;

				while ( $total_rows > 0 ) {

					if ( $total_rows < $segmentSize ) {
						$segment_set['rows_start'] = intval( $last_rows );
						$segment_set['rows_end']   = intval( $total_rows );
						$table_set['segments'][]   = $segment_set;

						break;
					}

					$segment_set['rows_start'] = intval( $last_rows );
					$segment_set['rows_end']   = $segmentSize;
					$last_rows                 = $last_rows + $segmentSize;

					$table_set['segments'][] = $segment_set;

					$total_rows -= $segmentSize;
				}
			}

			return $table_set;
		}

		/**
		 * Utility function to add some custom schedule intervals to the default WordPress schedules.
		 *
		 * @since 1.0.2
		 *
		 * @param $schedules Passed in by WordPress. The current array of schedules.
		 *
		 * @return mixed $schedules And updated list containing our custom items.
		 */
		public static function add_cron_schedules( $schedules ) {

			$snapshot_schedules = array(
				'snapshot-5minutes' => array(
					'interval' => 60 * 5,
					'display'  => __( 'Every 5 Minutes', SNAPSHOT_I18N_DOMAIN ),
				),
				'snapshot-15minutes' => array(
					'interval' => 60 * 15,
					'display'  => __( 'Every 15 Minutes', SNAPSHOT_I18N_DOMAIN ),
				),
				'snapshot-30minutes' => array(
					'interval' => 60 * 30,
					'display'  => __( 'Every 30 Minutes', SNAPSHOT_I18N_DOMAIN ),
				),
				'snapshot-hourly' => array(
					'interval' => 60 * 60,
					'display'  => __( 'Once Hourly', SNAPSHOT_I18N_DOMAIN ),
				),
				'snapshot-daily' => array(
					'interval' => 1 * 24 * 60 * 60,                //	86,400
					'display'  => __( 'Daily', SNAPSHOT_I18N_DOMAIN ),
				),
				'snapshot-twicedaily' => array(
					'interval' => 1 * 12 * 60 * 60,                // 43,200
					'display'  => __( 'Twice Daily', SNAPSHOT_I18N_DOMAIN ),
				),
				'snapshot-weekly' => array(
					'interval' => 7 * 24 * 60 * 60,                // 604,800
					'display'  => __( 'Weekly', SNAPSHOT_I18N_DOMAIN ),
				),
				'snapshot-twiceweekly' => array(
					'interval' => 7 * 12 * 60 * 60,                // 302,400
					'display'  => __( 'Twice Weekly', SNAPSHOT_I18N_DOMAIN ),
				),
				'snapshot-monthly' => array(
					'interval' => 30 * 24 * 60 * 60,                // 2,592,000
					'display'  => __( 'Monthly', SNAPSHOT_I18N_DOMAIN ),
				),
				'snapshot-twicemonthly' => array(
					'interval' => 15 * 24 * 60 * 60,                // 1,296,000
					'display'  => __( 'Twice Monthly', SNAPSHOT_I18N_DOMAIN ),
				),
			);

			$schedules = array_merge( $snapshot_schedules, $schedules );
			return $schedules;
		}

		/**
		 * Utility function to get the pretty display text for a WordPress schedule interval
		 *
		 * @since 1.0.2
		 *
		 * @param $sched_key Key to item in wp_get_schedules array
		 *
		 * @return string Display text for the scheduled item. If found.
		 */
		public static function get_sched_display( $sched_key ) {

			$scheds = (array) wp_get_schedules();

			if ( isset( $scheds[ $sched_key ] ) ) {
				return $scheds[ $sched_key ]['display'];
			}

		}

		/**
		 * Utility function to get the interval for a WordPress schedule.
		 *
		 * @since 1.0.2
		 *
		 * @param $sched_key Key to item in wp_get_schedules array
		 *
		 * @return mixed
		 */
		public static function get_sched_interval( $sched_key ) {

			$scheds = (array) wp_get_schedules();

			if ( isset( $scheds[ $sched_key ] ) ) {
				return $scheds[ $sched_key ]['interval'];
			}

		}

		/**
		 * Calculate interval offset.
		 * @since 1.0.2
		 *
		 * @param string $interval
		 * @param string $interval_offset
		 *
		 * @return int|number
		 */
		public static function calculate_interval_offset_time( $interval = '', $interval_offset = '' ) {

			if ( ( empty( $interval ) ) || ( empty( $interval_offset ) ) ) {
				return 0;
			}

			$current_timestamp = time() + ( get_option( 'gmt_offset' ) * 3600 );
			$current_localtime = localtime( $current_timestamp, true );

			$diff_timestamp = $current_timestamp;

			$_offset_seconds = 0;

			if ( ( "snapshot-hourly" === $interval ) && ( isset( $interval_offset['snapshot-hourly'] ) ) ) {
				$_offset = $interval_offset['snapshot-hourly'];

			} else if ( ( ( "snapshot-daily" === $interval ) || ( "snapshot-twicedaily" === $interval ) ) && ( isset( $interval_offset['snapshot-daily'] ) ) ) {
				$_offset = $interval_offset['snapshot-daily'];
			} else if ( ( ( "snapshot-weekly" === $interval ) || ( "snapshot-twiceweekly" === $interval ) ) && ( isset( $interval_offset['snapshot-weekly'] ) ) ) {
				$_offset = $interval_offset['snapshot-weekly'];
			} else if ( ( ( "snapshot-monthly" === $interval ) || ( "snapshot-twicemonthly" === $interval ) ) && ( isset( $interval_offset['snapshot-monthly'] ) ) ) {
				$_offset = $interval_offset['snapshot-monthly'];
			} else {
				return $_offset_seconds;
			}

			//echo "offset<pre>"; print_r($_offset); echo "</pre>";

			if ( isset( $_offset['tm_min'] ) ) {

				$_tm_min = intval( $_offset['tm_min'] ) - $current_localtime['tm_min'];
				//echo "_tm_min=[". $_tm_min ."]<br />";
				if ( $_tm_min > 0 ) {
					$_offset_seconds += intval( $_tm_min ) * 60;
				} else if ( $_tm_min < 0 ) {
					$_offset_seconds -= abs( $_tm_min ) * 60;
				}
			}

			if ( isset( $_offset['tm_hour'] ) ) {

				$_tm_hour = intval( $_offset['tm_hour'] ) - $current_localtime['tm_hour'];
				//echo "_tm_hour=[". $_tm_hour ."]<br />";

				if ( $_tm_hour > 0 ) {
					$_offset_seconds += intval( $_tm_hour ) * 60 * 60;
				} else if ( $_tm_hour < 0 ) {
					$_offset_seconds -= abs( $_tm_hour ) * 60 * 60;
				}
			}

			if ( isset( $_offset['tm_wday'] ) ) {

				$_tm_wday = intval( $_offset['tm_wday'] ) - $current_localtime['tm_wday'];
				//echo "_tm_wday=[". $_tm_wday ."]<br />";

				if ( $_tm_wday > 0 ) {
					$_offset_seconds += intval( $_tm_wday ) * 24 * 60 * 60;
				} else if ( $_tm_wday < 0 ) {
					$_offset_seconds -= abs( $_tm_wday ) * 24 * 60 * 60;
				}
			}

			if ( isset( $_offset['tm_mday'] ) ) {

				$_tm_mday = intval( $_offset['tm_mday'] ) - $current_localtime['tm_mday'];
				//echo "_tm_mday=[". $_tm_mday ."]<br />";

				if ( $_tm_mday > 0 ) {
					$_offset_seconds += intval( $_tm_mday ) * 24 * 60 * 60;
				} else if ( $_tm_mday < 0 ) {
					$_offset_seconds -= abs( $_tm_mday ) * 24 * 60 * 60;
				}
			}

			if ( $_offset_seconds < 0 ) {

				$_sched_interval = self::get_sched_interval( $interval );
				$_offset_seconds += $_sched_interval;
			}

			//echo "next data: ". date('Y-m-d h:i', $current_timestamp + $_offset_seconds) ."<br />";
			//return $current_timestamp + $_offset_seconds;
			return $_offset_seconds;
		}

		/**
		 * Utility function to parse the snapshot entry backup log file into an array. The array break points
		 * are based on the string '-------------' which divides the different backup attempts.
		 *
		 * @todo: $snapshot_filename
		 *
		 * @since 1.0.2
		 *
		 * @param $backupLogFileFull
		 *
		 * @return array
		 */
		public static function get_archive_log_entries( $backupLogFileFull ) {

			if ( file_exists( $backupLogFileFull ) ) {

				$log_content = file( $backupLogFileFull );
				if ( $log_content ) {

					$log_entries     = array();
					$log_content_tmp = array();
					foreach ( $log_content as $log_content_line ) {

						$log_content_line = trim( $log_content_line );
						if ( ! strlen( $log_content_line ) ) {
							continue;
						}
						if ( strstr( $log_content_line, "----------" ) !== false ) {
							$log_entries[ $snapshot_filename ] = $log_content_tmp;
							unset( $log_content_tmp );
							$log_content_tmp = array();
							continue;
						}

						$log_content_tmp[] = $log_content_line;

						if ( strstr( $log_content_line, "finish:" ) !== false ) {
							$pos_col           = strrpos( $log_content_line, ':' );
							$snapshot_filename = substr( $log_content_line, $pos_col + 1 );
							$snapshot_filename = trim( $snapshot_filename );
						}
					}
					//echo "log_entries<pre>"; print_r($log_entries); echo "</pre>";
					if ( count( $log_entries ) ) {
						return $log_entries;
					}
				}
			}
		}

		/**
		 * Utility function to recursively remove directories.
		 *
		 * @since 1.0.3
		 * @see
		 *
		 * @param none
		 *
		 * @return none
		 */
		public static function recursive_rmdir( $dir ) {
			if ( is_dir( $dir ) ) {
				$objects = scandir( $dir );

				foreach ( $objects as $object ) {
					if ( "." !== $object && ".." !== $object ) {
						if ( filetype( $dir . "/" . $object ) === "dir" ) {
							self::recursive_rmdir( $dir . "/" . $object );
						} else {
							unlink( $dir . "/" . $object );
						}
					}
				}
				reset( $objects );
				rmdir( $dir );
			}
		}

		/**
		 * Utility function to remove remaining sql files.
		 *
		 * @since 3.2.0.2
		 *
		 * @param string $dir Directory from where the sql files are to be removed.
		 *
		 * @return none
		 */
		public static function remove_sql_files( $dir ) {
			if ( is_dir( $dir ) ) {
				$dir = trailingslashit( wp_normalize_path( $dir ) );
				$sql_files = glob($dir . '*.sql');

				foreach ( $sql_files as $sql_file) {
					unlink( $sql_file );
				}
			}
		}

		/**
		 * Utility function to remove the snapshot manifest.
		 *
		 * @since 3.2.0.2
		 *
		 * @param string $dir Directory from where the manifest file is to be removed.
		 *
		 * @return none
		 */
		public static function remove_manifest( $dir ) {
			if ( is_dir( $dir ) ) {
				$dir = trailingslashit( wp_normalize_path( $dir ) );
				$manifest_file = $dir . 'snapshot_manifest.txt';

				if ( file_exists( $manifest_file ) ) {
					unlink( $manifest_file );
				}
			}
		}

		/**
		 * Utility function to access the latest item's data set.
		 *
		 * @since 1.0.4
		 *
		 * @param $data_items
		 *
		 * @return mixed
		 */
		public static function latest_data_item( $data_items ) {
			krsort( $data_items );
			foreach ( $data_items as $data_key => $data_item ) {
				return $data_item;
			}
		}

		/**
		 * Utility function to access the latest backup ever.
		 *
		 * @since 1.0.4
		 *
		 * @param $data_items
		 *
		 * @return mixed
		 */
		public static function latest_backup( $items ) {
			$last_files = array();

			foreach ($items as $key => $backup) {
				if( isset( $backup['data'] ) ){
					$data_backup = self::latest_data_item( $backup['data'] );
						if( isset( $data_backup["timestamp"] ) ) {
							$last_files[$data_backup["timestamp"]] = $data_backup;
						}
					}
				}

			krsort( $last_files );
			return reset( $last_files );
		}

		/**
		 * Utility function Add index.php and .htaccess files to archive folders
		 *
		 * @since 1.0.5
		 *
		 * @param string $folder Destination folder to apply security files to
		 */
		public static function secure_folder( $folder ) {

			if ( ! file_exists( trailingslashit( $folder ) . "index.php" ) ) {
				global $wp_filesystem;

				if( self::connect_fs() ) {
					$wp_filesystem->put_contents( trailingslashit( $folder ) . "index.php", "<?php // Silence is golden. ?>", FS_CHMOD_FILE );
				} else {
					return new WP_Error("filesystem_error", "Cannot initialize filesystem");
				}

			}
			if ( ! file_exists( trailingslashit( $folder ) . ".htaccess" ) ) {
				global $wp_filesystem;

				if( self::connect_fs() ) {
					$wp_filesystem->put_contents( trailingslashit( $folder ) . ".htaccess", "IndexIgnore *\r\nOptions -Indexes`\r\n", FS_CHMOD_FILE );
				} else {
					return new WP_Error("filesystem_error", "Cannot initialize filesystem");
				}
			}

			if ( ! file_exists( trailingslashit( $folder ) . "CACHEDIR.TAG" ) ) {
				global $wp_filesystem;

				if( self::connect_fs() ) {
					$wp_filesystem->put_contents( trailingslashit( $folder ) . "CACHEDIR.TAG", "", FS_CHMOD_FILE );
				} else {
					return new WP_Error("filesystem_error", "Cannot initialize filesystem");
				}
			}

		}

		/**
		 * Get the upload path of the blog.
		 *
		 * @param int $switched_blog_id
		 * @param string $key
		 *
		 * @return array|mixed
		 */
		public static function get_blog_upload_path( $switched_blog_id = 0, $key = 'basedir' ) {
			global $blog_id;
			$home_path = apply_filters( 'snapshot_home_path', get_home_path() );

			//echo "switched_blog_id[". $switched_blog_id ."] key[". $key ."]<br />";
			if ( is_multisite() ) {
				$blog_id_org = $blog_id;

				switch_to_blog( $switched_blog_id );
				$uploads = wp_upload_dir();

				if ( "basedir" === $key ) {
					if ( isset( $uploads['basedir'] ) ) {
						$upload_path = str_replace( '\\', '/', $uploads['basedir'] );
						$upload_path = str_replace( $home_path, '', $upload_path );
					}
				} else if ( "baseurl" === $key ) {

					if ( isset( $uploads['baseurl'] ) ) {
						$upload_path        = array();
						$upload_path['raw'] = str_replace( '\\', '/', $uploads['baseurl'] );

						if ( ( defined( 'UPLOADS' ) ) && ( UPLOADS !== '' ) ) {
							$UPLOADS                = str_replace( '/' . $blog_id_org . '/', '/' . $switched_blog_id . '/', untrailingslashit( UPLOADS ) );
							$upload_path['rewrite'] = str_replace( $UPLOADS, 'files', $upload_path['raw'] );
							$upload_path['rewrite'] = str_replace( get_option( 'siteurl' ) . '/', '', $upload_path['rewrite'] );
						}
						$upload_path['raw'] = str_replace( get_option( 'siteurl' ) . '/', '', $upload_path['raw'] );
					}
				}
				restore_current_blog();

			} else {
				$uploads = wp_upload_dir();
				if ( "basedir" === $key ) {
					if ( isset( $uploads['basedir'] ) ) {
						$upload_path = str_replace( '\\', '/', $uploads['basedir'] );
						$upload_path = str_replace( $home_path, '', $upload_path );
					}
				} else if ( "baseurl" === $key ) {
					if ( isset( $uploads['baseurl'] ) ) {
						$upload_path = str_replace( get_site_url(), '', $uploads['baseurl'] );
					}
				}
			}

			if ( "basedir" === $key ) {
				if ( ! $upload_path ) {
					$upload_path = trailingslashit( WP_CONTENT_DIR ) . "uploads";
					$upload_path = str_replace( '\\', '/', $upload_path );
					$upload_path = str_replace( $home_path, '', $upload_path );
				}
			}

			return $upload_path;
		}

		/**
		 * @param $item
		 *
		 * @return array
		 */
		public static function get_tables_sections_display( $item ) {

			$tables_sections_out           = array();
			$tables_sections_out['click']  = '';
			$tables_sections_out['hidden'] = '';

			//echo "item<pre>"; print_r($item); echo "</pre>";

			if ( isset( $item['tables-option'] ) ) {
				$tables_sections_out['click'] .= __( 'Tables:', SNAPSHOT_I18N_DOMAIN ) . " (" . $item['tables-option'] . ")";

				if ( isset( $item['tables-sections'] ) ) {

					foreach ( $item['tables-sections'] as $section_key => $section_tables ) {

						if ( "wp" === $section_key ) {
							$section_label = __( 'core', SNAPSHOT_I18N_DOMAIN );
						} else if ( "non" === $section_key ) {
							$section_label = __( 'non-core', SNAPSHOT_I18N_DOMAIN );
						} else if ( "other" === $section_key ) {
							$section_label = __( 'other', SNAPSHOT_I18N_DOMAIN );
						} else if ( "error" === $section_key ) {
							$section_label = __( 'error', SNAPSHOT_I18N_DOMAIN );
						} else if ( "global" === $section_key ) {
							$section_label = __( 'global', SNAPSHOT_I18N_DOMAIN );
						}

						if ( count( $section_tables ) ) {
							if ( strlen( $tables_sections_out['click'] ) ) {
								$tables_sections_out['click'] .= ", ";
							}
							$tables_sections_out['click'] .= '<a class="snapshot-list-table-' . $section_key . '-show" href="#">' . sprintf( '%d %s',
									count( $section_tables ), $section_label ) . '</a>';

							$tables_sections_out['hidden'] .= '<p style="display: none" class="snapshot-list-table-' . $section_key . '-container">' .
							                                  implode( ', ', $section_tables ) . '</p>';
						}
					}
				}
			}

			return $tables_sections_out;
		}

		/**
		 * @param $data_item
		 *
		 * @return array
		 */
		public static function get_files_sections_display( $data_item ) {

			$files_sections_out           = array();
			$files_sections_out['click']  = '';
			$files_sections_out['hidden'] = '';

			if ( isset( $data_item['files-option'] ) ) {
				$files_sections_out['click'] .= __( 'Files:', SNAPSHOT_I18N_DOMAIN ) . ' (';
				$files_sections_out['click'] .= $data_item['files-option'] . ") ";

				//if ((isset($data_item['files-count'])) && (intval($data_item['files-count']))) {
				//	$files_sections_out['click'] .= ' '. $data_item['files-count'] .' ';
				//}

				if ( isset( $data_item['files-sections'] ) ) {
					$sections_str = '';
					foreach ( $data_item['files-sections'] as $section ) {
						if ( strlen( $sections_str ) ) {
							$sections_str .= ", ";
						}
						$sections_str .= ucwords( $section );
					}
					$files_sections_out['click'] .= $sections_str;
				}
			}

			return $files_sections_out;
		}

		/**
		 * Read a file and display its content chunk by chunk.
		 *
		 * @param $filename
		 * @param bool $retbytes
		 *
		 * @todo DO WE REALLY NEED TO ECHO THE BUFFER?
		 *
		 * @return bool|int
		 */
		public static function file_output_stream_chunked( $filename, $retbytes = true ) {

			$CHUNK_SIZE = 1024 * 1024; // Size (in bytes) of tiles chunk

			$buffer = '';
			$cnt    = 0;

			$handle = fopen( $filename, 'rb' ); // phpcs:ignore
			if ( false === $handle ) {
				return false;
			}

			while ( ! feof( $handle ) ) {
				$buffer = fread( $handle, $CHUNK_SIZE ); // phpcs:ignore
				echo $buffer; // phpcs:ignore
				flush();
				if( ob_get_level() > 0 ){
					ob_flush();
				}
				if ( $retbytes ) {
					$cnt += strlen( $buffer );
				}
			}

			$status = fclose( $handle ); // phpcs:ignore
			if ( $retbytes && $status ) {
				return $cnt; // return num. bytes delivered like readfile() does.
			}
			return $status;
		}

		/**
		 * @param $someFolder
		 */
		public static function clean_folder( $someFolder ) {

			$someFolder = trailingslashit( $someFolder );

			// Cleanup any files from a previous restore attempt
			$dh = opendir( $someFolder );
			if ( $dh ) {
				$file = readdir( $dh );
				while ( false !== $file ) {
					if ( ( '.' === $file ) || ( '..' === $file ) ) {
						$file = readdir( $dh );
						continue;
					}

					self::recursive_rmdir( $someFolder . $file );
					$file = readdir( $dh );
				}
				closedir( $dh );
			}
		}

		/**
		 * @param $manifest_array
		 * @param $manifestFile
		 *
		 * @return bool
		 */
		public static function create_archive_manifest( $manifest_array, $manifestFile ) {
			if ( ! $manifest_array ) {
				return false;
			}

			global $wp_filesystem;

			if( self::connect_fs() ) {
				foreach ( $manifest_array as $token => $token_data ) {
					$wp_filesystem->put_contents($manifestFile, $wp_filesystem->get_contents( $manifestFile ) . $token . ":" . maybe_serialize( $token_data ) . "\r\n", FS_CHMOD_FILE);
				}

				return true;
			}
		}

		/**
		 *
		 * @param $manifest_file
		 *
		 * @return array
		 */
		public static function consume_archive_manifest( $manifest_file ) {
			$snapshot_manifest = array();
			$manifest_array = file( $manifest_file );

			$sessionRestoreFolder = trailingslashit( WPMUDEVSnapshot::instance()->get_setting( 'backupRestoreFolderFull' ) );

			/* Return an empty array if the manifest is empty */
			if ( ! $manifest_array ) {
				return array();
			}

			/* Read the manifest file into an array, joining entries that are split across multiple lines */
			$manifest = array();
			$last_key = '';

			foreach ( $manifest_array as $line ) {
				$matches = array();
				preg_match( '/^([\w\s-]+):(.+)$/', $line, $matches );

				if ( $matches ) {

					/* If the line matches the expected format, extract the values and add them to the array */
					$label = trim( $matches[1] );
					$data = $matches[2];

					$manifest[ $label ] = $data;
					$last_key = $label;

				} elseif ( $last_key ) {
					/* Otherwise, treat this line as part of the previous one */
					$manifest[ $last_key ] .= "\n" . $line;
				}
			}

			/* Parse the raw manifest data into its proper form */
			foreach ( $manifest as $key => $value ) {

				if ( "TABLES" === $key ) {
					if ( is_serialized( $value ) ) {
						$value = maybe_unserialize( $value );
					} else {
						$table_values = explode( ',', $value );

						foreach ( $table_values as $idx => $table_name ) {
							$table_values[ $idx ] = trim( $table_name );
						}

						$value = $table_values;
					}
				} else if ( ( "TABLES-DATA" === $key ) || ( "ITEM" === $key ) || ( "FILES-DATA" === $key ) || ( 'WP_UPLOAD_URLS' === $key ) ) {
					if ( is_serialized( $value ) ) {
						$value = maybe_unserialize( $value );
					} else {
						$value = trim( $value );
					}

				} else {
					$value = trim( $value );
				}

				$snapshot_manifest[ $key ] = $value;
			}
			//echo "snapshot_manifest<pre>"; print_r($snapshot_manifest); echo "</pre>";
			//die();

			if ( ! isset( $snapshot_manifest['SNAPSHOT_VERSION'] ) ) {
				if ( isset( $snapshot_manifest['VERSION'] ) ) {
					$snapshot_manifest['SNAPSHOT_VERSION'] = $snapshot_manifest['VERSION'];
					unset( $snapshot_manifest['VERSION'] );
				}
			}

			if ( ! isset( $snapshot_manifest['WP_BLOG_ID'] ) ) {
				if ( isset( $snapshot_manifest['BLOG-ID'] ) ) {
					$snapshot_manifest['WP_BLOG_ID'] = $snapshot_manifest['BLOG-ID'];
					unset( $snapshot_manifest['BLOG-ID'] );
				}
			}
			if ( ! isset( $snapshot_manifest['WP_DB_NAME'] ) ) {
				if ( isset( $snapshot_manifest['DB_NAME'] ) ) {
					$snapshot_manifest['WP_DB_NAME'] = $snapshot_manifest['DB_NAME'];
					unset( $snapshot_manifest['DB_NAME'] );
				}
			}
			if ( ! isset( $snapshot_manifest['WP_DB_BASE_PREFIX'] ) ) {
				if ( isset( $snapshot_manifest['BASE_PREFIX'] ) ) {
					$snapshot_manifest['WP_DB_BASE_PREFIX'] = $snapshot_manifest['BASE_PREFIX'];
					unset( $snapshot_manifest['BASE_PREFIX'] );
				}
			}
			if ( ! isset( $snapshot_manifest['WP_DB_PREFIX'] ) ) {
				if ( isset( $snapshot_manifest['PREFIX'] ) ) {
					$snapshot_manifest['WP_DB_PREFIX'] = $snapshot_manifest['PREFIX'];
					unset( $snapshot_manifest['PREFIX'] );
				}
			}
			if ( ! isset( $snapshot_manifest['WP_DB_CHARSET_COLLATE'] ) ) {
				if ( isset( $snapshot_manifest['CHARSET_COLLATE'] ) ) {
					$snapshot_manifest['WP_DB_CHARSET_COLLATE'] = $snapshot_manifest['CHARSET_COLLATE'];
					unset( $snapshot_manifest['CHARSET_COLLATE'] );
				}
			}
			if ( ! isset( $snapshot_manifest['WP_UPLOAD_PATH'] ) ) {
				if ( isset( $snapshot_manifest['UPLOAD_PATH'] ) ) {
					$snapshot_manifest['WP_UPLOAD_PATH'] = $snapshot_manifest['UPLOAD_PATH'];
					unset( $snapshot_manifest['UPLOAD_PATH'] );
				}
			}
			if ( ! isset( $snapshot_manifest['WP_HOME'] ) ) {
				if ( isset( $snapshot_manifest['HOME'] ) ) {
					$snapshot_manifest['WP_HOME'] = $snapshot_manifest['HOME'];
					unset( $snapshot_manifest['HOME'] );
				}
			}
			if ( ! isset( $snapshot_manifest['WP_SITEURL'] ) ) {
				if ( isset( $snapshot_manifest['SITEURL'] ) ) {
					$snapshot_manifest['WP_SITEURL'] = $snapshot_manifest['SITEURL'];
					unset( $snapshot_manifest['SITEURL'] );
				}
			}

			if ( ! isset( $snapshot_manifest['WP_BLOG_NAME'] ) ) {
				$snapshot_manifest['WP_BLOG_NAME'] = '';
			}

			if ( ! isset( $snapshot_manifest['WP_BLOG_DOMAIN'] ) ) {
				if ( isset( $snapshot_manifest['WP_SITEURL'] ) ) {
					$snapshot_manifest['WP_BLOG_DOMAIN'] = wp_parse_url( $snapshot_manifest['WP_SITEURL'], PHP_URL_HOST );
				}
			}

			if ( ! isset( $snapshot_manifest['WP_BLOG_PATH'] ) ) {
				if ( isset( $snapshot_manifest['WP_SITEURL'] ) ) {
					$snapshot_manifest['WP_BLOG_PATH'] = wp_parse_url( $snapshot_manifest['WP_SITEURL'], PHP_URL_PATH );
				}
			}

			//echo "snapshot_manifest<pre>"; print_r($snapshot_manifest); echo "</pre>";

			return $snapshot_manifest;
		}

		/**
		 * @param string $archiveFilename
		 * @param string $restoreFolder
		 *
		 * @return bool|string
		 */
		public static function extract_archive_manifest( $archiveFilename = '', $restoreFolder = '' ) {

			$manifest_file = 'snapshot_manifest.txt';

			if ( ! file_exists( $archiveFilename ) ) {
				return false;
			}

			if ( ! $restoreFolder ) {
				$restoreFolder = WPMUDEVSnapshot::instance()->get_setting( 'backupRestoreFolderFull' );
			}

			// It is assumed the folder already exists!~~~
			// Clear out the restore folder.
			self::recursive_rmdir( $restoreFolder );

			$ret = wp_mkdir_p( $restoreFolder );

			//echo "zipLibrary[". WPMUDEVSnapshot::instance()->config_data['config']['zipLibrary'] ."]<br />";
			//die();

			if ( "PclZip" === WPMUDEVSnapshot::instance()->config_data['config']['zipLibrary'] ) {
				if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) ) {
					define( 'PCLZIP_TEMPORARY_DIR', $restoreFolder );
				}

				if ( ! class_exists( 'class PclZip' ) ) {
					require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
				}

				$zipArchive         = new PclZip( $archiveFilename );
				$exteact_files_list = $zipArchive->extract( PCLZIP_OPT_PATH, $restoreFolder, PCLZIP_OPT_BY_NAME, array( 'snapshot_manifest.txt' ) );

			} else {

				$normalizedArchiveFilename = wp_normalize_path( $archiveFilename );

				if ( strpos( strtolower( trim( $normalizedArchiveFilename ) ), '../' ) !== false ) {
					throw new Exception('path traversal is not allowed');
				}

				$zip = new ZipArchive();
				$res = $zip->open( $normalizedArchiveFilename );
				if ( true === $res ) {
					$zip->extractTo( $restoreFolder, array( 'snapshot_manifest.txt' ) );
					$zip->close();
				}
			}

			$manifest_filename = trailingslashit( $restoreFolder ) . $manifest_file;

			if ( file_exists( $manifest_filename ) ) {
				return $manifest_filename;
			} else {
				return false;
			}
		}

		/**
		 * @param $restoreFile
		 * @param $restoreFolder
		 *
		 * @return array
		 */
		public static function archives_import_proc( $restoreFile, $restoreFolder ) {
			global $wpdb;

			WPMUDEVSnapshot::instance()->load_config();
			WPMUDEVSnapshot::instance()->set_backup_folder();
			WPMUDEVSnapshot::instance()->set_log_folders();

			$CONFIG_CHANGED = false;

//	echo "restoreFile=[". $restoreFile ."]<br />";
//	echo "restoreFolder=[". $restoreFolder ."]<br />";
//	echo "before items<pre>"; print_r(WPMUDEVSnapshot::instance()->config_data['items']); echo "</pre>";

			$error_status                 = array();
			$error_status['errorStatus']  = false;
			$error_status['errorText']    = "";
			$error_status['responseText'] = "";

			$snapshot_manifest = self::extract_archive_manifest( $restoreFile, $restoreFolder );

			if ( file_exists( $snapshot_manifest ) ) {
				//echo "snapshot_manifest[". $snapshot_manifest ."]<br />";
				$CONFIG_CHANGED = false;

				$manifest_data = self::consume_archive_manifest( $snapshot_manifest );
				//echo "manifest_data<pre>"; print_r($manifest_data); echo "</pre>";
				//die();

				if ( empty( $manifest_data ) ) {
					$error_status['errorStatus'] = true;
					$error_status['errorText']   = __( "Manifest data not found in archive.", SNAPSHOT_I18N_DOMAIN );

					return $error_status;
				}

				if ( ( ! isset( $manifest_data['ITEM'] ) ) || ( empty( $manifest_data['ITEM'] ) ) ) {
					$error_status['errorStatus'] = true;
					$error_status['errorText']   = __( "Manifest data does not contain ITEM section.", SNAPSHOT_I18N_DOMAIN );

					return $error_status;
				}
				$item = $manifest_data['ITEM'];

				if ( ( ! isset( $item['timestamp'] ) ) || ( empty( $item['timestamp'] ) ) ) {
					$error_status['errorStatus'] = true;
					$error_status['errorText']   = __( "Manifest ITEM does not contain 'timestamp' item.", SNAPSHOT_I18N_DOMAIN );

					return $error_status;
				}

				//$siteurl = get_option('siteurl');
				//echo "siteurl=[". $siteurl ."]<br />";

				$RESTORE['LOCAL'] = array();

				if ( is_multisite() ) {
					$blog_details = get_blog_details( $manifest_data['WP_BLOG_ID'] );
					//echo "blog_details<pre>"; print_r($blog_details); echo "</pre>";
					if ( ( isset( $blog_details->domain ) ) && ( ! empty( $blog_details->domain ) ) ) {
						$RESTORE['LOCAL']['WP_BLOG_DOMAIN'] = $blog_details->domain;
					} else {
						$RESTORE['LOCAL']['WP_BLOG_DOMAIN'] = '';
					}

					if ( ( isset( $blog_details->path ) ) && ( ! empty( $blog_details->path ) ) ) {
						$RESTORE['LOCAL']['WP_BLOG_PATH'] = $blog_details->path;
					} else {
						$RESTORE['LOCAL']['WP_BLOG_PATH'] = '';
					}
				} else {
					$siteurl                            = get_option( 'siteurl' );
					$RESTORE['LOCAL']['WP_BLOG_DOMAIN'] = wp_parse_url( $siteurl, PHP_URL_HOST );
					$RESTORE['LOCAL']['WP_BLOG_PATH']   = wp_parse_url( $siteurl, PHP_URL_PATH );
					//$RESTORE['LOCAL']['WP_BLOG_ID']		= $blog_id;
				}

				$RESTORE['IMPORT'] = array();

				if ( isset( $manifest_data['WP_BLOG_ID'] ) ) {
					$RESTORE['IMPORT']['WP_BLOG_ID'] = $manifest_data['WP_BLOG_ID'];
				} else {
					$RESTORE['IMPORT']['WP_BLOG_ID'] = '';
				}


				if ( isset( $manifest_data['WP_BLOG_NAME'] ) ) {
					$RESTORE['IMPORT']['WP_BLOG_NAME'] = $manifest_data['WP_BLOG_NAME'];
				} else {
					$RESTORE['IMPORT']['WP_BLOG_NAME'] = '';
				}


				if ( isset( $manifest_data['WP_DB_NAME'] ) ) {
					$RESTORE['IMPORT']['WP_DB_NAME'] = $manifest_data['WP_DB_NAME'];
				} else {
					$RESTORE['IMPORT']['WP_DB_NAME'] = '';
				}


				if ( isset( $manifest_data['WP_DB_BASE_PREFIX'] ) ) {
					$RESTORE['IMPORT']['WP_DB_BASE_PREFIX'] = $manifest_data['WP_DB_BASE_PREFIX'];
				} else {
					$RESTORE['IMPORT']['WP_DB_BASE_PREFIX'] = '';
				}


				if ( isset( $manifest_data['WP_DB_PREFIX'] ) ) {
					$RESTORE['IMPORT']['WP_DB_PREFIX'] = $manifest_data['WP_DB_PREFIX'];
				} else {
					$RESTORE['IMPORT']['WP_DB_PREFIX'] = '';
				}


				if ( isset( $manifest_data['WP_DB_CHARSET_COLLATE'] ) ) {
					$RESTORE['IMPORT']['WP_DB_CHARSET_COLLATE'] = $manifest_data['WP_DB_CHARSET_COLLATE'];
				} else {
					$RESTORE['IMPORT']['WP_DB_CHARSET_COLLATE'] = '';
				}


				if ( isset( $manifest_data['WP_HOME'] ) ) {
					$RESTORE['IMPORT']['WP_HOME'] = $manifest_data['WP_HOME'];
				}

				if ( isset( $manifest_data['WP_SITEURL'] ) ) {
					$RESTORE['IMPORT']['WP_SITEURL'] = $manifest_data['WP_SITEURL'];
				} else {
					$RESTORE['IMPORT']['WP_SITEURL'] = '';
				}


				if ( isset( $manifest_data['WP_UPLOAD_PATH'] ) ) {
					$RESTORE['IMPORT']['WP_UPLOAD_PATH'] = $manifest_data['WP_UPLOAD_PATH'];
				} else {
					$RESTORE['IMPORT']['WP_UPLOAD_PATH'] = '';
				}


				if ( isset( $manifest_data['WP_UPLOAD_URLS'] ) ) {
					$RESTORE['IMPORT']['WP_UPLOAD_URLS'] = $manifest_data['WP_UPLOAD_URLS'];
				} else {
					$RESTORE['IMPORT']['WP_UPLOAD_URLS'] = array();
				}


				if ( isset( $manifest_data['WP_BLOG_DOMAIN'] ) ) {
					$RESTORE['IMPORT']['WP_BLOG_DOMAIN'] = $manifest_data['WP_BLOG_DOMAIN'];
				} else if ( isset( $manifest_data['WP_SITEURL'] ) ) {
					$RESTORE['LOCAL']['WP_BLOG_DOMAIN'] = wp_parse_url( $manifest_data['WP_SITEURL'], PHP_URL_HOST );
				}

				if ( isset( $manifest_data['WP_BLOG_PATH'] ) ) {
					$RESTORE['IMPORT']['WP_BLOG_PATH'] = $manifest_data['WP_BLOG_PATH'];
				} else if ( isset( $manifest_data['WP_SITEURL'] ) ) {
					$RESTORE['IMPORT']['WP_BLOG_PATH'] = wp_parse_url( $manifest_data['WP_SITEURL'], PHP_URL_PATH );
				}

				//echo "RESTORE<pre>"; print_r($RESTORE); echo "</pre>";
				//die();

				if ( ( $RESTORE['IMPORT']['WP_BLOG_DOMAIN'] !== $RESTORE['LOCAL']['WP_BLOG_DOMAIN'] )
				     || ( $RESTORE['IMPORT']['WP_BLOG_PATH'] !== $RESTORE['LOCAL']['WP_BLOG_PATH'] )
				) {

					$item['IMPORT'] = $RESTORE['IMPORT'];

					// For Multisite we try and lookup the site based on the DOMAIN+PATH
					if ( is_multisite() ) {
						global $wpdb;

						if ( is_subdomain_install() ) {
							$sql_str = $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $RESTORE['IMPORT']['WP_BLOG_DOMAIN'] );
							//$sql_str = $wpdb->prepare("SELECT blog_id FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $RESTORE['LOCAL']['WP_BLOG_DOMAIN']);
							$blog = $wpdb->get_row( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $RESTORE['IMPORT']['WP_BLOG_DOMAIN'] ) );
						} else {
							$snapshot_blog_id_search_path   = trailingslashit( $RESTORE['IMPORT']['WP_BLOG_PATH'] );
							$snapshot_blog_id_search_domain = untrailingslashit( $RESTORE['IMPORT']['WP_BLOG_DOMAIN'] );
							$sql_str                        = $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s LIMIT 1",
								$snapshot_blog_id_search_domain, $snapshot_blog_id_search_path );
							$blog = $wpdb->get_row( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s LIMIT 1",
								$snapshot_blog_id_search_domain, $snapshot_blog_id_search_path ) );
						}
						if ( ( isset( $blog->blog_id ) ) && ( $blog->blog_id > 0 ) ) { // found
							//echo "blog<pre>"; print_r($blog); echo "</pre>";
							$item['blog-id'] = $blog->blog_id;
						} else {
							$item['blog-id'] = 0;
						}
					} else {
						$item['blog-id'] = 0;
					}
				}

				//echo "item<pre>"; print_r($item); echo "</pre>";
				//die();

				$item_key = $item['timestamp'];

				if ( ( ! isset( $item['data'] ) ) || ( ! count( $item['data'] ) ) ) {
					$error_status['errorStatus'] = true;
					$error_status['errorText']   = __( "Manifest ITEM does not contain 'data' section.", SNAPSHOT_I18N_DOMAIN );

					return $error_status;
				}

				$normalizedPath = strtolower( trim( $restoreFile ) );

				if ( strpos( $normalizedPath, 'phar://' ) !== false ) {
					throw new Exception('phar handler not allowed');
				}

				// Now we check the manifest item against the config data.
				foreach ( $item['data'] as $data_item_key => $data_item ) {

					if ( ( ! isset( $data_item['filename'] ) ) || ( empty( $data_item['filename'] ) ) ) {
						$item['data'][ $data_item_key ]['filename'] = basename( $restoreFile );
					}

					if ( ( ! isset( $data_item['file_size'] ) ) || ( empty( $data_item['file_size'] ) ) ) {
						$item['data'][ $data_item_key ]['file_size'] = filesize( $restoreFile );
					}
				}

				if ( ! isset( WPMUDEVSnapshot::instance()->config_data['items'][ $item_key ] ) ) {
					WPMUDEVSnapshot::instance()->config_data['items'][ $item_key ] = $item;
					$CONFIG_CHANGED                                                = true;

					$error_status['errorStatus']  = false;
					$error_status['responseText'] = __( "Archive imported successfully.", SNAPSHOT_I18N_DOMAIN );

				} else {
					foreach ( $item['data'] as $data_item_key => $data_item ) {

						if ( ! isset( WPMUDEVSnapshot::instance()->config_data['items'][ $item_key ]['data'][ $data_item_key ] ) ) {
							WPMUDEVSnapshot::instance()->config_data['items'][ $item_key ]['data'][ $data_item_key ] = $data_item;
							$CONFIG_CHANGED                                                                          = true;

							$error_status['errorStatus']  = false;
							$error_status['responseText'] = __( "Archive imported successfully.", SNAPSHOT_I18N_DOMAIN );

						} else {
							$error_status['errorStatus']  = false;
							$error_status['responseText'] = __( "already present. not importing.", SNAPSHOT_I18N_DOMAIN );
						}
					}
				}

				if ( true === $CONFIG_CHANGED ) {
					WPMUDEVSnapshot::instance()->save_config();
				}
			} else {
				$error_status['errorStatus'] = true;
				$error_status['errorText']   = __( "Manifest data not found in archive.", SNAPSHOT_I18N_DOMAIN );
			}

			return $error_status;
		}

		/**
		 * Convert bytes to human readable format.
		 *
		 * @since 2.0.3
		 *
		 * @param int $bytes Size in bytes to convert
		 * @param int $precision
		 *
		 * @return string
		 */
		public static function size_format( $bytes = 0, $precision = 2 ) {
			return size_format($bytes, $precision);
			/*
			$kilobyte = 1000;
			$megabyte = $kilobyte * 1000;
			$gigabyte = $megabyte * 1000;
			$terabyte = $gigabyte * 1000;

			if ( ( $bytes >= 0 ) && ( $bytes < $kilobyte ) ) {
				return $bytes . 'b';

			} elseif ( ( $bytes >= $kilobyte ) && ( $bytes < $megabyte ) ) {
				return round( $bytes / $kilobyte, $precision ) . 'kb';

			} elseif ( ( $bytes >= $megabyte ) && ( $bytes < $gigabyte ) ) {
				return round( $bytes / $megabyte, $precision ) . 'M';

			} elseif ( ( $bytes >= $gigabyte ) && ( $bytes < $terabyte ) ) {
				return round( $bytes / $gigabyte, $precision ) . 'G';

			} elseif ( $bytes >= $terabyte ) {
				return round( $bytes / $terabyte, $precision ) . 'T';
			} else {
				return $bytes . 'b';
			}
			*/
		}

		/**
		 * Returns human readable file size to bytes.
		 *
		 * @param $val
		 *
		 * @return int|string
		 */
		public static function size_unformat( $val ) {
			$val  = trim( $val );
			$last = strtolower( $val[ strlen( $val ) - 1 ] );

			// Explicitly typecast the value to a numeric one
			$val = (float)$val;

			switch ( $last ) {
				// The 'G' modifier is available since PHP 5.1.0
				case 'g':
					$val *= 1024;
					// No break
				case 'm':
					$val *= 1024;
					// No break
				case 'k':
					$val *= 1024;
					// No break
				case 'b':
					$val = $val;
					// No break
			}

			return $val;
		}

		/**
		 * @param string $item_key
		 *
		 * @return array|mixed|string|void
		 */
		public static function item_get_lock_info( $item_key = '' ) {

			if ( ! $item_key ) {
				return;
			}

			$lock_info           = array();
			$lock_info['locked'] = false;
			$lock_info['file']   = trailingslashit( WPMUDEVSnapshot::instance()->get_setting( 'backupLockFolderFull' ) ) . $item_key . ".lock";
			if ( file_exists( $lock_info['file'] ) ) {
				// phpcs:ignore
				$lock_fp = fopen( $lock_info['file'], 'r' );
				if ( $lock_fp ) {

					// Try to obtain exclusive lock to prevent multiple processes.
					if ( ! flock( $lock_fp, LOCK_EX | LOCK_NB ) ) {
						$lock_info['locked'] = true;
						flock( $lock_fp, LOCK_UN );
					}
					$lock_info = fgets( $lock_fp, 4096 );
					if ( $lock_info ) {
						$lock_info = maybe_unserialize( $lock_info );
					}
					// phpcs:ignore
					fclose( $lock_fp );
				}
			}

			return $lock_info;
		}


		/**
		 * Wrapper for WP current_user_can.
		 *
		 * @todo Is this still needed?
		 *
		 * @param $cap
		 *
		 * @return bool
		 */
		public static function current_user_can( $cap ) {
			if ( is_multisite() ) {
				if ( is_network_admin() ) {
					return true;
				}

			} else {
				return current_user_can( $cap );
			}
		}

		/**
		 * @param $data_item
		 *
		 * @return int
		 */
		public static function data_item_file_processed_count( $data_item ) {
			if ( ! isset( $data_item['destination-status'] ) ) {
				return 0;
			}

			$_count = 0;
			foreach ( $data_item['destination-status'] as $_status ) {
				if ( isset( $_status['syncFilesTotal'] ) ) {
					$_count += intval( $_status['syncFilesTotal'] );
				}
			}

			return intval( $_count );
		}

		/**
		 * Will be used to replace old home URL with new home URL if the URL is changed during restore.
		 *
		 * @todo Method name is too generic
		 *
		 * @param $value
		 * @param $old_site_url
		 * @param $new_site_url
		 *
		 * @return mixed|string
		 */
		public static function replace_value( $value, $old_site_url, $new_site_url ) {
			if ( is_serialized( $value ) ) {
				$unserialized     = maybe_unserialize( $value );
				$unserialized_new = self::replace_value( $unserialized, $old_site_url, $new_site_url ); // recurse!
				return maybe_serialize( $unserialized_new );
			} elseif ( is_array( $value ) ) {
				foreach ( $value as $key => &$val ) {
					$val = self::replace_value( $val, $old_site_url, $new_site_url ); // recurse!
				}

				return $value;
			} elseif ( ( is_object( $value ) ) || ( gettype( $value ) === 'object' ) ) {
				try {
					$new_object = clone $value;
					foreach ( $value as $key => $val ) {
						$new_object->$key = self::replace_value( $val, $old_site_url, $new_site_url ); // recurse!
					}

					return $new_object;
				} catch ( Exception $e ) {
					assert(true);
				}
			} elseif ( is_string( $value ) ) {
				return str_replace( $old_site_url, $new_site_url, $value ); // no more recursion
			} else {
				assert(true); //echo "type unknown [". $val ."]<br />";
			}

			return $value;
		}

		/**
		 *
		 * @todo Look for another way.
		 *
		 * @param $remote_url
		 * @param $local_file
		 */
		public static function remote_url_to_local_file( $remote_url, $local_file ) {

			if ( ! file_exists( dirname( $local_file ) ) ) {
				mkdir( dirname( $local_file ), 0777, true );
			}

			if ( file_exists( $local_file ) ) {
				unlink( $local_file );
			}

			$remote_host = wp_parse_url( $remote_url, PHP_URL_HOST );
			if ( strpos( $remote_host, 'dropbox.com' ) ) {
				$remote_url = add_query_arg( 'dl', '1', $remote_url );
			}

			global $wp_filesystem;

			if( self::connect_fs() ) {
				$create_file = $wp_filesystem->put_contents( $local_file, '' );

				if ( $create_file ){
					$response = wp_remote_get( $remote_url, array(
										'sslverify' => false
									)
								);
					$wp_filesystem->put_contents( $local_file, $response['body'] );
					return self::size_format( $response['headers']['content-length'] );
				} else {
					echo wp_kses_post( "Unable to open local file [" . $local_file . "] for writing. Check parent folder permissions and reload the page." );
					die();
				}
			} else {
				echo wp_kses_post( "Cannot initialize filesystem." );
				die();
			}

		}

		/**
		 * @param $status
		 *
		 * @return string
		 */
		public static function get_zip_archive_status_string( $status ) {
			switch ( (int) $status ) {
				case ZipArchive::ER_OK           :
					return 'N No error';
				case ZipArchive::ER_MULTIDISK    :
					return 'N Multi-disk zip archives not supported';
				case ZipArchive::ER_RENAME       :
					return 'S Renaming temporary file failed';
				case ZipArchive::ER_CLOSE        :
					return 'S Closing zip archive failed';
				case ZipArchive::ER_SEEK         :
					return 'S Seek error';
				case ZipArchive::ER_READ         :
					return 'S Read error';
				case ZipArchive::ER_WRITE        :
					return 'S Write error';
				case ZipArchive::ER_CRC          :
					return 'N CRC error';
				case ZipArchive::ER_ZIPCLOSED    :
					return 'N Containing zip archive was closed';
				case ZipArchive::ER_NOENT        :
					return 'N No such file';
				case ZipArchive::ER_EXISTS       :
					return 'N File already exists';
				case ZipArchive::ER_OPEN         :
					return 'S Can\'t open file';
				case ZipArchive::ER_TMPOPEN      :
					return 'S Failure to create temporary file';
				case ZipArchive::ER_ZLIB         :
					return 'Z Zlib error';
				case ZipArchive::ER_MEMORY       :
					return 'N Malloc failure';
				case ZipArchive::ER_CHANGED      :
					return 'N Entry has been changed';
				case ZipArchive::ER_COMPNOTSUPP  :
					return 'N Compression method not supported';
				case ZipArchive::ER_EOF          :
					return 'N Premature EOF';
				case ZipArchive::ER_INVAL        :
					return 'N Invalid argument';
				case ZipArchive::ER_NOZIP        :
					return 'N Not a zip archive';
				case ZipArchive::ER_INTERNAL     :
					return 'N Internal error';
				case ZipArchive::ER_INCONS       :
					return 'N Zip archive inconsistent';
				case ZipArchive::ER_REMOVE       :
					return 'S Can\'t remove file';
				case ZipArchive::ER_DELETED      :
					return 'N Entry has been deleted';

				default:
					return sprintf( 'Unknown status %s', $status );
			}
		}

		/**
		 * Is this Snapshot Pro?
		 *
		 * @since 2.5
		 *
		 * @return bool
		 */
		public static function is_pro() {
			return true;
		}

		/**
		 * Check system requirements
		 *
		 * @since 3.1
		 *
		 * @param $requirements
		 *
		 * @return Array
		 */
		public static function check_system_requirements($requirements = array()) {
			$current_timeout = (int)ini_get( 'max_execution_time' );
			$defaults = array(
				'PhpVersion' => array(
					'test' => version_compare(PHP_VERSION, '5.2') >= 0,
					'value' => PHP_VERSION
				),
				'MaxExecTime' => array(
					'test' => 0 >= $current_timeout || $current_timeout >= 150,
					'value' => (int)ini_get('max_execution_time'),
					'warning' => true
				),
				'Mysqli' => array(
					'test' => (bool)function_exists('mysqli_connect'),
				),
				'Zip' => array(
					'test' => defined('SNAPSHOT_FORCE_ZIP_LIBRARY') && 'pclzip' === SNAPSHOT_FORCE_ZIP_LIBRARY
						? true
						: class_exists('ZipArchive')
				)
			);

			$requirements = wp_parse_args( $requirements, $defaults );

			$all_good = true;
			$warning = false;
			foreach ($requirements as $check) {
				if (!empty($check['test'])) continue;
				if (!empty($check['warning']) && ($check['warning'])){
					$warning = true;
					continue;
				}
				$all_good = false;
				break;
			}
			$results = array(
				'checks' => $requirements,
				'warning' => $warning,
				'all_good' => $all_good
				);
			return $results;
		}

		/**
		 * Connect to the filesystem
		 *
		 * @param $url
		 * @param $method
		 * @param $context
		 * @param $fields
		 *
		 * @return bool
		 */
		public static function connect_fs( $url = '', $method = '', $context = '', $fields = null ) {
			global $wp_filesystem;
			$credentials = request_filesystem_credentials($url, $method, false, $context, $fields);
			if( false === ($credentials) ) {
				return false;
			}

			//check if credentials are correct or not.
			if( ! WP_Filesystem( $credentials ) )
			{
				request_filesystem_credentials( $url, $method, true, $context );
				return false;
			}

			return true;
		}

		/**
		 * Checks whether we're on WPMU DEV Hosting
		 *
		 * @return bool
		 */
		public static function is_wpmu_hosting() {
			return isset( $_SERVER['WPMUDEV_HOSTED'] ) && ! empty( $_SERVER['WPMUDEV_HOSTED'] );
		}

		/**
		 * Checks whether we're on WPEngine
		 *
		 * @return bool
		 */
		public static function is_wpengine_hosting() {
			return defined('WPE_APIKEY');
		}

		/**
		 * Return converted UTC to local hosting backup time
		 *
		 * @return false|string
		 */
		public static function get_hosting_backup_local_time() {
			// Currently backup time is hardcoded to 2:00AM UTC
			$time = '2:00';

			// Convert to local time
			$time = Snapshot_Helper_Utility::show_date_time( strtotime( $time ), 'g:ia' );

			return $time;
		}

		/**
		 * Checks whether the S3 request handler is properly spawned.
		 *
		 * @param $s3
		 *
		 * @return bool
		 */
		public static function spawned_S3_handler( $s3 ) {
			if ( false === $s3 ) {
				Snapshot_Helper_Log::error( 'Error spawning the S3 request handler, most probably due to a plugin conflict' );
				return false;
			} else {
				return true;
			}
		}

	}
}