init web ems all
This commit is contained in:
675
phpMyAdmin/libraries/classes/Advisor.php
Executable file
675
phpMyAdmin/libraries/classes/Advisor.php
Executable file
@@ -0,0 +1,675 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* A simple rules engine, that parses and executes the rules in advisory_rules.txt.
|
||||
* Adjusted to phpMyAdmin.
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use Exception;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\SysInfo;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||
|
||||
/**
|
||||
* Advisor class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class Advisor
|
||||
{
|
||||
const GENERIC_RULES_FILE = 'libraries/advisory_rules_generic.txt';
|
||||
const BEFORE_MYSQL80003_RULES_FILE = 'libraries/advisory_rules_mysql_before80003.txt';
|
||||
|
||||
protected $dbi;
|
||||
protected $variables;
|
||||
protected $globals;
|
||||
protected $parseResult;
|
||||
protected $runResult;
|
||||
protected $expression;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface object
|
||||
* @param ExpressionLanguage $expression ExpressionLanguage object
|
||||
*/
|
||||
public function __construct(DatabaseInterface $dbi, ExpressionLanguage $expression)
|
||||
{
|
||||
$this->dbi = $dbi;
|
||||
$this->expression = $expression;
|
||||
/*
|
||||
* Register functions for ExpressionLanguage, we intentionally
|
||||
* do not implement support for compile as we do not use it.
|
||||
*/
|
||||
$this->expression->register(
|
||||
'round',
|
||||
function (){},
|
||||
function ($arguments, $num) {
|
||||
return round($num);
|
||||
}
|
||||
);
|
||||
$this->expression->register(
|
||||
'substr',
|
||||
function (){},
|
||||
function ($arguments, $string, $start, $length) {
|
||||
return substr($string, $start, $length);
|
||||
}
|
||||
);
|
||||
$this->expression->register(
|
||||
'preg_match',
|
||||
function (){},
|
||||
function ($arguments, $pattern , $subject) {
|
||||
return preg_match($pattern, $subject);
|
||||
}
|
||||
);
|
||||
$this->expression->register(
|
||||
'ADVISOR_bytime',
|
||||
function (){},
|
||||
function ($arguments, $num, $precision) {
|
||||
return self::byTime($num, $precision);
|
||||
}
|
||||
);
|
||||
$this->expression->register(
|
||||
'ADVISOR_timespanFormat',
|
||||
function (){},
|
||||
function ($arguments, $seconds) {
|
||||
return self::timespanFormat($seconds);
|
||||
}
|
||||
);
|
||||
$this->expression->register(
|
||||
'ADVISOR_formatByteDown',
|
||||
function (){},
|
||||
function ($arguments, $value, $limes = 6, $comma = 0) {
|
||||
return self::formatByteDown($value, $limes, $comma);
|
||||
}
|
||||
);
|
||||
$this->expression->register(
|
||||
'fired',
|
||||
function (){},
|
||||
function ($arguments, $value) {
|
||||
if (!isset($this->runResult['fired'])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Did matching rule fire?
|
||||
foreach ($this->runResult['fired'] as $rule) {
|
||||
if ($rule['id'] == $value) {
|
||||
return '1';
|
||||
}
|
||||
}
|
||||
|
||||
return '0';
|
||||
}
|
||||
);
|
||||
/* Some global variables for advisor */
|
||||
$this->globals = array(
|
||||
'PMA_MYSQL_INT_VERSION' => $this->dbi->getVersion(),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get variables
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getVariables()
|
||||
{
|
||||
return $this->variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set variables
|
||||
*
|
||||
* @param array $variables Variables
|
||||
*
|
||||
* @return Advisor
|
||||
*/
|
||||
public function setVariables(array $variables)
|
||||
{
|
||||
$this->variables = $variables;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a variable and its value
|
||||
*
|
||||
* @param string|int $variable Variable to set
|
||||
* @param mixed $value Value to set
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setVariable($variable, $value)
|
||||
{
|
||||
$this->variables[$variable] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parseResult
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParseResult()
|
||||
{
|
||||
return $this->parseResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set parseResult
|
||||
*
|
||||
* @param array $parseResult Parse result
|
||||
*
|
||||
* @return Advisor
|
||||
*/
|
||||
public function setParseResult(array $parseResult)
|
||||
{
|
||||
$this->parseResult = $parseResult;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get runResult
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRunResult()
|
||||
{
|
||||
return $this->runResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set runResult
|
||||
*
|
||||
* @param array $runResult Run result
|
||||
*
|
||||
* @return Advisor
|
||||
*/
|
||||
public function setRunResult(array $runResult)
|
||||
{
|
||||
$this->runResult = $runResult;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and executes advisor rules
|
||||
*
|
||||
* @return array with run and parse results
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// HowTo: A simple Advisory system in 3 easy steps.
|
||||
|
||||
// Step 1: Get some variables to evaluate on
|
||||
$this->setVariables(
|
||||
array_merge(
|
||||
$this->dbi->fetchResult('SHOW GLOBAL STATUS', 0, 1),
|
||||
$this->dbi->fetchResult('SHOW GLOBAL VARIABLES', 0, 1)
|
||||
)
|
||||
);
|
||||
|
||||
// Add total memory to variables as well
|
||||
$sysinfo = SysInfo::get();
|
||||
$memory = $sysinfo->memory();
|
||||
$this->variables['system_memory']
|
||||
= isset($memory['MemTotal']) ? $memory['MemTotal'] : 0;
|
||||
|
||||
$ruleFiles = $this->defineRulesFiles();
|
||||
|
||||
// Step 2: Read and parse the list of rules
|
||||
$parsedResults = [];
|
||||
foreach ($ruleFiles as $ruleFile) {
|
||||
$parsedResults[] = $this->parseRulesFile($ruleFile);
|
||||
}
|
||||
$this->setParseResult(call_user_func_array('array_merge_recursive', $parsedResults));
|
||||
|
||||
// Step 3: Feed the variables to the rules and let them fire. Sets
|
||||
// $runResult
|
||||
$this->runRules();
|
||||
|
||||
return array(
|
||||
'parse' => array('errors' => $this->parseResult['errors']),
|
||||
'run' => $this->runResult
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores current error in run results.
|
||||
*
|
||||
* @param string $description description of an error.
|
||||
* @param Exception $exception exception raised
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function storeError($description, $exception)
|
||||
{
|
||||
$this->runResult['errors'][] = $description
|
||||
. ' '
|
||||
. sprintf(
|
||||
__('Error when evaluating: %s'),
|
||||
$exception->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes advisor rules
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function runRules()
|
||||
{
|
||||
$this->setRunResult(
|
||||
array(
|
||||
'fired' => array(),
|
||||
'notfired' => array(),
|
||||
'unchecked' => array(),
|
||||
'errors' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
foreach ($this->parseResult['rules'] as $rule) {
|
||||
$this->variables['value'] = 0;
|
||||
$precond = true;
|
||||
|
||||
if (isset($rule['precondition'])) {
|
||||
try {
|
||||
$precond = $this->ruleExprEvaluate($rule['precondition']);
|
||||
} catch (Exception $e) {
|
||||
$this->storeError(
|
||||
sprintf(
|
||||
__('Failed evaluating precondition for rule \'%s\'.'),
|
||||
$rule['name']
|
||||
),
|
||||
$e
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $precond) {
|
||||
$this->addRule('unchecked', $rule);
|
||||
} else {
|
||||
try {
|
||||
$value = $this->ruleExprEvaluate($rule['formula']);
|
||||
} catch (Exception $e) {
|
||||
$this->storeError(
|
||||
sprintf(
|
||||
__('Failed calculating value for rule \'%s\'.'),
|
||||
$rule['name']
|
||||
),
|
||||
$e
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->variables['value'] = $value;
|
||||
|
||||
try {
|
||||
if ($this->ruleExprEvaluate($rule['test'])) {
|
||||
$this->addRule('fired', $rule);
|
||||
} else {
|
||||
$this->addRule('notfired', $rule);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->storeError(
|
||||
sprintf(
|
||||
__('Failed running test for rule \'%s\'.'),
|
||||
$rule['name']
|
||||
),
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes percent string to be used in format string.
|
||||
*
|
||||
* @param string $str string to escape
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function escapePercent($str)
|
||||
{
|
||||
return preg_replace('/%( |,|\.|$|\(|\)|<|>)/', '%%\1', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function for translating.
|
||||
*
|
||||
* @param string $str the string
|
||||
* @param string $param the parameters
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function translate($str, $param = null)
|
||||
{
|
||||
$string = _gettext(self::escapePercent($str));
|
||||
if (! is_null($param)) {
|
||||
$params = $this->ruleExprEvaluate('[' . $param . ']');
|
||||
} else {
|
||||
$params = array();
|
||||
}
|
||||
return vsprintf($string, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits justification to text and formula.
|
||||
*
|
||||
* @param array $rule the rule
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function splitJustification(array $rule)
|
||||
{
|
||||
$jst = preg_split('/\s*\|\s*/', $rule['justification'], 2);
|
||||
if (count($jst) > 1) {
|
||||
return array($jst[0], $jst[1]);
|
||||
}
|
||||
return array($rule['justification']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a rule to the result list
|
||||
*
|
||||
* @param string $type type of rule
|
||||
* @param array $rule rule itself
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addRule($type, array $rule)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'notfired':
|
||||
case 'fired':
|
||||
$jst = self::splitJustification($rule);
|
||||
if (count($jst) > 1) {
|
||||
try {
|
||||
/* Translate */
|
||||
$str = $this->translate($jst[0], $jst[1]);
|
||||
} catch (Exception $e) {
|
||||
$this->storeError(
|
||||
sprintf(
|
||||
__('Failed formatting string for rule \'%s\'.'),
|
||||
$rule['name']
|
||||
),
|
||||
$e
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$rule['justification'] = $str;
|
||||
} else {
|
||||
$rule['justification'] = $this->translate($rule['justification']);
|
||||
}
|
||||
$rule['id'] = $rule['name'];
|
||||
$rule['name'] = $this->translate($rule['name']);
|
||||
$rule['issue'] = $this->translate($rule['issue']);
|
||||
|
||||
// Replaces {server_variable} with 'server_variable'
|
||||
// linking to server_variables.php
|
||||
$rule['recommendation'] = preg_replace_callback(
|
||||
'/\{([a-z_0-9]+)\}/Ui',
|
||||
array($this, 'replaceVariable'),
|
||||
$this->translate($rule['recommendation'])
|
||||
);
|
||||
|
||||
// Replaces external Links with Core::linkURL() generated links
|
||||
$rule['recommendation'] = preg_replace_callback(
|
||||
'#href=("|\')(https?://[^\1]+)\1#i',
|
||||
array($this, 'replaceLinkURL'),
|
||||
$rule['recommendation']
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->runResult[$type][] = $rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the rules files to use
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function defineRulesFiles()
|
||||
{
|
||||
$isMariaDB = false !== strpos($this->getVariables()['version'], 'MariaDB');
|
||||
$ruleFiles = [self::GENERIC_RULES_FILE];
|
||||
// If MariaDB (= not MySQL) OR MYSQL < 8.0.3, add another rules file.
|
||||
if ($isMariaDB || $this->globals['PMA_MYSQL_INT_VERSION'] < 80003) {
|
||||
$ruleFiles[] = self::BEFORE_MYSQL80003_RULES_FILE;
|
||||
}
|
||||
return $ruleFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for wrapping links with Core::linkURL
|
||||
*
|
||||
* @param array $matches List of matched elements form preg_replace_callback
|
||||
*
|
||||
* @return string Replacement value
|
||||
*/
|
||||
private function replaceLinkURL(array $matches)
|
||||
{
|
||||
return 'href="' . Core::linkURL($matches[2]) . '" target="_blank" rel="noopener noreferrer"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for wrapping variable edit links
|
||||
*
|
||||
* @param array $matches List of matched elements form preg_replace_callback
|
||||
*
|
||||
* @return string Replacement value
|
||||
*/
|
||||
private function replaceVariable(array $matches)
|
||||
{
|
||||
return '<a href="server_variables.php' . Url::getCommon(array('filter' => $matches[1]))
|
||||
. '">' . htmlspecialchars($matches[1]) . '</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a code expression, replacing variable names with their respective
|
||||
* values
|
||||
*
|
||||
* @param string $expr expression to evaluate
|
||||
*
|
||||
* @return integer result of evaluated expression
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function ruleExprEvaluate($expr)
|
||||
{
|
||||
// Actually evaluate the code
|
||||
// This can throw exception
|
||||
$value = $this->expression->evaluate(
|
||||
$expr,
|
||||
array_merge($this->variables, $this->globals)
|
||||
);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the rule file into an array, throwing errors messages on syntax
|
||||
* errors.
|
||||
*
|
||||
* @param string $filename Name of file to parse
|
||||
*
|
||||
* @return array with parsed data
|
||||
*/
|
||||
public static function parseRulesFile($filename)
|
||||
{
|
||||
$file = file($filename, FILE_IGNORE_NEW_LINES);
|
||||
|
||||
$errors = array();
|
||||
$rules = array();
|
||||
$lines = array();
|
||||
|
||||
if ($file === false) {
|
||||
$errors[] = sprintf(
|
||||
__('Error in reading file: The file \'%s\' does not exist or is not readable!'),
|
||||
$filename
|
||||
);
|
||||
return array('rules' => $rules, 'lines' => $lines, 'errors' => $errors);
|
||||
}
|
||||
|
||||
$ruleSyntax = array(
|
||||
'name', 'formula', 'test', 'issue', 'recommendation', 'justification'
|
||||
);
|
||||
$numRules = count($ruleSyntax);
|
||||
$numLines = count($file);
|
||||
$ruleNo = -1;
|
||||
$ruleLine = -1;
|
||||
|
||||
for ($i = 0; $i < $numLines; $i++) {
|
||||
$line = $file[$i];
|
||||
if ($line == "" || $line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Reading new rule
|
||||
if (substr($line, 0, 4) == 'rule') {
|
||||
if ($ruleLine > 0) {
|
||||
$errors[] = sprintf(
|
||||
__(
|
||||
'Invalid rule declaration on line %1$s, expected line '
|
||||
. '%2$s of previous rule.'
|
||||
),
|
||||
$i + 1,
|
||||
$ruleSyntax[$ruleLine++]
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (preg_match("/rule\s'(.*)'( \[(.*)\])?$/", $line, $match)) {
|
||||
$ruleLine = 1;
|
||||
$ruleNo++;
|
||||
$rules[$ruleNo] = array('name' => $match[1]);
|
||||
$lines[$ruleNo] = array('name' => $i + 1);
|
||||
if (isset($match[3])) {
|
||||
$rules[$ruleNo]['precondition'] = $match[3];
|
||||
$lines[$ruleNo]['precondition'] = $i + 1;
|
||||
}
|
||||
} else {
|
||||
$errors[] = sprintf(
|
||||
__('Invalid rule declaration on line %s.'),
|
||||
$i + 1
|
||||
);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
if ($ruleLine == -1) {
|
||||
$errors[] = sprintf(
|
||||
__('Unexpected characters on line %s.'),
|
||||
$i + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Reading rule lines
|
||||
if ($ruleLine > 0) {
|
||||
if (!isset($line[0])) {
|
||||
continue; // Empty lines are ok
|
||||
}
|
||||
// Non tabbed lines are not
|
||||
if ($line[0] != "\t") {
|
||||
$errors[] = sprintf(
|
||||
__(
|
||||
'Unexpected character on line %1$s. Expected tab, but '
|
||||
. 'found "%2$s".'
|
||||
),
|
||||
$i + 1,
|
||||
$line[0]
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$rules[$ruleNo][$ruleSyntax[$ruleLine]] = chop(
|
||||
mb_substr($line, 1)
|
||||
);
|
||||
$lines[$ruleNo][$ruleSyntax[$ruleLine]] = $i + 1;
|
||||
++$ruleLine;
|
||||
}
|
||||
|
||||
// Rule complete
|
||||
if ($ruleLine == $numRules) {
|
||||
$ruleLine = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return array('rules' => $rules, 'lines' => $lines, 'errors' => $errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats interval like 10 per hour
|
||||
*
|
||||
* @param integer $num number to format
|
||||
* @param integer $precision required precision
|
||||
*
|
||||
* @return string formatted string
|
||||
*/
|
||||
public static function byTime($num, $precision)
|
||||
{
|
||||
if ($num >= 1) { // per second
|
||||
$per = __('per second');
|
||||
} elseif ($num * 60 >= 1) { // per minute
|
||||
$num = $num * 60;
|
||||
$per = __('per minute');
|
||||
} elseif ($num * 60 * 60 >= 1 ) { // per hour
|
||||
$num = $num * 60 * 60;
|
||||
$per = __('per hour');
|
||||
} else {
|
||||
$num = $num * 60 * 60 * 24;
|
||||
$per = __('per day');
|
||||
}
|
||||
|
||||
$num = round($num, $precision);
|
||||
|
||||
if ($num == 0) {
|
||||
$num = '<' . pow(10, -$precision);
|
||||
}
|
||||
|
||||
return "$num $per";
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for PhpMyAdmin\Util::timespanFormat
|
||||
*
|
||||
* This function is used when evaluating advisory_rules.txt
|
||||
*
|
||||
* @param int $seconds the timespan
|
||||
*
|
||||
* @return string the formatted value
|
||||
*/
|
||||
public static function timespanFormat($seconds)
|
||||
{
|
||||
return Util::timespanFormat($seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around PhpMyAdmin\Util::formatByteDown
|
||||
*
|
||||
* This function is used when evaluating advisory_rules.txt
|
||||
*
|
||||
* @param double $value the value to format
|
||||
* @param int $limes the sensitiveness
|
||||
* @param int $comma the number of decimals to retain
|
||||
*
|
||||
* @return string the formatted value with unit
|
||||
*/
|
||||
public static function formatByteDown($value, $limes = 6, $comma = 0)
|
||||
{
|
||||
return implode(' ', Util::formatByteDown($value, $limes, $comma));
|
||||
}
|
||||
}
|
||||
383
phpMyAdmin/libraries/classes/Bookmark.php
Executable file
383
phpMyAdmin/libraries/classes/Bookmark.php
Executable file
@@ -0,0 +1,383 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Handles bookmarking SQL queries
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Relation;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Handles bookmarking SQL queries
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class Bookmark
|
||||
{
|
||||
/**
|
||||
* ID of the bookmark
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_id;
|
||||
/**
|
||||
* Database the bookmark belongs to
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_database;
|
||||
/**
|
||||
* The user to whom the bookmark belongs, empty for public bookmarks
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_user;
|
||||
/**
|
||||
* Label of the bookmark
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_label;
|
||||
/**
|
||||
* SQL query that is bookmarked
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_query;
|
||||
|
||||
/**
|
||||
* @var DatabaseInterface
|
||||
*/
|
||||
private $dbi;
|
||||
|
||||
/**
|
||||
* Current user
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $user;
|
||||
|
||||
public function __construct(DatabaseInterface $dbi, $user)
|
||||
{
|
||||
$this->dbi = $dbi;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the bookmark
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the database of the bookmark
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDatabase()
|
||||
{
|
||||
return $this->_database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user whom the bookmark belongs to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label of the bookmark
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLabel()
|
||||
{
|
||||
return $this->_label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->_query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a bookmark
|
||||
*
|
||||
* @return boolean whether the INSERT succeeds or not
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$cfgBookmark = self::getParams($this->user);
|
||||
if (empty($cfgBookmark)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = "INSERT INTO " . Util::backquote($cfgBookmark['db'])
|
||||
. "." . Util::backquote($cfgBookmark['table'])
|
||||
. " (id, dbase, user, query, label) VALUES (NULL, "
|
||||
. "'" . $this->dbi->escapeString($this->_database) . "', "
|
||||
. "'" . $this->dbi->escapeString($this->_user) . "', "
|
||||
. "'" . $this->dbi->escapeString($this->_query) . "', "
|
||||
. "'" . $this->dbi->escapeString($this->_label) . "')";
|
||||
return $this->dbi->query($query, DatabaseInterface::CONNECT_CONTROL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a bookmark
|
||||
*
|
||||
* @return bool true if successful
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
$cfgBookmark = self::getParams($this->user);
|
||||
if (empty($cfgBookmark)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = "DELETE FROM " . Util::backquote($cfgBookmark['db'])
|
||||
. "." . Util::backquote($cfgBookmark['table'])
|
||||
. " WHERE id = " . $this->_id;
|
||||
return $this->dbi->tryQuery($query, DatabaseInterface::CONNECT_CONTROL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of variables in a bookmark
|
||||
*
|
||||
* @return number number of variables
|
||||
*/
|
||||
public function getVariableCount()
|
||||
{
|
||||
$matches = array();
|
||||
preg_match_all("/\[VARIABLE[0-9]*\]/", $this->_query, $matches, PREG_SET_ORDER);
|
||||
return count($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the placeholders in the bookmark query with variables
|
||||
*
|
||||
* @param array $variables array of variables
|
||||
*
|
||||
* @return string query with variables applied
|
||||
*/
|
||||
public function applyVariables(array $variables)
|
||||
{
|
||||
// remove comments that encloses a variable placeholder
|
||||
$query = preg_replace(
|
||||
'|/\*(.*\[VARIABLE[0-9]*\].*)\*/|imsU',
|
||||
'${1}',
|
||||
$this->_query
|
||||
);
|
||||
// replace variable placeholders with values
|
||||
$number_of_variables = $this->getVariableCount();
|
||||
for ($i = 1; $i <= $number_of_variables; $i++) {
|
||||
$var = '';
|
||||
if (! empty($variables[$i])) {
|
||||
$var = $this->dbi->escapeString($variables[$i]);
|
||||
}
|
||||
$query = str_replace('[VARIABLE' . $i . ']', $var, $query);
|
||||
// backward compatibility
|
||||
if ($i == 1) {
|
||||
$query = str_replace('[VARIABLE]', $var, $query);
|
||||
}
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the bookmark parameters for the current user
|
||||
*
|
||||
* @param string $user Current user
|
||||
* @return array the bookmark parameters for the current user
|
||||
* @access public
|
||||
*/
|
||||
public static function getParams($user)
|
||||
{
|
||||
static $cfgBookmark = null;
|
||||
|
||||
if (null !== $cfgBookmark) {
|
||||
return $cfgBookmark;
|
||||
}
|
||||
|
||||
$relation = new Relation();
|
||||
$cfgRelation = $relation->getRelationsParam();
|
||||
if ($cfgRelation['bookmarkwork']) {
|
||||
$cfgBookmark = array(
|
||||
'user' => $user,
|
||||
'db' => $cfgRelation['db'],
|
||||
'table' => $cfgRelation['bookmark'],
|
||||
);
|
||||
} else {
|
||||
$cfgBookmark = false;
|
||||
}
|
||||
|
||||
return $cfgBookmark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Bookmark object from the parameters
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface object
|
||||
* @param string $user Current user
|
||||
* @param array $bkm_fields the properties of the bookmark to add; here,
|
||||
* $bkm_fields['bkm_sql_query'] is urlencoded
|
||||
* @param boolean $all_users whether to make the bookmark
|
||||
* available for all users
|
||||
*
|
||||
* @return Bookmark|false
|
||||
*/
|
||||
public static function createBookmark(
|
||||
DatabaseInterface $dbi,
|
||||
$user,
|
||||
array $bkm_fields,
|
||||
$all_users = false
|
||||
) {
|
||||
if (!(isset($bkm_fields['bkm_sql_query'])
|
||||
&& strlen($bkm_fields['bkm_sql_query']) > 0
|
||||
&& isset($bkm_fields['bkm_label'])
|
||||
&& strlen($bkm_fields['bkm_label']) > 0)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$bookmark = new Bookmark($dbi, $user);
|
||||
$bookmark->_database = $bkm_fields['bkm_database'];
|
||||
$bookmark->_label = $bkm_fields['bkm_label'];
|
||||
$bookmark->_query = $bkm_fields['bkm_sql_query'];
|
||||
$bookmark->_user = $all_users ? '' : $bkm_fields['bkm_user'];
|
||||
|
||||
return $bookmark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of bookmarks defined for the current database
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface object
|
||||
* @param string $user Current user
|
||||
* @param string|bool $db the current database name or false
|
||||
*
|
||||
* @return Bookmark[] the bookmarks list
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function getList(DatabaseInterface $dbi, $user, $db = false)
|
||||
{
|
||||
$cfgBookmark = self::getParams($user);
|
||||
if (empty($cfgBookmark)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$query = "SELECT * FROM " . Util::backquote($cfgBookmark['db'])
|
||||
. "." . Util::backquote($cfgBookmark['table'])
|
||||
. " WHERE ( `user` = ''"
|
||||
. " OR `user` = '" . $dbi->escapeString($cfgBookmark['user']) . "' )";
|
||||
if ($db !== false) {
|
||||
$query .= " AND dbase = '" . $dbi->escapeString($db) . "'";
|
||||
}
|
||||
$query .= " ORDER BY label ASC";
|
||||
|
||||
$result = $dbi->fetchResult(
|
||||
$query,
|
||||
null,
|
||||
null,
|
||||
DatabaseInterface::CONNECT_CONTROL,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
|
||||
if (! empty($result)) {
|
||||
$bookmarks = array();
|
||||
foreach ($result as $row) {
|
||||
$bookmark = new Bookmark($dbi, $user);
|
||||
$bookmark->_id = $row['id'];
|
||||
$bookmark->_database = $row['dbase'];
|
||||
$bookmark->_user = $row['user'];
|
||||
$bookmark->_label = $row['label'];
|
||||
$bookmark->_query = $row['query'];
|
||||
$bookmarks[] = $bookmark;
|
||||
}
|
||||
|
||||
return $bookmarks;
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a specific bookmark
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface object
|
||||
* @param string $user Current user
|
||||
* @param string $db the current database name
|
||||
* @param mixed $id an identifier of the bookmark to get
|
||||
* @param string $id_field which field to look up the identifier
|
||||
* @param boolean $action_bookmark_all true: get all bookmarks regardless
|
||||
* of the owning user
|
||||
* @param boolean $exact_user_match whether to ignore bookmarks with no user
|
||||
*
|
||||
* @return Bookmark the bookmark
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
*/
|
||||
public static function get(
|
||||
DatabaseInterface $dbi,
|
||||
$user,
|
||||
$db,
|
||||
$id,
|
||||
$id_field = 'id',
|
||||
$action_bookmark_all = false,
|
||||
$exact_user_match = false
|
||||
) {
|
||||
$cfgBookmark = self::getParams($user);
|
||||
if (empty($cfgBookmark)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$query = "SELECT * FROM " . Util::backquote($cfgBookmark['db'])
|
||||
. "." . Util::backquote($cfgBookmark['table'])
|
||||
. " WHERE dbase = '" . $dbi->escapeString($db) . "'";
|
||||
if (! $action_bookmark_all) {
|
||||
$query .= " AND (user = '"
|
||||
. $dbi->escapeString($cfgBookmark['user']) . "'";
|
||||
if (! $exact_user_match) {
|
||||
$query .= " OR user = ''";
|
||||
}
|
||||
$query .= ")";
|
||||
}
|
||||
$query .= " AND " . Util::backquote($id_field)
|
||||
. " = '" . $dbi->escapeString($id) . "' LIMIT 1";
|
||||
|
||||
$result = $dbi->fetchSingleRow($query, 'ASSOC', DatabaseInterface::CONNECT_CONTROL);
|
||||
if (! empty($result)) {
|
||||
$bookmark = new Bookmark($dbi, $user);
|
||||
$bookmark->_id = $result['id'];
|
||||
$bookmark->_database = $result['dbase'];
|
||||
$bookmark->_user = $result['user'];
|
||||
$bookmark->_label = $result['label'];
|
||||
$bookmark->_query = $result['query'];
|
||||
return $bookmark;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
346
phpMyAdmin/libraries/classes/BrowseForeigners.php
Executable file
346
phpMyAdmin/libraries/classes/BrowseForeigners.php
Executable file
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Contains functions used by browse_foreigners.php
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* PhpMyAdmin\BrowseForeigners class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class BrowseForeigners
|
||||
{
|
||||
private $limitChars;
|
||||
private $maxRows;
|
||||
private $repeatCells;
|
||||
private $showAll;
|
||||
private $themeImage;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $limitChars Maximum number of characters to show
|
||||
* @param int $maxRows Number of rows to display
|
||||
* @param int $repeatCells Repeat the headers every X cells, or 0 to deactivate
|
||||
* @param boolean $showAll Shows the 'Show all' button or not
|
||||
* @param string $themeImage Theme image path
|
||||
*/
|
||||
public function __construct(
|
||||
$limitChars,
|
||||
$maxRows,
|
||||
$repeatCells,
|
||||
$showAll,
|
||||
$themeImage
|
||||
) {
|
||||
$this->limitChars = (int) $limitChars;
|
||||
$this->maxRows = (int) $maxRows;
|
||||
$this->repeatCells = (int) $repeatCells;
|
||||
$this->showAll = (bool) $showAll;
|
||||
$this->themeImage = $themeImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get html for one relational key
|
||||
*
|
||||
* @param integer $horizontal_count the current horizontal count
|
||||
* @param string $header table header
|
||||
* @param array $keys all the keys
|
||||
* @param integer $indexByKeyname index by keyname
|
||||
* @param array $descriptions descriptions
|
||||
* @param integer $indexByDescription index by description
|
||||
* @param string $current_value current value on the edit form
|
||||
*
|
||||
* @return string $html the generated html
|
||||
*/
|
||||
private function getHtmlForOneKey(
|
||||
$horizontal_count,
|
||||
$header,
|
||||
array $keys,
|
||||
$indexByKeyname,
|
||||
array $descriptions,
|
||||
$indexByDescription,
|
||||
$current_value
|
||||
) {
|
||||
$horizontal_count++;
|
||||
$output = '';
|
||||
|
||||
// whether the key name corresponds to the selected value in the form
|
||||
$rightKeynameIsSelected = false;
|
||||
$leftKeynameIsSelected = false;
|
||||
|
||||
if ($this->repeatCells > 0 && $horizontal_count > $this->repeatCells) {
|
||||
$output .= $header;
|
||||
$horizontal_count = 0;
|
||||
}
|
||||
|
||||
// key names and descriptions for the left section,
|
||||
// sorted by key names
|
||||
$leftKeyname = $keys[$indexByKeyname];
|
||||
list(
|
||||
$leftDescription,
|
||||
$leftDescriptionTitle
|
||||
) = $this->getDescriptionAndTitle($descriptions[$indexByKeyname]);
|
||||
|
||||
// key names and descriptions for the right section,
|
||||
// sorted by descriptions
|
||||
$rightKeyname = $keys[$indexByDescription];
|
||||
list(
|
||||
$rightDescription,
|
||||
$rightDescriptionTitle
|
||||
) = $this->getDescriptionAndTitle($descriptions[$indexByDescription]);
|
||||
|
||||
$indexByDescription++;
|
||||
|
||||
if (! empty($current_value)) {
|
||||
$rightKeynameIsSelected = $rightKeyname == $current_value;
|
||||
$leftKeynameIsSelected = $leftKeyname == $current_value;
|
||||
}
|
||||
|
||||
$output .= '<tr class="noclick">';
|
||||
|
||||
$output .= Template::get('table/browse_foreigners/column_element')->render([
|
||||
'keyname' => $leftKeyname,
|
||||
'description' => $leftDescription,
|
||||
'title' => $leftDescriptionTitle,
|
||||
'is_selected' => $leftKeynameIsSelected,
|
||||
'nowrap' => true,
|
||||
]);
|
||||
$output .= Template::get('table/browse_foreigners/column_element')->render([
|
||||
'keyname' => $leftKeyname,
|
||||
'description' => $leftDescription,
|
||||
'title' => $leftDescriptionTitle,
|
||||
'is_selected' => $leftKeynameIsSelected,
|
||||
'nowrap' => false,
|
||||
]);
|
||||
|
||||
$output .= '<td width="20%">'
|
||||
. '<img src="' . $this->themeImage . 'spacer.png" alt=""'
|
||||
. ' width="1" height="1" /></td>';
|
||||
|
||||
$output .= Template::get('table/browse_foreigners/column_element')->render([
|
||||
'keyname' => $rightKeyname,
|
||||
'description' => $rightDescription,
|
||||
'title' => $rightDescriptionTitle,
|
||||
'is_selected' => $rightKeynameIsSelected,
|
||||
'nowrap' => false,
|
||||
]);
|
||||
$output .= Template::get('table/browse_foreigners/column_element')->render([
|
||||
'keyname' => $rightKeyname,
|
||||
'description' => $rightDescription,
|
||||
'title' => $rightDescriptionTitle,
|
||||
'is_selected' => $rightKeynameIsSelected,
|
||||
'nowrap' => true,
|
||||
]);
|
||||
|
||||
$output .= '</tr>';
|
||||
|
||||
return array($output, $horizontal_count, $indexByDescription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get html for relational field selection
|
||||
*
|
||||
* @param string $db current database
|
||||
* @param string $table current table
|
||||
* @param string $field field
|
||||
* @param array $foreignData foreign column data
|
||||
* @param string $fieldkey field key
|
||||
* @param string $current_value current columns's value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHtmlForRelationalFieldSelection(
|
||||
$db,
|
||||
$table,
|
||||
$field,
|
||||
array $foreignData,
|
||||
$fieldkey,
|
||||
$current_value
|
||||
) {
|
||||
$gotopage = $this->getHtmlForGotoPage($foreignData);
|
||||
$foreignShowAll = Template::get('table/browse_foreigners/show_all')->render([
|
||||
'foreign_data' => $foreignData,
|
||||
'show_all' => $this->showAll,
|
||||
'max_rows' => $this->maxRows,
|
||||
]);
|
||||
|
||||
$output = '<form class="ajax" '
|
||||
. 'id="browse_foreign_form" name="browse_foreign_from" '
|
||||
. 'action="browse_foreigners.php" method="post">'
|
||||
. '<fieldset>'
|
||||
. Url::getHiddenInputs($db, $table)
|
||||
. '<input type="hidden" name="field" value="' . htmlspecialchars($field)
|
||||
. '" />'
|
||||
. '<input type="hidden" name="fieldkey" value="'
|
||||
. (isset($fieldkey) ? htmlspecialchars($fieldkey) : '') . '" />';
|
||||
|
||||
if (isset($_POST['rownumber'])) {
|
||||
$output .= '<input type="hidden" name="rownumber" value="'
|
||||
. htmlspecialchars($_POST['rownumber']) . '" />';
|
||||
}
|
||||
$filter_value = (isset($_POST['foreign_filter'])
|
||||
? htmlspecialchars($_POST['foreign_filter'])
|
||||
: '');
|
||||
$output .= '<span class="formelement">'
|
||||
. '<label for="input_foreign_filter">' . __('Search:') . '</label>'
|
||||
. '<input type="text" name="foreign_filter" '
|
||||
. 'id="input_foreign_filter" '
|
||||
. 'value="' . $filter_value . '" data-old="' . $filter_value . '" '
|
||||
. '/>'
|
||||
. '<input type="submit" name="submit_foreign_filter" value="'
|
||||
. __('Go') . '" />'
|
||||
. '</span>'
|
||||
. '<span class="formelement">' . $gotopage . '</span>'
|
||||
. '<span class="formelement">' . $foreignShowAll . '</span>'
|
||||
. '</fieldset>'
|
||||
. '</form>';
|
||||
|
||||
$output .= '<table width="100%" id="browse_foreign_table">';
|
||||
|
||||
if (!is_array($foreignData['disp_row'])) {
|
||||
$output .= '</tbody>'
|
||||
. '</table>';
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
$header = '<tr>
|
||||
<th>' . __('Keyname') . '</th>
|
||||
<th>' . __('Description') . '</th>
|
||||
<td width="20%"></td>
|
||||
<th>' . __('Description') . '</th>
|
||||
<th>' . __('Keyname') . '</th>
|
||||
</tr>';
|
||||
|
||||
$output .= '<thead>' . $header . '</thead>' . "\n"
|
||||
. '<tfoot>' . $header . '</tfoot>' . "\n"
|
||||
. '<tbody>' . "\n";
|
||||
|
||||
$descriptions = array();
|
||||
$keys = array();
|
||||
foreach ($foreignData['disp_row'] as $relrow) {
|
||||
if ($foreignData['foreign_display'] != false) {
|
||||
$descriptions[] = $relrow[$foreignData['foreign_display']];
|
||||
} else {
|
||||
$descriptions[] = '';
|
||||
}
|
||||
|
||||
$keys[] = $relrow[$foreignData['foreign_field']];
|
||||
}
|
||||
|
||||
asort($keys);
|
||||
|
||||
$horizontal_count = 0;
|
||||
$indexByDescription = 0;
|
||||
|
||||
foreach ($keys as $indexByKeyname => $value) {
|
||||
list(
|
||||
$html,
|
||||
$horizontal_count,
|
||||
$indexByDescription
|
||||
) = $this->getHtmlForOneKey(
|
||||
$horizontal_count,
|
||||
$header,
|
||||
$keys,
|
||||
$indexByKeyname,
|
||||
$descriptions,
|
||||
$indexByDescription,
|
||||
$current_value
|
||||
);
|
||||
$output .= $html;
|
||||
}
|
||||
|
||||
$output .= '</tbody>'
|
||||
. '</table>';
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the description (possibly truncated) and the title
|
||||
*
|
||||
* @param string $description the key name's description
|
||||
*
|
||||
* @return array the new description and title
|
||||
*/
|
||||
private function getDescriptionAndTitle($description)
|
||||
{
|
||||
if (mb_strlen($description) <= $this->limitChars) {
|
||||
$description = htmlspecialchars(
|
||||
$description
|
||||
);
|
||||
$descriptionTitle = '';
|
||||
} else {
|
||||
$descriptionTitle = htmlspecialchars(
|
||||
$description
|
||||
);
|
||||
$description = htmlspecialchars(
|
||||
mb_substr(
|
||||
$description, 0, $this->limitChars
|
||||
)
|
||||
. '...'
|
||||
);
|
||||
}
|
||||
return array($description, $descriptionTitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get html for the goto page option
|
||||
*
|
||||
* @param array|null $foreignData foreign data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForGotoPage($foreignData)
|
||||
{
|
||||
$gotopage = '';
|
||||
isset($_POST['pos']) ? $pos = $_POST['pos'] : $pos = 0;
|
||||
if ($foreignData === null || ! is_array($foreignData['disp_row'])) {
|
||||
return $gotopage;
|
||||
}
|
||||
|
||||
$pageNow = @floor($pos / $this->maxRows) + 1;
|
||||
$nbTotalPage = @ceil($foreignData['the_total'] / $this->maxRows);
|
||||
|
||||
if ($foreignData['the_total'] > $this->maxRows) {
|
||||
$gotopage = Util::pageselector(
|
||||
'pos',
|
||||
$this->maxRows,
|
||||
$pageNow,
|
||||
$nbTotalPage,
|
||||
200,
|
||||
5,
|
||||
5,
|
||||
20,
|
||||
10,
|
||||
__('Page number:')
|
||||
);
|
||||
}
|
||||
|
||||
return $gotopage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get foreign limit
|
||||
*
|
||||
* @param string $foreignShowAll foreign navigation
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getForeignLimit($foreignShowAll)
|
||||
{
|
||||
if (isset($foreignShowAll) && $foreignShowAll == __('Show all')) {
|
||||
return null;
|
||||
}
|
||||
isset($_POST['pos']) ? $pos = $_POST['pos'] : $pos = 0;
|
||||
return 'LIMIT ' . $pos . ', ' . $this->maxRows . ' ';
|
||||
}
|
||||
}
|
||||
1453
phpMyAdmin/libraries/classes/CentralColumns.php
Executable file
1453
phpMyAdmin/libraries/classes/CentralColumns.php
Executable file
File diff suppressed because it is too large
Load Diff
704
phpMyAdmin/libraries/classes/Charsets.php
Executable file
704
phpMyAdmin/libraries/classes/Charsets.php
Executable file
@@ -0,0 +1,704 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* MySQL charset metadata and manipulations
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Class used to manage MySQL charsets
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class Charsets
|
||||
{
|
||||
/**
|
||||
* MySQL charsets map
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $mysql_charset_map = array(
|
||||
'big5' => 'big5',
|
||||
'cp-866' => 'cp866',
|
||||
'euc-jp' => 'ujis',
|
||||
'euc-kr' => 'euckr',
|
||||
'gb2312' => 'gb2312',
|
||||
'gbk' => 'gbk',
|
||||
'iso-8859-1' => 'latin1',
|
||||
'iso-8859-2' => 'latin2',
|
||||
'iso-8859-7' => 'greek',
|
||||
'iso-8859-8' => 'hebrew',
|
||||
'iso-8859-8-i' => 'hebrew',
|
||||
'iso-8859-9' => 'latin5',
|
||||
'iso-8859-13' => 'latin7',
|
||||
'iso-8859-15' => 'latin1',
|
||||
'koi8-r' => 'koi8r',
|
||||
'shift_jis' => 'sjis',
|
||||
'tis-620' => 'tis620',
|
||||
'utf-8' => 'utf8',
|
||||
'windows-1250' => 'cp1250',
|
||||
'windows-1251' => 'cp1251',
|
||||
'windows-1252' => 'latin1',
|
||||
'windows-1256' => 'cp1256',
|
||||
'windows-1257' => 'cp1257',
|
||||
);
|
||||
|
||||
private static $_charsets = array();
|
||||
|
||||
/**
|
||||
* The charset for the server
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $_charset_server;
|
||||
|
||||
private static $_charsets_descriptions = array();
|
||||
private static $_collations = array();
|
||||
private static $_default_collations = array();
|
||||
|
||||
/**
|
||||
* Loads charset data from the MySQL server.
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function loadCharsets(DatabaseInterface $dbi, $disableIs)
|
||||
{
|
||||
/* Data already loaded */
|
||||
if (count(self::$_charsets) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($disableIs) {
|
||||
$sql = 'SHOW CHARACTER SET';
|
||||
} else {
|
||||
$sql = 'SELECT `CHARACTER_SET_NAME` AS `Charset`,'
|
||||
. ' `DESCRIPTION` AS `Description`'
|
||||
. ' FROM `information_schema`.`CHARACTER_SETS`';
|
||||
}
|
||||
$res = $dbi->query($sql);
|
||||
|
||||
self::$_charsets = array();
|
||||
while ($row = $dbi->fetchAssoc($res)) {
|
||||
$name = $row['Charset'];
|
||||
self::$_charsets[] = $name;
|
||||
self::$_charsets_descriptions[$name] = $row['Description'];
|
||||
}
|
||||
$dbi->freeResult($res);
|
||||
|
||||
sort(self::$_charsets, SORT_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads collation data from the MySQL server.
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function loadCollations(DatabaseInterface $dbi, $disableIs)
|
||||
{
|
||||
/* Data already loaded */
|
||||
if (count(self::$_collations) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($disableIs) {
|
||||
$sql = 'SHOW COLLATION';
|
||||
} else {
|
||||
$sql = 'SELECT `CHARACTER_SET_NAME` AS `Charset`,'
|
||||
. ' `COLLATION_NAME` AS `Collation`, `IS_DEFAULT` AS `Default`'
|
||||
. ' FROM `information_schema`.`COLLATIONS`';
|
||||
}
|
||||
|
||||
$res = $dbi->query($sql);
|
||||
while ($row = $dbi->fetchAssoc($res)) {
|
||||
$char_set_name = $row['Charset'];
|
||||
$name = $row['Collation'];
|
||||
self::$_collations[$char_set_name][] = $name;
|
||||
if ($row['Default'] == 'Yes' || $row['Default'] == '1') {
|
||||
self::$_default_collations[$char_set_name] = $name;
|
||||
}
|
||||
}
|
||||
$dbi->freeResult($res);
|
||||
|
||||
foreach (self::$_collations as $key => $value) {
|
||||
sort(self::$_collations[$key], SORT_STRING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current MySQL server charset.
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getServerCharset(DatabaseInterface $dbi)
|
||||
{
|
||||
if (self::$_charset_server) {
|
||||
return self::$_charset_server;
|
||||
} else {
|
||||
$charsetServer = $dbi->getVariable('character_set_server');
|
||||
if (! is_string($charsetServer)) {// MySQL 5.7.8 fallback, issue #15614
|
||||
$charsetServer = $dbi->fetchValue("SELECT @@character_set_server;");
|
||||
}
|
||||
self::$_charset_server = $charsetServer;
|
||||
return self::$_charset_server;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MySQL charsets
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getMySQLCharsets(DatabaseInterface $dbi, $disableIs)
|
||||
{
|
||||
self::loadCharsets($dbi, $disableIs);
|
||||
return self::$_charsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MySQL charsets descriptions
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getMySQLCharsetsDescriptions(DatabaseInterface $dbi, $disableIs)
|
||||
{
|
||||
self::loadCharsets($dbi, $disableIs);
|
||||
return self::$_charsets_descriptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MySQL collations
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getMySQLCollations(DatabaseInterface $dbi, $disableIs)
|
||||
{
|
||||
self::loadCollations($dbi, $disableIs);
|
||||
return self::$_collations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MySQL default collations
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getMySQLCollationsDefault(DatabaseInterface $dbi, $disableIs)
|
||||
{
|
||||
self::loadCollations($dbi, $disableIs);
|
||||
return self::$_default_collations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate charset dropdown box
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
* @param string $name Element name
|
||||
* @param string $id Element id
|
||||
* @param null|string $default Default value
|
||||
* @param bool $label Label
|
||||
* @param bool $submitOnChange Submit on change
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getCharsetDropdownBox(
|
||||
DatabaseInterface $dbi,
|
||||
$disableIs,
|
||||
$name = null,
|
||||
$id = null,
|
||||
$default = null,
|
||||
$label = true,
|
||||
$submitOnChange = false
|
||||
) {
|
||||
self::loadCharsets($dbi, $disableIs);
|
||||
if (empty($name)) {
|
||||
$name = 'character_set';
|
||||
}
|
||||
|
||||
$return_str = '<select lang="en" dir="ltr" name="'
|
||||
. htmlspecialchars($name) . '"'
|
||||
. (empty($id) ? '' : ' id="' . htmlspecialchars($id) . '"')
|
||||
. ($submitOnChange ? ' class="autosubmit"' : '') . '>' . "\n";
|
||||
if ($label) {
|
||||
$return_str .= '<option value="">'
|
||||
. __('Charset')
|
||||
. '</option>' . "\n";
|
||||
}
|
||||
$return_str .= '<option value=""></option>' . "\n";
|
||||
foreach (self::$_charsets as $current_charset) {
|
||||
$current_cs_descr
|
||||
= empty(self::$_charsets_descriptions[$current_charset])
|
||||
? $current_charset
|
||||
: self::$_charsets_descriptions[$current_charset];
|
||||
|
||||
$return_str .= '<option value="' . $current_charset
|
||||
. '" title="' . $current_cs_descr . '"'
|
||||
. ($default == $current_charset ? ' selected="selected"' : '') . '>'
|
||||
. $current_charset . '</option>' . "\n";
|
||||
}
|
||||
$return_str .= '</select>' . "\n";
|
||||
|
||||
return $return_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate collation dropdown box
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
* @param string $name Element name
|
||||
* @param string $id Element id
|
||||
* @param null|string $default Default value
|
||||
* @param bool $label Label
|
||||
* @param bool $submitOnChange Submit on change
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getCollationDropdownBox(
|
||||
DatabaseInterface $dbi,
|
||||
$disableIs,
|
||||
$name = null,
|
||||
$id = null,
|
||||
$default = null,
|
||||
$label = true,
|
||||
$submitOnChange = false
|
||||
) {
|
||||
self::loadCharsets($dbi, $disableIs);
|
||||
self::loadCollations($dbi, $disableIs);
|
||||
if (empty($name)) {
|
||||
$name = 'collation';
|
||||
}
|
||||
|
||||
$return_str = '<select lang="en" dir="ltr" name="'
|
||||
. htmlspecialchars($name) . '"'
|
||||
. (empty($id) ? '' : ' id="' . htmlspecialchars($id) . '"')
|
||||
. ($submitOnChange ? ' class="autosubmit"' : '') . '>' . "\n";
|
||||
if ($label) {
|
||||
$return_str .= '<option value="">'
|
||||
. __('Collation')
|
||||
. '</option>' . "\n";
|
||||
}
|
||||
$return_str .= '<option value=""></option>' . "\n";
|
||||
foreach (self::$_charsets as $current_charset) {
|
||||
$current_cs_descr
|
||||
= empty(self::$_charsets_descriptions[$current_charset])
|
||||
? $current_charset
|
||||
: self::$_charsets_descriptions[$current_charset];
|
||||
|
||||
$return_str .= '<optgroup label="' . $current_charset
|
||||
. '" title="' . $current_cs_descr . '">' . "\n";
|
||||
foreach (self::$_collations[$current_charset] as $current_collation) {
|
||||
$return_str .= '<option value="' . $current_collation
|
||||
. '" title="' . self::getCollationDescr($current_collation) . '"'
|
||||
. ($default == $current_collation ? ' selected="selected"' : '')
|
||||
. '>'
|
||||
. $current_collation . '</option>' . "\n";
|
||||
}
|
||||
$return_str .= '</optgroup>' . "\n";
|
||||
}
|
||||
$return_str .= '</select>' . "\n";
|
||||
|
||||
return $return_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description for given collation
|
||||
*
|
||||
* @param string $collation MySQL collation string
|
||||
*
|
||||
* @return string collation description
|
||||
*/
|
||||
public static function getCollationDescr($collation)
|
||||
{
|
||||
$parts = explode('_', $collation);
|
||||
|
||||
$name = __('Unknown');
|
||||
$variant = null;
|
||||
$suffixes = array();
|
||||
$unicode = false;
|
||||
$unknown = false;
|
||||
|
||||
$level = 0;
|
||||
foreach ($parts as $part) {
|
||||
if ($level == 0) {
|
||||
/* Next will be language */
|
||||
$level = 1;
|
||||
/* First should be charset */
|
||||
switch ($part) {
|
||||
case 'binary':
|
||||
$name = _pgettext('Collation', 'Binary');
|
||||
break;
|
||||
// Unicode charsets
|
||||
case 'utf8mb4':
|
||||
$variant = 'UCA 4.0.0';
|
||||
// Fall through to other unicode
|
||||
case 'ucs2':
|
||||
case 'utf8':
|
||||
case 'utf16':
|
||||
case 'utf16le':
|
||||
case 'utf16be':
|
||||
case 'utf32':
|
||||
$name = _pgettext('Collation', 'Unicode');
|
||||
$unicode = true;
|
||||
break;
|
||||
// West European charsets
|
||||
case 'ascii':
|
||||
case 'cp850':
|
||||
case 'dec8':
|
||||
case 'hp8':
|
||||
case 'latin1':
|
||||
case 'macroman':
|
||||
$name = _pgettext('Collation', 'West European');
|
||||
break;
|
||||
// Central European charsets
|
||||
case 'cp1250':
|
||||
case 'cp852':
|
||||
case 'latin2':
|
||||
case 'macce':
|
||||
$name = _pgettext('Collation', 'Central European');
|
||||
break;
|
||||
// Russian charsets
|
||||
case 'cp866':
|
||||
case 'koi8r':
|
||||
$name = _pgettext('Collation', 'Russian');
|
||||
break;
|
||||
// Chinese charsets
|
||||
case 'gb2312':
|
||||
case 'gbk':
|
||||
$name = _pgettext('Collation', 'Simplified Chinese');
|
||||
break;
|
||||
case 'big5':
|
||||
$name = _pgettext('Collation', 'Traditional Chinese');
|
||||
break;
|
||||
case 'gb18030':
|
||||
$name = _pgettext('Collation', 'Chinese');
|
||||
$unicode = true;
|
||||
break;
|
||||
// Japanese charsets
|
||||
case 'sjis':
|
||||
case 'ujis':
|
||||
case 'cp932':
|
||||
case 'eucjpms':
|
||||
$name = _pgettext('Collation', 'Japanese');
|
||||
break;
|
||||
// Baltic charsets
|
||||
case 'cp1257':
|
||||
case 'latin7':
|
||||
$name = _pgettext('Collation', 'Baltic');
|
||||
break;
|
||||
// Other
|
||||
case 'armscii8':
|
||||
case 'armscii':
|
||||
$name = _pgettext('Collation', 'Armenian');
|
||||
break;
|
||||
case 'cp1251':
|
||||
$name = _pgettext('Collation', 'Cyrillic');
|
||||
break;
|
||||
case 'cp1256':
|
||||
$name = _pgettext('Collation', 'Arabic');
|
||||
break;
|
||||
case 'euckr':
|
||||
$name = _pgettext('Collation', 'Korean');
|
||||
break;
|
||||
case 'hebrew':
|
||||
$name = _pgettext('Collation', 'Hebrew');
|
||||
break;
|
||||
case 'geostd8':
|
||||
$name = _pgettext('Collation', 'Georgian');
|
||||
break;
|
||||
case 'greek':
|
||||
$name = _pgettext('Collation', 'Greek');
|
||||
break;
|
||||
case 'keybcs2':
|
||||
$name = _pgettext('Collation', 'Czech-Slovak');
|
||||
break;
|
||||
case 'koi8u':
|
||||
$name = _pgettext('Collation', 'Ukrainian');
|
||||
break;
|
||||
case 'latin5':
|
||||
$name = _pgettext('Collation', 'Turkish');
|
||||
break;
|
||||
case 'swe7':
|
||||
$name = _pgettext('Collation', 'Swedish');
|
||||
break;
|
||||
case 'tis620':
|
||||
$name = _pgettext('Collation', 'Thai');
|
||||
break;
|
||||
default:
|
||||
$name = _pgettext('Collation', 'Unknown');
|
||||
$unknown = true;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($level == 1) {
|
||||
/* Next will be variant unless changed later */
|
||||
$level = 4;
|
||||
/* Locale name or code */
|
||||
$found = true;
|
||||
switch ($part) {
|
||||
case 'general':
|
||||
break;
|
||||
case 'bulgarian':
|
||||
case 'bg':
|
||||
$name = _pgettext('Collation', 'Bulgarian');
|
||||
break;
|
||||
case 'chinese':
|
||||
case 'cn':
|
||||
case 'zh':
|
||||
if ($unicode) {
|
||||
$name = _pgettext('Collation', 'Chinese');
|
||||
}
|
||||
break;
|
||||
case 'croatian':
|
||||
case 'hr':
|
||||
$name = _pgettext('Collation', 'Croatian');
|
||||
break;
|
||||
case 'czech':
|
||||
case 'cs':
|
||||
$name = _pgettext('Collation', 'Czech');
|
||||
break;
|
||||
case 'danish':
|
||||
case 'da':
|
||||
$name = _pgettext('Collation', 'Danish');
|
||||
break;
|
||||
case 'english':
|
||||
case 'en':
|
||||
$name = _pgettext('Collation', 'English');
|
||||
break;
|
||||
case 'esperanto':
|
||||
case 'eo':
|
||||
$name = _pgettext('Collation', 'Esperanto');
|
||||
break;
|
||||
case 'estonian':
|
||||
case 'et':
|
||||
$name = _pgettext('Collation', 'Estonian');
|
||||
break;
|
||||
case 'german1':
|
||||
$name = _pgettext('Collation', 'German (dictionary order)');
|
||||
break;
|
||||
case 'german2':
|
||||
$name = _pgettext('Collation', 'German (phone book order)');
|
||||
break;
|
||||
case 'german':
|
||||
case 'de':
|
||||
/* Name is set later */
|
||||
$level = 2;
|
||||
break;
|
||||
case 'hungarian':
|
||||
case 'hu':
|
||||
$name = _pgettext('Collation', 'Hungarian');
|
||||
break;
|
||||
case 'icelandic':
|
||||
case 'is':
|
||||
$name = _pgettext('Collation', 'Icelandic');
|
||||
break;
|
||||
case 'japanese':
|
||||
case 'ja':
|
||||
$name = _pgettext('Collation', 'Japanese');
|
||||
break;
|
||||
case 'la':
|
||||
$name = _pgettext('Collation', 'Classical Latin');
|
||||
break;
|
||||
case 'latvian':
|
||||
case 'lv':
|
||||
$name = _pgettext('Collation', 'Latvian');
|
||||
break;
|
||||
case 'lithuanian':
|
||||
case 'lt':
|
||||
$name = _pgettext('Collation', 'Lithuanian');
|
||||
break;
|
||||
case 'korean':
|
||||
case 'ko':
|
||||
$name = _pgettext('Collation', 'Korean');
|
||||
break;
|
||||
case 'myanmar':
|
||||
case 'my':
|
||||
$name = _pgettext('Collation', 'Burmese');
|
||||
break;
|
||||
case 'persian':
|
||||
$name = _pgettext('Collation', 'Persian');
|
||||
break;
|
||||
case 'polish':
|
||||
case 'pl':
|
||||
$name = _pgettext('Collation', 'Polish');
|
||||
break;
|
||||
case 'roman':
|
||||
$name = _pgettext('Collation', 'West European');
|
||||
break;
|
||||
case 'romanian':
|
||||
case 'ro':
|
||||
$name = _pgettext('Collation', 'Romanian');
|
||||
break;
|
||||
case 'ru':
|
||||
$name = _pgettext('Collation', 'Russian');
|
||||
break;
|
||||
case 'si':
|
||||
case 'sinhala':
|
||||
$name = _pgettext('Collation', 'Sinhalese');
|
||||
break;
|
||||
case 'slovak':
|
||||
case 'sk':
|
||||
$name = _pgettext('Collation', 'Slovak');
|
||||
break;
|
||||
case 'slovenian':
|
||||
case 'sl':
|
||||
$name = _pgettext('Collation', 'Slovenian');
|
||||
break;
|
||||
case 'spanish':
|
||||
$name = _pgettext('Collation', 'Spanish (modern)');
|
||||
break;
|
||||
case 'es':
|
||||
/* Name is set later */
|
||||
$level = 3;
|
||||
break;
|
||||
case 'spanish2':
|
||||
$name = _pgettext('Collation', 'Spanish (traditional)');
|
||||
break;
|
||||
case 'swedish':
|
||||
case 'sv':
|
||||
$name = _pgettext('Collation', 'Swedish');
|
||||
break;
|
||||
case 'thai':
|
||||
case 'th':
|
||||
$name = _pgettext('Collation', 'Thai');
|
||||
break;
|
||||
case 'turkish':
|
||||
case 'tr':
|
||||
$name = _pgettext('Collation', 'Turkish');
|
||||
break;
|
||||
case 'ukrainian':
|
||||
case 'uk':
|
||||
$name = _pgettext('Collation', 'Ukrainian');
|
||||
break;
|
||||
case 'vietnamese':
|
||||
case 'vi':
|
||||
$name = _pgettext('Collation', 'Vietnamese');
|
||||
break;
|
||||
case 'unicode':
|
||||
if ($unknown) {
|
||||
$name = _pgettext('Collation', 'Unicode');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$found = false;
|
||||
}
|
||||
if ($found) {
|
||||
continue;
|
||||
}
|
||||
// Not parsed token, fall to next level
|
||||
}
|
||||
if ($level == 2) {
|
||||
/* Next will be variant */
|
||||
$level = 4;
|
||||
/* Germal variant */
|
||||
if ($part == 'pb') {
|
||||
$name = _pgettext('Collation', 'German (phone book order)');
|
||||
continue;
|
||||
}
|
||||
$name = _pgettext('Collation', 'German (dictionary order)');
|
||||
// Not parsed token, fall to next level
|
||||
}
|
||||
if ($level == 3) {
|
||||
/* Next will be variant */
|
||||
$level = 4;
|
||||
/* Spanish variant */
|
||||
if ($part == 'trad') {
|
||||
$name = _pgettext('Collation', 'Spanish (traditional)');
|
||||
continue;
|
||||
}
|
||||
$name = _pgettext('Collation', 'Spanish (modern)');
|
||||
// Not parsed token, fall to next level
|
||||
}
|
||||
if ($level == 4) {
|
||||
/* Next will be suffix */
|
||||
$level = 5;
|
||||
/* Variant */
|
||||
$found = true;
|
||||
switch ($part) {
|
||||
case '0900':
|
||||
$variant = 'UCA 9.0.0';
|
||||
break;
|
||||
case '520':
|
||||
$variant = 'UCA 5.2.0';
|
||||
break;
|
||||
case 'mysql561':
|
||||
$variant = 'MySQL 5.6.1';
|
||||
break;
|
||||
case 'mysql500':
|
||||
$variant = 'MySQL 5.0.0';
|
||||
break;
|
||||
default:
|
||||
$found = false;
|
||||
}
|
||||
if ($found) {
|
||||
continue;
|
||||
}
|
||||
// Not parsed token, fall to next level
|
||||
}
|
||||
if ($level == 5) {
|
||||
/* Suffixes */
|
||||
switch ($part) {
|
||||
case 'ci':
|
||||
$suffixes[] = _pgettext('Collation variant', 'case-insensitive');
|
||||
break;
|
||||
case 'cs':
|
||||
$suffixes[] = _pgettext('Collation variant', 'case-sensitive');
|
||||
break;
|
||||
case 'ai':
|
||||
$suffixes[] = _pgettext('Collation variant', 'accent-insensitive');
|
||||
break;
|
||||
case 'as':
|
||||
$suffixes[] = _pgettext('Collation variant', 'accent-sensitive');
|
||||
break;
|
||||
case 'ks':
|
||||
$suffixes[] = _pgettext('Collation variant', 'kana-sensitive');
|
||||
break;
|
||||
case 'w2':
|
||||
case 'l2':
|
||||
$suffixes[] = _pgettext('Collation variant', 'multi-level');
|
||||
break;
|
||||
case 'bin':
|
||||
$suffixes[] = _pgettext('Collation variant', 'binary');
|
||||
break;
|
||||
case 'nopad':
|
||||
$suffixes[] = _pgettext('Collation variant', 'no-pad');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result = $name;
|
||||
if (! is_null($variant)) {
|
||||
$result .= ' (' . $variant . ')';
|
||||
}
|
||||
if (count($suffixes) > 0) {
|
||||
$result .= ', ' . implode(', ', $suffixes);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
338
phpMyAdmin/libraries/classes/CheckUserPrivileges.php
Executable file
338
phpMyAdmin/libraries/classes/CheckUserPrivileges.php
Executable file
@@ -0,0 +1,338 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Get user's global privileges and some db-specific privileges
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* PhpMyAdmin\CheckUserPrivileges class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class CheckUserPrivileges
|
||||
{
|
||||
/**
|
||||
* @var DatabaseInterface
|
||||
*/
|
||||
private $dbi;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface object
|
||||
*/
|
||||
public function __construct(DatabaseInterface $dbi)
|
||||
{
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts details from a result row of a SHOW GRANT query
|
||||
*
|
||||
* @param string $row grant row
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getItemsFromShowGrantsRow($row)
|
||||
{
|
||||
$db_name_offset = mb_strpos($row, ' ON ') + 4;
|
||||
|
||||
$tblname_end_offset = mb_strpos($row, ' TO ');
|
||||
$tblname_start_offset = false;
|
||||
|
||||
if ($__tblname_start_offset = mb_strpos($row, '`.', $db_name_offset)) {
|
||||
if ($__tblname_start_offset < $tblname_end_offset) {
|
||||
$tblname_start_offset = $__tblname_start_offset + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$tblname_start_offset) {
|
||||
$tblname_start_offset = mb_strpos($row, '.', $db_name_offset);
|
||||
}
|
||||
|
||||
$show_grants_dbname = mb_substr(
|
||||
$row,
|
||||
$db_name_offset,
|
||||
$tblname_start_offset - $db_name_offset
|
||||
);
|
||||
|
||||
$show_grants_dbname = Util::unQuote($show_grants_dbname, '`');
|
||||
|
||||
$show_grants_str = mb_substr(
|
||||
$row,
|
||||
6,
|
||||
(mb_strpos($row, ' ON ') - 6)
|
||||
);
|
||||
|
||||
$show_grants_tblname = mb_substr(
|
||||
$row,
|
||||
$tblname_start_offset + 1,
|
||||
$tblname_end_offset - $tblname_start_offset - 1
|
||||
);
|
||||
$show_grants_tblname = Util::unQuote($show_grants_tblname, '`');
|
||||
|
||||
return array(
|
||||
$show_grants_str,
|
||||
$show_grants_dbname,
|
||||
$show_grants_tblname
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user has required privileges for
|
||||
* performing 'Adjust privileges' operations
|
||||
*
|
||||
* @param string $show_grants_str string containing grants for user
|
||||
* @param string $show_grants_dbname name of db extracted from grant string
|
||||
* @param string $show_grants_tblname name of table extracted from grant string
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function checkRequiredPrivilegesForAdjust(
|
||||
$show_grants_str,
|
||||
$show_grants_dbname,
|
||||
$show_grants_tblname
|
||||
) {
|
||||
// '... ALL PRIVILEGES ON *.* ...' OR '... ALL PRIVILEGES ON `mysql`.* ..'
|
||||
// OR
|
||||
// SELECT, INSERT, UPDATE, DELETE .... ON *.* OR `mysql`.*
|
||||
if ($show_grants_str == 'ALL'
|
||||
|| $show_grants_str == 'ALL PRIVILEGES'
|
||||
|| (mb_strpos(
|
||||
$show_grants_str, 'SELECT, INSERT, UPDATE, DELETE'
|
||||
) !== false)
|
||||
) {
|
||||
if ($show_grants_dbname == '*'
|
||||
&& $show_grants_tblname == '*'
|
||||
) {
|
||||
$GLOBALS['col_priv'] = true;
|
||||
$GLOBALS['db_priv'] = true;
|
||||
$GLOBALS['proc_priv'] = true;
|
||||
$GLOBALS['table_priv'] = true;
|
||||
|
||||
if ($show_grants_str == 'ALL PRIVILEGES'
|
||||
|| $show_grants_str == 'ALL'
|
||||
) {
|
||||
$GLOBALS['is_reload_priv'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// check for specific tables in `mysql` db
|
||||
// Ex. '... ALL PRIVILEGES on `mysql`.`columns_priv` .. '
|
||||
if ($show_grants_dbname == 'mysql') {
|
||||
switch ($show_grants_tblname) {
|
||||
case "columns_priv":
|
||||
$GLOBALS['col_priv'] = true;
|
||||
break;
|
||||
case "db":
|
||||
$GLOBALS['db_priv'] = true;
|
||||
break;
|
||||
case "procs_priv":
|
||||
$GLOBALS['proc_priv'] = true;
|
||||
break;
|
||||
case "tables_priv":
|
||||
$GLOBALS['table_priv'] = true;
|
||||
break;
|
||||
case "*":
|
||||
$GLOBALS['col_priv'] = true;
|
||||
$GLOBALS['db_priv'] = true;
|
||||
$GLOBALS['proc_priv'] = true;
|
||||
$GLOBALS['table_priv'] = true;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets privilege information extracted from SHOW GRANTS result
|
||||
*
|
||||
* Detection for some CREATE privilege.
|
||||
*
|
||||
* Since MySQL 4.1.2, we can easily detect current user's grants using $userlink
|
||||
* (no control user needed) and we don't have to try any other method for
|
||||
* detection
|
||||
*
|
||||
* @todo fix to get really all privileges, not only explicitly defined for this user
|
||||
* from MySQL manual: (https://dev.mysql.com/doc/refman/5.0/en/show-grants.html)
|
||||
* SHOW GRANTS displays only the privileges granted explicitly to the named
|
||||
* account. Other privileges might be available to the account, but they are not
|
||||
* displayed. For example, if an anonymous account exists, the named account
|
||||
* might be able to use its privileges, but SHOW GRANTS will not display them.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function analyseShowGrant()
|
||||
{
|
||||
if (Util::cacheExists('is_create_db_priv')) {
|
||||
$GLOBALS['is_create_db_priv'] = Util::cacheGet(
|
||||
'is_create_db_priv'
|
||||
);
|
||||
$GLOBALS['is_reload_priv'] = Util::cacheGet(
|
||||
'is_reload_priv'
|
||||
);
|
||||
$GLOBALS['db_to_create'] = Util::cacheGet(
|
||||
'db_to_create'
|
||||
);
|
||||
$GLOBALS['dbs_where_create_table_allowed'] = Util::cacheGet(
|
||||
'dbs_where_create_table_allowed'
|
||||
);
|
||||
$GLOBALS['dbs_to_test'] = Util::cacheGet(
|
||||
'dbs_to_test'
|
||||
);
|
||||
|
||||
$GLOBALS['db_priv'] = Util::cacheGet(
|
||||
'db_priv'
|
||||
);
|
||||
$GLOBALS['col_priv'] = Util::cacheGet(
|
||||
'col_priv'
|
||||
);
|
||||
$GLOBALS['table_priv'] = Util::cacheGet(
|
||||
'table_priv'
|
||||
);
|
||||
$GLOBALS['proc_priv'] = Util::cacheGet(
|
||||
'proc_priv'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// defaults
|
||||
$GLOBALS['is_create_db_priv'] = false;
|
||||
$GLOBALS['is_reload_priv'] = false;
|
||||
$GLOBALS['db_to_create'] = '';
|
||||
$GLOBALS['dbs_where_create_table_allowed'] = array();
|
||||
$GLOBALS['dbs_to_test'] = $this->dbi->getSystemSchemas();
|
||||
$GLOBALS['proc_priv'] = false;
|
||||
$GLOBALS['db_priv'] = false;
|
||||
$GLOBALS['col_priv'] = false;
|
||||
$GLOBALS['table_priv'] = false;
|
||||
|
||||
$rs_usr = $this->dbi->tryQuery('SHOW GRANTS');
|
||||
|
||||
if (! $rs_usr) {
|
||||
return;
|
||||
}
|
||||
|
||||
$re0 = '(^|(\\\\\\\\)+|[^\\\\])'; // non-escaped wildcards
|
||||
$re1 = '(^|[^\\\\])(\\\)+'; // escaped wildcards
|
||||
|
||||
while ($row = $this->dbi->fetchRow($rs_usr)) {
|
||||
list(
|
||||
$show_grants_str,
|
||||
$show_grants_dbname,
|
||||
$show_grants_tblname
|
||||
) = $this->getItemsFromShowGrantsRow($row[0]);
|
||||
|
||||
if ($show_grants_dbname == '*') {
|
||||
if ($show_grants_str != 'USAGE') {
|
||||
$GLOBALS['dbs_to_test'] = false;
|
||||
}
|
||||
} elseif ($GLOBALS['dbs_to_test'] !== false) {
|
||||
$GLOBALS['dbs_to_test'][] = $show_grants_dbname;
|
||||
}
|
||||
|
||||
if (
|
||||
mb_strpos($show_grants_str,'RELOAD') !== false
|
||||
) {
|
||||
$GLOBALS['is_reload_priv'] = true;
|
||||
}
|
||||
|
||||
// check for the required privileges for adjust
|
||||
$this->checkRequiredPrivilegesForAdjust(
|
||||
$show_grants_str,
|
||||
$show_grants_dbname,
|
||||
$show_grants_tblname
|
||||
);
|
||||
|
||||
/**
|
||||
* @todo if we find CREATE VIEW but not CREATE, do not offer
|
||||
* the create database dialog box
|
||||
*/
|
||||
if ($show_grants_str == 'ALL'
|
||||
|| $show_grants_str == 'ALL PRIVILEGES'
|
||||
|| $show_grants_str == 'CREATE'
|
||||
|| strpos($show_grants_str, 'CREATE,') !== false
|
||||
) {
|
||||
if ($show_grants_dbname == '*') {
|
||||
// a global CREATE privilege
|
||||
$GLOBALS['is_create_db_priv'] = true;
|
||||
$GLOBALS['is_reload_priv'] = true;
|
||||
$GLOBALS['db_to_create'] = '';
|
||||
$GLOBALS['dbs_where_create_table_allowed'][] = '*';
|
||||
// @todo we should not break here, cause GRANT ALL *.*
|
||||
// could be revoked by a later rule like GRANT SELECT ON db.*
|
||||
break;
|
||||
} else {
|
||||
// this array may contain wildcards
|
||||
$GLOBALS['dbs_where_create_table_allowed'][] = $show_grants_dbname;
|
||||
|
||||
$dbname_to_test = Util::backquote($show_grants_dbname);
|
||||
|
||||
if ($GLOBALS['is_create_db_priv']) {
|
||||
// no need for any more tests if we already know this
|
||||
continue;
|
||||
}
|
||||
|
||||
// does this db exist?
|
||||
if ((preg_match('/' . $re0 . '%|_/', $show_grants_dbname)
|
||||
&& ! preg_match('/\\\\%|\\\\_/', $show_grants_dbname))
|
||||
|| (! $this->dbi->tryQuery(
|
||||
'USE ' . preg_replace(
|
||||
'/' . $re1 . '(%|_)/', '\\1\\3', $dbname_to_test
|
||||
)
|
||||
)
|
||||
&& mb_substr($this->dbi->getError(), 1, 4) != 1044)
|
||||
) {
|
||||
/**
|
||||
* Do not handle the underscore wildcard
|
||||
* (this case must be rare anyway)
|
||||
*/
|
||||
$GLOBALS['db_to_create'] = preg_replace(
|
||||
'/' . $re0 . '%/', '\\1',
|
||||
$show_grants_dbname
|
||||
);
|
||||
$GLOBALS['db_to_create'] = preg_replace(
|
||||
'/' . $re1 . '(%|_)/', '\\1\\3',
|
||||
$GLOBALS['db_to_create']
|
||||
);
|
||||
$GLOBALS['is_create_db_priv'] = true;
|
||||
|
||||
/**
|
||||
* @todo collect $GLOBALS['db_to_create'] into an array,
|
||||
* to display a drop-down in the "Create database" dialog
|
||||
*/
|
||||
// we don't break, we want all possible databases
|
||||
//break;
|
||||
} // end if
|
||||
} // end elseif
|
||||
} // end if
|
||||
|
||||
} // end while
|
||||
|
||||
$this->dbi->freeResult($rs_usr);
|
||||
|
||||
// must also cacheUnset() them in
|
||||
// PhpMyAdmin\Plugins\Auth\AuthenticationCookie
|
||||
Util::cacheSet('is_create_db_priv', $GLOBALS['is_create_db_priv']);
|
||||
Util::cacheSet('is_reload_priv', $GLOBALS['is_reload_priv']);
|
||||
Util::cacheSet('db_to_create', $GLOBALS['db_to_create']);
|
||||
Util::cacheSet(
|
||||
'dbs_where_create_table_allowed',
|
||||
$GLOBALS['dbs_where_create_table_allowed']
|
||||
);
|
||||
Util::cacheSet('dbs_to_test', $GLOBALS['dbs_to_test']);
|
||||
|
||||
Util::cacheSet('proc_priv', $GLOBALS['proc_priv']);
|
||||
Util::cacheSet('table_priv', $GLOBALS['table_priv']);
|
||||
Util::cacheSet('col_priv', $GLOBALS['col_priv']);
|
||||
Util::cacheSet('db_priv', $GLOBALS['db_priv']);
|
||||
} // end function
|
||||
}
|
||||
1896
phpMyAdmin/libraries/classes/Config.php
Executable file
1896
phpMyAdmin/libraries/classes/Config.php
Executable file
File diff suppressed because it is too large
Load Diff
531
phpMyAdmin/libraries/classes/Config/ConfigFile.php
Executable file
531
phpMyAdmin/libraries/classes/Config/ConfigFile.php
Executable file
@@ -0,0 +1,531 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Config file management
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Core;
|
||||
|
||||
/**
|
||||
* Config file management class.
|
||||
* Stores its data in $_SESSION
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class ConfigFile
|
||||
{
|
||||
/**
|
||||
* Stores default PMA config from config.default.php
|
||||
* @var array
|
||||
*/
|
||||
private $_defaultCfg;
|
||||
|
||||
/**
|
||||
* Stores allowed values for non-standard fields
|
||||
* @var array
|
||||
*/
|
||||
private $_cfgDb;
|
||||
|
||||
/**
|
||||
* Stores original PMA config, not modified by user preferences
|
||||
* @var Config
|
||||
*/
|
||||
private $_baseCfg;
|
||||
|
||||
/**
|
||||
* Whether we are currently working in PMA Setup context
|
||||
* @var bool
|
||||
*/
|
||||
private $_isInSetup;
|
||||
|
||||
/**
|
||||
* Keys which will be always written to config file
|
||||
* @var array
|
||||
*/
|
||||
private $_persistKeys = array();
|
||||
|
||||
/**
|
||||
* Changes keys while updating config in {@link updateWithGlobalConfig()}
|
||||
* or reading by {@link getConfig()} or {@link getConfigArray()}
|
||||
* @var array
|
||||
*/
|
||||
private $_cfgUpdateReadMapping = array();
|
||||
|
||||
/**
|
||||
* Key filter for {@link set()}
|
||||
* @var array|null
|
||||
*/
|
||||
private $_setFilter;
|
||||
|
||||
/**
|
||||
* Instance id (key in $_SESSION array, separate for each server -
|
||||
* ConfigFile{server id})
|
||||
* @var string
|
||||
*/
|
||||
private $_id;
|
||||
|
||||
/**
|
||||
* Result for {@link _flattenArray()}
|
||||
* @var array|null
|
||||
*/
|
||||
private $_flattenArrayResult;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array|null $base_config base configuration read from
|
||||
* {@link PhpMyAdmin\Config::$base_config},
|
||||
* use only when not in PMA Setup
|
||||
*/
|
||||
public function __construct($base_config = null)
|
||||
{
|
||||
// load default config values
|
||||
$cfg = &$this->_defaultCfg;
|
||||
include './libraries/config.default.php';
|
||||
$cfg['fontsize'] = '82%';
|
||||
|
||||
// load additional config information
|
||||
$cfg_db = &$this->_cfgDb;
|
||||
include './libraries/config.values.php';
|
||||
|
||||
// apply default values overrides
|
||||
if (count($cfg_db['_overrides'])) {
|
||||
foreach ($cfg_db['_overrides'] as $path => $value) {
|
||||
Core::arrayWrite($path, $cfg, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_baseCfg = $base_config;
|
||||
$this->_isInSetup = is_null($base_config);
|
||||
$this->_id = 'ConfigFile' . $GLOBALS['server'];
|
||||
if (!isset($_SESSION[$this->_id])) {
|
||||
$_SESSION[$this->_id] = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets names of config options which will be placed in config file even if
|
||||
* they are set to their default values (use only full paths)
|
||||
*
|
||||
* @param array $keys the names of the config options
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPersistKeys(array $keys)
|
||||
{
|
||||
// checking key presence is much faster than searching so move values
|
||||
// to keys
|
||||
$this->_persistKeys = array_flip($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns flipped array set by {@link setPersistKeys()}
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPersistKeysMap()
|
||||
{
|
||||
return $this->_persistKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default ConfigFile allows setting of all configuration keys, use
|
||||
* this method to set up a filter on {@link set()} method
|
||||
*
|
||||
* @param array|null $keys array of allowed keys or null to remove filter
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setAllowedKeys($keys)
|
||||
{
|
||||
if ($keys === null) {
|
||||
$this->_setFilter = null;
|
||||
return;
|
||||
}
|
||||
// checking key presence is much faster than searching so move values
|
||||
// to keys
|
||||
$this->_setFilter = array_flip($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets path mapping for updating config in
|
||||
* {@link updateWithGlobalConfig()} or reading
|
||||
* by {@link getConfig()} or {@link getConfigArray()}
|
||||
*
|
||||
* @param array $mapping Contains the mapping of "Server/config options"
|
||||
* to "Server/1/config options"
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setCfgUpdateReadMapping(array $mapping)
|
||||
{
|
||||
$this->_cfgUpdateReadMapping = $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets configuration data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetConfigData()
|
||||
{
|
||||
$_SESSION[$this->_id] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets configuration data (overrides old data)
|
||||
*
|
||||
* @param array $cfg Configuration options
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setConfigData(array $cfg)
|
||||
{
|
||||
$_SESSION[$this->_id] = $cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets config value
|
||||
*
|
||||
* @param string $path Path
|
||||
* @param mixed $value Value
|
||||
* @param string $canonical_path Canonical path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($path, $value, $canonical_path = null)
|
||||
{
|
||||
if ($canonical_path === null) {
|
||||
$canonical_path = $this->getCanonicalPath($path);
|
||||
}
|
||||
// apply key whitelist
|
||||
if ($this->_setFilter !== null
|
||||
&& ! isset($this->_setFilter[$canonical_path])
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// if the path isn't protected it may be removed
|
||||
if (isset($this->_persistKeys[$canonical_path])) {
|
||||
Core::arrayWrite($path, $_SESSION[$this->_id], $value);
|
||||
return;
|
||||
}
|
||||
|
||||
$default_value = $this->getDefault($canonical_path);
|
||||
$remove_path = $value === $default_value;
|
||||
if ($this->_isInSetup) {
|
||||
// remove if it has a default value or is empty
|
||||
$remove_path = $remove_path
|
||||
|| (empty($value) && empty($default_value));
|
||||
} else {
|
||||
// get original config values not overwritten by user
|
||||
// preferences to allow for overwriting options set in
|
||||
// config.inc.php with default values
|
||||
$instance_default_value = Core::arrayRead(
|
||||
$canonical_path,
|
||||
$this->_baseCfg
|
||||
);
|
||||
// remove if it has a default value and base config (config.inc.php)
|
||||
// uses default value
|
||||
$remove_path = $remove_path
|
||||
&& ($instance_default_value === $default_value);
|
||||
}
|
||||
if ($remove_path) {
|
||||
Core::arrayRemove($path, $_SESSION[$this->_id]);
|
||||
return;
|
||||
}
|
||||
|
||||
Core::arrayWrite($path, $_SESSION[$this->_id], $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens multidimensional array, changes indices to paths
|
||||
* (eg. 'key/subkey').
|
||||
* Used as array_walk() callback.
|
||||
*
|
||||
* @param mixed $value Value
|
||||
* @param mixed $key Key
|
||||
* @param mixed $prefix Prefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _flattenArray($value, $key, $prefix)
|
||||
{
|
||||
// no recursion for numeric arrays
|
||||
if (is_array($value) && !isset($value[0])) {
|
||||
$prefix .= $key . '/';
|
||||
array_walk($value, array($this, '_flattenArray'), $prefix);
|
||||
} else {
|
||||
$this->_flattenArrayResult[$prefix . $key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default config in a flattened array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFlatDefaultConfig()
|
||||
{
|
||||
$this->_flattenArrayResult = array();
|
||||
array_walk($this->_defaultCfg, array($this, '_flattenArray'), '');
|
||||
$flat_cfg = $this->_flattenArrayResult;
|
||||
$this->_flattenArrayResult = null;
|
||||
return $flat_cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates config with values read from given array
|
||||
* (config will contain differences to defaults from config.defaults.php).
|
||||
*
|
||||
* @param array $cfg Configuration
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateWithGlobalConfig(array $cfg)
|
||||
{
|
||||
// load config array and flatten it
|
||||
$this->_flattenArrayResult = array();
|
||||
array_walk($cfg, array($this, '_flattenArray'), '');
|
||||
$flat_cfg = $this->_flattenArrayResult;
|
||||
$this->_flattenArrayResult = null;
|
||||
|
||||
// save values map for translating a few user preferences paths,
|
||||
// should be complemented by code reading from generated config
|
||||
// to perform inverse mapping
|
||||
foreach ($flat_cfg as $path => $value) {
|
||||
if (isset($this->_cfgUpdateReadMapping[$path])) {
|
||||
$path = $this->_cfgUpdateReadMapping[$path];
|
||||
}
|
||||
$this->set($path, $value, $path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns config value or $default if it's not set
|
||||
*
|
||||
* @param string $path Path of config file
|
||||
* @param mixed $default Default values
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($path, $default = null)
|
||||
{
|
||||
return Core::arrayRead($path, $_SESSION[$this->_id], $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default config value or $default it it's not set ie. it doesn't
|
||||
* exist in config.default.php ($cfg) and config.values.php
|
||||
* ($_cfg_db['_overrides'])
|
||||
*
|
||||
* @param string $canonical_path Canonical path
|
||||
* @param mixed $default Default value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault($canonical_path, $default = null)
|
||||
{
|
||||
return Core::arrayRead($canonical_path, $this->_defaultCfg, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns config value, if it's not set uses the default one; returns
|
||||
* $default if the path isn't set and doesn't contain a default value
|
||||
*
|
||||
* @param string $path Path
|
||||
* @param mixed $default Default value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue($path, $default = null)
|
||||
{
|
||||
$v = Core::arrayRead($path, $_SESSION[$this->_id], null);
|
||||
if ($v !== null) {
|
||||
return $v;
|
||||
}
|
||||
$path = $this->getCanonicalPath($path);
|
||||
return $this->getDefault($path, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns canonical path
|
||||
*
|
||||
* @param string $path Path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCanonicalPath($path)
|
||||
{
|
||||
return preg_replace('#^Servers/([\d]+)/#', 'Servers/1/', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns config database entry for $path ($cfg_db in config_info.php)
|
||||
*
|
||||
* @param string $path path of the variable in config db
|
||||
* @param mixed $default default value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDbEntry($path, $default = null)
|
||||
{
|
||||
return Core::arrayRead($path, $this->_cfgDb, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns server count
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getServerCount()
|
||||
{
|
||||
return isset($_SESSION[$this->_id]['Servers'])
|
||||
? count($_SESSION[$this->_id]['Servers'])
|
||||
: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns server list
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getServers()
|
||||
{
|
||||
return isset($_SESSION[$this->_id]['Servers'])
|
||||
? $_SESSION[$this->_id]['Servers']
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns DSN of given server
|
||||
*
|
||||
* @param integer $server server index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getServerDSN($server)
|
||||
{
|
||||
if (!isset($_SESSION[$this->_id]['Servers'][$server])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$path = 'Servers/' . $server;
|
||||
$dsn = 'mysqli://';
|
||||
if ($this->getValue("$path/auth_type") == 'config') {
|
||||
$dsn .= $this->getValue("$path/user");
|
||||
if (! empty($this->getValue("$path/password"))) {
|
||||
$dsn .= ':***';
|
||||
}
|
||||
$dsn .= '@';
|
||||
}
|
||||
if ($this->getValue("$path/host") != 'localhost') {
|
||||
$dsn .= $this->getValue("$path/host");
|
||||
$port = $this->getValue("$path/port");
|
||||
if ($port) {
|
||||
$dsn .= ':' . $port;
|
||||
}
|
||||
} else {
|
||||
$dsn .= $this->getValue("$path/socket");
|
||||
}
|
||||
return $dsn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns server name
|
||||
*
|
||||
* @param int $id server index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getServerName($id)
|
||||
{
|
||||
if (!isset($_SESSION[$this->_id]['Servers'][$id])) {
|
||||
return '';
|
||||
}
|
||||
$verbose = $this->get("Servers/$id/verbose");
|
||||
if (!empty($verbose)) {
|
||||
return $verbose;
|
||||
}
|
||||
$host = $this->get("Servers/$id/host");
|
||||
return empty($host) ? 'localhost' : $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes server
|
||||
*
|
||||
* @param int $server server index
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function removeServer($server)
|
||||
{
|
||||
if (!isset($_SESSION[$this->_id]['Servers'][$server])) {
|
||||
return;
|
||||
}
|
||||
$last_server = $this->getServerCount();
|
||||
|
||||
for ($i = $server; $i < $last_server; $i++) {
|
||||
$_SESSION[$this->_id]['Servers'][$i]
|
||||
= $_SESSION[$this->_id]['Servers'][$i + 1];
|
||||
}
|
||||
unset($_SESSION[$this->_id]['Servers'][$last_server]);
|
||||
|
||||
if (isset($_SESSION[$this->_id]['ServerDefault'])
|
||||
&& $_SESSION[$this->_id]['ServerDefault'] == $last_server
|
||||
) {
|
||||
unset($_SESSION[$this->_id]['ServerDefault']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns configuration array (full, multidimensional format)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
$c = $_SESSION[$this->_id];
|
||||
foreach ($this->_cfgUpdateReadMapping as $map_to => $map_from) {
|
||||
// if the key $c exists in $map_to
|
||||
if (Core::arrayRead($map_to, $c) !== null) {
|
||||
Core::arrayWrite($map_to, $c, Core::arrayRead($map_from, $c));
|
||||
Core::arrayRemove($map_from, $c);
|
||||
}
|
||||
}
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns configuration array (flat format)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getConfigArray()
|
||||
{
|
||||
$this->_flattenArrayResult = array();
|
||||
array_walk($_SESSION[$this->_id], array($this, '_flattenArray'), '');
|
||||
$c = $this->_flattenArrayResult;
|
||||
$this->_flattenArrayResult = null;
|
||||
|
||||
$persistKeys = array_diff(
|
||||
array_keys($this->_persistKeys),
|
||||
array_keys($c)
|
||||
);
|
||||
foreach ($persistKeys as $k) {
|
||||
$c[$k] = $this->getDefault($this->getCanonicalPath($k));
|
||||
}
|
||||
|
||||
foreach ($this->_cfgUpdateReadMapping as $map_to => $map_from) {
|
||||
if (!isset($c[$map_from])) {
|
||||
continue;
|
||||
}
|
||||
$c[$map_to] = $c[$map_from];
|
||||
unset($c[$map_from]);
|
||||
}
|
||||
return $c;
|
||||
}
|
||||
}
|
||||
1493
phpMyAdmin/libraries/classes/Config/Descriptions.php
Executable file
1493
phpMyAdmin/libraries/classes/Config/Descriptions.php
Executable file
File diff suppressed because it is too large
Load Diff
233
phpMyAdmin/libraries/classes/Config/Form.php
Executable file
233
phpMyAdmin/libraries/classes/Config/Form.php
Executable file
@@ -0,0 +1,233 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Form handling code.
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
|
||||
/**
|
||||
* Base class for forms, loads default configuration options, checks allowed
|
||||
* values etc.
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class Form
|
||||
{
|
||||
/**
|
||||
* Form name
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Arbitrary index, doesn't affect class' behavior
|
||||
* @var int
|
||||
*/
|
||||
public $index;
|
||||
|
||||
/**
|
||||
* Form fields (paths), filled by {@link readFormPaths()}, indexed by field name
|
||||
* @var array
|
||||
*/
|
||||
public $fields;
|
||||
|
||||
/**
|
||||
* Stores default values for some fields (eg. pmadb tables)
|
||||
* @var array
|
||||
*/
|
||||
public $default;
|
||||
|
||||
/**
|
||||
* Caches field types, indexed by field names
|
||||
* @var array
|
||||
*/
|
||||
private $_fieldsTypes;
|
||||
|
||||
/**
|
||||
* ConfigFile instance
|
||||
* @var ConfigFile
|
||||
*/
|
||||
private $_configFile;
|
||||
|
||||
/**
|
||||
* Constructor, reads default config values
|
||||
*
|
||||
* @param string $form_name Form name
|
||||
* @param array $form Form data
|
||||
* @param ConfigFile $cf Config file instance
|
||||
* @param int $index arbitrary index, stored in Form::$index
|
||||
*/
|
||||
public function __construct(
|
||||
$form_name, array $form, ConfigFile $cf, $index = null
|
||||
) {
|
||||
$this->index = $index;
|
||||
$this->_configFile = $cf;
|
||||
$this->loadForm($form_name, $form);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns type of given option
|
||||
*
|
||||
* @param string $option_name path or field name
|
||||
*
|
||||
* @return string|null one of: boolean, integer, double, string, select, array
|
||||
*/
|
||||
public function getOptionType($option_name)
|
||||
{
|
||||
$key = ltrim(
|
||||
mb_substr(
|
||||
$option_name,
|
||||
mb_strrpos($option_name, '/')
|
||||
),
|
||||
'/'
|
||||
);
|
||||
return isset($this->_fieldsTypes[$key])
|
||||
? $this->_fieldsTypes[$key]
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns allowed values for select fields
|
||||
*
|
||||
* @param string $option_path Option path
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptionValueList($option_path)
|
||||
{
|
||||
$value = $this->_configFile->getDbEntry($option_path);
|
||||
if ($value === null) {
|
||||
trigger_error("$option_path - select options not defined", E_USER_ERROR);
|
||||
return array();
|
||||
}
|
||||
if (!is_array($value)) {
|
||||
trigger_error("$option_path - not a static value list", E_USER_ERROR);
|
||||
return array();
|
||||
}
|
||||
// convert array('#', 'a', 'b') to array('a', 'b')
|
||||
if (isset($value[0]) && $value[0] === '#') {
|
||||
// remove first element ('#')
|
||||
array_shift($value);
|
||||
// $value has keys and value names, return it
|
||||
return $value;
|
||||
}
|
||||
|
||||
// convert value list array('a', 'b') to array('a' => 'a', 'b' => 'b')
|
||||
$has_string_keys = false;
|
||||
$keys = array();
|
||||
for ($i = 0, $nb = count($value); $i < $nb; $i++) {
|
||||
if (!isset($value[$i])) {
|
||||
$has_string_keys = true;
|
||||
break;
|
||||
}
|
||||
$keys[] = is_bool($value[$i]) ? (int)$value[$i] : $value[$i];
|
||||
}
|
||||
if (! $has_string_keys) {
|
||||
$value = array_combine($keys, $value);
|
||||
}
|
||||
|
||||
// $value has keys and value names, return it
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* array_walk callback function, reads path of form fields from
|
||||
* array (see docs for \PhpMyAdmin\Config\Forms\BaseForm::getForms)
|
||||
*
|
||||
* @param mixed $value Value
|
||||
* @param mixed $key Key
|
||||
* @param mixed $prefix Prefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _readFormPathsCallback($value, $key, $prefix)
|
||||
{
|
||||
static $group_counter = 0;
|
||||
|
||||
if (is_array($value)) {
|
||||
$prefix .= $key . '/';
|
||||
array_walk($value, array($this, '_readFormPathsCallback'), $prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_int($key)) {
|
||||
$this->default[$prefix . $key] = $value;
|
||||
$value = $key;
|
||||
}
|
||||
// add unique id to group ends
|
||||
if ($value == ':group:end') {
|
||||
$value .= ':' . $group_counter++;
|
||||
}
|
||||
$this->fields[] = $prefix . $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads form paths to {@link $fields}
|
||||
*
|
||||
* @param array $form Form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function readFormPaths(array $form)
|
||||
{
|
||||
// flatten form fields' paths and save them to $fields
|
||||
$this->fields = array();
|
||||
array_walk($form, array($this, '_readFormPathsCallback'), '');
|
||||
|
||||
// $this->fields is an array of the form: [0..n] => 'field path'
|
||||
// change numeric indexes to contain field names (last part of the path)
|
||||
$paths = $this->fields;
|
||||
$this->fields = array();
|
||||
foreach ($paths as $path) {
|
||||
$key = ltrim(
|
||||
mb_substr($path, mb_strrpos($path, '/')),
|
||||
'/'
|
||||
);
|
||||
$this->fields[$key] = $path;
|
||||
}
|
||||
// now $this->fields is an array of the form: 'field name' => 'field path'
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads fields' types to $this->_fieldsTypes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function readTypes()
|
||||
{
|
||||
$cf = $this->_configFile;
|
||||
foreach ($this->fields as $name => $path) {
|
||||
if (mb_strpos($name, ':group:') === 0) {
|
||||
$this->_fieldsTypes[$name] = 'group';
|
||||
continue;
|
||||
}
|
||||
$v = $cf->getDbEntry($path);
|
||||
if ($v !== null) {
|
||||
$type = is_array($v) ? 'select' : $v;
|
||||
} else {
|
||||
$type = gettype($cf->getDefault($path));
|
||||
}
|
||||
$this->_fieldsTypes[$name] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads form settings and prepares class to work with given subset of
|
||||
* config file
|
||||
*
|
||||
* @param string $form_name Form name
|
||||
* @param array $form Form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function loadForm($form_name, array $form)
|
||||
{
|
||||
$this->name = $form_name;
|
||||
$this->readFormPaths($form);
|
||||
$this->readTypes();
|
||||
}
|
||||
}
|
||||
880
phpMyAdmin/libraries/classes/Config/FormDisplay.php
Executable file
880
phpMyAdmin/libraries/classes/Config/FormDisplay.php
Executable file
@@ -0,0 +1,880 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Form management class, displays and processes forms
|
||||
*
|
||||
* Explanation of used terms:
|
||||
* o work_path - original field path, eg. Servers/4/verbose
|
||||
* o system_path - work_path modified so that it points to the first server,
|
||||
* eg. Servers/1/verbose
|
||||
* o translated_path - work_path modified for HTML field name, a path with
|
||||
* slashes changed to hyphens, eg. Servers-4-verbose
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\Descriptions;
|
||||
use PhpMyAdmin\Config\Form;
|
||||
use PhpMyAdmin\Config\FormDisplayTemplate;
|
||||
use PhpMyAdmin\Config\Forms\User\UserFormList;
|
||||
use PhpMyAdmin\Config\Validator;
|
||||
use PhpMyAdmin\Sanitize;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Form management class, displays and processes forms
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class FormDisplay
|
||||
{
|
||||
/**
|
||||
* ConfigFile instance
|
||||
* @var ConfigFile
|
||||
*/
|
||||
private $_configFile;
|
||||
|
||||
/**
|
||||
* Form list
|
||||
* @var Form[]
|
||||
*/
|
||||
private $_forms = array();
|
||||
|
||||
/**
|
||||
* Stores validation errors, indexed by paths
|
||||
* [ Form_name ] is an array of form errors
|
||||
* [path] is a string storing error associated with single field
|
||||
* @var array
|
||||
*/
|
||||
private $_errors = array();
|
||||
|
||||
/**
|
||||
* Paths changed so that they can be used as HTML ids, indexed by paths
|
||||
* @var array
|
||||
*/
|
||||
private $_translatedPaths = array();
|
||||
|
||||
/**
|
||||
* Server paths change indexes so we define maps from current server
|
||||
* path to the first one, indexed by work path
|
||||
* @var array
|
||||
*/
|
||||
private $_systemPaths = array();
|
||||
|
||||
/**
|
||||
* Language strings which will be sent to PMA_messages JS variable
|
||||
* Will be looked up in $GLOBALS: str{value} or strSetup{value}
|
||||
* @var array
|
||||
*/
|
||||
private $_jsLangStrings = array();
|
||||
|
||||
/**
|
||||
* Tells whether forms have been validated
|
||||
* @var bool
|
||||
*/
|
||||
private $_isValidated = true;
|
||||
|
||||
/**
|
||||
* Dictionary with user preferences keys
|
||||
* @var array|null
|
||||
*/
|
||||
private $_userprefsKeys;
|
||||
|
||||
/**
|
||||
* Dictionary with disallowed user preferences keys
|
||||
* @var array
|
||||
*/
|
||||
private $_userprefsDisallow;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ConfigFile $cf Config file instance
|
||||
*/
|
||||
public function __construct(ConfigFile $cf)
|
||||
{
|
||||
$this->_jsLangStrings = array(
|
||||
'error_nan_p' => __('Not a positive number!'),
|
||||
'error_nan_nneg' => __('Not a non-negative number!'),
|
||||
'error_incorrect_port' => __('Not a valid port number!'),
|
||||
'error_invalid_value' => __('Incorrect value!'),
|
||||
'error_value_lte' => __('Value must be less than or equal to %s!'));
|
||||
$this->_configFile = $cf;
|
||||
// initialize validators
|
||||
Validator::getValidators($this->_configFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link ConfigFile} associated with this instance
|
||||
*
|
||||
* @return ConfigFile
|
||||
*/
|
||||
public function getConfigFile()
|
||||
{
|
||||
return $this->_configFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers form in form manager
|
||||
*
|
||||
* @param string $form_name Form name
|
||||
* @param array $form Form data
|
||||
* @param int $server_id 0 if new server, validation; >= 1 if editing a server
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerForm($form_name, array $form, $server_id = null)
|
||||
{
|
||||
$this->_forms[$form_name] = new Form(
|
||||
$form_name, $form, $this->_configFile, $server_id
|
||||
);
|
||||
$this->_isValidated = false;
|
||||
foreach ($this->_forms[$form_name]->fields as $path) {
|
||||
$work_path = $server_id === null
|
||||
? $path
|
||||
: str_replace('Servers/1/', "Servers/$server_id/", $path);
|
||||
$this->_systemPaths[$work_path] = $path;
|
||||
$this->_translatedPaths[$work_path] = str_replace('/', '-', $work_path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes forms, returns true on successful save
|
||||
*
|
||||
* @param bool $allow_partial_save allows for partial form saving
|
||||
* on failed validation
|
||||
* @param bool $check_form_submit whether check for $_POST['submit_save']
|
||||
*
|
||||
* @return boolean whether processing was successful
|
||||
*/
|
||||
public function process($allow_partial_save = true, $check_form_submit = true)
|
||||
{
|
||||
if ($check_form_submit && !isset($_POST['submit_save'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// save forms
|
||||
if (count($this->_forms) > 0) {
|
||||
return $this->save(array_keys($this->_forms), $allow_partial_save);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs validation for all registered forms
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _validate()
|
||||
{
|
||||
if ($this->_isValidated) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paths = array();
|
||||
$values = array();
|
||||
foreach ($this->_forms as $form) {
|
||||
/* @var $form Form */
|
||||
$paths[] = $form->name;
|
||||
// collect values and paths
|
||||
foreach ($form->fields as $path) {
|
||||
$work_path = array_search($path, $this->_systemPaths);
|
||||
$values[$path] = $this->_configFile->getValue($work_path);
|
||||
$paths[] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
// run validation
|
||||
$errors = Validator::validate(
|
||||
$this->_configFile, $paths, $values, false
|
||||
);
|
||||
|
||||
// change error keys from canonical paths to work paths
|
||||
if (is_array($errors) && count($errors) > 0) {
|
||||
$this->_errors = array();
|
||||
foreach ($errors as $path => $error_list) {
|
||||
$work_path = array_search($path, $this->_systemPaths);
|
||||
// field error
|
||||
if (! $work_path) {
|
||||
// form error, fix path
|
||||
$work_path = $path;
|
||||
}
|
||||
$this->_errors[$work_path] = $error_list;
|
||||
}
|
||||
}
|
||||
$this->_isValidated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs HTML for the forms under the menu tab
|
||||
*
|
||||
* @param bool $show_restore_default whether to show "restore default"
|
||||
* button besides the input field
|
||||
* @param array &$js_default stores JavaScript code
|
||||
* to be displayed
|
||||
* @param array &$js will be updated with javascript code
|
||||
* @param bool $show_buttons whether show submit and reset button
|
||||
*
|
||||
* @return string $htmlOutput
|
||||
*/
|
||||
private function _displayForms(
|
||||
$show_restore_default, array &$js_default, array &$js, $show_buttons
|
||||
) {
|
||||
$htmlOutput = '';
|
||||
$validators = Validator::getValidators($this->_configFile);
|
||||
|
||||
foreach ($this->_forms as $form) {
|
||||
/* @var $form Form */
|
||||
$form_errors = isset($this->_errors[$form->name])
|
||||
? $this->_errors[$form->name] : null;
|
||||
$htmlOutput .= FormDisplayTemplate::displayFieldsetTop(
|
||||
Descriptions::get("Form_{$form->name}"),
|
||||
Descriptions::get("Form_{$form->name}", 'desc'),
|
||||
$form_errors,
|
||||
array('id' => $form->name)
|
||||
);
|
||||
|
||||
foreach ($form->fields as $field => $path) {
|
||||
$work_path = array_search($path, $this->_systemPaths);
|
||||
$translated_path = $this->_translatedPaths[$work_path];
|
||||
// always true/false for user preferences display
|
||||
// otherwise null
|
||||
$userprefs_allow = isset($this->_userprefsKeys[$path])
|
||||
? !isset($this->_userprefsDisallow[$path])
|
||||
: null;
|
||||
// display input
|
||||
$htmlOutput .= $this->_displayFieldInput(
|
||||
$form,
|
||||
$field,
|
||||
$path,
|
||||
$work_path,
|
||||
$translated_path,
|
||||
$show_restore_default,
|
||||
$userprefs_allow,
|
||||
$js_default
|
||||
);
|
||||
// register JS validators for this field
|
||||
if (isset($validators[$path])) {
|
||||
FormDisplayTemplate::addJsValidate($translated_path, $validators[$path], $js);
|
||||
}
|
||||
}
|
||||
$htmlOutput .= FormDisplayTemplate::displayFieldsetBottom($show_buttons);
|
||||
}
|
||||
return $htmlOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs HTML for forms
|
||||
*
|
||||
* @param bool $tabbed_form if true, use a form with tabs
|
||||
* @param bool $show_restore_default whether show "restore default" button
|
||||
* besides the input field
|
||||
* @param bool $show_buttons whether show submit and reset button
|
||||
* @param string $form_action action attribute for the form
|
||||
* @param array|null $hidden_fields array of form hidden fields (key: field
|
||||
* name)
|
||||
*
|
||||
* @return string HTML for forms
|
||||
*/
|
||||
public function getDisplay(
|
||||
$tabbed_form = false,
|
||||
$show_restore_default = false,
|
||||
$show_buttons = true,
|
||||
$form_action = null,
|
||||
$hidden_fields = null
|
||||
) {
|
||||
static $js_lang_sent = false;
|
||||
|
||||
$htmlOutput = '';
|
||||
|
||||
$js = array();
|
||||
$js_default = array();
|
||||
|
||||
$htmlOutput .= FormDisplayTemplate::displayFormTop($form_action, 'post', $hidden_fields);
|
||||
|
||||
if ($tabbed_form) {
|
||||
$tabs = array();
|
||||
foreach ($this->_forms as $form) {
|
||||
$tabs[$form->name] = Descriptions::get("Form_$form->name");
|
||||
}
|
||||
$htmlOutput .= FormDisplayTemplate::displayTabsTop($tabs);
|
||||
}
|
||||
|
||||
// validate only when we aren't displaying a "new server" form
|
||||
$is_new_server = false;
|
||||
foreach ($this->_forms as $form) {
|
||||
/* @var $form Form */
|
||||
if ($form->index === 0) {
|
||||
$is_new_server = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! $is_new_server) {
|
||||
$this->_validate();
|
||||
}
|
||||
|
||||
// user preferences
|
||||
$this->_loadUserprefsInfo();
|
||||
|
||||
// display forms
|
||||
$htmlOutput .= $this->_displayForms(
|
||||
$show_restore_default, $js_default, $js, $show_buttons
|
||||
);
|
||||
|
||||
if ($tabbed_form) {
|
||||
$htmlOutput .= FormDisplayTemplate::displayTabsBottom();
|
||||
}
|
||||
$htmlOutput .= FormDisplayTemplate::displayFormBottom();
|
||||
|
||||
// if not already done, send strings used for validation to JavaScript
|
||||
if (! $js_lang_sent) {
|
||||
$js_lang_sent = true;
|
||||
$js_lang = array();
|
||||
foreach ($this->_jsLangStrings as $strName => $strValue) {
|
||||
$js_lang[] = "'$strName': '" . Sanitize::jsFormat($strValue, false) . '\'';
|
||||
}
|
||||
$js[] = "$.extend(PMA_messages, {\n\t"
|
||||
. implode(",\n\t", $js_lang) . '})';
|
||||
}
|
||||
|
||||
$js[] = "$.extend(defaultValues, {\n\t"
|
||||
. implode(",\n\t", $js_default) . '})';
|
||||
$htmlOutput .= FormDisplayTemplate::displayJavascript($js);
|
||||
|
||||
return $htmlOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares data for input field display and outputs HTML code
|
||||
*
|
||||
* @param Form $form Form object
|
||||
* @param string $field field name as it appears in $form
|
||||
* @param string $system_path field path, eg. Servers/1/verbose
|
||||
* @param string $work_path work path, eg. Servers/4/verbose
|
||||
* @param string $translated_path work path changed so that it can be
|
||||
* used as XHTML id
|
||||
* @param bool $show_restore_default whether show "restore default" button
|
||||
* besides the input field
|
||||
* @param bool|null $userprefs_allow whether user preferences are enabled
|
||||
* for this field (null - no support,
|
||||
* true/false - enabled/disabled)
|
||||
* @param array &$js_default array which stores JavaScript code
|
||||
* to be displayed
|
||||
*
|
||||
* @return string HTML for input field
|
||||
*/
|
||||
private function _displayFieldInput(
|
||||
Form $form, $field, $system_path, $work_path,
|
||||
$translated_path, $show_restore_default, $userprefs_allow, array &$js_default
|
||||
) {
|
||||
$name = Descriptions::get($system_path);
|
||||
$description = Descriptions::get($system_path, 'desc');
|
||||
|
||||
$value = $this->_configFile->get($work_path);
|
||||
$value_default = $this->_configFile->getDefault($system_path);
|
||||
$value_is_default = false;
|
||||
if ($value === null || $value === $value_default) {
|
||||
$value = $value_default;
|
||||
$value_is_default = true;
|
||||
}
|
||||
|
||||
$opts = array(
|
||||
'doc' => $this->getDocLink($system_path),
|
||||
'show_restore_default' => $show_restore_default,
|
||||
'userprefs_allow' => $userprefs_allow,
|
||||
'userprefs_comment' => Descriptions::get($system_path, 'cmt')
|
||||
);
|
||||
if (isset($form->default[$system_path])) {
|
||||
$opts['setvalue'] = $form->default[$system_path];
|
||||
}
|
||||
|
||||
if (isset($this->_errors[$work_path])) {
|
||||
$opts['errors'] = $this->_errors[$work_path];
|
||||
}
|
||||
|
||||
$type = '';
|
||||
switch ($form->getOptionType($field)) {
|
||||
case 'string':
|
||||
$type = 'text';
|
||||
break;
|
||||
case 'short_string':
|
||||
$type = 'short_text';
|
||||
break;
|
||||
case 'double':
|
||||
case 'integer':
|
||||
$type = 'number_text';
|
||||
break;
|
||||
case 'boolean':
|
||||
$type = 'checkbox';
|
||||
break;
|
||||
case 'select':
|
||||
$type = 'select';
|
||||
$opts['values'] = $form->getOptionValueList($form->fields[$field]);
|
||||
break;
|
||||
case 'array':
|
||||
$type = 'list';
|
||||
$value = (array) $value;
|
||||
$value_default = (array) $value_default;
|
||||
break;
|
||||
case 'group':
|
||||
// :group:end is changed to :group:end:{unique id} in Form class
|
||||
$htmlOutput = '';
|
||||
if (mb_substr($field, 7, 4) != 'end:') {
|
||||
$htmlOutput .= FormDisplayTemplate::displayGroupHeader(
|
||||
mb_substr($field, 7)
|
||||
);
|
||||
} else {
|
||||
FormDisplayTemplate::displayGroupFooter();
|
||||
}
|
||||
return $htmlOutput;
|
||||
case 'NULL':
|
||||
trigger_error("Field $system_path has no type", E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
|
||||
// detect password fields
|
||||
if ($type === 'text'
|
||||
&& (mb_substr($translated_path, -9) === '-password'
|
||||
|| mb_substr($translated_path, -4) === 'pass'
|
||||
|| mb_substr($translated_path, -4) === 'Pass')
|
||||
) {
|
||||
$type = 'password';
|
||||
}
|
||||
|
||||
// TrustedProxies requires changes before displaying
|
||||
if ($system_path == 'TrustedProxies') {
|
||||
foreach ($value as $ip => &$v) {
|
||||
if (!preg_match('/^-\d+$/', $ip)) {
|
||||
$v = $ip . ': ' . $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->_setComments($system_path, $opts);
|
||||
|
||||
// send default value to form's JS
|
||||
$js_line = '\'' . $translated_path . '\': ';
|
||||
switch ($type) {
|
||||
case 'text':
|
||||
case 'short_text':
|
||||
case 'number_text':
|
||||
case 'password':
|
||||
$js_line .= '\'' . Sanitize::escapeJsString($value_default) . '\'';
|
||||
break;
|
||||
case 'checkbox':
|
||||
$js_line .= $value_default ? 'true' : 'false';
|
||||
break;
|
||||
case 'select':
|
||||
$value_default_js = is_bool($value_default)
|
||||
? (int) $value_default
|
||||
: $value_default;
|
||||
$js_line .= '[\'' . Sanitize::escapeJsString($value_default_js) . '\']';
|
||||
break;
|
||||
case 'list':
|
||||
$js_line .= '\'' . Sanitize::escapeJsString(implode("\n", $value_default))
|
||||
. '\'';
|
||||
break;
|
||||
}
|
||||
$js_default[] = $js_line;
|
||||
|
||||
return FormDisplayTemplate::displayInput(
|
||||
$translated_path, $name, $type, $value,
|
||||
$description, $value_is_default, $opts
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays errors
|
||||
*
|
||||
* @return string HTML for errors
|
||||
*/
|
||||
public function displayErrors()
|
||||
{
|
||||
$this->_validate();
|
||||
if (count($this->_errors) == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$htmlOutput = '';
|
||||
|
||||
foreach ($this->_errors as $system_path => $error_list) {
|
||||
if (isset($this->_systemPaths[$system_path])) {
|
||||
$name = Descriptions::get($this->_systemPaths[$system_path]);
|
||||
} else {
|
||||
$name = Descriptions::get('Form_' . $system_path);
|
||||
}
|
||||
$htmlOutput .= FormDisplayTemplate::displayErrors($name, $error_list);
|
||||
}
|
||||
|
||||
return $htmlOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts erroneous fields to their default values
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function fixErrors()
|
||||
{
|
||||
$this->_validate();
|
||||
if (count($this->_errors) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cf = $this->_configFile;
|
||||
foreach (array_keys($this->_errors) as $work_path) {
|
||||
if (!isset($this->_systemPaths[$work_path])) {
|
||||
continue;
|
||||
}
|
||||
$canonical_path = $this->_systemPaths[$work_path];
|
||||
$cf->set($work_path, $cf->getDefault($canonical_path));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates select field and casts $value to correct type
|
||||
*
|
||||
* @param string &$value Current value
|
||||
* @param array $allowed List of allowed values
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function _validateSelect(&$value, array $allowed)
|
||||
{
|
||||
$value_cmp = is_bool($value)
|
||||
? (int) $value
|
||||
: $value;
|
||||
foreach ($allowed as $vk => $v) {
|
||||
// equality comparison only if both values are numeric or not numeric
|
||||
// (allows to skip 0 == 'string' equalling to true)
|
||||
// or identity (for string-string)
|
||||
if (($vk == $value && !(is_numeric($value_cmp) xor is_numeric($vk)))
|
||||
|| $vk === $value
|
||||
) {
|
||||
// keep boolean value as boolean
|
||||
if (!is_bool($value)) {
|
||||
settype($value, gettype($vk));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and saves form data to session
|
||||
*
|
||||
* @param array|string $forms array of form names
|
||||
* @param bool $allow_partial_save allows for partial form saving on
|
||||
* failed validation
|
||||
*
|
||||
* @return boolean true on success (no errors and all saved)
|
||||
*/
|
||||
public function save($forms, $allow_partial_save = true)
|
||||
{
|
||||
$result = true;
|
||||
$forms = (array) $forms;
|
||||
|
||||
$values = array();
|
||||
$to_save = array();
|
||||
$is_setup_script = $GLOBALS['PMA_Config']->get('is_setup');
|
||||
if ($is_setup_script) {
|
||||
$this->_loadUserprefsInfo();
|
||||
}
|
||||
|
||||
$this->_errors = array();
|
||||
foreach ($forms as $form_name) {
|
||||
/* @var $form Form */
|
||||
if (isset($this->_forms[$form_name])) {
|
||||
$form = $this->_forms[$form_name];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
// get current server id
|
||||
$change_index = $form->index === 0
|
||||
? $this->_configFile->getServerCount() + 1
|
||||
: false;
|
||||
// grab POST values
|
||||
foreach ($form->fields as $field => $system_path) {
|
||||
$work_path = array_search($system_path, $this->_systemPaths);
|
||||
$key = $this->_translatedPaths[$work_path];
|
||||
$type = $form->getOptionType($field);
|
||||
|
||||
// skip groups
|
||||
if ($type == 'group') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// ensure the value is set
|
||||
if (!isset($_POST[$key])) {
|
||||
// checkboxes aren't set by browsers if they're off
|
||||
if ($type == 'boolean') {
|
||||
$_POST[$key] = false;
|
||||
} else {
|
||||
$this->_errors[$form->name][] = sprintf(
|
||||
__('Missing data for %s'),
|
||||
'<i>' . Descriptions::get($system_path) . '</i>'
|
||||
);
|
||||
$result = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// user preferences allow/disallow
|
||||
if ($is_setup_script
|
||||
&& isset($this->_userprefsKeys[$system_path])
|
||||
) {
|
||||
if (isset($this->_userprefsDisallow[$system_path])
|
||||
&& isset($_POST[$key . '-userprefs-allow'])
|
||||
) {
|
||||
unset($this->_userprefsDisallow[$system_path]);
|
||||
} elseif (!isset($_POST[$key . '-userprefs-allow'])) {
|
||||
$this->_userprefsDisallow[$system_path] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// cast variables to correct type
|
||||
switch ($type) {
|
||||
case 'double':
|
||||
$_POST[$key] = Util::requestString($_POST[$key]);
|
||||
settype($_POST[$key], 'float');
|
||||
break;
|
||||
case 'boolean':
|
||||
case 'integer':
|
||||
if ($_POST[$key] !== '') {
|
||||
$_POST[$key] = Util::requestString($_POST[$key]);
|
||||
settype($_POST[$key], $type);
|
||||
}
|
||||
break;
|
||||
case 'select':
|
||||
$successfully_validated = $this->_validateSelect(
|
||||
$_POST[$key],
|
||||
$form->getOptionValueList($system_path)
|
||||
);
|
||||
if (! $successfully_validated) {
|
||||
$this->_errors[$work_path][] = __('Incorrect value!');
|
||||
$result = false;
|
||||
// "continue" for the $form->fields foreach-loop
|
||||
continue 2;
|
||||
}
|
||||
break;
|
||||
case 'string':
|
||||
case 'short_string':
|
||||
$_POST[$key] = Util::requestString($_POST[$key]);
|
||||
break;
|
||||
case 'array':
|
||||
// eliminate empty values and ensure we have an array
|
||||
$post_values = is_array($_POST[$key])
|
||||
? $_POST[$key]
|
||||
: explode("\n", $_POST[$key]);
|
||||
$_POST[$key] = array();
|
||||
$this->_fillPostArrayParameters($post_values, $key);
|
||||
break;
|
||||
}
|
||||
|
||||
// now we have value with proper type
|
||||
$values[$system_path] = $_POST[$key];
|
||||
if ($change_index !== false) {
|
||||
$work_path = str_replace(
|
||||
"Servers/$form->index/",
|
||||
"Servers/$change_index/", $work_path
|
||||
);
|
||||
}
|
||||
$to_save[$work_path] = $system_path;
|
||||
}
|
||||
}
|
||||
|
||||
// save forms
|
||||
if (!$allow_partial_save && !empty($this->_errors)) {
|
||||
// don't look for non-critical errors
|
||||
$this->_validate();
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach ($to_save as $work_path => $path) {
|
||||
// TrustedProxies requires changes before saving
|
||||
if ($path == 'TrustedProxies') {
|
||||
$proxies = array();
|
||||
$i = 0;
|
||||
foreach ($values[$path] as $value) {
|
||||
$matches = array();
|
||||
$match = preg_match(
|
||||
"/^(.+):(?:[ ]?)(\\w+)$/", $value, $matches
|
||||
);
|
||||
if ($match) {
|
||||
// correct 'IP: HTTP header' pair
|
||||
$ip = trim($matches[1]);
|
||||
$proxies[$ip] = trim($matches[2]);
|
||||
} else {
|
||||
// save also incorrect values
|
||||
$proxies["-$i"] = $value;
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
$values[$path] = $proxies;
|
||||
}
|
||||
$this->_configFile->set($work_path, $values[$path], $path);
|
||||
}
|
||||
if ($is_setup_script) {
|
||||
$this->_configFile->set(
|
||||
'UserprefsDisallow',
|
||||
array_keys($this->_userprefsDisallow)
|
||||
);
|
||||
}
|
||||
|
||||
// don't look for non-critical errors
|
||||
$this->_validate();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether form validation failed
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasErrors()
|
||||
{
|
||||
return count($this->_errors) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns link to documentation
|
||||
*
|
||||
* @param string $path Path to documentation
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDocLink($path)
|
||||
{
|
||||
$test = mb_substr($path, 0, 6);
|
||||
if ($test == 'Import' || $test == 'Export') {
|
||||
return '';
|
||||
}
|
||||
return Util::getDocuLink(
|
||||
'config',
|
||||
'cfg_' . $this->_getOptName($path)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes path so it can be used in URLs
|
||||
*
|
||||
* @param string $path Path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _getOptName($path)
|
||||
{
|
||||
return str_replace(array('Servers/1/', '/'), array('Servers/', '_'), $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills out {@link userprefs_keys} and {@link userprefs_disallow}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _loadUserprefsInfo()
|
||||
{
|
||||
if ($this->_userprefsKeys !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_userprefsKeys = array_flip(UserFormList::getFields());
|
||||
// read real config for user preferences display
|
||||
$userprefs_disallow = $GLOBALS['PMA_Config']->get('is_setup')
|
||||
? $this->_configFile->get('UserprefsDisallow', array())
|
||||
: $GLOBALS['cfg']['UserprefsDisallow'];
|
||||
$this->_userprefsDisallow = array_flip($userprefs_disallow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets field comments and warnings based on current environment
|
||||
*
|
||||
* @param string $system_path Path to settings
|
||||
* @param array &$opts Chosen options
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _setComments($system_path, array &$opts)
|
||||
{
|
||||
// RecodingEngine - mark unavailable types
|
||||
if ($system_path == 'RecodingEngine') {
|
||||
$comment = '';
|
||||
if (!function_exists('iconv')) {
|
||||
$opts['values']['iconv'] .= ' (' . __('unavailable') . ')';
|
||||
$comment = sprintf(
|
||||
__('"%s" requires %s extension'), 'iconv', 'iconv'
|
||||
);
|
||||
}
|
||||
if (!function_exists('recode_string')) {
|
||||
$opts['values']['recode'] .= ' (' . __('unavailable') . ')';
|
||||
$comment .= ($comment ? ", " : '') . sprintf(
|
||||
__('"%s" requires %s extension'),
|
||||
'recode', 'recode'
|
||||
);
|
||||
}
|
||||
/* mbstring is always there thanks to polyfill */
|
||||
$opts['comment'] = $comment;
|
||||
$opts['comment_warning'] = true;
|
||||
}
|
||||
// ZipDump, GZipDump, BZipDump - check function availability
|
||||
if ($system_path == 'ZipDump'
|
||||
|| $system_path == 'GZipDump'
|
||||
|| $system_path == 'BZipDump'
|
||||
) {
|
||||
$comment = '';
|
||||
$funcs = array(
|
||||
'ZipDump' => array('zip_open', 'gzcompress'),
|
||||
'GZipDump' => array('gzopen', 'gzencode'),
|
||||
'BZipDump' => array('bzopen', 'bzcompress'));
|
||||
if (!function_exists($funcs[$system_path][0])) {
|
||||
$comment = sprintf(
|
||||
__(
|
||||
'Compressed import will not work due to missing function %s.'
|
||||
),
|
||||
$funcs[$system_path][0]
|
||||
);
|
||||
}
|
||||
if (!function_exists($funcs[$system_path][1])) {
|
||||
$comment .= ($comment ? '; ' : '') . sprintf(
|
||||
__(
|
||||
'Compressed export will not work due to missing function %s.'
|
||||
),
|
||||
$funcs[$system_path][1]
|
||||
);
|
||||
}
|
||||
$opts['comment'] = $comment;
|
||||
$opts['comment_warning'] = true;
|
||||
}
|
||||
if (! $GLOBALS['PMA_Config']->get('is_setup')) {
|
||||
if (($system_path == 'MaxDbList' || $system_path == 'MaxTableList'
|
||||
|| $system_path == 'QueryHistoryMax')
|
||||
) {
|
||||
$opts['comment'] = sprintf(
|
||||
__('maximum %s'), $GLOBALS['cfg'][$system_path]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy items of an array to $_POST variable
|
||||
*
|
||||
* @param array $post_values List of parameters
|
||||
* @param string $key Array key
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _fillPostArrayParameters(array $post_values, $key)
|
||||
{
|
||||
foreach ($post_values as $v) {
|
||||
$v = Util::requestString($v);
|
||||
if ($v !== '') {
|
||||
$_POST[$key][] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
493
phpMyAdmin/libraries/classes/Config/FormDisplayTemplate.php
Executable file
493
phpMyAdmin/libraries/classes/Config/FormDisplayTemplate.php
Executable file
@@ -0,0 +1,493 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Form templates
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Sanitize;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* PhpMyAdmin\Config\FormDisplayTemplate class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class FormDisplayTemplate
|
||||
{
|
||||
/**
|
||||
* Displays top part of the form
|
||||
*
|
||||
* @param string $action default: $_SERVER['REQUEST_URI']
|
||||
* @param string $method 'post' or 'get'
|
||||
* @param array|null $hidden_fields array of form hidden fields (key: field name)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function displayFormTop($action = null, $method = 'post', $hidden_fields = null)
|
||||
{
|
||||
static $has_check_page_refresh = false;
|
||||
|
||||
if ($action === null) {
|
||||
$action = $_SERVER['REQUEST_URI'];
|
||||
}
|
||||
if ($method != 'post') {
|
||||
$method = 'get';
|
||||
}
|
||||
$htmlOutput = '<form method="' . $method . '" action="'
|
||||
. htmlspecialchars($action) . '" class="config-form disableAjax">';
|
||||
$htmlOutput .= '<input type="hidden" name="tab_hash" value="" />';
|
||||
// we do validation on page refresh when browser remembers field values,
|
||||
// add a field with known value which will be used for checks
|
||||
if (! $has_check_page_refresh) {
|
||||
$has_check_page_refresh = true;
|
||||
$htmlOutput .= '<input type="hidden" name="check_page_refresh" '
|
||||
. ' id="check_page_refresh" value="" />' . "\n";
|
||||
}
|
||||
$htmlOutput .= Url::getHiddenInputs('', '', 0, 'server') . "\n";
|
||||
$htmlOutput .= Url::getHiddenFields((array)$hidden_fields);
|
||||
return $htmlOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays form tabs which are given by an array indexed by fieldset id
|
||||
* ({@link self::displayFieldsetTop}), with values being tab titles.
|
||||
*
|
||||
* @param array $tabs tab names
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function displayTabsTop(array $tabs)
|
||||
{
|
||||
$items = array();
|
||||
foreach ($tabs as $tab_id => $tab_name) {
|
||||
$items[] = array(
|
||||
'content' => htmlspecialchars($tab_name),
|
||||
'url' => array(
|
||||
'href' => '#' . $tab_id,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$htmlOutput = Template::get('list/unordered')->render(
|
||||
array(
|
||||
'class' => 'tabs responsivetable',
|
||||
'items' => $items,
|
||||
)
|
||||
);
|
||||
$htmlOutput .= '<br />';
|
||||
$htmlOutput .= '<div class="tabs_contents">';
|
||||
return $htmlOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays top part of a fieldset
|
||||
*
|
||||
* @param string $title title of fieldset
|
||||
* @param string $description description shown on top of fieldset
|
||||
* @param array|null $errors error messages to display
|
||||
* @param array $attributes optional extra attributes of fieldset
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function displayFieldsetTop(
|
||||
$title = '',
|
||||
$description = '',
|
||||
$errors = null,
|
||||
array $attributes = array()
|
||||
) {
|
||||
global $_FormDisplayGroup;
|
||||
|
||||
$_FormDisplayGroup = 0;
|
||||
|
||||
$attributes = array_merge(array('class' => 'optbox'), $attributes);
|
||||
|
||||
return Template::get('config/form_display/fieldset_top')->render([
|
||||
'attributes' => $attributes,
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
'errors' => $errors,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays input field
|
||||
*
|
||||
* $opts keys:
|
||||
* o doc - (string) documentation link
|
||||
* o errors - error array
|
||||
* o setvalue - (string) shows button allowing to set predefined value
|
||||
* o show_restore_default - (boolean) whether show "restore default" button
|
||||
* o userprefs_allow - whether user preferences are enabled for this field
|
||||
* (null - no support, true/false - enabled/disabled)
|
||||
* o userprefs_comment - (string) field comment
|
||||
* o values - key - value pairs for <select> fields
|
||||
* o values_escaped - (boolean) tells whether values array is already escaped
|
||||
* (defaults to false)
|
||||
* o values_disabled - (array)list of disabled values (keys from values)
|
||||
* o comment - (string) tooltip comment
|
||||
* o comment_warning - (bool) whether this comments warns about something
|
||||
*
|
||||
* @param string $path config option path
|
||||
* @param string $name config option name
|
||||
* @param string $type type of config option
|
||||
* @param mixed $value current value
|
||||
* @param string $description verbose description
|
||||
* @param bool $value_is_default whether value is default
|
||||
* @param array|null $opts see above description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function displayInput($path, $name, $type, $value, $description = '',
|
||||
$value_is_default = true, $opts = null
|
||||
) {
|
||||
global $_FormDisplayGroup;
|
||||
static $icons; // An array of IMG tags used further below in the function
|
||||
|
||||
if (defined('TESTSUITE')) {
|
||||
$icons = null;
|
||||
}
|
||||
|
||||
$is_setup_script = $GLOBALS['PMA_Config']->get('is_setup');
|
||||
if ($icons === null) { // if the static variables have not been initialised
|
||||
$icons = array();
|
||||
// Icon definitions:
|
||||
// The same indexes will be used in the $icons array.
|
||||
// The first element contains the filename and the second
|
||||
// element is used for the "alt" and "title" attributes.
|
||||
$icon_init = array(
|
||||
'edit' => array('b_edit', ''),
|
||||
'help' => array('b_help', __('Documentation')),
|
||||
'reload' => array('s_reload', ''),
|
||||
'tblops' => array('b_tblops', '')
|
||||
);
|
||||
if ($is_setup_script) {
|
||||
// When called from the setup script, we don't have access to the
|
||||
// sprite-aware getImage() function because the PMA_theme class
|
||||
// has not been loaded, so we generate the img tags manually.
|
||||
foreach ($icon_init as $k => $v) {
|
||||
$title = '';
|
||||
if (! empty($v[1])) {
|
||||
$title = ' title="' . $v[1] . '"';
|
||||
}
|
||||
$icons[$k] = sprintf(
|
||||
'<img alt="%s" src="%s"%s />',
|
||||
$v[1],
|
||||
"../themes/pmahomme/img/{$v[0]}.png",
|
||||
$title
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// In this case we just use getImage() because it's available
|
||||
foreach ($icon_init as $k => $v) {
|
||||
$icons[$k] = Util::getImage(
|
||||
$v[0], $v[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$has_errors = isset($opts['errors']) && !empty($opts['errors']);
|
||||
$option_is_disabled = ! $is_setup_script && isset($opts['userprefs_allow'])
|
||||
&& ! $opts['userprefs_allow'];
|
||||
$name_id = 'name="' . htmlspecialchars($path) . '" id="'
|
||||
. htmlspecialchars($path) . '"';
|
||||
$field_class = $type == 'checkbox' ? 'checkbox' : '';
|
||||
if (! $value_is_default) {
|
||||
$field_class .= ($field_class == '' ? '' : ' ')
|
||||
. ($has_errors ? 'custom field-error' : 'custom');
|
||||
}
|
||||
$field_class = $field_class ? ' class="' . $field_class . '"' : '';
|
||||
$tr_class = $_FormDisplayGroup > 0
|
||||
? 'group-field group-field-' . $_FormDisplayGroup
|
||||
: '';
|
||||
if (isset($opts['setvalue']) && $opts['setvalue'] == ':group') {
|
||||
unset($opts['setvalue']);
|
||||
$_FormDisplayGroup++;
|
||||
$tr_class = 'group-header-field group-header-' . $_FormDisplayGroup;
|
||||
}
|
||||
if ($option_is_disabled) {
|
||||
$tr_class .= ($tr_class ? ' ' : '') . 'disabled-field';
|
||||
}
|
||||
$tr_class = $tr_class ? ' class="' . $tr_class . '"' : '';
|
||||
|
||||
$htmlOutput = '<tr' . $tr_class . '>';
|
||||
$htmlOutput .= '<th>';
|
||||
$htmlOutput .= '<label for="' . htmlspecialchars($path) . '">' . htmlspecialchars_decode($name)
|
||||
. '</label>';
|
||||
|
||||
if (! empty($opts['doc'])) {
|
||||
$htmlOutput .= '<span class="doc">';
|
||||
$htmlOutput .= '<a href="' . $opts['doc']
|
||||
. '" target="documentation">' . $icons['help'] . '</a>';
|
||||
$htmlOutput .= "\n";
|
||||
$htmlOutput .= '</span>';
|
||||
}
|
||||
|
||||
if ($option_is_disabled) {
|
||||
$htmlOutput .= '<span class="disabled-notice" title="';
|
||||
$htmlOutput .= __(
|
||||
'This setting is disabled, it will not be applied to your configuration.'
|
||||
);
|
||||
$htmlOutput .= '">' . __('Disabled') . "</span>";
|
||||
}
|
||||
|
||||
if (!empty($description)) {
|
||||
$htmlOutput .= '<small>' . $description . '</small>';
|
||||
}
|
||||
|
||||
$htmlOutput .= '</th>';
|
||||
$htmlOutput .= '<td>';
|
||||
|
||||
switch ($type) {
|
||||
case 'text':
|
||||
$htmlOutput .= '<input type="text" class="all85" ' . $name_id . $field_class
|
||||
. ' value="' . htmlspecialchars($value) . '" />';
|
||||
break;
|
||||
case 'password':
|
||||
$htmlOutput .= '<input type="password" class="all85" ' . $name_id . $field_class
|
||||
. ' value="' . htmlspecialchars($value) . '" />';
|
||||
break;
|
||||
case 'short_text':
|
||||
// As seen in the reporting server (#15042) we sometimes receive
|
||||
// an array here. No clue about its origin nor content, so let's avoid
|
||||
// a notice on htmlspecialchars().
|
||||
if (! is_array($value)) {
|
||||
$htmlOutput .= '<input type="text" size="25" ' . $name_id
|
||||
. $field_class . ' value="' . htmlspecialchars($value)
|
||||
. '" />';
|
||||
}
|
||||
break;
|
||||
case 'number_text':
|
||||
$htmlOutput .= '<input type="number" ' . $name_id . $field_class
|
||||
. ' value="' . htmlspecialchars($value) . '" />';
|
||||
break;
|
||||
case 'checkbox':
|
||||
$htmlOutput .= '<span' . $field_class . '><input type="checkbox" ' . $name_id
|
||||
. ($value ? ' checked="checked"' : '') . ' /></span>';
|
||||
break;
|
||||
case 'select':
|
||||
$htmlOutput .= '<select class="all85" ' . $name_id . $field_class . '>';
|
||||
$escape = !(isset($opts['values_escaped']) && $opts['values_escaped']);
|
||||
$values_disabled = isset($opts['values_disabled'])
|
||||
? array_flip($opts['values_disabled']) : array();
|
||||
foreach ($opts['values'] as $opt_value_key => $opt_value) {
|
||||
// set names for boolean values
|
||||
if (is_bool($opt_value)) {
|
||||
$opt_value = mb_strtolower(
|
||||
$opt_value ? __('Yes') : __('No')
|
||||
);
|
||||
}
|
||||
// escape if necessary
|
||||
if ($escape) {
|
||||
$display = htmlspecialchars($opt_value);
|
||||
$display_value = htmlspecialchars($opt_value_key);
|
||||
} else {
|
||||
$display = $opt_value;
|
||||
$display_value = $opt_value_key;
|
||||
}
|
||||
// compare with selected value
|
||||
// boolean values are cast to integers when used as array keys
|
||||
$selected = is_bool($value)
|
||||
? (int) $value === $opt_value_key
|
||||
: $opt_value_key === $value;
|
||||
$htmlOutput .= '<option value="' . $display_value . '"';
|
||||
if ($selected) {
|
||||
$htmlOutput .= ' selected="selected"';
|
||||
}
|
||||
if (isset($values_disabled[$opt_value_key])) {
|
||||
$htmlOutput .= ' disabled="disabled"';
|
||||
}
|
||||
$htmlOutput .= '>' . $display . '</option>';
|
||||
}
|
||||
$htmlOutput .= '</select>';
|
||||
break;
|
||||
case 'list':
|
||||
$htmlOutput .= '<textarea cols="35" rows="5" ' . $name_id . $field_class
|
||||
. '>' . htmlspecialchars(implode("\n", $value)) . '</textarea>';
|
||||
break;
|
||||
}
|
||||
if (isset($opts['comment']) && $opts['comment']) {
|
||||
$class = 'field-comment-mark';
|
||||
if (isset($opts['comment_warning']) && $opts['comment_warning']) {
|
||||
$class .= ' field-comment-warning';
|
||||
}
|
||||
$htmlOutput .= '<span class="' . $class . '" title="'
|
||||
. htmlspecialchars($opts['comment']) . '">i</span>';
|
||||
}
|
||||
if ($is_setup_script
|
||||
&& isset($opts['userprefs_comment'])
|
||||
&& $opts['userprefs_comment']
|
||||
) {
|
||||
$htmlOutput .= '<a class="userprefs-comment" title="'
|
||||
. htmlspecialchars($opts['userprefs_comment']) . '">'
|
||||
. $icons['tblops'] . '</a>';
|
||||
}
|
||||
if (isset($opts['setvalue']) && $opts['setvalue']) {
|
||||
$htmlOutput .= '<a class="set-value hide" href="#'
|
||||
. htmlspecialchars("$path={$opts['setvalue']}") . '" title="'
|
||||
. sprintf(__('Set value: %s'), htmlspecialchars($opts['setvalue']))
|
||||
. '">' . $icons['edit'] . '</a>';
|
||||
}
|
||||
if (isset($opts['show_restore_default']) && $opts['show_restore_default']) {
|
||||
$htmlOutput .= '<a class="restore-default hide" href="#' . $path . '" title="'
|
||||
. __('Restore default value') . '">' . $icons['reload'] . '</a>';
|
||||
}
|
||||
// this must match with displayErrors() in scripts/config.js
|
||||
if ($has_errors) {
|
||||
$htmlOutput .= "\n <dl class=\"inline_errors\">";
|
||||
foreach ($opts['errors'] as $error) {
|
||||
$htmlOutput .= '<dd>' . htmlspecialchars($error) . '</dd>';
|
||||
}
|
||||
$htmlOutput .= '</dl>';
|
||||
}
|
||||
$htmlOutput .= '</td>';
|
||||
if ($is_setup_script && isset($opts['userprefs_allow'])) {
|
||||
$htmlOutput .= '<td class="userprefs-allow" title="' .
|
||||
__('Allow users to customize this value') . '">';
|
||||
$htmlOutput .= '<input type="checkbox" name="' . $path
|
||||
. '-userprefs-allow" ';
|
||||
if ($opts['userprefs_allow']) {
|
||||
$htmlOutput .= 'checked="checked"';
|
||||
};
|
||||
$htmlOutput .= '/>';
|
||||
$htmlOutput .= '</td>';
|
||||
} elseif ($is_setup_script) {
|
||||
$htmlOutput .= '<td> </td>';
|
||||
}
|
||||
$htmlOutput .= '</tr>';
|
||||
return $htmlOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display group header
|
||||
*
|
||||
* @param string $headerText Text of header
|
||||
*
|
||||
* @return string|void
|
||||
*/
|
||||
public static function displayGroupHeader($headerText)
|
||||
{
|
||||
global $_FormDisplayGroup;
|
||||
|
||||
$_FormDisplayGroup++;
|
||||
if (! $headerText) {
|
||||
return null;
|
||||
}
|
||||
$colspan = $GLOBALS['PMA_Config']->get('is_setup') ? 3 : 2;
|
||||
|
||||
return Template::get('config/form_display/group_header')->render([
|
||||
'group' => $_FormDisplayGroup,
|
||||
'colspan' => $colspan,
|
||||
'header_text' => $headerText,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display group footer
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function displayGroupFooter()
|
||||
{
|
||||
global $_FormDisplayGroup;
|
||||
|
||||
$_FormDisplayGroup--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays bottom part of a fieldset
|
||||
*
|
||||
* @param bool $showButtons Whether show submit and reset button
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function displayFieldsetBottom($showButtons = true)
|
||||
{
|
||||
return Template::get('config/form_display/fieldset_bottom')->render([
|
||||
'show_buttons' => $showButtons,
|
||||
'is_setup' => $GLOBALS['PMA_Config']->get('is_setup'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes form tabs
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function displayTabsBottom()
|
||||
{
|
||||
return Template::get('config/form_display/tabs_bottom')->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays bottom part of the form
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function displayFormBottom()
|
||||
{
|
||||
return Template::get('config/form_display/form_bottom')->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends JS validation code to $js_array
|
||||
*
|
||||
* @param string $field_id ID of field to validate
|
||||
* @param string|array $validators validators callback
|
||||
* @param array &$js_array will be updated with javascript code
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function addJsValidate($field_id, $validators, array &$js_array)
|
||||
{
|
||||
foreach ((array)$validators as $validator) {
|
||||
$validator = (array)$validator;
|
||||
$v_name = array_shift($validator);
|
||||
$v_name = "PMA_" . $v_name;
|
||||
$v_args = array();
|
||||
foreach ($validator as $arg) {
|
||||
$v_args[] = Sanitize::escapeJsString($arg);
|
||||
}
|
||||
$v_args = $v_args ? ", ['" . implode("', '", $v_args) . "']" : '';
|
||||
$js_array[] = "validateField('$field_id', '$v_name', true$v_args)";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays JavaScript code
|
||||
*
|
||||
* @param array $js_array lines of javascript code
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function displayJavascript(array $js_array)
|
||||
{
|
||||
if (empty($js_array)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Template::get('javascript/display')->render(
|
||||
array('js_array' => $js_array,)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays error list
|
||||
*
|
||||
* @param string $name Name of item with errors
|
||||
* @param array $errorList List of errors to show
|
||||
*
|
||||
* @return string HTML for errors
|
||||
*/
|
||||
public static function displayErrors($name, array $errorList)
|
||||
{
|
||||
return Template::get('config/form_display/errors')->render([
|
||||
'name' => $name,
|
||||
'error_list' => $errorList,
|
||||
]);
|
||||
}
|
||||
}
|
||||
85
phpMyAdmin/libraries/classes/Config/Forms/BaseForm.php
Executable file
85
phpMyAdmin/libraries/classes/Config/Forms/BaseForm.php
Executable file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Base class for preferences.
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms;
|
||||
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\FormDisplay;
|
||||
|
||||
/**
|
||||
* Base form for user preferences
|
||||
*/
|
||||
abstract class BaseForm extends FormDisplay
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ConfigFile $cf Config file instance
|
||||
* @param int|null $server_id 0 if new server, validation; >= 1 if editing a server
|
||||
*/
|
||||
public function __construct(ConfigFile $cf, $server_id = null)
|
||||
{
|
||||
parent::__construct($cf);
|
||||
foreach (static::getForms() as $form_name => $form) {
|
||||
$this->registerForm($form_name, $form, $server_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List of available forms, each form is described as an array of fields to display.
|
||||
* Fields MUST have their counterparts in the $cfg array.
|
||||
*
|
||||
* To define form field, use the notation below:
|
||||
* $forms['Form group']['Form name'] = array('Option/path');
|
||||
*
|
||||
* You can assign default values set by special button ("set value: ..."), eg.:
|
||||
* 'Servers/1/pmadb' => 'phpmyadmin'
|
||||
*
|
||||
* To group options, use:
|
||||
* ':group:' . __('group name') // just define a group
|
||||
* or
|
||||
* 'option' => ':group' // group starting from this option
|
||||
* End group blocks with:
|
||||
* ':group:end'
|
||||
*
|
||||
* @todo This should be abstract, but that does not work in PHP 5
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getForms()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of fields used in the form.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getFields()
|
||||
{
|
||||
$names = [];
|
||||
foreach (static::getForms() as $form) {
|
||||
foreach ($form as $k => $v) {
|
||||
$names[] = is_int($k) ? $v : $k;
|
||||
}
|
||||
}
|
||||
return $names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns name of the form
|
||||
*
|
||||
* @todo This should be abstract, but that does not work in PHP 5
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
127
phpMyAdmin/libraries/classes/Config/Forms/BaseFormList.php
Executable file
127
phpMyAdmin/libraries/classes/Config/Forms/BaseFormList.php
Executable file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms;
|
||||
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
|
||||
class BaseFormList
|
||||
{
|
||||
/**
|
||||
* List of all forms
|
||||
*/
|
||||
protected static $all = array();
|
||||
|
||||
protected static $ns = 'PhpMyAdmin\\Config\\Forms\\';
|
||||
|
||||
private $_forms;
|
||||
|
||||
public static function getAll()
|
||||
{
|
||||
return static::$all;
|
||||
}
|
||||
|
||||
public static function isValid($name)
|
||||
{
|
||||
return in_array($name, static::$all);
|
||||
}
|
||||
|
||||
public static function get($name)
|
||||
{
|
||||
if (static::isValid($name)) {
|
||||
return static::$ns . $name . 'Form';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ConfigFile $cf Config file instance
|
||||
*/
|
||||
public function __construct(ConfigFile $cf)
|
||||
{
|
||||
$this->_forms = array();
|
||||
foreach (static::$all as $form) {
|
||||
$class = static::get($form);
|
||||
$this->_forms[] = new $class($cf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes forms, returns true on successful save
|
||||
*
|
||||
* @param bool $allow_partial_save allows for partial form saving
|
||||
* on failed validation
|
||||
* @param bool $check_form_submit whether check for $_POST['submit_save']
|
||||
*
|
||||
* @return boolean whether processing was successful
|
||||
*/
|
||||
public function process($allow_partial_save = true, $check_form_submit = true)
|
||||
{
|
||||
$ret = true;
|
||||
foreach ($this->_forms as $form) {
|
||||
$ret = $ret && $form->process($allow_partial_save, $check_form_submit);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays errors
|
||||
*
|
||||
* @return string HTML for errors
|
||||
*/
|
||||
public function displayErrors()
|
||||
{
|
||||
$ret = '';
|
||||
foreach ($this->_forms as $form) {
|
||||
$ret .= $form->displayErrors();
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts erroneous fields to their default values
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function fixErrors()
|
||||
{
|
||||
foreach ($this->_forms as $form) {
|
||||
$form->fixErrors();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether form validation failed
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasErrors()
|
||||
{
|
||||
$ret = false;
|
||||
foreach ($this->_forms as $form) {
|
||||
$ret = $ret || $form->hasErrors();
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of fields used in the form.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getFields()
|
||||
{
|
||||
$names = [];
|
||||
foreach (static::$all as $form) {
|
||||
$class = static::get($form);
|
||||
$names = array_merge($names, $class::getFields());
|
||||
}
|
||||
return $names;
|
||||
}
|
||||
}
|
||||
21
phpMyAdmin/libraries/classes/Config/Forms/Page/BrowseForm.php
Executable file
21
phpMyAdmin/libraries/classes/Config/Forms/Page/BrowseForm.php
Executable file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
use PhpMyAdmin\Config\Forms\User\MainForm;
|
||||
|
||||
class BrowseForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'Browse' => MainForm::getForms()['Browse']
|
||||
];
|
||||
}
|
||||
}
|
||||
22
phpMyAdmin/libraries/classes/Config/Forms/Page/DbStructureForm.php
Executable file
22
phpMyAdmin/libraries/classes/Config/Forms/Page/DbStructureForm.php
Executable file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
use PhpMyAdmin\Config\Forms\User\MainForm;
|
||||
|
||||
class DbStructureForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'DbStructure' => MainForm::getForms()['DbStructure']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
23
phpMyAdmin/libraries/classes/Config/Forms/Page/EditForm.php
Executable file
23
phpMyAdmin/libraries/classes/Config/Forms/Page/EditForm.php
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
use PhpMyAdmin\Config\Forms\User\MainForm;
|
||||
use PhpMyAdmin\Config\Forms\User\FeaturesForm;
|
||||
|
||||
class EditForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'Edit' => MainForm::getForms()['Edit'],
|
||||
'Text_fields' => FeaturesForm::getForms()['Text_fields'],
|
||||
];
|
||||
}
|
||||
}
|
||||
12
phpMyAdmin/libraries/classes/Config/Forms/Page/ExportForm.php
Executable file
12
phpMyAdmin/libraries/classes/Config/Forms/Page/ExportForm.php
Executable file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
class ExportForm extends \PhpMyAdmin\Config\Forms\User\ExportForm
|
||||
{
|
||||
}
|
||||
12
phpMyAdmin/libraries/classes/Config/Forms/Page/ImportForm.php
Executable file
12
phpMyAdmin/libraries/classes/Config/Forms/Page/ImportForm.php
Executable file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
class ImportForm extends \PhpMyAdmin\Config\Forms\User\ImportForm
|
||||
{
|
||||
}
|
||||
12
phpMyAdmin/libraries/classes/Config/Forms/Page/NaviForm.php
Executable file
12
phpMyAdmin/libraries/classes/Config/Forms/Page/NaviForm.php
Executable file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
class NaviForm extends \PhpMyAdmin\Config\Forms\User\NaviForm
|
||||
{
|
||||
}
|
||||
25
phpMyAdmin/libraries/classes/Config/Forms/Page/PageFormList.php
Executable file
25
phpMyAdmin/libraries/classes/Config/Forms/Page/PageFormList.php
Executable file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Page preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseFormList;
|
||||
|
||||
class PageFormList extends BaseFormList
|
||||
{
|
||||
protected static $all = array(
|
||||
'Browse',
|
||||
'DbStructure',
|
||||
'Edit',
|
||||
'Export',
|
||||
'Import',
|
||||
'Navi',
|
||||
'Sql',
|
||||
'TableStructure',
|
||||
);
|
||||
protected static $ns = '\\PhpMyAdmin\\Config\\Forms\\Page\\';
|
||||
}
|
||||
12
phpMyAdmin/libraries/classes/Config/Forms/Page/SqlForm.php
Executable file
12
phpMyAdmin/libraries/classes/Config/Forms/Page/SqlForm.php
Executable file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
class SqlForm extends \PhpMyAdmin\Config\Forms\User\SqlForm
|
||||
{
|
||||
}
|
||||
22
phpMyAdmin/libraries/classes/Config/Forms/Page/TableStructureForm.php
Executable file
22
phpMyAdmin/libraries/classes/Config/Forms/Page/TableStructureForm.php
Executable file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Page;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
use PhpMyAdmin\Config\Forms\User\MainForm;
|
||||
|
||||
class TableStructureForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
return [
|
||||
'TableStructure' => MainForm::getForms()['TableStructure']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
23
phpMyAdmin/libraries/classes/Config/Forms/Setup/ConfigForm.php
Executable file
23
phpMyAdmin/libraries/classes/Config/Forms/Setup/ConfigForm.php
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
class ConfigForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
return array(
|
||||
'Config' => array(
|
||||
'DefaultLang',
|
||||
'ServerDefault'
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
12
phpMyAdmin/libraries/classes/Config/Forms/Setup/ExportForm.php
Executable file
12
phpMyAdmin/libraries/classes/Config/Forms/Setup/ExportForm.php
Executable file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
class ExportForm extends \PhpMyAdmin\Config\Forms\User\ExportForm
|
||||
{
|
||||
}
|
||||
63
phpMyAdmin/libraries/classes/Config/Forms/Setup/FeaturesForm.php
Executable file
63
phpMyAdmin/libraries/classes/Config/Forms/Setup/FeaturesForm.php
Executable file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
class FeaturesForm extends \PhpMyAdmin\Config\Forms\User\FeaturesForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
$result = parent::getForms();
|
||||
/* Remove only_db/hide_db, we have proper Server form in setup */
|
||||
$result['Databases'] = array_diff(
|
||||
$result['Databases'],
|
||||
['Servers/1/only_db', 'Servers/1/hide_db']
|
||||
);
|
||||
/* Following are not available to user */
|
||||
$result['Import_export'] = array(
|
||||
'UploadDir',
|
||||
'SaveDir',
|
||||
'RecodingEngine' => ':group',
|
||||
'IconvExtraParams',
|
||||
':group:end',
|
||||
'ZipDump',
|
||||
'GZipDump',
|
||||
'BZipDump',
|
||||
'CompressOnFly'
|
||||
);
|
||||
$result['Security'] = array(
|
||||
'blowfish_secret',
|
||||
'CheckConfigurationPermissions',
|
||||
'TrustedProxies',
|
||||
'AllowUserDropDatabase',
|
||||
'AllowArbitraryServer',
|
||||
'ArbitraryServerRegexp',
|
||||
'LoginCookieRecall',
|
||||
'LoginCookieStore',
|
||||
'LoginCookieDeleteAll',
|
||||
'CaptchaLoginPublicKey',
|
||||
'CaptchaLoginPrivateKey'
|
||||
);
|
||||
$result['Developer'] = array(
|
||||
'UserprefsDeveloperTab',
|
||||
'DBG/sql',
|
||||
);
|
||||
$result['Other_core_settings'] = array(
|
||||
'OBGzip',
|
||||
'PersistentConnections',
|
||||
'ExecTimeLimit',
|
||||
'MemoryLimit',
|
||||
'UseDbSearch',
|
||||
'ProxyUrl',
|
||||
'ProxyUser',
|
||||
'ProxyPass',
|
||||
'AllowThirdPartyFraming',
|
||||
'ZeroConf',
|
||||
);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
12
phpMyAdmin/libraries/classes/Config/Forms/Setup/ImportForm.php
Executable file
12
phpMyAdmin/libraries/classes/Config/Forms/Setup/ImportForm.php
Executable file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
class ImportForm extends \PhpMyAdmin\Config\Forms\User\ImportForm
|
||||
{
|
||||
}
|
||||
20
phpMyAdmin/libraries/classes/Config/Forms/Setup/MainForm.php
Executable file
20
phpMyAdmin/libraries/classes/Config/Forms/Setup/MainForm.php
Executable file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
class MainForm extends \PhpMyAdmin\Config\Forms\User\MainForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
$result = parent::getForms();
|
||||
/* Following are not available to user */
|
||||
$result['Startup'][] = 'ShowPhpInfo';
|
||||
$result['Startup'][] = 'ShowChgPassword';
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
12
phpMyAdmin/libraries/classes/Config/Forms/Setup/NaviForm.php
Executable file
12
phpMyAdmin/libraries/classes/Config/Forms/Setup/NaviForm.php
Executable file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
class NaviForm extends \PhpMyAdmin\Config\Forms\User\NaviForm
|
||||
{
|
||||
}
|
||||
81
phpMyAdmin/libraries/classes/Config/Forms/Setup/ServersForm.php
Executable file
81
phpMyAdmin/libraries/classes/Config/Forms/Setup/ServersForm.php
Executable file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
class ServersForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
return array(
|
||||
'Server' => array('Servers' => array(1 => array(
|
||||
'verbose',
|
||||
'host',
|
||||
'port',
|
||||
'socket',
|
||||
'ssl',
|
||||
'compress'))),
|
||||
'Server_auth' => array('Servers' => array(1 => array(
|
||||
'auth_type',
|
||||
':group:' . __('Config authentication'),
|
||||
'user',
|
||||
'password',
|
||||
':group:end',
|
||||
':group:' . __('HTTP authentication'),
|
||||
'auth_http_realm',
|
||||
':group:end',
|
||||
':group:' . __('Signon authentication'),
|
||||
'SignonSession',
|
||||
'SignonURL',
|
||||
'LogoutURL'))),
|
||||
'Server_config' => array('Servers' => array(1 => array(
|
||||
'only_db',
|
||||
'hide_db',
|
||||
'AllowRoot',
|
||||
'AllowNoPassword',
|
||||
'DisableIS',
|
||||
'AllowDeny/order',
|
||||
'AllowDeny/rules',
|
||||
'SessionTimeZone'))),
|
||||
'Server_pmadb' => array('Servers' => array(1 => array(
|
||||
'pmadb' => 'phpmyadmin',
|
||||
'controlhost',
|
||||
'controlport',
|
||||
'controluser',
|
||||
'controlpass',
|
||||
'bookmarktable' => 'pma__bookmark',
|
||||
'relation' => 'pma__relation',
|
||||
'userconfig' => 'pma__userconfig',
|
||||
'users' => 'pma__users',
|
||||
'usergroups' => 'pma__usergroups',
|
||||
'navigationhiding' => 'pma__navigationhiding',
|
||||
'table_info' => 'pma__table_info',
|
||||
'column_info' => 'pma__column_info',
|
||||
'history' => 'pma__history',
|
||||
'recent' => 'pma__recent',
|
||||
'favorite' => 'pma__favorite',
|
||||
'table_uiprefs' => 'pma__table_uiprefs',
|
||||
'tracking' => 'pma__tracking',
|
||||
'table_coords' => 'pma__table_coords',
|
||||
'pdf_pages' => 'pma__pdf_pages',
|
||||
'savedsearches' => 'pma__savedsearches',
|
||||
'central_columns' => 'pma__central_columns',
|
||||
'designer_settings' => 'pma__designer_settings',
|
||||
'export_templates' => 'pma__export_templates',
|
||||
'MaxTableUiprefs' => 100))),
|
||||
'Server_tracking' => array('Servers' => array(1 => array(
|
||||
'tracking_version_auto_create',
|
||||
'tracking_default_statements',
|
||||
'tracking_add_drop_view',
|
||||
'tracking_add_drop_table',
|
||||
'tracking_add_drop_database',
|
||||
))),
|
||||
);
|
||||
}
|
||||
}
|
||||
25
phpMyAdmin/libraries/classes/Config/Forms/Setup/SetupFormList.php
Executable file
25
phpMyAdmin/libraries/classes/Config/Forms/Setup/SetupFormList.php
Executable file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Setup preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseFormList;
|
||||
|
||||
class SetupFormList extends BaseFormList
|
||||
{
|
||||
protected static $all = array(
|
||||
'Config',
|
||||
'Export',
|
||||
'Features',
|
||||
'Import',
|
||||
'Main',
|
||||
'Navi',
|
||||
'Servers',
|
||||
'Sql',
|
||||
);
|
||||
protected static $ns = '\\PhpMyAdmin\\Config\\Forms\\Setup\\';
|
||||
}
|
||||
19
phpMyAdmin/libraries/classes/Config/Forms/Setup/SqlForm.php
Executable file
19
phpMyAdmin/libraries/classes/Config/Forms/Setup/SqlForm.php
Executable file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\Setup;
|
||||
|
||||
class SqlForm extends \PhpMyAdmin\Config\Forms\User\SqlForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
$result = parent::getForms();
|
||||
/* Following are not available to user */
|
||||
$result['Sql_queries'][] = 'QueryHistoryDB';
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
142
phpMyAdmin/libraries/classes/Config/Forms/User/ExportForm.php
Executable file
142
phpMyAdmin/libraries/classes/Config/Forms/User/ExportForm.php
Executable file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
class ExportForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
return array(
|
||||
'Export_defaults' => array(
|
||||
'Export/method',
|
||||
':group:' . __('Quick'),
|
||||
'Export/quick_export_onserver',
|
||||
'Export/quick_export_onserver_overwrite',
|
||||
':group:end',
|
||||
':group:' . __('Custom'),
|
||||
'Export/format',
|
||||
'Export/compression',
|
||||
'Export/charset',
|
||||
'Export/lock_tables',
|
||||
'Export/as_separate_files',
|
||||
'Export/asfile' => ':group',
|
||||
'Export/onserver',
|
||||
'Export/onserver_overwrite',
|
||||
':group:end',
|
||||
'Export/file_template_table',
|
||||
'Export/file_template_database',
|
||||
'Export/file_template_server'
|
||||
),
|
||||
'Sql' => array(
|
||||
'Export/sql_include_comments' => ':group',
|
||||
'Export/sql_dates',
|
||||
'Export/sql_relation',
|
||||
'Export/sql_mime',
|
||||
':group:end',
|
||||
'Export/sql_use_transaction',
|
||||
'Export/sql_disable_fk',
|
||||
'Export/sql_views_as_tables',
|
||||
'Export/sql_metadata',
|
||||
'Export/sql_compatibility',
|
||||
'Export/sql_structure_or_data',
|
||||
':group:' . __('Structure'),
|
||||
'Export/sql_drop_database',
|
||||
'Export/sql_create_database',
|
||||
'Export/sql_drop_table',
|
||||
'Export/sql_create_table' => ':group',
|
||||
'Export/sql_if_not_exists',
|
||||
'Export/sql_auto_increment',
|
||||
':group:end',
|
||||
'Export/sql_create_view',
|
||||
'Export/sql_procedure_function',
|
||||
'Export/sql_create_trigger',
|
||||
'Export/sql_backquotes',
|
||||
':group:end',
|
||||
':group:' . __('Data'),
|
||||
'Export/sql_delayed',
|
||||
'Export/sql_ignore',
|
||||
'Export/sql_type',
|
||||
'Export/sql_insert_syntax',
|
||||
'Export/sql_max_query_size',
|
||||
'Export/sql_hex_for_binary',
|
||||
'Export/sql_utc_time'
|
||||
),
|
||||
'CodeGen' => array(
|
||||
'Export/codegen_format'
|
||||
),
|
||||
'Csv' => array(
|
||||
':group:' . __('CSV'),
|
||||
'Export/csv_separator',
|
||||
'Export/csv_enclosed',
|
||||
'Export/csv_escaped',
|
||||
'Export/csv_terminated',
|
||||
'Export/csv_null',
|
||||
'Export/csv_removeCRLF',
|
||||
'Export/csv_columns',
|
||||
':group:end',
|
||||
':group:' . __('CSV for MS Excel'),
|
||||
'Export/excel_null',
|
||||
'Export/excel_removeCRLF',
|
||||
'Export/excel_columns',
|
||||
'Export/excel_edition'
|
||||
),
|
||||
'Latex' => array(
|
||||
'Export/latex_caption',
|
||||
'Export/latex_structure_or_data',
|
||||
':group:' . __('Structure'),
|
||||
'Export/latex_structure_caption',
|
||||
'Export/latex_structure_continued_caption',
|
||||
'Export/latex_structure_label',
|
||||
'Export/latex_relation',
|
||||
'Export/latex_comments',
|
||||
'Export/latex_mime',
|
||||
':group:end',
|
||||
':group:' . __('Data'),
|
||||
'Export/latex_columns',
|
||||
'Export/latex_data_caption',
|
||||
'Export/latex_data_continued_caption',
|
||||
'Export/latex_data_label',
|
||||
'Export/latex_null'
|
||||
),
|
||||
'Microsoft_Office' => array(
|
||||
':group:' . __('Microsoft Word 2000'),
|
||||
'Export/htmlword_structure_or_data',
|
||||
'Export/htmlword_null',
|
||||
'Export/htmlword_columns'),
|
||||
'Open_Document' => array(
|
||||
':group:' . __('OpenDocument Spreadsheet'),
|
||||
'Export/ods_columns',
|
||||
'Export/ods_null',
|
||||
':group:end',
|
||||
':group:' . __('OpenDocument Text'),
|
||||
'Export/odt_structure_or_data',
|
||||
':group:' . __('Structure'),
|
||||
'Export/odt_relation',
|
||||
'Export/odt_comments',
|
||||
'Export/odt_mime',
|
||||
':group:end',
|
||||
':group:' . __('Data'),
|
||||
'Export/odt_columns',
|
||||
'Export/odt_null'
|
||||
),
|
||||
'Texy' => array(
|
||||
'Export/texytext_structure_or_data',
|
||||
':group:' . __('Data'),
|
||||
'Export/texytext_null',
|
||||
'Export/texytext_columns'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return __('Export');
|
||||
}
|
||||
}
|
||||
84
phpMyAdmin/libraries/classes/Config/Forms/User/FeaturesForm.php
Executable file
84
phpMyAdmin/libraries/classes/Config/Forms/User/FeaturesForm.php
Executable file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
class FeaturesForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
$result = array(
|
||||
'General' => array(
|
||||
'VersionCheck',
|
||||
'NaturalOrder',
|
||||
'InitialSlidersState',
|
||||
'SkipLockedTables',
|
||||
'DisableMultiTableMaintenance',
|
||||
'ShowHint',
|
||||
'SendErrorReports',
|
||||
'ConsoleEnterExecutes',
|
||||
'DisableShortcutKeys',
|
||||
'FontSize',
|
||||
),
|
||||
'Databases' => array(
|
||||
'Servers/1/only_db', // saves to Server/only_db
|
||||
'Servers/1/hide_db', // saves to Server/hide_db
|
||||
'MaxDbList',
|
||||
'MaxTableList',
|
||||
'DefaultConnectionCollation',
|
||||
),
|
||||
'Text_fields' => array(
|
||||
'CharEditing',
|
||||
'MinSizeForInputField',
|
||||
'MaxSizeForInputField',
|
||||
'CharTextareaCols',
|
||||
'CharTextareaRows',
|
||||
'TextareaCols',
|
||||
'TextareaRows',
|
||||
'LongtextDoubleTextarea'
|
||||
),
|
||||
'Page_titles' => array(
|
||||
'TitleDefault',
|
||||
'TitleTable',
|
||||
'TitleDatabase',
|
||||
'TitleServer'
|
||||
),
|
||||
'Warnings' => array(
|
||||
'PmaNoRelation_DisableWarning',
|
||||
'SuhosinDisableWarning',
|
||||
'LoginCookieValidityDisableWarning',
|
||||
'ReservedWordDisableWarning'
|
||||
),
|
||||
'Console' => array(
|
||||
'Console/Mode',
|
||||
'Console/StartHistory',
|
||||
'Console/AlwaysExpand',
|
||||
'Console/CurrentQuery',
|
||||
'Console/EnterExecutes',
|
||||
'Console/DarkTheme',
|
||||
'Console/Height',
|
||||
'Console/GroupQueries',
|
||||
'Console/OrderBy',
|
||||
'Console/Order',
|
||||
),
|
||||
);
|
||||
// skip Developer form if no setting is available
|
||||
if ($GLOBALS['cfg']['UserprefsDeveloperTab']) {
|
||||
$result['Developer'] = array(
|
||||
'DBG/sql'
|
||||
);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return __('Features');
|
||||
}
|
||||
}
|
||||
60
phpMyAdmin/libraries/classes/Config/Forms/User/ImportForm.php
Executable file
60
phpMyAdmin/libraries/classes/Config/Forms/User/ImportForm.php
Executable file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
class ImportForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
return array(
|
||||
'Import_defaults' => array(
|
||||
'Import/format',
|
||||
'Import/charset',
|
||||
'Import/allow_interrupt',
|
||||
'Import/skip_queries'
|
||||
),
|
||||
'Sql' => array(
|
||||
'Import/sql_compatibility',
|
||||
'Import/sql_no_auto_value_on_zero',
|
||||
'Import/sql_read_as_multibytes'
|
||||
),
|
||||
'Csv' => array(
|
||||
':group:' . __('CSV'),
|
||||
'Import/csv_replace',
|
||||
'Import/csv_ignore',
|
||||
'Import/csv_terminated',
|
||||
'Import/csv_enclosed',
|
||||
'Import/csv_escaped',
|
||||
'Import/csv_col_names',
|
||||
':group:end',
|
||||
':group:' . __('CSV using LOAD DATA'),
|
||||
'Import/ldi_replace',
|
||||
'Import/ldi_ignore',
|
||||
'Import/ldi_terminated',
|
||||
'Import/ldi_enclosed',
|
||||
'Import/ldi_escaped',
|
||||
'Import/ldi_local_option'
|
||||
),
|
||||
'Open_Document' => array(
|
||||
':group:' . __('OpenDocument Spreadsheet'),
|
||||
'Import/ods_col_names',
|
||||
'Import/ods_empty_rows',
|
||||
'Import/ods_recognize_percentages',
|
||||
'Import/ods_recognize_currency'
|
||||
),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return __('Import');
|
||||
}
|
||||
}
|
||||
86
phpMyAdmin/libraries/classes/Config/Forms/User/MainForm.php
Executable file
86
phpMyAdmin/libraries/classes/Config/Forms/User/MainForm.php
Executable file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
class MainForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
return array(
|
||||
'Startup' => array(
|
||||
'ShowCreateDb',
|
||||
'ShowStats',
|
||||
'ShowServerInfo'
|
||||
),
|
||||
'DbStructure' => array(
|
||||
'ShowDbStructureCharset',
|
||||
'ShowDbStructureComment',
|
||||
'ShowDbStructureCreation',
|
||||
'ShowDbStructureLastUpdate',
|
||||
'ShowDbStructureLastCheck'
|
||||
),
|
||||
'TableStructure' => array(
|
||||
'HideStructureActions',
|
||||
'ShowColumnComments',
|
||||
':group:' . __('Default transformations'),
|
||||
'DefaultTransformations/Hex',
|
||||
'DefaultTransformations/Substring',
|
||||
'DefaultTransformations/Bool2Text',
|
||||
'DefaultTransformations/External',
|
||||
'DefaultTransformations/PreApPend',
|
||||
'DefaultTransformations/DateFormat',
|
||||
'DefaultTransformations/Inline',
|
||||
'DefaultTransformations/TextImageLink',
|
||||
'DefaultTransformations/TextLink',
|
||||
':group:end'
|
||||
),
|
||||
'Browse' => array(
|
||||
'TableNavigationLinksMode',
|
||||
'ActionLinksMode',
|
||||
'ShowAll',
|
||||
'MaxRows',
|
||||
'Order',
|
||||
'BrowsePointerEnable',
|
||||
'BrowseMarkerEnable',
|
||||
'GridEditing',
|
||||
'SaveCellsAtOnce',
|
||||
'RepeatCells',
|
||||
'LimitChars',
|
||||
'RowActionLinks',
|
||||
'RowActionLinksWithoutUnique',
|
||||
'TablePrimaryKeyOrder',
|
||||
'RememberSorting',
|
||||
'RelationalDisplay'
|
||||
),
|
||||
'Edit' => array(
|
||||
'ProtectBinary',
|
||||
'ShowFunctionFields',
|
||||
'ShowFieldTypesInDataEditView',
|
||||
'InsertRows',
|
||||
'ForeignKeyDropdownOrder',
|
||||
'ForeignKeyMaxLimit'
|
||||
),
|
||||
'Tabs' => array(
|
||||
'TabsMode',
|
||||
'DefaultTabServer',
|
||||
'DefaultTabDatabase',
|
||||
'DefaultTabTable'
|
||||
),
|
||||
'DisplayRelationalSchema' => array(
|
||||
'PDFDefaultPageSize'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return __('Main panel');
|
||||
}
|
||||
}
|
||||
61
phpMyAdmin/libraries/classes/Config/Forms/User/NaviForm.php
Executable file
61
phpMyAdmin/libraries/classes/Config/Forms/User/NaviForm.php
Executable file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
class NaviForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
return array(
|
||||
'Navi_panel' => array(
|
||||
'ShowDatabasesNavigationAsTree',
|
||||
'NavigationLinkWithMainPanel',
|
||||
'NavigationDisplayLogo',
|
||||
'NavigationLogoLink',
|
||||
'NavigationLogoLinkWindow',
|
||||
'NavigationTreePointerEnable',
|
||||
'FirstLevelNavigationItems',
|
||||
'NavigationTreeDisplayItemFilterMinimum',
|
||||
'NumRecentTables',
|
||||
'NumFavoriteTables',
|
||||
'NavigationWidth',
|
||||
),
|
||||
'Navi_tree' => array(
|
||||
'MaxNavigationItems',
|
||||
'NavigationTreeEnableGrouping',
|
||||
'NavigationTreeEnableExpansion',
|
||||
'NavigationTreeShowTables',
|
||||
'NavigationTreeShowViews',
|
||||
'NavigationTreeShowFunctions',
|
||||
'NavigationTreeShowProcedures',
|
||||
'NavigationTreeShowEvents'
|
||||
),
|
||||
'Navi_servers' => array(
|
||||
'NavigationDisplayServers',
|
||||
'DisplayServersList',
|
||||
),
|
||||
'Navi_databases' => array(
|
||||
'NavigationTreeDisplayDbFilterMinimum',
|
||||
'NavigationTreeDbSeparator'
|
||||
),
|
||||
'Navi_tables' => array(
|
||||
'NavigationTreeDefaultTabTable',
|
||||
'NavigationTreeDefaultTabTable2',
|
||||
'NavigationTreeTableSeparator',
|
||||
'NavigationTreeTableLevel',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return __('Navigation panel');
|
||||
}
|
||||
}
|
||||
42
phpMyAdmin/libraries/classes/Config/Forms/User/SqlForm.php
Executable file
42
phpMyAdmin/libraries/classes/Config/Forms/User/SqlForm.php
Executable file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseForm;
|
||||
|
||||
class SqlForm extends BaseForm
|
||||
{
|
||||
public static function getForms()
|
||||
{
|
||||
return array(
|
||||
'Sql_queries' => array(
|
||||
'ShowSQL',
|
||||
'Confirm',
|
||||
'QueryHistoryMax',
|
||||
'IgnoreMultiSubmitErrors',
|
||||
'MaxCharactersInDisplayedSQL',
|
||||
'RetainQueryBox',
|
||||
'CodemirrorEnable',
|
||||
'LintEnable',
|
||||
'EnableAutocompleteForTablesAndColumns',
|
||||
'DefaultForeignKeyChecks',
|
||||
),
|
||||
'Sql_box' => array(
|
||||
'SQLQuery/Edit',
|
||||
'SQLQuery/Explain',
|
||||
'SQLQuery/ShowAsPHP',
|
||||
'SQLQuery/Refresh',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return __('SQL queries');
|
||||
}
|
||||
}
|
||||
23
phpMyAdmin/libraries/classes/Config/Forms/User/UserFormList.php
Executable file
23
phpMyAdmin/libraries/classes/Config/Forms/User/UserFormList.php
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* User preferences form
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config\Forms\User;
|
||||
|
||||
use PhpMyAdmin\Config\Forms\BaseFormList;
|
||||
|
||||
class UserFormList extends BaseFormList
|
||||
{
|
||||
protected static $all = array(
|
||||
'Features',
|
||||
'Sql',
|
||||
'Navi',
|
||||
'Main',
|
||||
'Import',
|
||||
'Export',
|
||||
);
|
||||
protected static $ns = '\\PhpMyAdmin\\Config\\Forms\\User\\';
|
||||
}
|
||||
231
phpMyAdmin/libraries/classes/Config/PageSettings.php
Executable file
231
phpMyAdmin/libraries/classes/Config/PageSettings.php
Executable file
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Page-related settings
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\FormDisplay;
|
||||
use PhpMyAdmin\Config\Forms\Page\PageFormList;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Response;
|
||||
use PhpMyAdmin\UserPreferences;
|
||||
|
||||
/**
|
||||
* Page-related settings
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class PageSettings
|
||||
{
|
||||
|
||||
/**
|
||||
* Contains id of the form element
|
||||
* @var string
|
||||
*/
|
||||
private $_elemId = 'page_settings_modal';
|
||||
|
||||
/**
|
||||
* Name of the group to show
|
||||
* @var string
|
||||
*/
|
||||
private $_groupName = '';
|
||||
|
||||
/**
|
||||
* Contains HTML of errors
|
||||
* @var string
|
||||
*/
|
||||
private $_errorHTML = '';
|
||||
|
||||
/**
|
||||
* Contains HTML of settings
|
||||
* @var string
|
||||
*/
|
||||
private $_HTML = '';
|
||||
|
||||
/**
|
||||
* @var UserPreferences
|
||||
*/
|
||||
private $userPreferences;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $formGroupName The name of config form group to display
|
||||
* @param string $elemId Id of the div containing settings
|
||||
*/
|
||||
public function __construct($formGroupName, $elemId = null)
|
||||
{
|
||||
$this->userPreferences = new UserPreferences();
|
||||
|
||||
$form_class = PageFormList::get($formGroupName);
|
||||
if (is_null($form_class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['printview']) && $_REQUEST['printview'] == '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($elemId)) {
|
||||
$this->_elemId = $elemId;
|
||||
}
|
||||
$this->_groupName = $formGroupName;
|
||||
|
||||
$cf = new ConfigFile($GLOBALS['PMA_Config']->base_settings);
|
||||
$this->userPreferences->pageInit($cf);
|
||||
|
||||
$form_display = new $form_class($cf);
|
||||
|
||||
// Process form
|
||||
$error = null;
|
||||
if (isset($_POST['submit_save'])
|
||||
&& $_POST['submit_save'] == $formGroupName
|
||||
) {
|
||||
$this->_processPageSettings($form_display, $cf, $error);
|
||||
}
|
||||
|
||||
// Display forms
|
||||
$this->_HTML = $this->_getPageSettingsDisplay($form_display, $error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process response to form
|
||||
*
|
||||
* @param FormDisplay &$form_display Form
|
||||
* @param ConfigFile &$cf Configuration file
|
||||
* @param Message|null &$error Error message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _processPageSettings(&$form_display, &$cf, &$error)
|
||||
{
|
||||
if ($form_display->process(false) && !$form_display->hasErrors()) {
|
||||
// save settings
|
||||
$result = $this->userPreferences->save($cf->getConfigArray());
|
||||
if ($result === true) {
|
||||
// reload page
|
||||
$response = Response::getInstance();
|
||||
Core::sendHeaderLocation(
|
||||
$response->getFooter()->getSelfUrl('unencoded')
|
||||
);
|
||||
exit();
|
||||
} else {
|
||||
$error = $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store errors in _errorHTML
|
||||
*
|
||||
* @param FormDisplay &$form_display Form
|
||||
* @param Message|null &$error Error message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _storeError(&$form_display, &$error)
|
||||
{
|
||||
$retval = '';
|
||||
if ($error) {
|
||||
$retval .= $error->getDisplay();
|
||||
}
|
||||
if ($form_display->hasErrors()) {
|
||||
// form has errors
|
||||
$retval .= '<div class="error config-form">'
|
||||
. '<b>' . __(
|
||||
'Cannot save settings, submitted configuration form contains '
|
||||
. 'errors!'
|
||||
) . '</b>'
|
||||
. $form_display->displayErrors()
|
||||
. '</div>';
|
||||
}
|
||||
$this->_errorHTML = $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display page-related settings
|
||||
*
|
||||
* @param FormDisplay &$form_display Form
|
||||
* @param Message &$error Error message
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _getPageSettingsDisplay(&$form_display, &$error)
|
||||
{
|
||||
$response = Response::getInstance();
|
||||
|
||||
$retval = '';
|
||||
|
||||
$this->_storeError($form_display, $error);
|
||||
|
||||
$retval .= '<div id="' . $this->_elemId . '">';
|
||||
$retval .= '<div class="page_settings">';
|
||||
$retval .= $form_display->getDisplay(
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
$response->getFooter()->getSelfUrl(),
|
||||
array(
|
||||
'submit_save' => $this->_groupName
|
||||
)
|
||||
);
|
||||
$retval .= '</div>';
|
||||
$retval .= '</div>';
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML output
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHTML()
|
||||
{
|
||||
return $this->_HTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error HTML output
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getErrorHTML()
|
||||
{
|
||||
return $this->_errorHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group to show for Page-related settings
|
||||
* @param string $formGroupName The name of config form group to display
|
||||
* @return PageSettings
|
||||
*/
|
||||
public static function showGroup($formGroupName)
|
||||
{
|
||||
$object = new PageSettings($formGroupName);
|
||||
|
||||
$response = Response::getInstance();
|
||||
$response->addHTML($object->getErrorHTML());
|
||||
$response->addHTML($object->getHTML());
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML for navigation settings
|
||||
* @return string
|
||||
*/
|
||||
public static function getNaviSettings()
|
||||
{
|
||||
$object = new PageSettings('Navi', 'pma_navigation_settings');
|
||||
|
||||
$response = Response::getInstance();
|
||||
$response->addHTML($object->getErrorHTML());
|
||||
return $object->getHTML();
|
||||
}
|
||||
}
|
||||
560
phpMyAdmin/libraries/classes/Config/ServerConfigChecks.php
Executable file
560
phpMyAdmin/libraries/classes/Config/ServerConfigChecks.php
Executable file
@@ -0,0 +1,560 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Server config checks management
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\Descriptions;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Sanitize;
|
||||
use PhpMyAdmin\Setup\Index as SetupIndex;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Performs various compatibility, security and consistency checks on current config
|
||||
*
|
||||
* Outputs results to message list, must be called between SetupIndex::messagesBegin()
|
||||
* and SetupIndex::messagesEnd()
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class ServerConfigChecks
|
||||
{
|
||||
/**
|
||||
* @var ConfigFile configurations being checked
|
||||
*/
|
||||
protected $cfg;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ConfigFile $cfg Configuration
|
||||
*/
|
||||
public function __construct(ConfigFile $cfg)
|
||||
{
|
||||
$this->cfg = $cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform config checks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function performConfigChecks()
|
||||
{
|
||||
$blowfishSecret = $this->cfg->get('blowfish_secret');
|
||||
$blowfishSecretSet = false;
|
||||
$cookieAuthUsed = false;
|
||||
|
||||
list($cookieAuthUsed, $blowfishSecret, $blowfishSecretSet)
|
||||
= $this->performConfigChecksServers(
|
||||
$cookieAuthUsed, $blowfishSecret, $blowfishSecretSet
|
||||
);
|
||||
|
||||
$this->performConfigChecksCookieAuthUsed(
|
||||
$cookieAuthUsed, $blowfishSecretSet,
|
||||
$blowfishSecret
|
||||
);
|
||||
|
||||
//
|
||||
// $cfg['AllowArbitraryServer']
|
||||
// should be disabled
|
||||
//
|
||||
if ($this->cfg->getValue('AllowArbitraryServer')) {
|
||||
$sAllowArbitraryServerWarn = sprintf(
|
||||
__(
|
||||
'This %soption%s should be disabled as it allows attackers to '
|
||||
. 'bruteforce login to any MySQL server. If you feel this is necessary, '
|
||||
. 'use %srestrict login to MySQL server%s or %strusted proxies list%s. '
|
||||
. 'However, IP-based protection with trusted proxies list may not be '
|
||||
. 'reliable if your IP belongs to an ISP where thousands of users, '
|
||||
. 'including you, are connected to.'
|
||||
),
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Security]',
|
||||
'[/a]',
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Security]',
|
||||
'[/a]',
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Security]',
|
||||
'[/a]'
|
||||
);
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'AllowArbitraryServer',
|
||||
Descriptions::get('AllowArbitraryServer'),
|
||||
Sanitize::sanitize($sAllowArbitraryServerWarn)
|
||||
);
|
||||
}
|
||||
|
||||
$this->performConfigChecksLoginCookie();
|
||||
|
||||
$sDirectoryNotice = __(
|
||||
'This value should be double checked to ensure that this directory is '
|
||||
. 'neither world accessible nor readable or writable by other users on '
|
||||
. 'your server.'
|
||||
);
|
||||
|
||||
//
|
||||
// $cfg['SaveDir']
|
||||
// should not be world-accessible
|
||||
//
|
||||
if ($this->cfg->getValue('SaveDir') != '') {
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'SaveDir',
|
||||
Descriptions::get('SaveDir'),
|
||||
Sanitize::sanitize($sDirectoryNotice)
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// $cfg['TempDir']
|
||||
// should not be world-accessible
|
||||
//
|
||||
if ($this->cfg->getValue('TempDir') != '') {
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'TempDir',
|
||||
Descriptions::get('TempDir'),
|
||||
Sanitize::sanitize($sDirectoryNotice)
|
||||
);
|
||||
}
|
||||
|
||||
$this->performConfigChecksZips();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check config of servers
|
||||
*
|
||||
* @param boolean $cookieAuthUsed Cookie auth is used
|
||||
* @param string $blowfishSecret Blowfish secret
|
||||
* @param boolean $blowfishSecretSet Blowfish secret set
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function performConfigChecksServers(
|
||||
$cookieAuthUsed, $blowfishSecret,
|
||||
$blowfishSecretSet
|
||||
) {
|
||||
$serverCnt = $this->cfg->getServerCount();
|
||||
for ($i = 1; $i <= $serverCnt; $i++) {
|
||||
$cookieAuthServer
|
||||
= ($this->cfg->getValue("Servers/$i/auth_type") == 'cookie');
|
||||
$cookieAuthUsed |= $cookieAuthServer;
|
||||
$serverName = $this->performConfigChecksServersGetServerName(
|
||||
$this->cfg->getServerName($i), $i
|
||||
);
|
||||
$serverName = htmlspecialchars($serverName);
|
||||
|
||||
list($blowfishSecret, $blowfishSecretSet)
|
||||
= $this->performConfigChecksServersSetBlowfishSecret(
|
||||
$blowfishSecret, $cookieAuthServer, $blowfishSecretSet
|
||||
);
|
||||
|
||||
//
|
||||
// $cfg['Servers'][$i]['ssl']
|
||||
// should be enabled if possible
|
||||
//
|
||||
if (!$this->cfg->getValue("Servers/$i/ssl")) {
|
||||
$title = Descriptions::get('Servers/1/ssl') . " ($serverName)";
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
"Servers/$i/ssl",
|
||||
$title,
|
||||
__(
|
||||
'You should use SSL connections if your database server '
|
||||
. 'supports it.'
|
||||
)
|
||||
);
|
||||
}
|
||||
$sSecurityInfoMsg = Sanitize::sanitize(sprintf(
|
||||
__(
|
||||
'If you feel this is necessary, use additional protection settings - '
|
||||
. '%1$shost authentication%2$s settings and %3$strusted proxies list%4%s. '
|
||||
. 'However, IP-based protection may not be reliable if your IP belongs '
|
||||
. 'to an ISP where thousands of users, including you, are connected to.'
|
||||
),
|
||||
'[a@' . Url::getCommon(array('page' => 'servers', 'mode' => 'edit', 'id' => $i)) . '#tab_Server_config]',
|
||||
'[/a]',
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Security]',
|
||||
'[/a]'
|
||||
));
|
||||
|
||||
//
|
||||
// $cfg['Servers'][$i]['auth_type']
|
||||
// warn about full user credentials if 'auth_type' is 'config'
|
||||
//
|
||||
if ($this->cfg->getValue("Servers/$i/auth_type") == 'config'
|
||||
&& $this->cfg->getValue("Servers/$i/user") != ''
|
||||
&& $this->cfg->getValue("Servers/$i/password") != ''
|
||||
) {
|
||||
$title = Descriptions::get('Servers/1/auth_type')
|
||||
. " ($serverName)";
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
"Servers/$i/auth_type",
|
||||
$title,
|
||||
Sanitize::sanitize(sprintf(
|
||||
__(
|
||||
'You set the [kbd]config[/kbd] authentication type and included '
|
||||
. 'username and password for auto-login, which is not a desirable '
|
||||
. 'option for live hosts. Anyone who knows or guesses your phpMyAdmin '
|
||||
. 'URL can directly access your phpMyAdmin panel. Set %1$sauthentication '
|
||||
. 'type%2$s to [kbd]cookie[/kbd] or [kbd]http[/kbd].'
|
||||
),
|
||||
'[a@' . Url::getCommon(array('page' => 'servers', 'mode' => 'edit', 'id' => $i)) . '#tab_Server]',
|
||||
'[/a]'
|
||||
))
|
||||
. ' ' . $sSecurityInfoMsg
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// $cfg['Servers'][$i]['AllowRoot']
|
||||
// $cfg['Servers'][$i]['AllowNoPassword']
|
||||
// serious security flaw
|
||||
//
|
||||
if ($this->cfg->getValue("Servers/$i/AllowRoot")
|
||||
&& $this->cfg->getValue("Servers/$i/AllowNoPassword")
|
||||
) {
|
||||
$title = Descriptions::get('Servers/1/AllowNoPassword')
|
||||
. " ($serverName)";
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
"Servers/$i/AllowNoPassword",
|
||||
$title,
|
||||
__('You allow for connecting to the server without a password.')
|
||||
. ' ' . $sSecurityInfoMsg
|
||||
);
|
||||
}
|
||||
}
|
||||
return array($cookieAuthUsed, $blowfishSecret, $blowfishSecretSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set blowfish secret
|
||||
*
|
||||
* @param string $blowfishSecret Blowfish secret
|
||||
* @param boolean $cookieAuthServer Cookie auth is used
|
||||
* @param boolean $blowfishSecretSet Blowfish secret set
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function performConfigChecksServersSetBlowfishSecret(
|
||||
$blowfishSecret, $cookieAuthServer, $blowfishSecretSet
|
||||
) {
|
||||
if ($cookieAuthServer && $blowfishSecret === null) {
|
||||
$blowfishSecretSet = true;
|
||||
$this->cfg->set('blowfish_secret', Util::generateRandom(32));
|
||||
}
|
||||
return array($blowfishSecret, $blowfishSecretSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define server name
|
||||
*
|
||||
* @param string $serverName Server name
|
||||
* @param int $serverId Server id
|
||||
*
|
||||
* @return string Server name
|
||||
*/
|
||||
protected function performConfigChecksServersGetServerName(
|
||||
$serverName, $serverId
|
||||
) {
|
||||
if ($serverName == 'localhost') {
|
||||
$serverName .= " [$serverId]";
|
||||
return $serverName;
|
||||
}
|
||||
return $serverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform config checks for zip part.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function performConfigChecksZips() {
|
||||
$this->performConfigChecksServerGZipdump();
|
||||
$this->performConfigChecksServerBZipdump();
|
||||
$this->performConfigChecksServersZipdump();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform config checks for zip part.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function performConfigChecksServersZipdump() {
|
||||
//
|
||||
// $cfg['ZipDump']
|
||||
// requires zip_open in import
|
||||
//
|
||||
if ($this->cfg->getValue('ZipDump') && !$this->functionExists('zip_open')) {
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'ZipDump_import',
|
||||
Descriptions::get('ZipDump'),
|
||||
Sanitize::sanitize(sprintf(
|
||||
__(
|
||||
'%sZip decompression%s requires functions (%s) which are unavailable '
|
||||
. 'on this system.'
|
||||
),
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Import_export]',
|
||||
'[/a]',
|
||||
'zip_open'
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// $cfg['ZipDump']
|
||||
// requires gzcompress in export
|
||||
//
|
||||
if ($this->cfg->getValue('ZipDump') && !$this->functionExists('gzcompress')) {
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'ZipDump_export',
|
||||
Descriptions::get('ZipDump'),
|
||||
Sanitize::sanitize(sprintf(
|
||||
__(
|
||||
'%sZip compression%s requires functions (%s) which are unavailable on '
|
||||
. 'this system.'
|
||||
),
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Import_export]',
|
||||
'[/a]',
|
||||
'gzcompress'
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check config of servers
|
||||
*
|
||||
* @param boolean $cookieAuthUsed Cookie auth is used
|
||||
* @param boolean $blowfishSecretSet Blowfish secret set
|
||||
* @param string $blowfishSecret Blowfish secret
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function performConfigChecksCookieAuthUsed(
|
||||
$cookieAuthUsed, $blowfishSecretSet,
|
||||
$blowfishSecret
|
||||
) {
|
||||
//
|
||||
// $cfg['blowfish_secret']
|
||||
// it's required for 'cookie' authentication
|
||||
//
|
||||
if ($cookieAuthUsed) {
|
||||
if ($blowfishSecretSet) {
|
||||
// 'cookie' auth used, blowfish_secret was generated
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'blowfish_secret_created',
|
||||
Descriptions::get('blowfish_secret'),
|
||||
Sanitize::sanitize(__(
|
||||
'You didn\'t have blowfish secret set and have enabled '
|
||||
. '[kbd]cookie[/kbd] authentication, so a key was automatically '
|
||||
. 'generated for you. It is used to encrypt cookies; you don\'t need to '
|
||||
. 'remember it.'
|
||||
))
|
||||
);
|
||||
} else {
|
||||
$blowfishWarnings = array();
|
||||
// check length
|
||||
if (strlen($blowfishSecret) < 32) {
|
||||
// too short key
|
||||
$blowfishWarnings[] = __(
|
||||
'Key is too short, it should have at least 32 characters.'
|
||||
);
|
||||
}
|
||||
// check used characters
|
||||
$hasDigits = (bool)preg_match('/\d/', $blowfishSecret);
|
||||
$hasChars = (bool)preg_match('/\S/', $blowfishSecret);
|
||||
$hasNonword = (bool)preg_match('/\W/', $blowfishSecret);
|
||||
if (!$hasDigits || !$hasChars || !$hasNonword) {
|
||||
$blowfishWarnings[] = Sanitize::sanitize(
|
||||
__(
|
||||
'Key should contain letters, numbers [em]and[/em] '
|
||||
. 'special characters.'
|
||||
)
|
||||
);
|
||||
}
|
||||
if (!empty($blowfishWarnings)) {
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'blowfish_warnings' . count($blowfishWarnings),
|
||||
Descriptions::get('blowfish_secret'),
|
||||
implode('<br />', $blowfishWarnings)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check configuration for login cookie
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function performConfigChecksLoginCookie() {
|
||||
//
|
||||
// $cfg['LoginCookieValidity']
|
||||
// value greater than session.gc_maxlifetime will cause
|
||||
// random session invalidation after that time
|
||||
$loginCookieValidity = $this->cfg->getValue('LoginCookieValidity');
|
||||
if ($loginCookieValidity > ini_get('session.gc_maxlifetime')
|
||||
) {
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'LoginCookieValidity',
|
||||
Descriptions::get('LoginCookieValidity'),
|
||||
Sanitize::sanitize(sprintf(
|
||||
__(
|
||||
'%1$sLogin cookie validity%2$s greater than %3$ssession.gc_maxlifetime%4$s may '
|
||||
. 'cause random session invalidation (currently session.gc_maxlifetime '
|
||||
. 'is %5$d).'
|
||||
),
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Security]',
|
||||
'[/a]',
|
||||
'[a@' . Core::getPHPDocLink('session.configuration.php#ini.session.gc-maxlifetime') . ']',
|
||||
'[/a]',
|
||||
ini_get('session.gc_maxlifetime')
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// $cfg['LoginCookieValidity']
|
||||
// should be at most 1800 (30 min)
|
||||
//
|
||||
if ($loginCookieValidity > 1800) {
|
||||
SetupIndex::messagesSet(
|
||||
'notice',
|
||||
'LoginCookieValidity',
|
||||
Descriptions::get('LoginCookieValidity'),
|
||||
Sanitize::sanitize(sprintf(
|
||||
__(
|
||||
'%sLogin cookie validity%s should be set to 1800 seconds (30 minutes) '
|
||||
. 'at most. Values larger than 1800 may pose a security risk such as '
|
||||
. 'impersonation.'
|
||||
),
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Security]',
|
||||
'[/a]'
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// $cfg['LoginCookieValidity']
|
||||
// $cfg['LoginCookieStore']
|
||||
// LoginCookieValidity must be less or equal to LoginCookieStore
|
||||
//
|
||||
if (($this->cfg->getValue('LoginCookieStore') != 0)
|
||||
&& ($loginCookieValidity > $this->cfg->getValue('LoginCookieStore'))
|
||||
) {
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'LoginCookieValidity',
|
||||
Descriptions::get('LoginCookieValidity'),
|
||||
Sanitize::sanitize(sprintf(
|
||||
__(
|
||||
'If using [kbd]cookie[/kbd] authentication and %sLogin cookie store%s '
|
||||
. 'is not 0, %sLogin cookie validity%s must be set to a value less or '
|
||||
. 'equal to it.'
|
||||
),
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Security]',
|
||||
'[/a]',
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Security]',
|
||||
'[/a]'
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check GZipDump configuration
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function performConfigChecksServerBZipdump()
|
||||
{
|
||||
//
|
||||
// $cfg['BZipDump']
|
||||
// requires bzip2 functions
|
||||
//
|
||||
if ($this->cfg->getValue('BZipDump')
|
||||
&& (!$this->functionExists('bzopen') || !$this->functionExists('bzcompress'))
|
||||
) {
|
||||
$functions = $this->functionExists('bzopen')
|
||||
? '' :
|
||||
'bzopen';
|
||||
$functions .= $this->functionExists('bzcompress')
|
||||
? ''
|
||||
: ($functions ? ', ' : '') . 'bzcompress';
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'BZipDump',
|
||||
Descriptions::get('BZipDump'),
|
||||
Sanitize::sanitize(
|
||||
sprintf(
|
||||
__(
|
||||
'%1$sBzip2 compression and decompression%2$s requires functions (%3$s) which '
|
||||
. 'are unavailable on this system.'
|
||||
),
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Import_export]',
|
||||
'[/a]',
|
||||
$functions
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check GZipDump configuration
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function performConfigChecksServerGZipdump()
|
||||
{
|
||||
//
|
||||
// $cfg['GZipDump']
|
||||
// requires zlib functions
|
||||
//
|
||||
if ($this->cfg->getValue('GZipDump')
|
||||
&& (!$this->functionExists('gzopen') || !$this->functionExists('gzencode'))
|
||||
) {
|
||||
SetupIndex::messagesSet(
|
||||
'error',
|
||||
'GZipDump',
|
||||
Descriptions::get('GZipDump'),
|
||||
Sanitize::sanitize(sprintf(
|
||||
__(
|
||||
'%1$sGZip compression and decompression%2$s requires functions (%3$s) which '
|
||||
. 'are unavailable on this system.'
|
||||
),
|
||||
'[a@' . Url::getCommon(array('page' => 'form', 'formset' => 'Features')) . '#tab_Import_export]',
|
||||
'[/a]',
|
||||
'gzencode'
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around function_exists to allow mock in test
|
||||
*
|
||||
* @param string $name Function name
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function functionExists($name)
|
||||
{
|
||||
return function_exists($name);
|
||||
}
|
||||
}
|
||||
589
phpMyAdmin/libraries/classes/Config/Validator.php
Executable file
589
phpMyAdmin/libraries/classes/Config/Validator.php
Executable file
@@ -0,0 +1,589 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Form validation for configuration editor
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Config;
|
||||
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Validation class for various validation functions
|
||||
*
|
||||
* Validation function takes two argument: id for which it is called
|
||||
* and array of fields' values (usually values for entire formset, as defined
|
||||
* in forms.inc.php).
|
||||
* The function must always return an array with an error (or error array)
|
||||
* assigned to a form element (formset name or field path). Even if there are
|
||||
* no errors, key must be set with an empty value.
|
||||
*
|
||||
* Validation functions are assigned in $cfg_db['_validators'] (config.values.php).
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class Validator
|
||||
{
|
||||
/**
|
||||
* Returns validator list
|
||||
*
|
||||
* @param ConfigFile $cf Config file instance
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getValidators(ConfigFile $cf)
|
||||
{
|
||||
static $validators = null;
|
||||
|
||||
if ($validators !== null) {
|
||||
return $validators;
|
||||
}
|
||||
|
||||
$validators = $cf->getDbEntry('_validators', array());
|
||||
if ($GLOBALS['PMA_Config']->get('is_setup')) {
|
||||
return $validators;
|
||||
}
|
||||
|
||||
// not in setup script: load additional validators for user
|
||||
// preferences we need original config values not overwritten
|
||||
// by user preferences, creating a new PhpMyAdmin\Config instance is a
|
||||
// better idea than hacking into its code
|
||||
$uvs = $cf->getDbEntry('_userValidators', array());
|
||||
foreach ($uvs as $field => $uv_list) {
|
||||
$uv_list = (array)$uv_list;
|
||||
foreach ($uv_list as &$uv) {
|
||||
if (!is_array($uv)) {
|
||||
continue;
|
||||
}
|
||||
for ($i = 1, $nb = count($uv); $i < $nb; $i++) {
|
||||
if (mb_substr($uv[$i], 0, 6) == 'value:') {
|
||||
$uv[$i] = Core::arrayRead(
|
||||
mb_substr($uv[$i], 6),
|
||||
$GLOBALS['PMA_Config']->base_settings
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$validators[$field] = isset($validators[$field])
|
||||
? array_merge((array)$validators[$field], $uv_list)
|
||||
: $uv_list;
|
||||
}
|
||||
return $validators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs validation $validator_id on values $values and returns error list.
|
||||
*
|
||||
* Return values:
|
||||
* o array, keys - field path or formset id, values - array of errors
|
||||
* when $isPostSource is true values is an empty array to allow for error list
|
||||
* cleanup in HTML document
|
||||
* o false - when no validators match name(s) given by $validator_id
|
||||
*
|
||||
* @param ConfigFile $cf Config file instance
|
||||
* @param string|array $validator_id ID of validator(s) to run
|
||||
* @param array &$values Values to validate
|
||||
* @param bool $isPostSource tells whether $values are directly from
|
||||
* POST request
|
||||
*
|
||||
* @return bool|array
|
||||
*/
|
||||
public static function validate(
|
||||
ConfigFile $cf, $validator_id, array &$values, $isPostSource
|
||||
) {
|
||||
// find validators
|
||||
$validator_id = (array) $validator_id;
|
||||
$validators = static::getValidators($cf);
|
||||
$vids = array();
|
||||
foreach ($validator_id as &$vid) {
|
||||
$vid = $cf->getCanonicalPath($vid);
|
||||
if (isset($validators[$vid])) {
|
||||
$vids[] = $vid;
|
||||
}
|
||||
}
|
||||
if (empty($vids)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// create argument list with canonical paths and remember path mapping
|
||||
$arguments = array();
|
||||
$key_map = array();
|
||||
foreach ($values as $k => $v) {
|
||||
$k2 = $isPostSource ? str_replace('-', '/', $k) : $k;
|
||||
$k2 = mb_strpos($k2, '/')
|
||||
? $cf->getCanonicalPath($k2)
|
||||
: $k2;
|
||||
$key_map[$k2] = $k;
|
||||
$arguments[$k2] = $v;
|
||||
}
|
||||
|
||||
// validate
|
||||
$result = array();
|
||||
foreach ($vids as $vid) {
|
||||
// call appropriate validation functions
|
||||
foreach ((array)$validators[$vid] as $validator) {
|
||||
$vdef = (array) $validator;
|
||||
$vname = array_shift($vdef);
|
||||
$vname = 'PhpMyAdmin\Config\Validator::' . $vname;
|
||||
$args = array_merge(array($vid, &$arguments), $vdef);
|
||||
$r = call_user_func_array($vname, $args);
|
||||
|
||||
// merge results
|
||||
if (!is_array($r)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($r as $key => $error_list) {
|
||||
// skip empty values if $isPostSource is false
|
||||
if (! $isPostSource && empty($error_list)) {
|
||||
continue;
|
||||
}
|
||||
if (! isset($result[$key])) {
|
||||
$result[$key] = array();
|
||||
}
|
||||
$result[$key] = array_merge(
|
||||
$result[$key], (array)$error_list
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restore original paths
|
||||
$new_result = array();
|
||||
foreach ($result as $k => $v) {
|
||||
$k2 = isset($key_map[$k]) ? $key_map[$k] : $k;
|
||||
if (is_array($v)) {
|
||||
$new_result[$k2] = array_map('htmlspecialchars', $v);
|
||||
} else {
|
||||
$new_result[$k2] = htmlspecialchars($v);
|
||||
}
|
||||
}
|
||||
return empty($new_result) ? true : $new_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test database connection
|
||||
*
|
||||
* @param string $host host name
|
||||
* @param string $port tcp port to use
|
||||
* @param string $socket socket to use
|
||||
* @param string $user username to use
|
||||
* @param string $pass password to use
|
||||
* @param string $error_key key to use in return array
|
||||
*
|
||||
* @return bool|array
|
||||
*/
|
||||
public static function testDBConnection(
|
||||
$host,
|
||||
$port,
|
||||
$socket,
|
||||
$user,
|
||||
$pass = null,
|
||||
$error_key = 'Server'
|
||||
) {
|
||||
if ($GLOBALS['cfg']['DBG']['demo']) {
|
||||
// Connection test disabled on the demo server!
|
||||
return true;
|
||||
}
|
||||
|
||||
$error = null;
|
||||
$host = Core::sanitizeMySQLHost($host);
|
||||
|
||||
if (function_exists('error_clear_last')) {
|
||||
/* PHP 7 only code */
|
||||
error_clear_last();
|
||||
}
|
||||
|
||||
if (DatabaseInterface::checkDbExtension('mysqli')) {
|
||||
$socket = empty($socket) ? null : $socket;
|
||||
$port = empty($port) ? null : $port;
|
||||
$extension = 'mysqli';
|
||||
} else {
|
||||
$socket = empty($socket) ? null : ':' . ($socket[0] == '/' ? '' : '/') . $socket;
|
||||
$port = empty($port) ? null : ':' . $port;
|
||||
$extension = 'mysql';
|
||||
}
|
||||
|
||||
if ($extension == 'mysql') {
|
||||
$conn = @mysql_connect($host . $port . $socket, $user, $pass);
|
||||
if (! $conn) {
|
||||
$error = __('Could not connect to the database server!');
|
||||
} else {
|
||||
mysql_close($conn);
|
||||
}
|
||||
} else {
|
||||
$conn = @mysqli_connect($host, $user, $pass, null, $port, $socket);
|
||||
if (! $conn) {
|
||||
$error = __('Could not connect to the database server!');
|
||||
} else {
|
||||
mysqli_close($conn);
|
||||
}
|
||||
}
|
||||
if (! is_null($error)) {
|
||||
$error .= ' - ' . error_get_last();
|
||||
}
|
||||
return is_null($error) ? true : array($error_key => $error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate server config
|
||||
*
|
||||
* @param string $path path to config, not used
|
||||
* keep this parameter since the method is invoked using
|
||||
* reflection along with other similar methods
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validateServer($path, array $values)
|
||||
{
|
||||
$result = array(
|
||||
'Server' => '',
|
||||
'Servers/1/user' => '',
|
||||
'Servers/1/SignonSession' => '',
|
||||
'Servers/1/SignonURL' => ''
|
||||
);
|
||||
$error = false;
|
||||
if (empty($values['Servers/1/auth_type'])) {
|
||||
$values['Servers/1/auth_type'] = '';
|
||||
$result['Servers/1/auth_type'] = __('Invalid authentication type!');
|
||||
$error = true;
|
||||
}
|
||||
if ($values['Servers/1/auth_type'] == 'config'
|
||||
&& empty($values['Servers/1/user'])
|
||||
) {
|
||||
$result['Servers/1/user'] = __(
|
||||
'Empty username while using [kbd]config[/kbd] authentication method!'
|
||||
);
|
||||
$error = true;
|
||||
}
|
||||
if ($values['Servers/1/auth_type'] == 'signon'
|
||||
&& empty($values['Servers/1/SignonSession'])
|
||||
) {
|
||||
$result['Servers/1/SignonSession'] = __(
|
||||
'Empty signon session name '
|
||||
. 'while using [kbd]signon[/kbd] authentication method!'
|
||||
);
|
||||
$error = true;
|
||||
}
|
||||
if ($values['Servers/1/auth_type'] == 'signon'
|
||||
&& empty($values['Servers/1/SignonURL'])
|
||||
) {
|
||||
$result['Servers/1/SignonURL'] = __(
|
||||
'Empty signon URL while using [kbd]signon[/kbd] authentication '
|
||||
. 'method!'
|
||||
);
|
||||
$error = true;
|
||||
}
|
||||
|
||||
if (! $error && $values['Servers/1/auth_type'] == 'config') {
|
||||
$password = '';
|
||||
if (! empty($values['Servers/1/password'])) {
|
||||
$password = $values['Servers/1/password'];
|
||||
}
|
||||
$test = static::testDBConnection(
|
||||
empty($values['Servers/1/host']) ? '' : $values['Servers/1/host'],
|
||||
empty($values['Servers/1/port']) ? '' : $values['Servers/1/port'],
|
||||
empty($values['Servers/1/socket']) ? '' : $values['Servers/1/socket'],
|
||||
empty($values['Servers/1/user']) ? '' : $values['Servers/1/user'],
|
||||
$password,
|
||||
'Server'
|
||||
);
|
||||
|
||||
if ($test !== true) {
|
||||
$result = array_merge($result, $test);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate pmadb config
|
||||
*
|
||||
* @param string $path path to config, not used
|
||||
* keep this parameter since the method is invoked using
|
||||
* reflection along with other similar methods
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validatePMAStorage($path, array $values)
|
||||
{
|
||||
$result = array(
|
||||
'Server_pmadb' => '',
|
||||
'Servers/1/controluser' => '',
|
||||
'Servers/1/controlpass' => ''
|
||||
);
|
||||
$error = false;
|
||||
|
||||
if (empty($values['Servers/1/pmadb'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
if (empty($values['Servers/1/controluser'])) {
|
||||
$result['Servers/1/controluser'] = __(
|
||||
'Empty phpMyAdmin control user while using phpMyAdmin configuration '
|
||||
. 'storage!'
|
||||
);
|
||||
$error = true;
|
||||
}
|
||||
if (empty($values['Servers/1/controlpass'])) {
|
||||
$result['Servers/1/controlpass'] = __(
|
||||
'Empty phpMyAdmin control user password while using phpMyAdmin '
|
||||
. 'configuration storage!'
|
||||
);
|
||||
$error = true;
|
||||
}
|
||||
if (! $error) {
|
||||
$test = static::testDBConnection(
|
||||
empty($values['Servers/1/host']) ? '' : $values['Servers/1/host'],
|
||||
empty($values['Servers/1/port']) ? '' : $values['Servers/1/port'],
|
||||
empty($values['Servers/1/socket']) ? '' : $values['Servers/1/socket'],
|
||||
empty($values['Servers/1/controluser']) ? '' : $values['Servers/1/controluser'],
|
||||
empty($values['Servers/1/controlpass']) ? '' : $values['Servers/1/controlpass'],
|
||||
'Server_pmadb'
|
||||
);
|
||||
if ($test !== true) {
|
||||
$result = array_merge($result, $test);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validates regular expression
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validateRegex($path, array $values)
|
||||
{
|
||||
$result = array($path => '');
|
||||
|
||||
if (empty($values[$path])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (function_exists('error_clear_last')) {
|
||||
/* PHP 7 only code */
|
||||
error_clear_last();
|
||||
$last_error = null;
|
||||
} else {
|
||||
// As fallback we trigger another error to ensure
|
||||
// that preg error will be different
|
||||
@strpos();
|
||||
$last_error = error_get_last();
|
||||
}
|
||||
|
||||
$matches = array();
|
||||
// in libraries/ListDatabase.php _checkHideDatabase(),
|
||||
// a '/' is used as the delimiter for hide_db
|
||||
@preg_match('/' . Util::requestString($values[$path]) . '/', '', $matches);
|
||||
|
||||
$current_error = error_get_last();
|
||||
|
||||
if ($current_error !== $last_error) {
|
||||
$error = preg_replace('/^preg_match\(\): /', '', $current_error['message']);
|
||||
return array($path => $error);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates TrustedProxies field
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validateTrustedProxies($path, array $values)
|
||||
{
|
||||
$result = array($path => array());
|
||||
|
||||
if (empty($values[$path])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (is_array($values[$path]) || is_object($values[$path])) {
|
||||
// value already processed by FormDisplay::save
|
||||
$lines = array();
|
||||
foreach ($values[$path] as $ip => $v) {
|
||||
$v = Util::requestString($v);
|
||||
$lines[] = preg_match('/^-\d+$/', $ip)
|
||||
? $v
|
||||
: $ip . ': ' . $v;
|
||||
}
|
||||
} else {
|
||||
// AJAX validation
|
||||
$lines = explode("\n", $values[$path]);
|
||||
}
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line);
|
||||
$matches = array();
|
||||
// we catch anything that may (or may not) be an IP
|
||||
if (!preg_match("/^(.+):(?:[ ]?)\\w+$/", $line, $matches)) {
|
||||
$result[$path][] = __('Incorrect value:') . ' '
|
||||
. htmlspecialchars($line);
|
||||
continue;
|
||||
}
|
||||
// now let's check whether we really have an IP address
|
||||
if (filter_var($matches[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false
|
||||
&& filter_var($matches[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false
|
||||
) {
|
||||
$ip = htmlspecialchars(trim($matches[1]));
|
||||
$result[$path][] = sprintf(__('Incorrect IP address: %s'), $ip);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests integer value
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
* @param bool $allow_neg allow negative values
|
||||
* @param bool $allow_zero allow zero
|
||||
* @param int $max_value max allowed value
|
||||
* @param string $error_string error message string
|
||||
*
|
||||
* @return string empty string if test is successful
|
||||
*/
|
||||
public static function validateNumber(
|
||||
$path,
|
||||
array $values,
|
||||
$allow_neg,
|
||||
$allow_zero,
|
||||
$max_value,
|
||||
$error_string
|
||||
) {
|
||||
if (empty($values[$path])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$value = Util::requestString($values[$path]);
|
||||
|
||||
if (intval($value) != $value
|
||||
|| (! $allow_neg && $value < 0)
|
||||
|| (! $allow_zero && $value == 0)
|
||||
|| $value > $max_value
|
||||
) {
|
||||
return $error_string;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates port number
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validatePortNumber($path, array $values)
|
||||
{
|
||||
return array(
|
||||
$path => static::validateNumber(
|
||||
$path,
|
||||
$values,
|
||||
false,
|
||||
false,
|
||||
65535,
|
||||
__('Not a valid port number!')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates positive number
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validatePositiveNumber($path, array $values)
|
||||
{
|
||||
return array(
|
||||
$path => static::validateNumber(
|
||||
$path,
|
||||
$values,
|
||||
false,
|
||||
false,
|
||||
PHP_INT_MAX,
|
||||
__('Not a positive number!')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates non-negative number
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validateNonNegativeNumber($path, array $values)
|
||||
{
|
||||
return array(
|
||||
$path => static::validateNumber(
|
||||
$path,
|
||||
$values,
|
||||
false,
|
||||
true,
|
||||
PHP_INT_MAX,
|
||||
__('Not a non-negative number!')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates value according to given regular expression
|
||||
* Pattern and modifiers must be a valid for PCRE <b>and</b> JavaScript RegExp
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
* @param string $regex regular expression to match
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validateByRegex($path, array $values, $regex)
|
||||
{
|
||||
if (!isset($values[$path])) {
|
||||
return '';
|
||||
}
|
||||
$result = preg_match($regex, Util::requestString($values[$path]));
|
||||
return array($path => ($result ? '' : __('Incorrect value!')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates upper bound for numeric inputs
|
||||
*
|
||||
* @param string $path path to config
|
||||
* @param array $values config values
|
||||
* @param int $max_value maximal allowed value
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function validateUpperBound($path, array $values, $max_value)
|
||||
{
|
||||
$result = $values[$path] <= $max_value;
|
||||
return array($path => ($result ? ''
|
||||
: sprintf(__('Value must be less than or equal to %s!'), $max_value)));
|
||||
}
|
||||
}
|
||||
152
phpMyAdmin/libraries/classes/Console.php
Executable file
152
phpMyAdmin/libraries/classes/Console.php
Executable file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Used to render the console of PMA's pages
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use PhpMyAdmin\Bookmark;
|
||||
use PhpMyAdmin\Relation;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Class used to output the console
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class Console
|
||||
{
|
||||
/**
|
||||
* Whether to display anything
|
||||
*
|
||||
* @access private
|
||||
* @var bool
|
||||
*/
|
||||
private $_isEnabled;
|
||||
|
||||
/**
|
||||
* Whether we are servicing an ajax request.
|
||||
*
|
||||
* @access private
|
||||
* @var bool
|
||||
*/
|
||||
private $_isAjax;
|
||||
|
||||
/**
|
||||
* @var Relation
|
||||
*/
|
||||
private $relation;
|
||||
|
||||
/**
|
||||
* Creates a new class instance
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->_isEnabled = true;
|
||||
$this->relation = new Relation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ajax flag to indicate whether
|
||||
* we are servicing an ajax request
|
||||
*
|
||||
* @param bool $isAjax Whether we are servicing an ajax request
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setAjax($isAjax)
|
||||
{
|
||||
$this->_isAjax = (boolean) $isAjax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the rendering of the footer
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disable()
|
||||
{
|
||||
$this->_isEnabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the bookmark content
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public static function getBookmarkContent()
|
||||
{
|
||||
$cfgBookmark = Bookmark::getParams($GLOBALS['cfg']['Server']['user']);
|
||||
if ($cfgBookmark) {
|
||||
$bookmarks = Bookmark::getList(
|
||||
$GLOBALS['dbi'],
|
||||
$GLOBALS['cfg']['Server']['user']
|
||||
);
|
||||
$count_bookmarks = count($bookmarks);
|
||||
if ($count_bookmarks > 0) {
|
||||
$welcomeMessage = sprintf(
|
||||
_ngettext(
|
||||
'Showing %1$d bookmark (both private and shared)',
|
||||
'Showing %1$d bookmarks (both private and shared)',
|
||||
$count_bookmarks
|
||||
),
|
||||
$count_bookmarks
|
||||
);
|
||||
} else {
|
||||
$welcomeMessage = __('No bookmarks');
|
||||
}
|
||||
unset($count_bookmarks, $private_message, $shared_message);
|
||||
return Template::get('console/bookmark_content')
|
||||
->render(
|
||||
array(
|
||||
'welcome_message' => $welcomeMessage,
|
||||
'bookmarks' => $bookmarks,
|
||||
)
|
||||
);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of JS scripts required by console
|
||||
*
|
||||
* @return array list of scripts
|
||||
*/
|
||||
public function getScripts()
|
||||
{
|
||||
return array('console.js');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the console
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getDisplay()
|
||||
{
|
||||
if ((! $this->_isAjax) && $this->_isEnabled) {
|
||||
$cfgBookmark = Bookmark::getParams(
|
||||
$GLOBALS['cfg']['Server']['user']
|
||||
);
|
||||
|
||||
$image = Util::getImage('console', __('SQL Query Console'));
|
||||
$_sql_history = $this->relation->getHistory(
|
||||
$GLOBALS['cfg']['Server']['user']
|
||||
);
|
||||
$bookmarkContent = static::getBookmarkContent();
|
||||
|
||||
return Template::get('console/display')->render([
|
||||
'cfg_bookmark' => $cfgBookmark,
|
||||
'image' => $image,
|
||||
'sql_history' => $_sql_history,
|
||||
'bookmark_content' => $bookmarkContent,
|
||||
]);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
39
phpMyAdmin/libraries/classes/Controllers/Controller.php
Executable file
39
phpMyAdmin/libraries/classes/Controllers/Controller.php
Executable file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\Controller
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Response;
|
||||
|
||||
/**
|
||||
* Base class for all of controller
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
abstract class Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Response
|
||||
*/
|
||||
protected $response;
|
||||
|
||||
/**
|
||||
* @var DatabaseInterface
|
||||
*/
|
||||
protected $dbi;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($response, $dbi)
|
||||
{
|
||||
$this->response = $response;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
}
|
||||
1115
phpMyAdmin/libraries/classes/Controllers/Database/DatabaseStructureController.php
Executable file
1115
phpMyAdmin/libraries/classes/Controllers/Database/DatabaseStructureController.php
Executable file
File diff suppressed because it is too large
Load Diff
30
phpMyAdmin/libraries/classes/Controllers/DatabaseController.php
Executable file
30
phpMyAdmin/libraries/classes/Controllers/DatabaseController.php
Executable file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\DatabaseController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
/**
|
||||
* Handles database related logic
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
abstract class DatabaseController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var string $db
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($response, $dbi, $db)
|
||||
{
|
||||
parent::__construct($response, $dbi);
|
||||
$this->db = $db;
|
||||
}
|
||||
}
|
||||
263
phpMyAdmin/libraries/classes/Controllers/Server/ServerBinlogController.php
Executable file
263
phpMyAdmin/libraries/classes/Controllers/Server/ServerBinlogController.php
Executable file
@@ -0,0 +1,263 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\Server\ServerBinlogController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Controllers\Controller;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Server\Common;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Handles viewing binary logs
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
class ServerBinlogController extends Controller
|
||||
{
|
||||
/**
|
||||
* array binary log files
|
||||
*/
|
||||
protected $binary_logs;
|
||||
|
||||
/**
|
||||
* Constructs ServerBinlogController
|
||||
*/
|
||||
public function __construct($response, $dbi)
|
||||
{
|
||||
parent::__construct($response, $dbi);
|
||||
$this->binary_logs = $this->dbi->fetchResult(
|
||||
'SHOW MASTER LOGS',
|
||||
'Log_name',
|
||||
null,
|
||||
DatabaseInterface::CONNECT_USER,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Index action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
/**
|
||||
* Does the common work
|
||||
*/
|
||||
include_once 'libraries/server_common.inc.php';
|
||||
|
||||
$url_params = array();
|
||||
if (! isset($_POST['log'])
|
||||
|| ! array_key_exists($_POST['log'], $this->binary_logs)
|
||||
) {
|
||||
$_POST['log'] = '';
|
||||
} else {
|
||||
$url_params['log'] = $_POST['log'];
|
||||
}
|
||||
|
||||
if (!empty($_POST['dontlimitchars'])) {
|
||||
$url_params['dontlimitchars'] = 1;
|
||||
}
|
||||
|
||||
$this->response->addHTML(
|
||||
Template::get('server/sub_page_header')->render([
|
||||
'type' => 'binlog',
|
||||
])
|
||||
);
|
||||
$this->response->addHTML($this->_getLogSelector($url_params));
|
||||
$this->response->addHTML($this->_getLogInfo($url_params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the html for log selector.
|
||||
*
|
||||
* @param array $url_params links parameters
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _getLogSelector(array $url_params)
|
||||
{
|
||||
return Template::get('server/binlog/log_selector')->render(
|
||||
array(
|
||||
'url_params' => $url_params,
|
||||
'binary_logs' => $this->binary_logs,
|
||||
'log' => $_POST['log'],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the html for binary log information.
|
||||
*
|
||||
* @param array $url_params links parameters
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _getLogInfo(array $url_params)
|
||||
{
|
||||
/**
|
||||
* Need to find the real end of rows?
|
||||
*/
|
||||
if (! isset($_POST['pos'])) {
|
||||
$pos = 0;
|
||||
} else {
|
||||
/* We need this to be a integer */
|
||||
$pos = (int) $_POST['pos'];
|
||||
}
|
||||
|
||||
$sql_query = 'SHOW BINLOG EVENTS';
|
||||
if (! empty($_POST['log'])) {
|
||||
$sql_query .= ' IN \'' . $_POST['log'] . '\'';
|
||||
}
|
||||
$sql_query .= ' LIMIT ' . $pos . ', ' . intval($GLOBALS['cfg']['MaxRows']);
|
||||
|
||||
/**
|
||||
* Sends the query
|
||||
*/
|
||||
$result = $this->dbi->query($sql_query);
|
||||
|
||||
/**
|
||||
* prepare some vars for displaying the result table
|
||||
*/
|
||||
// Gets the list of fields properties
|
||||
if (isset($result) && $result) {
|
||||
$num_rows = $this->dbi->numRows($result);
|
||||
} else {
|
||||
$num_rows = 0;
|
||||
}
|
||||
|
||||
if (empty($_POST['dontlimitchars'])) {
|
||||
$dontlimitchars = false;
|
||||
} else {
|
||||
$dontlimitchars = true;
|
||||
$url_params['dontlimitchars'] = 1;
|
||||
}
|
||||
|
||||
//html output
|
||||
$html = Util::getMessage(Message::success(), $sql_query);
|
||||
$html .= '<table id="binlogTable">'
|
||||
. '<thead>'
|
||||
. '<tr>'
|
||||
. '<td colspan="6" class="center">';
|
||||
|
||||
$html .= $this->_getNavigationRow($url_params, $pos, $num_rows, $dontlimitchars);
|
||||
|
||||
$html .= '</td>'
|
||||
. '</tr>'
|
||||
. '<tr>'
|
||||
. '<th>' . __('Log name') . '</th>'
|
||||
. '<th>' . __('Position') . '</th>'
|
||||
. '<th>' . __('Event type') . '</th>'
|
||||
. '<th>' . __('Server ID') . '</th>'
|
||||
. '<th>' . __('Original position') . '</th>'
|
||||
. '<th>' . __('Information') . '</th>'
|
||||
. '</tr>'
|
||||
. '</thead>'
|
||||
. '<tbody>';
|
||||
|
||||
$html .= $this->_getAllLogItemInfo($result, $dontlimitchars);
|
||||
|
||||
$html .= '</tbody>'
|
||||
. '</table>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the html for Navigation Row.
|
||||
*
|
||||
* @param array $url_params Links parameters
|
||||
* @param int $pos Position to display
|
||||
* @param int $num_rows Number of results row
|
||||
* @param bool $dontlimitchars Whether limit chars
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _getNavigationRow(array $url_params, $pos, $num_rows, $dontlimitchars)
|
||||
{
|
||||
$html = "";
|
||||
// we do not know how much rows are in the binlog
|
||||
// so we can just force 'NEXT' button
|
||||
if ($pos > 0) {
|
||||
$this_url_params = $url_params;
|
||||
if ($pos > $GLOBALS['cfg']['MaxRows']) {
|
||||
$this_url_params['pos'] = $pos - $GLOBALS['cfg']['MaxRows'];
|
||||
}
|
||||
|
||||
$html .= '<a href="server_binlog.php" data-post="'
|
||||
. Url::getCommon($this_url_params, '', false) . '"';
|
||||
if (Util::showIcons('TableNavigationLinksMode')) {
|
||||
$html .= ' title="' . _pgettext('Previous page', 'Previous') . '">';
|
||||
} else {
|
||||
$html .= '>' . _pgettext('Previous page', 'Previous');
|
||||
} // end if... else...
|
||||
$html .= ' < </a> - ';
|
||||
}
|
||||
|
||||
$this_url_params = $url_params;
|
||||
if ($pos > 0) {
|
||||
$this_url_params['pos'] = $pos;
|
||||
}
|
||||
if ($dontlimitchars) {
|
||||
unset($this_url_params['dontlimitchars']);
|
||||
$tempTitle = __('Truncate Shown Queries');
|
||||
$tempImgMode = 'partial';
|
||||
} else {
|
||||
$this_url_params['dontlimitchars'] = 1;
|
||||
$tempTitle = __('Show Full Queries');
|
||||
$tempImgMode = 'full';
|
||||
}
|
||||
$html .= '<a href="server_binlog.php" data-post="' . Url::getCommon($this_url_params, '', false)
|
||||
. '" title="' . $tempTitle . '">'
|
||||
. '<img src="' . $GLOBALS['pmaThemeImage'] . 's_' . $tempImgMode
|
||||
. 'text.png" alt="' . $tempTitle . '" /></a>';
|
||||
|
||||
// we do not now how much rows are in the binlog
|
||||
// so we can just force 'NEXT' button
|
||||
if ($num_rows >= $GLOBALS['cfg']['MaxRows']) {
|
||||
$this_url_params = $url_params;
|
||||
$this_url_params['pos'] = $pos + $GLOBALS['cfg']['MaxRows'];
|
||||
$html .= ' - <a href="server_binlog.php" data-post="'
|
||||
. Url::getCommon($this_url_params, '', false)
|
||||
. '"';
|
||||
if (Util::showIcons('TableNavigationLinksMode')) {
|
||||
$html .= ' title="' . _pgettext('Next page', 'Next') . '">';
|
||||
} else {
|
||||
$html .= '>' . _pgettext('Next page', 'Next');
|
||||
} // end if... else...
|
||||
$html .= ' > </a>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the html for all binary log items.
|
||||
*
|
||||
* @param resource $result MySQL Query result
|
||||
* @param bool $dontlimitchars Whether limit chars
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _getAllLogItemInfo($result, $dontlimitchars)
|
||||
{
|
||||
$html = "";
|
||||
while ($value = $this->dbi->fetchAssoc($result)) {
|
||||
$html .= Template::get('server/binlog/log_row')->render(
|
||||
array(
|
||||
'value' => $value,
|
||||
'dontlimitchars' => $dontlimitchars,
|
||||
)
|
||||
);
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\Server\ServerCollationsController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Controllers\Controller;
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\Server\Common;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
/**
|
||||
* Handles viewing character sets and collations
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
class ServerCollationsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Index action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$dbi = $GLOBALS['dbi'];
|
||||
$disableIs = $GLOBALS['cfg']['Server']['DisableIS'];
|
||||
|
||||
/**
|
||||
* Does the common work
|
||||
*/
|
||||
include_once 'libraries/server_common.inc.php';
|
||||
|
||||
$this->response->addHTML(
|
||||
Template::get('server/sub_page_header')->render([
|
||||
'type' => 'collations',
|
||||
])
|
||||
);
|
||||
$this->response->addHTML(
|
||||
$this->_getHtmlForCharsets(
|
||||
Charsets::getMySQLCharsets($dbi, $disableIs),
|
||||
Charsets::getMySQLCollations($dbi, $disableIs),
|
||||
Charsets::getMySQLCharsetsDescriptions($dbi, $disableIs),
|
||||
Charsets::getMySQLCollationsDefault($dbi, $disableIs)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the html for server Character Sets and Collations.
|
||||
*
|
||||
* @param array $mysqlCharsets Mysql Charsets list
|
||||
* @param array $mysqlCollations Mysql Collations list
|
||||
* @param array $mysqlCharsetsDesc Charsets descriptions
|
||||
* @param array $mysqlDftCollations Default Collations list
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function _getHtmlForCharsets(array $mysqlCharsets, array $mysqlCollations,
|
||||
array $mysqlCharsetsDesc, array $mysqlDftCollations
|
||||
) {
|
||||
return Template::get('server/collations/charsets')->render(
|
||||
array(
|
||||
'mysql_charsets' => $mysqlCharsets,
|
||||
'mysql_collations' => $mysqlCollations,
|
||||
'mysql_charsets_desc' => $mysqlCharsetsDesc,
|
||||
'mysql_dft_collations' => $mysqlDftCollations,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
470
phpMyAdmin/libraries/classes/Controllers/Server/ServerDatabasesController.php
Executable file
470
phpMyAdmin/libraries/classes/Controllers/Server/ServerDatabasesController.php
Executable file
@@ -0,0 +1,470 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\Server\ServerDatabasesController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Controllers\Controller;
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Response;
|
||||
use PhpMyAdmin\Server\Common;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Handles viewing and creating and deleting databases
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
class ServerDatabasesController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var array array of database details
|
||||
*/
|
||||
private $_databases;
|
||||
/**
|
||||
* @var int number of databases
|
||||
*/
|
||||
private $_database_count;
|
||||
/**
|
||||
* @var string sort by column
|
||||
*/
|
||||
private $_sort_by;
|
||||
/**
|
||||
* @var string sort order of databases
|
||||
*/
|
||||
private $_sort_order;
|
||||
/**
|
||||
* @var boolean whether to show database statistics
|
||||
*/
|
||||
private $_dbstats;
|
||||
/**
|
||||
* @var int position in list navigation
|
||||
*/
|
||||
private $_pos;
|
||||
|
||||
/**
|
||||
* Index action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
include_once 'libraries/check_user_privileges.inc.php';
|
||||
|
||||
$response = Response::getInstance();
|
||||
|
||||
if (isset($_POST['drop_selected_dbs'])
|
||||
&& $response->isAjax()
|
||||
&& ($GLOBALS['dbi']->isSuperuser() || $GLOBALS['cfg']['AllowUserDropDatabase'])
|
||||
) {
|
||||
$this->dropDatabasesAction();
|
||||
return;
|
||||
}
|
||||
|
||||
include_once 'libraries/replication.inc.php';
|
||||
|
||||
if (isset($_POST['new_db'])
|
||||
&& $response->isAjax()
|
||||
) {
|
||||
$this->createDatabaseAction();
|
||||
return;
|
||||
}
|
||||
|
||||
include_once 'libraries/server_common.inc.php';
|
||||
|
||||
$header = $this->response->getHeader();
|
||||
$scripts = $header->getScripts();
|
||||
$scripts->addFile('server_databases.js');
|
||||
|
||||
$this->_setSortDetails();
|
||||
$this->_dbstats = ! empty($_POST['dbstats']);
|
||||
$this->_pos = empty($_REQUEST['pos']) ? 0 : (int) $_REQUEST['pos'];
|
||||
|
||||
/**
|
||||
* Gets the databases list
|
||||
*/
|
||||
if ($GLOBALS['server'] > 0) {
|
||||
$this->_databases = $this->dbi->getDatabasesFull(
|
||||
null, $this->_dbstats, DatabaseInterface::CONNECT_USER, $this->_sort_by,
|
||||
$this->_sort_order, $this->_pos, true
|
||||
);
|
||||
$this->_database_count = count($GLOBALS['dblist']->databases);
|
||||
} else {
|
||||
$this->_database_count = 0;
|
||||
}
|
||||
|
||||
if ($this->_database_count > 0 && ! empty($this->_databases)) {
|
||||
$databases = $this->_getHtmlForDatabases($replication_types);
|
||||
}
|
||||
|
||||
$this->response->addHTML(Template::get('server/databases/index')->render([
|
||||
'show_create_db' => $GLOBALS['cfg']['ShowCreateDb'],
|
||||
'is_create_db_priv' => $GLOBALS['is_create_db_priv'],
|
||||
'dbstats' => $this->_dbstats,
|
||||
'db_to_create' => $GLOBALS['db_to_create'],
|
||||
'server_collation' => $GLOBALS['dbi']->getServerCollation(),
|
||||
'databases' => isset($databases) ? $databases : null,
|
||||
'dbi' => $GLOBALS['dbi'],
|
||||
'disable_is' => $GLOBALS['cfg']['Server']['DisableIS'],
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles creating a new database
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createDatabaseAction()
|
||||
{
|
||||
// lower_case_table_names=1 `DB` becomes `db`
|
||||
if ($GLOBALS['dbi']->getLowerCaseNames() === '1') {
|
||||
$_POST['new_db'] = mb_strtolower(
|
||||
$_POST['new_db']
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Builds and executes the db creation sql query
|
||||
*/
|
||||
$sql_query = 'CREATE DATABASE ' . Util::backquote($_POST['new_db']);
|
||||
if (! empty($_POST['db_collation'])) {
|
||||
list($db_charset) = explode('_', $_POST['db_collation']);
|
||||
$charsets = Charsets::getMySQLCharsets(
|
||||
$GLOBALS['dbi'],
|
||||
$GLOBALS['cfg']['Server']['DisableIS']
|
||||
);
|
||||
$collations = Charsets::getMySQLCollations(
|
||||
$GLOBALS['dbi'],
|
||||
$GLOBALS['cfg']['Server']['DisableIS']
|
||||
);
|
||||
if (in_array($db_charset, $charsets)
|
||||
&& in_array($_POST['db_collation'], $collations[$db_charset])
|
||||
) {
|
||||
$sql_query .= ' DEFAULT'
|
||||
. Util::getCharsetQueryPart($_POST['db_collation']);
|
||||
}
|
||||
}
|
||||
$sql_query .= ';';
|
||||
|
||||
$result = $GLOBALS['dbi']->tryQuery($sql_query);
|
||||
|
||||
if (! $result) {
|
||||
// avoid displaying the not-created db name in header or navi panel
|
||||
$GLOBALS['db'] = '';
|
||||
|
||||
$message = Message::rawError($GLOBALS['dbi']->getError());
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $message);
|
||||
} else {
|
||||
$GLOBALS['db'] = $_POST['new_db'];
|
||||
|
||||
$message = Message::success(__('Database %1$s has been created.'));
|
||||
$message->addParam($_POST['new_db']);
|
||||
$this->response->addJSON('message', $message);
|
||||
$this->response->addJSON(
|
||||
'sql_query', Util::getMessage(null, $sql_query, 'success')
|
||||
);
|
||||
|
||||
$this->response->addJSON(
|
||||
'url_query',
|
||||
Util::getScriptNameForOption(
|
||||
$GLOBALS['cfg']['DefaultTabDatabase'], 'database'
|
||||
)
|
||||
. Url::getCommon(array('db' => $_POST['new_db']))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles dropping multiple databases
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropDatabasesAction()
|
||||
{
|
||||
if (! isset($_POST['selected_dbs'])) {
|
||||
$message = Message::error(__('No databases selected.'));
|
||||
} else {
|
||||
$action = 'server_databases.php';
|
||||
$err_url = $action . Url::getCommon();
|
||||
|
||||
$GLOBALS['submit_mult'] = 'drop_db';
|
||||
$GLOBALS['mult_btn'] = __('Yes');
|
||||
|
||||
include 'libraries/mult_submits.inc.php';
|
||||
|
||||
if (empty($message)) { // no error message
|
||||
$number_of_databases = count($selected);
|
||||
$message = Message::success(
|
||||
_ngettext(
|
||||
'%1$d database has been dropped successfully.',
|
||||
'%1$d databases have been dropped successfully.',
|
||||
$number_of_databases
|
||||
)
|
||||
);
|
||||
$message->addParam($number_of_databases);
|
||||
}
|
||||
}
|
||||
|
||||
if ($message instanceof Message) {
|
||||
$this->response->setRequestStatus($message->isSuccess());
|
||||
$this->response->addJSON('message', $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts parameters $sort_order and $sort_by
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _setSortDetails()
|
||||
{
|
||||
if (empty($_REQUEST['sort_by'])) {
|
||||
$this->_sort_by = 'SCHEMA_NAME';
|
||||
} else {
|
||||
$sort_by_whitelist = array(
|
||||
'SCHEMA_NAME',
|
||||
'DEFAULT_COLLATION_NAME',
|
||||
'SCHEMA_TABLES',
|
||||
'SCHEMA_TABLE_ROWS',
|
||||
'SCHEMA_DATA_LENGTH',
|
||||
'SCHEMA_INDEX_LENGTH',
|
||||
'SCHEMA_LENGTH',
|
||||
'SCHEMA_DATA_FREE'
|
||||
);
|
||||
if (in_array($_REQUEST['sort_by'], $sort_by_whitelist)) {
|
||||
$this->_sort_by = $_REQUEST['sort_by'];
|
||||
} else {
|
||||
$this->_sort_by = 'SCHEMA_NAME';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['sort_order'])
|
||||
&& mb_strtolower($_REQUEST['sort_order']) == 'desc'
|
||||
) {
|
||||
$this->_sort_order = 'desc';
|
||||
} else {
|
||||
$this->_sort_order = 'asc';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the html for Database List
|
||||
*
|
||||
* @param array $replication_types replication types
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _getHtmlForDatabases(array $replication_types)
|
||||
{
|
||||
$first_database = reset($this->_databases);
|
||||
// table col order
|
||||
$column_order = $this->_getColumnOrder();
|
||||
|
||||
// calculate aggregate stats to display in footer
|
||||
foreach ($this->_databases as $current) {
|
||||
foreach ($column_order as $stat_name => $stat) {
|
||||
if (array_key_exists($stat_name, $current)
|
||||
&& is_numeric($stat['footer'])
|
||||
) {
|
||||
$column_order[$stat_name]['footer'] += $current[$stat_name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$_url_params = array(
|
||||
'pos' => $this->_pos,
|
||||
'dbstats' => $this->_dbstats,
|
||||
'sort_by' => $this->_sort_by,
|
||||
'sort_order' => $this->_sort_order,
|
||||
);
|
||||
|
||||
$html = Template::get('server/databases/databases_header')->render([
|
||||
'database_count' => $this->_database_count,
|
||||
'pos' => $this->_pos,
|
||||
'url_params' => $_url_params,
|
||||
'max_db_list' => $GLOBALS['cfg']['MaxDbList'],
|
||||
'sort_by' => $this->_sort_by,
|
||||
'sort_order' => $this->_sort_order,
|
||||
'column_order' => $column_order,
|
||||
'first_database' => $first_database,
|
||||
'master_replication' => $GLOBALS['replication_info']['master']['status'],
|
||||
'slave_replication' => $GLOBALS['replication_info']['slave']['status'],
|
||||
'is_superuser' => $GLOBALS['dbi']->isSuperuser(),
|
||||
'allow_user_drop_database' => $GLOBALS['cfg']['AllowUserDropDatabase'],
|
||||
]);
|
||||
|
||||
$html .= $this->_getHtmlForTableBody($column_order, $replication_types);
|
||||
|
||||
$html .= Template::get('server/databases/databases_footer')->render([
|
||||
'column_order' => $column_order,
|
||||
'first_database' => $first_database,
|
||||
'master_replication' => $GLOBALS['replication_info']['master']['status'],
|
||||
'slave_replication' => $GLOBALS['replication_info']['slave']['status'],
|
||||
'database_count' => $this->_database_count,
|
||||
'is_superuser' => $GLOBALS['dbi']->isSuperuser(),
|
||||
'allow_user_drop_database' => $GLOBALS['cfg']['AllowUserDropDatabase'],
|
||||
'pma_theme_image' => $GLOBALS['pmaThemeImage'],
|
||||
'text_dir' => $GLOBALS['text_dir'],
|
||||
'dbstats' => $this->_dbstats,
|
||||
]);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the $column_order array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _getColumnOrder()
|
||||
{
|
||||
$column_order = array();
|
||||
$column_order['DEFAULT_COLLATION_NAME'] = array(
|
||||
'disp_name' => __('Collation'),
|
||||
'description_function' => array(Charsets::class, 'getCollationDescr'),
|
||||
'format' => 'string',
|
||||
'footer' => $this->dbi->getServerCollation(),
|
||||
);
|
||||
$column_order['SCHEMA_TABLES'] = array(
|
||||
'disp_name' => __('Tables'),
|
||||
'format' => 'number',
|
||||
'footer' => 0,
|
||||
);
|
||||
$column_order['SCHEMA_TABLE_ROWS'] = array(
|
||||
'disp_name' => __('Rows'),
|
||||
'format' => 'number',
|
||||
'footer' => 0,
|
||||
);
|
||||
$column_order['SCHEMA_DATA_LENGTH'] = array(
|
||||
'disp_name' => __('Data'),
|
||||
'format' => 'byte',
|
||||
'footer' => 0,
|
||||
);
|
||||
$column_order['SCHEMA_INDEX_LENGTH'] = array(
|
||||
'disp_name' => __('Indexes'),
|
||||
'format' => 'byte',
|
||||
'footer' => 0,
|
||||
);
|
||||
$column_order['SCHEMA_LENGTH'] = array(
|
||||
'disp_name' => __('Total'),
|
||||
'format' => 'byte',
|
||||
'footer' => 0,
|
||||
);
|
||||
$column_order['SCHEMA_DATA_FREE'] = array(
|
||||
'disp_name' => __('Overhead'),
|
||||
'format' => 'byte',
|
||||
'footer' => 0,
|
||||
);
|
||||
|
||||
return $column_order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the html for Database List
|
||||
*
|
||||
* @param array $column_order column order
|
||||
* @param array $replication_types replication types
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _getHtmlForTableBody(array $column_order, array $replication_types)
|
||||
{
|
||||
$html = '<tbody>' . "\n";
|
||||
|
||||
foreach ($this->_databases as $current) {
|
||||
$tr_class = ' db-row';
|
||||
if ($this->dbi->isSystemSchema($current['SCHEMA_NAME'], true)) {
|
||||
$tr_class .= ' noclick';
|
||||
}
|
||||
|
||||
$generated_html = $this->_buildHtmlForDb(
|
||||
$current,
|
||||
$column_order,
|
||||
$replication_types,
|
||||
$GLOBALS['replication_info'],
|
||||
$tr_class
|
||||
);
|
||||
$html .= $generated_html;
|
||||
} // end foreach ($this->_databases as $key => $current)
|
||||
$html .= '</tbody>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the HTML for one database to display in the list
|
||||
* of databases from server_databases.php
|
||||
*
|
||||
* @param array $current current database
|
||||
* @param array $column_order column order
|
||||
* @param array $replication_types replication types
|
||||
* @param array $replication_info replication info
|
||||
* @param string $tr_class HTMl class for the row
|
||||
*
|
||||
* @return array $column_order, $out
|
||||
*/
|
||||
function _buildHtmlForDb(
|
||||
array $current, array $column_order,
|
||||
array $replication_types, array $replication_info, $tr_class = ''
|
||||
) {
|
||||
$master_replication = $slave_replication = '';
|
||||
foreach ($replication_types as $type) {
|
||||
if ($replication_info[$type]['status']) {
|
||||
$out = '';
|
||||
$key = array_search(
|
||||
$current["SCHEMA_NAME"],
|
||||
$replication_info[$type]['Ignore_DB']
|
||||
);
|
||||
if (strlen($key) > 0) {
|
||||
$out = Util::getIcon(
|
||||
's_cancel',
|
||||
__('Not replicated')
|
||||
);
|
||||
} else {
|
||||
$key = array_search(
|
||||
$current["SCHEMA_NAME"], $replication_info[$type]['Do_DB']
|
||||
);
|
||||
|
||||
if (strlen($key) > 0
|
||||
|| count($replication_info[$type]['Do_DB']) == 0
|
||||
) {
|
||||
// if ($key != null) did not work for index "0"
|
||||
$out = Util::getIcon(
|
||||
's_success',
|
||||
__('Replicated')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($type == 'master') {
|
||||
$master_replication = $out;
|
||||
} elseif ($type == 'slave') {
|
||||
$slave_replication = $out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Template::get('server/databases/table_row')->render([
|
||||
'current' => $current,
|
||||
'tr_class' => $tr_class,
|
||||
'column_order' => $column_order,
|
||||
'master_replication_status' => $GLOBALS['replication_info']['master']['status'],
|
||||
'master_replication' => $master_replication,
|
||||
'slave_replication_status' => $GLOBALS['replication_info']['slave']['status'],
|
||||
'slave_replication' => $slave_replication,
|
||||
'is_superuser' => $GLOBALS['dbi']->isSuperuser(),
|
||||
'allow_user_drop_database' => $GLOBALS['cfg']['AllowUserDropDatabase'],
|
||||
'is_system_schema' => $GLOBALS['dbi']->isSystemSchema($current['SCHEMA_NAME'], true),
|
||||
'default_tab_database' => $GLOBALS['cfg']['DefaultTabDatabase'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
100
phpMyAdmin/libraries/classes/Controllers/Server/ServerEnginesController.php
Executable file
100
phpMyAdmin/libraries/classes/Controllers/Server/ServerEnginesController.php
Executable file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\Server\ServerEnginesController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Controllers\Controller;
|
||||
use PhpMyAdmin\Server\Common;
|
||||
use PhpMyAdmin\StorageEngine;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Handles viewing storage engine details
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
class ServerEnginesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Index action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
/**
|
||||
* Does the common work
|
||||
*/
|
||||
require 'libraries/server_common.inc.php';
|
||||
|
||||
/**
|
||||
* Displays the sub-page heading
|
||||
*/
|
||||
$this->response->addHTML(
|
||||
Template::get('server/sub_page_header')->render([
|
||||
'type' => 'engines',
|
||||
])
|
||||
);
|
||||
|
||||
/**
|
||||
* Did the user request information about a certain storage engine?
|
||||
*/
|
||||
if (empty($_REQUEST['engine'])
|
||||
|| ! StorageEngine::isValid($_REQUEST['engine'])
|
||||
) {
|
||||
$this->response->addHTML($this->_getHtmlForAllServerEngines());
|
||||
} else {
|
||||
$engine = StorageEngine::getEngine($_REQUEST['engine']);
|
||||
$this->response->addHTML($this->_getHtmlForServerEngine($engine));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML with all Storage Engine information
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _getHtmlForAllServerEngines()
|
||||
{
|
||||
return Template::get('server/engines/engines')->render(
|
||||
array('engines' => StorageEngine::getStorageEngines())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML for a given Storage Engine
|
||||
*
|
||||
* @param StorageEngine $engine storage engine
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _getHtmlForServerEngine(StorageEngine $engine)
|
||||
{
|
||||
$page = isset($_REQUEST['page']) ? $_REQUEST['page'] : '';
|
||||
$pageOutput = ! empty($page) ? $engine->getPage($page) : '';
|
||||
|
||||
/**
|
||||
* Displays details about a given Storage Engine
|
||||
*/
|
||||
return Template::get('server/engines/engine')->render(
|
||||
array(
|
||||
'title' => $engine->getTitle(),
|
||||
'help_page' => $engine->getMysqlHelpPage(),
|
||||
'comment' => $engine->getComment(),
|
||||
'info_pages' => $engine->getInfoPages(),
|
||||
'support' => $engine->getSupportInformationMessage(),
|
||||
'variables' => $engine->getHtmlVariables(),
|
||||
'page_output' => $pageOutput,
|
||||
'page' => $page,
|
||||
'engine' => $_REQUEST['engine'],
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
111
phpMyAdmin/libraries/classes/Controllers/Server/ServerPluginsController.php
Executable file
111
phpMyAdmin/libraries/classes/Controllers/Server/ServerPluginsController.php
Executable file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\Server\ServerPluginsController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Controllers\Controller;
|
||||
use PhpMyAdmin\Server\Common;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
/**
|
||||
* Handles viewing server plugin details
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
class ServerPluginsController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var array plugin details
|
||||
*/
|
||||
protected $plugins;
|
||||
|
||||
/**
|
||||
* Constructs ServerPluginsController
|
||||
*/
|
||||
public function __construct($response, $dbi)
|
||||
{
|
||||
parent::__construct($response, $dbi);
|
||||
$this->_setServerPlugins();
|
||||
}
|
||||
|
||||
/**
|
||||
* Index action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
include 'libraries/server_common.inc.php';
|
||||
|
||||
$header = $this->response->getHeader();
|
||||
$scripts = $header->getScripts();
|
||||
$scripts->addFile('vendor/jquery/jquery.tablesorter.js');
|
||||
$scripts->addFile('server_plugins.js');
|
||||
|
||||
/**
|
||||
* Displays the page
|
||||
*/
|
||||
$this->response->addHTML(
|
||||
Template::get('server/sub_page_header')->render([
|
||||
'type' => 'plugins',
|
||||
])
|
||||
);
|
||||
$this->response->addHTML($this->_getPluginsHtml());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets details about server plugins
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _setServerPlugins()
|
||||
{
|
||||
$sql = "SELECT plugin_name,
|
||||
plugin_type,
|
||||
(plugin_status = 'ACTIVE') AS is_active,
|
||||
plugin_type_version,
|
||||
plugin_author,
|
||||
plugin_description,
|
||||
plugin_license
|
||||
FROM information_schema.plugins
|
||||
ORDER BY plugin_type, plugin_name";
|
||||
|
||||
$res = $this->dbi->query($sql);
|
||||
$this->plugins = array();
|
||||
while ($row = $this->dbi->fetchAssoc($res)) {
|
||||
$this->plugins[$row['plugin_type']][] = $row;
|
||||
}
|
||||
$this->dbi->freeResult($res);
|
||||
ksort($this->plugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the html for plugin Tab.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _getPluginsHtml()
|
||||
{
|
||||
$html = '<div id="plugins_plugins">';
|
||||
$html .= Template::get('server/plugins/section_links')
|
||||
->render(array('plugins' => $this->plugins));
|
||||
|
||||
foreach ($this->plugins as $plugin_type => $plugin_list) {
|
||||
$html .= Template::get('server/plugins/section')
|
||||
->render(
|
||||
array(
|
||||
'plugin_type' => $plugin_type,
|
||||
'plugin_list' => $plugin_list,
|
||||
)
|
||||
);
|
||||
}
|
||||
$html .= '</div>';
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
2837
phpMyAdmin/libraries/classes/Controllers/Server/ServerVariablesController.php
Executable file
2837
phpMyAdmin/libraries/classes/Controllers/Server/ServerVariablesController.php
Executable file
File diff suppressed because it is too large
Load Diff
246
phpMyAdmin/libraries/classes/Controllers/Table/TableChartController.php
Executable file
246
phpMyAdmin/libraries/classes/Controllers/Table/TableChartController.php
Executable file
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\Table\TableChartController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
namespace PhpMyAdmin\Controllers\Table;
|
||||
|
||||
use PhpMyAdmin\Controllers\TableController;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Response;
|
||||
use PhpMyAdmin\SqlParser\Components\Limit;
|
||||
use PhpMyAdmin\SqlParser\Parser;
|
||||
use PhpMyAdmin\Table;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Handles table related logic
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
class TableChartController extends TableController
|
||||
{
|
||||
/**
|
||||
* @var string $sql_query
|
||||
*/
|
||||
protected $sql_query;
|
||||
|
||||
/**
|
||||
* @var string $url_query
|
||||
*/
|
||||
protected $url_query;
|
||||
|
||||
/**
|
||||
* @var array $cfg
|
||||
*/
|
||||
protected $cfg;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $sql_query Query
|
||||
* @param string $url_query Query URL
|
||||
* @param array $cfg Configuration
|
||||
*/
|
||||
public function __construct(
|
||||
$response,
|
||||
$dbi,
|
||||
$db,
|
||||
$table,
|
||||
$sql_query,
|
||||
$url_query,
|
||||
array $cfg
|
||||
) {
|
||||
parent::__construct($response, $dbi, $db, $table);
|
||||
|
||||
$this->sql_query = $sql_query;
|
||||
$this->url_query = $url_query;
|
||||
$this->cfg = $cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query and return the result
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$response = Response::getInstance();
|
||||
if ($response->isAjax()
|
||||
&& isset($_REQUEST['pos'])
|
||||
&& isset($_REQUEST['session_max_rows'])
|
||||
) {
|
||||
$this->ajaxAction();
|
||||
return;
|
||||
}
|
||||
|
||||
// Throw error if no sql query is set
|
||||
if (!isset($this->sql_query) || $this->sql_query == '') {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addHTML(
|
||||
Message::error(__('No SQL query was set to fetch data.'))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->getHeader()->getScripts()->addFiles(
|
||||
array(
|
||||
'chart.js',
|
||||
'tbl_chart.js',
|
||||
'vendor/jqplot/jquery.jqplot.js',
|
||||
'vendor/jqplot/plugins/jqplot.barRenderer.js',
|
||||
'vendor/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js',
|
||||
'vendor/jqplot/plugins/jqplot.canvasTextRenderer.js',
|
||||
'vendor/jqplot/plugins/jqplot.categoryAxisRenderer.js',
|
||||
'vendor/jqplot/plugins/jqplot.dateAxisRenderer.js',
|
||||
'vendor/jqplot/plugins/jqplot.pointLabels.js',
|
||||
'vendor/jqplot/plugins/jqplot.pieRenderer.js',
|
||||
'vendor/jqplot/plugins/jqplot.enhancedPieLegendRenderer.js',
|
||||
'vendor/jqplot/plugins/jqplot.highlighter.js'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Extract values for common work
|
||||
* @todo Extract common files
|
||||
*/
|
||||
$db = &$this->db;
|
||||
$table = &$this->table;
|
||||
$url_params = array();
|
||||
|
||||
/**
|
||||
* Runs common work
|
||||
*/
|
||||
if (strlen($this->table) > 0) {
|
||||
$url_params['goto'] = Util::getScriptNameForOption(
|
||||
$this->cfg['DefaultTabTable'], 'table'
|
||||
);
|
||||
$url_params['back'] = 'tbl_sql.php';
|
||||
include 'libraries/tbl_common.inc.php';
|
||||
$GLOBALS['dbi']->selectDb($GLOBALS['db']);
|
||||
} elseif (strlen($this->db) > 0) {
|
||||
$url_params['goto'] = Util::getScriptNameForOption(
|
||||
$this->cfg['DefaultTabDatabase'], 'database'
|
||||
);
|
||||
$url_params['back'] = 'sql.php';
|
||||
include 'libraries/db_common.inc.php';
|
||||
} else {
|
||||
$url_params['goto'] = Util::getScriptNameForOption(
|
||||
$this->cfg['DefaultTabServer'], 'server'
|
||||
);
|
||||
$url_params['back'] = 'sql.php';
|
||||
include 'libraries/server_common.inc.php';
|
||||
}
|
||||
|
||||
$data = array();
|
||||
|
||||
$result = $this->dbi->tryQuery($this->sql_query);
|
||||
$fields_meta = $this->dbi->getFieldsMeta($result);
|
||||
while ($row = $this->dbi->fetchAssoc($result)) {
|
||||
$data[] = $row;
|
||||
}
|
||||
|
||||
$keys = array_keys($data[0]);
|
||||
|
||||
$numeric_types = array('int', 'real');
|
||||
$numeric_column_count = 0;
|
||||
foreach ($keys as $idx => $key) {
|
||||
if (in_array($fields_meta[$idx]->type, $numeric_types)) {
|
||||
$numeric_column_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($numeric_column_count == 0) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON(
|
||||
'message',
|
||||
__('No numeric columns present in the table to plot.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$url_params['db'] = $this->db;
|
||||
$url_params['reload'] = 1;
|
||||
|
||||
/**
|
||||
* Displays the page
|
||||
*/
|
||||
$this->response->addHTML(
|
||||
Template::get('table/chart/tbl_chart')->render(
|
||||
array(
|
||||
'url_query' => $this->url_query,
|
||||
'url_params' => $url_params,
|
||||
'keys' => $keys,
|
||||
'fields_meta' => $fields_meta,
|
||||
'numeric_types' => $numeric_types,
|
||||
'numeric_column_count' => $numeric_column_count,
|
||||
'sql_query' => $this->sql_query
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle ajax request
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxAction()
|
||||
{
|
||||
/**
|
||||
* Extract values for common work
|
||||
* @todo Extract common files
|
||||
*/
|
||||
$db = &$this->db;
|
||||
$table = &$this->table;
|
||||
|
||||
if (strlen($this->table) > 0 && strlen($this->db) > 0) {
|
||||
include './libraries/tbl_common.inc.php';
|
||||
}
|
||||
|
||||
$parser = new Parser($this->sql_query);
|
||||
$statement = $parser->statements[0];
|
||||
if (empty($statement->limit)) {
|
||||
$statement->limit = new Limit(
|
||||
$_REQUEST['session_max_rows'], $_REQUEST['pos']
|
||||
);
|
||||
} else {
|
||||
$start = $statement->limit->offset + $_REQUEST['pos'];
|
||||
$rows = min(
|
||||
$_REQUEST['session_max_rows'],
|
||||
$statement->limit->rowCount - $_REQUEST['pos']
|
||||
);
|
||||
$statement->limit = new Limit($rows, $start);
|
||||
}
|
||||
$sql_with_limit = $statement->build();
|
||||
|
||||
$data = array();
|
||||
$result = $this->dbi->tryQuery($sql_with_limit);
|
||||
while ($row = $this->dbi->fetchAssoc($result)) {
|
||||
$data[] = $row;
|
||||
}
|
||||
|
||||
if (empty($data)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', __('No data to display'));
|
||||
return;
|
||||
}
|
||||
$sanitized_data = array();
|
||||
|
||||
foreach ($data as $data_row_number => $data_row) {
|
||||
$tmp_row = array();
|
||||
foreach ($data_row as $data_column => $data_value) {
|
||||
$tmp_row[htmlspecialchars($data_column)] = htmlspecialchars(
|
||||
$data_value
|
||||
);
|
||||
}
|
||||
$sanitized_data[] = $tmp_row;
|
||||
}
|
||||
$this->response->setRequestStatus(true);
|
||||
$this->response->addJSON('message', null);
|
||||
$this->response->addJSON('chartData', json_encode($sanitized_data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\Table\TableIndexesController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
namespace PhpMyAdmin\Controllers\Table;
|
||||
|
||||
use PhpMyAdmin\Controllers\TableController;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Gis\GisVisualization;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
require_once 'libraries/common.inc.php';
|
||||
require_once 'libraries/db_common.inc.php';
|
||||
|
||||
/**
|
||||
* Class TableGisVisualizationController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
class TableGisVisualizationController extends TableController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array $url_params
|
||||
*/
|
||||
protected $url_params;
|
||||
|
||||
/**
|
||||
* @var string $sql_query
|
||||
*/
|
||||
protected $sql_query;
|
||||
|
||||
/**
|
||||
* @var array $visualizationSettings
|
||||
*/
|
||||
protected $visualizationSettings;
|
||||
|
||||
/**
|
||||
* @var \PhpMyAdmin\Gis\GisVisualization $visualization
|
||||
*/
|
||||
protected $visualization;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $sql_query SQL query for retrieving GIS data
|
||||
* @param array $url_params array of URL parameters
|
||||
* @param string $goto goto script
|
||||
* @param string $back back script
|
||||
* @param array $visualizationSettings visualization settings
|
||||
*/
|
||||
public function __construct(
|
||||
$response,
|
||||
$dbi,
|
||||
$db,
|
||||
$table,
|
||||
$sql_query,
|
||||
array $url_params,
|
||||
$goto,
|
||||
$back,
|
||||
array $visualizationSettings
|
||||
) {
|
||||
parent::__construct($response, $dbi, $db, $table);
|
||||
|
||||
$this->sql_query = $sql_query;
|
||||
$this->url_params = $url_params;
|
||||
$this->url_params['goto'] = $goto;
|
||||
$this->url_params['back'] = $back;
|
||||
$this->visualizationSettings = $visualizationSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save to file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function saveToFileAction()
|
||||
{
|
||||
$this->response->disable();
|
||||
$file_name = $this->visualizationSettings['spatialColumn'];
|
||||
$save_format = $_GET['fileFormat'];
|
||||
$this->visualization->toFile($file_name, $save_format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Index
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
// Throw error if no sql query is set
|
||||
if (! isset($this->sql_query) || $this->sql_query == '') {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addHTML(
|
||||
Message::error(__('No SQL query was set to fetch data.'))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute the query and return the result
|
||||
$result = $this->dbi->tryQuery($this->sql_query);
|
||||
// Get the meta data of results
|
||||
$meta = $this->dbi->getFieldsMeta($result);
|
||||
|
||||
// Find the candidate fields for label column and spatial column
|
||||
$labelCandidates = array();
|
||||
$spatialCandidates = array();
|
||||
foreach ($meta as $column_meta) {
|
||||
if ($column_meta->type == 'geometry') {
|
||||
$spatialCandidates[] = $column_meta->name;
|
||||
} else {
|
||||
$labelCandidates[] = $column_meta->name;
|
||||
}
|
||||
}
|
||||
|
||||
// Get settings if any posted
|
||||
if (Core::isValid($_POST['visualizationSettings'], 'array')) {
|
||||
$this->visualizationSettings = $_POST['visualizationSettings'];
|
||||
}
|
||||
|
||||
// Check mysql version
|
||||
$this->visualizationSettings['mysqlVersion'] = $this->dbi->getVersion();
|
||||
|
||||
if (!isset($this->visualizationSettings['labelColumn'])
|
||||
&& isset($labelCandidates[0])
|
||||
) {
|
||||
$this->visualizationSettings['labelColumn'] = '';
|
||||
}
|
||||
|
||||
// If spatial column is not set, use first geometric column as spatial column
|
||||
if (! isset($this->visualizationSettings['spatialColumn'])) {
|
||||
$this->visualizationSettings['spatialColumn'] = $spatialCandidates[0];
|
||||
}
|
||||
|
||||
// Convert geometric columns from bytes to text.
|
||||
$pos = isset($_GET['pos']) ? $_GET['pos']
|
||||
: $_SESSION['tmpval']['pos'];
|
||||
if (isset($_GET['session_max_rows'])) {
|
||||
$rows = $_GET['session_max_rows'];
|
||||
} else {
|
||||
if ($_SESSION['tmpval']['max_rows'] != 'all') {
|
||||
$rows = $_SESSION['tmpval']['max_rows'];
|
||||
} else {
|
||||
$rows = $GLOBALS['cfg']['MaxRows'];
|
||||
}
|
||||
}
|
||||
$this->visualization = GisVisualization::get(
|
||||
$this->sql_query,
|
||||
$this->visualizationSettings,
|
||||
$rows,
|
||||
$pos
|
||||
);
|
||||
|
||||
if (isset($_GET['saveToFile'])) {
|
||||
$this->saveToFileAction();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->getHeader()->getScripts()->addFiles(
|
||||
array(
|
||||
'vendor/openlayers/OpenLayers.js',
|
||||
'vendor/jquery/jquery.svg.js',
|
||||
'tbl_gis_visualization.js',
|
||||
)
|
||||
);
|
||||
|
||||
// If all the rows contain SRID, use OpenStreetMaps on the initial loading.
|
||||
if (! isset($_POST['displayVisualization'])) {
|
||||
if ($this->visualization->hasSrid()) {
|
||||
$this->visualizationSettings['choice'] = 'useBaseLayer';
|
||||
} else {
|
||||
unset($this->visualizationSettings['choice']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->visualization->setUserSpecifiedSettings($this->visualizationSettings);
|
||||
if ($this->visualizationSettings != null) {
|
||||
foreach ($this->visualization->getSettings() as $setting => $val) {
|
||||
if (! isset($this->visualizationSettings[$setting])) {
|
||||
$this->visualizationSettings[$setting] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the page
|
||||
*/
|
||||
$this->url_params['sql_query'] = $this->sql_query;
|
||||
$downloadUrl = 'tbl_gis_visualization.php' . Url::getCommon(
|
||||
array_merge(
|
||||
$this->url_params,
|
||||
array(
|
||||
'sql_signature' => Core::signSqlQuery($this->sql_query),
|
||||
'saveToFile' => true,
|
||||
'session_max_rows' => $rows,
|
||||
'pos' => $pos
|
||||
)
|
||||
)
|
||||
);
|
||||
$html = Template::get('table/gis_visualization/gis_visualization')->render(
|
||||
array(
|
||||
'url_params' => $this->url_params,
|
||||
'download_url' => $downloadUrl,
|
||||
'label_candidates' => $labelCandidates,
|
||||
'spatial_candidates' => $spatialCandidates,
|
||||
'visualization_settings' => $this->visualizationSettings,
|
||||
'sql_query' => $this->sql_query,
|
||||
'visualization' => $this->visualization->toImage('svg'),
|
||||
'draw_ol' => $this->visualization->asOl(),
|
||||
'pma_theme_image' => $GLOBALS['pmaThemeImage']
|
||||
)
|
||||
);
|
||||
|
||||
$this->response->addHTML($html);
|
||||
}
|
||||
}
|
||||
177
phpMyAdmin/libraries/classes/Controllers/Table/TableIndexesController.php
Executable file
177
phpMyAdmin/libraries/classes/Controllers/Table/TableIndexesController.php
Executable file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\Table\TableIndexesController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
namespace PhpMyAdmin\Controllers\Table;
|
||||
|
||||
use PhpMyAdmin\Controllers\TableController;
|
||||
use PhpMyAdmin\Index;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Response;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Class TableIndexesController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
class TableIndexesController extends TableController
|
||||
{
|
||||
/**
|
||||
* @var Index $index
|
||||
*/
|
||||
protected $index;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Index $index Index
|
||||
*/
|
||||
public function __construct(
|
||||
$response,
|
||||
$dbi,
|
||||
$db,
|
||||
$table,
|
||||
$index
|
||||
) {
|
||||
parent::__construct($response, $dbi, $db, $table);
|
||||
|
||||
$this->index = $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Index
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
if (isset($_POST['do_save_data'])) {
|
||||
$this->doSaveDataAction();
|
||||
return;
|
||||
} // end builds the new index
|
||||
|
||||
$this->displayFormAction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the form to edit/create an index
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function displayFormAction()
|
||||
{
|
||||
$GLOBALS['dbi']->selectDb($GLOBALS['db']);
|
||||
$add_fields = 0;
|
||||
if (isset($_POST['index']) && is_array($_POST['index'])) {
|
||||
// coming already from form
|
||||
if (isset($_POST['index']['columns']['names'])) {
|
||||
$add_fields = count($_POST['index']['columns']['names'])
|
||||
- $this->index->getColumnCount();
|
||||
}
|
||||
if (isset($_POST['add_fields'])) {
|
||||
$add_fields += $_POST['added_fields'];
|
||||
}
|
||||
} elseif (isset($_POST['create_index'])) {
|
||||
$add_fields = $_POST['added_fields'];
|
||||
} // end preparing form values
|
||||
|
||||
// Get fields and stores their name/type
|
||||
if (isset($_POST['create_edit_table'])) {
|
||||
$fields = json_decode($_POST['columns'], true);
|
||||
$index_params = array(
|
||||
'Non_unique' => ($_POST['index']['Index_choice'] == 'UNIQUE')
|
||||
? '0' : '1',
|
||||
);
|
||||
$this->index->set($index_params);
|
||||
$add_fields = count($fields);
|
||||
} else {
|
||||
$fields = $this->dbi->getTable($this->db, $this->table)
|
||||
->getNameAndTypeOfTheColumns();
|
||||
}
|
||||
|
||||
$form_params = array(
|
||||
'db' => $this->db,
|
||||
'table' => $this->table,
|
||||
);
|
||||
|
||||
if (isset($_POST['create_index'])) {
|
||||
$form_params['create_index'] = 1;
|
||||
} elseif (isset($_POST['old_index'])) {
|
||||
$form_params['old_index'] = $_POST['old_index'];
|
||||
} elseif (isset($_POST['index'])) {
|
||||
$form_params['old_index'] = $_POST['index'];
|
||||
}
|
||||
|
||||
$this->response->getHeader()->getScripts()->addFile('indexes.js');
|
||||
|
||||
$this->response->addHTML(
|
||||
Template::get('table/index_form')->render(
|
||||
array(
|
||||
'fields' => $fields,
|
||||
'index' => $this->index,
|
||||
'form_params' => $form_params,
|
||||
'add_fields' => $add_fields,
|
||||
'create_edit_table' => isset($_POST['create_edit_table'])
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the data from the edit/create index form,
|
||||
* run the query to build the new index
|
||||
* and moves back to "tbl_sql.php"
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function doSaveDataAction()
|
||||
{
|
||||
$error = false;
|
||||
|
||||
$sql_query = $this->dbi->getTable($this->db, $this->table)
|
||||
->getSqlQueryForIndexCreateOrEdit($this->index, $error);
|
||||
|
||||
// If there is a request for SQL previewing.
|
||||
if (isset($_POST['preview_sql'])) {
|
||||
|
||||
$this->response->addJSON(
|
||||
'sql_data',
|
||||
Template::get('preview_sql')
|
||||
->render(
|
||||
array(
|
||||
'query_data' => $sql_query
|
||||
)
|
||||
)
|
||||
);
|
||||
} elseif (!$error) {
|
||||
|
||||
$this->dbi->query($sql_query);
|
||||
$response = Response::getInstance();
|
||||
if ($response->isAjax()) {
|
||||
$message = Message::success(
|
||||
__('Table %1$s has been altered successfully.')
|
||||
);
|
||||
$message->addParam($this->table);
|
||||
$this->response->addJSON(
|
||||
'message', Util::getMessage($message, $sql_query, 'success')
|
||||
);
|
||||
$this->response->addJSON(
|
||||
'index_table',
|
||||
Index::getHtmlForIndexes(
|
||||
$this->table, $this->db
|
||||
)
|
||||
);
|
||||
} else {
|
||||
include 'tbl_structure.php';
|
||||
}
|
||||
} else {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $error);
|
||||
}
|
||||
}
|
||||
}
|
||||
390
phpMyAdmin/libraries/classes/Controllers/Table/TableRelationController.php
Executable file
390
phpMyAdmin/libraries/classes/Controllers/Table/TableRelationController.php
Executable file
@@ -0,0 +1,390 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\Table\TableRelationController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
namespace PhpMyAdmin\Controllers\Table;
|
||||
|
||||
use PhpMyAdmin\Controllers\TableController;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Index;
|
||||
use PhpMyAdmin\Relation;
|
||||
use PhpMyAdmin\Table;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Handles table relation logic
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
class TableRelationController extends TableController
|
||||
{
|
||||
/**
|
||||
* @var array $options_array
|
||||
*/
|
||||
protected $options_array;
|
||||
|
||||
/**
|
||||
* @var array $cfgRelation
|
||||
*/
|
||||
protected $cfgRelation;
|
||||
|
||||
/**
|
||||
* @var array $existrel
|
||||
*/
|
||||
protected $existrel;
|
||||
|
||||
/**
|
||||
* @var string $tbl_storage_engine
|
||||
*/
|
||||
protected $tbl_storage_engine;
|
||||
|
||||
/**
|
||||
* @var array $existrel_foreign
|
||||
*/
|
||||
protected $existrel_foreign;
|
||||
|
||||
/**
|
||||
* @var Table $udp_query
|
||||
*/
|
||||
protected $upd_query;
|
||||
|
||||
/**
|
||||
* @var Relation $relation
|
||||
*/
|
||||
private $relation;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array|null $options_array Options
|
||||
* @param array|null $cfgRelation Config relation
|
||||
* @param string $tbl_storage_engine Table storage engine
|
||||
* @param array|null $existrel Relations
|
||||
* @param array|null $existrel_foreign External relations
|
||||
* @param string $upd_query Update query
|
||||
*/
|
||||
public function __construct(
|
||||
$response,
|
||||
$dbi,
|
||||
$db,
|
||||
$table,
|
||||
$options_array,
|
||||
$cfgRelation,
|
||||
$tbl_storage_engine,
|
||||
$existrel,
|
||||
$existrel_foreign,
|
||||
$upd_query
|
||||
) {
|
||||
parent::__construct($response, $dbi, $db, $table);
|
||||
|
||||
$this->options_array = $options_array;
|
||||
$this->cfgRelation = $cfgRelation;
|
||||
$this->tbl_storage_engine = $tbl_storage_engine;
|
||||
$this->existrel = $existrel;
|
||||
$this->existrel_foreign = $existrel_foreign;
|
||||
$this->upd_query = $upd_query;
|
||||
$this->relation = new Relation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Index
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
// Send table of column names to populate corresponding dropdowns depending
|
||||
// on the current selection
|
||||
if (isset($_POST['getDropdownValues'])
|
||||
&& $_POST['getDropdownValues'] === 'true'
|
||||
) {
|
||||
// if both db and table are selected
|
||||
if (isset($_POST['foreignTable'])) {
|
||||
$this->getDropdownValueForTableAction();
|
||||
} else { // if only the db is selected
|
||||
$this->getDropdownValueForDbAction();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->getHeader()->getScripts()->addFiles(
|
||||
array(
|
||||
'tbl_relation.js',
|
||||
'indexes.js'
|
||||
)
|
||||
);
|
||||
|
||||
// Set the database
|
||||
$this->dbi->selectDb($this->db);
|
||||
|
||||
// updates for Internal relations
|
||||
if (isset($_POST['destination_db']) && $this->cfgRelation['relwork']) {
|
||||
$this->updateForInternalRelationAction();
|
||||
}
|
||||
|
||||
// updates for foreign keys
|
||||
$this->updateForForeignKeysAction();
|
||||
|
||||
// Updates for display field
|
||||
if ($this->cfgRelation['displaywork'] && isset($_POST['display_field'])) {
|
||||
$this->updateForDisplayField();
|
||||
}
|
||||
|
||||
// If we did an update, refresh our data
|
||||
if (isset($_POST['destination_db']) && $this->cfgRelation['relwork']) {
|
||||
$this->existrel = $this->relation->getForeigners(
|
||||
$this->db, $this->table, '', 'internal'
|
||||
);
|
||||
}
|
||||
if (isset($_POST['destination_foreign_db'])
|
||||
&& Util::isForeignKeySupported($this->tbl_storage_engine)
|
||||
) {
|
||||
$this->existrel_foreign = $this->relation->getForeigners(
|
||||
$this->db, $this->table, '', 'foreign'
|
||||
);
|
||||
}
|
||||
|
||||
// display secondary level tabs if necessary
|
||||
$engine = $this->dbi->getTable($this->db, $this->table)->getStorageEngine();
|
||||
|
||||
$this->response->addHTML(
|
||||
Template::get('table/secondary_tabs')->render(
|
||||
array(
|
||||
'url_params' => array(
|
||||
'db' => $GLOBALS['db'],
|
||||
'table' => $GLOBALS['table']
|
||||
),
|
||||
'is_foreign_key_supported' => Util::isForeignKeySupported($engine),
|
||||
'cfg_relation' => $this->relation->getRelationsParam(),
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->response->addHTML('<div id="structure_content">');
|
||||
|
||||
/**
|
||||
* Dialog
|
||||
*/
|
||||
// Now find out the columns of our $table
|
||||
// need to use DatabaseInterface::QUERY_STORE with $this->dbi->numRows()
|
||||
// in mysqli
|
||||
$columns = $this->dbi->getColumns($this->db, $this->table);
|
||||
|
||||
$column_array = array();
|
||||
$column_array[''] = '';
|
||||
foreach ($columns as $column) {
|
||||
if (strtoupper($this->tbl_storage_engine) == 'INNODB'
|
||||
|| ! empty($column['Key'])
|
||||
) {
|
||||
$column_array[$column['Field']] = $column['Field'];
|
||||
}
|
||||
}
|
||||
if ($GLOBALS['cfg']['NaturalOrder']) {
|
||||
uksort($column_array, 'strnatcasecmp');
|
||||
}
|
||||
|
||||
// common form
|
||||
$this->response->addHTML(
|
||||
Template::get('table/relation/common_form')->render([
|
||||
'db' => $this->db,
|
||||
'table' => $this->table,
|
||||
'cfg_relation' => $this->cfgRelation,
|
||||
'tbl_storage_engine' => $this->tbl_storage_engine,
|
||||
'existrel' => isset($this->existrel) ? $this->existrel : array(),
|
||||
'existrel_foreign' => is_array($this->existrel_foreign) && array_key_exists('foreign_keys_data', $this->existrel_foreign)
|
||||
? $this->existrel_foreign['foreign_keys_data'] : array(),
|
||||
'options_array' => $this->options_array,
|
||||
'column_array' => $column_array,
|
||||
'save_row' => array_values($columns),
|
||||
'url_params' => $GLOBALS['url_params'],
|
||||
'databases' => $GLOBALS['dblist']->databases,
|
||||
'dbi' => $GLOBALS['dbi'],
|
||||
])
|
||||
);
|
||||
|
||||
if (Util::isForeignKeySupported($this->tbl_storage_engine)) {
|
||||
$this->response->addHTML(Index::getHtmlForDisplayIndexes());
|
||||
}
|
||||
$this->response->addHTML('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update for display field
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateForDisplayField()
|
||||
{
|
||||
if ($this->upd_query->updateDisplayField(
|
||||
$_POST['display_field'], $this->cfgRelation
|
||||
)
|
||||
) {
|
||||
$this->response->addHTML(
|
||||
Util::getMessage(
|
||||
__('Display column was successfully updated.'),
|
||||
'', 'success'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update for FK
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateForForeignKeysAction()
|
||||
{
|
||||
$multi_edit_columns_name = isset($_POST['foreign_key_fields_name'])
|
||||
? $_POST['foreign_key_fields_name']
|
||||
: null;
|
||||
$preview_sql_data = '';
|
||||
$seen_error = false;
|
||||
|
||||
// (for now, one index name only; we keep the definitions if the
|
||||
// foreign db is not the same)
|
||||
if (isset($_POST['destination_foreign_db'])
|
||||
&& isset($_POST['destination_foreign_table'])
|
||||
&& isset($_POST['destination_foreign_column'])) {
|
||||
list($html, $preview_sql_data, $display_query, $seen_error)
|
||||
= $this->upd_query->updateForeignKeys(
|
||||
$_POST['destination_foreign_db'],
|
||||
$multi_edit_columns_name, $_POST['destination_foreign_table'],
|
||||
$_POST['destination_foreign_column'], $this->options_array,
|
||||
$this->table,
|
||||
is_array($this->existrel_foreign) && array_key_exists('foreign_keys_data', $this->existrel_foreign)
|
||||
? $this->existrel_foreign['foreign_keys_data']
|
||||
: []
|
||||
);
|
||||
$this->response->addHTML($html);
|
||||
}
|
||||
|
||||
// If there is a request for SQL previewing.
|
||||
if (isset($_POST['preview_sql'])) {
|
||||
Core::previewSQL($preview_sql_data);
|
||||
}
|
||||
|
||||
if (!empty($display_query) && !$seen_error) {
|
||||
$GLOBALS['display_query'] = $display_query;
|
||||
$this->response->addHTML(
|
||||
Util::getMessage(
|
||||
__('Your SQL query has been executed successfully.'),
|
||||
null, 'success'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update for internal relation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateForInternalRelationAction()
|
||||
{
|
||||
$multi_edit_columns_name = isset($_POST['fields_name'])
|
||||
? $_POST['fields_name']
|
||||
: null;
|
||||
|
||||
if ($this->upd_query->updateInternalRelations(
|
||||
$multi_edit_columns_name,
|
||||
$_POST['destination_db'],
|
||||
$_POST['destination_table'],
|
||||
$_POST['destination_column'],
|
||||
$this->cfgRelation,
|
||||
isset($this->existrel) ? $this->existrel : null
|
||||
)
|
||||
) {
|
||||
$this->response->addHTML(
|
||||
Util::getMessage(
|
||||
__('Internal relationships were successfully updated.'),
|
||||
'', 'success'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send table columns for foreign table dropdown
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
public function getDropdownValueForTableAction()
|
||||
{
|
||||
$foreignTable = $_POST['foreignTable'];
|
||||
$table_obj = $this->dbi->getTable($_POST['foreignDb'], $foreignTable);
|
||||
// Since views do not have keys defined on them provide the full list of
|
||||
// columns
|
||||
if ($table_obj->isView()) {
|
||||
$columnList = $table_obj->getColumns(false, false);
|
||||
} else {
|
||||
$columnList = $table_obj->getIndexedColumns(false, false);
|
||||
}
|
||||
$columns = array();
|
||||
foreach ($columnList as $column) {
|
||||
$columns[] = htmlspecialchars($column);
|
||||
}
|
||||
if ($GLOBALS['cfg']['NaturalOrder']) {
|
||||
usort($columns, 'strnatcasecmp');
|
||||
}
|
||||
$this->response->addJSON('columns', $columns);
|
||||
|
||||
// @todo should be: $server->db($db)->table($table)->primary()
|
||||
$primary = Index::getPrimary($foreignTable, $_POST['foreignDb']);
|
||||
if (false === $primary) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->addJSON('primary', array_keys($primary->getColumns()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send database selection values for dropdown
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
public function getDropdownValueForDbAction()
|
||||
{
|
||||
$tables = array();
|
||||
$foreign = isset($_POST['foreign']) && $_POST['foreign'] === 'true';
|
||||
|
||||
if ($foreign) {
|
||||
$query = 'SHOW TABLE STATUS FROM '
|
||||
. Util::backquote($_POST['foreignDb']);
|
||||
$tables_rs = $this->dbi->query(
|
||||
$query,
|
||||
DatabaseInterface::CONNECT_USER,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
|
||||
while ($row = $this->dbi->fetchArray($tables_rs)) {
|
||||
if (isset($row['Engine'])
|
||||
&& mb_strtoupper($row['Engine']) == $this->tbl_storage_engine
|
||||
) {
|
||||
$tables[] = htmlspecialchars($row['Name']);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$query = 'SHOW TABLES FROM '
|
||||
. Util::backquote($_POST['foreignDb']);
|
||||
$tables_rs = $this->dbi->query(
|
||||
$query,
|
||||
DatabaseInterface::CONNECT_USER,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
while ($row = $this->dbi->fetchArray($tables_rs)) {
|
||||
$tables[] = htmlspecialchars($row[0]);
|
||||
}
|
||||
}
|
||||
if ($GLOBALS['cfg']['NaturalOrder']) {
|
||||
usort($tables, 'strnatcasecmp');
|
||||
}
|
||||
$this->response->addJSON('tables', $tables);
|
||||
}
|
||||
}
|
||||
1173
phpMyAdmin/libraries/classes/Controllers/Table/TableSearchController.php
Executable file
1173
phpMyAdmin/libraries/classes/Controllers/Table/TableSearchController.php
Executable file
File diff suppressed because it is too large
Load Diff
1502
phpMyAdmin/libraries/classes/Controllers/Table/TableStructureController.php
Executable file
1502
phpMyAdmin/libraries/classes/Controllers/Table/TableStructureController.php
Executable file
File diff suppressed because it is too large
Load Diff
40
phpMyAdmin/libraries/classes/Controllers/TableController.php
Executable file
40
phpMyAdmin/libraries/classes/Controllers/TableController.php
Executable file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Controllers\TableController
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
/**
|
||||
* Handles table related logic
|
||||
*
|
||||
* @package PhpMyAdmin\Controllers
|
||||
*/
|
||||
abstract class TableController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var string $db
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* @var string $table
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct(
|
||||
$response,
|
||||
$dbi,
|
||||
$db,
|
||||
$table
|
||||
) {
|
||||
parent::__construct($response, $dbi);
|
||||
$this->db = $db;
|
||||
$this->table = $table;
|
||||
}
|
||||
}
|
||||
1352
phpMyAdmin/libraries/classes/Core.php
Executable file
1352
phpMyAdmin/libraries/classes/Core.php
Executable file
File diff suppressed because it is too large
Load Diff
556
phpMyAdmin/libraries/classes/CreateAddField.php
Executable file
556
phpMyAdmin/libraries/classes/CreateAddField.php
Executable file
@@ -0,0 +1,556 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\CreateAddField class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Index;
|
||||
use PhpMyAdmin\Table;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Set of functions for tbl_create.php and tbl_addfield.php
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class CreateAddField
|
||||
{
|
||||
/**
|
||||
* @var DatabaseInterface
|
||||
*/
|
||||
private $dbi;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface interface
|
||||
*/
|
||||
public function __construct(DatabaseInterface $dbi)
|
||||
{
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the radio button field_key into 4 arrays
|
||||
*
|
||||
* @return array An array of arrays which represents column keys for each index type
|
||||
*/
|
||||
private function getIndexedColumns()
|
||||
{
|
||||
$fieldCount = count($_POST['field_name']);
|
||||
$fieldPrimary = json_decode($_POST['primary_indexes'], true);
|
||||
$fieldIndex = json_decode($_POST['indexes'], true);
|
||||
$fieldUnique = json_decode($_POST['unique_indexes'], true);
|
||||
$fieldFullText = json_decode($_POST['fulltext_indexes'], true);
|
||||
$fieldSpatial = json_decode($_POST['spatial_indexes'], true);
|
||||
|
||||
return [
|
||||
$fieldCount,
|
||||
$fieldPrimary,
|
||||
$fieldIndex,
|
||||
$fieldUnique,
|
||||
$fieldFullText,
|
||||
$fieldSpatial,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the column creation statement according to the table creation or
|
||||
* add columns to a existing table
|
||||
*
|
||||
* @param int $fieldCount number of columns
|
||||
* @param boolean $isCreateTable true if requirement is to get the statement
|
||||
* for table creation
|
||||
*
|
||||
* @return array $definitions An array of initial sql statements
|
||||
* according to the request
|
||||
*/
|
||||
private function buildColumnCreationStatement(
|
||||
$fieldCount,
|
||||
$isCreateTable = true
|
||||
) {
|
||||
$definitions = [];
|
||||
$previousField = -1;
|
||||
for ($i = 0; $i < $fieldCount; ++$i) {
|
||||
// '0' is also empty for php :-(
|
||||
if (strlen($_POST['field_name'][$i]) === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$definition = $this->getStatementPrefix($isCreateTable) .
|
||||
Table::generateFieldSpec(
|
||||
trim($_POST['field_name'][$i]),
|
||||
$_POST['field_type'][$i],
|
||||
$_POST['field_length'][$i],
|
||||
$_POST['field_attribute'][$i],
|
||||
isset($_POST['field_collation'][$i])
|
||||
? $_POST['field_collation'][$i]
|
||||
: '',
|
||||
isset($_POST['field_null'][$i])
|
||||
? $_POST['field_null'][$i]
|
||||
: 'NO',
|
||||
$_POST['field_default_type'][$i],
|
||||
$_POST['field_default_value'][$i],
|
||||
isset($_POST['field_extra'][$i])
|
||||
? $_POST['field_extra'][$i]
|
||||
: false,
|
||||
isset($_POST['field_comments'][$i])
|
||||
? $_POST['field_comments'][$i]
|
||||
: '',
|
||||
isset($_POST['field_virtuality'][$i])
|
||||
? $_POST['field_virtuality'][$i]
|
||||
: '',
|
||||
isset($_POST['field_expression'][$i])
|
||||
? $_POST['field_expression'][$i]
|
||||
: ''
|
||||
);
|
||||
|
||||
$definition .= $this->setColumnCreationStatementSuffix($i, $previousField, $isCreateTable);
|
||||
$previousField = $i;
|
||||
$definitions[] = $definition;
|
||||
} // end for
|
||||
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set column creation suffix according to requested position of the new column
|
||||
*
|
||||
* @param int $currentFieldNumber current column number
|
||||
* @param int $previousField previous field for ALTER statement
|
||||
* @param boolean $isCreateTable true if requirement is to get the statement
|
||||
* for table creation
|
||||
*
|
||||
* @return string $sqlSuffix suffix
|
||||
*/
|
||||
private function setColumnCreationStatementSuffix(
|
||||
$currentFieldNumber,
|
||||
$previousField,
|
||||
$isCreateTable = true
|
||||
) {
|
||||
// no suffix is needed if request is a table creation
|
||||
$sqlSuffix = ' ';
|
||||
if ($isCreateTable) {
|
||||
return $sqlSuffix;
|
||||
}
|
||||
|
||||
if ((string) $_POST['field_where'] === 'last') {
|
||||
return $sqlSuffix;
|
||||
}
|
||||
|
||||
// Only the first field can be added somewhere other than at the end
|
||||
if ($previousField == -1) {
|
||||
if ((string) $_POST['field_where'] === 'first') {
|
||||
$sqlSuffix .= ' FIRST';
|
||||
} else if (! empty($_POST['after_field'])) {
|
||||
$sqlSuffix .= ' AFTER '
|
||||
. Util::backquote($_POST['after_field']);
|
||||
}
|
||||
} else {
|
||||
$sqlSuffix .= ' AFTER '
|
||||
. Util::backquote(
|
||||
$_POST['field_name'][$previousField]
|
||||
);
|
||||
}
|
||||
|
||||
return $sqlSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create relevant index statements
|
||||
*
|
||||
* @param array $index an array of index columns
|
||||
* @param string $indexChoice index choice that which represents
|
||||
* the index type of $indexed_fields
|
||||
* @param boolean $isCreateTable true if requirement is to get the statement
|
||||
* for table creation
|
||||
*
|
||||
* @return array an array of sql statements for indexes
|
||||
*/
|
||||
private function buildIndexStatements(
|
||||
array $index,
|
||||
$indexChoice,
|
||||
$isCreateTable = true
|
||||
) {
|
||||
$statement = [];
|
||||
if (!count($index)) {
|
||||
return $statement;
|
||||
}
|
||||
|
||||
$sqlQuery = $this->getStatementPrefix($isCreateTable)
|
||||
. ' ' . $indexChoice;
|
||||
|
||||
if (! empty($index['Key_name']) && $index['Key_name'] != 'PRIMARY') {
|
||||
$sqlQuery .= ' ' . Util::backquote($index['Key_name']);
|
||||
}
|
||||
|
||||
$indexFields = [];
|
||||
foreach ($index['columns'] as $key => $column) {
|
||||
$indexFields[$key] = Util::backquote(
|
||||
$_POST['field_name'][$column['col_index']]
|
||||
);
|
||||
if ($column['size']) {
|
||||
$indexFields[$key] .= '(' . $column['size'] . ')';
|
||||
}
|
||||
}
|
||||
|
||||
$sqlQuery .= ' (' . implode(', ', $indexFields) . ')';
|
||||
|
||||
$keyBlockSizes = $index['Key_block_size'];
|
||||
if (! empty($keyBlockSizes)) {
|
||||
$sqlQuery .= " KEY_BLOCK_SIZE = "
|
||||
. $this->dbi->escapeString($keyBlockSizes);
|
||||
}
|
||||
|
||||
// specifying index type is allowed only for primary, unique and index only
|
||||
$type = $index['Index_type'];
|
||||
if ($index['Index_choice'] != 'SPATIAL'
|
||||
&& $index['Index_choice'] != 'FULLTEXT'
|
||||
&& in_array($type, Index::getIndexTypes())
|
||||
) {
|
||||
$sqlQuery .= ' USING ' . $type;
|
||||
}
|
||||
|
||||
$parser = $index['Parser'];
|
||||
if ($index['Index_choice'] == 'FULLTEXT' && ! empty($parser)) {
|
||||
$sqlQuery .= " WITH PARSER " . $this->dbi->escapeString($parser);
|
||||
}
|
||||
|
||||
$comment = $index['Index_comment'];
|
||||
if (! empty($comment)) {
|
||||
$sqlQuery .= " COMMENT '" . $this->dbi->escapeString($comment)
|
||||
. "'";
|
||||
}
|
||||
|
||||
$statement[] = $sqlQuery;
|
||||
|
||||
return $statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Statement prefix for the buildColumnCreationStatement()
|
||||
*
|
||||
* @param boolean $isCreateTable true if requirement is to get the statement
|
||||
* for table creation
|
||||
*
|
||||
* @return string $sqlPrefix prefix
|
||||
*/
|
||||
private function getStatementPrefix($isCreateTable = true)
|
||||
{
|
||||
$sqlPrefix = " ";
|
||||
if (! $isCreateTable) {
|
||||
$sqlPrefix = ' ADD ';
|
||||
}
|
||||
return $sqlPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge index definitions for one type of index
|
||||
*
|
||||
* @param array $definitions the index definitions to merge to
|
||||
* @param boolean $isCreateTable true if requirement is to get the statement
|
||||
* for table creation
|
||||
* @param array $indexedColumns the columns for one type of index
|
||||
* @param string $indexKeyword the index keyword to use in the definition
|
||||
*
|
||||
* @return array $index_definitions
|
||||
*/
|
||||
private function mergeIndexStatements(
|
||||
array $definitions,
|
||||
$isCreateTable,
|
||||
array $indexedColumns,
|
||||
$indexKeyword
|
||||
) {
|
||||
foreach ($indexedColumns as $index) {
|
||||
$statements = $this->buildIndexStatements(
|
||||
$index,
|
||||
" " . $indexKeyword . " ",
|
||||
$isCreateTable
|
||||
);
|
||||
$definitions = array_merge($definitions, $statements);
|
||||
}
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sql statement according to the column and index specifications as
|
||||
* requested
|
||||
*
|
||||
* @param boolean $isCreateTable true if requirement is to get the statement
|
||||
* for table creation
|
||||
*
|
||||
* @return string sql statement
|
||||
*/
|
||||
private function getColumnCreationStatements($isCreateTable = true)
|
||||
{
|
||||
$sqlStatement = "";
|
||||
list(
|
||||
$fieldCount,
|
||||
$fieldPrimary,
|
||||
$fieldIndex,
|
||||
$fieldUnique,
|
||||
$fieldFullText,
|
||||
$fieldSpatial
|
||||
) = $this->getIndexedColumns();
|
||||
$definitions = $this->buildColumnCreationStatement(
|
||||
$fieldCount,
|
||||
$isCreateTable
|
||||
);
|
||||
|
||||
// Builds the PRIMARY KEY statements
|
||||
$primaryKeyStatements = $this->buildIndexStatements(
|
||||
isset($fieldPrimary[0]) ? $fieldPrimary[0] : [],
|
||||
" PRIMARY KEY ",
|
||||
$isCreateTable
|
||||
);
|
||||
$definitions = array_merge($definitions, $primaryKeyStatements);
|
||||
|
||||
// Builds the INDEX statements
|
||||
$definitions = $this->mergeIndexStatements(
|
||||
$definitions,
|
||||
$isCreateTable,
|
||||
$fieldIndex,
|
||||
"INDEX"
|
||||
);
|
||||
|
||||
// Builds the UNIQUE statements
|
||||
$definitions = $this->mergeIndexStatements(
|
||||
$definitions,
|
||||
$isCreateTable,
|
||||
$fieldUnique,
|
||||
"UNIQUE"
|
||||
);
|
||||
|
||||
// Builds the FULLTEXT statements
|
||||
$definitions = $this->mergeIndexStatements(
|
||||
$definitions,
|
||||
$isCreateTable,
|
||||
$fieldFullText,
|
||||
"FULLTEXT"
|
||||
);
|
||||
|
||||
// Builds the SPATIAL statements
|
||||
$definitions = $this->mergeIndexStatements(
|
||||
$definitions,
|
||||
$isCreateTable,
|
||||
$fieldSpatial,
|
||||
"SPATIAL"
|
||||
);
|
||||
|
||||
if (count($definitions)) {
|
||||
$sqlStatement = implode(', ', $definitions);
|
||||
}
|
||||
$sqlStatement = preg_replace('@, $@', '', $sqlStatement);
|
||||
|
||||
return $sqlStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the partitioning clause
|
||||
*
|
||||
* @return string partitioning clause
|
||||
*/
|
||||
public function getPartitionsDefinition()
|
||||
{
|
||||
$sqlQuery = "";
|
||||
if (! empty($_POST['partition_by'])
|
||||
&& ! empty($_POST['partition_expr'])
|
||||
&& ! empty($_POST['partition_count'])
|
||||
&& $_POST['partition_count'] > 1
|
||||
) {
|
||||
$sqlQuery .= " PARTITION BY " . $_POST['partition_by']
|
||||
. " (" . $_POST['partition_expr'] . ")"
|
||||
. " PARTITIONS " . $_POST['partition_count'];
|
||||
}
|
||||
|
||||
if (! empty($_POST['subpartition_by'])
|
||||
&& ! empty($_POST['subpartition_expr'])
|
||||
&& ! empty($_POST['subpartition_count'])
|
||||
&& $_POST['subpartition_count'] > 1
|
||||
) {
|
||||
$sqlQuery .= " SUBPARTITION BY " . $_POST['subpartition_by']
|
||||
. " (" . $_POST['subpartition_expr'] . ")"
|
||||
. " SUBPARTITIONS " . $_POST['subpartition_count'];
|
||||
}
|
||||
|
||||
if (! empty($_POST['partitions'])) {
|
||||
$i = 0;
|
||||
$partitions = [];
|
||||
foreach ($_POST['partitions'] as $partition) {
|
||||
$partitions[] = $this->getPartitionDefinition($partition);
|
||||
$i++;
|
||||
}
|
||||
$sqlQuery .= " (" . implode(", ", $partitions) . ")";
|
||||
}
|
||||
|
||||
return $sqlQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the definition of a partition/subpartition
|
||||
*
|
||||
* @param array $partition array of partition/subpartition detiails
|
||||
* @param boolean $isSubPartition whether a subpartition
|
||||
*
|
||||
* @return string partition/subpartition definition
|
||||
*/
|
||||
private function getPartitionDefinition(array $partition, $isSubPartition = false)
|
||||
{
|
||||
$sqlQuery = " " . ($isSubPartition ? "SUB" : "") . "PARTITION ";
|
||||
$sqlQuery .= $partition['name'];
|
||||
|
||||
if (! empty($partition['value_type'])) {
|
||||
$sqlQuery .= " VALUES " . $partition['value_type'];
|
||||
|
||||
if ($partition['value_type'] != 'LESS THAN MAXVALUE') {
|
||||
$sqlQuery .= " (" . $partition['value'] . ")";
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($partition['engine'])) {
|
||||
$sqlQuery .= " ENGINE = " . $partition['engine'];
|
||||
}
|
||||
if (! empty($partition['comment'])) {
|
||||
$sqlQuery .= " COMMENT = '" . $partition['comment'] . "'";
|
||||
}
|
||||
if (! empty($partition['data_directory'])) {
|
||||
$sqlQuery .= " DATA DIRECTORY = '" . $partition['data_directory'] . "'";
|
||||
}
|
||||
if (! empty($partition['index_directory'])) {
|
||||
$sqlQuery .= " INDEX_DIRECTORY = '" . $partition['index_directory'] . "'";
|
||||
}
|
||||
if (! empty($partition['max_rows'])) {
|
||||
$sqlQuery .= " MAX_ROWS = " . $partition['max_rows'];
|
||||
}
|
||||
if (! empty($partition['min_rows'])) {
|
||||
$sqlQuery .= " MIN_ROWS = " . $partition['min_rows'];
|
||||
}
|
||||
if (! empty($partition['tablespace'])) {
|
||||
$sqlQuery .= " TABLESPACE = " . $partition['tablespace'];
|
||||
}
|
||||
if (! empty($partition['node_group'])) {
|
||||
$sqlQuery .= " NODEGROUP = " . $partition['node_group'];
|
||||
}
|
||||
|
||||
if (! empty($partition['subpartitions'])) {
|
||||
$j = 0;
|
||||
$subpartitions = [];
|
||||
foreach ($partition['subpartitions'] as $subpartition) {
|
||||
$subpartitions[] = $this->getPartitionDefinition(
|
||||
$subpartition,
|
||||
true
|
||||
);
|
||||
$j++;
|
||||
}
|
||||
$sqlQuery .= " (" . implode(", ", $subpartitions) . ")";
|
||||
}
|
||||
|
||||
return $sqlQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get table creation sql query
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTableCreationQuery($db, $table)
|
||||
{
|
||||
// get column addition statements
|
||||
$sqlStatement = $this->getColumnCreationStatements(true);
|
||||
|
||||
// Builds the 'create table' statement
|
||||
$sqlQuery = 'CREATE TABLE ' . Util::backquote($db) . '.'
|
||||
. Util::backquote(trim($table)) . ' (' . $sqlStatement . ')';
|
||||
|
||||
// Adds table type, character set, comments and partition definition
|
||||
if (!empty($_POST['tbl_storage_engine'])
|
||||
&& ($_POST['tbl_storage_engine'] != 'Default')
|
||||
) {
|
||||
$sqlQuery .= ' ENGINE = ' . $_POST['tbl_storage_engine'];
|
||||
}
|
||||
if (!empty($_POST['tbl_collation'])) {
|
||||
$sqlQuery .= Util::getCharsetQueryPart($_POST['tbl_collation']);
|
||||
}
|
||||
if (! empty($_POST['connection'])
|
||||
&& ! empty($_POST['tbl_storage_engine'])
|
||||
&& $_POST['tbl_storage_engine'] == 'FEDERATED'
|
||||
) {
|
||||
$sqlQuery .= " CONNECTION = '"
|
||||
. $this->dbi->escapeString($_POST['connection']) . "'";
|
||||
}
|
||||
if (!empty($_POST['comment'])) {
|
||||
$sqlQuery .= ' COMMENT = \''
|
||||
. $this->dbi->escapeString($_POST['comment']) . '\'';
|
||||
}
|
||||
$sqlQuery .= $this->getPartitionsDefinition();
|
||||
$sqlQuery .= ';';
|
||||
|
||||
return $sqlQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get the number of fields for the table creation form
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumberOfFieldsFromRequest()
|
||||
{
|
||||
// Limit to 4096 fields (MySQL maximal value)
|
||||
$mysqlLimit = 4096;
|
||||
|
||||
if (isset($_POST['submit_num_fields'])) { // adding new fields
|
||||
$numberOfFields = intval($_POST['orig_num_fields']) + intval($_POST['added_fields']);
|
||||
} elseif (isset($_POST['orig_num_fields'])) { // retaining existing fields
|
||||
$numberOfFields = intval($_POST['orig_num_fields']);
|
||||
} elseif (isset($_POST['num_fields'])
|
||||
&& intval($_POST['num_fields']) > 0
|
||||
) { // new table with specified number of fields
|
||||
$numberOfFields = intval($_POST['num_fields']);
|
||||
} else { // new table with unspecified number of fields
|
||||
$numberOfFields = 4;
|
||||
}
|
||||
|
||||
return min($numberOfFields, $mysqlLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to execute the column creation statement
|
||||
*
|
||||
* @param string $db current database
|
||||
* @param string $table current table
|
||||
* @param string $errorUrl error page url
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function tryColumnCreationQuery($db, $table, $errorUrl)
|
||||
{
|
||||
// get column addition statements
|
||||
$sqlStatement = $this->getColumnCreationStatements(false);
|
||||
|
||||
// To allow replication, we first select the db to use and then run queries
|
||||
// on this db.
|
||||
if (!($this->dbi->selectDb($db))) {
|
||||
Util::mysqlDie(
|
||||
$this->dbi->getError(),
|
||||
'USE ' . Util::backquote($db),
|
||||
false,
|
||||
$errorUrl
|
||||
);
|
||||
}
|
||||
$sqlQuery = 'ALTER TABLE ' .
|
||||
Util::backquote($table) . ' ' . $sqlStatement . ';';
|
||||
// If there is a request for SQL previewing.
|
||||
if (isset($_POST['preview_sql'])) {
|
||||
Core::previewSQL($sqlQuery);
|
||||
}
|
||||
return [$this->dbi->tryQuery($sqlQuery), $sqlQuery];
|
||||
}
|
||||
}
|
||||
161
phpMyAdmin/libraries/classes/Crypto/Crypto.php
Executable file
161
phpMyAdmin/libraries/classes/Crypto/Crypto.php
Executable file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace PhpMyAdmin\Crypto;
|
||||
|
||||
use Exception;
|
||||
use phpseclib\Crypt\AES;
|
||||
use phpseclib\Crypt\Random;
|
||||
|
||||
final class Crypto
|
||||
{
|
||||
/** @var bool */
|
||||
private $hasRandomBytesSupport;
|
||||
|
||||
/** @var bool */
|
||||
private $hasSodiumSupport;
|
||||
|
||||
/**
|
||||
* @param bool $forceFallback Force the usage of the fallback functions.
|
||||
*/
|
||||
public function __construct($forceFallback = false)
|
||||
{
|
||||
$this->hasRandomBytesSupport = ! $forceFallback && is_callable('random_bytes');
|
||||
$this->hasSodiumSupport = ! $forceFallback
|
||||
&& $this->hasRandomBytesSupport
|
||||
&& is_callable('sodium_crypto_secretbox')
|
||||
&& is_callable('sodium_crypto_secretbox_open')
|
||||
&& defined('SODIUM_CRYPTO_SECRETBOX_NONCEBYTES')
|
||||
&& defined('SODIUM_CRYPTO_SECRETBOX_KEYBYTES');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plaintext
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encrypt($plaintext)
|
||||
{
|
||||
if ($this->hasSodiumSupport) {
|
||||
return $this->encryptWithSodium($plaintext);
|
||||
}
|
||||
|
||||
return $this->encryptWithPhpseclib($plaintext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ciphertext
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function decrypt($ciphertext)
|
||||
{
|
||||
if ($this->hasSodiumSupport) {
|
||||
return $this->decryptWithSodium($ciphertext);
|
||||
}
|
||||
|
||||
return $this->decryptWithPhpseclib($ciphertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getEncryptionKey()
|
||||
{
|
||||
global $PMA_Config;
|
||||
|
||||
$keyLength = $this->hasSodiumSupport ? SODIUM_CRYPTO_SECRETBOX_KEYBYTES : 32;
|
||||
|
||||
$key = $PMA_Config->get('URLQueryEncryptionSecretKey');
|
||||
if (is_string($key) && mb_strlen($key, '8bit') === $keyLength) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
$key = isset($_SESSION['URLQueryEncryptionSecretKey']) ? $_SESSION['URLQueryEncryptionSecretKey'] : null;
|
||||
if (is_string($key) && mb_strlen($key, '8bit') === $keyLength) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
$key = $this->hasRandomBytesSupport ? random_bytes($keyLength) : Random::string($keyLength);
|
||||
$_SESSION['URLQueryEncryptionSecretKey'] = $key;
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plaintext
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function encryptWithPhpseclib($plaintext)
|
||||
{
|
||||
$key = $this->getEncryptionKey();
|
||||
$cipher = new AES(AES::MODE_CBC);
|
||||
$iv = $this->hasRandomBytesSupport ? random_bytes(16) : Random::string(16);
|
||||
$cipher->setIV($iv);
|
||||
$cipher->setKey($key);
|
||||
$ciphertext = $cipher->encrypt($plaintext);
|
||||
$hmac = hash_hmac('sha256', $iv . $ciphertext, $key, true);
|
||||
|
||||
return $hmac . $iv . $ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encrypted
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function decryptWithPhpseclib($encrypted)
|
||||
{
|
||||
$key = $this->getEncryptionKey();
|
||||
$hmac = mb_substr($encrypted, 0, 32, '8bit');
|
||||
$iv = mb_substr($encrypted, 32, 16, '8bit');
|
||||
$ciphertext = mb_substr($encrypted, 48, null, '8bit');
|
||||
$calculatedHmac = hash_hmac('sha256', $iv . $ciphertext, $key, true);
|
||||
if (! hash_equals($hmac, $calculatedHmac)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cipher = new AES(AES::MODE_CBC);
|
||||
$cipher->setIV($iv);
|
||||
$cipher->setKey($key);
|
||||
|
||||
return $cipher->decrypt($ciphertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plaintext
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function encryptWithSodium($plaintext)
|
||||
{
|
||||
$key = $this->getEncryptionKey();
|
||||
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
|
||||
$ciphertext = sodium_crypto_secretbox($plaintext, $nonce, $key);
|
||||
|
||||
return $nonce . $ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encrypted
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function decryptWithSodium($encrypted)
|
||||
{
|
||||
$key = $this->getEncryptionKey();
|
||||
$nonce = mb_substr($encrypted, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
|
||||
$ciphertext = mb_substr($encrypted, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
|
||||
try {
|
||||
$decrypted = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($decrypted === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $decrypted;
|
||||
}
|
||||
}
|
||||
58
phpMyAdmin/libraries/classes/Database/DatabaseList.php
Executable file
58
phpMyAdmin/libraries/classes/Database/DatabaseList.php
Executable file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* holds the PhpMyAdmin\Database\DatabaseList class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*
|
||||
*/
|
||||
namespace PhpMyAdmin\Database;
|
||||
|
||||
use PhpMyAdmin\ListDatabase;
|
||||
|
||||
/**
|
||||
* holds the DatabaseList class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class DatabaseList
|
||||
{
|
||||
/**
|
||||
* Holds database list
|
||||
*
|
||||
* @var ListDatabase
|
||||
*/
|
||||
protected $databases = null;
|
||||
|
||||
/**
|
||||
* magic access to protected/inaccessible members/properties
|
||||
*
|
||||
* @param string $param parameter name
|
||||
*
|
||||
* @return mixed
|
||||
* @see https://www.php.net/language.oop5.overloading
|
||||
*/
|
||||
public function __get($param)
|
||||
{
|
||||
switch ($param) {
|
||||
case 'databases' :
|
||||
return $this->getDatabaseList();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor to PMA::$databases
|
||||
*
|
||||
* @return ListDatabase
|
||||
*/
|
||||
public function getDatabaseList()
|
||||
{
|
||||
if (null === $this->databases) {
|
||||
$this->databases = new ListDatabase();
|
||||
}
|
||||
|
||||
return $this->databases;
|
||||
}
|
||||
}
|
||||
432
phpMyAdmin/libraries/classes/Database/Designer.php
Executable file
432
phpMyAdmin/libraries/classes/Database/Designer.php
Executable file
@@ -0,0 +1,432 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Database\Designer class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Database;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\Plugins\SchemaPlugin;
|
||||
use PhpMyAdmin\Relation;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Set of functions related to database designer
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class Designer
|
||||
{
|
||||
/**
|
||||
* @var Relation $relation
|
||||
*/
|
||||
private $relation;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->relation = new Relation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get html for displaying the page edit/delete form
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $operation 'edit' or 'delete' depending on the operation
|
||||
*
|
||||
* @return string html content
|
||||
*/
|
||||
public function getHtmlForEditOrDeletePages($db, $operation)
|
||||
{
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
return Template::get('database/designer/edit_delete_pages')->render([
|
||||
'db' => $db,
|
||||
'operation' => $operation,
|
||||
'pdfwork' => $cfgRelation['pdfwork'],
|
||||
'pages' => $this->getPageIdsAndNames($db),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get html for displaying the page save as form
|
||||
*
|
||||
* @param string $db database name
|
||||
*
|
||||
* @return string html content
|
||||
*/
|
||||
public function getHtmlForPageSaveAs($db)
|
||||
{
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
return Template::get('database/designer/page_save_as')->render([
|
||||
'db' => $db,
|
||||
'pdfwork' => $cfgRelation['pdfwork'],
|
||||
'pages' => $this->getPageIdsAndNames($db),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve IDs and names of schema pages
|
||||
*
|
||||
* @param string $db database name
|
||||
*
|
||||
* @return array array of schema page id and names
|
||||
*/
|
||||
private function getPageIdsAndNames($db)
|
||||
{
|
||||
$result = [];
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
if (! $cfgRelation['pdfwork']) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$page_query = "SELECT `page_nr`, `page_descr` FROM "
|
||||
. Util::backquote($cfgRelation['db']) . "."
|
||||
. Util::backquote($cfgRelation['pdf_pages'])
|
||||
. " WHERE db_name = '" . $GLOBALS['dbi']->escapeString($db) . "'"
|
||||
. " ORDER BY `page_descr`";
|
||||
$page_rs = $this->relation->queryAsControlUser(
|
||||
$page_query,
|
||||
false,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
|
||||
while ($curr_page = $GLOBALS['dbi']->fetchAssoc($page_rs)) {
|
||||
$result[intval($curr_page['page_nr'])] = $curr_page['page_descr'];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get html for displaying the schema export
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param int $page the page to be exported
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHtmlForSchemaExport($db, $page)
|
||||
{
|
||||
/* Scan for schema plugins */
|
||||
/* @var $export_list SchemaPlugin[] */
|
||||
$export_list = Plugins::getPlugins(
|
||||
"schema",
|
||||
'libraries/classes/Plugins/Schema/',
|
||||
null
|
||||
);
|
||||
|
||||
/* Fail if we didn't find any schema plugin */
|
||||
if (empty($export_list)) {
|
||||
return Message::error(
|
||||
__('Could not load schema plugins, please check your installation!')
|
||||
)->getDisplay();
|
||||
}
|
||||
|
||||
return Template::get('database/designer/schema_export')
|
||||
->render(
|
||||
[
|
||||
'db' => $db,
|
||||
'page' => $page,
|
||||
'export_list' => $export_list
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for including some variable to be accessed by JavaScript
|
||||
*
|
||||
* @param array $script_tables array on foreign key support for each table
|
||||
* @param array $script_contr initialization data array
|
||||
* @param Designer\DesignerTable[] $script_display_field displayed tables in designer with their display fields
|
||||
* @param int $display_page page number of the selected page
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getHtmlForJsFields(
|
||||
array $script_tables,
|
||||
array $script_contr,
|
||||
array $script_display_field,
|
||||
$display_page
|
||||
) {
|
||||
$displayedFields = [];
|
||||
foreach ($script_display_field as $designerTable) {
|
||||
if ($designerTable->getDisplayField() !== null) {
|
||||
$displayedFields[$designerTable->getTableName()] = $designerTable->getDisplayField();
|
||||
}
|
||||
}
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
$designerConfig = new \stdClass();
|
||||
$designerConfig->db = $_GET['db'];
|
||||
$designerConfig->scriptTables = $script_tables;
|
||||
$designerConfig->scriptContr = $script_contr;
|
||||
$designerConfig->server = $GLOBALS['server'];
|
||||
$designerConfig->scriptDisplayField = $displayedFields;
|
||||
$designerConfig->displayPage = (int) $display_page;
|
||||
$designerConfig->tablesEnabled = $cfgRelation['pdfwork'];
|
||||
return Template::get('database/designer/js_fields')->render([
|
||||
'designer_config' => json_encode($designerConfig)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for the menu bar of the designer page
|
||||
*
|
||||
* @param boolean $visualBuilder whether this is visual query builder
|
||||
* @param string $selectedPage name of the selected page
|
||||
* @param array $paramsArray array with class name for various buttons
|
||||
* on side menu
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getPageMenu($visualBuilder, $selectedPage, array $paramsArray)
|
||||
{
|
||||
return Template::get('database/designer/side_menu')->render([
|
||||
'visual_builder' => $visualBuilder,
|
||||
'selected_page' => $selectedPage,
|
||||
'params_array' => $paramsArray,
|
||||
'theme' => $GLOBALS['PMA_Theme'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of stored values of Designer Settings
|
||||
*
|
||||
* @return array stored values
|
||||
*/
|
||||
private function getSideMenuParamsArray()
|
||||
{
|
||||
$params = [];
|
||||
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
|
||||
if ($cfgRelation['designersettingswork']) {
|
||||
$query = 'SELECT `settings_data` FROM '
|
||||
. Util::backquote($cfgRelation['db']) . '.'
|
||||
. Util::backquote($cfgRelation['designer_settings'])
|
||||
. ' WHERE ' . Util::backquote('username') . ' = "'
|
||||
. $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user'])
|
||||
. '";';
|
||||
|
||||
$result = $GLOBALS['dbi']->fetchSingleRow($query);
|
||||
|
||||
$params = json_decode($result['settings_data'], true);
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class names for various buttons on Designer Side Menu
|
||||
*
|
||||
* @return array class names of various buttons
|
||||
*/
|
||||
public function returnClassNamesFromMenuButtons()
|
||||
{
|
||||
$classes_array = [];
|
||||
$params_array = $this->getSideMenuParamsArray();
|
||||
|
||||
if (isset($params_array['angular_direct'])
|
||||
&& $params_array['angular_direct'] == 'angular'
|
||||
) {
|
||||
$classes_array['angular_direct'] = 'M_butt_Selected_down';
|
||||
} else {
|
||||
$classes_array['angular_direct'] = 'M_butt';
|
||||
}
|
||||
|
||||
if (isset($params_array['snap_to_grid'])
|
||||
&& $params_array['snap_to_grid'] == 'on'
|
||||
) {
|
||||
$classes_array['snap_to_grid'] = 'M_butt_Selected_down';
|
||||
} else {
|
||||
$classes_array['snap_to_grid'] = 'M_butt';
|
||||
}
|
||||
|
||||
if (isset($params_array['pin_text'])
|
||||
&& $params_array['pin_text'] == 'true'
|
||||
) {
|
||||
$classes_array['pin_text'] = 'M_butt_Selected_down';
|
||||
} else {
|
||||
$classes_array['pin_text'] = 'M_butt';
|
||||
}
|
||||
|
||||
if (isset($params_array['relation_lines'])
|
||||
&& $params_array['relation_lines'] == 'false'
|
||||
) {
|
||||
$classes_array['relation_lines'] = 'M_butt_Selected_down';
|
||||
} else {
|
||||
$classes_array['relation_lines'] = 'M_butt';
|
||||
}
|
||||
|
||||
if (isset($params_array['small_big_all'])
|
||||
&& $params_array['small_big_all'] == 'v'
|
||||
) {
|
||||
$classes_array['small_big_all'] = 'M_butt_Selected_down';
|
||||
} else {
|
||||
$classes_array['small_big_all'] = 'M_butt';
|
||||
}
|
||||
|
||||
if (isset($params_array['side_menu'])
|
||||
&& $params_array['side_menu'] == 'true'
|
||||
) {
|
||||
$classes_array['side_menu'] = 'M_butt_Selected_down';
|
||||
} else {
|
||||
$classes_array['side_menu'] = 'M_butt';
|
||||
}
|
||||
|
||||
return $classes_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for the canvas element
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getHtmlCanvas()
|
||||
{
|
||||
return Template::get('database/designer/canvas')->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML for the table list
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getHtmlTableList()
|
||||
{
|
||||
return Template::get('database/designer/table_list')->render([
|
||||
'theme' => $GLOBALS['PMA_Theme'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML to display tables on designer page
|
||||
*
|
||||
* @param string $db The database name from the request
|
||||
* @param array $designerTables The designer tables
|
||||
* @param array $tab_pos tables positions
|
||||
* @param int $display_page page number of the selected page
|
||||
* @param array $tab_column table column info
|
||||
* @param array $tables_all_keys all indices
|
||||
* @param array $tables_pk_or_unique_keys unique or primary indices
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getDatabaseTables(
|
||||
$db,
|
||||
array $designerTables,
|
||||
array $tab_pos,
|
||||
$display_page,
|
||||
array $tab_column,
|
||||
array $tables_all_keys,
|
||||
array $tables_pk_or_unique_keys
|
||||
) {
|
||||
return Template::get('database/designer/database_tables')->render([
|
||||
'db' => $GLOBALS['db'],
|
||||
'get_db' => $db,
|
||||
'has_query' => isset($_REQUEST['query']),
|
||||
'tab_pos' => $tab_pos,
|
||||
'display_page' => $display_page,
|
||||
'tab_column' => $tab_column,
|
||||
'tables_all_keys' => $tables_all_keys,
|
||||
'tables_pk_or_unique_keys' => $tables_pk_or_unique_keys,
|
||||
'tables' => $designerTables,
|
||||
'theme' => $GLOBALS['PMA_Theme'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for the new relations panel.
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getNewRelationPanel()
|
||||
{
|
||||
return Template::get('database/designer/new_relation_panel')
|
||||
->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for the relations delete panel
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getDeleteRelationPanel()
|
||||
{
|
||||
return Template::get('database/designer/delete_relation_panel')
|
||||
->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for the options panel
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getOptionsPanel()
|
||||
{
|
||||
return Template::get('database/designer/options_panel')->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML for the 'rename to' panel
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getRenameToPanel()
|
||||
{
|
||||
return Template::get('database/designer/rename_to_panel')
|
||||
->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for the 'having' panel
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getHavingQueryPanel()
|
||||
{
|
||||
return Template::get('database/designer/having_query_panel')
|
||||
->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for the 'aggregate' panel
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getAggregateQueryPanel()
|
||||
{
|
||||
return Template::get('database/designer/aggregate_query_panel')
|
||||
->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for the 'where' panel
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getWhereQueryPanel()
|
||||
{
|
||||
return Template::get('database/designer/where_query_panel')
|
||||
->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for the query details panel
|
||||
*
|
||||
* @param string $db Database name
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
public function getQueryDetails($db)
|
||||
{
|
||||
return Template::get('database/designer/query_details')->render([
|
||||
'db' => $db,
|
||||
]);
|
||||
}
|
||||
}
|
||||
792
phpMyAdmin/libraries/classes/Database/Designer/Common.php
Executable file
792
phpMyAdmin/libraries/classes/Database/Designer/Common.php
Executable file
@@ -0,0 +1,792 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Database\Designer\Common class
|
||||
*
|
||||
* @package PhpMyAdmin-Designer
|
||||
*/
|
||||
namespace PhpMyAdmin\Database\Designer;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Index;
|
||||
use PhpMyAdmin\Relation;
|
||||
use PhpMyAdmin\Table;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Database\Designer\DesignerTable;
|
||||
|
||||
/**
|
||||
* Common functions for Designer
|
||||
*
|
||||
* @package PhpMyAdmin-Designer
|
||||
*/
|
||||
class Common
|
||||
{
|
||||
/**
|
||||
* @var Relation $relation
|
||||
*/
|
||||
private $relation;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->relation = new Relation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves table info and returns it
|
||||
*
|
||||
* @param string $db (optional) Filter only a DB ($table is required if you use $db)
|
||||
* @param string $table (optional) Filter only a table ($db is now required)
|
||||
* @return DesignerTable[] with table info
|
||||
*/
|
||||
public function getTablesInfo($db = null, $table = null)
|
||||
{
|
||||
$designerTables = array();
|
||||
$db = ($db === null) ? $GLOBALS['db'] : $db;
|
||||
// seems to be needed later
|
||||
$GLOBALS['dbi']->selectDb($db);
|
||||
if ($db === null && $table === null) {
|
||||
$tables = $GLOBALS['dbi']->getTablesFull($db);
|
||||
} else {
|
||||
$tables = $GLOBALS['dbi']->getTablesFull($db, $table);
|
||||
}
|
||||
|
||||
foreach ($tables as $one_table) {
|
||||
$DF = $this->relation->getDisplayField($db, $one_table['TABLE_NAME']);
|
||||
$DF = is_string($DF) ? $DF : '';
|
||||
$DF = ($DF !== '') ? $DF : null;
|
||||
$designerTables[] = new DesignerTable(
|
||||
$db,
|
||||
$one_table['TABLE_NAME'],
|
||||
is_string($one_table['ENGINE']) ? $one_table['ENGINE'] : '',
|
||||
$DF
|
||||
);
|
||||
}
|
||||
|
||||
return $designerTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves table column info
|
||||
*
|
||||
* @param DesignerTable[] $designerTables The designer tables
|
||||
* @return array table column nfo
|
||||
*/
|
||||
public function getColumnsInfo($designerTables)
|
||||
{
|
||||
//$GLOBALS['dbi']->selectDb($GLOBALS['db']);
|
||||
$tabColumn = array();
|
||||
|
||||
foreach($designerTables as $designerTable) {
|
||||
$fieldsRs = $GLOBALS['dbi']->query(
|
||||
$GLOBALS['dbi']->getColumnsSql(
|
||||
$designerTable->getDatabaseName(),
|
||||
$designerTable->getTableName(),
|
||||
null,
|
||||
true
|
||||
),
|
||||
DatabaseInterface::CONNECT_USER,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
$j = 0;
|
||||
while ($row = $GLOBALS['dbi']->fetchAssoc($fieldsRs)) {
|
||||
if (! isset($tabColumn[$designerTable->getDbTableString()])) {
|
||||
$tabColumn[$designerTable->getDbTableString()] = [];
|
||||
}
|
||||
$tabColumn[$designerTable->getDbTableString()]['COLUMN_ID'][$j] = $j;
|
||||
$tabColumn[$designerTable->getDbTableString()]['COLUMN_NAME'][$j] = $row['Field'];
|
||||
$tabColumn[$designerTable->getDbTableString()]['TYPE'][$j] = $row['Type'];
|
||||
$tabColumn[$designerTable->getDbTableString()]['NULLABLE'][$j] = $row['Null'];
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
|
||||
return $tabColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns JavaScript code for initializing vars
|
||||
*
|
||||
* @param DesignerTable[] $designerTables The designer tables
|
||||
* @return string JavaScript code
|
||||
*/
|
||||
public function getScriptContr($designerTables)
|
||||
{
|
||||
$GLOBALS['dbi']->selectDb($GLOBALS['db']);
|
||||
$con = array();
|
||||
$con["C_NAME"] = array();
|
||||
$i = 0;
|
||||
$alltab_rs = $GLOBALS['dbi']->query(
|
||||
'SHOW TABLES FROM ' . Util::backquote($GLOBALS['db']),
|
||||
DatabaseInterface::CONNECT_USER,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
while ($val = @$GLOBALS['dbi']->fetchRow($alltab_rs)) {
|
||||
$row = $this->relation->getForeigners($GLOBALS['db'], $val[0], '', 'internal');
|
||||
|
||||
if ($row !== false) {
|
||||
foreach ($row as $field => $value) {
|
||||
$con['C_NAME'][$i] = '';
|
||||
$con['DTN'][$i] = rawurlencode($GLOBALS['db'] . "." . $val[0]);
|
||||
$con['DCN'][$i] = rawurlencode($field);
|
||||
$con['STN'][$i] = rawurlencode(
|
||||
$value['foreign_db'] . "." . $value['foreign_table']
|
||||
);
|
||||
$con['SCN'][$i] = rawurlencode($value['foreign_field']);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
$row = $this->relation->getForeigners($GLOBALS['db'], $val[0], '', 'foreign');
|
||||
|
||||
// We do not have access to the foreign keys if he user has partial access to the columns
|
||||
if ($row !== false && isset($row['foreign_keys_data'])) {
|
||||
foreach ($row['foreign_keys_data'] as $one_key) {
|
||||
foreach ($one_key['index_list'] as $index => $one_field) {
|
||||
$con['C_NAME'][$i] = rawurlencode($one_key['constraint']);
|
||||
$con['DTN'][$i] = rawurlencode($GLOBALS['db'] . "." . $val[0]);
|
||||
$con['DCN'][$i] = rawurlencode($one_field);
|
||||
$con['STN'][$i] = rawurlencode(
|
||||
(isset($one_key['ref_db_name']) ?
|
||||
$one_key['ref_db_name'] : $GLOBALS['db'])
|
||||
. "." . $one_key['ref_table_name']
|
||||
);
|
||||
$con['SCN'][$i] = rawurlencode($one_key['ref_index_list'][$index]);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tableDbNames = [];
|
||||
foreach($designerTables as $designerTable) {
|
||||
$tableDbNames[] = $designerTable->getDbTableString();
|
||||
}
|
||||
|
||||
$ti = 0;
|
||||
$retval = array();
|
||||
for ($i = 0, $cnt = count($con["C_NAME"]); $i < $cnt; $i++) {
|
||||
$c_name_i = $con['C_NAME'][$i];
|
||||
$dtn_i = $con['DTN'][$i];
|
||||
$retval[$ti] = array();
|
||||
$retval[$ti][$c_name_i] = array();
|
||||
if (in_array($dtn_i, $tableDbNames) && in_array($con['STN'][$i], $tableDbNames)) {
|
||||
$retval[$ti][$c_name_i][$dtn_i] = array();
|
||||
$retval[$ti][$c_name_i][$dtn_i][$con['DCN'][$i]] = array(
|
||||
0 => $con['STN'][$i],
|
||||
1 => $con['SCN'][$i]
|
||||
);
|
||||
}
|
||||
$ti++;
|
||||
}
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns UNIQUE and PRIMARY indices
|
||||
*
|
||||
* @param DesignerTable[] $designerTables The designer tables
|
||||
* @return array unique or primary indices
|
||||
*/
|
||||
public function getPkOrUniqueKeys($designerTables)
|
||||
{
|
||||
return $this->getAllKeys($designerTables, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all indices
|
||||
*
|
||||
* @param DesignerTable[] $designerTables The designer tables
|
||||
* @param bool $unique_only whether to include only unique ones
|
||||
*
|
||||
* @return array indices
|
||||
*/
|
||||
public function getAllKeys($designerTables, $unique_only = false)
|
||||
{
|
||||
$keys = array();
|
||||
|
||||
foreach ($designerTables as $designerTable) {
|
||||
$schema = $designerTable->getDatabaseName();
|
||||
// for now, take into account only the first index segment
|
||||
foreach (Index::getFromTable($designerTable->getTableName(), $schema) as $index) {
|
||||
if ($unique_only && ! $index->isUnique()) {
|
||||
continue;
|
||||
}
|
||||
$columns = $index->getColumns();
|
||||
foreach ($columns as $column_name => $dummy) {
|
||||
$keys[$schema . '.' . $designerTable->getTableName() . '.' . $column_name] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return j_tab and h_tab arrays
|
||||
*
|
||||
* @param DesignerTable[] $designerTables The designer tables
|
||||
* @return array
|
||||
*/
|
||||
public function getScriptTabs($designerTables)
|
||||
{
|
||||
$retval = array(
|
||||
'j_tabs' => array(),
|
||||
'h_tabs' => array()
|
||||
);
|
||||
|
||||
foreach($designerTables as $designerTable) {
|
||||
$key = rawurlencode($designerTable->getDbTableString());
|
||||
$retval['j_tabs'][$key] = $designerTable->supportsForeignkeys() ? 1 : 0;
|
||||
$retval['h_tabs'][$key] = 1;
|
||||
}
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns table positions of a given pdf page
|
||||
*
|
||||
* @param int $pg pdf page id
|
||||
*
|
||||
* @return array of table positions
|
||||
*/
|
||||
public function getTablePositions($pg)
|
||||
{
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
if (! $cfgRelation['pdfwork']) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$query = "
|
||||
SELECT CONCAT_WS('.', `db_name`, `table_name`) AS `name`,
|
||||
`db_name` as `dbName`, `table_name` as `tableName`,
|
||||
`x` AS `X`,
|
||||
`y` AS `Y`,
|
||||
1 AS `V`,
|
||||
1 AS `H`
|
||||
FROM " . Util::backquote($cfgRelation['db'])
|
||||
. "." . Util::backquote($cfgRelation['table_coords']) . "
|
||||
WHERE pdf_page_number = " . intval($pg);
|
||||
|
||||
$tab_pos = $GLOBALS['dbi']->fetchResult(
|
||||
$query,
|
||||
'name',
|
||||
null,
|
||||
DatabaseInterface::CONNECT_CONTROL,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
return $tab_pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns page name of a given pdf page
|
||||
*
|
||||
* @param int $pg pdf page id
|
||||
*
|
||||
* @return string|null table name
|
||||
*/
|
||||
public function getPageName($pg)
|
||||
{
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
if (! $cfgRelation['pdfwork']) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$query = "SELECT `page_descr`"
|
||||
. " FROM " . Util::backquote($cfgRelation['db'])
|
||||
. "." . Util::backquote($cfgRelation['pdf_pages'])
|
||||
. " WHERE " . Util::backquote('page_nr') . " = " . intval($pg);
|
||||
$page_name = $GLOBALS['dbi']->fetchResult(
|
||||
$query,
|
||||
null,
|
||||
null,
|
||||
DatabaseInterface::CONNECT_CONTROL,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
return ( is_array($page_name) && isset($page_name[0]) ) ? $page_name[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a given pdf page and its corresponding coordinates
|
||||
*
|
||||
* @param int $pg page id
|
||||
*
|
||||
* @return boolean success/failure
|
||||
*/
|
||||
public function deletePage($pg)
|
||||
{
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
if (! $cfgRelation['pdfwork']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = "DELETE FROM " . Util::backquote($cfgRelation['db'])
|
||||
. "." . Util::backquote($cfgRelation['table_coords'])
|
||||
. " WHERE " . Util::backquote('pdf_page_number') . " = " . intval($pg);
|
||||
$success = $this->relation->queryAsControlUser(
|
||||
$query, true, DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
|
||||
if ($success) {
|
||||
$query = "DELETE FROM " . Util::backquote($cfgRelation['db'])
|
||||
. "." . Util::backquote($cfgRelation['pdf_pages'])
|
||||
. " WHERE " . Util::backquote('page_nr') . " = " . intval($pg);
|
||||
$success = $this->relation->queryAsControlUser(
|
||||
$query, true, DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
}
|
||||
|
||||
return (boolean) $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the default pdf page of the database.
|
||||
* Default page is the one which has the same name as the database.
|
||||
*
|
||||
* @param string $db database
|
||||
*
|
||||
* @return int id of the default pdf page for the database
|
||||
*/
|
||||
public function getDefaultPage($db)
|
||||
{
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
if (! $cfgRelation['pdfwork']) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
$query = "SELECT `page_nr`"
|
||||
. " FROM " . Util::backquote($cfgRelation['db'])
|
||||
. "." . Util::backquote($cfgRelation['pdf_pages'])
|
||||
. " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($db) . "'"
|
||||
. " AND `page_descr` = '" . $GLOBALS['dbi']->escapeString($db) . "'";
|
||||
|
||||
$default_page_no = $GLOBALS['dbi']->fetchResult(
|
||||
$query,
|
||||
null,
|
||||
null,
|
||||
DatabaseInterface::CONNECT_CONTROL,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
|
||||
if (is_array($default_page_no) && isset($default_page_no[0])) {
|
||||
return intval($default_page_no[0]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the page to load. If a default page exists it will be returned.
|
||||
* If no such exists, returns the id of the first page of the database.
|
||||
*
|
||||
* @param string $db database
|
||||
*
|
||||
* @return int id of the page to load
|
||||
*/
|
||||
public function getLoadingPage($db)
|
||||
{
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
if (! $cfgRelation['pdfwork']) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
$page_no = -1;
|
||||
|
||||
$default_page_no = $this->getDefaultPage($db);
|
||||
if ($default_page_no != -1) {
|
||||
$page_no = $default_page_no;
|
||||
} else {
|
||||
$query = "SELECT MIN(`page_nr`)"
|
||||
. " FROM " . Util::backquote($cfgRelation['db'])
|
||||
. "." . Util::backquote($cfgRelation['pdf_pages'])
|
||||
. " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($db) . "'";
|
||||
|
||||
$min_page_no = $GLOBALS['dbi']->fetchResult(
|
||||
$query,
|
||||
null,
|
||||
null,
|
||||
DatabaseInterface::CONNECT_CONTROL,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
if (is_array($min_page_no) && isset($min_page_no[0])) {
|
||||
$page_no = $min_page_no[0];
|
||||
}
|
||||
}
|
||||
return intval($page_no);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new page and returns its auto-incrementing id
|
||||
*
|
||||
* @param string $pageName name of the page
|
||||
* @param string $db name of the database
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function createNewPage($pageName, $db)
|
||||
{
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
if ($cfgRelation['pdfwork']) {
|
||||
$pageNumber = $this->relation->createPage(
|
||||
$pageName,
|
||||
$cfgRelation,
|
||||
$db
|
||||
);
|
||||
return $pageNumber;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves positions of table(s) of a given pdf page
|
||||
*
|
||||
* @param int $pg pdf page id
|
||||
*
|
||||
* @return boolean success/failure
|
||||
*/
|
||||
public function saveTablePositions($pg)
|
||||
{
|
||||
$pageId = $GLOBALS['dbi']->escapeString($pg);
|
||||
|
||||
$db = $GLOBALS['dbi']->escapeString($_POST['db']);
|
||||
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
if (! $cfgRelation['pdfwork']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = "DELETE FROM "
|
||||
. Util::backquote($cfgRelation['db'])
|
||||
. "." . Util::backquote(
|
||||
$cfgRelation['table_coords']
|
||||
)
|
||||
. " WHERE `pdf_page_number` = '" . $pageId . "'";
|
||||
|
||||
$res = $this->relation->queryAsControlUser(
|
||||
$query,
|
||||
true,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
|
||||
if (!$res) {
|
||||
return (boolean)$res;
|
||||
}
|
||||
|
||||
foreach ($_POST['t_h'] as $key => $value) {
|
||||
$DB = $_POST['t_db'][$key];
|
||||
$TAB = $_POST['t_tbl'][$key];
|
||||
if (!$value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$query = "INSERT INTO "
|
||||
. Util::backquote($cfgRelation['db']) . "."
|
||||
. Util::backquote($cfgRelation['table_coords'])
|
||||
. " (`db_name`, `table_name`, `pdf_page_number`, `x`, `y`)"
|
||||
. " VALUES ("
|
||||
. "'" . $GLOBALS['dbi']->escapeString($DB) . "', "
|
||||
. "'" . $GLOBALS['dbi']->escapeString($TAB) . "', "
|
||||
. "'" . $pageId . "', "
|
||||
. "'" . $GLOBALS['dbi']->escapeString($_POST['t_x'][$key]) . "', "
|
||||
. "'" . $GLOBALS['dbi']->escapeString($_POST['t_y'][$key]) . "')";
|
||||
|
||||
$res = $this->relation->queryAsControlUser(
|
||||
$query, true, DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
}
|
||||
|
||||
return (boolean) $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the display field for a table.
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $field display field name
|
||||
*
|
||||
* @return array<bool,string>
|
||||
*/
|
||||
public function saveDisplayField($db, $table, $field)
|
||||
{
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
if (! $cfgRelation['displaywork']) {
|
||||
return [
|
||||
false,
|
||||
_pgettext(
|
||||
'phpMyAdmin configuration storage is not configured for "Display Features" on designer when user tries to set a display field.',
|
||||
'phpMyAdmin configuration storage is not configured for "Display Features".'
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
$upd_query = new Table($table, $db, $GLOBALS['dbi']);
|
||||
$upd_query->updateDisplayField($field, $cfgRelation);
|
||||
|
||||
return [
|
||||
true,
|
||||
null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new foreign relation
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $T1 foreign table
|
||||
* @param string $F1 foreign field
|
||||
* @param string $T2 master table
|
||||
* @param string $F2 master field
|
||||
* @param string $on_delete on delete action
|
||||
* @param string $on_update on update action
|
||||
* @param string $DB1 database
|
||||
* @param string $DB2 database
|
||||
*
|
||||
* @return array array of success/failure and message
|
||||
*/
|
||||
public function addNewRelation($db, $T1, $F1, $T2, $F2, $on_delete, $on_update, $DB1, $DB2)
|
||||
{
|
||||
$tables = $GLOBALS['dbi']->getTablesFull($DB1, $T1);
|
||||
$type_T1 = mb_strtoupper($tables[$T1]['ENGINE']);
|
||||
$tables = $GLOBALS['dbi']->getTablesFull($DB2, $T2);
|
||||
$type_T2 = mb_strtoupper($tables[$T2]['ENGINE']);
|
||||
|
||||
// native foreign key
|
||||
if (Util::isForeignKeySupported($type_T1)
|
||||
&& Util::isForeignKeySupported($type_T2)
|
||||
&& $type_T1 == $type_T2
|
||||
) {
|
||||
// relation exists?
|
||||
$existrel_foreign = $this->relation->getForeigners($DB2, $T2, '', 'foreign');
|
||||
$foreigner = $this->relation->searchColumnInForeigners($existrel_foreign, $F2);
|
||||
if ($foreigner
|
||||
&& isset($foreigner['constraint'])
|
||||
) {
|
||||
return array(false, __('Error: relationship already exists.'));
|
||||
}
|
||||
// note: in InnoDB, the index does not requires to be on a PRIMARY
|
||||
// or UNIQUE key
|
||||
// improve: check all other requirements for InnoDB relations
|
||||
$result = $GLOBALS['dbi']->query(
|
||||
'SHOW INDEX FROM ' . Util::backquote($DB1)
|
||||
. '.' . Util::backquote($T1) . ';'
|
||||
);
|
||||
|
||||
// will be use to emphasis prim. keys in the table view
|
||||
$index_array1 = array();
|
||||
while ($row = $GLOBALS['dbi']->fetchAssoc($result)) {
|
||||
$index_array1[$row['Column_name']] = 1;
|
||||
}
|
||||
$GLOBALS['dbi']->freeResult($result);
|
||||
|
||||
$result = $GLOBALS['dbi']->query(
|
||||
'SHOW INDEX FROM ' . Util::backquote($DB2)
|
||||
. '.' . Util::backquote($T2) . ';'
|
||||
);
|
||||
// will be used to emphasis prim. keys in the table view
|
||||
$index_array2 = array();
|
||||
while ($row = $GLOBALS['dbi']->fetchAssoc($result)) {
|
||||
$index_array2[$row['Column_name']] = 1;
|
||||
}
|
||||
$GLOBALS['dbi']->freeResult($result);
|
||||
|
||||
if (! empty($index_array1[$F1]) && ! empty($index_array2[$F2])) {
|
||||
$upd_query = 'ALTER TABLE ' . Util::backquote($DB2)
|
||||
. '.' . Util::backquote($T2)
|
||||
. ' ADD FOREIGN KEY ('
|
||||
. Util::backquote($F2) . ')'
|
||||
. ' REFERENCES '
|
||||
. Util::backquote($DB1) . '.'
|
||||
. Util::backquote($T1) . '('
|
||||
. Util::backquote($F1) . ')';
|
||||
|
||||
if ($on_delete != 'nix') {
|
||||
$upd_query .= ' ON DELETE ' . $on_delete;
|
||||
}
|
||||
if ($on_update != 'nix') {
|
||||
$upd_query .= ' ON UPDATE ' . $on_update;
|
||||
}
|
||||
$upd_query .= ';';
|
||||
if ($GLOBALS['dbi']->tryQuery($upd_query)) {
|
||||
return array(true, __('FOREIGN KEY relationship has been added.'));
|
||||
}
|
||||
|
||||
$error = $GLOBALS['dbi']->getError();
|
||||
return array(
|
||||
false,
|
||||
__('Error: FOREIGN KEY relationship could not be added!')
|
||||
. "<br/>" . $error
|
||||
);
|
||||
}
|
||||
|
||||
return array(false, __('Error: Missing index on column(s).'));
|
||||
}
|
||||
|
||||
// internal (pmadb) relation
|
||||
if ($GLOBALS['cfgRelation']['relwork'] == false) {
|
||||
return array(false, __('Error: Relational features are disabled!'));
|
||||
}
|
||||
|
||||
// no need to recheck if the keys are primary or unique at this point,
|
||||
// this was checked on the interface part
|
||||
|
||||
$q = "INSERT INTO "
|
||||
. Util::backquote($GLOBALS['cfgRelation']['db'])
|
||||
. "."
|
||||
. Util::backquote($GLOBALS['cfgRelation']['relation'])
|
||||
. "(master_db, master_table, master_field, "
|
||||
. "foreign_db, foreign_table, foreign_field)"
|
||||
. " values("
|
||||
. "'" . $GLOBALS['dbi']->escapeString($DB2) . "', "
|
||||
. "'" . $GLOBALS['dbi']->escapeString($T2) . "', "
|
||||
. "'" . $GLOBALS['dbi']->escapeString($F2) . "', "
|
||||
. "'" . $GLOBALS['dbi']->escapeString($DB1) . "', "
|
||||
. "'" . $GLOBALS['dbi']->escapeString($T1) . "', "
|
||||
. "'" . $GLOBALS['dbi']->escapeString($F1) . "')";
|
||||
|
||||
if ($this->relation->queryAsControlUser($q, false, DatabaseInterface::QUERY_STORE)
|
||||
) {
|
||||
return array(true, __('Internal relationship has been added.'));
|
||||
}
|
||||
|
||||
$error = $GLOBALS['dbi']->getError(DatabaseInterface::CONNECT_CONTROL);
|
||||
return array(
|
||||
false,
|
||||
__('Error: Internal relationship could not be added!')
|
||||
. "<br/>" . $error
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a foreign relation
|
||||
*
|
||||
* @param string $T1 foreign db.table
|
||||
* @param string $F1 foreign field
|
||||
* @param string $T2 master db.table
|
||||
* @param string $F2 master field
|
||||
*
|
||||
* @return array array of success/failure and message
|
||||
*/
|
||||
public function removeRelation($T1, $F1, $T2, $F2)
|
||||
{
|
||||
list($DB1, $T1) = explode(".", $T1);
|
||||
list($DB2, $T2) = explode(".", $T2);
|
||||
|
||||
$tables = $GLOBALS['dbi']->getTablesFull($DB1, $T1);
|
||||
$type_T1 = mb_strtoupper($tables[$T1]['ENGINE']);
|
||||
$tables = $GLOBALS['dbi']->getTablesFull($DB2, $T2);
|
||||
$type_T2 = mb_strtoupper($tables[$T2]['ENGINE']);
|
||||
|
||||
if (Util::isForeignKeySupported($type_T1)
|
||||
&& Util::isForeignKeySupported($type_T2)
|
||||
&& $type_T1 == $type_T2
|
||||
) {
|
||||
// InnoDB
|
||||
$existrel_foreign = $this->relation->getForeigners($DB2, $T2, '', 'foreign');
|
||||
$foreigner = $this->relation->searchColumnInForeigners($existrel_foreign, $F2);
|
||||
|
||||
if (isset($foreigner['constraint'])) {
|
||||
$upd_query = 'ALTER TABLE ' . Util::backquote($DB2)
|
||||
. '.' . Util::backquote($T2) . ' DROP FOREIGN KEY '
|
||||
. Util::backquote($foreigner['constraint']) . ';';
|
||||
if ($GLOBALS['dbi']->query($upd_query)) {
|
||||
return array(true, __('FOREIGN KEY relationship has been removed.'));
|
||||
}
|
||||
|
||||
$error = $GLOBALS['dbi']->getError();
|
||||
return array(
|
||||
false,
|
||||
__('Error: FOREIGN KEY relationship could not be removed!')
|
||||
. "<br/>" . $error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// internal relations
|
||||
$delete_query = "DELETE FROM "
|
||||
. Util::backquote($GLOBALS['cfgRelation']['db']) . "."
|
||||
. $GLOBALS['cfgRelation']['relation'] . " WHERE "
|
||||
. "master_db = '" . $GLOBALS['dbi']->escapeString($DB2) . "'"
|
||||
. " AND master_table = '" . $GLOBALS['dbi']->escapeString($T2) . "'"
|
||||
. " AND master_field = '" . $GLOBALS['dbi']->escapeString($F2) . "'"
|
||||
. " AND foreign_db = '" . $GLOBALS['dbi']->escapeString($DB1) . "'"
|
||||
. " AND foreign_table = '" . $GLOBALS['dbi']->escapeString($T1) . "'"
|
||||
. " AND foreign_field = '" . $GLOBALS['dbi']->escapeString($F1) . "'";
|
||||
|
||||
$result = $this->relation->queryAsControlUser(
|
||||
$delete_query,
|
||||
false,
|
||||
DatabaseInterface::QUERY_STORE
|
||||
);
|
||||
|
||||
if (!$result) {
|
||||
$error = $GLOBALS['dbi']->getError(DatabaseInterface::CONNECT_CONTROL);
|
||||
return array(
|
||||
false,
|
||||
__('Error: Internal relationship could not be removed!') . "<br/>" . $error
|
||||
);
|
||||
}
|
||||
|
||||
return array(true, __('Internal relationship has been removed.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save value for a designer setting
|
||||
*
|
||||
* @param string $index setting
|
||||
* @param string $value value
|
||||
*
|
||||
* @return bool whether the operation succeeded
|
||||
*/
|
||||
public function saveSetting($index, $value)
|
||||
{
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
$success = true;
|
||||
if ($cfgRelation['designersettingswork']) {
|
||||
|
||||
$cfgDesigner = array(
|
||||
'user' => $GLOBALS['cfg']['Server']['user'],
|
||||
'db' => $cfgRelation['db'],
|
||||
'table' => $cfgRelation['designer_settings']
|
||||
);
|
||||
|
||||
$orig_data_query = "SELECT settings_data"
|
||||
. " FROM " . Util::backquote($cfgDesigner['db'])
|
||||
. "." . Util::backquote($cfgDesigner['table'])
|
||||
. " WHERE username = '"
|
||||
. $GLOBALS['dbi']->escapeString($cfgDesigner['user']) . "';";
|
||||
|
||||
$orig_data = $GLOBALS['dbi']->fetchSingleRow(
|
||||
$orig_data_query, 'ASSOC', DatabaseInterface::CONNECT_CONTROL
|
||||
);
|
||||
|
||||
if (! empty($orig_data)) {
|
||||
$orig_data = json_decode($orig_data['settings_data'], true);
|
||||
$orig_data[$index] = $value;
|
||||
$orig_data = json_encode($orig_data);
|
||||
|
||||
$save_query = "UPDATE "
|
||||
. Util::backquote($cfgDesigner['db'])
|
||||
. "." . Util::backquote($cfgDesigner['table'])
|
||||
. " SET settings_data = '" . $orig_data . "'"
|
||||
. " WHERE username = '"
|
||||
. $GLOBALS['dbi']->escapeString($cfgDesigner['user']) . "';";
|
||||
|
||||
$success = $this->relation->queryAsControlUser($save_query);
|
||||
} else {
|
||||
$save_data = array($index => $value);
|
||||
|
||||
$query = "INSERT INTO "
|
||||
. Util::backquote($cfgDesigner['db'])
|
||||
. "." . Util::backquote($cfgDesigner['table'])
|
||||
. " (username, settings_data)"
|
||||
. " VALUES('" . $GLOBALS['dbi']->escapeString($cfgDesigner['user'])
|
||||
. "', '" . json_encode($save_data) . "');";
|
||||
|
||||
$success = $this->relation->queryAsControlUser($query);
|
||||
}
|
||||
}
|
||||
|
||||
return (bool) $success;
|
||||
}
|
||||
}
|
||||
98
phpMyAdmin/libraries/classes/Database/Designer/DesignerTable.php
Executable file
98
phpMyAdmin/libraries/classes/Database/Designer/DesignerTable.php
Executable file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Database\Designer\DesignerTable class
|
||||
*
|
||||
* @package PhpMyAdmin-Designer
|
||||
*/
|
||||
namespace PhpMyAdmin\Database\Designer;
|
||||
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Common functions for Designer
|
||||
*
|
||||
* @package PhpMyAdmin-Designer
|
||||
*/
|
||||
class DesignerTable
|
||||
{
|
||||
private $tableName;
|
||||
private $databaseName;
|
||||
private $tableEngine;
|
||||
private $displayField;
|
||||
|
||||
/**
|
||||
* Create a new DesignerTable
|
||||
*
|
||||
* @param string $databaseName The database name
|
||||
* @param string $tableName The table name
|
||||
* @param string $tableEngine The table engine
|
||||
* @param string|null $displayField The display field if available
|
||||
*/
|
||||
public function __construct(
|
||||
$databaseName,
|
||||
$tableName,
|
||||
$tableEngine,
|
||||
$displayField
|
||||
) {
|
||||
$this->databaseName = $databaseName;
|
||||
$this->tableName = $tableName;
|
||||
$this->tableEngine = $tableEngine;
|
||||
$this->displayField = $displayField;
|
||||
}
|
||||
|
||||
/**
|
||||
* The table engine supports or not foreign keys
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function supportsForeignkeys() {
|
||||
return Util::isForeignKeySupported($this->tableEngine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the database name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDatabaseName() {
|
||||
return $this->databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTableName() {
|
||||
return $this->tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table engine
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTableEngine() {
|
||||
return $this->tableEngine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayed field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDisplayField()
|
||||
{
|
||||
return $this->displayField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the db and table separated with a dot
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDbTableString() {
|
||||
return $this->databaseName . '.' . $this->tableName;
|
||||
}
|
||||
}
|
||||
135
phpMyAdmin/libraries/classes/Database/MultiTableQuery.php
Executable file
135
phpMyAdmin/libraries/classes/Database/MultiTableQuery.php
Executable file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Handles DB Multi-table query
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Database;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ParseAnalyze;
|
||||
use PhpMyAdmin\Sql;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
/**
|
||||
* Class to handle database Multi-table querying
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class MultiTableQuery
|
||||
{
|
||||
/**
|
||||
* DatabaseInterface instance
|
||||
*
|
||||
* @access private
|
||||
* @var DatabaseInterface
|
||||
*/
|
||||
private $dbi;
|
||||
|
||||
/**
|
||||
* Database name
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* Default number of columns
|
||||
*
|
||||
* @access private
|
||||
* @var integer
|
||||
*/
|
||||
private $defaultNoOfColumns;
|
||||
|
||||
/**
|
||||
* Table names
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $tables;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param string $dbName Database name
|
||||
* @param integer $defaultNoOfColumns Default number of columns
|
||||
*/
|
||||
public function __construct(
|
||||
DatabaseInterface $dbi,
|
||||
$dbName,
|
||||
$defaultNoOfColumns = 3
|
||||
) {
|
||||
$this->dbi = $dbi;
|
||||
$this->db = $dbName;
|
||||
$this->defaultNoOfColumns = $defaultNoOfColumns;
|
||||
|
||||
$this->tables = $this->dbi->getTables($this->db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Multi-Table query page HTML
|
||||
*
|
||||
* @return string Multi-Table query page HTML
|
||||
*/
|
||||
public function getFormHtml()
|
||||
{
|
||||
$tables = [];
|
||||
foreach($this->tables as $table) {
|
||||
$tables[$table]['hash'] = md5($table);
|
||||
$tables[$table]['columns'] = array_keys(
|
||||
$this->dbi->getColumns($this->db, $table)
|
||||
);
|
||||
}
|
||||
return Template::get('database/multi_table_query/form')->render([
|
||||
'db' => $this->db,
|
||||
'tables' => $tables,
|
||||
'default_no_of_columns' => $this->defaultNoOfColumns,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays multi-table query results
|
||||
*
|
||||
* @param string $sqlQuery The query to parse
|
||||
* @param string $db The current database
|
||||
* @param string $pmaThemeImage Uri of the PMA theme image
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function displayResults($sqlQuery, $db, $pmaThemeImage)
|
||||
{
|
||||
list(
|
||||
$analyzedSqlResults,
|
||||
$db,
|
||||
$tableFromSql
|
||||
) = ParseAnalyze::sqlQuery($sqlQuery, $db);
|
||||
|
||||
extract($analyzedSqlResults);
|
||||
$goto = 'db_multi_table_query.php';
|
||||
$sql = new Sql();
|
||||
$sql->executeQueryAndSendQueryResponse(
|
||||
null, // analyzed_sql_results
|
||||
false, // is_gotofile
|
||||
$db, // db
|
||||
null, // table
|
||||
null, // find_real_end
|
||||
null, // sql_query_for_bookmark - see below
|
||||
null, // extra_data
|
||||
null, // message_to_show
|
||||
null, // message
|
||||
null, // sql_data
|
||||
$goto, // goto
|
||||
$pmaThemeImage, // pmaThemeImage
|
||||
null, // disp_query
|
||||
null, // disp_message
|
||||
null, // query_type
|
||||
$sqlQuery, // sql_query
|
||||
null, // selectedTables
|
||||
null // complete_query
|
||||
);
|
||||
}
|
||||
}
|
||||
1961
phpMyAdmin/libraries/classes/Database/Qbe.php
Executable file
1961
phpMyAdmin/libraries/classes/Database/Qbe.php
Executable file
File diff suppressed because it is too large
Load Diff
339
phpMyAdmin/libraries/classes/Database/Search.php
Executable file
339
phpMyAdmin/libraries/classes/Database/Search.php
Executable file
@@ -0,0 +1,339 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Handles Database Search
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Database;
|
||||
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Class to handle database search
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class Search
|
||||
{
|
||||
/**
|
||||
* Database name
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* Table Names
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $tablesNamesOnly;
|
||||
|
||||
/**
|
||||
* Type of search
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $searchTypes;
|
||||
|
||||
/**
|
||||
* Already set search type
|
||||
*
|
||||
* @access private
|
||||
* @var integer
|
||||
*/
|
||||
private $criteriaSearchType;
|
||||
|
||||
/**
|
||||
* Already set search type's description
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $searchTypeDescription;
|
||||
|
||||
/**
|
||||
* Search string/regexp
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $criteriaSearchString;
|
||||
|
||||
/**
|
||||
* Criteria Tables to search in
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $criteriaTables;
|
||||
|
||||
/**
|
||||
* Restrict the search to this column
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $criteriaColumnName;
|
||||
|
||||
/**
|
||||
* Public Constructor
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function __construct($db)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->searchTypes = array(
|
||||
'1' => __('at least one of the words'),
|
||||
'2' => __('all of the words'),
|
||||
'3' => __('the exact phrase as substring'),
|
||||
'4' => __('the exact phrase as whole field'),
|
||||
'5' => __('as regular expression'),
|
||||
);
|
||||
// Sets criteria parameters
|
||||
$this->setSearchParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets search parameters
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function setSearchParams()
|
||||
{
|
||||
$this->tablesNamesOnly = $GLOBALS['dbi']->getTables($this->db);
|
||||
|
||||
if (empty($_POST['criteriaSearchType'])
|
||||
|| ! is_string($_POST['criteriaSearchType'])
|
||||
|| ! array_key_exists(
|
||||
$_POST['criteriaSearchType'],
|
||||
$this->searchTypes
|
||||
)
|
||||
) {
|
||||
$this->criteriaSearchType = 1;
|
||||
unset($_POST['submit_search']);
|
||||
} else {
|
||||
$this->criteriaSearchType = (int) $_POST['criteriaSearchType'];
|
||||
$this->searchTypeDescription
|
||||
= $this->searchTypes[$_POST['criteriaSearchType']];
|
||||
}
|
||||
|
||||
if (empty($_POST['criteriaSearchString'])
|
||||
|| ! is_string($_POST['criteriaSearchString'])
|
||||
) {
|
||||
$this->criteriaSearchString = '';
|
||||
unset($_POST['submit_search']);
|
||||
} else {
|
||||
$this->criteriaSearchString = $_POST['criteriaSearchString'];
|
||||
}
|
||||
|
||||
$this->criteriaTables = array();
|
||||
if (empty($_POST['criteriaTables'])
|
||||
|| ! is_array($_POST['criteriaTables'])
|
||||
) {
|
||||
unset($_POST['submit_search']);
|
||||
} else {
|
||||
$this->criteriaTables = array_intersect(
|
||||
$_POST['criteriaTables'], $this->tablesNamesOnly
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($_POST['criteriaColumnName'])
|
||||
|| ! is_string($_POST['criteriaColumnName'])
|
||||
) {
|
||||
unset($this->criteriaColumnName);
|
||||
} else {
|
||||
$this->criteriaColumnName = $GLOBALS['dbi']->escapeString(
|
||||
$_POST['criteriaColumnName']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the SQL search query
|
||||
*
|
||||
* @param string $table The table name
|
||||
*
|
||||
* @return array 3 SQL queries (for count, display and delete results)
|
||||
*
|
||||
* @todo can we make use of fulltextsearch IN BOOLEAN MODE for this?
|
||||
* PMA_backquote
|
||||
* DatabaseInterface::freeResult
|
||||
* DatabaseInterface::fetchAssoc
|
||||
* $GLOBALS['db']
|
||||
* explode
|
||||
* count
|
||||
* strlen
|
||||
*/
|
||||
private function getSearchSqls($table)
|
||||
{
|
||||
// Statement types
|
||||
$sqlstr_select = 'SELECT';
|
||||
$sqlstr_delete = 'DELETE';
|
||||
// Table to use
|
||||
$sqlstr_from = ' FROM '
|
||||
. Util::backquote($GLOBALS['db']) . '.'
|
||||
. Util::backquote($table);
|
||||
// Gets where clause for the query
|
||||
$where_clause = $this->getWhereClause($table);
|
||||
// Builds complete queries
|
||||
$sql = array();
|
||||
$sql['select_columns'] = $sqlstr_select . ' * ' . $sqlstr_from
|
||||
. $where_clause;
|
||||
// here, I think we need to still use the COUNT clause, even for
|
||||
// VIEWs, anyway we have a WHERE clause that should limit results
|
||||
$sql['select_count'] = $sqlstr_select . ' COUNT(*) AS `count`'
|
||||
. $sqlstr_from . $where_clause;
|
||||
$sql['delete'] = $sqlstr_delete . $sqlstr_from . $where_clause;
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides where clause for building SQL query
|
||||
*
|
||||
* @param string $table The table name
|
||||
*
|
||||
* @return string The generated where clause
|
||||
*/
|
||||
private function getWhereClause($table)
|
||||
{
|
||||
// Columns to select
|
||||
$allColumns = $GLOBALS['dbi']->getColumns($GLOBALS['db'], $table);
|
||||
$likeClauses = array();
|
||||
// Based on search type, decide like/regex & '%'/''
|
||||
$like_or_regex = (($this->criteriaSearchType == 5) ? 'REGEXP' : 'LIKE');
|
||||
$automatic_wildcard = (($this->criteriaSearchType < 4) ? '%' : '');
|
||||
// For "as regular expression" (search option 5), LIKE won't be used
|
||||
// Usage example: If user is searching for a literal $ in a regexp search,
|
||||
// he should enter \$ as the value.
|
||||
$criteriaSearchStringEscaped = $GLOBALS['dbi']->escapeString(
|
||||
$this->criteriaSearchString
|
||||
);
|
||||
// Extract search words or pattern
|
||||
$search_words = (($this->criteriaSearchType > 2)
|
||||
? array($criteriaSearchStringEscaped)
|
||||
: explode(' ', $criteriaSearchStringEscaped));
|
||||
|
||||
foreach ($search_words as $search_word) {
|
||||
// Eliminates empty values
|
||||
if (strlen($search_word) === 0) {
|
||||
continue;
|
||||
}
|
||||
$likeClausesPerColumn = array();
|
||||
// for each column in the table
|
||||
foreach ($allColumns as $column) {
|
||||
if (! isset($this->criteriaColumnName)
|
||||
|| strlen($this->criteriaColumnName) === 0
|
||||
|| $column['Field'] == $this->criteriaColumnName
|
||||
) {
|
||||
$column = 'CONVERT(' . Util::backquote($column['Field'])
|
||||
. ' USING utf8)';
|
||||
$likeClausesPerColumn[] = $column . ' ' . $like_or_regex . ' '
|
||||
. "'"
|
||||
. $automatic_wildcard . $search_word . $automatic_wildcard
|
||||
. "'";
|
||||
}
|
||||
} // end for
|
||||
if (count($likeClausesPerColumn) > 0) {
|
||||
$likeClauses[] = implode(' OR ', $likeClausesPerColumn);
|
||||
}
|
||||
} // end for
|
||||
// Use 'OR' if 'at least one word' is to be searched, else use 'AND'
|
||||
$implode_str = ($this->criteriaSearchType == 1 ? ' OR ' : ' AND ');
|
||||
if (empty($likeClauses)) {
|
||||
// this could happen when the "inside column" does not exist
|
||||
// in any selected tables
|
||||
$where_clause = ' WHERE FALSE';
|
||||
} else {
|
||||
$where_clause = ' WHERE ('
|
||||
. implode(') ' . $implode_str . ' (', $likeClauses)
|
||||
. ')';
|
||||
}
|
||||
return $where_clause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays database search results
|
||||
*
|
||||
* @return string HTML for search results
|
||||
*/
|
||||
public function getSearchResults()
|
||||
{
|
||||
$resultTotal = 0;
|
||||
$rows = [];
|
||||
// For each table selected as search criteria
|
||||
foreach ($this->criteriaTables as $eachTable) {
|
||||
// Gets the SQL statements
|
||||
$newSearchSqls = $this->getSearchSqls($eachTable);
|
||||
// Executes the "COUNT" statement
|
||||
$resultCount = intval($GLOBALS['dbi']->fetchValue(
|
||||
$newSearchSqls['select_count']
|
||||
));
|
||||
$resultTotal += $resultCount;
|
||||
// Gets the result row's HTML for a table
|
||||
$rows[] = [
|
||||
'table' => htmlspecialchars($eachTable),
|
||||
'new_search_sqls' => $newSearchSqls,
|
||||
'result_count' => $resultCount,
|
||||
];
|
||||
}
|
||||
|
||||
return Template::get('database/search/results')->render([
|
||||
'db' => $this->db,
|
||||
'rows' => $rows,
|
||||
'result_total' => $resultTotal,
|
||||
'criteria_tables' => $this->criteriaTables,
|
||||
'criteria_search_string' => htmlspecialchars($this->criteriaSearchString),
|
||||
'search_type_description' => $this->searchTypeDescription,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the main search form's html
|
||||
*
|
||||
* @return string HTML for selection form
|
||||
*/
|
||||
public function getSelectionForm()
|
||||
{
|
||||
$choices = array(
|
||||
'1' => $this->searchTypes[1] . ' '
|
||||
. Util::showHint(
|
||||
__('Words are separated by a space character (" ").')
|
||||
),
|
||||
'2' => $this->searchTypes[2] . ' '
|
||||
. Util::showHint(
|
||||
__('Words are separated by a space character (" ").')
|
||||
),
|
||||
'3' => $this->searchTypes[3],
|
||||
'4' => $this->searchTypes[4],
|
||||
'5' => $this->searchTypes[5] . ' ' . Util::showMySQLDocu('Regexp')
|
||||
);
|
||||
return Template::get('database/search/selection_form')->render([
|
||||
'db' => $this->db,
|
||||
'choices' => $choices,
|
||||
'criteria_search_string' => $this->criteriaSearchString,
|
||||
'criteria_search_type' => $this->criteriaSearchType,
|
||||
'criteria_tables' => $this->criteriaTables,
|
||||
'tables_names_only' => $this->tablesNamesOnly,
|
||||
'criteria_column_name' => isset($this->criteriaColumnName)
|
||||
? $this->criteriaColumnName : null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides div tags for browsing search results and sql query form.
|
||||
*
|
||||
* @return string div tags
|
||||
*/
|
||||
public function getResultDivs()
|
||||
{
|
||||
return Template::get('database/search/result_divs')->render();
|
||||
}
|
||||
}
|
||||
3113
phpMyAdmin/libraries/classes/DatabaseInterface.php
Executable file
3113
phpMyAdmin/libraries/classes/DatabaseInterface.php
Executable file
File diff suppressed because it is too large
Load Diff
454
phpMyAdmin/libraries/classes/Dbi/DbiDummy.php
Executable file
454
phpMyAdmin/libraries/classes/Dbi/DbiDummy.php
Executable file
@@ -0,0 +1,454 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Fake database driver for testing purposes
|
||||
*
|
||||
* It has hardcoded results for given queries what makes easy to use it
|
||||
* in testsuite. Feel free to include other queries which your test will
|
||||
* need.
|
||||
*
|
||||
* @package PhpMyAdmin-DBI
|
||||
* @subpackage Dummy
|
||||
*/
|
||||
namespace PhpMyAdmin\Dbi;
|
||||
|
||||
require_once 'libraries/dbi/dbi_dummy.inc.php';
|
||||
|
||||
/**
|
||||
* Fake database driver for testing purposes
|
||||
*
|
||||
* It has hardcoded results for given queries what makes easy to use it
|
||||
* in testsuite. Feel free to include other queries which your test will
|
||||
* need.
|
||||
*
|
||||
* @package PhpMyAdmin-DBI
|
||||
* @subpackage Dummy
|
||||
*/
|
||||
class DbiDummy implements DbiExtension
|
||||
{
|
||||
private $_queries = array();
|
||||
const OFFSET_GLOBAL = 1000;
|
||||
|
||||
/**
|
||||
* connects to the database server
|
||||
*
|
||||
* @param string $user mysql user name
|
||||
* @param string $password mysql user password
|
||||
* @param array $server host/port/socket/persistent
|
||||
*
|
||||
* @return mixed false on error or a mysqli object on success
|
||||
*/
|
||||
public function connect(
|
||||
$user,
|
||||
$password,
|
||||
array $server = []
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* selects given database
|
||||
*
|
||||
* @param string $dbname name of db to select
|
||||
* @param resource $link mysql link resource
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function selectDb($dbname, $link)
|
||||
{
|
||||
$GLOBALS['dummy_db'] = $dbname;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* runs a query and returns the result
|
||||
*
|
||||
* @param string $query query to run
|
||||
* @param resource $link mysql link resource
|
||||
* @param int $options query options
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function realQuery($query, $link = null, $options = 0)
|
||||
{
|
||||
$query = trim(preg_replace('/ */', ' ', str_replace("\n", ' ', $query)));
|
||||
for ($i = 0, $nb = count($this->_queries); $i < $nb; $i++) {
|
||||
if ($this->_queries[$i]['query'] != $query) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->_queries[$i]['pos'] = 0;
|
||||
if (!is_array($this->_queries[$i]['result'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $i;
|
||||
}
|
||||
for ($i = 0, $nb = count($GLOBALS['dummy_queries']); $i < $nb; $i++) {
|
||||
if ($GLOBALS['dummy_queries'][$i]['query'] != $query) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$GLOBALS['dummy_queries'][$i]['pos'] = 0;
|
||||
if (!is_array($GLOBALS['dummy_queries'][$i]['result'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $i + self::OFFSET_GLOBAL;
|
||||
}
|
||||
echo "Not supported query: $query\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the multi query and output the results
|
||||
*
|
||||
* @param resource $link connection object
|
||||
* @param string $query multi query statement to execute
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function realMultiQuery($link, $query)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns result data from $result
|
||||
*
|
||||
* @param object $result MySQL result
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchAny($result)
|
||||
{
|
||||
$query_data = &$this->getQueryData($result);
|
||||
if ($query_data['pos'] >= count($query_data['result'])) {
|
||||
return false;
|
||||
}
|
||||
$ret = $query_data['result'][$query_data['pos']];
|
||||
$query_data['pos'] += 1;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns array of rows with associative and numeric keys from $result
|
||||
*
|
||||
* @param object $result result MySQL result
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchArray($result)
|
||||
{
|
||||
$query_data = &$this->getQueryData($result);
|
||||
$data = $this->fetchAny($result);
|
||||
if (!is_array($data)
|
||||
|| !isset($query_data['columns'])
|
||||
) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
$data[$query_data['columns'][$key]] = $val;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns array of rows with associative keys from $result
|
||||
*
|
||||
* @param object $result MySQL result
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchAssoc($result)
|
||||
{
|
||||
$data = $this->fetchAny($result);
|
||||
$query_data = &$this->getQueryData($result);
|
||||
if (!is_array($data) || !isset($query_data['columns'])) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$ret = array();
|
||||
foreach ($data as $key => $val) {
|
||||
$ret[$query_data['columns'][$key]] = $val;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns array of rows with numeric keys from $result
|
||||
*
|
||||
* @param object $result MySQL result
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchRow($result)
|
||||
{
|
||||
$data = $this->fetchAny($result);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the result pointer to an arbitrary row in the result
|
||||
*
|
||||
* @param object $result database result
|
||||
* @param integer $offset offset to seek
|
||||
*
|
||||
* @return bool true on success, false on failure
|
||||
*/
|
||||
public function dataSeek($result, $offset)
|
||||
{
|
||||
$query_data = &$this->getQueryData($result);
|
||||
if ($offset > count($query_data['result'])) {
|
||||
return false;
|
||||
}
|
||||
$query_data['pos'] = $offset;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees memory associated with the result
|
||||
*
|
||||
* @param object $result database result
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are any more query results from a multi query
|
||||
*
|
||||
* @param resource $link the connection object
|
||||
*
|
||||
* @return bool false
|
||||
*/
|
||||
public function moreResults($link)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare next result from multi_query
|
||||
*
|
||||
* @param resource $link the connection object
|
||||
*
|
||||
* @return boolean false
|
||||
*/
|
||||
public function nextResult($link)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the result returned from multi query
|
||||
*
|
||||
* @param resource $link the connection object
|
||||
*
|
||||
* @return mixed false when empty results / result set when not empty
|
||||
*/
|
||||
public function storeResult($link)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the type of connection used
|
||||
*
|
||||
* @param resource $link mysql link
|
||||
*
|
||||
* @return string type of connection used
|
||||
*/
|
||||
public function getHostInfo($link)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the MySQL protocol used
|
||||
*
|
||||
* @param resource $link mysql link
|
||||
*
|
||||
* @return integer version of the MySQL protocol used
|
||||
*/
|
||||
public function getProtoInfo($link)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a string that represents the client library version
|
||||
*
|
||||
* @return string MySQL client library version
|
||||
*/
|
||||
public function getClientInfo()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* returns last error message or false if no errors occurred
|
||||
*
|
||||
* @param resource $link connection link
|
||||
*
|
||||
* @return string|bool $error or false
|
||||
*/
|
||||
public function getError($link)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the number of rows returned by last query
|
||||
*
|
||||
* @param object $result MySQL result
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
if (is_bool($result)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$query_data = &$this->getQueryData($result);
|
||||
|
||||
return count($query_data['result']);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the number of rows affected by last query
|
||||
*
|
||||
* @param resource $link the mysql object
|
||||
* @param bool $get_from_cache whether to retrieve from cache
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function affectedRows($link = null, $get_from_cache = true)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns metainfo for fields in $result
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
*
|
||||
* @return array meta info for fields in $result
|
||||
*/
|
||||
public function getFieldsMeta($result)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* return number of fields in given $result
|
||||
*
|
||||
* @param object $result MySQL result
|
||||
*
|
||||
* @return int field count
|
||||
*/
|
||||
public function numFields($result)
|
||||
{
|
||||
$query_data = &$this->getQueryData($result);
|
||||
if (!isset($query_data['columns'])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return count($query_data['columns']);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the length of the given field $i in $result
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
* @param int $i field
|
||||
*
|
||||
* @return int length of field
|
||||
*/
|
||||
public function fieldLen($result, $i)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns name of $i. field in $result
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
* @param int $i field
|
||||
*
|
||||
* @return string name of $i. field in $result
|
||||
*/
|
||||
public function fieldName($result, $i)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* returns concatenated string of human readable field flags
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
* @param int $i field
|
||||
*
|
||||
* @return string field flags
|
||||
*/
|
||||
public function fieldFlags($result, $i)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* returns properly escaped string for use in MySQL queries
|
||||
*
|
||||
* @param mixed $link database link
|
||||
* @param string $str string to be escaped
|
||||
*
|
||||
* @return string a MySQL escaped string
|
||||
*/
|
||||
public function escapeString($link, $str)
|
||||
{
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds query result for testing
|
||||
*
|
||||
* @param string $query SQL
|
||||
* @param array $result Expected result
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setResult($query, $result)
|
||||
{
|
||||
$this->_queries[] = array(
|
||||
'query' => $query,
|
||||
'result' => $result,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return query data for ID
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function &getQueryData($result)
|
||||
{
|
||||
if ($result >= self::OFFSET_GLOBAL) {
|
||||
return $GLOBALS['dummy_queries'][$result - self::OFFSET_GLOBAL];
|
||||
} else {
|
||||
return $this->_queries[$result];
|
||||
}
|
||||
}
|
||||
}
|
||||
242
phpMyAdmin/libraries/classes/Dbi/DbiExtension.php
Executable file
242
phpMyAdmin/libraries/classes/Dbi/DbiExtension.php
Executable file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
/**
|
||||
* Contract for every database extension supported by phpMyAdmin
|
||||
*
|
||||
* @package PhpMyAdmin-DBI
|
||||
*/
|
||||
namespace PhpMyAdmin\Dbi;
|
||||
|
||||
/**
|
||||
* Contract for every database extension supported by phpMyAdmin
|
||||
*
|
||||
* @package PhpMyAdmin-DBI
|
||||
*/
|
||||
interface DbiExtension
|
||||
{
|
||||
/**
|
||||
* connects to the database server
|
||||
*
|
||||
* @param string $user user name
|
||||
* @param string $password user password
|
||||
* @param array $server host/port/socket/persistent
|
||||
*
|
||||
* @return mixed false on error or a connection object on success
|
||||
*/
|
||||
public function connect(
|
||||
$user, $password, array $server
|
||||
);
|
||||
|
||||
/**
|
||||
* selects given database
|
||||
*
|
||||
* @param string $dbname database name to select
|
||||
* @param resource $link connection object
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function selectDb($dbname, $link);
|
||||
|
||||
/**
|
||||
* runs a query and returns the result
|
||||
*
|
||||
* @param string $query query to execute
|
||||
* @param resource $link connection object
|
||||
* @param int $options query options
|
||||
*
|
||||
* @return mixed result
|
||||
*/
|
||||
public function realQuery($query, $link, $options);
|
||||
|
||||
/**
|
||||
* Run the multi query and output the results
|
||||
*
|
||||
* @param resource $link connection object
|
||||
* @param string $query multi query statement to execute
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function realMultiQuery($link, $query);
|
||||
|
||||
/**
|
||||
* returns array of rows with associative and numeric keys from $result
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchArray($result);
|
||||
|
||||
/**
|
||||
* returns array of rows with associative keys from $result
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchAssoc($result);
|
||||
|
||||
/**
|
||||
* returns array of rows with numeric keys from $result
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchRow($result);
|
||||
|
||||
/**
|
||||
* Adjusts the result pointer to an arbitrary row in the result
|
||||
*
|
||||
* @param object $result database result
|
||||
* @param integer $offset offset to seek
|
||||
*
|
||||
* @return bool true on success, false on failure
|
||||
*/
|
||||
public function dataSeek($result, $offset);
|
||||
|
||||
/**
|
||||
* Frees memory associated with the result
|
||||
*
|
||||
* @param object $result database result
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function freeResult($result);
|
||||
|
||||
/**
|
||||
* Check if there are any more query results from a multi query
|
||||
*
|
||||
* @param resource $link the connection object
|
||||
*
|
||||
* @return bool true or false
|
||||
*/
|
||||
public function moreResults($link);
|
||||
|
||||
/**
|
||||
* Prepare next result from multi_query
|
||||
*
|
||||
* @param resource $link the connection object
|
||||
*
|
||||
* @return bool true or false
|
||||
*/
|
||||
public function nextResult($link);
|
||||
|
||||
/**
|
||||
* Store the result returned from multi query
|
||||
*
|
||||
* @param resource $link mysql link
|
||||
*
|
||||
* @return mixed false when empty results / result set when not empty
|
||||
*/
|
||||
public function storeResult($link);
|
||||
|
||||
/**
|
||||
* Returns a string representing the type of connection used
|
||||
*
|
||||
* @param resource $link mysql link
|
||||
*
|
||||
* @return string type of connection used
|
||||
*/
|
||||
public function getHostInfo($link);
|
||||
|
||||
/**
|
||||
* Returns the version of the MySQL protocol used
|
||||
*
|
||||
* @param resource $link mysql link
|
||||
*
|
||||
* @return integer version of the MySQL protocol used
|
||||
*/
|
||||
public function getProtoInfo($link);
|
||||
|
||||
/**
|
||||
* returns a string that represents the client library version
|
||||
*
|
||||
* @return string MySQL client library version
|
||||
*/
|
||||
public function getClientInfo();
|
||||
|
||||
/**
|
||||
* returns last error message or false if no errors occurred
|
||||
*
|
||||
* @param resource $link connection link
|
||||
*
|
||||
* @return string|bool $error or false
|
||||
*/
|
||||
public function getError($link);
|
||||
|
||||
/**
|
||||
* returns the number of rows returned by last query
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function numRows($result);
|
||||
|
||||
/**
|
||||
* returns the number of rows affected by last query
|
||||
*
|
||||
* @param resource $link the connection object
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function affectedRows($link);
|
||||
|
||||
/**
|
||||
* returns metainfo for fields in $result
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
*
|
||||
* @return array meta info for fields in $result
|
||||
*/
|
||||
public function getFieldsMeta($result);
|
||||
|
||||
/**
|
||||
* return number of fields in given $result
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
*
|
||||
* @return int field count
|
||||
*/
|
||||
public function numFields($result);
|
||||
|
||||
/**
|
||||
* returns the length of the given field $i in $result
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
* @param int $i field
|
||||
*
|
||||
* @return int length of field
|
||||
*/
|
||||
public function fieldLen($result, $i);
|
||||
|
||||
/**
|
||||
* returns name of $i. field in $result
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
* @param int $i field
|
||||
*
|
||||
* @return string name of $i. field in $result
|
||||
*/
|
||||
public function fieldName($result, $i);
|
||||
|
||||
/**
|
||||
* returns concatenated string of human readable field flags
|
||||
*
|
||||
* @param object $result result set identifier
|
||||
* @param int $i field
|
||||
*
|
||||
* @return string field flags
|
||||
*/
|
||||
public function fieldFlags($result, $i);
|
||||
|
||||
/**
|
||||
* returns properly escaped string for use in MySQL queries
|
||||
*
|
||||
* @param mixed $link database link
|
||||
* @param string $str string to be escaped
|
||||
*
|
||||
* @return string a MySQL escaped string
|
||||
*/
|
||||
public function escapeString($link, $str);
|
||||
}
|
||||
461
phpMyAdmin/libraries/classes/Dbi/DbiMysql.php
Executable file
461
phpMyAdmin/libraries/classes/Dbi/DbiMysql.php
Executable file
@@ -0,0 +1,461 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Interface to the classic MySQL extension
|
||||
*
|
||||
* @package PhpMyAdmin-DBI
|
||||
* @subpackage MySQL
|
||||
*/
|
||||
namespace PhpMyAdmin\Dbi;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
|
||||
if (! defined('PHPMYADMIN')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if (! extension_loaded('mysql')) {
|
||||
// The old MySQL extension is deprecated as of PHP 5.5.0, and will be
|
||||
// removed in the future. Instead, the `MySQLi` or `PDO_MySQL` extension
|
||||
// should be used.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to the classic MySQL extension
|
||||
*
|
||||
* @package PhpMyAdmin-DBI
|
||||
* @subpackage MySQL
|
||||
*/
|
||||
class DbiMysql implements DbiExtension
|
||||
{
|
||||
/**
|
||||
* Helper function for connecting to the database server
|
||||
*
|
||||
* @param string $server host/port/socket
|
||||
* @param string $user mysql user name
|
||||
* @param string $password mysql user password
|
||||
* @param int $client_flags client flags of connection
|
||||
* @param bool $persistent whether to use persistent connection
|
||||
*
|
||||
* @return mixed false on error or a mysql connection resource on success
|
||||
*/
|
||||
private function _realConnect($server, $user, $password, $client_flags,
|
||||
$persistent = false
|
||||
) {
|
||||
global $cfg;
|
||||
|
||||
if (ini_get('mysql.allow_local_infile')) {
|
||||
Core::fatalError(__('Please disable mysql.allow_local_infile in your PHP configuration or install the mysqli extension.'));
|
||||
}
|
||||
|
||||
if (empty($client_flags)) {
|
||||
if ($cfg['PersistentConnections'] || $persistent) {
|
||||
$link = @mysql_pconnect($server, $user, $password);
|
||||
} else {
|
||||
$link = @mysql_connect($server, $user, $password);
|
||||
}
|
||||
} else {
|
||||
if ($cfg['PersistentConnections'] || $persistent) {
|
||||
$link = @mysql_pconnect($server, $user, $password, $client_flags);
|
||||
} else {
|
||||
$link = @mysql_connect(
|
||||
$server, $user, $password, false, $client_flags
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the multi query and output the results
|
||||
*
|
||||
* @param mysqli $link mysqli object
|
||||
* @param string $query multi query statement to execute
|
||||
*
|
||||
* @return boolean false always false since mysql extension not support
|
||||
* for multi query executions
|
||||
*/
|
||||
public function realMultiQuery($link, $query)
|
||||
{
|
||||
// N.B.: PHP's 'mysql' extension does not support
|
||||
// multi_queries so this function will always
|
||||
// return false. Use the 'mysqli' extension, if
|
||||
// you need support for multi_queries.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* connects to the database server
|
||||
*
|
||||
* @param string $user mysql user name
|
||||
* @param string $password mysql user password
|
||||
* @param array $server host/port/socket/persistent
|
||||
*
|
||||
* @return mixed false on error or a mysqli object on success
|
||||
*/
|
||||
public function connect(
|
||||
$user, $password, array $server
|
||||
) {
|
||||
if ($server['port'] === 0) {
|
||||
$server_port = '';
|
||||
} else {
|
||||
$server_port = ':' . $server['port'];
|
||||
}
|
||||
|
||||
if (is_null($server['socket'])) {
|
||||
$server_socket = '';
|
||||
} else {
|
||||
$server_socket = ':' . $server['socket'];
|
||||
}
|
||||
|
||||
$client_flags = 0;
|
||||
|
||||
if (defined('PMA_ENABLE_LDI')) {
|
||||
// use CLIENT_LOCAL_FILES as defined in mysql_com.h
|
||||
// for the case where the client library was not compiled
|
||||
// with --enable-local-infile
|
||||
$client_flags |= 128;
|
||||
}
|
||||
|
||||
/* Optionally compress connection */
|
||||
if (defined('MYSQL_CLIENT_COMPRESS') && $server['compress']) {
|
||||
$client_flags |= MYSQL_CLIENT_COMPRESS;
|
||||
}
|
||||
|
||||
/* Optionally enable SSL */
|
||||
if (defined('MYSQL_CLIENT_SSL') && $server['ssl']) {
|
||||
$client_flags |= MYSQL_CLIENT_SSL;
|
||||
}
|
||||
|
||||
if (!isset($server['host'])) {
|
||||
$link = $this->_realConnect($server_socket, $user, $password, null);
|
||||
} else {
|
||||
$link = $this->_realConnect(
|
||||
$server['host'] . $server_port . $server_socket,
|
||||
$user, $password, null
|
||||
);
|
||||
}
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* selects given database
|
||||
*
|
||||
* @param string $dbname name of db to select
|
||||
* @param resource|null $link mysql link resource
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function selectDb($dbname, $link)
|
||||
{
|
||||
return mysql_select_db($dbname, $link);
|
||||
}
|
||||
|
||||
/**
|
||||
* runs a query and returns the result
|
||||
*
|
||||
* @param string $query query to run
|
||||
* @param resource|null $link mysql link resource
|
||||
* @param int $options query options
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function realQuery($query, $link, $options)
|
||||
{
|
||||
if ($options == ($options | DatabaseInterface::QUERY_STORE)) {
|
||||
return mysql_query($query, $link);
|
||||
} elseif ($options == ($options | DatabaseInterface::QUERY_UNBUFFERED)) {
|
||||
return mysql_unbuffered_query($query, $link);
|
||||
}
|
||||
|
||||
return mysql_query($query, $link);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns array of rows with associative and numeric keys from $result
|
||||
*
|
||||
* @param resource $result result MySQL result
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchArray($result)
|
||||
{
|
||||
return mysql_fetch_array($result, MYSQL_BOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns array of rows with associative keys from $result
|
||||
*
|
||||
* @param resource $result MySQL result
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchAssoc($result)
|
||||
{
|
||||
return mysql_fetch_array($result, MYSQL_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns array of rows with numeric keys from $result
|
||||
*
|
||||
* @param resource $result MySQL result
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchRow($result)
|
||||
{
|
||||
return mysql_fetch_array($result, MYSQL_NUM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the result pointer to an arbitrary row in the result
|
||||
*
|
||||
* @param resource $result database result
|
||||
* @param integer $offset offset to seek
|
||||
*
|
||||
* @return bool true on success, false on failure
|
||||
*/
|
||||
public function dataSeek($result, $offset)
|
||||
{
|
||||
return mysql_data_seek($result, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees memory associated with the result
|
||||
*
|
||||
* @param resource $result database result
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
if (is_resource($result) && get_resource_type($result) === 'mysql result') {
|
||||
mysql_free_result($result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are any more query results from a multi query
|
||||
*
|
||||
* @param resource $link the connection object
|
||||
*
|
||||
* @return bool false
|
||||
*/
|
||||
public function moreResults($link)
|
||||
{
|
||||
// N.B.: PHP's 'mysql' extension does not support
|
||||
// multi_queries so this function will always
|
||||
// return false. Use the 'mysqli' extension, if
|
||||
// you need support for multi_queries.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare next result from multi_query
|
||||
*
|
||||
* @param resource $link the connection object
|
||||
*
|
||||
* @return boolean false
|
||||
*/
|
||||
public function nextResult($link)
|
||||
{
|
||||
// N.B.: PHP's 'mysql' extension does not support
|
||||
// multi_queries so this function will always
|
||||
// return false. Use the 'mysqli' extension, if
|
||||
// you need support for multi_queries.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the type of connection used
|
||||
*
|
||||
* @param resource|null $link mysql link
|
||||
*
|
||||
* @return string type of connection used
|
||||
*/
|
||||
public function getHostInfo($link)
|
||||
{
|
||||
return mysql_get_host_info($link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the MySQL protocol used
|
||||
*
|
||||
* @param resource|null $link mysql link
|
||||
*
|
||||
* @return int version of the MySQL protocol used
|
||||
*/
|
||||
public function getProtoInfo($link)
|
||||
{
|
||||
return mysql_get_proto_info($link);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a string that represents the client library version
|
||||
*
|
||||
* @return string MySQL client library version
|
||||
*/
|
||||
public function getClientInfo()
|
||||
{
|
||||
return mysql_get_client_info();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns last error message or false if no errors occurred
|
||||
*
|
||||
* @param resource|null $link mysql link
|
||||
*
|
||||
* @return string|bool $error or false
|
||||
*/
|
||||
public function getError($link)
|
||||
{
|
||||
$GLOBALS['errno'] = 0;
|
||||
|
||||
if (null !== $link && false !== $link) {
|
||||
$error_number = mysql_errno($link);
|
||||
$error_message = mysql_error($link);
|
||||
} else {
|
||||
$error_number = mysql_errno();
|
||||
$error_message = mysql_error();
|
||||
}
|
||||
if (0 == $error_number) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// keep the error number for further check after
|
||||
// the call to getError()
|
||||
$GLOBALS['errno'] = $error_number;
|
||||
|
||||
return $GLOBALS['dbi']->formatError($error_number, $error_message);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the number of rows returned by last query
|
||||
*
|
||||
* @param resource $result MySQL result
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
if (is_bool($result)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mysql_num_rows($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the number of rows affected by last query
|
||||
*
|
||||
* @param resource|null $link the mysql object
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function affectedRows($link)
|
||||
{
|
||||
return mysql_affected_rows($link);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns metainfo for fields in $result
|
||||
*
|
||||
* @param resource $result MySQL result
|
||||
*
|
||||
* @return array meta info for fields in $result
|
||||
*
|
||||
* @todo add missing keys like in mysqli_query (decimals)
|
||||
*/
|
||||
public function getFieldsMeta($result)
|
||||
{
|
||||
$fields = array();
|
||||
$num_fields = mysql_num_fields($result);
|
||||
for ($i = 0; $i < $num_fields; $i++) {
|
||||
$field = mysql_fetch_field($result, $i);
|
||||
$field->flags = mysql_field_flags($result, $i);
|
||||
$field->orgtable = mysql_field_table($result, $i);
|
||||
$field->orgname = mysql_field_name($result, $i);
|
||||
$fields[] = $field;
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* return number of fields in given $result
|
||||
*
|
||||
* @param resource $result MySQL result
|
||||
*
|
||||
* @return int field count
|
||||
*/
|
||||
public function numFields($result)
|
||||
{
|
||||
return mysql_num_fields($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the length of the given field $i in $result
|
||||
*
|
||||
* @param resource $result MySQL result
|
||||
* @param int $i field
|
||||
*
|
||||
* @return int length of field
|
||||
*/
|
||||
public function fieldLen($result, $i)
|
||||
{
|
||||
return mysql_field_len($result, $i);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns name of $i. field in $result
|
||||
*
|
||||
* @param resource $result MySQL result
|
||||
* @param int $i field
|
||||
*
|
||||
* @return string name of $i. field in $result
|
||||
*/
|
||||
public function fieldName($result, $i)
|
||||
{
|
||||
return mysql_field_name($result, $i);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns concatenated string of human readable field flags
|
||||
*
|
||||
* @param resource $result MySQL result
|
||||
* @param int $i field
|
||||
*
|
||||
* @return string field flags
|
||||
*/
|
||||
public function fieldFlags($result, $i)
|
||||
{
|
||||
return mysql_field_flags($result, $i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the result returned from multi query
|
||||
*
|
||||
* @param resource $result MySQL result
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
public function storeResult($result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns properly escaped string for use in MySQL queries
|
||||
*
|
||||
* @param mixed $link database link
|
||||
* @param string $str string to be escaped
|
||||
*
|
||||
* @return string a MySQL escaped string
|
||||
*/
|
||||
public function escapeString($link, $str)
|
||||
{
|
||||
return mysql_real_escape_string($str, $link);
|
||||
}
|
||||
}
|
||||
637
phpMyAdmin/libraries/classes/Dbi/DbiMysqli.php
Executable file
637
phpMyAdmin/libraries/classes/Dbi/DbiMysqli.php
Executable file
@@ -0,0 +1,637 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Interface to the improved MySQL extension (MySQLi)
|
||||
*
|
||||
* @package PhpMyAdmin-DBI
|
||||
* @subpackage MySQLi
|
||||
*/
|
||||
namespace PhpMyAdmin\Dbi;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
|
||||
if (! defined('PHPMYADMIN')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* some PHP versions are reporting extra messages like "No index used in query"
|
||||
*/
|
||||
|
||||
mysqli_report(MYSQLI_REPORT_OFF);
|
||||
|
||||
/**
|
||||
* some older mysql client libs are missing these constants ...
|
||||
*/
|
||||
if (! defined('MYSQLI_BINARY_FLAG')) {
|
||||
define('MYSQLI_BINARY_FLAG', 128);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://bugs.php.net/36007
|
||||
*/
|
||||
if (! defined('MYSQLI_TYPE_NEWDECIMAL')) {
|
||||
define('MYSQLI_TYPE_NEWDECIMAL', 246);
|
||||
}
|
||||
if (! defined('MYSQLI_TYPE_BIT')) {
|
||||
define('MYSQLI_TYPE_BIT', 16);
|
||||
}
|
||||
if (! defined('MYSQLI_TYPE_JSON')) {
|
||||
define('MYSQLI_TYPE_JSON', 245);
|
||||
}
|
||||
|
||||
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Interface to the improved MySQL extension (MySQLi)
|
||||
*
|
||||
* @package PhpMyAdmin-DBI
|
||||
* @subpackage MySQLi
|
||||
*/
|
||||
class DbiMysqli implements DbiExtension
|
||||
{
|
||||
static private $pma_mysqli_flag_names = array(
|
||||
MYSQLI_NUM_FLAG => 'num',
|
||||
MYSQLI_PART_KEY_FLAG => 'part_key',
|
||||
MYSQLI_SET_FLAG => 'set',
|
||||
MYSQLI_TIMESTAMP_FLAG => 'timestamp',
|
||||
MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment',
|
||||
MYSQLI_ENUM_FLAG => 'enum',
|
||||
MYSQLI_ZEROFILL_FLAG => 'zerofill',
|
||||
MYSQLI_UNSIGNED_FLAG => 'unsigned',
|
||||
MYSQLI_BLOB_FLAG => 'blob',
|
||||
MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key',
|
||||
MYSQLI_UNIQUE_KEY_FLAG => 'unique_key',
|
||||
MYSQLI_PRI_KEY_FLAG => 'primary_key',
|
||||
MYSQLI_NOT_NULL_FLAG => 'not_null',
|
||||
);
|
||||
|
||||
/**
|
||||
* connects to the database server
|
||||
*
|
||||
* @param string $user mysql user name
|
||||
* @param string $password mysql user password
|
||||
* @param array $server host/port/socket/persistent
|
||||
*
|
||||
* @return mixed false on error or a mysqli object on success
|
||||
*/
|
||||
public function connect(
|
||||
$user, $password, array $server
|
||||
) {
|
||||
if ($server) {
|
||||
$server['host'] = (empty($server['host']))
|
||||
? 'localhost'
|
||||
: $server['host'];
|
||||
}
|
||||
|
||||
// NULL enables connection to the default socket
|
||||
|
||||
$link = mysqli_init();
|
||||
|
||||
$client_flags = 0;
|
||||
|
||||
/* Optionally compress connection */
|
||||
if ($server['compress'] && defined('MYSQLI_CLIENT_COMPRESS')) {
|
||||
$client_flags |= MYSQLI_CLIENT_COMPRESS;
|
||||
}
|
||||
|
||||
/* Optionally enable SSL */
|
||||
if ($server['ssl']) {
|
||||
$client_flags |= MYSQLI_CLIENT_SSL;
|
||||
if (! empty($server['ssl_key']) ||
|
||||
! empty($server['ssl_cert']) ||
|
||||
! empty($server['ssl_ca']) ||
|
||||
! empty($server['ssl_ca_path']) ||
|
||||
! empty($server['ssl_ciphers'])
|
||||
) {
|
||||
if (! isset($server['ssl_key']) || is_null($server['ssl_key'])) {
|
||||
$server['ssl_key'] = '';
|
||||
}
|
||||
if (! isset($server['ssl_cert']) || is_null($server['ssl_cert'])) {
|
||||
$server['ssl_cert'] = '';
|
||||
}
|
||||
if (! isset($server['ssl_ca']) || is_null($server['ssl_ca'])) {
|
||||
$server['ssl_ca'] = '';
|
||||
}
|
||||
if (! isset($server['ssl_ca_path']) || is_null($server['ssl_ca_path'])) {
|
||||
$server['ssl_ca_path'] = '';
|
||||
}
|
||||
if (! isset($server['ssl_ciphers']) || is_null($server['ssl_ciphers'])) {
|
||||
$server['ssl_ciphers'] = '';
|
||||
}
|
||||
mysqli_ssl_set(
|
||||
$link,
|
||||
$server['ssl_key'],
|
||||
$server['ssl_cert'],
|
||||
$server['ssl_ca'],
|
||||
$server['ssl_ca_path'],
|
||||
$server['ssl_ciphers']
|
||||
);
|
||||
}
|
||||
/*
|
||||
* disables SSL certificate validation on mysqlnd for MySQL 5.6 or later
|
||||
* @link https://bugs.php.net/bug.php?id=68344
|
||||
* @link https://github.com/phpmyadmin/phpmyadmin/pull/11838
|
||||
*/
|
||||
if (! $server['ssl_verify']) {
|
||||
mysqli_options(
|
||||
$link,
|
||||
MYSQLI_OPT_SSL_VERIFY_SERVER_CERT,
|
||||
$server['ssl_verify']
|
||||
);
|
||||
$client_flags |= MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT;
|
||||
}
|
||||
}
|
||||
|
||||
if ($GLOBALS['cfg']['PersistentConnections']) {
|
||||
$host = 'p:' . $server['host'];
|
||||
} else {
|
||||
$host = $server['host'];
|
||||
}
|
||||
|
||||
if ($server['hide_connection_errors']) {
|
||||
$return_value = @mysqli_real_connect(
|
||||
$link,
|
||||
$host,
|
||||
$user,
|
||||
$password,
|
||||
'',
|
||||
$server['port'],
|
||||
$server['socket'],
|
||||
$client_flags
|
||||
);
|
||||
} else {
|
||||
$return_value = mysqli_real_connect(
|
||||
$link,
|
||||
$host,
|
||||
$user,
|
||||
$password,
|
||||
'',
|
||||
$server['port'],
|
||||
$server['socket'],
|
||||
$client_flags
|
||||
);
|
||||
}
|
||||
|
||||
if ($return_value === false || is_null($return_value)) {
|
||||
/*
|
||||
* Switch to SSL if server asked us to do so, unfortunately
|
||||
* there are more ways MySQL server can tell this:
|
||||
*
|
||||
* - MySQL 8.0 and newer should return error 3159
|
||||
* - #2001 - SSL Connection is required. Please specify SSL options and retry.
|
||||
* - #9002 - SSL connection is required. Please specify SSL options and retry.
|
||||
*/
|
||||
$error_number = mysqli_connect_errno();
|
||||
$error_message = mysqli_connect_error();
|
||||
if (! $server['ssl'] && ($error_number == 3159 ||
|
||||
(($error_number == 2001 || $error_number == 9002) && stripos($error_message, 'SSL Connection is required') !== false))
|
||||
) {
|
||||
trigger_error(
|
||||
__('SSL connection enforced by server, automatically enabling it.'),
|
||||
E_USER_WARNING
|
||||
);
|
||||
$server['ssl'] = true;
|
||||
return self::connect($user, $password, $server);
|
||||
} elseif ($error_number === 1045 && $server['hide_connection_errors']) {
|
||||
trigger_error(
|
||||
sprintf(
|
||||
__(
|
||||
'Error 1045: Access denied for user. Additional error information'
|
||||
. ' may be available, but is being hidden by the %s configuration directive.'
|
||||
),
|
||||
'[code][doc@cfg_Servers_hide_connection_errors]'
|
||||
. '$cfg[\'Servers\'][$i][\'hide_connection_errors\'][/doc][/code]'
|
||||
),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (defined('PMA_ENABLE_LDI')) {
|
||||
mysqli_options($link, MYSQLI_OPT_LOCAL_INFILE, true);
|
||||
} else {
|
||||
mysqli_options($link, MYSQLI_OPT_LOCAL_INFILE, false);
|
||||
}
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* selects given database
|
||||
*
|
||||
* @param string $dbname database name to select
|
||||
* @param mysqli $link the mysqli object
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function selectDb($dbname, $link)
|
||||
{
|
||||
return mysqli_select_db($link, $dbname);
|
||||
}
|
||||
|
||||
/**
|
||||
* runs a query and returns the result
|
||||
*
|
||||
* @param string $query query to execute
|
||||
* @param mysqli $link mysqli object
|
||||
* @param int $options query options
|
||||
*
|
||||
* @return mysqli_result|bool
|
||||
*/
|
||||
public function realQuery($query, $link, $options)
|
||||
{
|
||||
if ($options == ($options | DatabaseInterface::QUERY_STORE)) {
|
||||
$method = MYSQLI_STORE_RESULT;
|
||||
} elseif ($options == ($options | DatabaseInterface::QUERY_UNBUFFERED)) {
|
||||
$method = MYSQLI_USE_RESULT;
|
||||
} else {
|
||||
$method = 0;
|
||||
}
|
||||
|
||||
return mysqli_query($link, $query, $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the multi query and output the results
|
||||
*
|
||||
* @param mysqli $link mysqli object
|
||||
* @param string $query multi query statement to execute
|
||||
*
|
||||
* @return mysqli_result collection | boolean(false)
|
||||
*/
|
||||
public function realMultiQuery($link, $query)
|
||||
{
|
||||
return mysqli_multi_query($link, $query);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns array of rows with associative and numeric keys from $result
|
||||
*
|
||||
* @param mysqli_result $result result set identifier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchArray($result)
|
||||
{
|
||||
return mysqli_fetch_array($result, MYSQLI_BOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns array of rows with associative keys from $result
|
||||
*
|
||||
* @param mysqli_result $result result set identifier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchAssoc($result)
|
||||
{
|
||||
return mysqli_fetch_array($result, MYSQLI_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns array of rows with numeric keys from $result
|
||||
*
|
||||
* @param mysqli_result $result result set identifier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fetchRow($result)
|
||||
{
|
||||
return mysqli_fetch_array($result, MYSQLI_NUM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the result pointer to an arbitrary row in the result
|
||||
*
|
||||
* @param mysqli_result $result database result
|
||||
* @param integer $offset offset to seek
|
||||
*
|
||||
* @return bool true on success, false on failure
|
||||
*/
|
||||
public function dataSeek($result, $offset)
|
||||
{
|
||||
return mysqli_data_seek($result, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees memory associated with the result
|
||||
*
|
||||
* @param mysqli_result $result database result
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
if ($result instanceof mysqli_result) {
|
||||
mysqli_free_result($result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are any more query results from a multi query
|
||||
*
|
||||
* @param mysqli $link the mysqli object
|
||||
*
|
||||
* @return bool true or false
|
||||
*/
|
||||
public function moreResults($link)
|
||||
{
|
||||
return mysqli_more_results($link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare next result from multi_query
|
||||
*
|
||||
* @param mysqli $link the mysqli object
|
||||
*
|
||||
* @return bool true or false
|
||||
*/
|
||||
public function nextResult($link)
|
||||
{
|
||||
return mysqli_next_result($link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the result returned from multi query
|
||||
*
|
||||
* @param mysqli $link the mysqli object
|
||||
*
|
||||
* @return mixed false when empty results / result set when not empty
|
||||
*/
|
||||
public function storeResult($link)
|
||||
{
|
||||
return mysqli_store_result($link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the type of connection used
|
||||
*
|
||||
* @param resource $link mysql link
|
||||
*
|
||||
* @return string type of connection used
|
||||
*/
|
||||
public function getHostInfo($link)
|
||||
{
|
||||
return mysqli_get_host_info($link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the MySQL protocol used
|
||||
*
|
||||
* @param resource $link mysql link
|
||||
*
|
||||
* @return integer version of the MySQL protocol used
|
||||
*/
|
||||
public function getProtoInfo($link)
|
||||
{
|
||||
return mysqli_get_proto_info($link);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a string that represents the client library version
|
||||
*
|
||||
* @return string MySQL client library version
|
||||
*/
|
||||
public function getClientInfo()
|
||||
{
|
||||
return mysqli_get_client_info();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns last error message or false if no errors occurred
|
||||
*
|
||||
* @param resource $link mysql link
|
||||
*
|
||||
* @return string|bool $error or false
|
||||
*/
|
||||
public function getError($link)
|
||||
{
|
||||
$GLOBALS['errno'] = 0;
|
||||
|
||||
if (null !== $link && false !== $link) {
|
||||
$error_number = mysqli_errno($link);
|
||||
$error_message = mysqli_error($link);
|
||||
} else {
|
||||
$error_number = mysqli_connect_errno();
|
||||
$error_message = mysqli_connect_error();
|
||||
}
|
||||
if (0 == $error_number) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// keep the error number for further check after
|
||||
// the call to getError()
|
||||
$GLOBALS['errno'] = $error_number;
|
||||
|
||||
return $GLOBALS['dbi']->formatError($error_number, $error_message);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the number of rows returned by last query
|
||||
*
|
||||
* @param mysqli_result $result result set identifier
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
// see the note for tryQuery();
|
||||
if (is_bool($result)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return @mysqli_num_rows($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the number of rows affected by last query
|
||||
*
|
||||
* @param mysqli $link the mysqli object
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function affectedRows($link)
|
||||
{
|
||||
return mysqli_affected_rows($link);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns metainfo for fields in $result
|
||||
*
|
||||
* @param mysqli_result $result result set identifier
|
||||
*
|
||||
* @return array meta info for fields in $result
|
||||
*/
|
||||
public function getFieldsMeta($result)
|
||||
{
|
||||
// Build an associative array for a type look up
|
||||
$typeAr = array();
|
||||
$typeAr[MYSQLI_TYPE_DECIMAL] = 'real';
|
||||
$typeAr[MYSQLI_TYPE_NEWDECIMAL] = 'real';
|
||||
$typeAr[MYSQLI_TYPE_BIT] = 'int';
|
||||
$typeAr[MYSQLI_TYPE_TINY] = 'int';
|
||||
$typeAr[MYSQLI_TYPE_SHORT] = 'int';
|
||||
$typeAr[MYSQLI_TYPE_LONG] = 'int';
|
||||
$typeAr[MYSQLI_TYPE_FLOAT] = 'real';
|
||||
$typeAr[MYSQLI_TYPE_DOUBLE] = 'real';
|
||||
$typeAr[MYSQLI_TYPE_NULL] = 'null';
|
||||
$typeAr[MYSQLI_TYPE_TIMESTAMP] = 'timestamp';
|
||||
$typeAr[MYSQLI_TYPE_LONGLONG] = 'int';
|
||||
$typeAr[MYSQLI_TYPE_INT24] = 'int';
|
||||
$typeAr[MYSQLI_TYPE_DATE] = 'date';
|
||||
$typeAr[MYSQLI_TYPE_TIME] = 'time';
|
||||
$typeAr[MYSQLI_TYPE_DATETIME] = 'datetime';
|
||||
$typeAr[MYSQLI_TYPE_YEAR] = 'year';
|
||||
$typeAr[MYSQLI_TYPE_NEWDATE] = 'date';
|
||||
$typeAr[MYSQLI_TYPE_ENUM] = 'unknown';
|
||||
$typeAr[MYSQLI_TYPE_SET] = 'unknown';
|
||||
$typeAr[MYSQLI_TYPE_TINY_BLOB] = 'blob';
|
||||
$typeAr[MYSQLI_TYPE_MEDIUM_BLOB] = 'blob';
|
||||
$typeAr[MYSQLI_TYPE_LONG_BLOB] = 'blob';
|
||||
$typeAr[MYSQLI_TYPE_BLOB] = 'blob';
|
||||
$typeAr[MYSQLI_TYPE_VAR_STRING] = 'string';
|
||||
$typeAr[MYSQLI_TYPE_STRING] = 'string';
|
||||
// MySQL returns MYSQLI_TYPE_STRING for CHAR
|
||||
// and MYSQLI_TYPE_CHAR === MYSQLI_TYPE_TINY
|
||||
// so this would override TINYINT and mark all TINYINT as string
|
||||
// see https://github.com/phpmyadmin/phpmyadmin/issues/8569
|
||||
//$typeAr[MYSQLI_TYPE_CHAR] = 'string';
|
||||
$typeAr[MYSQLI_TYPE_GEOMETRY] = 'geometry';
|
||||
$typeAr[MYSQLI_TYPE_BIT] = 'bit';
|
||||
$typeAr[MYSQLI_TYPE_JSON] = 'json';
|
||||
|
||||
$fields = mysqli_fetch_fields($result);
|
||||
|
||||
// this happens sometimes (seen under MySQL 4.0.25)
|
||||
if (!is_array($fields)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($fields as $k => $field) {
|
||||
$fields[$k]->_type = $field->type;
|
||||
$fields[$k]->type = $typeAr[$field->type];
|
||||
$fields[$k]->_flags = $field->flags;
|
||||
$fields[$k]->flags = $this->fieldFlags($result, $k);
|
||||
|
||||
// Enhance the field objects for mysql-extension compatibility
|
||||
//$flags = explode(' ', $fields[$k]->flags);
|
||||
//array_unshift($flags, 'dummy');
|
||||
$fields[$k]->multiple_key
|
||||
= (int) (bool) ($fields[$k]->_flags & MYSQLI_MULTIPLE_KEY_FLAG);
|
||||
$fields[$k]->primary_key
|
||||
= (int) (bool) ($fields[$k]->_flags & MYSQLI_PRI_KEY_FLAG);
|
||||
$fields[$k]->unique_key
|
||||
= (int) (bool) ($fields[$k]->_flags & MYSQLI_UNIQUE_KEY_FLAG);
|
||||
$fields[$k]->not_null
|
||||
= (int) (bool) ($fields[$k]->_flags & MYSQLI_NOT_NULL_FLAG);
|
||||
$fields[$k]->unsigned
|
||||
= (int) (bool) ($fields[$k]->_flags & MYSQLI_UNSIGNED_FLAG);
|
||||
$fields[$k]->zerofill
|
||||
= (int) (bool) ($fields[$k]->_flags & MYSQLI_ZEROFILL_FLAG);
|
||||
$fields[$k]->numeric
|
||||
= (int) (bool) ($fields[$k]->_flags & MYSQLI_NUM_FLAG);
|
||||
$fields[$k]->blob
|
||||
= (int) (bool) ($fields[$k]->_flags & MYSQLI_BLOB_FLAG);
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* return number of fields in given $result
|
||||
*
|
||||
* @param mysqli_result $result result set identifier
|
||||
*
|
||||
* @return int field count
|
||||
*/
|
||||
public function numFields($result)
|
||||
{
|
||||
return mysqli_num_fields($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the length of the given field $i in $result
|
||||
*
|
||||
* @param mysqli_result $result result set identifier
|
||||
* @param int $i field
|
||||
*
|
||||
* @return int length of field
|
||||
*/
|
||||
public function fieldLen($result, $i)
|
||||
{
|
||||
if ($i >= $this->numFields($result)) {
|
||||
return false;
|
||||
}
|
||||
return mysqli_fetch_field_direct($result, $i)->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns name of $i. field in $result
|
||||
*
|
||||
* @param mysqli_result $result result set identifier
|
||||
* @param int $i field
|
||||
*
|
||||
* @return string name of $i. field in $result
|
||||
*/
|
||||
public function fieldName($result, $i)
|
||||
{
|
||||
if ($i >= $this->numFields($result)) {
|
||||
return false;
|
||||
}
|
||||
return mysqli_fetch_field_direct($result, $i)->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns concatenated string of human readable field flags
|
||||
*
|
||||
* @param mysqli_result $result result set identifier
|
||||
* @param int $i field
|
||||
*
|
||||
* @return string field flags
|
||||
*/
|
||||
public function fieldFlags($result, $i)
|
||||
{
|
||||
if ($i >= $this->numFields($result)) {
|
||||
return false;
|
||||
}
|
||||
$f = mysqli_fetch_field_direct($result, $i);
|
||||
$type = $f->type;
|
||||
$charsetnr = $f->charsetnr;
|
||||
$f = $f->flags;
|
||||
$flags = array();
|
||||
foreach (self::$pma_mysqli_flag_names as $flag => $name) {
|
||||
if ($f & $flag) {
|
||||
$flags[] = $name;
|
||||
}
|
||||
}
|
||||
// See https://dev.mysql.com/doc/refman/6.0/en/c-api-datatypes.html:
|
||||
// to determine if a string is binary, we should not use MYSQLI_BINARY_FLAG
|
||||
// but instead the charsetnr member of the MYSQL_FIELD
|
||||
// structure. Watch out: some types like DATE returns 63 in charsetnr
|
||||
// so we have to check also the type.
|
||||
// Unfortunately there is no equivalent in the mysql extension.
|
||||
if (($type == MYSQLI_TYPE_TINY_BLOB || $type == MYSQLI_TYPE_BLOB
|
||||
|| $type == MYSQLI_TYPE_MEDIUM_BLOB || $type == MYSQLI_TYPE_LONG_BLOB
|
||||
|| $type == MYSQLI_TYPE_VAR_STRING || $type == MYSQLI_TYPE_STRING)
|
||||
&& 63 == $charsetnr
|
||||
) {
|
||||
$flags[] = 'binary';
|
||||
}
|
||||
return implode(' ', $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns properly escaped string for use in MySQL queries
|
||||
*
|
||||
* @param mixed $link database link
|
||||
* @param string $str string to be escaped
|
||||
*
|
||||
* @return string a MySQL escaped string
|
||||
*/
|
||||
public function escapeString($link, $str)
|
||||
{
|
||||
return mysqli_real_escape_string($link, $str);
|
||||
}
|
||||
}
|
||||
46
phpMyAdmin/libraries/classes/Di/AliasItem.php
Executable file
46
phpMyAdmin/libraries/classes/Di/AliasItem.php
Executable file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Di\AliasItem class
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
namespace PhpMyAdmin\Di;
|
||||
|
||||
/**
|
||||
* Class AliasItem
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
class AliasItem implements Item
|
||||
{
|
||||
|
||||
/** @var Container */
|
||||
protected $container;
|
||||
|
||||
/** @var string */
|
||||
protected $target;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Container $container Container
|
||||
* @param string $target Target
|
||||
*/
|
||||
public function __construct(Container $container, $target)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->target = $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the target item
|
||||
*
|
||||
* @param array $params Parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(array $params = array())
|
||||
{
|
||||
return $this->container->get($this->target, $params);
|
||||
}
|
||||
}
|
||||
189
phpMyAdmin/libraries/classes/Di/Container.php
Executable file
189
phpMyAdmin/libraries/classes/Di/Container.php
Executable file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Di\Container class
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
namespace PhpMyAdmin\Di;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Class Container
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
class Container implements ContainerInterface
|
||||
{
|
||||
/**
|
||||
* @var Item[] $content
|
||||
*/
|
||||
protected $content = array();
|
||||
|
||||
/**
|
||||
* @var Container
|
||||
*/
|
||||
protected static $defaultContainer;
|
||||
|
||||
/**
|
||||
* Create a dependency injection container
|
||||
*
|
||||
* @param Container $base Container
|
||||
*/
|
||||
public function __construct(Container $base = null)
|
||||
{
|
||||
if (isset($base)) {
|
||||
$this->content = $base->content;
|
||||
} else {
|
||||
$this->alias('container', 'Container');
|
||||
}
|
||||
$this->set('Container', $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an object with given name and parameters
|
||||
*
|
||||
* @param string $name Name
|
||||
* @param array $params Parameters
|
||||
*
|
||||
* @throws NotFoundException No entry was found for **this** identifier.
|
||||
* @throws ContainerException Error while retrieving the entry.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, array $params = array())
|
||||
{
|
||||
if (!$this->has($name)) {
|
||||
throw new NotFoundException("No entry was found for $name identifier.");
|
||||
}
|
||||
|
||||
if (isset($this->content[$name])) {
|
||||
return $this->content[$name]->get($params);
|
||||
} elseif (isset($GLOBALS[$name])) {
|
||||
return $GLOBALS[$name];
|
||||
} else {
|
||||
throw new ContainerException("Error while retrieving the entry.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the container can return an entry for the given identifier.
|
||||
* Returns false otherwise.
|
||||
*
|
||||
* `has($name)` returning true does not mean that `get($name)` will not throw an exception.
|
||||
* It does however mean that `get($name)` will not throw a `NotFoundException`.
|
||||
*
|
||||
* @param string $name Identifier of the entry to look for.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return isset($this->content[$name]) || isset($GLOBALS[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an object from container
|
||||
*
|
||||
* @param string $name Name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
unset($this->content[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename an object in container
|
||||
*
|
||||
* @param string $name Name
|
||||
* @param string $newName New name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function rename($name, $newName)
|
||||
{
|
||||
$this->content[$newName] = $this->content[$name];
|
||||
$this->remove($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set values in the container
|
||||
*
|
||||
* @param string|array $name Name
|
||||
* @param mixed $value Value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($name, $value = null)
|
||||
{
|
||||
if (is_array($name)) {
|
||||
foreach ($name as $key => $val) {
|
||||
$this->set($key, $val);
|
||||
}
|
||||
return;
|
||||
}
|
||||
$this->content[$name] = new ValueItem($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a service in the container
|
||||
*
|
||||
* @param string $name Name
|
||||
* @param mixed $service Service
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function service($name, $service = null)
|
||||
{
|
||||
if (!isset($service)) {
|
||||
$service = $name;
|
||||
}
|
||||
$this->content[$name] = new ServiceItem($this, $service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a factory in the container
|
||||
*
|
||||
* @param string $name Name
|
||||
* @param mixed $factory Factory
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function factory($name, $factory = null)
|
||||
{
|
||||
if (!isset($factory)) {
|
||||
$factory = $name;
|
||||
}
|
||||
$this->content[$name] = new FactoryItem($this, $factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an alias in the container
|
||||
*
|
||||
* @param string $name Name
|
||||
* @param string $target Target
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function alias($name, $target)
|
||||
{
|
||||
// The target may be not defined yet
|
||||
$this->content[$name] = new AliasItem($this, $target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the global default container
|
||||
*
|
||||
* @return Container
|
||||
*/
|
||||
public static function getDefaultContainer()
|
||||
{
|
||||
if (!isset(static::$defaultContainer)) {
|
||||
static::$defaultContainer = new Container();
|
||||
}
|
||||
return static::$defaultContainer;
|
||||
}
|
||||
}
|
||||
21
phpMyAdmin/libraries/classes/Di/ContainerException.php
Executable file
21
phpMyAdmin/libraries/classes/Di/ContainerException.php
Executable file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Di\ContainerException class
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
namespace PhpMyAdmin\Di;
|
||||
|
||||
use Exception;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
|
||||
/**
|
||||
* Class ContainerException
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
class ContainerException extends Exception implements ContainerExceptionInterface
|
||||
{
|
||||
|
||||
}
|
||||
29
phpMyAdmin/libraries/classes/Di/FactoryItem.php
Executable file
29
phpMyAdmin/libraries/classes/Di/FactoryItem.php
Executable file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Di\FactoryItem class
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
namespace PhpMyAdmin\Di;
|
||||
|
||||
/**
|
||||
* Factory manager
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
class FactoryItem extends ReflectorItem
|
||||
{
|
||||
|
||||
/**
|
||||
* Construct an instance
|
||||
*
|
||||
* @param array $params Parameters
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(array $params = array())
|
||||
{
|
||||
return $this->invoke($params);
|
||||
}
|
||||
}
|
||||
25
phpMyAdmin/libraries/classes/Di/Item.php
Executable file
25
phpMyAdmin/libraries/classes/Di/Item.php
Executable file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Di\Item class
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
namespace PhpMyAdmin\Di;
|
||||
|
||||
/**
|
||||
* Interface Item
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
interface Item
|
||||
{
|
||||
|
||||
/**
|
||||
* Get a value from the item
|
||||
*
|
||||
* @param array $params Parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(array $params = array());
|
||||
}
|
||||
20
phpMyAdmin/libraries/classes/Di/NotFoundException.php
Executable file
20
phpMyAdmin/libraries/classes/Di/NotFoundException.php
Executable file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Di\NotFoundException class
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
namespace PhpMyAdmin\Di;
|
||||
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
/**
|
||||
* Class NotFoundException
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
class NotFoundException extends ContainerException implements NotFoundExceptionInterface
|
||||
{
|
||||
|
||||
}
|
||||
128
phpMyAdmin/libraries/classes/Di/ReflectorItem.php
Executable file
128
phpMyAdmin/libraries/classes/Di/ReflectorItem.php
Executable file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Di\ReflectorItem class
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
namespace PhpMyAdmin\Di;
|
||||
|
||||
/**
|
||||
* Reflector manager
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
abstract class ReflectorItem implements Item
|
||||
{
|
||||
|
||||
/** @var Container */
|
||||
private $_container;
|
||||
|
||||
/** @var \Reflector */
|
||||
private $_reflector;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Container $container Container
|
||||
* @param mixed $definition Definition
|
||||
*/
|
||||
public function __construct(Container $container, $definition)
|
||||
{
|
||||
$this->_container = $container;
|
||||
$this->_reflector = self::_resolveReflector($definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the reflector with given parameters
|
||||
*
|
||||
* @param array $params Parameters
|
||||
* @return mixed
|
||||
*/
|
||||
protected function invoke(array $params = array())
|
||||
{
|
||||
$args = array();
|
||||
$reflector = $this->_reflector;
|
||||
if ($reflector instanceof \ReflectionClass) {
|
||||
$constructor = $reflector->getConstructor();
|
||||
if (isset($constructor)) {
|
||||
$args = $this->_resolveArgs(
|
||||
$constructor->getParameters(),
|
||||
$params
|
||||
);
|
||||
}
|
||||
return $reflector->newInstanceArgs($args);
|
||||
}
|
||||
/** @var \ReflectionFunctionAbstract $reflector */
|
||||
$args = $this->_resolveArgs(
|
||||
$reflector->getParameters(),
|
||||
$params
|
||||
);
|
||||
if ($reflector instanceof \ReflectionMethod) {
|
||||
/** @var \ReflectionMethod $reflector */
|
||||
return $reflector->invokeArgs(null, $args);
|
||||
}
|
||||
/** @var \ReflectionFunction $reflector */
|
||||
return $reflector->invokeArgs($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getting required arguments with given parameters
|
||||
*
|
||||
* @param \ReflectionParameter[] $required Arguments
|
||||
* @param array $params Parameters
|
||||
*
|
||||
*@return array
|
||||
*/
|
||||
private function _resolveArgs($required, array $params = array())
|
||||
{
|
||||
$args = array();
|
||||
foreach ($required as $param) {
|
||||
$name = $param->getName();
|
||||
$type = $param->getClass();
|
||||
if (isset($type)) {
|
||||
$type = $type->getName();
|
||||
}
|
||||
if (isset($params[$name])) {
|
||||
$args[] = $params[$name];
|
||||
} elseif (is_string($type) && isset($params[$type])) {
|
||||
$args[] = $params[$type];
|
||||
} else {
|
||||
try {
|
||||
$content = $this->_container->get($name);
|
||||
if (isset($content)) {
|
||||
$args[] = $content;
|
||||
} elseif (is_string($type)) {
|
||||
$args[] = $this->_container->get($type);
|
||||
} else {
|
||||
$args[] = null;
|
||||
}
|
||||
} catch (NotFoundException $e) {
|
||||
$args[] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the reflection
|
||||
*
|
||||
* @param mixed $definition Definition
|
||||
*
|
||||
* @return \Reflector
|
||||
*/
|
||||
private static function _resolveReflector($definition)
|
||||
{
|
||||
if (function_exists($definition)) {
|
||||
return new \ReflectionFunction($definition);
|
||||
}
|
||||
if (is_string($definition)) {
|
||||
$definition = explode('::', $definition);
|
||||
}
|
||||
if (!isset($definition[1])) {
|
||||
return new \ReflectionClass($definition[0]);
|
||||
}
|
||||
return new \ReflectionMethod($definition[0], $definition[1]);
|
||||
}
|
||||
}
|
||||
34
phpMyAdmin/libraries/classes/Di/ServiceItem.php
Executable file
34
phpMyAdmin/libraries/classes/Di/ServiceItem.php
Executable file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Di\ServiceItem class
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
namespace PhpMyAdmin\Di;
|
||||
|
||||
/**
|
||||
* Service manager
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
class ServiceItem extends ReflectorItem
|
||||
{
|
||||
|
||||
/** @var mixed */
|
||||
protected $instance;
|
||||
|
||||
/**
|
||||
* Get the instance of the service
|
||||
*
|
||||
* @param array $params Parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(array $params = array())
|
||||
{
|
||||
if (!isset($this->instance)) {
|
||||
$this->instance = $this->invoke();
|
||||
}
|
||||
return $this->instance;
|
||||
}
|
||||
}
|
||||
41
phpMyAdmin/libraries/classes/Di/ValueItem.php
Executable file
41
phpMyAdmin/libraries/classes/Di/ValueItem.php
Executable file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Holds the PhpMyAdmin\Di\ValueItem class
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
namespace PhpMyAdmin\Di;
|
||||
|
||||
/**
|
||||
* Value manager
|
||||
*
|
||||
* @package PhpMyAdmin\Di
|
||||
*/
|
||||
class ValueItem implements Item
|
||||
{
|
||||
|
||||
/** @var mixed */
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param mixed $value Value
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value
|
||||
*
|
||||
* @param array $params Parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(array $params = array())
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
165
phpMyAdmin/libraries/classes/Display/ChangePassword.php
Executable file
165
phpMyAdmin/libraries/classes/Display/ChangePassword.php
Executable file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Displays form for password change
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Display;
|
||||
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Server\Privileges;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Displays form for password change
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class ChangePassword
|
||||
{
|
||||
/**
|
||||
* Get HTML for the Change password dialog
|
||||
*
|
||||
* @param string $mode where is the function being called?
|
||||
* values : 'change_pw' or 'edit_other'
|
||||
* @param string $username username
|
||||
* @param string $hostname hostname
|
||||
*
|
||||
* @return string html snippet
|
||||
*/
|
||||
public static function getHtml($mode, $username, $hostname)
|
||||
{
|
||||
/**
|
||||
* autocomplete feature of IE kills the "onchange" event handler and it
|
||||
* must be replaced by the "onpropertychange" one in this case
|
||||
*/
|
||||
$chg_evt_handler = 'onchange';
|
||||
|
||||
$is_privileges = basename($_SERVER['SCRIPT_NAME']) === 'server_privileges.php';
|
||||
|
||||
$html = '<form method="post" id="change_password_form" '
|
||||
. 'action="' . basename($GLOBALS['PMA_PHP_SELF']) . '" '
|
||||
. 'name="chgPassword" '
|
||||
. 'class="' . ($is_privileges ? 'submenu-item' : '') . '">';
|
||||
|
||||
$html .= Url::getHiddenInputs();
|
||||
|
||||
if (strpos($GLOBALS['PMA_PHP_SELF'], 'server_privileges') !== false) {
|
||||
$html .= '<input type="hidden" name="username" '
|
||||
. 'value="' . htmlspecialchars($username) . '" />'
|
||||
. '<input type="hidden" name="hostname" '
|
||||
. 'value="' . htmlspecialchars($hostname) . '" />';
|
||||
}
|
||||
$html .= '<fieldset id="fieldset_change_password">'
|
||||
. '<legend'
|
||||
. ($is_privileges
|
||||
? ' data-submenu-label="' . __('Change password') . '"'
|
||||
: ''
|
||||
)
|
||||
. '>' . __('Change password') . '</legend>'
|
||||
. '<table class="data noclick">'
|
||||
. '<tr>'
|
||||
. '<td colspan="2">'
|
||||
. '<input type="radio" name="nopass" value="1" id="nopass_1" '
|
||||
. 'onclick="pma_pw.value = \'\'; pma_pw2.value = \'\'; '
|
||||
. 'this.checked = true" />'
|
||||
. '<label for="nopass_1">' . __('No Password') . '</label>'
|
||||
. '</td>'
|
||||
. '</tr>'
|
||||
. '<tr class="vmiddle">'
|
||||
. '<td>'
|
||||
. '<input type="radio" name="nopass" value="0" id="nopass_0" '
|
||||
. 'onclick="document.getElementById(\'text_pma_change_pw\').focus();" '
|
||||
. 'checked="checked" />'
|
||||
. '<label for="nopass_0">' . __('Password:') . ' </label>'
|
||||
. '</td>'
|
||||
. '<td>'
|
||||
. __('Enter:') . '  '
|
||||
. '<input type="password" name="pma_pw" id="text_pma_change_pw" size="10" '
|
||||
. 'class="textfield"'
|
||||
. 'onkeyup="checkPasswordStrength($(this).val(), $(\'#change_password_strength_meter\'), meter_obj_label = $(\'#change_password_strength\'), PMA_commonParams.get(\'user\'));" '
|
||||
. $chg_evt_handler . '="nopass[1].checked = true" />'
|
||||
. '<span>Strength:</span> '
|
||||
. '<meter max="4" id="change_password_strength_meter" name="pw_meter"></meter> '
|
||||
. '<span id="change_password_strength" name="pw_strength">Good</span>'
|
||||
. '<br>' . __('Re-type:') . ' '
|
||||
. '<input type="password" name="pma_pw2" id="text_pma_change_pw2" size="10" '
|
||||
. 'class="textfield"'
|
||||
. $chg_evt_handler . '="nopass[1].checked = true" />'
|
||||
. '</td>'
|
||||
. '</tr>';
|
||||
|
||||
$serverType = Util::getServerType();
|
||||
$serverVersion = $GLOBALS['dbi']->getVersion();
|
||||
$orig_auth_plugin = Privileges::getCurrentAuthenticationPlugin(
|
||||
'change',
|
||||
$username,
|
||||
$hostname
|
||||
);
|
||||
|
||||
if (($serverType == 'MySQL'
|
||||
&& $serverVersion >= 50507)
|
||||
|| ($serverType == 'MariaDB'
|
||||
&& $serverVersion >= 50200)
|
||||
) {
|
||||
// Provide this option only for 5.7.6+
|
||||
// OR for privileged users in 5.5.7+
|
||||
if (($serverType == 'MySQL'
|
||||
&& $serverVersion >= 50706)
|
||||
|| ($GLOBALS['dbi']->isSuperuser() && $mode == 'edit_other')
|
||||
) {
|
||||
$auth_plugin_dropdown = Privileges::getHtmlForAuthPluginsDropdown(
|
||||
$orig_auth_plugin, 'change_pw', 'new'
|
||||
);
|
||||
|
||||
$html .= '<tr class="vmiddle">'
|
||||
. '<td>' . __('Password Hashing:') . '</td><td>';
|
||||
$html .= $auth_plugin_dropdown;
|
||||
$html .= '</td></tr>'
|
||||
. '<tr id="tr_element_before_generate_password"></tr>'
|
||||
. '</table>';
|
||||
|
||||
$html .= '<div'
|
||||
. ($orig_auth_plugin != 'sha256_password'
|
||||
? ' class="hide"'
|
||||
: '')
|
||||
. ' id="ssl_reqd_warning_cp">'
|
||||
. Message::notice(
|
||||
__(
|
||||
'This method requires using an \'<i>SSL connection</i>\' '
|
||||
. 'or an \'<i>unencrypted connection that encrypts the '
|
||||
. 'password using RSA</i>\'; while connecting to the server.'
|
||||
)
|
||||
. Util::showMySQLDocu(
|
||||
'sha256-authentication-plugin'
|
||||
)
|
||||
)
|
||||
->getDisplay()
|
||||
. '</div>';
|
||||
} else {
|
||||
$html .= '<tr id="tr_element_before_generate_password"></tr>'
|
||||
. '</table>';
|
||||
}
|
||||
} else {
|
||||
$auth_plugin_dropdown = Privileges::getHtmlForAuthPluginsDropdown(
|
||||
$orig_auth_plugin, 'change_pw', 'old'
|
||||
);
|
||||
|
||||
$html .= '<tr class="vmiddle">'
|
||||
. '<td>' . __('Password Hashing:') . '</td><td>';
|
||||
$html .= $auth_plugin_dropdown . '</td></tr>'
|
||||
. '<tr id="tr_element_before_generate_password"></tr>'
|
||||
. '</table>';
|
||||
}
|
||||
|
||||
$html .= '</fieldset>'
|
||||
. '<fieldset id="fieldset_change_password_footer" class="tblFooters">'
|
||||
. '<input type="hidden" name="change_pw" value="1" />'
|
||||
. '<input type="submit" value="' . __('Go') . '" />'
|
||||
. '</fieldset>'
|
||||
. '</form>';
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
53
phpMyAdmin/libraries/classes/Display/CreateTable.php
Executable file
53
phpMyAdmin/libraries/classes/Display/CreateTable.php
Executable file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Displays form for creating a table (if user has privileges for that)
|
||||
*
|
||||
* for MySQL >= 4.1.0, we should be able to detect if user has a CREATE
|
||||
* privilege by looking at SHOW GRANTS output;
|
||||
* for < 4.1.0, it could be more difficult because the logic tries to
|
||||
* detect the current host and it might be expressed in many ways; also
|
||||
* on a shared server, the user might be unable to define a controluser
|
||||
* that has the proper rights to the "mysql" db;
|
||||
* so we give up and assume that user has the right to create a table
|
||||
*
|
||||
* Note: in this case we could even skip the following "foreach" logic
|
||||
*
|
||||
* Addendum, 2006-01-19: ok, I give up. We got some reports about servers
|
||||
* where the hostname field in mysql.user is not the same as the one
|
||||
* in mysql.db for a user. In this case, SHOW GRANTS does not return
|
||||
* the db-specific privileges. And probably, those users are on a shared
|
||||
* server, so can't set up a control user with rights to the "mysql" db.
|
||||
* We cannot reliably detect the db-specific privileges, so no more
|
||||
* warnings about the lack of privileges for CREATE TABLE. Tested
|
||||
* on MySQL 5.0.18.
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Display;
|
||||
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
require_once './libraries/check_user_privileges.inc.php';
|
||||
|
||||
/**
|
||||
* PhpMyAdmin\Display\CreateTable class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class CreateTable
|
||||
{
|
||||
/**
|
||||
* Returns the html for create table.
|
||||
*
|
||||
* @param string $db database name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtml($db)
|
||||
{
|
||||
return Template::get('database/create_table')->render(
|
||||
array('db' => $db)
|
||||
);
|
||||
}
|
||||
}
|
||||
806
phpMyAdmin/libraries/classes/Display/Export.php
Executable file
806
phpMyAdmin/libraries/classes/Display/Export.php
Executable file
@@ -0,0 +1,806 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* functions for displaying server, database and table export
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Display;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Encoding;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Relation;
|
||||
use PhpMyAdmin\Response;
|
||||
use PhpMyAdmin\Table;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* PhpMyAdmin\Display\Export class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class Export
|
||||
{
|
||||
/**
|
||||
* @var Relation $relation
|
||||
*/
|
||||
private $relation;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->relation = new Relation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs appropriate checked statement for checkbox.
|
||||
*
|
||||
* @param string $str option name
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function checkboxCheck($str)
|
||||
{
|
||||
return isset($GLOBALS['cfg']['Export'][$str])
|
||||
&& $GLOBALS['cfg']['Export'][$str];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Selection Options
|
||||
*
|
||||
* @param string $tmpSelect Tmp selected method of export
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHtmlForSelectOptions($tmpSelect = '')
|
||||
{
|
||||
// Check if the selected databases are defined in $_POST
|
||||
// (from clicking Back button on export.php)
|
||||
if (isset($_POST['db_select'])) {
|
||||
$_POST['db_select'] = urldecode($_POST['db_select']);
|
||||
$_POST['db_select'] = explode(",", $_POST['db_select']);
|
||||
}
|
||||
|
||||
$databases = [];
|
||||
foreach ($GLOBALS['dblist']->databases as $currentDb) {
|
||||
if ($GLOBALS['dbi']->isSystemSchema($currentDb, true)) {
|
||||
continue;
|
||||
}
|
||||
$isSelected = false;
|
||||
if (isset($_POST['db_select'])) {
|
||||
if (in_array($currentDb, $_POST['db_select'])) {
|
||||
$isSelected = true;
|
||||
}
|
||||
} elseif (!empty($tmpSelect)) {
|
||||
if (mb_strpos(
|
||||
' ' . $tmpSelect,
|
||||
'|' . $currentDb . '|'
|
||||
)) {
|
||||
$isSelected = true;
|
||||
}
|
||||
} else {
|
||||
$isSelected = true;
|
||||
}
|
||||
$databases[] = [
|
||||
'name' => $currentDb,
|
||||
'is_selected' => $isSelected,
|
||||
];
|
||||
}
|
||||
|
||||
return Template::get('display/export/select_options')->render([
|
||||
'databases' => $databases,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Hidden Input
|
||||
*
|
||||
* @param string $exportType Selected Export Type
|
||||
* @param string $db Selected DB
|
||||
* @param string $table Selected Table
|
||||
* @param string $singleTable Single Table
|
||||
* @param string $sqlQuery SQL Query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHtmlForHiddenInputs(
|
||||
$exportType,
|
||||
$db,
|
||||
$table,
|
||||
$singleTable,
|
||||
$sqlQuery
|
||||
) {
|
||||
global $cfg;
|
||||
|
||||
// If the export method was not set, the default is quick
|
||||
if (isset($_POST['export_method'])) {
|
||||
$cfg['Export']['method'] = $_POST['export_method'];
|
||||
} elseif (! isset($cfg['Export']['method'])) {
|
||||
$cfg['Export']['method'] = 'quick';
|
||||
}
|
||||
|
||||
if (empty($sqlQuery) && isset($_POST['sql_query'])) {
|
||||
$sqlQuery = $_POST['sql_query'];
|
||||
}
|
||||
|
||||
return Template::get('display/export/hidden_inputs')->render([
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
'export_type' => $exportType,
|
||||
'export_method' => $cfg['Export']['method'],
|
||||
'single_table' => $singleTable,
|
||||
'sql_query' => $sqlQuery,
|
||||
'template_id' => isset($_POST['template_id']) ? $_POST['template_id'] : '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for the options in template dropdown
|
||||
*
|
||||
* @param string $exportType export type - server, database, or table
|
||||
*
|
||||
* @return string HTML for the options in teplate dropdown
|
||||
*/
|
||||
private function getOptionsForTemplates($exportType)
|
||||
{
|
||||
// Get the relation settings
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
|
||||
$query = "SELECT `id`, `template_name` FROM "
|
||||
. Util::backquote($cfgRelation['db']) . '.'
|
||||
. Util::backquote($cfgRelation['export_templates'])
|
||||
. " WHERE `username` = "
|
||||
. "'" . $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user'])
|
||||
. "' AND `export_type` = '" . $GLOBALS['dbi']->escapeString($exportType) . "'"
|
||||
. " ORDER BY `template_name`;";
|
||||
|
||||
$result = $this->relation->queryAsControlUser($query);
|
||||
|
||||
$templates = [];
|
||||
if ($result !== false) {
|
||||
while ($row = $GLOBALS['dbi']->fetchAssoc($result, DatabaseInterface::CONNECT_CONTROL)) {
|
||||
$templates[] = [
|
||||
'name' => $row['template_name'],
|
||||
'id' => $row['id'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return Template::get('display/export/template_options')->render([
|
||||
'templates' => $templates,
|
||||
'selected_template' => !empty($_POST['template_id']) ? $_POST['template_id'] : null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options Method
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsMethod()
|
||||
{
|
||||
global $cfg;
|
||||
if (isset($_POST['quick_or_custom'])) {
|
||||
$exportMethod = $_POST['quick_or_custom'];
|
||||
} else {
|
||||
$exportMethod = $cfg['Export']['method'];
|
||||
}
|
||||
|
||||
return Template::get('display/export/method')->render([
|
||||
'export_method' => $exportMethod,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options Selection
|
||||
*
|
||||
* @param string $exportType Selected Export Type
|
||||
* @param string $multiValues Export Options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsSelection($exportType, $multiValues)
|
||||
{
|
||||
return Template::get('display/export/selection')->render([
|
||||
'export_type' => $exportType,
|
||||
'multi_values' => $multiValues,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options Format dropdown
|
||||
*
|
||||
* @param ExportPlugin[] $exportList Export List
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsFormatDropdown($exportList)
|
||||
{
|
||||
$dropdown = Plugins::getChoice('Export', 'what', $exportList, 'format');
|
||||
return Template::get('display/export/format_dropdown')->render([
|
||||
'dropdown' => $dropdown,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options Format-specific options
|
||||
*
|
||||
* @param ExportPlugin[] $exportList Export List
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsFormat($exportList)
|
||||
{
|
||||
global $cfg;
|
||||
$options = Plugins::getOptions('Export', $exportList);
|
||||
|
||||
return Template::get('display/export/options_format')->render([
|
||||
'options' => $options,
|
||||
'can_convert_kanji' => Encoding::canConvertKanji(),
|
||||
'exec_time_limit' => $cfg['ExecTimeLimit'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options Rows
|
||||
*
|
||||
* @param string $db Selected DB
|
||||
* @param string $table Selected Table
|
||||
* @param string $unlimNumRows Num of Rows
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsRows($db, $table, $unlimNumRows)
|
||||
{
|
||||
$tableObject = new Table($table, $db);
|
||||
$numberOfRows = $tableObject->countRecords();
|
||||
|
||||
return Template::get('display/export/options_rows')->render([
|
||||
'allrows' => isset($_POST['allrows']) ? $_POST['allrows'] : null,
|
||||
'limit_to' => isset($_POST['limit_to']) ? $_POST['limit_to'] : null,
|
||||
'limit_from' => isset($_POST['limit_from']) ? $_POST['limit_from'] : null,
|
||||
'unlim_num_rows' => $unlimNumRows,
|
||||
'number_of_rows' => $numberOfRows,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options Quick Export
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsQuickExport()
|
||||
{
|
||||
global $cfg;
|
||||
$saveDir = Util::userDir($cfg['SaveDir']);
|
||||
$exportIsChecked = $this->checkboxCheck(
|
||||
'quick_export_onserver'
|
||||
);
|
||||
$exportOverwriteIsChecked = $this->checkboxCheck(
|
||||
'quick_export_onserver_overwrite'
|
||||
);
|
||||
|
||||
return Template::get('display/export/options_quick_export')->render([
|
||||
'save_dir' => $saveDir,
|
||||
'export_is_checked' => $exportIsChecked,
|
||||
'export_overwrite_is_checked' => $exportOverwriteIsChecked,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options Save Dir
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsOutputSaveDir()
|
||||
{
|
||||
global $cfg;
|
||||
$saveDir = Util::userDir($cfg['SaveDir']);
|
||||
$exportIsChecked = $this->checkboxCheck(
|
||||
'onserver'
|
||||
);
|
||||
$exportOverwriteIsChecked = $this->checkboxCheck(
|
||||
'onserver_overwrite'
|
||||
);
|
||||
|
||||
return Template::get('display/export/options_output_save_dir')->render([
|
||||
'save_dir' => $saveDir,
|
||||
'export_is_checked' => $exportIsChecked,
|
||||
'export_overwrite_is_checked' => $exportOverwriteIsChecked,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options
|
||||
*
|
||||
* @param string $exportType Selected Export Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsOutputFormat($exportType)
|
||||
{
|
||||
$trans = new Message;
|
||||
$trans->addText(__('@SERVER@ will become the server name'));
|
||||
if ($exportType == 'database' || $exportType == 'table') {
|
||||
$trans->addText(__(', @DATABASE@ will become the database name'));
|
||||
if ($exportType == 'table') {
|
||||
$trans->addText(__(', @TABLE@ will become the table name'));
|
||||
}
|
||||
}
|
||||
|
||||
$msg = new Message(
|
||||
__(
|
||||
'This value is interpreted using %1$sstrftime%2$s, '
|
||||
. 'so you can use time formatting strings. '
|
||||
. 'Additionally the following transformations will happen: %3$s. '
|
||||
. 'Other text will be kept as is. See the %4$sFAQ%5$s for details.'
|
||||
)
|
||||
);
|
||||
$msg->addParamHtml(
|
||||
'<a href="' . Core::linkURL(Core::getPHPDocLink('function.strftime.php'))
|
||||
. '" target="documentation" title="' . __('Documentation') . '">'
|
||||
);
|
||||
$msg->addParamHtml('</a>');
|
||||
$msg->addParam($trans);
|
||||
$docUrl = Util::getDocuLink('faq', 'faq6-27');
|
||||
$msg->addParamHtml(
|
||||
'<a href="' . $docUrl . '" target="documentation">'
|
||||
);
|
||||
$msg->addParamHtml('</a>');
|
||||
|
||||
if (isset($_POST['filename_template'])) {
|
||||
$filenameTemplate = $_POST['filename_template'];
|
||||
} else {
|
||||
if ($exportType == 'database') {
|
||||
$filenameTemplate = $GLOBALS['PMA_Config']->getUserValue(
|
||||
'pma_db_filename_template',
|
||||
$GLOBALS['cfg']['Export']['file_template_database']
|
||||
);
|
||||
} elseif ($exportType == 'table') {
|
||||
$filenameTemplate = $GLOBALS['PMA_Config']->getUserValue(
|
||||
'pma_table_filename_template',
|
||||
$GLOBALS['cfg']['Export']['file_template_table']
|
||||
);
|
||||
} else {
|
||||
$filenameTemplate = $GLOBALS['PMA_Config']->getUserValue(
|
||||
'pma_server_filename_template',
|
||||
$GLOBALS['cfg']['Export']['file_template_server']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Template::get('display/export/options_output_format')->render([
|
||||
'message' => $msg->getMessage(),
|
||||
'filename_template' => $filenameTemplate,
|
||||
'is_checked' => $this->checkboxCheck('remember_file_template'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options Charset
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsOutputCharset()
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
return Template::get('display/export/options_output_charset')->render([
|
||||
'encodings' => Encoding::listEncodings(),
|
||||
'export_charset' => $cfg['Export']['charset'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options Compression
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsOutputCompression()
|
||||
{
|
||||
global $cfg;
|
||||
if (isset($_POST['compression'])) {
|
||||
$selectedCompression = $_POST['compression'];
|
||||
} elseif (isset($cfg['Export']['compression'])) {
|
||||
$selectedCompression = $cfg['Export']['compression'];
|
||||
} else {
|
||||
$selectedCompression = 'none';
|
||||
}
|
||||
|
||||
// Since separate files export works with ZIP only
|
||||
if (isset($cfg['Export']['as_separate_files'])
|
||||
&& $cfg['Export']['as_separate_files']
|
||||
) {
|
||||
$selectedCompression = 'zip';
|
||||
}
|
||||
|
||||
// zip and gzip encode features
|
||||
$isZip = ($cfg['ZipDump'] && function_exists('gzcompress'));
|
||||
$isGzip = ($cfg['GZipDump'] && function_exists('gzencode'));
|
||||
|
||||
return Template::get('display/export/options_output_compression')->render([
|
||||
'is_zip' => $isZip,
|
||||
'is_gzip' => $isGzip,
|
||||
'selected_compression' => $selectedCompression,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options Radio
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsOutputRadio()
|
||||
{
|
||||
return Template::get('display/export/options_output_radio')->render([
|
||||
'has_repopulate' => isset($_POST['repopulate']),
|
||||
'export_asfile' => $GLOBALS['cfg']['Export']['asfile'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options Checkbox - Separate files
|
||||
*
|
||||
* @param string $exportType Selected Export Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsOutputSeparateFiles($exportType)
|
||||
{
|
||||
$isChecked = $this->checkboxCheck('as_separate_files');
|
||||
|
||||
return Template::get('display/export/options_output_separate_files')->render([
|
||||
'is_checked' => $isChecked,
|
||||
'export_type' => $exportType,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options
|
||||
*
|
||||
* @param string $exportType Selected Export Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptionsOutput($exportType)
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
$hasAliases = isset($_SESSION['tmpval']['aliases'])
|
||||
&& !Core::emptyRecursive($_SESSION['tmpval']['aliases']);
|
||||
unset($_SESSION['tmpval']['aliases']);
|
||||
|
||||
$isCheckedLockTables = $this->checkboxCheck('lock_tables');
|
||||
$isCheckedAsfile = $this->checkboxCheck('asfile');
|
||||
|
||||
$optionsOutputSaveDir = '';
|
||||
if (isset($cfg['SaveDir']) && !empty($cfg['SaveDir'])) {
|
||||
$optionsOutputSaveDir = $this->getHtmlForOptionsOutputSaveDir();
|
||||
}
|
||||
$optionsOutputFormat = $this->getHtmlForOptionsOutputFormat($exportType);
|
||||
$optionsOutputCharset = '';
|
||||
if (Encoding::isSupported()) {
|
||||
$optionsOutputCharset = $this->getHtmlForOptionsOutputCharset();
|
||||
}
|
||||
$optionsOutputCompression = $this->getHtmlForOptionsOutputCompression();
|
||||
$optionsOutputSeparateFiles = '';
|
||||
if ($exportType == 'server' || $exportType == 'database') {
|
||||
$optionsOutputSeparateFiles = $this->getHtmlForOptionsOutputSeparateFiles(
|
||||
$exportType
|
||||
);
|
||||
}
|
||||
$optionsOutputRadio = $this->getHtmlForOptionsOutputRadio();
|
||||
|
||||
return Template::get('display/export/options_output')->render([
|
||||
'has_aliases' => $hasAliases,
|
||||
'export_type' => $exportType,
|
||||
'is_checked_lock_tables' => $isCheckedLockTables,
|
||||
'is_checked_asfile' => $isCheckedAsfile,
|
||||
'repopulate' => isset($_POST['repopulate']),
|
||||
'lock_tables' => isset($_POST['lock_tables']),
|
||||
'save_dir' => isset($cfg['SaveDir']) ? $cfg['SaveDir'] : null,
|
||||
'is_encoding_supported' => Encoding::isSupported(),
|
||||
'options_output_save_dir' => $optionsOutputSaveDir,
|
||||
'options_output_format' => $optionsOutputFormat,
|
||||
'options_output_charset' => $optionsOutputCharset,
|
||||
'options_output_compression' => $optionsOutputCompression,
|
||||
'options_output_separate_files' => $optionsOutputSeparateFiles,
|
||||
'options_output_radio' => $optionsOutputRadio,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Export Options
|
||||
*
|
||||
* @param string $exportType Selected Export Type
|
||||
* @param string $db Selected DB
|
||||
* @param string $table Selected Table
|
||||
* @param string $multiValues Export selection
|
||||
* @param string $numTables number of tables
|
||||
* @param ExportPlugin[] $exportList Export List
|
||||
* @param string $unlimNumRows Number of Rows
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHtmlForOptions(
|
||||
$exportType,
|
||||
$db,
|
||||
$table,
|
||||
$multiValues,
|
||||
$numTables,
|
||||
$exportList,
|
||||
$unlimNumRows
|
||||
) {
|
||||
global $cfg;
|
||||
$html = $this->getHtmlForOptionsMethod();
|
||||
$html .= $this->getHtmlForOptionsFormatDropdown($exportList);
|
||||
$html .= $this->getHtmlForOptionsSelection($exportType, $multiValues);
|
||||
|
||||
$tableObject = new Table($table, $db);
|
||||
if (strlen($table) > 0 && empty($numTables) && ! $tableObject->isMerge()) {
|
||||
$html .= $this->getHtmlForOptionsRows($db, $table, $unlimNumRows);
|
||||
}
|
||||
|
||||
if (isset($cfg['SaveDir']) && !empty($cfg['SaveDir'])) {
|
||||
$html .= $this->getHtmlForOptionsQuickExport();
|
||||
}
|
||||
|
||||
$html .= $this->getHtmlForAliasModalDialog();
|
||||
$html .= $this->getHtmlForOptionsOutput($exportType);
|
||||
$html .= $this->getHtmlForOptionsFormat($exportList);
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Html For currently defined aliases
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForCurrentAlias()
|
||||
{
|
||||
$result = '<table id="alias_data"><thead><tr><th colspan="4">'
|
||||
. __('Defined aliases')
|
||||
. '</th></tr></thead><tbody>';
|
||||
|
||||
$template = Template::get('export/alias_item');
|
||||
if (isset($_SESSION['tmpval']['aliases'])) {
|
||||
foreach ($_SESSION['tmpval']['aliases'] as $db => $dbData) {
|
||||
if (isset($dbData['alias'])) {
|
||||
$result .= $template->render(array(
|
||||
'type' => _pgettext('Alias', 'Database'),
|
||||
'name' => $db,
|
||||
'field' => 'aliases[' . $db . '][alias]',
|
||||
'value' => $dbData['alias'],
|
||||
));
|
||||
}
|
||||
if (! isset($dbData['tables'])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($dbData['tables'] as $table => $tableData) {
|
||||
if (isset($tableData['alias'])) {
|
||||
$result .= $template->render(array(
|
||||
'type' => _pgettext('Alias', 'Table'),
|
||||
'name' => $db . '.' . $table,
|
||||
'field' => 'aliases[' . $db . '][tables][' . $table . '][alias]',
|
||||
'value' => $tableData['alias'],
|
||||
));
|
||||
}
|
||||
if (! isset($tableData['columns'])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($tableData['columns'] as $column => $columnName) {
|
||||
$result .= $template->render(array(
|
||||
'type' => _pgettext('Alias', 'Column'),
|
||||
'name' => $db . '.' . $table . '.'. $column,
|
||||
'field' => 'aliases[' . $db . '][tables][' . $table . '][colums][' . $column . ']',
|
||||
'value' => $columnName,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Empty row for javascript manipulations
|
||||
$result .= '</tbody><tfoot class="hide">' . $template->render(array(
|
||||
'type' => '', 'name' => '', 'field' => 'aliases_new', 'value' => ''
|
||||
)) . '</tfoot>';
|
||||
|
||||
return $result . '</table>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Html For Alias Modal Dialog
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHtmlForAliasModalDialog()
|
||||
{
|
||||
$title = __('Rename exported databases/tables/columns');
|
||||
|
||||
$html = '<div id="alias_modal" class="hide" title="' . $title . '">';
|
||||
$html .= $this->getHtmlForCurrentAlias();
|
||||
$html .= Template::get('export/alias_add')->render();
|
||||
|
||||
$html .= '</div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets HTML to display export dialogs
|
||||
*
|
||||
* @param string $exportType export type: server|database|table
|
||||
* @param string $db selected DB
|
||||
* @param string $table selected table
|
||||
* @param string $sqlQuery SQL query
|
||||
* @param int $numTables number of tables
|
||||
* @param int $unlimNumRows unlimited number of rows
|
||||
* @param string $multiValues selector options
|
||||
*
|
||||
* @return string $html
|
||||
*/
|
||||
public function getDisplay(
|
||||
$exportType,
|
||||
$db,
|
||||
$table,
|
||||
$sqlQuery,
|
||||
$numTables,
|
||||
$unlimNumRows,
|
||||
$multiValues
|
||||
) {
|
||||
$cfgRelation = $this->relation->getRelationsParam();
|
||||
|
||||
if (isset($_POST['single_table'])) {
|
||||
$GLOBALS['single_table'] = $_POST['single_table'];
|
||||
}
|
||||
|
||||
// Export a single table
|
||||
if (isset($_GET['single_table'])) {
|
||||
$GLOBALS['single_table'] = $_GET['single_table'];
|
||||
}
|
||||
|
||||
/* Scan for plugins */
|
||||
/* @var $exportList ExportPlugin[] */
|
||||
$exportList = Plugins::getPlugins(
|
||||
"export",
|
||||
'libraries/classes/Plugins/Export/',
|
||||
array(
|
||||
'export_type' => $exportType,
|
||||
'single_table' => isset($GLOBALS['single_table'])
|
||||
)
|
||||
);
|
||||
|
||||
/* Fail if we didn't find any plugin */
|
||||
if (empty($exportList)) {
|
||||
Message::error(
|
||||
__('Could not load export plugins, please check your installation!')
|
||||
)->display();
|
||||
exit;
|
||||
}
|
||||
|
||||
$html = Template::get('display/export/option_header')->render([
|
||||
'export_type' => $exportType,
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
]);
|
||||
|
||||
if ($cfgRelation['exporttemplateswork']) {
|
||||
$html .= Template::get('display/export/template_loading')->render([
|
||||
'options' => $this->getOptionsForTemplates($exportType),
|
||||
]);
|
||||
}
|
||||
|
||||
$html .= '<form method="post" action="export.php" '
|
||||
. ' name="dump" class="disableAjax">';
|
||||
|
||||
//output Hidden Inputs
|
||||
$singleTableStr = isset($GLOBALS['single_table']) ? $GLOBALS['single_table']
|
||||
: '';
|
||||
$html .= $this->getHtmlForHiddenInputs(
|
||||
$exportType,
|
||||
$db,
|
||||
$table,
|
||||
$singleTableStr,
|
||||
$sqlQuery
|
||||
);
|
||||
|
||||
//output Export Options
|
||||
$html .= $this->getHtmlForOptions(
|
||||
$exportType,
|
||||
$db,
|
||||
$table,
|
||||
$multiValues,
|
||||
$numTables,
|
||||
$exportList,
|
||||
$unlimNumRows
|
||||
);
|
||||
|
||||
$html .= '</form>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles export template actions
|
||||
*
|
||||
* @param array $cfgRelation Relation configuration
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handleTemplateActions(array $cfgRelation)
|
||||
{
|
||||
if (isset($_POST['templateId'])) {
|
||||
$id = $GLOBALS['dbi']->escapeString($_POST['templateId']);
|
||||
} else {
|
||||
$id = '';
|
||||
}
|
||||
|
||||
$templateTable = Util::backquote($cfgRelation['db']) . '.'
|
||||
. Util::backquote($cfgRelation['export_templates']);
|
||||
$user = $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user']);
|
||||
|
||||
switch ($_POST['templateAction']) {
|
||||
case 'create':
|
||||
$query = "INSERT INTO " . $templateTable . "("
|
||||
. " `username`, `export_type`,"
|
||||
. " `template_name`, `template_data`"
|
||||
. ") VALUES ("
|
||||
. "'" . $user . "', "
|
||||
. "'" . $GLOBALS['dbi']->escapeString($_POST['exportType'])
|
||||
. "', '" . $GLOBALS['dbi']->escapeString($_POST['templateName'])
|
||||
. "', '" . $GLOBALS['dbi']->escapeString($_POST['templateData'])
|
||||
. "');";
|
||||
break;
|
||||
case 'load':
|
||||
$query = "SELECT `template_data` FROM " . $templateTable
|
||||
. " WHERE `id` = " . $id . " AND `username` = '" . $user . "'";
|
||||
break;
|
||||
case 'update':
|
||||
$query = "UPDATE " . $templateTable . " SET `template_data` = "
|
||||
. "'" . $GLOBALS['dbi']->escapeString($_POST['templateData']) . "'"
|
||||
. " WHERE `id` = " . $id . " AND `username` = '" . $user . "'";
|
||||
break;
|
||||
case 'delete':
|
||||
$query = "DELETE FROM " . $templateTable
|
||||
. " WHERE `id` = " . $id . " AND `username` = '" . $user . "'";
|
||||
break;
|
||||
default:
|
||||
$query = '';
|
||||
break;
|
||||
}
|
||||
|
||||
$result = $this->relation->queryAsControlUser($query, false);
|
||||
|
||||
$response = Response::getInstance();
|
||||
if (! $result) {
|
||||
$error = $GLOBALS['dbi']->getError(DatabaseInterface::CONNECT_CONTROL);
|
||||
$response->setRequestStatus(false);
|
||||
$response->addJSON('message', $error);
|
||||
exit;
|
||||
}
|
||||
|
||||
$response->setRequestStatus(true);
|
||||
if ('create' == $_POST['templateAction']) {
|
||||
$response->addJSON(
|
||||
'data',
|
||||
$this->getOptionsForTemplates($_POST['exportType'])
|
||||
);
|
||||
} elseif ('load' == $_POST['templateAction']) {
|
||||
$data = null;
|
||||
while ($row = $GLOBALS['dbi']->fetchAssoc(
|
||||
$result, DatabaseInterface::CONNECT_CONTROL
|
||||
)) {
|
||||
$data = $row['template_data'];
|
||||
}
|
||||
$response->addJSON('data', $data);
|
||||
}
|
||||
$GLOBALS['dbi']->freeResult($result);
|
||||
}
|
||||
}
|
||||
103
phpMyAdmin/libraries/classes/Display/GitRevision.php
Executable file
103
phpMyAdmin/libraries/classes/Display/GitRevision.php
Executable file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Displays git revision
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Display;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Response;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* PhpMyAdmin\Display\GitRevision class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class GitRevision
|
||||
{
|
||||
/**
|
||||
* Prints details about the current Git commit revision
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function display()
|
||||
{
|
||||
|
||||
// load revision data from repo
|
||||
$GLOBALS['PMA_Config']->checkGitRevision();
|
||||
|
||||
if (! $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT')) {
|
||||
$response = Response::getInstance();
|
||||
$response->setRequestStatus(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// if using a remote commit fast-forwarded, link to GitHub
|
||||
$commit_hash = substr(
|
||||
$GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_COMMITHASH'),
|
||||
0,
|
||||
7
|
||||
);
|
||||
$commit_hash = '<strong title="'
|
||||
. htmlspecialchars($GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_MESSAGE'))
|
||||
. '">' . htmlspecialchars($commit_hash) . '</strong>';
|
||||
if ($GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_ISREMOTECOMMIT')) {
|
||||
$commit_hash = '<a href="'
|
||||
. Core::linkURL(
|
||||
'https://github.com/phpmyadmin/phpmyadmin/commit/'
|
||||
. htmlspecialchars($GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_COMMITHASH'))
|
||||
)
|
||||
. '" rel="noopener noreferrer" target="_blank">' . $commit_hash . '</a>';
|
||||
}
|
||||
|
||||
$branch = $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_BRANCH');
|
||||
$isRemoteBranch = $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_ISREMOTEBRANCH');
|
||||
if ($isRemoteBranch) {
|
||||
$branch = '<a href="'
|
||||
. Core::linkURL(
|
||||
'https://github.com/phpmyadmin/phpmyadmin/tree/'
|
||||
. $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_BRANCH')
|
||||
)
|
||||
. '" rel="noopener noreferrer" target="_blank">' . htmlspecialchars($branch) . '</a>';
|
||||
}
|
||||
if ($branch !== false) {
|
||||
$branch = sprintf(
|
||||
__('%1$s from %2$s branch'),
|
||||
$commit_hash,
|
||||
$isRemoteBranch ? $branch : htmlspecialchars($branch)
|
||||
);
|
||||
} else {
|
||||
$branch = $commit_hash . ' (' . __('no branch') . ')';
|
||||
}
|
||||
|
||||
$committer = $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_COMMITTER');
|
||||
$author = $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_AUTHOR');
|
||||
Core::printListItem(
|
||||
__('Git revision:') . ' '
|
||||
. $branch . ',<br /> '
|
||||
. sprintf(
|
||||
__('committed on %1$s by %2$s'),
|
||||
Util::localisedDate(strtotime($committer['date'])),
|
||||
'<a href="' . Core::linkURL(
|
||||
'mailto:' . htmlspecialchars($committer['email'])
|
||||
) . '">'
|
||||
. htmlspecialchars($committer['name']) . '</a>'
|
||||
)
|
||||
. ($author != $committer
|
||||
? ', <br />'
|
||||
. sprintf(
|
||||
__('authored on %1$s by %2$s'),
|
||||
Util::localisedDate(strtotime($author['date'])),
|
||||
'<a href="' . Core::linkURL(
|
||||
'mailto:' . htmlspecialchars($author['email'])
|
||||
) . '">'
|
||||
. htmlspecialchars($author['name']) . '</a>'
|
||||
)
|
||||
: ''),
|
||||
'li_pma_version_git', null, null, null
|
||||
);
|
||||
}
|
||||
}
|
||||
111
phpMyAdmin/libraries/classes/Display/Import.php
Executable file
111
phpMyAdmin/libraries/classes/Display/Import.php
Executable file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* functions for displaying import for: server, database and table
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Display;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Display\ImportAjax;
|
||||
use PhpMyAdmin\Encoding;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
/**
|
||||
* PhpMyAdmin\Display\Import class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class Import
|
||||
{
|
||||
/**
|
||||
* Gets HTML to display import dialogs
|
||||
*
|
||||
* @param string $importType Import type: server|database|table
|
||||
* @param string $db Selected DB
|
||||
* @param string $table Selected Table
|
||||
* @param int $maxUploadSize Max upload size
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
public static function get($importType, $db, $table, $maxUploadSize)
|
||||
{
|
||||
global $cfg;
|
||||
global $SESSION_KEY;
|
||||
|
||||
list(
|
||||
$SESSION_KEY,
|
||||
$uploadId,
|
||||
) = ImportAjax::uploadProgressSetup();
|
||||
|
||||
/* Scan for plugins */
|
||||
/* @var $importList \PhpMyAdmin\Plugins\ImportPlugin[] */
|
||||
$importList = Plugins::getPlugins(
|
||||
"import",
|
||||
'libraries/classes/Plugins/Import/',
|
||||
$importType
|
||||
);
|
||||
|
||||
/* Fail if we didn't find any plugin */
|
||||
if (empty($importList)) {
|
||||
Message::error(
|
||||
__(
|
||||
'Could not load import plugins, please check your installation!'
|
||||
)
|
||||
)->display();
|
||||
exit;
|
||||
}
|
||||
|
||||
if (Core::isValid($_REQUEST['offset'], 'numeric')) {
|
||||
$offset = intval($_REQUEST['offset']);
|
||||
}
|
||||
if (isset($_REQUEST['timeout_passed'])) {
|
||||
$timeoutPassed = $_REQUEST['timeout_passed'];
|
||||
}
|
||||
|
||||
$localImportFile = '';
|
||||
if (isset($_REQUEST['local_import_file'])) {
|
||||
$localImportFile = $_REQUEST['local_import_file'];
|
||||
}
|
||||
|
||||
// zip, gzip and bzip2 encode features
|
||||
$compressions = array();
|
||||
if ($cfg['GZipDump'] && function_exists('gzopen')) {
|
||||
$compressions[] = 'gzip';
|
||||
}
|
||||
if ($cfg['BZipDump'] && function_exists('bzopen')) {
|
||||
$compressions[] = 'bzip2';
|
||||
}
|
||||
if ($cfg['ZipDump'] && function_exists('zip_open')) {
|
||||
$compressions[] = 'zip';
|
||||
}
|
||||
|
||||
return Template::get('display/import/import')->render([
|
||||
'upload_id' => $uploadId,
|
||||
'handler' => $_SESSION[$SESSION_KEY]["handler"],
|
||||
'id_key' => $_SESSION[$SESSION_KEY]['handler']::getIdKey(),
|
||||
'pma_theme_image' => $GLOBALS['pmaThemeImage'],
|
||||
'import_type' => $importType,
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
'max_upload_size' => $maxUploadSize,
|
||||
'import_list' => $importList,
|
||||
'local_import_file' => $localImportFile,
|
||||
'is_upload' => $GLOBALS['is_upload'],
|
||||
'upload_dir' => isset($cfg['UploadDir']) ? $cfg['UploadDir'] : null,
|
||||
'timeout_passed_global' => isset($GLOBALS['timeout_passed']) ? $GLOBALS['timeout_passed'] : null,
|
||||
'compressions' => $compressions,
|
||||
'is_encoding_supported' => Encoding::isSupported(),
|
||||
'encodings' => Encoding::listEncodings(),
|
||||
'import_charset' => isset($cfg['Import']['charset']) ? $cfg['Import']['charset'] : null,
|
||||
'dbi' => $GLOBALS['dbi'],
|
||||
'disable_is' => $cfg['Server']['DisableIS'],
|
||||
'timeout_passed' => isset($timeoutPassed) ? $timeoutPassed : null,
|
||||
'offset' => isset($offset) ? $offset : null,
|
||||
'can_convert_kanji' => Encoding::canConvertKanji(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
134
phpMyAdmin/libraries/classes/Display/ImportAjax.php
Executable file
134
phpMyAdmin/libraries/classes/Display/ImportAjax.php
Executable file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Handles plugins that show the upload progress
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin\Display;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
|
||||
/**
|
||||
* PhpMyAdmin\Display\ImportAjax class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class ImportAjax
|
||||
{
|
||||
/**
|
||||
* Sets up some variables for upload progress
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function uploadProgressSetup()
|
||||
{
|
||||
/**
|
||||
* constant for differentiating array in $_SESSION variable
|
||||
*/
|
||||
$SESSION_KEY = '__upload_status';
|
||||
|
||||
/**
|
||||
* sets default plugin for handling the import process
|
||||
*/
|
||||
$_SESSION[$SESSION_KEY]["handler"] = "";
|
||||
|
||||
/**
|
||||
* unique ID for each upload
|
||||
*/
|
||||
$upload_id = uniqid("");
|
||||
|
||||
/**
|
||||
* list of available plugins
|
||||
*/
|
||||
$plugins = array(
|
||||
// PHP 5.4 session-based upload progress is problematic, see bug 3964
|
||||
//"session",
|
||||
"progress",
|
||||
"apc",
|
||||
"noplugin"
|
||||
);
|
||||
|
||||
// select available plugin
|
||||
foreach ($plugins as $plugin) {
|
||||
$check = $plugin . "Check";
|
||||
|
||||
if (self::$check()) {
|
||||
$upload_class = 'PhpMyAdmin\Plugins\Import\Upload\Upload' . ucwords(
|
||||
$plugin
|
||||
);
|
||||
$_SESSION[$SESSION_KEY]["handler"] = $upload_class;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return array($SESSION_KEY, $upload_id, $plugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if APC bar extension is available and configured correctly.
|
||||
*
|
||||
* @return boolean true if APC extension is available and if rfc1867 is enabled,
|
||||
* false if it is not
|
||||
*/
|
||||
public static function apcCheck()
|
||||
{
|
||||
if (! extension_loaded('apc')
|
||||
|| ! function_exists('apc_fetch')
|
||||
|| ! function_exists('getallheaders')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return (ini_get('apc.enabled') && ini_get('apc.rfc1867'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if PhpMyAdmin\Plugins\Import\Upload\UploadProgress bar extension is
|
||||
* available.
|
||||
*
|
||||
* @return boolean true if PhpMyAdmin\Plugins\Import\Upload\UploadProgress
|
||||
* extension is available, false if it is not
|
||||
*/
|
||||
public static function progressCheck()
|
||||
{
|
||||
return function_exists("uploadprogress_get_info")
|
||||
&& function_exists('getallheaders');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if PHP 5.4 session upload-progress feature is available.
|
||||
*
|
||||
* @return boolean true if PHP 5.4 session upload-progress is available,
|
||||
* false if it is not
|
||||
*/
|
||||
public static function sessionCheck()
|
||||
{
|
||||
return ini_get('session.upload_progress.enabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* Default plugin for handling import.
|
||||
* If no other plugin is available, noplugin is used.
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
public static function nopluginCheck()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function outputs json encoded status of uploaded.
|
||||
* It uses PMA_getUploadStatus, which is defined in plugin's file.
|
||||
*
|
||||
* @param string $id ID of transfer, usually $upload_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function status($id)
|
||||
{
|
||||
Core::headerJSON();
|
||||
echo json_encode(
|
||||
$_SESSION[$GLOBALS['SESSION_KEY']]['handler']::getUploadStatus($id)
|
||||
);
|
||||
}
|
||||
}
|
||||
5687
phpMyAdmin/libraries/classes/Display/Results.php
Executable file
5687
phpMyAdmin/libraries/classes/Display/Results.php
Executable file
File diff suppressed because it is too large
Load Diff
334
phpMyAdmin/libraries/classes/Encoding.php
Executable file
334
phpMyAdmin/libraries/classes/Encoding.php
Executable file
@@ -0,0 +1,334 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Hold the PhpMyAdmin\Encoding class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
/**
|
||||
* Encoding conversion helper class
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
class Encoding
|
||||
{
|
||||
/**
|
||||
* None encoding conversion engine
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
|
||||
const ENGINE_NONE = 0;
|
||||
/**
|
||||
* iconv encoding conversion engine
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const ENGINE_ICONV = 1;
|
||||
|
||||
/**
|
||||
* recode encoding conversion engine
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const ENGINE_RECODE = 2;
|
||||
|
||||
/**
|
||||
* mbstring encoding conversion engine
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const ENGINE_MB = 3;
|
||||
|
||||
/**
|
||||
* Chosen encoding engine
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $_engine = null;
|
||||
|
||||
/**
|
||||
* Map of conversion engine configurations
|
||||
*
|
||||
* Each entry contains:
|
||||
*
|
||||
* - function to detect
|
||||
* - engine contant
|
||||
* - extension name to warn when missing
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $_enginemap = array(
|
||||
'iconv' => array('iconv', self::ENGINE_ICONV, 'iconv'),
|
||||
'recode' => array('recode_string', self::ENGINE_RECODE, 'recode'),
|
||||
'mb' => array('mb_convert_encoding', self::ENGINE_MB, 'mbstring'),
|
||||
'none' => array('isset', self::ENGINE_NONE, ''),
|
||||
);
|
||||
|
||||
/**
|
||||
* Order of automatic detection of engines
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $_engineorder = array(
|
||||
'iconv', 'mb', 'recode',
|
||||
);
|
||||
|
||||
/**
|
||||
* Kanji encodings list
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $_kanji_encodings = 'ASCII,SJIS,EUC-JP,JIS';
|
||||
|
||||
/**
|
||||
* Initializes encoding engine detecting available backends.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function initEngine()
|
||||
{
|
||||
$engine = 'auto';
|
||||
if (isset($GLOBALS['cfg']['RecodingEngine'])) {
|
||||
$engine = $GLOBALS['cfg']['RecodingEngine'];
|
||||
}
|
||||
|
||||
/* Use user configuration */
|
||||
if (isset(self::$_enginemap[$engine])) {
|
||||
if (function_exists(self::$_enginemap[$engine][0])) {
|
||||
self::$_engine = self::$_enginemap[$engine][1];
|
||||
return;
|
||||
} else {
|
||||
Core::warnMissingExtension(self::$_enginemap[$engine][2]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Autodetection */
|
||||
foreach (self::$_engineorder as $engine) {
|
||||
if (function_exists(self::$_enginemap[$engine][0])) {
|
||||
self::$_engine = self::$_enginemap[$engine][1];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback to none conversion */
|
||||
self::$_engine = self::ENGINE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for engine. Use with caution, mostly useful for testing.
|
||||
*
|
||||
* @param int $engine Engine enconding
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setEngine($engine)
|
||||
{
|
||||
self::$_engine = $engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether there is any charset conversion supported
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
if (is_null(self::$_engine)) {
|
||||
self::initEngine();
|
||||
}
|
||||
return self::$_engine != self::ENGINE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts encoding of text according to parameters with detected
|
||||
* conversion function.
|
||||
*
|
||||
* @param string $src_charset source charset
|
||||
* @param string $dest_charset target charset
|
||||
* @param string $what what to convert
|
||||
*
|
||||
* @return string converted text
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function convertString($src_charset, $dest_charset, $what)
|
||||
{
|
||||
if ($src_charset == $dest_charset) {
|
||||
return $what;
|
||||
}
|
||||
if (is_null(self::$_engine)) {
|
||||
self::initEngine();
|
||||
}
|
||||
switch (self::$_engine) {
|
||||
case self::ENGINE_RECODE:
|
||||
return recode_string(
|
||||
$src_charset . '..' . $dest_charset,
|
||||
$what
|
||||
);
|
||||
case self::ENGINE_ICONV:
|
||||
return iconv(
|
||||
$src_charset,
|
||||
$dest_charset .
|
||||
(isset($GLOBALS['cfg']['IconvExtraParams']) ? $GLOBALS['cfg']['IconvExtraParams'] : ''),
|
||||
$what
|
||||
);
|
||||
case self::ENGINE_MB:
|
||||
return mb_convert_encoding(
|
||||
$what,
|
||||
$dest_charset,
|
||||
$src_charset
|
||||
);
|
||||
default:
|
||||
return $what;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects whether Kanji encoding is available
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function canConvertKanji()
|
||||
{
|
||||
return $GLOBALS['lang'] == 'ja';
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for Kanji encodings. Use with caution, mostly useful for testing.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getKanjiEncodings()
|
||||
{
|
||||
return self::$_kanji_encodings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for Kanji encodings. Use with caution, mostly useful for testing.
|
||||
*
|
||||
* @param string $value Kanji encodings list
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setKanjiEncodings($value)
|
||||
{
|
||||
self::$_kanji_encodings = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses SJIS & EUC-JP position in the encoding codes list
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function kanjiChangeOrder()
|
||||
{
|
||||
$parts = explode(',', self::$_kanji_encodings);
|
||||
if ($parts[1] == 'EUC-JP') {
|
||||
self::$_kanji_encodings = 'ASCII,SJIS,EUC-JP,JIS';
|
||||
} else {
|
||||
self::$_kanji_encodings = 'ASCII,EUC-JP,SJIS,JIS';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kanji string encoding convert
|
||||
*
|
||||
* @param string $str the string to convert
|
||||
* @param string $enc the destination encoding code
|
||||
* @param string $kana set 'kana' convert to JIS-X208-kana
|
||||
*
|
||||
* @return string the converted string
|
||||
*/
|
||||
public static function kanjiStrConv($str, $enc, $kana)
|
||||
{
|
||||
if ($enc == '' && $kana == '') {
|
||||
return $str;
|
||||
}
|
||||
|
||||
$string_encoding = mb_detect_encoding($str, self::$_kanji_encodings);
|
||||
if ($string_encoding === false) {
|
||||
$string_encoding = 'utf-8';
|
||||
}
|
||||
|
||||
if ($kana == 'kana') {
|
||||
$dist = mb_convert_kana($str, 'KV', $string_encoding);
|
||||
$str = $dist;
|
||||
}
|
||||
if ($string_encoding != $enc && $enc != '') {
|
||||
$dist = mb_convert_encoding($str, $enc, $string_encoding);
|
||||
} else {
|
||||
$dist = $str;
|
||||
}
|
||||
return $dist;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Kanji file encoding convert
|
||||
*
|
||||
* @param string $file the name of the file to convert
|
||||
* @param string $enc the destination encoding code
|
||||
* @param string $kana set 'kana' convert to JIS-X208-kana
|
||||
*
|
||||
* @return string the name of the converted file
|
||||
*/
|
||||
public static function kanjiFileConv($file, $enc, $kana)
|
||||
{
|
||||
if ($enc == '' && $kana == '') {
|
||||
return $file;
|
||||
}
|
||||
$tmpfname = tempnam($GLOBALS['PMA_Config']->getUploadTempDir(), $enc);
|
||||
$fpd = fopen($tmpfname, 'wb');
|
||||
$fps = fopen($file, 'r');
|
||||
self::kanjiChangeOrder();
|
||||
while (!feof($fps)) {
|
||||
$line = fgets($fps, 4096);
|
||||
$dist = self::kanjiStrConv($line, $enc, $kana);
|
||||
fputs($fpd, $dist);
|
||||
} // end while
|
||||
self::kanjiChangeOrder();
|
||||
fclose($fps);
|
||||
fclose($fpd);
|
||||
unlink($file);
|
||||
|
||||
return $tmpfname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines radio form fields to switch between encoding modes
|
||||
*
|
||||
* @return string xhtml code for the radio controls
|
||||
*/
|
||||
public static function kanjiEncodingForm()
|
||||
{
|
||||
return Template::get('encoding/kanji_encoding_form')->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists available encodings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function listEncodings()
|
||||
{
|
||||
if (is_null(self::$_engine)) {
|
||||
self::initEngine();
|
||||
}
|
||||
/* Most engines do not support listing */
|
||||
if (self::$_engine != self::ENGINE_MB) {
|
||||
return $GLOBALS['cfg']['AvailableCharsets'];
|
||||
}
|
||||
|
||||
return array_intersect(
|
||||
array_map('strtolower', mb_list_encodings()),
|
||||
$GLOBALS['cfg']['AvailableCharsets']
|
||||
);
|
||||
}
|
||||
}
|
||||
75
phpMyAdmin/libraries/classes/Engines/Bdb.php
Executable file
75
phpMyAdmin/libraries/classes/Engines/Bdb.php
Executable file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* The BDB storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
namespace PhpMyAdmin\Engines;
|
||||
|
||||
use PhpMyAdmin\StorageEngine;
|
||||
|
||||
/**
|
||||
* The BDB storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
class Bdb extends StorageEngine
|
||||
{
|
||||
/**
|
||||
* Returns array with variable names related to this storage engine
|
||||
*
|
||||
* @return array variable names
|
||||
*/
|
||||
public function getVariables()
|
||||
{
|
||||
return array(
|
||||
'version_bdb' => array(
|
||||
'title' => __('Version information'),
|
||||
),
|
||||
'bdb_cache_size' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'bdb_home' => array(),
|
||||
'bdb_log_buffer_size' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'bdb_logdir' => array(),
|
||||
'bdb_max_lock' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'bdb_shared_data' => array(),
|
||||
'bdb_tmpdir' => array(),
|
||||
'bdb_data_direct' => array(),
|
||||
'bdb_lock_detect' => array(),
|
||||
'bdb_log_direct' => array(),
|
||||
'bdb_no_recover' => array(),
|
||||
'bdb_no_sync' => array(),
|
||||
'skip_sync_bdb_logs' => array(),
|
||||
'sync_bdb_logs' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pattern to be used in the query for SQL variables
|
||||
* related to this storage engine
|
||||
*
|
||||
* @return string LIKE pattern
|
||||
*/
|
||||
public function getVariablesLikePattern()
|
||||
{
|
||||
return '%bdb%';
|
||||
}
|
||||
|
||||
/**
|
||||
* returns string with filename for the MySQL helppage
|
||||
* about this storage engine
|
||||
*
|
||||
* @return string mysql helppage filename
|
||||
*/
|
||||
public function getMysqlHelpPage()
|
||||
{
|
||||
return 'bdb';
|
||||
}
|
||||
}
|
||||
|
||||
18
phpMyAdmin/libraries/classes/Engines/Berkeleydb.php
Executable file
18
phpMyAdmin/libraries/classes/Engines/Berkeleydb.php
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* The BerkeleyDB storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
namespace PhpMyAdmin\Engines;
|
||||
|
||||
/**
|
||||
* This is same as BDB
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
class Berkeleydb extends Bdb
|
||||
{
|
||||
}
|
||||
|
||||
30
phpMyAdmin/libraries/classes/Engines/Binlog.php
Executable file
30
phpMyAdmin/libraries/classes/Engines/Binlog.php
Executable file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* The binary log storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
namespace PhpMyAdmin\Engines;
|
||||
|
||||
use PhpMyAdmin\StorageEngine;
|
||||
|
||||
/**
|
||||
* The binary log storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
class Binlog extends StorageEngine
|
||||
{
|
||||
/**
|
||||
* Returns string with filename for the MySQL helppage
|
||||
* about this storage engine
|
||||
*
|
||||
* @return string mysql helppage filename
|
||||
*/
|
||||
public function getMysqlHelpPage()
|
||||
{
|
||||
return 'binary-log';
|
||||
}
|
||||
}
|
||||
|
||||
17
phpMyAdmin/libraries/classes/Engines/Innobase.php
Executable file
17
phpMyAdmin/libraries/classes/Engines/Innobase.php
Executable file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* The Innobase storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
namespace PhpMyAdmin\Engines;
|
||||
|
||||
/**
|
||||
* The Innobase storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
class Innobase extends Innodb
|
||||
{
|
||||
}
|
||||
395
phpMyAdmin/libraries/classes/Engines/Innodb.php
Executable file
395
phpMyAdmin/libraries/classes/Engines/Innodb.php
Executable file
@@ -0,0 +1,395 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* The InnoDB storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
namespace PhpMyAdmin\Engines;
|
||||
|
||||
use PhpMyAdmin\StorageEngine;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* The InnoDB storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
class Innodb extends StorageEngine
|
||||
{
|
||||
/**
|
||||
* Returns array with variable names related to InnoDB storage engine
|
||||
*
|
||||
* @return array variable names
|
||||
*/
|
||||
public function getVariables()
|
||||
{
|
||||
return array(
|
||||
'innodb_data_home_dir' => array(
|
||||
'title' => __('Data home directory'),
|
||||
'desc' => __(
|
||||
'The common part of the directory path for all InnoDB data '
|
||||
. 'files.'
|
||||
),
|
||||
),
|
||||
'innodb_data_file_path' => array(
|
||||
'title' => __('Data files'),
|
||||
),
|
||||
'innodb_autoextend_increment' => array(
|
||||
'title' => __('Autoextend increment'),
|
||||
'desc' => __(
|
||||
'The increment size for extending the size of an autoextending '
|
||||
. 'tablespace when it becomes full.'
|
||||
),
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'innodb_buffer_pool_size' => array(
|
||||
'title' => __('Buffer pool size'),
|
||||
'desc' => __(
|
||||
'The size of the memory buffer InnoDB uses to cache data and '
|
||||
. 'indexes of its tables.'
|
||||
),
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'innodb_additional_mem_pool_size' => array(
|
||||
'title' => 'innodb_additional_mem_pool_size',
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'innodb_buffer_pool_awe_mem_mb' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'innodb_checksums' => array(),
|
||||
'innodb_commit_concurrency' => array(),
|
||||
'innodb_concurrency_tickets' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'innodb_doublewrite' => array(),
|
||||
'innodb_fast_shutdown' => array(),
|
||||
'innodb_file_io_threads' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'innodb_file_per_table' => array(),
|
||||
'innodb_flush_log_at_trx_commit' => array(),
|
||||
'innodb_flush_method' => array(),
|
||||
'innodb_force_recovery' => array(),
|
||||
'innodb_lock_wait_timeout' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'innodb_locks_unsafe_for_binlog' => array(),
|
||||
'innodb_log_arch_dir' => array(),
|
||||
'innodb_log_archive' => array(),
|
||||
'innodb_log_buffer_size' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'innodb_log_file_size' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'innodb_log_files_in_group' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'innodb_log_group_home_dir' => array(),
|
||||
'innodb_max_dirty_pages_pct' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'innodb_max_purge_lag' => array(),
|
||||
'innodb_mirrored_log_groups' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'innodb_open_files' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'innodb_support_xa' => array(),
|
||||
'innodb_sync_spin_loops' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'innodb_table_locks' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_BOOLEAN,
|
||||
),
|
||||
'innodb_thread_concurrency' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'innodb_thread_sleep_delay' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pattern to be used in the query for SQL variables
|
||||
* related to InnoDb storage engine
|
||||
*
|
||||
* @return string SQL query LIKE pattern
|
||||
*/
|
||||
public function getVariablesLikePattern()
|
||||
{
|
||||
return 'innodb\\_%';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information pages
|
||||
*
|
||||
* @return array detail pages
|
||||
*/
|
||||
public function getInfoPages()
|
||||
{
|
||||
if ($this->support < PMA_ENGINE_SUPPORT_YES) {
|
||||
return array();
|
||||
}
|
||||
$pages = array();
|
||||
$pages['Bufferpool'] = __('Buffer Pool');
|
||||
$pages['Status'] = __('InnoDB Status');
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns html tables with stats over inno db buffer pool
|
||||
*
|
||||
* @return string html table with stats
|
||||
*/
|
||||
public function getPageBufferpool()
|
||||
{
|
||||
// The following query is only possible because we know
|
||||
// that we are on MySQL 5 here (checked above)!
|
||||
// side note: I love MySQL 5 for this. :-)
|
||||
$sql
|
||||
= '
|
||||
SHOW STATUS
|
||||
WHERE Variable_name LIKE \'Innodb\\_buffer\\_pool\\_%\'
|
||||
OR Variable_name = \'Innodb_page_size\';';
|
||||
$status = $GLOBALS['dbi']->fetchResult($sql, 0, 1);
|
||||
|
||||
$output = '<table class="data" id="table_innodb_bufferpool_usage">' . "\n"
|
||||
. ' <caption class="tblHeaders">' . "\n"
|
||||
. ' ' . __('Buffer Pool Usage') . "\n"
|
||||
. ' </caption>' . "\n"
|
||||
. ' <tfoot>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th colspan="2">' . "\n"
|
||||
. ' ' . __('Total') . "\n"
|
||||
. ' : '
|
||||
. Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_pages_total'],
|
||||
0
|
||||
)
|
||||
. ' ' . __('pages')
|
||||
. ' / '
|
||||
. join(
|
||||
' ',
|
||||
Util::formatByteDown(
|
||||
$status['Innodb_buffer_pool_pages_total']
|
||||
* $status['Innodb_page_size']
|
||||
)
|
||||
) . "\n"
|
||||
. ' </th>' . "\n"
|
||||
. ' </tr>' . "\n"
|
||||
. ' </tfoot>' . "\n"
|
||||
. ' <tbody>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th>' . __('Free pages') . '</th>' . "\n"
|
||||
. ' <td class="value">'
|
||||
. Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_pages_free'],
|
||||
0
|
||||
)
|
||||
. '</td>' . "\n"
|
||||
. ' </tr>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th>' . __('Dirty pages') . '</th>' . "\n"
|
||||
. ' <td class="value">'
|
||||
. Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_pages_dirty'],
|
||||
0
|
||||
)
|
||||
. '</td>' . "\n"
|
||||
. ' </tr>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th>' . __('Pages containing data') . '</th>' . "\n"
|
||||
. ' <td class="value">'
|
||||
. Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_pages_data'],
|
||||
0
|
||||
) . "\n"
|
||||
. '</td>' . "\n"
|
||||
. ' </tr>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th>' . __('Pages to be flushed') . '</th>' . "\n"
|
||||
. ' <td class="value">'
|
||||
. Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_pages_flushed'],
|
||||
0
|
||||
) . "\n"
|
||||
. '</td>' . "\n"
|
||||
. ' </tr>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th>' . __('Busy pages') . '</th>' . "\n"
|
||||
. ' <td class="value">'
|
||||
. Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_pages_misc'],
|
||||
0
|
||||
) . "\n"
|
||||
. '</td>' . "\n"
|
||||
. ' </tr>';
|
||||
|
||||
// not present at least since MySQL 5.1.40
|
||||
if (isset($status['Innodb_buffer_pool_pages_latched'])) {
|
||||
$output .= ' <tr>'
|
||||
. ' <th>' . __('Latched pages') . '</th>'
|
||||
. ' <td class="value">'
|
||||
. Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_pages_latched'],
|
||||
0
|
||||
)
|
||||
. '</td>'
|
||||
. ' </tr>';
|
||||
}
|
||||
|
||||
$output .= ' </tbody>' . "\n"
|
||||
. '</table>' . "\n\n"
|
||||
. '<table class="data" id="table_innodb_bufferpool_activity">' . "\n"
|
||||
. ' <caption class="tblHeaders">' . "\n"
|
||||
. ' ' . __('Buffer Pool Activity') . "\n"
|
||||
. ' </caption>' . "\n"
|
||||
. ' <tbody>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th>' . __('Read requests') . '</th>' . "\n"
|
||||
. ' <td class="value">'
|
||||
. Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_read_requests'],
|
||||
0
|
||||
) . "\n"
|
||||
. '</td>' . "\n"
|
||||
. ' </tr>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th>' . __('Write requests') . '</th>' . "\n"
|
||||
. ' <td class="value">'
|
||||
. Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_write_requests'],
|
||||
0
|
||||
) . "\n"
|
||||
. '</td>' . "\n"
|
||||
. ' </tr>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th>' . __('Read misses') . '</th>' . "\n"
|
||||
. ' <td class="value">'
|
||||
. Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_reads'],
|
||||
0
|
||||
) . "\n"
|
||||
. '</td>' . "\n"
|
||||
. ' </tr>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th>' . __('Write waits') . '</th>' . "\n"
|
||||
. ' <td class="value">'
|
||||
. Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_wait_free'],
|
||||
0
|
||||
) . "\n"
|
||||
. '</td>' . "\n"
|
||||
. ' </tr>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th>' . __('Read misses in %') . '</th>' . "\n"
|
||||
. ' <td class="value">'
|
||||
. ($status['Innodb_buffer_pool_read_requests'] == 0
|
||||
? '---'
|
||||
: htmlspecialchars(
|
||||
Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_reads'] * 100
|
||||
/ $status['Innodb_buffer_pool_read_requests'],
|
||||
3,
|
||||
2
|
||||
)
|
||||
) . ' %') . "\n"
|
||||
. '</td>' . "\n"
|
||||
. ' </tr>' . "\n"
|
||||
. ' <tr>' . "\n"
|
||||
. ' <th>' . __('Write waits in %') . '</th>' . "\n"
|
||||
. ' <td class="value">'
|
||||
. ($status['Innodb_buffer_pool_write_requests'] == 0
|
||||
? '---'
|
||||
: htmlspecialchars(
|
||||
Util::formatNumber(
|
||||
$status['Innodb_buffer_pool_wait_free'] * 100
|
||||
/ $status['Innodb_buffer_pool_write_requests'],
|
||||
3,
|
||||
2
|
||||
)
|
||||
) . ' %') . "\n"
|
||||
. '</td>' . "\n"
|
||||
. ' </tr>' . "\n"
|
||||
. ' </tbody>' . "\n"
|
||||
. '</table>' . "\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns InnoDB status
|
||||
*
|
||||
* @return string result of SHOW ENGINE INNODB STATUS inside pre tags
|
||||
*/
|
||||
public function getPageStatus()
|
||||
{
|
||||
return '<pre id="pre_innodb_status">' . "\n"
|
||||
. htmlspecialchars(
|
||||
$GLOBALS['dbi']->fetchValue('SHOW ENGINE INNODB STATUS;', 0, 'Status')
|
||||
) . "\n"
|
||||
. '</pre>' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* returns string with filename for the MySQL helppage
|
||||
* about this storage engine
|
||||
*
|
||||
* @return string mysql helppage filename
|
||||
*/
|
||||
public function getMysqlHelpPage()
|
||||
{
|
||||
return 'innodb-storage-engine';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the InnoDB plugin version number
|
||||
*
|
||||
* @return string the version number, or empty if not running as a plugin
|
||||
*/
|
||||
public function getInnodbPluginVersion()
|
||||
{
|
||||
return $GLOBALS['dbi']->fetchValue('SELECT @@innodb_version;');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the InnoDB file format
|
||||
*
|
||||
* (do not confuse this with phpMyAdmin's storage engine plugins!)
|
||||
*
|
||||
* @return string the InnoDB file format
|
||||
*/
|
||||
public function getInnodbFileFormat()
|
||||
{
|
||||
return $GLOBALS['dbi']->fetchValue(
|
||||
"SHOW GLOBAL VARIABLES LIKE 'innodb_file_format';",
|
||||
0,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if this server supports the innodb_file_per_table feature
|
||||
*
|
||||
* (do not confuse this with phpMyAdmin's storage engine plugins!)
|
||||
*
|
||||
* @return boolean whether this feature is supported or not
|
||||
*/
|
||||
public function supportsFilePerTable()
|
||||
{
|
||||
return (
|
||||
$GLOBALS['dbi']->fetchValue(
|
||||
"SHOW GLOBAL VARIABLES LIKE 'innodb_file_per_table';",
|
||||
0,
|
||||
1
|
||||
) == 'ON'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
33
phpMyAdmin/libraries/classes/Engines/Memory.php
Executable file
33
phpMyAdmin/libraries/classes/Engines/Memory.php
Executable file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* The MEMORY (HEAP) storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
namespace PhpMyAdmin\Engines;
|
||||
|
||||
use PhpMyAdmin\StorageEngine;
|
||||
|
||||
/**
|
||||
* The MEMORY (HEAP) storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
class Memory extends StorageEngine
|
||||
{
|
||||
/**
|
||||
* Returns array with variable names dedicated to MEMORY storage engine
|
||||
*
|
||||
* @return array variable names
|
||||
*/
|
||||
public function getVariables()
|
||||
{
|
||||
return array(
|
||||
'max_heap_table_size' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
20
phpMyAdmin/libraries/classes/Engines/Merge.php
Executable file
20
phpMyAdmin/libraries/classes/Engines/Merge.php
Executable file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* The MERGE storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
namespace PhpMyAdmin\Engines;
|
||||
|
||||
use PhpMyAdmin\StorageEngine;
|
||||
|
||||
/**
|
||||
* The MERGE storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
class Merge extends StorageEngine
|
||||
{
|
||||
}
|
||||
|
||||
27
phpMyAdmin/libraries/classes/Engines/MrgMyisam.php
Executable file
27
phpMyAdmin/libraries/classes/Engines/MrgMyisam.php
Executable file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* The MERGE storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
namespace PhpMyAdmin\Engines;
|
||||
|
||||
/**
|
||||
* The MERGE storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
class MrgMyisam extends Merge
|
||||
{
|
||||
/**
|
||||
* returns string with filename for the MySQL helppage
|
||||
* about this storage engine
|
||||
*
|
||||
* @return string mysql helppage filename
|
||||
*/
|
||||
public function getMysqlHelpPage()
|
||||
{
|
||||
return 'merge-storage-engine';
|
||||
}
|
||||
}
|
||||
87
phpMyAdmin/libraries/classes/Engines/Myisam.php
Executable file
87
phpMyAdmin/libraries/classes/Engines/Myisam.php
Executable file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* The MyISAM storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
namespace PhpMyAdmin\Engines;
|
||||
|
||||
use PhpMyAdmin\StorageEngine;
|
||||
|
||||
/**
|
||||
* The MyISAM storage engine
|
||||
*
|
||||
* @package PhpMyAdmin-Engines
|
||||
*/
|
||||
class Myisam extends StorageEngine
|
||||
{
|
||||
/**
|
||||
* Returns array with variable names dedicated to MyISAM storage engine
|
||||
*
|
||||
* @return array variable names
|
||||
*/
|
||||
public function getVariables()
|
||||
{
|
||||
return array(
|
||||
'myisam_data_pointer_size' => array(
|
||||
'title' => __('Data pointer size'),
|
||||
'desc' => __(
|
||||
'The default pointer size in bytes, to be used by CREATE TABLE '
|
||||
. 'for MyISAM tables when no MAX_ROWS option is specified.'
|
||||
),
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'myisam_recover_options' => array(
|
||||
'title' => __('Automatic recovery mode'),
|
||||
'desc' => __(
|
||||
'The mode for automatic recovery of crashed MyISAM tables, as '
|
||||
. 'set via the --myisam-recover server startup option.'
|
||||
),
|
||||
),
|
||||
'myisam_max_sort_file_size' => array(
|
||||
'title' => __('Maximum size for temporary sort files'),
|
||||
'desc' => __(
|
||||
'The maximum size of the temporary file MySQL is allowed to use '
|
||||
. 'while re-creating a MyISAM index (during REPAIR TABLE, ALTER '
|
||||
. 'TABLE, or LOAD DATA INFILE).'
|
||||
),
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'myisam_max_extra_sort_file_size' => array(
|
||||
'title' => __('Maximum size for temporary files on index creation'),
|
||||
'desc' => __(
|
||||
'If the temporary file used for fast MyISAM index creation '
|
||||
. 'would be larger than using the key cache by the amount '
|
||||
. 'specified here, prefer the key cache method.'
|
||||
),
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'myisam_repair_threads' => array(
|
||||
'title' => __('Repair threads'),
|
||||
'desc' => __(
|
||||
'If this value is greater than 1, MyISAM table indexes are '
|
||||
. 'created in parallel (each index in its own thread) during '
|
||||
. 'the repair by sorting process.'
|
||||
),
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_NUMERIC,
|
||||
),
|
||||
'myisam_sort_buffer_size' => array(
|
||||
'title' => __('Sort buffer size'),
|
||||
'desc' => __(
|
||||
'The buffer that is allocated when sorting MyISAM indexes '
|
||||
. 'during a REPAIR TABLE or when creating indexes with CREATE '
|
||||
. 'INDEX or ALTER TABLE.'
|
||||
),
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'myisam_stats_method' => array(),
|
||||
'delay_key_write' => array(),
|
||||
'bulk_insert_buffer_size' => array(
|
||||
'type' => PMA_ENGINE_DETAILS_TYPE_SIZE,
|
||||
),
|
||||
'skip_external_locking' => array(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user