init web ems all
This commit is contained in:
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user