PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /home/trave494/veezar.kerihosting.com/wp-content/plugins/duplicator/classes/package/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //home/trave494/veezar.kerihosting.com/wp-content/plugins/duplicator/classes/package/class.pack.php |
<?php use Duplicator\Libs\Snap\SnapJson; use Duplicator\Libs\Snap\SnapUtil; defined('ABSPATH') || defined('DUPXABSPATH') || exit; // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) { exit; } require_once(DUPLICATOR_PLUGIN_PATH . 'classes/utilities/class.u.php'); require_once(DUPLICATOR_PLUGIN_PATH . 'classes/package/class.pack.archive.php'); require_once(DUPLICATOR_PLUGIN_PATH . 'classes/package/class.pack.installer.php'); require_once(DUPLICATOR_PLUGIN_PATH . 'classes/package/class.pack.database.php'); /** * Class used to keep track of the build progress * * @package Duplicator\classes */ class DUP_Build_Progress { public $thread_start_time; public $initialized = false; public $installer_built = false; public $archive_started = false; public $archive_has_database = false; public $archive_built = false; public $database_script_built = false; public $failed = false; public $retries = 0; public $build_failures = array(); public $validation_failures = array(); /** * * @var DUP_Package */ private $package; /** * * @param DUP_Package $package */ public function __construct($package) { $this->package = $package; } /** * * @return bool */ public function has_completed() { return $this->failed || ($this->installer_built && $this->archive_built && $this->database_script_built); } public function timed_out($max_time) { if ($max_time > 0) { $time_diff = time() - $this->thread_start_time; return ($time_diff >= $max_time); } else { return false; } } public function start_timer() { $this->thread_start_time = time(); } public function set_validation_failures($failures) { $this->validation_failures = array(); foreach ($failures as $failure) { $this->validation_failures[] = $failure; } } public function set_build_failures($failures) { $this->build_failures = array(); foreach ($failures as $failure) { $this->build_failures[] = $failure->description; } } public function set_failed($failure_message = null) { if ($failure_message !== null) { $failure = new StdClass(); $failure->type = 0; $failure->subject = ''; $failure->description = $failure_message; $failure->isCritical = true; $this->build_failures[] = $failure; } $this->failed = true; $this->package->Status = DUP_PackageStatus::ERROR; } } /** * Class used to emulate and ENUM to give the status of a package from 0 to 100% * * @package Duplicator\classes */ final class DUP_PackageStatus { private function __construct() { } const ERROR = -1; const CREATED = 0; const START = 10; const DBSTART = 20; const DBDONE = 30; const ARCSTART = 40; const ARCVALIDATION = 60; const ARCDONE = 65; const COMPLETE = 100; } /** * Class used to emulate and ENUM to determine how the package was made. * For lite only the MANUAL type is used. * * @package Duplicator\classes */ final class DUP_PackageType { const MANUAL = 0; const SCHEDULED = 1; } /** * Class used to emulate and ENUM to determine the various file types used in a package * * @package Duplicator\classes */ abstract class DUP_PackageFileType { const Installer = 0; const Archive = 1; const SQL = 2; const Log = 3; const Scan = 4; } /** * Class used to store and process all Package logic * * Standard: PSR-2 * * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator\classes */ class DUP_Package { const OPT_ACTIVE = 'duplicator_package_active'; //Properties /** @var string */ public $Created = ''; public $Version; public $VersionWP; public $VersionDB; public $VersionPHP; public $VersionOS; public $ID; public $Name; public $Hash; public $NameHash; //Set to DUP_PackageType public $Type; public $Notes; public $ScanFile; public $TimerStart = -1; public $Runtime; public $ExeSize; public $ZipSize; public $Status; public $WPUser; /** @var DUP_Archive */ public $Archive; /** @var DUP_Installer */ public $Installer; /** @var DUP_Database */ public $Database; /** @var DUP_Build_Progress */ public $BuildProgress; /** * Manages the Package Process */ public function __construct() { $this->ID = null; $this->Version = DUPLICATOR_VERSION; $this->Type = DUP_PackageType::MANUAL; $this->Name = self::getDefaultName(); $this->Notes = null; $this->Database = new DUP_Database($this); $this->Archive = new DUP_Archive($this); $this->Installer = new DUP_Installer($this); $this->BuildProgress = new DUP_Build_Progress($this); $this->Status = DUP_PackageStatus::CREATED; } /** * Generates a JSON scan report * * @return array of scan results * * @notes: Testing = /wp-admin/admin-ajax.php?action=duplicator_package_scan */ public function runScanner() { $timerStart = DUP_Util::getMicrotime(); $report = array(); $this->ScanFile = "{$this->NameHash}_scan.json"; $report['RPT']['ScanTime'] = "0"; $report['RPT']['ScanFile'] = $this->ScanFile; //SERVER $srv = DUP_Server::getChecks(); $report['SRV'] = $srv['SRV']; //FILES $this->Archive->getScannerData(); $dirCount = count($this->Archive->Dirs); $fileCount = count($this->Archive->Files); $fullCount = $dirCount + $fileCount; $report['ARC']['Size'] = DUP_Util::byteSize($this->Archive->Size) or "unknown"; $report['ARC']['DirCount'] = number_format($dirCount); $report['ARC']['FileCount'] = number_format($fileCount); $report['ARC']['FullCount'] = number_format($fullCount); $report['ARC']['WarnFileCount'] = count($this->Archive->FilterInfo->Files->Warning); $report['ARC']['WarnDirCount'] = count($this->Archive->FilterInfo->Dirs->Warning); $report['ARC']['UnreadableDirCount'] = count($this->Archive->FilterInfo->Dirs->Unreadable); $report['ARC']['UnreadableFileCount'] = count($this->Archive->FilterInfo->Files->Unreadable); $report['ARC']['FilterDirsAll'] = $this->Archive->FilterDirsAll; $report['ARC']['FilterFilesAll'] = $this->Archive->FilterFilesAll; $report['ARC']['FilterExtsAll'] = $this->Archive->FilterExtsAll; $report['ARC']['FilterInfo'] = $this->Archive->FilterInfo; $report['ARC']['RecursiveLinks'] = $this->Archive->RecursiveLinks; $report['ARC']['UnreadableItems'] = array_merge($this->Archive->FilterInfo->Files->Unreadable, $this->Archive->FilterInfo->Dirs->Unreadable); $report['ARC']['Status']['Size'] = ($this->Archive->Size > DUPLICATOR_SCAN_SIZE_DEFAULT) ? 'Warn' : 'Good'; $report['ARC']['Status']['Names'] = (count($this->Archive->FilterInfo->Files->Warning) + count($this->Archive->FilterInfo->Dirs->Warning)) ? 'Warn' : 'Good'; $report['ARC']['Status']['UnreadableItems'] = !empty($this->Archive->RecursiveLinks) || !empty($report['ARC']['UnreadableItems']) ? 'Warn' : 'Good'; /* $overwriteInstallerParams = apply_filters('duplicator_overwrite_params_data', array()); $package_can_be_migrate = !(isset($overwriteInstallerParams['mode_chunking']['value']) && $overwriteInstallerParams['mode_chunking']['value'] == 3 && isset($overwriteInstallerParams['mode_chunking']['formStatus']) && $overwriteInstallerParams['mode_chunking']['formStatus'] == 'st_infoonly'); */ $package_can_be_migrate = true; $report['ARC']['Status']['MigratePackage'] = $package_can_be_migrate ? 'Good' : 'Warn'; $report['ARC']['Status']['CanbeMigratePackage'] = $package_can_be_migrate; $privileges_to_show_create_proc_func = true; $procedures = $GLOBALS['wpdb']->get_col("SHOW PROCEDURE STATUS WHERE `Db` = '" . $GLOBALS['wpdb']->dbname . "'", 1); if (count($procedures)) { $create = $GLOBALS['wpdb']->get_row("SHOW CREATE PROCEDURE `" . $procedures[0] . "`", ARRAY_N); $privileges_to_show_create_proc_func = isset($create[2]); } $functions = $GLOBALS['wpdb']->get_col("SHOW FUNCTION STATUS WHERE `Db` = '" . $GLOBALS['wpdb']->dbname . "'", 1); if (count($functions)) { $create = $GLOBALS['wpdb']->get_row("SHOW CREATE FUNCTION `" . $functions[0] . "`", ARRAY_N); $privileges_to_show_create_proc_func = $privileges_to_show_create_proc_func && isset($create[2]); } $privileges_to_show_create_proc_func = apply_filters('duplicator_privileges_to_show_create_proc_func', $privileges_to_show_create_proc_func); $report['ARC']['Status']['showCreateProcFuncStatus'] = $privileges_to_show_create_proc_func ? 'Good' : 'Warn'; $report['ARC']['Status']['showCreateProcFunc'] = $privileges_to_show_create_proc_func; //$report['ARC']['Status']['Big'] = count($this->Archive->FilterInfo->Files->Size) ? 'Warn' : 'Good'; $report['ARC']['Dirs'] = $this->Archive->Dirs; $report['ARC']['Files'] = $this->Archive->Files; $report['ARC']['Status']['AddonSites'] = count($this->Archive->FilterInfo->Dirs->AddonSites) ? 'Warn' : 'Good'; //DATABASE $db = $this->Database->getScannerData(); $report['DB'] = $db; //Lite Limits $rawTotalSize = $this->Archive->Size + $report['DB']['RawSize']; $report['LL']['TotalSize'] = DUP_Util::byteSize($rawTotalSize); $report['LL']['Status']['TotalSize'] = ($rawTotalSize > DUPLICATOR_MAX_DUPARCHIVE_SIZE) ? 'Fail' : 'Good'; $warnings = array( $report['SRV']['SYS']['ALL'], $report['SRV']['WP']['ALL'], $report['ARC']['Status']['Size'], $report['ARC']['Status']['Names'], $db['Status']['DB_Size'], $db['Status']['DB_Rows'] ); //array_count_values will throw a warning message if it has null values, //so lets replace all nulls with empty string foreach ($warnings as $i => $value) { if (is_null($value)) { $warnings[$i] = ''; } } $warn_counts = is_array($warnings) ? array_count_values($warnings) : 0; $report['RPT']['Warnings'] = is_null($warn_counts['Warn']) ? 0 : $warn_counts['Warn']; $report['RPT']['Success'] = is_null($warn_counts['Good']) ? 0 : $warn_counts['Good']; $report['RPT']['ScanTime'] = DUP_Util::elapsedTime(DUP_Util::getMicrotime(), $timerStart); $fp = fopen(DUP_Settings::getSsdirTmpPath() . "/{$this->ScanFile}", 'w'); fwrite($fp, SnapJson::jsonEncodePPrint($report)); fclose($fp); return $report; } /** * Validates the inputs from the UI for correct data input * * @return DUP_Validator */ public function validateInputs() { $validator = new DUP_Validator(); $validator->filter_custom( $this->Name, DUP_Validator::FILTER_VALIDATE_NOT_EMPTY, array( 'valkey' => 'Name' , 'errmsg' => __('Package name can\'t be empty', 'duplicator'), ) ); $validator->explode_filter_custom( $this->Archive->FilterDirs, ';', DUP_Validator::FILTER_VALIDATE_FOLDER, array( 'valkey' => 'FilterDirs' , 'errmsg' => __('Directories: <b>%1$s</b> isn\'t a valid path', 'duplicator'), ) ); $validator->explode_filter_custom( $this->Archive->FilterExts, ';', DUP_Validator::FILTER_VALIDATE_FILE_EXT, array( 'valkey' => 'FilterExts' , 'errmsg' => __('File extension: <b>%1$s</b> isn\'t a valid extension', 'duplicator'), ) ); $validator->explode_filter_custom( $this->Archive->FilterFiles, ';', DUP_Validator::FILTER_VALIDATE_FILE, array( 'valkey' => 'FilterFiles' , 'errmsg' => __('Files: <b>%1$s</b> isn\'t a valid file name', 'duplicator'), ) ); //FILTER_VALIDATE_DOMAIN throws notice message on PHP 5.6 if (defined('FILTER_VALIDATE_DOMAIN')) { $validator->filter_var($this->Installer->OptsDBHost, FILTER_VALIDATE_DOMAIN, array( 'valkey' => 'OptsDBHost' , 'errmsg' => __('MySQL Server Host: <b>%1$s</b> isn\'t a valid host', 'duplicator'), 'acc_vals' => array( '' , 'localhost' ) )); } $validator->filter_var($this->Installer->OptsDBPort, FILTER_VALIDATE_INT, array( 'valkey' => 'OptsDBPort' , 'errmsg' => __('MySQL Server Port: <b>%1$s</b> isn\'t a valid port', 'duplicator'), 'acc_vals' => array( '' ), 'options' => array( 'min_range' => 0 ) )); return $validator; } /** * * @return string */ public function getInstDownloadName($onlySecureName = false) { $mode = ($onlySecureName) ? DUP_Settings::INSTALLER_NAME_MODE_WITH_HASH : DUP_Settings::Get('installer_name_mode'); switch ($mode) { case DUP_Settings::INSTALLER_NAME_MODE_SIMPLE: $name = DUP_Installer::DEFAULT_INSTALLER_FILE_NAME_WITHOUT_HASH . DUP_Installer::INSTALLER_SERVER_EXTENSION; break; case DUP_Settings::INSTALLER_NAME_MODE_WITH_HASH: default: $name = basename($this->getLocalPackageFile(DUP_PackageFileType::Installer)); break; } $info = pathinfo($name); return $info['filename']; } /** * * @return bool return true if package is a active_package_id and status is bewteen 0 and 100 */ public function isRunning() { return DUP_Settings::Get('active_package_id') == $this->ID && $this->Status >= 0 && $this->Status < 100; } protected function cleanObjectBeforeSave() { $this->Archive->FilterInfo->reset(); } /** * Saves the active package to the package table * * @return void */ public function save($extension) { global $wpdb; $this->Archive->Format = strtoupper($extension); $this->Archive->File = "{$this->NameHash}_archive.{$extension}"; $this->Installer->File = apply_filters( 'duplicator_installer_file_path', "{$this->NameHash}_installer" . DUP_Installer::INSTALLER_SERVER_EXTENSION ); $this->Database->File = "{$this->NameHash}_database.sql"; $current_user = wp_get_current_user(); $this->WPUser = isset($current_user->user_login) ? $current_user->user_login : 'unknown'; //START LOGGING DUP_Log::Open($this->NameHash); do_action('duplicator_lite_build_before_start', $this); $this->writeLogHeader(); //CREATE DB RECORD $this->cleanObjectBeforeSave(); $packageObj = serialize($this); if (!$packageObj) { DUP_Log::error("Unable to serialize package object while building record."); } $this->ID = $this->getHashKey($this->Hash); if ($this->ID != 0) { DUP_LOG::Trace("ID non zero so setting to start"); $this->setStatus(DUP_PackageStatus::START); } else { DUP_LOG::Trace("ID IS zero so creating another package"); $tablePrefix = DUP_Util::getTablePrefix(); $results = $wpdb->insert($tablePrefix . "duplicator_packages", array( 'name' => $this->Name, 'hash' => $this->Hash, 'status' => DUP_PackageStatus::START, 'created' => current_time('mysql', get_option('gmt_offset', 1)), 'owner' => isset($current_user->user_login) ? $current_user->user_login : 'unknown', 'package' => $packageObj)); if ($results === false) { $wpdb->print_error(); DUP_LOG::Trace("Problem inserting package: {$wpdb->last_error}"); DUP_Log::error("Duplicator is unable to insert a package record into the database table.", "'{$wpdb->last_error}'"); } $this->ID = $wpdb->insert_id; } do_action('duplicator_lite_build_start', $this); } /** * Delete all files associated with this package ID * * @return void */ public function delete() { global $wpdb; $tablePrefix = DUP_Util::getTablePrefix(); $tblName = $tablePrefix . 'duplicator_packages'; $getResult = $wpdb->get_results($wpdb->prepare("SELECT name, hash FROM `{$tblName}` WHERE id = %d", $this->ID), ARRAY_A); if ($getResult) { $row = $getResult[0]; $nameHash = "{$row['name']}_{$row['hash']}"; $delResult = $wpdb->query($wpdb->prepare("DELETE FROM `{$tblName}` WHERE id = %d", $this->ID)); if ($delResult != 0) { $tmpPath = DUP_Settings::getSsdirTmpPath(); $ssdPath = DUP_Settings::getSsdirPath(); $archiveFile = $this->getArchiveFilename(); $wpConfigFile = "{$this->NameHash}_wp-config.txt"; //Perms @chmod($tmpPath . "/{$archiveFile}", 0644); @chmod($tmpPath . "/{$nameHash}_database.sql", 0644); @chmod($tmpPath . "/{$nameHash}_installer" . DUP_Installer::INSTALLER_SERVER_EXTENSION, 0644); @chmod($tmpPath . "/{$nameHash}_scan.json", 0644); @chmod($tmpPath . "/{$wpConfigFile}", 0644); @chmod($tmpPath . "/{$nameHash}.log", 0644); @chmod($ssdPath . "/{$archiveFile}", 0644); @chmod($ssdPath . "/{$nameHash}_database.sql", 0644); @chmod($ssdPath . "/{$nameHash}_installer" . DUP_Installer::INSTALLER_SERVER_EXTENSION, 0644); @chmod($ssdPath . "/{$nameHash}_scan.json", 0644); // In older version, The plugin was storing [HASH]_wp-config.txt in main storage area. The below line code is for backward compatibility @chmod($ssdPath . "/{$wpConfigFile}", 0644); @chmod($ssdPath . "/{$nameHash}.log", 0644); //Remove @unlink($tmpPath . "/{$archiveFile}"); @unlink($tmpPath . "/{$nameHash}_database.sql"); @unlink($tmpPath . "/{$nameHash}_installer" . DUP_Installer::INSTALLER_SERVER_EXTENSION); @unlink($tmpPath . "/{$nameHash}_scan.json"); @unlink($tmpPath . "/{$wpConfigFile}"); @unlink($tmpPath . "/{$nameHash}.log"); @unlink($ssdPath . "/{$archiveFile}"); @unlink($ssdPath . "/{$nameHash}_database.sql"); @unlink($ssdPath . "/{$nameHash}_installer" . DUP_Installer::INSTALLER_SERVER_EXTENSION); @unlink($ssdPath . "/{$nameHash}_scan.json"); // In older version, The plugin was storing [HASH]_wp-config.txt in main storage area. The below line code is for backward compatibility @unlink($ssdPath . "/{$wpConfigFile}"); @unlink($ssdPath . "/{$nameHash}.log"); } } } /** * Get package archive size. * If package isn't complete it get size from sum of temp files. * * @return int size in byte */ public function getArchiveSize() { $size = 0; if ($this->Status >= DUP_PackageStatus::COMPLETE) { $size = $this->Archive->Size; } else { $tmpSearch = glob(DUP_Settings::getSsdirTmpPath() . "/{$this->NameHash}_*"); if (is_array($tmpSearch)) { $result = array_map('filesize', $tmpSearch); $size = array_sum($result); } } return $size; } /** * Return true if active package exist and have an active status * * @return bool */ public static function isPackageRunning() { $activePakcs = self::get_ids_by_status(array( array('op' => '>=', 'status' => DUP_PackageStatus::CREATED), array('op' => '<', 'status' => DUP_PackageStatus::COMPLETE) ), true); return in_array(DUP_Settings::Get('active_package_id'), $activePakcs); } /** * * @param array $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * * @return string */ protected static function statusContitionsToWhere($conditions = array()) { if (empty($conditions)) { return ''; } else { $accepted_op = array('<', '>', '=', '<>', '>=', '<='); $relation = (isset($conditions['relation']) && strtoupper($conditions['relation']) == 'OR') ? ' OR ' : ' AND '; unset($conditions['relation']); $str_conds = array(); foreach ($conditions as $cond) { $op = (isset($cond['op']) && in_array($cond['op'], $accepted_op)) ? $cond['op'] : '='; $status = isset($cond['status']) ? (int) $cond['status'] : 0; $str_conds[] = 'status ' . $op . ' ' . $status; } return ' WHERE ' . implode($relation, $str_conds) . ' '; } } /** * Get packages with status conditions and/or pagination * * @global wpdb $wpdb * * @param array // $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * if empty get all pacages * @param int $limit // max row numbers fi false the limit is PHP_INT_MAX * @param int $offset // offset 0 is at begin * @param string $orderBy // default `id` ASC if empty no order * @param string $resultType // ids => int[] * row => row without backage blob * fullRow => row with package blob * objs => array of DUP_Package objects * * @return DUP_Package[]|object[]|int[] */ public static function get_packages_by_status($conditions = array(), $limit = false, $offset = 0, $orderBy = '`id` ASC', $resultType = 'obj') { global $wpdb; $table = $wpdb->base_prefix . "duplicator_packages"; $where = self::statusContitionsToWhere($conditions); $packages = array(); $offsetStr = ' OFFSET ' . (int) $offset; $limitStr = ' LIMIT ' . ($limit !== false ? max(0, $limit) : PHP_INT_MAX); $orderByStr = empty($orderBy) ? '' : ' ORDER BY ' . $orderBy . ' '; switch ($resultType) { case 'ids': $cols = '`id`'; break; case 'row': $cols = '`id`,`name`,`hash`,`status`,`created`,`owner`'; break; case 'fullRow': $cols = '*'; break; case 'objs': default: $cols = '`status`,`package`'; break; } $rows = $wpdb->get_results('SELECT ' . $cols . ' FROM `' . $table . '` ' . $where . $orderByStr . $limitStr . $offsetStr); if ($rows != null) { switch ($resultType) { case 'ids': foreach ($rows as $row) { $packages[] = $row->id; } break; case 'row': case 'fullRow': $packages = $rows; break; case 'objs': default: foreach ($rows as $row) { $Package = unserialize($row->package); if ($Package) { // We was not storing Status in Lite 1.2.52, so it is for backward compatibility if (!isset($Package->Status)) { $Package->Status = $row->status; } $packages[] = $Package; } } } } return $packages; } /** * Get packages row db with status conditions and/or pagination * * @param array // $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * if empty get all pacages * @param int $limit // max row numbers * @param int $offset // offset 0 is at begin * @param string $orderBy // default `id` ASC if empty no order * * @return object[] // return row database without package blob */ public static function get_row_by_status($conditions = array(), $limit = false, $offset = 0, $orderBy = '`id` ASC') { return self::get_packages_by_status($conditions, $limit, $offset, $orderBy, 'row'); } /** * Get packages ids with status conditions and/or pagination * * @param array // $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * if empty get all pacages * @param int $limit // max row numbers * @param int $offset // offset 0 is at begin * @param string $orderBy // default `id` ASC if empty no order * * @return array[] // return row database without package blob */ public static function get_ids_by_status($conditions = array(), $limit = false, $offset = 0, $orderBy = '`id` ASC') { return self::get_packages_by_status($conditions, $limit, $offset, $orderBy, 'ids'); } /** * count package with status condition * * @param array $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * * @return int */ public static function count_by_status($conditions = array()) { global $wpdb; $table = $wpdb->base_prefix . "duplicator_packages"; $where = self::statusContitionsToWhere($conditions); $count = $wpdb->get_var("SELECT count(id) FROM `{$table}` " . $where); return $count; } /** * Execute $callback function foreach package result * For each iteration the memory is released * * @param callable $callback // function callback(DUP_Package $package) * @param array // $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * if empty get all pacages * @param int $limit // max row numbers * @param int $offset // offset 0 is at begin * @param string $orderBy // default `id` ASC if empty no order * * @return void */ public static function by_status_callback($callback, $conditions = array(), $limit = false, $offset = 0, $orderBy = '`id` ASC') { if (!is_callable($callback)) { throw new Exception('No callback function passed'); } $offset = max(0, $offset); $numPackages = self::count_by_status($conditions); $maxLimit = $offset + ($limit !== false ? max(0, $limit) : PHP_INT_MAX - $offset); $numPackages = min($maxLimit, $numPackages); $orderByStr = empty($orderBy) ? '' : ' ORDER BY ' . $orderBy . ' '; global $wpdb; $table = $wpdb->base_prefix . "duplicator_packages"; $where = self::statusContitionsToWhere($conditions); $sql = 'SELECT * FROM `' . $table . '` ' . $where . $orderByStr . ' LIMIT 1 OFFSET '; for (; $offset < $numPackages; $offset++) { $rows = $wpdb->get_results($sql . $offset); if ($rows != null) { $Package = @unserialize($rows[0]->package); if ($Package) { if (empty($Package->ID)) { $Package->ID = $rows[0]->id; } // We was not storing Status in Lite 1.2.52, so it is for backward compatibility if (!isset($Package->Status)) { $Package->Status = $rows[0]->status; } call_user_func($callback, $Package); unset($Package); } unset($rows); } } } public static function purge_incomplete_package() { $packages = self::get_packages_by_status(array( 'relation' => 'AND', array('op' => '>=', 'status' => DUP_PackageStatus::CREATED), array('op' => '<', 'status' => DUP_PackageStatus::COMPLETE) ), 1, 0, '`id` ASC'); if (count($packages) > 0) { foreach ($packages as $package) { if (!$package->isRunning()) { $package->delete(); } } } } /** * Check the DupArchive build to make sure it is good * * @return void */ public function runDupArchiveBuildIntegrityCheck() { //INTEGRITY CHECKS //We should not rely on data set in the serlized object, we need to manually check each value //indepentantly to have a true integrity check. DUP_Log::info("\n********************************************************************************"); DUP_Log::info("INTEGRITY CHECKS:"); DUP_Log::info("********************************************************************************"); //------------------------ //SQL CHECK: File should be at minimum 5K. A base WP install with only Create tables is about 9K $sql_temp_path = DUP_Settings::getSsdirTmpPath() . '/' . $this->Database->File; $sql_temp_size = @filesize($sql_temp_path); $sql_easy_size = DUP_Util::byteSize($sql_temp_size); $sql_done_txt = DUP_Util::tailFile($sql_temp_path, 3); DUP_Log::Trace('[DUP ARCHIVE] ' . __FUNCTION__ . ' ' . __LINE__); // Note: Had to add extra size check of 800 since observed bad sql when filter was on if ( !strstr($sql_done_txt, 'DUPLICATOR_MYSQLDUMP_EOF') || ( !$this->Database->FilterOn && $sql_temp_size < 5120) || ($this->Database->FilterOn && $this->Database->info->tablesFinalCount > 0 && $sql_temp_size < 800 ) ) { DUP_Log::Trace('[DUP ARCHIVE] ' . __FUNCTION__ . ' ' . __LINE__); $error_text = "ERROR: SQL file not complete. The file {$sql_temp_path} looks too small ($sql_temp_size bytes) or the end of file marker was not found."; $this->BuildProgress->set_failed($error_text); $this->setStatus(DUP_PackageStatus::ERROR); DUP_Log::error("$error_text", '', Dup_ErrorBehavior::LogOnly); return; } DUP_Log::Trace('[DUP ARCHIVE] ' . __FUNCTION__ . ' ' . __LINE__); DUP_Log::Info("SQL FILE: {$sql_easy_size}"); //------------------------ //INSTALLER CHECK: $exe_temp_path = DUP_Settings::getSsdirTmpPath() . '/' . $this->Installer->File; $exe_temp_size = @filesize($exe_temp_path); $exe_easy_size = DUP_Util::byteSize($exe_temp_size); $exe_done_txt = DUP_Util::tailFile($exe_temp_path, 10); if (!strstr($exe_done_txt, 'DUPLICATOR_INSTALLER_EOF') && !$this->BuildProgress->failed) { //$this->BuildProgress->failed = true; $error_message = 'ERROR: Installer file not complete. The end of file marker was not found. Please try to re-create the package.'; $this->BuildProgress->set_failed($error_message); $this->Status = DUP_PackageStatus::ERROR; $this->update(); DUP_Log::error($error_message, '', Dup_ErrorBehavior::LogOnly); return; } DUP_Log::info("INSTALLER FILE: {$exe_easy_size}"); //------------------------ //ARCHIVE CHECK: DUP_LOG::trace("Archive file count is " . $this->Archive->file_count); if ($this->Archive->file_count != -1) { $zip_easy_size = DUP_Util::byteSize($this->Archive->Size); if (!($this->Archive->Size)) { //$this->BuildProgress->failed = true; $error_message = "ERROR: The archive file contains no size."; $this->BuildProgress->set_failed($error_message); $this->setStatus(DUP_PackageStatus::ERROR); DUP_Log::error($error_message, "Archive Size: {$zip_easy_size}", Dup_ErrorBehavior::LogOnly); return; } $scan_filepath = DUP_Settings::getSsdirTmpPath() . "/{$this->NameHash}_scan.json"; $json = ''; DUP_LOG::Trace("***********Does $scan_filepath exist?"); if (file_exists($scan_filepath)) { $json = file_get_contents($scan_filepath); } else { $error_message = sprintf(__("Can't find Scanfile %s. Please ensure there no non-English characters in the package or schedule name.", 'duplicator'), $scan_filepath); //$this->BuildProgress->failed = true; //$this->setStatus(DUP_PackageStatus::ERROR); $this->BuildProgress->set_failed($error_message); $this->setStatus(DUP_PackageStatus::ERROR); DUP_Log::error($error_message, '', Dup_ErrorBehavior::LogOnly); return; } $scanReport = json_decode($json); //RSR TODO: rework/simplify the validateion of duparchive $dirCount = count($scanReport->ARC->Dirs); $numInstallerDirs = $this->Installer->numDirsAdded; $fileCount = count($scanReport->ARC->Files); $numInstallerFiles = $this->Installer->numFilesAdded; $expected_filecount = $dirCount + $numInstallerDirs + $fileCount + $numInstallerFiles + 1 - 1; // Adding database.sql but subtracting the root dir //Dup_Log::trace("#### a:{$dirCount} b:{$numInstallerDirs} c:{$fileCount} d:{$numInstallerFiles} = {$expected_filecount}"); DUP_Log::info("ARCHIVE FILE: {$zip_easy_size} "); DUP_Log::info(sprintf(__('EXPECTED FILE/DIRECTORY COUNT: %1$s', 'duplicator'), number_format($expected_filecount))); DUP_Log::info(sprintf(__('ACTUAL FILE/DIRECTORY COUNT: %1$s', 'duplicator'), number_format($this->Archive->file_count))); $this->ExeSize = $exe_easy_size; $this->ZipSize = $zip_easy_size; /* ------- ZIP Filecount Check -------- */ // Any zip of over 500 files should be within 2% - this is probably too loose but it will catch gross errors DUP_LOG::trace("Expected filecount = $expected_filecount and archive filecount=" . $this->Archive->file_count); if ($expected_filecount > 500) { $straight_ratio = (float) $expected_filecount / (float) $this->Archive->file_count; $warning_count = $scanReport->ARC->WarnFileCount + $scanReport->ARC->WarnDirCount + $scanReport->ARC->UnreadableFileCount + $scanReport->ARC->UnreadableDirCount; DUP_LOG::trace( "Warn/unread counts) warnfile:{$scanReport->ARC->WarnFileCount} warndir:{$scanReport->ARC->WarnDirCount}" . " unreadfile:{$scanReport->ARC->UnreadableFileCount} unreaddir:{$scanReport->ARC->UnreadableDirCount}" ); $warning_ratio = ((float) ($expected_filecount + $warning_count)) / (float) $this->Archive->file_count; DUP_LOG::trace( "Straight ratio is $straight_ratio and warning ratio is $warning_ratio. # Expected=$expected_filecount " . "# Warning=$warning_count and #Archive File {$this->Archive->file_count}" ); // Allow the real file count to exceed the expected by 10% but only allow 1% the other way if (($straight_ratio < 0.90) || ($straight_ratio > 1.01)) { // Has to exceed both the straight as well as the warning ratios if (($warning_ratio < 0.90) || ($warning_ratio > 1.01)) { $error_message = sprintf('ERROR: File count in archive vs expected suggests a bad archive (%1$d vs %2$d).', $this->Archive->file_count, $expected_filecount); $this->BuildProgress->set_failed($error_message); $this->Status = DUP_PackageStatus::ERROR; $this->update(); DUP_Log::error($error_message, ''); return; } } } } /* ------ ZIP CONSISTENCY CHECK ------ */ if ($this->Archive->getBuildMode() == DUP_Archive_Build_Mode::ZipArchive) { DUP_LOG::trace("Running ZipArchive consistency check"); $zipPath = DUP_Settings::getSsdirTmpPath() . "/{$this->Archive->File}"; $zip = new ZipArchive(); // ZipArchive::CHECKCONS will enforce additional consistency checks $res = $zip->open($zipPath, ZipArchive::CHECKCONS); if ($res !== true) { $consistency_error = sprintf(__('ERROR: Cannot open created archive. Error code = %1$s', 'duplicator'), $res); DUP_LOG::trace($consistency_error); switch ($res) { case ZipArchive::ER_NOZIP: $consistency_error = __('ERROR: Archive is not valid zip archive.', 'duplicator'); break; case ZipArchive::ER_INCONS: $consistency_error = __("ERROR: Archive doesn't pass consistency check.", 'duplicator'); break; case ZipArchive::ER_CRC: $consistency_error = __("ERROR: Archive checksum is bad.", 'duplicator'); break; } $this->BuildProgress->set_failed($consistency_error); $this->Status = DUP_PackageStatus::ERROR; $this->update(); DUP_LOG::trace($consistency_error); DUP_Log::error($consistency_error, ''); } else { DUP_Log::info(__('ARCHIVE CONSISTENCY TEST: Pass', 'duplicator')); DUP_LOG::trace("Zip for package $this->ID passed consistency test"); } $zip->close(); } } public function getLocalPackageFile($file_type) { $file_path = null; if ($file_type == DUP_PackageFileType::Installer) { DUP_Log::Trace("Installer requested"); $file_name = apply_filters('duplicator_installer_file_path', $this->getInstallerFilename()); } elseif ($file_type == DUP_PackageFileType::Archive) { DUP_Log::Trace("Archive requested"); $file_name = $this->getArchiveFilename(); } elseif ($file_type == DUP_PackageFileType::SQL) { DUP_Log::Trace("SQL requested"); $file_name = $this->getDatabaseFilename(); } else { DUP_Log::Trace("Log requested"); $file_name = $this->getLogFilename(); } $file_path = DUP_Settings::getSsdirPath() . "/$file_name"; DUP_Log::Trace("File path $file_path"); if (file_exists($file_path)) { return $file_path; } else { return null; } } public function getScanFilename() { return $this->NameHash . '_scan.json'; } public function getScanUrl() { return DUP_Settings::getSsdirUrl() . "/" . $this->getScanFilename(); } public function getLogFilename() { return $this->NameHash . '.log'; } public function getLogUrl() { return DUP_Settings::getSsdirUrl() . "/" . $this->getLogFilename(); } public function getArchiveFilename() { $extension = strtolower($this->Archive->Format); return "{$this->NameHash}_archive.{$extension}"; } public function getInstallerFilename() { return "{$this->NameHash}_installer" . DUP_Installer::INSTALLER_SERVER_EXTENSION; } public function getDatabaseFilename() { return $this->NameHash . '_database.sql'; } public function get_files_list_filename() { return $this->NameHash . DUP_Archive::FILES_LIST_FILE_NAME_SUFFIX; } public function get_dirs_list_filename() { return $this->NameHash . DUP_Archive::DIRS_LIST_FILE_NAME_SUFFIX; } /** * @param int $type * * @return array */ public function getPackageFileDownloadInfo($type) { $result = array( "filename" => "", "url" => "" ); switch ($type) { case DUP_PackageFileType::Archive: $result["filename"] = $this->Archive->File; $result["url"] = $this->Archive->getURL(); break; case DUP_PackageFileType::SQL: $result["filename"] = $this->Database->File; $result["url"] = $this->Database->getURL(); break; case DUP_PackageFileType::Log: $result["filename"] = $this->getLogFilename(); $result["url"] = $this->getLogUrl(); break; case DUP_PackageFileType::Scan: $result["filename"] = $this->getScanFilename(); $result["url"] = $this->getScanUrl(); break; default: break; } return $result; } public function getInstallerDownloadInfo() { return array( "id" => $this->ID, "hash" => $this->Hash ); } /** * Removes all files except those of active packages */ public static function not_active_files_tmp_cleanup() { //Check for the 'tmp' folder just for safe measures if (! is_dir(DUP_Settings::getSsdirTmpPath()) && (strpos(DUP_Settings::getSsdirTmpPath(), 'tmp') !== false)) { return; } $globs = glob(DUP_Settings::getSsdirTmpPath() . '/*.*'); if (! is_array($globs) || $globs === false) { return; } // RUNNING PACKAGES $active_pack = self::get_row_by_status(array( 'relation' => 'AND', array('op' => '>=' , 'status' => DUP_PackageStatus::CREATED ), array('op' => '<' , 'status' => DUP_PackageStatus::COMPLETE ) )); $active_files = array(); foreach ($active_pack as $row) { $active_files[] = $row->name . '_' . $row->hash; } // ERRORS PACKAGES $err_pack = self::get_row_by_status(array( array('op' => '<' , 'status' => DUP_PackageStatus::CREATED ) )); $force_del_files = array(); foreach ($err_pack as $row) { $force_del_files[] = $row->name . '_' . $row->hash; } // Don't remove json file; $extension_filter = array('json', 'txt'); // Calculate delta time for old files $oldTimeToClean = time() - DUPLICATOR_TEMP_CLEANUP_SECONDS; foreach ($globs as $glob_full_path) { // Don't remove sub dir if (is_dir($glob_full_path)) { continue; } $file_name = basename($glob_full_path); // skip all active packages foreach ($active_files as $c_nameHash) { if (strpos($file_name, $c_nameHash) === 0) { continue 2; } } // Remove all old files if (filemtime($glob_full_path) <= $oldTimeToClean) { @unlink($glob_full_path); continue; } // remove all error packages files foreach ($force_del_files as $c_nameHash) { if (strpos($file_name, $c_nameHash) === 0) { @unlink($glob_full_path); continue 2; } } $file_info = pathinfo($glob_full_path); // skip json file for pre build packages if (in_array($file_info['extension'], $extension_filter) || in_array($file_name, $active_files)) { continue; } @unlink($glob_full_path); } } /** * Cleans up the temp storage folder have a time interval * * @return void */ public static function safeTmpCleanup($purge_temp_archives = false) { if ($purge_temp_archives) { $dir = DUP_Settings::getSsdirTmpPath() . "/*_archive.zip.*"; foreach (glob($dir) as $file_path) { unlink($file_path); } $dir = DUP_Settings::getSsdirTmpPath() . "/*_archive.daf.*"; foreach (glob($dir) as $file_path) { unlink($file_path); } } else { //Remove all temp files that are 24 hours old $dir = DUP_Settings::getSsdirTmpPath() . "/*"; $files = glob($dir); if ($files !== false) { foreach ($files as $file_path) { // Cut back to keeping things around for just an hour 15 min if (filemtime($file_path) <= time() - DUPLICATOR_TEMP_CLEANUP_SECONDS) { unlink($file_path); } } } } } /** * Starts the package DupArchive progressive build process - always assumed to only run off active package, NOT one in the package table * * @return obj Returns a DUP_Package object */ public function runDupArchiveBuild() { $this->BuildProgress->start_timer(); DUP_Log::Trace('Called'); if ($this->BuildProgress->failed) { DUP_LOG::Trace("build progress failed so setting package to failed"); $this->setStatus(DUP_PackageStatus::ERROR); $message = "Package creation failed."; DUP_Log::Trace($message); return true; } if ($this->BuildProgress->initialized == false) { DUP_Log::Trace('[DUP ARCHIVE] INIZIALIZE'); $this->BuildProgress->initialized = true; $this->TimerStart = Dup_Util::getMicrotime(); $this->update(); } //START BUILD if (!$this->BuildProgress->database_script_built) { DUP_Log::Info('[DUP ARCHIVE] BUILDING DATABASE'); $this->Database->build($this, Dup_ErrorBehavior::ThrowException); DUP_Log::Info('[DUP ARCHIVE] VALIDATING DATABASE'); $this->BuildProgress->database_script_built = true; $this->update(); DUP_Log::Info('[DUP ARCHIVE] DONE DATABASE'); } elseif (!$this->BuildProgress->archive_built) { DUP_Log::Info('[DUP ARCHIVE] BUILDING ARCHIVE'); $this->Archive->build($this); $this->update(); DUP_Log::Info('[DUP ARCHIVE] DONE ARCHIVE'); } elseif (!$this->BuildProgress->installer_built) { DUP_Log::Info('[DUP ARCHIVE] BUILDING INSTALLER'); // Installer being built is stuffed into the archive build phase } if ($this->BuildProgress->has_completed()) { DUP_Log::Info('[DUP ARCHIVE] HAS COMPLETED CLOSING'); if (!$this->BuildProgress->failed) { DUP_LOG::Info("[DUP ARCHIVE] DUP ARCHIVE INTEGRITY CHECK"); // Only makees sense to perform build integrity check on completed archives $this->runDupArchiveBuildIntegrityCheck(); } else { DUP_LOG::trace("top of loop build progress failed"); } $timerEnd = DUP_Util::getMicrotime(); $timerSum = DUP_Util::elapsedTime($timerEnd, $this->TimerStart); $this->Runtime = $timerSum; //FINAL REPORT $info = "\n********************************************************************************\n"; $info .= "RECORD ID:[{$this->ID}]\n"; $info .= "TOTAL PROCESS RUNTIME: {$timerSum}\n"; $info .= "PEAK PHP MEMORY USED: " . DUP_Server::getPHPMemory(true) . "\n"; $info .= "DONE PROCESSING => {$this->Name} " . @date("Y-m-d H:i:s") . "\n"; DUP_Log::info($info); DUP_LOG::trace("Done package building"); if (!$this->BuildProgress->failed) { DUP_Log::Trace('[DUP ARCHIVE] HAS COMPLETED DONE'); $this->setStatus(DUP_PackageStatus::COMPLETE); DUP_LOG::Trace("Cleaning up duparchive temp files"); //File Cleanup $this->buildCleanup(); do_action('duplicator_lite_build_completed', $this); } else { DUP_Log::Trace('[DUP ARCHIVE] HAS COMPLETED ERROR'); } } DUP_Log::Close(); return $this->BuildProgress->has_completed(); } /** * Starts the package build process * * @return obj Returns a DUP_Package object */ public function runZipBuild() { $timerStart = DUP_Util::getMicrotime(); DUP_Log::Trace('#### start of zip build'); //START BUILD //PHPs serialze method will return the object, but the ID above is not passed //for one reason or another so passing the object back in seems to do the trick $this->Database->build($this, Dup_ErrorBehavior::ThrowException); $this->Archive->build($this); $this->Installer->build($this); //INTEGRITY CHECKS /*DUP_Log::Info("\n********************************************************************************"); DUP_Log::Info("INTEGRITY CHECKS:"); DUP_Log::Info("********************************************************************************");*/ $this->runDupArchiveBuildIntegrityCheck(); $dbSizeRead = DUP_Util::byteSize($this->Database->Size); $zipSizeRead = DUP_Util::byteSize($this->Archive->Size); $exeSizeRead = DUP_Util::byteSize($this->Installer->Size); $timerEnd = DUP_Util::getMicrotime(); $timerSum = DUP_Util::elapsedTime($timerEnd, $timerStart); $this->Runtime = $timerSum; $this->ExeSize = $exeSizeRead; $this->ZipSize = $zipSizeRead; $this->buildCleanup(); //FINAL REPORT $info = "\n********************************************************************************\n"; $info .= "RECORD ID:[{$this->ID}]\n"; $info .= "TOTAL PROCESS RUNTIME: {$timerSum}\n"; $info .= "PEAK PHP MEMORY USED: " . DUP_Server::getPHPMemory(true) . "\n"; $info .= "DONE PROCESSING => {$this->Name} " . @date(get_option('date_format') . " " . get_option('time_format')) . "\n"; DUP_Log::Info($info); DUP_Log::Close(); $this->setStatus(DUP_PackageStatus::COMPLETE); return $this; } /** * Saves the active options associted with the active(latest) package. * * @see DUP_Package::getActive * * @param $_POST $post The Post server object * * @return null */ public function saveActive($post = null) { global $wp_version; if (isset($post)) { $post = stripslashes_deep($post); $name = isset($post['package-name']) ? trim($post['package-name']) : self::getDefaultName(); $name = str_replace(array(' ', '-'), '_', $name); $name = str_replace(array('.', ';', ':', "'", '"'), '', $name); $name = sanitize_file_name($name); $name = substr(trim($name), 0, 40); if (isset($post['filter-dirs'])) { $post_filter_dirs = sanitize_text_field($post['filter-dirs']); $filter_dirs = $this->Archive->parseDirectoryFilter($post_filter_dirs); } else { $filter_dirs = ''; } if (isset($post['filter-files'])) { $post_filter_files = sanitize_text_field($post['filter-files']); $filter_files = $this->Archive->parseFileFilter($post_filter_files); } else { $filter_files = ''; } if (isset($post['filter-exts'])) { $post_filter_exts = sanitize_text_field($post['filter-exts']); $filter_exts = $this->Archive->parseExtensionFilter($post_filter_exts); } else { $filter_exts = ''; } $tablelist = ''; if (isset($post['dbtables'])) { $tablelist = implode(',', $post['dbtables']); } if (isset($post['dbcompat'])) { $compatlist = is_array($post['dbcompat']) ? implode(',', $post['dbcompat']) : sanitize_text_field($post['dbcompat']); } else { $compatlist = ''; } $dbversion = DUP_DB::getVersion(); $dbversion = is_null($dbversion) ? '- unknown -' : sanitize_text_field($dbversion); $dbcomments = sanitize_text_field(DUP_DB::getVariable('version_comment')); $dbcomments = is_null($dbcomments) ? '- unknown -' : sanitize_text_field($dbcomments); //PACKAGE $this->Created = gmdate("Y-m-d H:i:s"); $this->Version = DUPLICATOR_VERSION; $this->VersionOS = defined('PHP_OS') ? PHP_OS : 'unknown'; $this->VersionWP = $wp_version; $this->VersionPHP = phpversion(); $this->VersionDB = sanitize_text_field($dbversion); $this->Name = sanitize_text_field($name); $this->Hash = $this->makeHash(); $this->NameHash = sanitize_text_field("{$this->Name}_{$this->Hash}"); $this->Notes = sanitize_textarea_field($post['package-notes']); //ARCHIVE $this->Archive->Format = 'ZIP'; $this->Archive->FilterOn = isset($post['filter-on']) ? 1 : 0; $this->Archive->ExportOnlyDB = isset($post['export-onlydb']) ? 1 : 0; $this->Archive->FilterDirs = sanitize_textarea_field($filter_dirs); $this->Archive->FilterFiles = sanitize_textarea_field($filter_files); $this->Archive->FilterExts = str_replace(array('.', ' '), '', $filter_exts); //INSTALLER $this->Installer->OptsDBHost = sanitize_text_field($post['dbhost']); $this->Installer->OptsDBPort = sanitize_text_field($post['dbport']); $this->Installer->OptsDBName = sanitize_text_field($post['dbname']); $this->Installer->OptsDBUser = sanitize_text_field($post['dbuser']); $this->Installer->OptsDBCharset = sanitize_text_field($post['dbcharset']); $this->Installer->OptsDBCollation = sanitize_text_field($post['dbcollation']); $this->Installer->OptsSecureOn = isset($post['secure-on']) ? 1 : 0; $post_secure_pass = sanitize_text_field($post['secure-pass']); $this->Installer->OptsSecurePass = DUP_Util::installerScramble($post_secure_pass); //DATABASE $this->Database->FilterOn = isset($post['dbfilter-on']) ? 1 : 0; $this->Database->FilterTables = sanitize_text_field($tablelist); $this->Database->Compatible = $compatlist; $this->Database->Comments = sanitize_text_field($dbcomments); update_option(self::OPT_ACTIVE, $this); } } /** * Update the serialized package and status in the database * * @return void */ public function update() { global $wpdb; $this->Status = number_format($this->Status, 1, '.', ''); $this->cleanObjectBeforeSave(); $packageObj = serialize($this); if (!$packageObj) { DUP_Log::error("Package SetStatus was unable to serialize package object while updating record."); } $wpdb->flush(); $tablePrefix = DUP_Util::getTablePrefix(); $table = $tablePrefix . "duplicator_packages"; $sql = "UPDATE `{$table}` SET status = {$this->Status},"; $sql .= "package = '" . esc_sql($packageObj) . "'"; $sql .= "WHERE ID = {$this->ID}"; DUP_Log::Trace("UPDATE PACKAGE ID = {$this->ID} STATUS = {$this->Status}"); //DUP_Log::Trace('####Executing SQL' . $sql . '-----------'); $wpdb->query($sql); } /** * Save any property of this class through reflection * * @param $property A valid public property in this class * @param $value The value for the new dynamic property * * @return null */ public function saveActiveItem($property, $value) { $package = self::getActive(); $reflectionClass = new ReflectionClass($package); $reflectionClass->getProperty($property)->setValue($package, $value); update_option(self::OPT_ACTIVE, $package); } /** * Sets the status to log the state of the build * The status level for where the package is * * @param int $status * * @return void */ public function setStatus($status) { if (!isset($status)) { DUP_Log::error("Package SetStatus did not receive a proper code."); } $this->Status = $status; $this->update(); } /** * Does a hash already exists * Returns 0 if no hash is found, if found returns the table ID * * @param string $hash An existing hash value * * @return int */ public function getHashKey($hash) { global $wpdb; $tablePrefix = DUP_Util::getTablePrefix(); $table = $tablePrefix . "duplicator_packages"; $qry = $wpdb->get_row("SELECT ID, hash FROM `{$table}` WHERE hash = '{$hash}'"); if (is_null($qry) || strlen($qry->hash) == 0) { return 0; } else { return $qry->ID; } } /** * Makes the hashkey for the package files * * @return string // A unique hashkey */ public function makeHash() { try { if (function_exists('random_bytes') && DUP_Util::PHP53()) { return bin2hex(random_bytes(8)) . mt_rand(1000, 9999) . '_' . date("YmdHis"); } else { return strtolower(md5(uniqid(rand(), true))) . '_' . date("YmdHis"); } } catch (Exception $exc) { return strtolower(md5(uniqid(rand(), true))) . '_' . date("YmdHis"); } } /** * Gets the active package which is defined as the package that was lasted saved. * Do to cache issues with the built in WP function get_option moved call to a direct DB call. * * @see DUP_Package::saveActive * * @return DUP_Package // A copy of the DUP_Package object */ public static function getActive() { global $wpdb; $obj = new DUP_Package(); $row = $wpdb->get_row($wpdb->prepare("SELECT option_value FROM `{$wpdb->options}` WHERE option_name = %s LIMIT 1", self::OPT_ACTIVE)); if (is_object($row)) { $obj = @unserialize($row->option_value); } //Incase unserilaize fails $obj = (is_object($obj)) ? $obj : new DUP_Package(); return $obj; } /** * Gets the Package by ID * * @param int $id A valid package id form the duplicator_packages table * * @return DUP_Package // A copy of the DUP_Package object */ public static function getByID($id) { global $wpdb; $obj = new DUP_Package(); $tablePrefix = DUP_Util::getTablePrefix(); $sql = $wpdb->prepare("SELECT * FROM `{$tablePrefix}duplicator_packages` WHERE ID = %d", $id); $row = $wpdb->get_row($sql); if (is_object($row)) { $obj = @unserialize($row->package); // We was not storing Status in Lite 1.2.52, so it is for backward compatibility if (!isset($obj->Status)) { $obj->Status = $row->status; } } //Incase unserilaize fails $obj = (is_object($obj)) ? $obj : null; return $obj; } /** * Gets a default name for the package * * @return string // A default package name such as 20170218_blogname */ public static function getDefaultName($preDate = true) { //Remove specail_chars from final result $special_chars = array(".", "-"); $name = ($preDate) ? date('Ymd') . '_' . sanitize_title(get_bloginfo('name', 'display')) : sanitize_title(get_bloginfo('name', 'display')) . '_' . date('Ymd'); $name = substr(sanitize_file_name($name), 0, 40); $name = str_replace($special_chars, '', $name); return $name; } /** * Cleanup all tmp files * * @param all empty all contents * * @return null */ public static function tempFileCleanup($all = false) { if ($all) { //Delete all files now $dir = DUP_Settings::getSsdirTmpPath() . "/*"; foreach (glob($dir) as $file) { @unlink($file); } } else { //Remove scan files that are 24 hours old $dir = DUP_Settings::getSsdirTmpPath() . "/*_scan.json"; foreach (glob($dir) as $file) { if (filemtime($file) <= time() - 86400) { @unlink($file); } } } } /** * Provides various date formats * * @param $utcDate created date in the GMT timezone * @param $format Various date formats to apply * * @return string // a formated date based on the $format */ public static function getCreatedDateFormat($utcDate, $format = 1) { $date = get_date_from_gmt($utcDate); $date = new DateTime($date); switch ($format) { //YEAR case 1: return $date->format('Y-m-d H:i'); break; case 2: return $date->format('Y-m-d H:i:s'); break; case 3: return $date->format('y-m-d H:i'); break; case 4: return $date->format('y-m-d H:i:s'); break; //MONTH case 5: return $date->format('m-d-Y H:i'); break; case 6: return $date->format('m-d-Y H:i:s'); break; case 7: return $date->format('m-d-y H:i'); break; case 8: return $date->format('m-d-y H:i:s'); break; //DAY case 9: return $date->format('d-m-Y H:i'); break; case 10: return $date->format('d-m-Y H:i:s'); break; case 11: return $date->format('d-m-y H:i'); break; case 12: return $date->format('d-m-y H:i:s'); break; default: return $date->format('Y-m-d H:i'); } } /** * Cleans up all the tmp files as part of the package build process */ public function buildCleanup() { $files = DUP_Util::listFiles(DUP_Settings::getSsdirTmpPath()); $newPath = DUP_Settings::getSsdirPath(); $filesToStore = array( $this->Installer->File, $this->Archive->File, ); foreach ($files as $file) { $fileName = basename($file); if (!strstr($fileName, $this->NameHash)) { continue; } if (in_array($fileName, $filesToStore)) { if (function_exists('rename')) { rename($file, "{$newPath}/{$fileName}"); } elseif (function_exists('copy')) { copy($file, "{$newPath}/{$fileName}"); } else { throw new Exception('PHP copy and rename functions not found! Contact hosting provider!'); } } if (file_exists($file)) { unlink($file); } } } /** * Get package hash * * @return string package hash */ public function getPackageHash() { $hashParts = explode('_', $this->Hash); $firstPart = substr($hashParts[0], 0, 7); $secondPart = substr($hashParts[1], -8); $package_hash = $firstPart . '-' . $secondPart; return $package_hash; } public function getSecondaryPackageHash() { $newHash = $this->makeHash(); $hashParts = explode('_', $newHash); $firstPart = substr($hashParts[0], 0, 7); $hashParts = explode('_', $this->Hash); $secondPart = substr($hashParts[1], -8); $package_hash = $firstPart . '-' . $secondPart; return $package_hash; } /** * Provides the full sql file path in archive * * @return the full sql file path in archive */ public function getSqlArkFilePath() { $package_hash = $this->getPackageHash(); $sql_ark_file_Path = 'dup-installer/dup-database__' . $package_hash . '.sql'; return $sql_ark_file_Path; } private function writeLogHeader() { $php_max_time = @ini_get("max_execution_time"); if (SnapUtil::isIniValChangeable('memory_limit')) { $php_max_memory = @ini_set('memory_limit', DUPLICATOR_PHP_MAX_MEMORY); } else { $php_max_memory = @ini_get('memory_limit'); } $php_max_time = ($php_max_time == 0) ? "(0) no time limit imposed" : "[{$php_max_time}] not allowed"; $php_max_memory = ($php_max_memory === false) ? "Unabled to set php memory_limit" : DUPLICATOR_PHP_MAX_MEMORY . " ({$php_max_memory} default)"; $info = "********************************************************************************\n"; $info .= "DUPLICATOR-LITE PACKAGE-LOG: " . @date(get_option('date_format') . " " . get_option('time_format')) . "\n"; $info .= "NOTICE: Do NOT post to public sites or forums \n"; $info .= "********************************************************************************\n"; $info .= "VERSION:\t" . DUPLICATOR_VERSION . "\n"; $info .= "WORDPRESS:\t{$GLOBALS['wp_version']}\n"; $info .= "PHP INFO:\t" . phpversion() . ' | ' . 'SAPI: ' . php_sapi_name() . "\n"; $info .= "SERVER:\t\t{$_SERVER['SERVER_SOFTWARE']} \n"; $info .= "PHP TIME LIMIT: {$php_max_time} \n"; $info .= "PHP MAX MEMORY: {$php_max_memory} \n"; $info .= "MEMORY STACK: " . DUP_Server::getPHPMemory(); DUP_Log::Info($info); $info = null; } /** * Return package life * * @param string $type can be hours,human,timestamp * * @return int|string package life in hours, timestamp or human readable format */ public function getPackageLife($type = 'timestamp') { $created = strtotime($this->Created); $current = strtotime(gmdate("Y-m-d H:i:s")); $delta = $current - $created; switch ($type) { case 'hours': return max(0, floor($delta / 60 / 60)); case 'human': return human_time_diff($created, $current); case 'timestamp': default: return $delta; } } }