getPathname()); } return $files; } catch (Exception $exc) { $result = array(); $files = @scandir($path); if (is_array($files)) { foreach ($files as $file) { $result[] = str_replace("\\", '/', $path) . $file; } } return $result; } } /** * Get only the files and excludes directories and dots * * @param string $dir The full path to the directory * * @return array of only files in that path */ public static function getFilesOnly($dir = '.') { $files = array(); foreach (new DirectoryIterator($dir) as $file) { if (!$file->isDir()) $files[] = str_replace("\\", '/', $file->getPathname()); } return $files; } /** * Safely creates a directory * * @param string $dir The full path to the directory to be created * @param octal $mode The mode is 0755 by default * @param bool $recursive Allows the creation of nested directories specified in the pathname. * * @return TRUE on success and if directory already exists. FALSE on failure */ public static function createDir($dir, $mode = 0755, $recursive = false) { if (file_exists($dir) && @is_dir($dir)) return true; if (@mkdir($dir, $mode, $recursive) === false) { DUP_PRO_LOG::traceError("Error creating directory: {$dir}."); return false; } return true; } /** * List all of the directories of a path * * @param string $dir to a system directory * * @return array of all directories in that path */ public static function getDirs($dir = '.') { $dirs = array(); foreach (new DirectoryIterator($dir) as $file) { if ($file->isDir() && !$file->isDot()) { $dirs[] = DUP_PRO_U::safePath($file->getPathname()); } } return $dirs; } /** * Does the directory have content * * @param string $dir A system directory * * @return array of all directories in that path */ public static function isDirEmpty($dir) { if (!is_readable($dir)) return NULL; return (count(scandir($dir)) == 2); } /** * Size of the directory recursively in bytes * * @param string $dir A system directory * * @return int Returns the size of all data in the directory in bytes */ public static function getDirSize($dir) { if (!file_exists($dir)) return 0; if (is_file($dir)) return filesize($dir); $size = 0; $list = glob($dir . "/*"); if (!empty($list)) { foreach ($list as $file) $size += self::getDirSize($file); } return $size; } /** * @todo ASKBOB */ public static function restoreBackup($filepath, $backup_filepath) { if (is_dir($filepath) || (file_exists($filepath) && (is_file($filepath) == false))) { DUP_PRO_LOG::trace("Trying to restore backup to a directory ($filepath) rather than file which isn't allowed."); } if (file_exists($filepath)) { DUP_PRO_LOG::trace("Deleting $filepath"); if (@unlink($filepath)) { DUP_PRO_LOG::trace("Deleted $filepath"); } else { $message = "Couldn't delete $filepath"; DUP_PRO_Log::error($message, false); DUP_PRO_LOG::trace($message); } } if (file_exists($backup_filepath)) { DUP_PRO_LOG::trace("Renaming $backup_filepath to $filepath"); if (@rename($backup_filepath, $filepath)) { DUP_PRO_LOG::trace("Renamed $backup_filepath to $filepath"); } else { $message = "Couldn't rename $backup_filepath to $filepath"; DUP_PRO_Log::error($message, false); DUP_PRO_LOG::trace($message); } } } /** * @todo ASKBOB */ public static function copyToDir($filepath, $directory) { if(!file_exists($directory)) { @mkdir($directory); } $destination_filepath = $directory . '/' . basename($filepath); return @copy($filepath, $destination_filepath); } public static function deleteTree($directory) { $success = true; if(!file_exists("{$directory}/wp-config.php")) { $filenames = array_diff(scandir($directory), array('.', '..')); foreach ($filenames as $filename) { if (is_dir("$directory/$filename")) { $success = self::deleteTree("$directory/$filename"); } else { $success = @unlink("$directory/$filename"); } if ($success === false) { DUP_PRO_LOG::trace("Problem deleting $directory/$filename"); break; } } } else { DUP_PRO_LOG::trace("Attempted to delete a directory with wp-config.php in it! ({$directory})"); return false; } return $success && @rmdir($directory); } public static function copyDir($src, $dst) { $success = true; $dir = opendir($src); @mkdir($dst); while (false !== ( $file = readdir($dir))) { if (( $file != '.' ) && ( $file != '..' )) { if (is_dir($src . '/' . $file)) { $success = $success && self::copyDir($src . '/' . $file, $dst . '/' . $file); } else { $src_filepath = $src . '/' . $file; $dst_filepath = $dst . '/' . $file; DUP_PRO_LOG::trace("attempting to copy $src_filepath to $dst_filepath"); if (copy($src_filepath, $dst_filepath) === false) { $success = false; //self::log("error copy $src_filepath to $dst_filepath"); DUP_PRO_LOG::trace("error copy $src_filepath to $dst_filepath"); } } } } closedir($dir); return $success; } public static function copyWithVerify($source_filepath, $dest_filepath) { DUP_PRO_LOG::trace("Copy with verify $source_filepath to $dest_filepath"); $ret_val = false; if (copy($source_filepath, $dest_filepath)) { if (function_exists('sha1_file')) { $source_sha1 = sha1_file($source_filepath); $dest_sha1 = sha1_file($dest_filepath); if ($source_sha1 === $dest_sha1 && ($source_sha1 !== false)) { DUP_PRO_LOG::trace("Sha1 of $source_filepath and $dest_filepath match"); $ret_val = true; } else { DUP_PRO_LOG::trace("Sha1 hash of $dest_filepath doesn't match $source_filepath!"); } } else { DUP_PRO_LOG::trace("sha1_file not present so doing existence check"); $ret_val = file_exists($dest_filepath); if ($ret_val != true) { DUP_PRO_LOG::trace("$dest_filepath doesn't exist after copy!"); } } } else { DUP_PRO_LOG::trace("Problem copying $source_filepath to $dest_filepath"); } return $ret_val; } /** * @todo ASKBOB */ // Copy source to destination while preserving the backup if the destination already exists // Note: Intended to be used during package building only since fatal log errors are utilized public static function copyWithBackup($source_filepath, $dest_filepath, $backup_filepath) { DUP_PRO_LOG::trace("Copy with backup $source_filepath $dest_filepath $backup_filepath"); if (is_dir($dest_filepath) || (file_exists($dest_filepath) && (is_file($dest_filepath) == false))) { DUP_PRO_Log::error("Trying to copy to a directory ($dest_filepath) not a file which isn't allowed."); } // In the event there is a file with that same name present we have to save it off into $backup_filepath if (file_exists($backup_filepath)) { DUP_PRO_LOG::trace("Deleting $backup_filepath"); if (@unlink($backup_filepath)) { DUP_PRO_LOG::trace("Deleted $backup_filepath"); } else { DUP_PRO_Log::error("ERROR: Couldn't delete backup file $backup_filepath"); } } if (file_exists($dest_filepath)) { DUP_PRO_LOG::trace("Renaming $dest_filepath to $backup_filepath"); if (@rename($dest_filepath, $backup_filepath)) { DUP_PRO_LOG::trace("Renamed $dest_filepath to $backup_filepath"); } else { DUP_PRO_Log::error("ERROR: Couldn't rename $dest_filepath $backup_filepath"); } } DUP_PRO_LOG::trace("Copying $source_filepath to $dest_filepath"); if (copy($source_filepath, $dest_filepath)) { DUP_PRO_LOG::trace("Copied $source_filepath to $dest_filepath"); } else { @rename($backup_filepath, $dest_filepath); DUP_PRO_Log::error("ERROR: Couldn't copy the $source_filepath to $dest_filepath"); } } } InitializeSystemSettings(); $global->ResetUserSettings(); // Default local selected by default array_push($global->manual_mode_storage_ids, -2); $global->save(); } } public function InitializeSystemSettings() { //STORAGE $this->manual_mode_storage_ids = array(); //LICENSING $this->license_status = DUP_PRO_License_Status::Unknown; $this->license_expiration_time = time() - 10; // Ensure it expires right away $this->license_no_activations_left = false; $this->license_key_visible = true; $this->lkp = ''; // Not actively used but required for upgrade $this->license_limit = -1; //UPDATE CACHING $this->last_edd_api_response = null; $this->last_edd_api_timestamp = 0; $this->last_system_check_timestamp = 0; $this->initial_activation_timestamp = 0; } // Resets to defaults public function ResetUserSettings() { //GENERAL $this->uninstall_settings = false; $this->uninstall_files = false; $this->uninstall_tables = true; $this->wpfront_integrate = false; //PACKAGES::Visual $this->package_ui_created = 1; //PACKAGES::Basic::Database $this->package_mysqldump = true; $this->package_mysqldump_path = ''; $this->package_phpdump_qrylimit = 100; //PACKAGES::Basic::Archive $this->archive_build_mode = DUP_PRO_Archive_Build_Mode::Unconfigured; $this->archive_compression = true; // TODO: PHP 7 allows ZipArchive to be set to Store - implement later $this->ziparchive_validation = false; $this->ziparchive_mode = DUP_PRO_ZipArchive_Mode::Multithreaded; $this->ziparchive_chunk_size_in_mb = 6; $this->archive_build_mode_schedule = DUP_PRO_Archive_Build_Mode::Unconfigured; $this->archive_compression_schedule = true; //PACKAGES::Basic::Processing $this->server_load_reduction = DUP_PRO_Server_Load_Reduction::None; $this->max_package_runtime_in_min = 90; $this->php_max_worker_time_in_sec = 15; //PACKAGES::Adanced $this->lock_mode = self::get_lock_type(); $this->json_mode = DUP_PRO_JSON_Mode::PHP; $this->ajax_protocol = "http"; $this->custom_ajax_url = ""; $this->clientside_kickoff = false; $this->basic_auth_enabled = false; $this->basic_auth_user = ''; // Not actively used but required for upgrade $this->basic_auth_password = ''; $this->installer_base_name = 'installer.php'; //SCHEDULES $this->send_email_on_build_mode = DUP_PRO_Email_Build_Mode::Email_On_Failure; $this->notification_email_address = ''; //STORAGE $this->storage_htaccess_off = false; $this->max_storage_retries = 10; $this->max_default_store_files = 20; $this->dropbox_upload_chunksize_in_kb = 2000; $this->dropbox_transfer_mode = DUP_PRO_Dropbox_Transfer_Mode::Unconfigured; $this->gdrive_upload_chunksize_in_kb = 2000; // Not exposed through the UI (yet) $this->s3_upload_part_size_in_kb = 6000; // Not exposed through the UI (yet) //DEBUG $this->debug_on = false; $this->trace_profiler_on = false; //ADVANCED $this->profile_idea = false; $this->profile_alpha = false; $this->profile_beta = false; $max_execution_time = ini_get("max_execution_time"); if (empty($max_execution_time) || ($max_execution_time == 0) || ($max_execution_time == -1)) { $max_execution_time = 30; } // Default is just a bit under the .7 max $this->php_max_worker_time_in_sec = (int) (0.6 * (float) $max_execution_time); if ($this->php_max_worker_time_in_sec > 18) { // Cap it at 18 as a starting point since there have been some oddities experienced on a couple servers $this->php_max_worker_time_in_sec = 18; } $this->set_build_mode(); $this->custom_ajax_url = admin_url('admin-ajax.php', 'http'); } // TODO: Rework this to test proper operation of File locking - suspect a timeout in sql locking could cause problems so auto-setting to sql lock may cause issues public static function get_lock_type() { $lock_name = 'dup_pro_test_lock'; $lock_type = DUP_PRO_Thread_Lock_Mode::Flock; @mkdir(DUPLICATOR_PRO_SSDIR_PATH_TMP, 0755, true); $test_file_path = DUPLICATOR_PRO_SSDIR_PATH_TMP.'/lock_test.txt'; $fp = fopen($test_file_path,'w+'); if($fp !== false) { if(flock($fp,LOCK_EX|LOCK_NB,$eWouldBlock) || !$eWouldBlock){ $url = admin_url('admin-ajax.php?action=duplicator_pro_try_to_lock_test_file'); $args = array( 'timeout' => 3, 'method' => 'POST' ); $res = wp_remote_request($url,$args); if (!is_wp_error($res)) { $body = wp_remote_retrieve_body($res); if($body == DUP_PRO_File_Lock_Check::Flock_Success){ $lock_type = DUP_PRO_Thread_Lock_Mode::SQL_Lock; } }else{ DUP_PRO_LOG::trace("Could not check system for file lock support. wp_remote_request failed"); } } fclose($fp); } DUP_PRO_LOG::trace("Lock type auto set to {$lock_type}"); return $lock_type; } public function set_from_data($global_data) { //GENERAL $this->uninstall_settings = $global_data->uninstall_settings; $this->uninstall_files = $global_data->uninstall_files; $this->uninstall_tables = $global_data->uninstall_tables; $this->wpfront_integrate = $global_data->wpfront_integrate; //PACKAGES::Processing $this->package_mysqldump = $global_data->package_mysqldump; $this->package_mysqldump_path = $global_data->package_mysqldump_path; $this->package_phpdump_qrylimit = $global_data->package_phpdump_qrylimit; $this->archive_build_mode = $global_data->archive_build_mode; $this->archive_compression = $global_data->archive_compression; // TODO: PHP 7 allows ZipArchive to be set to Store - implement later $this->ziparchive_chunk_size_in_mb = $global_data->ziparchive_chunk_size_in_mb; $this->ziparchive_mode = $global_data->ziparchive_mode; $this->archive_build_mode_schedule = $global_data->archive_build_mode_schedule; $this->archive_compression_schedule = $global_data->archive_compression_schedule; $this->server_load_reduction = $global_data->server_load_reduction; $this->max_package_runtime_in_min = $global_data->max_package_runtime_in_min; $this->php_max_worker_time_in_sec = $global_data->php_max_worker_time_in_sec; //PACKAGES::Adanced $this->lock_mode = $global_data->lock_mode; $this->json_mode = $global_data->json_mode; $this->ajax_protocol = $global_data->ajax_protocol; $this->custom_ajax_url = $global_data->custom_ajax_url; $this->clientside_kickoff = $global_data->clientside_kickoff; $this->basic_auth_enabled = $global_data->basic_auth_enabled; $this->basic_auth_user = $global_data->basic_auth_user; $this->installer_base_name = $global_data->installer_base_name; //SCHEDULES $this->send_email_on_build_mode = $global_data->send_email_on_build_mode; $this->notification_email_address = $global_data->notification_email_address; //STORAGE $this->storage_htaccess_off = $global_data->storage_htaccess_off; $this->max_storage_retries = $global_data->max_storage_retries; $this->max_default_store_files = $global_data->max_default_store_files; $this->dropbox_upload_chunksize_in_kb = $global_data->dropbox_upload_chunksize_in_kb; $this->dropbox_transfer_mode = $global_data->dropbox_transfer_mode; $this->gdrive_upload_chunksize_in_kb = $global_data->gdrive_upload_chunksize_in_kb; // Not exposed through the UI (yet) $this->s3_upload_part_size_in_kb = $global_data->s3_upload_part_size_in_kb; // Not exposed through the UI (yet) $this->manual_mode_storage_ids = $global_data->manual_mode_storage_ids; //LICENSING $this->license_status = DUP_PRO_License_Status::Unknown; $this->license_expiration_time = 0; $this->license_no_activations_left = false; $this->license_key_visible = $global_data->license_key_visible; //UPDATE CACHING $this->last_edd_api_response = null; $this->last_edd_api_timestamp = 0; //MISC - SOME SHOULD BE IN SYSTEM GLOBAL $this->last_system_check_timestamp = 0; $this->initial_activation_timestamp = 0; //DEBUG $this->debug_on = $global_data->debug_on; $this->trace_profiler_on = $global_data->trace_profiler_on; //ADVANCED $this->profile_idea = $global_data->profile_idea; $this->profile_alpha = $global_data->profile_alpha; $this->profile_beta = $global_data->profile_beta; } public function set_build_mode() { $is_shellexec_zip_available = (DUP_PRO_Zip_U::getShellExecZipPath() != null);//--New default duparchive logic to be included in 5.5.4+ // If unconfigured go with auto logic for shell exec verify that mode exists otherwise slam it back// if (($this->archive_build_mode == DUP_PRO_Archive_Build_Mode::Unconfigured) || ($this->archive_build_mode == DUP_PRO_Archive_Build_Mode::Auto)) {//// $this->archive_ = DUP_PRO_Archive_Build_Mode::DupArchive;// } else if ($this->archive_build_mode == DUP_PRO_Archive_Build_Mode::Shell_Exec) {// if (!$is_shellexec_zip_available) {// $this->archive_build_mode = DUP_PRO_Archive_Build_Mode::ZipArchive;//// if(DUP_PRO_U::PHP70() === false) {// $this->archive_compression = true;// }// }// } // If unconfigured go with auto logic for shell exec verify that mode exists otherwise slam it back if (($this->archive_build_mode == DUP_PRO_Archive_Build_Mode::Unconfigured) || ($this->archive_build_mode_schedule == DUP_PRO_Archive_Build_Mode::Auto)) { $this->archive_build_mode = ($is_shellexec_zip_available) ? DUP_PRO_Archive_Build_Mode::Shell_Exec : DUP_PRO_Archive_Build_Mode::ZipArchive; } else if ($this->archive_build_mode == DUP_PRO_Archive_Build_Mode::Shell_Exec) { if (!$is_shellexec_zip_available) { $this->archive_build_mode = DUP_PRO_Archive_Build_Mode::ZipArchive; if(DUP_PRO_U::PHP70() === false) { $this->archive_compression = true; } } } // If unconfigured go with auto logic for shell exec verify that mode exists otherwise slam it back if (($this->archive_build_mode_schedule == DUP_PRO_Archive_Build_Mode::Unconfigured) || ($this->archive_build_mode_schedule == DUP_PRO_Archive_Build_Mode::Auto)) { $this->archive_build_mode_schedule = ($is_shellexec_zip_available) ? DUP_PRO_Archive_Build_Mode::Shell_Exec : DUP_PRO_Archive_Build_Mode::ZipArchive; } else if ($this->archive_build_mode_schedule == DUP_PRO_Archive_Build_Mode::Shell_Exec) { if (!$is_shellexec_zip_available) { $this->archive_build_mode_schedule = DUP_PRO_Archive_Build_Mode::ZipArchive; if(DUP_PRO_U::PHP70() === false) { $this->archive_compression_schedule = true; } } } } public function get_auto_zip_mode() { $build_mode; if (($this->archive_build_mode === DUP_PRO_Archive_Build_Mode::Shell_Exec) || ($this->archive_build_mode === DUP_PRO_Archive_Build_Mode::ZipArchive)) { // Don't override, just use what is configured $build_mode = $this->archive_build_mode; } else { $is_shellexec_zip_available = (DUP_PRO_Zip_U::getShellExecZipPath() != null); if ($is_shellexec_zip_available) { $build_mode = DUP_PRO_Archive_Build_Mode::Shell_Exec; } else { $build_mode = DUP_PRO_Archive_Build_Mode::ZipArchive; } } return $build_mode; } // Important: Even though we are no longer using the encrypted lkp and basic_auth_user fields we still need them for upgrade purposes public function save() { $result = false; $this->encrypt(); $result = parent::save(); $this->decrypt(); // Whenever its in memory its unencrypted return $result; } // Change settings that may need to be changed because we have restored to a different system public function adjust_settings_for_system() { $save_required = false; if ($save_required) { $this->save(); } } private function encrypt() { if (!empty($this->basic_auth_password)) { $this->basic_auth_password = DUP_PRO_Crypt_Blowfish::encrypt($this->basic_auth_password); } if (!empty($this->lkp)) { $this->lkp = DUP_PRO_Crypt_Blowfish::encrypt($this->lkp); } } private function decrypt() { if (!empty($this->basic_auth_password)) { $this->basic_auth_password = DUP_PRO_Crypt_Blowfish::decrypt($this->basic_auth_password); } if (!empty($this->lkp)) { $this->lkp = DUP_PRO_Crypt_Blowfish::decrypt($this->lkp); } } public static function &get_instance() { if (isset($GLOBALS[self::GLOBAL_NAME]) == false) { $global = null; $globals = DUP_PRO_JSON_Entity_Base::get_by_type(get_class()); if (count($globals) > 0) { $global = $globals[0]; $global->decrypt(); } else { DUP_PRO_LOG::trace("Global entity is null!"); } $GLOBALS[self::GLOBAL_NAME] = $global; } return $GLOBALS[self::GLOBAL_NAME]; } public function configure_dropbox_transfer_mode() { if ($this->dropbox_transfer_mode == DUP_PRO_Dropbox_Transfer_Mode::Unconfigured) { $has_curl = DUP_PRO_Server::isCurlEnabled(); $has_fopen_url = DUP_PRO_Server::isURLFopenEnabled(); if ($has_curl) { $this->dropbox_transfer_mode = DUP_PRO_Dropbox_Transfer_Mode::cURL; } else { if ($has_fopen_url) { $this->dropbox_transfer_mode = DUP_PRO_Dropbox_Transfer_Mode::FOpen_URL; } else { $this->dropbox_transfer_mode = DUP_PRO_Dropbox_Transfer_Mode::Disabled; } } $this->save(); } } public function get_installer_backup_filename() { $installer_extension = $this->get_installer_extension(); if (trim($installer_extension) == '') { return 'installer-backup'; } else { return "installer-backup.$installer_extension"; } } public function get_installer_extension() { return pathinfo($this->installer_base_name, PATHINFO_EXTENSION); } public function get_archive_engine() { $mode = ''; switch ($this->archive_build_mode) { case DUP_PRO_Archive_Build_Mode::ZipArchive: $mode = ($this->ziparchive_mode == DUP_PRO_ZipArchive_Mode::Multithreaded) ? DUP_PRO_U::__("ZipArchive: multi-thread") : DUP_PRO_U::__("ZipArchive: single-thread"); break; case DUP_PRO_Archive_Build_Mode::DupArchive : $mode = DUP_PRO_U::__('DupArchive'); break; default: $mode = DUP_PRO_U::__("Shell Zip"); break; } return $mode; }} $object) { $path = DUP_PRO_U::safePath($path); $local_name = ltrim(str_replace($directoryPath, '', $path), '/'); if ($retainDirectory) { $local_name = basename($directoryPath)."/$local_name"; } $local_name = $localPrefix . $local_name; if (!is_dir($path)) { if (is_readable($path)) { $added = DUP_PRO_Zip_U::addFileToZipArchive($zipArchive, $path, $local_name, $isCompressed); } else { $added = false; } } else { $added = true; } if (!$added) { DUP_PRO_Log::error("Couldn't add file $path to archive", '', false); $success = false; break; } } return $success; } /** * Gets an array of possible ShellExec Zip problems on the server * * @return array Returns array of DUP_PRO_Problem_Fix objects */ public static function getShellExecZipProblems() { $problem_fixes = array(); if (!self::getShellExecZipPath()) { $filepath = null; $possible_paths = array( '/usr/bin/zip', '/opt/local/bin/zip'// RSR TODO put back in when we support shellexec on windows, //'C:/Program\ Files\ (x86)/GnuWin32/bin/zip.exe'); ); foreach ($possible_paths as $path) { if (file_exists($path)) { $filepath = $path; break; } } if ($filepath == null) { $problem_fix = new DUP_PRO_Problem_Fix(); $problem_fix->problem = DUP_PRO_U::__('Zip executable not present'); $problem_fix->fix = DUP_PRO_U::__('Install the zip executable and make it accessible to PHP.'); $problem_fixes[] = $problem_fix; } $cmds = array('shell_exec', 'escapeshellarg', 'escapeshellcmd', 'extension_loaded'); //Function disabled at server level if (array_intersect($cmds, array_map('trim', explode(',', @ini_get('disable_functions'))))) { $problem_fix = new DUP_PRO_Problem_Fix(); $problem_fix->problem = DUP_PRO_U::__('Required functions disabled in the php.ini.'); $problem_fix->fix = DUP_PRO_U::__('Remove any of the following from the disable_functions setting in the php.ini files: shell_exec, escapeshellarg, escapeshellcmd, and extension_loaded.'); $problem_fixes[] = $problem_fix; } if (extension_loaded('suhosin')) { $suhosin_ini = @ini_get("suhosin.executor.func.blacklist"); if (array_intersect($cmds, array_map('trim', explode(',', $suhosin_ini)))) { $problem_fix = new DUP_PRO_Problem_Fix(); $problem_fix->problem = DUP_PRO_U::__('Suhosin is blocking PHP shell_exec.'); $problem_fix->fix = DUP_PRO_U::__('In the php.ini file - Remove the following from the suhosin.executor.func.blacklist setting: shell_exec, escapeshellarg, escapeshellcmd, and extension_loaded.'); $problem_fixes[] = $problem_fix; } } } return $problem_fixes; } /** * Get the path to the zip program executable on the server * * @return string Returns the path to the zip program */ public static function getShellExecZipPath() { $filepath = null; if (DUP_PRO_Shell_U::isShellExecEnabled()) { if (shell_exec('hash zip 2>&1') == NULL) { $filepath = 'zip'; } else { $possible_paths = array( '/usr/bin/zip', '/opt/local/bin/zip'// RSR TODO put back in when we support shellexec on windows, //'C:/Program\ Files\ (x86)/GnuWin32/bin/zip.exe'); ); foreach ($possible_paths as $path) { if (file_exists($path)) { $filepath = $path; break; } } } } return $filepath; } public static function extractFiles($archiveFilepath, $relativeFilesToExtract, $destinationDirectory, $useShellUnZip) { // TODO: Unzip using either shell unzip or ziparchive if($useShellUnZip) { $shellExecPath = DUPX_Server::get_unzip_filepath(); $filenameString = implode(' ', $relativeFilesToExtract); $command = "{$shellExecPath} -o -qq \"{$archiveFilepath}\" {$filenameString} -d {$destinationDirectory} 2>&1"; $stderr = shellexec($command); if ($stderr != '') { $errorMessage = DUP_PRO_U::__("Error extracting {$archiveFilepath}): {$stderr}"); throw new Exception($errorMessage); } } else { $zipArchive = new ZipArchive(); $result = $zipArchive->open($archiveFilepath); if($result !== true) { throw new Exception("Error opening {$archiveFilepath} when extracting. Error code: {$retVal}"); } $result = $zipArchive->extractTo($destinationDirectory, $relativeFilesToExtract); if($result === false) { throw new Exception("Error extracting {$archiveFilepath}."); } } } /** * Add a directory to an existing ZipArchive object * * @param string $sourceFilePath The file to add to the zip file * @param string $zipFilePath The zip file to be added to * @param bool $deleteOld Delete the zip file before adding a file * @param string $newName Rename the $sourceFile if needed * * @return bool Returns true if the file was added to the zip file */ public static function zipFile($sourceFilePath, $zipFilePath, $deleteOld, $newName, $isCompressed) { if ($deleteOld && file_exists($zipFilePath)) { DUP_PRO_IO::deleteFile($zipFilePath); } if (file_exists($sourceFilePath)) { $zip_archive = new ZipArchive(); $is_zip_open = ($zip_archive->open($zipFilePath, ZIPARCHIVE::CREATE) === TRUE); if ($is_zip_open === false) { DUP_PRO_Log::error("Cannot create zip archive {$zipFilePath}"); } else { //ADD SQL if ($newName == null) { $source_filename = basename($sourceFilePath); DUP_PRO_LOG::trace("adding {$source_filename}"); } else { $source_filename = $newName; DUP_PRO_LOG::trace("new name added {$newName}"); } $in_zip = DUP_PRO_Zip_U::addFileToZipArchive($zip_archive, $sourceFilePath, $source_filename, $isCompressed); if ($in_zip === false) { DUP_PRO_Log::error("Unable to add {$sourceFilePath} to $zipFilePath"); } $zip_archive->close(); return true; } } else { DUP_PRO_Log::error("Trying to add {$sourceFilePath} to a zip but it doesn't exist!"); } return false; } public static function addFileToZipArchive(&$zipArchive, $filepath, $localName, $isCompressed) { $global = DUP_PRO_Global_Entity::get_instance(); $added = $zipArchive->addFile($filepath, $localName); if(DUP_PRO_U::$PHP7_plus && !$isCompressed) { $zipArchive->setCompressionName($localName, ZipArchive::CM_STORE); } return $added; }} 'activate_license', 'license' => $license, 'item_name' => urlencode(EDD_DUPPRO_ITEM_NAME), // the name of our product in EDD, 'url' => home_url() ); } else { $api_params = array( 'edd_action' => 'deactivate_license', 'license' => $license, 'item_name' => urlencode(EDD_DUPPRO_ITEM_NAME), // the name of our product in EDD, 'url' => home_url() ); } // Call the custom API. global $wp_version; $agent_string = "WordPress/".$wp_version; DUP_PRO_LOG::trace("Wordpress agent string $agent_string"); $response = wp_remote_post(EDD_DUPPRO_STORE_URL, array('timeout' => 15, 'sslverify' => false, 'user-agent' => $agent_string, 'body' => $api_params)); // make sure the response came back okay if (is_wp_error($response)) { if ($activate) { $action = 'activating'; } else { $action = 'deactivating'; } DUP_PRO_LOG::traceObject("Error $action $license", $response); return DUP_PRO_License_Activation_Response::POST_ERROR; } $license_data = json_decode(wp_remote_retrieve_body($response)); if ($activate) { // decode the license data if ($license_data->license == 'valid') { DUP_PRO_LOG::trace("Activated license $license"); return DUP_PRO_License_Activation_Response::OK; } else { DUP_PRO_LOG::traceObject("Problem activating license $license", $license_data); return DUP_PRO_License_Activation_Response::INVALID_RESPONSE; } } else { // check that license:deactivated and item:Duplicator Pro json if ($license_data->license == 'deactivated') { DUP_PRO_LOG::trace("Deactivated license $license"); return DUP_PRO_License_Activation_Response::OK; } else { // problems activating //update_option('edd_sample_license_status', $license_data->license); DUP_PRO_LOG::traceObject("Problems deactivating license $license", $license_data); return DUP_PRO_License_Activation_Response::INVALID_RESPONSE; } } } public static function isValidOvrKey($scrambledKey) { $isValid = true; $unscrambledKey = DUP_PRO_Crypt::unscramble($scrambledKey); if (DUP_PRO_STR::startsWith($unscrambledKey, 'SCOVRK')) { $index = strpos($unscrambledKey, '_'); if ($index !== false) { $index++; $count = substr($unscrambledKey, $index); if (is_numeric($count) && ($count > 0)) { $isValid = true; } } } return $isValid; } public static function setOvrKey($scrambledKey) { if (self::isValidOvrKey($scrambledKey)) { $unscrambledKey = DUP_PRO_Crypt::unscramble($scrambledKey); $index = strpos($unscrambledKey, '_'); if ($index !== false) { $index++; $count = substr($unscrambledKey, $index); /* @var $global DUP_PRO_Global_Entity */ $global = DUP_PRO_Global_Entity::get_instance(); $global->license_limit = $count; $global->license_no_activations_left = false; $global->license_status = DUP_PRO_License_Status::Valid; $global->save(); DUP_PRO_LOG::trace("$unscrambledKey is an ovr key with license limit $count"); update_option(DUP_PRO_Constants::LICENSE_KEY_OPTION_NAME, $scrambledKey); } } else { throw new Exception("Ovr key in wrong format: $unscrambledKey"); } } public static function getStandardKeyFromOvrKey($scrambledKey) { $standardKey = ''; if (self::isValidOvrKey($scrambledKey)) { $unscrambledKey = DUP_PRO_Crypt::unscramble($scrambledKey); $standardKey = substr($unscrambledKey, 6, 32); } else { throw new Exception("Ovr key in wrong format: $unscrambledKey"); } return $standardKey; } public static function getLicenseStatus($forceRefresh) { /* @var $global DUP_PRO_Global_Entity */ $global = DUP_PRO_Global_Entity::get_instance(); $license_key = get_option(DUP_PRO_Constants::LICENSE_KEY_OPTION_NAME, ''); if (self::isValidOvrKey($license_key)) { if ($global->license_status != DUP_PRO_License_Status::Valid) { $global->license_status = DUP_PRO_License_Status::Valid; $global->save(); } } else { $initial_status = $global->license_status; if ($forceRefresh === false) { if (time() > $global->license_expiration_time) { DUP_PRO_LOG::trace("Uncaching license because current time = ".time()." and expiration time = {$global->license_expiration_time}"); $global->license_status = DUP_PRO_License_Status::Uncached; } } else { DUP_PRO_LOG::trace("forcing live license update"); $global->license_status = DUP_PRO_License_Status::Uncached; } if ($global->license_limit == -1) { $global->license_status = DUP_PRO_License_Status::Uncached; } if ($global->license_status == DUP_PRO_License_Status::Uncached) { DUP_PRO_LOG::trace("retrieving live license status"); $store_url = 'https://snapcreek.com'; $item_name = 'Duplicator Pro'; if ($license_key != '') { $api_params = array( 'edd_action' => 'check_license', 'license' => $license_key, 'item_name' => urlencode($item_name), 'url' => home_url() ); global $wp_version; $agent_string = "WordPress/".$wp_version; $response = wp_remote_post($store_url, array('timeout' => 15, 'sslverify' => false, 'user-agent' => $agent_string, 'body' => $api_params)); if (is_wp_error($response)) { $global->license_status = $initial_status; DUP_PRO_LOG::trace("Error getting license check response for $license_key so leaving status alone"); } else { $license_data = json_decode(wp_remote_retrieve_body($response)); DUP_PRO_LOG::traceObject("license data in response returned", $response); DUP_PRO_LOG::traceObject("license data returned", $license_data); $global->license_status = self::getLicenseStatusFromString($license_data->license); $global->license_no_activations_left = false; if(!isset($license_data->license_limit)) { $global->license_limit = -1; } else { $global->license_limit = $license_data->license_limit; } if (($global->license_status == DUP_PRO_License_Status::Site_Inactive) && ($license_data->activations_left === 0)) { $global->license_no_activations_left = true; } if ($global->license_status == DUP_PRO_License_Status::Unknown) { DUP_PRO_LOG::trace("Problem retrieving license status for $license_key"); } } } else { $global->license_limit = -1; $global->license_status = DUP_PRO_License_Status::Invalid; $global->license_no_activations_left = false; } $global->license_expiration_time = time() + self::$licenseCacheTime; $global->save(); DUP_PRO_LOG::trace("Set cached value from with expiration ".self::$licenseCacheTime." seconds from now ({$global->license_expiration_time})"); } } return $global->license_status; } public static function getLicenseStatusString($licenseStatusString) { switch ($licenseStatusString) { case DUP_PRO_License_Status::Valid: return DUP_PRO_U::__('Valid'); case DUP_PRO_License_Status::Invalid: return DUP_PRO_U::__('Invalid'); case DUP_PRO_License_Status::Expired: return DUP_PRO_U::__('Expired'); case DUP_PRO_License_Status::Disabled: return DUP_PRO_U::__('Disabled'); case DUP_PRO_License_Status::Site_Inactive: return DUP_PRO_U::__('Site Inactive'); case DUP_PRO_License_Status::Expired: return DUP_PRO_U::__('Expired'); default: return DUP_PRO_U::__('Unknown'); } } public static function getLicenseType() { /* @var $global DUP_PRO_Global_Entity */ $global = DUP_PRO_Global_Entity::get_instance(); $license_type = DUP_PRO_License_Type::Personal; if ($global->license_limit < 0) { $license_type = DUP_PRO_License_Type::Unlicensed; } else if ($global->license_limit < 15) { $license_type = DUP_PRO_License_Type::Personal; } else if ($global->license_limit < 500) { $license_type = DUP_PRO_License_Type::Freelancer; } else if ($global->license_limit >= 500) { $license_type = DUP_PRO_License_Type::BusinessGold; } return $license_type; } private static function getLicenseStatusFromString($licenseStatusString) { switch ($licenseStatusString) { case 'valid': return DUP_PRO_License_Status::Valid; break; case 'invalid': return DUP_PRO_License_Status::Invalid; case 'expired': return DUP_PRO_License_Status::Expired; case 'disabled': return DUP_PRO_License_Status::Disabled; case 'site_inactive': return DUP_PRO_License_Status::Site_Inactive; case 'inactive': return DUP_PRO_License_Status::Inactive; default: return DUP_PRO_License_Status::Unknown; } }}DUP_PRO_License_U::init();archive_build_mode_schedule === DUP_PRO_Archive_Build_Mode::Unconfigured) { error_log("schedule build mode unconfigured on upgrade"); if(($global->archive_build_mode === DUP_PRO_Archive_Build_Mode::Shell_Exec) || ($global->archive_build_mode === DUP_PRO_Archive_Build_Mode::ZipArchive)) { $global->archive_build_mode_schedule = $global->archive_build_mode; $global->archive_compression_schedule = $global->archive_compression; $global->save(); error_log("existing build mode is a zip mode so set build mode schedule to {$global->archive_build_mode_schedule} and schedule compression to {$global->archive_compression_schedule}"); } } else { error_log("Build mode schedule already set to {$global->archive_build_mode_schedule} so not setting"); } } static function MoveDataToSecureGlobal() { /* @var $global DUP_PRO_Global_Entity */ /* @var $sglobal DUP_PRO_Secure_Global_Entity */ $global = DUP_PRO_Global_Entity::get_instance(); if($global->lkp !== '' || $global->basic_auth_user !== '') { error_log('setting sglobal'); $sglobal = DUP_PRO_Secure_Global_Entity::getInstance(); $sglobal->lkp = $global->lkp; $sglobal->basic_auth_password = $global->basic_auth_password; $global->lkp = ''; $global->basic_auth_password = ''; $sglobal->save(); $global->save(); } }}encrypt($string); DUP_PRO_LOG::profile('blowfish encrypt', false); $encrypted_value = base64_encode($encrypted_value); return $encrypted_value; } public static function decrypt($encryptedString, $key = null) { if (empty($encryptedString)) { return ''; } else { if ($key == null) { $key = self::getDefaultKey(); } $crypt = new pcrypt(MODE_ECB, "BLOWFISH", $key); $orig = $encryptedString; $encryptedString = base64_decode($encryptedString); if (empty($encryptedString)) { DUP_PRO_LOG::traceObject("Bad encrypted string for $orig", debug_backtrace()); } $decrypted_value = $crypt->decrypt($encryptedString); return $decrypted_value; } } } id = -1; $this->type = get_class($this); $this->dirty = false; $this->verifiers = array(); $this->table_name = $wpdb->base_prefix.$table_name; } public static function init_table($table_name = self::DEFAULT_TABLE_NAME) { global $wpdb; $table_name = $wpdb->base_prefix.$table_name; $index_query = "select count(*) from information_schema.statistics where table_name = '$table_name' and index_name = 'type_idx' and TABLE_SCHEMA = DATABASE()"; if ($wpdb->get_var($index_query) != 0) { $sql = "ALTER TABLE ".$table_name." DROP INDEX type_idx"; // DUP_PRO_U::debug("removing index type_idx for $table_name using sql $sql"); $wpdb->query($sql); } $query_string = "CREATE TABLE IF NOT EXISTS ".$table_name."("; $query_string .= "id INT NOT NULL AUTO_INCREMENT,"; $query_string .= "type varchar(255), "; $query_string .= "data TEXT, "; // $query_string .= "PRIMARY KEY (id)) ENGINE = InnoDB;"; $query_string .= "PRIMARY KEY (id))"; //$wpdb->query($query_string); dbDelta($query_string); $query_string = "CREATE INDEX type_idx ON $table_name (type);"; $wpdb->query($query_string); } public function insert() { global $wpdb; // DUP_PRO_LOG::trace("inserting type $this->type"); $query_string = "INSERT INTO ".$this->table_name; $query_string .= " (type, data) VALUES (%s, %s)"; $data = DUP_PRO_Low_U::getPublicProperties($this); $serialized_data = json_encode($data); if (strlen($serialized_data) < 65536) { $prepared_query = $wpdb->prepare($query_string, $this->type, $serialized_data); $wpdb->query($prepared_query); $this->id = $wpdb->insert_id; if ($this->id == false) { $this->id = -1; DUP_PRO_Low_U::errLog("Error inserting. Query: ".$prepared_query); return false; } } else { DUP_PRO_Low_U::errLog("Entity ({$this->type}) trying to be inserted exceeds max size of 65K!"); return false; } return true; } public function update() { global $wpdb; $query_string = "UPDATE ".$this->table_name; $query_string .= " SET type = %s, data = %s WHERE id = %d"; $data = DUP_PRO_Low_U::getPublicProperties($this); $serialized_data = json_encode($data); if (strlen($serialized_data) < 65536) { $prepared_query = $wpdb->prepare($query_string, $this->type, $serialized_data, $this->id); $wpdb->query($prepared_query); $this->dirty = false; return true; } else { DUP_PRO_Low_U::errLog("Entity ({$this->type}) trying to be updated exceeds max size of 65K!"); return false; } } public function delete() { // self::delete_by_id($this->id, $this->table_name); global $wpdb; // $table_name = $wpdb->base_prefix . $table_name; $query_string = "DELETE FROM ".$this->table_name; $query_string .= " WHERE id = %d"; $prepared_query = $wpdb->prepare($query_string, $this->id); $wpdb->query($prepared_query); $this->id = -1; $this->dirty = false; } public static function get_by_id_and_type($id, $type, $table_name = self::DEFAULT_TABLE_NAME) { global $wpdb; $table_name = $wpdb->base_prefix.$table_name; $query_string = "SELECT * FROM ".$table_name; $query_string .= " WHERE id = %d"; $prepped = $wpdb->prepare($query_string, $id); $row = $wpdb->get_row($prepped); if ($row != NULL) { $instance = new $type(); $instance->id = (int) $row->id; $instance->type = $row->type; $instance->table_name = $table_name; $data = json_decode($row->data); foreach ($data as $property_name => $property_value) { // The if fixes the bug introduced in 3.0.13 if (($property_name != 'verifiers') && ($property_name != 'table_name') && ($property_name != 'dirty')) { $instance->$property_name = $property_value; } } return $instance; } else { // DUP_PRO_Low_U::errLog("get_by_id_and_type: row $prepped is null".print_r(debug_backtrace(), true)); // Storage ids can disappear return null; } } public static function delete_by_id_base($id, $table_name = self::DEFAULT_TABLE_NAME) { global $wpdb; $table_name = $wpdb->base_prefix.$table_name; $query_string = "DELETE FROM ".$table_name; $query_string .= " WHERE id = %d"; $prepared_query = $wpdb->prepare($query_string, $id); $wpdb->query($prepared_query); } public static function delete_by_type_and_field($type, $field_name, $field_value, $table_name = self::DEFAULT_TABLE_NAME) { $instances = self::get_by_type_and_field($type, $field_name, $field_value, $table_name); foreach ($instances as $instance) { $instance->delete(); } } public static function get_by_type_and_field($type, $field_name, $field_value, $table_name = self::DEFAULT_TABLE_NAME) { $filtered_instances = array(); $instances = self::get_by_type($type, $table_name); foreach ($instances as $instance) { if ($instance->$field_name == $field_value) { array_push($filtered_instances, $instance); } } return $filtered_instances; } public static function get_by_type($type, $table_name = self::DEFAULT_TABLE_NAME, $page = 0) { global $wpdb; $table_name = $wpdb->base_prefix.$table_name; $query_string = "SELECT * FROM ".$table_name; $query_string .= " WHERE type = %s"; if ($page > 0) { $records_per_page = 50; $offset = ($page - 1) * $records_per_page; $query_string .= " LIMIT $offset, $records_per_page"; } $prepared = $wpdb->prepare($query_string, $type); $rows = $wpdb->get_results($prepared); $instances = array(); foreach ($rows as $row) { $instance = new $type(); $instance->id = $row->id; $instance->type = $row->type; $instance->table_name = $table_name; $data = json_decode($row->data); foreach ($data as $property_name => $property_value) { // The if fixes the bug introduced in 3.0.13 if (($property_name != 'verifiers') && ($property_name != 'table_name') && ($property_name != 'dirty')) { $instance->$property_name = $property_value; } } array_push($instances, $instance); } return $instances; } public function save() { $saved = false; if ($this->id == -1) { $saved = $this->insert(); } else { //screw the dirty part - too problematic if we update member directlyif ($this->dirty) { $saved = $this->update(); $this->dirty = false; } return $saved; } public function set_post_variables($post) { $error_string = ''; // First do a verifier scrub and only then let it fall through to set foreach ($post as $key => $value) { if (is_array($value)) { foreach ($value as $individual_value) { $local_error = $this->verify_posted_variable($key, $individual_value); if ($local_error != '') { $error_string .= $local_error.".
"; } } } else { $local_error = $this->verify_posted_variable($key, $value); if ($local_error != '') { $error_string .= $local_error.".
"; } } } return $error_string; } private function verify_posted_variable($key, $value) { $error_string = ''; $value = stripslashes($value); if (array_key_exists($key, $this->verifiers)) { $error_string = $this->verifiers[$key]->verify($value); $this->set($key, $value); } else { $this->set($key, $value); } return $error_string; } public function set($property_name, $property_value) { if (property_exists($this->type, $property_name)) { $this->$property_name = $property_value; $this->dirty = true; } } public function get($property_name) { if (property_exists($this->type, $property_name)) { return $this->$property_name; } else { return null; } } }