File "class.validation.database.service.php"
Full Path: /home/aiclgcwq/photonindustriespvt.com/wp-content/plugins/duplicator/installer/dup-installer/classes/validation/class.validation.database.service.php
File size: 25.95 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/**
* Validation object
*
* Standard: PSR-2
*
* @link http://www.php-fig.org/psr/psr-2 Full Documentation
*
* @package SC\DUPX\U
*/
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
use Duplicator\Installer\Utils\Log\Log;
use Duplicator\Installer\Core\Params\PrmMng;
use Duplicator\Libs\Snap\SnapOS;
class DUPX_Validation_database_service
{
/**
*
* @var self
*/
private static $instance = null;
/**
*
* @var mysqli
*/
private $dbh = null;
/**
*
* @var bool
*/
private $skipOtherTests = false;
/**
*
* @var bool
*/
private $dbCreated = false;
/**
*
* @return self
*/
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct()
{
}
/**
*
* @return mysqli <p>Returns an object which represents the connection to a MySQL Server.</p>
*/
public function getDbConnection()
{
if (is_null($this->dbh)) {
$paramsManager = PrmMng::getInstance();
$this->dbh = DUPX_DB_Functions::getInstance()->dbConnection(array(
'dbhost' => $paramsManager->getValue(PrmMng::PARAM_DB_HOST),
'dbuser' => $paramsManager->getValue(PrmMng::PARAM_DB_USER),
'dbpass' => $paramsManager->getValue(PrmMng::PARAM_DB_PASS),
'dbname' => null
));
if (empty($this->dbh)) {
DUPX_DB_Functions::getInstance()->closeDbConnection();
$this->dbh = false;
}
}
return $this->dbh;
}
/**
* close db connection if is open
*/
public function closeDbConnection()
{
if (!is_null($this->dbh)) {
mysqli_close($this->dbh);
$this->dbh = null;
}
}
public function setSkipOtherTests($skip = true)
{
$this->skipOtherTests = (bool) $skip;
}
public function skipDatabaseTests()
{
return $this->skipOtherTests;
}
public function databaseExists(&$errorMessage = null)
{
try {
$result = true;
if (!$this->getDbConnection()) {
throw new Exception('Database not connected');
}
$paramsManager = PrmMng::getInstance();
if (mysqli_select_db($this->dbh, $paramsManager->getValue(PrmMng::PARAM_DB_NAME)) !== true) {
$errorMessage = mysqli_error($this->dbh);
$result = false;
}
} catch (Exception $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE SELECT EXCEPTION: ');
$result = false;
} catch (Error $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE SELECT EXCEPTION: ');
$result = false;
}
return $result;
}
public function createDatabase(&$errorMessage = null)
{
if ($this->dbCreated) {
return true;
}
try {
$result = true;
if (!$this->getDbConnection()) {
throw new Exception('Database not connected');
}
$dbName = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_NAME);
switch (PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_VIEW_MODE)) {
case 'basic':
case 'cpnl':
$query = 'CREATE DATABASE `' . mysqli_real_escape_string($this->dbh, $dbName) . '`';
if (DUPX_DB::mysqli_query($this->dbh, $query) === false) {
$errorMessage = mysqli_error($this->dbh);
$result = false;
}
if ($result && $this->databaseExists() === false) {
$errorMessage = 'Can\'t select database after creation';
$result = false;
}
break;
default:
$result = false;
$errorMessage = 'Invalid db view mode';
break;
}
} catch (Exception $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CREATE EXCEPTION: ');
$result = false;
} catch (Error $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CREATE EXCEPTION: ');
$result = false;
}
if ($result) {
$this->dbCreated = true;
return true;
} else {
return false;
}
}
public function isDatabaseCreated()
{
return $this->dbCreated;
}
public function cleanUpDatabase(&$errorMessage = null)
{
if (!$this->dbCreated) {
return true;
}
$result = true;
try {
$dbName = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_NAME);
switch (PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_VIEW_MODE)) {
case 'basic':
case 'cpnl':
//DELETE DB
if (DUPX_DB::mysqli_query($this->dbh, "DROP DATABASE IF EXISTS `" . mysqli_real_escape_string($this->dbh, $dbName) . "`") === false) {
$errorMessage = mysqli_error($this->dbh);
$result = false;
}
break;
default:
$errorMessage = 'Invalid db view mode';
$result = false;
break;
}
} catch (Exception $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CLEANUP EXCEPTION: ');
$result = false;
} catch (Error $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CLEANUP EXCEPTION: ');
$result = false;
}
if ($result) {
$this->dbCreated = false;
}
return $result;
}
public function getDatabases()
{
if (!$this->getDbConnection()) {
return array();
}
switch (PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_VIEW_MODE)) {
case 'basic':
case 'cpnl':
$dbUser = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_USER);
$host_user = substr_replace($dbUser, '', strpos($dbUser, '_'));
break;
default:
return array();
}
return DUPX_DB::getDatabases($this->dbh, $host_user);
}
/**
* Get list of tables that are affect by the DB action
*
* @param string|null $dbAction Adb action, if null get param db action
*
* @return string[]
*/
public function getDBActionAffectedTables($dbAction = null)
{
if ($dbAction === null) {
$dbAction = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_ACTION);
}
$affectedTables = array();
$excludeTables = DUPX_DB_Functions::getExcludedTables();
$escapedDbName = mysqli_real_escape_string($this->dbh, PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_NAME));
$allTables = DUPX_DB::queryColumnToArray($this->dbh, 'SHOW TABLES FROM `' . $escapedDbName . '`');
switch ($dbAction) {
case DUPX_DBInstall::DBACTION_EMPTY:
case DUPX_DBInstall::DBACTION_RENAME:
$affectedTables = array_diff($allTables, $excludeTables);
break;
case DUPX_DBInstall::DBACTION_REMOVE_ONLY_TABLES:
$affectedTables = array_intersect(
DUPX_DB_Tables::getInstance()->getNewTablesNames(),
array_diff($allTables, $excludeTables)
);
break;
default:
break;
}
return $affectedTables;
}
/**
* Get number of tables that are affect by the DB action
*
* @param string|null $dbAction Adb action, if null get param db action
*
* @return int
*/
public function getDBActionAffectedTablesCount($dbAction = null)
{
$isCreateNewDatabase = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_ACTION) == DUPX_DBInstall::DBACTION_CREATE;
return ($isCreateNewDatabase) ? 0 : count($this->getDBActionAffectedTables($dbAction));
}
public function checkDbVisibility(&$errorMessage = null)
{
$result = true;
try {
if (!$this->getDbConnection()) {
throw new Exception('Database not connected');
}
switch (PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_VIEW_MODE)) {
case 'basic':
case 'cpnl':
$result = $this->databaseExists($errorMessage);
break;
default:
$errorMessage = 'Invalid db view mode';
$result = false;
break;
}
} catch (Exception $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CHECK VISIBILITY EXCEPTION: ');
$result = false;
} catch (Error $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CHECK VISIBILITY EXCEPTION: ');
$result = false;
}
return $result;
}
/**
* This is validation test for "Prefix too long". Checks if there are
* any new table names longer than 64 characters.
*
* @param string &$errorMessage // Will be filled with error message in case when validation test fails
*
* @return bool // Returns true if validation test passes, false otherwise
*/
public function checkDbPrefixTooLong(&$errorMessage = null)
{
$result = true;
$numOfTooLongNewTableNames = count($this->getTooLongNewTableNames());
if ($numOfTooLongNewTableNames > 0) {
$errorMessage = "Length of $numOfTooLongNewTableNames table names exceeds limit of 64 after adding prefix.";
$result = false;
}
return $result;
}
/**
* Returns list of new table names whose length is bigger than 64 limit
*
* @return array
*/
public function getTooLongNewTableNames()
{
$tooLongNewTableNames = array();
$newTableNames = array();
$newTableNames = DUPX_DB_Tables::getInstance()->getNewTablesNames();
for ($i = 0; $i < count($newTableNames); $i++) {
if (strlen($newTableNames[$i]) > 64) {
$tooLongNewTableNames[] = $newTableNames[$i];
}
}
return $tooLongNewTableNames;
}
public function dbTablesCount(&$errorMessage = null)
{
$result = true;
try {
if (!$this->getDbConnection()) {
throw new Exception('Database not connected');
}
$dbName = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_NAME);
$result = DUPX_DB::countTables($this->dbh, $dbName);
} catch (Exception $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE TABLES COUNT EXCEPTION: ');
$result = false;
} catch (Error $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE TABLES COUNT EXCEPTION: ');
$result = false;
}
return $result;
}
/**
*
* @param array $perms
* @param array $errorMessages
*
* @return int // test result level
*/
public function dbCheckUserPerms(&$perms = array(), &$errorMessages = array())
{
$perms = array(
'create' => DUPX_Validation_abstract_item::LV_SKIP,
'insert' => DUPX_Validation_abstract_item::LV_SKIP,
'select' => DUPX_Validation_abstract_item::LV_SKIP,
'update' => DUPX_Validation_abstract_item::LV_SKIP,
'delete' => DUPX_Validation_abstract_item::LV_SKIP,
'drop' => DUPX_Validation_abstract_item::LV_SKIP,
'view' => DUPX_Validation_abstract_item::LV_SKIP,
'proc' => DUPX_Validation_abstract_item::LV_SKIP,
'func' => DUPX_Validation_abstract_item::LV_SKIP,
'trigger' => DUPX_Validation_abstract_item::LV_SKIP
);
$errorMessages = array();
try {
if (!$this->getDbConnection()) {
throw new Exception('Database not connected');
}
$dbName = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_NAME);
if (mysqli_select_db($this->dbh, $dbName) === false) {
throw new Exception('Can\'t select database ' . $dbName);
}
$tmpTable = '__dpro_temp_' . rand(1000, 9999) . '_' . date("ymdHis");
$tmpTableEscaped = '`' . mysqli_real_escape_string($this->dbh, $tmpTable) . '`';
if (
$this->isQueryWorking("CREATE TABLE " . $tmpTableEscaped . " ("
. "`id` int(11) NOT NULL AUTO_INCREMENT, "
. "`text` text NOT NULL, "
. "PRIMARY KEY (`id`))", $errorMessages)
) {
$perms['create'] = DUPX_Validation_abstract_item::LV_PASS;
} else {
$perms['create'] = DUPX_Validation_abstract_item::LV_FAIL;
}
if ($perms['create']) {
if ($this->isQueryWorking("INSERT INTO " . $tmpTableEscaped . " (`text`) VALUES ('TEXT-1')", $errorMessages)) {
$perms['insert'] = DUPX_Validation_abstract_item::LV_PASS;
} else {
$perms['insert'] = DUPX_Validation_abstract_item::LV_FAIL;
}
if ($this->isQueryWorking("SELECT COUNT(*) FROM " . $tmpTableEscaped, $errorMessages)) {
$perms['select'] = DUPX_Validation_abstract_item::LV_PASS;
} else {
$perms['select'] = DUPX_Validation_abstract_item::LV_FAIL;
}
if ($this->isQueryWorking("UPDATE " . $tmpTableEscaped . " SET text = 'TEXT-2' WHERE text = 'TEXT-1'", $errorMessages)) {
$perms['update'] = DUPX_Validation_abstract_item::LV_PASS;
} else {
$perms['update'] = DUPX_Validation_abstract_item::LV_FAIL;
}
if ($this->isQueryWorking("DELETE FROM " . $tmpTableEscaped . " WHERE text = 'TEXT-2'", $errorMessages)) {
$perms['delete'] = DUPX_Validation_abstract_item::LV_PASS;
} else {
$perms['delete'] = DUPX_Validation_abstract_item::LV_FAIL;
}
if ($this->isQueryWorking("DROP TABLE IF EXISTS " . $tmpTableEscaped . ";", $errorMessages)) {
$perms['drop'] = DUPX_Validation_abstract_item::LV_PASS;
} else {
$perms['drop'] = DUPX_Validation_abstract_item::LV_FAIL;
}
}
if ($this->dbHasViews()) {
if ($this->dbCheckGrants(array("CREATE VIEW"), $errorMessages)) {
$perms['view'] = DUPX_Validation_abstract_item::LV_PASS;
} else {
$perms['view'] = DUPX_Validation_abstract_item::LV_HARD_WARNING;
}
}
if ($this->dbHasProcedures()) {
if ($this->dbCheckGrants(array("CREATE ROUTINE", "ALTER ROUTINE"), $errorMessages)) {
$perms['proc'] = DUPX_Validation_abstract_item::LV_PASS;
} else {
$perms['proc'] = DUPX_Validation_abstract_item::LV_HARD_WARNING;
}
}
if ($this->dbHasFunctions()) {
if ($this->dbCheckGrants(array("CREATE ROUTINE", "ALTER ROUTINE"), $errorMessages)) {
$perms['func'] = DUPX_Validation_abstract_item::LV_PASS;
} else {
$perms['func'] = DUPX_Validation_abstract_item::LV_HARD_WARNING;
}
}
if ($this->dbHasTriggers()) {
if ($this->dbCheckGrants(array("TRIGGER"), $errorMessages)) {
$perms['trigger'] = DUPX_Validation_abstract_item::LV_PASS;
} else {
$perms['trigger'] = DUPX_Validation_abstract_item::LV_SOFT_WARNING;
}
}
} catch (Exception $e) {
$errorMessages[] = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CHECK USER PERMS EXCEPTION: ');
} catch (Error $e) {
$errorMessages[] = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CHECK USER PERMS EXCEPTION: ');
}
return min($perms);
}
/**
*
* @param string $query The SQL query
* @param array $errorMessages Optionally you can capture the errors in this array
*
* @return boolean returns true if running the query did not fail
*/
public function isQueryWorking($query, &$errorMessages = array())
{
$result = true;
try {
if (DUPX_DB::mysqli_query($this->dbh, $query) === false) {
$currentError = mysqli_error($this->dbh);
$result = false;
}
} catch (Exception $e) {
$currentError = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'TESTING QUERY: ');
$result = false;
} catch (Error $e) {
$currentError = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'TESTING QUERY: ');
$result = false;
}
if ($result === false) {
$errorMessages[] = $currentError;
}
return $result;
}
/**
*
* @param array $grants // list of grants to check
* @param array $errorMessages
*
* @return boolean
*/
public function dbCheckGrants($grants, &$errorMessages = array())
{
try {
if (($queryResult = DUPX_DB::mysqli_query($this->dbh, "SHOW GRANTS")) === false) {
$errorMessages[] = mysqli_error($this->dbh);
return false;
}
$dbName = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_NAME);
$regex = '/^GRANT\s+(?!USAGE)(.+)\s+ON\s+(\*|`.*?`)\..*$/';
$matches = null;
$matchFound = false;
while ($row = mysqli_fetch_array($queryResult)) {
if (!preg_match($regex, $row[0], $matches)) {
continue;
}
if (
$matches['2'] === '*' ||
$matches['2'] === $dbName ||
$matches['2'] === addcslashes($dbName, '_%')
) {
Log::info('SHOW GRANTS CURRENT DB: ' . $row[0], Log::LV_DEBUG);
$matchFound = true;
break;
}
//The GRANT queries can have wildcarsds in them which we have to take into account.
//Turn wildcards into regex expressions and try matching the expression against the DB name.
$dbNameRegex = preg_replace('/(?<!\\\\)%/', '.*', $matches['2']); // unescaped % becomes .*
$dbNameRegex = preg_replace('/(?<!\\\\)_/', '.', $dbNameRegex); // unescaped _ becomes .
if (preg_match($dbNameRegex, $dbName) === 1) {
Log::info('Grant matched via Wildcard: ' . $dbNameRegex, Log::LV_DEBUG);
Log::info('SHOW GRANTS CURRENT DB: ' . $row[0], Log::LV_DEBUG);
$matchFound = true;
break;
}
}
if (!$matchFound) {
Log::info('GRANTS LINE OF CURRENT DB NOT FOUND');
return false;
}
if ($matches['1'] === 'ALL PRIVILEGES') {
return true;
}
$userPrivileges = preg_split('/\s*,\s*/', $matches['1']);
if (($notGrants = array_diff($grants, $userPrivileges))) {
$message = "The mysql user does not have the '" . implode(', ', $notGrants) . "' permission.";
Log::info('NO GRANTS: ' . $message);
$errorMessages[] = $message;
return false;
} else {
return true;
}
} catch (Exception $e) {
$errorMessages[] = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CHECK PERM EXCEPTION: ');
return false;
}
return false;
}
public function dbHasProcedures()
{
if (DUPX_ArchiveConfig::getInstance()->dbInfo->procCount > 0) {
Log::info("SOURCE SITE DB HAD PROCEDURES", Log::LV_DEBUG);
return true;
}
if (($result = DUPX_DB::mysqli_query($this->dbh, "SHOW PROCEDURE STATUS"))) {
if (mysqli_num_rows($result) > 0) {
Log::info("INSTALL SITE HAS PROCEDURES", Log::LV_DEBUG);
return true;
}
}
return false;
}
public function dbHasFunctions()
{
if (DUPX_ArchiveConfig::getInstance()->dbInfo->funcCount > 0) {
Log::info("SOURCE SITE DB HAD FUNCTIONS", Log::LV_DEBUG);
return true;
}
if (($result = DUPX_DB::mysqli_query($this->dbh, "SHOW FUNCTION STATUS"))) {
if (mysqli_num_rows($result) > 0) {
Log::info("INSTALL SITE HAS FUNCTIONS", Log::LV_DEBUG);
return true;
}
}
return false;
}
public function dbHasTriggers()
{
if (($result = DUPX_DB::mysqli_query($this->dbh, "SHOW TRIGGERS"))) {
if (mysqli_num_rows($result) > 0) {
Log::info("INSTALL SITE HAS TRIGGERS", Log::LV_DEBUG);
return true;
}
}
return false;
}
public function dbHasViews()
{
if (DUPX_ArchiveConfig::getInstance()->dbInfo->viewCount > 0) {
Log::info("SOURCE SITE DB HAD VIEWS", Log::LV_DEBUG);
return true;
}
if (($result = DUPX_DB::mysqli_query($this->dbh, "SHOW FULL TABLES WHERE Table_Type = 'VIEW'"))) {
if (mysqli_num_rows($result) > 0) {
Log::info("INSTALL SITE HAS VIEWS", Log::LV_DEBUG);
return true;
}
}
return false;
}
public function dbGtidModeEnabled(&$errorMessage = array())
{
try {
$gtidModeEnabled = false;
if (($result = DUPX_DB::mysqli_query($this->dbh, 'SELECT @@GLOBAL.GTID_MODE', Log::LV_DEBUG)) === false) {
if (Log::isLevel(Log::LV_DEBUG)) {
// It is normal for this query to generate an error when the GTID is not active. So normally it is better not to worry users with managed error messages.
$errorMessage = mysqli_error($this->dbh);
}
} else {
if (($row = mysqli_fetch_array($result, MYSQLI_NUM)) !== false) {
if (strcasecmp($row[0], 'on') === 0) {
$gtidModeEnabled = true;
}
}
}
$result = $gtidModeEnabled;
} catch (Exception $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CHECK CHARSET EXCEPTION: ');
$result = false;
} catch (Error $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CHECK CHARSET EXCEPTION: ');
$result = false;
}
return $result;
}
/**
*
* @param string $errorMessage
*
* @return int // -1 fail
*/
public function caseSensitiveTablesValue(&$errorMessage = array())
{
try {
if (!$this->getDbConnection()) {
throw new Exception('Database not connected');
}
if (($lowerCaseTableNames = DUPX_DB::getVariable($this->dbh, 'lower_case_table_names')) === null) {
if (SnapOS::isWindows()) {
$lowerCaseTableNames = 1;
} elseif (SnapOS::isOSX()) {
$lowerCaseTableNames = 2;
} else {
$lowerCaseTableNames = 0;
}
}
$result = $lowerCaseTableNames;
} catch (Exception $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CHECK CHARSET EXCEPTION: ');
$result = -1;
} catch (Error $e) {
$errorMessage = $e->getMessage();
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CHECK CHARSET EXCEPTION: ');
$result = -1;
}
return (int) $result;
}
/**
* @return array|false
*/
public function getUserResources()
{
try {
$host = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_HOST);
$user = PrmMng::getInstance()->getValue(PrmMng::PARAM_DB_USER);
$query = "SELECT max_questions, max_updates, max_connections FROM mysql.user WHERE user = '{$user}' AND host = '{$host}'";
if (($result = DUPX_DB::mysqli_query($this->dbh, $query, Log::LV_DEFAULT)) != false && $result->num_rows > 0) {
return $result->fetch_assoc();
}
} catch (Exception $e) {
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CHECK USER RESOURCE EXCEPTION: ');
} catch (Error $e) {
Log::logException($e, Log::LV_DEFAULT, 'DATABASE CHECK USER RESOURCE ERROR: ');
}
return false;
}
private function __clone()
{
}
}