| Server IP : 146.59.209.152 / Your IP : 216.73.216.46 Web Server : Apache System : Linux webm005.cluster131.gra.hosting.ovh.net 5.15.167-ovh-vps-grsec-zfs-classid #1 SMP Tue Sep 17 08:14:20 UTC 2024 x86_64 User : infrafs ( 43850) PHP Version : 8.2.29 Disable Function : _dyuweyrj4,_dyuweyrj4r,dl MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/i/n/f/infrafs/INFRABIKEIT/wp-content/plugins/ |
Upload File : |
classes/package/index.php 0000644 00000000016 15133606540 0011414 0 ustar 00 <?php
//silent classes/package/class.pack.archive.php 0000644 00000070205 15133606540 0013756 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
// Exit if accessed directly
if (!defined('DUPLICATOR_VERSION')) exit;
require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/duparchive/class.pack.archive.duparchive.php');
require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.filters.php');
require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.zip.php');
require_once (DUPLICATOR_PLUGIN_PATH.'lib/forceutf8/Encoding.php');
/**
* Class for handling archive setup and build process
*
* Standard: PSR-2 (almost)
* @link http://www.php-fig.org/psr/psr-2
*
* @package DUP
* @subpackage classes/package
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
class DUP_Archive
{
//PUBLIC
public $FilterDirs;
public $FilterFiles;
public $FilterExts;
public $FilterDirsAll = array();
public $FilterFilesAll = array();
public $FilterExtsAll = array();
public $FilterOn;
public $ExportOnlyDB;
public $File;
public $Format;
public $PackDir;
public $Size = 0;
public $Dirs = array();
public $Files = array();
/**
*
* @var DUP_Archive_Filter_Info
*/
public $FilterInfo = null;
public $RecursiveLinks = array();
public $file_count = -1;
//PROTECTED
protected $Package;
private $tmpFilterDirsAll = array();
private $wpCorePaths = array();
private $wpCoreExactPaths = array();
/**
* Init this object
*/
public function __construct($package)
{
$this->Package = $package;
$this->FilterOn = false;
$this->ExportOnlyDB = false;
$this->FilterInfo = new DUP_Archive_Filter_Info();
$homePath = duplicator_get_home_path();
$this->wpCorePaths[] = DUP_Util::safePath("{$homePath}/wp-admin");
$this->wpCorePaths[] = DUP_Util::safePath(WP_CONTENT_DIR."/languages");
$this->wpCorePaths[] = DUP_Util::safePath("{$homePath}/wp-includes");
$this->wpCoreExactPaths[] = DUP_Util::safePath("{$homePath}");
$this->wpCoreExactPaths[] = DUP_Util::safePath(WP_CONTENT_DIR);
$this->wpCoreExactPaths[] = DUP_Util::safePath(WP_CONTENT_DIR."/uploads");
$this->wpCoreExactPaths[] = DUP_Util::safePath(WP_CONTENT_DIR."/plugins");
$this->wpCoreExactPaths[] = DUP_Util::safePath(get_theme_root());
}
/**
* Builds the archive based on the archive type
*
* @param obj $package The package object that started this process
*
* @return null
*/
public function build($package, $rethrow_exception = false)
{
DUP_LOG::trace("b1");
$this->Package = $package;
if (!isset($this->PackDir) && !is_dir($this->PackDir)) throw new Exception("The 'PackDir' property must be a valid directory.");
if (!isset($this->File)) throw new Exception("A 'File' property must be set.");
DUP_LOG::trace("b2");
$completed = false;
switch ($this->Format) {
case 'TAR': break;
case 'TAR-GZIP': break;
case 'DAF':
$completed = DUP_DupArchive::create($this, $this->Package->BuildProgress, $this->Package);
$this->Package->Update();
break;
default:
if (class_exists('ZipArchive')) {
$this->Format = 'ZIP';
DUP_Zip::create($this, $this->Package->BuildProgress);
$completed = true;
}
break;
}
DUP_LOG::Trace("Completed build or build thread");
if ($this->Package->BuildProgress === null) {
// Zip path
DUP_LOG::Trace("Completed Zip");
$storePath = DUP_Settings::getSsdirTmpPath()."/{$this->File}";
$this->Size = @filesize($storePath);
$this->Package->setStatus(DUP_PackageStatus::ARCDONE);
} else if ($completed) {
// Completed DupArchive path
DUP_LOG::Trace("Completed DupArchive build");
if ($this->Package->BuildProgress->failed) {
DUP_LOG::Trace("Error building DupArchive");
$this->Package->setStatus(DUP_PackageStatus::ERROR);
} else {
$filepath = DUP_Settings::getSsdirTmpPath()."/{$this->File}";
$this->Size = @filesize($filepath);
$this->Package->setStatus(DUP_PackageStatus::ARCDONE);
DUP_LOG::Trace("Done building archive");
}
} else {
DUP_Log::trace("DupArchive chunk done but package not completed yet");
}
}
/**
*
* @return int return DUP_Archive_Build_Mode
*/
public function getBuildMode()
{
switch ($this->Format) {
case 'TAR': break;
case 'TAR-GZIP': break;
case 'DAF':
return DUP_Archive_Build_Mode::DupArchive;
default:
if (class_exists('ZipArchive')) {
return DUP_Archive_Build_Mode::ZipArchive;
} else {
return DUP_Archive_Build_Mode::Unconfigured;
}
break;
}
}
/**
* Builds a list of files and directories to be included in the archive
*
* Get the directory size recursively, but don't calc the snapshot directory, exclusion directories
* @link http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx Windows filename restrictions
*
* @return obj Returns a DUP_Archive object
*/
public function getScannerData()
{
$this->createFilterInfo();
$rootPath = duplicator_get_abs_path();
$this->RecursiveLinks = array();
//If the root directory is a filter then skip it all
if (in_array($this->PackDir, $this->FilterDirsAll) || $this->Package->Archive->ExportOnlyDB) {
$this->Dirs = array();
} else {
$this->Dirs[] = $this->PackDir;
$this->getFileLists($rootPath);
if ($this->isOuterWPContentDir()) {
$this->Dirs[] = WP_CONTENT_DIR;
$this->getFileLists(WP_CONTENT_DIR);
}
$this->setDirFilters();
$this->setFileFilters();
$this->setTreeFilters();
}
$this->FilterDirsAll = array_merge($this->FilterDirsAll, $this->FilterInfo->Dirs->Unreadable);
$this->FilterFilesAll = array_merge($this->FilterFilesAll, $this->FilterInfo->Files->Unreadable);
sort($this->FilterDirsAll);
return $this;
}
/**
* 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 bool Returns true if the value has changed.
*/
public function saveActiveItem($package, $property, $value)
{
$package = DUP_Package::getActive();
$reflectionClass = new ReflectionClass($package->Archive);
$reflectionClass->getProperty($property)->setValue($package->Archive, $value);
return update_option(DUP_Package::OPT_ACTIVE, $package);
}
/**
* Properly creates the directory filter list that is used for filtering directories
*
* @param string $dirs A semi-colon list of dir paths
* /path1_/path/;/path1_/path2/;
*
* @returns string A cleaned up list of directory filters
* @return string
*/
public function parseDirectoryFilter($dirs = "")
{
$filters = "";
$dir_array = array_unique(explode(";", $dirs));
$clean_array = array();
foreach ($dir_array as $val) {
$val = DupLiteSnapLibIOU::safePathUntrailingslashit(DupLiteSnapLibUtil::sanitize_non_stamp_chars_newline_and_trim($val));
if (strlen($val) >= 2 && is_dir($val)) {
$clean_array[] = $val;
}
}
if (count($clean_array)) {
$clean_array = array_unique($clean_array);
sort($clean_array);
$filters = implode(';', $clean_array).';';
}
return $filters;
}
/**
* Properly creates the file filter list that is used for filtering files
*
* @param string $files A semi-colon list of file paths
* /path1_/path/file1.ext;/path1_/path2/file2.ext;
*
* @returns string A cleaned up list of file filters
* @return string
*/
public function parseFileFilter($files = "")
{
$filters = "";
$file_array = array_unique(explode(";", $files));
$clean_array = array();
foreach ($file_array as $val) {
$val = DupLiteSnapLibIOU::safePathUntrailingslashit(DupLiteSnapLibUtil::sanitize_non_stamp_chars_newline_and_trim($val));
if (strlen($val) >= 2 && file_exists($val)) {
$clean_array[] = $val;
}
}
if (count($clean_array)) {
$clean_array = array_unique($clean_array);
sort($clean_array);
$filters = implode(';', $clean_array).';';
}
return $filters;
}
/**
* Properly creates the extension filter list that is used for filtering extensions
*
* @param string $dirs A semi-colon list of dir paths
* .jpg;.zip;.gif;
*
* @returns string A cleaned up list of extension filters
*/
public function parseExtensionFilter($extensions = "")
{
$filter_exts = "";
if (strlen($extensions) >= 1 && $extensions != ";") {
$filter_exts = str_replace(array(' ', '.'), '', $extensions);
$filter_exts = str_replace(",", ";", $filter_exts);
$filter_exts = DUP_Util::appendOnce($extensions, ";");
}
return $filter_exts;
}
/**
* Creates the filter info setup data used for filtering the archive
*
* @return null
*/
private function createFilterInfo()
{
//FILTER: INSTANCE ITEMS
//Add the items generated at create time
if ($this->FilterOn) {
$this->FilterInfo->Dirs->Instance = array_map('DUP_Util::safePath', explode(";", $this->FilterDirs, -1));
$this->FilterInfo->Files->Instance = array_map('DUP_Util::safePath', explode(";", $this->FilterFiles, -1));
$this->FilterInfo->Exts->Instance = explode(";", $this->FilterExts, -1);
}
//FILTER: CORE ITMES
//Filters Duplicator free packages & All pro local directories
$wp_root = duplicator_get_abs_path();
$upload_dir = wp_upload_dir();
$upload_dir = isset($upload_dir['basedir']) ? basename($upload_dir['basedir']) : 'uploads';
$wp_content = str_replace("\\", "/", WP_CONTENT_DIR);
$wp_content_upload = "{$wp_content}/{$upload_dir}";
$this->FilterInfo->Dirs->Core = array(
//WP-ROOT
DUP_Settings::getSsdirPathLegacy(),
DUP_Settings::getSsdirPathWpCont(),
$wp_root.'/.opcache',
//WP-CONTENT
$wp_content.'/backups-dup-pro',
$wp_content.'/ai1wm-backups',
$wp_content.'/backupwordpress',
$wp_content.'/content/cache',
$wp_content.'/contents/cache',
$wp_content.'/infinitewp/backups',
$wp_content.'/managewp/backups',
$wp_content.'/old-cache',
$wp_content.'/plugins/all-in-one-wp-migration/storage',
$wp_content.'/updraft',
$wp_content.'/wishlist-backup',
$wp_content.'/wfcache',
$wp_content.'/bps-backup', // BulletProof Security backup folder
$wp_content.'/cache',
//WP-CONTENT-UPLOADS
$wp_content_upload.'/aiowps_backups',
$wp_content_upload.'/backupbuddy_temp',
$wp_content_upload.'/backupbuddy_backups',
$wp_content_upload.'/ithemes-security/backups',
$wp_content_upload.'/mainwp/backup',
$wp_content_upload.'/pb_backupbuddy',
$wp_content_upload.'/snapshots',
$wp_content_upload.'/sucuri',
$wp_content_upload.'/wp-clone',
$wp_content_upload.'/wp_all_backup',
$wp_content_upload.'/wpbackitup_backups'
);
if (class_exists('BackWPup')) {
$upload_dir = wp_upload_dir(null, false, true);
$this->FilterInfo->Dirs->Core[] = trailingslashit(str_replace( '\\',
'/',
$upload_dir['basedir'])).'backwpup-'.BackWPup::get_plugin_data('hash').'-backups/';
$backwpup_cfg_logfolder = get_site_option('backwpup_cfg_logfolder');
if (false !== $backwpup_cfg_logfolder) {
$this->FilterInfo->Dirs->Core[] = $wp_content.'/'.$backwpup_cfg_logfolder;
}
}
$duplicator_global_file_filters_on = apply_filters('duplicator_global_file_filters_on', $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS_ON']);
if ($GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS_ON']) {
$duplicator_global_file_filters = apply_filters('duplicator_global_file_filters', $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS']);
$this->FilterInfo->Files->Global = $duplicator_global_file_filters;
}
// Prevent adding double wp-content dir conflicts
if ($this->isOuterWPContentDir()) {
$default_wp_content_dir_path = DUP_Util::safePath(ABSPATH.'wp-content');
if (file_exists($default_wp_content_dir_path)) {
if (is_dir($default_wp_content_dir_path)) {
$this->FilterInfo->Dirs->Core[] = $default_wp_content_dir_path;
} else {
$this->FilterInfo->Files->Core[] = $default_wp_content_dir_path;
}
}
}
$this->FilterDirsAll = array_merge($this->FilterInfo->Dirs->Instance, $this->FilterInfo->Dirs->Core);
$this->FilterExtsAll = array_merge($this->FilterInfo->Exts->Instance, $this->FilterInfo->Exts->Core);
$this->FilterFilesAll = array_merge($this->FilterInfo->Files->Instance, $this->FilterInfo->Files->Global);
$abs_path = duplicator_get_abs_path();
$this->FilterFilesAll[] = $abs_path.'/.htaccess';
$this->FilterFilesAll[] = $abs_path.'/web.config';
$this->FilterFilesAll[] = $abs_path.'/wp-config.php';
$this->tmpFilterDirsAll = $this->FilterDirsAll;
//PHP 5 on windows decode patch
if (!DUP_Util::$PHP7_plus && DUP_Util::isWindows()) {
foreach ($this->tmpFilterDirsAll as $key => $value) {
if (preg_match('/[^\x20-\x7f]/', $value)) {
$this->tmpFilterDirsAll[$key] = utf8_decode($value);
}
}
}
}
/**
* Get All Directories then filter
*
* @return null
*/
private function setDirFilters()
{
$this->FilterInfo->Dirs->Warning = array();
$this->FilterInfo->Dirs->Unreadable = array();
$this->FilterInfo->Dirs->AddonSites = array();
$skip_archive_scan = DUP_Settings::Get('skip_archive_scan');
$utf8_key_list = array();
$unset_key_list = array();
//Filter directories invalid test checks for:
// - characters over 250
// - invlaid characters
// - empty string
// - directories ending with period (Windows incompatable)
foreach ($this->Dirs as $key => $val) {
$name = basename($val);
//Dir is not readble remove flag for removal
if (!is_readable($this->Dirs[$key])) {
$unset_key_list[] = $key;
$this->FilterInfo->Dirs->Unreadable[] = DUP_Encoding::toUTF8($val);
}
if (!$skip_archive_scan) {
//Locate invalid directories and warn
$invalid_test = (defined('PHP_MAXPATHLEN') && (strlen($val) > PHP_MAXPATHLEN)) || preg_match('/(\/|\*|\?|\>|\<|\:|\\|\|)/', $name) || trim($name) == '' || (strrpos($name, '.') == strlen($name) - 1 && substr($name, -1)
== '.') || preg_match('/[^\x20-\x7f]/', $name);
if ($invalid_test) {
$utf8_key_list[] = $key;
$this->FilterInfo->Dirs->Warning[] = DUP_Encoding::toUTF8($val);
}
}
//Check for other WordPress installs
if ($name === 'wp-admin') {
$parent_dir = realpath(dirname($this->Dirs[$key]));
if ($parent_dir != realpath(duplicator_get_abs_path())) {
if (file_exists("$parent_dir/wp-includes")) {
if (file_exists("$parent_dir/wp-config.php")) {
// Ensure we aren't adding any critical directories
$parent_name = basename($parent_dir);
if (($parent_name != 'wp-includes') && ($parent_name != 'wp-content') && ($parent_name != 'wp-admin')) {
$this->FilterInfo->Dirs->AddonSites[] = str_replace("\\", '/', $parent_dir);
}
}
}
}
}
}
//Try to repair utf8 paths
foreach ($utf8_key_list as $key) {
$this->Dirs[$key] = DUP_Encoding::toUTF8($this->Dirs[$key]);
}
//Remove unreadable items outside of main loop for performance
if (count($unset_key_list)) {
foreach ($unset_key_list as $key) {
unset($this->Dirs[$key]);
}
$this->Dirs = array_values($this->Dirs);
}
}
/**
* Get all files and filter out error prone subsets
*
* @return null
*/
private function setFileFilters()
{
//Init for each call to prevent concatination from stored entity objects
$this->Size = 0;
$this->FilterInfo->Files->Size = array();
$this->FilterInfo->Files->Warning = array();
$this->FilterInfo->Files->Unreadable = array();
$skip_archive_scan = DUP_Settings::Get('skip_archive_scan');
$utf8_key_list = array();
$unset_key_list = array();
$wpconfig_filepath = $this->getWPConfigFilePath();
if (!is_readable($wpconfig_filepath)) {
$this->FilterInfo->Files->Unreadable[] = $wpconfig_filepath;
}
foreach ($this->Files as $key => $filePath) {
$fileName = basename($filePath);
if (!is_readable($filePath)) {
$unset_key_list[] = $key;
$this->FilterInfo->Files->Unreadable[] = $filePath;
continue;
}
$fileSize = @filesize($filePath);
$fileSize = empty($fileSize) ? 0 : $fileSize;
$this->Size += $fileSize;
if (!$skip_archive_scan) {
$invalid_test = (defined('PHP_MAXPATHLEN') && (strlen($filePath) > PHP_MAXPATHLEN)) || preg_match('/(\/|\*|\?|\>|\<|\:|\\|\|)/', $fileName) || trim($fileName) == "" || preg_match('/[^\x20-\x7f]/', $fileName);
if ($invalid_test) {
$utf8_key_list[] = $key;
$filePath = DUP_Encoding::toUTF8($filePath);
$fileName = basename($filePath);
$this->FilterInfo->Files->Warning[] = array(
'name' => $fileName,
'dir' => pathinfo($filePath, PATHINFO_DIRNAME),
'path' => $filePath);
}
if ($fileSize > DUPLICATOR_SCAN_WARNFILESIZE) {
//$ext = pathinfo($filePath, PATHINFO_EXTENSION);
$this->FilterInfo->Files->Size[] = array(
'ubytes' => $fileSize,
'bytes' => DUP_Util::byteSize($fileSize, 0),
'name' => $fileName,
'dir' => pathinfo($filePath, PATHINFO_DIRNAME),
'path' => $filePath);
}
}
}
//Try to repair utf8 paths
foreach ($utf8_key_list as $key) {
$this->Files[$key] = DUP_Encoding::toUTF8($this->Files[$key]);
}
//Remove unreadable items outside of main loop for performance
if (count($unset_key_list)) {
foreach ($unset_key_list as $key) {
unset($this->Files[$key]);
}
$this->Files = array_values($this->Files);
}
}
/**
* Recursive function to get all directories in a wp install
*
* @notes:
* Older PHP logic which is more stable on older version of PHP
* NOTE RecursiveIteratorIterator is problematic on some systems issues include:
* - error 'too many files open' for recursion
* - $file->getExtension() is not reliable as it silently fails at least in php 5.2.17
* - issues with when a file has a permission such as 705 and trying to get info (had to fallback to pathinfo)
* - basic conclusion wait on the SPL libs until after php 5.4 is a requirments
* - tight recursive loop use caution for speed
*
* @return array Returns an array of directories to include in the archive
*/
private function getFileLists($path) {
$handle = @opendir($path);
if ($handle) {
while (($file = readdir($handle)) !== false) {
if ($file == '.' || $file == '..') {
continue;
}
$fullPath = str_replace("\\", '/', "{$path}/{$file}");
// @todo: Don't leave it like this. Convert into an option on the package to not follow symbolic links
// if (is_dir($fullPath) && (is_link($fullPath) == false))
if (is_dir($fullPath)) {
$add = true;
if (!is_link($fullPath)){
foreach ($this->tmpFilterDirsAll as $key => $val) {
$trimmedFilterDir = rtrim($val, '/');
if ($fullPath == $trimmedFilterDir || strpos($fullPath, $trimmedFilterDir . '/') !== false) {
$add = false;
unset($this->tmpFilterDirsAll[$key]);
break;
}
}
} else{
//Convert relative path of link to absolute path
chdir($fullPath);
$link_path = str_replace("\\", '/', realpath(readlink($fullPath)));
chdir(dirname(__FILE__));
$link_pos = strpos($fullPath,$link_path);
if($link_pos === 0 && (strlen($link_path) < strlen($fullPath))){
$add = false;
$this->RecursiveLinks[] = $fullPath;
$this->FilterDirsAll[] = $fullPath;
} else {
foreach ($this->tmpFilterDirsAll as $key => $val) {
$trimmedFilterDir = rtrim($val, '/');
if ($fullPath == $trimmedFilterDir || strpos($fullPath, $trimmedFilterDir . '/') !== false) {
$add = false;
unset($this->tmpFilterDirsAll[$key]);
break;
}
}
}
}
if ($add) {
$this->getFileLists($fullPath);
$this->Dirs[] = $fullPath;
}
} else {
if ( ! (in_array(pathinfo($file, PATHINFO_EXTENSION), $this->FilterExtsAll)
|| in_array($fullPath, $this->FilterFilesAll)
|| in_array($file, $this->FilterFilesAll))) {
$this->Files[] = $fullPath;
}
}
}
closedir($handle);
}
return $this->Dirs;
}
/**
* Builds a tree for both file size warnings and name check warnings
* The trees are used to apply filters from the scan screen
*
* @return null
*/
private function setTreeFilters()
{
//-------------------------
//SIZE TREE
//BUILD: File Size tree
$dir_group = DUP_Util::array_group_by($this->FilterInfo->Files->Size, "dir");
ksort($dir_group);
foreach ($dir_group as $dir => $files) {
$sum = 0;
foreach ($files as $key => $value) {
$sum += $value['ubytes'];
}
//Locate core paths, wp-admin, wp-includes, etc.
$iscore = 0;
foreach ($this->wpCorePaths as $core_dir) {
if (strpos(DUP_Util::safePath($dir), DUP_Util::safePath($core_dir)) !== false) {
$iscore = 1;
break;
}
}
// Check root and content exact dir
if (!$iscore) {
if (in_array($dir, $this->wpCoreExactPaths)) {
$iscore = 1;
}
}
$this->FilterInfo->TreeSize[] = array(
'size' => DUP_Util::byteSize($sum, 0),
'dir' => $dir,
'sdir' => str_replace(duplicator_get_abs_path(), '/', $dir),
'iscore' => $iscore,
'files' => $files
);
}
//-------------------------
//NAME TREE
//BUILD: Warning tree for file names
$dir_group = DUP_Util::array_group_by($this->FilterInfo->Files->Warning, "dir");
ksort($dir_group);
foreach ($dir_group as $dir => $files) {
//Locate core paths, wp-admin, wp-includes, etc.
$iscore = 0;
foreach ($this->wpCorePaths as $core_dir) {
if (strpos($dir, $core_dir) !== false) {
$iscore = 1;
break;
}
}
// Check root and content exact dir
if (!$iscore) {
if (in_array($dir, $this->wpCoreExactPaths)) {
$iscore = 1;
}
}
$this->FilterInfo->TreeWarning[] = array(
'dir' => $dir,
'sdir' => str_replace(duplicator_get_abs_path(), '/', $dir),
'iscore' => $iscore,
'count' => count($files),
'files' => $files);
}
//BUILD: Warning tree for dir names
foreach ($this->FilterInfo->Dirs->Warning as $dir) {
$add_dir = true;
foreach ($this->FilterInfo->TreeWarning as $key => $value) {
if ($value['dir'] == $dir) {
$add_dir = false;
break;
}
}
if ($add_dir) {
//Locate core paths, wp-admin, wp-includes, etc.
$iscore = 0;
foreach ($this->wpCorePaths as $core_dir) {
if (strpos(DUP_Util::safePath($dir), DUP_Util::safePath($core_dir)) !== false) {
$iscore = 1;
break;
}
}
// Check root and content exact dir
if (!$iscore) {
if (in_array($dir, $this->wpCoreExactPaths)) {
$iscore = 1;
}
}
$this->FilterInfo->TreeWarning[] = array(
'dir' => $dir,
'sdir' => str_replace(duplicator_get_abs_path(), '/', $dir),
'iscore' => $iscore,
'count' => 0);
}
}
function _sortDir($a, $b)
{
return strcmp($a["dir"], $b["dir"]);
}
usort($this->FilterInfo->TreeWarning, "_sortDir");
}
public function getWPConfigFilePath()
{
$wpconfig_filepath = '';
$abs_path = duplicator_get_abs_path();
if (file_exists($abs_path.'/wp-config.php')) {
$wpconfig_filepath = $abs_path.'/wp-config.php';
} elseif (@file_exists(dirname($abs_path).'/wp-config.php') && !@file_exists(dirname($abs_path).'/wp-settings.php')) {
$wpconfig_filepath = dirname($abs_path).'/wp-config.php';
}
return $wpconfig_filepath;
}
public function isOuterWPContentDir()
{
if (!isset($this->isOuterWPContentDir)) {
$abspath_normalize = wp_normalize_path(ABSPATH);
$wp_content_dir_normalize = wp_normalize_path(WP_CONTENT_DIR);
if (0 !== strpos($wp_content_dir_normalize, $abspath_normalize)) {
$this->isOuterWPContentDir = true;
} else {
$this->isOuterWPContentDir = false;
}
}
return $this->isOuterWPContentDir;
}
public function wpContentDirNormalizePath()
{
if (!isset($this->wpContentDirNormalizePath)) {
$this->wpContentDirNormalizePath = trailingslashit(wp_normalize_path(WP_CONTENT_DIR));
}
return $this->wpContentDirNormalizePath;
}
public function getUrl()
{
return DUP_Settings::getSsdirUrl()."/".$this->File;
}
public function getLocalDirPath($dir, $basePath = '')
{
$isOuterWPContentDir = $this->isOuterWPContentDir();
$wpContentDirNormalizePath = $this->wpContentDirNormalizePath();
$compressDir = rtrim(wp_normalize_path(DUP_Util::safePath($this->PackDir)), '/');
$dir = trailingslashit(wp_normalize_path($dir));
if ($isOuterWPContentDir && 0 === strpos($dir, $wpContentDirNormalizePath)) {
$newWPContentDirPath = empty($basePath) ? 'wp-content/' : $basePath.'wp-content/';
$emptyDir = ltrim(str_replace($wpContentDirNormalizePath, $newWPContentDirPath, $dir), '/');
} else {
$emptyDir = ltrim($basePath.preg_replace('/^'.preg_quote($compressDir, '/').'(.*)/m', '$1', $dir), '/');
}
return $emptyDir;
}
public function getLocalFilePath($file, $basePath = '')
{
$isOuterWPContentDir = $this->isOuterWPContentDir();
$wpContentDirNormalizePath = $this->wpContentDirNormalizePath();
$compressDir = rtrim(wp_normalize_path(DUP_Util::safePath($this->PackDir)), '/');
$file = wp_normalize_path($file);
if ($isOuterWPContentDir && 0 === strpos($file, $wpContentDirNormalizePath)) {
$newWPContentDirPath = empty($basePath) ? 'wp-content/' : $basePath.'wp-content/';
$localFileName = ltrim(str_replace($wpContentDirNormalizePath, $newWPContentDirPath, $file), '/');
} else {
$localFileName = ltrim($basePath.preg_replace('/^'.preg_quote($compressDir, '/').'(.*)/m', '$1', $file), '/');
}
return $localFileName;
}
} classes/package/class.pack.database.php 0000644 00000074666 15133606540 0014120 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
// Exit if accessed directly
if (!defined('DUPLICATOR_VERSION'))
exit;
/**
* Class for gathering system information about a database
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
*/
class DUP_DatabaseInfo
{
/**
* The SQL file was built with mysqldump or PHP
*/
public $buildMode;
/**
* A unique list of all the collation table types used in the database
*/
public $collationList;
/**
* Does any filtered table have an upper case character in it
*/
public $isTablesUpperCase;
/**
* Does the database name have any filtered characters in it
*/
public $isNameUpperCase;
/**
* The real name of the database
*/
public $name;
/**
* The full count of all tables in the database
*/
public $tablesBaseCount;
/**
* The count of tables after the tables filter has been applied
*/
public $tablesFinalCount;
/**
* The number of rows from all filtered tables in the database
*/
public $tablesRowCount;
/**
* The estimated data size on disk from all filtered tables in the database
*/
public $tablesSizeOnDisk;
/**
* Gets the server variable lower_case_table_names
*
* 0 store=lowercase; compare=sensitive (works only on case sensitive file systems )
* 1 store=lowercase; compare=insensitive
* 2 store=exact; compare=insensitive (works only on case INsensitive file systems )
* default is 0/Linux ; 1/Windows
*/
public $varLowerCaseTables;
/**
* The simple numeric version number of the database server
* @exmaple: 5.5
*/
public $version;
/**
* The full text version number of the database server
* @exmaple: 10.2 mariadb.org binary distribution
*/
public $versionComment;
/**
* table wise row counts array, Key as table name and value as row count
* table name => row count
*/
public $tableWiseRowCounts;
/**
* @var array List of triggers included in the database
*/
public $triggerList = array();
/**
* Integer field file structure of table, table name as key
*/
private $intFieldsStruct = array();
/**
* $currentIndex => processedSchemaSize
*/
private $indexProcessedSchemaSize = array();
//CONSTRUCTOR
function __construct()
{
$this->collationList = array();
$this->tableWiseRowCounts = array();
}
public function addTriggers()
{
global $wpdb;
if (!is_array($triggers = $wpdb->get_results("SHOW TRIGGERS", ARRAY_A))) {
return;
}
foreach ($triggers as $trigger) {
$name = $trigger["Trigger"];
$create = $wpdb->get_row("SHOW CREATE TRIGGER `{$name}`", ARRAY_N);
$this->triggerList[$name] = array(
"create" => "DELIMITER ;;\n".$create[2].";;\nDELIMITER ;"
);
}
}
}
class DUP_Database
{
//PUBLIC
public $Type = 'MySQL';
public $Size;
public $File;
public $Path;
public $FilterTables;
public $FilterOn;
public $Name;
public $Compatible;
public $Comments;
/**
*
* @var DUP_DatabaseInfo
*/
public $info = null;
//PROTECTED
protected $Package;
//PRIVATE
private $tempDbPath;
private $EOFMarker;
private $networkFlush;
/**
* Init this object
*/
function __construct($package)
{
$this->Package = $package;
$this->EOFMarker = "";
$package_zip_flush = DUP_Settings::Get('package_zip_flush');
$this->networkFlush = empty($package_zip_flush) ? false : $package_zip_flush;
$this->info = new DUP_DatabaseInfo();
$this->info->varLowerCaseTables = DUP_Util::isWindows() ? 1 : 0;
}
/**
* Build the database script
*
* @param DUP_Package $package A reference to the package that this database object belongs in
*
* @return null
*/
public function build($package, $errorBehavior = Dup_ErrorBehavior::ThrowException)
{
try {
$this->Package = $package;
do_action('duplicator_lite_build_database_before_start', $package);
$time_start = DUP_Util::getMicrotime();
$this->Package->setStatus(DUP_PackageStatus::DBSTART);
$this->tempDbPath = DUP_Settings::getSsdirTmpPath()."/{$this->File}";
$package_mysqldump = DUP_Settings::Get('package_mysqldump');
$package_phpdump_qrylimit = DUP_Settings::Get('package_phpdump_qrylimit');
$mysqlDumpPath = DUP_DB::getMySqlDumpPath();
$mode = DUP_DB::getBuildMode();
$reserved_db_filepath = duplicator_get_abs_path().'/database.sql';
$log = "\n********************************************************************************\n";
$log .= "DATABASE:\n";
$log .= "********************************************************************************\n";
$log .= "BUILD MODE: {$mode}";
$log .= ($mode == 'PHP') ? "(query limit - {$package_phpdump_qrylimit})\n" : "\n";
$log .= "MYSQLTIMEOUT: ".DUPLICATOR_DB_MAX_TIME."\n";
$log .= "MYSQLDUMP: ";
$log .= ($mysqlDumpPath) ? "Is Supported" : "Not Supported";
DUP_Log::Info($log);
$log = null;
do_action('duplicator_lite_build_database_start', $package);
switch ($mode) {
case 'MYSQLDUMP':
$this->mysqlDump($mysqlDumpPath);
break;
case 'PHP' :
$this->phpDump($package);
break;
}
DUP_Log::Info("SQL CREATED: {$this->File}");
$time_end = DUP_Util::getMicrotime();
$time_sum = DUP_Util::elapsedTime($time_end, $time_start);
//File below 10k considered incomplete
$sql_file_size = is_file($this->tempDbPath) ? @filesize($this->tempDbPath) : 0;
DUP_Log::Info("SQL FILE SIZE: ".DUP_Util::byteSize($sql_file_size)." ({$sql_file_size})");
if ($sql_file_size < 1350) {
$error_message = "SQL file size too low.";
$package->BuildProgress->set_failed($error_message);
$package->Status = DUP_PackageStatus::ERROR;
$package->Update();
DUP_Log::error($error_message, "File does not look complete. Check permission on file and parent directory at [{$this->tempDbPath}]", $errorBehavior);
do_action('duplicator_lite_build_database_fail', $package);
} else {
do_action('duplicator_lite_build_database_completed', $package);
}
DUP_Log::Info("SQL FILE TIME: ".date("Y-m-d H:i:s"));
DUP_Log::Info("SQL RUNTIME: {$time_sum}");
$this->Size = is_file($this->tempDbPath) ? @filesize($this->tempDbPath) : 0;
$this->Package->setStatus(DUP_PackageStatus::DBDONE);
}
catch (Exception $e) {
do_action('duplicator_lite_build_database_fail', $package);
DUP_Log::error("Runtime error in DUP_Database::Build. ".$e->getMessage(), "Exception: {$e}", $errorBehavior);
}
}
/**
* Get the database meta-data such as tables as all there details
*
* @return array Returns an array full of meta-data about the database
*/
public function getScannerData()
{
global $wpdb;
$filterTables = isset($this->FilterTables) ? explode(',', $this->FilterTables) : array();
$tblBaseCount = 0;
$tblCount = 0;
$tables = $wpdb->get_results("SHOW TABLE STATUS", ARRAY_A);
$info = array();
$info['Status']['Success'] = is_null($tables) ? false : true;
//DB_Case for the database name is never checked on
$info['Status']['DB_Case'] = 'Good';
$info['Status']['DB_Rows'] = 'Good';
$info['Status']['DB_Size'] = 'Good';
$info['Status']['TBL_Case'] = 'Good';
$info['Status']['TBL_Rows'] = 'Good';
$info['Status']['TBL_Size'] = 'Good';
$info['Size'] = 0;
$info['Rows'] = 0;
$info['TableCount'] = 0;
$info['TableList'] = array();
$tblCaseFound = 0;
$tblRowsFound = 0;
$tblSizeFound = 0;
//Grab Table Stats
$filteredTables = array();
foreach ($tables as $table) {
$tblBaseCount++;
$name = $table["Name"];
if ($this->FilterOn && is_array($filterTables)) {
if (in_array($name, $filterTables)) {
continue;
}
}
$size = ($table["Data_length"] + $table["Index_length"]);
$rows = empty($table["Rows"]) ? '0' : $table["Rows"];
$info['Size'] += $size;
$info['Rows'] += ($table["Rows"]);
$info['TableList'][$name]['Case'] = preg_match('/[A-Z]/', $name) ? 1 : 0;
$info['TableList'][$name]['Rows'] = number_format($rows);
$info['TableList'][$name]['Size'] = DUP_Util::byteSize($size);
$info['TableList'][$name]['USize'] = $size;
$filteredTables[] = $name;
$tblCount++;
//Table Uppercase
if ($info['TableList'][$name]['Case']) {
if (!$tblCaseFound) {
$tblCaseFound = 1;
}
}
//Table Row Count
if ($rows > DUPLICATOR_SCAN_DB_TBL_ROWS) {
if (!$tblRowsFound) {
$tblRowsFound = 1;
}
}
//Table Size
if ($size > DUPLICATOR_SCAN_DB_TBL_SIZE) {
if (!$tblSizeFound) {
$tblSizeFound = 1;
}
}
}
$this->setInfoObj($filteredTables);
$this->info->addTriggers();
$info['Status']['DB_Case'] = preg_match('/[A-Z]/', $wpdb->dbname) ? 'Warn' : 'Good';
$info['Status']['DB_Rows'] = ($info['Rows'] > DUPLICATOR_SCAN_DB_ALL_ROWS) ? 'Warn' : 'Good';
$info['Status']['DB_Size'] = ($info['Size'] > DUPLICATOR_SCAN_DB_ALL_SIZE) ? 'Warn' : 'Good';
$info['Status']['TBL_Case'] = ($tblCaseFound) ? 'Warn' : 'Good';
$info['Status']['TBL_Rows'] = ($tblRowsFound) ? 'Warn' : 'Good';
$info['Status']['TBL_Size'] = ($tblSizeFound) ? 'Warn' : 'Good';
$info['Status']['Triggers'] = count($this->info->triggerList) > 0 ? 'Warn' : 'Good';
$info['RawSize'] = $info['Size'];
$info['Size'] = DUP_Util::byteSize($info['Size']) or "unknown";
$info['Rows'] = number_format($info['Rows']) or "unknown";
$info['TableList'] = $info['TableList'] or "unknown";
$info['TableCount'] = $tblCount;
$this->info->isTablesUpperCase = $tblCaseFound;
$this->info->tablesBaseCount = $tblBaseCount;
$this->info->tablesFinalCount = $tblCount;
$this->info->tablesRowCount = $info['Rows'];
$this->info->tablesSizeOnDisk = $info['Size'];
return $info;
}
/**
* @param array &$filteredTables Filtered names of tables to include in collation search.
* Parameter does not change in the function, is passed by reference only to avoid copying.
*
* @return void
*/
public function setInfoObj(&$filteredTables)
{
global $wpdb;
$this->info->buildMode = DUP_DB::getBuildMode();
$this->info->version = DUP_DB::getVersion();
$this->info->versionComment = DUP_DB::getVariable('version_comment');
$this->info->varLowerCaseTables = DUP_DB::getVariable('lower_case_table_names');
$this->info->name = $wpdb->dbname;
$this->info->isNameUpperCase = preg_match('/[A-Z]/', $wpdb->dbname) ? 1 : 0;
$this->info->collationList = DUP_DB::getTableCollationList($filteredTables);
}
/**
* Unset tableWiseRowCounts table key for which row count is unstable
*
* @param object $package The reference to the current package being built *
* @return void
*/
public function validateTableWiseRowCounts()
{
foreach ($this->Package->Database->info->tableWiseRowCounts as $rewriteTableAs => $rowCount) {
$newRowCount = $GLOBALS['wpdb']->get_var("SELECT Count(*) FROM `{$rewriteTableAs}`");
if ($rowCount != $newRowCount) {
unset($this->Package->Database->info->tableWiseRowCounts[$rewriteTableAs]);
}
}
}
/**
* Build the database script using mysqldump
*
* @return bool Returns true if the sql script was successfully created
*/
private function mysqlDump($exePath)
{
global $wpdb;
require_once (DUPLICATOR_PLUGIN_PATH.'classes/utilities/class.u.shell.php');
$host = explode(':', DB_HOST);
$host = reset($host);
$port = strpos(DB_HOST, ':') ? end(explode(':', DB_HOST)) : '';
$name = DB_NAME;
$mysqlcompat_on = isset($this->Compatible) && strlen($this->Compatible);
//Build command
$cmd = escapeshellarg($exePath);
$cmd .= ' --no-create-db';
$cmd .= ' --single-transaction';
$cmd .= ' --hex-blob';
$cmd .= ' --skip-add-drop-table';
$cmd .= ' --routines';
$cmd .= ' --quote-names';
$cmd .= ' --skip-comments';
$cmd .= ' --skip-set-charset';
$cmd .= ' --skip-triggers';
$cmd .= ' --allow-keywords';
$cmd .= ' --no-tablespaces';
//Compatibility mode
if ($mysqlcompat_on) {
DUP_Log::Info("COMPATIBLE: [{$this->Compatible}]");
$cmd .= " --compatible={$this->Compatible}";
}
//Filter tables
$res = $wpdb->get_results('SHOW FULL TABLES', ARRAY_N);
$tables = array();
$baseTables = array();
foreach ($res as $row) {
if (DUP_Util::isTableExists($row[0])) {
$tables[] = $row[0];
if ('BASE TABLE' == $row[1]) {
$baseTables[] = $row[0];
}
}
}
$filterTables = isset($this->FilterTables) ? explode(',', $this->FilterTables) : null;
$tblAllCount = count($tables);
foreach ($tables as $table) {
if (in_array($table, $baseTables)) {
$row_count = $GLOBALS['wpdb']->get_var("SELECT Count(*) FROM `{$table}`");
$rewrite_table_as = $this->rewriteTableNameAs($table);
$this->Package->Database->info->tableWiseRowCounts[$rewrite_table_as] = $row_count;
}
}
//$tblFilterOn = ($this->FilterOn) ? 'ON' : 'OFF';
if (is_array($filterTables) && $this->FilterOn) {
foreach ($tables as $key => $val) {
if (in_array($tables[$key], $filterTables)) {
$cmd .= " --ignore-table={$name}.{$tables[$key]} ";
unset($tables[$key]);
}
}
}
$cmd .= ' -u '.escapeshellarg(DB_USER);
$cmd .= (DB_PASSWORD) ?
' -p'.DUP_Shell_U::escapeshellargWindowsSupport(DB_PASSWORD) : '';
$cmd .= ' -h '.escapeshellarg($host);
$cmd .= (!empty($port) && is_numeric($port) ) ?
' -P '.$port : '';
$isPopenEnabled = DUP_Shell_U::isPopenEnabled();
if (!$isPopenEnabled) {
$cmd .= ' -r '.escapeshellarg($this->tempDbPath);
}
$cmd .= ' '.escapeshellarg(DB_NAME);
$cmd .= ' 2>&1';
if ($isPopenEnabled) {
$needToRewrite = false;
foreach ($tables as $tableName) {
$rewriteTableAs = $this->rewriteTableNameAs($tableName);
if ($tableName != $rewriteTableAs) {
$needToRewrite = true;
break;
}
}
if ($needToRewrite) {
$findReplaceTableNames = array(); // orignal table name => rewrite table name
foreach ($tables as $tableName) {
$rewriteTableAs = $this->rewriteTableNameAs($tableName);
if ($tableName != $rewriteTableAs) {
$findReplaceTableNames[$tableName] = $rewriteTableAs;
}
}
}
$firstLine = '';
DUP_LOG::trace("Executing mysql dump command by popen: $cmd");
$handle = popen($cmd, "r");
if ($handle) {
$sql_header = "/* DUPLICATOR-LITE (MYSQL-DUMP BUILD MODE) MYSQL SCRIPT CREATED ON : ".@date("Y-m-d H:i:s")." */\n\n";
file_put_contents($this->tempDbPath, $sql_header, FILE_APPEND);
while (!feof($handle)) {
$line = fgets($handle); //get ony one line
if ($line) {
if (empty($firstLine)) {
$firstLine = $line;
if (false !== stripos($line, 'Using a password on the command line interface can be insecure'))
continue;
}
if ($needToRewrite) {
$replaceCount = 1;
if (preg_match('/CREATE TABLE `(.*?)`/', $line, $matches)) {
$tableName = $matches[1];
if (isset($findReplaceTableNames[$tableName])) {
$rewriteTableAs = $findReplaceTableNames[$tableName];
$line = str_replace('CREATE TABLE `'.$tableName.'`', 'CREATE TABLE `'.$rewriteTableAs.'`', $line, $replaceCount);
}
} elseif (preg_match('/INSERT INTO `(.*?)`/', $line, $matches)) {
$tableName = $matches[1];
if (isset($findReplaceTableNames[$tableName])) {
$rewriteTableAs = $findReplaceTableNames[$tableName];
$line = str_replace('INSERT INTO `'.$tableName.'`', 'INSERT INTO `'.$rewriteTableAs.'`', $line, $replaceCount);
}
} elseif (preg_match('/LOCK TABLES `(.*?)`/', $line, $matches)) {
$tableName = $matches[1];
if (isset($findReplaceTableNames[$tableName])) {
$rewriteTableAs = $findReplaceTableNames[$tableName];
$line = str_replace('LOCK TABLES `'.$tableName.'`', 'LOCK TABLES `'.$rewriteTableAs.'`', $line, $replaceCount);
}
}
}
file_put_contents($this->tempDbPath, $line, FILE_APPEND);
$output = "Ran from {$exePath}";
}
}
$mysqlResult = pclose($handle);
} else {
$output = '';
}
// Password bug > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546)
if (empty($output) && trim($firstLine) === 'Warning: Using a password on the command line interface can be insecure.') {
$output = '';
}
} else {
DUP_LOG::trace("Executing mysql dump command $cmd");
exec($cmd, $output, $mysqlResult);
$output = implode("\n", $output);
// Password bug > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546)
if (trim($output) === 'Warning: Using a password on the command line interface can be insecure.') {
$output = '';
}
$output = (strlen($output)) ? $output : "Ran from {$exePath}";
$tblCreateCount = count($tables);
$tblFilterCount = $tblAllCount - $tblCreateCount;
//DEBUG
//DUP_Log::Info("COMMAND: {$cmd}");
DUP_Log::Info("FILTERED: [{$this->FilterTables}]");
DUP_Log::Info("RESPONSE: {$output}");
DUP_Log::Info("TABLES: total:{$tblAllCount} | filtered:{$tblFilterCount} | create:{$tblCreateCount}");
}
$sql_footer = "\n\n/* Duplicator WordPress Timestamp: ".date("Y-m-d H:i:s")."*/\n";
$sql_footer .= "/* ".DUPLICATOR_DB_EOF_MARKER." */\n";
file_put_contents($this->tempDbPath, $sql_footer, FILE_APPEND);
if ($mysqlResult !== 0) {
/**
* -1 error command shell
* mysqldump return
* 0 - Success
* 1 - Warning
* 2 - Exception
*/
DUP_Log::Info('MYSQL DUMP ERROR '.print_r($mysqlResult, true));
DUP_Log::error(__('Shell mysql dump error. Change SQL Mode to the "PHP Code" in the Duplicator > Settings > Packages.', 'duplicator'), implode("\n", DupLiteSnapLibIOU::getLastLinesOfFile($this->tempDbPath,
DUPLICATOR_DB_MYSQLDUMP_ERROR_CONTAINING_LINE_COUNT, DUPLICATOR_DB_MYSQLDUMP_ERROR_CHARS_IN_LINE_COUNT)), Dup_ErrorBehavior::ThrowException);
return false;
}
return true;
}
/**
* Build the database script using php
*
* @return bool Returns true if the sql script was successfully created
*/
private function phpDump($package)
{
global $wpdb;
$wpdb->query("SET session wait_timeout = ".DUPLICATOR_DB_MAX_TIME);
if (($handle = fopen($this->tempDbPath, 'w+')) == false) {
DUP_Log::error('[PHP DUMP] ERROR Can\'t open sbStorePath "'.$this->tempDbPath.'"', Dup_ErrorBehavior::ThrowException);
}
$tables = $wpdb->get_col("SHOW FULL TABLES WHERE Table_Type != 'VIEW'");
$filterTables = isset($this->FilterTables) ? explode(',', $this->FilterTables) : null;
$tblAllCount = count($tables);
//$tblFilterOn = ($this->FilterOn) ? 'ON' : 'OFF';
$qryLimit = DUP_Settings::Get('package_phpdump_qrylimit');
if (is_array($filterTables) && $this->FilterOn) {
foreach ($tables as $key => $val) {
if (in_array($tables[$key], $filterTables)) {
unset($tables[$key]);
}
}
}
$tblCreateCount = count($tables);
$tblFilterCount = $tblAllCount - $tblCreateCount;
DUP_Log::Info("TABLES: total:{$tblAllCount} | filtered:{$tblFilterCount} | create:{$tblCreateCount}");
DUP_Log::Info("FILTERED: [{$this->FilterTables}]");
//Added 'NO_AUTO_VALUE_ON_ZERO' at plugin version 1.2.12 to fix :
//**ERROR** database error write 'Invalid default value for for older mysql versions
$sql_header = "/* DUPLICATOR-LITE (PHP BUILD MODE) MYSQL SCRIPT CREATED ON : ".@date("Y-m-d H:i:s")." */\n\n";
$sql_header .= "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n\n";
$sql_header .= "SET FOREIGN_KEY_CHECKS = 0;\n\n";
fwrite($handle, $sql_header);
//BUILD CREATES:
//All creates must be created before inserts do to foreign key constraints
foreach ($tables as $table) {
$rewrite_table_as = $this->rewriteTableNameAs($table);
$create = $wpdb->get_row("SHOW CREATE TABLE `{$table}`", ARRAY_N);
$count = 1;
$create_table_query = str_replace($table, $rewrite_table_as, $create[1], $count);
@fwrite($handle, "{$create_table_query};\n\n");
}
$procedures = $wpdb->get_col("SHOW PROCEDURE STATUS WHERE `Db` = '{$wpdb->dbname}'", 1);
if (count($procedures)) {
foreach ($procedures as $procedure) {
@fwrite($handle, "DELIMITER ;;\n");
$create = $wpdb->get_row("SHOW CREATE PROCEDURE `{$procedure}`", ARRAY_N);
@fwrite($handle, "{$create[2]} ;;\n");
@fwrite($handle, "DELIMITER ;\n\n");
}
}
$functions = $wpdb->get_col("SHOW FUNCTION STATUS WHERE `Db` = '{$wpdb->dbname}'", 1);
if (count($functions)) {
foreach ($functions as $function) {
@fwrite($handle, "DELIMITER ;;\n");
$create = $wpdb->get_row("SHOW CREATE FUNCTION `{$function}`", ARRAY_N);
@fwrite($handle, "{$create[2]} ;;\n");
@fwrite($handle, "DELIMITER ;\n\n");
}
}
$views = $wpdb->get_col("SHOW FULL TABLES WHERE Table_Type = 'VIEW'");
if (count($views)) {
foreach ($views as $view) {
$create = $wpdb->get_row("SHOW CREATE VIEW `{$view}`", ARRAY_N);
@fwrite($handle, "{$create[1]};\n\n");
}
}
$table_count = count($tables);
$table_number = 0;
//BUILD INSERTS:
//Create Insert in 100 row increments to better handle memory
foreach ($tables as $table) {
$table_number++;
if ($table_number % 2 == 0) {
$this->Package->Status = DupLiteSnapLibUtil::getWorkPercent(DUP_PackageStatus::DBSTART, DUP_PackageStatus::DBDONE, $table_count, $table_number);
$this->Package->update();
}
$row_count = $wpdb->get_var("SELECT Count(*) FROM `{$table}`");
$rewrite_table_as = $this->rewriteTableNameAs($table);
$this->Package->Database->info->tableWiseRowCounts[$rewrite_table_as] = $row_count;
if ($row_count > $qryLimit) {
$row_count = ceil($row_count / $qryLimit);
} else if ($row_count > 0) {
$row_count = 1;
}
if ($row_count >= 1) {
fwrite($handle, "\n/* INSERT TABLE DATA: {$table} */\n");
}
for ($i = 0; $i < $row_count; $i++) {
$sql = "";
$limit = $i * $qryLimit;
$query = "SELECT * FROM `{$table}` LIMIT {$limit}, {$qryLimit}";
$rows = $wpdb->get_results($query, ARRAY_A);
$select_last_error = $wpdb->last_error;
if ('' !== $select_last_error) {
$fix = esc_html__('Please contact your DataBase administrator to fix the error.', 'duplicator');
$errorMessage = $select_last_error.' '.$fix.'.';
$package->BuildProgress->set_failed($errorMessage);
$package->BuildProgress->failed = true;
$package->failed = true;
$package->Status = DUP_PackageStatus::ERROR;
$package->Update();
DUP_Log::error($select_last_error, $fix, Dup_ErrorBehavior::ThrowException);
return;
}
if (is_array($rows)) {
foreach ($rows as $row) {
$sql .= "INSERT INTO `{$rewrite_table_as}` VALUES(";
$num_values = count($row);
$num_counter = 1;
foreach ($row as $value) {
if (is_null($value) || !isset($value)) {
($num_values == $num_counter) ? $sql .= 'NULL' : $sql .= 'NULL, ';
} else {
($num_values == $num_counter) ? $sql .= '"'.DUP_DB::escSQL($value, true).'"' : $sql .= '"'.DUP_DB::escSQL($value, true).'", ';
}
$num_counter++;
}
$sql .= ");\n";
}
fwrite($handle, $sql);
}
}
//Flush buffer if enabled
if ($this->networkFlush) {
DUP_Util::fcgiFlush();
}
$sql = null;
$rows = null;
}
$sql_footer = "\nSET FOREIGN_KEY_CHECKS = 1; \n\n";
$sql_footer .= "/* Duplicator WordPress Timestamp: ".date("Y-m-d H:i:s")."*/\n";
$sql_footer .= "/* ".DUPLICATOR_DB_EOF_MARKER." */\n";
fwrite($handle, $sql_footer);
$wpdb->flush();
fclose($handle);
}
private function rewriteTableNameAs($table)
{
$table_prefix = $this->getTablePrefix();
if (!isset($this->sameNameTableExists)) {
global $wpdb;
$this->sameNameTableExists = false;
$all_tables = $wpdb->get_col("SHOW FULL TABLES WHERE Table_Type != 'VIEW'");
foreach ($all_tables as $table_name) {
if (strtolower($table_name) != $table_name && in_array(strtolower($table_name), $all_tables)) {
$this->sameNameTableExists = true;
break;
}
}
}
if (false === $this->sameNameTableExists && 0 === stripos($table, $table_prefix) && 0 !== strpos($table, $table_prefix)) {
$post_fix = substr($table, strlen($table_prefix));
$rewrite_table_name = $table_prefix.$post_fix;
} else {
$rewrite_table_name = $table;
}
return $rewrite_table_name;
}
private function getTablePrefix()
{
global $wpdb;
$table_prefix = (is_multisite() && !defined('MULTISITE')) ? $wpdb->base_prefix : $wpdb->get_blog_prefix(0);
return $table_prefix;
}
public function getUrl()
{
return DUP_Settings::getSsdirUrl()."/".$this->File;
}
} classes/package/class.pack.installer.php 0000644 00000051353 15133606540 0014335 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
// Exit if accessed directly
/* @var $global DUP_Global_Entity */
require_once(DUPLICATOR_PLUGIN_PATH.'/classes/class.archive.config.php');
require_once(DUPLICATOR_PLUGIN_PATH.'/classes/utilities/class.u.zip.php');
require_once(DUPLICATOR_PLUGIN_PATH.'/classes/utilities/class.u.multisite.php');
require_once(DUPLICATOR_PLUGIN_PATH.'/classes/class.password.php');
class DUP_Installer
{
const DEFAULT_INSTALLER_FILE_NAME_WITHOUT_HASH = 'installer.php';
//PUBLIC
public $File;
public $Size = 0;
public $OptsDBHost;
public $OptsDBPort;
public $OptsDBName;
public $OptsDBUser;
public $OptsDBCharset;
public $OptsDBCollation;
public $OptsSecureOn = 0;
public $OptsSecurePass;
public $numFilesAdded = 0;
public $numDirsAdded = 0;
//PROTECTED
protected $Package;
/**
* Init this object
*/
function __construct($package)
{
$this->Package = $package;
}
public function build($package, $error_behavior = Dup_ErrorBehavior::Quit)
{
DUP_Log::Info("building installer");
$this->Package = $package;
$success = false;
if ($this->create_enhanced_installer_files()) {
$success = $this->add_extra_files($package);
} else {
DUP_Log::Info("error creating enhanced installer files");
}
if ($success) {
// No longer need to store wp-config.txt file in main storage area
$temp_conf_ark_file_path = $this->getTempWPConfArkFilePath();
@unlink($temp_conf_ark_file_path);
$package->BuildProgress->installer_built = true;
} else {
$error_message = 'Error adding installer';
$package->BuildProgress->set_failed($error_message);
$package->Status = DUP_PackageStatus::ERROR;
$package->Update();
DUP_Log::error($error_message, "Marking build progress as failed because couldn't add installer files", $error_behavior);
//$package->BuildProgress->failed = true;
//$package->setStatus(DUP_PackageStatus::ERROR);
}
return $success;
}
private function create_enhanced_installer_files()
{
$success = false;
if ($this->create_enhanced_installer()) {
$success = $this->create_archive_config_file();
}
return $success;
}
private function create_enhanced_installer()
{
$success = true;
$archive_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->Archive->File}";
$installer_filepath = apply_filters('duplicator_installer_file_path', DUP_Settings::getSsdirTmpPath()."/{$this->Package->NameHash}_installer.php");
$template_filepath = DUPLICATOR_PLUGIN_PATH.'/installer/installer.tpl';
$mini_expander_filepath = DUPLICATOR_PLUGIN_PATH.'/lib/dup_archive/classes/class.duparchive.mini.expander.php';
// Replace the @@ARCHIVE@@ token
$installer_contents = file_get_contents($template_filepath);
if (DUP_Settings::Get('archive_build_mode') == DUP_Archive_Build_Mode::DupArchive) {
$mini_expander_string = file_get_contents($mini_expander_filepath);
if ($mini_expander_string === false) {
DUP_Log::error(DUP_U::__('Error reading DupArchive mini expander'), DUP_U::__('Error reading DupArchive mini expander'), Dup_ErrorBehavior::LogOnly);
return false;
}
} else {
$mini_expander_string = '';
}
$search_array = array('@@ARCHIVE@@', '@@VERSION@@', '@@ARCHIVE_SIZE@@', '@@PACKAGE_HASH@@', '@@SECONDARY_PACKAGE_HASH@@', '@@DUPARCHIVE_MINI_EXPANDER@@');
$package_hash = $this->Package->getPackageHash();
$secondary_package_hash = $this->Package->getSecondaryPackageHash();
$replace_array = array($this->Package->Archive->File, DUPLICATOR_VERSION, @filesize($archive_filepath), $package_hash, $secondary_package_hash, $mini_expander_string);
$installer_contents = str_replace($search_array, $replace_array, $installer_contents);
if (@file_put_contents($installer_filepath, $installer_contents) === false) {
DUP_Log::error(esc_html__('Error writing installer contents', 'duplicator'), esc_html__("Couldn't write to $installer_filepath", 'duplicator'));
$success = false;
}
if ($success) {
$storePath = DUP_Settings::getSsdirTmpPath()."/{$this->File}";
$this->Size = @filesize($storePath);
}
return $success;
}
/**
* Create archive.txt file */
private function create_archive_config_file()
{
global $wpdb;
$success = true;
$archive_config_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->NameHash}_archive.txt";
$ac = new DUP_Archive_Config();
$extension = strtolower($this->Package->Archive->Format);
$hasher = new DUP_PasswordHash(8, FALSE);
$pass_hash = $hasher->HashPassword($this->Package->Installer->OptsSecurePass);
$this->Package->Database->getScannerData();
//READ-ONLY: COMPARE VALUES
$ac->created = $this->Package->Created;
$ac->version_dup = DUPLICATOR_VERSION;
$ac->version_wp = $this->Package->VersionWP;
$ac->version_db = $this->Package->VersionDB;
$ac->version_php = $this->Package->VersionPHP;
$ac->version_os = $this->Package->VersionOS;
$ac->dup_type = 'lite';
$ac->dbInfo = $this->Package->Database->info;
//READ-ONLY: GENERAL
// $ac->installer_base_name = $global->installer_base_name;
$ac->installer_base_name = 'installer.php';
$ac->installer_backup_name = $this->Package->NameHash.'_installer-backup.php';
$ac->package_name = "{$this->Package->NameHash}_archive.{$extension}";
$ac->package_hash = $this->Package->getPackageHash();
$ac->package_notes = $this->Package->Notes;
$ac->url_old = get_option('siteurl');
$ac->opts_delete = DupLiteSnapJsonU::wp_json_encode_pprint($GLOBALS['DUPLICATOR_OPTS_DELETE']);
$ac->blogname = esc_html(get_option('blogname'));
$abs_path = duplicator_get_abs_path();
$ac->wproot = $abs_path;
$ac->relative_content_dir = str_replace($abs_path, '', WP_CONTENT_DIR);
$ac->exportOnlyDB = $this->Package->Archive->ExportOnlyDB;
$ac->installSiteOverwriteOn = DUPLICATOR_INSTALL_SITE_OVERWRITE_ON;
$ac->wplogin_url = wp_login_url();
//PRE-FILLED: GENERAL
$ac->secure_on = $this->Package->Installer->OptsSecureOn;
$ac->secure_pass = $pass_hash;
$ac->skipscan = false;
$ac->dbhost = $this->Package->Installer->OptsDBHost;
$ac->dbname = $this->Package->Installer->OptsDBName;
$ac->dbuser = $this->Package->Installer->OptsDBUser;
$ac->dbpass = '';
$ac->dbcharset = $this->Package->Installer->OptsDBCharset;
$ac->dbcollation = $this->Package->Installer->OptsDBCollation;
$ac->wp_tableprefix = $wpdb->base_prefix;
$ac->mu_mode = DUP_MU::getMode();
$ac->is_outer_root_wp_config_file = (!file_exists($abs_path.'/wp-config.php')) ? true : false;
$ac->is_outer_root_wp_content_dir = $this->Package->Archive->isOuterWPContentDir();
$json = DupLiteSnapJsonU::wp_json_encode_pprint($ac);
DUP_Log::TraceObject('json', $json);
if (file_put_contents($archive_config_filepath, $json) === false) {
DUP_Log::error("Error writing archive config", "Couldn't write archive config at $archive_config_filepath", Dup_ErrorBehavior::LogOnly);
$success = false;
}
return $success;
}
/**
* Puts an installer zip file in the archive for backup purposes.
*/
private function add_extra_files($package)
{
$success = false;
$installer_filepath = apply_filters('duplicator_installer_file_path', DUP_Settings::getSsdirTmpPath()."/{$this->Package->NameHash}_installer.php");
$scan_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->NameHash}_scan.json";
$sql_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->Database->File}";
$archive_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->Archive->File}";
$archive_config_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->NameHash}_archive.txt";
DUP_Log::Info("add_extra_files1");
if (file_exists($installer_filepath) == false) {
DUP_Log::error("Installer $installer_filepath not present", '', Dup_ErrorBehavior::LogOnly);
return false;
}
DUP_Log::Info("add_extra_files2");
if (file_exists($sql_filepath) == false) {
DUP_Log::error("Database SQL file $sql_filepath not present", '', Dup_ErrorBehavior::LogOnly);
return false;
}
DUP_Log::Info("add_extra_files3");
if (file_exists($archive_config_filepath) == false) {
DUP_Log::error("Archive configuration file $archive_config_filepath not present", '', Dup_ErrorBehavior::LogOnly);
return false;
}
DUP_Log::Info("add_extra_files4");
if ($package->Archive->file_count != 2) {
DUP_Log::Info("Doing archive file check");
// Only way it's 2 is if the root was part of the filter in which case the archive won't be there
DUP_Log::Info("add_extra_files5");
if (file_exists($archive_filepath) == false) {
DUP_Log::error("$error_text. **RECOMMENDATION: $fix_text", '', Dup_ErrorBehavior::LogOnly);
return false;
}
DUP_Log::Info("add_extra_files6");
}
$wpconfig_filepath = $package->Archive->getWPConfigFilePath();
if ($package->Archive->Format == 'DAF') {
DUP_Log::Info("add_extra_files7");
$success = $this->add_extra_files_using_duparchive($installer_filepath, $scan_filepath, $sql_filepath, $archive_filepath, $archive_config_filepath, $wpconfig_filepath);
} else {
DUP_Log::Info("add_extra_files8");
$success = $this->add_extra_files_using_ziparchive($installer_filepath, $scan_filepath, $sql_filepath, $archive_filepath, $archive_config_filepath, $wpconfig_filepath);
}
// No sense keeping the archive config around
@unlink($archive_config_filepath);
$package->Archive->Size = @filesize($archive_filepath);
return $success;
}
private function add_extra_files_using_duparchive($installer_filepath, $scan_filepath, $sql_filepath, $archive_filepath, $archive_config_filepath, $wpconfig_filepath)
{
$success = false;
try {
DUP_Log::Info("add_extra_files_using_da1");
$htaccess_filepath = $this->getHtaccessFilePath();
$webconf_filepath = duplicator_get_abs_path().'/web.config';
$logger = new DUP_DupArchive_Logger();
DupArchiveEngine::init($logger, 'DUP_Log::profile');
$embedded_scan_ark_file_path = $this->getEmbeddedScanFilePath();
DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $scan_filepath, $embedded_scan_ark_file_path);
$this->numFilesAdded++;
if (file_exists($htaccess_filepath)) {
$htaccess_ark_file_path = $this->getHtaccessArkFilePath();
try {
DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $htaccess_filepath, $htaccess_ark_file_path);
$this->numFilesAdded++;
}
catch (Exception $ex) {
// Non critical so bury exception
}
}
if (file_exists($webconf_filepath)) {
try {
DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $webconf_filepath, DUPLICATOR_WEBCONFIG_ORIG_FILENAME);
$this->numFilesAdded++;
}
catch (Exception $ex) {
// Non critical so bury exception
}
}
if (file_exists($wpconfig_filepath)) {
$conf_ark_file_path = $this->getWPConfArkFilePath();
$temp_conf_ark_file_path = $this->getTempWPConfArkFilePath();
if (copy($wpconfig_filepath, $temp_conf_ark_file_path)) {
$this->cleanTempWPConfArkFilePath($temp_conf_ark_file_path);
DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $temp_conf_ark_file_path, $conf_ark_file_path);
} else {
DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $wpconfig_filepath, $conf_ark_file_path);
}
$this->numFilesAdded++;
}
$this->add_installer_files_using_duparchive($archive_filepath, $installer_filepath, $archive_config_filepath);
$success = true;
}
catch (Exception $ex) {
DUP_Log::error("Error adding installer files to archive. ", $ex->getMessage(), Dup_ErrorBehavior::ThrowException);
}
return $success;
}
private function add_installer_files_using_duparchive($archive_filepath, $installer_filepath, $archive_config_filepath)
{
$installer_backup_filename = $this->Package->NameHash.'_installer-backup.php';
DUP_Log::Info('Adding enhanced installer files to archive using DupArchive');
DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $installer_filepath, $installer_backup_filename);
$this->numFilesAdded++;
$base_installer_directory = DUPLICATOR_PLUGIN_PATH.'installer';
$installer_directory = "$base_installer_directory/dup-installer";
$counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $installer_directory, $base_installer_directory, true);
$this->numFilesAdded += $counts->numFilesAdded;
$this->numDirsAdded += $counts->numDirsAdded;
$archive_config_relative_path = $this->getArchiveTxtFilePath();
DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $archive_config_filepath, $archive_config_relative_path);
$this->numFilesAdded++;
// Include dup archive
$duparchive_lib_directory = DUPLICATOR_PLUGIN_PATH.'lib/dup_archive';
$duparchive_lib_counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $duparchive_lib_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/');
$this->numFilesAdded += $duparchive_lib_counts->numFilesAdded;
$this->numDirsAdded += $duparchive_lib_counts->numDirsAdded;
// Include snaplib
$snaplib_directory = DUPLICATOR_PLUGIN_PATH.'lib/snaplib';
$snaplib_counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $snaplib_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/');
$this->numFilesAdded += $snaplib_counts->numFilesAdded;
$this->numDirsAdded += $snaplib_counts->numDirsAdded;
// Include fileops
$fileops_directory = DUPLICATOR_PLUGIN_PATH.'lib/fileops';
$fileops_counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $fileops_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/');
$this->numFilesAdded += $fileops_counts->numFilesAdded;
$this->numDirsAdded += $fileops_counts->numDirsAdded;
// Include config
$config_directory = DUPLICATOR_PLUGIN_PATH.'lib/config';
$config_counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $config_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/');
$this->numFilesAdded += $config_counts->numFilesAdded;
$this->numDirsAdded += $fileops_counts->numDirsAdded;
}
private function add_extra_files_using_ziparchive($installer_filepath, $scan_filepath, $sql_filepath, $zip_filepath, $archive_config_filepath, $wpconfig_filepath)
{
$htaccess_filepath = $this->getHtaccessFilePath();
$webconfig_filepath = duplicator_get_abs_path().'/web.config';
$success = false;
$zipArchive = new ZipArchive();
if ($zipArchive->open($zip_filepath, ZIPARCHIVE::CREATE) === TRUE) {
DUP_Log::Info("Successfully opened zip $zip_filepath");
if (file_exists($htaccess_filepath)) {
$htaccess_ark_file_path = $this->getHtaccessArkFilePath();
DUP_Zip_U::addFileToZipArchive($zipArchive, $htaccess_filepath, $htaccess_ark_file_path, true);
}
if (file_exists($webconfig_filepath)) {
DUP_Zip_U::addFileToZipArchive($zipArchive, $webconfig_filepath, DUPLICATOR_WEBCONFIG_ORIG_FILENAME, true);
}
if (!empty($wpconfig_filepath)) {
$conf_ark_file_path = $this->getWPConfArkFilePath();
$temp_conf_ark_file_path = $this->getTempWPConfArkFilePath();
if (copy($wpconfig_filepath, $temp_conf_ark_file_path)) {
$this->cleanTempWPConfArkFilePath($temp_conf_ark_file_path);
DUP_Zip_U::addFileToZipArchive($zipArchive, $temp_conf_ark_file_path, $conf_ark_file_path, true);
} else {
DUP_Zip_U::addFileToZipArchive($zipArchive, $wpconfig_filepath, $conf_ark_file_path, true);
}
}
$embedded_scan_file_path = $this->getEmbeddedScanFilePath();
if (DUP_Zip_U::addFileToZipArchive($zipArchive, $scan_filepath, $embedded_scan_file_path, true)) {
if ($this->add_installer_files_using_zip_archive($zipArchive, $installer_filepath, $archive_config_filepath, true)) {
DUP_Log::info("Installer files added to archive");
DUP_Log::info("Added to archive");
$success = true;
} else {
DUP_Log::error("Unable to add enhanced enhanced installer files to archive.", '', Dup_ErrorBehavior::LogOnly);
}
} else {
DUP_Log::error("Unable to add scan file to archive.", '', Dup_ErrorBehavior::LogOnly);
}
if ($zipArchive->close() === false) {
DUP_Log::error("Couldn't close archive when adding extra files.", '');
$success = false;
}
DUP_Log::Info('After ziparchive close when adding installer');
}
return $success;
}
// Add installer directory to the archive and the archive.cfg
private function add_installer_files_using_zip_archive(&$zip_archive, $installer_filepath, $archive_config_filepath, $is_compressed)
{
$success = false;
$installer_backup_filename = $this->Package->NameHash.'_installer-backup.php';
DUP_Log::Info('Adding enhanced installer files to archive using ZipArchive');
if (DUP_Zip_U::addFileToZipArchive($zip_archive, $installer_filepath, $installer_backup_filename, true)) {
DUPLICATOR_PLUGIN_PATH.'installer/';
$installer_directory = DUPLICATOR_PLUGIN_PATH.'installer/dup-installer';
if (DUP_Zip_U::addDirWithZipArchive($zip_archive, $installer_directory, true, '', $is_compressed)) {
$archive_config_local_name = $this->getArchiveTxtFilePath();
if (DUP_Zip_U::addFileToZipArchive($zip_archive, $archive_config_filepath, $archive_config_local_name, true)) {
$snaplib_directory = DUPLICATOR_PLUGIN_PATH.'lib/snaplib';
$config_directory = DUPLICATOR_PLUGIN_PATH.'lib/config';
if (DUP_Zip_U::addDirWithZipArchive($zip_archive, $snaplib_directory, true, 'dup-installer/lib/', $is_compressed) &&
DUP_Zip_U::addDirWithZipArchive($zip_archive, $config_directory, true, 'dup-installer/lib/', $is_compressed)
) {
$success = true;
} else {
DUP_Log::error("Error adding directory {$snaplib_directory} and {$config_directory} to zipArchive", '', Dup_ErrorBehavior::LogOnly);
}
} else {
DUP_Log::error("Error adding $archive_config_filepath to zipArchive", '', Dup_ErrorBehavior::LogOnly);
}
} else {
DUP_Log::error("Error adding directory $installer_directory to zipArchive", '', Dup_ErrorBehavior::LogOnly);
}
} else {
DUP_Log::error("Error adding backup installer file to zipArchive", '', Dup_ErrorBehavior::LogOnly);
}
return $success;
}
/**
* Get .htaccess file path
*
* @return string
*/
private function getHtaccessFilePath()
{
return duplicator_get_abs_path().'/.htaccess';
}
/**
* Get .htaccss in archive file
*
* @return string
*/
private function getHtaccessArkFilePath()
{
$packageHash = $this->Package->getPackageHash();
$htaccessArkFilePath = '.htaccess__'.$packageHash;
return $htaccessArkFilePath;
}
/**
* Get wp-config.php file path along with name in archive file
*/
private function getWPConfArkFilePath()
{
if (DUPLICATOR_INSTALL_SITE_OVERWRITE_ON) {
$package_hash = $this->Package->getPackageHash();
$conf_ark_file_path = 'dup-wp-config-arc__'.$package_hash.'.txt';
} else {
$conf_ark_file_path = 'wp-config.php';
}
return $conf_ark_file_path;
}
/**
* Get temp wp-config.php file path along with name in temp folder
*/
private function getTempWPConfArkFilePath()
{
$temp_conf_ark_file_path = DUP_Settings::getSsdirTmpPath().'/'.$this->Package->NameHash.'_wp-config.txt';
return $temp_conf_ark_file_path;
}
/**
* Clear out sensitive database connection information
*
* @param $temp_conf_ark_file_path Temp config file path
*/
private static function cleanTempWPConfArkFilePath($temp_conf_ark_file_path)
{
if (function_exists('token_get_all')) {
require_once(DUPLICATOR_PLUGIN_PATH.'lib/config/class.wp.config.tranformer.php');
$transformer = new DupLiteWPConfigTransformer($temp_conf_ark_file_path);
$constants = array('DB_NAME', 'DB_USER', 'DB_PASSWORD', 'DB_HOST');
foreach ($constants as $constant) {
if ($transformer->exists('constant', $constant)) {
$transformer->update('constant', $constant, '');
}
}
}
}
/**
* Get scan.json file path along with name in archive file
*/
private function getEmbeddedScanFilePath()
{
$package_hash = $this->Package->getPackageHash();
$embedded_scan_ark_file_path = 'dup-installer/dup-scan__'.$package_hash.'.json';
return $embedded_scan_ark_file_path;
}
/**
* Get archive.txt file path along with name in archive file
*/
private function getArchiveTxtFilePath()
{
$package_hash = $this->Package->getPackageHash();
$archive_txt_file_path = 'dup-installer/dup-archive__'.$package_hash.'.txt';
return $archive_txt_file_path;
}
}
classes/package/duparchive/class.pack.archive.duparchive.state.create.php 0000644 00000005327 15133606540 0022625 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.create.php');
require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/class.duparchive.processing.failure.php');
class DUP_DupArchive_Create_State extends DupArchiveCreateState
{
/* @var $package DUP_Package */
// private $package;
// public function setPackage(&$package)
public function setPackage(&$package)
{
// $this->package = &$package;
}
// Only one active package so straightforward
// public static function createFromPackage(&$package)
public static function get_instance()
{
$instance = new DUP_DupArchive_Create_State();
$data = DUP_Settings::Get('duparchive_create_state');
DUP_Util::objectCopy($data, $instance);
$instance->startTimestamp = time();
DUP_Log::TraceObject("retrieving create state", $instance);
return $instance;
}
public static function createNew($archivePath, $basePath, $timeSliceInSecs, $isCompressed, $setArchiveOffsetToEndOfArchive)
{
$instance = new DUP_DupArchive_Create_State();
if ($setArchiveOffsetToEndOfArchive) {
$instance->archiveOffset = filesize($archivePath);
} else {
$instance->archiveOffset = 0;
}
$instance->archivePath = $archivePath;
$instance->basePath = $basePath;
$instance->currentDirectoryIndex = 0;
$instance->currentFileOffset = 0;
$instance->currentFileIndex = 0;
$instance->failures = array();
$instance->globSize = DupArchiveCreateState::DEFAULT_GLOB_SIZE;
$instance->isCompressed = $isCompressed;
$instance->timeSliceInSecs = $timeSliceInSecs;
$instance->working = true;
$instance->skippedDirectoryCount = 0;
$instance->skippedFileCount = 0;
$instance->startTimestamp = time();
return $instance;
}
public function addFailure($type, $subject, $description, $isCritical = false)
{
parent::addFailure($type, $subject, $description, $isCritical);
}
public function save()
{
DUP_Log::TraceObject("Saving create state", $this);
DUP_Settings::Set('duparchive_create_state', $this);
DUP_Settings::Save();
}
}
classes/package/duparchive/class.pack.archive.duparchive.php 0000644 00000040157 15133606540 0020244 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/duparchive/class.pack.archive.duparchive.state.expand.php');
require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/duparchive/class.pack.archive.duparchive.state.create.php');
require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/class.duparchive.loggerbase.php');
require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/class.duparchive.engine.php');
require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.create.php');
require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.expand.php');
require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/class.duparchive.processing.failure.php');
class DUP_DupArchive_Logger extends DupArchiveLoggerBase
{
public function log($s, $flush = false, $callingFunctionOverride = null)
{
DUP_Log::Trace($s, true, $callingFunctionOverride);
}
}
class DUP_DupArchive
{
// Using a worker time override since evidence shorter time works much
const WorkerTimeInSec = 10;
/**
* CREATE
* Creates the zip file and adds the SQL file to the archive
*/
public static function create($archive, $buildProgress, $package)
{
/* @var $buildProgress DUP_Build_Progress */
DUP_LOG::trace("start");
try {
DUP_Log::Open($package->NameHash);
if ($buildProgress->retries > DUPLICATOR_MAX_BUILD_RETRIES) {
$error_msg = __('Package build appears stuck so marking package as failed. Is the Max Worker Time set too high?.', 'duplicator');
DUP_Log::error(esc_html__('Build Failure', 'duplicator'), esc_html($error_msg), Dup_ErrorBehavior::LogOnly);
//$buildProgress->failed = true;
$buildProgress->set_failed($error_msg);
$package->setStatus(DUP_PackageStatus::ERROR);
;
return true;
} else {
// If all goes well retries will be reset to 0 at the end of this function.
$buildProgress->retries++;
$package->update();
}
$done = false;
DupArchiveEngine::init(new DUP_DupArchive_Logger(), null, $archive);
DUP_Package::safeTmpCleanup(true);
$compressDir = rtrim(DUP_Util::safePath($archive->PackDir), '/');
$sqlPath = DUP_Settings::getSsdirTmpPath()."/{$package->Database->File}";
$archivePath = DUP_Settings::getSsdirTmpPath()."/{$archive->File}";
$scanFilepath = DUP_Settings::getSsdirTmpPath()."/{$package->NameHash}_scan.json";
$skipArchiveFinalization = false;
$json = '';
if (file_exists($scanFilepath)) {
$json = file_get_contents($scanFilepath);
if (empty($json)) {
$errorText = __("Scan file $scanFilepath is empty!", 'duplicator');
$fixText = __("Click on \"Resolve This\" button to fix the JSON settings.", 'duplicator');
DUP_Log::Trace($errorText);
DUP_Log::error(esc_html($errorText)." **RECOMMENDATION: ".esc_html($fixText).".", '', Dup_ErrorBehavior::LogOnly);
//$buildProgress->failed = true;
$buildProgress->set_failed($errorText);
$package->setStatus(DUP_PackageStatus::ERROR);
return true;
}
} else {
DUP_Log::trace("**** scan file $scanFilepath doesn't exist!!");
$errorMessage = sprintf(__("ERROR: Can't find Scanfile %s. Please ensure there no non-English characters in the package or schedule name.", 'duplicator'), $scanFilepath);
DUP_Log::error($errorMessage, '', Dup_ErrorBehavior::LogOnly);
//$buildProgress->failed = true;
$buildProgress->set_failed($errorMessage);
$package->setStatus(DUP_PackageStatus::ERROR);
return true;
}
Dup_Log::TraceObject("buildprogress object", $buildProgress, false);
$scanReport = json_decode($json);
if ($buildProgress->archive_started == false) {
$filterDirs = empty($archive->FilterDirs) ? 'not set' : $archive->FilterDirs;
$filterExts = empty($archive->FilterExts) ? 'not set' : $archive->FilterExts;
$filterFiles = empty($archive->FilterFiles) ? 'not set' : $archive->FilterFiles;
$filterOn = ($archive->FilterOn) ? 'ON' : 'OFF';
$filterDirsFormat = rtrim(str_replace(';', "\n\t", $filterDirs));
$filterFilesFormat = rtrim(str_replace(';', "\n\t", $filterFiles));
DUP_Log::info("\n********************************************************************************");
DUP_Log::info("ARCHIVE Type=DUP Mode=DupArchive");
DUP_Log::info("********************************************************************************");
DUP_Log::info("ARCHIVE DIR: ".$compressDir);
DUP_Log::info("ARCHIVE FILE: ".basename($archivePath));
DUP_Log::info("FILTERS: *{$filterOn}*");
DUP_Log::Info("DIRS:\n\t{$filterDirsFormat}");
DUP_Log::Info("FILES:\n\t{$filterFilesFormat}");
DUP_Log::info("EXTS: {$filterExts}");
DUP_Log::info("----------------------------------------");
DUP_Log::info("COMPRESSING");
DUP_Log::info("SIZE:\t".$scanReport->ARC->Size);
DUP_Log::info("STATS:\tDirs ".$scanReport->ARC->DirCount." | Files ".$scanReport->ARC->FileCount." | Total ".$scanReport->ARC->FullCount);
if (($scanReport->ARC->DirCount == '') || ($scanReport->ARC->FileCount == '') || ($scanReport->ARC->FullCount == '')) {
$error_message = 'Invalid Scan Report Detected';
DUP_Log::error($error_message, 'Invalid Scan Report Detected', Dup_ErrorBehavior::LogOnly);
$buildProgress->set_failed($error_message);
$package->setStatus(DUP_PackageStatus::ERROR);
return true;
}
try {
DupArchiveEngine::createArchive($archivePath, true);
$sql_ark_file_path = $package->getSqlArkFilePath();
DupArchiveEngine::addRelativeFileToArchiveST($archivePath, $sqlPath, $sql_ark_file_path);
}
catch (Exception $ex) {
$error_message = 'Error adding database.sql to archive';
DUP_Log::error($error_message, $ex->getMessage(), Dup_ErrorBehavior::LogOnly);
$buildProgress->set_failed($error_message);
$package->setStatus(DUP_PackageStatus::ERROR);
return true;
}
$buildProgress->archive_started = true;
$buildProgress->retries = 0;
$createState = DUP_DupArchive_Create_State::createNew($archivePath, $compressDir, self::WorkerTimeInSec, true, true);
$createState->throttleDelayInUs = 0;
$createState->save();
$package->Update();
}
try {
$createState = DUP_DupArchive_Create_State::get_instance();
if ($buildProgress->retries > 1) {
// Indicates it had problems before so move into robustness mode
$createState->isRobust = true;
$createState->save();
}
if ($createState->working) {
DUP_LOG::Trace("Create state is working");
//die(0);//rsr
// DupArchiveEngine::addItemsToArchive($createState, $scanReport->ARC, $archive);
DupArchiveEngine::addItemsToArchive($createState, $scanReport->ARC);
$buildProgress->set_build_failures($createState->failures);
if ($createState->isCriticalFailurePresent()) {
throw new Exception($createState->getFailureSummary());
}
$totalFileCount = count($scanReport->ARC->Files);
$package->Status = DupLiteSnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCSTART, DUP_PackageStatus::ARCVALIDATION, $totalFileCount, $createState->currentFileIndex);
$buildProgress->retries = 0;
$createState->save();
DUP_LOG::TraceObject("Stored Create State", $createState);
DUP_LOG::TraceObject('Stored build_progress', $package->BuildProgress);
if ($createState->working == false) {
// Want it to do the final cleanup work in an entirely new thread so return immediately
$skipArchiveFinalization = true;
DUP_LOG::TraceObject("Done build phase. Create State=", $createState);
}
}
}
catch (Exception $ex) {
$message = __('Problem adding items to archive.', 'duplicator').' '.$ex->getMessage();
DUP_Log::error(__('Problems adding items to archive.', 'duplicator'), $message, Dup_ErrorBehavior::LogOnly);
DUP_Log::TraceObject($message." EXCEPTION:", $ex);
//$buildProgress->failed = true;
$buildProgress->set_failed($message);
$package->setStatus(DUP_PackageStatus::ERROR);
return true;
}
//-- Final Wrapup of the Archive
if ((!$skipArchiveFinalization) && ($createState->working == false)) {
DUP_LOG::Trace("Create state is not working and not skip archive finalization");
if (!$buildProgress->installer_built) {
if ($package->Installer->build($package, false)) {
$package->Runtime = -1;
$package->ExeSize = DUP_Util::byteSize($package->Installer->Size);
$package->ZipSize = DUP_Util::byteSize($package->Archive->Size);
$package->update();
} else {
$package->update();
return;
}
DUP_Log::Trace("Installer has been built so running expand now");
$expandState = DUP_DupArchive_Expand_State::getInstance(true);
$expandState->archivePath = $archivePath;
$expandState->working = true;
$expandState->timeSliceInSecs = self::WorkerTimeInSec;
$expandState->basePath = DUP_Settings::getSsdirTmpPath().'/validate';
$expandState->throttleDelayInUs = 0; // RSR TODO
$expandState->validateOnly = true;
$expandState->validationType = DupArchiveValidationTypes::Standard;
$expandState->working = true;
$expandState->expectedDirectoryCount = count($scanReport->ARC->Dirs) - $createState->skippedDirectoryCount + $package->Installer->numDirsAdded;
$expandState->expectedFileCount = count($scanReport->ARC->Files) + 1 - $createState->skippedFileCount + $package->Installer->numFilesAdded; // database.sql will be in there
$expandState->save();
$sfc = count($scanReport->ARC->Files);
$nfa = $package->Installer->numFilesAdded;
Dup_Log::trace("####scan files {$sfc} skipped files {$createState->skippedFileCount} num files added {$nfa}");
DUP_LOG::traceObject("EXPAND STATE AFTER SAVE", $expandState);
} else {
try {
$expandState = DUP_DupArchive_Expand_State::getInstance();
if ($buildProgress->retries > 1) {
// Indicates it had problems before so move into robustness mode
$expandState->isRobust = true;
$expandState->save();
}
DUP_Log::traceObject('Resumed validation expand state', $expandState);
DupArchiveEngine::expandArchive($expandState);
$buildProgress->set_validation_failures($expandState->failures);
$totalFileCount = count($scanReport->ARC->Files);
$archiveSize = @filesize($expandState->archivePath);
$package->Status = DupLiteSnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCVALIDATION, DUP_PackageStatus::COMPLETE, $archiveSize,
$expandState->archiveOffset);
DUP_LOG::TraceObject("package status after expand=", $package->Status);
DUP_LOG::Trace("archive size:{$archiveSize} expand offset:{$expandState->archiveOffset}");
}
catch (Exception $ex) {
DUP_Log::Trace('Exception:'.$ex->getMessage().':'.$ex->getTraceAsString());
$buildProgress->set_failed('Error validating archive');
$package->setStatus(DUP_PackageStatus::ERROR);
return true;
}
if ($expandState->isCriticalFailurePresent()) {
// Fail immediately if critical failure present - even if havent completed processing the entire archive.
$error_message = __('Critical failure present in validation', 'duplicator');
DUP_Log::error($error_message, $expandState->getFailureSummary(), Dup_ErrorBehavior::LogOnly);
$buildProgress->set_failed($error_message);
return true;
} else if (!$expandState->working) {
$buildProgress->archive_built = true;
$buildProgress->retries = 0;
$package->update();
$timerAllEnd = DUP_Util::getMicrotime();
$timerAllSum = DUP_Util::elapsedTime($timerAllEnd, $package->TimerStart);
DUP_LOG::traceObject("create state", $createState);
$archiveFileSize = @filesize($archivePath);
DUP_Log::info("COMPRESSED SIZE: ".DUP_Util::byteSize($archiveFileSize));
DUP_Log::info("ARCHIVE RUNTIME: {$timerAllSum}");
DUP_Log::info("MEMORY STACK: ".DUP_Server::getPHPMemory());
DUP_Log::info("CREATE WARNINGS: ".$createState->getFailureSummary(false, true));
DUP_Log::info("VALIDATION WARNINGS: ".$expandState->getFailureSummary(false, true));
$archive->file_count = $expandState->fileWriteCount + $expandState->directoryWriteCount;
$package->update();
$done = true;
} else {
$expandState->save();
}
}
}
}
catch (Exception $ex) {
// Have to have a catchall since the main system that calls this function is not prepared to handle exceptions
DUP_Log::trace('Top level create Exception:'.$ex->getMessage().':'.$ex->getTraceAsString());
//$buildProgress->failed = true;
$buildProgress->set_failed('Error encoundtered creating archive. See package log');
return true;
}
$buildProgress->retries = 0;
return $done;
}
} classes/package/duparchive/class.pack.archive.duparchive.state.expand.php 0000644 00000012524 15133606540 0022636 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.expand.php');
class DUP_DupArchive_Expand_State extends DupArchiveExpandState
{
public static function getInstance($reset = false)
{
$instance = new DUP_DupArchive_Expand_State();
if ($reset) {
$instance->initMembers();
} else {
$instance->loadMembers();
}
return $instance;
}
private function loadMembers()
{
$data = DUP_Settings::Get('duparchive_expand_state');
DUP_LOG::traceObject("****RAW EXPAND STATE LOADED****", $data);
if($data->currentFileHeaderString != null) {
$this->currentFileHeader = DUP_JSON::decode($data->currentFileHeaderString);
} else {
$this->currentFileHeader = null;
}
if($data->archiveHeaderString != null) {
$this->archiveHeader = DUP_JSON::decode($data->archiveHeaderString);
} else {
$this->archiveHeader = null;
}
if ($data->failuresString) {
$this->failures = DUP_JSON::decode($data->failuresString);
} else {
$this->failures = array();
}
DUP_Util::objectCopy($data, $this, array('archiveHeaderString', 'currentFileHeaderString', 'failuresString'));
//
// $this->archiveOffset = $data->archiveOffset;
// $this->archivePath = $data->archivePath;
// $this->basePath = $data->basePath;
// $this->currentFileOffset = $data->currentFileOffset;
// $this->failures = $data->failures;
// $this->isCompressed = $data->isCompressed;
// $this->startTimestamp = $data->startTimestamp;
// $this->timeSliceInSecs = $data->timeSliceInSecs;
// $this->fileWriteCount = $data->fileWriteCount;
// $this->directoryWriteCount = $data->directoryWriteCount;
// $this->working = $data->working;
// $this->directoryModeOverride = $data->directoryModeOverride;
// $this->fileModeOverride = $data->fileModeOverride;
// $this->throttleDelayInUs = $data->throttleDelayInUs;
// $this->validateOnly = $data->validateOnly;
// $this->validationType = $data->validationType;
}
public function save()
{
$data = new stdClass();
if($this->currentFileHeader != null) {
$data->currentFileHeaderString = DupLiteSnapJsonU::wp_json_encode($this->currentFileHeader);
} else {
$data->currentFileHeaderString = null;
}
if($this->archiveHeader != null) {
$data->archiveHeaderString = DupLiteSnapJsonU::wp_json_encode($this->archiveHeader);
} else {
$data->archiveHeaderString = null;
}
$data->failuresString = DupLiteSnapJsonU::wp_json_encode($this->failures);
// Object members auto skipped
DUP_Util::objectCopy($this, $data);
// $data->archiveOffset = $this->archiveOffset;
// $data->archivePath = $this->archivePath;
// $data->basePath = $this->basePath;
// $data->currentFileOffset = $this->currentFileOffset;
// $data->failures = $this->failures;
// $data->isCompressed = $this->isCompressed;
// $data->startTimestamp = $this->startTimestamp;
// $data->timeSliceInSecs = $this->timeSliceInSecs;
// $data->fileWriteCount = $this->fileWriteCount;
// $data->directoryWriteCount = $this->directoryWriteCount;
// $data->working = $this->working;
// $data->directoryModeOverride = $this->directoryModeOverride;
// $data->fileModeOverride = $this->fileModeOverride;
// $data->throttleDelayInUs = $this->throttleDelayInUs;
// $data->validateOnly = $this->validateOnly;
// $data->validationType = $this->validationType;
DUP_LOG::traceObject("****SAVING EXPAND STATE****", $this);
DUP_LOG::traceObject("****SERIALIZED STATE****", $data);
DUP_Settings::Set('duparchive_expand_state', $data);
DUP_Settings::Save();
}
private function initMembers()
{
$this->currentFileHeader = null;
$this->archiveOffset = 0;
$this->archiveHeader = null;
$this->archivePath = null;
$this->basePath = null;
$this->currentFileOffset = 0;
$this->failures = array();
$this->isCompressed = false;
$this->startTimestamp = time();
$this->timeSliceInSecs = -1;
$this->working = false;
$this->validateOnly = false;
$this->directoryModeOverride = -1;
$this->fileModeOverride = -1;
$this->throttleDelayInUs = 0;
}
}
classes/package/duparchive/index.php 0000644 00000000016 15133606540 0013546 0 ustar 00 <?php
//silent classes/package/class.pack.archive.zip.php 0000644 00000026247 15133606540 0014566 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.php');
/**
* Creates a zip file using the built in PHP ZipArchive class
*/
class DUP_Zip extends DUP_Archive
{
//PRIVATE
private static $compressDir;
private static $countDirs = 0;
private static $countFiles = 0;
private static $sqlPath;
private static $zipPath;
private static $zipFileSize;
private static $zipArchive;
private static $limitItems = 0;
private static $networkFlush = false;
private static $scanReport;
/**
* Creates the zip file and adds the SQL file to the archive
*/
public static function create(DUP_Archive $archive, $buildProgress)
{
try {
$timerAllStart = DUP_Util::getMicrotime();
$package_zip_flush = DUP_Settings::Get('package_zip_flush');
self::$compressDir = rtrim(wp_normalize_path(DUP_Util::safePath($archive->PackDir)), '/');
self::$sqlPath = DUP_Settings::getSsdirTmpPath()."/{$archive->Package->Database->File}";
self::$zipPath = DUP_Settings::getSsdirTmpPath()."/{$archive->File}";
self::$zipArchive = new ZipArchive();
self::$networkFlush = empty($package_zip_flush) ? false : $package_zip_flush;
$filterDirs = empty($archive->FilterDirs) ? 'not set' : $archive->FilterDirs;
$filterExts = empty($archive->FilterExts) ? 'not set' : $archive->FilterExts;
$filterFiles = empty($archive->FilterFiles) ? 'not set' : $archive->FilterFiles;
$filterOn = ($archive->FilterOn) ? 'ON' : 'OFF';
$filterDirsFormat = rtrim(str_replace(';', "\n\t", $filterDirs));
$filterFilesFormat = rtrim(str_replace(';', "\n\t", $filterFiles));
$lastDirSuccess = self::$compressDir;
//LOAD SCAN REPORT
$json = file_get_contents(DUP_Settings::getSsdirTmpPath()."/{$archive->Package->NameHash}_scan.json");
self::$scanReport = json_decode($json);
DUP_Log::Info("\n********************************************************************************");
DUP_Log::Info("ARCHIVE (ZIP):");
DUP_Log::Info("********************************************************************************");
$isZipOpen = (self::$zipArchive->open(self::$zipPath, ZIPARCHIVE::CREATE) === TRUE);
if (!$isZipOpen) {
$error_message = "Cannot open zip file with PHP ZipArchive.";
$buildProgress->set_failed($error_message);
DUP_Log::error($error_message, "Path location [".self::$zipPath."]", Dup_ErrorBehavior::LogOnly);
$archive->Package->setStatus(DUP_PackageStatus::ERROR);
return;
}
DUP_Log::Info("ARCHIVE DIR: ".self::$compressDir);
DUP_Log::Info("ARCHIVE FILE: ".basename(self::$zipPath));
DUP_Log::Info("FILTERS: *{$filterOn}*");
DUP_Log::Info("DIRS:\n\t{$filterDirsFormat}");
DUP_Log::Info("FILES:\n\t{$filterFilesFormat}");
DUP_Log::Info("EXTS: {$filterExts}");
DUP_Log::Info("----------------------------------------");
DUP_Log::Info("COMPRESSING");
DUP_Log::Info("SIZE:\t".self::$scanReport->ARC->Size);
DUP_Log::Info("STATS:\tDirs ".self::$scanReport->ARC->DirCount." | Files ".self::$scanReport->ARC->FileCount);
//ADD SQL
$sql_ark_file_path = $archive->Package->getSqlArkFilePath();
$isSQLInZip = self::$zipArchive->addFile(self::$sqlPath, $sql_ark_file_path);
if ($isSQLInZip) {
DUP_Log::Info("SQL ADDED: ".basename(self::$sqlPath));
} else {
$error_message = "Unable to add database.sql to archive.";
DUP_Log::error($error_message, "SQL File Path [".self::$sqlPath."]", Dup_ErrorBehavior::LogOnly);
$buildProgress->set_failed($error_message);
$archive->Package->setStatus(DUP_PackageStatus::ERROR);
return;
}
self::$zipArchive->close();
self::$zipArchive->open(self::$zipPath, ZipArchive::CREATE);
//ZIP DIRECTORIES
$info = '';
foreach (self::$scanReport->ARC->Dirs as $dir) {
$emptyDir = $archive->getLocalDirPath($dir);
if (is_readable($dir) && self::$zipArchive->addEmptyDir($emptyDir)) {
self::$countDirs++;
$lastDirSuccess = $dir;
} else {
//Don't warn when dirtory is the root path
if (strcmp($dir, rtrim(self::$compressDir, '/')) != 0) {
$dir_path = strlen($dir) ? "[{$dir}]" : "[Read Error] - last successful read was: [{$lastDirSuccess}]";
$info .= "DIR: {$dir_path}\n";
}
}
}
//LOG Unreadable DIR info
if (strlen($info)) {
DUP_Log::Info("\nWARNING: Unable to zip directories:");
DUP_Log::Info($info);
}
/**
* count update for integrity check
*/
$sumItems = (self::$countDirs + self::$countFiles);
/* ZIP FILES: Network Flush
* This allows the process to not timeout on fcgi
* setups that need a response every X seconds */
$totalFileCount = count(self::$scanReport->ARC->Files);
$info = '';
if (self::$networkFlush) {
foreach (self::$scanReport->ARC->Files as $file) {
$file_size = @filesize($file);
$localFileName = $archive->getLocalFilePath($file);
if (is_readable($file)) {
if (defined('DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR') && DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR && $file_size < DUP_Constants::ZIP_STRING_LIMIT && self::$zipArchive->addFromString($localFileName, file_get_contents($file))) {
Dup_Log::Info("Adding {$file} to zip");
self::$limitItems++;
self::$countFiles++;
} elseif (self::$zipArchive->addFile($file, $localFileName)) {
Dup_Log::Info("Adding {$file} to zip");
self::$limitItems++;
self::$countFiles++;
} else {
$info .= "FILE: [{$file}]\n";
}
} else {
$info .= "FILE: [{$file}]\n";
}
//Trigger a flush to the web server after so many files have been loaded.
if (self::$limitItems > DUPLICATOR_ZIP_FLUSH_TRIGGER) {
self::$zipArchive->close();
self::$zipArchive->open(self::$zipPath);
self::$limitItems = 0;
DUP_Util::fcgiFlush();
DUP_Log::Info("Items archived [{$sumItems}] flushing response.");
}
if(self::$countFiles % 500 == 0) {
// Every so many files update the status so the UI can display
$archive->Package->Status = DupLiteSnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCSTART, DUP_PackageStatus::ARCVALIDATION, $totalFileCount, self::$countFiles);
$archive->Package->update();
}
}
}
//Normal
else {
foreach (self::$scanReport->ARC->Files as $file) {
$file_size = @filesize($file);
$localFileName = $archive->getLocalFilePath($file);
if (is_readable($file)) {
if (defined('DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR') && DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR && $file_size < DUP_Constants::ZIP_STRING_LIMIT && self::$zipArchive->addFromString($localFileName, file_get_contents($file))) {
self::$countFiles++;
} elseif (self::$zipArchive->addFile($file, $localFileName)) {
self::$countFiles++;
} else {
$info .= "FILE: [{$file}]\n";
}
} else {
$info .= "FILE: [{$file}]\n";
}
if(self::$countFiles % 500 == 0) {
// Every so many files update the status so the UI can display
$archive->Package->Status = DupLiteSnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCSTART, DUP_PackageStatus::ARCVALIDATION, $totalFileCount, self::$countFiles);
$archive->Package->update();
}
}
}
//LOG Unreadable FILE info
if (strlen($info)) {
DUP_Log::Info("\nWARNING: Unable to zip files:");
DUP_Log::Info($info);
unset($info);
}
DUP_Log::Info(print_r(self::$zipArchive, true));
/**
* count update for integrity check
*/
$archive->file_count = self::$countDirs + self::$countFiles;
DUP_Log::Info("FILE ADDED TO ZIP: ".$archive->file_count);
//--------------------------------
//LOG FINAL RESULTS
DUP_Util::fcgiFlush();
$zipCloseResult = self::$zipArchive->close();
if($zipCloseResult) {
DUP_Log::Info("COMPRESSION RESULT: '{$zipCloseResult}'");
} else {
$error_message = "ZipArchive close failure.";
DUP_Log::error($error_message,
"The ZipArchive engine is having issues zipping up the files on this server. For more details visit the FAQ\n"
. "I'm getting a ZipArchive close failure when building. How can I resolve this?\n"
. "[https://snapcreek.com/duplicator/docs/faqs-tech/#faq-package-165-q]",
Dup_ErrorBehavior::LogOnly);
$buildProgress->set_failed($error_message);
$archive->Package->setStatus(DUP_PackageStatus::ERROR);
return;
}
$timerAllEnd = DUP_Util::getMicrotime();
$timerAllSum = DUP_Util::elapsedTime($timerAllEnd, $timerAllStart);
self::$zipFileSize = @filesize(self::$zipPath);
DUP_Log::Info("COMPRESSED SIZE: ".DUP_Util::byteSize(self::$zipFileSize));
DUP_Log::Info("ARCHIVE RUNTIME: {$timerAllSum}");
DUP_Log::Info("MEMORY STACK: ".DUP_Server::getPHPMemory());
} catch (Exception $e) {
$error_message = "Runtime error in class.pack.archive.zip.php constructor.";
DUP_Log::error($error_message, "Exception: {$e}", Dup_ErrorBehavior::LogOnly);
$buildProgress->set_failed($error_message);
$archive->Package->setStatus(DUP_PackageStatus::ERROR);
return;
}
}
} classes/package/class.pack.archive.filters.php 0000644 00000004461 15133606540 0015426 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* The base class for all filter types Directories/Files/Extentions
*
* @package Duplicator
* @subpackage classes/package
*
*/
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
class DUP_Archive_Filter_Scope_Base
{
//All internal storage items that duplicator decides to filter
public $Core = array();
//Global filter items added from settings
public $Global = array();
//Items when creating a package or template that a user decides to filter
public $Instance = array();
}
/**
* The filter types that belong to directories
*
* @package Duplicator
* @subpackage classes/package
*
*/
class DUP_Archive_Filter_Scope_Directory extends DUP_Archive_Filter_Scope_Base
{
//Items that are not readable
public $Warning = array();
//Items that are not readable
public $Unreadable = array();
public $AddonSites = array();
}
/**
* The filter types that belong to files
*
* @package Duplicator
* @subpackage classes/package
*
*/
class DUP_Archive_Filter_Scope_File extends DUP_Archive_Filter_Scope_Directory
{
//Items that are too large
public $Size = array();
}
/**
* The filter information object which store all information about the filtered
* data that is gathered to the execution of a scan process
*
* @package Duplicator
* @subpackage classes/package
*
*/
class DUP_Archive_Filter_Info
{
//Contains all folder filter info
public $Dirs = array();
//Contains all file filter info
public $Files = array();
//Contains all extensions filter info
public $Exts = array();
public $UDirCount = 0;
public $UFileCount = 0;
public $UExtCount = 0;
public $TreeSize;
public $TreeWarning;
/**
* Init this object
*/
public function __construct()
{
$this->reset();
}
/**
* reset and clean all object
*/
public function reset()
{
$this->Dirs = new DUP_Archive_Filter_Scope_Directory();
$this->Files = new DUP_Archive_Filter_Scope_File();
$this->Exts = new DUP_Archive_Filter_Scope_Base();
$this->TreeSize = array();
$this->TreeWarning = array();
}
}
classes/package/class.pack.php 0000644 00000210722 15133606540 0012336 0 ustar 00 <?php
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
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;
//Objects
public $Archive;
public $Installer;
public $Database;
public $BuildProgress;
/**
* Manages the Package Process
*/
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, DupLiteSnapJsonU::wp_json_encode_pprint($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()
{
switch (DUP_Settings::Get('installer_name_mode')) {
case DUP_Settings::INSTALLER_NAME_MODE_SIMPLE:
return DUP_Installer::DEFAULT_INSTALLER_FILE_NAME_WITHOUT_HASH;
case DUP_Settings::INSTALLER_NAME_MODE_WITH_HASH:
default:
return basename($this->getLocalPackageFile(DUP_PackageFileType::Installer));
}
}
/**
*
* @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.php");
$this->Database->File = "{$this->NameHash}_database.sql";
$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.php", 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.php", 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.php");
@unlink($tmpPath."/{$nameHash}_scan.json");
@unlink($tmpPath."/{$wpConfigFile}");
@unlink($tmpPath."/{$nameHash}.log");
@unlink($ssdPath."/{$archiveFile}");
@unlink($ssdPath."/{$nameHash}_database.sql");
@unlink($ssdPath."/{$nameHash}_installer.php");
@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 is_active_package_present()
{
$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[]|array[]|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 array[] // 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
*
* @global wpdb $wpdb
* @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());
} else if ($file_type == DUP_PackageFileType::Archive) {
DUP_Log::Trace("Archive requested");
$file_name = $this->getArchiveFilename();
} else if ($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.php";
}
public function getDatabaseFilename()
{
return $this->NameHash . '_database.sql';
}
/**
* @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');
// 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->Database->validateTableWiseRowCounts();
$this->BuildProgress->database_script_built = true;
$this->update();
DUP_Log::Info('[DUP ARCHIVE] DONE DATABASE');
} else if (!$this->BuildProgress->archive_built) {
DUP_Log::Info('[DUP ARCHIVE] BUILDING ARCHIVE');
$this->Archive->build($this);
$this->update();
DUP_Log::Info('[DUP ARCHIVE] DONE ARCHIVE');
} else if (!$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->Database->validateTableWiseRowCounts();
$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'])) {
$post_dbcompat = sanitize_text_field($post['dbcompat']);
$compatlist = isset($post['dbcompat']) ? implode(',', $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->PackDir = duplicator_get_abs_path();
$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)
{
//Delete all files now
if ($all) {
$dir = DUP_Settings::getSsdirTmpPath()."/*";
foreach (glob($dir) as $file) {
@unlink($file);
}
}
//Remove scan files that are 24 hours old
else {
$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 (DupLiteSnapLibUtil::wp_is_ini_value_changeable('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;
}
} classes/class.io.php 0000644 00000005040 15133606540 0010427 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* @copyright 2018 Snap Creek LLC
* Class for all IO operations
*/
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
class DUP_IO
{
/**
* Safely deletes a file
*
* @param string $file The full filepath to the file
*
* @return TRUE on success or if file does not exist. FALSE on failure
*/
public static function deleteFile($file)
{
if (file_exists($file)) {
if (@unlink($file) === false) {
DUP_Log::Info("Could not delete file: {$file}");
return false;
}
}
return true;
}
/**
* Removes a directory recursively except for the root of a WP Site
*
* @param string $directory The full filepath to the directory to remove
*
* @return TRUE on success FALSE on failure
*/
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) {
break;
}
}
} else {
return false;
}
return $success && @rmdir($directory);
}
/**
* Safely copies a file to a directory
*
* @param string $source_file The full filepath to the file to copy
* @param string $dest_dir The full path to the destination directory were the file will be copied
* @param string $delete_first Delete file before copying the new one
*
* @return TRUE on success or if file does not exist. FALSE on failure
*/
public static function copyFile($source_file, $dest_dir, $delete_first = false)
{
//Create directory
if (file_exists($dest_dir) == false)
{
if (wp_mkdir_p($dest_dir) === false) {
return false;
}
}
//Remove file with same name before copy
$filename = basename($source_file);
$dest_filepath = $dest_dir . "/$filename";
if($delete_first)
{
self::deleteFile($dest_filepath);
}
return copy($source_file, $dest_filepath);
}
}
classes/class.archive.config.php 0000644 00000002041 15133606540 0012703 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* @copyright 2016 Snap Creek LLC
*/
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
class DUP_Archive_Config
{
//READ-ONLY: COMPARE VALUES
public $created;
public $version_dup;
public $version_wp;
public $version_db;
public $version_php;
public $version_os;
public $dbInfo;
//READ-ONLY: GENERAL
public $url_old;
public $opts_delete;
public $blogname;
public $wproot;
public $wplogin_url;
public $relative_content_dir;
public $exportOnlyDB;
public $installSiteOverwriteOn;
//PRE-FILLED: GENERAL
public $secure_on;
public $secure_pass;
public $skipscan;
public $dbhost;
public $dbname;
public $dbuser;
public $dbpass;
public $dbcharset;
public $dbcollation;
// MULTISITE
public $mu_mode;
public $wp_tableprefix;
public $is_outer_root_wp_config_file;
public $is_outer_root_wp_content_dir;
}
classes/class.constants.php 0000644 00000000226 15133606540 0012035 0 ustar 00 <?php
defined("ABSPATH") || exit;
class DUP_Constants
{
const ZIP_STRING_LIMIT = 70000; // Cutoff for using ZipArchive addtostring vs addfile
}
classes/index.php 0000644 00000000016 15133606540 0010021 0 ustar 00 <?php
//silent classes/host/class.liquidweb.host.php 0000644 00000001145 15133606540 0013740 0 ustar 00 <?php
/**
* wpengine custom hosting class
*
* Standard: PSR-2
*
* @package SC\DUPX\HOST
* @link http://www.php-fig.org/psr/psr-2/
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
class DUP_Liquidweb_Host implements DUP_Host_interface
{
public static function getIdentifier()
{
return DUP_Custom_Host_Manager::HOST_LIQUIDWEB;
}
public function isHosting()
{
return apply_filters('duplicator_liquidweb_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/liquid-web.php'));
}
public function init()
{
}
} classes/host/class.wpengine.host.php 0000644 00000002617 15133606540 0013574 0 ustar 00 <?php
defined("ABSPATH") or die("");
// New encryption class
class DUP_WPEngine_Host implements DUP_Host_interface
{
public function init()
{
add_filter('duplicator_installer_file_path', array(__CLASS__, 'installerFilePath'), 10, 1);
add_filter('duplicator_global_file_filters_on', '__return_true');
add_filter('duplicator_global_file_filters', array(__CLASS__, 'globalFileFilters'), 10, 1);
add_filter('duplicator_defaults_settings', array(__CLASS__, 'defaultsSettings'));
}
public static function getIdentifier()
{
return DUP_Custom_Host_Manager::HOST_WPENGINE;
}
public function isHosting()
{
return apply_filters('duplicator_wp_engine_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/wpengine-security-auditor.php'));
}
public static function installerFilePath($path)
{
$path_info = pathinfo($path);
$newPath = $path;
if ('php' == $path_info['extension']) {
$newPath = substr_replace($path, '.txt', -4);
}
return $newPath;
}
public static function globalFileFilters($files)
{
$files[] = wp_normalize_path(WP_CONTENT_DIR).'/mysql.sql';
return $files;
}
public static function defaultsSettings($defaults)
{
$defaults['package_zip_flush'] = '1';
return $defaults;
}
} classes/host/interface.host.php 0000644 00000001135 15133606540 0012606 0 ustar 00 <?php
/**
* interface for specific hostings class
*
* Standard: PSR-2
*
* @package SC\DUPX\HOST
* @link http://www.php-fig.org/psr/psr-2/
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
interface DUP_Host_interface
{
/**
* return the current host itentifier
*
* @return string
*/
public static function getIdentifier();
/**
* @return bool true if is current host
*/
public function isHosting();
/**
* the init function.
* is called only if isHosting is true
*
* @return void
*/
public function init();
} classes/host/class.wordpresscom.host.php 0000644 00000001162 15133606540 0014501 0 ustar 00 <?php
/**
* godaddy custom hosting class
*
* Standard: PSR-2
*
* @package SC\DUPX\HOST
* @link http://www.php-fig.org/psr/psr-2/
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
class DUP_WordpressCom_Host implements DUP_Host_interface
{
public static function getIdentifier()
{
return DUP_Custom_Host_Manager::HOST_WORDPRESSCOM;
}
public function isHosting()
{
return apply_filters('duplicator_pro_wordpress_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/wpcomsh-loader.php'));
}
public function init()
{
}
} classes/host/class.flywheel.host.php 0000644 00000001146 15133606540 0013573 0 ustar 00 <?php
/**
* Flywheel custom hosting class
*
* Standard: PSR-2
*
* @package SC\DUPX\HOST
* @link http://www.php-fig.org/psr/psr-2/
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
class DUP_Flywheel_Host implements DUP_Host_interface
{
public static function getIdentifier()
{
return DUP_Custom_Host_Manager::HOST_FLYWHEEL;
}
public function isHosting()
{
$path = duplicator_get_home_path().'/.fw-config.php';
return apply_filters('duplicator_host_check', file_exists($path), self::getIdentifier());
}
public function init()
{
}
}
classes/host/class.custom.host.manager.php 0000644 00000011032 15133606540 0014672 0 ustar 00 <?php
/**
* custom hosting manager
* singleton class
*
* Standard: PSR-2
*
* @package SC\DUPX\HOST
* @link http://www.php-fig.org/psr/psr-2/
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/interface.host.php');
require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.godaddy.host.php');
require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.wpengine.host.php');
require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.wordpresscom.host.php');
require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.liquidweb.host.php');
require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.pantheon.host.php');
require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.flywheel.host.php');
class DUP_Custom_Host_Manager
{
const HOST_GODADDY = 'godaddy';
const HOST_WPENGINE = 'wpengine';
const HOST_WORDPRESSCOM = 'wordpresscom';
const HOST_LIQUIDWEB = 'liquidweb';
const HOST_PANTHEON = 'pantheon';
const HOST_FLYWHEEL = 'flywheel';
/**
*
* @var DUP_Custom_Host_Manager
*/
protected static $instance = null;
/**
*
* @var bool
*/
private $initialized = false;
/**
*
* @var DUP_Host_interface[]
*/
private $customHostings = array();
/**
*
* @var string[]
*/
private $activeHostings = array();
/**
*
* @return self
*/
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self;
}
return self::$instance;
}
private function __construct()
{
$this->customHostings[DUP_WPEngine_Host::getIdentifier()] = new DUP_WPEngine_Host();
$this->customHostings[DUP_GoDaddy_Host::getIdentifier()] = new DUP_GoDaddy_Host();
$this->customHostings[DUP_WordpressCom_Host::getIdentifier()] = new DUP_WordpressCom_Host();
$this->customHostings[DUP_Liquidweb_Host::getIdentifier()] = new DUP_Liquidweb_Host();
$this->customHostings[DUP_Pantheon_Host::getIdentifier()] = new DUP_Pantheon_Host();
$this->customHostings[DUP_Flywheel_Host::getIdentifier()] = new DUP_Flywheel_Host();
}
public function init()
{
if ($this->initialized) {
return true;
}
foreach ($this->customHostings as $cHost) {
if (!($cHost instanceof DUP_Host_interface)) {
throw new Exception('Host must implement DUP_Host_interface');
}
if ($cHost->isHosting()) {
$this->activeHostings[] = $cHost->getIdentifier();
$cHost->init();
}
}
$this->initialized = true;
return true;
}
public function getActiveHostings()
{
return $this->activeHostings;
}
public function isHosting($identifier)
{
return in_array($identifier, $this->activeHostings);
}
public function isManaged()
{
if ($this->isHosting(self::HOST_WORDPRESSCOM)) {
return true;
}
if ($this->isHosting(self::HOST_GODADDY)) {
return true;
}
if ($this->isHosting(self::HOST_WPENGINE)) {
return true;
}
if ($this->isHosting(self::HOST_LIQUIDWEB)) {
return true;
}
if ($this->isHosting(self::HOST_PANTHEON)) {
return true;
}
if ($this->isHosting(self::HOST_FLYWHEEL)) {
return true;
}
if ($this->WPConfigIsNotWriteable()) {
return true;
}
if ($this->notAccessibleCoreDirPresent()) {
return true;
}
return false;
}
public function WPConfigIsNotWriteable()
{
$wpConfigPath = duplicator_get_abs_path()."/wp-config.php";
return file_exists($wpConfigPath) && !is_writeable($wpConfigPath);
}
public function notAccessibleCoreDirPresent()
{
$absPath = duplicator_get_abs_path();
$coreDirs = array(
$absPath.'/wp-admin',
$absPath.'/wp-includes',
WP_CONTENT_DIR
);
foreach ($coreDirs as $coreDir) {
if (file_exists($coreDir) && !is_writeable($coreDir)) {
return true;
}
}
return false;
}
public function getHosting($identifier)
{
if ($this->isHosting($identifier)) {
return $this->activeHostings[$identifier];
} else {
return false;
}
}
}
classes/host/class.pantheon.host.php 0000644 00000001137 15133606540 0013570 0 ustar 00 <?php
/**
* godaddy custom hosting class
*
* Standard: PSR-2
*
* @package SC\DUPX\HOST
* @link http://www.php-fig.org/psr/psr-2/
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
class DUP_Pantheon_Host implements DUP_Host_interface
{
public static function getIdentifier()
{
return DUP_Custom_Host_Manager::HOST_PANTHEON;
}
public function isHosting()
{
return apply_filters('duplicator_pantheon_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/pantheon.php'));
}
public function init()
{
}
} classes/host/class.godaddy.host.php 0000644 00000001312 15133606540 0013362 0 ustar 00 <?php
defined("ABSPATH") or die("");
class DUP_GoDaddy_Host implements DUP_Host_interface
{
public static function getIdentifier()
{
return DUP_Custom_Host_Manager::HOST_GODADDY;
}
public function isHosting()
{
return apply_filters('duplicator_godaddy_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/gd-system-plugin.php'));
}
public function init()
{
add_filter('duplicator_defaults_settings', array(__CLASS__, 'defaultsSettings'));
}
public static function defaultsSettings($defaults)
{
$defaults['archive_build_mode'] = DUP_Archive_Build_Mode::DupArchive;
return $defaults;
}
} classes/class.settings.php 0000644 00000024441 15133606540 0011666 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
// Exit if accessed directly
if (!defined('DUPLICATOR_VERSION'))
exit;
abstract class DUP_Archive_Build_Mode
{
const Unconfigured = -1;
const Auto = 0; // should no longer be used
// const Shell_Exec = 1;
const ZipArchive = 2;
const DupArchive = 3;
}
class DUP_Settings
{
const OPT_SETTINGS = 'duplicator_settings';
const INSTALLER_NAME_MODE_WITH_HASH = 'withhash';
const INSTALLER_NAME_MODE_SIMPLE = 'simple';
const STORAGE_POSITION_LECAGY = 'legacy';
const STORAGE_POSITION_WP_CONTENT = 'wpcont';
const SSDIR_NAME_LEGACY = 'wp-snapshots';
const SSDIR_NAME_NEW = 'backups-dup-lite';
protected static $Data;
protected static $ssDirPath = null;
protected static $ssDirUrl = null;
/**
* Class used to manage all the settings for the plugin
*/
public static function init()
{
self::$Data = get_option(self::OPT_SETTINGS);
//when the plugin updated, this will be true
if (empty(self::$Data) || empty(self::$Data['version']) || version_compare(DUPLICATOR_VERSION, self::$Data['version'], '>')) {
self::SetDefaults();
}
}
/**
* Find the setting value
* @param string $key The name of the key to find
* @return The value stored in the key returns null if key does not exist
*/
public static function Get($key = '')
{
$result = null;
if (isset(self::$Data[$key])) {
$result = self::$Data[$key];
} else {
$defaults = self::GetAllDefaults();
if (isset($defaults[$key])) {
$result = $defaults[$key];
}
}
return $result;
}
/**
* Set the settings value in memory only
* @param string $key The name of the key to find
* @param string $value The value to set
* remarks: The Save() method must be called to write the Settings object to the DB
*/
public static function Set($key, $value)
{
if (isset(self::$Data[$key])) {
self::$Data[$key] = ($value == null) ? '' : $value;
} elseif (!empty($key)) {
self::$Data[$key] = ($value == null) ? '' : $value;
}
}
public static function setStoragePosition($newPosition)
{
$legacyPath = self::getSsdirPathLegacy();
$wpContPath = self::getSsdirPathWpCont();
$oldStoragePost = self::Get('storage_position');
self::resetPositionVars();
switch ($newPosition) {
case self::STORAGE_POSITION_LECAGY:
self::$Data['storage_position'] = self::STORAGE_POSITION_LECAGY;
if (!DUP_Util::initSnapshotDirectory()) {
self::resetPositionVars();
self::$Data['storage_position'] = $oldStoragePost;
return false;
}
if (is_dir($wpContPath)) {
if (DupLiteSnapLibIOU::moveContentDirToTarget($wpContPath, $legacyPath, true)) {
DupLiteSnapLibIOU::rrmdir($wpContPath);
}
}
break;
case self::STORAGE_POSITION_WP_CONTENT:
self::$Data['storage_position'] = self::STORAGE_POSITION_WP_CONTENT;
if (!DUP_Util::initSnapshotDirectory()) {
self::resetPositionVars();
self::$Data['storage_position'] = $oldStoragePost;
return false;
}
if (is_dir($legacyPath)) {
if (DupLiteSnapLibIOU::moveContentDirToTarget($legacyPath, $wpContPath, true)) {
DupLiteSnapLibIOU::rrmdir($legacyPath);
}
}
break;
default:
throw new Exception('Unknown storage position');
}
return true;
}
protected static function resetPositionVars()
{
self::$ssDirPath = null;
self::$ssDirUrl = null;
}
/**
* Saves all the setting values to the database
* @return True if option value has changed, false if not or if update failed.
*/
public static function Save()
{
return update_option(self::OPT_SETTINGS, self::$Data);
}
/**
* Deletes all the setting values to the database
* @return True if option value has changed, false if not or if update failed.
*/
public static function Delete()
{
return delete_option(self::OPT_SETTINGS);
}
/**
* Sets the defaults if they have not been set
* @return True if option value has changed, false if not or if update failed.
*/
public static function SetDefaults()
{
$defaults = self::GetAllDefaults();
self::$Data = apply_filters('duplicator_defaults_settings', $defaults);
return self::Save();
}
/**
* DeleteWPOption: Cleans up legacy data
*/
public static function DeleteWPOption($optionName)
{
if (in_array($optionName, $GLOBALS['DUPLICATOR_OPTS_DELETE'])) {
return delete_option($optionName);
}
return false;
}
public static function GetAllDefaults()
{
$default = array();
$default['version'] = DUPLICATOR_VERSION;
//Flag used to remove the wp_options value duplicator_settings which are all the settings in this class
$default['uninstall_settings'] = isset(self::$Data['uninstall_settings']) ? self::$Data['uninstall_settings'] : true;
//Flag used to remove entire wp-snapshot directory
$default['uninstall_files'] = isset(self::$Data['uninstall_files']) ? self::$Data['uninstall_files'] : true;
//Flag used to remove all tables
$default['uninstall_tables'] = isset(self::$Data['uninstall_tables']) ? self::$Data['uninstall_tables'] : true;
//Flag used to show debug info
$default['package_debug'] = isset(self::$Data['package_debug']) ? self::$Data['package_debug'] : false;
//Flag used to enable mysqldump
$default['package_mysqldump'] = isset(self::$Data['package_mysqldump']) ? self::$Data['package_mysqldump'] : true;
//Optional mysqldump search path
$default['package_mysqldump_path'] = isset(self::$Data['package_mysqldump_path']) ? self::$Data['package_mysqldump_path'] : '';
//Optional mysql limit size
$default['package_phpdump_qrylimit'] = isset(self::$Data['package_phpdump_qrylimit']) ? self::$Data['package_phpdump_qrylimit'] : "100";
//Optional mysqldump search path
$default['package_zip_flush'] = isset(self::$Data['package_zip_flush']) ? self::$Data['package_zip_flush'] : false;
//Optional mysqldump search path
$default['installer_name_mode'] = isset(self::$Data['installer_name_mode']) ? self::$Data['installer_name_mode'] : self::INSTALLER_NAME_MODE_SIMPLE;
// storage position
$default['storage_position'] = isset(self::$Data['storage_position']) ? self::$Data['storage_position'] : self::STORAGE_POSITION_WP_CONTENT;
//Flag for .htaccess file
$default['storage_htaccess_off'] = isset(self::$Data['storage_htaccess_off']) ? self::$Data['storage_htaccess_off'] : false;
// Initial archive build mode
if (isset(self::$Data['archive_build_mode'])) {
$default['archive_build_mode'] = self::$Data['archive_build_mode'];
} else {
$is_ziparchive_available = apply_filters('duplicator_is_ziparchive_available', class_exists('ZipArchive'));
$default['archive_build_mode'] = $is_ziparchive_available ? DUP_Archive_Build_Mode::ZipArchive : DUP_Archive_Build_Mode::DupArchive;
}
// $default['package_zip_flush'] = apply_filters('duplicator_package_zip_flush_default_setting', '0');
//Skip scan archive
$default['skip_archive_scan'] = isset(self::$Data['skip_archive_scan']) ? self::$Data['skip_archive_scan'] : false;
$default['unhook_third_party_js'] = isset(self::$Data['unhook_third_party_js']) ? self::$Data['unhook_third_party_js'] : false;
$default['unhook_third_party_css'] = isset(self::$Data['unhook_third_party_css']) ? self::$Data['unhook_third_party_css'] : false;
$default['active_package_id'] = -1;
return $default;
}
public static function get_create_date_format()
{
static $ui_create_frmt = null;
if (is_null($ui_create_frmt)) {
$ui_create_frmt = is_numeric(self::Get('package_ui_created')) ? self::Get('package_ui_created') : 1;
}
return $ui_create_frmt;
}
public static function getSsdirPathLegacy()
{
return DupLiteSnapLibIOU::safePathTrailingslashit(duplicator_get_abs_path()).self::SSDIR_NAME_LEGACY;
}
public static function getSsdirPathWpCont()
{
return DupLiteSnapLibIOU::safePathTrailingslashit(WP_CONTENT_DIR).self::SSDIR_NAME_NEW;
}
public static function getSsdirPath()
{
if (is_null(self::$ssDirPath)) {
if (self::Get('storage_position') === self::STORAGE_POSITION_LECAGY) {
self::$ssDirPath = self::getSsdirPathLegacy();
} else {
self::$ssDirPath = self::getSsdirPathWpCont();
}
}
return self::$ssDirPath;
}
public static function getSsdirUrl()
{
if (is_null(self::$ssDirUrl)) {
if (self::Get('storage_position') === self::STORAGE_POSITION_LECAGY) {
self::$ssDirUrl = DupLiteSnapLibIOU::trailingslashit(DUPLICATOR_SITE_URL).self::SSDIR_NAME_LEGACY;
} else {
self::$ssDirUrl = DupLiteSnapLibIOU::trailingslashit(content_url()).self::SSDIR_NAME_NEW;
}
}
return self::$ssDirUrl;
}
public static function getSsdirTmpPath()
{
return self::getSsdirPath().'/tmp';
}
public static function getSsdirInstallerPath()
{
return self::getSsdirPath().'/installer';
}
} classes/class.plugin.upgrade.php 0000644 00000004642 15133606540 0012753 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Upgrade logic of plugin resides here
*/
class DUP_LITE_Plugin_Upgrade
{
const DUP_VERSION_OPT_KEY = 'duplicator_version_plugin';
public static function onActivationAction()
{
if (($oldDupVersion = get_option(self::DUP_VERSION_OPT_KEY, false)) === false) {
self::newInstallation();
} else {
self::updateInstallation($oldDupVersion);
}
//Setup All Directories
DUP_Util::initSnapshotDirectory();
}
protected static function newInstallation()
{
self::updateDatabase();
//WordPress Options Hooks
update_option(self::DUP_VERSION_OPT_KEY, DUPLICATOR_VERSION);
}
protected static function updateInstallation($oldVersion)
{
self::updateDatabase();
//PRE 1.3.35
//Do not update to new wp-content storage till after
if (version_compare($oldVersion, '1.3.35', '<')) {
DUP_Settings::Set('storage_position', DUP_Settings::STORAGE_POSITION_LECAGY);
DUP_Settings::Save();
}
//PRE 1.4.7
//Remove the core dup-install file that might exist in local storage directory
if (version_compare($oldVersion, '1.4.7', '<')) {
$ssdir = DUP_Settings::getSsdirPath();
$dupInstallFile = "{$ssdir}/dup-installer/main.installer.php";
if (file_exists($dupInstallFile) ) {
@unlink("{$dupInstallFile}");
}
}
//WordPress Options Hooks
update_option(self::DUP_VERSION_OPT_KEY, DUPLICATOR_VERSION);
}
protected static function updateDatabase()
{
global $wpdb;
$table_name = $wpdb->prefix."duplicator_packages";
//PRIMARY KEY must have 2 spaces before for dbDelta to work
//see: https://codex.wordpress.org/Creating_Tables_with_Plugins
$sql = "CREATE TABLE `{$table_name}` (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(250) NOT NULL,
hash VARCHAR(50) NOT NULL,
status INT(11) NOT NULL,
created DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
owner VARCHAR(60) NOT NULL,
package LONGTEXT NOT NULL,
PRIMARY KEY (id),
KEY hash (hash))";
$abs_path = duplicator_get_abs_path();
require_once($abs_path.'/wp-admin/includes/upgrade.php');
@dbDelta($sql);
}
} classes/ui/class.ui.messages.php 0000644 00000006501 15133606540 0012663 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Used to generate a thick box inline dialog such as an alert or confirm pop-up
*
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package Duplicator
* @subpackage classes/ui
* @copyright (c) 2017, Snapcreek LLC
*/
class DUP_UI_Messages
{
const UNIQUE_ID_PREFIX = 'dup_ui_msg_';
const NOTICE = 'updated';
const WARNING = 'update-nag';
const ERROR = 'error';
private static $unique_id = 0;
private $id;
public $type = self::NOTICE;
public $content = '';
public $wrap_cont_tag = 'p';
public $hide_on_init = true;
public $is_dismissible = false;
/**
*
* @var int delay in milliseconds
*/
public $auto_hide_delay = 0;
public $callback_on_show = null;
public $callback_on_hide = null;
public function __construct($content = '', $type = self::NOTICE)
{
self::$unique_id ++;
$this->id = self::UNIQUE_ID_PREFIX.self::$unique_id;
$this->content = (string) $content;
$this->type = $type;
}
protected function get_notice_classes($classes = array())
{
if (is_string($classes)) {
$classes = explode(' ', $classes);
} else if (is_array($classes)) {
} else {
$classes = array();
}
if ($this->is_dismissible) {
$classes[] = 'is-dismissible';
}
$result = array_merge(array('notice', $this->type), $classes);
return trim(implode(' ', $result));
}
public function initMessage()
{
$classes = array();
if ($this->hide_on_init) {
$classes[] = 'no_display';
}
$this->wrap_tag = empty($this->wrap_tag) ? 'p' : $this->wrap_tag;
echo '<div id="'.$this->id.'" class="'.$this->get_notice_classes($classes).'">'.
'<'.$this->wrap_cont_tag.' class="msg-content">'.
$this->content.
'</'.$this->wrap_cont_tag.'>'.
'</div>';
}
public function updateMessage($jsVarName, $echo = true)
{
$result = 'jQuery("#'.$this->id.' > .msg-content").html('.$jsVarName.');';
if ($echo) {
echo $result;
} else {
return $result;
}
}
public function showMessage($echo = true)
{
$callStr = !empty($this->callback_on_show) ? $this->callback_on_show.';' : '';
$result = 'jQuery("#'.$this->id.'").fadeIn( "slow", function() { $(this).removeClass("no_display");'.$callStr.' });';
if ($this->auto_hide_delay > 0) {
$result .= 'setTimeout(function () { '.$this->hideMessage(false).' }, '.$this->auto_hide_delay.');';
}
if ($echo) {
echo $result;
} else {
return $result;
}
}
public function hideMessage($echo = true)
{
$callStr = !empty($this->callback_on_hide) ? $this->callback_on_hide.';' : '';
$result = 'jQuery("#'.$this->id.'").fadeOut( "slow", function() { $(this).addClass("no_display");'.$callStr.' });';
if ($echo) {
echo $result;
} else {
return $result;
}
}
} classes/ui/index.php 0000644 00000000016 15133606540 0010436 0 ustar 00 <?php
//silent classes/ui/class.ui.dialog.php 0000644 00000015371 15133606540 0012320 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Used to generate a thick-box inline dialog such as an alert or confirm pop-up
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package Duplicator
* @subpackage classes/ui
* @copyright (c) 2017, Snapcreek LLC
*
*/
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
class DUP_UI_Dialog
{
/**
* The title that shows up in the dialog
*/
public $title;
/**
* The message displayed in the body of the dialog
*/
public $message;
/**
* The width of the dialog the default is used if not set
* Alert = 475px (default) | Confirm = 500px (default)
*/
public $width;
/**
* The height of the dialog the default is used if not set
* Alert = 125px (default) | Confirm = 150px (default)
*/
public $height;
/**
* When the progress meter is running show this text
* Available only on confirm dialogs
*/
public $progressText;
/**
* When true a progress meter will run until page is reloaded
* Available only on confirm dialogs
*/
public $progressOn = true;
/**
* The javascript call back method to call when the 'Yes' button is clicked
* Available only on confirm dialogs
*/
public $jscallback;
/**
*
* @var string
*/
public $okText;
/**
*
* @var string
*/
public $cancelText;
/**
* If true close dialog on confirm
* @var bool
*/
public $closeOnConfirm = false;
/**
* The id given to the full dialog
*/
private $id;
/**
* A unique id that is added to all id elements
*/
private $uniqid;
/**
* Init this object when created
*/
public function __construct()
{
add_thickbox();
$this->progressText = __('Processing please wait...', 'duplicator');
$this->uniqid = substr(uniqid('',true),0,14) . rand();
$this->id = 'dup-dlg-'.$this->uniqid;
$this->okText = __('OK', 'duplicator');
$this->cancelText = __('Cancel', 'duplicator');
}
/**
* Gets the unique id that is assigned to each instance of a dialog
*
* @return int The unique ID of this dialog
*/
public function getID()
{
return $this->id;
}
/**
* Gets the unique id that is assigned to each instance of a dialogs message text
*
* @return int The unique ID of the message
*/
public function getMessageID()
{
return "{$this->id}_message";
}
/**
* Initialize the alert base html code used to display when needed
*
* @return string The html content used for the alert dialog
*/
public function initAlert()
{
$onClickClose = '';
if (!is_null($this->jscallback)) {
$onClickClose .= $this->jscallback.';';
}
$onClickClose .= 'tb_remove();';
if (strlen($this->okText) == 0) {
$hideButton = "style='display:none'";
}
$html = '
<div id="'.esc_attr($this->id).'" style="display:none">
<div class="dup-dlg-alert-txt">
'.$this->message.'
<br/><br/>
</div>
<div class="dup-dlg-alert-btns">
<input type="button" class="button button-large" value="'.esc_attr($this->okText).'" onclick="'.$onClickClose.'" '. $hideButton . '/>
</div>
</div>';
echo $html;
}
/**
* Shows the alert base JS code used to display when needed
*
* @return string The javascript content used for the alert dialog
*/
public function showAlert()
{
$this->width = is_numeric($this->width) ? $this->width : 500;
$this->height = is_numeric($this->height) ? $this->height : 175;
$html = "tb_show('".esc_js($this->title)."', '#TB_inline?width=".esc_js($this->width)."&height=".esc_js($this->height)."&inlineId=".esc_js($this->id)."');\n" .
"var styleData = jQuery('#TB_window').attr('style') + 'height: ".esc_js($this->height)."px !important';\n" .
"jQuery('#TB_window').attr('style', styleData);";
echo $html;
}
/**
* Shows the confirm base JS code used to display when needed
*
* @return string The javascript content used for the confirm dialog
*/
public function initConfirm()
{
$progress_data = '';
$progress_func2 = '';
$onClickConfirm = '';
if (!is_null($this->jscallback)) {
$onClickConfirm .= $this->jscallback.';';
}
//Enable the progress spinner
if ($this->progressOn) {
$progress_func1 = "__DUP_UI_Dialog_".$this->uniqid;
$progress_func2 = ";{$progress_func1}(this)";
$progress_data = "<div class='dup-dlg-confirm-progress'><i class='fas fa-circle-notch fa-spin fa-lg fa-fw'></i> ".esc_js($this->progressText)."</div>
<script>
function {$progress_func1}(obj)
{
jQuery(obj).parent().parent().find('.dup-dlg-confirm-progress').show();
jQuery(obj).closest('.dup-dlg-confirm-btns').find('input').attr('disabled', 'true');
}
</script>";
$onClickConfirm .= $progress_func2.';';
}
if ($this->closeOnConfirm) {
$onClickConfirm .= 'tb_remove();';
}
$html =
'<div id="'.esc_attr($this->id).'" style="display:none">
<div class="dup-dlg-confirm-txt">
<span id="'.esc_attr($this->id).'_message">'.esc_html($this->message).'</span>
<br/><br/>
'.$progress_data.'
</div>
<div class="dup-dlg-confirm-btns">
<input type="button" class="button button-large" value="'.esc_attr($this->okText).'" onclick="'.$onClickConfirm.'" />
<input type="button" class="button button-large" value="'.esc_attr($this->cancelText).'" onclick="tb_remove()" />
</div>
</div>';
echo $html;
}
/**
* Shows the confirm base JS code used to display when needed
*
* @return string The javascript content used for the confirm dialog
*/
public function showConfirm()
{
$this->width = is_numeric($this->width) ? $this->width : 500;
$this->height = is_numeric($this->height) ? $this->height : 225;
$html = "tb_show('".esc_js($this->title)."', '#TB_inline?width=".esc_js($this->width)."&height=".esc_js($this->height)."&inlineId=".esc_js($this->id)."');\n" .
"var styleData = jQuery('#TB_window').attr('style') + 'height: ".esc_js($this->height)."px !important';\n" .
"jQuery('#TB_window').attr('style', styleData);";
echo $html;
}
} classes/ui/class.ui.screen.base.php 0000644 00000010170 15133606540 0013241 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* The base class for all screen.php files. This class is used to control items that are common
* among all screens, namely the Help tab and Screen Options drop down items. When creating a
* screen object please extent this class.
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package Duplicator
* @subpackage classes/ui
* @copyright (c) 2017, Snapcreek LLC
*
*/
// Exit if accessed directly
if (!defined('DUPLICATOR_VERSION'))
exit;
class DUP_UI_Screen
{
/**
* Used as a placeholder for the current screen object
*/
public $screen;
/**
* Init this object when created
*/
public function __construct()
{
}
public static function getCustomCss()
{
$screen = get_current_screen();
if (!in_array($screen->id, array(
'toplevel_page_duplicator',
'duplicator_page_duplicator-tools',
'duplicator_page_duplicator-settings',
'duplicator_page_duplicator-gopro'))) {
return;
}
$colorScheme = self::getCurrentColorScheme();
if ($colorScheme !== false) {
?>
<style>
.link-style {
color: <?php echo $colorScheme->colors[2]; ?>;
}
.link-style:hover {
color: <?php echo $colorScheme->colors[3]; ?>;
}
</style>
<?php
}
}
public static function getCurrentColorScheme()
{
global $_wp_admin_css_colors;
if(!isset($_wp_admin_css_colors) || !is_array($_wp_admin_css_colors)){
return false;
}
$colorScheme = get_user_option('admin_color');
if (isset($_wp_admin_css_colors[$colorScheme])) {
return $_wp_admin_css_colors[$colorScheme];
} else {
return $_wp_admin_css_colors[DupLiteSnapLibUtil::arrayKeyFirst($_wp_admin_css_colors)];
}
}
/**
* Get the help support tab view content shown in the help system
*
* @param string $guide The target URL to navigate to on the online user guide
* @param string $faq The target URL to navigate to on the online user tech FAQ
*
* @return null
*/
public function getSupportTab($guide, $faq)
{
$content = __("<b>Need Help?</b> Please check out these resources first:"
."<ul>"
."<li><a href='https://snapcreek.com/duplicator/docs/guide{$guide}' target='_sc-faq'>Full Online User Guide</a></li>"
."<li><a href='https://snapcreek.com/duplicator/docs/faqs-tech{$faq}' target='_sc-faq'>Frequently Asked Questions</a></li>"
."</ul>", 'duplicator');
$this->screen->add_help_tab(array(
'id' => 'dup_help_tab_callback',
'title' => esc_html__('Support', 'duplicator'),
'content' => "<p>{$content}</p>"
)
);
}
/**
* Get the help support side bar found in the right most part of the help system
*
* @return null
*/
public function getHelpSidbar()
{
$txt_title = __("Resources", 'duplicator');
$txt_home = __("Knowledge Base", 'duplicator');
$txt_guide = __("Full User Guide", 'duplicator');
$txt_faq = __("Technical FAQs", 'duplicator');
$txt_sets = __("Package Settings", 'duplicator');
$this->screen->set_help_sidebar(
"<div class='dup-screen-hlp-info'><b>".esc_html($txt_title).":</b> <br/>"
."<i class='fa fa-home'></i> <a href='https://snapcreek.com/duplicator/docs/' target='_sc-home'>".esc_html($txt_home)."</a> <br/>"
."<i class='fa fa-book'></i> <a href='https://snapcreek.com/duplicator/docs/guide/' target='_sc-guide'>".esc_html($txt_guide)."</a> <br/>"
."<i class='far fa-file-code'></i> <a href='https://snapcreek.com/duplicator/docs/faqs-tech/' target='_sc-faq'>".esc_html($txt_faq)."</a> <br/>"
."<i class='fa fa-cog'></i> <a href='admin.php?page=duplicator-settings&tab=package'>".esc_html($txt_sets)."</a></div>"
);
}
} classes/ui/class.ui.notice.php 0000644 00000036166 15133606540 0012347 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Used to display notices in the WordPress Admin area
* This class takes advantage of the admin_notice action.
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package Duplicator
* @subpackage classes/ui
* @copyright (c) 2017, Snapcreek LLC
*
*/
class DUP_UI_Notice
{
const OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL = 'duplicator_reactivate_plugins_after_installation';
//TEMPLATE VALUE: This is a just a simple example for setting up quick notices
const OPTION_KEY_NEW_NOTICE_TEMPLATE = 'duplicator_new_template_notice';
const OPTION_KEY_IS_PRO_ENABLE_NOTICE_DISMISSED = 'duplicator_is_pro_enable_notice_dismissed';
const OPTION_KEY_IS_MU_NOTICE_DISMISSED = 'duplicator_is_mu_notice_dismissed';
const GEN_INFO_NOTICE = 0;
const GEN_SUCCESS_NOTICE = 1;
const GEN_WARNING_NOTICE = 2;
const GEN_ERROR_NOTICE = 3;
/**
* init notice actions
*/
public static function init()
{
$methods = array(
'showReservedFilesNotice',
'installAutoDeactivatePlugins',
'showFeedBackNotice',
'showNoExportCapabilityNotice',
//FUTURE NOTICE TEMPLATE
//'newNotice_TEMPLATE',
);
foreach ($methods as $method) {
add_action('admin_notices', array(__CLASS__, $method));
}
}
/**
* NOTICE SAMPLE: This method serves as a quick example for how to quickly setup a new notice
* Please do not edit this method, but simply use to copy a new setup.
*/
public static function newNotice_TEMPLATE()
{
if (get_option(self::OPTION_KEY_NEW_NOTICE_TEMPLATE) != true) {
return;
}
$screen = get_current_screen();
if (!in_array($screen->parent_base, array('plugins', 'duplicator'))) {
return;
}
?>
<div class="notice notice-success duplicator-admin-notice is-dismissible" data-to-dismiss="<?php echo esc_attr(self::OPTION_KEY_NEW_NOTICE_TEMPLATE); ?>" >
<p>
<?php esc_html_e('NOTICE: This is a sample message notice demo.', 'duplicator'); ?><br>
<?php
echo sprintf(__('Example for passing dynamic data to notice message <i>%s</i> to <i>%s</i>', 'duplicator'),
esc_html("test 1"),
esc_html(time()));
?>
</p>
<p>
<?php echo sprintf(__('More info here: Goto <a href="%s">General Settings</a>', 'duplicator'), 'admin.php?page=duplicator-settings'); ?>
</p>
</div>
<?php
}
/**
* Shows a display message in the wp-admin if any reserved files are found
*
* @return string Html formatted text notice warnings
*/
public static function showReservedFilesNotice()
{
//Show only on Duplicator pages and Dashboard when plugin is active
$dup_active = is_plugin_active('duplicator/duplicator.php');
$dup_perm = current_user_can('manage_options');
if (!$dup_active || !$dup_perm)
return;
$screen = get_current_screen();
if (!isset($screen))
return;
$is_installer_cleanup_req = ($screen->id == 'duplicator_page_duplicator-tools' && isset($_GET['action']) && $_GET['action'] == 'installer');
if (DUP_Server::hasInstallerFiles() && !$is_installer_cleanup_req) {
DUP_Migration::renameInstallersPhpFiles();
$on_active_tab = isset($_GET['section']) ? $_GET['section'] : '';
echo '<div class="dup-updated notice notice-success dup-global-error-reserved-files" id="message"><p>';
//Safe Mode Notice
$safe_html = '';
if (get_option("duplicator_exe_safe_mode", 0) > 0) {
$safe_msg1 = __('Safe Mode:', 'duplicator');
$safe_msg2 = __('During the install safe mode was enabled deactivating all plugins.<br/> Please be sure to ', 'duplicator');
$safe_msg3 = __('re-activate the plugins', 'duplicator');
$safe_html = "<div class='notice-safemode'><b>{$safe_msg1}</b><br/>{$safe_msg2} <a href='plugins.php'>{$safe_msg3}</a>!</div><br/>";
}
//On Tools > Cleanup Page
if ($screen->id == 'duplicator_page_duplicator-tools' && ($on_active_tab == "info" || $on_active_tab == '')) {
$title = __('This site has been successfully migrated!', 'duplicator');
$msg1 = __('Final step(s):', 'duplicator');
$msg2 = __('This message will be removed after all installer files are removed. Installer files must be removed to maintain a secure site. '
.'Click the link above or button below to remove all installer files and complete the migration.', 'duplicator');
echo "<b class='pass-msg'><i class='fa fa-check-circle'></i> ".esc_html($title)."</b> <br/> {$safe_html} <b>".esc_html($msg1)."</b> <br/>";
printf("1. <a href='javascript:void(0)' onclick='jQuery(\"#dup-remove-installer-files-btn\").click()'>%s</a><br/>", esc_html__('Remove Installation Files Now!', 'duplicator'));
printf("2. <a href='https://wordpress.org/support/plugin/duplicator/reviews/?filter=5' target='wporg'>%s</a> <br/> ", esc_html__('Optionally, Review Duplicator at WordPress.org...', 'duplicator'));
echo "<div class='pass-msg'>".esc_html($msg2)."</div>";
//All other Pages
} else {
$title = __('Migration Almost Complete!', 'duplicator');
$msg = __('Reserved Duplicator installation files have been detected in the root directory. Please delete these installation files to '
.'avoid security issues. <br/> Go to:Duplicator > Tools > Information >Stored Data and click the "Remove Installation Files" button', 'duplicator');
$nonce = wp_create_nonce('duplicator_cleanup_page');
$url = self_admin_url('admin.php?page=duplicator-tools&tab=diagnostics§ion=info&_wpnonce='.$nonce);
echo "<b>{$title}</b><br/> {$safe_html} {$msg}";
@printf("<br/><a href='{$url}'>%s</a>", __('Take me there now!', 'duplicator'));
}
echo "</p></div>";
}
}
/**
* Shows a message for redirecting a page
*
* @return string The location to redirect to
*/
public static function redirect($location)
{
echo '<div class="dup-redirect"><i class="fas fa-circle-notch fa-spin fa-fw"></i>';
esc_html__('Redirecting Please Wait...', 'duplicator');
echo '</div>';
echo "<script>window.location = '{$location}';</script>";
die(esc_html__('Invalid token permissions to perform this request.', 'duplicator'));
}
/**
* Shows install deactivated function
*/
public static function installAutoDeactivatePlugins()
{
$reactivatePluginsAfterInstallation = get_option(self::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL, false);
if (is_array($reactivatePluginsAfterInstallation)) {
$installedPlugins = array_keys(get_plugins());
$shouldBeActivated = array();
foreach ($reactivatePluginsAfterInstallation as $pluginSlug => $pluginTitle) {
if (in_array($pluginSlug, $installedPlugins) && !is_plugin_active($pluginSlug)) {
$shouldBeActivated[$pluginSlug] = $pluginTitle;
}
}
if (empty($shouldBeActivated)) {
delete_option(self::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL);
} else {
$activatePluginsAnchors = array();
foreach ($shouldBeActivated as $slug => $title) {
$activateURL = wp_nonce_url(admin_url('plugins.php?action=activate&plugin='.$slug), 'activate-plugin_'.$slug);
$anchorTitle = sprintf(esc_html__('Activate %s', 'duplicator'), $title);
$activatePluginsAnchors[] = '<a href="'.$activateURL.'"
title="'.esc_attr($anchorTitle).'">'.
$title.'</a>';
}
?>
<div class="update-nag duplicator-plugin-activation-admin-notice notice notice-warning duplicator-admin-notice is-dismissible"
data-to-dismiss="<?php echo esc_attr(self::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL); ?>" >
<p>
<?php
echo "<b>".esc_html__("Warning!", "duplicator")."</b> ".esc_html__("Migration Almost Complete!", "duplicator")." <br/>";
echo esc_html__("Plugin(s) listed here have been deactivated during installation to help prevent issues. Please activate them to finish this migration: ", "duplicator")."<br/>";
echo implode(' ,', $activatePluginsAnchors);
?>
</p>
</div>
<?php
}
}
}
/**
* Shows feedback notices after certain no. of packages successfully created
*/
public static function showFeedBackNotice()
{
$notice_id = 'rate_us_feedback';
if (!current_user_can('manage_options')) {
return;
}
$notices = get_user_meta(get_current_user_id(), DUPLICATOR_ADMIN_NOTICES_USER_META_KEY, true);
if (empty($notices)) {
$notices = array();
}
$duplicator_pages = array(
'toplevel_page_duplicator',
'duplicator_page_duplicator-tools',
'duplicator_page_duplicator-settings',
'duplicator_page_duplicator-gopro',
);
if (!in_array(get_current_screen()->id, $duplicator_pages) || (isset($notices[$notice_id]) && 'true' === $notices[$notice_id])) {
return;
}
// not using DUP_Util::getTablePrefix() in place of $tablePrefix because DUP_UI_Notice included initially (Duplicator\Lite\Requirement is depended on the DUP_UI_Notice)
$tablePrefix = (is_multisite() && is_plugin_active_for_network('duplicator/duplicator.php')) ? $GLOBALS['wpdb']->base_prefix : $GLOBALS['wpdb']->prefix;
$packagesCount = $GLOBALS['wpdb']->get_var('SELECT count(id) FROM '.$tablePrefix.'duplicator_packages WHERE status=100');
if ($packagesCount < DUPLICATOR_FEEDBACK_NOTICE_SHOW_AFTER_NO_PACKAGE) {
return;
}
$notices[$notice_id] = 'false';
update_user_meta(get_current_user_id(), DUPLICATOR_ADMIN_NOTICES_USER_META_KEY, $notices);
$dismiss_url = wp_nonce_url(
add_query_arg(array(
'action' => 'duplicator_set_admin_notice_viewed',
'notice_id' => esc_attr($notice_id),
), admin_url('admin-post.php')),
'duplicator_set_admin_notice_viewed',
'nonce'
);
?>
<div class="notice updated duplicator-message duplicator-message-dismissed" data-notice_id="<?php echo esc_attr($notice_id); ?>">
<div class="duplicator-message-inner">
<div class="duplicator-message-icon">
<img src="<?php echo esc_url(DUPLICATOR_PLUGIN_URL."assets/img/logo.png"); ?>" style="text-align:top; margin:0; height:60px; width:60px;" alt="Duplicator">
</div>
<div class="duplicator-message-content">
<p><strong><?php echo __('Congrats!', 'duplicator'); ?></strong> <?php printf(esc_html__('You created over %d packages with Duplicator. Great job! If you can spare a minute, please help us by leaving a five star review on WordPress.org.', 'duplicator'), DUPLICATOR_FEEDBACK_NOTICE_SHOW_AFTER_NO_PACKAGE); ?></p>
<p class="duplicator-message-actions">
<a href="https://wordpress.org/support/plugin/duplicator/reviews/?filter=5/#new-post" target="_blank" class="button button-primary duplicator-notice-rate-now"><?php esc_html_e("Sure! I'd love to help", 'duplicator'); ?></a>
<a href="<?php echo esc_url_raw($dismiss_url); ?>" class="button duplicator-notice-dismiss"><?php esc_html_e('Hide Notification', 'duplicator'); ?></a>
</p>
</div>
</div>
</div>
<?php
}
/**
* Shows a display message in the wp-admin if the logged in user role has not export capability
*
* @return void
*/
public static function showNoExportCapabilityNotice()
{
if (is_admin() && in_array('administrator', $GLOBALS['current_user']->roles) && !current_user_can('export')) {
$errorMessage = __('<strong>Duplicator</strong><hr> Your logged-in user role does not have export capability so you don\'t have access to Duplicator functionality.', 'duplicator').
"<br>".
sprintf(__('<strong>RECOMMENDATION:</strong> Add export capability to your role. See FAQ: <a target="_blank" href="%s">%s</a>', 'duplicator'), 'https://snapcreek.com/duplicator/docs/faqs-tech/#faq-licensing-040-q', __('Why is the Duplicator/Packages menu missing from my admin menu?', 'duplicator'));
DUP_UI_Notice::displayGeneralAdminNotice($errorMessage, self::GEN_ERROR_NOTICE, true);
}
}
/**
* display genral admin notice by printing it
*
* @param string $htmlMsg html code to be printed
* @param integer $noticeType constant value of SELF::GEN_
* @param boolean $isDismissible whether the notice is dismissable or not. Default is true
* @param array|string $extraClasses add more classes to the notice div
* @return void
*/
public static function displayGeneralAdminNotice($htmlMsg, $noticeType, $isDismissible = true, $extraClasses = array())
{
if (empty($extraClasses)) {
$classes = array();
} elseif (is_array($extraClasses)) {
$classes = $extraClasses;
} else {
$classes = array($extraClasses);
}
$classes[] = 'notice';
switch ($noticeType) {
case self::GEN_INFO_NOTICE:
$classes[] = 'notice-info';
break;
case self::GEN_SUCCESS_NOTICE:
$classes[] = 'notice-success';
break;
case self::GEN_WARNING_NOTICE:
$classes[] = 'notice-warning';
break;
case self::GEN_ERROR_NOTICE:
$classes[] = 'notice-error';
break;
default:
throw new Exception('Invalid Admin notice type!');
}
if ($isDismissible) {
$classes[] = 'is-dismissible';
}
$classesStr = implode(' ', $classes);
?>
<div class="<?php echo esc_attr($classesStr); ?>">
<p>
<?php
if (self::GEN_ERROR_NOTICE == $noticeType) {
?>
<i class='fa fa-exclamation-triangle'></i>
<?php
}
?>
<?php
echo $htmlMsg;
?>
</p>
</div>
<?php
}
} classes/ui/class.ui.viewstate.php 0000644 00000004457 15133606540 0013077 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Gets the view state of UI elements to remember its viewable state
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package Duplicator
* @subpackage classes/ui
* @copyright (c) 2017, Snapcreek LLC
*
*/
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
class DUP_UI_ViewState
{
/**
* The key used in the wp_options table
*
* @var string
*/
private static $optionsViewStateKey = 'duplicator_ui_view_state';
/**
* Save the view state of UI elements
*
* @param string $key A unique key to define the UI element
* @param string $value A generic value to use for the view state
*
* @return bool Returns true if the value was successfully saved
*/
public static function save($key, $value)
{
$view_state = array();
$view_state = get_option(self::$optionsViewStateKey);
$view_state[$key] = $value;
$success = update_option(self::$optionsViewStateKey, $view_state);
return $success;
}
/**
* Gets all the values from the settings array
*
* @return array Returns and array of all the values stored in the settings array
*/
public static function getArray()
{
return get_option(self::$optionsViewStateKey);
}
/**
* Sets all the values from the settings array
* @param array $view_state states
*
* @return boolean Returns whether updated or not
*/
public static function setArray($view_state)
{
return update_option(self::$optionsViewStateKey, $view_state);
}
/**
* Return the value of the of view state item
*
* @param type $searchKey The key to search on
* @return string Returns the value of the key searched or null if key is not found
*/
public static function getValue($searchKey)
{
$view_state = get_option(self::$optionsViewStateKey);
if (is_array($view_state)) {
foreach ($view_state as $key => $value) {
if ($key == $searchKey) {
return $value;
}
}
}
return null;
}
} classes/class.db.php 0000644 00000020052 15133606540 0010405 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Lightweight abstraction layer for common simple database routines
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package Duplicator
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
*
*/
// Exit if accessed directly
if (!defined('DUPLICATOR_VERSION')) exit;
class DUP_DB extends wpdb
{
const MAX_TABLE_COUNT_IN_PACKET = 100;
public static $remove_placeholder_escape_exists = null;
public static function init()
{
global $wpdb;
self::$remove_placeholder_escape_exists = method_exists($wpdb, 'remove_placeholder_escape');
}
/**
* Get the requested MySQL system variable
*
* @param string $name The database variable name to lookup
*
* @return string the server variable to query for
*/
public static function getVariable($name)
{
global $wpdb;
if (strlen($name)) {
$row = $wpdb->get_row("SHOW VARIABLES LIKE '{$name}'", ARRAY_N);
return isset($row[1]) ? $row[1] : null;
} else {
return null;
}
}
/**
* Gets the MySQL database version number
*
* @param bool $full True: Gets the full version
* False: Gets only the numeric portion i.e. 5.5.6 or 10.1.2 (for MariaDB)
*
* @return false|string 0 on failure, version number on success
*/
public static function getVersion($full = false)
{
global $wpdb;
if ($full) {
$version = self::getVariable('version');
} else {
$version = preg_replace('/[^0-9.].*/', '', self::getVariable('version'));
}
//Fall-back for servers that have restricted SQL for SHOW statement
if (empty($version)) {
$version = $wpdb->db_version();
}
return empty($version) ? 0 : $version;
}
/**
* Try to return the mysqldump path on Windows servers
*
* @return boolean|string
*/
public static function getWindowsMySqlDumpRealPath()
{
if (function_exists('php_ini_loaded_file')) {
$get_php_ini_path = php_ini_loaded_file();
if (file_exists($get_php_ini_path)) {
$search = array(
dirname(dirname($get_php_ini_path)).'/mysql/bin/mysqldump.exe',
dirname(dirname(dirname($get_php_ini_path))).'/mysql/bin/mysqldump.exe',
dirname(dirname($get_php_ini_path)).'/mysql/bin/mysqldump',
dirname(dirname(dirname($get_php_ini_path))).'/mysql/bin/mysqldump',
);
foreach ($search as $mysqldump) {
if (file_exists($mysqldump)) {
return str_replace("\\", "/", $mysqldump);
}
}
}
}
unset($search);
unset($get_php_ini_path);
return false;
}
/**
* Returns the correct database build mode PHP, MYSQLDUMP, PHPCHUNKING
*
* @return string Returns a string with one of theses three values PHP, MYSQLDUMP, PHPCHUNKING
*/
public static function getBuildMode()
{
$package_mysqldump = DUP_Settings::Get('package_mysqldump');
$mysqlDumpPath = DUP_DB::getMySqlDumpPath();
return ($mysqlDumpPath && $package_mysqldump) ? 'MYSQLDUMP' : 'PHP';
}
/**
* Returns the mysqldump path if the server is enabled to execute it otherwise false
*
* @return boolean|string
*/
public static function getMySqlDumpPath()
{
//Is shell_exec possible
if (!DUP_Util::hasShellExec()) {
return false;
}
$custom_mysqldump_path = DUP_Settings::Get('package_mysqldump_path');
$custom_mysqldump_path = (strlen($custom_mysqldump_path)) ? $custom_mysqldump_path : '';
//Common Windows Paths
if (DUP_Util::isWindows()) {
$paths = array(
$custom_mysqldump_path,
'mysqldump.exe',
self::getWindowsMySqlDumpRealPath(),
'C:/xampp/mysql/bin/mysqldump.exe',
'C:/Program Files/xampp/mysql/bin/mysqldump',
'C:/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump',
'C:/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump',
'C:/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump'
);
//Common Linux Paths
} else {
$paths = array(
$custom_mysqldump_path,
'mysqldump',
'/usr/local/bin/mysqldump',
'/usr/local/mysql/bin/mysqldump',
'/usr/mysql/bin/mysqldump',
'/usr/bin/mysqldump',
'/opt/local/lib/mysql6/bin/mysqldump',
'/opt/local/lib/mysql5/bin/mysqldump',
'/usr/bin/mysqldump',
);
}
$exec_available = function_exists('exec');
foreach ($paths as $path) {
if (@file_exists($path)) {
if (DUP_Util::isExecutable($path)) {
return $path;
}
} elseif ($exec_available) {
$out = array();
$rc = -1;
$cmd = $path . ' --help';
@exec($cmd, $out, $rc);
if ($rc === 0) {
return $path;
}
}
}
return false;
}
/**
* Returns all collation types that are assigned to the tables and columns table in
* the current database. Each element in the array is unique
*
* @param array &$tablesToInclude A list of tables to include in the search.
* Parameter does not change in the function, is passed by reference only to avoid copying.
*
* @return array Returns an array with all the collation types being used
*/
public static function getTableCollationList(&$tablesToInclude)
{
global $wpdb;
static $collations = null;
if (is_null($collations)) {
$collations = array();
//use half the number of tables since we are using them twice
foreach (array_chunk($tablesToInclude, self::MAX_TABLE_COUNT_IN_PACKET) as $tablesChunk) {
$sqlTables = implode(",", array_map(array(__CLASS__, 'escValueToQueryString'), $tablesChunk));
//UNION is by default DISTINCT
$query = "SELECT `COLLATION_NAME` FROM `information_schema`.`columns` WHERE `COLLATION_NAME` IS NOT NULL AND `table_schema` = '{$wpdb->dbname}' "
. "AND `table_name` in (" . $sqlTables . ")"
. "UNION SELECT `TABLE_COLLATION` FROM `information_schema`.`tables` WHERE `TABLE_COLLATION` IS NOT NULL AND `table_schema` = '{$wpdb->dbname}' "
. "AND `table_name` in (" . $sqlTables . ")";
if (!$wpdb->query($query)) {
DUP_Log::Info("GET TABLE COLLATION ERROR: " . $wpdb->last_error);
continue;
}
$collations = array_unique(array_merge($collations, $wpdb->get_col()));
}
sort($collations);
}
return $collations;
}
/**
* Returns an escaped SQL string
*
* @param string $sql The SQL to escape
* @param bool $removePlaceholderEscape Patch for how the default WP function works.
*
* @return boolean|string
* @also see: https://make.wordpress.org/core/2017/10/31/changed-behaviour-of-esc_sql-in-wordpress-4-8-3/
*/
public static function escSQL($sql, $removePlaceholderEscape = false)
{
global $wpdb;
$removePlaceholderEscape = $removePlaceholderEscape && self::$remove_placeholder_escape_exists;
if ($removePlaceholderEscape) {
return $wpdb->remove_placeholder_escape(@esc_sql($sql));
} else {
return @esc_sql($sql);
}
}
/**
* this function escape sql string without add and remove remove_placeholder_escape
* doesn't work on array
*
* @global type $wpdb
* @param mixed $sql
* @return string
*/
public static function escValueToQueryString($value)
{
global $wpdb;
if (is_null($value)) {
return 'NULL';
}
if ($wpdb->use_mysqli) {
return '"'.mysqli_real_escape_string($wpdb->dbh, $value).'"';
} else {
return '"'.mysql_real_escape_string($value, $wpdb->dbh).'"';
}
}
} classes/class.password.php 0000644 00000014360 15133606540 0011667 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
#
# Portable PHP password hashing framework.
#
# Version 0.5 / genuine.
#
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
# the public domain. Revised in subsequent years, still public domain.
#
# There's absolutely no warranty.
#
# The homepage URL for this framework is:
#
# http://www.openwall.com/phpass/
#
# Please be sure to update the Version line if you edit this file in any way.
# It is suggested that you leave the main version number intact, but indicate
# your project name (after the slash) and add your own revision information.
#
# Please do not change the "private" password hashing method implemented in
# here, thereby making your hashes incompatible. However, if you must, please
# change the hash type identifier (the "$P$") to something different.
#
# Obviously, since this code is in the public domain, the above are not
# requirements (there can be none), but merely suggestions.
#
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
class DUP_PasswordHash
{
var $itoa64;
var $iteration_count_log2;
var $portable_hashes;
var $random_state;
function __construct($iteration_count_log2, $portable_hashes)
{
$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
$iteration_count_log2 = 8;
$this->iteration_count_log2 = $iteration_count_log2;
$this->portable_hashes = $portable_hashes;
$this->random_state = microtime();
if (function_exists('getmypid'))
$this->random_state .= getmypid();
}
function PasswordHash($iteration_count_log2, $portable_hashes)
{
self::__construct($iteration_count_log2, $portable_hashes);
}
function get_random_bytes($count)
{
$output = '';
if (@is_readable('/dev/urandom') &&
($fh = @fopen('/dev/urandom', 'rb'))) {
$output = fread($fh, $count);
fclose($fh);
}
if (strlen($output) < $count) {
$output = '';
for ($i = 0; $i < $count; $i += 16) {
$this->random_state =
md5(microtime() . $this->random_state);
$output .= md5($this->random_state, TRUE);
}
$output = substr($output, 0, $count);
}
return $output;
}
function encode64($input, $count)
{
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function gensalt_private($input)
{
$output = '$P$';
$output .= $this->itoa64[min($this->iteration_count_log2 +
((PHP_VERSION >= '5') ? 5 : 3), 30)];
$output .= $this->encode64($input, 6);
return $output;
}
function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) === $output)
$output = '*1';
$id = substr($setting, 0, 3);
# We use "$P$", phpBB3 uses "$H$" for the same thing
if ($id !== '$P$' && $id !== '$H$')
return $output;
$count_log2 = strpos($this->itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30)
return $output;
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) !== 8)
return $output;
# We were kind of forced to use MD5 here since it's the only
# cryptographic primitive that was available in all versions
# of PHP in use. To implement our own low-level crypto in PHP
# would have resulted in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
$output = substr($setting, 0, 12);
$output .= $this->encode64($hash, 16);
return $output;
}
function gensalt_blowfish($input)
{
# This one needs to use a different order of characters and a
# different encoding scheme from the one in encode64() above.
# We care because the last character in our encoded string will
# only represent 2 bits. While two known implementations of
# bcrypt will happily accept and correct a salt string which
# has the 4 unused bits set to non-zero, we do not want to take
# chances and we also do not want to waste an additional byte
# of entropy.
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '$2a$';
$output .= chr(ord('0') + (int)($this->iteration_count_log2 / 10));
$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
$output .= '$';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
function HashPassword($password)
{
$random = '';
if (CRYPT_BLOWFISH === 1 && !$this->portable_hashes) {
$random = $this->get_random_bytes(16);
$hash =
crypt($password, $this->gensalt_blowfish($random));
if (strlen($hash) === 60)
return $hash;
}
if (strlen($random) < 6)
$random = $this->get_random_bytes(6);
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) === 34)
return $hash;
# Returning '*' on error is safe here, but would _not_ be safe
# in a crypt(3)-like function used _both_ for generating new
# hashes and for validating passwords against existing hashes.
return '*';
}
function CheckPassword($password, $stored_hash)
{
$hash = $this->crypt_private($password, $stored_hash);
if ($hash[0] === '*')
$hash = crypt($password, $stored_hash);
return $hash === $stored_hash;
}
}
classes/class.logging.php 0000644 00000035515 15133606540 0011460 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
// Exit if accessed directly
if (!defined('DUPLICATOR_VERSION')) exit;
/**
* Helper Class for logging
* @package Duplicator\classes
*/
abstract class Dup_ErrorBehavior
{
const LogOnly = 0;
const ThrowException = 1;
const Quit = 2;
}
class DUP_Log
{
/**
* The file handle used to write to the package log file
*/
private static $logFileHandle = null;
/**
* Get the setting which indicates if tracing is enabled
*/
private static $traceEnabled = false;
public static $profileLogs = null;
/**
* Init this static object
*/
public static function Init()
{
self::$traceEnabled = (DUP_Settings::Get('trace_log_enabled') == 1);
}
/**
* Open a log file connection for writing to the package log file
*
* @param string $nameHas The Name of the log file to create
*
* @return nul
*/
public static function Open($nameHash)
{
if (!isset($nameHash)) {
throw new Exception("A name value is required to open a file log.");
}
self::Close();
if ((self::$logFileHandle = @fopen(DUP_Settings::getSsdirPath()."/{$nameHash}.log", "a+")) === false) {
self::$logFileHandle = null;
return false;
} else {
/**
* By initializing the error_handler on opening the log, I am sure that when a package is processed, the handler is active.
*/
DUP_Handler::init_error_handler();
return true;
}
}
/**
* Close the package log file connection if is opened
*
* @return bool Returns TRUE on success or FALSE on failure.
*/
public static function Close()
{
$result = true;
if (!is_null(self::$logFileHandle)) {
$result = @fclose(self::$logFileHandle);
self::$logFileHandle = null;
} else {
$result = true;
}
return $result;
}
/**
* General information send to the package log if opened
* @param string $msg The message to log
*
* REPLACE TO DEBUG: Memory consumption as script runs
* $results = DUP_Util::byteSize(memory_get_peak_usage(true)) . "\t" . $msg;
* @fwrite(self::$logFileHandle, "{$results} \n");
*
* @param string $msg The message to log
*
* @return null
*/
public static function Info($msg)
{
if (self::$traceEnabled) {
self::Trace($msg);
}
if (!is_null(self::$logFileHandle)) {
@fwrite(self::$logFileHandle, $msg."\n");
}
}
public static function print_r_info($val, $name = '')
{
$msg = empty($name) ? '' : 'VALUE '.$name.': ';
$msg .= print_r($val, true);
self::info($msg);
}
/**
* Does the trace file exists
*
* @return bool Returns true if an active trace file exists
*/
public static function TraceFileExists()
{
$file_path = self::getTraceFilepath();
return file_exists($file_path);
}
/**
* Gets the current file size of the active trace file
*
* @return string Returns a human readable file size of the active trace file
*/
public static function getTraceStatus()
{
$file_path = DUP_Log::getTraceFilepath();
$backup_path = DUP_Log::getBackupTraceFilepath();
if (file_exists($file_path)) {
$filesize = is_file($file_path) ? @filesize($file_path) : 0;
//Its possible mulitple trace log files exist due to size
if (is_file($backup_path)) {
$filesize += @filesize($backup_path);
}
$message = sprintf('%1$s', DUP_Util::byteSize($filesize));
} else {
$message = esc_html__('No Log', 'duplicator');
}
return $message;
}
// RSR TODO: Swap trace logic out for real trace later
public static function Trace($message, $calling_function_override = null)
{
if (self::$traceEnabled) {
$unique_id = sprintf("%08x", abs(crc32($_SERVER['REMOTE_ADDR'].$_SERVER['REQUEST_TIME'].$_SERVER['REMOTE_PORT'])));
if ($calling_function_override == null) {
$calling_function = DupLiteSnapLibUtil::getCallingFunctionName();
} else {
$calling_function = $calling_function_override;
}
if (is_object($message)) {
$ov = get_object_vars($message);
$message = print_r($ov, true);
} else if (is_array($message)) {
$message = print_r($message, true);
}
$logging_message = "{$unique_id}|{$calling_function} | {$message}";
$ticks = time() + ((int) get_option('gmt_offset') * 3600);
$formatted_time = date('d-m-H:i:s', $ticks);
$formatted_logging_message = "{$formatted_time}|DUP|{$logging_message} \r\n";
// Always write to error log - if they don't want the info they can turn off WordPress error logging or tracing
self::ErrLog($logging_message);
// Everything goes to the plugin log, whether it's part of package generation or not.
self::WriteToTrace($formatted_logging_message);
}
}
public static function print_r_trace($val, $name = '', $calling_function_override = null)
{
$msg = empty($name) ? '' : 'VALUE '.$name.': ';
$msg .= print_r($val, true);
self::trace($msg, $calling_function_override);
}
public static function errLog($message)
{
$message = 'DUP:'.$message;
error_log($message);
}
public static function TraceObject($msg, $o, $log_private_members = true)
{
if (self::$traceEnabled) {
if (!$log_private_members) {
$o = get_object_vars($o);
}
self::Trace($msg.':'.print_r($o, true));
}
}
public static function GetDefaultKey()
{
$auth_key = defined('AUTH_KEY') ? AUTH_KEY : 'atk';
$auth_key .= defined('DB_HOST') ? DB_HOST : 'dbh';
$auth_key .= defined('DB_NAME') ? DB_NAME : 'dbn';
$auth_key .= defined('DB_USER') ? DB_USER : 'dbu';
return hash('md5', $auth_key);
}
/**
* Gets the current file size of the old trace file "1"
*
* @return string Returns a human readable file size of the active trace file
*/
public static function GetBackupTraceFilepath()
{
$default_key = self::getDefaultKey();
$backup_log_filename = "dup_$default_key.log1";
$backup_path = DUP_Settings::getSsdirPath()."/".$backup_log_filename;
return $backup_path;
}
/**
* Gets the active trace file path
*
* @return string Returns the full path to the active trace file (i.e. dup-pro_hash.log)
*/
public static function GetTraceFilepath()
{
$default_key = self::getDefaultKey();
$log_filename = "dup_$default_key.log";
$file_path = DUP_Settings::getSsdirPath()."/".$log_filename;
return $file_path;
}
/**
* Deletes the trace log and backup trace log files
*
* @return null
*/
public static function DeleteTraceLog()
{
$file_path = self::GetTraceFilepath();
$backup_path = self::GetBackupTraceFilepath();
self::trace("deleting $file_path");
@unlink($file_path);
self::trace("deleting $backup_path");
@unlink($backup_path);
}
/**
* Called when an error is detected and no further processing should occur
* @param string $msg The message to log
* @param string $detail Additional details to help resolve the issue if possible
* @param int $behavior
* @throws Exception
*/
public static function error($msg, $detail = '', $behavior = Dup_ErrorBehavior::Quit)
{
error_log($msg.' DETAIL:'.$detail);
$source = self::getStack(debug_backtrace());
$err_msg = "\n==================================================================================\n";
$err_msg .= "DUPLICATOR ERROR\n";
$err_msg .= "Please try again! If the error persists see the Duplicator 'Help' menu.\n";
$err_msg .= "---------------------------------------------------------------------------------\n";
$err_msg .= "MESSAGE:\n\t{$msg}\n";
if (strlen($detail)) {
$err_msg .= "DETAILS:\n\t{$detail}\n";
}
$err_msg .= "TRACE:\n{$source}";
$err_msg .= "==================================================================================\n\n";
@fwrite(self::$logFileHandle, "{$err_msg}");
switch ($behavior) {
case Dup_ErrorBehavior::ThrowException:
DUP_LOG::trace("throwing exception");
throw new Exception($msg);
break;
case Dup_ErrorBehavior::Quit:
DUP_LOG::trace("quitting");
die("DUPLICATOR ERROR: Please see the 'Package Log' file link below.");
break;
default:
// Nothing
}
}
/**
* The current stack trace of a PHP call
* @param $stacktrace The current debug stack
* @return string
*/
public static function getStack($stacktrace)
{
$output = "";
$i = 1;
foreach ($stacktrace as $node) {
$output .= "\t $i. ".basename($node['file'])." : ".$node['function']." (".$node['line'].")\n";
$i++;
}
return $output;
}
/**
* Manages writing the active or backup log based on the size setting
*
* @return null
*/
private static function WriteToTrace($formatted_logging_message)
{
$log_filepath = self::GetTraceFilepath();
if (@filesize($log_filepath) > DUPLICATOR_MAX_LOG_SIZE) {
$backup_log_filepath = self::GetBackupTraceFilepath();
if (file_exists($backup_log_filepath)) {
if (@unlink($backup_log_filepath) === false) {
self::errLog("Couldn't delete backup log $backup_log_filepath");
}
}
if (@rename($log_filepath, $backup_log_filepath) === false) {
self::errLog("Couldn't rename log $log_filepath to $backup_log_filepath");
}
}
if (@file_put_contents($log_filepath, $formatted_logging_message, FILE_APPEND) === false) {
// Not en error worth reporting
}
}
}
class DUP_Handler
{
const MODE_OFF = 0; // don't write in log
const MODE_LOG = 1; // write errors in log file
const MODE_VAR = 2; // put php errors in $varModeLog static var
const SHUTDOWN_TIMEOUT = 'tm';
/**
*
* @var bool
*/
private static $initialized = false;
/**
*
* @var array
*/
private static $shutdownReturns = array(
'tm' => 'timeout'
);
/**
*
* @var int
*/
private static $handlerMode = self::MODE_LOG;
/**
*
* @var bool // print code reference and errno at end of php error line [CODE:10|FILE:test.php|LINE:100]
*/
private static $codeReference = true;
/**
*
* @var bool // print prefix in php error line [PHP ERR][WARN] MSG: .....
*/
private static $errPrefix = true;
/**
*
* @var string // php errors in MODE_VAR
*/
private static $varModeLog = '';
/**
* This function only initializes the error handler the first time it is called
*/
public static function init_error_handler()
{
if (!self::$initialized) {
@set_error_handler(array(__CLASS__, 'error'));
@register_shutdown_function(array(__CLASS__, 'shutdown'));
self::$initialized = true;
}
}
/**
* Error handler
*
* @param integer $errno Error level
* @param string $errstr Error message
* @param string $errfile Error file
* @param integer $errline Error line
* @return void
*/
public static function error($errno, $errstr, $errfile, $errline)
{
switch (self::$handlerMode) {
case self::MODE_OFF:
if ($errno == E_ERROR) {
$log_message = self::getMessage($errno, $errstr, $errfile, $errline);
DUP_Log::error($log_message);
}
break;
case self::MODE_VAR:
self::$varModeLog .= self::getMessage($errno, $errstr, $errfile, $errline)."\n";
break;
case self::MODE_LOG:
default:
switch ($errno) {
case E_ERROR :
$log_message = self::getMessage($errno, $errstr, $errfile, $errline);
DUP_Log::error($log_message);
break;
case E_NOTICE :
case E_WARNING :
default :
$log_message = self::getMessage($errno, $errstr, $errfile, $errline);
DUP_Log::Info($log_message);
break;
}
}
}
private static function getMessage($errno, $errstr, $errfile, $errline)
{
$result = '';
if (self::$errPrefix) {
$result = '[PHP ERR]';
switch ($errno) {
case E_ERROR :
$result .= '[FATAL]';
break;
case E_WARNING :
$result .= '[WARN]';
break;
case E_NOTICE :
$result .= '[NOTICE]';
break;
default :
$result .= '[ISSUE]';
break;
}
$result .= ' MSG:';
}
$result .= $errstr;
if (self::$codeReference) {
$result .= ' [CODE:'.$errno.'|FILE:'.$errfile.'|LINE:'.$errline.']';
$result .= "\n".wp_debug_backtrace_summary();
}
return $result;
}
/**
* if setMode is called without params set as default
*
* @param int $mode
* @param bool $errPrefix // print prefix in php error line [PHP ERR][WARN] MSG: .....
* @param bool $codeReference // print code reference and errno at end of php error line [CODE:10|FILE:test.php|LINE:100]
*/
public static function setMode($mode = self::MODE_LOG, $errPrefix = true, $codeReference = true)
{
switch ($mode) {
case self::MODE_OFF:
case self::MODE_VAR:
self::$handlerMode = $mode;
break;
case self::MODE_LOG:
default:
self::$handlerMode = self::MODE_LOG;
}
self::$varModeLog = '';
self::$errPrefix = $errPrefix;
self::$codeReference = $codeReference;
}
/**
*
* @return string // return var log string in MODE_VAR
*/
public static function getVarLog()
{
return self::$varModeLog;
}
/**
*
* @return string // return var log string in MODE_VAR and clean var
*/
public static function getVarLogClean()
{
$result = self::$varModeLog;
self::$varModeLog = '';
return $result;
}
/**
*
* @param string $status // timeout
* @param string
*/
public static function setShutdownReturn($status, $str)
{
self::$shutdownReturns[$status] = $str;
}
/**
* Shutdown handler
*
* @return void
*/
public static function shutdown()
{
if (($error = error_get_last())) {
if (preg_match('/^Maximum execution time (?:.+) exceeded$/i', $error['message'])) {
echo self::$shutdownReturns[self::SHUTDOWN_TIMEOUT];
}
self::error($error['type'], $error['message'], $error['file'], $error['line']);
}
}
}
classes/utilities/class.u.shell.php 0000644 00000002452 15133606540 0013411 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
class DUP_Shell_U
{
/**
* Escape a string to be used as a shell argument with bypass support for Windows
*
* NOTES:
* Provides a way to support shell args on Windows OS and allows %,! on Windows command line
* Safe if input is know such as a defined constant and not from user input escape shellarg
* on Windows with turn %,! into spaces
*
* @return string
*/
public static function escapeshellargWindowsSupport($string)
{
if (strncasecmp(PHP_OS, 'WIN', 3) == 0) {
if (strstr($string, '%') || strstr($string, '!')) {
$result = '"'.str_replace('"', '', $string).'"';
return $result;
}
}
return escapeshellarg($string);
}
/**
*
* @return boolean
*
*/
public static function isPopenEnabled() {
if (!DUP_Util::isIniFunctionEnalbe('popen') || !DUP_Util::isIniFunctionEnalbe('proc_open')) {
$ret = false;
} else {
$ret = true;
}
$ret = apply_filters('duplicator_is_popen_enabled', $ret);
return $ret;
}
} classes/utilities/class.u.zip.php 0000644 00000013646 15133606540 0013113 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Utility class for zipping up content
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*/
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
class DUP_Zip_U
{
/**
* Add a directory to an existing ZipArchive object
*
* @param ZipArchive $zipArchive An existing ZipArchive object
* @param string $directoryPath The full directory path to add to the ZipArchive
* @param bool $retainDirectory Should the full directory path be retained in the archive
*
* @return bool Returns true if the directory was added to the object
*/
public static function addDirWithZipArchive(&$zipArchive, $directoryPath, $retainDirectory, $localPrefix, $isCompressed)
{
$success = TRUE;
$directoryPath = rtrim($directoryPath, '/\\').'/';
if (!$fp = @opendir($directoryPath)) {
return FALSE;
}
while (FALSE !== ($file = readdir($fp))) {
if ($file === '.' || $file === '..') continue;
$objectPath = $directoryPath . $file;
// Not used DUP_U::safePath(), because I would like to decrease max_nest_level
// Otherwise we will get the error:
// PHP Fatal error: Uncaught Error: Maximum function nesting level of '512' reached, aborting! in ...
// $objectPath = DUP_U::safePath($objectPath);
$objectPath = str_replace("\\", '/', $objectPath);
$localName = ltrim(str_replace($directoryPath, '', $objectPath), '/');
if ($retainDirectory) {
$localName = basename($directoryPath)."/$localName";
}
$localName = $localPrefix . $localName;
if (is_dir($objectPath)) {
$localPrefixArg = substr($localName, 0, strrpos($localName, '/')).'/';
$added = self::addDirWithZipArchive($zipArchive, $objectPath, $retainDirectory, $localPrefixArg, $isCompressed);
} else if (is_readable($objectPath)) {
$added = DUP_Zip_U::addFileToZipArchive($zipArchive, $objectPath, $localName, $isCompressed);
} else {
$added = FALSE;
}
if (!$added) {
DUP_Log::error("Couldn't add file $objectPath to archive", '', false);
$success = FALSE;
break;
}
}
@closedir($fp);
return $success;
}
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 = shell_exec($command);
if ($stderr != '') {
$errorMessage = DUP_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_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_Log::error("Cannot create zip archive {$zipFilePath}");
} else {
//ADD SQL
if ($newName == null) {
$source_filename = basename($sourceFilePath);
DUP_Log::Info("adding {$source_filename}");
} else {
$source_filename = $newName;
DUP_Log::Info("new name added {$newName}");
}
$in_zip = DUP_Zip_U::addFileToZipArchive($zip_archive, $sourceFilePath, $source_filename, $isCompressed);
if ($in_zip === false) {
DUP_Log::error("Unable to add {$sourceFilePath} to $zipFilePath");
}
$zip_archive->close();
return true;
}
} else {
DUP_Log::error("Trying to add {$sourceFilePath} to a zip but it doesn't exist!");
}
return false;
}
public static function addFileToZipArchive(&$zipArchive, $filepath, $localName, $isCompressed)
{
$added = $zipArchive->addFile($filepath, $localName);
return $added;
}
} classes/utilities/class.u.string.php 0000644 00000006011 15133606540 0013603 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Utility class working with strings
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package DUP
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
class DUP_STR
{
/**
* Append the value to the string if it doesn't already exist
*
* @param string $string The string to append to
* @param string $value The string to append to the $string
*
* @return string Returns the string with the $value appended once
*/
public static function appendOnce($string, $value)
{
return $string.(substr($string, -1) == $value ? '' : $value);
}
/**
* Returns true if the string contains UTF8 characters
* @see http://php.net/manual/en/function.mb-detect-encoding.php
*
* @param string $string The class name where the $destArray exists
*
* @return null
*/
public static function hasUTF8($string)
{
return preg_match('%(?:
[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|\xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
|\xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
|\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
|[\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
|\xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)+%xs', $string);
}
/**
* Returns true if the $needle is found in the $haystack
*
* @param string $haystack The full string to search in
* @param string $needle The string to for
*
* @return bool
*/
public static function contains($haystack, $needle)
{
$pos = strpos($haystack, $needle);
return ($pos !== false);
}
/**
* Returns true if the $haystack string starts with the $needle
*
* @param string $haystack The full string to search in
* @param string $needle The string to for
*
* @return bool Returns true if the $haystack string starts with the $needle
*/
public static function startsWith($haystack, $needle)
{
$length = strlen($needle);
return (substr($haystack, 0, $length) === $needle);
}
/**
* Returns true if the $haystack string ends with the $needle
*
* @param string $haystack The full string to search in
* @param string $needle The string to for
*
* @return bool Returns true if the $haystack string ends with the $needle
*/
public static function endsWith($haystack, $needle)
{
$length = strlen($needle);
if ($length == 0) {
return true;
}
return (substr($haystack, -$length) === $needle);
}
}
classes/utilities/class.u.multisite.php 0000644 00000001613 15133606540 0014317 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Methods used to work with WordPress MU sites
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package Duplicator
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
*
* @todo Refactor out IO methods into class.io.php file
*/
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
class DUP_MU
{
public static function isMultisite()
{
return self::getMode() > 0;
}
// 0 = single site; 1 = multisite subdomain; 2 = multisite subdirectory
public static function getMode()
{
if(is_multisite()) {
if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
return 1;
} else {
return 2;
}
} else {
return 0;
}
}
} classes/utilities/class.u.validator.php 0000644 00000013417 15133606540 0014272 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Validate variables
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package Duplicator
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
*
*/
// Exit if accessed directly
if (!defined('DUPLICATOR_VERSION')) {
exit;
}
class DUP_Validator
{
/**
* @var array $patterns
*/
private static $patterns = array(
'fdir' => '/^([a-zA-Z]:[\\\\\/]|\/|\\\\\\\\|\/\/)[^<>\0]+$/',
'ffile' => '/^([a-zA-Z]:[\\\\\/]|\/|\\\\\\\\|\/\/)[^<>\0]+$/',
'fext' => '/^\.?[^\\\\\/*:<>\0?"|\s\.]+$/',
'email' => '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_\`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/',
'empty' => '/^$/',
'nempty' => '/^.+$/',
);
const FILTER_VALIDATE_IS_EMPTY = 'empty';
const FILTER_VALIDATE_NOT_EMPTY = 'nempty';
const FILTER_VALIDATE_FILE = 'ffile';
const FILTER_VALIDATE_FOLDER = 'fdir';
const FILTER_VALIDATE_FILE_EXT = 'fext';
const FILTER_VALIDATE_EMAIL = 'email';
/**
* @var array $errors [ ['key' => string field key,
* 'msg' => error message ] , [] ]
*/
private $errors = array();
/**
*
*/
public function __construct()
{
$this->errors = array();
}
/**
*
*/
public function reset()
{
$this->errors = array();
}
/**
*
* @return bool
*/
public function isSuccess()
{
return empty($this->errors);
}
/**
*
* @return array
*/
public function getErrors()
{
return $this->errors;
}
/**
*
* @return array return errors messages
*/
public function getErrorsMsg()
{
$result = array();
foreach ($this->errors as $err) {
$result[] = $err['msg'];
}
return $result;
}
/**
*
* @param string $format printf format message where %s is the variable content default "%s\n"
* @param bool $echo if false return string
* @return void|string
*/
public function getErrorsFormat($format = "%s\n", $echo = true)
{
$msgs = $this->getErrorsMsg();
ob_start();
foreach ($msgs as $msg) {
printf($format, $msg);
}
if ($echo) {
ob_end_flush();
} else {
return ob_get_clean();
}
}
/**
*
* @param string $key
* @param string $msg
*/
protected function addError($key, $msg)
{
$this->errors[] = array(
'key' => $key,
'msg' => $msg
);
}
/**
* filter_var function wrapper see http://php.net/manual/en/function.filter-var.php
*
* additional options
* valkey => key of field
* errmsg => error message; % s will be replaced with the contents of the variable es. "<b>%s</b> isn't a valid field"
* acc_vals => array of accepted values that skip validation
*
* @param mixed $variable
* @param int $filter
* @param array $options
* @return mixed
*/
public function filter_var($variable, $filter = FILTER_DEFAULT, $options = array())
{
$success = true;
$result = null;
if (isset($options['acc_vals']) && in_array($variable, $options['acc_vals'])) {
return $variable;
}
if ($filter === FILTER_VALIDATE_BOOLEAN) {
$options['flags'] = FILTER_NULL_ON_FAILURE;
$result = filter_var($variable, $filter, $options);
if (is_null($result)) {
$success = false;
}
} else {
$result = filter_var($variable, $filter, $options);
if ($result === false) {
$success = false;
}
}
if (!$success) {
$key = isset($options['valkey']) ? $options['valkey'] : '';
if (isset($options['errmsg'])) {
$msg = sprintf($options['errmsg'], $variable);
} else {
$msg = sprintf('%1$s isn\'t a valid value', $variable);
}
$this->addError($key, $msg);
}
return $result;
}
/**
* validation of predefined regular expressions
*
* @param mixed $variable
* @param string $filter
* @param array $options
* @return type
* @throws Exception
*/
public function filter_custom($variable, $filter, $options = array())
{
if (!isset(self::$patterns[$filter])) {
throw new Exception('Filter not valid');
}
$options = array_merge($options, array(
'options' => array(
'regexp' => self::$patterns[$filter])
)
);
//$options['regexp'] = self::$patterns[$filter];
return $this->filter_var($variable, FILTER_VALIDATE_REGEXP, $options);
}
/**
* it explodes a string with a delimiter and validates every element of the array
*
* @param string $variable
* @param string $delimiter
* @param string $filter
* @param array $options
*/
public function explode_filter_custom($variable, $delimiter, $filter, $options = array())
{
if (empty($variable)) {
return array();
}
$vals = explode($delimiter, trim($variable, $delimiter));
$res = array();
foreach ($vals as $val) {
$res[] = $this->filter_custom($val, $filter, $options);
}
return $res;
}
} classes/utilities/class.u.json.php 0000644 00000011340 15133606540 0013247 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Utility class for working with JSON data
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*/
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
class DUP_JSON
{
protected static $_messages = array(
JSON_ERROR_NONE => 'No error has occurred',
JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded',
JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
JSON_ERROR_SYNTAX => 'Syntax error',
JSON_ERROR_UTF8 => 'Malformed UTF-8 characters. To resolve see https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=malformed_utf8#faq-package-170-q'
);
/**
* Used on PHP 5.3+ to better handle calling the json_encode method
*
* Returns a string containing the JSON representation of the supplied value
*
* @return string
*/
public static function customEncode($value, $iteration = 1)
{
if (DUP_Util::$on_php_53_plus) {
$encoded = DupLiteSnapJsonU::wp_json_encode_pprint($value);
switch (json_last_error()) {
case JSON_ERROR_NONE:
return $encoded;
case JSON_ERROR_DEPTH:
throw new RuntimeException('Maximum stack depth exceeded');
case JSON_ERROR_STATE_MISMATCH:
throw new RuntimeException('Underflow or the modes mismatch');
case JSON_ERROR_CTRL_CHAR:
throw new RuntimeException('Unexpected control character found');
case JSON_ERROR_SYNTAX:
throw new RuntimeException('Syntax error, malformed JSON');
case JSON_ERROR_UTF8:
if ($iteration == 1) {
$clean = self::makeUTF8($value);
return self::customEncode($clean, $iteration + 1);
} else {
throw new RuntimeException('UTF-8 error loop');
}
default:
throw new RuntimeException('Unknown error');
}
} else {
return self::oldCustomEncode($value);
}
}
public static function safeEncode($data, $options = 0, $depth = 512)
{
try {
$jsonString = DupLiteSnapJsonU::wp_json_encode($data, $options, $depth);
} catch (Exception $e) {
$jsonString = false;
}
if (($jsonString === false) || trim($jsonString) == '') {
$jsonString = self::customEncode($value);
if (($jsonString === false) || trim($jsonString) == '') {
throw new Exception('Unable to generate JSON from object');
}
}
return $jsonString;
}
/**
* Attempts to only call the json_decode method directly
*
* Returns the value encoded in json in appropriate PHP type. Values true, false and null are returned as TRUE, FALSE and NULL respectively.
* NULL is returned if the json cannot be decoded or if the encoded data is deeper than the recursion limit.
*
* @return object
*/
public static function decode($json, $assoc = false)
{
$result = json_decode($json, $assoc);
if ($result !== null) {
return $result;
}
if (function_exists('json_last_error')) {
throw new RuntimeException(self::$_messages[json_last_error()]);
} else {
throw new RuntimeException("DUP_JSON decode error");
}
}
private static function makeUTF8($mixed)
{
if (is_array($mixed)) {
foreach ($mixed as $key => $value) {
$mixed[$key] = self::makeUTF8($value);
}
} else if (is_string($mixed)) {
return utf8_encode($mixed);
}
return $mixed;
}
private static function escapeString($str)
{
return addcslashes($str, "\v\t\n\r\f\"\\/");
}
private static function oldCustomEncode($in)
{
$out = "";
if (is_object($in)) {
$arr[$key] = "\"".self::escapeString($key)."\":\"{$val}\"";
$in = get_object_vars($in);
}
if (is_array($in)) {
$obj = false;
$arr = array();
foreach ($in AS $key => $val) {
if (!is_numeric($key)) {
$obj = true;
}
$arr[$key] = self::oldCustomEncode($val);
}
if ($obj) {
foreach ($arr AS $key => $val) {
$arr[$key] = "\"".self::escapeString($key)."\":{$val}";
}
$val = implode(',', $arr);
$out .= "{{$val}}";
} else {
$val = implode(',', $arr);
$out .= "[{$val}]";
}
} elseif (is_bool($in)) {
$out .= $in ? 'true' : 'false';
} elseif (is_null($in)) {
$out .= 'null';
} elseif (is_string($in)) {
$out .= "\"".self::escapeString($in)."\"";
} else {
$out .= $in;
}
return "{$out}";
}
} classes/utilities/class.u.migration.php 0000644 00000011532 15133606540 0014272 0 ustar 00 <?php
/**
* Utility class managing th emigration data
*
* Standard: PSR_2
* @link http://www.php_fig.org/psr/psr_2
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL_3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
class DUP_Migration
{
const CLEAN_INSTALL_REPORT_OPTION = 'duplicator_clean_install_report';
const ARCHIVE_REGEX_PATTERN = '/^(.+_[a-z0-9]{7,}_[0-9]{14})_archive\.(?:zip|daf)$/';
/**
* messages to be displayed in the successful migration box
*
* @var array
*/
protected static $migrationCleanupReport = array(
'removed' => array(),
'stored' => array(),
'instFile' => array()
);
/**
* Check the root path and in case there are installer files without hashes rename them.
*
* @return void
*/
public static function renameInstallersPhpFiles()
{
$pathsTocheck = array(
DupLiteSnapLibIOU::safePathTrailingslashit(ABSPATH),
DupLiteSnapLibIOU::safePathTrailingslashit(DupLiteSnapLibUtilWp::getHomePath()),
DupLiteSnapLibIOU::safePathTrailingslashit(WP_CONTENT_DIR)
);
$pathsTocheck = array_unique($pathsTocheck);
$filesToCheck = array();
foreach ($pathsTocheck as $cFolder) {
if (
!is_dir($cFolder) ||
!is_writable($cFolder) // rename permissions
) {
continue;
}
$cFile = $cFolder . 'installer.php';
if (
!is_file($cFile) ||
!DupLiteSnapLibIOU::chmod($cFile, 'u+rw') ||
!is_readable($cFile)
) {
continue;
}
$filesToCheck[] = $cFile;
}
$installerTplCheck = '/class DUPX_Bootstrap.+const\s+ARCHIVE_FILENAME\s*=\s*[\'"](.+?)[\'"]\s*;.*const\s+PACKAGE_HASH\s*=\s*[\'"](.+?)[\'"];/s';
foreach ($filesToCheck as $file) {
$fileName = basename($file);
if (($content = @file_get_contents($file, false, null, 0, 5000)) === false) {
continue;
}
$matches = null;
if (preg_match($installerTplCheck, $content, $matches) !== 1) {
continue;
}
$archiveName = $matches[1];
$hash = $matches[2];
$matches = null;
if (preg_match(self::ARCHIVE_REGEX_PATTERN, $archiveName, $matches) !== 1) {
if (DupLiteSnapLibIOU::unlink($file)) {
self::$migrationCleanupReport['instFile'][] = "<div class='failure'>"
. "<i class='fa fa-check green'></i> "
. sprintf(__('Installer file <b>%s</b> removed for secority reasons', 'duplicator'), esc_html($fileName))
. "</div>";
} else {
self::$migrationCleanupReport['instFile'][] = "<div class='success'>"
. '<i class="fa fa-exclamation-triangle red"></i> '
. sprintf(__('Can\'t remove installer file <b>%s</b>, please remove it for security reasons', 'duplicator'), esc_html($fileName))
. '</div>';
}
continue;
}
$archiveHash = $matches[1];
if (strpos($file, $archiveHash) === false) {
if (DupLiteSnapLibIOU::rename($file, dirname($file) . '/' . $archiveHash . '_installer.php', true)) {
self::$migrationCleanupReport['instFile'][] = "<div class='failure'>"
. "<i class='fa fa-check green'></i> "
. sprintf(__('Installer file <b>%s</b> renamed with HASH', 'duplicator'), esc_html($fileName))
. "</div>";
} else {
self::$migrationCleanupReport['instFile'][] = "<div class='success'>"
. '<i class="fa fa-exclamation-triangle red"></i> '
. sprintf(__('Can\'t rename installer file <b>%s</b> with HASH, please remove it for security reasons', 'duplicator'), esc_html($fileName))
. '</div>';
}
}
}
}
/**
* return cleanup report
*
* @return array
*/
public static function getCleanupReport()
{
$option = get_option(self::CLEAN_INSTALL_REPORT_OPTION);
if (is_array($option)) {
self::$migrationCleanupReport = array_merge(self::$migrationCleanupReport, $option);
}
return self::$migrationCleanupReport;
}
/**
* save clean up report in wordpress options
*
* @return boolean
*/
public static function saveCleanupReport()
{
return add_option(self::CLEAN_INSTALL_REPORT_OPTION, self::$migrationCleanupReport, '', 'no');
}
}
classes/utilities/class.u.php 0000644 00000063456 15133606540 0012316 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Recursivly scans a directory and finds all sym-links and unreadable files
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package Duplicator
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
*
* @todo Refactor out IO methods into class.io.php file
*/
class DUP_Util
{
/**
* Is PHP 5.2.9 or better running
*/
public static $on_php_529_plus;
/**
* Is PHP 5.3 or better running
*/
public static $on_php_53_plus;
/**
* Is PHP 5.4 or better running
*/
public static $on_php_54_plus;
/**
* Is PHP 7 or better running
*/
public static $PHP7_plus;
/**
* array of ini disable functions
*
* @var array
*/
private static $iniDisableFuncs = null;
/**
* Initialized on load (see end of file)
*/
public static function init()
{
self::$on_php_529_plus = version_compare(PHP_VERSION, '5.2.9') >= 0;
self::$on_php_53_plus = version_compare(PHP_VERSION, '5.3.0') >= 0;
self::$on_php_54_plus = version_compare(PHP_VERSION, '5.4.0') >= 0;
self::$PHP7_plus = version_compare(PHP_VERSION, '7.0.0', '>=');
}
public static function getArchitectureString()
{
$php_int_size = PHP_INT_SIZE;
switch ($php_int_size) {
case 4:
return esc_html__('32-bit', 'duplicator');
break;
case 8:
return esc_html__('64-bit', 'duplicator');
break;
default:
return esc_html__('Unknown', 'duplicator');
}
}
public static function objectCopy($srcObject, $destObject, $skipMemberArray = null)
{
foreach ($srcObject as $member_name => $member_value) {
if (!is_object($member_value) && (($skipMemberArray == null) || !in_array($member_name, $skipMemberArray))) {
// Skipping all object members
$destObject->$member_name = $member_value;
}
}
}
public static function getWPCoreDirs()
{
$wp_core_dirs = array(get_home_path().'wp-admin', get_home_path().'wp-includes');
//if wp_content is overrided
$wp_path = get_home_path()."wp-content";
if (get_home_path().'wp-content' != WP_CONTENT_DIR) {
$wp_path = WP_CONTENT_DIR;
}
$wp_path = str_replace("\\", "/", $wp_path);
$wp_core_dirs[] = $wp_path;
$wp_core_dirs[] = $wp_path.'/plugins';
$wp_core_dirs[] = $wp_path.'/themes';
return $wp_core_dirs;
}
/**
* return absolute path for the files that are core directories
* @return string array
*/
public static function getWPCoreFiles()
{
$wp_cored_dirs = array(get_home_path().'wp-config.php');
return $wp_cored_dirs;
}
/**
* Groups an array into arrays by a given key, or set of keys, shared between all array members.
*
* Based on {@author Jake Zatecky}'s {@link https://github.com/jakezatecky/array_group_by array_group_by()} function.
* This variant allows $key to be closures.
*
* @param array $array The array to have grouping performed on.
* @param mixed $key,... The key to group or split by. Can be a _string_, an _integer_, a _float_, or a _callable_.
* - If the key is a callback, it must return a valid key from the array.
* - If the key is _NULL_, the iterated element is skipped.
* - string|oink callback ( mixed $item )
*
* @return array|null Returns a multidimensional array or `null` if `$key` is invalid.
*/
public static function array_group_by(array $array, $key)
{
if (!is_string($key) && !is_int($key) && !is_float($key) && !is_callable($key)) {
trigger_error('array_group_by(): The key should be a string, an integer, or a callback', E_USER_ERROR);
return null;
}
$func = (!is_string($key) && is_callable($key) ? $key : null);
$_key = $key;
// Load the new array, splitting by the target key
$grouped = array();
foreach ($array as $value) {
$key = null;
if (is_callable($func)) {
$key = call_user_func($func, $value);
} elseif (is_object($value) && isset($value->{$_key})) {
$key = $value->{$_key};
} elseif (isset($value[$_key])) {
$key = $value[$_key];
}
if ($key === null) {
continue;
}
$grouped[$key][] = $value;
}
// Recursively build a nested grouping if more parameters are supplied
// Each grouped array value is grouped according to the next sequential key
if (func_num_args() > 2) {
$args = func_get_args();
foreach ($grouped as $key => $value) {
$params = array_merge(array($value), array_slice($args, 2, func_num_args()));
$grouped[$key] = call_user_func_array('DUP_Util::array_group_by', $params);
}
}
return $grouped;
}
/**
* PHP_SAPI for FCGI requires a data flush of at least 256
* bytes every 40 seconds or else it forces a script halt
*
* @return string A series of 256 space characters
*/
public static function fcgiFlush()
{
echo(str_repeat(' ', 300));
@flush();
@ob_flush();
}
public static function isWpDebug()
{
return defined('WP_DEBUG') && WP_DEBUG;
}
/**
* Returns the last N lines of a file. Equivalent to tail command
*
* @param string $filepath The full path to the file to be tailed
* @param int $lines The number of lines to return with each tail call
*
* @return string The last N parts of the file
*/
public static function tailFile($filepath, $lines = 2)
{
// Open file
$f = @fopen($filepath, "rb");
if ($f === false)
return false;
// Sets buffer size
$buffer = 256;
// Jump to last character
fseek($f, -1, SEEK_END);
// Read it and adjust line number if necessary
// (Otherwise the result would be wrong if file doesn't end with a blank line)
if (fread($f, 1) != "\n")
$lines -= 1;
// Start reading
$output = '';
$chunk = '';
// While we would like more
while (ftell($f) > 0 && $lines >= 0) {
// Figure out how far back we should jump
$seek = min(ftell($f), $buffer);
// Do the jump (backwards, relative to where we are)
fseek($f, -$seek, SEEK_CUR);
// Read a chunk and prepend it to our output
$output = ($chunk = fread($f, $seek)).$output;
// Jump back to where we started reading
fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR);
// Decrease our line counter
$lines -= substr_count($chunk, "\n");
}
// While we have too many lines
// (Because of buffer size we might have read too many)
while ($lines++ < 0) {
// Find first newline and remove all text before that
$output = substr($output, strpos($output, "\n") + 1);
}
fclose($f);
return trim($output);
}
/**
* Display human readable byte sizes
*
* @param int $size The size in bytes
*
* @return string The size of bytes readable such as 100KB, 20MB, 1GB etc.
*/
public static function byteSize($size, $roundBy = 2)
{
try {
$units = array('B', 'KB', 'MB', 'GB', 'TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++) {
$size /= 1024;
}
return round($size, $roundBy).$units[$i];
}
catch (Exception $e) {
return "n/a";
}
}
/**
* Makes path safe for any OS
* Paths should ALWAYS READ be "/"
* uni: /home/path/file.txt
* win: D:/home/path/file.txt
*
* @param string $path The path to make safe
*
* @return string A path with all slashes facing "/"
*/
public static function safePath($path)
{
return str_replace("\\", "/", $path);
}
/**
* Get current microtime as a float. Method is used for simple profiling
*
* @see elapsedTime
*
* @return string A float in the form "msec sec", where sec is the number of seconds since the Unix epoch
*/
public static function getMicrotime()
{
return microtime(true);
}
/**
* Append the value to the string if it doesn't already exist
*
* @param string $string The string to append to
* @param string $value The string to append to the $string
*
* @return string Returns the string with the $value appended once
*/
public static function appendOnce($string, $value)
{
return $string.(substr($string, -1) == $value ? '' : $value);
}
/**
* Return a string with the elapsed time
*
* @see getMicrotime()
*
* @param mixed number $end The final time in the sequence to measure
* @param mixed number $start The start time in the sequence to measure
*
* @return string The time elapsed from $start to $end
*/
public static function elapsedTime($end, $start)
{
return sprintf("%.2f sec.", abs($end - $start));
}
/**
* List all of the files of a path
*
* @param string $path The full path to a system directory
*
* @return array of all files in that path
*
* Notes:
* - Avoid using glob() as GLOB_BRACE is not an option on some operating systems
* - Pre PHP 5.3 DirectoryIterator will crash on unreadable files
* - Scandir will not crash on unreadable items, but will not return results
*/
public static function listFiles($path = '.')
{
try {
$files = array();
if ($dh = opendir($path)) {
while (($file = readdir($dh)) !== false) {
if ($file == '.' || $file == '..')
continue;
$full_file_path = trailingslashit($path).$file;
$files[] = str_replace("\\", '/', $full_file_path);
}
@closedir($dh);
}
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;
}
}
/**
* List all of the directories of a path
*
* @param string $path The full path to a system directory
*
* @return array of all dirs in the $path
*/
public static function listDirs($path = '.')
{
$dirs = array();
foreach (new DirectoryIterator($path) as $file) {
if ($file->isDir() && !$file->isDot()) {
$dirs[] = DUP_Util::safePath($file->getPathname());
}
}
return $dirs;
}
/**
* Does the directory have content
*
* @param string $path The full path to a system directory
*
* @return bool Returns true if directory is empty
*/
public static function isDirectoryEmpty($path)
{
if (!is_readable($path))
return NULL;
return (count(scandir($path)) == 2);
}
/**
* Size of the directory recursively in bytes
*
* @param string $path The full path to a system directory
*
* @return int Returns the size of the directory in bytes
*
*/
public static function getDirectorySize($path)
{
if (!file_exists($path))
return 0;
if (is_file($path))
return filesize($path);
$size = 0;
$list = glob($path."/*");
if (!empty($list)) {
foreach ($list as $file)
$size += self::getDirectorySize($file);
}
return $size;
}
/**
* Can shell_exec be called on this server
*
* @return bool Returns true if shell_exec can be called on server
*
*/
public static function hasShellExec()
{
$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')))))
return apply_filters('duplicator_is_shellzip_available', false);
//Suhosin: http://www.hardened-php.net/suhosin/
//Will cause PHP to silently fail
if (extension_loaded('suhosin')) {
$suhosin_ini = @ini_get("suhosin.executor.func.blacklist");
if (array_intersect($cmds, array_map('trim', explode(',', $suhosin_ini))))
return apply_filters('duplicator_is_shellzip_available', false);
}
if (! function_exists('shell_exec')) {
return apply_filters('duplicator_is_shellzip_available', false);
}
// Can we issue a simple echo command?
if (!@shell_exec('echo duplicator'))
return apply_filters('duplicator_is_shellzip_available', false);
return apply_filters('duplicator_is_shellzip_available', true);
}
/**
* Is the server running Windows operating system
*
* @return bool Returns true if operating system is Windows
*
*/
public static function isWindows()
{
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
return true;
}
return false;
}
/**
* Wrap to prevent malware scanners from reporting false/positive
* Switched from our old method to avoid WordFence reporting a false positive
*
* @param string $string The string to decrypt i.e. base64_decode
*
* @return string Returns the string base64 decoded
*/
public static function installerUnscramble($string)
{
return base64_decode($string);
}
/**
* Wrap to prevent malware scanners from reporting false/positive
* Switched from our old method to avoid WordFence reporting a false positive
*
* @param string $string The string to decrypt i.e. base64_encode
*
* @return string Returns the string base64 encode
*/
public static function installerScramble($string)
{
return base64_encode($string);
}
const SECURE_ISSUE_DIE = 'die';
const SECURE_ISSUE_THROW = 'throw';
const SECURE_ISSUE_RETURN = 'return';
/**
* Does the current user have the capability
*
* @param type $permission
* @param type $exit // SECURE_ISSUE_DIE die script with die function
* SECURE_ISSUE_THROW throw an exception if fail
* SECURE_ISSUE_RETURN return false if fail
*
* @return boolean // return false is fail and $exit is SECURE_ISSUE_THROW
* // true if success
*
* @throws Exception // thow exception if $exit is SECURE_ISSUE_THROW
*/
public static function hasCapability($permission = 'read', $exit = self::SECURE_ISSUE_DIE)
{
$capability = apply_filters('wpfront_user_role_editor_duplicator_translate_capability', $permission);
if (!current_user_can($capability)) {
$exitMsg = __('You do not have sufficient permissions to access this page.', 'duplicator');
DUP_LOG::Trace('You do not have sufficient permissions to access this page. PERMISSION: '.$permission);
switch ($exit) {
case self::SECURE_ISSUE_THROW:
throw new Exception($exitMsg);
case self::SECURE_ISSUE_RETURN:
return false;
case self::SECURE_ISSUE_DIE:
default:
wp_die($exitMsg);
}
}
return true;
}
/**
* Gets the name of the owner of the current PHP script
*
* @return string The name of the owner of the current PHP script
*/
public static function getCurrentUser()
{
$unreadable = 'Undetectable';
if (function_exists('get_current_user') && is_callable('get_current_user')) {
$user = get_current_user();
return strlen($user) ? $user : $unreadable;
}
return $unreadable;
}
/**
* Gets the owner of the PHP process
*
* @return string Gets the owner of the PHP process
*/
public static function getProcessOwner()
{
$unreadable = 'Undetectable';
$user = '';
try {
if (function_exists('exec')) {
$user = @exec('whoami');
}
if (!strlen($user) && function_exists('posix_getpwuid') && function_exists('posix_geteuid')) {
$user = posix_getpwuid(posix_geteuid());
$user = $user['name'];
}
return strlen($user) ? $user : $unreadable;
}
catch (Exception $ex) {
return $unreadable;
}
}
/**
* Creates the snapshot directory if it doesn't already exist
*
* @return bool
*/
public static function initSnapshotDirectory()
{
$error = false;
$path_wproot = duplicator_get_abs_path();
$path_ssdir = DUP_Settings::getSsdirPath();
$path_plugin = DUP_Util::safePath(DUPLICATOR_PLUGIN_PATH);
if (!file_exists($path_ssdir)) {
$old_root_perm = @fileperms($path_wproot);
//--------------------------------
//CHMOD DIRECTORY ACCESS
//wordpress root directory
DupLiteSnapLibIOU::chmod($path_wproot, 'u+rwx');
//snapshot directory
if (DupLiteSnapLibIOU::dirWriteCheckOrMkdir($path_ssdir, 'u+rwx,go+rx') == false) {
$error = true;
}
// restore original root perms
DupLiteSnapLibIOU::chmod($path_wproot, $old_root_perm);
if ($error) {
return false;
}
}
DupLiteSnapLibIOU::chmod($path_ssdir, 'u+rwx,go+rx');
DupLiteSnapLibIOU::dirWriteCheckOrMkdir(DUP_Settings::getSsdirTmpPath(), 'u+rwx');
//plugins dir/files
DupLiteSnapLibIOU::dirWriteCheckOrMkdir($path_plugin.'files', 'u+rwx');
//--------------------------------
//FILE CREATION
//SSDIR: Create Index File
$fileName = $path_ssdir.'/index.php';
if (!file_exists($fileName)) {
$ssfile = @fopen($fileName, 'w');
@fwrite($ssfile,
'<?php error_reporting(0); if (stristr(php_sapi_name(), "fcgi")) { $url = "http://" . $_SERVER["HTTP_HOST"]; header("Location: {$url}/404.html");} else { header("HTTP/1.1 404 Not Found", true, 404);} exit(); ?>');
@fclose($ssfile);
}
//SSDIR: Create .htaccess
$storage_htaccess_off = DUP_Settings::Get('storage_htaccess_off');
$fileName = $path_ssdir.'/.htaccess';
if ($storage_htaccess_off) {
@unlink($fileName);
} else if (!file_exists($fileName)) {
$htfile = @fopen($fileName, 'w');
$htoutput = "Options -Indexes";
@fwrite($htfile, $htoutput);
@fclose($htfile);
}
//SSDIR: Robots.txt file
$fileName = $path_ssdir.'/robots.txt';
if (!file_exists($fileName)) {
$robotfile = @fopen($fileName, 'w');
@fwrite($robotfile,
"User-agent: * \n"
."Disallow: /".DUP_Settings::SSDIR_NAME_LEGACY."/\n"
."Disallow: /".DUP_Settings::SSDIR_NAME_NEW."/");
@fclose($robotfile);
}
return true;
}
/**
* Attempts to get the file zip path on a users system
*
* @return null
*/
public static function getZipPath()
{
$filepath = null;
if (self::hasShellExec()) {
if (shell_exec('hash zip 2>&1') == NULL) {
$filepath = 'zip';
} else {
$possible_paths = array(
'/usr/bin/zip',
'/opt/local/bin/zip'
//'C:/Program\ Files\ (x86)/GnuWin32/bin/zip.exe');
);
foreach ($possible_paths as $path) {
if (@file_exists($path)) {
$filepath = $path;
break;
}
}
}
}
return $filepath;
}
/**
* Is the server PHP 5.3 or better
*
* @return bool Returns true if the server PHP 5.3 or better
*/
public static function PHP53()
{
return version_compare(PHP_VERSION, '5.3.2', '>=');
}
/**
* Returns an array of the WordPress core tables.
*
* @return array Returns all WP core tables
*/
public static function getWPCoreTables()
{
global $wpdb;
$result = array();
foreach (self::getWPCoreTablesEnd() as $tend) {
$result[] = $wpdb->prefix.$tend;
}
return $result;
}
public static function getWPCoreTablesEnd()
{
return array(
'commentmeta',
'comments',
'links',
'options',
'postmeta',
'posts',
'term_relationships',
'term_taxonomy',
'termmeta',
'terms',
'usermeta',
'blogs',
'blog_versions',
'blogmeta',
'users',
'site',
'sitemeta',
'signups',
'registration_log',
'blog_versions');
}
public static function isWPCoreTable($table)
{
global $wpdb;
if (strpos($table, $wpdb->prefix) !== 0) {
return false;
}
$subTName = substr($table, strlen($wpdb->prefix));
$coreEnds = self::getWPCoreTablesEnd();
if (in_array($subTName, $coreEnds)) {
return true;
} else if (is_multisite()) {
$exTable = explode('_', $subTName);
if (count($exTable) >= 2 && is_numeric($exTable[0])) {
$tChekc = implode('_', array_slice($exTable, 1));
if (get_blog_details((int) $exTable[0], false) !== false && in_array($tChekc, $coreEnds)) {
return true;
}
}
}
return false;
}
public static function getWPBlogIdTable($table)
{
global $wpdb;
if (!is_multisite() || strpos($table, $wpdb->prefix) !== 0) {
return 0;
}
$subTName = substr($table, strlen($wpdb->prefix));
$exTable = explode('_', $subTName);
if (count($exTable) >= 2 && is_numeric($exTable[0]) && get_blog_details((int) $exTable[0], false) !== false) {
return (int) $exTable[0];
} else {
return 0;
}
}
/**
* Check given table is exist in real
*
* @param $table string Table name
* @return booleam
*/
public static function isTableExists($table)
{
// It will clear the $GLOBALS['wpdb']->last_error var
$GLOBALS['wpdb']->flush();
$sql = "SELECT 1 FROM `".esc_sql($table)."` LIMIT 1;";
$ret = $GLOBALS['wpdb']->get_var($sql);
if (empty($GLOBALS['wpdb']->last_error))
return true;
return false;
}
/**
* Finds if its a valid executable or not
*
* @param type $exe A non zero length executable path to find if that is executable or not.
* @param type $expectedValue expected value for the result
* @return boolean
*/
public static function isExecutable($cmd)
{
if (strlen($cmd) < 1)
return false;
if (@is_executable($cmd)) {
return true;
}
$output = shell_exec($cmd);
if (!is_null($output)) {
return true;
}
$output = shell_exec($cmd.' -?');
if (!is_null($output)) {
return true;
}
return false;
}
/**
* Display human readable byte sizes
*
* @param string $size The size in bytes
*
* @return string Human readable bytes such as 50MB, 1GB
*/
public static function readableByteSize($size)
{
try {
$units = array('B', 'KB', 'MB', 'GB', 'TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++)
$size /= 1024;
return round($size, 2).$units[$i];
}
catch (Exception $e) {
return "n/a";
}
}
public static function getTablePrefix()
{
global $wpdb;
$tablePrefix = (is_multisite() && is_plugin_active_for_network('duplicator/duplicator.php')) ? $wpdb->base_prefix : $wpdb->prefix;
return $tablePrefix;
}
/**
* return ini disable functions array
*
* @return array
*/
public static function getIniDisableFuncs()
{
if (is_null(self::$iniDisableFuncs)) {
$tmpFuncs = ini_get('disable_functions');
$tmpFuncs = explode(',', $tmpFuncs);
self::$iniDisableFuncs = array();
foreach ($tmpFuncs as $cFunc) {
self::$iniDisableFuncs[] = trim($cFunc);
}
}
return self::$iniDisableFuncs;
}
/**
* Check if function exists and isn't in ini disable_functions
*
* @param string $function_name
* @return bool
*/
public static function isIniFunctionEnalbe($function_name)
{
return function_exists($function_name) && !in_array($function_name, self::getIniDisableFuncs());
}
} classes/utilities/class.u.scancheck.php 0000644 00000012073 15133606540 0014224 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/**
* Recursivly scans a directory and finds all sym-links and unreadable files
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package Duplicator
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
*
*/
// Exit if accessed directly
if (! defined('DUPLICATOR_VERSION')) exit;
class DUP_ScanCheck
{
/**
* The number of files scanned
*/
public $fileCount = 0;
/**
* The number of directories scanned
*/
public $dirCount = 0;
/**
* The maximum count of files before the recursive function stops
*/
public $maxFiles = 1000000;
/**
* The maximum count of directories before the recursive function stops
*/
public $maxDirs = 75000;
/**
* Recursivly scan the root directory provided
*/
public $recursion = true;
/**
* Stores a list of symbolic link files
*/
public $symLinks = array();
/**
* Stores a list of files unreadable by PHP
*/
public $unreadable = array();
/**
* Stores a list of dirs with utf8 settings
*/
public $nameTestDirs = array();
/**
* Stores a list of files with utf8 settings
*/
public $nameTestFiles = array();
/**
* If the maxFiles or maxDirs limit is reached then true
*/
protected $limitReached = false;
/**
* Is the server running on Windows
*/
private $isWindows = false;
/**
* Init this instance of the object
*/
function __construct()
{
$this->isWindows = defined('PHP_WINDOWS_VERSION_BUILD');
}
/**
* Start the scan process
*
* @param string $dir A valid directory path where the scan will run
* @param array $results Used for recursion, do not pass in value with calling
*
* @return obj The scan check object with the results of the scan
*/
public function run($dir, &$results = array())
{
//Stop Recursion if Max search is reached
if ($this->fileCount > $this->maxFiles || $this->dirCount > $this->maxDirs) {
$this->limitReached = true;
return $results;
}
$files = @scandir($dir);
if (is_array($files)) {
foreach ($files as $key => $value) {
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if ($path) {
//Files
if (!is_dir($path)) {
if (!is_readable($path)) {
$results[] = $path;
$this->unreadable[] = $path;
} else if ($this->isLink($path)) {
$results[] = $path;
$this->symLinks[] = $path;
} else {
$name = basename($path);
$invalid_test = preg_match('/(\/|\*|\?|\>|\<|\:|\\|\|)/', $name)
|| trim($name) == ''
|| (strrpos($name, '.') == strlen($name) - 1 && substr($name, -1) == '.')
|| preg_match('/[^\x20-\x7f]/', $name);
if ($invalid_test) {
if (! DUP_Util::$PHP7_plus && DUP_Util::isWindows()) {
$this->nameTestFiles[] = utf8_decode($path);
} else {
$this->nameTestFiles[] = $path;
}
}
}
$this->fileCount++;
}
//Dirs
else if ($value != "." && $value != "..") {
if (!$this->isLink($path) && $this->recursion) {
$this->Run($path, $results);
}
if (!is_readable($path)) {
$results[] = $path;
$this->unreadable[] = $path;
} else if ($this->isLink($path)) {
$results[] = $path;
$this->symLinks[] = $path;
} else {
$invalid_test = strlen($path) > 244
|| trim($path) == ''
|| preg_match('/[^\x20-\x7f]/', $path);
if ($invalid_test) {
if (! DUP_Util::$PHP7_plus && DUP_Util::isWindows()) {
$this->nameTestDirs[] = utf8_decode($path);
} else {
$this->nameTestDirs[] = $path;
}
}
}
$this->dirCount++;
}
}
}
}
return $this;
}
/**
* Separation logic for supporting how different operating systems work
*
* @param string $target A valid file path
*
* @return bool Is the target a sym link
*/
private function isLink($target)
{
//Currently Windows does not support sym-link detection
if ($this->isWindows) {
return false;
} elseif (is_link($target)) {
return true;
}
return false;
}
} classes/class.server.php 0000644 00000033424 15133606540 0011335 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
require_once (DUPLICATOR_PLUGIN_PATH.'classes/utilities/class.u.php');
/**
* Used to get various pieces of information about the server environment
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package Duplicator
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
*
*/
class DUP_Server
{
const LockFileName = 'lockfile.txt';
// Possibly use in the future if we want to prevent double building
public static function isEngineLocked()
{
if (self::setEngineLock(true)) {
self::setEngineLock(false);
$locked = false;
} else {
$locked = true;
}
}
// Possibly use in the future if we want to prevent double building
public static function setEngineLock($shouldLock)
{
$success = false;
$locking_file = @fopen(self::LockFileName, 'c+');
if ($locking_file != false) {
if ($shouldLock) {
$success = @flock($locking_file, LOCK_EX | LOCK_NB);
} else {
$success = @flock($locking_file, LOCK_UN);
}
@fclose($locking_file);
}
return $success;
}
public static function mysqlEscapeIsOk()
{
$escape_test_string = chr(0).chr(26)."\r\n'\"\\";
$escape_expected_result = "\"\\0\Z\\r\\n\\'\\\"\\\\\"";
$escape_actual_result = DUP_DB::escValueToQueryString($escape_test_string);
$result = $escape_expected_result === $escape_actual_result;
if (!$result) {
$msg = "mysqli_real_escape_string test results\n".
"Expected escape result: ".$escape_expected_result."\n".
"Actual escape result: ".$escape_actual_result;
DUP_Log::trace($msg);
}
return $result;
}
/**
* Gets the system requirements which must pass to build a package
*
* @return array An array of requirements
*/
public static function getRequirements()
{
$dup_tests = array();
//PHP SUPPORT
$safe_ini = strtolower(ini_get('safe_mode'));
$dup_tests['PHP']['SAFE_MODE'] = $safe_ini != 'on' || $safe_ini != 'yes' || $safe_ini != 'true' || ini_get("safe_mode") != 1 ? 'Pass' : 'Fail';
self::logRequirementFail($dup_tests['PHP']['SAFE_MODE'], 'SAFE_MODE is on.');
$dup_tests['PHP']['VERSION'] = DUP_Util::$on_php_529_plus ? 'Pass' : 'Fail';
$phpversion = phpversion();
self::logRequirementFail($dup_tests['PHP']['VERSION'], 'PHP version('.$phpversion.') is lower than 5.2.9');
if (DUP_Settings::Get('archive_build_mode') == DUP_Archive_Build_Mode::ZipArchive) {
$dup_tests['PHP']['ZIP'] = class_exists('ZipArchive') ? 'Pass' : 'Fail';
self::logRequirementFail($dup_tests['PHP']['ZIP'], 'ZipArchive class doesn\'t exist.');
}
$dup_tests['PHP']['FUNC_1'] = function_exists("file_get_contents") ? 'Pass' : 'Fail';
self::logRequirementFail($dup_tests['PHP']['FUNC_1'], 'file_get_contents function doesn\'t exist.');
$dup_tests['PHP']['FUNC_2'] = function_exists("file_put_contents") ? 'Pass' : 'Fail';
self::logRequirementFail($dup_tests['PHP']['FUNC_2'], 'file_put_contents function doesn\'t exist.');
$dup_tests['PHP']['FUNC_3'] = function_exists("mb_strlen") ? 'Pass' : 'Fail';
self::logRequirementFail($dup_tests['PHP']['FUNC_3'], 'mb_strlen function doesn\'t exist.');
$dup_tests['PHP']['ALL'] = !in_array('Fail', $dup_tests['PHP']) ? 'Pass' : 'Fail';
//REQUIRED PATHS
$abs_path = duplicator_get_abs_path();
$handle_test = @opendir($abs_path);
$dup_tests['IO']['WPROOT'] = is_writeable($abs_path) && $handle_test ? 'Pass' : 'Warn';
@closedir($handle_test);
self::logRequirementFail($dup_tests['IO']['WPROOT'], $abs_path.' (abs path) can\'t be opened.');
$dup_tests['IO']['SSDIR'] = is_writeable(DUP_Settings::getSsdirPath()) ? 'Pass' : 'Fail';
self::logRequirementFail($dup_tests['IO']['SSDIR'], DUP_Settings::getSsdirPath().' (DUPLICATOR_SSDIR_PATH) can\'t be writeable.');
$dup_tests['IO']['SSTMP'] = is_writeable(DUP_Settings::getSsdirTmpPath()) ? 'Pass' : 'Fail';
self::logRequirementFail($dup_tests['IO']['SSTMP'], DUP_Settings::getSsdirTmpPath().' (DUPLICATOR_SSDIR_PATH_TMP) can\'t be writeable.');
$dup_tests['IO']['ALL'] = !in_array('Fail', $dup_tests['IO']) ? 'Pass' : 'Fail';
//SERVER SUPPORT
$dup_tests['SRV']['MYSQLi'] = function_exists('mysqli_connect') ? 'Pass' : 'Fail';
self::logRequirementFail($dup_tests['SRV']['MYSQLi'], 'mysqli_connect function doesn\'t exist.');
//mysqli_real_escape_string test
$dup_tests['SRV']['MYSQL_ESC'] = self::mysqlEscapeIsOk() ? 'Pass' : 'Fail';
self::logRequirementFail($dup_tests['SRV']['MYSQL_ESC'], "The function mysqli_real_escape_string is not escaping strings as expected.");
$db_version = DUP_DB::getVersion();
$dup_tests['SRV']['MYSQL_VER'] = version_compare($db_version, '5.0', '>=') ? 'Pass' : 'Fail';
self::logRequirementFail($dup_tests['SRV']['MYSQL_VER'], 'MySQL version '.$db_version.' is lower than 5.0.');
$dup_tests['SRV']['ALL'] = !in_array('Fail', $dup_tests['SRV']) ? 'Pass' : 'Fail';
//RESERVED FILES
$dup_tests['RES']['INSTALL'] = !(self::hasInstallerFiles()) ? 'Pass' : 'Fail';
self::logRequirementFail($dup_tests['RES']['INSTALL'], 'Installer file(s) are exist on the server.');
$dup_tests['Success'] = $dup_tests['PHP']['ALL'] == 'Pass' && $dup_tests['IO']['ALL'] == 'Pass' && $dup_tests['SRV']['ALL'] == 'Pass' && $dup_tests['RES']['INSTALL'] == 'Pass';
$dup_tests['Warning'] = $dup_tests['IO']['WPROOT'] == 'Warn';
return $dup_tests;
}
/**
* Logs requirement fail status informative message
*
* @param string $testStatus Either it is Pass or Fail
* @param string $errorMessage Error message which should be logged
* @return void
*/
private static function logRequirementFail($testStatus, $errorMessage)
{
if (empty($testStatus)) {
throw new Exception('Exception: Empty $testStatus [File: '.__FILE__.', Ln: '.__LINE__);
}
if (empty($errorMessage)) {
throw new Exception('Exception: Empty $errorMessage [File: '.__FILE__.', Ln: '.__LINE__);
}
$validTestStatuses = array('Pass', 'Fail', 'Warn');
if (!in_array($testStatus, $validTestStatuses)) {
throw new Exception('Exception: Invalid $testStatus value: '.$testStatus.' [File: '.__FILE__.', Ln: '.__LINE__);
}
if ('Fail' == $testStatus) {
DUP_LOG::trace($errorMessage);
}
}
/**
* Gets the system checks which are not required
*
* @return array An array of system checks
*/
public static function getChecks()
{
$checks = array();
//PHP/SYSTEM SETTINGS
//Web Server
$php_test0 = false;
foreach ($GLOBALS['DUPLICATOR_SERVER_LIST'] as $value) {
if (stristr($_SERVER['SERVER_SOFTWARE'], $value)) {
$php_test0 = true;
break;
}
}
self::logCheckFalse($php_test0, 'Any out of server software ('.implode(', ', $GLOBALS['DUPLICATOR_SERVER_LIST']).') doesn\'t exist.');
$php_test1 = ini_get("open_basedir");
$php_test1 = empty($php_test1) ? true : false;
self::logCheckFalse($php_test1, 'open_basedir is enabled.');
$max_execution_time = ini_get("max_execution_time");
$php_test2 = ($max_execution_time > DUPLICATOR_SCAN_TIMEOUT) || (strcmp($max_execution_time, 'Off') == 0 || $max_execution_time == 0) ? true : false;
if (strcmp($max_execution_time, 'Off') == 0) {
$max_execution_time_error_message = '$max_execution_time should not be'.$max_execution_time;
} else {
$max_execution_time_error_message = '$max_execution_time ('.$max_execution_time.') should not be lower than the DUPLICATOR_SCAN_TIMEOUT'.DUPLICATOR_SCAN_TIMEOUT;
}
self::logCheckFalse($php_test2, $max_execution_time_error_message);
$php_test3 = function_exists('mysqli_connect');
self::logCheckFalse($php_test3, 'mysqli_connect function doesn\'t exist.');
$php_test4 = DUP_Util::$on_php_53_plus ? true : false;
self::logCheckFalse($php_test4, 'PHP Version is lower than 5.3.');
$checks['SRV']['PHP']['websrv'] = $php_test0;
$checks['SRV']['PHP']['openbase'] = $php_test1;
$checks['SRV']['PHP']['maxtime'] = $php_test2;
$checks['SRV']['PHP']['mysqli'] = $php_test3;
$checks['SRV']['PHP']['version'] = $php_test4;
//MANAGED HOST
$checks['SRV']['SYS']['managedHost'] = !DUP_Custom_Host_Manager::getInstance()->isManaged();
$checks['SRV']['SYS']['ALL'] = ($php_test0 && $php_test1 && $php_test2 && $php_test3 && $php_test4 && $checks['SRV']['SYS']['managedHost']) ? 'Good' : 'Warn';
//WORDPRESS SETTINGS
global $wp_version;
$wp_test1 = version_compare($wp_version, DUPLICATOR_SCAN_MIN_WP) >= 0 ? true : false;
self::logCheckFalse($wp_test1, 'WP version ('.$wp_version.') is lower than the DUPLICATOR_SCAN_MIN_WP ('.DUPLICATOR_SCAN_MIN_WP.').');
//Core Files
$files = array();
$proper_wp_config_file_path = duplicator_get_abs_path().'/wp-config.php';
$files['wp-config.php'] = file_exists($proper_wp_config_file_path);
self::logCheckFalse($files['wp-config.php'], 'The wp-config.php file doesn\'t exist on the '.$proper_wp_config_file_path);
/** searching wp-config in working word press is not worthy
* if this script is executing that means wp-config.php exists :)
* we need to know the core folders and files added by the user at this point
* retaining old logic as else for the case if its used some where else
*/
//Core dir and files logic
if (isset($_POST['file_notice']) && isset($_POST['dir_notice'])) {
//means if there are core directories excluded or core files excluded return false
if ((bool) $_POST['file_notice'] || (bool) $_POST['dir_notice'])
$wp_test2 = false;
else
$wp_test2 = true;
} else {
$wp_test2 = $files['wp-config.php'];
}
//Cache
/*
$Package = DUP_Package::getActive();
$cache_path = DUP_Util::safePath(WP_CONTENT_DIR) . '/cache';
$dirEmpty = DUP_Util::isDirectoryEmpty($cache_path);
$dirSize = DUP_Util::getDirectorySize($cache_path);
$cach_filtered = in_array($cache_path, explode(';', $Package->Archive->FilterDirs));
$wp_test3 = ($cach_filtered || $dirEmpty || $dirSize < DUPLICATOR_SCAN_CACHESIZE ) ? true : false;
*/
$wp_test3 = is_multisite();
self::logCheckFalse($wp_test3, 'WP is multi-site setup.');
$checks['SRV']['WP']['version'] = $wp_test1;
$checks['SRV']['WP']['core'] = $wp_test2;
$checks['SRV']['WP']['ismu'] = $wp_test3;
$checks['SRV']['WP']['ALL'] = $wp_test1 && $wp_test2 && !$wp_test3 ? 'Good' : 'Warn';
return $checks;
}
/**
* Logs checks false informative message
*
* @param boolean $check Either it is true or false
* @param string $errorMessage Error message which should be logged when check is false
* @return void
*/
private static function logCheckFalse($check, $errorMessage)
{
if (empty($errorMessage)) {
throw new Exception('Exception: Empty $errorMessage variable [File: '.__FILE__.', Ln: '.__LINE__);
}
if (filter_var($check, FILTER_VALIDATE_BOOLEAN) === false) {
DUP_LOG::trace($errorMessage);
}
}
/**
* Check to see if duplicator installer files are present
*
* @return bool True if any reserved files are found
*/
public static function hasInstallerFiles()
{
$files = self::getInstallerFiles();
foreach ($files as $file => $path) {
if (false !== strpos($path, '*')) {
$glob_files = glob($path);
if (!empty($glob_files)) {
return true;
}
} elseif (file_exists($path))
return true;
}
return false;
}
/**
* Gets a list of all the installer files by name and full path
*
* @remarks
* FILES: installer.php, installer-backup.php, dup-installer-bootlog__[HASH].txt
* DIRS: dup-installer
* DEV FILES: wp-config.orig
* Last set is for lazy developer cleanup files that a developer may have
* accidently left around lets be proactive for the user just in case.
*
* @return array [file_name, file_path]
*/
public static function getInstallerFiles()
{
// alphanumeric 7 time, then -(dash), then 8 digits
$abs_path = duplicator_get_abs_path();
$four_digit_glob_pattern = '[0-9][0-9][0-9][0-9]';
$retArr = array(
basename(DUPLICATOR_INSTALLER_DIRECTORY).' '.esc_html__('(directory)', 'duplicator') => DUPLICATOR_INSTALLER_DIRECTORY,
DUPLICATOR_INSTALL_PHP => $abs_path.'/'.DUPLICATOR_INSTALL_PHP,
'[HASH]'.'_'.DUPLICATOR_INSTALL_PHP => $abs_path.'/*_*'.$four_digit_glob_pattern.'_'.DUPLICATOR_INSTALL_PHP,
DUPLICATOR_INSTALL_BAK => $abs_path.'/'.DUPLICATOR_INSTALL_BAK,
'[HASH]'.'_'.DUPLICATOR_INSTALL_BAK => $abs_path.'/*_*'.$four_digit_glob_pattern.'_'.DUPLICATOR_INSTALL_BAK,
'[HASH]_archive.zip|daf' => $abs_path.'/*_*'.$four_digit_glob_pattern.'_archive.[zd][ia][pf]',
'dup-installer-bootlog__[HASH].txt' => $abs_path.'/dup-installer-bootlog__'.DUPLICATOR_INSTALLER_HASH_PATTERN.'.txt',
);
if (DUPLICATOR_INSTALL_SITE_OVERWRITE_ON) {
$retArr['dup-wp-config-arc__[HASH].txt'] = $abs_path.'/dup-wp-config-arc__'.DUPLICATOR_INSTALLER_HASH_PATTERN.'.txt';
}
return $retArr;
}
/**
* Get the IP of a client machine
*
* @return string IP of the client machine
*/
public static function getClientIP()
{
if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
return $_SERVER["HTTP_X_FORWARDED_FOR"];
} else if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
return $_SERVER["REMOTE_ADDR"];
} else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) {
return $_SERVER["HTTP_CLIENT_IP"];
}
return '';
}
/**
* Get PHP memory usage
*
* @return string Returns human readable memory usage.
*/
public static function getPHPMemory($peak = false)
{
if ($peak) {
$result = 'Unable to read PHP peak memory usage';
if (function_exists('memory_get_peak_usage')) {
$result = DUP_Util::byteSize(memory_get_peak_usage(true));
}
} else {
$result = 'Unable to read PHP memory usage';
if (function_exists('memory_get_usage')) {
$result = DUP_Util::byteSize(memory_get_usage(true));
}
}
return $result;
}
} lib/forceutf8/README.md 0000644 00000003555 15133606540 0010511 0 ustar 00 forceutf8
=========
PHP Class Encoding featuring popular \ForceUTF8\Encoding::toUTF8() function --formerly known as forceUTF8()-- that fixes mixed encoded strings.
Description
===========
If you apply the PHP function utf8_encode() to an already-UTF8 string it will return a garbled UTF8 string.
This class addresses this issue and provides a handy static function called \ForceUTF8\Encoding::toUTF8().
You don't need to know what the encoding of your strings is. It can be Latin1 (iso 8859-1), Windows-1252 or UTF8, or the string can have a mix of them. \ForceUTF8\Encoding::toUTF8() will convert everything to UTF8.
Sometimes you have to deal with services that are unreliable in terms of encoding, possibly mixing UTF8 and Latin1 in the same string.
Update:
I've included another function, \ForceUTF8\Encoding::fixUTF8(), which will fix the double (or multiple) encoded UTF8 string that looks garbled.
Usage:
======
use \ForceUTF8\Encoding;
$utf8_string = Encoding::toUTF8($utf8_or_latin1_or_mixed_string);
$latin1_string = Encoding::toLatin1($utf8_or_latin1_or_mixed_string);
also:
$utf8_string = Encoding::fixUTF8($garbled_utf8_string);
Examples:
use \ForceUTF8\Encoding;
echo Encoding::fixUTF8("Fédération Camerounaise de Football\n");
echo Encoding::fixUTF8("Fédération Camerounaise de Football\n");
echo Encoding::fixUTF8("Fédération Camerounaise de Football\n");
echo Encoding::fixUTF8("Fédération Camerounaise de Football\n");
will output:
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Install via composer:
=====================
Edit your composer.json file to include the following:
```json
{
"require": {
"neitanod/forceutf8": "dev-master"
}
}
```
lib/forceutf8/index.php 0000644 00000000016 15133606540 0011037 0 ustar 00 <?php
//silent lib/forceutf8/Encoding.php 0000644 00000026220 15133606540 0011463 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/*
Copyright (c) 2008 Sebastián Grignoli
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of copyright holders nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author "Sebastián Grignoli" <grignoli@gmail.com>
* @package Encoding
* @version 2.0
* @link https://github.com/neitanod/forceutf8
* @example https://github.com/neitanod/forceutf8
* @license Revised BSD
*/
//namespace ForceUTF8;
if (!class_exists('DUP_Encoding'))
{
class DUP_Encoding {
const ICONV_TRANSLIT = "TRANSLIT";
const ICONV_IGNORE = "IGNORE";
const WITHOUT_ICONV = "";
protected static $win1252ToUtf8 = array(
128 => "\xe2\x82\xac",
130 => "\xe2\x80\x9a",
131 => "\xc6\x92",
132 => "\xe2\x80\x9e",
133 => "\xe2\x80\xa6",
134 => "\xe2\x80\xa0",
135 => "\xe2\x80\xa1",
136 => "\xcb\x86",
137 => "\xe2\x80\xb0",
138 => "\xc5\xa0",
139 => "\xe2\x80\xb9",
140 => "\xc5\x92",
142 => "\xc5\xbd",
145 => "\xe2\x80\x98",
146 => "\xe2\x80\x99",
147 => "\xe2\x80\x9c",
148 => "\xe2\x80\x9d",
149 => "\xe2\x80\xa2",
150 => "\xe2\x80\x93",
151 => "\xe2\x80\x94",
152 => "\xcb\x9c",
153 => "\xe2\x84\xa2",
154 => "\xc5\xa1",
155 => "\xe2\x80\xba",
156 => "\xc5\x93",
158 => "\xc5\xbe",
159 => "\xc5\xb8"
);
protected static $brokenUtf8ToUtf8 = array(
"\xc2\x80" => "\xe2\x82\xac",
"\xc2\x82" => "\xe2\x80\x9a",
"\xc2\x83" => "\xc6\x92",
"\xc2\x84" => "\xe2\x80\x9e",
"\xc2\x85" => "\xe2\x80\xa6",
"\xc2\x86" => "\xe2\x80\xa0",
"\xc2\x87" => "\xe2\x80\xa1",
"\xc2\x88" => "\xcb\x86",
"\xc2\x89" => "\xe2\x80\xb0",
"\xc2\x8a" => "\xc5\xa0",
"\xc2\x8b" => "\xe2\x80\xb9",
"\xc2\x8c" => "\xc5\x92",
"\xc2\x8e" => "\xc5\xbd",
"\xc2\x91" => "\xe2\x80\x98",
"\xc2\x92" => "\xe2\x80\x99",
"\xc2\x93" => "\xe2\x80\x9c",
"\xc2\x94" => "\xe2\x80\x9d",
"\xc2\x95" => "\xe2\x80\xa2",
"\xc2\x96" => "\xe2\x80\x93",
"\xc2\x97" => "\xe2\x80\x94",
"\xc2\x98" => "\xcb\x9c",
"\xc2\x99" => "\xe2\x84\xa2",
"\xc2\x9a" => "\xc5\xa1",
"\xc2\x9b" => "\xe2\x80\xba",
"\xc2\x9c" => "\xc5\x93",
"\xc2\x9e" => "\xc5\xbe",
"\xc2\x9f" => "\xc5\xb8"
);
protected static $utf8ToWin1252 = array(
"\xe2\x82\xac" => "\x80",
"\xe2\x80\x9a" => "\x82",
"\xc6\x92" => "\x83",
"\xe2\x80\x9e" => "\x84",
"\xe2\x80\xa6" => "\x85",
"\xe2\x80\xa0" => "\x86",
"\xe2\x80\xa1" => "\x87",
"\xcb\x86" => "\x88",
"\xe2\x80\xb0" => "\x89",
"\xc5\xa0" => "\x8a",
"\xe2\x80\xb9" => "\x8b",
"\xc5\x92" => "\x8c",
"\xc5\xbd" => "\x8e",
"\xe2\x80\x98" => "\x91",
"\xe2\x80\x99" => "\x92",
"\xe2\x80\x9c" => "\x93",
"\xe2\x80\x9d" => "\x94",
"\xe2\x80\xa2" => "\x95",
"\xe2\x80\x93" => "\x96",
"\xe2\x80\x94" => "\x97",
"\xcb\x9c" => "\x98",
"\xe2\x84\xa2" => "\x99",
"\xc5\xa1" => "\x9a",
"\xe2\x80\xba" => "\x9b",
"\xc5\x93" => "\x9c",
"\xc5\xbe" => "\x9e",
"\xc5\xb8" => "\x9f"
);
static function toUTF8($text){
/**
* Function \ForceUTF8\Encoding::toUTF8
*
* This function leaves UTF8 characters alone, while converting almost all non-UTF8 to UTF8.
*
* It assumes that the encoding of the original string is either Windows-1252 or ISO 8859-1.
*
* It may fail to convert characters to UTF-8 if they fall into one of these scenarios:
*
* 1) when any of these characters: ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞß
* are followed by any of these: ("group B")
* ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶•¸¹º»¼½¾¿
* For example: %ABREPRESENT%C9%BB. «REPRESENTÉ»
* The "«" (%AB) character will be converted, but the "É" followed by "»" (%C9%BB)
* is also a valid unicode character, and will be left unchanged.
*
* 2) when any of these: àáâãäåæçèéêëìíîï are followed by TWO chars from group B,
* 3) when any of these: ðñòó are followed by THREE chars from group B.
*
* @name toUTF8
* @param string $text Any string.
* @return string The same string, UTF8 encoded
*
*/
if(is_array($text))
{
foreach($text as $k => $v)
{
$text[$k] = self::toUTF8($v);
}
return $text;
}
if(!is_string($text)) {
return $text;
}
$max = self::strlen($text);
$buf = "";
for($i = 0; $i < $max; $i++){
$c1 = $text[$i];
if($c1>="\xc0"){ //Should be converted to UTF8, if it's not UTF8 already
$c2 = $i+1 >= $max? "\x00" : $text[$i+1];
$c3 = $i+2 >= $max? "\x00" : $text[$i+2];
$c4 = $i+3 >= $max? "\x00" : $text[$i+3];
if($c1 >= "\xc0" & $c1 <= "\xdf"){ //looks like 2 bytes UTF8
if($c2 >= "\x80" && $c2 <= "\xbf"){ //yeah, almost sure it's UTF8 already
$buf .= $c1 . $c2;
$i++;
} else { //not valid UTF8. Convert it.
$cc1 = (chr(ord($c1) / 64) | "\xc0");
$cc2 = ($c1 & "\x3f") | "\x80";
$buf .= $cc1 . $cc2;
}
} elseif($c1 >= "\xe0" & $c1 <= "\xef"){ //looks like 3 bytes UTF8
if($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf"){ //yeah, almost sure it's UTF8 already
$buf .= $c1 . $c2 . $c3;
$i = $i + 2;
} else { //not valid UTF8. Convert it.
$cc1 = (chr(ord($c1) / 64) | "\xc0");
$cc2 = ($c1 & "\x3f") | "\x80";
$buf .= $cc1 . $cc2;
}
} elseif($c1 >= "\xf0" & $c1 <= "\xf7"){ //looks like 4 bytes UTF8
if($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf" && $c4 >= "\x80" && $c4 <= "\xbf"){ //yeah, almost sure it's UTF8 already
$buf .= $c1 . $c2 . $c3 . $c4;
$i = $i + 3;
} else { //not valid UTF8. Convert it.
$cc1 = (chr(ord($c1) / 64) | "\xc0");
$cc2 = ($c1 & "\x3f") | "\x80";
$buf .= $cc1 . $cc2;
}
} else { //doesn't look like UTF8, but should be converted
$cc1 = (chr(ord($c1) / 64) | "\xc0");
$cc2 = (($c1 & "\x3f") | "\x80");
$buf .= $cc1 . $cc2;
}
} elseif(($c1 & "\xc0") == "\x80"){ // needs conversion
if(isset(self::$win1252ToUtf8[ord($c1)])) { //found in Windows-1252 special cases
$buf .= self::$win1252ToUtf8[ord($c1)];
} else {
$cc1 = (chr(ord($c1) / 64) | "\xc0");
$cc2 = (($c1 & "\x3f") | "\x80");
$buf .= $cc1 . $cc2;
}
} else { // it doesn't need conversion
$buf .= $c1;
}
}
return $buf;
}
static function toWin1252($text, $option = self::WITHOUT_ICONV) {
if(is_array($text)) {
foreach($text as $k => $v) {
$text[$k] = self::toWin1252($v, $option);
}
return $text;
} else if(is_string($text)) {
return self::utf8_decode($text, $option);
} else {
return $text;
}
}
static function toISO8859($text) {
return self::toWin1252($text);
}
static function toLatin1($text) {
return self::toWin1252($text);
}
static function fixUTF8($text, $option = self::WITHOUT_ICONV){
if(is_array($text)) {
foreach($text as $k => $v) {
$text[$k] = self::fixUTF8($v, $option);
}
return $text;
}
$last = "";
while($last <> $text){
$last = $text;
$text = self::toUTF8(self::utf8_decode($text, $option));
}
$text = self::toUTF8(self::utf8_decode($text, $option));
return $text;
}
static function UTF8FixWin1252Chars($text){
// If you received an UTF-8 string that was converted from Windows-1252 as it was ISO8859-1
// (ignoring Windows-1252 chars from 80 to 9F) use this function to fix it.
// See: http://en.wikipedia.org/wiki/Windows-1252
return str_replace(array_keys(self::$brokenUtf8ToUtf8), array_values(self::$brokenUtf8ToUtf8), $text);
}
static function removeBOM($str=""){
if(substr($str, 0,3) == pack("CCC",0xef,0xbb,0xbf)) {
$str=substr($str, 3);
}
return $str;
}
protected static function strlen($text)
{
if((version_compare(PHP_VERSION, '7.2.0') >= 0)) {
return (function_exists('mb_strlen'))
? mb_strlen($text,'8bit')
: strlen($text);
} else {
return (function_exists('mb_strlen') && ((int) ini_get('mbstring.func_overload')) & 2)
? mb_strlen($text,'8bit')
: strlen($text);
}
}
public static function normalizeEncoding($encodingLabel)
{
$encoding = strtoupper($encodingLabel);
$encoding = preg_replace('/[^a-zA-Z0-9\s]/', '', $encoding);
$equivalences = array(
'ISO88591' => 'ISO-8859-1',
'ISO8859' => 'ISO-8859-1',
'ISO' => 'ISO-8859-1',
'LATIN1' => 'ISO-8859-1',
'LATIN' => 'ISO-8859-1',
'UTF8' => 'UTF-8',
'UTF' => 'UTF-8',
'WIN1252' => 'ISO-8859-1',
'WINDOWS1252' => 'ISO-8859-1'
);
if(empty($equivalences[$encoding])){
return 'UTF-8';
}
return $equivalences[$encoding];
}
public static function encode($encodingLabel, $text)
{
$encodingLabel = self::normalizeEncoding($encodingLabel);
if($encodingLabel == 'ISO-8859-1') return self::toLatin1($text);
return self::toUTF8($text);
}
protected static function utf8_decode($text, $option)
{
if ($option == self::WITHOUT_ICONV || !function_exists('iconv')) {
$o = utf8_decode(
str_replace(array_keys(self::$utf8ToWin1252), array_values(self::$utf8ToWin1252), self::toUTF8($text))
);
} else {
$o = iconv("UTF-8", "Windows-1252" . ($option == self::ICONV_TRANSLIT ? '//TRANSLIT' : ($option == self::ICONV_IGNORE ? '//IGNORE' : '')), $text);
}
return $o;
}
}
} lib/snaplib/class.snaplib.exceptions.php 0000644 00000000706 15133606540 0014375 0 ustar 00 <?php
/**
* Snap exceptions
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package DupLiteSnapLib
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLib_32BitSizeLimitException', false)) {
class DupLiteSnapLib_32BitSizeLimitException extends Exception
{
}
} lib/snaplib/class.snaplib.u.json.php 0000644 00000025520 15133606540 0013431 0 ustar 00 <?php
/**
* Snap JSON utils
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package SnapLib
* @copyright (c) 2019, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!interface_exists('JsonSerializable')) {
define('SNAP_WP_JSON_SERIALIZE_COMPATIBLE', true);
/**
* JsonSerializable interface.
*
* Compatibility shim for PHP <5.4
*
* @link https://secure.php.net/jsonserializable
*
* @since 4.4.0
*/
interface JsonSerializable
{
public function jsonSerialize();
}
}
if (!class_exists('DupLiteSnapJsonU', false)) {
class DupLiteSnapJsonU
{
/**
* Encode a variable into JSON, with some sanity checks.
*
* @since 4.1.0
*
* @param mixed $data Variable (usually an array or object) to encode as JSON.
* @param int $options Optional. Options to be passed to json_encode(). Default 0.
* @param int $depth Optional. Maximum depth to walk through $data. Must be
* greater than 0. Default 512.
* @return string|false The JSON encoded string, or false if it cannot be encoded.
*/
public static function wp_json_encode($data, $options = 0, $depth = 512)
{
if (function_exists('wp_json_encode')) {
return wp_json_encode($data, $options, $depth);
}
/*
* json_encode() has had extra params added over the years.
* $options was added in 5.3, and $depth in 5.5.
* We need to make sure we call it with the correct arguments.
*/
if (version_compare(PHP_VERSION, '5.5', '>=')) {
$args = array($data, $options, $depth);
} elseif (version_compare(PHP_VERSION, '5.3', '>=')) {
$args = array($data, $options);
} else {
$args = array($data);
}
// Prepare the data for JSON serialization.
$args[0] = self::_wp_json_prepare_data($data);
$json = @call_user_func_array('json_encode', $args);
// If json_encode() was successful, no need to do more sanity checking.
// ... unless we're in an old version of PHP, and json_encode() returned
// a string containing 'null'. Then we need to do more sanity checking.
if (false !== $json && ( version_compare(PHP_VERSION, '5.5', '>=') || false === strpos($json, 'null') )) {
return $json;
}
try {
$args[0] = self::_wp_json_sanity_check($data, $depth);
}
catch (Exception $e) {
return false;
}
return call_user_func_array('json_encode', $args);
}
/**
* wp_json_encode with pretty print if define exists
*
* @param mixed $data Variable (usually an array or object) to encode as JSON.
* @param int $options Optional. Options to be passed to json_encode(). Default 0.
* @param int $depth Optional. Maximum depth to walk through $data. Must be
* greater than 0. Default 512.
* @return string|false The JSON encoded string, or false if it cannot be encoded.
*/
public static function wp_json_encode_pprint($data, $options = 0, $depth = 512)
{
if (defined('JSON_PRETTY_PRINT')) {
return self::wp_json_encode($data, JSON_PRETTY_PRINT | $options, $depth);
} else {
return self::wp_json_encode($data, $options, $depth);
}
}
/**
* Prepares response data to be serialized to JSON.
*
* This supports the JsonSerializable interface for PHP 5.2-5.3 as well.
*
* @ignore
* @since 4.4.0
* @access private
*
* @param mixed $data Native representation.
* @return bool|int|float|null|string|array Data ready for `json_encode()`.
*/
private static function _wp_json_prepare_data($data)
{
if (!defined('SNAP_WP_JSON_SERIALIZE_COMPATIBLE') || SNAP_WP_JSON_SERIALIZE_COMPATIBLE === false || !defined('WP_JSON_SERIALIZE_COMPATIBLE') || WP_JSON_SERIALIZE_COMPATIBLE === false) {
return $data;
}
switch (gettype($data)) {
case 'boolean':
case 'integer':
case 'double':
case 'string':
case 'NULL':
// These values can be passed through.
return $data;
case 'array':
// Arrays must be mapped in case they also return objects.
return array_map(array(__CLASS__, '_wp_json_prepare_data'), $data);
case 'object':
// If this is an incomplete object (__PHP_Incomplete_Class), bail.
if (!is_object($data)) {
return null;
}
if ($data instanceof JsonSerializable) {
$data = $data->jsonSerialize();
} else {
$data = get_object_vars($data);
}
// Now, pass the array (or whatever was returned from jsonSerialize through).
return self::_wp_json_prepare_data($data);
default:
return null;
}
}
/**
* Perform sanity checks on data that shall be encoded to JSON.
*
* @ignore
* @since 4.1.0
* @access private
*
* @see wp_json_encode()
*
* @param mixed $data Variable (usually an array or object) to encode as JSON.
* @param int $depth Maximum depth to walk through $data. Must be greater than 0.
* @return mixed The sanitized data that shall be encoded to JSON.
*/
private static function _wp_json_sanity_check($data, $depth)
{
if ($depth < 0) {
throw new Exception('Reached depth limit');
}
if (is_array($data)) {
$output = array();
foreach ($data as $id => $el) {
// Don't forget to sanitize the ID!
if (is_string($id)) {
$clean_id = self::_wp_json_convert_string($id);
} else {
$clean_id = $id;
}
// Check the element type, so that we're only recursing if we really have to.
if (is_array($el) || is_object($el)) {
$output[$clean_id] = self::_wp_json_sanity_check($el, $depth - 1);
} elseif (is_string($el)) {
$output[$clean_id] = self::_wp_json_convert_string($el);
} else {
$output[$clean_id] = $el;
}
}
} elseif (is_object($data)) {
$output = new stdClass;
foreach ($data as $id => $el) {
if (is_string($id)) {
$clean_id = self::_wp_json_convert_string($id);
} else {
$clean_id = $id;
}
if (is_array($el) || is_object($el)) {
$output->$clean_id = self::_wp_json_sanity_check($el, $depth - 1);
} elseif (is_string($el)) {
$output->$clean_id = self::_wp_json_convert_string($el);
} else {
$output->$clean_id = $el;
}
}
} elseif (is_string($data)) {
return self::_wp_json_convert_string($data);
} else {
return $data;
}
return $output;
}
private static function _wp_json_convert_string($string)
{
static $use_mb = null;
if (is_null($use_mb)) {
$use_mb = function_exists('mb_convert_encoding');
}
if ($use_mb) {
$encoding = mb_detect_encoding($string, mb_detect_order(), true);
if ($encoding) {
return mb_convert_encoding($string, 'UTF-8', $encoding);
} else {
return mb_convert_encoding($string, 'UTF-8', 'UTF-8');
}
} else {
return self::wp_check_invalid_utf8($string, true);
}
}
/**
* Checks for invalid UTF8 in a string.
*
* @since 2.8.0
*
* @staticvar bool $utf8_pcre
*
* @param string $string The text which is to be checked.
* @param bool $strip Optional. Whether to attempt to strip out invalid UTF8. Default is false.
* @return string The checked text.
*/
public static function wp_check_invalid_utf8($string, $strip = false)
{
$string = (string) $string;
if (0 === strlen($string)) {
return '';
}
// Check for support for utf8 in the installed PCRE library once and store the result in a static
static $utf8_pcre = null;
if (!isset($utf8_pcre)) {
$utf8_pcre = @preg_match('/^./u', 'a');
}
// We can't demand utf8 in the PCRE installation, so just return the string in those cases
if (!$utf8_pcre) {
return $string;
}
// preg_match fails when it encounters invalid UTF8 in $string
if (1 === @preg_match('/^./us', $string)) {
return $string;
}
// Attempt to strip the bad chars if requested (not recommended)
if ($strip && function_exists('iconv')) {
return iconv('utf-8', 'utf-8', $string);
}
return '';
}
/**
* @param mixed $val object to be encoded
* @return string escaped json string
*/
public static function json_encode_esc_attr($val)
{
return esc_attr(json_encode($val));
}
/**
* this function return a json encoded string without quotes at the beginning and the end
*
* @param string $string
* @return string
* @throws Exception
*/
public static function getJsonWithoutQuotes($string)
{
if (!is_string($string)) {
throw new Exception('the function getJsonStringWithoutQuotes take only strings');
}
return substr(self::wp_json_encode($string), 1, -1);
}
}
}
lib/snaplib/class.snaplib.u.util.php 0000644 00000046750 15133606540 0013445 0 ustar 00 <?php
/**
* Utility functions
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package snaplib
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLibUtil', false)) {
class DupLiteSnapLibUtil
{
public static function getArrayValue(&$array, $key, $required = true, $default = null)
{
if (array_key_exists($key, $array)) {
return $array[$key];
} else {
if ($required) {
throw new Exception("Key {$key} not present in array");
} else {
return $default;
}
}
}
/**
* Gets the calling function name from where this method is called
*
* @return string Returns the calling function name from where this method is called
*/
public static function getCallingFunctionName($backTraceBack = 0)
{
$callers = debug_backtrace();
$backTraceL1 = 1 + $backTraceBack;
$backTraceL2 = 2 + $backTraceBack;
$result = '['.str_pad(basename($callers[$backTraceL1]['file']), 25, '_', STR_PAD_RIGHT).':'.str_pad($callers[$backTraceL1]['line'], 4, ' ', STR_PAD_LEFT).']';
if (isset($callers[$backTraceL2]) && (isset($callers[$backTraceL2]['class']) || isset($callers[$backTraceL2]['function']))) {
$result .= ' [';
$result .= isset($callers[$backTraceL2]['class']) ? $callers[$backTraceL2]['class'].'::' : '';
$result .= isset($callers[$backTraceL2]['function']) ? $callers[$backTraceL2]['function'] : '';
$result .= ']';
}
return str_pad($result, 80, '_', STR_PAD_RIGHT);
}
public static function getWorkPercent($startingPercent, $endingPercent, $totalTaskCount, $currentTaskCount)
{
if ($totalTaskCount > 0) {
$percent = $startingPercent + (($endingPercent - $startingPercent) * ($currentTaskCount / (float) $totalTaskCount));
} else {
$percent = $startingPercent;
}
return min(max($startingPercent, $percent), $endingPercent);
}
public static function make_hash()
{
// IMPORTANT! Be VERY careful in changing this format - the FTP delete logic requires 3 segments with the last segment to be the date in YmdHis format.
try {
if (function_exists('random_bytes') && self::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");
}
}
public static function PHP53()
{
return version_compare(PHP_VERSION, '5.3.2', '>=');
}
/**
* Groups an array into arrays by a given key, or set of keys, shared between all array members.
*
* Based on {@author Jake Zatecky}'s {@link https://github.com/jakezatecky/array_group_by array_group_by()} function.
* This variant allows $key to be closures.
*
* @param array $array The array to have grouping performed on.
* @param mixed $key,... The key to group or split by. Can be a _string_, an _integer_, a _float_, or a _callable_.
* - If the key is a callback, it must return a valid key from the array.
* - If the key is _NULL_, the iterated element is skipped.
* - string|int callback ( mixed $item )
*
* @return array|null Returns a multidimensional array or `null` if `$key` is invalid.
*/
public static function arrayGroupBy(array $array, $key)
{
if (!is_string($key) && !is_int($key) && !is_float($key) && !is_callable($key)) {
trigger_error('array_group_by(): The key should be a string, an integer, or a callback', E_USER_ERROR);
return null;
}
$func = (!is_string($key) && is_callable($key) ? $key : null);
$_key = $key;
// Load the new array, splitting by the target key
$grouped = array();
foreach ($array as $value) {
$key = null;
if (is_callable($func)) {
$key = call_user_func($func, $value);
} elseif (is_object($value) && isset($value->{$_key})) {
$key = $value->{$_key};
} elseif (isset($value[$_key])) {
$key = $value[$_key];
}
if ($key === null) {
continue;
}
$grouped[$key][] = $value;
}
// Recursively build a nested grouping if more parameters are supplied
// Each grouped array value is grouped according to the next sequential key
if (func_num_args() > 2) {
$args = func_get_args();
foreach ($grouped as $key => $value) {
$params = array_merge(array($value), array_slice($args, 2, func_num_args()));
$grouped[$key] = call_user_func_array(array(__CLASS__, 'arrayGroupBy'), $params);
}
}
return $grouped;
}
/**
* Converts human readable types (10GB) to bytes
*
* @param string $from A human readable byte size such as 100MB
*
* @return int Returns and integer of the byte size
*/
public static function convertToBytes($from)
{
if (is_numeric($from)) {
return $from;
}
$number = substr($from, 0, -2);
switch (strtoupper(substr($from, -2))) {
case "KB": return $number * 1024;
case "MB": return $number * pow(1024, 2);
case "GB": return $number * pow(1024, 3);
case "TB": return $number * pow(1024, 4);
case "PB": return $number * pow(1024, 5);
}
$number = substr($from, 0, -1);
switch (strtoupper(substr($from, -1))) {
case "K": return $number * 1024;
case "M": return $number * pow(1024, 2);
case "G": return $number * pow(1024, 3);
case "T": return $number * pow(1024, 4);
case "P": return $number * pow(1024, 5);
}
return $from;
}
/**
* Sanitize input for XSS code
*
* @param string $val The value to sanitize
*
* @return string Returns the input value cleaned up.
*/
public static function sanitize($input)
{
return filter_var($input, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
}
/**
* remove all non stamp chars from string
*
* @param string $string
* @return string
*/
public static function sanitize_non_stamp_chars($string)
{
return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $string);
}
/**
* remove all non stamp chars from string and newline
* trim string
*
* @param string $string
* @return string
*/
public static function sanitize_non_stamp_chars_and_newline($string)
{
return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\r\n]/u', '', $string);
}
/**
* remove all non stamp chars from string and newline
* trim string
*
* @param string $string
* @return string
*/
public static function sanitize_non_stamp_chars_newline_and_trim($string)
{
return trim(self::sanitize_non_stamp_chars_and_newline($string));
}
/**
* Determines whether a PHP ini value is changeable at runtime.
*
* @since 4.6.0
*
* @staticvar array $ini_all
*
* @link https://secure.php.net/manual/en/function.ini-get-all.php
*
* @param string $setting The name of the ini setting to check.
* @return bool True if the value is changeable at runtime. False otherwise.
*/
public static function wp_is_ini_value_changeable($setting)
{
// if ini_set is disabled can change the values
if (!function_exists('ini_set')) {
return false;
}
if (function_exists('wp_is_ini_value_changeable')) {
return wp_is_ini_value_changeable($setting);
}
static $ini_all;
if (!isset($ini_all)) {
$ini_all = false;
// Sometimes `ini_get_all()` is disabled via the `disable_functions` option for "security purposes".
if (function_exists('ini_get_all')) {
$ini_all = ini_get_all();
}
}
// Bit operator to workaround https://bugs.php.net/bug.php?id=44936 which changes access level to 63 in PHP 5.2.6 - 5.2.17.
if (isset($ini_all[$setting]['access']) && ( INI_ALL === ( $ini_all[$setting]['access'] & 7 ) || INI_USER === ( $ini_all[$setting]['access'] & 7 ) )) {
return true;
}
// If we were unable to retrieve the details, fail gracefully to assume it's changeable.
if (!is_array($ini_all)) {
return true;
}
return false;
}
/**
* The val value returns if it is between min and max otherwise it returns min or max
*
* @param int $val
* @param int $min
* @param int $max
* @return int
*/
public static function getIntBetween($val, $min, $max)
{
return min((int) $max, max((int) $min, (int) $val));
}
/**
* Find matching string from $strArr1 and $strArr2 until first numeric occurence
*
* @param array $strArr1 array of strings
* @param array $strArr2 array of strings
* @return string matching str which will be best for replacement
*/
public static function getMatchingStrFromArrayElemsUntilFirstNumeric($strArr1, $strArr2)
{
$matchingStr = '';
$strPartialArr = array();
foreach ($strArr1 as $str1) {
$str1_str_length = strlen($str1);
$tempStr1Chars = str_split($str1);
$tempPartialStr = '';
// The flag is for whether non-numeric character passed after numeric character occurence in str1. For ex. str1 is utf8mb4, the flag wil be true when parsing m after utf8.
$numericCharPassFlag = false;
$charPositionInStr1 = 0;
while ($charPositionInStr1 < $str1_str_length) {
if ($numericCharPassFlag && !is_numeric($tempStr1Chars[$charPositionInStr1])) {
break;
}
if (is_numeric($tempStr1Chars[$charPositionInStr1])) {
$numericCharPassFlag = true;
}
$tempPartialStr .= $tempStr1Chars[$charPositionInStr1];
$charPositionInStr1++;
}
$strPartialArr[] = $tempPartialStr;
}
foreach ($strPartialArr as $strPartial) {
if (!empty($matchingStr)) {
break;
}
foreach ($strArr2 as $str2) {
if (0 === stripos($str2, $strPartial)) {
$matchingStr = $str2;
break;
}
}
}
return $matchingStr;
}
/**
* Find matching string from $strArr1 and $strArr2
*
* @param array $strArr1 array of strings
* @param array $strArr2 array of strings
* @param boolean $match_until_first_numeric only match until first numeric occurrence
* @return string matching str which will be best for replacement
*/
public static function getMatchingStrFromArrayElemsBasedOnUnderScore($strArr1, $strArr2)
{
$matchingStr = '';
$str1PartialFirstArr = array();
$str1PartialFirstArr = array();
$str1PartialStartNMiddleArr = array();
$str1PartialMiddleNLastArr = array();
$str1PartialLastArr = array();
foreach ($strArr1 as $str1) {
$str1PartialArr = explode('_', $str1);
$str1_parts_count = count($str1PartialArr);
$str1PartialFirstArr[] = $str1PartialArr[0];
$str1LastPartIndex = $str1_parts_count - 1;
if ($str1LastPartIndex > 0) {
$str1PartialLastArr[] = $str1PartialArr[$str1LastPartIndex];
$str1PartialStartNMiddleArr[] = substr($str1, 0, strripos($str1, '_'));
$str1PartialMiddleNLastArr[] = substr($str1, stripos($str1, '_') + 1);
}
}
for ($caseNo = 1; $caseNo <= 5; $caseNo++) {
if (!empty($matchingStr)) {
break;
}
foreach ($strArr2 as $str2) {
switch ($caseNo) {
// Both Start and End match
case 1:
$str2PartialArr = explode('_', $str2);
$str2FirstPart = $str2PartialArr[0];
$str2PartsCount = count($str2PartialArr);
$str2LastPartIndex = $str2PartsCount - 1;
if ($str2LastPartIndex > 0) {
$str2LastPart = $str2PartialArr[$str2LastPartIndex];
} else {
$str2LastPart = '';
}
if (!empty($str2LastPart) && !empty($str1PartialLastArr) && in_array($str2FirstPart, $str1PartialFirstArr) && in_array($str2LastPart, $str1PartialLastArr)) {
$matchingStr = $str2;
}
break;
// Start Middle Match
case 2:
$str2PartialFirstNMiddleParts = substr($str2, 0, strripos($str2, '_'));
if (in_array($str2PartialFirstNMiddleParts, $str1PartialStartNMiddleArr)) {
$matchingStr = $str2;
}
break;
// End Middle Match
case 3:
$str2PartialMiddleNLastParts = stripos($str2, '_') !== false ? substr($str2, stripos($str2, '_') + 1) : '';
if (!empty($str2PartialMiddleNLastParts) && in_array($str2PartialMiddleNLastParts, $str1PartialMiddleNLastArr)) {
$matchingStr = $str2;
}
break;
// Start Match
case 4:
$str2PartialArr = explode('_', $str2);
$str2FirstPart = $str2PartialArr[0];
if (in_array($str2FirstPart, $str1PartialFirstArr)) {
$matchingStr = $str2;
}
break;
// End Match
case 5:
$str2PartialArr = explode('_', $str2);
$str2PartsCount = count($str2PartialArr);
$str2LastPartIndex = $str2PartsCount - 1;
if ($str2LastPartIndex > 0) {
$str2LastPart = $str2PartialArr[$str2LastPartIndex];
} else {
$str2LastPart = '';
}
if (!empty($str2LastPart) && in_array($str2LastPart, $str1PartialLastArr)) {
$matchingStr = $str2;
}
break;
}
if (!empty($matchingStr)) {
break;
}
}
}
return $matchingStr;
}
/**
* Gets a specific external variable by name and optionally filters it
* @param int $type <p>One of <b><code>INPUT_GET</code></b>, <b><code>INPUT_POST</code></b>, <b><code>INPUT_COOKIE</code></b>, <b><code>INPUT_SERVER</code></b>, or <b><code>INPUT_ENV</code></b>.</p>
* @param string $variable_name <p>Name of a variable to get.</p>
* @param int $filter <p>The ID of the filter to apply. The Types of filters manual page lists the available filters.</p> <p>If omitted, <b><code>FILTER_DEFAULT</code></b> will be used, which is equivalent to <b><code>FILTER_UNSAFE_RAW</code></b>. This will result in no filtering taking place by default.</p>
* @param mixed $options <p>Associative array of options or bitwise disjunction of flags. If filter accepts options, flags can be provided in "flags" field of array.</p>
* @return mixed <p>Value of the requested variable on success, <b><code>FALSE</code></b> if the filter fails, or <b><code>NULL</code></b> if the <code>variable_name</code> variable is not set. If the flag <b><code>FILTER_NULL_ON_FAILURE</code></b> is used, it returns <b><code>FALSE</code></b> if the variable is not set and <b><code>NULL</code></b> if the filter fails.</p>
* @link http://php.net/manual/en/function.filter-input.php
* @see filter_var(), filter_input_array(), filter_var_array()
* @since PHP 5 >= 5.2.0, PHP 7
*/
public static function filterInputRequest($variable_name, $filter = FILTER_DEFAULT, $options = NULL)
{
if (isset($_GET[$variable_name]) && !isset($_POST[$variable_name])) {
return filter_input(INPUT_GET, $variable_name, $filter, $options);
}
return filter_input(INPUT_POST, $variable_name, $filter, $options);
}
/**
* Implemented array_key_first
*
* @link https://www.php.net/manual/en/function.array-key-first.php
* @param array $arr
* @return int|string|null
*/
public static function arrayKeyFirst($arr)
{
if (!function_exists('array_key_first')) {
foreach ($arr as $key => $unused) {
return $key;
}
return null;
} else {
return array_key_first($arr);
}
}
/**
* Get number of bit supported by PHP
*
* @return string
*/
public static function getArchitectureString()
{
return (PHP_INT_SIZE * 8).'-bit';
}
}
}
lib/snaplib/class.snaplib.u.url.php 0000644 00000017207 15133606540 0013265 0 ustar 00 <?php
/**
* Utility class used for working with URLs
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package DupLiteSnapLib
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLibURLU', false)) {
class DupLiteSnapLibURLU
{
protected static $DEF_ARRAY_PARSE_URL = array(
'scheme' => false,
'host' => false,
'port' => false,
'user' => false,
'pass' => false,
'path' => '',
'scheme' => false,
'query' => false,
'fragment' => false
);
/**
* Append a new query value to the end of a URL
*
* @param string $url The URL to append the new value to
* @param string $key The new key name
* @param string $value The new key name value
*
* @return string Returns the new URL with with the query string name and value
*/
public static function appendQueryValue($url, $key, $value)
{
$separator = (parse_url($url, PHP_URL_QUERY) == NULL) ? '?' : '&';
$modified_url = $url."$separator$key=$value";
return $modified_url;
}
/**
* add www. in url if don't have
*
* @param string $url
* @return string
*/
public static function wwwAdd($url)
{
return preg_replace('/^((?:\w+\:)?\/\/)(?!www\.)(.+)/', '$1www.$2', $url);
}
/**
* remove www. in url if don't have
*
* @param string $url
* @return string
*/
public static function wwwRemove($url)
{
return preg_replace('/^((?:\w+\:)?\/\/)www\.(.+)/', '$1$2', $url);
}
/**
* Fetches current URL via php
*
* @param bool $queryString If true the query string will also be returned.
* @param int $getParentDirLevel if 0 get current script name or parent folder, if 1 parent folder if 2 parent of parent folder ...
*
* @returns The current page url
*/
public static function getCurrentUrl($queryString = true, $requestUri = false, $getParentDirLevel = 0)
{
// *** HOST
if (isset($_SERVER['HTTP_X_ORIGINAL_HOST'])) {
$host = $_SERVER['HTTP_X_ORIGINAL_HOST'];
} else {
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']; //WAS SERVER_NAME and caused problems on some boxes
}
// *** PROTOCOL
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER ['HTTPS'] = 'on';
}
if (isset($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'https') {
$_SERVER ['HTTPS'] = 'on';
}
if (isset($_SERVER['HTTP_CF_VISITOR'])) {
$visitor = json_decode($_SERVER['HTTP_CF_VISITOR']);
if ($visitor->scheme == 'https') {
$_SERVER ['HTTPS'] = 'on';
}
}
$protocol = 'http'.((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) === 'on') ? 's' : '');
if ($requestUri) {
$serverUrlSelf = preg_replace('/\?.*$/', '', $_SERVER['REQUEST_URI']);
} else {
// *** SCRIPT NAME
$serverUrlSelf = $_SERVER['SCRIPT_NAME'];
for ($i = 0; $i < $getParentDirLevel; $i++) {
$serverUrlSelf = preg_match('/^[\\\\\/]?$/', dirname($serverUrlSelf)) ? '' : dirname($serverUrlSelf);
}
}
// *** QUERY STRING
$query = ($queryString && isset($_SERVER['QUERY_STRING']) && strlen($_SERVER['QUERY_STRING']) > 0 ) ? '?'.$_SERVER['QUERY_STRING'] : '';
return $protocol.'://'.$host.$serverUrlSelf.$query;
}
/**
* this function is a native PHP parse_url wrapper
* this function returns an associative array with all the keys present and the values = false if they do not exist.
*
* @param string $url <p>The URL to parse. Invalid characters are replaced by <i>_</i>.</p>
* @param int $component
* @return mixed <p>On seriously malformed URLs, <b>parse_url()</b> may return <b><code>FALSE</code></b>.</p><p>If the <code>component</code> parameter is omitted, an associative <code>array</code> is returned. At least one element will be present within the array. Potential keys within this array are:</p><ul> <li> scheme - e.g. http </li> <li> host </li> <li> port </li> <li> user </li> <li> pass </li> <li> path </li> <li> query - after the question mark <i>?</i> </li> <li> fragment - after the hashmark <i>#</i> </li> </ul><p>If the <code>component</code> parameter is specified, <b>parse_url()</b> returns a <code>string</code> (or an <code>integer</code>, in the case of <b><code>PHP_URL_PORT</code></b>) instead of an <code>array</code>. If the requested component doesn't exist within the given URL, <b><code>NULL</code></b> will be returned.</p>
*/
public static function parseUrl($url, $component = -1)
{
$result = parse_url($url, $component);
if (is_array($result)) {
$result = array_merge(self::$DEF_ARRAY_PARSE_URL, $result);
}
return $result;
}
/**
* this function build a url from array result of parse url.
* if work with both parse_url native function result and snap parseUrl result
*
* @param array $parts
* @return bool|string return false if param isn't array
*/
public static function buildUrl($parts)
{
if (!is_array($parts)) {
return false;
}
$result = '';
$result .= (isset($parts['scheme']) && $parts['scheme'] !== false) ? $parts['scheme'].':' : '';
$result .= (
(isset($parts['user']) && $parts['user'] !== false) ||
(isset($parts['host']) && $parts['host'] !== false)) ? '//' : '';
$result .= (isset($parts['user']) && $parts['user'] !== false) ? $parts['user'] : '';
$result .= (isset($parts['pass']) && $parts['pass'] !== false) ? ':'.$parts['pass'] : '';
$result .= (isset($parts['user']) && $parts['user'] !== false) ? '@' : '';
$result .= (isset($parts['host']) && $parts['host'] !== false) ? $parts['host'] : '';
$result .= (isset($parts['port']) && $parts['port'] !== false) ? ':'.$parts['port'] : '';
$result .= (isset($parts['path']) && $parts['path'] !== false) ? $parts['path'] : '';
$result .= (isset($parts['query']) && $parts['query'] !== false) ? '?'.$parts['query'] : '';
$result .= (isset($parts['fragment']) && $parts['fragment'] !== false) ? '#'.$parts['fragment'] : '';
return $result;
}
/**
* encode alla chars
*
* @param string $url
* @return string
*/
public static function urlEncodeAll($url)
{
$hex = unpack('H*', urldecode($url));
return preg_replace('~..~', '%$0', strtoupper($hex[1]));
}
}
}
lib/snaplib/class.snaplib.u.string.php 0000644 00000007766 15133606540 0014002 0 ustar 00 <?php
/**
* Snap strings utils
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package DupLiteSnapLib
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLibStringU', false)) {
class DupLiteSnapLibStringU
{
public static function boolToString($b)
{
return ($b ? 'true' : 'false');
}
public static function truncateString($s, $maxWidth)
{
if (strlen($s) > $maxWidth) {
$s = substr($s, 0, $maxWidth - 3).'...';
}
return $s;
}
/**
* Returns true if the $haystack string starts with the $needle
*
* @param string $haystack The full string to search in
* @param string $needle The string to for
*
* @return bool Returns true if the $haystack string starts with the $needle
*/
public static function startsWith($haystack, $needle)
{
$length = strlen($needle);
return (substr($haystack, 0, $length) === $needle);
}
/**
* Returns true if the $haystack string end with the $needle
*
* @param string $haystack The full string to search in
* @param string $needle The string to for
*
* @return bool Returns true if the $haystack string starts with the $needle
*/
public static function endsWith($haystack, $needle)
{
$length = strlen($needle);
if ($length == 0) {
return true;
}
return (substr($haystack, -$length) === $needle);
}
/**
* Returns true if the $needle is found in the $haystack
*
* @param string $haystack The full string to search in
* @param string $needle The string to for
*
* @return bool
*/
public static function contains($haystack, $needle)
{
$pos = strpos($haystack, $needle);
return ($pos !== false);
}
/**
*
* @param string $glue
* @param array $pieces
* @param string $format
* @return string
*/
public static function implodeKeyVals($glue, $pieces, $format = '%s="%s"')
{
$strList = array();
foreach ($pieces as $key => $value) {
if (is_scalar($value)) {
$strList[] = sprintf($format, $key, $value);
} else {
$strList[] = sprintf($format, $key, print_r($value, true));
}
}
return implode($glue, $strList);
}
/**
* Replace last occurrence
*
* @param String $search The value being searched for
* @param String $replace The replacement value that replaces found search values
* @param String $str The string or array being searched and replaced on, otherwise known as the haystack
* @param Boolean $caseSensitive Whether the replacement should be case sensitive or not
*
* @return String
*/
public static function strLastReplace($search, $replace, $str, $caseSensitive = true)
{
$pos = $caseSensitive ? strrpos($str, $search) : strripos($str, $search);
if (false !== $pos) {
$str = substr_replace($str, $replace, $pos, strlen($search));
}
return $str;
}
/**
*
* @param string $string
* @return boolean
*/
public static function isHTML($string)
{
return ($string != strip_tags($string));
}
}
}
lib/snaplib/snaplib.all.php 0000644 00000002424 15133606540 0011657 0 ustar 00 <?php
/**
* include all snap lib
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package snaplib
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!defined('DUPLITE_SNAPLIB_INCLUDE_ALL')) {
define('DUPLITE_SNAPLIB_INCLUDE_ALL', true);
$dir = dirname(__FILE__);
require_once($dir.'/class.snaplib.exceptions.php');
require_once($dir.'/class.snaplib.logger.php');
require_once($dir.'/class.snaplib.u.util.php');
require_once($dir.'/class.snaplib.u.io.php');
require_once($dir.'/class.snaplib.u.db.php');
require_once($dir.'/class.snaplib.u.json.php');
require_once($dir.'/class.snaplib.jsonSerializable.abstract.php');
require_once($dir.'/class.snaplib.u.net.php');
require_once($dir.'/class.snaplib.u.orig.files.manager.php');
require_once($dir.'/class.snaplib.u.os.php');
require_once($dir.'/class.snaplib.u.stream.php');
require_once($dir.'/class.snaplib.u.string.php');
require_once($dir.'/class.snaplib.u.ui.php');
require_once($dir.'/class.snaplib.u.url.php');
require_once($dir.'/class.snaplib.u.wp.php');
}
lib/snaplib/class.snaplib.u.os.php 0000644 00000003375 15133606540 0013105 0 ustar 00 <?php
/**
* Snap OS utils
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package DupLiteSnapLib
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLibOSU', false)) {
class DupLiteSnapLibOSU
{
const DEFAULT_WINDOWS_MAXPATH = 260;
const DEFAULT_LINUX_MAXPATH = 4096;
/**
* return true if current SO is windows
*
* @staticvar bool $isWindows
* @return bool
*/
public static function isWindows()
{
static $isWindows = null;
if (is_null($isWindows)) {
$isWindows = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
}
return $isWindows;
}
public static function isOSX()
{
static $isOSX = null;
if (is_null($isOSX)) {
$isOSX = (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
}
return $isOSX;
}
/**
* return current SO path path len
* @staticvar int $maxPath
* @return int
*/
public static function maxPathLen()
{
static $maxPath = null;
if (is_null($maxPath)) {
if (defined('PHP_MAXPATHLEN')) {
$maxPath = PHP_MAXPATHLEN;
} else {
// for PHP < 5.3.0
$maxPath = self::isWindows() ? self::DEFAULT_WINDOWS_MAXPATH : self::DEFAULT_LINUX_MAXPATH;
}
}
return $maxPath;
}
}
}
lib/snaplib/class.snaplib.u.db.php 0000644 00000021051 15133606540 0013040 0 ustar 00 <?php
/**
* Snap Database utils
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package SnapLib
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
class DupLiteSnapLibDB
{
const CACHE_PREFIX_PRIMARY_KEY_COLUMN = 'pkcol_';
const DB_ENGINE_MYSQL = 'MySQL';
const DB_ENGINE_MARIA = 'MariaDB';
const DB_ENGINE_PERCONA = 'Percona';
private static $cache = array();
/**
*
* @param mysqli $dbh // Database connection handle
* @param string $tableName
* @return string|string[] // return array if primary key is composite key
* @throws Exception
*/
public static function getUniqueIndexColumn(\mysqli $dbh, $tableName, $logCallback = null)
{
$cacheKey = self::CACHE_PREFIX_PRIMARY_KEY_COLUMN.$tableName;
if (!isset(self::$cache[$cacheKey])) {
$query = 'SHOW COLUMNS FROM `'.mysqli_real_escape_string($dbh, $tableName).'` WHERE `Key` IN ("PRI","UNI")';
if (($result = mysqli_query($dbh, $query)) === false) {
if (is_callable($logCallback)) {
call_user_func($logCallback, $dbh, $result, $query);
}
throw new Exception('SHOW KEYS QUERY ERROR: '.mysqli_error($dbh));
}
if (is_callable($logCallback)) {
call_user_func($logCallback, $dbh, $result, $query);
}
if ($result->num_rows == 0) {
self::$cache[$cacheKey] = false;
} else {
$primary = false;
$unique = false;
while ($row = $result->fetch_assoc()) {
switch ($row['Key']) {
case 'PRI':
if ($primary === false) {
$primary = $row['Field'];
} else {
if (is_scalar($primary)) {
$primary = array($primary);
}
$primary[] = $row['Field'];
}
break;
case 'UNI':
$unique = $row['Field'];
break;
default:
break;
}
}
if ($primary !== false) {
self::$cache[$cacheKey] = $primary;
} else if ($unique !== false) {
self::$cache[$cacheKey] = $unique;
} else {
self::$cache[$cacheKey] = false;
}
}
$result->free();
}
return self::$cache[$cacheKey];
}
/**
*
* @param array $row
* @param string|string[] $indexColumns
* @return string|string[]
*/
public static function getOffsetFromRowAssoc($row, $indexColumns, $lastOffset)
{
if (is_array($indexColumns)) {
$result = array();
foreach ($indexColumns as $col) {
$result[$col] = isset($row[$col]) ? $row[$col] : 0;
}
return $result;
} else if (strlen($indexColumns) > 0) {
return isset($row[$indexColumns]) ? $row[$indexColumns] : 0;
} else {
return $lastOffset + 1;
}
}
/**
* This function performs a select by structuring the primary key as offset if the table has a primary key.
* For optimization issues, no checks are performed on the input query and it is assumed that the select has at least a where value.
* If there are no conditions, you still have to perform an always true condition, for example
* SELECT * FROM `copy1_postmeta` WHERE 1
*
* @param mysqli $dbh // Database connection handle
* @param string $query
* @param string $table
* @param int $offset
* @param int $limit // 0 no limit
* @param mixed $lastRowOffset // last offset to use on next function call
* @return mysqli_result
* @throws Exception // exception on query fail
*/
public static function selectUsingPrimaryKeyAsOffset(\mysqli $dbh, $query, $table, $offset, $limit, &$lastRowOffset = null, $logCallback = null)
{
$where = '';
$orderby = '';
$offsetStr = '';
$limitStr = $limit > 0 ? ' LIMIT '.$limit : '';
if (($primaryColumn = self::getUniqueIndexColumn($dbh, $table, $logCallback)) == false) {
$offsetStr = ' OFFSET '.(is_scalar($offset) ? $offset : 0);
} else {
if (is_array($primaryColumn)) {
// COMPOSITE KEY
$orderByCols = array();
foreach ($primaryColumn as $colIndex => $col) {
$orderByCols[] = '`'.$col.'` ASC';
}
$orderby = ' ORDER BY '.implode(',', $orderByCols);
} else {
$orderby = ' ORDER BY `'.$primaryColumn.'` ASC';
}
$where = self::getOffsetKeyCondition($dbh, $primaryColumn, $offset);
}
$query .= $where.$orderby.$limitStr.$offsetStr;
if (($result = mysqli_query($dbh, $query)) === false) {
if (is_callable($logCallback)) {
call_user_func($logCallback, $dbh, $result, $query);
}
throw new Exception('SELECT ERROR: '.mysqli_error($dbh));
}
if (is_callable($logCallback)) {
call_user_func($logCallback, $dbh, $result, $query);
}
if ($primaryColumn == false) {
$lastRowOffset = $offset + $result->num_rows;
} else {
if ($result->num_rows == 0) {
$lastRowOffset = $offset;
} else {
$result->data_seek(($result->num_rows - 1));
$row = $result->fetch_assoc();
if (is_array($primaryColumn)) {
$lastRowOffset = array();
foreach ($primaryColumn as $col) {
$lastRowOffset[$col] = $row[$col];
}
} else {
$lastRowOffset = $row[$primaryColumn];
}
$result->data_seek(0);
}
}
return $result;
}
/**
* Depending on the structure type of the primary key returns the condition to position at the right offset
*
* @param string|string[] $primaryColumn
* @param mixed $offset
* @return string
*/
protected static function getOffsetKeyCondition(\mysqli $dbh, $primaryColumn, $offset)
{
$condition = '';
if ($offset === 0) {
return '';
}
// COUPOUND KEY
if (is_array($primaryColumn)) {
foreach ($primaryColumn as $colIndex => $col) {
if (is_array($offset) && isset($offset[$col]) && $offset[$col] > 0) {
$condition .= ($colIndex == 0 ? '' : ' OR ');
$condition .= ' (';
for ($prevColIndex = 0; $prevColIndex < $colIndex; $prevColIndex++) {
$condition .= ' `'.$primaryColumn[$prevColIndex].'` = "'.mysqli_real_escape_string($dbh, $offset[$primaryColumn[$prevColIndex]]).'" AND ';
}
$condition .= ' `'.$col.'` > "'.mysqli_real_escape_string($dbh, $offset[$col]).'")';
}
}
} else {
$condition = '`'.$primaryColumn.'` > "'.mysqli_real_escape_string($dbh, (is_scalar($offset) ? $offset : 0)).'"';
}
return (strlen($condition) ? ' AND ('.$condition.')' : '');
}
public static function getDBEngine(\mysqli $dbh)
{
$result = mysqli_query($dbh, "SHOW VARIABLES LIKE 'version%'");
$rows = @mysqli_fetch_all($result);
@mysqli_free_result($result);
$version = isset($rows[0][1]) ? $rows[0][1] : false;
$versionComment = isset($rows[1][1]) ? $rows[1][1] : false;
//Default is mysql
if ($version === false && $versionComment === false) {
return self::DB_ENGINE_MYSQL;
}
if (stripos($version, 'maria') !== false || stripos($versionComment, 'maria') !== false) {
return self::DB_ENGINE_MARIA;
}
if (stripos($version, 'percona') !== false || stripos($versionComment, 'percona') !== false) {
return self::DB_ENGINE_PERCONA;
}
return self::DB_ENGINE_MYSQL;
}
}
lib/snaplib/index.php 0000644 00000000017 15133606540 0010563 0 ustar 00 <?php
//silent lib/snaplib/class.snaplib.u.stream.php 0000644 00000001317 15133606540 0013751 0 ustar 00 <?php
/**
* Snap stream utils
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package DupLiteSnapLib
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLibStreamU', false)) {
class DupLiteSnapLibStreamU
{
public static function streamGetLine($handle, $length, $ending)
{
$line = stream_get_line($handle, $length, $ending);
if ($line === false) {
throw new Exception('Error reading line.');
}
return $line;
}
}
} lib/snaplib/class.snaplib.jsonSerializable.abstract.php 0000644 00000013520 15133606540 0017314 0 ustar 00 <?php
/**
* Json class serialize / unserialize json
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package SnapLib
* @copyright (c) 2019, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapJsonSerializable', false)) {
abstract class DupLiteSnapJsonSerializable
{
const CLASS_KEY_FOR_JSON_SERIALIZE = '==_CLASS_==_NAME_==';
protected static function objectToPublicArrayClass($obj = null)
{
$reflect = new ReflectionObject($obj);
$result = array(
self::CLASS_KEY_FOR_JSON_SERIALIZE => $reflect->name
);
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
/**
* get all props of current class but not props private of parent class
*/
$props = $reflect->getProperties();
foreach ($props as $prop) {
$prop->setAccessible(true);
$propName = $prop->getName();
$propValue = $prop->getValue($obj);
$result[$propName] = self::parseValueToArray($propValue);
}
} else {
$objArray = (array) $obj;
$re = '/(?:.*\x00)?(.+)/';
$subst = '$1';
foreach ($objArray as $origPropName => $propValue) {
$propName = preg_replace($re, $subst, $origPropName, 1);
$result[$propName] = self::parseValueToArray($propValue);
}
}
return $result;
}
protected static function parseValueToArray($value)
{
if (is_object($value)) {
return self::objectToPublicArrayClass($value);
} else if (is_array($value)) {
$result = array();
foreach ($value as $key => $arrayVal) {
$result[$key] = self::parseValueToArray($arrayVal);
}
return $result;
} else {
return $value;
}
}
protected static function parseArrayToValue($value, $classFromProp = null)
{
if (($newClassName = self::getClassFromArray($value, $classFromProp)) !== false) {
if (class_exists($newClassName)) {
$newObj = new $newClassName();
} else {
$newObj = new StdClass();
}
if (is_subclass_of($newObj, __CLASS__)) {
$newObj->initFromPublicArray($value, $classFromProp);
} else {
$reflect = new ReflectionObject($newObj);
$excludeProps = array(self::CLASS_KEY_FOR_JSON_SERIALIZE);
$privateProps = $reflect->getProperties(ReflectionProperty::IS_PROTECTED + ReflectionProperty::IS_PRIVATE + ReflectionProperty::IS_STATIC);
foreach ($privateProps as $pros) {
$excludeProps[] = $pros->getName();
}
foreach ($value as $arrayProp => $arrayValue) {
if (in_array($arrayProp, $excludeProps)) {
continue;
}
$newObj->{$arrayProp} = self::parseArrayToValue($arrayValue, $classFromProp);
}
}
return $newObj;
} else if (is_array($value)) {
$result = array();
foreach ($value as $key => $arrayVal) {
$result[$key] = self::parseArrayToValue($arrayVal);
}
return $result;
} else {
return $value;
}
}
protected function initFromPublicArray($array, $classFromProp = null)
{
if (!is_array($array)) {
return false;
}
$reflect = new ReflectionObject($this);
$classFromArray = self::getClassFromArray($array, $classFromProp);
if ($classFromArray == false || $classFromArray !== $reflect->name) {
return false;
}
$excludeProps = array(self::CLASS_KEY_FOR_JSON_SERIALIZE);
$privateProps = $reflect->getProperties(ReflectionProperty::IS_PRIVATE + ReflectionProperty::IS_STATIC);
foreach ($privateProps as $pros) {
$excludeProps[] = $pros->getName();
}
foreach ($array as $propName => $propValue) {
if (in_array($propName, $excludeProps)) {
continue;
}
$this->{$propName} = self::parseArrayToValue($propValue, $classFromProp);
}
}
protected static function getClassFromArray($array, $classFromProp = null)
{
if (!is_array($array)) {
return false;
} else if (isset($array[self::CLASS_KEY_FOR_JSON_SERIALIZE])) {
return $array[self::CLASS_KEY_FOR_JSON_SERIALIZE];
} else if (!is_null($classFromProp) && isset($array[$classFromProp])) {
return $array[$classFromProp];
} else {
return false;
}
}
/**
*
*/
public function jsonSerialize()
{
return DupLiteSnapJsonU::wp_json_encode_pprint(self::objectToPublicArrayClass($this));
}
/**
*
* @param string $json
* @return type
*/
public static function jsonUnserialize($json, $classFromProp = null)
{
$publicArray = json_decode($json, true);
return self::parseArrayToValue($publicArray, $classFromProp);
}
}
}
lib/snaplib/class.snaplib.u.net.php 0000644 00000003447 15133606540 0013252 0 ustar 00 <?php
/**
* Snap Net utils
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package DupLiteSnapLib
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLibNetU', false)) {
class DupLiteSnapLibNetU
{
public static function postWithoutWait($url, $params)
{
foreach ($params as $key => &$val) {
if (is_array($val)) {
$val = implode(',', $val);
}
$post_params[] = $key.'='.urlencode($val);
}
$post_string = implode('&', $post_params);
$parts = parse_url($url);
$fp = fsockopen($parts['host'], isset($parts['port']) ? $parts['port'] : 80, $errno, $errstr, 60);
$out = "POST ".$parts['path']." HTTP/1.1\r\n";
$out .= "Host: ".$parts['host']."\r\n";
$out .= "Content-Type: application/x-www-form-urlencoded\r\n";
$out .= "Content-Length: ".strlen($post_string)."\r\n";
$out .= "Connection: Close\r\n\r\n";
if (isset($post_string)) {
$out .= $post_string;
}
fwrite($fp, $out);
fclose($fp);
}
public static function getRequestValue($paramName, $isRequired = true, $default = null)
{
if (isset($_REQUEST[$paramName])) {
return $_REQUEST[$paramName];
} else {
if ($isRequired) {
throw new Exception("Parameter $paramName not present");
}
return $default;
}
}
}
} lib/snaplib/wordpress.core.files.php 0000644 00000353741 15133606540 0013553 0 ustar 00 <?php
/**
* >>>>>> THIS FILE IS AUTOGENERATED DON'T MODIFY THIS DIRECTLY <<<<<
* >>>>>> USE THE GENERATOR SCRIPT <<<<<
*
* >>>>>> THIS FILE IS AUTOGENERATED DON'T MODIFY THIS DIRECTLY <<<<<
* >>>>>> USE THE GENERATOR SCRIPT <<<<<
*
* >>>>>> THIS FILE IS AUTOGENERATED DON'T MODIFY THIS DIRECTLY <<<<<
* >>>>>> USE THE GENERATOR SCRIPT <<<<<
*
* Core wordpress file list
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package snaplib
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/*
* >>>>>> THIS FILE IS AUTOGENERATED DON'T MODIFY THIS DIRECTLY <<<<<
* >>>>>> USE THE GENERATOR SCRIPT <<<<<
*
* >>>>>> THIS FILE IS AUTOGENERATED DON'T MODIFY THIS DIRECTLY <<<<<
* >>>>>> USE THE GENERATOR SCRIPT <<<<<
*
* >>>>>> THIS FILE IS AUTOGENERATED DON'T MODIFY THIS DIRECTLY <<<<<
* >>>>>> USE THE GENERATOR SCRIPT <<<<<
*
*/
self::$corePathList = array(
'wp-login.php' => array(),
'wp-config-sample.php' => array(),
'wp-activate.php' => array(),
'wp-comments-post.php' => array(),
'wp-signup.php' => array(),
'wp-mail.php' => array(),
'wp-links-opml.php' => array(),
'wp-load.php' => array(),
'wp-blog-header.php' => array(),
'wp-content' => array(
'index.php' => array()
),
'wp-includes' => array(
'category-template.php' => array(),
'class-wp-recovery-mode-email-service.php' => array(),
'default-constants.php' => array(),
'class-wp-http-requests-hooks.php' => array(),
'class-wp-block-patterns-registry.php' => array(),
'media.php' => array(),
'block-patterns.php' => array(),
'functions.php' => array(),
'ms-network.php' => array(),
'class-requests.php' => array(),
'cache.php' => array(),
'class-wp-dependency.php' => array(),
'class-wp-http-proxy.php' => array(),
'class-phpass.php' => array(),
'ms-settings.php' => array(),
'class-wp-customize-manager.php' => array(),
'class-wp-block-styles-registry.php' => array(),
'class-wp-recovery-mode-key-service.php' => array(),
'class-walker-category.php' => array(),
'class-wp-metadata-lazyloader.php' => array(),
'blocks.php' => array(),
'l10n.php' => array(),
'cron.php' => array(),
'template.php' => array(),
'class-wp-widget-factory.php' => array(),
'class-wp-network.php' => array(),
'nav-menu-template.php' => array(),
'class-wp-matchesmapregex.php' => array(),
'feed-rdf.php' => array(),
'widgets' => array(
'class-wp-widget-pages.php' => array(),
'class-wp-widget-text.php' => array(),
'class-wp-widget-custom-html.php' => array(),
'class-wp-widget-recent-comments.php' => array(),
'class-wp-widget-tag-cloud.php' => array(),
'class-wp-widget-links.php' => array(),
'class-wp-widget-media-video.php' => array(),
'class-wp-widget-archives.php' => array(),
'class-wp-widget-search.php' => array(),
'class-wp-widget-calendar.php' => array(),
'class-wp-widget-meta.php' => array(),
'class-wp-widget-media.php' => array(),
'class-wp-nav-menu-widget.php' => array(),
'class-wp-widget-media-audio.php' => array(),
'class-wp-widget-recent-posts.php' => array(),
'class-wp-widget-categories.php' => array(),
'class-wp-widget-rss.php' => array(),
'class-wp-widget-media-image.php' => array(),
'class-wp-widget-media-gallery.php' => array()
),
'class-wp-paused-extensions-storage.php' => array(),
'class-walker-page-dropdown.php' => array(),
'class-wp-text-diff-renderer-inline.php' => array(),
'theme-compat' => array(
'sidebar.php' => array(),
'embed-404.php' => array(),
'embed-content.php' => array(),
'footer-embed.php' => array(),
'header-embed.php' => array(),
'header.php' => array(),
'footer.php' => array(),
'embed.php' => array(),
'comments.php' => array(),
'comments-popup.php' => array()
),
'class-phpmailer.php' => array(),
'class-wp-post-type.php' => array(),
'class-wp-locale-switcher.php' => array(),
'load.php' => array(),
'class-wp-recovery-mode-cookie-service.php' => array(),
'class-wp-role.php' => array(),
'pluggable-deprecated.php' => array(),
'class-wp-oembed-controller.php' => array(),
'class-wp-term.php' => array(),
'class-smtp.php' => array(),
'capabilities.php' => array(),
'IXR' => array(
'class-IXR-server.php' => array(),
'class-IXR-date.php' => array(),
'class-IXR-request.php' => array(),
'class-IXR-error.php' => array(),
'class-IXR-client.php' => array(),
'class-IXR-base64.php' => array(),
'class-IXR-clientmulticall.php' => array(),
'class-IXR-value.php' => array(),
'class-IXR-message.php' => array(),
'class-IXR-introspectionserver.php' => array()
),
'class-wp-text-diff-renderer-table.php' => array(),
'class-wp-xmlrpc-server.php' => array(),
'class-wp-site-query.php' => array(),
'class-wp-admin-bar.php' => array(),
'session.php' => array(),
'class-wp-block-type-registry.php' => array(),
'rewrite.php' => array(),
'registration-functions.php' => array(),
'option.php' => array(),
'class-walker-comment.php' => array(),
'post-formats.php' => array(),
'class-wp-customize-setting.php' => array(),
'pluggable.php' => array(),
'class-wp-block-type.php' => array(),
'class-wp-http-response.php' => array(),
'class-wp-error.php' => array(),
'deprecated.php' => array(),
'blocks' => array(
'pullquote' => array(
'block.json' => array()
),
'gallery' => array(
'block.json' => array()
),
'code' => array(
'block.json' => array()
),
'more' => array(
'block.json' => array()
),
'social-link.php' => array(),
'image' => array(
'block.json' => array()
),
'latest-posts' => array(
'block.json' => array()
),
'block' => array(
'block.json' => array()
),
'media-text' => array(
'block.json' => array()
),
'archives.php' => array(),
'spacer' => array(
'block.json' => array()
),
'buttons' => array(
'block.json' => array()
),
'video' => array(
'block.json' => array()
),
'subhead' => array(
'block.json' => array()
),
'audio' => array(
'block.json' => array()
),
'table' => array(
'block.json' => array()
),
'latest-comments.php' => array(),
'social-links' => array(
'block.json' => array()
),
'button' => array(
'block.json' => array()
),
'rss' => array(
'block.json' => array()
),
'columns' => array(
'block.json' => array()
),
'calendar.php' => array(),
'calendar' => array(
'block.json' => array()
),
'quote' => array(
'block.json' => array()
),
'text-columns' => array(
'block.json' => array()
),
'separator' => array(
'block.json' => array()
),
'archives' => array(
'block.json' => array()
),
'social-link' => array(
'block.json' => array()
),
'missing' => array(
'block.json' => array()
),
'shortcode.php' => array(),
'verse' => array(
'block.json' => array()
),
'categories' => array(
'block.json' => array()
),
'classic' => array(
'block.json' => array()
),
'tag-cloud' => array(
'block.json' => array()
),
'latest-posts.php' => array(),
'rss.php' => array(),
'shortcode' => array(
'block.json' => array()
),
'file' => array(
'block.json' => array()
),
'categories.php' => array(),
'index.php' => array(),
'search' => array(
'block.json' => array()
),
'list' => array(
'block.json' => array()
),
'column' => array(
'block.json' => array()
),
'group' => array(
'block.json' => array()
),
'preformatted' => array(
'block.json' => array()
),
'html' => array(
'block.json' => array()
),
'nextpage' => array(
'block.json' => array()
),
'latest-comments' => array(
'block.json' => array()
),
'block.php' => array(),
'heading' => array(
'block.json' => array()
),
'search.php' => array(),
'tag-cloud.php' => array(),
'paragraph' => array(
'block.json' => array()
)
),
'default-filters.php' => array(),
'ms-load.php' => array(),
'class-wp-feed-cache.php' => array(),
'plugin.php' => array(),
'fonts' => array(
'dashicons.svg' => array(),
'dashicons.woff2' => array(),
'dashicons.ttf' => array(),
'dashicons.woff' => array(),
'dashicons.eot' => array()
),
'query.php' => array(),
'class-pop3.php' => array(),
'class-wp-user-request.php' => array(),
'class-wp-user-meta-session-tokens.php' => array(),
'class-wp-oembed.php' => array(),
'class-wp-editor.php' => array(),
'class-wp-image-editor-gd.php' => array(),
'class.wp-scripts.php' => array(),
'class-walker-nav-menu.php' => array(),
'author-template.php' => array(),
'ms-blogs.php' => array(),
'class-wp-simplepie-sanitize-kses.php' => array(),
'class-wp-walker.php' => array(),
'taxonomy.php' => array(),
'compat.php' => array(),
'class-wp-block.php' => array(),
'category.php' => array(),
'atomlib.php' => array(),
'class.wp-dependencies.php' => array(),
'class-wp-recovery-mode.php' => array(),
'Requests' => array(
'Utility' => array(
'CaseInsensitiveDictionary.php' => array(),
'FilteredIterator.php' => array()
),
'IDNAEncoder.php' => array(),
'Transport' => array(
'cURL.php' => array(),
'fsockopen.php' => array()
),
'Proxy.php' => array(),
'IPv6.php' => array(),
'Exception.php' => array(),
'Hooks.php' => array(),
'Proxy' => array(
'HTTP.php' => array()
),
'Response.php' => array(),
'IRI.php' => array(),
'SSL.php' => array(),
'Auth' => array(
'Basic.php' => array()
),
'Response' => array(
'Headers.php' => array()
),
'Session.php' => array(),
'Exception' => array(
'Transport' => array(
'cURL.php' => array()
),
'HTTP' => array(
'431.php' => array(),
'415.php' => array(),
'428.php' => array(),
'414.php' => array(),
'408.php' => array(),
'417.php' => array(),
'502.php' => array(),
'306.php' => array(),
'412.php' => array(),
'410.php' => array(),
'416.php' => array(),
'505.php' => array(),
'401.php' => array(),
'305.php' => array(),
'404.php' => array(),
'403.php' => array(),
'411.php' => array(),
'500.php' => array(),
'429.php' => array(),
'504.php' => array(),
'402.php' => array(),
'501.php' => array(),
'405.php' => array(),
'409.php' => array(),
'406.php' => array(),
'413.php' => array(),
'304.php' => array(),
'418.php' => array(),
'511.php' => array(),
'407.php' => array(),
'503.php' => array(),
'400.php' => array(),
'Unknown.php' => array()
),
'HTTP.php' => array(),
'Transport.php' => array()
),
'Auth.php' => array(),
'Cookie' => array(
'Jar.php' => array()
),
'Transport.php' => array(),
'Cookie.php' => array(),
'Hooker.php' => array()
),
'revision.php' => array(),
'wp-diff.php' => array(),
'class-wp-roles.php' => array(),
'sitemaps' => array(
'class-wp-sitemaps-index.php' => array(),
'class-wp-sitemaps-renderer.php' => array(),
'class-wp-sitemaps-stylesheet.php' => array(),
'class-wp-sitemaps-registry.php' => array(),
'class-wp-sitemaps.php' => array(),
'class-wp-sitemaps-provider.php' => array(),
'providers' => array(
'class-wp-sitemaps-posts.php' => array(),
'class-wp-sitemaps-taxonomies.php' => array(),
'class-wp-sitemaps-users.php' => array()
)
),
'js' => array(
'hoverIntent.js' => array(),
'wp-a11y.min.js' => array(),
'media-audiovideo.js' => array(),
'zxcvbn-async.js' => array(),
'media-models.js' => array(),
'twemoji.js' => array(),
'wp-pointer.js' => array(),
'customize-preview-nav-menus.min.js' => array(),
'wp-pointer.min.js' => array(),
'json2.min.js' => array(),
'backbone.js' => array(),
'swfupload' => array(
'handlers.js' => array(),
'license.txt' => array(),
'handlers.min.js' => array(),
'swfupload.js' => array(),
'plugins' => array(
'swfupload.swfobject.js' => array(),
'swfupload.cookies.js' => array(),
'swfupload.queue.js' => array(),
'swfupload.speed.js' => array()
),
'swfupload.swf' => array()
),
'twemoji.min.js' => array(),
'mce-view.min.js' => array(),
'swfobject.js' => array(),
'colorpicker.min.js' => array(),
'wp-emoji.js' => array(),
'customize-preview-widgets.min.js' => array(),
'zxcvbn.min.js' => array(),
'wp-ajax-response.js' => array(),
'wp-util.js' => array(),
'underscore.js' => array(),
'wp-emoji.min.js' => array(),
'customize-preview-nav-menus.js' => array(),
'underscore.min.js' => array(),
'admin-bar.min.js' => array(),
'wp-sanitize.js' => array(),
'imagesloaded.min.js' => array(),
'thickbox' => array(
'loadingAnimation.gif' => array(),
'thickbox.css' => array(),
'thickbox.js' => array(),
'macFFBgHack.png' => array()
),
'wplink.min.js' => array(),
'tinymce' => array(
'wp-mce-help.php' => array(),
'themes' => array(
'modern' => array(
'theme.js' => array(),
'theme.min.js' => array()
),
'inlite' => array(
'theme.js' => array(),
'theme.min.js' => array()
)
),
'wp-tinymce.js' => array(),
'langs' => array(
'wp-langs-en.js' => array()
),
'wp-tinymce.js.gz' => array(),
'license.txt' => array(),
'utils' => array(
'mctabs.js' => array(),
'form_utils.js' => array(),
'editable_selects.js' => array(),
'validate.js' => array()
),
'plugins' => array(
'wordpress' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'directionality' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'image' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'wpview' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'wpeditimage' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'hr' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'lists' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'wpfullscreen' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'wptextpattern' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'link' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'fullscreen' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'wpembed' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'wplink' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'wpdialogs' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'textcolor' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'wpemoji' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'colorpicker' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'paste' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'compat3x' => array(
'css' => array(
'dialog.css' => array()
),
'plugin.js' => array(),
'plugin.min.js' => array()
),
'charmap' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'tabfocus' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'wpgallery' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
),
'media' => array(
'plugin.js' => array(),
'moxieplayer.swf' => array(),
'plugin.min.js' => array()
),
'wpautoresize' => array(
'plugin.js' => array(),
'plugin.min.js' => array()
)
),
'wp-tinymce.php' => array(),
'tiny_mce_popup.js' => array(),
'skins' => array(
'wordpress' => array(
'wp-content.css' => array(),
'images' => array(
'gallery-2x.png' => array(),
'playlist-video.png' => array(),
'more-2x.png' => array(),
'pagebreak.png' => array(),
'audio.png' => array(),
'playlist-audio.png' => array(),
'dashicon-no-alt.png' => array(),
'dashicon-no.png' => array(),
'dashicon-edit.png' => array(),
'embedded.png' => array(),
'video.png' => array(),
'pagebreak-2x.png' => array(),
'gallery.png' => array(),
'more.png' => array()
)
),
'lightgray' => array(
'content.inline.min.css' => array(),
'content.min.css' => array(),
'skin.ie7.min.css' => array(),
'fonts' => array(
'tinymce-small.json' => array(),
'tinymce.ttf' => array(),
'tinymce-small.svg' => array(),
'tinymce-small.woff' => array(),
'tinymce.json' => array(),
'readme.md' => array(),
'tinymce.svg' => array(),
'tinymce.woff' => array(),
'tinymce-small.ttf' => array(),
'tinymce-small.eot' => array(),
'tinymce.eot' => array()
),
'img' => array(
'loader.gif' => array(),
'object.gif' => array(),
'trans.gif' => array(),
'anchor.gif' => array()
),
'skin.min.css' => array()
)
),
'tinymce.min.js' => array()
),
'wp-emoji-release.min.js' => array(),
'wp-emoji-loader.min.js' => array(),
'wp-list-revisions.min.js' => array(),
'wp-auth-check.js' => array(),
'api-request.min.js' => array(),
'customize-models.js' => array(),
'clipboard.min.js' => array(),
'customize-preview.min.js' => array(),
'quicktags.js' => array(),
'wp-list-revisions.js' => array(),
'customize-models.min.js' => array(),
'wp-util.min.js' => array(),
'customize-preview-widgets.js' => array(),
'admin-bar.js' => array(),
'wpdialog.min.js' => array(),
'wp-lists.min.js' => array(),
'wp-emoji-loader.js' => array(),
'clipboard.js' => array(),
'autosave.min.js' => array(),
'quicktags.min.js' => array(),
'customize-selective-refresh.js' => array(),
'jcrop' => array(
'Jcrop.gif' => array(),
'jquery.Jcrop.min.js' => array(),
'jquery.Jcrop.min.css' => array()
),
'wp-backbone.js' => array(),
'media-editor.js' => array(),
'media-editor.min.js' => array(),
'plupload' => array(
'handlers.js' => array(),
'moxie.js' => array(),
'moxie.min.js' => array(),
'license.txt' => array(),
'plupload.flash.swf' => array(),
'wp-plupload.min.js' => array(),
'handlers.min.js' => array(),
'plupload.full.min.js' => array(),
'wp-plupload.js' => array(),
'plupload.silverlight.xap' => array(),
'plupload.js' => array(),
'plupload.min.js' => array()
),
'media-grid.js' => array(),
'hoverintent-js.min.js' => array(),
'media-views.min.js' => array(),
'wp-embed.js' => array(),
'heartbeat.min.js' => array(),
'wp-api.min.js' => array(),
'customize-views.js' => array(),
'customize-loader.js' => array(),
'autosave.js' => array(),
'crop' => array(
'cropper.js' => array(),
'cropper.css' => array(),
'marqueeHoriz.gif' => array(),
'marqueeVert.gif' => array()
),
'wp-auth-check.min.js' => array(),
'jquery' => array(
'jquery.js' => array(),
'jquery.form.min.js' => array(),
'jquery.ui.touch-punch.js' => array(),
'jquery.table-hotkeys.js' => array(),
'jquery.query.js' => array(),
'jquery.hotkeys.min.js' => array(),
'jquery-migrate.min.js' => array(),
'jquery.schedule.js' => array(),
'jquery.hotkeys.js' => array(),
'suggest.js' => array(),
'jquery-migrate.js' => array(),
'jquery.form.js' => array(),
'ui' => array(
'jquery.ui.dialog.min.js' => array(),
'jquery.ui.menu.min.js' => array(),
'progressbar.min.js' => array(),
'jquery.ui.core.min.js' => array(),
'spinner.min.js' => array(),
'dialog.min.js' => array(),
'jquery.ui.position.min.js' => array(),
'jquery.ui.effect-drop.min.js' => array(),
'accordion.min.js' => array(),
'effect-clip.min.js' => array(),
'jquery.ui.sortable.min.js' => array(),
'jquery.ui.effect.min.js' => array(),
'effect-explode.min.js' => array(),
'jquery.ui.effect-transfer.min.js' => array(),
'jquery.ui.draggable.min.js' => array(),
'draggable.min.js' => array(),
'effect-fold.min.js' => array(),
'jquery.ui.spinner.min.js' => array(),
'effect-fade.min.js' => array(),
'droppable.min.js' => array(),
'effect.min.js' => array(),
'effect-drop.min.js' => array(),
'jquery.ui.effect-slide.min.js' => array(),
'selectable.min.js' => array(),
'tooltip.min.js' => array(),
'effect-shake.min.js' => array(),
'effect-highlight.min.js' => array(),
'jquery.ui.datepicker.min.js' => array(),
'effect-blind.min.js' => array(),
'sortable.min.js' => array(),
'position.min.js' => array(),
'jquery.ui.effect-pulsate.min.js' => array(),
'jquery.ui.mouse.min.js' => array(),
'jquery.ui.effect-explode.min.js' => array(),
'jquery.ui.autocomplete.min.js' => array(),
'effect-size.min.js' => array(),
'jquery.ui.effect-bounce.min.js' => array(),
'core.min.js' => array(),
'jquery.ui.progressbar.min.js' => array(),
'effect-puff.min.js' => array(),
'jquery.ui.selectable.min.js' => array(),
'effect-transfer.min.js' => array(),
'menu.min.js' => array(),
'jquery.ui.tabs.min.js' => array(),
'resizable.min.js' => array(),
'jquery.ui.effect-highlight.min.js' => array(),
'jquery.ui.tooltip.min.js' => array(),
'jquery.ui.droppable.min.js' => array(),
'mouse.min.js' => array(),
'jquery.ui.effect-fade.min.js' => array(),
'jquery.ui.effect-clip.min.js' => array(),
'jquery.ui.accordion.min.js' => array(),
'jquery.ui.resizable.min.js' => array(),
'effect-pulsate.min.js' => array(),
'effect-bounce.min.js' => array(),
'widget.min.js' => array(),
'jquery.ui.effect-blind.min.js' => array(),
'tabs.min.js' => array(),
'datepicker.min.js' => array(),
'button.min.js' => array(),
'selectmenu.min.js' => array(),
'jquery.ui.effect-shake.min.js' => array(),
'slider.min.js' => array(),
'effect-scale.min.js' => array(),
'jquery.ui.slider.min.js' => array(),
'jquery.ui.effect-scale.min.js' => array(),
'jquery.ui.button.min.js' => array(),
'effect-slide.min.js' => array(),
'jquery.ui.widget.min.js' => array(),
'autocomplete.min.js' => array(),
'jquery.ui.effect-fold.min.js' => array()
),
'jquery.table-hotkeys.min.js' => array(),
'suggest.min.js' => array(),
'jquery.serialize-object.js' => array(),
'jquery.masonry.min.js' => array(),
'jquery.color.min.js' => array()
),
'wpdialog.js' => array(),
'shortcode.js' => array(),
'colorpicker.js' => array(),
'tw-sack.min.js' => array(),
'heartbeat.js' => array(),
'wp-api.js' => array(),
'customize-base.js' => array(),
'media-models.min.js' => array(),
'wp-custom-header.js' => array(),
'media-audiovideo.min.js' => array(),
'mce-view.js' => array(),
'media-views.js' => array(),
'wp-embed-template.js' => array(),
'hoverIntent.min.js' => array(),
'wp-embed.min.js' => array(),
'utils.min.js' => array(),
'customize-views.min.js' => array(),
'customize-base.min.js' => array(),
'customize-selective-refresh.min.js' => array(),
'wp-ajax-response.min.js' => array(),
'zxcvbn-async.min.js' => array(),
'wp-lists.js' => array(),
'comment-reply.min.js' => array(),
'wp-embed-template.min.js' => array(),
'wp-backbone.min.js' => array(),
'wp-a11y.js' => array(),
'backbone.min.js' => array(),
'dist' => array(
'api-fetch.js' => array(),
'notices.min.js' => array(),
'data-controls.min.js' => array(),
'wordcount.min.js' => array(),
'editor.min.js' => array(),
'rich-text.js' => array(),
'dom.js' => array(),
'element.js' => array(),
'blocks.min.js' => array(),
'components.min.js' => array(),
'editor.js' => array(),
'blob.min.js' => array(),
'components.js' => array(),
'url.js' => array(),
'i18n.min.js' => array(),
'data-controls.js' => array(),
'deprecated.js' => array(),
'priority-queue.js' => array(),
'token-list.min.js' => array(),
'dom-ready.js' => array(),
'a11y.min.js' => array(),
'element.min.js' => array(),
'keycodes.js' => array(),
'list-reusable-blocks.js' => array(),
'autop.js' => array(),
'warning.js' => array(),
'escape-html.js' => array(),
'blob.js' => array(),
'block-directory.min.js' => array(),
'dom-ready.min.js' => array(),
'annotations.js' => array(),
'viewport.js' => array(),
'viewport.min.js' => array(),
'server-side-render.js' => array(),
'autop.min.js' => array(),
'compose.js' => array(),
'plugins.js' => array(),
'block-directory.js' => array(),
'primitives.js' => array(),
'block-editor.min.js' => array(),
'primitives.min.js' => array(),
'keyboard-shortcuts.js' => array(),
'html-entities.min.js' => array(),
'notices.js' => array(),
'wordcount.js' => array(),
'core-data.js' => array(),
'compose.min.js' => array(),
'warning.min.js' => array(),
'url.min.js' => array(),
'block-serialization-default-parser.js' => array(),
'data.min.js' => array(),
'edit-post.js' => array(),
'server-side-render.min.js' => array(),
'redux-routine.min.js' => array(),
'i18n.js' => array(),
'redux-routine.js' => array(),
'escape-html.min.js' => array(),
'edit-post.min.js' => array(),
'shortcode.js' => array(),
'token-list.js' => array(),
'date.min.js' => array(),
'hooks.min.js' => array(),
'html-entities.js' => array(),
'core-data.min.js' => array(),
'keycodes.min.js' => array(),
'priority-queue.min.js' => array(),
'blocks.js' => array(),
'format-library.min.js' => array(),
'is-shallow-equal.min.js' => array(),
'date.js' => array(),
'list-reusable-blocks.min.js' => array(),
'block-library.js' => array(),
'plugins.min.js' => array(),
'nux.min.js' => array(),
'media-utils.js' => array(),
'is-shallow-equal.js' => array(),
'media-utils.min.js' => array(),
'dom.min.js' => array(),
'vendor' => array(
'moment.min.js' => array(),
'wp-polyfill-element-closest.min.js' => array(),
'wp-polyfill-fetch.js' => array(),
'wp-polyfill-node-contains.js' => array(),
'moment.js' => array(),
'wp-polyfill-url.js' => array(),
'react.js' => array(),
'wp-polyfill.min.js' => array(),
'wp-polyfill-formdata.js' => array(),
'wp-polyfill-element-closest.js' => array(),
'wp-polyfill-dom-rect.min.js' => array(),
'react.min.js' => array(),
'wp-polyfill-dom-rect.js' => array(),
'lodash.min.js' => array(),
'wp-polyfill-fetch.min.js' => array(),
'react-dom.min.js' => array(),
'wp-polyfill-formdata.min.js' => array(),
'wp-polyfill-node-contains.min.js' => array(),
'react-dom.js' => array(),
'wp-polyfill-url.min.js' => array(),
'wp-polyfill.js' => array(),
'lodash.js' => array()
),
'annotations.min.js' => array(),
'block-editor.js' => array(),
'data.js' => array(),
'rich-text.min.js' => array(),
'hooks.js' => array(),
'api-fetch.min.js' => array(),
'a11y.js' => array(),
'block-serialization-default-parser.min.js' => array(),
'shortcode.min.js' => array(),
'format-library.js' => array(),
'block-library.min.js' => array(),
'deprecated.min.js' => array(),
'nux.js' => array(),
'keyboard-shortcuts.min.js' => array()
),
'api-request.js' => array(),
'customize-loader.min.js' => array(),
'imgareaselect' => array(
'jquery.imgareaselect.js' => array(),
'jquery.imgareaselect.min.js' => array(),
'border-anim-v.gif' => array(),
'border-anim-h.gif' => array(),
'imgareaselect.css' => array()
),
'customize-preview.js' => array(),
'utils.js' => array(),
'wplink.js' => array(),
'comment-reply.js' => array(),
'mediaelement' => array(
'controls.png' => array(),
'mediaelement-migrate.js' => array(),
'renderers' => array(
'vimeo.js' => array(),
'vimeo.min.js' => array()
),
'mediaelement-migrate.min.js' => array(),
'mediaelementplayer-legacy.min.css' => array(),
'jumpforward.png' => array(),
'skipback.png' => array(),
'wp-mediaelement.css' => array(),
'background.png' => array(),
'mediaelement-and-player.min.js' => array(),
'mediaelement.min.js' => array(),
'mejs-controls.svg' => array(),
'mediaelementplayer.min.css' => array(),
'bigplay.png' => array(),
'controls.svg' => array(),
'wp-mediaelement.js' => array(),
'mediaelement.js' => array(),
'mediaelementplayer-legacy.css' => array(),
'mejs-controls.png' => array(),
'mediaelement-and-player.js' => array(),
'wp-mediaelement.min.js' => array(),
'wp-playlist.js' => array(),
'bigplay.svg' => array(),
'wp-mediaelement.min.css' => array(),
'mediaelementplayer.css' => array(),
'wp-playlist.min.js' => array(),
'loading.gif' => array(),
'froogaloop.min.js' => array()
),
'media-grid.min.js' => array(),
'wp-custom-header.min.js' => array(),
'masonry.min.js' => array(),
'shortcode.min.js' => array(),
'wp-sanitize.min.js' => array(),
'tw-sack.js' => array(),
'json2.js' => array(),
'codemirror' => array(
'esprima.js' => array(),
'htmlhint-kses.js' => array(),
'csslint.js' => array(),
'jsonlint.js' => array(),
'codemirror.min.css' => array(),
'codemirror.min.js' => array(),
'fakejshint.js' => array(),
'htmlhint.js' => array(),
'jshint.js' => array()
)
),
'css' => array(
'wp-embed-template.min.css' => array(),
'admin-bar-rtl.css' => array(),
'wp-auth-check.min.css' => array(),
'buttons.min.css' => array(),
'wp-embed-template-ie.min.css' => array(),
'dashicons.css' => array(),
'buttons.css' => array(),
'editor.min.css' => array(),
'buttons-rtl.css' => array(),
'jquery-ui-dialog.css' => array(),
'dashicons.min.css' => array(),
'jquery-ui-dialog-rtl.min.css' => array(),
'wp-embed-template-ie.css' => array(),
'customize-preview.css' => array(),
'editor.css' => array(),
'editor-rtl.css' => array(),
'admin-bar.min.css' => array(),
'wp-auth-check-rtl.min.css' => array(),
'admin-bar-rtl.min.css' => array(),
'wp-pointer.min.css' => array(),
'wp-pointer-rtl.css' => array(),
'admin-bar.css' => array(),
'customize-preview-rtl.min.css' => array(),
'jquery-ui-dialog.min.css' => array(),
'wp-pointer-rtl.min.css' => array(),
'wp-pointer.css' => array(),
'editor-rtl.min.css' => array(),
'media-views.min.css' => array(),
'customize-preview-rtl.css' => array(),
'media-views-rtl.min.css' => array(),
'buttons-rtl.min.css' => array(),
'jquery-ui-dialog-rtl.css' => array(),
'wp-embed-template.css' => array(),
'dist' => array(
'list-reusable-blocks' => array(
'style-rtl.min.css' => array(),
'style.css' => array(),
'style-rtl.css' => array(),
'style.min.css' => array()
),
'format-library' => array(
'style-rtl.min.css' => array(),
'style.css' => array(),
'style-rtl.css' => array(),
'style.min.css' => array()
),
'nux' => array(
'style-rtl.min.css' => array(),
'style.css' => array(),
'style-rtl.css' => array(),
'style.min.css' => array()
),
'edit-post' => array(
'style-rtl.min.css' => array(),
'style.css' => array(),
'style-rtl.css' => array(),
'style.min.css' => array()
),
'block-directory' => array(
'style-rtl.min.css' => array(),
'style.css' => array(),
'style-rtl.css' => array(),
'style.min.css' => array()
),
'editor' => array(
'style-rtl.min.css' => array(),
'editor-styles-rtl.css' => array(),
'editor-styles-rtl.min.css' => array(),
'editor-styles.min.css' => array(),
'style.css' => array(),
'style-rtl.css' => array(),
'editor-styles.css' => array(),
'style.min.css' => array()
),
'block-library' => array(
'style-rtl.min.css' => array(),
'editor.min.css' => array(),
'editor.css' => array(),
'theme-rtl.css' => array(),
'editor-rtl.css' => array(),
'theme-rtl.min.css' => array(),
'editor-rtl.min.css' => array(),
'theme.css' => array(),
'style.css' => array(),
'style-rtl.css' => array(),
'theme.min.css' => array(),
'style.min.css' => array()
),
'block-editor' => array(
'style-rtl.min.css' => array(),
'style.css' => array(),
'style-rtl.css' => array(),
'style.min.css' => array()
),
'components' => array(
'style-rtl.min.css' => array(),
'style.css' => array(),
'style-rtl.css' => array(),
'style.min.css' => array()
)
),
'media-views-rtl.css' => array(),
'customize-preview.min.css' => array(),
'wp-auth-check.css' => array(),
'media-views.css' => array(),
'wp-auth-check-rtl.css' => array()
),
'bookmark-template.php' => array(),
'rest-api.php' => array(),
'class-http.php' => array(),
'post-template.php' => array(),
'user.php' => array(),
'class-wp-comment.php' => array(),
'class-wp-customize-section.php' => array(),
'registration.php' => array(),
'Text' => array(
'Diff.php' => array(),
'Diff' => array(
'Engine' => array(
'string.php' => array(),
'xdiff.php' => array(),
'native.php' => array(),
'shell.php' => array()
),
'Renderer.php' => array(),
'Renderer' => array(
'inline.php' => array()
)
)
),
'class-json.php' => array(),
'shortcodes.php' => array(),
'vars.php' => array(),
'spl-autoload-compat.php' => array(),
'class-wp-taxonomy.php' => array(),
'class-wp-site.php' => array(),
'post.php' => array(),
'version.php' => array(),
'ms-files.php' => array(),
'certificates' => array(
'ca-bundle.crt' => array()
),
'admin-bar.php' => array(),
'class-wp-meta-query.php' => array(),
'link-template.php' => array(),
'class-snoopy.php' => array(),
'class-wp-image-editor.php' => array(),
'class-wp-widget.php' => array(),
'feed-atom-comments.php' => array(),
'class-wp-http-streams.php' => array(),
'functions.wp-scripts.php' => array(),
'rss.php' => array(),
'PHPMailer' => array(
'PHPMailer.php' => array(),
'Exception.php' => array(),
'SMTP.php' => array()
),
'class-wp-feed-cache-transient.php' => array(),
'class-wp-user.php' => array(),
'post-thumbnail-template.php' => array(),
'class-wp-recovery-mode-link-service.php' => array(),
'class-IXR.php' => array(),
'general-template.php' => array(),
'ms-site.php' => array(),
'wlwmanifest.xml' => array(),
'class-wp-session-tokens.php' => array(),
'rest-api' => array(
'class-wp-rest-response.php' => array(),
'fields' => array(
'class-wp-rest-term-meta-fields.php' => array(),
'class-wp-rest-post-meta-fields.php' => array(),
'class-wp-rest-meta-fields.php' => array(),
'class-wp-rest-user-meta-fields.php' => array(),
'class-wp-rest-comment-meta-fields.php' => array()
),
'endpoints' => array(
'class-wp-rest-block-renderer-controller.php' => array(),
'class-wp-rest-block-types-controller.php' => array(),
'class-wp-rest-taxonomies-controller.php' => array(),
'class-wp-rest-search-controller.php' => array(),
'class-wp-rest-terms-controller.php' => array(),
'class-wp-rest-autosaves-controller.php' => array(),
'class-wp-rest-posts-controller.php' => array(),
'class-wp-rest-blocks-controller.php' => array(),
'class-wp-rest-block-directory-controller.php' => array(),
'class-wp-rest-settings-controller.php' => array(),
'class-wp-rest-post-statuses-controller.php' => array(),
'class-wp-rest-post-types-controller.php' => array(),
'class-wp-rest-comments-controller.php' => array(),
'class-wp-rest-themes-controller.php' => array(),
'class-wp-rest-plugins-controller.php' => array(),
'class-wp-rest-attachments-controller.php' => array(),
'class-wp-rest-revisions-controller.php' => array(),
'class-wp-rest-users-controller.php' => array(),
'class-wp-rest-controller.php' => array()
),
'search' => array(
'class-wp-rest-search-handler.php' => array(),
'class-wp-rest-post-search-handler.php' => array()
),
'class-wp-rest-server.php' => array(),
'class-wp-rest-request.php' => array()
),
'media-template.php' => array(),
'class-wp.php' => array(),
'images' => array(
'blank.gif' => array(),
'wpicons-2x.png' => array(),
'toggle-arrow.png' => array(),
'rss.png' => array(),
'w-logo-blue-white-bg.png' => array(),
'xit-2x.gif' => array(),
'uploader-icons-2x.png' => array(),
'wlw' => array(
'wp-comments.png' => array(),
'wp-watermark.png' => array(),
'wp-icon.png' => array()
),
'arrow-pointer-blue.png' => array(),
'down_arrow.gif' => array(),
'admin-bar-sprite-2x.png' => array(),
'crystal' => array(
'document.png' => array(),
'audio.png' => array(),
'license.txt' => array(),
'default.png' => array(),
'text.png' => array(),
'interactive.png' => array(),
'spreadsheet.png' => array(),
'archive.png' => array(),
'video.png' => array(),
'code.png' => array()
),
'uploader-icons.png' => array(),
'w-logo-blue.png' => array(),
'down_arrow-2x.gif' => array(),
'xit.gif' => array(),
'wpspin-2x.gif' => array(),
'wpicons.png' => array(),
'arrow-pointer-blue-2x.png' => array(),
'toggle-arrow-2x.png' => array(),
'rss-2x.png' => array(),
'media' => array(
'document.png' => array(),
'audio.png' => array(),
'default.png' => array(),
'text.png' => array(),
'interactive.png' => array(),
'spreadsheet.png' => array(),
'archive.png' => array(),
'video.png' => array(),
'code.png' => array()
),
'spinner-2x.gif' => array(),
'smilies' => array(
'icon_sad.gif' => array(),
'icon_question.gif' => array(),
'mrgreen.png' => array(),
'icon_mrgreen.gif' => array(),
'icon_surprised.gif' => array(),
'frownie.png' => array(),
'icon_razz.gif' => array(),
'simple-smile.png' => array(),
'icon_neutral.gif' => array(),
'icon_eek.gif' => array(),
'icon_confused.gif' => array(),
'icon_biggrin.gif' => array(),
'icon_exclaim.gif' => array(),
'icon_idea.gif' => array(),
'icon_mad.gif' => array(),
'icon_cool.gif' => array(),
'icon_rolleyes.gif' => array(),
'rolleyes.png' => array(),
'icon_redface.gif' => array(),
'icon_wink.gif' => array(),
'icon_lol.gif' => array(),
'icon_arrow.gif' => array(),
'icon_evil.gif' => array(),
'icon_cry.gif' => array(),
'icon_smile.gif' => array(),
'icon_twisted.gif' => array()
),
'spinner.gif' => array(),
'admin-bar-sprite.png' => array(),
'icon-pointer-flag.png' => array(),
'icon-pointer-flag-2x.png' => array(),
'wpspin.gif' => array()
),
'template-loader.php' => array(),
'class-wp-embed.php' => array(),
'rss-functions.php' => array(),
'class-wp-http-requests-response.php' => array(),
'class-wp-ajax-response.php' => array(),
'date.php' => array(),
'class-wp-simplepie-file.php' => array(),
'meta.php' => array(),
'kses.php' => array(),
'class-wp-tax-query.php' => array(),
'class-wp-network-query.php' => array(),
'class-wp-hook.php' => array(),
'ms-deprecated.php' => array(),
'class-walker-category-dropdown.php' => array(),
'class-wp-rewrite.php' => array(),
'class-simplepie.php' => array(),
'class.wp-styles.php' => array(),
'comment.php' => array(),
'sitemaps.php' => array(),
'pomo' => array(
'entry.php' => array(),
'mo.php' => array(),
'translations.php' => array(),
'streams.php' => array(),
'po.php' => array(),
'plural-forms.php' => array()
),
'class-wp-customize-panel.php' => array(),
'class-wp-http-cookie.php' => array(),
'ms-default-filters.php' => array(),
'class-walker-page.php' => array(),
'bookmark.php' => array(),
'customize' => array(
'class-wp-customize-background-image-setting.php' => array(),
'class-wp-customize-nav-menu-setting.php' => array(),
'class-wp-customize-filter-setting.php' => array(),
'class-wp-customize-date-time-control.php' => array(),
'class-wp-customize-header-image-control.php' => array(),
'class-wp-customize-nav-menus-panel.php' => array(),
'class-wp-customize-nav-menu-item-control.php' => array(),
'class-wp-customize-nav-menu-control.php' => array(),
'class-wp-customize-custom-css-setting.php' => array(),
'class-wp-widget-form-customize-control.php' => array(),
'class-wp-customize-code-editor-control.php' => array(),
'class-wp-widget-area-customize-control.php' => array(),
'class-wp-customize-new-menu-control.php' => array(),
'class-wp-customize-theme-control.php' => array(),
'class-wp-customize-new-menu-section.php' => array(),
'class-wp-customize-site-icon-control.php' => array(),
'class-wp-customize-cropped-image-control.php' => array(),
'class-wp-customize-upload-control.php' => array(),
'class-wp-customize-image-control.php' => array(),
'class-wp-customize-nav-menu-section.php' => array(),
'class-wp-customize-background-image-control.php' => array(),
'class-wp-customize-header-image-setting.php' => array(),
'class-wp-customize-nav-menu-location-control.php' => array(),
'class-wp-customize-partial.php' => array(),
'class-wp-customize-nav-menu-auto-add-control.php' => array(),
'class-wp-customize-sidebar-section.php' => array(),
'class-wp-customize-themes-section.php' => array(),
'class-wp-customize-themes-panel.php' => array(),
'class-wp-customize-nav-menu-item-setting.php' => array(),
'class-wp-customize-nav-menu-name-control.php' => array(),
'class-wp-customize-nav-menu-locations-control.php' => array(),
'class-wp-customize-background-position-control.php' => array(),
'class-wp-customize-color-control.php' => array(),
'class-wp-customize-media-control.php' => array(),
'class-wp-customize-selective-refresh.php' => array()
),
'class-wp-customize-control.php' => array(),
'class-wp-locale.php' => array(),
'theme.php' => array(),
'class-wp-user-query.php' => array(),
'class-wp-http-ixr-client.php' => array(),
'ms-functions.php' => array(),
'SimplePie' => array(
'Locator.php' => array(),
'Author.php' => array(),
'Sanitize.php' => array(),
'Registry.php' => array(),
'Caption.php' => array(),
'HTTP' => array(
'Parser.php' => array()
),
'Item.php' => array(),
'Exception.php' => array(),
'File.php' => array(),
'Rating.php' => array(),
'Restriction.php' => array(),
'IRI.php' => array(),
'Parser.php' => array(),
'Enclosure.php' => array(),
'Cache.php' => array(),
'XML' => array(
'Declaration' => array(
'Parser.php' => array()
)
),
'Decode' => array(
'HTML' => array(
'Entities.php' => array()
)
),
'Misc.php' => array(),
'Copyright.php' => array(),
'Parse' => array(
'Date.php' => array()
),
'Content' => array(
'Type' => array(
'Sniffer.php' => array()
)
),
'Source.php' => array(),
'Net' => array(
'IPv6.php' => array()
),
'Credit.php' => array(),
'Cache' => array(
'DB.php' => array(),
'Memcache.php' => array(),
'MySQL.php' => array(),
'Redis.php' => array(),
'File.php' => array(),
'Base.php' => array(),
'Memcached.php' => array()
),
'Core.php' => array(),
'gzdecode.php' => array(),
'Category.php' => array()
),
'class-oembed.php' => array(),
'class-wp-object-cache.php' => array(),
'assets' => array(
'script-loader-packages.php' => array()
),
'class-feed.php' => array(),
'class-wp-term-query.php' => array(),
'class-wp-fatal-error-handler.php' => array(),
'ms-default-constants.php' => array(),
'feed-rss2.php' => array(),
'locale.php' => array(),
'class-wp-list-util.php' => array(),
'embed.php' => array(),
'class-wp-customize-widgets.php' => array(),
'feed-rss2-comments.php' => array(),
'default-widgets.php' => array(),
'class-wp-block-parser.php' => array(),
'error-protection.php' => array(),
'ID3' => array(
'getid3.lib.php' => array(),
'module.tag.lyrics3.php' => array(),
'license.commercial.txt' => array(),
'module.audio.dts.php' => array(),
'license.txt' => array(),
'getid3.php' => array(),
'module.audio.ac3.php' => array(),
'module.audio.flac.php' => array(),
'module.tag.apetag.php' => array(),
'module.audio-video.matroska.php' => array(),
'module.audio-video.quicktime.php' => array(),
'module.audio.ogg.php' => array(),
'module.audio.mp3.php' => array(),
'module.audio-video.flv.php' => array(),
'readme.txt' => array(),
'module.tag.id3v2.php' => array(),
'module.audio-video.riff.php' => array(),
'module.audio-video.asf.php' => array(),
'module.tag.id3v1.php' => array()
),
'embed-template.php' => array(),
'update.php' => array(),
'comment-template.php' => array(),
'nav-menu.php' => array(),
'class-wp-query.php' => array(),
'widgets.php' => array(),
'formatting.php' => array(),
'http.php' => array(),
'class-wp-http-curl.php' => array(),
'class-wp-block-pattern-categories-registry.php' => array(),
'cache-compat.php' => array(),
'feed-atom.php' => array(),
'feed.php' => array(),
'class-wp-block-list.php' => array(),
'class-wp-customize-nav-menus.php' => array(),
'class-wp-http-encoding.php' => array(),
'class-wp-theme.php' => array(),
'canonical.php' => array(),
'sodium_compat' => array(
'lib' => array(
'namespaced.php' => array(),
'constants.php' => array(),
'php72compat_const.php' => array(),
'sodium_compat.php' => array(),
'php72compat.php' => array()
),
'src' => array(
'Core32' => array(
'Salsa20.php' => array(),
'Util.php' => array(),
'BLAKE2b.php' => array(),
'HSalsa20.php' => array(),
'SipHash.php' => array(),
'Poly1305' => array(
'State.php' => array()
),
'XSalsa20.php' => array(),
'Poly1305.php' => array(),
'X25519.php' => array(),
'Int64.php' => array(),
'Curve25519.php' => array(),
'Int32.php' => array(),
'HChaCha20.php' => array(),
'Curve25519' => array(
'Fe.php' => array(),
'H.php' => array(),
'Ge' => array(
'Precomp.php' => array(),
'P2.php' => array(),
'P1p1.php' => array(),
'Cached.php' => array(),
'P3.php' => array()
),
'README.md' => array()
),
'ChaCha20.php' => array(),
'XChaCha20.php' => array(),
'Ed25519.php' => array(),
'ChaCha20' => array(
'Ctx.php' => array(),
'IetfCtx.php' => array()
),
'SecretStream' => array(
'State.php' => array()
)
),
'Compat.php' => array(),
'Crypto32.php' => array(),
'File.php' => array(),
'Core' => array(
'Salsa20.php' => array(),
'Util.php' => array(),
'BLAKE2b.php' => array(),
'HSalsa20.php' => array(),
'SipHash.php' => array(),
'Base64' => array(
'UrlSafe.php' => array(),
'Original.php' => array(),
'Common.php' => array()
),
'Poly1305' => array(
'State.php' => array()
),
'XSalsa20.php' => array(),
'Poly1305.php' => array(),
'X25519.php' => array(),
'Curve25519.php' => array(),
'HChaCha20.php' => array(),
'Curve25519' => array(
'Fe.php' => array(),
'H.php' => array(),
'Ge' => array(
'Precomp.php' => array(),
'P2.php' => array(),
'P1p1.php' => array(),
'Cached.php' => array(),
'P3.php' => array()
),
'README.md' => array()
),
'ChaCha20.php' => array(),
'XChaCha20.php' => array(),
'Ed25519.php' => array(),
'ChaCha20' => array(
'Ctx.php' => array(),
'IetfCtx.php' => array()
),
'SecretStream' => array(
'State.php' => array()
)
),
'Crypto.php' => array(),
'SodiumException.php' => array(),
'PHP52' => array(
'SplFixedArray.php' => array()
)
),
'composer.json' => array(),
'namespaced' => array(
'Compat.php' => array(),
'File.php' => array(),
'Core' => array(
'Salsa20.php' => array(),
'Util.php' => array(),
'BLAKE2b.php' => array(),
'HSalsa20.php' => array(),
'SipHash.php' => array(),
'Poly1305' => array(
'State.php' => array()
),
'Poly1305.php' => array(),
'X25519.php' => array(),
'Curve25519.php' => array(),
'Xsalsa20.php' => array(),
'HChaCha20.php' => array(),
'Curve25519' => array(
'Fe.php' => array(),
'H.php' => array(),
'Ge' => array(
'Precomp.php' => array(),
'P2.php' => array(),
'P1p1.php' => array(),
'Cached.php' => array(),
'P3.php' => array()
)
),
'ChaCha20.php' => array(),
'XChaCha20.php' => array(),
'Ed25519.php' => array(),
'ChaCha20' => array(
'Ctx.php' => array(),
'IetfCtx.php' => array()
)
),
'Crypto.php' => array()
),
'autoload.php' => array(),
'LICENSE' => array()
),
'class-wp-post.php' => array(),
'random_compat' => array(
'random_bytes_dev_urandom.php' => array(),
'random_bytes_libsodium.php' => array(),
'random_bytes_libsodium_legacy.php' => array(),
'error_polyfill.php' => array(),
'random_bytes_openssl.php' => array(),
'random.php' => array(),
'random_bytes_mcrypt.php' => array(),
'cast_to_int.php' => array(),
'random_int.php' => array(),
'random_bytes_com_dotnet.php' => array(),
'byte_safe_strings.php' => array()
),
'feed-rss.php' => array(),
'class-wp-date-query.php' => array(),
'functions.wp-styles.php' => array(),
'script-loader.php' => array(),
'class-wp-image-editor-imagick.php' => array(),
'block-patterns' => array(
'quote.php' => array(),
'heading-paragraph.php' => array(),
'text-two-columns.php' => array(),
'text-two-columns-with-images.php' => array(),
'text-three-columns-buttons.php' => array(),
'three-buttons.php' => array(),
'large-header-button.php' => array(),
'two-buttons.php' => array(),
'large-header.php' => array(),
'two-images.php' => array()
),
'class-wp-comment-query.php' => array(),
'wp-db.php' => array()
),
'wp-cron.php' => array(),
'index.php' => array(),
'xmlrpc.php' => array(),
'wp-settings.php' => array(),
'wp-trackback.php' => array(),
'wp-admin' => array(
'export.php' => array(),
'media.php' => array(),
'media-new.php' => array(),
'freedoms.php' => array(),
'my-sites.php' => array(),
'edit-tags.php' => array(),
'erase-personal-data.php' => array(),
'edit-link-form.php' => array(),
'ms-users.php' => array(),
'customize.php' => array(),
'user-new.php' => array(),
'about.php' => array(),
'export-personal-data.php' => array(),
'edit-form-blocks.php' => array(),
'load-scripts.php' => array(),
'theme-editor.php' => array(),
'load-styles.php' => array(),
'setup-config.php' => array(),
'upload.php' => array(),
'tools.php' => array(),
'upgrade.php' => array(),
'edit-form-comment.php' => array(),
'options-privacy.php' => array(),
'themes.php' => array(),
'users.php' => array(),
'edit.php' => array(),
'options-writing.php' => array(),
'credits.php' => array(),
'includes' => array(
'class-custom-image-header.php' => array(),
'image-edit.php' => array(),
'export.php' => array(),
'ms.php' => array(),
'media.php' => array(),
'class-wp-theme-install-list-table.php' => array(),
'class-bulk-upgrader-skin.php' => array(),
'class-wp-ms-themes-list-table.php' => array(),
'class-wp-plugins-list-table.php' => array(),
'class-wp-upgrader-skins.php' => array(),
'class-wp-links-list-table.php' => array(),
'class-walker-nav-menu-checklist.php' => array(),
'class-wp-ms-users-list-table.php' => array(),
'class-wp-privacy-data-export-requests-list-table.php' => array(),
'class-bulk-theme-upgrader-skin.php' => array(),
'template.php' => array(),
'class-wp-press-this.php' => array(),
'class-wp-filesystem-ftpsockets.php' => array(),
'class-wp-site-health-auto-updates.php' => array(),
'class-wp-internal-pointers.php' => array(),
'class-wp-site-health.php' => array(),
'image.php' => array(),
'class-plugin-upgrader.php' => array(),
'edit-tag-messages.php' => array(),
'class-wp-upgrader.php' => array(),
'class-theme-upgrader.php' => array(),
'class-core-upgrader.php' => array(),
'deprecated.php' => array(),
'class-wp-comments-list-table.php' => array(),
'class-wp-privacy-requests-table.php' => array(),
'dashboard.php' => array(),
'class-wp-themes-list-table.php' => array(),
'plugin.php' => array(),
'class-wp-posts-list-table.php' => array(),
'upgrade.php' => array(),
'class-file-upload-upgrader.php' => array(),
'class-wp-filesystem-base.php' => array(),
'class-wp-ajax-upgrader-skin.php' => array(),
'class-wp-privacy-policy-content.php' => array(),
'class-wp-media-list-table.php' => array(),
'class-wp-filesystem-ftpext.php' => array(),
'class-wp-ms-sites-list-table.php' => array(),
'class-wp-users-list-table.php' => array(),
'taxonomy.php' => array(),
'credits.php' => array(),
'class-wp-list-table.php' => array(),
'noop.php' => array(),
'revision.php' => array(),
'class-language-pack-upgrader-skin.php' => array(),
'class-wp-post-comments-list-table.php' => array(),
'class-wp-privacy-data-removal-requests-list-table.php' => array(),
'import.php' => array(),
'menu.php' => array(),
'class-wp-community-events.php' => array(),
'class-pclzip.php' => array(),
'user.php' => array(),
'class-theme-installer-skin.php' => array(),
'class-wp-filesystem-ssh2.php' => array(),
'class-wp-upgrader-skin.php' => array(),
'plugin-install.php' => array(),
'class-wp-screen.php' => array(),
'post.php' => array(),
'class-wp-importer.php' => array(),
'list-table.php' => array(),
'class-ftp-pure.php' => array(),
'class-bulk-plugin-upgrader-skin.php' => array(),
'continents-cities.php' => array(),
'class-wp-site-icon.php' => array(),
'theme-install.php' => array(),
'class-wp-plugin-install-list-table.php' => array(),
'admin.php' => array(),
'options.php' => array(),
'class-plugin-upgrader-skin.php' => array(),
'class-language-pack-upgrader.php' => array(),
'class-plugin-installer-skin.php' => array(),
'translation-install.php' => array(),
'misc.php' => array(),
'class-wp-terms-list-table.php' => array(),
'class-wp-debug-data.php' => array(),
'class-walker-category-checklist.php' => array(),
'ms-deprecated.php' => array(),
'class-wp-automatic-updater.php' => array(),
'comment.php' => array(),
'screen.php' => array(),
'bookmark.php' => array(),
'admin-filters.php' => array(),
'theme.php' => array(),
'class-wp-list-table-compat.php' => array(),
'class-automatic-upgrader-skin.php' => array(),
'privacy-tools.php' => array(),
'class-walker-nav-menu-edit.php' => array(),
'class-custom-background.php' => array(),
'network.php' => array(),
'class-ftp.php' => array(),
'update.php' => array(),
'nav-menu.php' => array(),
'widgets.php' => array(),
'class-wp-filesystem-direct.php' => array(),
'schema.php' => array(),
'update-core.php' => array(),
'ms-admin-filters.php' => array(),
'class-theme-upgrader-skin.php' => array(),
'ajax-actions.php' => array(),
'file.php' => array(),
'class-ftp-sockets.php' => array(),
'meta-boxes.php' => array()
),
'ms-options.php' => array(),
'link.php' => array(),
'revision.php' => array(),
'privacy.php' => array(),
'js' => array(
'xfn.min.js' => array(),
'theme-plugin-editor.min.js' => array(),
'comment.min.js' => array(),
'tags.min.js' => array(),
'theme.js' => array(),
'press-this.js' => array(),
'privacy-tools.min.js' => array(),
'user-profile.min.js' => array(),
'media.js' => array(),
'word-count.min.js' => array(),
'password-strength-meter.min.js' => array(),
'editor.min.js' => array(),
'site-health.js' => array(),
'media-gallery.js' => array(),
'language-chooser.js' => array(),
'custom-background.js' => array(),
'widgets' => array(
'media-image-widget.min.js' => array(),
'media-image-widget.js' => array(),
'text-widgets.min.js' => array(),
'media-gallery-widget.js' => array(),
'media-audio-widget.js' => array(),
'text-widgets.js' => array(),
'custom-html-widgets.min.js' => array(),
'media-gallery-widget.min.js' => array(),
'media-widgets.min.js' => array(),
'media-video-widget.min.js' => array(),
'media-audio-widget.min.js' => array(),
'media-video-widget.js' => array(),
'custom-html-widgets.js' => array(),
'media-widgets.js' => array()
),
'widgets.js' => array(),
'widgets.min.js' => array(),
'accordion.min.js' => array(),
'wp-fullscreen-stub.min.js' => array(),
'editor.js' => array(),
'inline-edit-tax.min.js' => array(),
'theme-plugin-editor.js' => array(),
'password-strength-meter.js' => array(),
'image-edit.min.js' => array(),
'editor-expand.min.js' => array(),
'inline-edit-post.js' => array(),
'color-picker.js' => array(),
'user-suggest.min.js' => array(),
'edit-comments.min.js' => array(),
'link.js' => array(),
'plugin-install.min.js' => array(),
'xfn.js' => array(),
'media.min.js' => array(),
'revisions.min.js' => array(),
'accordion.js' => array(),
'color-picker.min.js' => array(),
'common.js' => array(),
'svg-painter.js' => array(),
'wp-fullscreen.min.js' => array(),
'set-post-thumbnail.min.js' => array(),
'post.js' => array(),
'farbtastic.js' => array(),
'gallery.js' => array(),
'image-edit.js' => array(),
'site-health.min.js' => array(),
'link.min.js' => array(),
'tags-box.js' => array(),
'customize-nav-menus.js' => array(),
'nav-menu.js' => array(),
'media-gallery.min.js' => array(),
'nav-menu.min.js' => array(),
'editor-expand.js' => array(),
'word-count.js' => array(),
'privacy-tools.js' => array(),
'code-editor.js' => array(),
'post.min.js' => array(),
'press-this.min.js' => array(),
'customize-widgets.min.js' => array(),
'theme.min.js' => array(),
'wp-fullscreen.js' => array(),
'edit-comments.js' => array(),
'inline-edit-tax.js' => array(),
'customize-controls.js' => array(),
'user-profile.js' => array(),
'media-upload.js' => array(),
'revisions.js' => array(),
'dashboard.min.js' => array(),
'dashboard.js' => array(),
'comment.js' => array(),
'customize-controls.min.js' => array(),
'custom-header.js' => array(),
'inline-edit-post.min.js' => array(),
'set-post-thumbnail.js' => array(),
'wp-fullscreen-stub.js' => array(),
'updates.js' => array(),
'code-editor.min.js' => array(),
'updates.min.js' => array(),
'iris.min.js' => array(),
'svg-painter.min.js' => array(),
'common.min.js' => array(),
'customize-nav-menus.min.js' => array(),
'bookmarklet.min.js' => array(),
'tags.js' => array(),
'customize-widgets.js' => array(),
'gallery.min.js' => array(),
'bookmarklet.js' => array(),
'postbox.js' => array(),
'tags-suggest.min.js' => array(),
'postbox.min.js' => array(),
'tags-box.min.js' => array(),
'tags-suggest.js' => array(),
'language-chooser.min.js' => array(),
'plugin-install.js' => array(),
'user-suggest.js' => array(),
'custom-background.min.js' => array(),
'media-upload.min.js' => array()
),
'css' => array(
'forms-rtl.min.css' => array(),
'customize-controls-rtl.css' => array(),
'site-icon.min.css' => array(),
'themes-rtl.min.css' => array(),
'press-this-editor-rtl.css' => array(),
'revisions-rtl.min.css' => array(),
'press-this-rtl.css' => array(),
'wp-admin.css' => array(),
'install-rtl.css' => array(),
'code-editor-rtl.min.css' => array(),
'widgets.min.css' => array(),
'themes-rtl.css' => array(),
'list-tables-rtl.css' => array(),
'press-this-editor.min.css' => array(),
'forms.min.css' => array(),
'customize-nav-menus-rtl.css' => array(),
'l10n.css' => array(),
'list-tables.min.css' => array(),
'press-this.css' => array(),
'media-rtl.css' => array(),
'customize-nav-menus.css' => array(),
'admin-menu.css' => array(),
'color-picker-rtl.min.css' => array(),
'login-rtl.min.css' => array(),
'press-this-editor.css' => array(),
'color-picker-rtl.css' => array(),
'nav-menus.css' => array(),
'site-icon-rtl.css' => array(),
'ie.css' => array(),
'edit.css' => array(),
'edit.min.css' => array(),
'media.min.css' => array(),
'about-rtl.min.css' => array(),
'widgets-rtl.min.css' => array(),
'common.min.css' => array(),
'customize-nav-menus.min.css' => array(),
'press-this-rtl.min.css' => array(),
'revisions-rtl.css' => array(),
'farbtastic.min.css' => array(),
'install-rtl.min.css' => array(),
'themes.css' => array(),
'l10n-rtl.min.css' => array(),
'edit-rtl.min.css' => array(),
'nav-menus-rtl.min.css' => array(),
'site-icon-rtl.min.css' => array(),
'media-rtl.min.css' => array(),
'colors' => array(
'sunrise' => array(
'colors.min.css' => array(),
'colors.scss' => array(),
'colors-rtl.min.css' => array(),
'colors.css' => array(),
'colors-rtl.css' => array()
),
'blue' => array(
'colors.min.css' => array(),
'colors.scss' => array(),
'colors-rtl.min.css' => array(),
'colors.css' => array(),
'colors-rtl.css' => array()
),
'ectoplasm' => array(
'colors.min.css' => array(),
'colors.scss' => array(),
'colors-rtl.min.css' => array(),
'colors.css' => array(),
'colors-rtl.css' => array()
),
'modern' => array(
'colors.min.css' => array(),
'colors.scss' => array(),
'colors-rtl.min.css' => array(),
'colors.css' => array(),
'colors-rtl.css' => array()
),
'_mixins.scss' => array(),
'_admin.scss' => array(),
'coffee' => array(
'colors.min.css' => array(),
'colors.scss' => array(),
'colors-rtl.min.css' => array(),
'colors.css' => array(),
'colors-rtl.css' => array()
),
'ocean' => array(
'colors.min.css' => array(),
'colors.scss' => array(),
'colors-rtl.min.css' => array(),
'colors.css' => array(),
'colors-rtl.css' => array()
),
'light' => array(
'colors.min.css' => array(),
'colors.scss' => array(),
'colors-rtl.min.css' => array(),
'colors.css' => array(),
'colors-rtl.css' => array()
),
'midnight' => array(
'colors.min.css' => array(),
'colors.scss' => array(),
'colors-rtl.min.css' => array(),
'colors.css' => array(),
'colors-rtl.css' => array()
),
'_variables.scss' => array()
),
'revisions.min.css' => array(),
'about.min.css' => array(),
'common-rtl.min.css' => array(),
'customize-nav-menus-rtl.min.css' => array(),
'customize-controls-rtl.min.css' => array(),
'site-health.css' => array(),
'code-editor-rtl.css' => array(),
'edit-rtl.css' => array(),
'forms.css' => array(),
'wp-admin-rtl.min.css' => array(),
'code-editor.css' => array(),
'customize-widgets-rtl.min.css' => array(),
'color-picker.min.css' => array(),
'l10n-rtl.css' => array(),
'site-icon.css' => array(),
'customize-widgets.css' => array(),
'color-picker.css' => array(),
'dashboard.css' => array(),
'deprecated-media-rtl.css' => array(),
'press-this-editor-rtl.min.css' => array(),
'deprecated-media.min.css' => array(),
'customize-widgets.min.css' => array(),
'admin-menu-rtl.min.css' => array(),
'widgets.css' => array(),
'revisions.css' => array(),
'dashboard-rtl.css' => array(),
'admin-menu-rtl.css' => array(),
'widgets-rtl.css' => array(),
'login.min.css' => array(),
'nav-menus-rtl.css' => array(),
'ie-rtl.min.css' => array(),
'ie.min.css' => array(),
'install.css' => array(),
'press-this.min.css' => array(),
'about.css' => array(),
'admin-menu.min.css' => array(),
'login-rtl.css' => array(),
'farbtastic.css' => array(),
'dashboard.min.css' => array(),
'forms-rtl.css' => array(),
'l10n.min.css' => array(),
'ie-rtl.css' => array(),
'themes.min.css' => array(),
'install.min.css' => array(),
'site-health.min.css' => array(),
'customize-widgets-rtl.css' => array(),
'farbtastic-rtl.css' => array(),
'wp-admin-rtl.css' => array(),
'common.css' => array(),
'list-tables.css' => array(),
'customize-controls.css' => array(),
'common-rtl.css' => array(),
'login.css' => array(),
'dashboard-rtl.min.css' => array(),
'list-tables-rtl.min.css' => array(),
'nav-menus.min.css' => array(),
'deprecated-media.css' => array(),
'about-rtl.css' => array(),
'customize-controls.min.css' => array(),
'site-health-rtl.css' => array(),
'site-health-rtl.min.css' => array(),
'media.css' => array(),
'code-editor.min.css' => array(),
'deprecated-media-rtl.min.css' => array(),
'farbtastic-rtl.min.css' => array(),
'wp-admin.min.css' => array()
),
'site-health-info.php' => array(),
'user' => array(
'freedoms.php' => array(),
'about.php' => array(),
'credits.php' => array(),
'privacy.php' => array(),
'menu.php' => array(),
'user-edit.php' => array(),
'admin.php' => array(),
'profile.php' => array(),
'index.php' => array()
),
'options-permalink.php' => array(),
'import.php' => array(),
'edit-form-advanced.php' => array(),
'menu.php' => array(),
'term.php' => array(),
'custom-background.php' => array(),
'link-manager.php' => array(),
'network' => array(
'freedoms.php' => array(),
'site-info.php' => array(),
'setup.php' => array(),
'user-new.php' => array(),
'about.php' => array(),
'theme-editor.php' => array(),
'upgrade.php' => array(),
'themes.php' => array(),
'users.php' => array(),
'edit.php' => array(),
'credits.php' => array(),
'privacy.php' => array(),
'site-themes.php' => array(),
'menu.php' => array(),
'site-settings.php' => array(),
'user-edit.php' => array(),
'plugin-install.php' => array(),
'theme-install.php' => array(),
'settings.php' => array(),
'admin.php' => array(),
'profile.php' => array(),
'plugins.php' => array(),
'site-new.php' => array(),
'index.php' => array(),
'site-users.php' => array(),
'plugin-editor.php' => array(),
'sites.php' => array(),
'update.php' => array(),
'update-core.php' => array()
),
'install-helper.php' => array(),
'user-edit.php' => array(),
'async-upload.php' => array(),
'plugin-install.php' => array(),
'post.php' => array(),
'options-discussion.php' => array(),
'theme-install.php' => array(),
'admin.php' => array(),
'options-reading.php' => array(),
'options.php' => array(),
'images' => array(
'list.png' => array(),
'icons32-vs-2x.png' => array(),
'resize-rtl.gif' => array(),
'media-button.png' => array(),
'comment-grey-bubble-2x.png' => array(),
'menu-2x.png' => array(),
'xit-2x.gif' => array(),
'sort-2x.gif' => array(),
'media-button-video.gif' => array(),
'icons32.png' => array(),
'bubble_bg.gif' => array(),
'media-button-other.gif' => array(),
'menu.png' => array(),
'browser-rtl.png' => array(),
'align-left-2x.png' => array(),
'browser.png' => array(),
'sort.gif' => array(),
'media-button-2x.png' => array(),
'post-formats.png' => array(),
'align-center.png' => array(),
'icons32-2x.png' => array(),
'resize-2x.gif' => array(),
'imgedit-icons.png' => array(),
'align-right-2x.png' => array(),
'wpspin_light.gif' => array(),
'wordpress-logo.svg' => array(),
'wheel.png' => array(),
'list-2x.png' => array(),
'resize.gif' => array(),
'w-logo-blue.png' => array(),
'xit.gif' => array(),
'imgedit-icons-2x.png' => array(),
'stars.png' => array(),
'arrows-2x.png' => array(),
'menu-vs.png' => array(),
'align-right.png' => array(),
'align-left.png' => array(),
'post-formats32.png' => array(),
'align-none-2x.png' => array(),
'wpspin_light-2x.gif' => array(),
'wordpress-logo-white.svg' => array(),
'resize-rtl-2x.gif' => array(),
'w-logo-white.png' => array(),
'se.png' => array(),
'media-button-image.gif' => array(),
'yes.png' => array(),
'wordpress-logo.png' => array(),
'generic.png' => array(),
'icons32-vs.png' => array(),
'menu-vs-2x.png' => array(),
'align-center-2x.png' => array(),
'media-button-music.gif' => array(),
'spinner-2x.gif' => array(),
'align-none.png' => array(),
'spinner.gif' => array(),
'comment-grey-bubble.png' => array(),
'arrows.png' => array(),
'date-button-2x.gif' => array(),
'stars-2x.png' => array(),
'no.png' => array(),
'date-button.gif' => array(),
'bubble_bg-2x.gif' => array(),
'post-formats-vs.png' => array(),
'post-formats32-vs.png' => array(),
'loading.gif' => array(),
'mask.png' => array(),
'marker.png' => array()
),
'profile.php' => array(),
'plugins.php' => array(),
'install.php' => array(),
'options-head.php' => array(),
'link-parse-opml.php' => array(),
'admin-functions.php' => array(),
'moderation.php' => array(),
'comment.php' => array(),
'index.php' => array(),
'ms-sites.php' => array(),
'site-health.php' => array(),
'link-add.php' => array(),
'edit-comments.php' => array(),
'plugin-editor.php' => array(),
'maint' => array(
'repair.php' => array()
),
'nav-menus.php' => array(),
'privacy-policy-guide.php' => array(),
'network.php' => array(),
'custom-header.php' => array(),
'options-general.php' => array(),
'options-media.php' => array(),
'post-new.php' => array(),
'update.php' => array(),
'widgets.php' => array(),
'ms-upgrade-network.php' => array(),
'media-upload.php' => array(),
'admin-header.php' => array(),
'update-core.php' => array(),
'ms-themes.php' => array(),
'ms-delete-site.php' => array(),
'upgrade-functions.php' => array(),
'menu-header.php' => array(),
'ms-admin.php' => array(),
'admin-footer.php' => array(),
'ms-edit.php' => array(),
'press-this.php' => array(),
'admin-ajax.php' => array(),
'admin-post.php' => array(),
'edit-tag-form.php' => array()
)
);
lib/snaplib/class.snaplib.logger.php 0000644 00000010543 15133606540 0013473 0 ustar 00 <?php
/**
* Snap Logger utils
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package DupLiteSnapLib
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLibLogger', false)) {
class DupLiteSnapLibLogger
{
public static $logFilepath = null;
public static $logHandle = null;
public static function init($logFilepath)
{
self::$logFilepath = $logFilepath;
}
public static function clearLog()
{
if (file_exists(self::$logFilepath)) {
if (self::$logHandle !== null) {
fflush(self::$logHandle);
fclose(self::$logHandle);
self::$logHandle = null;
}
@unlink(self::$logFilepath);
}
}
public static function logObject($s, $o, $flush = false)
{
self::log($s, $flush);
self::log(print_r($o, true), $flush);
}
public static function log($s, $flush = false, $callingFunctionOverride = null)
{
// echo "{$s}<br/>";
$lfp = self::$logFilepath;
// echo "logging $s to {$lfp}<br/>";
if (self::$logFilepath === null) {
throw new Exception('Logging not initialized');
}
if (isset($_SERVER['REQUEST_TIME_FLOAT'])) {
$timepart = $_SERVER['REQUEST_TIME_FLOAT'];
} else {
$timepart = $_SERVER['REQUEST_TIME'];
}
$thread_id = sprintf("%08x", abs(crc32($_SERVER['REMOTE_ADDR'].$timepart.$_SERVER['REMOTE_PORT'])));
$s = $thread_id.' '.date('h:i:s').":$s";
if (self::$logHandle === null) {
self::$logHandle = fopen(self::$logFilepath, 'a');
}
fwrite(self::$logHandle, "$s\n");
if ($flush) {
fflush(self::$logHandle);
fclose(self::$logHandle);
self::$logHandle = fopen(self::$logFilepath, 'a');
}
}
private static $profileLogArray = null;
private static $prevTS = -1;
public static function initProfiling()
{
self::$profileLogArray = array();
}
public static function writeToPLog($s)
{
throw new exception('not implemented');
$currentTime = microtime(true);
if (array_key_exists($s, self::$profileLogArray)) {
$dSame = $currentTime - self::$profileLogArray[$s];
$dSame = number_format($dSame, 7);
} else {
$dSame = 'N/A';
}
if (self::$prevTS != -1) {
$dPrev = $currentTime - self::$prevTS;
$dPrev = number_format($dPrev, 7);
} else {
$dPrev = 'N/A';
}
self::$profileLogArray[$s] = $currentTime;
self::$prevTS = $currentTime;
self::log(" {$dPrev} : {$dSame} : {$currentTime} : {$s}");
}
/**
*
* @param mixed $var
* @param bool $checkCallable // if true check if var is callable and display it
* @return string
*/
public static function varToString($var, $checkCallable = false)
{
if ($checkCallable && is_callable($var)) {
return '(callable) '.print_r($var, true);
}
switch (gettype($var)) {
case "boolean":
return $var ? 'true' : 'false';
case "integer":
case "double":
return (string) $var;
case "string":
return '"'.$var.'"';
case "array":
case "object":
return print_r($var, true);
case "resource":
case "resource (closed)":
case "NULL":
case "unknown type":
default:
return gettype($var);
}
}
}
}
lib/snaplib/class.snaplib.u.wp.php 0000644 00000020567 15133606540 0013114 0 ustar 00 <?php
/**
* Wordpress utility functions
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package snaplib
* @subpackage classes/utilities
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLibUtilWp', false)) {
/**
* Wordpress utility functions
*/
class DupLiteSnapLibUtilWp
{
const PATH_FULL = 0;
const PATH_RELATIVE = 1;
const PATH_AUTO = 2;
private static $corePathList = null;
private static $safeAbsPath = null;
/**
*
* @var string if not empty alters isWpCore's operation
*/
private static $wpCoreRelativePath = '';
/**
* return safe ABSPATH without last /
* perform safe function only one time
*
* @return string
*/
public static function getSafeAbsPath()
{
if (is_null(self::$safeAbsPath)) {
if (defined('ABSPATH')) {
self::$safeAbsPath = DupLiteSnapLibIOU::safePathUntrailingslashit(ABSPATH);
} else {
self::$safeAbsPath = '';
}
}
return self::$safeAbsPath;
}
/**
*
* @param string $folder
* @return boolean // return true if folder is wordpress home folder
*
*/
public static function isWpHomeFolder($folder)
{
$indexPhp = DupLiteSnapLibIOU::trailingslashit($folder).'index.php';
if (!file_exists($indexPhp)) {
return false;
}
if (($indexContent = file_get_contents($indexPhp)) === false) {
return false;
}
return (preg_match('/require\s*[\s\(].*[\'"].*wp-blog-header.php[\'"]\s*\)?/', $indexContent) === 1);
}
/**
* This function is the equivalent of the get_home_path function but with various fixes
*
* @staticvar string $home_path
* @return string
*/
public static function getHomePath()
{
static $home_path = null;
if (is_null($home_path)) {
// outside wordpress this function makes no sense
if (!defined('ABSPATH')) {
$home_path = false;
return $home_path;
}
if (isset($_SERVER['SCRIPT_FILENAME']) && is_readable($_SERVER['SCRIPT_FILENAME'])) {
$scriptFilename = $_SERVER['SCRIPT_FILENAME'];
} else {
$files = get_included_files();
$scriptFilename = array_shift($files);
}
$realScriptDirname = DupLiteSnapLibIOU::safePathTrailingslashit(dirname($scriptFilename), true);
$realAbsPath = DupLiteSnapLibIOU::safePathTrailingslashit(ABSPATH, true);
if (strpos($realScriptDirname, $realAbsPath) === 0) {
// normalize URLs without www
$home = DupLiteSnapLibURLU::wwwRemove(set_url_scheme(get_option('home'), 'http'));
$siteurl = DupLiteSnapLibURLU::wwwRemove(set_url_scheme(get_option('siteurl'), 'http'));
if (!empty($home) && 0 !== strcasecmp($home, $siteurl)) {
if (stripos($siteurl, $home) === 0) {
$wp_path_rel_to_home = str_ireplace($home, '', $siteurl); /* $siteurl - $home */
$pos = strripos(str_replace('\\', '/', $scriptFilename), DupLiteSnapLibIOU::trailingslashit($wp_path_rel_to_home));
$home_path = substr($scriptFilename, 0, $pos);
$home_path = DupLiteSnapLibIOU::trailingslashit($home_path);
} else {
$home_path = ABSPATH;
}
} else {
$home_path = ABSPATH;
}
} else {
// On frontend the home path is the folder of index.php
$home_path = DupLiteSnapLibIOU::trailingslashit(dirname($scriptFilename));
}
// make sure the folder exists or consider ABSPATH
if (!file_exists($home_path)) {
$home_path = ABSPATH;
}
$home_path = str_replace('\\', '/', $home_path);
}
return $home_path;
}
public static function setWpCoreRelativeAbsPath($string = '')
{
self::$wpCoreRelativePath = (string) $string;
}
/**
* check if path is in wordpress core list
*
* @param string $path
* @param int $fullPath // if PATH_AUTO check if is a full path or relative path
* if PATH_FULL remove ABSPATH len without check
* if PATH_RELATIVE consider path a relative path
* @param bool $isSafe // if false call rtrim(DupLiteSnapLibIOU::safePath( PATH ), '/')
* if true consider path a safe path without check
*
* PATH_FULL and PATH_RELATIVE is better optimized and perform less operations
*
* @return boolean
*/
public static function isWpCore($path, $fullPath = self::PATH_AUTO, $isSafe = false)
{
if ($isSafe == false) {
$path = rtrim(DupLiteSnapLibIOU::safePath($path), '/');
}
switch ($fullPath) {
case self::PATH_FULL:
$absPath = self::getSafeAbsPath();
if (strlen($path) < strlen($absPath)) {
return false;
}
$relPath = ltrim(substr($path, strlen($absPath)), '/');
break;
case self::PATH_RELATIVE:
if (($relPath = DupLiteSnapLibIOU::getRelativePath($path, self::$wpCoreRelativePath)) === false) {
return false;
}
break;
case self::PATH_AUTO:
default:
$absPath = self::getSafeAbsPath();
if (strpos($path, $absPath) === 0) {
$relPath = ltrim(substr($path, strlen($absPath)), '/');
} else {
$relPath = ltrim($path, '/');
}
}
// if rel path is empty is consider root path so is a core folder.
if (empty($relPath)) {
return true;
}
$pExploded = explode('/', $relPath);
$corePaths = self::getCorePathsList();
foreach ($pExploded as $current) {
if (!isset($corePaths[$current])) {
return false;
}
$corePaths = $corePaths[$current];
}
return true;
}
/**
* get core path list from relative abs path
* [
* 'folder' => [
* 's-folder1' => [
* file1 => [],
* file2 => [],
* ],
* 's-folder2' => [],
* file1 => []
* ]
* ]
*
* @return array
*/
public static function getCorePathsList()
{
if (is_null(self::$corePathList)) {
require_once(dirname(__FILE__).'/wordpress.core.files.php');
}
return self::$corePathList;
}
/**
* return object list of sites
*
* @return boolean
*/
public static function getSites($args = array())
{
if (!function_exists('is_multisite') || !is_multisite()) {
return false;
}
if (function_exists('get_sites')) {
return get_sites($args);
} else {
$result = array();
$blogs = wp_get_sites($args);
foreach ($blogs as $blog) {
$result[] = (object) $blog;
}
return $result;
}
}
}
}
lib/snaplib/class.snaplib.u.orig.files.manager.php 0000644 00000027146 15133606540 0016140 0 ustar 00 <?php
/**
* Original installer files manager
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2 Full Documentation
*
* @package SC\DUPX\U
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLibOrigFileManager', false)) {
/**
* Original installer files manager
*
* This class saves a file or folder in the original files folder and saves the original location persistent.
* By entry we mean a file or a folder but not the files contained within it.
* In this way it is possible, for example, to move an entire plugin to restore it later.
*
*/
class DupLiteSnapLibOrigFileManager
{
const MODE_MOVE = 'move';
const MODE_COPY = 'copy';
const ORIG_FOLDER_PREFIX = 'original_files_';
const PERSISTANCE_FILE_NAME = 'entries_stored.json';
/**
*
* @var string
*/
protected $persistanceFile = null;
/**
*
* @var string
*/
protected $origFilesFolder = null;
/**
*
* @var array
*/
protected $origFolderEntries = array();
/**
*
* @var string
*/
protected $rootPath = null;
public function __construct($root, $origFolderParentPath, $hash)
{
$this->rootPath = DupLiteSnapLibIOU::safePathUntrailingslashit($root, true);
$this->origFilesFolder = DupLiteSnapLibIOU::safePathTrailingslashit($origFolderParentPath, true).self::ORIG_FOLDER_PREFIX.$hash;
$this->persistanceFile = $this->origFilesFolder.'/'.self::PERSISTANCE_FILE_NAME;
}
/**
* create a main folder if don't exist and load the entries
*
* @param boolen $reset
*/
public function init($reset = false)
{
$this->createMainFolder($reset);
$this->load();
}
/**
*
* @param boolean $reset // if true delete current folder
* @return boolean // return true if succeded
* @throws Exception
*/
public function createMainFolder($reset = false)
{
if ($reset) {
$this->deleteMainFolder();
}
if (!file_exists($this->origFilesFolder)) {
if (!DupLiteSnapLibIOU::mkdir($this->origFilesFolder, 'u+rwx')) {
throw new Exception('Can\'t create the original files folder '.DupLiteSnapLibLogger::varToString($this->origFilesFolder));
}
}
$htaccessFile = $this->origFilesFolder.'/.htaccess';
if (!file_exists($htaccessFile)) {
$htfile = @fopen($htaccessFile, 'w');
$content = <<<HTACCESS
Order Allow,Deny
Deny from All
HTACCESS;
@fwrite($htfile, $content);
@fclose($htfile);
}
if (!file_exists($this->persistanceFile)) {
$this->save();
}
return true;
}
/**
* @return string Main folder path
* @throws Exception
*/
public function getMainFolder()
{
if (!file_exists($this->origFilesFolder)) {
throw new Exception('Can\'t get the original files folder '.DupLiteSnapLibLogger::varToString($this->origFilesFolder));
}
return $this->origFilesFolder;
}
/**
* delete origianl files folder
*
* @return boolean
* @throws Exception
*/
public function deleteMainFolder()
{
if (file_exists($this->origFilesFolder) && !DupLiteSnapLibIOU::rrmdir($this->origFilesFolder)) {
throw new Exception('Can\'t delete the original files folder '.DupLiteSnapLibLogger::varToString($this->origFilesFolder));
}
$this->origFolderEntries = array();
return true;
}
/**
* add a entry on original folder.
*
* @param string $identifier // entry identifier
* @param string $path // entry path. can be a file or a folder
* @param string $mode // MODE_MOVE move the item in original folder
* MODE_COPY copy the item in original folder
* @param bool|string $rename // if rename is a string the item is renamed in original folder.
* @return boolean // true if succeded
* @throws Exception
*/
public function addEntry($identifier, $path, $mode = self::MODE_MOVE, $rename = false)
{
if (!file_exists($path)) {
return false;
}
$baseName = empty($rename) ? basename($path) : $rename;
if (($relativePath = DupLiteSnapLibIOU::getRelativePath($path, $this->rootPath)) === false) {
$isRelative = false;
} else {
$isRelative = true;
}
$parentFolder = $isRelative ? dirname($relativePath) : DupLiteSnapLibIOU::removeRootPath(dirname($path));
if (empty($parentFolder) || $parentFolder === '.') {
$parentFolder = '';
} else {
$parentFolder .= '/';
}
$targetFolder = $this->origFilesFolder.'/'.$parentFolder;
if (!file_exists($targetFolder)) {
DupLiteSnapLibIOU::mkdir_p($targetFolder);
}
$dest = $targetFolder.$baseName;
switch ($mode) {
case self::MODE_MOVE:
if (!DupLiteSnapLibIOU::rename($path, $dest)) {
throw new Exception('Can\'t move the original file '.DupLiteSnapLibLogger::varToString($path));
}
break;
case self::MODE_COPY:
if (!DupLiteSnapLibIOU::rcopy($path, $dest)) {
throw new Exception('Can\'t copy the original file '.DupLiteSnapLibLogger::varToString($path));
}
break;
default:
throw new Exception('invalid mode addEntry');
}
$this->origFolderEntries[$identifier] = array(
'baseName' => $baseName,
'source' => $isRelative ? $relativePath : $path,
'stored' => $parentFolder.$baseName,
'mode' => $mode,
'isRelative' => $isRelative
);
$this->save();
return true;
}
/**
* get entry info from itendifier
*
* @param string $identifier
* @return boolean // false if entry don't exists
*/
public function getEntry($identifier)
{
if (isset($this->origFolderEntries[$identifier])) {
return $this->origFolderEntries[$identifier];
} else {
return false;
}
}
/**
* get entry stored path in original folder
*
* @param string $identifier
* @return boolean // false if entry don't exists
*/
public function getEntryStoredPath($identifier)
{
if (isset($this->origFolderEntries[$identifier])) {
return $this->origFilesFolder.'/'.$this->origFolderEntries[$identifier]['stored'];
} else {
return false;
}
}
public function isRelative($identifier)
{
if (isset($this->origFolderEntries[$identifier])) {
$this->origFolderEntries[$identifier]['isRelative'];
} else {
return false;
}
}
/**
* get entry target restore path
*
* @param string $identifier
* @param type $defaultIfIsAbsolute
* @return boolean // false if entry don't exists
*/
public function getEntryTargetPath($identifier, $defaultIfIsAbsolute = null)
{
if (isset($this->origFolderEntries[$identifier])) {
if ($this->origFolderEntries[$identifier]['isRelative']) {
return $this->rootPath.'/'.$this->origFolderEntries[$identifier]['source'];
} else {
if (is_null($defaultIfIsAbsolute)) {
return $this->origFolderEntries[$identifier]['source'];
} else {
return $defaultIfIsAbsolute;
}
}
} else {
return false;
}
}
/**
* this function restore current entry in original position.
* If mode is copy it simply delete the entry else move the entry in original position
*
* @param string $identifier // identified of current entrye
* @param boolean $save // update saved entries
* @return boolean // true if succeded
* @throws Exception
*/
public function restoreEntry($identifier, $save = true, $defaultIfIsntRelative = null)
{
if (!isset($this->origFolderEntries[$identifier])) {
return false;
}
$stored = $this->getEntryStoredPath($identifier);
if (($original = $this->getEntryTargetPath($identifier, $defaultIfIsntRelative)) === false) {
return false;
}
switch ($this->origFolderEntries[$identifier]['mode']) {
case self::MODE_MOVE:
if (!DupLiteSnapLibIOU::rename($stored, $original)) {
throw new Exception('Can\'t move the original file '.DupLiteSnapLibLogger::varToString($stored));
}
break;
case self::MODE_COPY:
if (!DupLiteSnapLibIOU::rrmdir($stored)) {
throw new Exception('Can\'t delete entry '.DupLiteSnapLibLogger::varToString($stored));
}
break;
default:
throw new Exception('invalid mode addEntry');
}
unset($this->origFolderEntries[$identifier]);
if ($save) {
$this->save();
}
return true;
}
/**
* put all entries on original position and empty original folder
*
* @return boolean
*/
public function restoreAll($exclude = array())
{
foreach (array_keys($this->origFolderEntries) as $ident) {
if (in_array($ident, $exclude)) {
continue;
}
$this->restoreEntry($ident, false);
}
$this->save();
return true;
}
/**
* save notices from json file
*/
public function save()
{
if (!file_put_contents($this->persistanceFile, DupLiteSnapJsonU::wp_json_encode_pprint($this->origFolderEntries))) {
throw new Exception('Can\'t write persistence file');
}
return true;
}
/**
* load notice from json file
*/
private function load()
{
if (file_exists($this->persistanceFile)) {
$json = file_get_contents($this->persistanceFile);
$this->origFolderEntries = json_decode($json, true);
} else {
$this->origFolderEntries = array();
}
return true;
}
}
}
lib/snaplib/class.snaplib.u.ui.php 0000644 00000002323 15133606540 0013071 0 ustar 00 <?php
/**
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package DupLiteSnapLib
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLibUIU', false)) {
class DupLiteSnapLibUIU
{
public static function echoBoolean($val)
{
echo $val ? 'true' : 'false';
}
public static function echoChecked($val)
{
// filter_var is available in >= php 5.2
if (function_exists('filter_var') && defined('FILTER_VALIDATE_BOOLEAN')) {
echo filter_var($val, FILTER_VALIDATE_BOOLEAN) ? 'checked' : '';
} else {
echo $val ? 'checked' : '';
}
}
public static function echoDisabled($val)
{
echo $val ? 'disabled' : '';
}
public static function echoSelected($val)
{
echo $val ? 'selected' : '';
}
public static function getSelected($val)
{
return ($val ? 'selected' : '');
}
}
} lib/snaplib/class.snaplib.u.io.php 0000644 00000136455 15133606540 0013101 0 ustar 00 <?php
/**
* Snap I/O utils
*
* Standard: PSR-2
* @link http://www.php-fig.org/psr/psr-2
*
* @package DupLiteSnapLib
* @copyright (c) 2017, Snapcreek LLC
* @license https://opensource.org/licenses/GPL-3.0 GNU Public License
*
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteSnapLibIOU', false)) {
require_once(dirname(__FILE__).'/class.snaplib.u.string.php');
require_once(dirname(__FILE__).'/class.snaplib.u.os.php');
class DupLiteSnapLibIOU
{
// Real upper bound of a signed int is 214748364.
// The value chosen below, makes sure we have a buffer of ~4.7 million.
const FileSizeLimit32BitPHP = 1900000000;
const FWRITE_CHUNK_SIZE = 4096; // bytes
public static function rmPattern($filePathPattern)
{
@array_map('unlink', glob($filePathPattern));
}
/**
*
* @param string $path
* @param array $args // array key / val where key is the var name in include
* @param bool $required
* @return string
* @throws Exception // thorw exception if is $required and file can't be read
*/
public static function getInclude($path, $args = array(), $required = true)
{
if (!is_readable($path)) {
if ($required) {
throw new Exception('Can\'t read required file '.$path);
} else {
return '';
}
}
foreach ($args as $var => $value) {
${$var} = $value;
}
ob_start();
if ($required) {
require ($path);
} else {
include ($path);
}
return ob_get_clean();
}
public static function chmodPattern($filePathPattern, $mode)
{
$filePaths = glob($filePathPattern);
$modes = array();
foreach ($filePaths as $filePath) {
$modes[] = $mode;
}
array_map(array(__CLASS__, 'chmod'), $filePaths, $modes);
}
public static function copy($source, $dest, $overwriteIfExists = true)
{
if (file_exists($dest)) {
if ($overwriteIfExists) {
self::rm($dest);
} else {
return false;
}
}
return copy($source, $dest);
}
/**
*
* @param string $source
* @param string $dest
* @return boolean false if fail
*/
public static function rcopy($source, $dest)
{
if (!is_readable($source)) {
return false;
}
if (is_dir($source)) {
if (!file_exists($dest)) {
if (!self::mkdir($dest)) {
return false;
}
}
if (($handle = opendir($source)) != false) {
return false;
}
while ($file = readdir($handle)) {
if ($file == "." && $file == "..") {
continue;
}
if (is_dir($source.'/'.$file)) {
if (!self::rcopy($source.'/'.$file, $dest.'/'.$file)) {
return false;
}
} else {
if (!self::copy($source.'/'.$file, $dest.'/'.$file)) {
return false;
}
}
}
closedir($handle);
return true;
} else {
return self::copy($source, $dest);
}
}
public static function untrailingslashit($path)
{
return rtrim($path, '/\\');
}
public static function trailingslashit($path)
{
return self::untrailingslashit($path).'/';
}
public static function safePath($path, $real = false)
{
if ($real) {
$res = realpath($path);
} else {
$res = $path;
}
return self::normalize_path($path);
}
public static function safePathUntrailingslashit($path, $real = false)
{
if ($real) {
$res = realpath($path);
} else {
$res = $path;
}
return rtrim(self::normalize_path($res), '/');
}
public static function safePathTrailingslashit($path, $real = false)
{
return self::safePathUntrailingslashit($path, $real).'/';
}
/**
*
* @param string $sourceFolder
* @param string $destFolder
* @param bool $skipIfExists
* @return boolean
*/
public static function moveContentDirToTarget($sourceFolder, $destFolder, $skipIfExists = false)
{
if (!is_dir($sourceFolder) || !is_readable($sourceFolder)) {
return false;
}
if (!is_dir($destFolder) || !is_writable($destFolder)) {
return false;
}
$sourceIterator = new DirectoryIterator($sourceFolder);
foreach ($sourceIterator as $fileinfo) {
if ($fileinfo->isDot()) {
continue;
}
$destPath = $destFolder.'/'.$fileinfo->getBasename();
if (file_exists($destPath)) {
if ($skipIfExists) {
continue;
} else {
return false;
}
}
if (self::rename($fileinfo->getPathname(), $destPath) == false) {
return false;
}
}
return true;
}
public static function massMove($fileSystemObjects, $destination, $exclusions = null, $exceptionOnError = true)
{
$failures = array();
$destination = rtrim($destination, '/\\');
if (!file_exists($destination) || !is_writeable($destination)) {
self::mkdir($destination, 'u+rwx');
}
foreach ($fileSystemObjects as $fileSystemObject) {
$shouldMove = true;
if ($exclusions != null) {
foreach ($exclusions as $exclusion) {
if (preg_match($exclusion, $fileSystemObject) === 1) {
$shouldMove = false;
break;
}
}
}
if ($shouldMove) {
$newName = $destination.'/'.basename($fileSystemObject);
if (!file_exists($fileSystemObject)) {
$failures[] = "Tried to move {$fileSystemObject} to {$newName} but it didn't exist!";
} else if (!@rename($fileSystemObject, $newName)) {
$failures[] = "Couldn't move {$fileSystemObject} to {$newName}";
}
}
}
if ($exceptionOnError && count($failures) > 0) {
throw new Exception(implode(',', $failures));
}
return $failures;
}
/**
* Remove file path
*
* @param string $file path
*
* @return bool <p>Returns <b><code>TRUE</code></b> on success or <b><code>FALSE</code></b> on failure.</p>
*/
public static function unlink($file)
{
try {
if (!file_exists($file)) {
return true;
}
if (!function_exists('unlink') || is_dir($file)) {
return false;
}
self::chmod($file, 'u+rw');
return @unlink($file);
} catch (Exception $e) {
return false;
} catch (Error $e) {
return false;
}
}
/**
* Rename file from old name to new name
*
* @param string $oldname path
* @param string $newname path
* @param bool $removeIfExists if true remove exists file
*
* @return bool <p>Returns <b><code>TRUE</code></b> on success or <b><code>FALSE</code></b> on failure.</p>
*/
public static function rename($oldname, $newname, $removeIfExists = false)
{
try {
if (!file_exists($oldname) || !function_exists('rename')) {
return false;
}
if ($removeIfExists && file_exists($newname)) {
if (!self::rrmdir($newname)) {
return false;
}
}
return @rename($oldname, $newname);
} catch (Exception $e) {
return false;
} catch (Error $e) {
return false;
}
}
public static function fopen($filepath, $mode, $throwOnError = true)
{
if (strlen($filepath) > DupLiteSnapLibOSU::maxPathLen()) {
throw new Exception('Skipping a file that exceeds allowed max path length ['.DupLiteSnapLibOSU::maxPathLen().']. File: '.$filepath);
}
if (DupLiteSnapLibStringU::startsWith($mode, 'w') || DupLiteSnapLibStringU::startsWith($mode, 'c') || file_exists($filepath)) {
$file_handle = @fopen($filepath, $mode);
} else {
if ($throwOnError) {
throw new Exception("$filepath doesn't exist");
} else {
return false;
}
}
if (!is_resource($file_handle)) {
if ($throwOnError) {
throw new Exception("Error opening $filepath");
} else {
return false;
}
} else {
return $file_handle;
}
}
public static function touch($filepath, $time = null)
{
if (!function_exists('touch')) {
return false;
}
if ($time === null) {
$time = time();
}
return @touch($filepath, $time);
}
public static function rmdir($dirname, $mustExist = false)
{
if (file_exists($dirname)) {
self::chmod($dirname, 'u+rwx');
if (self::rrmdir($dirname) === false) {
throw new Exception("Couldn't remove {$dirname}");
}
} else if ($mustExist) {
throw new Exception("{$dirname} doesn't exist");
}
}
public static function rm($filepath, $mustExist = false)
{
if (file_exists($filepath)) {
self::chmod($filepath, 'u+rw');
if (@unlink($filepath) === false) {
throw new Exception("Couldn't remove {$filepath}");
}
} else if ($mustExist) {
throw new Exception("{$filepath} doesn't exist");
}
}
/**
*
* @param resource $handle
* @param srtring $string
* @return int
* @throws Exception
*/
public static function fwrite($handle, $string)
{
$bytes_written = @fwrite($handle, $string);
if ($bytes_written != strlen($string)) {
throw new Exception('Error writing to file.');
} else {
return $bytes_written;
}
}
/**
* wrinte file in chunk mode. For big data.
* @param resource $handle
* @param string $content
* @return int
* @throws Exception
*/
public static function fwriteChunked($handle, $content)
{
$pieces = str_split($content, self::FWRITE_CHUNK_SIZE);
$written = 0;
foreach ($pieces as $piece) {
if (($fwResult = @fwrite($handle, $piece, self::FWRITE_CHUNK_SIZE)) === false) {
throw new Exception('Error writing to file.');
}
$written += $fwResult;
}
if ($written != strlen($content)) {
throw new Exception('Error writing to file.');
}
return $written;
}
public static function fgets($handle, $length)
{
$line = fgets($handle, $length);
if ($line === false) {
throw new Exception('Error reading line.');
}
return $line;
}
public static function fclose($handle, $exception_on_fail = true)
{
if ((@fclose($handle) === false) && $exception_on_fail) {
throw new Exception("Error closing file");
}
}
public static function flock($handle, $operation)
{
if (@flock($handle, $operation) === false) {
throw new Exception("Error locking file");
}
}
public static function ftell($file_handle)
{
$position = @ftell($file_handle);
if ($position === false) {
throw new Exception("Couldn't retrieve file offset.");
} else {
return $position;
}
}
/**
* Safely remove a directory and recursively files and directory upto multiple sublevels
*
* @param path $dir The full path to the directory to remove
*
* @return bool Returns true if all content was removed
*/
public static function rrmdir($path)
{
if (is_dir($path)) {
if (($dh = opendir($path)) === false) {
return false;
}
while (($object = readdir($dh)) !== false) {
if ($object == "." || $object == "..") {
continue;
}
if (!self::rrmdir($path."/".$object)) {
closedir($dh);
return false;
}
}
closedir($dh);
return @rmdir($path);
} else {
if (is_writable($path)) {
return @unlink($path);
} else {
return false;
}
}
}
public static function filesize($filename)
{
$file_size = @filesize($filename);
if ($file_size === false) {
throw new Exception("Error retrieving file size of $filename");
}
return $file_size;
}
public static function fseek($handle, $offset, $whence = SEEK_SET)
{
$ret_val = @fseek($handle, $offset, $whence);
if ($ret_val !== 0) {
$filepath = stream_get_meta_data($handle);
$filepath = $filepath["uri"];
$filesize = self::filesize($filepath);
// For future debug
/*
error_log('$offset: '.$offset);
error_log('$filesize: '.$filesize);
error_log($whence. ' == '. SEEK_SET);
*/
if ($ret_val === false) {
throw new Exception("Trying to fseek($offset, $whence) and came back false");
}
//This check is not strict, but in most cases 32 Bit PHP will be the issue
else if (abs($offset) > self::FileSizeLimit32BitPHP || $filesize > self::FileSizeLimit32BitPHP || ($offset <= 0 && ($whence == SEEK_SET || $whence == SEEK_END))) {
throw new DupLiteSnapLib_32BitSizeLimitException("Trying to seek on a file beyond the capability of 32 bit PHP. offset=$offset filesize=$filesize");
} else {
throw new Exception("Error seeking to file offset $offset. Retval = $ret_val");
}
}
}
public static function filemtime($filename)
{
$mtime = filemtime($filename);
if ($mtime === E_WARNING) {
throw new Exception("Cannot retrieve last modified time of $filename");
}
return $mtime;
}
/**
* exetute a file put contents after some checks. throw exception if fail.
*
* @param string $filename
* @param mixed $data
* @return boolean
* @throws Exception if putcontents fails
*/
public static function filePutContents($filename, $data)
{
if (($dirFile = realpath(dirname($filename))) === false) {
throw new Exception('FILE ERROR: put_content for file '.$filename.' failed [realpath fail]');
}
if (!is_dir($dirFile)) {
throw new Exception('FILE ERROR: put_content for file '.$filename.' failed [dir '.$dirFile.' don\'t exists]');
}
if (!is_writable($dirFile)) {
throw new Exception('FILE ERROR: put_content for file '.$filename.' failed [dir '.$dirFile.' exists but isn\'t writable]');
}
$realFileName = $dirFile.basename($filename);
if (file_exists($realFileName) && !is_writable($realFileName)) {
throw new Exception('FILE ERROR: put_content for file '.$filename.' failed [file exist '.$realFileName.' but isn\'t writable');
}
if (file_put_contents($filename, $data) === false) {
throw new Exception('FILE ERROR: put_content for file '.$filename.' failed [Couldn\'t write data to '.$realFileName.']');
}
return true;
}
public static function getFileName($file_path)
{
$info = new SplFileInfo($file_path);
return $info->getFilename();
}
public static function getPath($file_path)
{
$info = new SplFileInfo($file_path);
return $info->getPath();
}
/**
* this function make a chmod only if the are different from perms input and if chmod function is enabled
*
* this function handles the variable MODE in a way similar to the chmod of lunux
* So the MODE variable can be
* 1) an octal number (0755)
* 2) a string that defines an octal number ("644")
* 3) a string with the following format [ugoa]*([-+=]([rwx]*)+
*
* examples
* u+rw add read and write at the user
* u+rw,uo-wx add read and write ad the user and remove wx at groupd and other
* a=rw is equal at 666
* u=rwx,go-rwx is equal at 700
*
* @param string $file
* @param int|string $mode
* @return boolean
*/
public static function chmod($file, $mode)
{
if (!file_exists($file)) {
return false;
}
$octalMode = 0;
if (is_int($mode)) {
$octalMode = $mode;
} else if (is_numeric($mode)) {
$octalMode = intval((($mode[0] === '0' ? '' : '0').$mode), 8);
} else if (is_string($mode) && preg_match_all('/(a|[ugo]{1,3})([-=+])([rwx]{1,3})/', $mode, $gMatch, PREG_SET_ORDER)) {
if (!function_exists('fileperms')) {
return false;
}
// start by file permission
$octalMode = (fileperms($file) & 0777);
foreach ($gMatch as $matches) {
// [ugo] or a = ugo
$group = $matches[1];
if ($group === 'a') {
$group = 'ugo';
}
// can be + - =
$action = $matches[2];
// [rwx]
$gPerms = $matches[3];
// reset octal group perms
$octalGroupMode = 0;
// Init sub perms
$subPerm = 0;
$subPerm += strpos($gPerms, 'x') !== false ? 1 : 0; // mask 001
$subPerm += strpos($gPerms, 'w') !== false ? 2 : 0; // mask 010
$subPerm += strpos($gPerms, 'r') !== false ? 4 : 0; // mask 100
$ugoLen = strlen($group);
if ($action === '=') {
// generate octal group permsissions and ugo mask invert
$ugoMaskInvert = 0777;
for ($i = 0; $i < $ugoLen; $i++) {
switch ($group[$i]) {
case 'u':
$octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000
$ugoMaskInvert = $ugoMaskInvert & 077;
break;
case 'g':
$octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000
$ugoMaskInvert = $ugoMaskInvert & 0707;
break;
case 'o':
$octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx
$ugoMaskInvert = $ugoMaskInvert & 0770;
break;
}
}
// apply = action
$octalMode = $octalMode & ($ugoMaskInvert | $octalGroupMode);
} else {
// generate octal group permsissions
for ($i = 0; $i < $ugoLen; $i++) {
switch ($group[$i]) {
case 'u':
$octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000
break;
case 'g':
$octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000
break;
case 'o':
$octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx
break;
}
}
// apply + or - action
switch ($action) {
case '+':
$octalMode = $octalMode | $octalGroupMode;
break;
case '-':
$octalMode = $octalMode & ~$octalGroupMode;
break;
}
}
}
} else {
return true;
}
// if input permissions are equal at file permissions return true without performing chmod
if (function_exists('fileperms') && $octalMode === (fileperms($file) & 0777)) {
return true;
}
if (!function_exists('chmod')) {
return false;
}
return @chmod($file, $octalMode);
}
/**
* return file perms in string
*
* @param int|string $perms
* @return string|bool // false if fail
*/
public static function permsToString($perms)
{
if (is_int($perms)) {
return decoct($perms);
} else if (is_numeric($perms)) {
return ($perms[0] === '0' ? '' : '0').$perms;
} else if (is_string($perms)) {
return $perms;
} else {
false;
}
}
/**
* this function creates a folder if it does not exist and performs a chmod.
* it is different from the normal mkdir function to which an umask is applied to the input permissions.
*
* this function handles the variable MODE in a way similar to the chmod of lunux
* So the MODE variable can be
* 1) an octal number (0755)
* 2) a string that defines an octal number ("644")
* 3) a string with the following format [ugoa]*([-+=]([rwx]*)+
*
* @param string $path
* @param int|string $mode
* @param bool $recursive
* @param resource $context // not used fo windows bug
* @return boolean bool TRUE on success or FALSE on failure.
*
* @todo check recursive true and multiple chmod
*/
public static function mkdir($path, $mode = 0777, $recursive = false, $context = null)
{
if (strlen($path) > DupLiteSnapLibOSU::maxPathLen()) {
throw new Exception('Skipping a file that exceeds allowed max path length ['.DupLiteSnapLibOSU::maxPathLen().']. File: '.$path);
}
if (!file_exists($path)) {
if (!function_exists('mkdir')) {
return false;
}
if (!@mkdir($path, 0777, $recursive)) {
return false;
}
}
return self::chmod($path, $mode);
}
/**
* this function call snap mkdir if te folder don't exists od don't have write or exec permissions
*
* this function handles the variable MODE in a way similar to the chmod of lunux
* The mode variable can be set to have more flexibility but not giving the user write and read and exec permissions doesn't make much sense
*
* @param string $path
* @param int|string $mode
* @param bool $recursive
* @param resource $context
* @return boolean
*/
public static function dirWriteCheckOrMkdir($path, $mode = 'u+rwx', $recursive = false, $context = null)
{
if (!file_exists($path)) {
return self::mkdir($path, $mode, $recursive, $context);
} else if (!is_writable($path) || !is_executable($path)) {
return self::chmod($path, $mode);
} else {
return true;
}
}
/**
* from wordpress function wp_is_stream
*
* @param string $path The resource path or URL.
* @return bool True if the path is a stream URL.
*/
public static function is_stream($path)
{
$scheme_separator = strpos($path, '://');
if (false === $scheme_separator) {
// $path isn't a stream
return false;
}
$stream = substr($path, 0, $scheme_separator);
return in_array($stream, stream_get_wrappers(), true);
}
/**
* From Wordpress function: wp_mkdir_p
*
* Recursive directory creation based on full path.
*
* Will attempt to set permissions on folders.
*
* @param string $target Full path to attempt to create.
* @return bool Whether the path was created. True if path already exists.
*/
public static function mkdir_p($target)
{
$wrapper = null;
// Strip the protocol.
if (self::is_stream($target)) {
list( $wrapper, $target ) = explode('://', $target, 2);
}
// From php.net/mkdir user contributed notes.
$target = str_replace('//', '/', $target);
// Put the wrapper back on the target.
if ($wrapper !== null) {
$target = $wrapper.'://'.$target;
}
/*
* Safe mode fails with a trailing slash under certain PHP versions.
* Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
*/
$target = rtrim($target, '/');
if (empty($target)) {
$target = '/';
}
if (file_exists($target)) {
return @is_dir($target);
}
// We need to find the permissions of the parent folder that exists and inherit that.
$target_parent = dirname($target);
while ('.' != $target_parent && !is_dir($target_parent) && dirname($target_parent) !== $target_parent) {
$target_parent = dirname($target_parent);
}
// Get the permission bits.
if ($stat = @stat($target_parent)) {
$dir_perms = $stat['mode'] & 0007777;
} else {
$dir_perms = 0777;
}
if (@mkdir($target, $dir_perms, true)) {
/*
* If a umask is set that modifies $dir_perms, we'll have to re-set
* the $dir_perms correctly with chmod()
*/
if ($dir_perms != ( $dir_perms & ~umask() )) {
$folder_parts = explode('/', substr($target, strlen($target_parent) + 1));
for ($i = 1, $c = count($folder_parts); $i <= $c; $i++) {
@chmod($target_parent.'/'.implode('/', array_slice($folder_parts, 0, $i)), $dir_perms);
}
}
return true;
}
return false;
}
/**
*
* @param string|bool $path // return false if path isn't a sub path of main path or return the relative path
*/
public static function getRelativePath($path, $mainPath)
{
if (strlen($mainPath) == 0) {
return ltrim(self::safePathUntrailingslashit($path), '/');
}
$safePath = self::safePathUntrailingslashit($path);
$safeMainPath = self::safePathUntrailingslashit($mainPath);
if ($safePath === $safeMainPath) {
return '';
} else if (strpos($safePath, self::trailingslashit($safeMainPath)) === 0) {
return ltrim(substr($safePath, strlen($safeMainPath)), '/');
} else {
return false;
}
}
/**
* from wp_normalize_path
*
* @param string $path Path to normalize.
* @return string Normalized path.
*/
public static function normalize_path($path)
{
$wrapper = '';
if (self::is_stream($path)) {
list( $wrapper, $path ) = explode('://', $path, 2);
$wrapper .= '://';
}
// Standardise all paths to use /
$path = str_replace('\\', '/', $path);
// Replace multiple slashes down to a singular, allowing for network shares having two slashes.
$path = preg_replace('|(?<=.)/+|', '/', $path);
if (strpos($path, '//') === 0) {
$path = substr($path, 1);
}
// Windows paths should uppercase the drive letter
if (':' === substr($path, 1, 1)) {
$path = ucfirst($path);
}
return $wrapper.$path;
}
/**
* Get common parent path from given paths
*
* @param array $paths - array of paths
* @return common parent path
*/
public static function getCommonPath($paths = array())
{
if (empty($paths)) {
return '';
} if (!is_array($paths)) {
$paths = array($paths);
} else {
$paths = array_values($paths);
}
$pathAssoc = array();
$numPaths = count($paths);
$minPathCouts = PHP_INT_MAX;
for ($i = 0; $i < $numPaths; $i++) {
$pathAssoc[$i] = explode('/', self::safePathUntrailingslashit($paths[$i]));
$pathCount = count($pathAssoc[$i]);
if ($minPathCouts > $pathCount) {
$minPathCouts = $pathCount;
}
}
for ($partIndex = 0; $partIndex < $minPathCouts; $partIndex++) {
$currentPart = $pathAssoc[0][$partIndex];
for ($currentPath = 1; $currentPath < $numPaths; $currentPath++) {
if ($pathAssoc[$currentPath][$partIndex] != $currentPart) {
break 2;
}
}
}
$resultParts = array_slice($pathAssoc[0], 0, $partIndex);
return implode('/', $resultParts);
}
/**
* remove root path transforming the current path into a relative path
*
* ex. /aaa/bbb become aaa/bbb
* ex. C:\aaa\bbb become aaa\bbb
*
* @param string $path
* @return string
*/
public static function removeRootPath($path)
{
return preg_replace('/^(?:[A-Za-z]:)?[\/](.*)/', '$1', $path);
}
/**
* Returns the last N lines of a file. Simular to tail command
*
* @param string $filepath The full path to the file to be tailed
* @param int $lines The number of lines to return with each tail call
*
* @return string The last N parts of the file
*/
public static function tailFile($filepath, $lines = 2)
{
// Open file
$f = @fopen($filepath, "rb");
if ($f === false)
return false;
// Sets buffer size
$buffer = 256;
// Jump to last character
fseek($f, -1, SEEK_END);
// Read it and adjust line number if necessary
// (Otherwise the result would be wrong if file doesn't end with a blank line)
if (fread($f, 1) != "\n")
$lines -= 1;
// Start reading
$output = '';
$chunk = '';
// While we would like more
while (ftell($f) > 0 && $lines >= 0) {
// Figure out how far back we should jump
$seek = min(ftell($f), $buffer);
// Do the jump (backwards, relative to where we are)
fseek($f, -$seek, SEEK_CUR);
// Read a chunk and prepend it to our output
$output = ($chunk = fread($f, $seek)).$output;
// Jump back to where we started reading
fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR);
// Decrease our line counter
$lines -= substr_count($chunk, "\n");
}
// While we have too many lines
// (Because of buffer size we might have read too many)
while ($lines++ < 0) {
// Find first newline and remove all text before that
$output = substr($output, strpos($output, "\n") + 1);
}
fclose($f);
return trim($output);
}
/**
* @param string $path Path to the file
* @param int $n Number of lines to get
* @param int $charLimit Number of chars to include in each line
* @return bool|array Last $n lines of file
* @throws Exception
*/
public static function getLastLinesOfFile($path, $n, $charLimit = null)
{
if (!is_readable($path)) {
return false;
}
if (($handle = self::fopen($path, 'r', false)) === false) {
return false;
}
$result = array();
$pos = -1;
$currentLine = '';
$counter = 0;
while ($counter < $n && -1 !== fseek($handle, $pos, SEEK_END)) {
$char = fgetc($handle);
if (PHP_EOL == $char) {
$trimmedValue = trim($currentLine);
if (is_null($charLimit)) {
$currentLine = substr($currentLine, 0);
} else {
$currentLine = substr($currentLine, 0, (int) $charLimit);
if (strlen($currentLine) == $charLimit) {
$currentLine .= '...';
}
}
if (!empty($trimmedValue)) {
$result[] = $currentLine;
$counter++;
}
$currentLine = '';
} else {
$currentLine = $char.$currentLine;
}
$pos--;
}
self::fclose($handle, false);
return array_reverse($result);
}
/**
* return a list of paths
*
* @param string $dir
* @param callable $callback
* @param array $options // array(
* 'regexFile' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
* 'regexFolder' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
* 'checkFullPath' => bool, // if false only current file/folder name is passed at regex if true is passed the full path
* 'recursive' => bool, // if false check only passed folder or all sub folder recursively
* 'invert' => bool, // if false pass invert the result
* 'childFirst' => bool // if false is parsed parent folters first or child folders first
* )
*
* @return boolean
*/
public static function regexGlob($dir, $options)
{
$result = array();
self::regexGlobCallback($dir, function ($path) use (&$result) {
$result[] = $path;
}, $options);
return $result;
}
/**
* execute the callback function foreach right element, private function for optimization
*
* @param string $dir
* @param callable $callback
* @param array $options // array(
* 'regexFile' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
* 'regexFolder' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
* 'checkFullPath' => bool, // if false only current file/folder name is passed at regex if true is passed the full path
* 'recursive' => bool, // if false check only passed folder or all sub folder recursively
* 'invert' => bool, // if false pass invert the result
* 'childFirst' => bool // if false is parsed parent folters first or child folders first
* )
*
* @return boolean
*/
protected static function regexGlobCallbackPrivate($dir, $callback, $options)
{
if (!is_dir($dir) || !is_readable($dir)) {
return false;
}
if (($dh = opendir($dir)) == false) {
return false;
}
$trailingslashitDir = self::trailingslashit($dir);
while (($elem = readdir($dh)) !== false) {
if ($elem === '.' || $elem === '..') {
continue;
}
$fullPath = $trailingslashitDir.$elem;
$regex = is_dir($fullPath) ? $options['regexFolder'] : $options['regexFile'];
$pathCheck = $options['checkFullPath'] ? $fullPath : $elem;
if (is_bool($regex)) {
$match = ($regex xor $options['invert']);
} else {
$match = false;
foreach ($regex as $currentRegex) {
if (preg_match($currentRegex, $pathCheck) === 1) {
$match = true;
break;
}
}
if ($options['invert']) {
$match = !$match;
}
}
if ($match) {
if ($options['recursive'] && $options['childFirst'] === true && is_dir($fullPath)) {
self::regexGlobCallbackPrivate($fullPath, $callback, $options);
}
call_user_func($callback, $fullPath);
if ($options['recursive'] && $options['childFirst'] === false && is_dir($fullPath)) {
self::regexGlobCallbackPrivate($fullPath, $callback, $options);
}
}
}
closedir($dh);
return true;
}
/**
* execute the callback function foreach right element (folder or files)
*
* @param string $dir
* @param callable $callback
* @param array $options // array(
* 'regexFile' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
* 'regexFolder' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
* 'checkFullPath' => bool, // if false only current file/folder name is passed at regex if true is passed the full path
* 'recursive' => bool, // if false check only passed folder or all sub folder recursively
* 'invert' => bool, // if false pass invert the result
* 'childFirst' => bool // if false is parsed parent folters first or child folders first
* )
*
* @return boolean
*/
public static function regexGlobCallback($dir, $callback, $options = array())
{
if (!is_callable($callback)) {
return false;
}
$options = array_merge(array(
'regexFile' => true,
'regexFolder' => true,
'checkFullPath' => false,
'recursive' => false,
'invert' => false,
'childFirst' => false
), (array) $options);
if (is_scalar($options['regexFile']) && !is_bool($options['regexFile'])) {
$options['regexFile'] = array($options['regexFile']);
}
if (is_scalar($options['regexFolder']) && !is_bool($options['regexFolder'])) {
$options['regexFolder'] = array($options['regexFolder']);
}
return self::regexGlobCallbackPrivate(self::safePath($dir), $callback, $options);
}
public static function emptyDir($dir)
{
$dir = self::safePathTrailingslashit($dir);
if (!is_dir($dir) || !is_readable($dir)) {
return false;
}
if (($dh = opendir($dir)) == false) {
return false;
}
$listToDelete = array();
while (($elem = readdir($dh)) !== false) {
if ($elem === '.' || $elem === '..') {
continue;
}
$fullPath = $dir.$elem;
if (is_writable($fullPath)) {
$listToDelete[] = $fullPath;
}
}
closedir($dh);
foreach ($listToDelete as $path) {
self::rrmdir($path);
}
return true;
}
/**
* Returns a path to the base root folder of path taking into account the
* open_basedir setting.
*
* @param $path
* @return bool|string Base root path of $path if it's accessible, otherwise false;
*/
public static function getMaxAllowedRootOfPath($path)
{
$path = self::safePathUntrailingslashit($path, true);
if (!self::isOpenBaseDirEnabled()) {
$parts = explode("/", $path);
return $parts[0]."/";
} else {
return self::getOpenBaseDirRootOfPath($path);
}
}
/**
* @return bool true if open_basedir is set
*/
public static function isOpenBaseDirEnabled()
{
$iniVar = ini_get("open_basedir");
return !empty($iniVar);
}
/**
* @return array Paths contained in the open_basedir setting. Empty array if the setting
* is not enabled.
*/
public static function getOpenBaseDirPaths()
{
if (!($openBase = ini_get("open_basedir"))) {
return array();
}
return explode(PATH_SEPARATOR, $openBase);
}
/**
* @param $path
* @return bool|mixed|string Path to the base dir of $path if it exists, otherwise false
*/
public static function getOpenBaseDirRootOfPath($path)
{
foreach (self::getOpenBaseDirPaths() as $allowedPath) {
$allowedPath = $allowedPath !== "/" ? self::safePathUntrailingslashit($allowedPath) : "/";
if (strpos($path, $allowedPath) === 0) {
return $allowedPath;
}
}
return false;
}
}
}
lib/config/class.wp.config.tranformer.php 0000644 00000033445 15133606540 0014460 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteWPConfigTransformer')):
/**
* Transforms a wp-config.php file.
*/
class DupLiteWPConfigTransformer {
const REPLACE_TEMP_STIRNG = '_1_2_RePlAcE_3_4_TeMp_5_6_StRiNg_7_8_';
/**
* Path to the wp-config.php file.
*
* @var string
*/
protected $wp_config_path;
/**
* Original source of the wp-config.php file.
*
* @var string
*/
protected $wp_config_src;
/**
* Array of parsed configs.
*
* @var array
*/
protected $wp_configs = array();
/**
* Instantiates the class with a valid wp-config.php.
*
* @throws Exception If the wp-config.php file is missing.
* @throws Exception If the wp-config.php file is not writable.
*
* @param string $wp_config_path Path to a wp-config.php file.
*/
public function __construct( $wp_config_path ) {
if ( ! file_exists( $wp_config_path ) ) {
throw new Exception( 'wp-config.php file does not exist.' );
}
// Duplicator Extra
/*
if ( ! is_writable( $wp_config_path ) ) {
throw new Exception( 'wp-config.php file is not writable.' );
}
*/
$this->wp_config_path = $wp_config_path;
}
/**
* Checks if a config exists in the wp-config.php file.
*
* @throws Exception If the wp-config.php file is empty.
* @throws Exception If the requested config type is invalid.
*
* @param string $type Config type (constant or variable).
* @param string $name Config name.
*
* @return bool
*/
public function exists( $type, $name ) {
$wp_config_src = file_get_contents( $this->wp_config_path );
if ( ! trim( $wp_config_src ) ) {
throw new Exception( 'wp-config.php file is empty.' );
}
// SnapCreek custom change
// Normalize the newline to prevent an issue coming from OSX
$wp_config_src = str_replace(array("\n\r", "\r"), array("\n", "\n"), $wp_config_src);
$this->wp_config_src = $wp_config_src;
$this->wp_configs = $this->parse_wp_config( $this->wp_config_src );
if ( ! isset( $this->wp_configs[ $type ] ) ) {
throw new Exception( "Config type '{$type}' does not exist." );
}
return isset( $this->wp_configs[ $type ][ $name ] );
}
/**
* Get the value of a config in the wp-config.php file.
*
* @throws Exception If the wp-config.php file is empty.
* @throws Exception If the requested config type is invalid.
*
* @param string $type Config type (constant or variable).
* @param string $name Config name.
*
* @return array
*/
public function get_value( $type, $name, $get_real_value = true) {
$wp_config_src = file_get_contents( $this->wp_config_path );
if ( ! trim( $wp_config_src ) ) {
throw new Exception( 'wp-config.php file is empty.' );
}
// SnapCreek custom change
// Normalize the newline to prevent an issue coming from OSX
$wp_config_src = str_replace(array("\n\r", "\r"), array("\n", "\n"), $wp_config_src);
$this->wp_config_src = $wp_config_src;
$this->wp_configs = $this->parse_wp_config( $this->wp_config_src );
if ( ! isset( $this->wp_configs[ $type ] ) ) {
throw new Exception( "Config type '{$type}' does not exist." );
}
// Duplicator Extra
$val = $this->wp_configs[ $type ][ $name ]['value'];
if ($get_real_value) {
return self::getRealValFromVal($val);
} else {
return $val;
}
return $val;
}
public static function getRealValFromVal($val)
{
if ($val[0] === '\'') {
// string with '
$result = substr($val, 1, strlen($val) - 2);
return str_replace(array('\\\'', '\\\\'), array('\'', '\\'), $result);
} else if ($val[0] === '"') {
// string with "
return json_decode(str_replace('\\$', '$', $val));
} else if (strcasecmp($val, 'true') === 0) {
return true;
} else if (strcasecmp($val, 'false') === 0) {
return false;
} else if (strcasecmp($val, 'null') === 0) {
return null;
} else if (preg_match('/^[-+]?[0-9]+$/', $val)) {
return (int) $val;
} else if (preg_match('/^[-+]?[0-9]+\.[0-9]+$/', $val)) {
return (float) $val;
} else {
return $val;
}
}
/**
* Adds a config to the wp-config.php file.
*
* @throws Exception If the config value provided is not a string.
* @throws Exception If the config placement anchor could not be located.
*
* @param string $type Config type (constant or variable).
* @param string $name Config name.
* @param string $value Config value.
* @param array $options (optional) Array of special behavior options.
*
* @return bool
*/
public function add( $type, $name, $value, array $options = array() ) {
if ( ! is_string( $value ) ) {
throw new Exception( 'Config value must be a string.' );
}
if ( $this->exists( $type, $name ) ) {
return false;
}
$defaults = array(
'raw' => false, // Display value in raw format without quotes.
'anchor' => "/* That's all, stop editing!", // Config placement anchor string.
'separator' => PHP_EOL, // Separator between config definition and anchor string.
'placement' => 'before', // Config placement direction (insert before or after).
);
list( $raw, $anchor, $separator, $placement ) = array_values( array_merge( $defaults, $options ) );
$raw = (bool) $raw;
$anchor = (string) $anchor;
$separator = (string) $separator;
$placement = (string) $placement;
// Custom code by the SnapCreek Team
if ( false === strpos( $this->wp_config_src, $anchor ) ) {
$other_anchor_points = array(
'/** Absolute path to the WordPress directory',
// ABSPATH defined check with single quote
"if ( !defined('ABSPATH') )",
"if ( ! defined( 'ABSPATH' ) )",
"if (!defined('ABSPATH') )",
"if(!defined('ABSPATH') )",
"if(!defined('ABSPATH'))",
"if ( ! defined( 'ABSPATH' ))",
"if ( ! defined( 'ABSPATH') )",
"if ( ! defined('ABSPATH' ) )",
"if (! defined( 'ABSPATH' ))",
"if (! defined( 'ABSPATH') )",
"if (! defined('ABSPATH' ) )",
"if ( !defined( 'ABSPATH' ))",
"if ( !defined( 'ABSPATH') )",
"if ( !defined('ABSPATH' ) )",
"if( !defined( 'ABSPATH' ))",
"if( !defined( 'ABSPATH') )",
"if( !defined('ABSPATH' ) )",
// ABSPATH defined check with double quote
'if ( !defined("ABSPATH") )',
'if ( ! defined( "ABSPATH" ) )',
'if (!defined("ABSPATH") )',
'if(!defined("ABSPATH") )',
'if(!defined("ABSPATH"))',
'if ( ! defined( "ABSPATH" ))',
'if ( ! defined( "ABSPATH") )',
'if ( ! defined("ABSPATH" ) )',
'if (! defined( "ABSPATH" ))',
'if (! defined( "ABSPATH") )',
'if (! defined("ABSPATH" ) )',
'if ( !defined( "ABSPATH" ))',
'if ( !defined( "ABSPATH") )',
'if ( !defined("ABSPATH" ) )',
'if( !defined( "ABSPATH" ))',
'if( !defined( "ABSPATH") )',
'if( !defined("ABSPATH" ) )',
'/** Sets up WordPress vars and included files',
'require_once(ABSPATH',
'require_once ABSPATH',
'require_once( ABSPATH',
'require_once',
"define( 'DB_NAME'",
'define( "DB_NAME"',
"define('DB_NAME'",
'define("DB_NAME"',
'require',
'include_once',
);
foreach ($other_anchor_points as $anchor_point) {
$anchor_point = (string) $anchor_point;
if ( false !== strpos( $this->wp_config_src, $anchor_point ) ) {
$anchor = $anchor_point;
break;
}
}
}
if ( false === strpos( $this->wp_config_src, $anchor ) ) {
throw new Exception( 'Unable to locate placement anchor.' );
}
$new_src = $this->normalize( $type, $name, $this->format_value( $value, $raw ) );
$new_src = ( 'after' === $placement ) ? $anchor . $separator . $new_src : $new_src . $separator . $anchor;
$contents = str_replace( $anchor, $new_src, $this->wp_config_src );
return $this->save( $contents );
}
/**
* Updates an existing config in the wp-config.php file.
*
* @throws Exception If the config value provided is not a string.
*
* @param string $type Config type (constant or variable).
* @param string $name Config name.
* @param string $value Config value.
* @param array $options (optional) Array of special behavior options.
*
* @return bool
*/
public function update( $type, $name, $value, array $options = array() ) {
if ( ! is_string( $value ) ) {
throw new Exception( 'Config value must be a string.' );
}
$defaults = array(
'add' => true, // Add the config if missing.
'raw' => false, // Display value in raw format without quotes.
'normalize' => false, // Normalize config output using WP Coding Standards.
);
list( $add, $raw, $normalize ) = array_values( array_merge( $defaults, $options ) );
$add = (bool) $add;
$raw = (bool) $raw;
$normalize = (bool) $normalize;
if ( ! $this->exists( $type, $name ) ) {
return ( $add ) ? $this->add( $type, $name, $value, $options ) : false;
}
$old_src = $this->wp_configs[ $type ][ $name ]['src'];
$old_value = $this->wp_configs[ $type ][ $name ]['value'];
$new_value = $this->format_value( $value, $raw );
if ( $normalize ) {
$new_src = $this->normalize( $type, $name, $new_value );
} else {
$new_parts = $this->wp_configs[ $type ][ $name ]['parts'];
$new_parts[1] = str_replace( $old_value, $new_value, $new_parts[1] ); // Only edit the value part.
$new_src = implode( '', $new_parts );
}
$contents = preg_replace(
sprintf( '/(?<=^|;|<\?php\s|<\?\s)(\s*?)%s/m', preg_quote( trim( $old_src ), '/' ) ),
'$1' . self::REPLACE_TEMP_STIRNG ,
$this->wp_config_src
);
$contents = str_replace(self::REPLACE_TEMP_STIRNG, trim($new_src), $contents);
return $this->save( $contents );
}
/**
* Removes a config from the wp-config.php file.
*
* @param string $type Config type (constant or variable).
* @param string $name Config name.
*
* @return bool
*/
public function remove( $type, $name ) {
if ( ! $this->exists( $type, $name ) ) {
return false;
}
$pattern = sprintf( '/(?<=^|;|<\?php\s|<\?\s)%s\s*(\S|$)/m', preg_quote( $this->wp_configs[ $type ][ $name ]['src'], '/' ) );
$contents = preg_replace( $pattern, '$1', $this->wp_config_src );
return $this->save( $contents );
}
/**
* Applies formatting to a config value.
*
* @throws Exception When a raw value is requested for an empty string.
*
* @param string $value Config value.
* @param bool $raw Display value in raw format without quotes.
*
* @return mixed
*/
protected function format_value( $value, $raw ) {
if ( $raw && '' === trim( $value ) ) {
throw new Exception( 'Raw value for empty string not supported.' );
}
return ( $raw ) ? $value : var_export( $value, true );
}
/**
* Normalizes the source output for a name/value pair.
*
* @throws Exception If the requested config type does not support normalization.
*
* @param string $type Config type (constant or variable).
* @param string $name Config name.
* @param mixed $value Config value.
*
* @return string
*/
protected function normalize( $type, $name, $value ) {
if ( 'constant' === $type ) {
$placeholder = "define( '%s', %s );";
} elseif ( 'variable' === $type ) {
$placeholder = '$%s = %s;';
} else {
throw new Exception( "Unable to normalize config type '{$type}'." );
}
return sprintf( $placeholder, $name, $value );
}
/**
* Parses the source of a wp-config.php file.
*
* @param string $src Config file source.
*
* @return array
*/
protected function parse_wp_config( $src ) {
$configs = array();
$configs['constant'] = array();
$configs['variable'] = array();
// Strip comments.
foreach ( token_get_all( $src ) as $token ) {
if ( in_array( $token[0], array( T_COMMENT, T_DOC_COMMENT ), true ) ) {
$src = str_replace( $token[1], '', $src );
}
}
preg_match_all( '/(?<=^|;|<\?php\s|<\?\s)(\h*define\s*\(\s*[\'"](\w*?)[\'"]\s*)(,\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*)((?:,\s*(?:true|false)\s*)?\)\s*;)/ims', $src, $constants );
preg_match_all( '/(?<=^|;|<\?php\s|<\?\s)(\h*\$(\w+)\s*=)(\s*(\'\'|""|\'.*?[^\\\\]\'|".*?[^\\\\]"|.*?)\s*;)/ims', $src, $variables );
if ( ! empty( $constants[0] ) && ! empty( $constants[1] ) && ! empty( $constants[2] ) && ! empty( $constants[3] ) && ! empty( $constants[4] ) && ! empty( $constants[5] ) ) {
foreach ( $constants[2] as $index => $name ) {
$configs['constant'][ $name ] = array(
'src' => $constants[0][ $index ],
'value' => $constants[4][ $index ],
'parts' => array(
$constants[1][ $index ],
$constants[3][ $index ],
$constants[5][ $index ],
),
);
}
}
if ( ! empty( $variables[0] ) && ! empty( $variables[1] ) && ! empty( $variables[2] ) && ! empty( $variables[3] ) && ! empty( $variables[4] ) ) {
// Remove duplicate(s), last definition wins.
$variables[2] = array_reverse( array_unique( array_reverse( $variables[2], true ) ), true );
foreach ( $variables[2] as $index => $name ) {
$configs['variable'][ $name ] = array(
'src' => $variables[0][ $index ],
'value' => $variables[4][ $index ],
'parts' => array(
$variables[1][ $index ],
$variables[3][ $index ],
),
);
}
}
return $configs;
}
/**
* Saves new contents to the wp-config.php file.
*
* @throws Exception If the config file content provided is empty.
* @throws Exception If there is a failure when saving the wp-config.php file.
*
* @param string $contents New config contents.
*
* @return bool
*/
protected function save( $contents ) {
if ( ! trim( $contents ) ) {
throw new Exception( 'Cannot save the wp-config.php file with empty contents.' );
}
if ( $contents === $this->wp_config_src ) {
return false;
}
$result = file_put_contents( $this->wp_config_path, $contents, LOCK_EX );
if ( false === $result ) {
throw new Exception( 'Failed to update the wp-config.php file.' );
}
return true;
}
}
endif;
lib/config/class.wp.config.tranformer.src.php 0000644 00000005245 15133606540 0015243 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if (!class_exists('DupLiteWPConfigTransformer')) {
require_once(dirname(__FILE__).'/class.wp.config.tranformer.php');
}
if (!class_exists('DupLiteWPConfigTransformerSrc')):
/**
* Transforms a wp-config.php file.
*/
class DupLiteWPConfigTransformerSrc extends DupLiteWPConfigTransformer
{
/**
* Instantiates the class with a valid wp-config.php scr text
*
* @param string $wp_config_path Path to a wp-config.php file.
*/
public function __construct($wp_config_src)
{
// Normalize the newline to prevent an issue coming from OSX
$this->wp_config_src = str_replace(array("\n\r", "\r"), array("\n", "\n"), $wp_config_src);
}
public function getSrc()
{
return $this->wp_config_src;
}
/**
* Checks if a config exists in the wp-config.php src
*
* @throws Exception If the wp-config.php file is empty.
* @throws Exception If the requested config type is invalid.
*
* @param string $type Config type (constant or variable).
* @param string $name Config name.
*
* @return bool
*/
public function exists($type, $name)
{
$this->wp_configs = $this->parse_wp_config($this->wp_config_src);
if (!isset($this->wp_configs[$type])) {
throw new Exception("Config type '{$type}' does not exist.");
}
return isset($this->wp_configs[$type][$name]);
}
/**
* Get the value of a config in the wp-config.php src
*
* @param string $type Config type (constant or variable).
* @param string $name Config name.
*
* @return array
*/
public function get_value($type, $name, $get_real_value = true)
{
$this->wp_configs = $this->parse_wp_config($this->wp_config_src);
if (!isset($this->wp_configs[$type])) {
throw new Exception("Config type '{$type}' does not exist.");
}
// Duplicator Extra
$val = $this->wp_configs[$type][$name]['value'];
if ($get_real_value) {
return self::getRealValFromVal($val);
} else {
return $val;
}
}
/**
* update wp_config_src
*
* @param string $contents
* @return boolean
*/
protected function save($contents)
{
$this->wp_config_src = $contents;
return true;
}
}
endif;
lib/index.php 0000644 00000000034 15133606540 0007132 0 ustar 00 <?php
// Silence is golden.
lib/fileops/class.fileops.u.delete.php 0000644 00000002221 15133606540 0013735 0 ustar 00 <?php
if (!defined("ABSPATH") && !defined("DUPXABSPATH"))
die("");
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
class FileOpsDeleteConfig
{
public $workerTime;
public $directories;
public $throttleDelayInUs;
public $excludedDirectories;
public $excludedFiles;
public $fileLock;
}
class FileOpsDeleteU
{
// Move $directories, $files, $excludedFiles to $destination directory. Throws exception if it can't do something and $exceptionOnFaiure is true
// $exludedFiles can include * wildcard
// returns: array with list of failures
public static function delete($currentDirectory, &$deleteConfig)
{
$timedOut = false;
if (is_dir($currentDirectory)) {
$objects = scandir($currentDirectory);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (is_dir($currentDirectory."/".$object)) {
self::delete($currentDirectory."/".$object, $deleteConfig);
}
else {
@unlink($currentDirectory."/".$object);
}
}
}
@rmdir($currentDirectory);
}
}
} lib/fileops/class.fileops.u.move.php 0000644 00000002436 15133606540 0013451 0 ustar 00 <?php
if (!defined("ABSPATH") && !defined("DUPXABSPATH"))
die("");
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
class FileOpsMoveU
{
// Move $directories, $files, $excludedFiles to $destination directory. Throws exception if it can't do something and $exceptionOnFaiure is true
// $exludedFiles can include * wildcard
// returns: array with list of failures
public static function move($directories, $files, $excludedFiles, $destination)
{
DupLiteSnapLibLogger::logObject('directories', $directories);
DupLiteSnapLibLogger::logObject('files', $files);
DupLiteSnapLibLogger::logObject('excludedFiles', $excludedFiles);
DupLiteSnapLibLogger::logObject('destination', $destination);
$failures = array();
$directoryFailures = DupLiteSnapLibIOU::massMove($directories, $destination, null, false);
DupLiteSnapLibLogger::log('done directories');
$fileFailures = DupLiteSnapLibIOU::massMove($files, $destination, $excludedFiles, false);
DupLiteSnapLibLogger::log('done files');
return array_merge($directoryFailures, $fileFailures);
}
} lib/fileops/class.fileops.state.php 0000644 00000005211 15133606540 0013352 0 ustar 00 <?php
if (!defined("ABSPATH") && !defined("DUPXABSPATH"))
die("");
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
class FileOpsState
{
public static $instance = null;
private $workerTime;
private $directories;
private $throttleDelay;
private $excludedDirectories;
private $excludedFiles;
private $working = false;
const StateFilename = 'state.json';
public static function getInstance($reset = false)
{
if ((self::$instance == null) && (!$reset)) {
$stateFilepath = dirname(__FILE__).'/'.self::StateFilename;
self::$instance = new FileOpsState();
if (file_exists($stateFilepath)) {
$stateHandle = DupLiteSnapLibIOU::fopen($stateFilepath, 'rb');
DupLiteSnapLibIOU::flock($stateHandle, LOCK_EX);
$stateString = fread($stateHandle, filesize($stateFilepath));
$data = json_decode($stateString);
self::$instance->setFromData($data);
// self::$instance->fileRenames = (array)(self::$instance->fileRenames);
DupLiteSnapLibIOU::flock($stateHandle, LOCK_UN);
DupLiteSnapLibIOU::fclose($stateHandle);
} else {
$reset = true;
}
}
if ($reset) {
self::$instance = new FileOpsState();
self::$instance->reset();
}
return self::$instance;
}
private function setFromData($data)
{
// $this->currentFileHeader = $data->currentFileHeader;
}
public function reset()
{
$stateFilepath = dirname(__FILE__).'/'.self::StateFilename;
$stateHandle = DupLiteSnapLibIOU::fopen($stateFilepath, 'w');
DupLiteSnapLibIOU::flock($stateHandle, LOCK_EX);
$this->initMembers();
DupLiteSnapLibIOU::fwrite($stateHandle, json_encode($this));
DupLiteSnapLibIOU::fclose($stateHandle);
}
public function save()
{
$stateFilepath = dirname(__FILE__).'/'.self::StateFilename;
$stateHandle = DupLiteSnapLibIOU::fopen($stateFilepath, 'w');
DupLiteSnapLibIOU::flock($stateHandle, LOCK_EX);
DupArchiveUtil::tlog("saving state");
DupLiteSnapLibIOU::fwrite($stateHandle, json_encode($this));
DupLiteSnapLibIOU::fclose($stateHandle);
}
private function initMembers()
{
// $this->currentFileHeader = null;
}
} lib/fileops/class.fileops.constants.php 0000644 00000001745 15133606540 0014256 0 ustar 00 <?php
if (!defined("ABSPATH") && !defined("DUPXABSPATH"))
die("");
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
class FileOpsConstants
{
public static $FILEOPS_ROOT;
public static $DEFAULT_WORKER_TIME = 18;
public static $LIB_DIR;
public static $PROCESS_LOCK_FILEPATH;
public static $PROCESS_CANCEL_FILEPATH;
public static $KEY_FILEPATH;
public static $LOG_FILEPATH;
public static function init() {
self::$FILEOPS_ROOT = dirname(__FILE__);
self::$LIB_DIR = self::$FILEOPS_ROOT.'/..';
self::$PROCESS_LOCK_FILEPATH = self::$FILEOPS_ROOT.'/fileops_lock.bin';
self::$PROCESS_CANCEL_FILEPATH = self::$FILEOPS_ROOT.'/fileops_cancel.bin';
self::$LOG_FILEPATH = dirname(__FILE__).'/fileops.log';
}
}
FileOpsConstants::init(); lib/fileops/index.php 0000644 00000000017 15133606540 0010574 0 ustar 00 <?php
//silent lib/fileops/fileops.php 0000644 00000013305 15133606540 0011132 0 ustar 00 <?php
/** Absolute path to the DAWS directory. - necessary for php protection */
if ( !defined('ABSPATH') )
define('ABSPATH', dirname(__FILE__) . '/');
if (DupLiteSnapLibUtil::wp_is_ini_value_changeable('display_errors'))
@ini_set('display_errors', 1);
error_reporting(E_ALL);
set_error_handler("terminate_missing_variables");
require_once(dirname(__FILE__) . '/class.fileops.constants.php');
require_once(dirname(__FILE__) . '/class.fileops.u.move.php');
require_once(FileOpsConstants::$LIB_DIR . '/snaplib/snaplib.all.php');
class FileOps
{
private $lock_handle = null;
function __construct()
{
date_default_timezone_set('UTC'); // Some machines don’t have this set so just do it here.
DupLiteSnapLibLogger::init(FileOpsConstants::$LOG_FILEPATH);
}
public function processRequest()
{
try {
DupLiteSnapLibLogger::clearLog();
/* @var $state FileOpsState */
DupLiteSnapLibLogger::log('process request');
$retVal = new StdClass();
$retVal->pass = false;
if (isset($_REQUEST['action'])) {
//$params = $_REQUEST;
$params = array();
DupLiteSnapLibLogger::logObject('REQUEST', $_REQUEST);
foreach($_REQUEST as $key => $value)
{
$params[$key] = json_decode($value, true);
}
} else {
$json = file_get_contents('php://input');
DupLiteSnapLibLogger::logObject('json1', $json);
$params = json_decode($json, true);
DupLiteSnapLibLogger::logObject('json2', $json);
}
DupLiteSnapLibLogger::logObject('params', $params);
DupLiteSnapLibLogger::logObject('keys', array_keys($params));
$action = $params['action'];
if ($action == 'deltree') {
DupLiteSnapLibLogger::log('deltree');
$config = DeleteConfig();
$config->workerTime = DupLiteSnapLibUtil::GetArrayValue($params, 'worker_time');
$config->directories = DupLiteSnapLibUtil::getArrayValue($params, 'directories');
$config->throttleDelayInUs = DupLiteSnapLibUtil::getArrayValue($params, 'throttleDelay', false, 0) * 1000000;
$config->excludedDirectories = DupLiteSnapLibUtil::getArrayValue($params, 'excluded_directories', false, array());
$config->excludedFiles = DupLiteSnapLibUtil::getArrayValue($params, 'excluded_files', false, array());
$config->fileLock = DupLiteSnapLibUtil::GetArrayValue($params, 'fileLock');
DupLiteSnapLibLogger::logObject('Config', $config);
// TODO use appropriate lock type
DupLiteSnapLibIOU::flock($this->lock_handle, LOCK_EX);
$this->lock_handle = DupLiteSnapLibIOU::fopen(FileOpsConstants::$PROCESS_LOCK_FILEPATH, 'c+');
DupLiteSnapLibIOU::flock($this->lock_handle, LOCK_UN);
$retVal->pass = true;
$retVal->status = new stdClass;
//todo $retVal->status->errors = $moveErrors; // RSR TODO ensure putting right thing in here
} else if($action === 'move_files') {
$directories = DupLiteSnapLibUtil::getArrayValue($params, 'directories', false, array());
$files = DupLiteSnapLibUtil::getArrayValue($params, 'files', false, array());
$excludedFiles = DupLiteSnapLibUtil::getArrayValue($params, 'excluded_files', false, array());
$destination = DupLiteSnapLibUtil::getArrayValue($params, 'destination');
DupLiteSnapLibLogger::log('before move');
$moveErrors = FileOpsMoveU::move($directories, $files, $excludedFiles, $destination);
DupLiteSnapLibLogger::log('after move');
$retVal->pass = true;
$retVal->status = new stdClass();
$retVal->status->errors = $moveErrors; // RSR TODO ensure putting right thing in here
}
else {
throw new Exception('Unknown command.');
}
session_write_close();
} catch (Exception $ex) {
$error_message = "Error Encountered:" . $ex->getMessage() . '<br/>' . $ex->getTraceAsString();
DupLiteSnapLibLogger::log($error_message);
$retVal->pass = false;
$retVal->error = $error_message;
}
DupLiteSnapLibLogger::logObject("before json encode retval", $retVal);
$jsonRetVal = json_encode($retVal);
DupLiteSnapLibLogger::logObject("json encoded retval", $jsonRetVal);
echo $jsonRetVal;
}
}
function generateCallTrace()
{
$e = new Exception();
$trace = explode("\n", $e->getTraceAsString());
// reverse array to make steps line up chronologically
$trace = array_reverse($trace);
array_shift($trace); // remove {main}
array_pop($trace); // remove call to this method
$length = count($trace);
$result = array();
for ($i = 0; $i < $length; $i++) {
$result[] = ($i + 1) . ')' . substr($trace[$i], strpos($trace[$i], ' ')); // replace '#someNum' with '$i)', set the right ordering
}
return "\t" . implode("\n\t", $result);
}
function terminate_missing_variables($errno, $errstr, $errfile, $errline)
{
// echo "<br/>ERROR: $errstr $errfile $errline<br/>";
// if (($errno == E_NOTICE) and ( strstr($errstr, "Undefined variable"))) die("$errstr in $errfile line $errline");
DupLiteSnapLibLogger::log("ERROR $errno, $errstr, {$errfile}:{$errline}");
DupLiteSnapLibLogger::log(generateCallTrace());
// DaTesterLogging::clearLog();
// exit(1);
//return false; // Let the PHP error handler handle all the rest
}
$fileOps = new FileOps();
$fileOps->processRequest(); lib/dup_archive/classes/util/class.duparchive.util.scan.php 0000644 00000004411 15133606540 0020066 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
require_once(dirname(__FILE__).'/class.duparchive.u.json.php');
if(!class_exists('DupArchiveScanUtil')) {
/**
* Description of class
*
* @author Robert
*/
class DupArchiveScanUtil
{
public static function getScan($scanFilepath)
//put your code here private function get_scan()
{
DupArchiveUtil::tlog("Getting scen");
$scan_handle = fopen($scanFilepath, 'r');
if ($scan_handle === false) {
throw new Exception("Can't open {$scanFilepath}");
}
$scan_file = fread($scan_handle, filesize($scanFilepath));
if ($scan_file === false) {
throw new Exception("Can't read from {$scanFilepath}");
}
// $scan = json_decode($scan_file);
$scan = DupArchiveJsonU::decode($scan_file);
if ($scan == null) {
throw new Exception("Error decoding scan file");
}
fclose($scan_handle);
return $scan;
}
public static function createScanObject($sourceDirectory)
{
$scan = new stdClass();
$scan->Dirs = DupArchiveUtil::expandDirectories($sourceDirectory, true);
$scan->Files = DupArchiveUtil::expandFiles($sourceDirectory, true);
return $scan;
}
public static function createScan($scanFilepath, $sourceDirectory)
{
DupArchiveUtil::tlog("Creating scan");
// $scan = new stdClass();
//
// $scan->Dirs = DupArchiveUtil::expandDirectories($sourceDirectory, true);
// $scan->Files = DupArchiveUtil::expandFiles($sourceDirectory, true);
////$scan->Files = array();
$scan = self::createScanObject($sourceDirectory);
$scan_handle = fopen($scanFilepath, 'w');
if ($scan_handle === false) {
echo "Couldn't create scan file";
die();
}
$jsn = DupArchiveJsonU::customEncode($scan);
fwrite($scan_handle, $jsn);
// DupArchiveUtil::tlogObject('jsn', $jsn);
return $scan;
}
}
} lib/dup_archive/classes/util/index.php 0000644 00000000017 15133606540 0014036 0 ustar 00 <?php
//silent lib/dup_archive/classes/util/class.duparchive.u.json.php 0000644 00000012522 15133606540 0017404 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
if(!class_exists('DupArchiveJsonU')) {
class DupArchiveJsonU
{
protected static $_messages = array(
JSON_ERROR_NONE => 'No error has occurred',
JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded',
JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
JSON_ERROR_SYNTAX => 'Syntax error',
JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded. To resolve see https://snapcreek.com/duplicator/docs/faqs-tech/#faq-package-170-q'
);
public static function customEncode($value, $iteration = 1)
{
$encoded = DupLiteSnapJsonU::wp_json_encode($value);
switch (json_last_error()) {
case JSON_ERROR_NONE:
return $encoded;
case JSON_ERROR_DEPTH:
throw new RuntimeException('Maximum stack depth exceeded'); // or trigger_error() or throw new Exception()
case JSON_ERROR_STATE_MISMATCH:
throw new RuntimeException('Underflow or the modes mismatch'); // or trigger_error() or throw new Exception()
case JSON_ERROR_CTRL_CHAR:
throw new RuntimeException('Unexpected control character found');
case JSON_ERROR_SYNTAX:
throw new RuntimeException('Syntax error, malformed JSON'); // or trigger_error() or throw new Exception()
case JSON_ERROR_UTF8:
if ($iteration == 1) {
$clean = self::makeUTF8($value);
return self::customEncode($clean, $iteration + 1);
} else {
throw new RuntimeException('UTF-8 error loop');
}
default:
throw new RuntimeException('Unknown error'); // or trigger_error() or throw new Exception()
}
}
public static function encode($value, $options = 0)
{
$result = DupLiteSnapJsonU::wp_json_encode($value, $options);
if ($result !== FALSE) {
return $result;
}
if (function_exists('json_last_error')) {
$message = self::$_messages[json_last_error()];
} else {
$message = 'One or more filenames isn\'t compatible with JSON encoding';
}
throw new RuntimeException($message);
}
public static function decode($json, $assoc = false)
{
$result = json_decode($json, $assoc);
if ($result) {
return $result;
}
throw new RuntimeException(self::$_messages[json_last_error()]);
}
/** ========================================================
* PRIVATE METHODS
* ===================================================== */
private static function makeUTF8($mixed)
{
if (is_array($mixed)) {
foreach ($mixed as $key => $value) {
$mixed[$key] = self::makeUTF8($value);
}
} else if (is_string($mixed)) {
return utf8_encode($mixed);
}
return $mixed;
}
private static function escapeString($str)
{
return addcslashes($str, "\v\t\n\r\f\"\\/");
}
private static function oldCustomEncode($in)
{
$out = "";
if (is_object($in)) {
//$class_vars = get_object_vars(($in));
//$arr = array();
//foreach ($class_vars as $key => $val)
//{
$arr[$key] = "\"".self::escapeString($key)."\":\"{$val}\"";
//}
//$val = implode(',', $arr);
//$out .= "{{$val}}";
$in = get_object_vars($in);
}
//else
if (is_array($in)) {
$obj = false;
$arr = array();
foreach ($in AS $key => $val) {
if (!is_numeric($key)) {
$obj = true;
}
$arr[$key] = self::oldCustomEncode($val);
}
if ($obj) {
foreach ($arr AS $key => $val) {
$arr[$key] = "\"".self::escapeString($key)."\":{$val}";
}
$val = implode(',', $arr);
$out .= "{{$val}}";
} else {
$val = implode(',', $arr);
$out .= "[{$val}]";
}
} elseif (is_bool($in)) {
$out .= $in ? 'true' : 'false';
} elseif (is_null($in)) {
$out .= 'null';
} elseif (is_string($in)) {
$out .= "\"".self::escapeString($in)."\"";
} else {
$out .= $in;
}
return "{$out}";
}
private static function oldMakeUTF8($val)
{
if (is_array($val)) {
foreach ($val as $k => $v) {
$val[$k] = self::oldMakeUTF8($v);
}
} else if (is_object($val)) {
foreach ($val as $k => $v) {
$val->$k = self::oldMakeUTF8($v);
}
} else {
if (mb_detect_encoding($val, 'UTF-8', true)) {
return $val;
} else {
return utf8_encode($val);
}
}
return $val;
}
}
} lib/dup_archive/classes/util/class.duparchive.util.php 0000644 00000012566 15133606540 0017155 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of Util
*
* @author Bob
*/
require_once(dirname(__FILE__).'/../class.duparchive.constants.php');
require_once(DupArchiveConstants::$LibRoot.'/snaplib/class.snaplib.u.util.php');
if(!class_exists('DupArchiveUtil')) {
class DupArchiveUtil
{
public static $TRACE_ON = false; //rodo rework this
public static $logger = null;
public static $profilingFunction = null;
public static function boolToString($b)
{
return ($b ? 'true' : 'false');
}
public static function expandFiles($base_dir, $recurse)
{
$files = array();
foreach (scandir($base_dir) as $file) {
if (($file == '.') || ($file == '..')) {
continue;
}
$file = "{$base_dir}/{$file}";
if (is_file($file)) {
$files [] = $file;
} else if (is_dir($file) && $recurse) {
$files = array_merge($files, self::expandFiles($file, $recurse));
}
}
return $files;
}
public static function expandDirectories($base_dir, $recurse)
{
$directories = array();
foreach (scandir($base_dir) as $candidate) {
if (($candidate == '.') || ($candidate == '..')) {
continue;
}
$candidate = "{$base_dir}/{$candidate}";
// if (is_file($file)) {
// $directories [] = $file;
if (is_dir($candidate)) {
$directories[] = $candidate;
if ($recurse) {
$directories = array_merge($directories, self::expandDirectories($candidate, $recurse));
}
}
}
return $directories;
}
public static function getRelativePath($from, $to, $newBasePath = null)
{
// some compatibility fixes for Windows paths
$from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
$to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
$from = str_replace('\\', '/', $from);
$to = str_replace('\\', '/', $to);
$from = explode('/', $from);
$to = explode('/', $to);
$relPath = $to;
foreach ($from as $depth => $dir) {
// find first non-matching dir
if ($dir === $to[$depth]) {
// ignore this directory
array_shift($relPath);
} else {
// get number of remaining dirs to $from
$remaining = count($from) - $depth;
if ($remaining > 1) {
// add traversals up to first matching dir
$padLength = (count($relPath) + $remaining - 1) * -1;
$relPath = array_pad($relPath, $padLength, '..');
break;
} else {
//$relPath[0] = './' . $relPath[0];
}
}
}
$r = implode('/', $relPath);
if($newBasePath != null) {
$r = $newBasePath . $r;
}
return $r;
}
public static function log($s, $flush = false, $callingFunctionName = null)
{
if(self::$logger != null)
{
if($callingFunctionName === null)
{
$callingFunctionName = DupLiteSnapLibUtil::getCallingFunctionName();
}
self::$logger->log($s, $flush, $callingFunctionName);
}
else
{
// throw new Exception('Logging object not initialized');
}
}
// rodo fold into log
public static function tlog($s, $flush = false, $callingFunctionName = null)
{
if (self::$TRACE_ON) {
if($callingFunctionName === null)
{
$callingFunctionName = DupLiteSnapLibUtil::getCallingFunctionName();
}
self::log("####{$s}", $flush, $callingFunctionName);
}
}
public static function profileEvent($s, $start)
{
if(self::$profilingFunction != null)
{
call_user_func(self::$profilingFunction, $s, $start);
}
}
// rodo fold into logObject
public static function tlogObject($s, $o, $flush = false, $callingFunctionName = null)
{
if(is_object($o))
{
$o = get_object_vars($o);
}
$ostring = print_r($o, true);
if($callingFunctionName === null)
{
$callingFunctionName = DupLiteSnapLibUtil::getCallingFunctionName();
}
self::tlog($s, $flush, $callingFunctionName);
self::tlog($ostring, $flush, $callingFunctionName);
}
public static function logObject($s, $o, $flush = false, $callingFunctionName = null)
{
$ostring = print_r($o, true);
if($callingFunctionName === null)
{
$callingFunctionName = DupLiteSnapLibUtil::getCallingFunctionName();
}
self::log($s, $flush, $callingFunctionName);
self::log($ostring, $flush, $callingFunctionName);
}
}
} lib/dup_archive/classes/class.duparchive.engine.php 0000644 00000071654 15133606540 0016473 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
require_once(dirname(__FILE__) . '/class.duparchive.constants.php');
require_once(DupArchiveConstants::$LibRoot . '/snaplib/class.snaplib.u.io.php');
require_once(DupArchiveConstants::$LibRoot . '/snaplib/class.snaplib.u.stream.php');
require_once(dirname(__FILE__) . '/headers/class.duparchive.header.php');
require_once(dirname(__FILE__) . '/states/class.duparchive.state.create.php');
require_once(dirname(__FILE__) . '/states/class.duparchive.state.simplecreate.php');
require_once(dirname(__FILE__) . '/states/class.duparchive.state.simpleexpand.php');
require_once(dirname(__FILE__) . '/states/class.duparchive.state.expand.php');
require_once(dirname(__FILE__) . '/processors/class.duparchive.processor.file.php');
require_once(dirname(__FILE__) . '/processors/class.duparchive.processor.directory.php');
require_once(dirname(__FILE__) . '/class.duparchive.processing.failure.php');
require_once(dirname(__FILE__) . '/util/class.duparchive.util.php');
require_once(dirname(__FILE__) . '/util/class.duparchive.util.scan.php');
if(!class_exists('DupArchiveInfo')) {
class DupArchiveInfo
{
public $archiveHeader;
public $fileHeaders;
public $directoryHeaders;
public function __construct()
{
$this->fileHeaders = array();
$this->directoryHeaders = array();
}
}
}
if(!class_exists('DupArchiveItemAlias')) {
class DupArchiveItemAlias
{
public $oldName;
public $newName;
}
}
if(!class_exists('DupArchiveItemHeaderType')) {
class DupArchiveItemHeaderType
{
const None = 0;
const File = 1;
const Directory = 2;
const Glob = 3;
}
}
if(!class_exists('DupArchiveEngine')) {
class DupArchiveEngine
{
public static $archive;
public static function init($logger, $profilingFunction = null, $archive = null)
{
DupArchiveUtil::$logger = $logger;
DupArchiveUtil::$profilingFunction = $profilingFunction;
self::$archive = $archive;
}
public static function getNextHeaderType($archiveHandle)
{
$retVal = DupArchiveItemHeaderType::None;
$marker = fgets($archiveHandle, 4);
if (feof($archiveHandle) === false) {
switch ($marker) {
case '<D>':
$retVal = DupArchiveItemHeaderType::Directory;
break;
case '<F>':
$retVal = DupArchiveItemHeaderType::File;
break;
case '<G>':
$retVal = DupArchiveItemHeaderType::Glob;
break;
default:
throw new Exception("Invalid header marker {$marker}. Location:" . ftell($archiveHandle));
}
}
return $retVal;
}
public static function getArchiveInfo($filepath)
{
$archiveInfo = new DupArchiveInfo();
DupArchiveUtil::log("archive size=" . filesize($filepath));
$archiveHandle = DupLiteSnapLibIOU::fopen($filepath, 'rb');
$moreFiles = true;
$archiveInfo->archiveHeader = DupArchiveHeader::readFromArchive($archiveHandle);
$moreToRead = true;
while ($moreToRead) {
$headerType = self::getNextHeaderType($archiveHandle);
// DupArchiveUtil::log("next header type=$headerType: " . ftell($archiveHandle));
switch ($headerType) {
case DupArchiveItemHeaderType::File:
$fileHeader = DupArchiveFileHeader::readFromArchive($archiveHandle, true, true);
$archiveInfo->fileHeaders[] = $fileHeader;
DupArchiveUtil::log("file" . $fileHeader->relativePath);
break;
case DupArchiveItemHeaderType::Directory:
$directoryHeader = DupArchiveDirectoryHeader::readFromArchive($archiveHandle, true);
$archiveInfo->directoryHeaders[] = $directoryHeader;
break;
case DupArchiveItemHeaderType::None:
$moreToRead = false;
}
}
return $archiveInfo;
}
// can't span requests since create state can't store list of files
public static function addDirectoryToArchiveST($archiveFilepath, $directory, $basepath, $includeFiles = false, $newBasepath = null, $globSize = DupArchiveCreateState::DEFAULT_GLOB_SIZE)
{
if ($includeFiles) {
$scan = DupArchiveScanUtil::createScanObject($directory);
} else {
$scan->Files = array();
$scan->Dirs = array();
}
$createState = new DupArchiveSimpleCreateState();
$createState->archiveOffset = filesize($archiveFilepath);
$createState->archivePath = $archiveFilepath;
$createState->basePath = $basepath;
$createState->timerEnabled = false;
$createState->globSize = $globSize;
$createState->newBasePath = $newBasepath;
self::addItemsToArchive($createState, $scan);
$retVal = new stdClass();
$retVal->numDirsAdded = $createState->currentDirectoryIndex;
$retVal->numFilesAdded = $createState->currentFileIndex;
if($createState->skippedFileCount > 0) {
throw new Exception("One or more files were were not able to be added when adding {$directory} to {$archiveFilepath}");
}
else if($createState->skippedDirectoryCount > 0) {
throw new Exception("One or more directories were not able to be added when adding {$directory} to {$archiveFilepath}");
}
return $retVal;
}
public static function addRelativeFileToArchiveST($archiveFilepath, $filepath, $relativePath, $globSize = DupArchiveCreateState::DEFAULT_GLOB_SIZE)
{
$createState = new DupArchiveSimpleCreateState();
$createState->archiveOffset = filesize($archiveFilepath);
$createState->archivePath = $archiveFilepath;
$createState->basePath = null;
$createState->timerEnabled = false;
$createState->globSize = $globSize;
$scan = new stdClass();
$scan->Files = array();
$scan->Dirs = array();
$scan->Files[] = $filepath;
if ($relativePath != null) {
$scan->FileAliases = array();
$scan->FileAliases[$filepath] = $relativePath;
}
self::addItemsToArchive($createState, $scan);
}
public static function addFileToArchiveUsingBaseDirST($archiveFilepath, $basePath, $filepath, $globSize = DupArchiveCreateState::DEFAULT_GLOB_SIZE)
{
$createState = new DupArchiveSimpleCreateState();
$createState->archiveOffset = filesize($archiveFilepath);
$createState->archivePath = $archiveFilepath;
$createState->basePath = $basePath;
$createState->timerEnabled = false;
$createState->globSize = $globSize;
$scan = new stdClass();
$scan->Files = array();
$scan->Dirs = array();
$scan->Files[] = $filepath;
self::addItemsToArchive($createState, $scan);
}
public static function createArchive($archivePath, $isCompressed)
{
$archiveHandle = DupLiteSnapLibIOU::fopen($archivePath, 'w+b');
/* @var $archiveHeader DupArchiveHeader */
$archiveHeader = DupArchiveHeader::create($isCompressed);
$archiveHeader->writeToArchive($archiveHandle);
// Intentionally do not write build state since if something goes wrong we went it to start over on the archive
DupLiteSnapLibIOU::fclose($archiveHandle);
}
public static function addItemsToArchive($createState, $scanFSInfo)
{
if ($createState->globSize == -1) {
$createState->globSize = DupArchiveCreateState::DEFAULT_GLOB_SIZE;
}
/* @var $createState DupArchiveCreateState */
DupArchiveUtil::tlogObject("addItemsToArchive start", $createState);
$directoryCount = count($scanFSInfo->Dirs);
$fileCount = count($scanFSInfo->Files);
$createState->startTimer();
/* @var $createState DupArchiveCreateState */
$basepathLength = strlen($createState->basePath);
$archiveHandle = DupLiteSnapLibIOU::fopen($createState->archivePath, 'r+b');
DupArchiveUtil::tlog("Archive size=", filesize($createState->archivePath));
DupArchiveUtil::tlog("Archive location is now " . DupLiteSnapLibIOU::ftell($archiveHandle));
$archiveHeader = DupArchiveHeader::readFromArchive($archiveHandle);
$createState->isCompressed = $archiveHeader->isCompressed;
if ($createState->archiveOffset == filesize($createState->archivePath)) {
DupArchiveUtil::tlog("Seeking to end of archive location because of offset {$createState->archiveOffset} for file size " . filesize($createState->archivePath));
DupLiteSnapLibIOU::fseek($archiveHandle, 0, SEEK_END);
} else {
DupArchiveUtil::tlog("Seeking archive offset {$createState->archiveOffset} for file size " . filesize($createState->archivePath));
DupLiteSnapLibIOU::fseek($archiveHandle, $createState->archiveOffset);
}
while (($createState->currentDirectoryIndex < $directoryCount) && (!$createState->timedOut())) {
if ($createState->throttleDelayInUs !== 0) {
usleep($createState->throttleDelayInUs);
}
$directory = $scanFSInfo->Dirs[$createState->currentDirectoryIndex];
try {
$relativeDirectoryPath = null;
if (isset($scanFSInfo->DirectoryAliases) && array_key_exists($directory, $scanFSInfo->DirectoryAliases)) {
$relativeDirectoryPath = $scanFSInfo->DirectoryAliases[$directory];
} else {
if (null === self::$archive) {
$relativeDirectoryPath = substr($directory, $basepathLength);
$relativeDirectoryPath = ltrim($relativeDirectoryPath, '/');
if ($createState->newBasePath !== null) {
$relativeDirectoryPath = $createState->newBasePath . $relativeDirectoryPath;
}
} else {
$relativeDirectoryPath = self::$archive->getLocalDirPath($directory, $createState->newBasePath);
}
}
if($relativeDirectoryPath !== '') {
DupArchiveDirectoryProcessor::writeDirectoryToArchive($createState, $archiveHandle, $directory, $relativeDirectoryPath);
} else {
$createState->skippedDirectoryCount++;
$createState->currentDirectoryIndex++;
}
} catch (Exception $ex) {
DupArchiveUtil::log("Failed to add {$directory} to archive. Error: " . $ex->getMessage(), true);
$createState->addFailure(DupArchiveFailureTypes::Directory, $directory, $ex->getMessage(), false);
$createState->currentDirectoryIndex++;
$createState->skippedDirectoryCount++;
$createState->save();
}
}
$createState->archiveOffset = DupLiteSnapLibIOU::ftell($archiveHandle);
$workTimestamp = time();
while (($createState->currentFileIndex < $fileCount) && (!$createState->timedOut())) {
$filepath = $scanFSInfo->Files[$createState->currentFileIndex];
try {
$relativeFilePath = null;
if (isset($scanFSInfo->FileAliases) && array_key_exists($filepath, $scanFSInfo->FileAliases)) {
$relativeFilePath = $scanFSInfo->FileAliases[$filepath];
} else {
if (null === self::$archive) {
$relativeFilePath = substr($filepath, $basepathLength);
$relativeFilePath = ltrim($relativeFilePath, '/');
if ($createState->newBasePath !== null) {
$relativeFilePath = $createState->newBasePath . $relativeFilePath;
}
} else {
$relativeFilePath = self::$archive->getLocalFilePath($filepath, $createState->newBasePath);
}
}
// Uncomment when testing error handling
// if((strpos($relativeFilePath, 'dup-installer') !== false) || (strpos($relativeFilePath, 'lib') !== false)) {
// Dup_Log::Trace("Was going to do intentional error to {$relativeFilePath} but skipping");
// } else {
// throw new Exception("#### intentional file error when writing " . $relativeFilePath);
// }
// }
DupArchiveFileProcessor::writeFilePortionToArchive($createState, $archiveHandle, $filepath, $relativeFilePath);
if(($createState->isRobust) && (time() - $workTimestamp >= 1)){
DupArchiveUtil::log("Robust mode create state save");
// When in robustness mode save the state every second
$workTimestamp = time();
$createState->working = ($createState->currentDirectoryIndex < $directoryCount) || ($createState->currentFileIndex < $fileCount);
$createState->save();
}
} catch (Exception $ex) {
DupArchiveUtil::log("Failed to add {$filepath} to archive. Error: " . $ex->getMessage() . $ex->getTraceAsString(), true);
$createState->currentFileIndex++;
$createState->skippedFileCount++;
$createState->addFailure(DupArchiveFailureTypes::File, $filepath, $ex->getMessage(), ($ex->getCode() === DupArchiveExceptionCodes::Fatal));
$createState->save();
}
}
$createState->working = ($createState->currentDirectoryIndex < $directoryCount) || ($createState->currentFileIndex < $fileCount);
$createState->save();
DupLiteSnapLibIOU::fclose($archiveHandle);
if (!$createState->working) {
DupArchiveUtil::log("compress done");
} else {
DupArchiveUtil::tlog("compress not done so continuing later");
}
}
public static function expandDirectory($archivePath, $relativePath, $destPath)
{
self::expandItems($archivePath, $relativePath, $destPath);
}
public static function expandArchive($expandState)
{
/* @var $expandState DupArchiveExpandState */
$expandState->startTimer();
$archiveHandle = DupLiteSnapLibIOU::fopen($expandState->archivePath, 'rb');
DupLiteSnapLibIOU::fseek($archiveHandle, $expandState->archiveOffset);
if ($expandState->archiveOffset == 0) {
DupArchiveUtil::log("#### seeking to start of archive");
$expandState->archiveHeader = DupArchiveHeader::readFromArchive($archiveHandle);
$expandState->isCompressed = $expandState->archiveHeader->isCompressed;
$expandState->archiveOffset = DupLiteSnapLibIOU::ftell($archiveHandle);
$expandState->save();
} else {
DupArchiveUtil::log("#### seeking archive offset {$expandState->archiveOffset}");
}
if ((!$expandState->validateOnly) || ($expandState->validationType == DupArchiveValidationTypes::Full)) {
$moreItems = self::expandItems($expandState, $archiveHandle);
} else {
// profile ok
$moreItems = self::standardValidateItems($expandState, $archiveHandle);
// end profile ok
}
$expandState->working = $moreItems;
$expandState->save();
DupLiteSnapLibIOU::fclose($archiveHandle, false);
if (!$expandState->working) {
DupArchiveUtil::log("expand done");
DupArchiveUtil::logObject('expandstate', $expandState);
if (($expandState->expectedFileCount != -1) && ($expandState->expectedFileCount != $expandState->fileWriteCount)) {
$expandState->addFailure(DupArchiveFailureTypes::File, 'Archive', "Number of files expected ({$expandState->expectedFileCount}) doesn't equal number written ({$expandState->fileWriteCount}).");
}
if (($expandState->expectedDirectoryCount != -1) && ($expandState->expectedDirectoryCount != $expandState->directoryWriteCount)) {
$expandState->addFailure(DupArchiveFailureTypes::Directory, 'Archive', "Number of directories expected ({$expandState->expectedDirectoryCount}) doesn't equal number written ({$expandState->directoryWriteCount}).");
}
} else {
DupArchiveUtil::tlogObject("expand not done so continuing later", $expandState);
}
}
private static function skipFileInArchive($archiveHandle, $fileHeader)
{
if ($fileHeader->fileSize > 0) {
$dataSize = 0;
do {
$globHeader = DupArchiveGlobHeader::readFromArchive($archiveHandle, true);
$dataSize += $globHeader->originalSize;
$moreGlobs = ($dataSize < $fileHeader->fileSize);
} while ($moreGlobs);
}
}
// Assumes we are on one header and just need to get to the next
private static function skipToNextHeader($archiveHandle)
{
$headerType = self::getNextHeaderType($archiveHandle);
switch ($headerType) {
case DupArchiveItemHeaderType::File:
$fileHeader = DupArchiveFileHeader::readFromArchive($archiveHandle, false, true);
self::skipFileInArchive($archiveHandle, $fileHeader);
break;
case DupArchiveItemHeaderType::Directory:
$directoryHeader = DupArchiveDirectoryHeader::readFromArchive($archiveHandle, true);
break;
case DupArchiveItemHeaderType::None:
$moreToRead = false;
}
}
// Single-threaded file expansion
public static function expandFiles($archiveFilePath, $relativeFilePaths, $destPath)
{
// Not setting timeout timestamp so it will never timeout
DupArchiveUtil::tlog("opening archive {$archiveFilePath}");
$archiveHandle = DupLiteSnapLibIOU::fopen($archiveFilePath, 'r');
/* @var $expandState DupArchiveSimpleExpandState */
$expandState = new DupArchiveSimpleExpandState();
$expandState->archiveHeader = DupArchiveHeader::readFromArchive($archiveHandle);
$expandState->isCompressed = $expandState->archiveHeader->isCompressed;
$expandState->archiveOffset = DupLiteSnapLibIOU::ftell($archiveHandle);
$expandState->includedFiles = $relativeFilePaths;
$expandState->filteredDirectories = array('*');
$expandState->filteredFiles = array('*');
// $expandState->basePath = $destPath . '/tempExtract'; // RSR remove once extract works
$expandState->basePath = $destPath; // RSR remove once extract works
// TODO: Filter out all directories/files except those in the list
self::expandItems($expandState, $archiveHandle);
}
private static function expandItems(&$expandState, $archiveHandle)
{
/* @var $expandState DupArchiveExpandState */
$moreToRead = true;
$workTimestamp = time();
while ($moreToRead && (!$expandState->timedOut())) {
if ($expandState->throttleDelayInUs !== 0) {
usleep($expandState->throttleDelayInUs);
}
if ($expandState->currentFileHeader != null) {
DupArchiveUtil::tlog("Writing file {$expandState->currentFileHeader->relativePath}");
if (self::filePassesFilters($expandState->filteredDirectories, $expandState->filteredFiles, $expandState->includedFiles, $expandState->currentFileHeader->relativePath)) {
try {
$fileCompleted = DupArchiveFileProcessor::writeToFile($expandState, $archiveHandle);
} catch (Exception $ex) {
DupArchiveUtil::log("Failed to write to {$expandState->currentFileHeader->relativePath}. Error: " . $ex->getMessage(), true);
// Reset things - skip over this file within the archive.
DupLiteSnapLibIOU::fseek($archiveHandle, $expandState->lastHeaderOffset);
self::skipToNextHeader($archiveHandle, $expandState->currentFileHeader);
$expandState->archiveOffset = ftell($archiveHandle);
$expandState->addFailure(DupArchiveFailureTypes::File, $expandState->currentFileHeader->relativePath, $ex->getMessage(), false);
$expandState->resetForFile();
$expandState->lastHeaderOffset = -1;
$expandState->save();
}
} else {
DupArchiveUtil::log("skipping {$expandState->currentFileHeader->relativePath} because its part of the exclusion filter");
self::skipFileInArchive($archiveHandle, $expandState->currentFileHeader);
$expandState->resetForFile();
}
} else {
// Header is null so read in the next one
$expandState->lastHeaderOffset = @ftell($archiveHandle);
// profile ok
$headerType = self::getNextHeaderType($archiveHandle);
// end profile ok
DupArchiveUtil::tlog('header type ' . $headerType);
switch ($headerType) {
case DupArchiveItemHeaderType::File:
DupArchiveUtil::tlog('File header');
$expandState->currentFileHeader = DupArchiveFileHeader::readFromArchive($archiveHandle, false, true);
$expandState->archiveOffset = @ftell($archiveHandle);
DupArchiveUtil::tlog('Just read file header from archive');
break;
case DupArchiveItemHeaderType::Directory:
DupArchiveUtil::tlog('Directory Header');
$directoryHeader = DupArchiveDirectoryHeader::readFromArchive($archiveHandle, true);
if (self::passesDirectoryExclusion($expandState->filteredDirectories, $directoryHeader->relativePath)) {
$createdDirectory = true;
if (!$expandState->validateOnly) {
$directory = $expandState->basePath . '/' . $directoryHeader->relativePath;
$mode = 'u+rwx';
if ($expandState->directoryModeOverride != -1) {
$mode = $expandState->directoryModeOverride;
}
$createdDirectory = DupLiteSnapLibIOU::dirWriteCheckOrMkdir($directory, $mode, true);
}
if ($createdDirectory) {
$expandState->directoryWriteCount++;
} else {
$expandState->addFailure(DupArchiveFailureTypes::Directory, $directory, "Unable to create directory $directory", false);
}
}
$expandState->archiveOffset = ftell($archiveHandle);
DupArchiveUtil::tlog('Just read directory header ' . $directoryHeader->relativePath . ' from archive');
break;
case DupArchiveItemHeaderType::None:
$moreToRead = false;
}
}
if(($expandState->isRobust) && (time() - $workTimestamp >= 1)){
DupArchiveUtil::log("Robust mode extract state save for standard validate");
// When in robustness mode save the state every second
$workTimestamp = time();
$expandState->save();
}
}
$expandState->save();
return $moreToRead;
}
private static function passesDirectoryExclusion($directoryFilters, $candidate)
{
foreach ($directoryFilters as $directoryFilter) {
if($directoryFilter === '*') {
return false;
}
if (substr($candidate, 0, strlen($directoryFilter)) == $directoryFilter) {
return false;
}
}
return true;
}
private static function filePassesFilters($excludedDirectories, $excludedFiles, $includedFiles, $candidate)
{
$retVal = true;
// Included files trumps all exclusion filters
foreach($includedFiles as $includedFile) {
if($includedFile === $candidate) {
return true;
}
}
if (self::passesDirectoryExclusion($excludedDirectories, $candidate)) {
foreach ($excludedFiles as $fileFilter) {
if($fileFilter === '*') {
return false;
}
if ($fileFilter === $candidate) {
$retVal = false;
break;
}
}
} else {
$retVal = false;;
}
return $retVal;
}
private static function standardValidateItems(&$expandState, $archiveHandle)
{
$moreToRead = true;
// profile ok
$to = $expandState->timedOut();
// end profile ok
$workTimestamp = time();
while ($moreToRead && (!$to)) {
if ($expandState->throttleDelayInUs !== 0) {
usleep($expandState->throttleDelayInUs);
}
if ($expandState->currentFileHeader != null) {
try {
$fileCompleted = DupArchiveFileProcessor::standardValidateFileEntry($expandState, $archiveHandle);
if ($fileCompleted) {
$expandState->resetForFile();
}
// Expand state taken care of within the write to file to ensure consistency
} catch (Exception $ex) {
DupArchiveUtil::log("Failed validate file in archive. Error: " . $ex->getMessage(), true);
DupArchiveUtil::logObject("expand state", $expandState, true);
// $expandState->currentFileIndex++;
// RSR TODO: Need way to skip past that file
$expandState->addFailure(DupArchiveFailureTypes::File, $expandState->currentFileHeader->relativePath, $ex->getMessage());
$expandState->save();
$moreToRead = false;
}
} else {
// profile ok
$headerType = self::getNextHeaderType($archiveHandle);
switch ($headerType) {
case DupArchiveItemHeaderType::File:
// profile ok
$expandState->currentFileHeader = DupArchiveFileHeader::readFromArchive($archiveHandle, false, true);
$expandState->archiveOffset = ftell($archiveHandle);
// end profile ok
break;
case DupArchiveItemHeaderType::Directory:
// profile ok
$directoryHeader = DupArchiveDirectoryHeader::readFromArchive($archiveHandle, true);
$expandState->directoryWriteCount++;
$expandState->archiveOffset = ftell($archiveHandle);
break;
case DupArchiveItemHeaderType::None:
$moreToRead = false;
}
}
if(($expandState->isRobust) && (time() - $workTimestamp >= 1)){
DupArchiveUtil::log("Robust mdoe extract state save for standard validate");
// When in robustness mode save the state every second
$workTimestamp = time();
$expandState->save();
}
// profile ok
$to = $expandState->timedOut();
}
// profile ok
$expandState->save();
return $moreToRead;
}
}
}
lib/dup_archive/classes/headers/index.php 0000644 00000000017 15133606540 0014474 0 ustar 00 <?php
//silent lib/dup_archive/classes/headers/class.duparchive.header.file.php 0000644 00000011643 15133606540 0020777 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
require_once(dirname(__FILE__).'/../util/class.duparchive.util.php');
require_once(dirname(__FILE__).'/class.duparchive.header.u.php');
if(!class_exists('DupArchiveFileHeader')) {
// Format
class DupArchiveFileHeader// extends HeaderBase
{
public $fileSize;
public $mtime;
public $permissions;
public $hash;
public $relativePathLength;
public $relativePath;
const MaxHeaderSize = 8192;
const MaxPathLength = 4100;
// const MaxStandardHeaderFieldLength = 128;
private function __construct()
{
// Prevent direct instantiation
}
static function createFromFile($filepath, $relativeFilePath)
{
$instance = new DupArchiveFileHeader();
// RSR TODO Populate fields based on file already on system
// profile ok
$instance->fileSize = DupLiteSnapLibIOU::filesize($filepath);
// end profile ok
// profile ok
$instance->permissions = substr(sprintf('%o', fileperms($filepath)), -4);
// end profile ok
// profile ok
$instance->mtime = DupLiteSnapLibIOU::filemtime($filepath);
// end profile ok
if($instance->fileSize > DupArchiveConstants::$MaxFilesizeForHashing) {
$instance->hash = false;
}
else {
$instance->hash = hash_file('crc32b', $filepath);
}
$instance->relativePath = $relativeFilePath;
$instance->relativePathLength = strlen($instance->relativePath);
// DupArchiveUtil::tlog("paths=$filepath, {$instance->relativePath}");
if ($instance->hash === false) {
// RSR TODO: Best thing to do here?
$instance->hash = "00000000000000000000000000000000";
}
return $instance;
}
/*
* delta = 84-22 = 62 bytes per file -> 20000 files -> 1.2MB larger
* <F><FS>x</FS><MT>x</<MT><FP>x</FP><HA>x</HA><RFPL>x</RFPL><RFP>x</RFP></F>
# F#x#x#x#x#x#x!
*
*/
static function readFromArchive($archiveHandle, $skipContents, $skipMarker = false)
{
// RSR TODO Read header from archive handle and populate members
// TODO: return null if end of archive or throw exception if can read something but its not a file header
$instance = new DupArchiveFileHeader();
if (!$skipMarker) {
$marker = @fread($archiveHandle, 3);
if ($marker === false) {
if (feof($archiveHandle)) {
return false;
} else {
throw new Exception('Error reading file header');
}
}
if ($marker != '<F>') {
throw new Exception("Invalid file header marker found [{$marker}] : location ".ftell($archiveHandle));
}
}
$instance->fileSize = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'FS');
$instance->mtime = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'MT');
$instance->permissions = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'P');
$instance->hash = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'HA');
$instance->relativePathLength = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'RPL');
// Skip <RP>
fread($archiveHandle, 4);
$instance->relativePath = fread($archiveHandle, $instance->relativePathLength);
// Skip </RP>
// fread($archiveHandle, 5);
// Skip the </F>
// fread($archiveHandle, 4);
// Skip the </RP> and the </F>
fread($archiveHandle, 9);
if ($skipContents && ($instance->fileSize > 0)) {
$dataSize = 0;
$moreGlobs = true;
while ($moreGlobs) {
//echo 'read glob<br/>';
/* @var $globHeader DupArchiveGlobHeader */
$globHeader = DupArchiveGlobHeader::readFromArchive($archiveHandle, true);
$dataSize += $globHeader->originalSize;
$moreGlobs = ($dataSize < $instance->fileSize);
}
}
return $instance;
}
public function writeToArchive($archiveHandle)
{
$headerString = '<F><FS>'.$this->fileSize.'</FS><MT>'.$this->mtime.'</MT><P>'.$this->permissions.'</P><HA>'.$this->hash.'</HA><RPL>'.$this->relativePathLength.'</RPL><RP>'.$this->relativePath.'</RP></F>';
//DupLiteSnapLibIOU::fwrite($archiveHandle, $headerString);
$bytes_written = @fwrite($archiveHandle, $headerString);
if ($bytes_written === false) {
throw new Exception('Error writing to file.');
} else {
return $bytes_written;
}
}
}
} lib/dup_archive/classes/headers/class.duparchive.header.glob.php 0000644 00000004117 15133606540 0021001 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
require_once(dirname(__FILE__).'/../util/class.duparchive.util.php');
require_once(dirname(__FILE__).'/class.duparchive.header.u.php');
if(!class_exists('DupArchiveGlobHeader')) {
// Format
// #C#{$originalSize}#{$storedSize}!
class DupArchiveGlobHeader //extends HeaderBase
{
// public $marker;
public $originalSize;
public $storedSize;
public $hash;
const MaxHeaderSize = 255;
public function __construct()
{
}
public static function readFromArchive($archiveHandle, $skipGlob)
{
$instance = new DupArchiveGlobHeader();
DupArchiveUtil::log('Reading glob starting at ' . ftell($archiveHandle));
$startElement = fread($archiveHandle, 3);
//if ($marker != '?G#') {
if ($startElement !== '<G>') {
throw new Exception("Invalid glob header marker found {$startElement}. location:" . ftell($archiveHandle));
}
$instance->originalSize = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'OS');
$instance->storedSize = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'SS');
$instance->hash = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'HA');
// Skip the </G>
fread($archiveHandle, 4);
if ($skipGlob) {
DupLiteSnapLibIOU::fseek($archiveHandle, $instance->storedSize, SEEK_CUR);
}
return $instance;
}
public function writeToArchive($archiveHandle)
{
// <G><OS>x</OS>x<SS>x</SS><HA>x</HA></G>
$headerString = '<G><OS>'.$this->originalSize.'</OS><SS>'.$this->storedSize.'</SS><HA>'.$this->hash.'</HA></G>';
//DupLiteSnapLibIOU::fwrite($archiveHandle, $headerString);
$bytes_written = @fwrite($archiveHandle, $headerString);
if ($bytes_written === false) {
throw new Exception('Error writing to file.');
} else {
return $bytes_written;
}
}
}
} lib/dup_archive/classes/headers/class.duparchive.header.php 0000644 00000004706 15133606540 0020063 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
require_once(dirname(__FILE__).'/../util/class.duparchive.util.php');
require_once(dirname(__FILE__).'/class.duparchive.header.u.php');
require_once(dirname(__FILE__).'/../../define.php');
if(!class_exists('DupArchiveHeader')) {
//require_once(dirname(__FILE__).'/class.HeaderBase.php');
// Format: #A#{version:5}#{isCompressed}!
class DupArchiveHeader// extends HeaderBase
{
public $version;
public $isCompressed;
// public $directoryCount;
// public $fileCount;
// Format Version History
// 1 = Initial alpha format
// 2 = Pseudo xml based format
//const LatestVersion = 2;
const MaxHeaderSize = 60;
private function __construct()
{
// Prevent instantiation
}
// public static function create($isCompressed, $directoryCount, $fileCount, $version = self::LatestVersion)
public static function create($isCompressed)
{
$instance = new DupArchiveHeader();
// $instance->directoryCount = $directoryCount;
// $instance->fileCount = $fileCount;
$instance->version = DUPARCHIVE_VERSION;
$instance->isCompressed = $isCompressed;
return $instance;
}
public static function readFromArchive($archiveHandle)
{
$instance = new DupArchiveHeader();
$startElement = fgets($archiveHandle, 4);
if ($startElement != '<A>') {
throw new Exception("Invalid archive header marker found {$startElement}");
}
$instance->version = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'V');
$instance->isCompressed = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'C') == 'true' ? true : false;
// Skip the </A>
fgets($archiveHandle, 5);
return $instance;
}
public function writeToArchive($archiveHandle)
{
$isCompressedString = DupArchiveUtil::boolToString($this->isCompressed);
//DupLiteSnapLibIOU::fwrite($archiveHandle, "<A><V>{$this->version}</V><C>{$isCompressedString}</C></A>");
DupLiteSnapLibIOU::fwrite($archiveHandle, '<A><V>'.$this->version.'</V><C>'.$isCompressedString.'</C></A>');
}
}
} lib/dup_archive/classes/headers/class.duparchive.header.directory.php 0000644 00000006400 15133606540 0022057 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
require_once(dirname(__FILE__).'/../util/class.duparchive.util.php');
require_once(dirname(__FILE__).'/class.duparchive.header.u.php');
if(!class_exists('DupArchiveDirectoryHeader')) {
// Format
class DupArchiveDirectoryHeader// extends HeaderBase
{
public $mtime;
public $permissions;
public $relativePathLength;
public $relativePath;
const MaxHeaderSize = 8192;
const MaxPathLength = 4100;
//const MaxStandardHeaderFieldLength = 128;
public function __construct()
{
// Prevent direct instantiation
}
// static function createFromDirectory($directoryPath, $relativePath)
// {
// $instance = new DupArchiveDirectoryHeader();
//
// $instance->permissions = substr(sprintf('%o', fileperms($directoryPath)), -4);
// $instance->mtime = DupLiteSnapLibIOU::filemtime($directoryPath);
// $instance->relativePath = $relativePath;
// $instance->relativePathLength = strlen($instance->relativePath);
//
// return $instance;
// }
static function readFromArchive($archiveHandle, $skipStartElement = false)
{
$instance = new DupArchiveDirectoryHeader();
if(!$skipStartElement)
{
// <A>
$startElement = fread($archiveHandle, 3);
if ($startElement === false) {
if (feof($archiveHandle)) {
return false;
} else {
throw new Exception('Error reading directory header');
}
}
if ($startElement != '<D>') {
throw new Exception("Invalid directory header marker found [{$startElement}] : location ".ftell($archiveHandle));
}
}
$instance->mtime = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'MT');
$instance->permissions = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'P');
$instance->relativePathLength = DupArchiveHeaderU::readStandardHeaderField($archiveHandle, 'RPL');
// Skip the <RP>
fread($archiveHandle, 4);
$instance->relativePath = fread($archiveHandle, $instance->relativePathLength);
// Skip the </RP>
// fread($archiveHandle, 5);
//
// // Skip the </D>
// fread($archiveHandle, 4);
// Skip the </RP> and the </D>
fread($archiveHandle, 9);
return $instance;
}
public function writeToArchive($archiveHandle)
{
if($this->relativePathLength == 0)
{
// Don't allow a base path to be written to the archive
return;
}
$headerString = '<D><MT>'.$this->mtime.'</MT><P>'.$this->permissions.'</P><RPL>'.$this->relativePathLength.'</RPL><RP>'.$this->relativePath.'</RP></D>';
//DupLiteSnapLibIOU::fwrite($archiveHandle, $headerString);
$bytes_written = @fwrite($archiveHandle, $headerString);
if ($bytes_written === false) {
throw new Exception('Error writing to file.');
} else {
return $bytes_written;
}
}
}
} lib/dup_archive/classes/headers/class.duparchive.header.u.php 0000644 00000002252 15133606540 0020320 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
if(!class_exists('DupArchiveHeaderU')) {
class DupArchiveHeaderU
{
const MaxStandardHeaderFieldLength = 128;
public static function readStandardHeaderField($archiveHandle, $ename)
{
$expectedStart = '<'.$ename.'>';
$expectedEnd = '</'.$ename.'>';
$startingElement = fread($archiveHandle, strlen($expectedStart));
if($startingElement !== $expectedStart) {
throw new Exception("Invalid starting element. Was expecting {$expectedStart} but got {$startingElement}");
}
//return DupLiteSnapLibStreamU::streamGetLine($archiveHandle, self::MaxStandardHeaderFieldLength, $expectedEnd);
$headerString = stream_get_line($archiveHandle, self::MaxStandardHeaderFieldLength, $expectedEnd);
if ($headerString === false) {
throw new Exception('Error reading line.');
}
return $headerString;
}
}
} lib/dup_archive/classes/class.duparchive.mini.expander.php 0000644 00000033570 15133606540 0017762 0 ustar 00 <?php
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
//---------- DUPARCHIVE MINI EXPANDER: The contents of this file will be injected into the installer bootlog at build time ------------------------
class DupArchiveHeaderMiniU
{
const MaxStandardHeaderFieldLength = 128;
public static function readStandardHeaderField($archiveHandle, $ename)
{
$expectedStart = "<{$ename}>";
$expectedEnd = "</{$ename}>";
$startingElement = fread($archiveHandle, strlen($expectedStart));
if($startingElement !== $expectedStart) {
throw new Exception("Invalid starting element. Was expecting {$expectedStart} but got {$startingElement}");
}
return stream_get_line($archiveHandle, self::MaxStandardHeaderFieldLength, $expectedEnd);
}
}
class DupArchiveMiniItemHeaderType
{
const None = 0;
const File = 1;
const Directory = 2;
const Glob = 3;
}
class DupArchiveMiniFileHeader
{
public $fileSize;
public $mtime;
public $permissions;
public $hash;
public $relativePathLength;
public $relativePath;
static function readFromArchive($archiveHandle)
{
$instance = new DupArchiveMiniFileHeader();
$instance->fileSize = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'FS');
$instance->mtime = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'MT');
$instance->permissions = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'P');
$instance->hash = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'HA');
$instance->relativePathLength = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'RPL');
// Skip <RP>
fread($archiveHandle, 4);
$instance->relativePath = fread($archiveHandle, $instance->relativePathLength);
// Skip </RP>
fread($archiveHandle, 5);
// Skip the #F!
//fread($archiveHandle, 3);
// Skip the </F>
fread($archiveHandle, 4);
return $instance;
}
}
class DupArchiveMiniDirectoryHeader
{
public $mtime;
public $permissions;
public $relativePathLength;
public $relativePath;
// const MaxHeaderSize = 8192;
// const MaxStandardHeaderFieldLength = 128;
static function readFromArchive($archiveHandle)
{
$instance = new DupArchiveMiniDirectoryHeader();
$instance->mtime = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'MT');
$instance->permissions = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'P');
$instance->relativePathLength = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'RPL');
// Skip the <RP>
fread($archiveHandle, 4);
$instance->relativePath = fread($archiveHandle, $instance->relativePathLength);
// Skip the </RP>
fread($archiveHandle, 5);
// Skip the </D>
fread($archiveHandle, 4);
return $instance;
}
}
class DupArchiveMiniGlobHeader //extends HeaderBase
{
public $originalSize;
public $storedSize;
public $hash;
// const MaxHeaderSize = 255;
public static function readFromArchive($archiveHandle, $skipGlob)
{
$instance = new DupArchiveMiniGlobHeader();
// DupArchiveUtil::log('Reading glob starting at ' . ftell($archiveHandle));
$startElement = fread($archiveHandle, 3);
//if ($marker != '?G#') {
if ($startElement != '<G>') {
throw new Exception("Invalid glob header marker found {$startElement}. location:" . ftell($archiveHandle));
}
$instance->originalSize = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'OS');
$instance->storedSize = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'SS');
$instance->hash = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'HA');
// Skip the </G>
fread($archiveHandle, 4);
if ($skipGlob) {
// DupLiteSnapLibIOU::fseek($archiveHandle, $instance->storedSize, SEEK_CUR);
if(fseek($archiveHandle, $instance->storedSize, SEEK_CUR) === -1)
{
throw new Exception("Can't fseek when skipping glob at location:".ftell($archiveHandle));
}
}
return $instance;
}
}
class DupArchiveMiniHeader
{
public $version;
public $isCompressed;
// const MaxHeaderSize = 50;
private function __construct()
{
// Prevent instantiation
if (!class_exists('DUPX_Bootstrap')) {
throw new Exception('Class DUPX_Bootstrap not found');
}
}
public static function readFromArchive($archiveHandle)
{
$instance = new DupArchiveMiniHeader();
$startElement = fgets($archiveHandle, 4);
if ($startElement != '<A>') {
throw new Exception("Invalid archive header marker found {$startElement}");
}
$instance->version = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'V');
$instance->isCompressed = DupArchiveHeaderMiniU::readStandardHeaderField($archiveHandle, 'C') == 'true' ? true : false;
// Skip the </A>
fgets($archiveHandle, 5);
return $instance;
}
}
class DupArchiveMiniWriteInfo
{
public $archiveHandle = null;
public $currentFileHeader = null;
public $destDirectory = null;
public $directoryWriteCount = 0;
public $fileWriteCount = 0;
public $isCompressed = false;
public $enableWrite = false;
public function getCurrentDestFilePath()
{
if($this->destDirectory != null)
{
return "{$this->destDirectory}/{$this->currentFileHeader->relativePath}";
}
else
{
return null;
}
}
}
class DupArchiveMiniExpander
{
public static $loggingFunction = null;
public static function init($loggingFunction)
{
self::$loggingFunction = $loggingFunction;
}
public static function log($s, $flush=false)
{
if(self::$loggingFunction != null) {
call_user_func(self::$loggingFunction, "MINI EXPAND:$s", $flush);
}
}
public static function expandDirectory($archivePath, $relativePath, $destPath)
{
self::expandItems($archivePath, $relativePath, $destPath);
}
private static function expandItems($archivePath, $inclusionFilter, $destDirectory, $ignoreErrors = false)
{
$archiveHandle = fopen($archivePath, 'rb');
if ($archiveHandle === false) {
throw new Exception("Can’t open archive at $archivePath!");
}
$archiveHeader = DupArchiveMiniHeader::readFromArchive($archiveHandle);
$writeInfo = new DupArchiveMiniWriteInfo();
$writeInfo->destDirectory = $destDirectory;
$writeInfo->isCompressed = $archiveHeader->isCompressed;
$moreToRead = true;
while ($moreToRead) {
if ($writeInfo->currentFileHeader != null) {
try {
if (self::passesInclusionFilter($inclusionFilter, $writeInfo->currentFileHeader->relativePath)) {
self::writeToFile($archiveHandle, $writeInfo);
$writeInfo->fileWriteCount++;
}
else if($writeInfo->currentFileHeader->fileSize > 0) {
// self::log("skipping {$writeInfo->currentFileHeader->relativePath} since it doesn’t match the filter");
// Skip the contents since the it isn't a match
$dataSize = 0;
do {
$globHeader = DupArchiveMiniGlobHeader::readFromArchive($archiveHandle, true);
$dataSize += $globHeader->originalSize;
$moreGlobs = ($dataSize < $writeInfo->currentFileHeader->fileSize);
} while ($moreGlobs);
}
$writeInfo->currentFileHeader = null;
// Expand state taken care of within the write to file to ensure consistency
} catch (Exception $ex) {
if (!$ignoreErrors) {
throw $ex;
}
}
} else {
$headerType = self::getNextHeaderType($archiveHandle);
switch ($headerType) {
case DupArchiveMiniItemHeaderType::File:
//$writeInfo->currentFileHeader = DupArchiveMiniFileHeader::readFromArchive($archiveHandle, $inclusionFilter);
$writeInfo->currentFileHeader = DupArchiveMiniFileHeader::readFromArchive($archiveHandle);
break;
case DupArchiveMiniItemHeaderType::Directory:
$directoryHeader = DupArchiveMiniDirectoryHeader::readFromArchive($archiveHandle);
// self::log("considering $inclusionFilter and {$directoryHeader->relativePath}");
if (self::passesInclusionFilter($inclusionFilter, $directoryHeader->relativePath)) {
// self::log("passed");
$directory = "{$writeInfo->destDirectory}/{$directoryHeader->relativePath}";
// $mode = $directoryHeader->permissions;
// rodo handle this more elegantly @mkdir($directory, $directoryHeader->permissions, true);
DUPX_Bootstrap::mkdir($directory, 'u+rwx', true);
$writeInfo->directoryWriteCount++;
}
else {
// self::log("didnt pass");
}
break;
case DupArchiveMiniItemHeaderType::None:
$moreToRead = false;
}
}
}
fclose($archiveHandle);
}
private static function getNextHeaderType($archiveHandle)
{
$retVal = DupArchiveMiniItemHeaderType::None;
$marker = fgets($archiveHandle, 4);
if (feof($archiveHandle) === false) {
switch ($marker) {
case '<D>':
$retVal = DupArchiveMiniItemHeaderType::Directory;
break;
case '<F>':
$retVal = DupArchiveMiniItemHeaderType::File;
break;
case '<G>':
$retVal = DupArchiveMiniItemHeaderType::Glob;
break;
default:
throw new Exception("Invalid header marker {$marker}. Location:".ftell($archiveHandle));
}
}
return $retVal;
}
private static function writeToFile($archiveHandle, $writeInfo)
{
$destFilePath = $writeInfo->getCurrentDestFilePath();
if($writeInfo->currentFileHeader->fileSize > 0)
{
/* @var $writeInfo DupArchiveMiniWriteInfo */
$parentDir = dirname($destFilePath);
if (!file_exists($parentDir)) {
if (!DUPX_Bootstrap::mkdir($parentDir, 'u+rwx', true)) {
throw new Exception("Couldn't create {$parentDir}");
}
}
$destFileHandle = fopen($destFilePath, 'wb+');
if ($destFileHandle === false) {
throw new Exception("Couldn't open {$destFilePath} for writing.");
}
do {
self::appendGlobToFile($archiveHandle, $destFileHandle, $writeInfo);
$currentFileOffset = ftell($destFileHandle);
$moreGlobstoProcess = $currentFileOffset < $writeInfo->currentFileHeader->fileSize;
} while ($moreGlobstoProcess);
fclose($destFileHandle);
DUPX_Bootstrap::chmod($destFilePath, 'u+rw');
self::validateExpandedFile($writeInfo);
} else {
if(touch($destFilePath) === false) {
throw new Exception("Couldn't create $destFilePath");
}
DUPX_Bootstrap::chmod($destFilePath, 'u+rw');
}
}
private static function validateExpandedFile($writeInfo)
{
/* @var $writeInfo DupArchiveMiniWriteInfo */
if ($writeInfo->currentFileHeader->hash !== '00000000000000000000000000000000') {
$hash = hash_file('crc32b', $writeInfo->getCurrentDestFilePath());
if ($hash !== $writeInfo->currentFileHeader->hash) {
throw new Exception("MD5 validation fails for {$writeInfo->getCurrentDestFilePath()}");
}
}
}
// Assumption is that archive handle points to a glob header on this call
private static function appendGlobToFile($archiveHandle, $destFileHandle, $writeInfo)
{
/* @var $writeInfo DupArchiveMiniWriteInfo */
$globHeader = DupArchiveMiniGlobHeader::readFromArchive($archiveHandle, false);
$globContents = fread($archiveHandle, $globHeader->storedSize);
if ($globContents === false) {
throw new Exception("Error reading glob from {$writeInfo->getDestFilePath()}");
}
if ($writeInfo->isCompressed) {
$globContents = gzinflate($globContents);
}
if (fwrite($destFileHandle, $globContents) === false) {
throw new Exception("Error writing data glob to {$destFileHandle}");
}
}
private static function passesInclusionFilter($filter, $candidate)
{
return (substr($candidate, 0, strlen($filter)) == $filter);
}
}
?>