From 96223ca40b0ec13394f4577511d25ce68c5d8fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 13 Sep 2017 13:12:25 -0300 Subject: [PATCH 1/5] Refactor replication functions to static methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- .../Database/DatabaseStructureController.php | 7 +- libraries/classes/Replication.php | 173 +++++++++++++++++ libraries/replication.inc.php | 175 +----------------- libraries/replication_gui.lib.php | 17 +- 4 files changed, 195 insertions(+), 177 deletions(-) create mode 100644 libraries/classes/Replication.php diff --git a/libraries/classes/Controllers/Database/DatabaseStructureController.php b/libraries/classes/Controllers/Database/DatabaseStructureController.php index ea1b0904b6..73a072b69d 100644 --- a/libraries/classes/Controllers/Database/DatabaseStructureController.php +++ b/libraries/classes/Controllers/Database/DatabaseStructureController.php @@ -1,12 +1,10 @@ db == PMA_extractDbOrTable($db_table) + if ($this->db == Replication::extractDbOrTable($db_table) && preg_match( "@^" . - preg_quote(mb_substr(PMA_extractDbOrTable($db_table, 'table'), 0, -1)) . "@", + preg_quote(mb_substr(Replication::extractDbOrTable($db_table, 'table'), 0, -1)) . "@", $truename ) ) { diff --git a/libraries/classes/Replication.php b/libraries/classes/Replication.php new file mode 100644 index 0000000000..627c1f5bc2 --- /dev/null +++ b/libraries/classes/Replication.php @@ -0,0 +1,173 @@ +tryQuery($action . " SLAVE " . $control . ";", $link); + } + + /** + * Changes master for replication slave + * + * @param string $user replication user on master + * @param string $password password for the user + * @param string $host master's hostname or IP + * @param int $port port, where mysql is running + * @param array $pos position of mysql replication, + * array should contain fields File and Position + * @param bool $stop shall we stop slave? + * @param bool $start shall we start slave? + * @param mixed $link mysql link + * + * @return string output of CHANGE MASTER mysql command + */ + public static function slaveChangeMaster($user, $password, $host, $port, + $pos, $stop = true, $start = true, $link = null + ) { + if ($stop) { + self::slaveControl("STOP", null, $link); + } + + $out = $GLOBALS['dbi']->tryQuery( + 'CHANGE MASTER TO ' . + 'MASTER_HOST=\'' . $host . '\',' . + 'MASTER_PORT=' . ($port * 1) . ',' . + 'MASTER_USER=\'' . $user . '\',' . + 'MASTER_PASSWORD=\'' . $password . '\',' . + 'MASTER_LOG_FILE=\'' . $pos["File"] . '\',' . + 'MASTER_LOG_POS=' . $pos["Position"] . ';', $link + ); + + if ($start) { + self::slaveControl("START", null, $link); + } + + return $out; + } + + /** + * This function provides connection to remote mysql server + * + * @param string $user mysql username + * @param string $password password for the user + * @param string $host mysql server's hostname or IP + * @param int $port mysql remote port + * @param string $socket path to unix socket + * + * @return mixed $link mysql link on success + */ + public static function connectToMaster( + $user, $password, $host = null, $port = null, $socket = null + ) { + $server = array(); + $server['user'] = $user; + $server['password'] = $password; + $server["host"] = Core::sanitizeMySQLHost($host); + $server["port"] = $port; + $server["socket"] = $socket; + + // 5th parameter set to true means that it's an auxiliary connection + // and we must not go back to login page if it fails + return $GLOBALS['dbi']->connect(DatabaseInterface::CONNECT_AUXILIARY, $server); + } + + /** + * Fetches position and file of current binary log on master + * + * @param mixed $link mysql link + * + * @return array an array containing File and Position in MySQL replication + * on master server, useful for self::slaveChangeMaster + */ + public static function slaveBinLogMaster($link = null) + { + $data = $GLOBALS['dbi']->fetchResult('SHOW MASTER STATUS', null, null, $link); + $output = array(); + + if (! empty($data)) { + $output["File"] = $data[0]["File"]; + $output["Position"] = $data[0]["Position"]; + } + return $output; + } +} diff --git a/libraries/replication.inc.php b/libraries/replication.inc.php index 76a9c7889d..148accbb08 100644 --- a/libraries/replication.inc.php +++ b/libraries/replication.inc.php @@ -5,14 +5,12 @@ * * @package PhpMyAdmin */ - -use PhpMyAdmin\Core; -use PhpMyAdmin\DatabaseInterface; - if (! defined('PHPMYADMIN')) { exit; } +use PhpMyAdmin\Replication; + /** * get master replication from server */ @@ -130,198 +128,45 @@ foreach ($replication_types as $type) { } if ($GLOBALS['replication_info'][$type]['status']) { if ($type == "master") { - PMA_fillReplicationInfo( + Replication::fillInfo( $type, 'Do_DB', $server_master_replication[0], 'Binlog_Do_DB' ); - PMA_fillReplicationInfo( + Replication::fillInfo( $type, 'Ignore_DB', $server_master_replication[0], 'Binlog_Ignore_DB' ); } elseif ($type == "slave") { - PMA_fillReplicationInfo( + Replication::fillInfo( $type, 'Do_DB', $server_slave_replication[0], 'Replicate_Do_DB' ); - PMA_fillReplicationInfo( + Replication::fillInfo( $type, 'Ignore_DB', $server_slave_replication[0], 'Replicate_Ignore_DB' ); - PMA_fillReplicationInfo( + Replication::fillInfo( $type, 'Do_Table', $server_slave_replication[0], 'Replicate_Do_Table' ); - PMA_fillReplicationInfo( + Replication::fillInfo( $type, 'Ignore_Table', $server_slave_replication[0], 'Replicate_Ignore_Table' ); - PMA_fillReplicationInfo( + Replication::fillInfo( $type, 'Wild_Do_Table', $server_slave_replication[0], 'Replicate_Wild_Do_Table' ); - PMA_fillReplicationInfo( + Replication::fillInfo( $type, 'Wild_Ignore_Table', $server_slave_replication[0], 'Replicate_Wild_Ignore_Table' ); } } } - -/** - * Fill global replication_info variable. - * - * @param string $type Type: master, slave - * @param string $replicationInfoKey Key in replication_info variable - * @param array $mysqlInfo MySQL data about replication - * @param string $mysqlKey MySQL key - * - * @return array - */ -function PMA_fillReplicationInfo( - $type, $replicationInfoKey, $mysqlInfo, $mysqlKey -) { - $GLOBALS['replication_info'][$type][$replicationInfoKey] - = empty($mysqlInfo[$mysqlKey]) - ? array() - : explode( - ",", - $mysqlInfo[$mysqlKey] - ); - - return $GLOBALS['replication_info'][$type][$replicationInfoKey]; -} - -/** - * Extracts database or table name from string - * - * @param string $string contains "dbname.tablename" - * @param string $what what to extract (db|table) - * - * @return string the extracted part - */ -function PMA_extractDbOrTable($string, $what = 'db') -{ - $list = explode(".", $string); - if ('db' == $what) { - return $list[0]; - } else { - return $list[1]; - } -} - -/** - * Configures replication slave - * - * @param string $action possible values: START or STOP - * @param string $control default: null, - * possible values: SQL_THREAD or IO_THREAD or null. - * If it is set to null, it controls both - * SQL_THREAD and IO_THREAD - * @param mixed $link mysql link - * - * @return mixed output of DatabaseInterface::tryQuery - */ -function PMA_Replication_Slave_control($action, $control = null, $link = null) -{ - $action = mb_strtoupper($action); - $control = mb_strtoupper($control); - - if ($action != "START" && $action != "STOP") { - return -1; - } - if ($control != "SQL_THREAD" && $control != "IO_THREAD" && $control != null) { - return -1; - } - - return $GLOBALS['dbi']->tryQuery($action . " SLAVE " . $control . ";", $link); -} - -/** - * Changes master for replication slave - * - * @param string $user replication user on master - * @param string $password password for the user - * @param string $host master's hostname or IP - * @param int $port port, where mysql is running - * @param array $pos position of mysql replication, - * array should contain fields File and Position - * @param bool $stop shall we stop slave? - * @param bool $start shall we start slave? - * @param mixed $link mysql link - * - * @return string output of CHANGE MASTER mysql command - */ -function PMA_Replication_Slave_changeMaster($user, $password, $host, $port, - $pos, $stop = true, $start = true, $link = null -) { - if ($stop) { - PMA_Replication_Slave_control("STOP", null, $link); - } - - $out = $GLOBALS['dbi']->tryQuery( - 'CHANGE MASTER TO ' . - 'MASTER_HOST=\'' . $host . '\',' . - 'MASTER_PORT=' . ($port * 1) . ',' . - 'MASTER_USER=\'' . $user . '\',' . - 'MASTER_PASSWORD=\'' . $password . '\',' . - 'MASTER_LOG_FILE=\'' . $pos["File"] . '\',' . - 'MASTER_LOG_POS=' . $pos["Position"] . ';', $link - ); - - if ($start) { - PMA_Replication_Slave_control("START", null, $link); - } - - return $out; -} - -/** - * This function provides connection to remote mysql server - * - * @param string $user mysql username - * @param string $password password for the user - * @param string $host mysql server's hostname or IP - * @param int $port mysql remote port - * @param string $socket path to unix socket - * - * @return mixed $link mysql link on success - */ -function PMA_Replication_connectToMaster( - $user, $password, $host = null, $port = null, $socket = null -) { - $server = array(); - $server['user'] = $user; - $server['password'] = $password; - $server["host"] = Core::sanitizeMySQLHost($host); - $server["port"] = $port; - $server["socket"] = $socket; - - // 5th parameter set to true means that it's an auxiliary connection - // and we must not go back to login page if it fails - return $GLOBALS['dbi']->connect(databaseinterface::CONNECT_AUXILIARY, $server); -} -/** - * Fetches position and file of current binary log on master - * - * @param mixed $link mysql link - * - * @return array an array containing File and Position in MySQL replication - * on master server, useful for PMA_Replication_Slave_changeMaster - */ -function PMA_Replication_Slave_binLogMaster($link = null) -{ - $data = $GLOBALS['dbi']->fetchResult('SHOW MASTER STATUS', null, null, $link); - $output = array(); - - if (! empty($data)) { - $output["File"] = $data[0]["File"]; - $output["Position"] = $data[0]["Position"]; - } - return $output; -} diff --git a/libraries/replication_gui.lib.php b/libraries/replication_gui.lib.php index 12a108a5ca..9e5154c70d 100644 --- a/libraries/replication_gui.lib.php +++ b/libraries/replication_gui.lib.php @@ -8,6 +8,7 @@ use PhpMyAdmin\Core; use PhpMyAdmin\Message; +use PhpMyAdmin\Replication; use PhpMyAdmin\Response; use PhpMyAdmin\Url; @@ -974,7 +975,7 @@ function PMA_handleRequestForSlaveChangeMaster() $_SESSION['replication']['sr_action_info'] = __('Unknown error'); // Attempt to connect to the new master server - $link_to_master = PMA_Replication_connectToMaster( + $link_to_master = Replication::connectToMaster( $sr['username'], $sr['pma_pw'], $sr['hostname'], $sr['port'] ); @@ -986,7 +987,7 @@ function PMA_handleRequestForSlaveChangeMaster() ); } else { // Read the current master position - $position = PMA_Replication_Slave_binLogMaster($link_to_master); + $position = Replication::slaveBinLogMaster($link_to_master); if (empty($position)) { $_SESSION['replication']['sr_action_status'] = 'error'; @@ -998,7 +999,7 @@ function PMA_handleRequestForSlaveChangeMaster() } else { $_SESSION['replication']['m_correct'] = true; - if (! PMA_Replication_Slave_changeMaster( + if (! Replication::slaveChangeMaster( $sr['username'], $sr['pma_pw'], $sr['hostname'], @@ -1035,15 +1036,15 @@ function PMA_handleRequestForSlaveServerControl() $_REQUEST['sr_slave_control_parm'] = null; } if ($_REQUEST['sr_slave_action'] == 'reset') { - $qStop = PMA_Replication_Slave_control("STOP"); + $qStop = Replication::slaveControl("STOP"); $qReset = $GLOBALS['dbi']->tryQuery("RESET SLAVE;"); - $qStart = PMA_Replication_Slave_control("START"); + $qStart = Replication::slaveControl("START"); $result = ($qStop !== false && $qStop !== -1 && $qReset !== false && $qReset !== -1 && $qStart !== false && $qStart !== -1); } else { - $qControl = PMA_Replication_Slave_control( + $qControl = Replication::slaveControl( $_REQUEST['sr_slave_action'], $_REQUEST['sr_slave_control_parm'] ); @@ -1066,11 +1067,11 @@ function PMA_handleRequestForSlaveSkipError() $count = $_REQUEST['sr_skip_errors_count'] * 1; } - $qStop = PMA_Replication_Slave_control("STOP"); + $qStop = Replication::slaveControl("STOP"); $qSkip = $GLOBALS['dbi']->tryQuery( "SET GLOBAL SQL_SLAVE_SKIP_COUNTER = " . $count . ";" ); - $qStart = PMA_Replication_Slave_control("START"); + $qStart = Replication::slaveControl("START"); $result = ($qStop !== false && $qStop !== -1 && $qSkip !== false && $qSkip !== -1 && From dcedb418dce1a33f2c09ed374c801708ed1c962f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 13 Sep 2017 16:00:40 -0300 Subject: [PATCH 2/5] Refactor replication_gui functions to static methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- libraries/classes/ReplicationGui.php | 1093 +++++++++++++++++ libraries/classes/Server/Status.php | 3 +- libraries/replication.inc.php | 2 +- libraries/replication_gui.lib.php | 1081 ---------------- server_replication.php | 18 +- server_status.php | 1 - server_status_advisor.php | 1 - server_status_monitor.php | 1 - server_status_processes.php | 1 - server_status_queries.php | 1 - server_status_variables.php | 1 - .../ReplicationGuiTest.php} | 41 +- 12 files changed, 1126 insertions(+), 1118 deletions(-) create mode 100644 libraries/classes/ReplicationGui.php delete mode 100644 libraries/replication_gui.lib.php rename test/{libraries/PMA_server_replication_test.php => classes/ReplicationGuiTest.php} (87%) diff --git a/libraries/classes/ReplicationGui.php b/libraries/classes/ReplicationGui.php new file mode 100644 index 0000000000..cdcd44d731 --- /dev/null +++ b/libraries/classes/ReplicationGui.php @@ -0,0 +1,1093 @@ +getDisplay(); + $_SESSION['replication']['sr_action_status'] = 'unknown'; + } elseif ($_SESSION['replication']['sr_action_status'] == 'success') { + $success_message = $_SESSION['replication']['sr_action_info']; + $html .= Message::success($success_message)->getDisplay(); + $_SESSION['replication']['sr_action_status'] = 'unknown'; + } + } + return $html; + } + + /** + * returns HTML for master replication + * + * @return String HTML code + */ + public static function getHtmlForMasterReplication() + { + $html = ''; + if (! isset($_REQUEST['repl_clear_scr'])) { + $html .= '
'; + $html .= '' . __('Master replication') . ''; + $html .= __('This server is configured as master in a replication process.'); + $html .= '
    '; + $html .= '
  • '; + $html .= __('Show master status') . ''; + $html .= self::getHtmlForReplicationStatusTable('master', true, false); + $html .= '
  • '; + + $html .= '
  • '; + $html .= __('Show connected slaves') . ''; + $html .= self::getHtmlForReplicationSlavesTable(true); + $html .= '
  • '; + + $_url_params = $GLOBALS['url_params']; + $_url_params['mr_adduser'] = true; + $_url_params['repl_clear_scr'] = true; + + $html .= '
  • '; + $html .= __('Add slave replication user') . '
  • '; + } + + // Display 'Add replication slave user' form + if (isset($_REQUEST['mr_adduser'])) { + $html .= self::getHtmlForReplicationMasterAddSlaveUser(); + } elseif (! isset($_REQUEST['repl_clear_scr'])) { + $html .= "
"; + $html .= "
"; + } + + return $html; + } + + /** + * returns HTML for master replication configuration + * + * @return String HTML code + */ + public static function getHtmlForMasterConfiguration() + { + $html = '
'; + $html .= '' . __('Master configuration') . ''; + $html .= __( + 'This server is not configured as a master server in a ' + . 'replication process. You can choose from either replicating ' + . 'all databases and ignoring some of them (useful if you want to ' + . 'replicate a majority of the databases) or you can choose to ignore ' + . 'all databases by default and allow only certain databases to be ' + . 'replicated. Please select the mode:' + ) . '

'; + + $html .= ''; + $html .= '

'; + $html .= __('Please select databases:') . '
'; + $html .= self::getHtmlForReplicationDbMultibox(); + $html .= '

'; + $html .= __( + 'Now, add the following lines at the end of [mysqld] section' + . ' in your my.cnf and please restart the MySQL server afterwards.' + ) . '
'; + $html .= '
';
+        $html .= __(
+            'Once you restarted MySQL server, please click on Go button. '
+            . 'Afterwards, you should see a message informing you, that this server'
+            . ' is configured as master.'
+        );
+        $html .= '
'; + $html .= '
'; + $html .= '
'; + $html .= Url::getHiddenInputs('', ''); + $html .= ' '; + $html .= '
'; + $html .= '
'; + + return $html; + } + + /** + * returns HTML for slave replication configuration + * + * @param bool $server_slave_status Whether it is Master or Slave + * @param array $server_slave_replication Slave replication + * + * @return String HTML code + */ + public static function getHtmlForSlaveConfiguration( + $server_slave_status, $server_slave_replication + ) { + $html = '
'; + $html .= '' . __('Slave replication') . ''; + /** + * check for multi-master replication functionality + */ + $server_slave_multi_replication = $GLOBALS['dbi']->fetchResult( + 'SHOW ALL SLAVES STATUS' + ); + if ($server_slave_multi_replication) { + $html .= __('Master connection:'); + $html .= '
'; + $html .= Url::getHiddenInputs($GLOBALS['url_params']); + $html .= ' '; + $html .= ' '; + $html .= '
'; + $html .= '

'; + } + if ($server_slave_status) { + $html .= '
'; + + $_url_params = $GLOBALS['url_params']; + $_url_params['sr_take_action'] = true; + $_url_params['sr_slave_server_control'] = true; + + if ($server_slave_replication[0]['Slave_IO_Running'] == 'No') { + $_url_params['sr_slave_action'] = 'start'; + } else { + $_url_params['sr_slave_action'] = 'stop'; + } + + $_url_params['sr_slave_control_parm'] = 'IO_THREAD'; + $slave_control_io_link = 'server_replication.php' + . Url::getCommon($_url_params); + + if ($server_slave_replication[0]['Slave_SQL_Running'] == 'No') { + $_url_params['sr_slave_action'] = 'start'; + } else { + $_url_params['sr_slave_action'] = 'stop'; + } + + $_url_params['sr_slave_control_parm'] = 'SQL_THREAD'; + $slave_control_sql_link = 'server_replication.php' + . Url::getCommon($_url_params); + + if ($server_slave_replication[0]['Slave_IO_Running'] == 'No' + || $server_slave_replication[0]['Slave_SQL_Running'] == 'No' + ) { + $_url_params['sr_slave_action'] = 'start'; + } else { + $_url_params['sr_slave_action'] = 'stop'; + } + + $_url_params['sr_slave_control_parm'] = null; + $slave_control_full_link = 'server_replication.php' + . Url::getCommon($_url_params); + + $_url_params['sr_slave_action'] = 'reset'; + $slave_control_reset_link = 'server_replication.php' + . Url::getCommon($_url_params); + + $_url_params = $GLOBALS['url_params']; + $_url_params['sr_take_action'] = true; + $_url_params['sr_slave_skip_error'] = true; + $slave_skip_error_link = 'server_replication.php' + . Url::getCommon($_url_params); + + if ($server_slave_replication[0]['Slave_SQL_Running'] == 'No') { + $html .= Message::error( + __('Slave SQL Thread not running!') + )->getDisplay(); + } + if ($server_slave_replication[0]['Slave_IO_Running'] == 'No') { + $html .= Message::error( + __('Slave IO Thread not running!') + )->getDisplay(); + } + + $_url_params = $GLOBALS['url_params']; + $_url_params['sl_configure'] = true; + $_url_params['repl_clear_scr'] = true; + + $reconfiguremaster_link = 'server_replication.php' + . Url::getCommon($_url_params); + + $html .= __( + 'Server is configured as slave in a replication process. Would you ' . + 'like to:' + ); + $html .= '
'; + $html .= ''; + $html .= '
'; + + } elseif (! isset($_REQUEST['sl_configure'])) { + $_url_params = $GLOBALS['url_params']; + $_url_params['sl_configure'] = true; + $_url_params['repl_clear_scr'] = true; + + $html .= sprintf( + __( + 'This server is not configured as slave in a replication process. ' + . 'Would you like to configure it?' + ), + 'server_replication.php' . Url::getCommon($_url_params) + ); + } + $html .= '
'; + + return $html; + } + + /** + * returns HTML for Slave Error Management + * + * @param String $slave_skip_error_link error link + * + * @return String HTML code + */ + public static function getHtmlForSlaveErrorManagement($slave_skip_error_link) + { + $html = ''; + $html .= __('Error management:') . ''; + $html .= '
'; + $html .= Message::error( + __('Skipping errors might lead into unsynchronized master and slave!') + )->getDisplay(); + $html .= '
    '; + $html .= '
  • '; + $html .= __('Skip current error') . '
  • '; + $html .= '
  • '; + $html .= '
    '; + $html .= Url::getHiddenInputs('', ''); + $html .= sprintf( + __('Skip next %s errors.'), + '' + ); + $html .= ' '; + $html .= ' '; + $html .= '
  • '; + $html .= '
'; + $html .= '
'; + return $html; + } + + /** + * returns HTML for not configure for a server replication + * + * @return String HTML code + */ + public static function getHtmlForNotServerReplication() + { + $_url_params = $GLOBALS['url_params']; + $_url_params['mr_configure'] = true; + + $html = '
'; + $html .= '' . __('Master replication') . ''; + $html .= sprintf( + __( + 'This server is not configured as master in a replication process. ' + . 'Would you like to configure it?' + ), + 'server_replication.php' . Url::getCommon($_url_params) + ); + $html .= '
'; + return $html; + } + + /** + * returns HTML code for selecting databases + * + * @return String HTML code + */ + public static function getHtmlForReplicationDbMultibox() + { + $multi_values = ''; + $multi_values .= '
'; + $multi_values .= '' . __('Select all') . ''; + $multi_values .= ' / '; + $multi_values .= '' . __('Unselect all') . ''; + + return $multi_values; + } + + /** + * returns HTML for changing master + * + * @param String $submitname - submit button name + * + * @return String HTML code + */ + public static function getHtmlForReplicationChangeMaster($submitname) + { + $html = ''; + list($username_length, $hostname_length) + = self::getUsernameHostnameLength(); + + $html .= '
'; + $html .= Url::getHiddenInputs('', ''); + $html .= '
'; + $html .= ' ' . __('Slave configuration'); + $html .= ' - ' . __('Change or reconfigure master server') . ''; + $html .= __( + 'Make sure you have a unique server-id in your configuration file (my.cnf). ' + . 'If not, please add the following line into [mysqld] section:' + ); + $html .= '
'; + $html .= '
server-id=' . time() . '
'; + + $html .= self::getHtmlForAddUserInputDiv( + array('text'=>__('User name:'), 'for'=>"text_username"), + array( + 'type'=>'text', + 'name'=>'username', + 'id'=>'text_username', + 'maxlength'=>$username_length, + 'title'=>__('User name'), + 'required'=>'required' + ) + ); + + $html .= self::getHtmlForAddUserInputDiv( + array('text'=>__('Password:'), 'for'=>"text_pma_pw"), + array( + 'type'=>'password', + 'name'=>'pma_pw', + 'id'=>'text_pma_pw', + 'title'=>__('Password'), + 'required'=>'required' + ) + ); + + $html .= self::getHtmlForAddUserInputDiv( + array('text'=>__('Host:'), 'for'=>"text_hostname"), + array( + 'type'=>'text', + 'name'=>'hostname', + 'id'=>'text_hostname', + 'maxlength'=>$hostname_length, + 'value'=>'', + 'required'=>'required' + ) + ); + + $html .= self::getHtmlForAddUserInputDiv( + array('text'=>__('Port:'), 'for'=>"text_port"), + array( + 'type'=>'number', + 'name'=>'text_port', + 'id'=>'text_port', + 'maxlength'=>6, + 'value'=>'3306', + 'required'=>'required' + ) + ); + + $html .= '
'; + $html .= ' '; + $html .= '
'; + + return $html; + } + + /** + * returns HTML code for Add user input div + * + * @param array $label_array label tag elements + * @param array $input_array input tag elements + * + * @return String HTML code + */ + public static function getHtmlForAddUserInputDiv($label_array, $input_array) + { + $html = '
'; + $html .= ' '; + + $html .= ' $value) { + $html .= ' ' . $key . '="' . $value . '" '; + } + $html .= ' />'; + $html .= '
'; + return $html; + } + + /** + * This function returns html code for table with replication status. + * + * @param string $type either master or slave + * @param boolean $hidden if true, then default style is set to hidden, + * default value false + * @param boolean $title if true, then title is displayed, default true + * + * @return String HTML code + */ + public static function getHtmlForReplicationStatusTable($type, $hidden = false, $title = true) + { + global ${"{$type}_variables"}; + global ${"{$type}_variables_alerts"}; + global ${"{$type}_variables_oks"}; + global ${"server_{$type}_replication"}; + global ${"strReplicationStatus_{$type}"}; + + $html = ''; + + // TODO check the Masters server id? + // seems to default to '1' when queried via SHOW VARIABLES , + // but resulted in error on the master when slave connects + // [ERROR] Error reading packet from server: Misconfigured master + // - server id was not set ( server_errno=1236) + // [ERROR] Got fatal error 1236: 'Misconfigured master + // - server id was not set' from master when reading data from binary log + // + //$server_id = $GLOBALS['dbi']->fetchValue( + // "SHOW VARIABLES LIKE 'server_id'", 0, 1 + //); + + $html .= '
'; + + if ($title) { + if ($type == 'master') { + $html .= '

'; + $html .= __('Master status') . '

'; + } else { + $html .= '

'; + $html .= __('Slave status') . '

'; + } + } else { + $html .= '
'; + } + + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + + foreach (${"{$type}_variables"} as $variable) { + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + } + + $html .= ' '; + $html .= '
' . __('Variable') . '' . __('Value') . '
'; + $html .= htmlspecialchars($variable); + $html .= ' '; + + // TODO change to regexp or something, to allow for negative match + if (isset(${"{$type}_variables_alerts"}[$variable]) + && ${"{$type}_variables_alerts"}[$variable] == ${"server_{$type}_replication"}[0][$variable] + ) { + $html .= ''; + + } elseif (isset(${"{$type}_variables_oks"}[$variable]) + && ${"{$type}_variables_oks"}[$variable] == ${"server_{$type}_replication"}[0][$variable] + ) { + $html .= ''; + } else { + $html .= ''; + } + // allow wrapping long table lists into multiple lines + static $variables_wrap = array( + 'Replicate_Do_DB', 'Replicate_Ignore_DB', + 'Replicate_Do_Table', 'Replicate_Ignore_Table', + 'Replicate_Wild_Do_Table', 'Replicate_Wild_Ignore_Table'); + if (in_array($variable, $variables_wrap)) { + $html .= htmlspecialchars(str_replace( + ',', + ', ', + ${"server_{$type}_replication"}[0][$variable] + )); + } else { + $html .= htmlspecialchars(${"server_{$type}_replication"}[0][$variable]); + } + $html .= ''; + + $html .= '
'; + $html .= '
'; + $html .= '
'; + + return $html; + } + + /** + * returns html code for table with slave users connected to this master + * + * @param boolean $hidden - if true, then default style is set to hidden, + * - default value false + * + * @return string + */ + public static function getHtmlForReplicationSlavesTable($hidden = false) + { + $html = ''; + // Fetch data + $data = $GLOBALS['dbi']->fetchResult('SHOW SLAVE HOSTS', null, null); + + $html .= '
'; + $html .= '
'; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + + foreach ($data as $slave) { + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + } + + $html .= ' '; + $html .= '
' . __('Server ID') . '' . __('Host') . '
' . $slave['Server_id'] . '' . $slave['Host'] . '
'; + $html .= '
'; + $html .= Message::notice( + __( + 'Only slaves started with the ' + . '--report-host=host_name option are visible in this list.' + ) + )->getDisplay(); + $html .= '
'; + $html .= '
'; + + return $html; + } + + /** + * get the correct username and hostname lengths for this MySQL server + * + * @return array username length, hostname length + */ + public static function getUsernameHostnameLength() + { + $fields_info = $GLOBALS['dbi']->getColumns('mysql', 'user'); + $username_length = 16; + $hostname_length = 41; + foreach ($fields_info as $val) { + if ($val['Field'] == 'User') { + strtok($val['Type'], '()'); + $v = strtok('()'); + if (is_int($v)) { + $username_length = $v; + } + } elseif ($val['Field'] == 'Host') { + strtok($val['Type'], '()'); + $v = strtok('()'); + if (is_int($v)) { + $hostname_length = $v; + } + } + } + return array($username_length, $hostname_length); + } + + /** + * returns html code to add a replication slave user to the master + * + * @return String HTML code + */ + public static function getHtmlForReplicationMasterAddSlaveUser() + { + $html = ''; + list($username_length, $hostname_length) + = self::getUsernameHostnameLength(); + + if (isset($_REQUEST['username']) && strlen($_REQUEST['username']) === 0) { + $GLOBALS['pred_username'] = 'any'; + } + $html .= '
'; + $html .= '
' . __('Add slave replication user') . '' + . self::getHtmlForAddUserLoginForm($username_length) + . '
' + . '' + . '' + . ' ' + . '' + . '' + . ' ' + . '' + . '
' + . '' + . '' + . ' ' + . '' + . '' + . '
'; + + return $html; + } + + /** + * returns HTML for TableInfoForm + * + * @param int $hostname_length Selected hostname length + * + * @return String HTML code + */ + public static function getHtmlForTableInfoForm($hostname_length) + { + $html = ' ' + . ' ' + . ' ' + . '
' + . '' + . Util::showHint( + __( + 'When Host table is used, this field is ignored ' + . 'and values stored in Host table are used instead.' + ) + ) + . '
' + . '
' + . '' + . '' + . ' ' + . '' + . '' + . '
' + . '
' + . '' + . ' ' + . '' + . '
' + . '
' + . '' + . '' + . ' ' + . '' + . '' + . '
' + . ''; + $html .= ''; + return $html; + } + + /** + * handle control requests + * + * @return NULL + */ + public static function handleControlRequest() + { + if (isset($_REQUEST['sr_take_action'])) { + $refresh = false; + $result = false; + $messageSuccess = null; + $messageError = null; + + if (isset($_REQUEST['slave_changemaster']) && ! $GLOBALS['cfg']['AllowArbitraryServer']) { + $_SESSION['replication']['sr_action_status'] = 'error'; + $_SESSION['replication']['sr_action_info'] = __('Connection to server is disabled, please enable $cfg[\'AllowArbitraryServer\'] in phpMyAdmin configuration.'); + } elseif (isset($_REQUEST['slave_changemaster'])) { + $result = self::handleRequestForSlaveChangeMaster(); + } elseif (isset($_REQUEST['sr_slave_server_control'])) { + $result = self::handleRequestForSlaveServerControl(); + $refresh = true; + + switch ($_REQUEST['sr_slave_action']) { + case 'start': + $messageSuccess = __('Replication started successfully.'); + $messageError = __('Error starting replication.'); + break; + case 'stop': + $messageSuccess = __('Replication stopped successfully.'); + $messageError = __('Error stopping replication.'); + break; + case 'reset': + $messageSuccess = __('Replication resetting successfully.'); + $messageError = __('Error resetting replication.'); + break; + default: + $messageSuccess = __('Success.'); + $messageError = __('Error.'); + break; + } + } elseif (isset($_REQUEST['sr_slave_skip_error'])) { + $result = self::handleRequestForSlaveSkipError(); + } + + if ($refresh) { + $response = Response::getInstance(); + if ($response->isAjax()) { + $response->setRequestStatus($result); + $response->addJSON( + 'message', + $result + ? Message::success($messageSuccess) + : Message::error($messageError) + ); + } else { + Core::sendHeaderLocation( + './server_replication.php' + . Url::getCommonRaw($GLOBALS['url_params']) + ); + } + } + unset($refresh); + } + } + + /** + * handle control requests for Slave Change Master + * + * @return boolean + */ + public static function handleRequestForSlaveChangeMaster() + { + $sr = array(); + $_SESSION['replication']['m_username'] = $sr['username'] + = $GLOBALS['dbi']->escapeString($_REQUEST['username']); + $_SESSION['replication']['m_password'] = $sr['pma_pw'] + = $GLOBALS['dbi']->escapeString($_REQUEST['pma_pw']); + $_SESSION['replication']['m_hostname'] = $sr['hostname'] + = $GLOBALS['dbi']->escapeString($_REQUEST['hostname']); + $_SESSION['replication']['m_port'] = $sr['port'] + = $GLOBALS['dbi']->escapeString($_REQUEST['text_port']); + $_SESSION['replication']['m_correct'] = ''; + $_SESSION['replication']['sr_action_status'] = 'error'; + $_SESSION['replication']['sr_action_info'] = __('Unknown error'); + + // Attempt to connect to the new master server + $link_to_master = Replication::connectToMaster( + $sr['username'], $sr['pma_pw'], $sr['hostname'], $sr['port'] + ); + + if (! $link_to_master) { + $_SESSION['replication']['sr_action_status'] = 'error'; + $_SESSION['replication']['sr_action_info'] = sprintf( + __('Unable to connect to master %s.'), + htmlspecialchars($sr['hostname']) + ); + } else { + // Read the current master position + $position = Replication::slaveBinLogMaster($link_to_master); + + if (empty($position)) { + $_SESSION['replication']['sr_action_status'] = 'error'; + $_SESSION['replication']['sr_action_info'] + = __( + 'Unable to read master log position. ' + . 'Possible privilege problem on master.' + ); + } else { + $_SESSION['replication']['m_correct'] = true; + + if (! Replication::slaveChangeMaster( + $sr['username'], + $sr['pma_pw'], + $sr['hostname'], + $sr['port'], + $position, + true, + false + ) + ) { + $_SESSION['replication']['sr_action_status'] = 'error'; + $_SESSION['replication']['sr_action_info'] + = __('Unable to change master!'); + } else { + $_SESSION['replication']['sr_action_status'] = 'success'; + $_SESSION['replication']['sr_action_info'] = sprintf( + __('Master server changed successfully to %s.'), + htmlspecialchars($sr['hostname']) + ); + } + } + } + + return $_SESSION['replication']['sr_action_status'] === 'success'; + } + + /** + * handle control requests for Slave Server Control + * + * @return boolean + */ + public static function handleRequestForSlaveServerControl() + { + if (empty($_REQUEST['sr_slave_control_parm'])) { + $_REQUEST['sr_slave_control_parm'] = null; + } + if ($_REQUEST['sr_slave_action'] == 'reset') { + $qStop = Replication::slaveControl("STOP"); + $qReset = $GLOBALS['dbi']->tryQuery("RESET SLAVE;"); + $qStart = Replication::slaveControl("START"); + + $result = ($qStop !== false && $qStop !== -1 && + $qReset !== false && $qReset !== -1 && + $qStart !== false && $qStart !== -1); + } else { + $qControl = Replication::slaveControl( + $_REQUEST['sr_slave_action'], + $_REQUEST['sr_slave_control_parm'] + ); + + $result = ($qControl !== false && $qControl !== -1); + } + + return $result; + } + + /** + * handle control requests for Slave Skip Error + * + * @return boolean + */ + public static function handleRequestForSlaveSkipError() + { + $count = 1; + if (isset($_REQUEST['sr_skip_errors_count'])) { + $count = $_REQUEST['sr_skip_errors_count'] * 1; + } + + $qStop = Replication::slaveControl("STOP"); + $qSkip = $GLOBALS['dbi']->tryQuery( + "SET GLOBAL SQL_SLAVE_SKIP_COUNTER = " . $count . ";" + ); + $qStart = Replication::slaveControl("START"); + + $result = ($qStop !== false && $qStop !== -1 && + $qSkip !== false && $qSkip !== -1 && + $qStart !== false && $qStart !== -1); + + return $result; + } +} diff --git a/libraries/classes/Server/Status.php b/libraries/classes/Server/Status.php index 655ce28cad..d67054352f 100644 --- a/libraries/classes/Server/Status.php +++ b/libraries/classes/Server/Status.php @@ -9,6 +9,7 @@ */ namespace PhpMyAdmin\Server; +use PhpMyAdmin\ReplicationGui; use PhpMyAdmin\Server\Status\Data; use PhpMyAdmin\Util; @@ -126,7 +127,7 @@ class Status if (isset($GLOBALS['replication_info'][$type]['status']) && $GLOBALS['replication_info'][$type]['status'] ) { - $retval .= PMA_getHtmlForReplicationStatusTable($type); + $retval .= ReplicationGui::getHtmlForReplicationStatusTable($type); } } diff --git a/libraries/replication.inc.php b/libraries/replication.inc.php index 148accbb08..d2d21a9b18 100644 --- a/libraries/replication.inc.php +++ b/libraries/replication.inc.php @@ -100,7 +100,7 @@ $slave_variables = array( * define important variables, which need to be watched for * correct running of replication in slave mode * - * @usedby PMA_getHtmlForReplicationStatusTable() + * @usedby PhpMyAdmin\ReplicationGui::getHtmlForReplicationStatusTable() */ // TODO change to regexp or something, to allow for negative match. // To e.g. highlight 'Last_Error' diff --git a/libraries/replication_gui.lib.php b/libraries/replication_gui.lib.php deleted file mode 100644 index 9e5154c70d..0000000000 --- a/libraries/replication_gui.lib.php +++ /dev/null @@ -1,1081 +0,0 @@ -getDisplay(); - $_SESSION['replication']['sr_action_status'] = 'unknown'; - } elseif ($_SESSION['replication']['sr_action_status'] == 'success') { - $success_message = $_SESSION['replication']['sr_action_info']; - $html .= Message::success($success_message)->getDisplay(); - $_SESSION['replication']['sr_action_status'] = 'unknown'; - } - } - return $html; -} - -/** - * returns HTML for master replication - * - * @return String HTML code - */ -function PMA_getHtmlForMasterReplication() -{ - $html = ''; - if (! isset($_REQUEST['repl_clear_scr'])) { - $html .= '
'; - $html .= '' . __('Master replication') . ''; - $html .= __('This server is configured as master in a replication process.'); - $html .= '
    '; - $html .= '
  • '; - $html .= __('Show master status') . ''; - $html .= PMA_getHtmlForReplicationStatusTable('master', true, false); - $html .= '
  • '; - - $html .= '
  • '; - $html .= __('Show connected slaves') . ''; - $html .= PMA_getHtmlForReplicationSlavesTable(true); - $html .= '
  • '; - - $_url_params = $GLOBALS['url_params']; - $_url_params['mr_adduser'] = true; - $_url_params['repl_clear_scr'] = true; - - $html .= '
  • '; - $html .= __('Add slave replication user') . '
  • '; - } - - // Display 'Add replication slave user' form - if (isset($_REQUEST['mr_adduser'])) { - $html .= PMA_getHtmlForReplicationMasterAddSlaveuser(); - } elseif (! isset($_REQUEST['repl_clear_scr'])) { - $html .= "
"; - $html .= "
"; - } - - return $html; -} - -/** - * returns HTML for master replication configuration - * - * @return String HTML code - */ -function PMA_getHtmlForMasterConfiguration() -{ - $html = '
'; - $html .= '' . __('Master configuration') . ''; - $html .= __( - 'This server is not configured as a master server in a ' - . 'replication process. You can choose from either replicating ' - . 'all databases and ignoring some of them (useful if you want to ' - . 'replicate a majority of the databases) or you can choose to ignore ' - . 'all databases by default and allow only certain databases to be ' - . 'replicated. Please select the mode:' - ) . '

'; - - $html .= ''; - $html .= '

'; - $html .= __('Please select databases:') . '
'; - $html .= PMA_getHtmlForReplicationDbMultibox(); - $html .= '

'; - $html .= __( - 'Now, add the following lines at the end of [mysqld] section' - . ' in your my.cnf and please restart the MySQL server afterwards.' - ) . '
'; - $html .= '
';
-    $html .= __(
-        'Once you restarted MySQL server, please click on Go button. '
-        . 'Afterwards, you should see a message informing you, that this server'
-        . ' is configured as master.'
-    );
-    $html .= '
'; - $html .= '
'; - $html .= ' '; - $html .= Url::getHiddenInputs('', ''); - $html .= ' '; - $html .= ' '; - $html .= '
'; - - return $html; -} - -/** - * returns HTML for slave replication configuration - * - * @param bool $server_slave_status Whether it is Master or Slave - * @param array $server_slave_replication Slave replication - * - * @return String HTML code - */ -function PMA_getHtmlForSlaveConfiguration( - $server_slave_status, $server_slave_replication -) { - $html = '
'; - $html .= '' . __('Slave replication') . ''; - /** - * check for multi-master replication functionality - */ - $server_slave_multi_replication = $GLOBALS['dbi']->fetchResult( - 'SHOW ALL SLAVES STATUS' - ); - if ($server_slave_multi_replication) { - $html .= __('Master connection:'); - $html .= '
'; - $html .= Url::getHiddenInputs($GLOBALS['url_params']); - $html .= ' '; - $html .= ' '; - $html .= '
'; - $html .= '

'; - } - if ($server_slave_status) { - $html .= '
'; - - $_url_params = $GLOBALS['url_params']; - $_url_params['sr_take_action'] = true; - $_url_params['sr_slave_server_control'] = true; - - if ($server_slave_replication[0]['Slave_IO_Running'] == 'No') { - $_url_params['sr_slave_action'] = 'start'; - } else { - $_url_params['sr_slave_action'] = 'stop'; - } - - $_url_params['sr_slave_control_parm'] = 'IO_THREAD'; - $slave_control_io_link = 'server_replication.php' - . Url::getCommon($_url_params); - - if ($server_slave_replication[0]['Slave_SQL_Running'] == 'No') { - $_url_params['sr_slave_action'] = 'start'; - } else { - $_url_params['sr_slave_action'] = 'stop'; - } - - $_url_params['sr_slave_control_parm'] = 'SQL_THREAD'; - $slave_control_sql_link = 'server_replication.php' - . Url::getCommon($_url_params); - - if ($server_slave_replication[0]['Slave_IO_Running'] == 'No' - || $server_slave_replication[0]['Slave_SQL_Running'] == 'No' - ) { - $_url_params['sr_slave_action'] = 'start'; - } else { - $_url_params['sr_slave_action'] = 'stop'; - } - - $_url_params['sr_slave_control_parm'] = null; - $slave_control_full_link = 'server_replication.php' - . Url::getCommon($_url_params); - - $_url_params['sr_slave_action'] = 'reset'; - $slave_control_reset_link = 'server_replication.php' - . Url::getCommon($_url_params); - - $_url_params = $GLOBALS['url_params']; - $_url_params['sr_take_action'] = true; - $_url_params['sr_slave_skip_error'] = true; - $slave_skip_error_link = 'server_replication.php' - . Url::getCommon($_url_params); - - if ($server_slave_replication[0]['Slave_SQL_Running'] == 'No') { - $html .= Message::error( - __('Slave SQL Thread not running!') - )->getDisplay(); - } - if ($server_slave_replication[0]['Slave_IO_Running'] == 'No') { - $html .= Message::error( - __('Slave IO Thread not running!') - )->getDisplay(); - } - - $_url_params = $GLOBALS['url_params']; - $_url_params['sl_configure'] = true; - $_url_params['repl_clear_scr'] = true; - - $reconfiguremaster_link = 'server_replication.php' - . Url::getCommon($_url_params); - - $html .= __( - 'Server is configured as slave in a replication process. Would you ' . - 'like to:' - ); - $html .= '
'; - $html .= ''; - $html .= '
'; - - } elseif (! isset($_REQUEST['sl_configure'])) { - $_url_params = $GLOBALS['url_params']; - $_url_params['sl_configure'] = true; - $_url_params['repl_clear_scr'] = true; - - $html .= sprintf( - __( - 'This server is not configured as slave in a replication process. ' - . 'Would you like to configure it?' - ), - 'server_replication.php' . Url::getCommon($_url_params) - ); - } - $html .= '
'; - - return $html; -} - -/** - * returns HTML for Slave Error Management - * - * @param String $slave_skip_error_link error link - * - * @return String HTML code - */ -function PMA_getHtmlForSlaveErrorManagement($slave_skip_error_link) -{ - $html = ''; - $html .= __('Error management:') . ''; - $html .= '
'; - $html .= Message::error( - __('Skipping errors might lead into unsynchronized master and slave!') - )->getDisplay(); - $html .= '
    '; - $html .= '
  • '; - $html .= __('Skip current error') . '
  • '; - $html .= '
  • '; - $html .= '
    '; - $html .= Url::getHiddenInputs('', ''); - $html .= sprintf( - __('Skip next %s errors.'), - '' - ); - $html .= ' '; - $html .= ' '; - $html .= '
  • '; - $html .= '
'; - $html .= '
'; - return $html; -} - -/** - * returns HTML for not configure for a server replication - * - * @return String HTML code - */ -function PMA_getHtmlForNotServerReplication() -{ - $_url_params = $GLOBALS['url_params']; - $_url_params['mr_configure'] = true; - - $html = '
'; - $html .= '' . __('Master replication') . ''; - $html .= sprintf( - __( - 'This server is not configured as master in a replication process. ' - . 'Would you like to configure it?' - ), - 'server_replication.php' . Url::getCommon($_url_params) - ); - $html .= '
'; - return $html; -} - -/** - * returns HTML code for selecting databases - * - * @return String HTML code - */ -function PMA_getHtmlForReplicationDbMultibox() -{ - $multi_values = ''; - $multi_values .= '
'; - $multi_values .= '' . __('Select all') . ''; - $multi_values .= ' / '; - $multi_values .= '' . __('Unselect all') . ''; - - return $multi_values; -} - -/** - * returns HTML for changing master - * - * @param String $submitname - submit button name - * - * @return String HTML code - */ -function PMA_getHtmlForReplicationChangeMaster($submitname) -{ - $html = ''; - list($username_length, $hostname_length) - = PMA_replicationGetUsernameHostnameLength(); - - $html .= '
'; - $html .= Url::getHiddenInputs('', ''); - $html .= '
'; - $html .= ' ' . __('Slave configuration'); - $html .= ' - ' . __('Change or reconfigure master server') . ''; - $html .= __( - 'Make sure you have a unique server-id in your configuration file (my.cnf). ' - . 'If not, please add the following line into [mysqld] section:' - ); - $html .= '
'; - $html .= '
server-id=' . time() . '
'; - - $html .= PMA_getHtmlForAddUserInputDiv( - array('text'=>__('User name:'), 'for'=>"text_username"), - array( - 'type'=>'text', - 'name'=>'username', - 'id'=>'text_username', - 'maxlength'=>$username_length, - 'title'=>__('User name'), - 'required'=>'required' - ) - ); - - $html .= PMA_getHtmlForAddUserInputDiv( - array('text'=>__('Password:'), 'for'=>"text_pma_pw"), - array( - 'type'=>'password', - 'name'=>'pma_pw', - 'id'=>'text_pma_pw', - 'title'=>__('Password'), - 'required'=>'required' - ) - ); - - $html .= PMA_getHtmlForAddUserInputDiv( - array('text'=>__('Host:'), 'for'=>"text_hostname"), - array( - 'type'=>'text', - 'name'=>'hostname', - 'id'=>'text_hostname', - 'maxlength'=>$hostname_length, - 'value'=>'', - 'required'=>'required' - ) - ); - - $html .= PMA_getHtmlForAddUserInputDiv( - array('text'=>__('Port:'), 'for'=>"text_port"), - array( - 'type'=>'number', - 'name'=>'text_port', - 'id'=>'text_port', - 'maxlength'=>6, - 'value'=>'3306', - 'required'=>'required' - ) - ); - - $html .= '
'; - $html .= ' '; - $html .= '
'; - - return $html; -} - -/** - * returns HTML code for Add user input div - * - * @param array $label_array label tag elements - * @param array $input_array input tag elements - * - * @return String HTML code - */ -function PMA_getHtmlForAddUserInputDiv($label_array, $input_array) -{ - $html = '
'; - $html .= ' '; - - $html .= ' $value) { - $html .= ' ' . $key . '="' . $value . '" '; - } - $html .= ' />'; - $html .= '
'; - return $html; -} - -/** - * This function returns html code for table with replication status. - * - * @param string $type either master or slave - * @param boolean $hidden if true, then default style is set to hidden, - * default value false - * @param boolean $title if true, then title is displayed, default true - * - * @return String HTML code - */ -function PMA_getHtmlForReplicationStatusTable($type, $hidden = false, $title = true) -{ - global ${"{$type}_variables"}; - global ${"{$type}_variables_alerts"}; - global ${"{$type}_variables_oks"}; - global ${"server_{$type}_replication"}; - global ${"strReplicationStatus_{$type}"}; - - $html = ''; - - // TODO check the Masters server id? - // seems to default to '1' when queried via SHOW VARIABLES , - // but resulted in error on the master when slave connects - // [ERROR] Error reading packet from server: Misconfigured master - // - server id was not set ( server_errno=1236) - // [ERROR] Got fatal error 1236: 'Misconfigured master - // - server id was not set' from master when reading data from binary log - // - //$server_id = $GLOBALS['dbi']->fetchValue( - // "SHOW VARIABLES LIKE 'server_id'", 0, 1 - //); - - $html .= '
'; - - if ($title) { - if ($type == 'master') { - $html .= '

'; - $html .= __('Master status') . '

'; - } else { - $html .= '

'; - $html .= __('Slave status') . '

'; - } - } else { - $html .= '
'; - } - - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - - foreach (${"{$type}_variables"} as $variable) { - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - } - - $html .= ' '; - $html .= '
' . __('Variable') . '' . __('Value') . '
'; - $html .= htmlspecialchars($variable); - $html .= ' '; - - // TODO change to regexp or something, to allow for negative match - if (isset(${"{$type}_variables_alerts"}[$variable]) - && ${"{$type}_variables_alerts"}[$variable] == ${"server_{$type}_replication"}[0][$variable] - ) { - $html .= ''; - - } elseif (isset(${"{$type}_variables_oks"}[$variable]) - && ${"{$type}_variables_oks"}[$variable] == ${"server_{$type}_replication"}[0][$variable] - ) { - $html .= ''; - } else { - $html .= ''; - } - // allow wrapping long table lists into multiple lines - static $variables_wrap = array( - 'Replicate_Do_DB', 'Replicate_Ignore_DB', - 'Replicate_Do_Table', 'Replicate_Ignore_Table', - 'Replicate_Wild_Do_Table', 'Replicate_Wild_Ignore_Table'); - if (in_array($variable, $variables_wrap)) { - $html .= htmlspecialchars(str_replace( - ',', - ', ', - ${"server_{$type}_replication"}[0][$variable] - )); - } else { - $html .= htmlspecialchars(${"server_{$type}_replication"}[0][$variable]); - } - $html .= ''; - - $html .= '
'; - $html .= '
'; - $html .= '
'; - - return $html; -} - -/** - * returns html code for table with slave users connected to this master - * - * @param boolean $hidden - if true, then default style is set to hidden, - * - default value false - * - * @return string - */ -function PMA_getHtmlForReplicationSlavesTable($hidden = false) -{ - $html = ''; - // Fetch data - $data = $GLOBALS['dbi']->fetchResult('SHOW SLAVE HOSTS', null, null); - - $html .= '
'; - $html .= '
'; - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - - foreach ($data as $slave) { - $html .= ' '; - $html .= ' '; - $html .= ' '; - $html .= ' '; - } - - $html .= ' '; - $html .= '
' . __('Server ID') . '' . __('Host') . '
' . $slave['Server_id'] . '' . $slave['Host'] . '
'; - $html .= '
'; - $html .= Message::notice( - __( - 'Only slaves started with the ' - . '--report-host=host_name option are visible in this list.' - ) - )->getDisplay(); - $html .= '
'; - $html .= '
'; - - return $html; -} - -/** - * get the correct username and hostname lengths for this MySQL server - * - * @return array username length, hostname length - */ -function PMA_replicationGetUsernameHostnameLength() -{ - $fields_info = $GLOBALS['dbi']->getColumns('mysql', 'user'); - $username_length = 16; - $hostname_length = 41; - foreach ($fields_info as $val) { - if ($val['Field'] == 'User') { - strtok($val['Type'], '()'); - $v = strtok('()'); - if (is_int($v)) { - $username_length = $v; - } - } elseif ($val['Field'] == 'Host') { - strtok($val['Type'], '()'); - $v = strtok('()'); - if (is_int($v)) { - $hostname_length = $v; - } - } - } - return array($username_length, $hostname_length); -} - -/** - * returns html code to add a replication slave user to the master - * - * @return String HTML code - */ -function PMA_getHtmlForReplicationMasterAddSlaveuser() -{ - $html = ''; - list($username_length, $hostname_length) - = PMA_replicationGetUsernameHostnameLength(); - - if (isset($_REQUEST['username']) && strlen($_REQUEST['username']) === 0) { - $GLOBALS['pred_username'] = 'any'; - } - $html .= '
'; - $html .= '
' . __('Add slave replication user') . '' - . PMA_getHtmlForAddUserLoginForm($username_length) - . '
' - . '' - . '' - . ' ' - . '' - . '' - . ' ' - . '' - . '
' - . '' - . '' - . ' ' - . '' - . '' - . '
'; - - return $html; -} - -/** - * returns HTML for TableInfoForm - * - * @param int $hostname_length Selected hostname length - * - * @return String HTML code - */ -function PMA_getHtmlForTableInfoForm($hostname_length) -{ - $html = ' ' - . ' ' - . ' ' - . '
' - . '' - . PhpMyAdmin\Util::showHint( - __( - 'When Host table is used, this field is ignored ' - . 'and values stored in Host table are used instead.' - ) - ) - . '
' - . '
' - . '' - . '' - . ' ' - . '' - . '' - . '
' - . '
' - . '' - . ' ' - . '' - . '
' - . '
' - . '' - . '' - . ' ' - . '' - . '' - . '
' - . ''; - $html .= ''; - return $html; -} - -/** - * handle control requests - * - * @return NULL - */ -function PMA_handleControlRequest() -{ - if (isset($_REQUEST['sr_take_action'])) { - $refresh = false; - $result = false; - $messageSuccess = null; - $messageError = null; - - if (isset($_REQUEST['slave_changemaster']) && ! $GLOBALS['cfg']['AllowArbitraryServer']) { - $_SESSION['replication']['sr_action_status'] = 'error'; - $_SESSION['replication']['sr_action_info'] = __('Connection to server is disabled, please enable $cfg[\'AllowArbitraryServer\'] in phpMyAdmin configuration.'); - } elseif (isset($_REQUEST['slave_changemaster'])) { - $result = PMA_handleRequestForSlaveChangeMaster(); - } elseif (isset($_REQUEST['sr_slave_server_control'])) { - $result = PMA_handleRequestForSlaveServerControl(); - $refresh = true; - - switch ($_REQUEST['sr_slave_action']) { - case 'start': - $messageSuccess = __('Replication started successfully.'); - $messageError = __('Error starting replication.'); - break; - case 'stop': - $messageSuccess = __('Replication stopped successfully.'); - $messageError = __('Error stopping replication.'); - break; - case 'reset': - $messageSuccess = __('Replication resetting successfully.'); - $messageError = __('Error resetting replication.'); - break; - default: - $messageSuccess = __('Success.'); - $messageError = __('Error.'); - break; - } - } elseif (isset($_REQUEST['sr_slave_skip_error'])) { - $result = PMA_handleRequestForSlaveSkipError(); - } - - if ($refresh) { - $response = Response::getInstance(); - if ($response->isAjax()) { - $response->setRequestStatus($result); - $response->addJSON( - 'message', - $result - ? Message::success($messageSuccess) - : Message::error($messageError) - ); - } else { - Core::sendHeaderLocation( - './server_replication.php' - . Url::getCommonRaw($GLOBALS['url_params']) - ); - } - } - unset($refresh); - } -} -/** - * handle control requests for Slave Change Master - * - * @return boolean - */ -function PMA_handleRequestForSlaveChangeMaster() -{ - $sr = array(); - $_SESSION['replication']['m_username'] = $sr['username'] - = $GLOBALS['dbi']->escapeString($_REQUEST['username']); - $_SESSION['replication']['m_password'] = $sr['pma_pw'] - = $GLOBALS['dbi']->escapeString($_REQUEST['pma_pw']); - $_SESSION['replication']['m_hostname'] = $sr['hostname'] - = $GLOBALS['dbi']->escapeString($_REQUEST['hostname']); - $_SESSION['replication']['m_port'] = $sr['port'] - = $GLOBALS['dbi']->escapeString($_REQUEST['text_port']); - $_SESSION['replication']['m_correct'] = ''; - $_SESSION['replication']['sr_action_status'] = 'error'; - $_SESSION['replication']['sr_action_info'] = __('Unknown error'); - - // Attempt to connect to the new master server - $link_to_master = Replication::connectToMaster( - $sr['username'], $sr['pma_pw'], $sr['hostname'], $sr['port'] - ); - - if (! $link_to_master) { - $_SESSION['replication']['sr_action_status'] = 'error'; - $_SESSION['replication']['sr_action_info'] = sprintf( - __('Unable to connect to master %s.'), - htmlspecialchars($sr['hostname']) - ); - } else { - // Read the current master position - $position = Replication::slaveBinLogMaster($link_to_master); - - if (empty($position)) { - $_SESSION['replication']['sr_action_status'] = 'error'; - $_SESSION['replication']['sr_action_info'] - = __( - 'Unable to read master log position. ' - . 'Possible privilege problem on master.' - ); - } else { - $_SESSION['replication']['m_correct'] = true; - - if (! Replication::slaveChangeMaster( - $sr['username'], - $sr['pma_pw'], - $sr['hostname'], - $sr['port'], - $position, - true, - false - ) - ) { - $_SESSION['replication']['sr_action_status'] = 'error'; - $_SESSION['replication']['sr_action_info'] - = __('Unable to change master!'); - } else { - $_SESSION['replication']['sr_action_status'] = 'success'; - $_SESSION['replication']['sr_action_info'] = sprintf( - __('Master server changed successfully to %s.'), - htmlspecialchars($sr['hostname']) - ); - } - } - } - - return $_SESSION['replication']['sr_action_status'] === 'success'; -} - -/** - * handle control requests for Slave Server Control - * - * @return boolean - */ -function PMA_handleRequestForSlaveServerControl() -{ - if (empty($_REQUEST['sr_slave_control_parm'])) { - $_REQUEST['sr_slave_control_parm'] = null; - } - if ($_REQUEST['sr_slave_action'] == 'reset') { - $qStop = Replication::slaveControl("STOP"); - $qReset = $GLOBALS['dbi']->tryQuery("RESET SLAVE;"); - $qStart = Replication::slaveControl("START"); - - $result = ($qStop !== false && $qStop !== -1 && - $qReset !== false && $qReset !== -1 && - $qStart !== false && $qStart !== -1); - } else { - $qControl = Replication::slaveControl( - $_REQUEST['sr_slave_action'], - $_REQUEST['sr_slave_control_parm'] - ); - - $result = ($qControl !== false && $qControl !== -1); - } - - return $result; -} - -/** - * handle control requests for Slave Skip Error - * - * @return boolean - */ -function PMA_handleRequestForSlaveSkipError() -{ - $count = 1; - if (isset($_REQUEST['sr_skip_errors_count'])) { - $count = $_REQUEST['sr_skip_errors_count'] * 1; - } - - $qStop = Replication::slaveControl("STOP"); - $qSkip = $GLOBALS['dbi']->tryQuery( - "SET GLOBAL SQL_SLAVE_SKIP_COUNTER = " . $count . ";" - ); - $qStart = Replication::slaveControl("START"); - - $result = ($qStop !== false && $qStop !== -1 && - $qSkip !== false && $qSkip !== -1 && - $qStart !== false && $qStart !== -1); - - return $result; -} diff --git a/server_replication.php b/server_replication.php index 90176093fa..832f7ad74b 100644 --- a/server_replication.php +++ b/server_replication.php @@ -5,6 +5,8 @@ * * @package PhpMyAdmin */ + +use PhpMyAdmin\ReplicationGui; use PhpMyAdmin\Response; use PhpMyAdmin\Server\Common; @@ -13,9 +15,7 @@ use PhpMyAdmin\Server\Common; */ require_once 'libraries/common.inc.php'; require_once 'libraries/server_common.inc.php'; - require_once 'libraries/replication.inc.php'; -require_once 'libraries/replication_gui.lib.php'; /** * Does the common work @@ -46,7 +46,7 @@ if (isset($_REQUEST['url_params']) && is_array($_REQUEST['url_params'])) { /** * Handling control requests */ -PMA_handleControlRequest(); +ReplicationGui::handleControlRequest(); /** * start output @@ -55,19 +55,19 @@ $response->addHTML('
'); $response->addHTML(Common::getHtmlForSubPageHeader('replication')); // Display error messages -$response->addHTML(PMA_getHtmlForErrorMessage()); +$response->addHTML(ReplicationGui::getHtmlForErrorMessage()); if ($GLOBALS['replication_info']['master']['status']) { - $response->addHTML(PMA_getHtmlForMasterReplication()); + $response->addHTML(ReplicationGui::getHtmlForMasterReplication()); } elseif (! isset($_REQUEST['mr_configure']) && ! isset($_REQUEST['repl_clear_scr']) ) { - $response->addHTML(PMA_getHtmlForNotServerReplication()); + $response->addHTML(ReplicationGui::getHtmlForNotServerReplication()); } if (isset($_REQUEST['mr_configure'])) { // Render the 'Master configuration' section - $response->addHTML(PMA_getHtmlForMasterConfiguration()); + $response->addHTML(ReplicationGui::getHtmlForMasterConfiguration()); exit; } @@ -76,12 +76,12 @@ $response->addHTML('
'); if (! isset($_REQUEST['repl_clear_scr'])) { // Render the 'Slave configuration' section $response->addHTML( - PMA_getHtmlForSlaveConfiguration( + ReplicationGui::getHtmlForSlaveConfiguration( $GLOBALS['replication_info']['slave']['status'], $server_slave_replication ) ); } if (isset($_REQUEST['sl_configure'])) { - $response->addHTML(PMA_getHtmlForReplicationChangeMaster("slave_changemaster")); + $response->addHTML(ReplicationGui::getHtmlForReplicationChangeMaster("slave_changemaster")); } diff --git a/server_status.php b/server_status.php index 3441fca223..757ba04c99 100644 --- a/server_status.php +++ b/server_status.php @@ -18,7 +18,6 @@ require_once 'libraries/server_common.inc.php'; * Replication library */ require_once 'libraries/replication.inc.php'; -require_once 'libraries/replication_gui.lib.php'; /** * start output diff --git a/server_status_advisor.php b/server_status_advisor.php index e9df08518c..01f08070ab 100644 --- a/server_status_advisor.php +++ b/server_status_advisor.php @@ -13,7 +13,6 @@ use PhpMyAdmin\Server\Status\Data; require_once 'libraries/common.inc.php'; require_once 'libraries/replication.inc.php'; -require_once 'libraries/replication_gui.lib.php'; $serverStatusData = new Data(); diff --git a/server_status_monitor.php b/server_status_monitor.php index 091192eea1..7bfc6ac597 100644 --- a/server_status_monitor.php +++ b/server_status_monitor.php @@ -13,7 +13,6 @@ use PhpMyAdmin\Response; require_once 'libraries/common.inc.php'; require_once 'libraries/server_common.inc.php'; require_once 'libraries/replication.inc.php'; -require_once 'libraries/replication_gui.lib.php'; $response = Response::getInstance(); diff --git a/server_status_processes.php b/server_status_processes.php index 84165a6fe9..5919599e02 100644 --- a/server_status_processes.php +++ b/server_status_processes.php @@ -17,7 +17,6 @@ require_once 'libraries/server_common.inc.php'; * Replication library */ require_once 'libraries/replication.inc.php'; -require_once 'libraries/replication_gui.lib.php'; $serverStatusData = new Data(); $response = Response::getInstance(); diff --git a/server_status_queries.php b/server_status_queries.php index ac71c1c72c..27fa6c9956 100644 --- a/server_status_queries.php +++ b/server_status_queries.php @@ -15,7 +15,6 @@ use PhpMyAdmin\Server\Status\Queries; require_once 'libraries/common.inc.php'; require_once 'libraries/server_common.inc.php'; require_once 'libraries/replication.inc.php'; -require_once 'libraries/replication_gui.lib.php'; $serverStatusData = new Data(); diff --git a/server_status_variables.php b/server_status_variables.php index 7aee193a6d..492c14348d 100644 --- a/server_status_variables.php +++ b/server_status_variables.php @@ -14,7 +14,6 @@ use PhpMyAdmin\Server\Status\Variables; require_once 'libraries/common.inc.php'; require_once 'libraries/server_common.inc.php'; require_once 'libraries/replication.inc.php'; -require_once 'libraries/replication_gui.lib.php'; /** * flush status variables if requested diff --git a/test/libraries/PMA_server_replication_test.php b/test/classes/ReplicationGuiTest.php similarity index 87% rename from test/libraries/PMA_server_replication_test.php rename to test/classes/ReplicationGuiTest.php index 7daa47de91..e203af5763 100644 --- a/test/libraries/PMA_server_replication_test.php +++ b/test/classes/ReplicationGuiTest.php @@ -1,28 +1,29 @@ assertContains( @@ -120,7 +121,7 @@ class PMA_ServerReplication_Test extends PHPUnit_Framework_TestCase $html ); - //validate 2: PMA_getHtmlForReplicationStatusTable + //validate 2: ReplicationGui::getHtmlForReplicationStatusTable $this->assertContains( '
assertContains( 'replication_slaves_section', $html @@ -194,14 +195,14 @@ class PMA_ServerReplication_Test extends PHPUnit_Framework_TestCase } /** - * Test for PMA_getHtmlForNotServerReplication + * Test for ReplicationGui::getHtmlForNotServerReplication * * @return void */ public function testPMAGetHtmlForNotServerReplication() { //Call the test function - $html = PMA_getHtmlForNotServerReplication(); + $html = ReplicationGui::getHtmlForNotServerReplication(); $this->assertContains( 'Master replication', @@ -214,7 +215,7 @@ class PMA_ServerReplication_Test extends PHPUnit_Framework_TestCase } /** - * Test for PMA_getHtmlForSlaveConfiguration + * Test for ReplicationGui::getHtmlForSlaveConfiguration * * @return void */ @@ -223,7 +224,7 @@ class PMA_ServerReplication_Test extends PHPUnit_Framework_TestCase global $server_slave_replication; //Call the test function - $html = PMA_getHtmlForSlaveConfiguration( + $html = ReplicationGui::getHtmlForSlaveConfiguration( true, $server_slave_replication ); @@ -267,14 +268,14 @@ class PMA_ServerReplication_Test extends PHPUnit_Framework_TestCase } /** - * Test for PMA_getHtmlForReplicationChangeMaster + * Test for ReplicationGui::getHtmlForReplicationChangeMaster * * @return void */ public function testPMAGetHtmlForReplicationChangeMaster() { //Call the test function - $html = PMA_getHtmlForReplicationChangeMaster("slave_changemaster"); + $html = ReplicationGui::getHtmlForReplicationChangeMaster("slave_changemaster"); $this->assertContains( '', From d2c487e378fc8ab3f25ca60d1045a9154b465cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 13 Sep 2017 18:48:10 -0300 Subject: [PATCH 3/5] Refactor pmd_common functions to static methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- db_designer.php | 44 +- libraries/classes/PmdCommon.php | 775 ++++++++++++++++++ libraries/pmd_common.php | 773 ----------------- schema_export.php | 2 - .../PmdCommonTest.php} | 58 +- 5 files changed, 827 insertions(+), 825 deletions(-) create mode 100644 libraries/classes/PmdCommon.php delete mode 100644 libraries/pmd_common.php rename test/{libraries/PMA_PMD_common_test.php => classes/PmdCommonTest.php} (83%) diff --git a/db_designer.php b/db_designer.php index ceb4f89ed6..0db302be72 100644 --- a/db_designer.php +++ b/db_designer.php @@ -6,10 +6,10 @@ * @package PhpMyAdmin-Designer */ use PhpMyAdmin\Database\Designer; +use PhpMyAdmin\PmdCommon; use PhpMyAdmin\Response; require_once 'libraries/common.inc.php'; -require_once 'libraries/pmd_common.php'; $response = Response::getInstance(); @@ -26,11 +26,11 @@ if (isset($_REQUEST['dialog'])) { $GLOBALS['db'], $_REQUEST['selected_page'] ); } else if ($_REQUEST['dialog'] == 'add_table') { - $script_display_field = PMA_getTablesInfo(); + $script_display_field = PmdCommon::getTablesInfo(); $required = $GLOBALS['db'] . '.' . $GLOBALS['table']; - $tab_column = PMA_getColumnsInfo(); - $tables_all_keys = PMA_getAllKeys(); - $tables_pk_or_unique_keys = PMA_getPKOrUniqueKeys(); + $tab_column = PmdCommon::getColumnsInfo(); + $tables_all_keys = PmdCommon::getAllKeys(); + $tables_pk_or_unique_keys = PmdCommon::getPkOrUniqueKeys(); $req_key = array_search($required, $GLOBALS['PMD']['TABLE_NAME']); @@ -56,24 +56,24 @@ if (isset($_REQUEST['dialog'])) { if (isset($_REQUEST['operation'])) { if ($_REQUEST['operation'] == 'deletePage') { - $success = PMA_deletePage($_REQUEST['selected_page']); + $success = PmdCommon::deletePage($_REQUEST['selected_page']); $response->setRequestStatus($success); } elseif ($_REQUEST['operation'] == 'savePage') { if ($_REQUEST['save_page'] == 'same') { $page = $_REQUEST['selected_page']; } else { // new - $page = PMA_createNewPage($_REQUEST['selected_value'], $GLOBALS['db']); + $page = PmdCommon::createNewPage($_REQUEST['selected_value'], $GLOBALS['db']); $response->addJSON('id', $page); } - $success = PMA_saveTablePositions($page); + $success = PmdCommon::saveTablePositions($page); $response->setRequestStatus($success); } elseif ($_REQUEST['operation'] == 'setDisplayField') { - PMA_saveDisplayField( + PmdCommon::saveDisplayField( $_REQUEST['db'], $_REQUEST['table'], $_REQUEST['field'] ); $response->setRequestStatus(true); } elseif ($_REQUEST['operation'] == 'addNewRelation') { - list($success, $message) = PMA_addNewRelation( + list($success, $message) = PmdCommon::addNewRelation( $_REQUEST['db'], $_REQUEST['T1'], $_REQUEST['F1'], @@ -87,7 +87,7 @@ if (isset($_REQUEST['operation'])) { $response->setRequestStatus($success); $response->addJSON('message', $message); } elseif ($_REQUEST['operation'] == 'removeRelation') { - list($success, $message) = PMA_removeRelation( + list($success, $message) = PmdCommon::removeRelation( $_REQUEST['T1'], $_REQUEST['F1'], $_REQUEST['T2'], @@ -96,7 +96,7 @@ if (isset($_REQUEST['operation'])) { $response->setRequestStatus($success); $response->addJSON('message', $message); } elseif ($_REQUEST['operation'] == 'save_setting_value') { - $success = PMA_saveDesignerSetting($_REQUEST['index'], $_REQUEST['value']); + $success = PmdCommon::saveDesignerSetting($_REQUEST['index'], $_REQUEST['value']); $response->setRequestStatus($success); } @@ -105,30 +105,30 @@ if (isset($_REQUEST['operation'])) { require 'libraries/db_common.inc.php'; -$script_display_field = PMA_getTablesInfo(); -$tab_column = PMA_getColumnsInfo(); -$script_tables = PMA_getScriptTabs(); -$tables_pk_or_unique_keys = PMA_getPKOrUniqueKeys(); -$tables_all_keys = PMA_getAllKeys(); +$script_display_field = PmdCommon::getTablesInfo(); +$tab_column = PmdCommon::getColumnsInfo(); +$script_tables = PmdCommon::getScriptTabs(); +$tables_pk_or_unique_keys = PmdCommon::getPkOrUniqueKeys(); +$tables_all_keys = PmdCommon::getAllKeys(); $classes_side_menu = Designer::returnClassNamesFromMenuButtons(); $display_page = -1; $selected_page = null; if (isset($_REQUEST['query'])) { - $display_page = PMA_getDefaultPage($_REQUEST['db']); + $display_page = PmdCommon::getDefaultPage($_REQUEST['db']); } else { if (! empty($_REQUEST['page'])) { $display_page = $_REQUEST['page']; } else { - $display_page = PMA_getLoadingPage($_REQUEST['db']); + $display_page = PmdCommon::getLoadingPage($_REQUEST['db']); } } if ($display_page != -1) { - $selected_page = PMA_getPageName($display_page); + $selected_page = PmdCommon::getPageName($display_page); } -$tab_pos = PMA_getTablePositions($display_page); -$script_contr = PMA_getScriptContr(); +$tab_pos = PmdCommon::getTablePositions($display_page); +$script_contr = PmdCommon::getScriptContr(); $params = array('lang' => $GLOBALS['lang']); if (isset($_GET['db'])) { diff --git a/libraries/classes/PmdCommon.php b/libraries/classes/PmdCommon.php new file mode 100644 index 0000000000..3422918d90 --- /dev/null +++ b/libraries/classes/PmdCommon.php @@ -0,0 +1,775 @@ +getTablesFull($GLOBALS['db']); + // seems to be needed later + $GLOBALS['dbi']->selectDb($GLOBALS['db']); + $i = 0; + foreach ($tables as $one_table) { + $GLOBALS['PMD']['TABLE_NAME'][$i] + = $GLOBALS['db'] . "." . $one_table['TABLE_NAME']; + $GLOBALS['PMD']['OWNER'][$i] = $GLOBALS['db']; + $GLOBALS['PMD']['TABLE_NAME_SMALL'][$i] = htmlspecialchars( + $one_table['TABLE_NAME'], ENT_QUOTES + ); + + $GLOBALS['PMD_URL']['TABLE_NAME'][$i] + = $GLOBALS['db'] . "." . $one_table['TABLE_NAME']; + $GLOBALS['PMD_URL']['OWNER'][$i] = $GLOBALS['db']; + $GLOBALS['PMD_URL']['TABLE_NAME_SMALL'][$i] + = $one_table['TABLE_NAME']; + + $GLOBALS['PMD_OUT']['TABLE_NAME'][$i] = htmlspecialchars( + $GLOBALS['db'] . "." . $one_table['TABLE_NAME'], ENT_QUOTES + ); + $GLOBALS['PMD_OUT']['OWNER'][$i] = htmlspecialchars( + $GLOBALS['db'], ENT_QUOTES + ); + $GLOBALS['PMD_OUT']['TABLE_NAME_SMALL'][$i] = htmlspecialchars( + $one_table['TABLE_NAME'], ENT_QUOTES + ); + + $GLOBALS['PMD']['TABLE_TYPE'][$i] = mb_strtoupper( + $one_table['ENGINE'] + ); + + $DF = Relation::getDisplayField($GLOBALS['db'], $one_table['TABLE_NAME']); + if ($DF != '') { + $retval[$GLOBALS['PMD_URL']["TABLE_NAME_SMALL"][$i]] = $DF; + } + + $i++; + } + + return $retval; + } + + /** + * Retrieves table column info + * + * @return array table column nfo + */ + public static function getColumnsInfo() + { + $GLOBALS['dbi']->selectDb($GLOBALS['db']); + $tab_column = array(); + for ($i = 0, $cnt = count($GLOBALS['PMD']["TABLE_NAME"]); $i < $cnt; $i++) { + $fields_rs = $GLOBALS['dbi']->query( + $GLOBALS['dbi']->getColumnsSql( + $GLOBALS['db'], + $GLOBALS['PMD_URL']["TABLE_NAME_SMALL"][$i], + null, + true + ), + null, + DatabaseInterface::QUERY_STORE + ); + $tbl_name_i = $GLOBALS['PMD']['TABLE_NAME'][$i]; + $j = 0; + while ($row = $GLOBALS['dbi']->fetchAssoc($fields_rs)) { + $tab_column[$tbl_name_i]['COLUMN_ID'][$j] = $j; + $tab_column[$tbl_name_i]['COLUMN_NAME'][$j] = $row['Field']; + $tab_column[$tbl_name_i]['TYPE'][$j] = $row['Type']; + $tab_column[$tbl_name_i]['NULLABLE'][$j] = $row['Null']; + $j++; + } + } + return $tab_column; + } + + /** + * Returns JavaScript code for initializing vars + * + * @return string JavaScript code + */ + public static function getScriptContr() + { + $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']), + null, + DatabaseInterface::QUERY_STORE + ); + while ($val = @$GLOBALS['dbi']->fetchRow($alltab_rs)) { + $row = Relation::getForeigners($GLOBALS['db'], $val[0], '', 'internal'); + + if ($row !== false) { + foreach ($row as $field => $value) { + $con['C_NAME'][$i] = ''; + $con['DTN'][$i] = urlencode($GLOBALS['db'] . "." . $val[0]); + $con['DCN'][$i] = urlencode($field); + $con['STN'][$i] = urlencode( + $value['foreign_db'] . "." . $value['foreign_table'] + ); + $con['SCN'][$i] = urlencode($value['foreign_field']); + $i++; + } + } + $row = Relation::getForeigners($GLOBALS['db'], $val[0], '', 'foreign'); + + if ($row !== false) { + foreach ($row['foreign_keys_data'] as $one_key) { + foreach ($one_key['index_list'] as $index => $one_field) { + $con['C_NAME'][$i] = $one_key['constraint']; + $con['DTN'][$i] = urlencode($GLOBALS['db'] . "." . $val[0]); + $con['DCN'][$i] = urlencode($one_field); + $con['STN'][$i] = urlencode( + (isset($one_key['ref_db_name']) ? + $one_key['ref_db_name'] : $GLOBALS['db']) + . "." . $one_key['ref_table_name'] + ); + $con['SCN'][$i] = urlencode($one_key['ref_index_list'][$index]); + $i++; + } + } + } + } + + $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, $GLOBALS['PMD_URL']["TABLE_NAME"]) + && in_array($con['STN'][$i], $GLOBALS['PMD_URL']["TABLE_NAME"]) + ) { + $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 + * + * @return array unique or primary indices + */ + public static function getPkOrUniqueKeys() + { + return self::getAllKeys(true); + } + + /** + * Returns all indices + * + * @param bool $unique_only whether to include only unique ones + * + * @return array indices + */ + public static function getAllKeys($unique_only = false) + { + $keys = array(); + + foreach ($GLOBALS['PMD']['TABLE_NAME_SMALL'] as $I => $table) { + $schema = $GLOBALS['PMD']['OWNER'][$I]; + // for now, take into account only the first index segment + foreach (Index::getFromTable($table, $schema) as $index) { + if ($unique_only && ! $index->isUnique()) { + continue; + } + $columns = $index->getColumns(); + foreach ($columns as $column_name => $dummy) { + $keys[$schema . '.' . $table . '.' . $column_name] = 1; + } + } + } + return $keys; + } + + /** + * Return script to create j_tab and h_tab arrays + * + * @return string + */ + public static function getScriptTabs() + { + $retval = array( + 'j_tabs' => array(), + 'h_tabs' => array() + ); + + for ($i = 0, $cnt = count($GLOBALS['PMD']['TABLE_NAME']); $i < $cnt; $i++) { + $j = 0; + if (Util::isForeignKeySupported($GLOBALS['PMD']['TABLE_TYPE'][$i])) { + $j = 1; + } + $retval['j_tabs'][$GLOBALS['PMD_URL']['TABLE_NAME'][$i]] = $j; + $retval['h_tabs'][$GLOBALS['PMD_URL']['TABLE_NAME'][$i]] = 1; + } + return $retval; + } + + /** + * Returns table positions of a given pdf page + * + * @param int $pg pdf page id + * + * @return array of table positions + */ + public static function getTablePositions($pg) + { + $cfgRelation = Relation::getRelationsParam(); + if (! $cfgRelation['pdfwork']) { + return null; + } + + $query = " + SELECT CONCAT_WS('.', `db_name`, `table_name`) AS `name`, + `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, + $GLOBALS['controllink'], + DatabaseInterface::QUERY_STORE + ); + return $tab_pos; + } + + /** + * Returns page name of a given pdf page + * + * @param int $pg pdf page id + * + * @return String table name + */ + public static function getPageName($pg) + { + $cfgRelation = 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, + $GLOBALS['controllink'], + DatabaseInterface::QUERY_STORE + ); + return count($page_name) ? $page_name[0] : null; + } + + /** + * Deletes a given pdf page and its corresponding coordinates + * + * @param int $pg page id + * + * @return boolean success/failure + */ + public static function deletePage($pg) + { + $cfgRelation = 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 = 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 = 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 static function getDefaultPage($db) + { + $cfgRelation = Relation::getRelationsParam(); + if (! $cfgRelation['pdfwork']) { + return null; + } + + $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, + $GLOBALS['controllink'], + DatabaseInterface::QUERY_STORE + ); + + if (count($default_page_no)) { + 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 static function getLoadingPage($db) + { + $cfgRelation = Relation::getRelationsParam(); + if (! $cfgRelation['pdfwork']) { + return null; + } + + $page_no = -1; + + $default_page_no = self::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, + $GLOBALS['controllink'], + DatabaseInterface::QUERY_STORE + ); + if (count($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 static function createNewPage($pageName, $db) + { + $cfgRelation = Relation::getRelationsParam(); + if ($cfgRelation['pdfwork']) { + $pageNumber = 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 static function saveTablePositions($pg) + { + $cfgRelation = Relation::getRelationsParam(); + if (! $cfgRelation['pdfwork']) { + return false; + } + + $query = "DELETE FROM " + . Util::backquote($GLOBALS['cfgRelation']['db']) + . "." . Util::backquote( + $GLOBALS['cfgRelation']['table_coords'] + ) + . " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($_REQUEST['db']) + . "'" + . " AND `pdf_page_number` = '" . $GLOBALS['dbi']->escapeString($pg) + . "'"; + + $res = Relation::queryAsControlUser( + $query, + true, + DatabaseInterface::QUERY_STORE + ); + + if (!$res) { + return (boolean)$res; + } + + foreach ($_REQUEST['t_h'] as $key => $value) { + list($DB, $TAB) = explode(".", $key); + if (!$value) { + continue; + } + + $query = "INSERT INTO " + . Util::backquote($GLOBALS['cfgRelation']['db']) . "." + . Util::backquote($GLOBALS['cfgRelation']['table_coords']) + . " (`db_name`, `table_name`, `pdf_page_number`, `x`, `y`)" + . " VALUES (" + . "'" . $GLOBALS['dbi']->escapeString($DB) . "', " + . "'" . $GLOBALS['dbi']->escapeString($TAB) . "', " + . "'" . $GLOBALS['dbi']->escapeString($pg) . "', " + . "'" . $GLOBALS['dbi']->escapeString($_REQUEST['t_x'][$key]) . "', " + . "'" . $GLOBALS['dbi']->escapeString($_REQUEST['t_y'][$key]) . "')"; + + $res = 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 boolean + */ + public static function saveDisplayField($db, $table, $field) + { + $cfgRelation = Relation::getRelationsParam(); + if (!$cfgRelation['displaywork']) { + return false; + } + + $upd_query = new Table($table, $db, $GLOBALS['dbi']); + $upd_query->updateDisplayField($field, $cfgRelation); + + return true; + } + + /** + * 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 + * + * @return array array of success/failure and message + */ + public static 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 = Relation::getForeigners($DB2, $T2, '', 'foreign'); + $foreigner = 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!') + . "
" . $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 (Relation::queryAsControlUser($q, false, DatabaseInterface::QUERY_STORE) + ) { + return array(true, __('Internal relationship has been added.')); + } + + $error = $GLOBALS['dbi']->getError($GLOBALS['controllink']); + return array( + false, + __('Error: Internal relationship could not be added!') + . "
" . $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 static 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 = Relation::getForeigners($DB2, $T2, '', 'foreign'); + $foreigner = 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!') + . "
" . $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 = Relation::queryAsControlUser( + $delete_query, + false, + DatabaseInterface::QUERY_STORE + ); + + if (!$result) { + $error = $GLOBALS['dbi']->getError($GLOBALS['controllink']); + return array( + false, + __('Error: Internal relationship could not be removed!') . "
" . $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 static function saveDesignerSetting($index, $value) + { + $cfgRelation = Relation::getRelationsParam(); + $cfgDesigner = array( + 'user' => $GLOBALS['cfg']['Server']['user'], + 'db' => $cfgRelation['db'], + 'table' => $cfgRelation['designer_settings'] + ); + + $success = true; + if ($GLOBALS['cfgRelation']['designersettingswork']) { + + $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', $GLOBALS['controllink'] + ); + + 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 = 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('" . $cfgDesigner['user'] . "'," + . " '" . json_encode($save_data) . "');"; + + $success = Relation::queryAsControlUser($query); + } + } + + return (bool) $success; + } +} diff --git a/libraries/pmd_common.php b/libraries/pmd_common.php deleted file mode 100644 index 078b824f47..0000000000 --- a/libraries/pmd_common.php +++ /dev/null @@ -1,773 +0,0 @@ -getTablesFull($GLOBALS['db']); - // seems to be needed later - $GLOBALS['dbi']->selectDb($GLOBALS['db']); - $i = 0; - foreach ($tables as $one_table) { - $GLOBALS['PMD']['TABLE_NAME'][$i] - = $GLOBALS['db'] . "." . $one_table['TABLE_NAME']; - $GLOBALS['PMD']['OWNER'][$i] = $GLOBALS['db']; - $GLOBALS['PMD']['TABLE_NAME_SMALL'][$i] = htmlspecialchars( - $one_table['TABLE_NAME'], ENT_QUOTES - ); - - $GLOBALS['PMD_URL']['TABLE_NAME'][$i] - = $GLOBALS['db'] . "." . $one_table['TABLE_NAME']; - $GLOBALS['PMD_URL']['OWNER'][$i] = $GLOBALS['db']; - $GLOBALS['PMD_URL']['TABLE_NAME_SMALL'][$i] - = $one_table['TABLE_NAME']; - - $GLOBALS['PMD_OUT']['TABLE_NAME'][$i] = htmlspecialchars( - $GLOBALS['db'] . "." . $one_table['TABLE_NAME'], ENT_QUOTES - ); - $GLOBALS['PMD_OUT']['OWNER'][$i] = htmlspecialchars( - $GLOBALS['db'], ENT_QUOTES - ); - $GLOBALS['PMD_OUT']['TABLE_NAME_SMALL'][$i] = htmlspecialchars( - $one_table['TABLE_NAME'], ENT_QUOTES - ); - - $GLOBALS['PMD']['TABLE_TYPE'][$i] = mb_strtoupper( - $one_table['ENGINE'] - ); - - $DF = Relation::getDisplayField($GLOBALS['db'], $one_table['TABLE_NAME']); - if ($DF != '') { - $retval[$GLOBALS['PMD_URL']["TABLE_NAME_SMALL"][$i]] = $DF; - } - - $i++; - } - - return $retval; -} - -/** - * Retrieves table column info - * - * @return array table column nfo - */ -function PMA_getColumnsInfo() -{ - $GLOBALS['dbi']->selectDb($GLOBALS['db']); - $tab_column = array(); - for ($i = 0, $cnt = count($GLOBALS['PMD']["TABLE_NAME"]); $i < $cnt; $i++) { - $fields_rs = $GLOBALS['dbi']->query( - $GLOBALS['dbi']->getColumnsSql( - $GLOBALS['db'], - $GLOBALS['PMD_URL']["TABLE_NAME_SMALL"][$i], - null, - true - ), - null, - PhpMyAdmin\DatabaseInterface::QUERY_STORE - ); - $tbl_name_i = $GLOBALS['PMD']['TABLE_NAME'][$i]; - $j = 0; - while ($row = $GLOBALS['dbi']->fetchAssoc($fields_rs)) { - $tab_column[$tbl_name_i]['COLUMN_ID'][$j] = $j; - $tab_column[$tbl_name_i]['COLUMN_NAME'][$j] = $row['Field']; - $tab_column[$tbl_name_i]['TYPE'][$j] = $row['Type']; - $tab_column[$tbl_name_i]['NULLABLE'][$j] = $row['Null']; - $j++; - } - } - return $tab_column; -} - -/** - * Returns JavaScript code for initializing vars - * - * @return string JavaScript code - */ -function PMA_getScriptContr() -{ - $GLOBALS['dbi']->selectDb($GLOBALS['db']); - $con = array(); - $con["C_NAME"] = array(); - $i = 0; - $alltab_rs = $GLOBALS['dbi']->query( - 'SHOW TABLES FROM ' . PhpMyAdmin\Util::backquote($GLOBALS['db']), - null, - PhpMyAdmin\DatabaseInterface::QUERY_STORE - ); - while ($val = @$GLOBALS['dbi']->fetchRow($alltab_rs)) { - $row = Relation::getForeigners($GLOBALS['db'], $val[0], '', 'internal'); - - if ($row !== false) { - foreach ($row as $field => $value) { - $con['C_NAME'][$i] = ''; - $con['DTN'][$i] = urlencode($GLOBALS['db'] . "." . $val[0]); - $con['DCN'][$i] = urlencode($field); - $con['STN'][$i] = urlencode( - $value['foreign_db'] . "." . $value['foreign_table'] - ); - $con['SCN'][$i] = urlencode($value['foreign_field']); - $i++; - } - } - $row = Relation::getForeigners($GLOBALS['db'], $val[0], '', 'foreign'); - - if ($row !== false) { - foreach ($row['foreign_keys_data'] as $one_key) { - foreach ($one_key['index_list'] as $index => $one_field) { - $con['C_NAME'][$i] = $one_key['constraint']; - $con['DTN'][$i] = urlencode($GLOBALS['db'] . "." . $val[0]); - $con['DCN'][$i] = urlencode($one_field); - $con['STN'][$i] = urlencode( - (isset($one_key['ref_db_name']) ? - $one_key['ref_db_name'] : $GLOBALS['db']) - . "." . $one_key['ref_table_name'] - ); - $con['SCN'][$i] = urlencode($one_key['ref_index_list'][$index]); - $i++; - } - } - } - } - - $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, $GLOBALS['PMD_URL']["TABLE_NAME"]) - && in_array($con['STN'][$i], $GLOBALS['PMD_URL']["TABLE_NAME"]) - ) { - $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 - * - * @return array unique or primary indices - */ -function PMA_getPKOrUniqueKeys() -{ - return PMA_getAllKeys(true); -} - -/** - * Returns all indices - * - * @param bool $unique_only whether to include only unique ones - * - * @return array indices - */ -function PMA_getAllKeys($unique_only = false) -{ - $keys = array(); - - foreach ($GLOBALS['PMD']['TABLE_NAME_SMALL'] as $I => $table) { - $schema = $GLOBALS['PMD']['OWNER'][$I]; - // for now, take into account only the first index segment - foreach (PhpMyAdmin\Index::getFromTable($table, $schema) as $index) { - if ($unique_only && ! $index->isUnique()) { - continue; - } - $columns = $index->getColumns(); - foreach ($columns as $column_name => $dummy) { - $keys[$schema . '.' . $table . '.' . $column_name] = 1; - } - } - } - return $keys; -} - -/** - * Return script to create j_tab and h_tab arrays - * - * @return string - */ -function PMA_getScriptTabs() -{ - $retval = array( - 'j_tabs' => array(), - 'h_tabs' => array() - ); - - for ($i = 0, $cnt = count($GLOBALS['PMD']['TABLE_NAME']); $i < $cnt; $i++) { - $j = 0; - if (PhpMyAdmin\Util::isForeignKeySupported($GLOBALS['PMD']['TABLE_TYPE'][$i])) { - $j = 1; - } - $retval['j_tabs'][$GLOBALS['PMD_URL']['TABLE_NAME'][$i]] = $j; - $retval['h_tabs'][$GLOBALS['PMD_URL']['TABLE_NAME'][$i]] = 1; - } - return $retval; -} - -/** - * Returns table positions of a given pdf page - * - * @param int $pg pdf page id - * - * @return array of table positions - */ -function PMA_getTablePositions($pg) -{ - $cfgRelation = Relation::getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return null; - } - - $query = " - SELECT CONCAT_WS('.', `db_name`, `table_name`) AS `name`, - `x` AS `X`, - `y` AS `Y`, - 1 AS `V`, - 1 AS `H` - FROM " . PhpMyAdmin\Util::backquote($cfgRelation['db']) - . "." . PhpMyAdmin\Util::backquote($cfgRelation['table_coords']) . " - WHERE pdf_page_number = " . intval($pg); - - $tab_pos = $GLOBALS['dbi']->fetchResult( - $query, - 'name', - null, - $GLOBALS['controllink'], - PhpMyAdmin\DatabaseInterface::QUERY_STORE - ); - return $tab_pos; -} - -/** - * Returns page name of a given pdf page - * - * @param int $pg pdf page id - * - * @return String table name - */ -function PMA_getPageName($pg) -{ - $cfgRelation = Relation::getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return null; - } - - $query = "SELECT `page_descr`" - . " FROM " . PhpMyAdmin\Util::backquote($cfgRelation['db']) - . "." . PhpMyAdmin\Util::backquote($cfgRelation['pdf_pages']) - . " WHERE " . PhpMyAdmin\Util::backquote('page_nr') . " = " . intval($pg); - $page_name = $GLOBALS['dbi']->fetchResult( - $query, - null, - null, - $GLOBALS['controllink'], - PhpMyAdmin\DatabaseInterface::QUERY_STORE - ); - return count($page_name) ? $page_name[0] : null; -} - -/** - * Deletes a given pdf page and its corresponding coordinates - * - * @param int $pg page id - * - * @return boolean success/failure - */ -function PMA_deletePage($pg) -{ - $cfgRelation = Relation::getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return false; - } - - $query = "DELETE FROM " . PhpMyAdmin\Util::backquote($cfgRelation['db']) - . "." . PhpMyAdmin\Util::backquote($cfgRelation['table_coords']) - . " WHERE " . PhpMyAdmin\Util::backquote('pdf_page_number') . " = " . intval($pg); - $success = Relation::queryAsControlUser( - $query, true, PhpMyAdmin\DatabaseInterface::QUERY_STORE - ); - - if ($success) { - $query = "DELETE FROM " . PhpMyAdmin\Util::backquote($cfgRelation['db']) - . "." . PhpMyAdmin\Util::backquote($cfgRelation['pdf_pages']) - . " WHERE " . PhpMyAdmin\Util::backquote('page_nr') . " = " . intval($pg); - $success = Relation::queryAsControlUser( - $query, true, PhpMyAdmin\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 - */ -function PMA_getDefaultPage($db) -{ - $cfgRelation = Relation::getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return null; - } - - $query = "SELECT `page_nr`" - . " FROM " . PhpMyAdmin\Util::backquote($cfgRelation['db']) - . "." . PhpMyAdmin\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, - $GLOBALS['controllink'], - PhpMyAdmin\DatabaseInterface::QUERY_STORE - ); - - if (count($default_page_no)) { - 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 - */ -function PMA_getLoadingPage($db) -{ - $cfgRelation = Relation::getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return null; - } - - $page_no = -1; - - $default_page_no = PMA_getDefaultPage($db); - if ($default_page_no != -1) { - $page_no = $default_page_no; - } else { - $query = "SELECT MIN(`page_nr`)" - . " FROM " . PhpMyAdmin\Util::backquote($cfgRelation['db']) - . "." . PhpMyAdmin\Util::backquote($cfgRelation['pdf_pages']) - . " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($db) . "'"; - - $min_page_no = $GLOBALS['dbi']->fetchResult( - $query, - null, - null, - $GLOBALS['controllink'], - PhpMyAdmin\DatabaseInterface::QUERY_STORE - ); - if (count($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 - */ -function PMA_createNewPage($pageName, $db) -{ - $cfgRelation = Relation::getRelationsParam(); - if ($cfgRelation['pdfwork']) { - $pageNumber = 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 - */ -function PMA_saveTablePositions($pg) -{ - $cfgRelation = Relation::getRelationsParam(); - if (! $cfgRelation['pdfwork']) { - return false; - } - - $query = "DELETE FROM " - . PhpMyAdmin\Util::backquote($GLOBALS['cfgRelation']['db']) - . "." . PhpMyAdmin\Util::backquote( - $GLOBALS['cfgRelation']['table_coords'] - ) - . " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($_REQUEST['db']) - . "'" - . " AND `pdf_page_number` = '" . $GLOBALS['dbi']->escapeString($pg) - . "'"; - - $res = Relation::queryAsControlUser( - $query, - true, - PhpMyAdmin\DatabaseInterface::QUERY_STORE - ); - - if (!$res) { - return (boolean)$res; - } - - foreach ($_REQUEST['t_h'] as $key => $value) { - list($DB, $TAB) = explode(".", $key); - if (!$value) { - continue; - } - - $query = "INSERT INTO " - . PhpMyAdmin\Util::backquote($GLOBALS['cfgRelation']['db']) . "." - . PhpMyAdmin\Util::backquote($GLOBALS['cfgRelation']['table_coords']) - . " (`db_name`, `table_name`, `pdf_page_number`, `x`, `y`)" - . " VALUES (" - . "'" . $GLOBALS['dbi']->escapeString($DB) . "', " - . "'" . $GLOBALS['dbi']->escapeString($TAB) . "', " - . "'" . $GLOBALS['dbi']->escapeString($pg) . "', " - . "'" . $GLOBALS['dbi']->escapeString($_REQUEST['t_x'][$key]) . "', " - . "'" . $GLOBALS['dbi']->escapeString($_REQUEST['t_y'][$key]) . "')"; - - $res = Relation::queryAsControlUser( - $query, true, PhpMyAdmin\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 boolean - */ -function PMA_saveDisplayField($db, $table, $field) -{ - $cfgRelation = Relation::getRelationsParam(); - if (!$cfgRelation['displaywork']) { - return false; - } - - $upd_query = new Table($table, $db, $GLOBALS['dbi']); - $upd_query->updateDisplayField($field, $cfgRelation); - - return true; -} - -/** - * 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 - * - * @return array array of success/failure and message - */ -function PMA_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 (PhpMyAdmin\Util::isForeignKeySupported($type_T1) - && PhpMyAdmin\Util::isForeignKeySupported($type_T2) - && $type_T1 == $type_T2 - ) { - // relation exists? - $existrel_foreign = Relation::getForeigners($DB2, $T2, '', 'foreign'); - $foreigner = 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 ' . PhpMyAdmin\Util::backquote($DB1) - . '.' . PhpMyAdmin\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 ' . PhpMyAdmin\Util::backquote($DB2) - . '.' . PhpMyAdmin\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 ' . PhpMyAdmin\Util::backquote($DB2) - . '.' . PhpMyAdmin\Util::backquote($T2) - . ' ADD FOREIGN KEY (' - . PhpMyAdmin\Util::backquote($F2) . ')' - . ' REFERENCES ' - . PhpMyAdmin\Util::backquote($DB1) . '.' - . PhpMyAdmin\Util::backquote($T1) . '(' - . PhpMyAdmin\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!') - . "
" . $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 " - . PhpMyAdmin\Util::backquote($GLOBALS['cfgRelation']['db']) - . "." - . PhpMyAdmin\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 (Relation::queryAsControlUser($q, false, PhpMyAdmin\DatabaseInterface::QUERY_STORE) - ) { - return array(true, __('Internal relationship has been added.')); - } - - $error = $GLOBALS['dbi']->getError($GLOBALS['controllink']); - return array( - false, - __('Error: Internal relationship could not be added!') - . "
" . $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 - */ -function PMA_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 (PhpMyAdmin\Util::isForeignKeySupported($type_T1) - && PhpMyAdmin\Util::isForeignKeySupported($type_T2) - && $type_T1 == $type_T2 - ) { - // InnoDB - $existrel_foreign = Relation::getForeigners($DB2, $T2, '', 'foreign'); - $foreigner = Relation::searchColumnInForeigners($existrel_foreign, $F2); - - if (isset($foreigner['constraint'])) { - $upd_query = 'ALTER TABLE ' . PhpMyAdmin\Util::backquote($DB2) - . '.' . PhpMyAdmin\Util::backquote($T2) . ' DROP FOREIGN KEY ' - . PhpMyAdmin\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!') - . "
" . $error - ); - } - } - - // internal relations - $delete_query = "DELETE FROM " - . PhpMyAdmin\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 = Relation::queryAsControlUser( - $delete_query, - false, - PhpMyAdmin\DatabaseInterface::QUERY_STORE - ); - - if (!$result) { - $error = $GLOBALS['dbi']->getError($GLOBALS['controllink']); - return array( - false, - __('Error: Internal relationship could not be removed!') . "
" . $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 - */ -function PMA_saveDesignerSetting($index, $value) -{ - $cfgRelation = Relation::getRelationsParam(); - $cfgDesigner = array( - 'user' => $GLOBALS['cfg']['Server']['user'], - 'db' => $cfgRelation['db'], - 'table' => $cfgRelation['designer_settings'] - ); - - $success = true; - if ($GLOBALS['cfgRelation']['designersettingswork']) { - - $orig_data_query = "SELECT settings_data" - . " FROM " . PhpMyAdmin\Util::backquote($cfgDesigner['db']) - . "." . PhpMyAdmin\Util::backquote($cfgDesigner['table']) - . " WHERE username = '" - . $GLOBALS['dbi']->escapeString($cfgDesigner['user']) . "';"; - - $orig_data = $GLOBALS['dbi']->fetchSingleRow( - $orig_data_query, 'ASSOC', $GLOBALS['controllink'] - ); - - 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 " - . PhpMyAdmin\Util::backquote($cfgDesigner['db']) - . "." . PhpMyAdmin\Util::backquote($cfgDesigner['table']) - . " SET settings_data = '" . $orig_data . "'" - . " WHERE username = '" - . $GLOBALS['dbi']->escapeString($cfgDesigner['user']) . "';"; - - $success = Relation::queryAsControlUser($save_query); - } else { - $save_data = array($index => $value); - - $query = "INSERT INTO " - . PhpMyAdmin\Util::backquote($cfgDesigner['db']) - . "." . PhpMyAdmin\Util::backquote($cfgDesigner['table']) - . " (username, settings_data)" - . " VALUES('" . $cfgDesigner['user'] . "'," - . " '" . json_encode($save_data) . "');"; - - $success = Relation::queryAsControlUser($query); - } - } - - return (bool) $success; -} diff --git a/schema_export.php b/schema_export.php index 936cc0c263..fd5d2d13ce 100644 --- a/schema_export.php +++ b/schema_export.php @@ -22,8 +22,6 @@ require_once 'libraries/common.inc.php'; */ $cfgRelation = Relation::getRelationsParam(); -require_once 'libraries/pmd_common.php'; - if (! isset($_REQUEST['export_type'])) { PhpMyAdmin\Util::checkParameters(array('export_type')); } diff --git a/test/libraries/PMA_PMD_common_test.php b/test/classes/PmdCommonTest.php similarity index 83% rename from test/libraries/PMA_PMD_common_test.php rename to test/classes/PmdCommonTest.php index 0a6fac8dbd..ff2771a29d 100644 --- a/test/libraries/PMA_PMD_common_test.php +++ b/test/classes/PmdCommonTest.php @@ -1,17 +1,22 @@ method('fetchResult') ->with( " - SELECT CONCAT_WS('.', `db_name`, `table_name`) AS `name`, - `x` AS `X`, - `y` AS `Y`, - 1 AS `V`, - 1 AS `H` - FROM `pmadb`.`table_coords` - WHERE pdf_page_number = " . $pg, + SELECT CONCAT_WS('.', `db_name`, `table_name`) AS `name`, + `x` AS `X`, + `y` AS `Y`, + 1 AS `V`, + 1 AS `H` + FROM `pmadb`.`table_coords` + WHERE pdf_page_number = " . $pg, 'name', null, 2, - PhpMyAdmin\DatabaseInterface::QUERY_STORE + DatabaseInterface::QUERY_STORE ); $GLOBALS['dbi'] = $dbi; - PMA_getTablePositions($pg); + PmdCommon::getTablePositions($pg); } /** - * Test for PMA_getPageName() + * Test for PmdCommon::getPageName() * * @return void */ @@ -98,18 +100,18 @@ class PMA_PMD_CommonTest extends PHPUnit_Framework_TestCase null, null, 2, - PhpMyAdmin\DatabaseInterface::QUERY_STORE + DatabaseInterface::QUERY_STORE ) ->will($this->returnValue(array($pageName))); $GLOBALS['dbi'] = $dbi; - $result = PMA_getPageName($pg); + $result = PmdCommon::getPageName($pg); $this->assertEquals($pageName, $result); } /** - * Test for PMA_deletePage() + * Test for PmdCommon::deletePage() * * @return void */ @@ -132,7 +134,7 @@ class PMA_PMD_CommonTest extends PHPUnit_Framework_TestCase $GLOBALS['dbi'] = $dbi; - $result = PMA_deletePage($pg); + $result = PmdCommon::deletePage($pg); $this->assertEquals(true, $result); } @@ -160,7 +162,7 @@ class PMA_PMD_CommonTest extends PHPUnit_Framework_TestCase null, null, 2, - PhpMyAdmin\DatabaseInterface::QUERY_STORE + DatabaseInterface::QUERY_STORE ) ->will($this->returnValue(array($default_pg))); $dbi->expects($this->any())->method('escapeString') @@ -168,7 +170,7 @@ class PMA_PMD_CommonTest extends PHPUnit_Framework_TestCase $GLOBALS['dbi'] = $dbi; - $result = PMA_getDefaultPage($db); + $result = PmdCommon::getDefaultPage($db); $this->assertEquals($default_pg, $result); } @@ -194,7 +196,7 @@ class PMA_PMD_CommonTest extends PHPUnit_Framework_TestCase null, null, 2, - PhpMyAdmin\DatabaseInterface::QUERY_STORE + DatabaseInterface::QUERY_STORE ) ->will($this->returnValue(array())); $dbi->expects($this->any())->method('escapeString') @@ -202,7 +204,7 @@ class PMA_PMD_CommonTest extends PHPUnit_Framework_TestCase $GLOBALS['dbi'] = $dbi; - $result = PMA_getDefaultPage($db); + $result = PmdCommon::getDefaultPage($db); $this->assertEquals(-1, $result); } @@ -229,7 +231,7 @@ class PMA_PMD_CommonTest extends PHPUnit_Framework_TestCase null, null, 2, - PhpMyAdmin\DatabaseInterface::QUERY_STORE + DatabaseInterface::QUERY_STORE ) ->will($this->returnValue(array($default_pg))); $dbi->expects($this->any())->method('escapeString') @@ -237,7 +239,7 @@ class PMA_PMD_CommonTest extends PHPUnit_Framework_TestCase $GLOBALS['dbi'] = $dbi; - $result = PMA_getLoadingPage($db); + $result = PmdCommon::getLoadingPage($db); $this->assertEquals($default_pg, $result); } @@ -266,7 +268,7 @@ class PMA_PMD_CommonTest extends PHPUnit_Framework_TestCase $GLOBALS['dbi'] = $dbi; - $result = PMA_getLoadingPage($db); + $result = PmdCommon::getLoadingPage($db); $this->assertEquals($first_pg, $result); } } From 56fe75d730d7f4587b96b714cf61cec406132568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 13 Sep 2017 19:09:59 -0300 Subject: [PATCH 4/5] Refactor sql_query_form functions to static methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- db_sql.php | 4 +- libraries/classes/Sql.php | 2 +- libraries/classes/SqlQueryForm.php | 442 ++++++++++++++++++ libraries/classes/Tracking.php | 4 +- libraries/sql_query_form.lib.php | 435 ----------------- server_sql.php | 4 +- tbl_sql.php | 5 +- .../SqlQueryFormTest.php} | 27 +- 8 files changed, 464 insertions(+), 459 deletions(-) create mode 100644 libraries/classes/SqlQueryForm.php delete mode 100644 libraries/sql_query_form.lib.php rename test/{libraries/PMA_sql_query_form_test.php => classes/SqlQueryFormTest.php} (91%) diff --git a/db_sql.php b/db_sql.php index 5c1dee5ea8..9dfd3e7397 100644 --- a/db_sql.php +++ b/db_sql.php @@ -7,6 +7,7 @@ */ use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Response; +use PhpMyAdmin\SqlQueryForm; /** * @@ -26,7 +27,6 @@ $scripts->addFile('vendor/jquery/jquery.uitablefilter.js'); $scripts->addFile('sql.js'); require 'libraries/db_common.inc.php'; -require_once 'libraries/sql_query_form.lib.php'; // After a syntax error, we return to this script // with the typed query in the textarea. @@ -37,7 +37,7 @@ $back = 'db_sql.php'; * Query box, bookmark, insert data from textfile */ $response->addHTML( - PMA_getHtmlForSqlQueryForm( + SqlQueryForm::getHtml( true, false, isset($_REQUEST['delimiter']) ? htmlspecialchars($_REQUEST['delimiter']) diff --git a/libraries/classes/Sql.php b/libraries/classes/Sql.php index 53b9370704..bfa714a307 100644 --- a/libraries/classes/Sql.php +++ b/libraries/classes/Sql.php @@ -1371,7 +1371,7 @@ EOT; $message = Message::getMessageForAffectedRows($num_rows); // Ok, here is an explanation for the !$is_select. - // The form generated by sql_query_form.lib.php + // The form generated by PhpMyAdmin\SqlQueryForm // and db_sql.php has many submit buttons // on the same form, and some confusion arises from the // fact that $message_to_show is sent for every case. diff --git a/libraries/classes/SqlQueryForm.php b/libraries/classes/SqlQueryForm.php new file mode 100644 index 0000000000..85df1b8481 --- /dev/null +++ b/libraries/classes/SqlQueryForm.php @@ -0,0 +1,442 @@ +' . "\n"; + + $html .= '' + . "\n" . Url::getHiddenInputs($db, $table) . "\n" + . '' . "\n" + . '' . "\n" + . '' + . "\n" . '' . "\n"; + + // display querybox + if ($display_tab === 'full' || $display_tab === 'sql') { + $html .= self::getHtmlForInsert( + $query, $delimiter + ); + } + + // Bookmark Support + if ($display_tab === 'full') { + $cfgBookmark = Bookmark::getParams(); + if ($cfgBookmark) { + $html .= self::getHtmlForBookmark(); + } + } + + // Japanese encoding setting + if (Encoding::canConvertKanji()) { + $html .= Encoding::kanjiEncodingForm(); + } + + $html .= '' . "\n"; + // print an empty div, which will be later filled with + // the sql query results by ajax + $html .= '
'; + + return $html; + } + + /** + * Get initial values for Sql Query Form Insert + * + * @param string $query query to display in the textarea + * + * @return array ($legend, $query, $columns_list) + * + * @usedby self::getHtmlForInsert() + */ + public static function init($query) + { + $columns_list = array(); + if (strlen($GLOBALS['db']) === 0) { + // prepare for server related + $legend = sprintf( + __('Run SQL query/queries on server “%s”'), + htmlspecialchars( + ! empty($GLOBALS['cfg']['Servers'][$GLOBALS['server']]['verbose']) + ? $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['verbose'] + : $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['host'] + ) + ); + } elseif (strlen($GLOBALS['table']) === 0) { + // prepare for db related + $db = $GLOBALS['db']; + // if you want navigation: + $tmp_db_link = ''; + $legend = sprintf(__('Run SQL query/queries on database %s'), $tmp_db_link); + if (empty($query)) { + $query = Util::expandUserString( + $GLOBALS['cfg']['DefaultQueryDatabase'], 'backquote' + ); + } + } else { + $db = $GLOBALS['db']; + $table = $GLOBALS['table']; + // Get the list and number of fields + // we do a try_query here, because we could be in the query window, + // trying to synchronize and the table has not yet been created + $columns_list = $GLOBALS['dbi']->getColumns( + $db, $GLOBALS['table'], null, true + ); + + $tmp_tbl_link = ''; + $tmp_tbl_link .= htmlspecialchars($db) + . '.' . htmlspecialchars($table) . ''; + $legend = sprintf(__('Run SQL query/queries on table %s'), $tmp_tbl_link); + if (empty($query)) { + $query = Util::expandUserString( + $GLOBALS['cfg']['DefaultQueryTable'], 'backquote' + ); + } + } + $legend .= ': ' . Util::showMySQLDocu('SELECT'); + + return array($legend, $query, $columns_list); + } + + /** + * return HTML for Sql Query Form Insert + * + * @param string $query query to display in the textarea + * @param string $delimiter default delimiter to use + * + * @return string + * + * @usedby self::getHtml() + */ + public static function getHtmlForInsert( + $query = '', $delimiter = ';' + ) { + // enable auto select text in textarea + if ($GLOBALS['cfg']['TextareaAutoSelect']) { + $auto_sel = ' onclick="selectContent(this, sql_box_locked, true);"'; + } else { + $auto_sel = ''; + } + + $locking = ''; + $height = $GLOBALS['cfg']['TextareaRows'] * 2; + + list($legend, $query, $columns_list) = self::init($query); + + if (! empty($columns_list)) { + $sqlquerycontainer_id = 'sqlquerycontainer'; + } else { + $sqlquerycontainer_id = 'sqlquerycontainerfull'; + } + + $html = '' + . '
' + . '
'; + $html .= '' . $legend . ''; + $html .= '
'; + $html .= '
' + . ''; + $html .= '
'; + // Add buttons to generate query easily for + // select all, single select, insert, update and delete + if (! empty($columns_list)) { + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + } + $html .= ''; + if ($GLOBALS['cfg']['CodemirrorEnable']) { + $html .= ''; + } + $html .= ''; + + // parameter binding + $html .= '
'; + $html .= ''; + $html .= ''; + $html .= Util::showDocu('faq', 'faq6-40'); + $html .= '
'; + $html .= '
'; + + $html .= '
' . "\n"; + + if (! empty($columns_list)) { + $html .= '
' + . '' + . '' + . '
'; + if (Util::showIcons('ActionLinksMode')) { + $html .= ''; + } else { + $html .= ''; + } + $html .= '
' . "\n" + . '
' . "\n"; + } + + $html .= '
' . "\n"; + $html .= '
' . "\n"; + + $cfgBookmark = Bookmark::getParams(); + if ($cfgBookmark) { + $html .= '
'; + $html .= '
'; + $html .= ''; + $html .= ''; + $html .= '
'; + $html .= '
'; + $html .= ''; + $html .= ''; + $html .= '
'; + $html .= '
'; + $html .= ''; + $html .= ''; + $html .= '
'; + $html .= '
'; + } + + $html .= '
' . "\n"; + $html .= '
' . "\n" + . '
' . "\n"; + + $html .= '
' . "\n"; + $html .= '
' . "\n"; + $html .= '
' . "\n"; + + $html .= '
'; + $html .= '' . "\n"; + $html .= ' ]'; + $html .= '
'; + + $html .= '
'; + $html .= '' + . ''; + $html .= '
'; + + $html .= '
'; + $html .= '' + . ''; + $html .= '
'; + + $html .= '
'; + $html .= '' + . ''; + $html .= '
'; + + // Disable/Enable foreign key checks + $html .= '
'; + $html .= Util::getFKCheckbox(); + $html .= '
'; + + $html .= '' . "\n"; + $html .= '
' . "\n"; + $html .= '
' . "\n"; + + return $html; + } + + /** + * return HTML for sql Query Form Bookmark + * + * @return string|null + * + * @usedby self::getHtml() + */ + public static function getHtmlForBookmark() + { + $bookmark_list = Bookmark::getList($GLOBALS['db']); + if (empty($bookmark_list) || count($bookmark_list) < 1) { + return null; + } + + $html = '
'; + $html .= ''; + $html .= __('Bookmarked SQL query') . '' . "\n"; + $html .= '
'; + $html .= ' ' . "\n"; + $html .= '
' . "\n"; + $html .= '
' . "\n"; + $html .= '' + . '' . "\n"; + $html .= '' + . '' . "\n"; + $html .= '' + . '' . "\n"; + $html .= '
' . "\n"; + $html .= '
' . "\n"; + $html .= '
' . "\n"; + $html .= __('Variables'); + $html .= Util::showDocu('faq', 'faqbookmark'); + $html .= '
'; + $html .= '
' . "\n"; + $html .= '
' . "\n"; + + $html .= '
'; + $html .= ''; + $html .= '
' . "\n"; + $html .= '
' . "\n"; + + return $html; + } +} diff --git a/libraries/classes/Tracking.php b/libraries/classes/Tracking.php index 6c01c933ff..c4a7cfbd0b 100644 --- a/libraries/classes/Tracking.php +++ b/libraries/classes/Tracking.php @@ -12,6 +12,7 @@ use PhpMyAdmin\Message; use PhpMyAdmin\Relation; use PhpMyAdmin\Response; use PhpMyAdmin\Sanitize; +use PhpMyAdmin\SqlQueryForm; use PhpMyAdmin\Template; use PhpMyAdmin\Tracker; use PhpMyAdmin\Url; @@ -1142,9 +1143,8 @@ class Tracking $table_temp = $GLOBALS['table']; $GLOBALS['db'] = $GLOBALS['table'] = ''; - include_once './libraries/sql_query_form.lib.php'; - $html .= PMA_getHtmlForSqlQueryForm($new_query, 'sql'); + $html .= SqlQueryForm::getHtml($new_query, 'sql'); $GLOBALS['db'] = $db_temp; $GLOBALS['table'] = $table_temp; diff --git a/libraries/sql_query_form.lib.php b/libraries/sql_query_form.lib.php deleted file mode 100644 index 3da0bcf5e0..0000000000 --- a/libraries/sql_query_form.lib.php +++ /dev/null @@ -1,435 +0,0 @@ -' . "\n"; - - $html .= '' - . "\n" . Url::getHiddenInputs($db, $table) . "\n" - . '' . "\n" - . '' . "\n" - . '' - . "\n" . '' . "\n"; - - // display querybox - if ($display_tab === 'full' || $display_tab === 'sql') { - $html .= PMA_getHtmlForSqlQueryFormInsert( - $query, $delimiter - ); - } - - // Bookmark Support - if ($display_tab === 'full') { - $cfgBookmark = Bookmark::getParams(); - if ($cfgBookmark) { - $html .= PMA_getHtmlForSqlQueryFormBookmark(); - } - } - - // Japanese encoding setting - if (Encoding::canConvertKanji()) { - $html .= Encoding::kanjiEncodingForm(); - } - - $html .= '' . "\n"; - // print an empty div, which will be later filled with - // the sql query results by ajax - $html .= '
'; - - return $html; -} - -/** - * Get initial values for Sql Query Form Insert - * - * @param string $query query to display in the textarea - * - * @return array ($legend, $query, $columns_list) - * - * @usedby PMA_getHtmlForSqlQueryFormInsert() - */ -function PMA_initQueryForm($query) -{ - $columns_list = array(); - if (strlen($GLOBALS['db']) === 0) { - // prepare for server related - $legend = sprintf( - __('Run SQL query/queries on server “%s”'), - htmlspecialchars( - ! empty($GLOBALS['cfg']['Servers'][$GLOBALS['server']]['verbose']) - ? $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['verbose'] - : $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['host'] - ) - ); - } elseif (strlen($GLOBALS['table']) === 0) { - // prepare for db related - $db = $GLOBALS['db']; - // if you want navigation: - $tmp_db_link = ''; - $legend = sprintf(__('Run SQL query/queries on database %s'), $tmp_db_link); - if (empty($query)) { - $query = PhpMyAdmin\Util::expandUserString( - $GLOBALS['cfg']['DefaultQueryDatabase'], 'backquote' - ); - } - } else { - $db = $GLOBALS['db']; - $table = $GLOBALS['table']; - // Get the list and number of fields - // we do a try_query here, because we could be in the query window, - // trying to synchronize and the table has not yet been created - $columns_list = $GLOBALS['dbi']->getColumns( - $db, $GLOBALS['table'], null, true - ); - - $tmp_tbl_link = ''; - $tmp_tbl_link .= htmlspecialchars($db) - . '.' . htmlspecialchars($table) . ''; - $legend = sprintf(__('Run SQL query/queries on table %s'), $tmp_tbl_link); - if (empty($query)) { - $query = PhpMyAdmin\Util::expandUserString( - $GLOBALS['cfg']['DefaultQueryTable'], 'backquote' - ); - } - } - $legend .= ': ' . PhpMyAdmin\Util::showMySQLDocu('SELECT'); - - return array($legend, $query, $columns_list); -} - -/** - * return HTML for Sql Query Form Insert - * - * @param string $query query to display in the textarea - * @param string $delimiter default delimiter to use - * - * @return string - * - * @usedby PMA_getHtmlForSqlQueryForm() - */ -function PMA_getHtmlForSqlQueryFormInsert( - $query = '', $delimiter = ';' -) { - // enable auto select text in textarea - if ($GLOBALS['cfg']['TextareaAutoSelect']) { - $auto_sel = ' onclick="selectContent(this, sql_box_locked, true);"'; - } else { - $auto_sel = ''; - } - - $locking = ''; - $height = $GLOBALS['cfg']['TextareaRows'] * 2; - - list($legend, $query, $columns_list) = PMA_initQueryForm($query); - - if (! empty($columns_list)) { - $sqlquerycontainer_id = 'sqlquerycontainer'; - } else { - $sqlquerycontainer_id = 'sqlquerycontainerfull'; - } - - $html = '' - . '
' - . '
'; - $html .= '' . $legend . ''; - $html .= '
'; - $html .= '
' - . ''; - $html .= '
'; - // Add buttons to generate query easily for - // select all, single select, insert, update and delete - if (! empty($columns_list)) { - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - } - $html .= ''; - if ($GLOBALS['cfg']['CodemirrorEnable']) { - $html .= ''; - } - $html .= ''; - - // parameter binding - $html .= '
'; - $html .= ''; - $html .= ''; - $html .= PhpMyAdmin\Util::showDocu('faq', 'faq6-40'); - $html .= '
'; - $html .= '
'; - - $html .= '
' . "\n"; - - if (! empty($columns_list)) { - $html .= '
' - . '' - . '' - . '
'; - if (PhpMyAdmin\Util::showIcons('ActionLinksMode')) { - $html .= ''; - } else { - $html .= ''; - } - $html .= '
' . "\n" - . '
' . "\n"; - } - - $html .= '
' . "\n"; - $html .= '
' . "\n"; - - $cfgBookmark = Bookmark::getParams(); - if ($cfgBookmark) { - $html .= '
'; - $html .= '
'; - $html .= ''; - $html .= ''; - $html .= '
'; - $html .= '
'; - $html .= ''; - $html .= ''; - $html .= '
'; - $html .= '
'; - $html .= ''; - $html .= ''; - $html .= '
'; - $html .= '
'; - } - - $html .= '
' . "\n"; - $html .= '
' . "\n" - . '
' . "\n"; - - $html .= '
' . "\n"; - $html .= '
' . "\n"; - $html .= '
' . "\n"; - - $html .= '
'; - $html .= '' . "\n"; - $html .= ' ]'; - $html .= '
'; - - $html .= '
'; - $html .= '' - . ''; - $html .= '
'; - - $html .= '
'; - $html .= '' - . ''; - $html .= '
'; - - $html .= '
'; - $html .= '' - . ''; - $html .= '
'; - - // Disable/Enable foreign key checks - $html .= '
'; - $html .= PhpMyAdmin\Util::getFKCheckbox(); - $html .= '
'; - - $html .= '' . "\n"; - $html .= '
' . "\n"; - $html .= '
' . "\n"; - - return $html; -} - -/** - * return HTML for sql Query Form Bookmark - * - * @return string|null - * - * @usedby PMA_getHtmlForSqlQueryForm() - */ -function PMA_getHtmlForSqlQueryFormBookmark() -{ - $bookmark_list = Bookmark::getList($GLOBALS['db']); - if (empty($bookmark_list) || count($bookmark_list) < 1) { - return null; - } - - $html = '
'; - $html .= ''; - $html .= __('Bookmarked SQL query') . '' . "\n"; - $html .= '
'; - $html .= ' ' . "\n"; - $html .= '
' . "\n"; - $html .= '
' . "\n"; - $html .= '' - . '' . "\n"; - $html .= '' - . '' . "\n"; - $html .= '' - . '' . "\n"; - $html .= '
' . "\n"; - $html .= '
' . "\n"; - $html .= '
' . "\n"; - $html .= __('Variables'); - $html .= PhpMyAdmin\Util::showDocu('faq', 'faqbookmark'); - $html .= '
'; - $html .= '
' . "\n"; - $html .= '
' . "\n"; - - $html .= '
'; - $html .= ''; - $html .= '
' . "\n"; - $html .= '
' . "\n"; - - return $html; -} diff --git a/server_sql.php b/server_sql.php index 418903a05c..5d91eb38f0 100644 --- a/server_sql.php +++ b/server_sql.php @@ -7,6 +7,7 @@ */ use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Response; +use PhpMyAdmin\SqlQueryForm; /** * @@ -26,9 +27,8 @@ $scripts->addFile('vendor/jquery/jquery.uitablefilter.js'); $scripts->addFile('sql.js'); require_once 'libraries/server_common.inc.php'; -require_once 'libraries/sql_query_form.lib.php'; /** * Query box, bookmark, insert data from textfile */ -$response->addHTML(PMA_getHtmlForSqlQueryForm()); +$response->addHTML(SqlQueryForm::getHtml()); diff --git a/tbl_sql.php b/tbl_sql.php index f33569bb92..d6e50b9f79 100644 --- a/tbl_sql.php +++ b/tbl_sql.php @@ -7,6 +7,7 @@ */ use PhpMyAdmin\Config\PageSettings; use PhpMyAdmin\Response; +use PhpMyAdmin\SqlQueryForm; /** * @@ -28,8 +29,6 @@ $scripts->addFile('sql.js'); require 'libraries/tbl_common.inc.php'; $url_query .= '&goto=tbl_sql.php&back=tbl_sql.php'; -require_once 'libraries/sql_query_form.lib.php'; - $err_url = 'tbl_sql.php' . $err_url; // After a syntax error, we return to this script // with the typed query in the textarea. @@ -40,7 +39,7 @@ $back = 'tbl_sql.php'; * Query box, bookmark, insert data from textfile */ $response->addHTML( - PMA_getHtmlForSqlQueryForm( + SqlQueryForm::getHtml( true, false, isset($_REQUEST['delimiter']) ? htmlspecialchars($_REQUEST['delimiter']) diff --git a/test/libraries/PMA_sql_query_form_test.php b/test/classes/SqlQueryFormTest.php similarity index 91% rename from test/libraries/PMA_sql_query_form_test.php rename to test/classes/SqlQueryFormTest.php index e97e120470..09f60ba2e7 100644 --- a/test/libraries/PMA_sql_query_form_test.php +++ b/test/classes/SqlQueryFormTest.php @@ -1,32 +1,31 @@ assertContains( @@ -123,7 +122,7 @@ class PMA_SqlQueryForm_Test extends PHPUnit_Framework_TestCase //validate 3: showMySQLDocu $this->assertContains( - PhpMyAdmin\Util::showMySQLDocu('SELECT'), + Util::showMySQLDocu('SELECT'), $html ); @@ -161,7 +160,7 @@ class PMA_SqlQueryForm_Test extends PHPUnit_Framework_TestCase } /** - * Test for PMA_getHtmlForSqlQueryForm + * Test for SqlQueryForm::getHtml * * @return void */ @@ -171,7 +170,7 @@ class PMA_SqlQueryForm_Test extends PHPUnit_Framework_TestCase $GLOBALS['is_upload'] = true; $GLOBALS['lang'] = 'ja'; $query = "select * from PMA"; - $html = PMA_getHtmlForSqlQueryForm($query); + $html = SqlQueryForm::getHtml($query); //validate 1: query $this->assertContains( From a10e2b0b96bcf2ff8657a1a729aee8d25b17df3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 13 Sep 2017 20:51:08 -0300 Subject: [PATCH 5/5] Refactor error_report functions to static methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- error_report.php | 8 +- libraries/classes/ErrorReport.php | 331 ++++++++++++++++++++++++++++++ libraries/error_report.lib.php | 323 ----------------------------- 3 files changed, 335 insertions(+), 327 deletions(-) create mode 100644 libraries/classes/ErrorReport.php delete mode 100644 libraries/error_report.lib.php diff --git a/error_report.php b/error_report.php index 722277a1d5..3ac3c9ed80 100644 --- a/error_report.php +++ b/error_report.php @@ -5,11 +5,11 @@ * * @package PhpMyAdmin */ +use PhpMyAdmin\ErrorReport; use PhpMyAdmin\Response; use PhpMyAdmin\UserPreferences; require_once 'libraries/common.inc.php'; -require_once 'libraries/error_report.lib.php'; if (!isset($_REQUEST['exception_type']) ||!in_array($_REQUEST['exception_type'], array('js', 'php')) @@ -47,10 +47,10 @@ if (isset($_REQUEST['send_error_report']) ); } } - $reportData = PMA_getReportData($_REQUEST['exception_type']); + $reportData = ErrorReport::getReportData($_REQUEST['exception_type']); // report if and only if there were 'actual' errors. if (count($reportData) > 0) { - $server_response = PMA_sendErrorReport($reportData); + $server_response = ErrorReport::send($reportData); if ($server_response === false) { $success = false; } else { @@ -122,7 +122,7 @@ if (isset($_REQUEST['send_error_report']) $response->addJSON('report_setting', $GLOBALS['cfg']['SendErrorReports']); } else { if ($_REQUEST['exception_type'] == 'js') { - $response->addHTML(PMA_getErrorReportForm()); + $response->addHTML(ErrorReport::getForm()); } else { // clear previous errors & save new ones. $GLOBALS['error_handler']->savePreviousErrors(); diff --git a/libraries/classes/ErrorReport.php b/libraries/classes/ErrorReport.php new file mode 100644 index 0000000000..df1bcfd5b8 --- /dev/null +++ b/libraries/classes/ErrorReport.php @@ -0,0 +1,331 @@ + PMA_VERSION, + "browser_name" => PMA_USR_BROWSER_AGENT, + "browser_version" => PMA_USR_BROWSER_VER, + "user_os" => PMA_USR_OS, + "server_software" => $_SERVER['SERVER_SOFTWARE'], + "user_agent_string" => $_SERVER['HTTP_USER_AGENT'], + "locale" => $_COOKIE['pma_lang'], + "configuration_storage" => + is_null($relParams['db']) ? "disabled" : + "enabled", + "php_version" => phpversion() + ); + + if ($exception_type == 'js') { + if (empty($_REQUEST['exception'])) { + return array(); + } + $exception = $_REQUEST['exception']; + $exception["stack"] = self::translateStacktrace($exception["stack"]); + List($uri, $script_name) = self::sanitizeUrl($exception["url"]); + $exception["uri"] = $uri; + unset($exception["url"]); + + $report ["exception_type"] = 'js'; + $report ["exception"] = $exception; + $report ["script_name"] = $script_name; + $report ["microhistory"] = $_REQUEST['microhistory']; + + if (! empty($_REQUEST['description'])) { + $report['steps'] = $_REQUEST['description']; + } + } elseif ($exception_type == 'php') { + $errors = array(); + // create php error report + $i = 0; + if (!isset($_SESSION['prev_errors']) + || $_SESSION['prev_errors'] == '' + ) { + return array(); + } + foreach ($_SESSION['prev_errors'] as $errorObj) { + /* @var $errorObj PhpMyAdmin\Error */ + if ($errorObj->getLine() + && $errorObj->getType() + && $errorObj->getNumber() != E_USER_WARNING + ) { + $errors[$i++] = array( + "lineNum" => $errorObj->getLine(), + "file" => $errorObj->getFile(), + "type" => $errorObj->getType(), + "msg" => $errorObj->getOnlyMessage(), + "stackTrace" => $errorObj->getBacktrace(5), + "stackhash" => $errorObj->getHash() + ); + + } + } + + // if there were no 'actual' errors to be submitted. + if ($i==0) { + return array(); // then return empty array + } + $report ["exception_type"] = 'php'; + $report["errors"] = $errors; + } else { + return array(); + } + + return $report; + } + + /** + * Sanitize a url to remove the identifiable host name and extract the + * current script name from the url fragment + * + * It returns two things in an array. The first is the uri without the + * hostname and identifying query params. The second is the name of the + * php script in the url + * + * @param String $url the url to sanitize + * + * @return array the uri and script name + */ + public static function sanitizeUrl($url) + { + $components = parse_url($url); + if (isset($components["fragment"]) + && preg_match("", $components["fragment"], $matches) + ) { + $uri = str_replace($matches[0], "", $components["fragment"]); + $url = "https://example.com/" . $uri; + $components = parse_url($url); + } + + // get script name + preg_match("<([a-zA-Z\-_\d]*\.php)$>", $components["path"], $matches); + if (count($matches) < 2) { + $script_name = 'index.php'; + } else { + $script_name = $matches[1]; + } + + // remove deployment specific details to make uri more generic + if (isset($components["query"])) { + parse_str($components["query"], $query_array); + unset($query_array["db"]); + unset($query_array["table"]); + unset($query_array["token"]); + unset($query_array["server"]); + $query = http_build_query($query_array); + } else { + $query = ''; + } + + $uri = $script_name . "?" . $query; + return array($uri, $script_name); + } + + /** + * Sends report data to the error reporting server + * + * @param array $report the report info to be sent + * + * @return String the reply of the server + */ + public static function send($report) + { + $response = Util::httpRequest( + self::SUBMISSION_URL, + "POST", + false, + json_encode($report), + "Content-Type: application/json" + ); + return $response; + } + + /** + * Returns number of lines in given javascript file. + * + * @param string $filename javascript filename + * + * @return Number of lines + * + * @todo Should gracefully handle non existing files + */ + public static function countLines($filename) + { + /** + * The generated file that contains the line numbers for the js files + * If you change any of the js files you can run the scripts/line-counts.sh + */ + if (is_readable('js/line_counts.php')) { + include_once 'js/line_counts.php'; + } + + global $LINE_COUNT; + if (defined('LINE_COUNTS')) { + return $LINE_COUNT[$filename]; + } + + // ensure that the file is inside the phpMyAdmin folder + $depath = 1; + foreach (explode('/', $filename) as $part) { + if ($part == '..') { + $depath--; + } elseif ($part != '.' || $part === '') { + $depath++; + } + if ($depath < 0) { + return 0; + } + } + + $linecount = 0; + $handle = fopen('./js/' . $filename, 'r'); + while (!feof($handle)) { + $line = fgets($handle); + if ($line === false) { + break; + } + $linecount++; + } + fclose($handle); + return $linecount; + } + + /** + * returns the translated line number and the file name from the cumulative line + * number and an array of files + * + * uses the $LINE_COUNT global array of file names and line numbers + * + * @param array $filenames list of files in order of concatenation + * @param Integer $cumulative_number the cumulative line number in the + * concatenated files + * + * @return array the filename and line number + * Returns two variables in an array: + * - A String $filename the filename where the requested cumulative number + * exists + * - Integer $linenumber the translated line number in the returned file + */ + public static function getLineNumber($filenames, $cumulative_number) + { + $cumulative_sum = 0; + foreach ($filenames as $filename) { + $filecount = self::countLines($filename); + if ($cumulative_number <= $cumulative_sum + $filecount + 2) { + $linenumber = $cumulative_number - $cumulative_sum; + break; + } + $cumulative_sum += $filecount + 2; + } + if (! isset($filename)) { + $filename = ''; + } + return array($filename, $linenumber); + } + + /** + * translates the cumulative line numbers in the stack trace as well as sanitize + * urls and trim long lines in the context + * + * @param array $stack the stack trace + * + * @return array $stack the modified stack trace + */ + public static function translateStacktrace($stack) + { + foreach ($stack as &$level) { + foreach ($level["context"] as &$line) { + if (mb_strlen($line) > 80) { + $line = mb_substr($line, 0, 75) . "//..."; + } + } + if (preg_match("", $level["url"], $matches)) { + parse_str($matches[1], $vars); + List($file_name, $line_number) = self::getLineNumber( + $vars["scripts"], $level["line"] + ); + $level["filename"] = $file_name; + $level["line"] = $line_number; + } else { + unset($level["context"]); + List($uri, $script_name) = self::sanitizeUrl($level["url"]); + $level["uri"] = $uri; + $level["scriptname"] = $script_name; + } + unset($level["url"]); + } + unset($level); + return $stack; + } + + /** + * generates the error report form to collect user description and preview the + * report before being sent + * + * @return String the form + */ + public static function getForm() + { + $datas = array( + 'report_data' => self::getPrettyReportData(), + 'hidden_inputs' => Url::getHiddenInputs(), + 'hidden_fields' => null, + ); + + $reportData = self::getReportData(); + if (!empty($reportData)) { + $datas['hidden_fields'] = Url::getHiddenFields($reportData); + } + + return Template::get('error/report_form') + ->render($datas); + } +} diff --git a/libraries/error_report.lib.php b/libraries/error_report.lib.php deleted file mode 100644 index 569651e798..0000000000 --- a/libraries/error_report.lib.php +++ /dev/null @@ -1,323 +0,0 @@ - PMA_VERSION, - "browser_name" => PMA_USR_BROWSER_AGENT, - "browser_version" => PMA_USR_BROWSER_VER, - "user_os" => PMA_USR_OS, - "server_software" => $_SERVER['SERVER_SOFTWARE'], - "user_agent_string" => $_SERVER['HTTP_USER_AGENT'], - "locale" => $_COOKIE['pma_lang'], - "configuration_storage" => - is_null($relParams['db']) ? "disabled" : - "enabled", - "php_version" => phpversion() - ); - - if ($exception_type == 'js') { - if (empty($_REQUEST['exception'])) { - return array(); - } - $exception = $_REQUEST['exception']; - $exception["stack"] = PMA_translateStacktrace($exception["stack"]); - List($uri, $script_name) = PMA_sanitizeUrl($exception["url"]); - $exception["uri"] = $uri; - unset($exception["url"]); - - $report ["exception_type"] = 'js'; - $report ["exception"] = $exception; - $report ["script_name"] = $script_name; - $report ["microhistory"] = $_REQUEST['microhistory']; - - if (! empty($_REQUEST['description'])) { - $report['steps'] = $_REQUEST['description']; - } - } elseif ($exception_type == 'php') { - $errors = array(); - // create php error report - $i = 0; - if (!isset($_SESSION['prev_errors']) - || $_SESSION['prev_errors'] == '' - ) { - return array(); - } - foreach ($_SESSION['prev_errors'] as $errorObj) { - /* @var $errorObj PhpMyAdmin\Error */ - if ($errorObj->getLine() - && $errorObj->getType() - && $errorObj->getNumber() != E_USER_WARNING - ) { - $errors[$i++] = array( - "lineNum" => $errorObj->getLine(), - "file" => $errorObj->getFile(), - "type" => $errorObj->getType(), - "msg" => $errorObj->getOnlyMessage(), - "stackTrace" => $errorObj->getBacktrace(5), - "stackhash" => $errorObj->getHash() - ); - - } - } - - // if there were no 'actual' errors to be submitted. - if ($i==0) { - return array(); // then return empty array - } - $report ["exception_type"] = 'php'; - $report["errors"] = $errors; - } else { - return array(); - } - - return $report; -} - -/** - * Sanitize a url to remove the identifiable host name and extract the - * current script name from the url fragment - * - * It returns two things in an array. The first is the uri without the - * hostname and identifying query params. The second is the name of the - * php script in the url - * - * @param String $url the url to sanitize - * - * @return array the uri and script name - */ -function PMA_sanitizeUrl($url) -{ - $components = parse_url($url); - if (isset($components["fragment"]) - && preg_match("", $components["fragment"], $matches) - ) { - $uri = str_replace($matches[0], "", $components["fragment"]); - $url = "https://example.com/" . $uri; - $components = parse_url($url); - } - - // get script name - preg_match("<([a-zA-Z\-_\d]*\.php)$>", $components["path"], $matches); - if (count($matches) < 2) { - $script_name = 'index.php'; - } else { - $script_name = $matches[1]; - } - - // remove deployment specific details to make uri more generic - if (isset($components["query"])) { - parse_str($components["query"], $query_array); - unset($query_array["db"]); - unset($query_array["table"]); - unset($query_array["token"]); - unset($query_array["server"]); - $query = http_build_query($query_array); - } else { - $query = ''; - } - - $uri = $script_name . "?" . $query; - return array($uri, $script_name); -} - -/** - * Sends report data to the error reporting server - * - * @param array $report the report info to be sent - * - * @return String the reply of the server - */ -function PMA_sendErrorReport($report) -{ - $response = PhpMyAdmin\Util::httpRequest( - SUBMISSION_URL, - "POST", - false, - json_encode($report), - "Content-Type: application/json" - ); - return $response; -} - -/** - * Returns number of lines in given javascript file. - * - * @param string $filename javascript filename - * - * @return Number of lines - * - * @todo Should gracefully handle non existing files - */ -function PMA_countLines($filename) -{ - global $LINE_COUNT; - if (defined('LINE_COUNTS')) { - return $LINE_COUNT[$filename]; - } - - // ensure that the file is inside the phpMyAdmin folder - $depath = 1; - foreach (explode('/', $filename) as $part) { - if ($part == '..') { - $depath--; - } elseif ($part != '.' || $part === '') { - $depath++; - } - if ($depath < 0) { - return 0; - } - } - - $linecount = 0; - $handle = fopen('./js/' . $filename, 'r'); - while (!feof($handle)) { - $line = fgets($handle); - if ($line === false) { - break; - } - $linecount++; - } - fclose($handle); - return $linecount; -} - -/** - * returns the translated line number and the file name from the cumulative line - * number and an array of files - * - * uses the $LINE_COUNT global array of file names and line numbers - * - * @param array $filenames list of files in order of concatenation - * @param Integer $cumulative_number the cumulative line number in the - * concatenated files - * - * @return array the filename and line number - * Returns two variables in an array: - * - A String $filename the filename where the requested cumulative number - * exists - * - Integer $linenumber the translated line number in the returned file - */ -function PMA_getLineNumber($filenames, $cumulative_number) -{ - $cumulative_sum = 0; - foreach ($filenames as $filename) { - $filecount = PMA_countLines($filename); - if ($cumulative_number <= $cumulative_sum + $filecount + 2) { - $linenumber = $cumulative_number - $cumulative_sum; - break; - } - $cumulative_sum += $filecount + 2; - } - if (! isset($filename)) { - $filename = ''; - } - return array($filename, $linenumber); -} - -/** - * translates the cumulative line numbers in the stack trace as well as sanitize - * urls and trim long lines in the context - * - * @param array $stack the stack trace - * - * @return array $stack the modified stack trace - */ -function PMA_translateStacktrace($stack) -{ - foreach ($stack as &$level) { - foreach ($level["context"] as &$line) { - if (mb_strlen($line) > 80) { - $line = mb_substr($line, 0, 75) . "//..."; - } - } - if (preg_match("", $level["url"], $matches)) { - parse_str($matches[1], $vars); - List($file_name, $line_number) = PMA_getLineNumber( - $vars["scripts"], $level["line"] - ); - $level["filename"] = $file_name; - $level["line"] = $line_number; - } else { - unset($level["context"]); - List($uri, $script_name) = PMA_sanitizeUrl($level["url"]); - $level["uri"] = $uri; - $level["scriptname"] = $script_name; - } - unset($level["url"]); - } - unset($level); - return $stack; -} - -/** - * generates the error report form to collect user description and preview the - * report before being sent - * - * @return String the form - */ -function PMA_getErrorReportForm() -{ - $datas = array( - 'report_data' => PMA_getPrettyReportData(), - 'hidden_inputs' => Url::getHiddenInputs(), - 'hidden_fields' => null, - ); - - $reportData = PMA_getReportData(); - if (!empty($reportData)) { - $datas['hidden_fields'] = Url::getHiddenFields($reportData); - } - - return PhpMyAdmin\Template::get('error/report_form') - ->render($datas); -}