Sindbad~EG File Manager
<?php
namespace Duplicator\Installer\Core\Deploy\Database;
use Duplicator\Installer\Core\Params\Descriptors\ParamDescUsers;
use Duplicator\Installer\Core\Params\PrmMng;
use Duplicator\Installer\Models\ImportUser;
use Duplicator\Installer\Utils\Log\Log;
use Duplicator\Libs\Snap\JsonSerialize\AbstractJsonSerializable;
use Duplicator\Libs\Snap\SnapDB;
use Duplicator\Libs\Snap\SnapUtil;
use DUPX_ArchiveConfig;
use DUPX_DB;
use DUPX_DB_Functions;
use DUPX_DB_Tables;
use DUPX_InstallerState;
use DUPX_NOTICE_ITEM;
use DUPX_NOTICE_MANAGER;
use DUPX_Security;
use DUPX_UpdateEngine;
use Error;
use Exception;
class DbUserMode extends AbstractJsonSerializable
{
/** @var ImportUser[] */
protected $targetUsersById = array();
/** @var ImportUser[] */
protected $targetUsersByMail = array();
/** @var ImportUser[] */
protected $targetUsersByLogin = array();
/** @var int */
protected $usersAutoIncrement = -1;
/** @var int */
protected $usersMetaAutoIncrement = -1;
/** @var bool[] */
protected $addedUsers = array();
/** @var int[] */
protected $mappingIds = array();
/** @var string[] */
protected $existingsMetaIsd = array();
/** @var int */
protected $userTableNumCols = 0;
/** @var string */
protected $userMode = ParamDescUsers::USER_MODE_OVERWRITE;
/** @var string */
protected $prefixMetaRegexCheck = '';
/** @var array */
protected $prefixMetaMapping = array();
/**
* Class contructor
*/
public function __construct()
{
$prmMng = PrmMng::getInstance();
$this->userMode = ParamDescUsers::getUsersMode();
$this->prefixMetaRegexCheck = '/^' . preg_quote(DUPX_ArchiveConfig::getInstance()->wp_tableprefix, '/') . '(?:(\d+)_)?(.*)$/';
switch (DUPX_InstallerState::getInstType()) {
case DUPX_InstallerState::INSTALL_SINGLE_SITE:
$this->addPrefixMetaMapping(
0,
$prmMng->getValue(PrmMng::PARAM_DB_TABLE_PREFIX)
);
break;
case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBDOMAIN:
case DUPX_InstallerState::INSTALL_SINGLE_SITE_ON_SUBFOLDER:
throw new Exception('Invalid mode');
case DUPX_InstallerState::INSTALL_RBACKUP_SINGLE_SITE:
break;
case DUPX_InstallerState::INSTALL_NOT_SET:
throw new Exception('Cannot change setup with current installation type [' . DUPX_InstallerState::getInstType() . ']');
default:
throw new Exception('Unknown mode');
}
}
/**
* Add meta prefix meta mapping
*
* @param int $subsiteId subsite id
* @param string $prefix replace value
*
* @return void
*/
protected function addPrefixMetaMapping($subsiteId, $prefix)
{
Log::info('ADD PREFIX META MAP ID ' . $subsiteId . ' ' . $prefix);
$key = ($subsiteId == 1 ? 0 : $subsiteId);
$this->prefixMetaMapping[$key] = $prefix;
}
/**
* This function renames the user tables of the target site, also updates the user meta keys
*
* @return void
*/
public static function moveTargetUserTablesOnCurrentPrefix()
{
$paramsManager = PrmMng::getInstance();
if (ParamDescUsers::getUsersMode() === ParamDescUsers::USER_MODE_OVERWRITE) {
return;
}
Log::info("\nKEEP TARGET SITE USERS TABLES - USER MODE " . ParamDescUsers::getUsersMode());
$dbFunc = DUPX_DB_Functions::getInstance();
$overwriteData = $paramsManager->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA);
if ($overwriteData['table_prefix'] == $paramsManager->getValue(PrmMng::PARAM_DB_TABLE_PREFIX)) {
Log::info('TABLE NAMES ARE THE SAME, SO SKIP USERS TABLES RENAME');
return;
}
$targetUserTable = DUPX_DB_Functions::getUserTableName($overwriteData['table_prefix']);
$targetUserMetaTable = DUPX_DB_Functions::getUserMetaTableName($overwriteData['table_prefix']);
$currentUserTableName = DUPX_DB_Functions::getUserTableName();
$currentUserMetaTableName = DUPX_DB_Functions::getUserMetaTableName();
$dbFunc->renameTable($targetUserTable, $currentUserTableName, true);
$dbFunc->renameTable($targetUserMetaTable, $currentUserMetaTableName, true);
// Update table prefix on meta key
DUPX_UpdateEngine::updateTablePrefix(
$dbFunc->dbConnection(),
$currentUserMetaTableName,
'meta_key',
$overwriteData['table_prefix'],
$paramsManager->getValue(PrmMng::PARAM_DB_TABLE_PREFIX)
);
Log::info("USER TABLES RENAMED");
}
/**
* This function removes all meta keys of the current prefix in the usermeta table.
* This is needed to replace them with the meta keys that will be imported
*
* @return void
*/
public function removeAllUserMetaKeysOfCurrentPrefix()
{
$paramsManager = PrmMng::getInstance();
if (
ParamDescUsers::getUsersMode() !== ParamDescUsers::USER_MODE_IMPORT_USERS
) {
return;
}
$dbh = DUPX_DB_Functions::getInstance()->dbConnection();
$overwriteData = $paramsManager->getValue(PrmMng::PARAM_OVERWRITE_SITE_DATA);
$loggedInUserId = (int) $overwriteData['loggedUser']['id'];
foreach ($this->prefixMetaMapping as $overwriteId => $prefix) {
$where = 'user_id != ' . $loggedInUserId;
$escPergPrefix = mysqli_real_escape_string($dbh, SnapDB::quoteRegex($prefix));
if ($prefix == $overwriteData['table_prefix']) {
Log::info("\nREMOVE EXISTING USER META KEY WITH PREFIX " . $prefix . ' EXCEPT ' . $prefix . '[0-9]+_');
// SELECT * FROM `prefix_usermeta` WHERE user_id != 2 AND meta_key REGEXP "^prefix_" AND meta_key NOT REGEXP "^prefix_[0-9]+_"
$where .= ' AND meta_key REGEXP "^' . $escPergPrefix . '" AND meta_key NOT REGEXP "^' . $escPergPrefix . '[0-9]+_"';
} else {
Log::info("\nREMOVE EXISTING USER META KEY WITH PREFIX " . $prefix);
// SELECT * FROM `prefix_usermeta` WHERE user_id != 2 AND meta_key REGEXP "^prefix_2_"
$where .= ' AND meta_key REGEXP "^' . $escPergPrefix . '"';
}
DUPX_DB::chunksDelete($dbh, DUPX_DB_Functions::getUserMetaTableName(), $where);
}
}
/**
* Filter props on json encode
*
* @return strng[]
*/
public function __sleep()
{
$props = array_keys(get_object_vars($this));
return array_diff($props, array('targetUsersByMail', 'targetUsersByLogin'));
}
/**
* Called after json decode
*
* @return void
*/
public function __wakeup()
{
foreach ($this->targetUsersById as $user) {
$this->targetUsersByMail[$user->getMail()] = $user;
$this->targetUsersByLogin[$user->getLogin()] = $user;
}
}
/**
* Return the list of columns that contain user id to remap in an array( table => numberColumn)
*
* @return int[]
*/
protected static function getTableColIdsToRemap()
{
static $remapTables = null;
if (is_null($remapTables)) {
$remapTables = array();
foreach (DUPX_DB_Tables::getInstance()->getTablesByNameWithoutPrefix('posts') as $table) {
$remapTables[$table] = 1;
}
Log::info('REMAP USERS TABLES/COLUMN ' . Log::v2str($remapTables));
}
return $remapTables;
}
/**
* Load from users table the user list
*
* @return void
*/
public function initTargetSiteUsersData()
{
if ($this->userMode !== ParamDescUsers::USER_MODE_IMPORT_USERS) {
return;
}
$dbh = DUPX_DB_Functions::getInstance()->dbConnection();
Log::info('INIT IMPORT TARGET USER TABLE DATA');
$dbName = mysqli_real_escape_string($dbh, PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_NAME));
$userTable = mysqli_real_escape_string($dbh, DUPX_DB_Functions::getUserTableName());
// count num cols of user table, can be different from source to target
$query = 'SELECT count(*) AS num_cols FROM information_schema.columns WHERE table_schema = "' . $dbName . '" AND table_name = "' . $userTable . '"';
if (($queryRes = DUPX_DB::mysqli_query($dbh, $query)) === false) {
$err = mysqli_error($dbh);
throw new Exception('Query error: ' . $err);
}
$row = $queryRes->fetch_array();
$this->userTableNumCols = (int) $row[0];
Log::info('USER TABLE COLUMNS COUNT ' . $this->userTableNumCols, Log::LV_DETAILED);
$query = 'SELECT `ID`,`user_login`,`user_email` FROM `' . $userTable . '`';
if (($queryRes = DUPX_DB::mysqli_query($dbh, $query)) === false) {
$err = mysqli_error($dbh);
throw new Exception('Query error: ' . $err);
}
$this->usersAutoIncrement = -1;
while ($row = $queryRes->fetch_assoc()) {
$rowId = (int) $row['ID'];
$user = new ImportUser($rowId, $row['user_login'], $row['user_email']);
$this->targetUsersById[$user->getId()] = $user;
$this->targetUsersByMail[$user->getMail()] = $user;
$this->targetUsersByLogin[$user->getLogin()] = $user;
if ($rowId > $this->usersAutoIncrement) {
$this->usersAutoIncrement = $rowId;
}
}
$this->usersAutoIncrement++;
$queryRes->free_result();
Log::info('EXISTING USERS COUNT ' . count($this->targetUsersById), Log::LV_DETAILED);
Log::info('USERS TABLE AUTOINCREMENT VALUE ' . $this->usersAutoIncrement, Log::LV_DETAILED);
$this->initTargetSiteUserMetaData();
}
/**
* For each existing meta key, a list of IDs is associated with each user who has that key or true if all users have the key
*
* @return void
*/
protected function initTargetSiteUserMetaData()
{
$dbh = DUPX_DB_Functions::getInstance()->dbConnection();
Log::info('INIT IMPORT TARGET USERMETA TABLE DATA');
$userTable = mysqli_real_escape_string($dbh, DUPX_DB_Functions::getUserTableName());
$userMetaTable = mysqli_real_escape_string($dbh, DUPX_DB_Functions::getUserMetaTableName());
$query = 'SELECT max(umeta_id) AS maxId FROM `' . $userMetaTable . '`';
if (($queryRes = DUPX_DB::mysqli_query($dbh, $query)) === false) {
$err = mysqli_error($dbh);
throw new Exception('Query error: ' . $err);
}
$row = $queryRes->fetch_assoc();
$this->usersMetaAutoIncrement = ((int) $row['maxId']) + 1;
$queryRes->free_result();
Log::info('USERMETA TABLE AUTOINCREMENT VALUE ' . $this->usersAutoIncrement, Log::LV_DETAILED);
$query = 'SELECT COUNT(*) FROM `' . $userTable . '`';
if (($queryRes = DUPX_DB::mysqli_query($dbh, $query)) === false) {
$err = mysqli_error($dbh);
throw new Exception('Query error: ' . $err);
}
$row = $queryRes->fetch_array();
$maxNumIds = $row[0];
$query = 'SELECT `meta_key`, IF(COUNT(`user_id`) >= ' . $maxNumIds . ', "ALL", GROUP_CONCAT(`user_id` ORDER BY `user_id` ASC)) AS IDS ' .
'FROM `' . $userMetaTable . '`' .
'WHERE `user_id` IN (SELECT `ID` FROM `' . $userTable . '`) GROUP BY meta_key';
if (($queryRes = DUPX_DB::mysqli_query($dbh, $query)) === false) {
$err = mysqli_error($dbh);
throw new Exception('Query error: ' . $err);
}
while ($row = $queryRes->fetch_assoc()) {
$this->existingsMetaIsd[$row['meta_key']] = (
($row['IDS'] === 'ALL') ?
true :
array_map('intval', explode(',', $row['IDS']))
);
}
Log::info('NUM META KEYS READ ' . count($this->existingsMetaIsd), Log::LV_DETAILED);
$queryRes->free_result();
}
/**
* Apply inser query user fixes
*
* @param string $query query string
*
* @return string if the string is empty no query must be executed
*/
public function applyUsersFixes(&$query)
{
if ($this->userMode == ParamDescUsers::USER_MODE_OVERWRITE) {
return $query;
}
$matches = array();
if (preg_match('/^\s*(?:\/\*.*\*\/|#.*\n|--.*\n)?\s*INSERT\s+INTO\s+`?([^\s`]*?)`?\s+VALUES/s', $query, $matches) !== 1) {
return $query;
}
$tableName = SnapDB::parsedQueryValueToString($matches[1]);
if ($this->userMode == ParamDescUsers::USER_MODE_IMPORT_USERS) {
if ($tableName == DUPX_DB_Functions::getUserTableName()) {
return $this->getUserTableQueryFix(SnapDB::getValuesFromQueryInsert($query));
} elseif ($tableName == DUPX_DB_Functions::getUserMetaTableName()) {
return $this->getUserMetaTableQueryFix(SnapDB::getValuesFromQueryInsert($query));
}
}
$tablesColRemap = self::getTableColIdsToRemap();
if (in_array($tableName, array_keys($tablesColRemap))) {
return $this->getTableUserRemapQueryFix(
$tableName,
$tablesColRemap[$tableName],
SnapDB::getValuesFromQueryInsert($query)
);
}
return $query;
}
/**
* Generate import final report
*
* @return void
*/
public function generateImportReport()
{
if ($this->userMode !== ParamDescUsers::USER_MODE_IMPORT_USERS) {
return;
}
$numAdded = 0;
$numChanged = 0;
if (($fp = fopen(DUPX_INIT . '/' . self::getCsvReportName(), 'w')) === false) {
Log::info('Can\'t open report file ' . DUPX_INIT . '/' . self::getCsvReportName());
} else {
fputcsv($fp, ImportUser::getArrayReportTitles());
}
foreach ($this->targetUsersById as $user) {
if ($user->isAdded()) {
$numAdded++;
} elseif ($user->isChanged()) {
$numChanged++;
} else {
continue;
}
if ($fp != false) {
fputcsv($fp, $user->getArrayReport());
}
}
if ($fp != false) {
fclose($fp);
$csvUrl = DUPX_INIT_URL . '/' . self::getCsvReportName();
} else {
$csvUrl = false;
}
$longMsg = dupxTplRender(
'parts/reports/import_report',
array(
'numAdded' => $numAdded,
'numChanged' => $numChanged,
'csvUrl' => $csvUrl
),
false
);
$nManager = DUPX_NOTICE_MANAGER::getInstance();
$nManager->addFinalReportNotice(
array(
'shortMsg' => 'User import report',
'level' => DUPX_NOTICE_ITEM::NOTICE,
'longMsg' => $longMsg,
'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
'sections' => 'general'
)
);
$nManager->saveNotices();
}
/**
* Return csv report file name
*
* @return string
*/
protected static function getCsvReportName()
{
return 'dup-installer-import-report__' . DUPX_Security::getInstance()->getSecondaryPackageHash() . '.csv';
}
/**
* Apply query fix for user table
*
* @param array $queryValues two dimensional array where each item is a row containing the list of values
*
* @return string
*/
protected function getUserTableQueryFix($queryValues)
{
$dbh = DUPX_DB_Functions::getInstance()->dbConnection();
$resultValues = array();
$numColsQueryVals = isset($queryValues[0]) ? count($queryValues[0]) : 0;
$colsDeltaDiff = $this->userTableNumCols - $numColsQueryVals;
foreach ($queryValues as $rowVals) {
$rowId = SnapDB::parsedQueryValueToInt($rowVals[0]);
$rowLogin = SnapDB::parsedQueryValueToString($rowVals[1]);
$rowMail = SnapDB::parsedQueryValueToString($rowVals[4]);
if (isset($this->targetUsersByMail[$rowMail])) {
$targetUser = $this->targetUsersByMail[$rowMail];
$targetId = $targetUser->getId();
$targetLogin = $targetUser->getLogin();
if ($rowId != $targetId) {
$targetUser->setOldId($rowId);
$this->mappingIds[$rowId] = $targetId;
}
if ($rowLogin != $targetLogin) {
$targetUser->setOldLogin($rowLogin);
}
} else {
$rowVals[0] = $targetId = $this->usersAutoIncrement;
$this->usersAutoIncrement++;
if ($rowId != $targetId) {
$this->mappingIds[$rowId] = $targetId;
}
$newLogin = $rowLogin;
$postfixIndex = 0;
while (isset($this->targetUsersByLogin[$newLogin])) {
$postfixIndex++;
$newLogin = $rowLogin . $postfixIndex;
}
if ($rowLogin != $newLogin) {
$rowVals[1] = '"' . mysqli_real_escape_string($dbh, $newLogin) . '"';
$niceName = SnapDB::parsedQueryValueToString($rowVals[3]);
$rowVals[3] = '"' . mysqli_real_escape_string($dbh, $niceName) . $postfixIndex . '"';
$displayName = SnapDB::parsedQueryValueToString($rowVals[9]);
if ($rowLogin == $displayName) {
$rowVals[9] = '"' . mysqli_real_escape_string($dbh, $newLogin) . '"';
}
}
$user = new ImportUser($targetId, $newLogin, $rowMail, $rowId, $rowLogin, true);
$this->targetUsersById[$user->getId()] = $user;
$this->targetUsersByMail[$user->getMail()] = $user;
$this->targetUsersByLogin[$user->getLogin()] = $user;
$this->addedUsers[$user->getOldId()] = true;
if ($colsDeltaDiff == 0) {
$resultValues[] = $rowVals;
} elseif ($colsDeltaDiff < 0) {
$resultValues[] = array_slice($rowVals, 0, $this->userTableNumCols);
} else {
for ($i = 0; $i < $colsDeltaDiff; $i++) {
$rowVals[] = '"0"';
}
$resultValues[] = $rowVals;
}
}
}
if (empty($resultValues)) {
return '';
}
return 'INSERT INTO `' . mysqli_real_escape_string($dbh, DUPX_DB_Functions::getUserTableName()) . '` ' .
'VALUES ' . SnapDB::getQueryInsertValuesFromArray($resultValues) . ';';
}
/**
* Apply query fix for usermeta table
*
* @param array $queryValues two dimensional array where each item is a row containing the list of values
*
* @return string
*/
protected function getUserMetaTableQueryFix($queryValues)
{
$dbh = DUPX_DB_Functions::getInstance()->dbConnection();
$resultValues = array();
// reset value
$user = new ImportUser(-1, '', '');
$prefixMatches = null;
foreach ($queryValues as $rowVals) {
try {
$rowUserId = SnapDB::parsedQueryValueToInt($rowVals[1]);
$rowMetakey = SnapDB::parsedQueryValueToString($rowVals[2]);
if ($user->getId() != $rowUserId) {
$userId = isset($this->mappingIds[$rowUserId]) ? $this->mappingIds[$rowUserId] : $rowUserId;
if (isset($this->targetUsersById[$userId])) {
$user = $this->targetUsersById[$userId];
} else {
// This happens if there is a meta key that has a user id that does not belong to any user, it is an anomalous thing so it is skipped.
continue;
}
}
if (preg_match($this->prefixMetaRegexCheck, $rowMetakey, $prefixMatches) === 1) {
$currentId = (int)$prefixMatches[1];
if (!isset($this->prefixMetaMapping[$currentId])) {
// if the attribute is not of the selected sub-site then it is not inserted in the import
continue;
}
$rowMetakey = $this->prefixMetaMapping[$currentId] . $prefixMatches[2];
$rowVals[2] = '"' . mysqli_real_escape_string($dbh, $rowMetakey) . '"';
}
if (
$user->isAdded() ||
!isset($this->existingsMetaIsd[$rowMetakey]) ||
(
$this->existingsMetaIsd[$rowMetakey] !== true &&
SnapUtil::binarySearch($this->existingsMetaIsd[$rowMetakey], $user->getId()) == false
)
) {
$rowVals[0] = $this->usersMetaAutoIncrement;
$this->usersMetaAutoIncrement++;
$rowVals[1] = $user->getId();
if ($rowMetakey == 'nickname') {
// update nickname
$rowMetaValue = SnapDB::parsedQueryValueToString($rowVals[3]);
if ($rowMetaValue == $user->getOldLogin()) {
$rowVals[3] = '"' . mysqli_real_escape_string($dbh, $user->getLogin()) . '"';
}
}
$resultValues[] = $rowVals;
}
} catch (Exception $e) {
Log::logException($e, 'Error on parse user meta row');
} catch (Error $e) {
Log::logException($e, 'Error on parse user meta row');
}
}
if (empty($resultValues)) {
return '';
}
return 'INSERT INTO `' . mysqli_real_escape_string($dbh, DUPX_DB_Functions::getUserMetaTableName()) .
'` VALUES ' . SnapDB::getQueryInsertValuesFromArray($resultValues) . ';';
}
/**
* Apply query fix for table/colum user id
*
* @param string $tableName table name
* @param string $colNum column index, 0 is first
* @param array $queryValues two dimensional array where each item is a row containing the list of values
*
* @return void
*/
protected function getTableUserRemapQueryFix($tableName, $colNum, $queryValues)
{
$dbh = DUPX_DB_Functions::getInstance()->dbConnection();
for ($i = 0; $i < count($queryValues); $i++) {
$rowUserId = SnapDB::parsedQueryValueToInt($queryValues[$i][$colNum]);
if (isset($this->mappingIds[$rowUserId])) {
$queryValues[$i][$colNum] = $this->mappingIds[$rowUserId];
}
}
return 'INSERT INTO `' . mysqli_real_escape_string($dbh, $tableName) .
'` VALUES ' . SnapDB::getQueryInsertValuesFromArray($queryValues) . ';';
}
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists