From 2e52c0f1f816c2a528aec7b795232ab4ad121eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 8 Sep 2017 13:09:13 -0300 Subject: [PATCH 1/8] Refactor rte_events 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_events.php | 5 - libraries/classes/Rte/Events.php | 622 ++++++++++++++++++ libraries/rte/rte_events.lib.php | 615 ----------------- libraries/rte/rte_general.lib.php | 3 +- libraries/rte/rte_main.inc.php | 4 +- test/classes/Rte/EventsTest.php | 527 +++++++++++++++ .../rte/PMA_EVN_getDataFromRequest_test.php | 120 ---- .../rte/PMA_EVN_getEditorForm_test.php | 283 -------- .../rte/PMA_EVN_getQueryFromRequest_test.php | 175 ----- 9 files changed, 1153 insertions(+), 1201 deletions(-) create mode 100644 libraries/classes/Rte/Events.php delete mode 100644 libraries/rte/rte_events.lib.php create mode 100644 test/classes/Rte/EventsTest.php delete mode 100644 test/libraries/rte/PMA_EVN_getDataFromRequest_test.php delete mode 100644 test/libraries/rte/PMA_EVN_getEditorForm_test.php delete mode 100644 test/libraries/rte/PMA_EVN_getQueryFromRequest_test.php diff --git a/db_events.php b/db_events.php index 606b5d22fe..e13935fc68 100644 --- a/db_events.php +++ b/db_events.php @@ -11,11 +11,6 @@ */ require_once 'libraries/common.inc.php'; -/** - * Include all other files - */ -require_once 'libraries/rte/rte_events.lib.php'; - /** * Do the magic */ diff --git a/libraries/classes/Rte/Events.php b/libraries/classes/Rte/Events.php new file mode 100644 index 0000000000..b88ce3a9f5 --- /dev/null +++ b/libraries/classes/Rte/Events.php @@ -0,0 +1,622 @@ + array('ENABLE', + 'DISABLE', + 'DISABLE ON SLAVE'), + 'display' => array('ENABLED', + 'DISABLED', + 'SLAVESIDE_DISABLED') + ); + $event_type = array('RECURRING', + 'ONE TIME'); + $event_interval = array('YEAR', + 'QUARTER', + 'MONTH', + 'DAY', + 'HOUR', + 'MINUTE', + 'WEEK', + 'SECOND', + 'YEAR_MONTH', + 'DAY_HOUR', + 'DAY_MINUTE', + 'DAY_SECOND', + 'HOUR_MINUTE', + 'HOUR_SECOND', + 'MINUTE_SECOND'); + } + + /** + * Main function for the events functionality + * + * @return void + */ + public static function main() + { + global $db; + + self::setGlobals(); + /** + * Process all requests + */ + self::handleEditor(); + PMA_EVN_handleExport(); + /** + * Display a list of available events + */ + $items = $GLOBALS['dbi']->getEvents($db); + echo PMA_RTE_getList('event', $items); + /** + * Display a link for adding a new event, if + * the user has the privileges and a link to + * toggle the state of the event scheduler. + */ + echo PMA_EVN_getFooterLinks(); + } // end self::main() + + /** + * Handles editor requests for adding or editing an item + * + * @return void + */ + public static function handleEditor() + { + global $_REQUEST, $_POST, $errors, $db; + + if (! empty($_REQUEST['editor_process_add']) + || ! empty($_REQUEST['editor_process_edit']) + ) { + $sql_query = ''; + + $item_query = self::getQueryFromRequest(); + + if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest() + // Execute the created query + if (! empty($_REQUEST['editor_process_edit'])) { + // Backup the old trigger, in case something goes wrong + $create_item = $GLOBALS['dbi']->getDefinition( + $db, + 'EVENT', + $_REQUEST['item_original_name'] + ); + $drop_item = "DROP EVENT " + . Util::backquote($_REQUEST['item_original_name']) + . ";\n"; + $result = $GLOBALS['dbi']->tryQuery($drop_item); + if (! $result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($drop_item) + ) + . '
' + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + } else { + $result = $GLOBALS['dbi']->tryQuery($item_query); + if (! $result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($item_query) + ) + . '
' + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + // We dropped the old item, but were unable to create + // the new one. Try to restore the backup query + $result = $GLOBALS['dbi']->tryQuery($create_item); + $errors = checkResult( + $result, + __( + 'Sorry, we failed to restore the dropped event.' + ), + $create_item, + $errors + ); + } else { + $message = Message::success( + __('Event %1$s has been modified.') + ); + $message->addParam( + Util::backquote($_REQUEST['item_name']) + ); + $sql_query = $drop_item . $item_query; + } + } + } else { + // 'Add a new item' mode + $result = $GLOBALS['dbi']->tryQuery($item_query); + if (! $result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($item_query) + ) + . '

' + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + } else { + $message = Message::success( + __('Event %1$s has been created.') + ); + $message->addParam( + Util::backquote($_REQUEST['item_name']) + ); + $sql_query = $item_query; + } + } + } + + if (count($errors)) { + $message = Message::error( + '' + . __( + 'One or more errors have occurred while processing your request:' + ) + . '' + ); + $message->addHtml(''); + } + + $output = Util::getMessage($message, $sql_query); + $response = Response::getInstance(); + if ($response->isAjax()) { + if ($message->isSuccess()) { + $events = $GLOBALS['dbi']->getEvents($db, $_REQUEST['item_name']); + $event = $events[0]; + $response->addJSON( + 'name', + htmlspecialchars( + mb_strtoupper($_REQUEST['item_name']) + ) + ); + $response->addJSON('new_row', PMA_EVN_getRowForList($event)); + $response->addJSON('insert', ! empty($event)); + $response->addJSON('message', $output); + } else { + $response->setRequestStatus(false); + $response->addJSON('message', $message); + } + exit; + } + } + /** + * Display a form used to add/edit a trigger, if necessary + */ + if (count($errors) + || (empty($_REQUEST['editor_process_add']) + && empty($_REQUEST['editor_process_edit']) + && (! empty($_REQUEST['add_item']) + || ! empty($_REQUEST['edit_item']) + || ! empty($_REQUEST['item_changetype']))) + ) { // FIXME: this must be simpler than that + $operation = ''; + if (! empty($_REQUEST['item_changetype'])) { + $operation = 'change'; + } + // Get the data for the form (if any) + if (! empty($_REQUEST['add_item'])) { + $title = PMA_RTE_getWord('add'); + $item = self::getDataFromRequest(); + $mode = 'add'; + } else if (! empty($_REQUEST['edit_item'])) { + $title = __("Edit event"); + if (! empty($_REQUEST['item_name']) + && empty($_REQUEST['editor_process_edit']) + && empty($_REQUEST['item_changetype']) + ) { + $item = self::getDataFromName($_REQUEST['item_name']); + if ($item !== false) { + $item['item_original_name'] = $item['item_name']; + } + } else { + $item = self::getDataFromRequest(); + } + $mode = 'edit'; + } + PMA_RTE_sendEditor('EVN', $mode, $item, $title, $db, $operation); + } + } // end self::handleEditor() + + /** + * This function will generate the values that are required to for the editor + * + * @return array Data necessary to create the editor. + */ + public static function getDataFromRequest() + { + $retval = array(); + $indices = array('item_name', + 'item_original_name', + 'item_status', + 'item_execute_at', + 'item_interval_value', + 'item_interval_field', + 'item_starts', + 'item_ends', + 'item_definition', + 'item_preserve', + 'item_comment', + 'item_definer'); + foreach ($indices as $index) { + $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : ''; + } + $retval['item_type'] = 'ONE TIME'; + $retval['item_type_toggle'] = 'RECURRING'; + if (isset($_REQUEST['item_type']) && $_REQUEST['item_type'] == 'RECURRING') { + $retval['item_type'] = 'RECURRING'; + $retval['item_type_toggle'] = 'ONE TIME'; + } + return $retval; + } // end self::getDataFromRequest() + + /** + * This function will generate the values that are required to complete + * the "Edit event" form given the name of a event. + * + * @param string $name The name of the event. + * + * @return array Data necessary to create the editor. + */ + public static function getDataFromName($name) + { + global $db; + + $retval = array(); + $columns = "`EVENT_NAME`, `STATUS`, `EVENT_TYPE`, `EXECUTE_AT`, " + . "`INTERVAL_VALUE`, `INTERVAL_FIELD`, `STARTS`, `ENDS`, " + . "`EVENT_DEFINITION`, `ON_COMPLETION`, `DEFINER`, `EVENT_COMMENT`"; + $where = "EVENT_SCHEMA " . Util::getCollateForIS() . "=" + . "'" . $GLOBALS['dbi']->escapeString($db) . "' " + . "AND EVENT_NAME='" . $GLOBALS['dbi']->escapeString($name) . "'"; + $query = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE $where;"; + $item = $GLOBALS['dbi']->fetchSingleRow($query); + if (! $item) { + return false; + } + $retval['item_name'] = $item['EVENT_NAME']; + $retval['item_status'] = $item['STATUS']; + $retval['item_type'] = $item['EVENT_TYPE']; + if ($retval['item_type'] == 'RECURRING') { + $retval['item_type_toggle'] = 'ONE TIME'; + } else { + $retval['item_type_toggle'] = 'RECURRING'; + } + $retval['item_execute_at'] = $item['EXECUTE_AT']; + $retval['item_interval_value'] = $item['INTERVAL_VALUE']; + $retval['item_interval_field'] = $item['INTERVAL_FIELD']; + $retval['item_starts'] = $item['STARTS']; + $retval['item_ends'] = $item['ENDS']; + $retval['item_preserve'] = ''; + if ($item['ON_COMPLETION'] == 'PRESERVE') { + $retval['item_preserve'] = " checked='checked'"; + } + $retval['item_definition'] = $item['EVENT_DEFINITION']; + $retval['item_definer'] = $item['DEFINER']; + $retval['item_comment'] = $item['EVENT_COMMENT']; + + return $retval; + } // end self::getDataFromName() + + /** + * Displays a form used to add/edit an event + * + * @param string $mode If the editor will be used to edit an event + * or add a new one: 'edit' or 'add'. + * @param string $operation If the editor was previously invoked with + * JS turned off, this will hold the name of + * the current operation + * @param array $item Data for the event returned by + * self::getDataFromRequest() or + * self::getDataFromName() + * + * @return string HTML code for the editor. + */ + public static function getEditorForm($mode, $operation, $item) + { + global $db, $table, $event_status, $event_type, $event_interval; + + $modeToUpper = mb_strtoupper($mode); + + $response = Response::getInstance(); + + // Escape special characters + $need_escape = array( + 'item_original_name', + 'item_name', + 'item_type', + 'item_execute_at', + 'item_interval_value', + 'item_starts', + 'item_ends', + 'item_definition', + 'item_definer', + 'item_comment' + ); + foreach ($need_escape as $index) { + $item[$index] = htmlentities($item[$index], ENT_QUOTES); + } + $original_data = ''; + if ($mode == 'edit') { + $original_data = "\n"; + } + // Handle some logic first + if ($operation == 'change') { + if ($item['item_type'] == 'RECURRING') { + $item['item_type'] = 'ONE TIME'; + $item['item_type_toggle'] = 'RECURRING'; + } else { + $item['item_type'] = 'RECURRING'; + $item['item_type_toggle'] = 'ONE TIME'; + } + } + if ($item['item_type'] == 'ONE TIME') { + $isrecurring_class = ' hide'; + $isonetime_class = ''; + } else { + $isrecurring_class = ''; + $isonetime_class = ' hide'; + } + // Create the output + $retval = ""; + $retval .= "\n\n"; + $retval .= "
\n"; + $retval .= "\n"; + $retval .= $original_data; + $retval .= Url::getHiddenInputs($db, $table) . "\n"; + $retval .= "
\n"; + $retval .= "" . __('Details') . "\n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - - return $retval; -} // end PMA_RTN_getRowForList() - -/** - * Creates the contents for a row in the list of triggers - * - * @param array $trigger An array of routine data - * @param string $rowclass Additional class - * - * @return string HTML code of a cell for the list of triggers - */ -function PMA_TRI_getRowForList($trigger, $rowclass = '') -{ - global $ajax_class, $url_query, $db, $table, $titles; - - $retval = " \n"; - $retval .= " \n"; - $retval .= " \n"; - if (empty($table)) { - $retval .= " \n"; - } - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - - return $retval; -} // end PMA_TRI_getRowForList() - -/** - * Creates the contents for a row in the list of events - * - * @param array $event An array of routine data - * @param string $rowclass Additional class - * - * @return string HTML code of a cell for the list of events - */ -function PMA_EVN_getRowForList($event, $rowclass = '') -{ - global $ajax_class, $url_query, $db, $titles; - - $sql_drop = sprintf( - 'DROP EVENT IF EXISTS %s', - PhpMyAdmin\Util::backquote($event['name']) - ); - - $retval = " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - - return $retval; -} // end PMA_EVN_getRowForList() diff --git a/libraries/rte/rte_main.inc.php b/libraries/rte/rte_main.inc.php index d27d4b6cbe..447c6e69f7 100644 --- a/libraries/rte/rte_main.inc.php +++ b/libraries/rte/rte_main.inc.php @@ -18,7 +18,6 @@ if (! defined('PHPMYADMIN')) { * to routines, triggers and events. */ require_once './libraries/rte/rte_words.lib.php'; -require_once './libraries/rte/rte_list.lib.php'; $response = Response::getInstance(); diff --git a/libraries/rte/rte_routines.lib.php b/libraries/rte/rte_routines.lib.php index f5881fc804..201e9ff3ae 100644 --- a/libraries/rte/rte_routines.lib.php +++ b/libraries/rte/rte_routines.lib.php @@ -12,6 +12,7 @@ use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Export; use PhpMyAdmin\Rte\Footer; use PhpMyAdmin\Rte\General; +use PhpMyAdmin\Rte\RteList; use PhpMyAdmin\SqlParser\Statements\CreateStatement; use PhpMyAdmin\Url; use PhpMyAdmin\Util; @@ -68,7 +69,7 @@ function PMA_RTN_main($type) $type = null; } $items = $GLOBALS['dbi']->getRoutines($db, $type); - echo PMA_RTE_getList('routine', $items); + echo RteList::get('routine', $items); /** * Display the form for adding a new routine, if the user has the privileges. */ @@ -309,7 +310,7 @@ function PMA_RTN_handleRequestCreateOrEdit($errors, $db) mb_strtoupper($_REQUEST['item_name']) ) ); - $response->addJSON('new_row', PMA_RTN_getRowForList($routine)); + $response->addJSON('new_row', RteList::getRoutineRow($routine)); $response->addJSON('insert', !empty($routine)); $response->addJSON('message', $output); exit; diff --git a/libraries/rte/rte_triggers.lib.php b/libraries/rte/rte_triggers.lib.php index 1beeeacaea..d46c59941d 100644 --- a/libraries/rte/rte_triggers.lib.php +++ b/libraries/rte/rte_triggers.lib.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Export; use PhpMyAdmin\Rte\Footer; use PhpMyAdmin\Rte\General; +use PhpMyAdmin\Rte\RteList; use PhpMyAdmin\Url; if (! defined('PHPMYADMIN')) { @@ -51,7 +52,7 @@ function PMA_TRI_main() * Display a list of available triggers */ $items = $GLOBALS['dbi']->getTriggers($db, $table); - echo PMA_RTE_getList('trigger', $items); + echo RteList::get('trigger', $items); /** * Display a link for adding a new trigger, * if the user has the necessary privileges @@ -174,7 +175,7 @@ function PMA_TRI_handleEditor() || ($trigger !== false && $table == $trigger['table']) ) { $insert = true; - $response->addJSON('new_row', PMA_TRI_getRowForList($trigger)); + $response->addJSON('new_row', RteList::getTriggerRow($trigger)); $response->addJSON( 'name', htmlspecialchars( From 7a054c72e6eedcde6a151afc9d1bbbfe6093aabe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 8 Sep 2017 18:54:57 -0300 Subject: [PATCH 6/8] Refactor rte_words function to a static method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MaurĂ­cio Meneghini Fauth --- libraries/classes/Rte/Events.php | 3 +- libraries/classes/Rte/Export.php | 5 +- libraries/classes/Rte/Footer.php | 5 +- libraries/classes/Rte/General.php | 3 +- libraries/classes/Rte/RteList.php | 11 ++-- libraries/classes/Rte/Words.php | 87 ++++++++++++++++++++++++++++++ libraries/rte/rte_main.inc.php | 6 --- libraries/rte/rte_routines.lib.php | 9 ++-- libraries/rte/rte_triggers.lib.php | 3 +- libraries/rte/rte_words.lib.php | 82 ---------------------------- 10 files changed, 110 insertions(+), 104 deletions(-) create mode 100644 libraries/classes/Rte/Words.php delete mode 100644 libraries/rte/rte_words.lib.php diff --git a/libraries/classes/Rte/Events.php b/libraries/classes/Rte/Events.php index 41d61f6eb8..e4cb159f16 100644 --- a/libraries/classes/Rte/Events.php +++ b/libraries/classes/Rte/Events.php @@ -13,6 +13,7 @@ use PhpMyAdmin\Rte\Export; use PhpMyAdmin\Rte\Footer; use PhpMyAdmin\Rte\General; use PhpMyAdmin\Rte\RteList; +use PhpMyAdmin\Rte\Words; use PhpMyAdmin\Url; use PhpMyAdmin\Util; @@ -228,7 +229,7 @@ class Events } // Get the data for the form (if any) if (! empty($_REQUEST['add_item'])) { - $title = PMA_RTE_getWord('add'); + $title = Words::get('add'); $item = self::getDataFromRequest(); $mode = 'add'; } else if (! empty($_REQUEST['edit_item'])) { diff --git a/libraries/classes/Rte/Export.php b/libraries/classes/Rte/Export.php index fba95a1a6b..731b05052b 100644 --- a/libraries/classes/Rte/Export.php +++ b/libraries/classes/Rte/Export.php @@ -9,6 +9,7 @@ namespace PhpMyAdmin\Rte; use PhpMyAdmin\Message; use PhpMyAdmin\Response; +use PhpMyAdmin\Rte\Words; use PhpMyAdmin\Util; /** @@ -35,7 +36,7 @@ class Export $item_name = htmlspecialchars(Util::backquote($_GET['item_name'])); if ($export_data !== false) { $export_data = htmlspecialchars(trim($export_data)); - $title = sprintf(PMA_RTE_getWord('export'), $item_name); + $title = sprintf(Words::get('export'), $item_name); if ($response->isAjax()) { $response->addJSON('message', $export_data); $response->addJSON('title', $title); @@ -51,7 +52,7 @@ class Export } else { $_db = htmlspecialchars(Util::backquote($db)); $message = __('Error in processing request:') . ' ' - . sprintf(PMA_RTE_getWord('no_view'), $item_name, $_db); + . sprintf(Words::get('no_view'), $item_name, $_db); $message = Message::error($message); if ($response->isAjax()) { diff --git a/libraries/classes/Rte/Footer.php b/libraries/classes/Rte/Footer.php index deea4ba9a9..de130314c1 100644 --- a/libraries/classes/Rte/Footer.php +++ b/libraries/classes/Rte/Footer.php @@ -7,6 +7,7 @@ */ namespace PhpMyAdmin\Rte; +use PhpMyAdmin\Rte\Words; use PhpMyAdmin\Util; /** @@ -42,11 +43,11 @@ class Footer $retval .= "onclick='$.datepicker.initialized = false;'>"; $icon = 'b_' . $icon; $retval .= Util::getIcon($icon); - $retval .= PMA_RTE_getWord('add') . "\n"; + $retval .= Words::get('add') . "\n"; } else { $icon = 'bd_' . $icon; $retval .= Util::getIcon($icon); - $retval .= PMA_RTE_getWord('add') . "\n"; + $retval .= Words::get('add') . "\n"; } $retval .= " " . Util::showMySQLDocu($docu) . "\n"; $retval .= " \n"; diff --git a/libraries/classes/Rte/General.php b/libraries/classes/Rte/General.php index 717559c207..028c3618ba 100644 --- a/libraries/classes/Rte/General.php +++ b/libraries/classes/Rte/General.php @@ -10,6 +10,7 @@ namespace PhpMyAdmin\Rte; use PhpMyAdmin\Message; use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Events; +use PhpMyAdmin\Rte\Words; use PhpMyAdmin\Util; /** @@ -81,7 +82,7 @@ class General } else { $message = __('Error in processing request:') . ' '; $message .= sprintf( - PMA_RTE_getWord('not_found'), + Words::get('not_found'), htmlspecialchars(Util::backquote($_REQUEST['item_name'])), htmlspecialchars(Util::backquote($db)) ); diff --git a/libraries/classes/Rte/RteList.php b/libraries/classes/Rte/RteList.php index a283816618..92ed258d67 100644 --- a/libraries/classes/Rte/RteList.php +++ b/libraries/classes/Rte/RteList.php @@ -8,6 +8,7 @@ namespace PhpMyAdmin\Rte; use PhpMyAdmin\Response; +use PhpMyAdmin\Rte\Words; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statements\CreateStatement; use PhpMyAdmin\SqlParser\Utils\Routine; @@ -47,7 +48,7 @@ class RteList /** * Generate output */ - $retval = "\n"; + $retval = "\n"; $retval .= '
\n"; $retval .= " \n"; - $retval .= " " . PMA_RTE_getWord('title') . "\n"; + $retval .= " " . Words::get('title') . "\n"; $retval .= " " - . Util::showMySQLDocu(PMA_RTE_getWord('docu')) . "\n"; + . Util::showMySQLDocu(Words::get('docu')) . "\n"; $retval .= " \n"; $retval .= "
\n"; - $retval .= " " . PMA_RTE_getWord('nothing') . "\n"; + $retval .= " " . Words::get('nothing') . "\n"; $retval .= "
\n"; $retval .= "
" . __('Event name') . "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "
" . __('Event type') . "\n"; + if ($response->isAjax()) { + $retval .= " \n"; + } else { + $retval .= " \n"; + $retval .= " {$item['item_type']}\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " $value) { + $selected = ""; + if (! empty($item['item_interval_field']) + && $item['item_interval_field'] == $value + ) { + $selected = " selected='selected'"; + } + $retval .= "$value"; + } + $retval .= " \n"; + $retval .= "
" . _pgettext('Start of recurring event', 'Start'); + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "
" . __('On completion preserve') . "\n"; + $retval .= " \n"; + $retval .= " isAjax()) { + $retval .= "\n"; + $retval .= "\n"; + } + $retval .= "\n\n"; + $retval .= "\n\n"; + + return $retval; + } // end self::getEditorForm() + + /** + * Composes the query necessary to create an event from an HTTP request. + * + * @return string The CREATE EVENT query. + */ + public static function getQueryFromRequest() + { + global $_REQUEST, $errors, $event_status, $event_type, $event_interval; + + $query = 'CREATE '; + if (! empty($_REQUEST['item_definer'])) { + if (mb_strpos($_REQUEST['item_definer'], '@') !== false + ) { + $arr = explode('@', $_REQUEST['item_definer']); + $query .= 'DEFINER=' . Util::backquote($arr[0]); + $query .= '@' . Util::backquote($arr[1]) . ' '; + } else { + $errors[] = __('The definer must be in the "username@hostname" format!'); + } + } + $query .= 'EVENT '; + if (! empty($_REQUEST['item_name'])) { + $query .= Util::backquote($_REQUEST['item_name']) . ' '; + } else { + $errors[] = __('You must provide an event name!'); + } + $query .= 'ON SCHEDULE '; + if (! empty($_REQUEST['item_type']) + && in_array($_REQUEST['item_type'], $event_type) + ) { + if ($_REQUEST['item_type'] == 'RECURRING') { + if (! empty($_REQUEST['item_interval_value']) + && !empty($_REQUEST['item_interval_field']) + && in_array($_REQUEST['item_interval_field'], $event_interval) + ) { + $query .= 'EVERY ' . intval($_REQUEST['item_interval_value']) . ' '; + $query .= $_REQUEST['item_interval_field'] . ' '; + } else { + $errors[] + = __('You must provide a valid interval value for the event.'); + } + if (! empty($_REQUEST['item_starts'])) { + $query .= "STARTS '" + . $GLOBALS['dbi']->escapeString($_REQUEST['item_starts']) + . "' "; + } + if (! empty($_REQUEST['item_ends'])) { + $query .= "ENDS '" + . $GLOBALS['dbi']->escapeString($_REQUEST['item_ends']) + . "' "; + } + } else { + if (! empty($_REQUEST['item_execute_at'])) { + $query .= "AT '" + . $GLOBALS['dbi']->escapeString($_REQUEST['item_execute_at']) + . "' "; + } else { + $errors[] + = __('You must provide a valid execution time for the event.'); + } + } + } else { + $errors[] = __('You must provide a valid type for the event.'); + } + $query .= 'ON COMPLETION '; + if (empty($_REQUEST['item_preserve'])) { + $query .= 'NOT '; + } + $query .= 'PRESERVE '; + if (! empty($_REQUEST['item_status'])) { + foreach ($event_status['display'] as $key => $value) { + if ($value == $_REQUEST['item_status']) { + $query .= $event_status['query'][$key] . ' '; + break; + } + } + } + if (! empty($_REQUEST['item_comment'])) { + $query .= "COMMENT '" . $GLOBALS['dbi']->escapeString( + $_REQUEST['item_comment'] + ) . "' "; + } + $query .= 'DO '; + if (! empty($_REQUEST['item_definition'])) { + $query .= $_REQUEST['item_definition']; + } else { + $errors[] = __('You must provide an event definition.'); + } + + return $query; + } // end self::getQueryFromRequest() +} diff --git a/libraries/rte/rte_events.lib.php b/libraries/rte/rte_events.lib.php deleted file mode 100644 index 8204db63d1..0000000000 --- a/libraries/rte/rte_events.lib.php +++ /dev/null @@ -1,615 +0,0 @@ - array('ENABLE', - 'DISABLE', - 'DISABLE ON SLAVE'), - 'display' => array('ENABLED', - 'DISABLED', - 'SLAVESIDE_DISABLED') - ); - $event_type = array('RECURRING', - 'ONE TIME'); - $event_interval = array('YEAR', - 'QUARTER', - 'MONTH', - 'DAY', - 'HOUR', - 'MINUTE', - 'WEEK', - 'SECOND', - 'YEAR_MONTH', - 'DAY_HOUR', - 'DAY_MINUTE', - 'DAY_SECOND', - 'HOUR_MINUTE', - 'HOUR_SECOND', - 'MINUTE_SECOND'); -} - -/** - * Main function for the events functionality - * - * @return void - */ -function PMA_EVN_main() -{ - global $db; - - PMA_EVN_setGlobals(); - /** - * Process all requests - */ - PMA_EVN_handleEditor(); - PMA_EVN_handleExport(); - /** - * Display a list of available events - */ - $items = $GLOBALS['dbi']->getEvents($db); - echo PMA_RTE_getList('event', $items); - /** - * Display a link for adding a new event, if - * the user has the privileges and a link to - * toggle the state of the event scheduler. - */ - echo PMA_EVN_getFooterLinks(); -} // end PMA_EVN_main() - -/** - * Handles editor requests for adding or editing an item - * - * @return void - */ -function PMA_EVN_handleEditor() -{ - global $_REQUEST, $_POST, $errors, $db; - - if (! empty($_REQUEST['editor_process_add']) - || ! empty($_REQUEST['editor_process_edit']) - ) { - $sql_query = ''; - - $item_query = PMA_EVN_getQueryFromRequest(); - - if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest() - // Execute the created query - if (! empty($_REQUEST['editor_process_edit'])) { - // Backup the old trigger, in case something goes wrong - $create_item = $GLOBALS['dbi']->getDefinition( - $db, - 'EVENT', - $_REQUEST['item_original_name'] - ); - $drop_item = "DROP EVENT " - . PhpMyAdmin\Util::backquote($_REQUEST['item_original_name']) - . ";\n"; - $result = $GLOBALS['dbi']->tryQuery($drop_item); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($drop_item) - ) - . '
' - . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); - } else { - $result = $GLOBALS['dbi']->tryQuery($item_query); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($item_query) - ) - . '
' - . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); - // We dropped the old item, but were unable to create - // the new one. Try to restore the backup query - $result = $GLOBALS['dbi']->tryQuery($create_item); - $errors = checkResult( - $result, - __( - 'Sorry, we failed to restore the dropped event.' - ), - $create_item, - $errors - ); - } else { - $message = PhpMyAdmin\Message::success( - __('Event %1$s has been modified.') - ); - $message->addParam( - PhpMyAdmin\Util::backquote($_REQUEST['item_name']) - ); - $sql_query = $drop_item . $item_query; - } - } - } else { - // 'Add a new item' mode - $result = $GLOBALS['dbi']->tryQuery($item_query); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($item_query) - ) - . '

' - . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); - } else { - $message = PhpMyAdmin\Message::success( - __('Event %1$s has been created.') - ); - $message->addParam( - PhpMyAdmin\Util::backquote($_REQUEST['item_name']) - ); - $sql_query = $item_query; - } - } - } - - if (count($errors)) { - $message = PhpMyAdmin\Message::error( - '' - . __( - 'One or more errors have occurred while processing your request:' - ) - . '' - ); - $message->addHtml('
    '); - foreach ($errors as $string) { - $message->addHtml('
  • ' . $string . '
  • '); - } - $message->addHtml('
'); - } - - $output = PhpMyAdmin\Util::getMessage($message, $sql_query); - $response = Response::getInstance(); - if ($response->isAjax()) { - if ($message->isSuccess()) { - $events = $GLOBALS['dbi']->getEvents($db, $_REQUEST['item_name']); - $event = $events[0]; - $response->addJSON( - 'name', - htmlspecialchars( - mb_strtoupper($_REQUEST['item_name']) - ) - ); - $response->addJSON('new_row', PMA_EVN_getRowForList($event)); - $response->addJSON('insert', ! empty($event)); - $response->addJSON('message', $output); - } else { - $response->setRequestStatus(false); - $response->addJSON('message', $message); - } - exit; - } - } - /** - * Display a form used to add/edit a trigger, if necessary - */ - if (count($errors) - || (empty($_REQUEST['editor_process_add']) - && empty($_REQUEST['editor_process_edit']) - && (! empty($_REQUEST['add_item']) - || ! empty($_REQUEST['edit_item']) - || ! empty($_REQUEST['item_changetype']))) - ) { // FIXME: this must be simpler than that - $operation = ''; - if (! empty($_REQUEST['item_changetype'])) { - $operation = 'change'; - } - // Get the data for the form (if any) - if (! empty($_REQUEST['add_item'])) { - $title = PMA_RTE_getWord('add'); - $item = PMA_EVN_getDataFromRequest(); - $mode = 'add'; - } else if (! empty($_REQUEST['edit_item'])) { - $title = __("Edit event"); - if (! empty($_REQUEST['item_name']) - && empty($_REQUEST['editor_process_edit']) - && empty($_REQUEST['item_changetype']) - ) { - $item = PMA_EVN_getDataFromName($_REQUEST['item_name']); - if ($item !== false) { - $item['item_original_name'] = $item['item_name']; - } - } else { - $item = PMA_EVN_getDataFromRequest(); - } - $mode = 'edit'; - } - PMA_RTE_sendEditor('EVN', $mode, $item, $title, $db, $operation); - } -} // end PMA_EVN_handleEditor() - -/** - * This function will generate the values that are required to for the editor - * - * @return array Data necessary to create the editor. - */ -function PMA_EVN_getDataFromRequest() -{ - $retval = array(); - $indices = array('item_name', - 'item_original_name', - 'item_status', - 'item_execute_at', - 'item_interval_value', - 'item_interval_field', - 'item_starts', - 'item_ends', - 'item_definition', - 'item_preserve', - 'item_comment', - 'item_definer'); - foreach ($indices as $index) { - $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : ''; - } - $retval['item_type'] = 'ONE TIME'; - $retval['item_type_toggle'] = 'RECURRING'; - if (isset($_REQUEST['item_type']) && $_REQUEST['item_type'] == 'RECURRING') { - $retval['item_type'] = 'RECURRING'; - $retval['item_type_toggle'] = 'ONE TIME'; - } - return $retval; -} // end PMA_EVN_getDataFromRequest() - -/** - * This function will generate the values that are required to complete - * the "Edit event" form given the name of a event. - * - * @param string $name The name of the event. - * - * @return array Data necessary to create the editor. - */ -function PMA_EVN_getDataFromName($name) -{ - global $db; - - $retval = array(); - $columns = "`EVENT_NAME`, `STATUS`, `EVENT_TYPE`, `EXECUTE_AT`, " - . "`INTERVAL_VALUE`, `INTERVAL_FIELD`, `STARTS`, `ENDS`, " - . "`EVENT_DEFINITION`, `ON_COMPLETION`, `DEFINER`, `EVENT_COMMENT`"; - $where = "EVENT_SCHEMA " . PhpMyAdmin\Util::getCollateForIS() . "=" - . "'" . $GLOBALS['dbi']->escapeString($db) . "' " - . "AND EVENT_NAME='" . $GLOBALS['dbi']->escapeString($name) . "'"; - $query = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE $where;"; - $item = $GLOBALS['dbi']->fetchSingleRow($query); - if (! $item) { - return false; - } - $retval['item_name'] = $item['EVENT_NAME']; - $retval['item_status'] = $item['STATUS']; - $retval['item_type'] = $item['EVENT_TYPE']; - if ($retval['item_type'] == 'RECURRING') { - $retval['item_type_toggle'] = 'ONE TIME'; - } else { - $retval['item_type_toggle'] = 'RECURRING'; - } - $retval['item_execute_at'] = $item['EXECUTE_AT']; - $retval['item_interval_value'] = $item['INTERVAL_VALUE']; - $retval['item_interval_field'] = $item['INTERVAL_FIELD']; - $retval['item_starts'] = $item['STARTS']; - $retval['item_ends'] = $item['ENDS']; - $retval['item_preserve'] = ''; - if ($item['ON_COMPLETION'] == 'PRESERVE') { - $retval['item_preserve'] = " checked='checked'"; - } - $retval['item_definition'] = $item['EVENT_DEFINITION']; - $retval['item_definer'] = $item['DEFINER']; - $retval['item_comment'] = $item['EVENT_COMMENT']; - - return $retval; -} // end PMA_EVN_getDataFromName() - -/** - * Displays a form used to add/edit an event - * - * @param string $mode If the editor will be used to edit an event - * or add a new one: 'edit' or 'add'. - * @param string $operation If the editor was previously invoked with - * JS turned off, this will hold the name of - * the current operation - * @param array $item Data for the event returned by - * PMA_EVN_getDataFromRequest() or - * PMA_EVN_getDataFromName() - * - * @return string HTML code for the editor. - */ -function PMA_EVN_getEditorForm($mode, $operation, $item) -{ - global $db, $table, $event_status, $event_type, $event_interval; - - $modeToUpper = mb_strtoupper($mode); - - $response = Response::getInstance(); - - // Escape special characters - $need_escape = array( - 'item_original_name', - 'item_name', - 'item_type', - 'item_execute_at', - 'item_interval_value', - 'item_starts', - 'item_ends', - 'item_definition', - 'item_definer', - 'item_comment' - ); - foreach ($need_escape as $index) { - $item[$index] = htmlentities($item[$index], ENT_QUOTES); - } - $original_data = ''; - if ($mode == 'edit') { - $original_data = "\n"; - } - // Handle some logic first - if ($operation == 'change') { - if ($item['item_type'] == 'RECURRING') { - $item['item_type'] = 'ONE TIME'; - $item['item_type_toggle'] = 'RECURRING'; - } else { - $item['item_type'] = 'RECURRING'; - $item['item_type_toggle'] = 'ONE TIME'; - } - } - if ($item['item_type'] == 'ONE TIME') { - $isrecurring_class = ' hide'; - $isonetime_class = ''; - } else { - $isrecurring_class = ''; - $isonetime_class = ' hide'; - } - // Create the output - $retval = ""; - $retval .= "\n\n"; - $retval .= "
\n"; - $retval .= "\n"; - $retval .= $original_data; - $retval .= Url::getHiddenInputs($db, $table) . "\n"; - $retval .= "
\n"; - $retval .= "" . __('Details') . "\n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "\n"; - - $retval .= "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + + return $retval; + } // end self::getRoutineRow() + + /** + * Creates the contents for a row in the list of triggers + * + * @param array $trigger An array of routine data + * @param string $rowclass Additional class + * + * @return string HTML code of a cell for the list of triggers + */ + public static function getTriggerRow($trigger, $rowclass = '') + { + global $ajax_class, $url_query, $db, $table, $titles; + + $retval = " \n"; + $retval .= " \n"; + $retval .= " \n"; + if (empty($table)) { + $retval .= " \n"; + } + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + + return $retval; + } // end self::getTriggerRow() + + /** + * Creates the contents for a row in the list of events + * + * @param array $event An array of routine data + * @param string $rowclass Additional class + * + * @return string HTML code of a cell for the list of events + */ + public static function getEventRow($event, $rowclass = '') + { + global $ajax_class, $url_query, $db, $titles; + + $sql_drop = sprintf( + 'DROP EVENT IF EXISTS %s', + Util::backquote($event['name']) + ); + + $retval = " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + + return $retval; + } // end self::getEventRow() +} diff --git a/libraries/rte/rte_list.lib.php b/libraries/rte/rte_list.lib.php deleted file mode 100644 index 827fae0dbc..0000000000 --- a/libraries/rte/rte_list.lib.php +++ /dev/null @@ -1,482 +0,0 @@ -\n"; - $retval .= ''; - $retval .= Url::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']); - $retval .= "
\n"; - $retval .= " \n"; - $retval .= " " . PMA_RTE_getWord('title') . "\n"; - $retval .= " " - . PhpMyAdmin\Util::showMySQLDocu(PMA_RTE_getWord('docu')) . "\n"; - $retval .= " \n"; - $retval .= "
\n"; - $retval .= " " . PMA_RTE_getWord('nothing') . "\n"; - $retval .= "
\n"; - $retval .= "
" . __('Event name') . "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "
" . __('Event type') . "\n"; - if ($response->isAjax()) { - $retval .= " \n"; - } else { - $retval .= " \n"; - $retval .= " {$item['item_type']}\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " $value) { - $selected = ""; - if (! empty($item['item_interval_field']) - && $item['item_interval_field'] == $value - ) { - $selected = " selected='selected'"; - } - $retval .= "$value"; - } - $retval .= " \n"; - $retval .= "
" . _pgettext('Start of recurring event', 'Start'); - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "
" . __('On completion preserve') . "\n"; - $retval .= " \n"; - $retval .= " isAjax()) { - $retval .= "\n"; - $retval .= "\n"; - } - $retval .= "\n\n"; - $retval .= "\n\n"; - - return $retval; -} // end PMA_EVN_getEditorForm() - -/** - * Composes the query necessary to create an event from an HTTP request. - * - * @return string The CREATE EVENT query. - */ -function PMA_EVN_getQueryFromRequest() -{ - global $_REQUEST, $errors, $event_status, $event_type, $event_interval; - - $query = 'CREATE '; - if (! empty($_REQUEST['item_definer'])) { - if (mb_strpos($_REQUEST['item_definer'], '@') !== false - ) { - $arr = explode('@', $_REQUEST['item_definer']); - $query .= 'DEFINER=' . PhpMyAdmin\Util::backquote($arr[0]); - $query .= '@' . PhpMyAdmin\Util::backquote($arr[1]) . ' '; - } else { - $errors[] = __('The definer must be in the "username@hostname" format!'); - } - } - $query .= 'EVENT '; - if (! empty($_REQUEST['item_name'])) { - $query .= PhpMyAdmin\Util::backquote($_REQUEST['item_name']) . ' '; - } else { - $errors[] = __('You must provide an event name!'); - } - $query .= 'ON SCHEDULE '; - if (! empty($_REQUEST['item_type']) - && in_array($_REQUEST['item_type'], $event_type) - ) { - if ($_REQUEST['item_type'] == 'RECURRING') { - if (! empty($_REQUEST['item_interval_value']) - && !empty($_REQUEST['item_interval_field']) - && in_array($_REQUEST['item_interval_field'], $event_interval) - ) { - $query .= 'EVERY ' . intval($_REQUEST['item_interval_value']) . ' '; - $query .= $_REQUEST['item_interval_field'] . ' '; - } else { - $errors[] - = __('You must provide a valid interval value for the event.'); - } - if (! empty($_REQUEST['item_starts'])) { - $query .= "STARTS '" - . $GLOBALS['dbi']->escapeString($_REQUEST['item_starts']) - . "' "; - } - if (! empty($_REQUEST['item_ends'])) { - $query .= "ENDS '" - . $GLOBALS['dbi']->escapeString($_REQUEST['item_ends']) - . "' "; - } - } else { - if (! empty($_REQUEST['item_execute_at'])) { - $query .= "AT '" - . $GLOBALS['dbi']->escapeString($_REQUEST['item_execute_at']) - . "' "; - } else { - $errors[] - = __('You must provide a valid execution time for the event.'); - } - } - } else { - $errors[] = __('You must provide a valid type for the event.'); - } - $query .= 'ON COMPLETION '; - if (empty($_REQUEST['item_preserve'])) { - $query .= 'NOT '; - } - $query .= 'PRESERVE '; - if (! empty($_REQUEST['item_status'])) { - foreach ($event_status['display'] as $key => $value) { - if ($value == $_REQUEST['item_status']) { - $query .= $event_status['query'][$key] . ' '; - break; - } - } - } - if (! empty($_REQUEST['item_comment'])) { - $query .= "COMMENT '" . $GLOBALS['dbi']->escapeString( - $_REQUEST['item_comment'] - ) . "' "; - } - $query .= 'DO '; - if (! empty($_REQUEST['item_definition'])) { - $query .= $_REQUEST['item_definition']; - } else { - $errors[] = __('You must provide an event definition.'); - } - - return $query; -} // end PMA_EVN_getQueryFromRequest() - diff --git a/libraries/rte/rte_general.lib.php b/libraries/rte/rte_general.lib.php index ec6f42b460..6b3ea4a1b8 100644 --- a/libraries/rte/rte_general.lib.php +++ b/libraries/rte/rte_general.lib.php @@ -7,6 +7,7 @@ */ use PhpMyAdmin\Message; use PhpMyAdmin\Response; +use PhpMyAdmin\Rte\Events; if (! defined('PHPMYADMIN')) { exit; @@ -61,7 +62,7 @@ function PMA_RTE_sendEditor($type, $mode, $item, $title, $db, $operation = null) if ($type == 'TRI') { $editor = PMA_TRI_getEditorForm($mode, $item); } else { // EVN - $editor = PMA_EVN_getEditorForm($mode, $operation, $item); + $editor = Events::getEditorForm($mode, $operation, $item); } if ($response->isAjax()) { $response->addJSON('message', $editor); diff --git a/libraries/rte/rte_main.inc.php b/libraries/rte/rte_main.inc.php index 52f764b012..85e52d56bf 100644 --- a/libraries/rte/rte_main.inc.php +++ b/libraries/rte/rte_main.inc.php @@ -7,6 +7,7 @@ */ use PhpMyAdmin\Url; use PhpMyAdmin\Response; +use PhpMyAdmin\Rte\Events; if (! defined('PHPMYADMIN')) { exit; @@ -103,7 +104,6 @@ case 'TRI': PMA_TRI_main(); break; case 'EVN': - PMA_EVN_main(); + Events::main(); break; } - diff --git a/test/classes/Rte/EventsTest.php b/test/classes/Rte/EventsTest.php new file mode 100644 index 0000000000..0e7cea2d73 --- /dev/null +++ b/test/classes/Rte/EventsTest.php @@ -0,0 +1,527 @@ + $value) { + if ($value !== '') { + $_REQUEST[$key] = $value; + } + } + $this->assertEquals($out, Events::getDataFromRequest()); + } + + /** + * Data provider for testGetDataFromRequestEmpty + * + * @return array + */ + public function providerGetDataFromRequest() + { + return array( + array( + array( + 'item_name' => '', + 'item_type' => '', + 'item_original_name' => '', + 'item_status' => '', + 'item_execute_at' => '', + 'item_interval_value' => '', + 'item_interval_field' => '', + 'item_starts' => '', + 'item_ends' => '', + 'item_definition' => '', + 'item_preserve' => '', + 'item_comment' => '', + 'item_definer' => '' + ), + array( + 'item_name' => '', + 'item_type' => 'ONE TIME', + 'item_type_toggle' => 'RECURRING', + 'item_original_name' => '', + 'item_status' => '', + 'item_execute_at' => '', + 'item_interval_value' => '', + 'item_interval_field' => '', + 'item_starts' => '', + 'item_ends' => '', + 'item_definition' => '', + 'item_preserve' => '', + 'item_comment' => '', + 'item_definer' => '' + ) + ), + array( + array( + 'item_name' => 'foo', + 'item_type' => 'RECURRING', + 'item_original_name' => 'foo', + 'item_status' => 'foo', + 'item_execute_at' => 'foo', + 'item_interval_value' => 'foo', + 'item_interval_field' => 'foo', + 'item_starts' => 'foo', + 'item_ends' => 'foo', + 'item_definition' => 'foo', + 'item_preserve' => 'foo', + 'item_comment' => 'foo', + 'item_definer' => 'foo' + ), + array( + 'item_name' => 'foo', + 'item_type' => 'RECURRING', + 'item_type_toggle' => 'ONE TIME', + 'item_original_name' => 'foo', + 'item_status' => 'foo', + 'item_execute_at' => 'foo', + 'item_interval_value' => 'foo', + 'item_interval_field' => 'foo', + 'item_starts' => 'foo', + 'item_ends' => 'foo', + 'item_definition' => 'foo', + 'item_preserve' => 'foo', + 'item_comment' => 'foo', + 'item_definer' => 'foo' + ) + ), + ); + } + + /** + * Test for Events::getEditorForm + * + * @param array $data Data for routine + * @param array $matcher Matcher + * + * @return void + * + * @dataProvider providerGetEditorFormAdd + */ + public function testGetEditorFormAdd($data, $matcher) + { + Events::setGlobals(); + $this->assertContains( + $matcher, + Events::getEditorForm('add', 'change', $data) + ); + } + + /** + * Data provider for testGetEditorFormAdd + * + * @return array + */ + public function providerGetEditorFormAdd() + { + $data = array( + 'item_name' => '', + 'item_type' => 'ONE TIME', + 'item_type_toggle' => 'RECURRING', + 'item_original_name' => '', + 'item_status' => '', + 'item_execute_at' => '', + 'item_interval_value' => '', + 'item_interval_field' => '', + 'item_starts' => '', + 'item_ends' => '', + 'item_definition' => '', + 'item_preserve' => '', + 'item_comment' => '', + 'item_definer' => '' + ); + + return array( + array( + $data, + "assertContains( + $matcher, + Events::getEditorForm('edit', 'change', $data) + ); + } + + /** + * Data provider for testGetEditorFormEdit + * + * @return array + */ + public function providerGetEditorFormEdit() + { + $data = array( + 'item_name' => 'foo', + 'item_type' => 'RECURRING', + 'item_type_toggle' => 'ONE TIME', + 'item_original_name' => 'bar', + 'item_status' => 'ENABLED', + 'item_execute_at' => '', + 'item_interval_value' => '1', + 'item_interval_field' => 'DAY', + 'item_starts' => '', + 'item_ends' => '', + 'item_definition' => 'SET @A=1;', + 'item_preserve' => '', + 'item_comment' => '', + 'item_definer' => '' + ); + + return array( + array( + $data, + "setAjax(true); + Events::setGlobals(); + $this->assertContains( + $matcher, + Events::getEditorForm('edit', 'change', $data) + ); + Response::getInstance()->setAjax(false); + } + + /** + * Data provider for testGetEditorFormAjax + * + * @return array + */ + public function providerGetEditorFormAjax() + { + $data = array( + 'item_name' => '', + 'item_type' => 'RECURRING', + 'item_type_toggle' => 'ONE TIME', + 'item_original_name' => '', + 'item_status' => 'ENABLED', + 'item_execute_at' => '', + 'item_interval_value' => '', + 'item_interval_field' => 'DAY', + 'item_starts' => '', + 'item_ends' => '', + 'item_definition' => '', + 'item_preserve' => '', + 'item_comment' => '', + 'item_definer' => '' + ); + + return array( + array( + $data, + "assertContains( - $matcher, - PMA_EVN_getEditorForm('edit', 'change', $data) - ); - } - - /** - * Data provider for testgetEditorForm_edit - * - * @return array - */ - public function providerEdit() - { - $data = array( - 'item_name' => 'foo', - 'item_type' => 'RECURRING', - 'item_type_toggle' => 'ONE TIME', - 'item_original_name' => 'bar', - 'item_status' => 'ENABLED', - 'item_execute_at' => '', - 'item_interval_value' => '1', - 'item_interval_field' => 'DAY', - 'item_starts' => '', - 'item_ends' => '', - 'item_definition' => 'SET @A=1;', - 'item_preserve' => '', - 'item_comment' => '', - 'item_definer' => '' - ); - - return array( - array( - $data, - "setAjax(true); - PMA_EVN_setGlobals(); - $this->assertContains( - $matcher, - PMA_EVN_getEditorForm('edit', 'change', $data) - ); - Response::getInstance()->setAjax(false); - } - - /** - * Data provider for testgetEditorForm_ajax - * - * @return array - */ - public function providerAjax() - { - $data = array( - 'item_name' => '', - 'item_type' => 'RECURRING', - 'item_type_toggle' => 'ONE TIME', - 'item_original_name' => '', - 'item_status' => 'ENABLED', - 'item_execute_at' => '', - 'item_interval_value' => '', - 'item_interval_field' => 'DAY', - 'item_starts' => '', - 'item_ends' => '', - 'item_definition' => '', - 'item_preserve' => '', - 'item_comment' => '', - 'item_definer' => '' - ); - - return array( - array( - $data, - "'; + echo "
\n" + , "$title\n" + , $export_data + , "
\n"; + } + } else { + $_db = htmlspecialchars(Util::backquote($db)); + $message = __('Error in processing request:') . ' ' + . sprintf(PMA_RTE_getWord('no_view'), $item_name, $_db); + $message = Message::error($message); + + if ($response->isAjax()) { + $response->setRequestStatus(false); + $response->addJSON('message', $message); + exit; + } else { + $message->display(); + } + } + } // end self::handle() + + /** + * If necessary, prepares event information and passes + * it to self::handle() for the actual export. + * + * @return void + */ + public static function events() + { + global $_GET, $db; + + if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { + $item_name = $_GET['item_name']; + $export_data = $GLOBALS['dbi']->getDefinition($db, 'EVENT', $item_name); + if (! $export_data) { + $export_data = false; + } + self::handle($export_data); + } + } // end self::events() + + /** + * If necessary, prepares routine information and passes + * it to self::handle() for the actual export. + * + * @return void + */ + public static function routines() + { + global $_GET, $db; + + if (! empty($_GET['export_item']) + && ! empty($_GET['item_name']) + && ! empty($_GET['item_type']) + ) { + if ($_GET['item_type'] == 'FUNCTION' || $_GET['item_type'] == 'PROCEDURE') { + $rtn_definition + = $GLOBALS['dbi']->getDefinition( + $db, + $_GET['item_type'], + $_GET['item_name'] + ); + if (! $rtn_definition) { + $export_data = false; + } else { + $export_data = "DELIMITER $$\n" + . $rtn_definition + . "$$\nDELIMITER ;\n"; + } + + self::handle($export_data); + } + } + } // end self::routines() + + /** + * If necessary, prepares trigger information and passes + * it to self::handle() for the actual export. + * + * @return void + */ + public static function triggers() + { + global $_GET, $db, $table; + + if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { + $item_name = $_GET['item_name']; + $triggers = $GLOBALS['dbi']->getTriggers($db, $table, ''); + $export_data = false; + foreach ($triggers as $trigger) { + if ($trigger['name'] === $item_name) { + $export_data = $trigger['create']; + break; + } + } + self::handle($export_data); + } + } // end self::triggers() +} diff --git a/libraries/rte/rte_export.lib.php b/libraries/rte/rte_export.lib.php deleted file mode 100644 index 595e41249f..0000000000 --- a/libraries/rte/rte_export.lib.php +++ /dev/null @@ -1,137 +0,0 @@ -isAjax()) { - $response->addJSON('message', $export_data); - $response->addJSON('title', $title); - exit; - } else { - $export_data = ''; - echo "
\n" - , "$title\n" - , $export_data - , "
\n"; - } - } else { - $_db = htmlspecialchars(PhpMyAdmin\Util::backquote($db)); - $message = __('Error in processing request:') . ' ' - . sprintf(PMA_RTE_getWord('no_view'), $item_name, $_db); - $message = Message::error($message); - - if ($response->isAjax()) { - $response->setRequestStatus(false); - $response->addJSON('message', $message); - exit; - } else { - $message->display(); - } - } -} // end PMA_RTE_handleExport() - -/** - * If necessary, prepares event information and passes - * it to PMA_RTE_handleExport() for the actual export. - * - * @return void - */ -function PMA_EVN_handleExport() -{ - global $_GET, $db; - - if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { - $item_name = $_GET['item_name']; - $export_data = $GLOBALS['dbi']->getDefinition($db, 'EVENT', $item_name); - if (! $export_data) { - $export_data = false; - } - PMA_RTE_handleExport($export_data); - } -} // end PMA_EVN_handleExport() - -/** - * If necessary, prepares routine information and passes - * it to PMA_RTE_handleExport() for the actual export. - * - * @return void - */ -function PMA_RTN_handleExport() -{ - global $_GET, $db; - - if (! empty($_GET['export_item']) - && ! empty($_GET['item_name']) - && ! empty($_GET['item_type']) - ) { - if ($_GET['item_type'] == 'FUNCTION' || $_GET['item_type'] == 'PROCEDURE') { - $rtn_definition - = $GLOBALS['dbi']->getDefinition( - $db, - $_GET['item_type'], - $_GET['item_name'] - ); - if (! $rtn_definition) { - $export_data = false; - } else { - $export_data = "DELIMITER $$\n" - . $rtn_definition - . "$$\nDELIMITER ;\n"; - } - - PMA_RTE_handleExport($export_data); - } - } -} // end PMA_RTN_handleExport() - -/** - * If necessary, prepares trigger information and passes - * it to PMA_RTE_handleExport() for the actual export. - * - * @return void - */ -function PMA_TRI_handleExport() -{ - global $_GET, $db, $table; - - if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { - $item_name = $_GET['item_name']; - $triggers = $GLOBALS['dbi']->getTriggers($db, $table, ''); - $export_data = false; - foreach ($triggers as $trigger) { - if ($trigger['name'] === $item_name) { - $export_data = $trigger['create']; - break; - } - } - PMA_RTE_handleExport($export_data); - } -} // end PMA_TRI_handleExport() diff --git a/libraries/rte/rte_main.inc.php b/libraries/rte/rte_main.inc.php index 85e52d56bf..a6a40890cb 100644 --- a/libraries/rte/rte_main.inc.php +++ b/libraries/rte/rte_main.inc.php @@ -5,9 +5,9 @@ * * @package PhpMyAdmin */ -use PhpMyAdmin\Url; use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Events; +use PhpMyAdmin\Url; if (! defined('PHPMYADMIN')) { exit; @@ -19,7 +19,6 @@ if (! defined('PHPMYADMIN')) { */ require_once './libraries/rte/rte_general.lib.php'; require_once './libraries/rte/rte_words.lib.php'; -require_once './libraries/rte/rte_export.lib.php'; require_once './libraries/rte/rte_list.lib.php'; require_once './libraries/rte/rte_footer.lib.php'; diff --git a/libraries/rte/rte_routines.lib.php b/libraries/rte/rte_routines.lib.php index 06c670c3f1..2cef4bd9d8 100644 --- a/libraries/rte/rte_routines.lib.php +++ b/libraries/rte/rte_routines.lib.php @@ -9,9 +9,10 @@ use PhpMyAdmin\Charsets; use PhpMyAdmin\Core; use PhpMyAdmin\Message; use PhpMyAdmin\Response; -use PhpMyAdmin\Util; -use PhpMyAdmin\Url; +use PhpMyAdmin\Rte\Export; use PhpMyAdmin\SqlParser\Statements\CreateStatement; +use PhpMyAdmin\Url; +use PhpMyAdmin\Util; if (! defined('PHPMYADMIN')) { exit; @@ -57,7 +58,7 @@ function PMA_RTN_main($type) */ PMA_RTN_handleEditor(); PMA_RTN_handleExecute(); - PMA_RTN_handleExport(); + Export::routines(); /** * Display a list of available routines */ diff --git a/libraries/rte/rte_triggers.lib.php b/libraries/rte/rte_triggers.lib.php index c042ef5f83..612499198d 100644 --- a/libraries/rte/rte_triggers.lib.php +++ b/libraries/rte/rte_triggers.lib.php @@ -6,6 +6,7 @@ * @package PhpMyAdmin */ use PhpMyAdmin\Response; +use PhpMyAdmin\Rte\Export; use PhpMyAdmin\Url; if (! defined('PHPMYADMIN')) { @@ -43,7 +44,7 @@ function PMA_TRI_main() * Process all requests */ PMA_TRI_handleEditor(); - PMA_TRI_handleExport(); + Export::triggers(); /** * Display a list of available triggers */ @@ -463,4 +464,3 @@ function PMA_TRI_getQueryFromRequest() return $query; } // end PMA_TRI_getQueryFromRequest() - From 532f8214636f057cac6eebb5f486cdff87201780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 8 Sep 2017 16:24:22 -0300 Subject: [PATCH 3/8] Refactor rte_footer 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/Rte/Events.php | 3 +- libraries/classes/Rte/Footer.php | 136 +++++++++++++++++++++++++++++ libraries/classes/Util.php | 2 +- libraries/rte/rte_footer.lib.php | 128 --------------------------- libraries/rte/rte_main.inc.php | 1 - libraries/rte/rte_routines.lib.php | 3 +- libraries/rte/rte_triggers.lib.php | 3 +- 7 files changed, 143 insertions(+), 133 deletions(-) create mode 100644 libraries/classes/Rte/Footer.php delete mode 100644 libraries/rte/rte_footer.lib.php diff --git a/libraries/classes/Rte/Events.php b/libraries/classes/Rte/Events.php index b0451eba0b..95243c5932 100644 --- a/libraries/classes/Rte/Events.php +++ b/libraries/classes/Rte/Events.php @@ -10,6 +10,7 @@ namespace PhpMyAdmin\Rte; use PhpMyAdmin\Message; use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Export; +use PhpMyAdmin\Rte\Footer; use PhpMyAdmin\Url; use PhpMyAdmin\Util; @@ -81,7 +82,7 @@ class Events * the user has the privileges and a link to * toggle the state of the event scheduler. */ - echo PMA_EVN_getFooterLinks(); + echo Footer::events(); } // end self::main() /** diff --git a/libraries/classes/Rte/Footer.php b/libraries/classes/Rte/Footer.php new file mode 100644 index 0000000000..deea4ba9a9 --- /dev/null +++ b/libraries/classes/Rte/Footer.php @@ -0,0 +1,136 @@ +\n"; + $retval .= "
\n"; + $retval .= "" . _pgettext('Create new procedure', 'New') . "\n"; + $retval .= " \n"; + $retval .= "
\n"; + $retval .= "\n\n"; + + return $retval; + } // end self::getLinks() + + /** + * Creates a fieldset for adding a new routine, if the user has the privileges. + * + * @return string HTML code with containing the footer fieldset + */ + public static function routines() + { + return self::getLinks('CREATE_PROCEDURE', 'CREATE ROUTINE', 'ROUTINE'); + }// end self::routines() + + /** + * Creates a fieldset for adding a new trigger, if the user has the privileges. + * + * @return string HTML code with containing the footer fieldset + */ + public static function triggers() + { + return self::getLinks('CREATE_TRIGGER', 'TRIGGER', 'TRIGGER'); + } // end self::triggers() + + /** + * Creates a fieldset for adding a new event, if the user has the privileges. + * + * @return string HTML code with containing the footer fieldset + */ + public static function events() + { + global $db, $url_query; + + /** + * For events, we show the usual 'Add event' form and also + * a form for toggling the state of the event scheduler + */ + // Init options for the event scheduler toggle functionality + $es_state = $GLOBALS['dbi']->fetchValue( + "SHOW GLOBAL VARIABLES LIKE 'event_scheduler'", + 0, + 1 + ); + $es_state = mb_strtolower($es_state); + $options = array( + 0 => array( + 'label' => __('OFF'), + 'value' => "SET GLOBAL event_scheduler=\"OFF\"", + 'selected' => ($es_state != 'on') + ), + 1 => array( + 'label' => __('ON'), + 'value' => "SET GLOBAL event_scheduler=\"ON\"", + 'selected' => ($es_state == 'on') + ) + ); + // Generate output + $retval = "\n"; + $retval .= "
\n"; + // show the usual footer + $retval .= self::getLinks('CREATE_EVENT', 'EVENT', 'EVENT'); + $retval .= "
\n"; + $retval .= " \n"; + $retval .= " " . __('Event scheduler status') . "\n"; + $retval .= " \n"; + $retval .= "
\n"; + // show the toggle button + $retval .= Util::toggleButton( + "sql.php$url_query&goto=db_events.php" . urlencode("?db=$db"), + 'sql_query', + $options, + 'PMA_slidingMessage(data.sql_query);' + ); + $retval .= "
\n"; + $retval .= "
\n"; + $retval .= "
\n"; + $retval .= "
"; + $retval .= "\n"; + + return $retval; + } // end self::events() +} diff --git a/libraries/classes/Util.php b/libraries/classes/Util.php index bff06a935d..5770b24ad0 100644 --- a/libraries/classes/Util.php +++ b/libraries/classes/Util.php @@ -2681,7 +2681,7 @@ class Util * * @param string $action The URL for the request to be executed * @param string $select_name The name for the dropdown box - * @param array $options An array of options (see rte_footer.lib.php) + * @param array $options An array of options (see PhpMyAdmin\Rte\Footer) * @param string $callback A JS snippet to execute when the request is * successfully processed * diff --git a/libraries/rte/rte_footer.lib.php b/libraries/rte/rte_footer.lib.php deleted file mode 100644 index 2953074c36..0000000000 --- a/libraries/rte/rte_footer.lib.php +++ /dev/null @@ -1,128 +0,0 @@ -\n"; - $retval .= "
\n"; - $retval .= "" . _pgettext('Create new procedure', 'New') . "\n"; - $retval .= " \n"; - $retval .= "
\n"; - $retval .= "\n\n"; - - return $retval; -} // end PMA_RTE_getFooterLinks() - -/** - * Creates a fieldset for adding a new routine, if the user has the privileges. - * - * @return string HTML code with containing the footer fieldset - */ -function PMA_RTN_getFooterLinks() -{ - return PMA_RTE_getFooterLinks('CREATE_PROCEDURE', 'CREATE ROUTINE', 'ROUTINE'); -}// end PMA_RTN_getFooterLinks() - -/** - * Creates a fieldset for adding a new trigger, if the user has the privileges. - * - * @return string HTML code with containing the footer fieldset - */ -function PMA_TRI_getFooterLinks() -{ - return PMA_RTE_getFooterLinks('CREATE_TRIGGER', 'TRIGGER', 'TRIGGER'); -} // end PMA_TRI_getFooterLinks() - -/** - * Creates a fieldset for adding a new event, if the user has the privileges. - * - * @return string HTML code with containing the footer fieldset - */ -function PMA_EVN_getFooterLinks() -{ - global $db, $url_query; - - /** - * For events, we show the usual 'Add event' form and also - * a form for toggling the state of the event scheduler - */ - // Init options for the event scheduler toggle functionality - $es_state = $GLOBALS['dbi']->fetchValue( - "SHOW GLOBAL VARIABLES LIKE 'event_scheduler'", - 0, - 1 - ); - $es_state = mb_strtolower($es_state); - $options = array( - 0 => array( - 'label' => __('OFF'), - 'value' => "SET GLOBAL event_scheduler=\"OFF\"", - 'selected' => ($es_state != 'on') - ), - 1 => array( - 'label' => __('ON'), - 'value' => "SET GLOBAL event_scheduler=\"ON\"", - 'selected' => ($es_state == 'on') - ) - ); - // Generate output - $retval = "\n"; - $retval .= "
\n"; - // show the usual footer - $retval .= PMA_RTE_getFooterLinks('CREATE_EVENT', 'EVENT', 'EVENT'); - $retval .= "
\n"; - $retval .= " \n"; - $retval .= " " . __('Event scheduler status') . "\n"; - $retval .= " \n"; - $retval .= "
\n"; - // show the toggle button - $retval .= PhpMyAdmin\Util::toggleButton( - "sql.php$url_query&goto=db_events.php" . urlencode("?db=$db"), - 'sql_query', - $options, - 'PMA_slidingMessage(data.sql_query);' - ); - $retval .= "
\n"; - $retval .= "
\n"; - $retval .= "
\n"; - $retval .= "
"; - $retval .= "\n"; - - return $retval; -} // end PMA_EVN_getFooterLinks() diff --git a/libraries/rte/rte_main.inc.php b/libraries/rte/rte_main.inc.php index a6a40890cb..ca747e2540 100644 --- a/libraries/rte/rte_main.inc.php +++ b/libraries/rte/rte_main.inc.php @@ -20,7 +20,6 @@ if (! defined('PHPMYADMIN')) { require_once './libraries/rte/rte_general.lib.php'; require_once './libraries/rte/rte_words.lib.php'; require_once './libraries/rte/rte_list.lib.php'; -require_once './libraries/rte/rte_footer.lib.php'; $response = Response::getInstance(); diff --git a/libraries/rte/rte_routines.lib.php b/libraries/rte/rte_routines.lib.php index 2cef4bd9d8..79bf89664b 100644 --- a/libraries/rte/rte_routines.lib.php +++ b/libraries/rte/rte_routines.lib.php @@ -10,6 +10,7 @@ use PhpMyAdmin\Core; use PhpMyAdmin\Message; use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Export; +use PhpMyAdmin\Rte\Footer; use PhpMyAdmin\SqlParser\Statements\CreateStatement; use PhpMyAdmin\Url; use PhpMyAdmin\Util; @@ -70,7 +71,7 @@ function PMA_RTN_main($type) /** * Display the form for adding a new routine, if the user has the privileges. */ - echo PMA_RTN_getFooterLinks(); + echo Footer::routines(); /** * Display a warning for users with PHP's old "mysql" extension. */ diff --git a/libraries/rte/rte_triggers.lib.php b/libraries/rte/rte_triggers.lib.php index 612499198d..8e493133e6 100644 --- a/libraries/rte/rte_triggers.lib.php +++ b/libraries/rte/rte_triggers.lib.php @@ -7,6 +7,7 @@ */ use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Export; +use PhpMyAdmin\Rte\Footer; use PhpMyAdmin\Url; if (! defined('PHPMYADMIN')) { @@ -54,7 +55,7 @@ function PMA_TRI_main() * Display a link for adding a new trigger, * if the user has the necessary privileges */ - echo PMA_TRI_getFooterLinks(); + echo Footer::triggers(); } // end PMA_TRI_main() /** From fe1ac3b34333cef73352630074d315076c0cf4e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 8 Sep 2017 16:37:37 -0300 Subject: [PATCH 4/8] Refactor rte_general 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/Rte/Events.php | 5 +- libraries/classes/Rte/General.php | 98 ++++++++++++++++++++++++++++++ libraries/rte/rte_general.lib.php | 91 --------------------------- libraries/rte/rte_main.inc.php | 1 - libraries/rte/rte_routines.lib.php | 3 +- libraries/rte/rte_triggers.lib.php | 5 +- 6 files changed, 106 insertions(+), 97 deletions(-) create mode 100644 libraries/classes/Rte/General.php delete mode 100644 libraries/rte/rte_general.lib.php diff --git a/libraries/classes/Rte/Events.php b/libraries/classes/Rte/Events.php index 95243c5932..ccad0e1d26 100644 --- a/libraries/classes/Rte/Events.php +++ b/libraries/classes/Rte/Events.php @@ -11,6 +11,7 @@ use PhpMyAdmin\Message; use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Export; use PhpMyAdmin\Rte\Footer; +use PhpMyAdmin\Rte\General; use PhpMyAdmin\Url; use PhpMyAdmin\Util; @@ -133,7 +134,7 @@ class Events // We dropped the old item, but were unable to create // the new one. Try to restore the backup query $result = $GLOBALS['dbi']->tryQuery($create_item); - $errors = checkResult( + $errors = General::checkResult( $result, __( 'Sorry, we failed to restore the dropped event.' @@ -244,7 +245,7 @@ class Events } $mode = 'edit'; } - PMA_RTE_sendEditor('EVN', $mode, $item, $title, $db, $operation); + General::sendEditor('EVN', $mode, $item, $title, $db, $operation); } } // end self::handleEditor() diff --git a/libraries/classes/Rte/General.php b/libraries/classes/Rte/General.php new file mode 100644 index 0000000000..717559c207 --- /dev/null +++ b/libraries/classes/Rte/General.php @@ -0,0 +1,98 @@ +' + . __('The backed up query was:') + . "\"" . htmlspecialchars($createStatement) . "\"" . '
' + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + + return $errors; + } + + /** + * Send TRI or EVN editor via ajax or by echoing. + * + * @param string $type TRI or EVN + * @param string $mode Editor mode 'add' or 'edit' + * @param array $item Data necessary to create the editor + * @param string $title Title of the editor + * @param string $db Database + * @param string $operation Operation 'change' or '' + * + * @return void + */ + public static function sendEditor($type, $mode, $item, $title, $db, $operation = null) + { + $response = Response::getInstance(); + if ($item !== false) { + // Show form + if ($type == 'TRI') { + $editor = PMA_TRI_getEditorForm($mode, $item); + } else { // EVN + $editor = Events::getEditorForm($mode, $operation, $item); + } + if ($response->isAjax()) { + $response->addJSON('message', $editor); + $response->addJSON('title', $title); + } else { + echo "\n\n

$title

\n\n$editor"; + unset($_POST); + } + exit; + } else { + $message = __('Error in processing request:') . ' '; + $message .= sprintf( + PMA_RTE_getWord('not_found'), + htmlspecialchars(Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(Util::backquote($db)) + ); + $message = Message::error($message); + if ($response->isAjax()) { + $response->setRequestStatus(false); + $response->addJSON('message', $message); + exit; + } else { + $message->display(); + } + } + } +} diff --git a/libraries/rte/rte_general.lib.php b/libraries/rte/rte_general.lib.php deleted file mode 100644 index 6b3ea4a1b8..0000000000 --- a/libraries/rte/rte_general.lib.php +++ /dev/null @@ -1,91 +0,0 @@ -' - . __('The backed up query was:') - . "\"" . htmlspecialchars($createStatement) . "\"" . '
' - . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); - - return $errors; -} - -/** - * Send TRI or EVN editor via ajax or by echoing. - * - * @param string $type TRI or EVN - * @param string $mode Editor mode 'add' or 'edit' - * @param array $item Data necessary to create the editor - * @param string $title Title of the editor - * @param string $db Database - * @param string $operation Operation 'change' or '' - * - * @return void - */ -function PMA_RTE_sendEditor($type, $mode, $item, $title, $db, $operation = null) -{ - $response = Response::getInstance(); - if ($item !== false) { - // Show form - if ($type == 'TRI') { - $editor = PMA_TRI_getEditorForm($mode, $item); - } else { // EVN - $editor = Events::getEditorForm($mode, $operation, $item); - } - if ($response->isAjax()) { - $response->addJSON('message', $editor); - $response->addJSON('title', $title); - } else { - echo "\n\n

$title

\n\n$editor"; - unset($_POST); - } - exit; - } else { - $message = __('Error in processing request:') . ' '; - $message .= sprintf( - PMA_RTE_getWord('not_found'), - htmlspecialchars(PhpMyAdmin\Util::backquote($_REQUEST['item_name'])), - htmlspecialchars(PhpMyAdmin\Util::backquote($db)) - ); - $message = Message::error($message); - if ($response->isAjax()) { - $response->setRequestStatus(false); - $response->addJSON('message', $message); - exit; - } else { - $message->display(); - } - } -} diff --git a/libraries/rte/rte_main.inc.php b/libraries/rte/rte_main.inc.php index ca747e2540..d27d4b6cbe 100644 --- a/libraries/rte/rte_main.inc.php +++ b/libraries/rte/rte_main.inc.php @@ -17,7 +17,6 @@ if (! defined('PHPMYADMIN')) { * Include all other files that are common * to routines, triggers and events. */ -require_once './libraries/rte/rte_general.lib.php'; require_once './libraries/rte/rte_words.lib.php'; require_once './libraries/rte/rte_list.lib.php'; diff --git a/libraries/rte/rte_routines.lib.php b/libraries/rte/rte_routines.lib.php index 79bf89664b..f5881fc804 100644 --- a/libraries/rte/rte_routines.lib.php +++ b/libraries/rte/rte_routines.lib.php @@ -11,6 +11,7 @@ use PhpMyAdmin\Message; use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Export; use PhpMyAdmin\Rte\Footer; +use PhpMyAdmin\Rte\General; use PhpMyAdmin\SqlParser\Statements\CreateStatement; use PhpMyAdmin\Url; use PhpMyAdmin\Util; @@ -376,7 +377,7 @@ function PMA_RTN_createRoutine( // but were unable to create the new one // Try to restore the backup query $result = $GLOBALS['dbi']->tryQuery($create_routine); - $errors = checkResult( + $errors = General::checkResult( $result, __( 'Sorry, we failed to restore' diff --git a/libraries/rte/rte_triggers.lib.php b/libraries/rte/rte_triggers.lib.php index 8e493133e6..1beeeacaea 100644 --- a/libraries/rte/rte_triggers.lib.php +++ b/libraries/rte/rte_triggers.lib.php @@ -8,6 +8,7 @@ use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Export; use PhpMyAdmin\Rte\Footer; +use PhpMyAdmin\Rte\General; use PhpMyAdmin\Url; if (! defined('PHPMYADMIN')) { @@ -102,7 +103,7 @@ function PMA_TRI_handleEditor() // new one. Try to restore the backup query. $result = $GLOBALS['dbi']->tryQuery($create_item); - $errors = checkResult( + $errors = General::checkResult( $result, __( 'Sorry, we failed to restore the dropped trigger.' @@ -221,7 +222,7 @@ function PMA_TRI_handleEditor() } $mode = 'edit'; } - PMA_RTE_sendEditor('TRI', $mode, $item, $title, $db); + General::sendEditor('TRI', $mode, $item, $title, $db); } } // end PMA_TRI_handleEditor() From 6be2bfebf0da6eddc8446b522c706ee776107cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 8 Sep 2017 18:39:46 -0300 Subject: [PATCH 5/8] Refactor rte_list 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/Rte/Events.php | 5 +- libraries/classes/Rte/RteList.php | 491 +++++++++++++++++++++++++++++ libraries/rte/rte_list.lib.php | 482 ---------------------------- libraries/rte/rte_main.inc.php | 1 - libraries/rte/rte_routines.lib.php | 5 +- libraries/rte/rte_triggers.lib.php | 5 +- 6 files changed, 500 insertions(+), 489 deletions(-) create mode 100644 libraries/classes/Rte/RteList.php delete mode 100644 libraries/rte/rte_list.lib.php diff --git a/libraries/classes/Rte/Events.php b/libraries/classes/Rte/Events.php index ccad0e1d26..41d61f6eb8 100644 --- a/libraries/classes/Rte/Events.php +++ b/libraries/classes/Rte/Events.php @@ -12,6 +12,7 @@ use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Export; use PhpMyAdmin\Rte\Footer; use PhpMyAdmin\Rte\General; +use PhpMyAdmin\Rte\RteList; use PhpMyAdmin\Url; use PhpMyAdmin\Util; @@ -77,7 +78,7 @@ class Events * Display a list of available events */ $items = $GLOBALS['dbi']->getEvents($db); - echo PMA_RTE_getList('event', $items); + echo RteList::get('event', $items); /** * Display a link for adding a new event, if * the user has the privileges and a link to @@ -201,7 +202,7 @@ class Events mb_strtoupper($_REQUEST['item_name']) ) ); - $response->addJSON('new_row', PMA_EVN_getRowForList($event)); + $response->addJSON('new_row', RteList::getEventRow($event)); $response->addJSON('insert', ! empty($event)); $response->addJSON('message', $output); } else { diff --git a/libraries/classes/Rte/RteList.php b/libraries/classes/Rte/RteList.php new file mode 100644 index 0000000000..a283816618 --- /dev/null +++ b/libraries/classes/Rte/RteList.php @@ -0,0 +1,491 @@ +\n"; + $retval .= '
'; + $retval .= Url::getHiddenInputs($GLOBALS['db'], $GLOBALS['table']); + $retval .= "
\n"; + $retval .= " \n"; + $retval .= " " . PMA_RTE_getWord('title') . "\n"; + $retval .= " " + . Util::showMySQLDocu(PMA_RTE_getWord('docu')) . "\n"; + $retval .= " \n"; + $retval .= "
\n"; + $retval .= " " . PMA_RTE_getWord('nothing') . "\n"; + $retval .= "
\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + // th cells with a colspan need corresponding td cells, according to W3C + switch ($type) { + case 'routine': + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; // see comment above + for ($i = 0; $i < 7; $i++) { + $retval .= " \n"; + } + break; + case 'trigger': + $retval .= " \n"; + $retval .= " \n"; + if (empty($table)) { + $retval .= " \n"; + } + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; // see comment above + for ($i = 0; $i < (empty($table) ? 7 : 6); $i++) { + $retval .= " \n"; + } + break; + case 'event': + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; // see comment above + for ($i = 0; $i < 6; $i++) { + $retval .= " \n"; + } + break; + default: + break; + } + $retval .= " \n"; + $retval .= " \n"; + $count = 0; + $response = Response::getInstance(); + foreach ($items as $item) { + if ($response->isAjax() && empty($_REQUEST['ajax_page_request'])) { + $rowclass = 'ajaxInsert hide'; + } else { + $rowclass = ''; + } + // Get each row from the correct function + switch ($type) { + case 'routine': + $retval .= self::getRoutineRow($item, $rowclass); + break; + case 'trigger': + $retval .= self::getTriggerRow($item, $rowclass); + break; + case 'event': + $retval .= self::getEventRow($item, $rowclass); + break; + default: + break; + } + $count++; + } + $retval .= "
" . __('Name') . "" . __('Action') . "" . __('Type') . "" . __('Returns') . "
" . __('Name') . "" . __('Table') . "" . __('Action') . "" . __('Time') . "" . __('Event') . "
" . __('Name') . "" . __('Status') . "" . __('Action') . "" . __('Type') . "
\n"; + + if (count($items)) { + $retval .= '
'; + $retval .= Template::get('select_all') + ->render( + array( + 'pma_theme_image' => $GLOBALS['pmaThemeImage'], + 'text_dir' => $GLOBALS['text_dir'], + 'form_name' => 'rteListForm', + ) + ); + $retval .= Util::getButtonOrImage( + 'submit_mult', 'mult_submit', + __('Export'), 'b_export.png', 'export' + ); + $retval .= Util::getButtonOrImage( + 'submit_mult', 'mult_submit', + __('Drop'), 'b_drop.png', 'drop' + ); + $retval .= '
'; + } + + $retval .= "
\n"; + $retval .= "
\n"; + $retval .= "\n"; + + return $retval; + } // end self::get() + + /** + * Creates the contents for a row in the list of routines + * + * @param array $routine An array of routine data + * @param string $rowclass Additional class + * + * @return string HTML code of a row for the list of routines + */ + public static function getRoutineRow($routine, $rowclass = '') + { + global $ajax_class, $url_query, $db, $titles; + + $sql_drop = sprintf( + 'DROP %s IF EXISTS %s', + $routine['type'], + Util::backquote($routine['name']) + ); + $type_link = "item_type={$routine['type']}"; + + $retval = "
\n"; + $retval .= ' '; + $retval .= " \n"; + $retval .= " " + . htmlspecialchars($sql_drop) . "\n"; + $retval .= " \n"; + $retval .= " " + . htmlspecialchars($routine['name']) . "\n"; + $retval .= " \n"; + $retval .= " \n"; + + // this is for our purpose to decide whether to + // show the edit link or not, so we need the DEFINER for the routine + $where = "ROUTINE_SCHEMA " . Util::getCollateForIS() . "=" + . "'" . $GLOBALS['dbi']->escapeString($db) . "' " + . "AND SPECIFIC_NAME='" . $GLOBALS['dbi']->escapeString($routine['name']) . "'" + . "AND ROUTINE_TYPE='" . $GLOBALS['dbi']->escapeString($routine['type']) . "'"; + $query = "SELECT `DEFINER` FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;"; + $routine_definer = $GLOBALS['dbi']->fetchValue($query); + + $curr_user = $GLOBALS['dbi']->getCurrentUser(); + + // Since editing a procedure involved dropping and recreating, check also for + // CREATE ROUTINE privilege to avoid lost procedures. + if ((Util::currentUserHasPrivilege('CREATE ROUTINE', $db) + && $curr_user == $routine_definer) + || $GLOBALS['is_superuser'] + ) { + $retval .= ' ' . $titles['Edit'] . "\n"; + } else { + $retval .= " {$titles['NoEdit']}\n"; + } + $retval .= " \n"; + + // There is a problem with Util::currentUserHasPrivilege(): + // it does not detect all kinds of privileges, for example + // a direct privilege on a specific routine. So, at this point, + // we show the Execute link, hoping that the user has the correct rights. + // Also, information_schema might be hiding the ROUTINE_DEFINITION + // but a routine with no input parameters can be nonetheless executed. + + // Check if the routine has any input parameters. If it does, + // we will show a dialog to get values for these parameters, + // otherwise we can execute it directly. + + $definition = $GLOBALS['dbi']->getDefinition( + $db, $routine['type'], $routine['name'] + ); + if ($definition !== false) { + $parser = new Parser($definition); + + /** + * @var CreateStatement $stmt + */ + $stmt = $parser->statements[0]; + + $params = Routine::getParameters($stmt); + + if (Util::currentUserHasPrivilege('EXECUTE', $db)) { + $execute_action = 'execute_routine'; + for ($i = 0; $i < $params['num']; $i++) { + if ($routine['type'] == 'PROCEDURE' + && $params['dir'][$i] == 'OUT' + ) { + continue; + } + $execute_action = 'execute_dialog'; + break; + } + $retval .= ' ' . $titles['Execute'] . "\n"; + } else { + $retval .= " {$titles['NoExecute']}\n"; + } + } + + $retval .= " \n"; + if ((Util::currentUserHasPrivilege('CREATE ROUTINE', $db) + && $curr_user == $routine_definer) + || $GLOBALS['is_superuser'] + ) { + $retval .= ' ' . $titles['Export'] . "\n"; + } else { + $retval .= " {$titles['NoExport']}\n"; + } + $retval .= " \n"; + $retval .= ' ' . $titles['Drop'] . "\n"; + $retval .= " \n"; + $retval .= " {$routine['type']}\n"; + $retval .= " \n"; + $retval .= " " + . htmlspecialchars($routine['returns']) . "\n"; + $retval .= "
\n"; + $retval .= ' '; + $retval .= " \n"; + $retval .= " " + . htmlspecialchars($trigger['drop']) . "\n"; + $retval .= " \n"; + $retval .= " " . htmlspecialchars($trigger['name']) . "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "" + . htmlspecialchars($trigger['table']) . ""; + $retval .= " \n"; + if (Util::currentUserHasPrivilege('TRIGGER', $db, $table)) { + $retval .= ' ' . $titles['Edit'] . "\n"; + } else { + $retval .= " {$titles['NoEdit']}\n"; + } + $retval .= " \n"; + $retval .= ' ' . $titles['Export'] . "\n"; + $retval .= " \n"; + if (Util::currentUserHasPrivilege('TRIGGER', $db)) { + $retval .= ' ' . $titles['Drop'] . "\n"; + } else { + $retval .= " {$titles['NoDrop']}\n"; + } + $retval .= " \n"; + $retval .= " {$trigger['action_timing']}\n"; + $retval .= " \n"; + $retval .= " {$trigger['event_manipulation']}\n"; + $retval .= "
\n"; + $retval .= ' '; + $retval .= " \n"; + $retval .= " " + . htmlspecialchars($sql_drop) . "\n"; + $retval .= " \n"; + $retval .= " " + . htmlspecialchars($event['name']) . "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " {$event['status']}\n"; + $retval .= " \n"; + if (Util::currentUserHasPrivilege('EVENT', $db)) { + $retval .= ' ' . $titles['Edit'] . "\n"; + } else { + $retval .= " {$titles['NoEdit']}\n"; + } + $retval .= " \n"; + $retval .= ' ' . $titles['Export'] . "\n"; + $retval .= " \n"; + if (Util::currentUserHasPrivilege('EVENT', $db)) { + $retval .= ' ' . $titles['Drop'] . "\n"; + } else { + $retval .= " {$titles['NoDrop']}\n"; + } + $retval .= " \n"; + $retval .= " {$event['type']}\n"; + $retval .= "
\n"; - $retval .= " \n"; - $retval .= " \n"; - // th cells with a colspan need corresponding td cells, according to W3C - switch ($type) { - case 'routine': - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; // see comment above - for ($i = 0; $i < 7; $i++) { - $retval .= " \n"; - } - break; - case 'trigger': - $retval .= " \n"; - $retval .= " \n"; - if (empty($table)) { - $retval .= " \n"; - } - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; // see comment above - for ($i = 0; $i < (empty($table) ? 7 : 6); $i++) { - $retval .= " \n"; - } - break; - case 'event': - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; // see comment above - for ($i = 0; $i < 6; $i++) { - $retval .= " \n"; - } - break; - default: - break; - } - $retval .= " \n"; - $retval .= " \n"; - $count = 0; - $response = Response::getInstance(); - foreach ($items as $item) { - if ($response->isAjax() && empty($_REQUEST['ajax_page_request'])) { - $rowclass = 'ajaxInsert hide'; - } else { - $rowclass = ''; - } - // Get each row from the correct function - switch ($type) { - case 'routine': - $retval .= PMA_RTN_getRowForList($item, $rowclass); - break; - case 'trigger': - $retval .= PMA_TRI_getRowForList($item, $rowclass); - break; - case 'event': - $retval .= PMA_EVN_getRowForList($item, $rowclass); - break; - default: - break; - } - $count++; - } - $retval .= "
" . __('Name') . "" . __('Action') . "" . __('Type') . "" . __('Returns') . "
" . __('Name') . "" . __('Table') . "" . __('Action') . "" . __('Time') . "" . __('Event') . "
" . __('Name') . "" . __('Status') . "" . __('Action') . "" . __('Type') . "
\n"; - - if (count($items)) { - $retval .= '
'; - $retval .= Template::get('select_all') - ->render( - array( - 'pma_theme_image' => $GLOBALS['pmaThemeImage'], - 'text_dir' => $GLOBALS['text_dir'], - 'form_name' => 'rteListForm', - ) - ); - $retval .= PhpMyAdmin\Util::getButtonOrImage( - 'submit_mult', 'mult_submit', - __('Export'), 'b_export.png', 'export' - ); - $retval .= PhpMyAdmin\Util::getButtonOrImage( - 'submit_mult', 'mult_submit', - __('Drop'), 'b_drop.png', 'drop' - ); - $retval .= '
'; - } - - $retval .= "
\n"; - $retval .= "\n"; - $retval .= "\n"; - - return $retval; -} // end PMA_RTE_getList() - -/** - * Creates the contents for a row in the list of routines - * - * @param array $routine An array of routine data - * @param string $rowclass Additional class - * - * @return string HTML code of a row for the list of routines - */ -function PMA_RTN_getRowForList($routine, $rowclass = '') -{ - global $ajax_class, $url_query, $db, $titles; - - $sql_drop = sprintf( - 'DROP %s IF EXISTS %s', - $routine['type'], - PhpMyAdmin\Util::backquote($routine['name']) - ); - $type_link = "item_type={$routine['type']}"; - - $retval = "
\n"; - $retval .= ' '; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($sql_drop) . "\n"; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($routine['name']) . "\n"; - $retval .= " \n"; - $retval .= " \n"; - - // this is for our purpose to decide whether to - // show the edit link or not, so we need the DEFINER for the routine - $where = "ROUTINE_SCHEMA " . PhpMyAdmin\Util::getCollateForIS() . "=" - . "'" . $GLOBALS['dbi']->escapeString($db) . "' " - . "AND SPECIFIC_NAME='" . $GLOBALS['dbi']->escapeString($routine['name']) . "'" - . "AND ROUTINE_TYPE='" . $GLOBALS['dbi']->escapeString($routine['type']) . "'"; - $query = "SELECT `DEFINER` FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;"; - $routine_definer = $GLOBALS['dbi']->fetchValue($query); - - $curr_user = $GLOBALS['dbi']->getCurrentUser(); - - // Since editing a procedure involved dropping and recreating, check also for - // CREATE ROUTINE privilege to avoid lost procedures. - if ((PhpMyAdmin\Util::currentUserHasPrivilege('CREATE ROUTINE', $db) - && $curr_user == $routine_definer) - || $GLOBALS['is_superuser'] - ) { - $retval .= ' ' . $titles['Edit'] . "\n"; - } else { - $retval .= " {$titles['NoEdit']}\n"; - } - $retval .= " \n"; - - // There is a problem with PhpMyAdmin\Util::currentUserHasPrivilege(): - // it does not detect all kinds of privileges, for example - // a direct privilege on a specific routine. So, at this point, - // we show the Execute link, hoping that the user has the correct rights. - // Also, information_schema might be hiding the ROUTINE_DEFINITION - // but a routine with no input parameters can be nonetheless executed. - - // Check if the routine has any input parameters. If it does, - // we will show a dialog to get values for these parameters, - // otherwise we can execute it directly. - - $definition = $GLOBALS['dbi']->getDefinition( - $db, $routine['type'], $routine['name'] - ); - if ($definition !== false) { - $parser = new PhpMyAdmin\SqlParser\Parser($definition); - - /** - * @var CreateStatement $stmt - */ - $stmt = $parser->statements[0]; - - $params = PhpMyAdmin\SqlParser\Utils\Routine::getParameters($stmt); - - if (PhpMyAdmin\Util::currentUserHasPrivilege('EXECUTE', $db)) { - $execute_action = 'execute_routine'; - for ($i = 0; $i < $params['num']; $i++) { - if ($routine['type'] == 'PROCEDURE' - && $params['dir'][$i] == 'OUT' - ) { - continue; - } - $execute_action = 'execute_dialog'; - break; - } - $retval .= ' ' . $titles['Execute'] . "\n"; - } else { - $retval .= " {$titles['NoExecute']}\n"; - } - } - - $retval .= " \n"; - if ((PhpMyAdmin\Util::currentUserHasPrivilege('CREATE ROUTINE', $db) - && $curr_user == $routine_definer) - || $GLOBALS['is_superuser'] - ) { - $retval .= ' ' . $titles['Export'] . "\n"; - } else { - $retval .= " {$titles['NoExport']}\n"; - } - $retval .= " \n"; - $retval .= ' ' . $titles['Drop'] . "\n"; - $retval .= " \n"; - $retval .= " {$routine['type']}\n"; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($routine['returns']) . "\n"; - $retval .= "
\n"; - $retval .= ' '; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($trigger['drop']) . "\n"; - $retval .= " \n"; - $retval .= " " . htmlspecialchars($trigger['name']) . "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "" - . htmlspecialchars($trigger['table']) . ""; - $retval .= " \n"; - if (PhpMyAdmin\Util::currentUserHasPrivilege('TRIGGER', $db, $table)) { - $retval .= ' ' . $titles['Edit'] . "\n"; - } else { - $retval .= " {$titles['NoEdit']}\n"; - } - $retval .= " \n"; - $retval .= ' ' . $titles['Export'] . "\n"; - $retval .= " \n"; - if (PhpMyAdmin\Util::currentUserHasPrivilege('TRIGGER', $db)) { - $retval .= ' ' . $titles['Drop'] . "\n"; - } else { - $retval .= " {$titles['NoDrop']}\n"; - } - $retval .= " \n"; - $retval .= " {$trigger['action_timing']}\n"; - $retval .= " \n"; - $retval .= " {$trigger['event_manipulation']}\n"; - $retval .= "
\n"; - $retval .= ' '; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($sql_drop) . "\n"; - $retval .= " \n"; - $retval .= " " - . htmlspecialchars($event['name']) . "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " {$event['status']}\n"; - $retval .= " \n"; - if (PhpMyAdmin\Util::currentUserHasPrivilege('EVENT', $db)) { - $retval .= ' ' . $titles['Edit'] . "\n"; - } else { - $retval .= " {$titles['NoEdit']}\n"; - } - $retval .= " \n"; - $retval .= ' ' . $titles['Export'] . "\n"; - $retval .= " \n"; - if (PhpMyAdmin\Util::currentUserHasPrivilege('EVENT', $db)) { - $retval .= ' ' . $titles['Drop'] . "\n"; - } else { - $retval .= " {$titles['NoDrop']}\n"; - } - $retval .= " \n"; - $retval .= " {$event['type']}\n"; - $retval .= "
\n"; $retval .= " \n"; @@ -175,7 +176,7 @@ class RteList $retval .= "\n"; $retval .= "\n"; - $retval .= "\n"; + $retval .= "\n"; return $retval; } // end self::get() diff --git a/libraries/classes/Rte/Words.php b/libraries/classes/Rte/Words.php new file mode 100644 index 0000000000..ce3c305eb1 --- /dev/null +++ b/libraries/classes/Rte/Words.php @@ -0,0 +1,87 @@ + __('Add routine'), + 'docu' => 'STORED_ROUTINES', + 'export' => __('Export of routine %s'), + 'human' => __('routine'), + 'no_create' => __( + 'You do not have the necessary privileges to create a routine.' + ), + 'no_edit' => __( + 'No routine with name %1$s found in database %2$s. ' + . 'You might be lacking the necessary privileges to edit this routine.' + ), + 'no_view' => __( + 'No routine with name %1$s found in database %2$s. ' + . 'You might be lacking the necessary privileges to view/export this routine.' + ), + 'not_found' => __('No routine with name %1$s found in database %2$s.'), + 'nothing' => __('There are no routines to display.'), + 'title' => __('Routines'), + ); + break; + case 'TRI': + $words = array( + 'add' => __('Add trigger'), + 'docu' => 'TRIGGERS', + 'export' => __('Export of trigger %s'), + 'human' => __('trigger'), + 'no_create' => __( + 'You do not have the necessary privileges to create a trigger.' + ), + 'not_found' => __('No trigger with name %1$s found in database %2$s.'), + 'nothing' => __('There are no triggers to display.'), + 'title' => __('Triggers'), + ); + break; + case 'EVN': + $words = array( + 'add' => __('Add event'), + 'docu' => 'EVENTS', + 'export' => __('Export of event %s'), + 'human' => __('event'), + 'no_create' => __( + 'You do not have the necessary privileges to create an event.' + ), + 'not_found' => __('No event with name %1$s found in database %2$s.'), + 'nothing' => __('There are no events to display.'), + 'title' => __('Events'), + ); + break; + default: + $words = array(); + break; + } + + return isset($words[$index]) ? $words[$index] : ''; + } // end self::get() +} diff --git a/libraries/rte/rte_main.inc.php b/libraries/rte/rte_main.inc.php index 447c6e69f7..2a143fdc47 100644 --- a/libraries/rte/rte_main.inc.php +++ b/libraries/rte/rte_main.inc.php @@ -13,12 +13,6 @@ if (! defined('PHPMYADMIN')) { exit; } -/** - * Include all other files that are common - * to routines, triggers and events. - */ -require_once './libraries/rte/rte_words.lib.php'; - $response = Response::getInstance(); if (! $response->isAjax()) { diff --git a/libraries/rte/rte_routines.lib.php b/libraries/rte/rte_routines.lib.php index 201e9ff3ae..acc7e5f5a0 100644 --- a/libraries/rte/rte_routines.lib.php +++ b/libraries/rte/rte_routines.lib.php @@ -13,6 +13,7 @@ use PhpMyAdmin\Rte\Export; use PhpMyAdmin\Rte\Footer; use PhpMyAdmin\Rte\General; use PhpMyAdmin\Rte\RteList; +use PhpMyAdmin\Rte\Words; use PhpMyAdmin\SqlParser\Statements\CreateStatement; use PhpMyAdmin\Url; use PhpMyAdmin\Util; @@ -127,7 +128,7 @@ function PMA_RTN_handleEditor() } // Get the data for the form (if any) if (! empty($_REQUEST['add_item'])) { - $title = PMA_RTE_getWord('add'); + $title = Words::get('add'); $routine = PMA_RTN_getDataFromRequest(); $mode = 'add'; } else if (! empty($_REQUEST['edit_item'])) { @@ -162,7 +163,7 @@ function PMA_RTN_handleEditor() } else { $message = __('Error in processing request:') . ' '; $message .= sprintf( - PMA_RTE_getWord('no_edit'), + Words::get('no_edit'), htmlspecialchars( PhpMyAdmin\Util::backquote($_REQUEST['item_name']) ), @@ -1315,7 +1316,7 @@ function PMA_RTN_handleExecute() if ($routine === false) { $message = __('Error in processing request:') . ' '; $message .= sprintf( - PMA_RTE_getWord('not_found'), + Words::get('not_found'), htmlspecialchars(PhpMyAdmin\Util::backquote($_REQUEST['item_name'])), htmlspecialchars(PhpMyAdmin\Util::backquote($db)) ); @@ -1525,7 +1526,7 @@ function PMA_RTN_handleExecute() } else if (($response->isAjax())) { $message = __('Error in processing request:') . ' '; $message .= sprintf( - PMA_RTE_getWord('not_found'), + Words::get('not_found'), htmlspecialchars(PhpMyAdmin\Util::backquote($_REQUEST['item_name'])), htmlspecialchars(PhpMyAdmin\Util::backquote($db)) ); diff --git a/libraries/rte/rte_triggers.lib.php b/libraries/rte/rte_triggers.lib.php index d46c59941d..c8bcee6561 100644 --- a/libraries/rte/rte_triggers.lib.php +++ b/libraries/rte/rte_triggers.lib.php @@ -10,6 +10,7 @@ use PhpMyAdmin\Rte\Export; use PhpMyAdmin\Rte\Footer; use PhpMyAdmin\Rte\General; use PhpMyAdmin\Rte\RteList; +use PhpMyAdmin\Rte\Words; use PhpMyAdmin\Url; if (! defined('PHPMYADMIN')) { @@ -206,7 +207,7 @@ function PMA_TRI_handleEditor() ) { // Get the data for the form (if any) if (! empty($_REQUEST['add_item'])) { - $title = PMA_RTE_getWord('add'); + $title = Words::get('add'); $item = PMA_TRI_getDataFromRequest(); $mode = 'add'; } else if (! empty($_REQUEST['edit_item'])) { diff --git a/libraries/rte/rte_words.lib.php b/libraries/rte/rte_words.lib.php deleted file mode 100644 index 95fc5a1052..0000000000 --- a/libraries/rte/rte_words.lib.php +++ /dev/null @@ -1,82 +0,0 @@ - __('Add routine'), - 'docu' => 'STORED_ROUTINES', - 'export' => __('Export of routine %s'), - 'human' => __('routine'), - 'no_create' => __( - 'You do not have the necessary privileges to create a routine.' - ), - 'no_edit' => __( - 'No routine with name %1$s found in database %2$s. ' - . 'You might be lacking the necessary privileges to edit this routine.' - ), - 'no_view' => __( - 'No routine with name %1$s found in database %2$s. ' - . 'You might be lacking the necessary privileges to view/export this routine.' - ), - 'not_found' => __('No routine with name %1$s found in database %2$s.'), - 'nothing' => __('There are no routines to display.'), - 'title' => __('Routines'), - ); - break; - case 'TRI': - $words = array( - 'add' => __('Add trigger'), - 'docu' => 'TRIGGERS', - 'export' => __('Export of trigger %s'), - 'human' => __('trigger'), - 'no_create' => __( - 'You do not have the necessary privileges to create a trigger.' - ), - 'not_found' => __('No trigger with name %1$s found in database %2$s.'), - 'nothing' => __('There are no triggers to display.'), - 'title' => __('Triggers'), - ); - break; - case 'EVN': - $words = array( - 'add' => __('Add event'), - 'docu' => 'EVENTS', - 'export' => __('Export of event %s'), - 'human' => __('event'), - 'no_create' => __( - 'You do not have the necessary privileges to create an event.' - ), - 'not_found' => __('No event with name %1$s found in database %2$s.'), - 'nothing' => __('There are no events to display.'), - 'title' => __('Events'), - ); - break; - default: - $words = array(); - break; - } - - return isset($words[$index]) ? $words[$index] : ''; -} // end PMA_RTE_getWord() - From 1eac7bb3a22f08cf10731477c4d48d36b29966c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 8 Sep 2017 22:03:07 -0300 Subject: [PATCH 7/8] Refactor rte_routines 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_routines.php | 1 - libraries/classes/Rte/Events.php | 2 +- libraries/classes/Rte/Routines.php | 1715 +++++++++++++++++ libraries/rte/rte_main.inc.php | 3 +- libraries/rte/rte_routines.lib.php | 1706 ---------------- libraries/rte/rte_triggers.lib.php | 2 +- test/classes/Rte/RoutinesTest.php | 1338 +++++++++++++ .../rte/PMA_RTN_getDataFromRequest_test.php | 226 --- .../rte/PMA_RTN_getEditorForm_test.php | 644 ------- .../rte/PMA_RTN_getExecuteForm_test.php | 292 --- .../rte/PMA_RTN_getQueryFromRequest_test.php | 290 --- 11 files changed, 3057 insertions(+), 3162 deletions(-) create mode 100644 libraries/classes/Rte/Routines.php delete mode 100644 libraries/rte/rte_routines.lib.php create mode 100644 test/classes/Rte/RoutinesTest.php delete mode 100644 test/libraries/rte/PMA_RTN_getDataFromRequest_test.php delete mode 100644 test/libraries/rte/PMA_RTN_getEditorForm_test.php delete mode 100644 test/libraries/rte/PMA_RTN_getExecuteForm_test.php delete mode 100644 test/libraries/rte/PMA_RTN_getQueryFromRequest_test.php diff --git a/db_routines.php b/db_routines.php index 618736e25e..7e5c3ba093 100644 --- a/db_routines.php +++ b/db_routines.php @@ -15,7 +15,6 @@ require_once 'libraries/common.inc.php'; * Include all other files */ require_once 'libraries/check_user_privileges.lib.php'; -require_once 'libraries/rte/rte_routines.lib.php'; /** * Do the magic diff --git a/libraries/classes/Rte/Events.php b/libraries/classes/Rte/Events.php index e4cb159f16..91fc619673 100644 --- a/libraries/classes/Rte/Events.php +++ b/libraries/classes/Rte/Events.php @@ -104,7 +104,7 @@ class Events $item_query = self::getQueryFromRequest(); - if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest() + if (! count($errors)) { // set by PhpMyAdmin\Rte\Routines::getQueryFromRequest() // Execute the created query if (! empty($_REQUEST['editor_process_edit'])) { // Backup the old trigger, in case something goes wrong diff --git a/libraries/classes/Rte/Routines.php b/libraries/classes/Rte/Routines.php new file mode 100644 index 0000000000..1d9a8f60e4 --- /dev/null +++ b/libraries/classes/Rte/Routines.php @@ -0,0 +1,1715 @@ +getRoutines($db, $type); + echo RteList::get('routine', $items); + /** + * Display the form for adding a new routine, if the user has the privileges. + */ + echo Footer::routines(); + /** + * Display a warning for users with PHP's old "mysql" extension. + */ + if (! DatabaseInterface::checkDbExtension('mysqli')) { + trigger_error( + __( + 'You are using PHP\'s deprecated \'mysql\' extension, ' + . 'which is not capable of handling multi queries. ' + . '[strong]The execution of some stored routines may fail![/strong] ' + . 'Please use the improved \'mysqli\' extension to ' + . 'avoid any problems.' + ), + E_USER_WARNING + ); + } + } // end self::main() + + /** + * Handles editor requests for adding or editing an item + * + * @return void + */ + public static function handleEditor() + { + global $_GET, $_POST, $_REQUEST, $GLOBALS, $db, $errors; + + $errors = self::handleRequestCreateOrEdit($errors, $db); + $response = Response::getInstance(); + + /** + * Display a form used to add/edit a routine, if necessary + */ + // FIXME: this must be simpler than that + if (count($errors) + || ( empty($_REQUEST['editor_process_add']) + && empty($_REQUEST['editor_process_edit']) + && (! empty($_REQUEST['add_item']) || ! empty($_REQUEST['edit_item']) + || ! empty($_REQUEST['routine_addparameter']) + || ! empty($_REQUEST['routine_removeparameter']) + || ! empty($_REQUEST['routine_changetype']))) + ) { + // Handle requests to add/remove parameters and changing routine type + // This is necessary when JS is disabled + $operation = ''; + if (! empty($_REQUEST['routine_addparameter'])) { + $operation = 'add'; + } else if (! empty($_REQUEST['routine_removeparameter'])) { + $operation = 'remove'; + } else if (! empty($_REQUEST['routine_changetype'])) { + $operation = 'change'; + } + // Get the data for the form (if any) + if (! empty($_REQUEST['add_item'])) { + $title = Words::get('add'); + $routine = self::getDataFromRequest(); + $mode = 'add'; + } else if (! empty($_REQUEST['edit_item'])) { + $title = __("Edit routine"); + if (! $operation && ! empty($_REQUEST['item_name']) + && empty($_REQUEST['editor_process_edit']) + ) { + $routine = self::getDataFromName( + $_REQUEST['item_name'], $_REQUEST['item_type'] + ); + if ($routine !== false) { + $routine['item_original_name'] = $routine['item_name']; + $routine['item_original_type'] = $routine['item_type']; + } + } else { + $routine = self::getDataFromRequest(); + } + $mode = 'edit'; + } + if ($routine !== false) { + // Show form + $editor = self::getEditorForm($mode, $operation, $routine); + if ($response->isAjax()) { + $response->addJSON('message', $editor); + $response->addJSON('title', $title); + $response->addJSON('param_template', self::getParameterRow()); + $response->addJSON('type', $routine['item_type']); + } else { + echo "\n\n

$title

\n\n$editor"; + } + exit; + } else { + $message = __('Error in processing request:') . ' '; + $message .= sprintf( + Words::get('no_edit'), + htmlspecialchars( + Util::backquote($_REQUEST['item_name']) + ), + htmlspecialchars(Util::backquote($db)) + ); + + $message = Message::error($message); + if ($response->isAjax()) { + $response->setRequestStatus(false); + $response->addJSON('message', $message); + exit; + } else { + $message->display(); + } + } + } + } + + /** + * Handle request to create or edit a routine + * + * @param array $errors Errors + * @param string $db DB name + * + * @return array + */ + public static function handleRequestCreateOrEdit($errors, $db) + { + if (empty($_REQUEST['editor_process_add']) + && empty($_REQUEST['editor_process_edit']) + ) { + return $errors; + } + + $sql_query = ''; + $routine_query = self::getQueryFromRequest(); + if (!count($errors)) { // set by self::getQueryFromRequest() + // Execute the created query + if (!empty($_REQUEST['editor_process_edit'])) { + $isProcOrFunc = in_array( + $_REQUEST['item_original_type'], + array('PROCEDURE', 'FUNCTION') + ); + + if (!$isProcOrFunc) { + $errors[] = sprintf( + __('Invalid routine type: "%s"'), + htmlspecialchars($_REQUEST['item_original_type']) + ); + } else { + // Backup the old routine, in case something goes wrong + $create_routine = $GLOBALS['dbi']->getDefinition( + $db, + $_REQUEST['item_original_type'], + $_REQUEST['item_original_name'] + ); + + $privilegesBackup = self::backupPrivileges(); + + $drop_routine = "DROP {$_REQUEST['item_original_type']} " + . Util::backquote($_REQUEST['item_original_name']) + . ";\n"; + $result = $GLOBALS['dbi']->tryQuery($drop_routine); + if (!$result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($drop_routine) + ) + . '
' + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + } else { + list($newErrors, $message) = self::create( + $routine_query, + $create_routine, + $privilegesBackup + ); + if (empty($newErrors)) { + $sql_query = $drop_routine . $routine_query; + } else { + $errors = array_merge($errors, $newErrors); + } + unset($newErrors); + if (null === $message) { + unset($message); + } + } + } + } else { + // 'Add a new routine' mode + $result = $GLOBALS['dbi']->tryQuery($routine_query); + if (!$result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($routine_query) + ) + . '

' + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + } else { + $message = Message::success( + __('Routine %1$s has been created.') + ); + $message->addParam( + Util::backquote($_REQUEST['item_name']) + ); + $sql_query = $routine_query; + } + } + } + + if (count($errors)) { + $message = Message::error( + __( + 'One or more errors have occurred while' + . ' processing your request:' + ) + ); + $message->addHtml('
    '); + foreach ($errors as $string) { + $message->addHtml('
  • ' . $string . '
  • '); + } + $message->addHtml('
'); + } + + $output = Util::getMessage($message, $sql_query); + $response = Response::getInstance(); + if (!$response->isAjax()) { + return $errors; + } + + if (!$message->isSuccess()) { + $response->setRequestStatus(false); + $response->addJSON('message', $output); + exit; + } + + $routines = $GLOBALS['dbi']->getRoutines( + $db, + $_REQUEST['item_type'], + $_REQUEST['item_name'] + ); + $routine = $routines[0]; + $response->addJSON( + 'name', + htmlspecialchars( + mb_strtoupper($_REQUEST['item_name']) + ) + ); + $response->addJSON('new_row', RteList::getRoutineRow($routine)); + $response->addJSON('insert', !empty($routine)); + $response->addJSON('message', $output); + exit; + } + + /** + * Backup the privileges + * + * @return array + */ + public static function backupPrivileges() + { + if (! $GLOBALS['proc_priv'] || ! $GLOBALS['is_reload_priv']) { + return array(); + } + + // Backup the Old Privileges before dropping + // if $_REQUEST['item_adjust_privileges'] set + if (! isset($_REQUEST['item_adjust_privileges']) + || empty($_REQUEST['item_adjust_privileges']) + ) { + return array(); + } + + $privilegesBackupQuery = 'SELECT * FROM ' . Util::backquote( + 'mysql' + ) + . '.' . Util::backquote('procs_priv') + . ' where Routine_name = "' . $_REQUEST['item_original_name'] + . '" AND Routine_type = "' . $_REQUEST['item_original_type'] + . '";'; + + $privilegesBackup = $GLOBALS['dbi']->fetchResult( + $privilegesBackupQuery, + 0 + ); + + return $privilegesBackup; + } + + /** + * Create the routine + * + * @param string $routine_query Query to create routine + * @param string $create_routine Query to restore routine + * @param array $privilegesBackup Privileges backup + * + * @return array + */ + public static function create( + $routine_query, + $create_routine, + $privilegesBackup + ) { + $result = $GLOBALS['dbi']->tryQuery($routine_query); + if (!$result) { + $errors = array(); + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($routine_query) + ) + . '
' + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + // We dropped the old routine, + // but were unable to create the new one + // Try to restore the backup query + $result = $GLOBALS['dbi']->tryQuery($create_routine); + $errors = General::checkResult( + $result, + __( + 'Sorry, we failed to restore' + . ' the dropped routine.' + ), + $create_routine, + $errors + ); + + return array($errors, null); + } + + // Default value + $resultAdjust = false; + + if ($GLOBALS['proc_priv'] + && $GLOBALS['is_reload_priv'] + ) { + // Insert all the previous privileges + // but with the new name and the new type + foreach ($privilegesBackup as $priv) { + $adjustProcPrivilege = 'INSERT INTO ' + . Util::backquote('mysql') . '.' + . Util::backquote('procs_priv') + . ' VALUES("' . $priv[0] . '", "' + . $priv[1] . '", "' . $priv[2] . '", "' + . $_REQUEST['item_name'] . '", "' + . $_REQUEST['item_type'] . '", "' + . $priv[5] . '", "' + . $priv[6] . '", "' + . $priv[7] . '");'; + $resultAdjust = $GLOBALS['dbi']->query( + $adjustProcPrivilege + ); + } + } + + $message = self::flushPrivileges($resultAdjust); + + return array(array(), $message); + } + + /** + * Flush privileges and get message + * + * @param bool $flushPrivileges Flush privileges + * + * @return Message + */ + public static function flushPrivileges($flushPrivileges) + { + if ($flushPrivileges) { + // Flush the Privileges + $flushPrivQuery = 'FLUSH PRIVILEGES;'; + $GLOBALS['dbi']->query($flushPrivQuery); + + $message = Message::success( + __( + 'Routine %1$s has been modified. Privileges have been adjusted.' + ) + ); + } else { + $message = Message::success( + __('Routine %1$s has been modified.') + ); + } + $message->addParam( + Util::backquote($_REQUEST['item_name']) + ); + + return $message; + } // end self::handleEditor() + + /** + * This function will generate the values that are required to + * complete the editor form. It is especially necessary to handle + * the 'Add another parameter', 'Remove last parameter' and + * 'Change routine type' functionalities when JS is disabled. + * + * @return array Data necessary to create the routine editor. + */ + public static function getDataFromRequest() + { + global $_REQUEST, $param_directions, $param_sqldataaccess; + + $retval = array(); + $indices = array('item_name', + 'item_original_name', + 'item_returnlength', + 'item_returnopts_num', + 'item_returnopts_text', + 'item_definition', + 'item_comment', + 'item_definer'); + foreach ($indices as $index) { + $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : ''; + } + + $retval['item_type'] = 'PROCEDURE'; + $retval['item_type_toggle'] = 'FUNCTION'; + if (isset($_REQUEST['item_type']) && $_REQUEST['item_type'] == 'FUNCTION') { + $retval['item_type'] = 'FUNCTION'; + $retval['item_type_toggle'] = 'PROCEDURE'; + } + $retval['item_original_type'] = 'PROCEDURE'; + if (isset($_REQUEST['item_original_type']) + && $_REQUEST['item_original_type'] == 'FUNCTION' + ) { + $retval['item_original_type'] = 'FUNCTION'; + } + $retval['item_num_params'] = 0; + $retval['item_param_dir'] = array(); + $retval['item_param_name'] = array(); + $retval['item_param_type'] = array(); + $retval['item_param_length'] = array(); + $retval['item_param_opts_num'] = array(); + $retval['item_param_opts_text'] = array(); + if (isset($_REQUEST['item_param_name']) + && isset($_REQUEST['item_param_type']) + && isset($_REQUEST['item_param_length']) + && isset($_REQUEST['item_param_opts_num']) + && isset($_REQUEST['item_param_opts_text']) + && is_array($_REQUEST['item_param_name']) + && is_array($_REQUEST['item_param_type']) + && is_array($_REQUEST['item_param_length']) + && is_array($_REQUEST['item_param_opts_num']) + && is_array($_REQUEST['item_param_opts_text']) + ) { + if ($_REQUEST['item_type'] == 'PROCEDURE') { + $retval['item_param_dir'] = $_REQUEST['item_param_dir']; + foreach ($retval['item_param_dir'] as $key => $value) { + if (! in_array($value, $param_directions, true)) { + $retval['item_param_dir'][$key] = ''; + } + } + } + $retval['item_param_name'] = $_REQUEST['item_param_name']; + $retval['item_param_type'] = $_REQUEST['item_param_type']; + foreach ($retval['item_param_type'] as $key => $value) { + if (! in_array($value, Util::getSupportedDatatypes(), true)) { + $retval['item_param_type'][$key] = ''; + } + } + $retval['item_param_length'] = $_REQUEST['item_param_length']; + $retval['item_param_opts_num'] = $_REQUEST['item_param_opts_num']; + $retval['item_param_opts_text'] = $_REQUEST['item_param_opts_text']; + $retval['item_num_params'] = max( + count($retval['item_param_name']), + count($retval['item_param_type']), + count($retval['item_param_length']), + count($retval['item_param_opts_num']), + count($retval['item_param_opts_text']) + ); + } + $retval['item_returntype'] = ''; + if (isset($_REQUEST['item_returntype']) + && in_array($_REQUEST['item_returntype'], Util::getSupportedDatatypes()) + ) { + $retval['item_returntype'] = $_REQUEST['item_returntype']; + } + + $retval['item_isdeterministic'] = ''; + if (isset($_REQUEST['item_isdeterministic']) + && mb_strtolower($_REQUEST['item_isdeterministic']) == 'on' + ) { + $retval['item_isdeterministic'] = " checked='checked'"; + } + $retval['item_securitytype_definer'] = ''; + $retval['item_securitytype_invoker'] = ''; + if (isset($_REQUEST['item_securitytype'])) { + if ($_REQUEST['item_securitytype'] === 'DEFINER') { + $retval['item_securitytype_definer'] = " selected='selected'"; + } else if ($_REQUEST['item_securitytype'] === 'INVOKER') { + $retval['item_securitytype_invoker'] = " selected='selected'"; + } + } + $retval['item_sqldataaccess'] = ''; + if (isset($_REQUEST['item_sqldataaccess']) + && in_array($_REQUEST['item_sqldataaccess'], $param_sqldataaccess, true) + ) { + $retval['item_sqldataaccess'] = $_REQUEST['item_sqldataaccess']; + } + + return $retval; + } // end self::getDataFromRequest() + + /** + * This function will generate the values that are required to complete + * the "Edit routine" form given the name of a routine. + * + * @param string $name The name of the routine. + * @param string $type Type of routine (ROUTINE|PROCEDURE) + * @param bool $all Whether to return all data or just the info about parameters. + * + * @return array Data necessary to create the routine editor. + */ + public static function getDataFromName($name, $type, $all = true) + { + global $db; + + $retval = array(); + + // Build and execute the query + $fields = "SPECIFIC_NAME, ROUTINE_TYPE, DTD_IDENTIFIER, " + . "ROUTINE_DEFINITION, IS_DETERMINISTIC, SQL_DATA_ACCESS, " + . "ROUTINE_COMMENT, SECURITY_TYPE"; + $where = "ROUTINE_SCHEMA " . Util::getCollateForIS() . "=" + . "'" . $GLOBALS['dbi']->escapeString($db) . "' " + . "AND SPECIFIC_NAME='" . $GLOBALS['dbi']->escapeString($name) . "'" + . "AND ROUTINE_TYPE='" . $GLOBALS['dbi']->escapeString($type) . "'"; + $query = "SELECT $fields FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;"; + + $routine = $GLOBALS['dbi']->fetchSingleRow($query, 'ASSOC'); + + if (! $routine) { + return false; + } + + // Get required data + $retval['item_name'] = $routine['SPECIFIC_NAME']; + $retval['item_type'] = $routine['ROUTINE_TYPE']; + + $definition + = $GLOBALS['dbi']->getDefinition( + $db, + $routine['ROUTINE_TYPE'], + $routine['SPECIFIC_NAME'] + ); + + if ($definition == NULL) { + return false; + } + + $parser = new Parser($definition); + + /** + * @var CreateStatement $stmt + */ + $stmt = $parser->statements[0]; + + $params = Routine::getParameters($stmt); + $retval['item_num_params'] = $params['num']; + $retval['item_param_dir'] = $params['dir']; + $retval['item_param_name'] = $params['name']; + $retval['item_param_type'] = $params['type']; + $retval['item_param_length'] = $params['length']; + $retval['item_param_length_arr'] = $params['length_arr']; + $retval['item_param_opts_num'] = $params['opts']; + $retval['item_param_opts_text'] = $params['opts']; + + // Get extra data + if (!$all) { + return $retval; + } + + if ($retval['item_type'] == 'FUNCTION') { + $retval['item_type_toggle'] = 'PROCEDURE'; + } else { + $retval['item_type_toggle'] = 'FUNCTION'; + } + $retval['item_returntype'] = ''; + $retval['item_returnlength'] = ''; + $retval['item_returnopts_num'] = ''; + $retval['item_returnopts_text'] = ''; + + if (! empty($routine['DTD_IDENTIFIER'])) { + $options = array(); + foreach ($stmt->return->options->options as $opt) { + $options[] = is_string($opt) ? $opt : $opt['value']; + } + + $retval['item_returntype'] = $stmt->return->name; + $retval['item_returnlength'] = implode(',', $stmt->return->parameters); + $retval['item_returnopts_num'] = implode(' ', $options); + $retval['item_returnopts_text'] = implode(' ', $options); + } + + $retval['item_definer'] = $stmt->options->has('DEFINER'); + $retval['item_definition'] = $routine['ROUTINE_DEFINITION']; + $retval['item_isdeterministic'] = ''; + if ($routine['IS_DETERMINISTIC'] == 'YES') { + $retval['item_isdeterministic'] = " checked='checked'"; + } + $retval['item_securitytype_definer'] = ''; + $retval['item_securitytype_invoker'] = ''; + if ($routine['SECURITY_TYPE'] == 'DEFINER') { + $retval['item_securitytype_definer'] = " selected='selected'"; + } else if ($routine['SECURITY_TYPE'] == 'INVOKER') { + $retval['item_securitytype_invoker'] = " selected='selected'"; + } + $retval['item_sqldataaccess'] = $routine['SQL_DATA_ACCESS']; + $retval['item_comment'] = $routine['ROUTINE_COMMENT']; + + return $retval; + } // self::getDataFromName() + + /** + * Creates one row for the parameter table used in the routine editor. + * + * @param array $routine Data for the routine returned by + * self::getDataFromRequest() or + * self::getDataFromName() + * @param mixed $index Either a numeric index of the row being processed + * or NULL to create a template row for AJAX request + * @param string $class Class used to hide the direction column, if the + * row is for a stored function. + * + * @return string HTML code of one row of parameter table for the editor. + */ + public static function getParameterRow($routine = array(), $index = null, $class = '') + { + global $param_directions, $param_opts_num, $titles; + + if ($index === null) { + // template row for AJAX request + $i = 0; + $index = '%s'; + $drop_class = ''; + $routine = array( + 'item_param_dir' => array(0 => ''), + 'item_param_name' => array(0 => ''), + 'item_param_type' => array(0 => ''), + 'item_param_length' => array(0 => ''), + 'item_param_opts_num' => array(0 => ''), + 'item_param_opts_text' => array(0 => '') + ); + } else if (! empty($routine)) { + // regular row for routine editor + $drop_class = ' hide'; + $i = $index; + } else { + // No input data. This shouldn't happen, + // but better be safe than sorry. + return ''; + } + + // Create the output + $retval = ""; + $retval .= "
\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + + return $retval; + } // end self::getParameterRow() + + /** + * Displays a form used to add/edit a routine + * + * @param string $mode If the editor will be used to edit a routine + * or add a new one: 'edit' or 'add'. + * @param string $operation If the editor was previously invoked with + * JS turned off, this will hold the name of + * the current operation + * @param array $routine Data for the routine returned by + * self::getDataFromRequest() or + * self::getDataFromName() + * + * @return string HTML code for the editor. + */ + public static function getEditorForm($mode, $operation, $routine) + { + global $db, $errors, $param_sqldataaccess, $param_opts_num; + + $response = Response::getInstance(); + + // Escape special characters + $need_escape = array( + 'item_original_name', + 'item_name', + 'item_returnlength', + 'item_definition', + 'item_definer', + 'item_comment' + ); + foreach ($need_escape as $key => $index) { + $routine[$index] = htmlentities($routine[$index], ENT_QUOTES, 'UTF-8'); + } + for ($i = 0; $i < $routine['item_num_params']; $i++) { + $routine['item_param_name'][$i] = htmlentities( + $routine['item_param_name'][$i], + ENT_QUOTES + ); + $routine['item_param_length'][$i] = htmlentities( + $routine['item_param_length'][$i], + ENT_QUOTES + ); + } + + // Handle some logic first + if ($operation == 'change') { + if ($routine['item_type'] == 'PROCEDURE') { + $routine['item_type'] = 'FUNCTION'; + $routine['item_type_toggle'] = 'PROCEDURE'; + } else { + $routine['item_type'] = 'PROCEDURE'; + $routine['item_type_toggle'] = 'FUNCTION'; + } + } else if ($operation == 'add' + || ($routine['item_num_params'] == 0 && $mode == 'add' && ! $errors) + ) { + $routine['item_param_dir'][] = ''; + $routine['item_param_name'][] = ''; + $routine['item_param_type'][] = ''; + $routine['item_param_length'][] = ''; + $routine['item_param_opts_num'][] = ''; + $routine['item_param_opts_text'][] = ''; + $routine['item_num_params']++; + } else if ($operation == 'remove') { + unset($routine['item_param_dir'][$routine['item_num_params'] - 1]); + unset($routine['item_param_name'][$routine['item_num_params'] - 1]); + unset($routine['item_param_type'][$routine['item_num_params'] - 1]); + unset($routine['item_param_length'][$routine['item_num_params'] - 1]); + unset($routine['item_param_opts_num'][$routine['item_num_params'] - 1]); + unset($routine['item_param_opts_text'][$routine['item_num_params'] - 1]); + $routine['item_num_params']--; + } + $disableRemoveParam = ''; + if (! $routine['item_num_params']) { + $disableRemoveParam = " color: gray;' disabled='disabled"; + } + $original_routine = ''; + if ($mode == 'edit') { + $original_routine = "\n" + . "\n"; + } + $isfunction_class = ''; + $isprocedure_class = ''; + $isfunction_select = ''; + $isprocedure_select = ''; + if ($routine['item_type'] == 'PROCEDURE') { + $isfunction_class = ' hide'; + $isprocedure_select = " selected='selected'"; + } else { + $isprocedure_class = ' hide'; + $isfunction_select = " selected='selected'"; + } + + // Create the output + $retval = ""; + $retval .= "\n\n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= $original_routine; + $retval .= Url::getHiddenInputs($db) . "\n"; + $retval .= "
\n"; + $retval .= "" . __('Details') . "\n"; + $retval .= "
" + . "" + . "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " ---\n"; + $retval .= Charsets::getCharsetDropdownBox( + "item_param_opts_text[$index]", + null, + $routine['item_param_opts_text'][$i] + ); + $retval .= " ---\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " {$titles['Drop']}\n"; + $retval .= " \n"; + $retval .= "
\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " "; + $retval .= ""; + $retval .= ""; + $retval .= " "; + $retval .= " "; + $retval .= ""; + // parameter handling end + $retval .= ""; + $retval .= " "; + $retval .= " "; + $retval .= ""; + $retval .= ""; + $retval .= " "; + $retval .= " "; + $retval .= " "; + $retval .= ""; + $retval .= ""; + $retval .= " "; + $retval .= " "; + $retval .= ""; + $retval .= ""; + $retval .= " "; + $retval .= " "; + $retval .= ""; + $retval .= ""; + $retval .= " "; + $retval .= " "; + $retval .= ""; + if (isset($_REQUEST['edit_item']) + && ! empty($_REQUEST['edit_item']) + ) { + $retval .= ""; + $retval .= " "; + if ($GLOBALS['proc_priv'] + && $GLOBALS['is_reload_priv'] + ) { + $retval .= " "; + } else { + $retval .= " "; + } + $retval .= ""; + } + + $retval .= ""; + $retval .= " "; + $retval .= " "; + $retval .= ""; + $retval .= ""; + $retval .= " "; + $retval .= " "; + $retval .= ""; + $retval .= ""; + $retval .= " "; + $retval .= " "; + $retval .= ""; + $retval .= ""; + $retval .= " "; + $retval .= " "; + $retval .= ""; + $retval .= "
" . __('Routine name') . "\n"; + $retval .= " \n"; + if ($response->isAjax()) { + $retval .= " \n"; + } else { + $retval .= "\n" + . "
\n" + . $routine['item_type'] . "\n" + . "
\n" + . "\n"; + } + $retval .= "
" . __('Parameters') . "\n"; + // parameter handling start + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= " "; + $retval .= " \n"; + $retval .= " \n"; + for ($i = 0; $i < $routine['item_num_params']; $i++) { // each parameter + $retval .= self::getParameterRow($routine, $i, $isprocedure_class); + } + $retval .= " \n"; + $retval .= "
" + . __('Direction') . "" . __('Name') . "" . __('Type') . "" . __('Length/Values') . "" . __('Options') . " 
"; + $retval .= "
 "; + $retval .= " "; + $retval .= " "; + $retval .= "
" . __('Return type') . "
" . __('Return length/values') . "---
" . __('Return options') . "
"; + $retval .= Charsets::getCharsetDropdownBox( + "item_returnopts_text", + null, + $routine['item_returnopts_text'] + ); + $retval .= "
"; + $retval .= "
"; + $retval .= "
---
"; + $retval .= "
" . __('Definition') . "
" . __('Is deterministic') . "
" . __('Adjust privileges'); + $retval .= Util::showDocu('faq', 'faq6-39'); + $retval .= "
" . __('Definer') . "
" . __('Security type') . "
" . __('SQL data access') . "
" . __('Comment') . "
"; + $retval .= "
"; + if ($response->isAjax()) { + $retval .= ""; + $retval .= ""; + } + $retval .= ""; + $retval .= ""; + + return $retval; + } // end self::getEditorForm() + + /** + * Composes the query necessary to create a routine from an HTTP request. + * + * @return string The CREATE [ROUTINE | PROCEDURE] query. + */ + public static function getQueryFromRequest() + { + global $_REQUEST, $errors, $param_sqldataaccess, $param_directions, $PMA_Types; + + $_REQUEST['item_type'] = isset($_REQUEST['item_type']) + ? $_REQUEST['item_type'] : ''; + + $query = 'CREATE '; + if (! empty($_REQUEST['item_definer'])) { + if (mb_strpos($_REQUEST['item_definer'], '@') !== false) { + $arr = explode('@', $_REQUEST['item_definer']); + + $do_backquote = true; + if (substr($arr[0], 0, 1) === "`" + && substr($arr[0], -1) === "`" + ) { + $do_backquote = false; + } + $query .= 'DEFINER=' . Util::backquote($arr[0], $do_backquote); + + $do_backquote = true; + if (substr($arr[1], 0, 1) === "`" + && substr($arr[1], -1) === "`" + ) { + $do_backquote = false; + } + $query .= '@' . Util::backquote($arr[1], $do_backquote) . ' '; + } else { + $errors[] = __('The definer must be in the "username@hostname" format!'); + } + } + if ($_REQUEST['item_type'] == 'FUNCTION' + || $_REQUEST['item_type'] == 'PROCEDURE' + ) { + $query .= $_REQUEST['item_type'] . ' '; + } else { + $errors[] = sprintf( + __('Invalid routine type: "%s"'), + htmlspecialchars($_REQUEST['item_type']) + ); + } + if (! empty($_REQUEST['item_name'])) { + $query .= Util::backquote($_REQUEST['item_name']); + } else { + $errors[] = __('You must provide a routine name!'); + } + $params = ''; + $warned_about_dir = false; + $warned_about_length = false; + + if (! empty($_REQUEST['item_param_name']) + && ! empty($_REQUEST['item_param_type']) + && ! empty($_REQUEST['item_param_length']) + && is_array($_REQUEST['item_param_name']) + && is_array($_REQUEST['item_param_type']) + && is_array($_REQUEST['item_param_length']) + ) { + $item_param_name = $_REQUEST['item_param_name']; + $item_param_type = $_REQUEST['item_param_type']; + $item_param_length = $_REQUEST['item_param_length']; + + for ($i=0, $nb = count($item_param_name); $i < $nb; $i++) { + if (! empty($item_param_name[$i]) + && ! empty($item_param_type[$i]) + ) { + if ($_REQUEST['item_type'] == 'PROCEDURE' + && ! empty($_REQUEST['item_param_dir'][$i]) + && in_array($_REQUEST['item_param_dir'][$i], $param_directions) + ) { + $params .= $_REQUEST['item_param_dir'][$i] . " " + . Util::backquote($item_param_name[$i]) + . " " . $item_param_type[$i]; + } else if ($_REQUEST['item_type'] == 'FUNCTION') { + $params .= Util::backquote($item_param_name[$i]) + . " " . $item_param_type[$i]; + } else if (! $warned_about_dir) { + $warned_about_dir = true; + $errors[] = sprintf( + __('Invalid direction "%s" given for parameter.'), + htmlspecialchars($_REQUEST['item_param_dir'][$i]) + ); + } + if ($item_param_length[$i] != '' + && !preg_match( + '@^(DATE|TINYBLOB|TINYTEXT|BLOB|TEXT|' + . 'MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|' + . 'SERIAL|BOOLEAN)$@i', + $item_param_type[$i] + ) + ) { + $params .= "(" . $item_param_length[$i] . ")"; + } else if ($item_param_length[$i] == '' + && preg_match( + '@^(ENUM|SET|VARCHAR|VARBINARY)$@i', + $item_param_type[$i] + ) + ) { + if (! $warned_about_length) { + $warned_about_length = true; + $errors[] = __( + 'You must provide length/values for routine parameters' + . ' of type ENUM, SET, VARCHAR and VARBINARY.' + ); + } + } + if (! empty($_REQUEST['item_param_opts_text'][$i])) { + if ($PMA_Types->getTypeClass($item_param_type[$i]) == 'CHAR') { + $params .= ' CHARSET ' + . mb_strtolower( + $_REQUEST['item_param_opts_text'][$i] + ); + } + } + if (! empty($_REQUEST['item_param_opts_num'][$i])) { + if ($PMA_Types->getTypeClass($item_param_type[$i]) == 'NUMBER') { + $params .= ' ' + . mb_strtoupper( + $_REQUEST['item_param_opts_num'][$i] + ); + } + } + if ($i != (count($item_param_name) - 1)) { + $params .= ", "; + } + } else { + $errors[] = __( + 'You must provide a name and a type for each routine parameter.' + ); + break; + } + } + } + $query .= "(" . $params . ") "; + if ($_REQUEST['item_type'] == 'FUNCTION') { + $item_returntype = isset($_REQUEST['item_returntype']) + ? $_REQUEST['item_returntype'] + : null; + + if (! empty($item_returntype) + && in_array( + $item_returntype, Util::getSupportedDatatypes() + ) + ) { + $query .= "RETURNS " . $item_returntype; + } else { + $errors[] = __('You must provide a valid return type for the routine.'); + } + if (! empty($_REQUEST['item_returnlength']) + && !preg_match( + '@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|' + . 'MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|SERIAL|BOOLEAN)$@i', + $item_returntype + ) + ) { + $query .= "(" . $_REQUEST['item_returnlength'] . ")"; + } else if (empty($_REQUEST['item_returnlength']) + && preg_match( + '@^(ENUM|SET|VARCHAR|VARBINARY)$@i', $item_returntype + ) + ) { + if (! $warned_about_length) { + $errors[] = __( + 'You must provide length/values for routine parameters' + . ' of type ENUM, SET, VARCHAR and VARBINARY.' + ); + } + } + if (! empty($_REQUEST['item_returnopts_text'])) { + if ($PMA_Types->getTypeClass($item_returntype) == 'CHAR') { + $query .= ' CHARSET ' + . mb_strtolower($_REQUEST['item_returnopts_text']); + } + } + if (! empty($_REQUEST['item_returnopts_num'])) { + if ($PMA_Types->getTypeClass($item_returntype) == 'NUMBER') { + $query .= ' ' + . mb_strtoupper($_REQUEST['item_returnopts_num']); + } + } + $query .= ' '; + } + if (! empty($_REQUEST['item_comment'])) { + $query .= "COMMENT '" . $GLOBALS['dbi']->escapeString($_REQUEST['item_comment']) + . "' "; + } + if (isset($_REQUEST['item_isdeterministic'])) { + $query .= 'DETERMINISTIC '; + } else { + $query .= 'NOT DETERMINISTIC '; + } + if (! empty($_REQUEST['item_sqldataaccess']) + && in_array($_REQUEST['item_sqldataaccess'], $param_sqldataaccess) + ) { + $query .= $_REQUEST['item_sqldataaccess'] . ' '; + } + if (! empty($_REQUEST['item_securitytype'])) { + if ($_REQUEST['item_securitytype'] == 'DEFINER' + || $_REQUEST['item_securitytype'] == 'INVOKER' + ) { + $query .= 'SQL SECURITY ' . $_REQUEST['item_securitytype'] . ' '; + } + } + if (! empty($_REQUEST['item_definition'])) { + $query .= $_REQUEST['item_definition']; + } else { + $errors[] = __('You must provide a routine definition.'); + } + + return $query; + } // end self::getQueryFromRequest() + + /** + * Handles requests for executing a routine + * + * @return void + */ + public static function handleExecute() + { + global $_GET, $_POST, $_REQUEST, $GLOBALS, $db; + + $response = Response::getInstance(); + + /** + * Handle all user requests other than the default of listing routines + */ + if (! empty($_REQUEST['execute_routine']) && ! empty($_REQUEST['item_name'])) { + // Build the queries + $routine = self::getDataFromName( + $_REQUEST['item_name'], $_REQUEST['item_type'], false + ); + if ($routine === false) { + $message = __('Error in processing request:') . ' '; + $message .= sprintf( + Words::get('not_found'), + htmlspecialchars(Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(Util::backquote($db)) + ); + $message = Message::error($message); + if ($response->isAjax()) { + $response->setRequestStatus(false); + $response->addJSON('message', $message); + exit; + } else { + echo $message->getDisplay(); + unset($_POST); + } + } + + $queries = array(); + $end_query = array(); + $args = array(); + $all_functions = $GLOBALS['PMA_Types']->getAllFunctions(); + for ($i = 0; $i < $routine['item_num_params']; $i++) { + if (isset($_REQUEST['params'][$routine['item_param_name'][$i]])) { + $value = $_REQUEST['params'][$routine['item_param_name'][$i]]; + if (is_array($value)) { // is SET type + $value = implode(',', $value); + } + $value = $GLOBALS['dbi']->escapeString($value); + if (! empty($_REQUEST['funcs'][$routine['item_param_name'][$i]]) + && in_array( + $_REQUEST['funcs'][$routine['item_param_name'][$i]], + $all_functions + ) + ) { + $queries[] = "SET @p$i=" + . $_REQUEST['funcs'][$routine['item_param_name'][$i]] + . "('$value');\n"; + } else { + $queries[] = "SET @p$i='$value';\n"; + } + $args[] = "@p$i"; + } else { + $args[] = "@p$i"; + } + if ($routine['item_type'] == 'PROCEDURE') { + if ($routine['item_param_dir'][$i] == 'OUT' + || $routine['item_param_dir'][$i] == 'INOUT' + ) { + $end_query[] = "@p$i AS " + . Util::backquote($routine['item_param_name'][$i]); + } + } + } + if ($routine['item_type'] == 'PROCEDURE') { + $queries[] = "CALL " . Util::backquote($routine['item_name']) + . "(" . implode(', ', $args) . ");\n"; + if (count($end_query)) { + $queries[] = "SELECT " . implode(', ', $end_query) . ";\n"; + } + } else { + $queries[] = "SELECT " . Util::backquote($routine['item_name']) + . "(" . implode(', ', $args) . ") " + . "AS " . Util::backquote($routine['item_name']) + . ";\n"; + } + + // Get all the queries as one SQL statement + $multiple_query = implode("", $queries); + + $outcome = true; + $affected = 0; + + // Execute query + if (! $GLOBALS['dbi']->tryMultiQuery($multiple_query)) { + $outcome = false; + } + + // Generate output + if ($outcome) { + + // Pass the SQL queries through the "pretty printer" + $output = Util::formatSql(implode($queries, "\n")); + + // Display results + $output .= "
"; + $output .= sprintf( + __('Execution results of routine %s'), + Util::backquote(htmlspecialchars($routine['item_name'])) + ); + $output .= ""; + + $nbResultsetToDisplay = 0; + + do { + + $result = $GLOBALS['dbi']->storeResult(); + $num_rows = $GLOBALS['dbi']->numRows($result); + + if (($result !== false) && ($num_rows > 0)) { + + $output .= ""; + foreach ($GLOBALS['dbi']->getFieldsMeta($result) as $field) { + $output .= ""; + } + $output .= ""; + + while ($row = $GLOBALS['dbi']->fetchAssoc($result)) { + $output .= "" . self::browseRow($row) . ""; + } + + $output .= "
"; + $output .= htmlspecialchars($field->name); + $output .= "
"; + $nbResultsetToDisplay++; + $affected = $num_rows; + + } + + if (! $GLOBALS['dbi']->moreResults()) { + break; + } + + $output .= "
"; + + $GLOBALS['dbi']->freeResult($result); + + } while ($outcome = $GLOBALS['dbi']->nextResult()); + } + + if ($outcome) { + + $output .= "
"; + + $message = __('Your SQL query has been executed successfully.'); + if ($routine['item_type'] == 'PROCEDURE') { + $message .= '
'; + + // TODO : message need to be modified according to the + // output from the routine + $message .= sprintf( + _ngettext( + '%d row affected by the last statement inside the ' + . 'procedure.', + '%d rows affected by the last statement inside the ' + . 'procedure.', + $affected + ), + $affected + ); + } + $message = Message::success($message); + + if ($nbResultsetToDisplay == 0) { + $notice = __( + 'MySQL returned an empty result set (i.e. zero rows).' + ); + $output .= Message::notice($notice)->getDisplay(); + } + + } else { + $output = ''; + $message = Message::error( + sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($multiple_query) + ) + . '

' + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null) + ); + } + + // Print/send output + if ($response->isAjax()) { + $response->setRequestStatus($message->isSuccess()); + $response->addJSON('message', $message->getDisplay() . $output); + $response->addJSON('dialog', false); + exit; + } else { + echo $message->getDisplay() , $output; + if ($message->isError()) { + // At least one query has failed, so shouldn't + // execute any more queries, so we quit. + exit; + } + unset($_POST); + // Now deliberately fall through to displaying the routines list + } + return; + } else if (! empty($_GET['execute_dialog']) && ! empty($_GET['item_name'])) { + /** + * Display the execute form for a routine. + */ + $routine = self::getDataFromName( + $_GET['item_name'], $_GET['item_type'], true + ); + if ($routine !== false) { + $form = self::getExecuteForm($routine); + if ($response->isAjax()) { + $title = __("Execute routine") . " " . Util::backquote( + htmlentities($_GET['item_name'], ENT_QUOTES) + ); + $response->addJSON('message', $form); + $response->addJSON('title', $title); + $response->addJSON('dialog', true); + } else { + echo "\n\n

" . __("Execute routine") . "

\n\n"; + echo $form; + } + exit; + } else if (($response->isAjax())) { + $message = __('Error in processing request:') . ' '; + $message .= sprintf( + Words::get('not_found'), + htmlspecialchars(Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(Util::backquote($db)) + ); + $message = Message::error($message); + + $response->setRequestStatus(false); + $response->addJSON('message', $message); + exit; + } + } + } + + /** + * Browse row array + * + * @param array $row Columns + * + * @return string + */ + private static function browseRow($row) + { + $output = null; + foreach ($row as $value) { + if ($value === null) { + $value = 'NULL'; + } else { + $value = htmlspecialchars($value); + } + $output .= "" . $value . ""; + } + return $output; + } + + /** + * Creates the HTML code that shows the routine execution dialog. + * + * @param array $routine Data for the routine returned by + * self::getDataFromName() + * + * @return string HTML code for the routine execution dialog. + */ + public static function getExecuteForm($routine) + { + global $db, $cfg; + + $response = Response::getInstance(); + + // Escape special characters + $routine['item_name'] = htmlentities($routine['item_name'], ENT_QUOTES); + for ($i = 0; $i < $routine['item_num_params']; $i++) { + $routine['item_param_name'][$i] = htmlentities( + $routine['item_param_name'][$i], + ENT_QUOTES + ); + } + + // Create the output + $retval = ""; + $retval .= "\n\n"; + $retval .= "
isAjax()) { + $retval .= "{$routine['item_name']}\n"; + $retval .= "\n"; + $retval .= "\n"; + } else { + $retval .= "" . __('Routine parameters') . "\n"; + $retval .= "
\n"; + $retval .= __('Routine parameters'); + $retval .= "
\n"; + } + $retval .= "\n"; + $retval .= "\n"; + $retval .= "\n"; + if ($cfg['ShowFunctionFields']) { + $retval .= "\n"; + } + $retval .= "\n"; + $retval .= "\n"; + // Get a list of data types that are not yet supported. + $no_support_types = Util::unsupportedDatatypes(); + for ($i = 0; $i < $routine['item_num_params']; $i++) { // Each parameter + if ($routine['item_type'] == 'PROCEDURE' + && $routine['item_param_dir'][$i] == 'OUT' + ) { + continue; + } + $retval .= "\n\n"; + $retval .= "\n"; + $retval .= "\n"; + if ($cfg['ShowFunctionFields']) { + $retval .= "\n"; + } + // Append a class to date/time fields so that + // jQuery can attach a datepicker to them + $class = ''; + if ($routine['item_param_type'][$i] == 'DATETIME' + || $routine['item_param_type'][$i] == 'TIMESTAMP' + ) { + $class = 'datetimefield'; + } else if ($routine['item_param_type'][$i] == 'DATE') { + $class = 'datefield'; + } + $retval .= "\n"; + $retval .= "\n"; + } + $retval .= "\n
" . __('Name') . "" . __('Type') . "" . __('Function') . "" . __('Value') . "
{$routine['item_param_name'][$i]}{$routine['item_param_type'][$i]}\n"; + if (stristr($routine['item_param_type'][$i], 'enum') + || stristr($routine['item_param_type'][$i], 'set') + || in_array( + mb_strtolower($routine['item_param_type'][$i]), + $no_support_types + ) + ) { + $retval .= "--\n"; + } else { + $field = array( + 'True_Type' => mb_strtolower( + $routine['item_param_type'][$i] + ), + 'Type' => '', + 'Key' => '', + 'Field' => '', + 'Default' => '', + 'first_timestamp' => false + ); + $retval .= ""; + } + $retval .= "\n"; + if (in_array($routine['item_param_type'][$i], array('ENUM', 'SET'))) { + if ($routine['item_param_type'][$i] == 'ENUM') { + $input_type = 'radio'; + } else { + $input_type = 'checkbox'; + } + foreach ($routine['item_param_length_arr'][$i] as $value) { + $value = htmlentities(Util::unquote($value), ENT_QUOTES); + $retval .= "" + . $value . "
\n"; + } + } else if (in_array( + mb_strtolower($routine['item_param_type'][$i]), + $no_support_types + )) { + $retval .= "\n"; + } else { + $retval .= "\n"; + } + $retval .= "
\n"; + if (! $response->isAjax()) { + $retval .= "\n\n"; + $retval .= "
\n"; + $retval .= " \n"; + $retval .= "
\n"; + } else { + $retval .= ""; + $retval .= ""; + } + $retval .= "
\n\n"; + $retval .= "\n\n"; + + return $retval; + } // end self::getExecuteForm() +} diff --git a/libraries/rte/rte_main.inc.php b/libraries/rte/rte_main.inc.php index 2a143fdc47..626f0ffcdd 100644 --- a/libraries/rte/rte_main.inc.php +++ b/libraries/rte/rte_main.inc.php @@ -7,6 +7,7 @@ */ use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Events; +use PhpMyAdmin\Rte\Routines; use PhpMyAdmin\Url; if (! defined('PHPMYADMIN')) { @@ -88,7 +89,7 @@ case 'RTN': if (isset($_REQUEST['type'])) { $type = $_REQUEST['type']; } - PMA_RTN_main($type); + Routines::main($type); break; case 'TRI': PMA_TRI_main(); diff --git a/libraries/rte/rte_routines.lib.php b/libraries/rte/rte_routines.lib.php deleted file mode 100644 index acc7e5f5a0..0000000000 --- a/libraries/rte/rte_routines.lib.php +++ /dev/null @@ -1,1706 +0,0 @@ -getRoutines($db, $type); - echo RteList::get('routine', $items); - /** - * Display the form for adding a new routine, if the user has the privileges. - */ - echo Footer::routines(); - /** - * Display a warning for users with PHP's old "mysql" extension. - */ - if (! PhpMyAdmin\DatabaseInterface::checkDbExtension('mysqli')) { - trigger_error( - __( - 'You are using PHP\'s deprecated \'mysql\' extension, ' - . 'which is not capable of handling multi queries. ' - . '[strong]The execution of some stored routines may fail![/strong] ' - . 'Please use the improved \'mysqli\' extension to ' - . 'avoid any problems.' - ), - E_USER_WARNING - ); - } -} // end PMA_RTN_main() - -/** - * Handles editor requests for adding or editing an item - * - * @return void - */ -function PMA_RTN_handleEditor() -{ - global $_GET, $_POST, $_REQUEST, $GLOBALS, $db, $errors; - - $errors = PMA_RTN_handleRequestCreateOrEdit($errors, $db); - $response = Response::getInstance(); - - /** - * Display a form used to add/edit a routine, if necessary - */ - // FIXME: this must be simpler than that - if (count($errors) - || ( empty($_REQUEST['editor_process_add']) - && empty($_REQUEST['editor_process_edit']) - && (! empty($_REQUEST['add_item']) || ! empty($_REQUEST['edit_item']) - || ! empty($_REQUEST['routine_addparameter']) - || ! empty($_REQUEST['routine_removeparameter']) - || ! empty($_REQUEST['routine_changetype']))) - ) { - // Handle requests to add/remove parameters and changing routine type - // This is necessary when JS is disabled - $operation = ''; - if (! empty($_REQUEST['routine_addparameter'])) { - $operation = 'add'; - } else if (! empty($_REQUEST['routine_removeparameter'])) { - $operation = 'remove'; - } else if (! empty($_REQUEST['routine_changetype'])) { - $operation = 'change'; - } - // Get the data for the form (if any) - if (! empty($_REQUEST['add_item'])) { - $title = Words::get('add'); - $routine = PMA_RTN_getDataFromRequest(); - $mode = 'add'; - } else if (! empty($_REQUEST['edit_item'])) { - $title = __("Edit routine"); - if (! $operation && ! empty($_REQUEST['item_name']) - && empty($_REQUEST['editor_process_edit']) - ) { - $routine = PMA_RTN_getDataFromName( - $_REQUEST['item_name'], $_REQUEST['item_type'] - ); - if ($routine !== false) { - $routine['item_original_name'] = $routine['item_name']; - $routine['item_original_type'] = $routine['item_type']; - } - } else { - $routine = PMA_RTN_getDataFromRequest(); - } - $mode = 'edit'; - } - if ($routine !== false) { - // Show form - $editor = PMA_RTN_getEditorForm($mode, $operation, $routine); - if ($response->isAjax()) { - $response->addJSON('message', $editor); - $response->addJSON('title', $title); - $response->addJSON('param_template', PMA_RTN_getParameterRow()); - $response->addJSON('type', $routine['item_type']); - } else { - echo "\n\n

$title

\n\n$editor"; - } - exit; - } else { - $message = __('Error in processing request:') . ' '; - $message .= sprintf( - Words::get('no_edit'), - htmlspecialchars( - PhpMyAdmin\Util::backquote($_REQUEST['item_name']) - ), - htmlspecialchars(PhpMyAdmin\Util::backquote($db)) - ); - - $message = Message::error($message); - if ($response->isAjax()) { - $response->setRequestStatus(false); - $response->addJSON('message', $message); - exit; - } else { - $message->display(); - } - } - } -} - -/** - * Handle request to create or edit a routine - * - * @param array $errors Errors - * @param string $db DB name - * - * @return array - */ -function PMA_RTN_handleRequestCreateOrEdit($errors, $db) -{ - if (empty($_REQUEST['editor_process_add']) - && empty($_REQUEST['editor_process_edit']) - ) { - return $errors; - } - - $sql_query = ''; - $routine_query = PMA_RTN_getQueryFromRequest(); - if (!count($errors)) { // set by PMA_RTN_getQueryFromRequest() - // Execute the created query - if (!empty($_REQUEST['editor_process_edit'])) { - $isProcOrFunc = in_array( - $_REQUEST['item_original_type'], - array('PROCEDURE', 'FUNCTION') - ); - - if (!$isProcOrFunc) { - $errors[] = sprintf( - __('Invalid routine type: "%s"'), - htmlspecialchars($_REQUEST['item_original_type']) - ); - } else { - // Backup the old routine, in case something goes wrong - $create_routine = $GLOBALS['dbi']->getDefinition( - $db, - $_REQUEST['item_original_type'], - $_REQUEST['item_original_name'] - ); - - $privilegesBackup = PMA_RTN_backupPrivileges(); - - $drop_routine = "DROP {$_REQUEST['item_original_type']} " - . PhpMyAdmin\Util::backquote($_REQUEST['item_original_name']) - . ";\n"; - $result = $GLOBALS['dbi']->tryQuery($drop_routine); - if (!$result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($drop_routine) - ) - . '
' - . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); - } else { - list($newErrors, $message) = PMA_RTN_createRoutine( - $routine_query, - $create_routine, - $privilegesBackup - ); - if (empty($newErrors)) { - $sql_query = $drop_routine . $routine_query; - } else { - $errors = array_merge($errors, $newErrors); - } - unset($newErrors); - if (null === $message) { - unset($message); - } - } - } - } else { - // 'Add a new routine' mode - $result = $GLOBALS['dbi']->tryQuery($routine_query); - if (!$result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($routine_query) - ) - . '

' - . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); - } else { - $message = PhpMyAdmin\Message::success( - __('Routine %1$s has been created.') - ); - $message->addParam( - PhpMyAdmin\Util::backquote($_REQUEST['item_name']) - ); - $sql_query = $routine_query; - } - } - } - - if (count($errors)) { - $message = PhpMyAdmin\Message::error( - __( - 'One or more errors have occurred while' - . ' processing your request:' - ) - ); - $message->addHtml('
    '); - foreach ($errors as $string) { - $message->addHtml('
  • ' . $string . '
  • '); - } - $message->addHtml('
'); - } - - $output = PhpMyAdmin\Util::getMessage($message, $sql_query); - $response = Response::getInstance(); - if (!$response->isAjax()) { - return $errors; - } - - if (!$message->isSuccess()) { - $response->setRequestStatus(false); - $response->addJSON('message', $output); - exit; - } - - $routines = $GLOBALS['dbi']->getRoutines( - $db, - $_REQUEST['item_type'], - $_REQUEST['item_name'] - ); - $routine = $routines[0]; - $response->addJSON( - 'name', - htmlspecialchars( - mb_strtoupper($_REQUEST['item_name']) - ) - ); - $response->addJSON('new_row', RteList::getRoutineRow($routine)); - $response->addJSON('insert', !empty($routine)); - $response->addJSON('message', $output); - exit; -} - -/** - * Backup the privileges - * - * @return array - */ -function PMA_RTN_backupPrivileges() -{ - if (! $GLOBALS['proc_priv'] || ! $GLOBALS['is_reload_priv']) { - return array(); - } - - // Backup the Old Privileges before dropping - // if $_REQUEST['item_adjust_privileges'] set - if (! isset($_REQUEST['item_adjust_privileges']) - || empty($_REQUEST['item_adjust_privileges']) - ) { - return array(); - } - - $privilegesBackupQuery = 'SELECT * FROM ' . PhpMyAdmin\Util::backquote( - 'mysql' - ) - . '.' . PhpMyAdmin\Util::backquote('procs_priv') - . ' where Routine_name = "' . $_REQUEST['item_original_name'] - . '" AND Routine_type = "' . $_REQUEST['item_original_type'] - . '";'; - - $privilegesBackup = $GLOBALS['dbi']->fetchResult( - $privilegesBackupQuery, - 0 - ); - - return $privilegesBackup; -} - -/** - * Create the routine - * - * @param string $routine_query Query to create routine - * @param string $create_routine Query to restore routine - * @param array $privilegesBackup Privileges backup - * - * @return array - */ -function PMA_RTN_createRoutine( - $routine_query, - $create_routine, - $privilegesBackup -) { - $result = $GLOBALS['dbi']->tryQuery($routine_query); - if (!$result) { - $errors = array(); - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($routine_query) - ) - . '
' - . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); - // We dropped the old routine, - // but were unable to create the new one - // Try to restore the backup query - $result = $GLOBALS['dbi']->tryQuery($create_routine); - $errors = General::checkResult( - $result, - __( - 'Sorry, we failed to restore' - . ' the dropped routine.' - ), - $create_routine, - $errors - ); - - return array($errors, null); - } - - // Default value - $resultAdjust = false; - - if ($GLOBALS['proc_priv'] - && $GLOBALS['is_reload_priv'] - ) { - // Insert all the previous privileges - // but with the new name and the new type - foreach ($privilegesBackup as $priv) { - $adjustProcPrivilege = 'INSERT INTO ' - . Util::backquote('mysql') . '.' - . Util::backquote('procs_priv') - . ' VALUES("' . $priv[0] . '", "' - . $priv[1] . '", "' . $priv[2] . '", "' - . $_REQUEST['item_name'] . '", "' - . $_REQUEST['item_type'] . '", "' - . $priv[5] . '", "' - . $priv[6] . '", "' - . $priv[7] . '");'; - $resultAdjust = $GLOBALS['dbi']->query( - $adjustProcPrivilege - ); - } - } - - $message = PMA_RTN_flushPrivileges($resultAdjust); - - return array(array(), $message); -} - -/** - * Flush privileges and get message - * - * @param bool $flushPrivileges Flush privileges - * - * @return PhpMyAdmin\Message - */ -function PMA_RTN_flushPrivileges($flushPrivileges) -{ - if ($flushPrivileges) { - // Flush the Privileges - $flushPrivQuery = 'FLUSH PRIVILEGES;'; - $GLOBALS['dbi']->query($flushPrivQuery); - - $message = PhpMyAdmin\Message::success( - __( - 'Routine %1$s has been modified. Privileges have been adjusted.' - ) - ); - } else { - $message = PhpMyAdmin\Message::success( - __('Routine %1$s has been modified.') - ); - } - $message->addParam( - PhpMyAdmin\Util::backquote($_REQUEST['item_name']) - ); - - return $message; -} // end PMA_RTN_handleEditor() - -/** - * This function will generate the values that are required to - * complete the editor form. It is especially necessary to handle - * the 'Add another parameter', 'Remove last parameter' and - * 'Change routine type' functionalities when JS is disabled. - * - * @return array Data necessary to create the routine editor. - */ -function PMA_RTN_getDataFromRequest() -{ - global $_REQUEST, $param_directions, $param_sqldataaccess; - - $retval = array(); - $indices = array('item_name', - 'item_original_name', - 'item_returnlength', - 'item_returnopts_num', - 'item_returnopts_text', - 'item_definition', - 'item_comment', - 'item_definer'); - foreach ($indices as $index) { - $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : ''; - } - - $retval['item_type'] = 'PROCEDURE'; - $retval['item_type_toggle'] = 'FUNCTION'; - if (isset($_REQUEST['item_type']) && $_REQUEST['item_type'] == 'FUNCTION') { - $retval['item_type'] = 'FUNCTION'; - $retval['item_type_toggle'] = 'PROCEDURE'; - } - $retval['item_original_type'] = 'PROCEDURE'; - if (isset($_REQUEST['item_original_type']) - && $_REQUEST['item_original_type'] == 'FUNCTION' - ) { - $retval['item_original_type'] = 'FUNCTION'; - } - $retval['item_num_params'] = 0; - $retval['item_param_dir'] = array(); - $retval['item_param_name'] = array(); - $retval['item_param_type'] = array(); - $retval['item_param_length'] = array(); - $retval['item_param_opts_num'] = array(); - $retval['item_param_opts_text'] = array(); - if (isset($_REQUEST['item_param_name']) - && isset($_REQUEST['item_param_type']) - && isset($_REQUEST['item_param_length']) - && isset($_REQUEST['item_param_opts_num']) - && isset($_REQUEST['item_param_opts_text']) - && is_array($_REQUEST['item_param_name']) - && is_array($_REQUEST['item_param_type']) - && is_array($_REQUEST['item_param_length']) - && is_array($_REQUEST['item_param_opts_num']) - && is_array($_REQUEST['item_param_opts_text']) - ) { - if ($_REQUEST['item_type'] == 'PROCEDURE') { - $retval['item_param_dir'] = $_REQUEST['item_param_dir']; - foreach ($retval['item_param_dir'] as $key => $value) { - if (! in_array($value, $param_directions, true)) { - $retval['item_param_dir'][$key] = ''; - } - } - } - $retval['item_param_name'] = $_REQUEST['item_param_name']; - $retval['item_param_type'] = $_REQUEST['item_param_type']; - foreach ($retval['item_param_type'] as $key => $value) { - if (! in_array($value, PhpMyAdmin\Util::getSupportedDatatypes(), true)) { - $retval['item_param_type'][$key] = ''; - } - } - $retval['item_param_length'] = $_REQUEST['item_param_length']; - $retval['item_param_opts_num'] = $_REQUEST['item_param_opts_num']; - $retval['item_param_opts_text'] = $_REQUEST['item_param_opts_text']; - $retval['item_num_params'] = max( - count($retval['item_param_name']), - count($retval['item_param_type']), - count($retval['item_param_length']), - count($retval['item_param_opts_num']), - count($retval['item_param_opts_text']) - ); - } - $retval['item_returntype'] = ''; - if (isset($_REQUEST['item_returntype']) - && in_array($_REQUEST['item_returntype'], PhpMyAdmin\Util::getSupportedDatatypes()) - ) { - $retval['item_returntype'] = $_REQUEST['item_returntype']; - } - - $retval['item_isdeterministic'] = ''; - if (isset($_REQUEST['item_isdeterministic']) - && mb_strtolower($_REQUEST['item_isdeterministic']) == 'on' - ) { - $retval['item_isdeterministic'] = " checked='checked'"; - } - $retval['item_securitytype_definer'] = ''; - $retval['item_securitytype_invoker'] = ''; - if (isset($_REQUEST['item_securitytype'])) { - if ($_REQUEST['item_securitytype'] === 'DEFINER') { - $retval['item_securitytype_definer'] = " selected='selected'"; - } else if ($_REQUEST['item_securitytype'] === 'INVOKER') { - $retval['item_securitytype_invoker'] = " selected='selected'"; - } - } - $retval['item_sqldataaccess'] = ''; - if (isset($_REQUEST['item_sqldataaccess']) - && in_array($_REQUEST['item_sqldataaccess'], $param_sqldataaccess, true) - ) { - $retval['item_sqldataaccess'] = $_REQUEST['item_sqldataaccess']; - } - - return $retval; -} // end function PMA_RTN_getDataFromRequest() - -/** - * This function will generate the values that are required to complete - * the "Edit routine" form given the name of a routine. - * - * @param string $name The name of the routine. - * @param string $type Type of routine (ROUTINE|PROCEDURE) - * @param bool $all Whether to return all data or just the info about parameters. - * - * @return array Data necessary to create the routine editor. - */ -function PMA_RTN_getDataFromName($name, $type, $all = true) -{ - global $db; - - $retval = array(); - - // Build and execute the query - $fields = "SPECIFIC_NAME, ROUTINE_TYPE, DTD_IDENTIFIER, " - . "ROUTINE_DEFINITION, IS_DETERMINISTIC, SQL_DATA_ACCESS, " - . "ROUTINE_COMMENT, SECURITY_TYPE"; - $where = "ROUTINE_SCHEMA " . PhpMyAdmin\Util::getCollateForIS() . "=" - . "'" . $GLOBALS['dbi']->escapeString($db) . "' " - . "AND SPECIFIC_NAME='" . $GLOBALS['dbi']->escapeString($name) . "'" - . "AND ROUTINE_TYPE='" . $GLOBALS['dbi']->escapeString($type) . "'"; - $query = "SELECT $fields FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;"; - - $routine = $GLOBALS['dbi']->fetchSingleRow($query, 'ASSOC'); - - if (! $routine) { - return false; - } - - // Get required data - $retval['item_name'] = $routine['SPECIFIC_NAME']; - $retval['item_type'] = $routine['ROUTINE_TYPE']; - - $definition - = $GLOBALS['dbi']->getDefinition( - $db, - $routine['ROUTINE_TYPE'], - $routine['SPECIFIC_NAME'] - ); - - if ($definition == NULL) { - return false; - } - - $parser = new PhpMyAdmin\SqlParser\Parser($definition); - - /** - * @var CreateStatement $stmt - */ - $stmt = $parser->statements[0]; - - $params = PhpMyAdmin\SqlParser\Utils\Routine::getParameters($stmt); - $retval['item_num_params'] = $params['num']; - $retval['item_param_dir'] = $params['dir']; - $retval['item_param_name'] = $params['name']; - $retval['item_param_type'] = $params['type']; - $retval['item_param_length'] = $params['length']; - $retval['item_param_length_arr'] = $params['length_arr']; - $retval['item_param_opts_num'] = $params['opts']; - $retval['item_param_opts_text'] = $params['opts']; - - // Get extra data - if (!$all) { - return $retval; - } - - if ($retval['item_type'] == 'FUNCTION') { - $retval['item_type_toggle'] = 'PROCEDURE'; - } else { - $retval['item_type_toggle'] = 'FUNCTION'; - } - $retval['item_returntype'] = ''; - $retval['item_returnlength'] = ''; - $retval['item_returnopts_num'] = ''; - $retval['item_returnopts_text'] = ''; - - if (! empty($routine['DTD_IDENTIFIER'])) { - $options = array(); - foreach ($stmt->return->options->options as $opt) { - $options[] = is_string($opt) ? $opt : $opt['value']; - } - - $retval['item_returntype'] = $stmt->return->name; - $retval['item_returnlength'] = implode(',', $stmt->return->parameters); - $retval['item_returnopts_num'] = implode(' ', $options); - $retval['item_returnopts_text'] = implode(' ', $options); - } - - $retval['item_definer'] = $stmt->options->has('DEFINER'); - $retval['item_definition'] = $routine['ROUTINE_DEFINITION']; - $retval['item_isdeterministic'] = ''; - if ($routine['IS_DETERMINISTIC'] == 'YES') { - $retval['item_isdeterministic'] = " checked='checked'"; - } - $retval['item_securitytype_definer'] = ''; - $retval['item_securitytype_invoker'] = ''; - if ($routine['SECURITY_TYPE'] == 'DEFINER') { - $retval['item_securitytype_definer'] = " selected='selected'"; - } else if ($routine['SECURITY_TYPE'] == 'INVOKER') { - $retval['item_securitytype_invoker'] = " selected='selected'"; - } - $retval['item_sqldataaccess'] = $routine['SQL_DATA_ACCESS']; - $retval['item_comment'] = $routine['ROUTINE_COMMENT']; - - return $retval; -} // PMA_RTN_getDataFromName() - -/** - * Creates one row for the parameter table used in the routine editor. - * - * @param array $routine Data for the routine returned by - * PMA_RTN_getDataFromRequest() or - * PMA_RTN_getDataFromName() - * @param mixed $index Either a numeric index of the row being processed - * or NULL to create a template row for AJAX request - * @param string $class Class used to hide the direction column, if the - * row is for a stored function. - * - * @return string HTML code of one row of parameter table for the editor. - */ -function PMA_RTN_getParameterRow($routine = array(), $index = null, $class = '') -{ - global $param_directions, $param_opts_num, $titles; - - if ($index === null) { - // template row for AJAX request - $i = 0; - $index = '%s'; - $drop_class = ''; - $routine = array( - 'item_param_dir' => array(0 => ''), - 'item_param_name' => array(0 => ''), - 'item_param_type' => array(0 => ''), - 'item_param_length' => array(0 => ''), - 'item_param_opts_num' => array(0 => ''), - 'item_param_opts_text' => array(0 => '') - ); - } else if (! empty($routine)) { - // regular row for routine editor - $drop_class = ' hide'; - $i = $index; - } else { - // No input data. This shouldn't happen, - // but better be safe than sorry. - return ''; - } - - // Create the output - $retval = ""; - $retval .= " \n"; - $retval .= " " - . "" - . "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " ---\n"; - $retval .= " \n"; - $retval .= Charsets::getCharsetDropdownBox( - "item_param_opts_text[$index]", - null, - $routine['item_param_opts_text'][$i] - ); - $retval .= " \n"; - $retval .= " ---\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " {$titles['Drop']}\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - - return $retval; -} // end PMA_RTN_getParameterRow() - -/** - * Displays a form used to add/edit a routine - * - * @param string $mode If the editor will be used to edit a routine - * or add a new one: 'edit' or 'add'. - * @param string $operation If the editor was previously invoked with - * JS turned off, this will hold the name of - * the current operation - * @param array $routine Data for the routine returned by - * PMA_RTN_getDataFromRequest() or - * PMA_RTN_getDataFromName() - * - * @return string HTML code for the editor. - */ -function PMA_RTN_getEditorForm($mode, $operation, $routine) -{ - global $db, $errors, $param_sqldataaccess, $param_opts_num; - - $response = Response::getInstance(); - - // Escape special characters - $need_escape = array( - 'item_original_name', - 'item_name', - 'item_returnlength', - 'item_definition', - 'item_definer', - 'item_comment' - ); - foreach ($need_escape as $key => $index) { - $routine[$index] = htmlentities($routine[$index], ENT_QUOTES, 'UTF-8'); - } - for ($i = 0; $i < $routine['item_num_params']; $i++) { - $routine['item_param_name'][$i] = htmlentities( - $routine['item_param_name'][$i], - ENT_QUOTES - ); - $routine['item_param_length'][$i] = htmlentities( - $routine['item_param_length'][$i], - ENT_QUOTES - ); - } - - // Handle some logic first - if ($operation == 'change') { - if ($routine['item_type'] == 'PROCEDURE') { - $routine['item_type'] = 'FUNCTION'; - $routine['item_type_toggle'] = 'PROCEDURE'; - } else { - $routine['item_type'] = 'PROCEDURE'; - $routine['item_type_toggle'] = 'FUNCTION'; - } - } else if ($operation == 'add' - || ($routine['item_num_params'] == 0 && $mode == 'add' && ! $errors) - ) { - $routine['item_param_dir'][] = ''; - $routine['item_param_name'][] = ''; - $routine['item_param_type'][] = ''; - $routine['item_param_length'][] = ''; - $routine['item_param_opts_num'][] = ''; - $routine['item_param_opts_text'][] = ''; - $routine['item_num_params']++; - } else if ($operation == 'remove') { - unset($routine['item_param_dir'][$routine['item_num_params'] - 1]); - unset($routine['item_param_name'][$routine['item_num_params'] - 1]); - unset($routine['item_param_type'][$routine['item_num_params'] - 1]); - unset($routine['item_param_length'][$routine['item_num_params'] - 1]); - unset($routine['item_param_opts_num'][$routine['item_num_params'] - 1]); - unset($routine['item_param_opts_text'][$routine['item_num_params'] - 1]); - $routine['item_num_params']--; - } - $disableRemoveParam = ''; - if (! $routine['item_num_params']) { - $disableRemoveParam = " color: gray;' disabled='disabled"; - } - $original_routine = ''; - if ($mode == 'edit') { - $original_routine = "\n" - . "\n"; - } - $isfunction_class = ''; - $isprocedure_class = ''; - $isfunction_select = ''; - $isprocedure_select = ''; - if ($routine['item_type'] == 'PROCEDURE') { - $isfunction_class = ' hide'; - $isprocedure_select = " selected='selected'"; - } else { - $isprocedure_class = ' hide'; - $isfunction_select = " selected='selected'"; - } - - // Create the output - $retval = ""; - $retval .= "\n\n"; - $retval .= "
\n"; - $retval .= "\n"; - $retval .= $original_routine; - $retval .= Url::getHiddenInputs($db) . "\n"; - $retval .= "
\n"; - $retval .= "" . __('Details') . "\n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - // parameter handling end - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - if (isset($_REQUEST['edit_item']) - && ! empty($_REQUEST['edit_item']) - ) { - $retval .= ""; - $retval .= " "; - if ($GLOBALS['proc_priv'] - && $GLOBALS['is_reload_priv'] - ) { - $retval .= " "; - } else { - $retval .= " "; - } - $retval .= ""; - } - - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= ""; - $retval .= " "; - $retval .= " "; - $retval .= ""; - $retval .= "
" . __('Routine name') . "\n"; - $retval .= " \n"; - if ($response->isAjax()) { - $retval .= " \n"; - } else { - $retval .= "\n" - . "
\n" - . $routine['item_type'] . "\n" - . "
\n" - . "\n"; - } - $retval .= "
" . __('Parameters') . "\n"; - // parameter handling start - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= " "; - $retval .= " \n"; - $retval .= " \n"; - for ($i = 0; $i < $routine['item_num_params']; $i++) { // each parameter - $retval .= PMA_RTN_getParameterRow($routine, $i, $isprocedure_class); - } - $retval .= " \n"; - $retval .= "
" - . __('Direction') . "" . __('Name') . "" . __('Type') . "" . __('Length/Values') . "" . __('Options') . " 
"; - $retval .= "
 "; - $retval .= " "; - $retval .= " "; - $retval .= "
" . __('Return type') . "
" . __('Return length/values') . "---
" . __('Return options') . "
"; - $retval .= Charsets::getCharsetDropdownBox( - "item_returnopts_text", - null, - $routine['item_returnopts_text'] - ); - $retval .= "
"; - $retval .= "
"; - $retval .= "
---
"; - $retval .= "
" . __('Definition') . "
" . __('Is deterministic') . "
" . __('Adjust privileges'); - $retval .= PhpMyAdmin\Util::showDocu('faq', 'faq6-39'); - $retval .= "
" . __('Definer') . "
" . __('Security type') . "
" . __('SQL data access') . "
" . __('Comment') . "
"; - $retval .= "
"; - if ($response->isAjax()) { - $retval .= ""; - $retval .= ""; - } - $retval .= "
"; - $retval .= ""; - - return $retval; -} // end PMA_RTN_getEditorForm() - -/** - * Composes the query necessary to create a routine from an HTTP request. - * - * @return string The CREATE [ROUTINE | PROCEDURE] query. - */ -function PMA_RTN_getQueryFromRequest() -{ - global $_REQUEST, $errors, $param_sqldataaccess, $param_directions, $PMA_Types; - - $_REQUEST['item_type'] = isset($_REQUEST['item_type']) - ? $_REQUEST['item_type'] : ''; - - $query = 'CREATE '; - if (! empty($_REQUEST['item_definer'])) { - if (mb_strpos($_REQUEST['item_definer'], '@') !== false) { - $arr = explode('@', $_REQUEST['item_definer']); - - $do_backquote = true; - if (substr($arr[0], 0, 1) === "`" - && substr($arr[0], -1) === "`" - ) { - $do_backquote = false; - } - $query .= 'DEFINER=' . PhpMyAdmin\Util::backquote($arr[0], $do_backquote); - - $do_backquote = true; - if (substr($arr[1], 0, 1) === "`" - && substr($arr[1], -1) === "`" - ) { - $do_backquote = false; - } - $query .= '@' . PhpMyAdmin\Util::backquote($arr[1], $do_backquote) . ' '; - } else { - $errors[] = __('The definer must be in the "username@hostname" format!'); - } - } - if ($_REQUEST['item_type'] == 'FUNCTION' - || $_REQUEST['item_type'] == 'PROCEDURE' - ) { - $query .= $_REQUEST['item_type'] . ' '; - } else { - $errors[] = sprintf( - __('Invalid routine type: "%s"'), - htmlspecialchars($_REQUEST['item_type']) - ); - } - if (! empty($_REQUEST['item_name'])) { - $query .= PhpMyAdmin\Util::backquote($_REQUEST['item_name']); - } else { - $errors[] = __('You must provide a routine name!'); - } - $params = ''; - $warned_about_dir = false; - $warned_about_length = false; - - if (! empty($_REQUEST['item_param_name']) - && ! empty($_REQUEST['item_param_type']) - && ! empty($_REQUEST['item_param_length']) - && is_array($_REQUEST['item_param_name']) - && is_array($_REQUEST['item_param_type']) - && is_array($_REQUEST['item_param_length']) - ) { - $item_param_name = $_REQUEST['item_param_name']; - $item_param_type = $_REQUEST['item_param_type']; - $item_param_length = $_REQUEST['item_param_length']; - - for ($i=0, $nb = count($item_param_name); $i < $nb; $i++) { - if (! empty($item_param_name[$i]) - && ! empty($item_param_type[$i]) - ) { - if ($_REQUEST['item_type'] == 'PROCEDURE' - && ! empty($_REQUEST['item_param_dir'][$i]) - && in_array($_REQUEST['item_param_dir'][$i], $param_directions) - ) { - $params .= $_REQUEST['item_param_dir'][$i] . " " - . PhpMyAdmin\Util::backquote($item_param_name[$i]) - . " " . $item_param_type[$i]; - } else if ($_REQUEST['item_type'] == 'FUNCTION') { - $params .= PhpMyAdmin\Util::backquote($item_param_name[$i]) - . " " . $item_param_type[$i]; - } else if (! $warned_about_dir) { - $warned_about_dir = true; - $errors[] = sprintf( - __('Invalid direction "%s" given for parameter.'), - htmlspecialchars($_REQUEST['item_param_dir'][$i]) - ); - } - if ($item_param_length[$i] != '' - && !preg_match( - '@^(DATE|TINYBLOB|TINYTEXT|BLOB|TEXT|' - . 'MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|' - . 'SERIAL|BOOLEAN)$@i', - $item_param_type[$i] - ) - ) { - $params .= "(" . $item_param_length[$i] . ")"; - } else if ($item_param_length[$i] == '' - && preg_match( - '@^(ENUM|SET|VARCHAR|VARBINARY)$@i', - $item_param_type[$i] - ) - ) { - if (! $warned_about_length) { - $warned_about_length = true; - $errors[] = __( - 'You must provide length/values for routine parameters' - . ' of type ENUM, SET, VARCHAR and VARBINARY.' - ); - } - } - if (! empty($_REQUEST['item_param_opts_text'][$i])) { - if ($PMA_Types->getTypeClass($item_param_type[$i]) == 'CHAR') { - $params .= ' CHARSET ' - . mb_strtolower( - $_REQUEST['item_param_opts_text'][$i] - ); - } - } - if (! empty($_REQUEST['item_param_opts_num'][$i])) { - if ($PMA_Types->getTypeClass($item_param_type[$i]) == 'NUMBER') { - $params .= ' ' - . mb_strtoupper( - $_REQUEST['item_param_opts_num'][$i] - ); - } - } - if ($i != (count($item_param_name) - 1)) { - $params .= ", "; - } - } else { - $errors[] = __( - 'You must provide a name and a type for each routine parameter.' - ); - break; - } - } - } - $query .= "(" . $params . ") "; - if ($_REQUEST['item_type'] == 'FUNCTION') { - $item_returntype = isset($_REQUEST['item_returntype']) - ? $_REQUEST['item_returntype'] - : null; - - if (! empty($item_returntype) - && in_array( - $item_returntype, PhpMyAdmin\Util::getSupportedDatatypes() - ) - ) { - $query .= "RETURNS " . $item_returntype; - } else { - $errors[] = __('You must provide a valid return type for the routine.'); - } - if (! empty($_REQUEST['item_returnlength']) - && !preg_match( - '@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|' - . 'MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|SERIAL|BOOLEAN)$@i', - $item_returntype - ) - ) { - $query .= "(" . $_REQUEST['item_returnlength'] . ")"; - } else if (empty($_REQUEST['item_returnlength']) - && preg_match( - '@^(ENUM|SET|VARCHAR|VARBINARY)$@i', $item_returntype - ) - ) { - if (! $warned_about_length) { - $errors[] = __( - 'You must provide length/values for routine parameters' - . ' of type ENUM, SET, VARCHAR and VARBINARY.' - ); - } - } - if (! empty($_REQUEST['item_returnopts_text'])) { - if ($PMA_Types->getTypeClass($item_returntype) == 'CHAR') { - $query .= ' CHARSET ' - . mb_strtolower($_REQUEST['item_returnopts_text']); - } - } - if (! empty($_REQUEST['item_returnopts_num'])) { - if ($PMA_Types->getTypeClass($item_returntype) == 'NUMBER') { - $query .= ' ' - . mb_strtoupper($_REQUEST['item_returnopts_num']); - } - } - $query .= ' '; - } - if (! empty($_REQUEST['item_comment'])) { - $query .= "COMMENT '" . $GLOBALS['dbi']->escapeString($_REQUEST['item_comment']) - . "' "; - } - if (isset($_REQUEST['item_isdeterministic'])) { - $query .= 'DETERMINISTIC '; - } else { - $query .= 'NOT DETERMINISTIC '; - } - if (! empty($_REQUEST['item_sqldataaccess']) - && in_array($_REQUEST['item_sqldataaccess'], $param_sqldataaccess) - ) { - $query .= $_REQUEST['item_sqldataaccess'] . ' '; - } - if (! empty($_REQUEST['item_securitytype'])) { - if ($_REQUEST['item_securitytype'] == 'DEFINER' - || $_REQUEST['item_securitytype'] == 'INVOKER' - ) { - $query .= 'SQL SECURITY ' . $_REQUEST['item_securitytype'] . ' '; - } - } - if (! empty($_REQUEST['item_definition'])) { - $query .= $_REQUEST['item_definition']; - } else { - $errors[] = __('You must provide a routine definition.'); - } - - return $query; -} // end PMA_RTN_getQueryFromRequest() - -/** - * Handles requests for executing a routine - * - * @return void - */ -function PMA_RTN_handleExecute() -{ - global $_GET, $_POST, $_REQUEST, $GLOBALS, $db; - - $response = Response::getInstance(); - - /** - * Handle all user requests other than the default of listing routines - */ - if (! empty($_REQUEST['execute_routine']) && ! empty($_REQUEST['item_name'])) { - // Build the queries - $routine = PMA_RTN_getDataFromName( - $_REQUEST['item_name'], $_REQUEST['item_type'], false - ); - if ($routine === false) { - $message = __('Error in processing request:') . ' '; - $message .= sprintf( - Words::get('not_found'), - htmlspecialchars(PhpMyAdmin\Util::backquote($_REQUEST['item_name'])), - htmlspecialchars(PhpMyAdmin\Util::backquote($db)) - ); - $message = Message::error($message); - if ($response->isAjax()) { - $response->setRequestStatus(false); - $response->addJSON('message', $message); - exit; - } else { - echo $message->getDisplay(); - unset($_POST); - } - } - - $queries = array(); - $end_query = array(); - $args = array(); - $all_functions = $GLOBALS['PMA_Types']->getAllFunctions(); - for ($i = 0; $i < $routine['item_num_params']; $i++) { - if (isset($_REQUEST['params'][$routine['item_param_name'][$i]])) { - $value = $_REQUEST['params'][$routine['item_param_name'][$i]]; - if (is_array($value)) { // is SET type - $value = implode(',', $value); - } - $value = $GLOBALS['dbi']->escapeString($value); - if (! empty($_REQUEST['funcs'][$routine['item_param_name'][$i]]) - && in_array( - $_REQUEST['funcs'][$routine['item_param_name'][$i]], - $all_functions - ) - ) { - $queries[] = "SET @p$i=" - . $_REQUEST['funcs'][$routine['item_param_name'][$i]] - . "('$value');\n"; - } else { - $queries[] = "SET @p$i='$value';\n"; - } - $args[] = "@p$i"; - } else { - $args[] = "@p$i"; - } - if ($routine['item_type'] == 'PROCEDURE') { - if ($routine['item_param_dir'][$i] == 'OUT' - || $routine['item_param_dir'][$i] == 'INOUT' - ) { - $end_query[] = "@p$i AS " - . PhpMyAdmin\Util::backquote($routine['item_param_name'][$i]); - } - } - } - if ($routine['item_type'] == 'PROCEDURE') { - $queries[] = "CALL " . PhpMyAdmin\Util::backquote($routine['item_name']) - . "(" . implode(', ', $args) . ");\n"; - if (count($end_query)) { - $queries[] = "SELECT " . implode(', ', $end_query) . ";\n"; - } - } else { - $queries[] = "SELECT " . PhpMyAdmin\Util::backquote($routine['item_name']) - . "(" . implode(', ', $args) . ") " - . "AS " . PhpMyAdmin\Util::backquote($routine['item_name']) - . ";\n"; - } - - // Get all the queries as one SQL statement - $multiple_query = implode("", $queries); - - $outcome = true; - $affected = 0; - - // Execute query - if (! $GLOBALS['dbi']->tryMultiQuery($multiple_query)) { - $outcome = false; - } - - // Generate output - if ($outcome) { - - // Pass the SQL queries through the "pretty printer" - $output = PhpMyAdmin\Util::formatSql(implode($queries, "\n")); - - // Display results - $output .= "
"; - $output .= sprintf( - __('Execution results of routine %s'), - PhpMyAdmin\Util::backquote(htmlspecialchars($routine['item_name'])) - ); - $output .= ""; - - $nbResultsetToDisplay = 0; - - do { - - $result = $GLOBALS['dbi']->storeResult(); - $num_rows = $GLOBALS['dbi']->numRows($result); - - if (($result !== false) && ($num_rows > 0)) { - - $output .= ""; - foreach ($GLOBALS['dbi']->getFieldsMeta($result) as $field) { - $output .= ""; - } - $output .= ""; - - while ($row = $GLOBALS['dbi']->fetchAssoc($result)) { - $output .= "" . browseRow($row) . ""; - } - - $output .= "
"; - $output .= htmlspecialchars($field->name); - $output .= "
"; - $nbResultsetToDisplay++; - $affected = $num_rows; - - } - - if (! $GLOBALS['dbi']->moreResults()) { - break; - } - - $output .= "
"; - - $GLOBALS['dbi']->freeResult($result); - - } while ($outcome = $GLOBALS['dbi']->nextResult()); - } - - if ($outcome) { - - $output .= "
"; - - $message = __('Your SQL query has been executed successfully.'); - if ($routine['item_type'] == 'PROCEDURE') { - $message .= '
'; - - // TODO : message need to be modified according to the - // output from the routine - $message .= sprintf( - _ngettext( - '%d row affected by the last statement inside the ' - . 'procedure.', - '%d rows affected by the last statement inside the ' - . 'procedure.', - $affected - ), - $affected - ); - } - $message = Message::success($message); - - if ($nbResultsetToDisplay == 0) { - $notice = __( - 'MySQL returned an empty result set (i.e. zero rows).' - ); - $output .= Message::notice($notice)->getDisplay(); - } - - } else { - $output = ''; - $message = Message::error( - sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($multiple_query) - ) - . '

' - . __('MySQL said: ') . $GLOBALS['dbi']->getError(null) - ); - } - - // Print/send output - if ($response->isAjax()) { - $response->setRequestStatus($message->isSuccess()); - $response->addJSON('message', $message->getDisplay() . $output); - $response->addJSON('dialog', false); - exit; - } else { - echo $message->getDisplay() , $output; - if ($message->isError()) { - // At least one query has failed, so shouldn't - // execute any more queries, so we quit. - exit; - } - unset($_POST); - // Now deliberately fall through to displaying the routines list - } - return; - } else if (! empty($_GET['execute_dialog']) && ! empty($_GET['item_name'])) { - /** - * Display the execute form for a routine. - */ - $routine = PMA_RTN_getDataFromName( - $_GET['item_name'], $_GET['item_type'], true - ); - if ($routine !== false) { - $form = PMA_RTN_getExecuteForm($routine); - if ($response->isAjax()) { - $title = __("Execute routine") . " " . PhpMyAdmin\Util::backquote( - htmlentities($_GET['item_name'], ENT_QUOTES) - ); - $response->addJSON('message', $form); - $response->addJSON('title', $title); - $response->addJSON('dialog', true); - } else { - echo "\n\n

" . __("Execute routine") . "

\n\n"; - echo $form; - } - exit; - } else if (($response->isAjax())) { - $message = __('Error in processing request:') . ' '; - $message .= sprintf( - Words::get('not_found'), - htmlspecialchars(PhpMyAdmin\Util::backquote($_REQUEST['item_name'])), - htmlspecialchars(PhpMyAdmin\Util::backquote($db)) - ); - $message = Message::error($message); - - $response->setRequestStatus(false); - $response->addJSON('message', $message); - exit; - } - } -} - -/** - * Browse row array - * - * @param array $row Columns - * - * @return string - */ -function browseRow($row) -{ - $output = null; - foreach ($row as $value) { - if ($value === null) { - $value = 'NULL'; - } else { - $value = htmlspecialchars($value); - } - $output .= "" . $value . ""; - } - return $output; -} - -/** - * Creates the HTML code that shows the routine execution dialog. - * - * @param array $routine Data for the routine returned by - * PMA_RTN_getDataFromName() - * - * @return string HTML code for the routine execution dialog. - */ -function PMA_RTN_getExecuteForm($routine) -{ - global $db, $cfg; - - $response = Response::getInstance(); - - // Escape special characters - $routine['item_name'] = htmlentities($routine['item_name'], ENT_QUOTES); - for ($i = 0; $i < $routine['item_num_params']; $i++) { - $routine['item_param_name'][$i] = htmlentities( - $routine['item_param_name'][$i], - ENT_QUOTES - ); - } - - // Create the output - $retval = ""; - $retval .= "\n\n"; - $retval .= "
isAjax()) { - $retval .= "{$routine['item_name']}\n"; - $retval .= "\n"; - $retval .= "\n"; - } else { - $retval .= "" . __('Routine parameters') . "\n"; - $retval .= "
\n"; - $retval .= __('Routine parameters'); - $retval .= "
\n"; - } - $retval .= "\n"; - $retval .= "\n"; - $retval .= "\n"; - if ($cfg['ShowFunctionFields']) { - $retval .= "\n"; - } - $retval .= "\n"; - $retval .= "\n"; - // Get a list of data types that are not yet supported. - $no_support_types = PhpMyAdmin\Util::unsupportedDatatypes(); - for ($i = 0; $i < $routine['item_num_params']; $i++) { // Each parameter - if ($routine['item_type'] == 'PROCEDURE' - && $routine['item_param_dir'][$i] == 'OUT' - ) { - continue; - } - $retval .= "\n\n"; - $retval .= "\n"; - $retval .= "\n"; - if ($cfg['ShowFunctionFields']) { - $retval .= "\n"; - } - // Append a class to date/time fields so that - // jQuery can attach a datepicker to them - $class = ''; - if ($routine['item_param_type'][$i] == 'DATETIME' - || $routine['item_param_type'][$i] == 'TIMESTAMP' - ) { - $class = 'datetimefield'; - } else if ($routine['item_param_type'][$i] == 'DATE') { - $class = 'datefield'; - } - $retval .= "\n"; - $retval .= "\n"; - } - $retval .= "\n
" . __('Name') . "" . __('Type') . "" . __('Function') . "" . __('Value') . "
{$routine['item_param_name'][$i]}{$routine['item_param_type'][$i]}\n"; - if (stristr($routine['item_param_type'][$i], 'enum') - || stristr($routine['item_param_type'][$i], 'set') - || in_array( - mb_strtolower($routine['item_param_type'][$i]), - $no_support_types - ) - ) { - $retval .= "--\n"; - } else { - $field = array( - 'True_Type' => mb_strtolower( - $routine['item_param_type'][$i] - ), - 'Type' => '', - 'Key' => '', - 'Field' => '', - 'Default' => '', - 'first_timestamp' => false - ); - $retval .= ""; - } - $retval .= "\n"; - if (in_array($routine['item_param_type'][$i], array('ENUM', 'SET'))) { - if ($routine['item_param_type'][$i] == 'ENUM') { - $input_type = 'radio'; - } else { - $input_type = 'checkbox'; - } - foreach ($routine['item_param_length_arr'][$i] as $value) { - $value = htmlentities(PhpMyAdmin\Util::unquote($value), ENT_QUOTES); - $retval .= "" - . $value . "
\n"; - } - } else if (in_array( - mb_strtolower($routine['item_param_type'][$i]), - $no_support_types - )) { - $retval .= "\n"; - } else { - $retval .= "\n"; - } - $retval .= "
\n"; - if (! $response->isAjax()) { - $retval .= "\n\n"; - $retval .= "
\n"; - $retval .= " \n"; - $retval .= "
\n"; - } else { - $retval .= ""; - $retval .= ""; - } - $retval .= "
\n\n"; - $retval .= "\n\n"; - - return $retval; -} // end PMA_RTN_getExecuteForm() diff --git a/libraries/rte/rte_triggers.lib.php b/libraries/rte/rte_triggers.lib.php index c8bcee6561..644691cd2c 100644 --- a/libraries/rte/rte_triggers.lib.php +++ b/libraries/rte/rte_triggers.lib.php @@ -77,7 +77,7 @@ function PMA_TRI_handleEditor() $item_query = PMA_TRI_getQueryFromRequest(); - if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest() + if (! count($errors)) { // set by PhpMyAdmin\Rte\Routines::getQueryFromRequest() // Execute the created query if (! empty($_REQUEST['editor_process_edit'])) { // Backup the old trigger, in case something goes wrong diff --git a/test/classes/Rte/RoutinesTest.php b/test/classes/Rte/RoutinesTest.php new file mode 100644 index 0000000000..1622ad3844 --- /dev/null +++ b/test/classes/Rte/RoutinesTest.php @@ -0,0 +1,1338 @@ +getPath(); + } + + /** + * Test for Routines::getDataFromRequest + * + * @param array $in Input + * @param array $out Expected output + * + * @return void + * + * @dataProvider providerGetDataFromRequest + */ + public function testGetDataFromRequest($in, $out) + { + global $_REQUEST; + + unset($_REQUEST); + foreach ($in as $key => $value) { + if ($value !== '') { + $_REQUEST[$key] = $value; + } + } + Routines::setGlobals(); + $this->assertEquals($out, Routines::getDataFromRequest()); + } + + /** + * Data provider for testGetDataFromRequest + * + * @return array + */ + public function providerGetDataFromRequest() + { + return array( + array( + array( + 'item_name' => '', + 'item_original_name' => '', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => '', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => '', + 'item_type_toggle' => '', + 'item_original_type' => '', + 'item_param_dir' => '', + 'item_param_name' => '', + 'item_param_type' => '', + 'item_param_length' => '', + 'item_param_opts_num' => '', + 'item_param_opts_text' => '', + 'item_returntype' => '', + 'item_isdeterministic' => '', + 'item_securitytype' => '', + 'item_sqldataaccess' => '' + ), + array( + 'item_name' => '', + 'item_original_name' => '', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => '', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => 'PROCEDURE', + 'item_type_toggle' => 'FUNCTION', + 'item_original_type' => 'PROCEDURE', + 'item_num_params' => 0, + 'item_param_dir' => array(), + 'item_param_name' => array(), + 'item_param_type' => array(), + 'item_param_length' => array(), + 'item_param_opts_num' => array(), + 'item_param_opts_text' => array(), + 'item_returntype' => '', + 'item_isdeterministic' => '', + 'item_securitytype_definer' => '', + 'item_securitytype_invoker' => '', + 'item_sqldataaccess' => '' + ) + ), + array( + array( + 'item_name' => 'proc2', + 'item_original_name' => 'proc', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT NULL', + 'item_comment' => 'some text', + 'item_definer' => 'root@localhost', + 'item_type' => 'PROCEDURE', + 'item_type_toggle' => 'FUNCTION', + 'item_original_type' => 'PROCEDURE', + 'item_param_dir' => array(0 => 'IN', 1 => 'FAIL'), + 'item_param_name' => array(0 => 'bar', 1 => 'baz'), + 'item_param_type' => array(0 => 'INT', 1 => 'FAIL'), + 'item_param_length' => array(0 => '20', 1 => ''), + 'item_param_opts_num' => array(0 => 'UNSIGNED', 1 => ''), + 'item_param_opts_text' => array(0 => '', 1 => 'latin1'), + 'item_returntype' => '', + 'item_isdeterministic' => 'ON', + 'item_securitytype' => 'INVOKER', + 'item_sqldataaccess' => 'NO SQL' + ), + array( + 'item_name' => 'proc2', + 'item_original_name' => 'proc', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT NULL', + 'item_comment' => 'some text', + 'item_definer' => 'root@localhost', + 'item_type' => 'PROCEDURE', + 'item_type_toggle' => 'FUNCTION', + 'item_original_type' => 'PROCEDURE', + 'item_num_params' => 2, + 'item_param_dir' => array(0 => 'IN', 1 => ''), + 'item_param_name' => array(0 => 'bar', 1 => 'baz'), + 'item_param_type' => array(0 => 'INT', 1 => ''), + 'item_param_length' => array(0 => '20', 1 => ''), + 'item_param_opts_num' => array(0 => 'UNSIGNED', 1 => ''), + 'item_param_opts_text' => array(0 => '', 1 => 'latin1'), + 'item_returntype' => '', + 'item_isdeterministic' => ' checked=\'checked\'', + 'item_securitytype_definer' => '', + 'item_securitytype_invoker' => ' selected=\'selected\'', + 'item_sqldataaccess' => 'NO SQL' + ) + ), + array( + array( + 'item_name' => 'func2', + 'item_original_name' => 'func', + 'item_returnlength' => '20', + 'item_returnopts_num' => '', + 'item_returnopts_text' => 'CHARSET utf8', + 'item_definition' => 'SELECT NULL', + 'item_comment' => 'some text', + 'item_definer' => 'root@localhost', + 'item_type' => 'FUNCTION', + 'item_type_toggle' => 'PROCEDURE', + 'item_original_type' => 'FUNCTION', + 'item_param_dir' => array(0 => '', 1 => ''), + 'item_param_name' => array(0 => 'bar', 1 => 'baz'), + 'item_param_type' => array( + 0 => 'XSS', + 1 => 'TEXT' + ), + 'item_param_length' => array(0 => '10,10', 1 => ''), + 'item_param_opts_num' => array(0 => 'UNSIGNED', 1 => ''), + 'item_param_opts_text' => array(0 => '', 1 => 'utf8'), + 'item_returntype' => 'VARCHAR', + 'item_isdeterministic' => '', + 'item_securitytype' => 'DEFINER', + 'item_sqldataaccess' => '' + ), + array( + 'item_name' => 'func2', + 'item_original_name' => 'func', + 'item_returnlength' => '20', + 'item_returnopts_num' => '', + 'item_returnopts_text' => 'CHARSET utf8', + 'item_definition' => 'SELECT NULL', + 'item_comment' => 'some text', + 'item_definer' => 'root@localhost', + 'item_type' => 'FUNCTION', + 'item_type_toggle' => 'PROCEDURE', + 'item_original_type' => 'FUNCTION', + 'item_num_params' => '2', + 'item_param_dir' => array(), + 'item_param_name' => array(0 => 'bar', 1 => 'baz'), + 'item_param_type' => array(0 => '', 1 => 'TEXT'), + 'item_param_length' => array(0 => '10,10', 1 => ''), + 'item_param_opts_num' => array(0 => 'UNSIGNED', 1 => ''), + 'item_param_opts_text' => array(0 => '', 1 => 'utf8'), + 'item_returntype' => 'VARCHAR', + 'item_isdeterministic' => '', + 'item_securitytype_definer' => ' selected=\'selected\'', + 'item_securitytype_invoker' => '', + 'item_sqldataaccess' => '' + ) + ), + ); + } + + /** + * Test for Routines::getParameterRow + * + * @return void + */ + public function testGetParameterRowEmpty() + { + Routines::setGlobals(); + $this->assertEquals('', Routines::getParameterRow(array(), 0)); + } + + /** + * Test for Routines::getParameterRow + * + * @param array $data Data for routine + * @param mixed $index Index + * @param array $matcher Matcher + * + * @return void + * + * @depends testGetParameterRowEmpty + * @dataProvider providerGetParameterRow + */ + public function testGetParameterRow($data, $index, $matcher) + { + Routines::setGlobals(); + $this->assertContains( + $matcher, + Routines::getParameterRow($data, $index) + ); + } + + /** + * Data provider for testGetParameterRow + * + * @return array + */ + public function providerGetParameterRow() + { + $data = array( + 'item_name' => '', + 'item_original_name' => '', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => '', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => 'PROCEDURE', + 'item_type_toggle' => 'FUNCTION', + 'item_original_type' => 'PROCEDURE', + 'item_num_params' => 1, + 'item_param_dir' => array(0 => 'IN'), + 'item_param_name' => array(0 => 'foo'), + 'item_param_type' => array(0 => 'INT'), + 'item_param_length' => array(0 => ''), + 'item_param_opts_num' => array(0 => 'UNSIGNED'), + 'item_param_opts_text' => array(0 => ''), + 'item_returntype' => '', + 'item_isdeterministic' => '', + 'item_securitytype_definer' => '', + 'item_securitytype_invoker' => '', + 'item_sqldataaccess' => '' + ); + + return array( + array( + $data, + 0, + "assertContains( + $matcher, + Routines::getEditorForm('add', '', $data) + ); + } + + /** + * Data provider for testGetEditorForm1 + * + * @return array + */ + public function providerGetEditorForm1() + { + $data = array( + 'item_name' => '', + 'item_original_name' => '', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => '', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => 'PROCEDURE', + 'item_type_toggle' => 'FUNCTION', + 'item_original_type' => 'PROCEDURE', + 'item_num_params' => 0, + 'item_param_dir' => array(), + 'item_param_name' => array(), + 'item_param_type' => array(), + 'item_param_length' => array(), + 'item_param_opts_num' => array(), + 'item_param_opts_text' => array(), + 'item_returntype' => '', + 'item_isdeterministic' => '', + 'item_securitytype_definer' => '', + 'item_securitytype_invoker' => '', + 'item_sqldataaccess' => '' + ); + + return array( + array( + $data, + "assertContains( + $matcher, + Routines::getEditorForm('edit', 'change', $data) + ); + } + + /** + * Data provider for testGetEditorForm2 + * + * @return array + */ + public function providerGetEditorForm2() + { + $data = array( + 'item_name' => 'foo', + 'item_original_name' => 'bar', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT 1', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => 'PROCEDURE', + 'item_type_toggle' => 'FUNCTION', + 'item_original_type' => 'PROCEDURE', + 'item_num_params' => 1, + 'item_param_dir' => array(0 => 'IN'), + 'item_param_name' => array(0 => 'baz'), + 'item_param_type' => array(0 => 'INT'), + 'item_param_length' => array(0 => '20'), + 'item_param_opts_num' => array(0 => 'UNSIGNED'), + 'item_param_opts_text' => array(0 => ''), + 'item_returntype' => '', + 'item_isdeterministic' => '', + 'item_securitytype_definer' => '', + 'item_securitytype_invoker' => '', + 'item_sqldataaccess' => 'NO SQL' + ); + + return array( + array( + $data, + "name='edit_item'" + ), + array( + $data, + "name='item_name'" + ), + array( + $data, + "setAjax(true); + Routines::setGlobals(); + $this->assertContains( + $matcher, + Routines::getEditorForm('edit', 'remove', $data) + ); + Response::getInstance()->setAjax(false); + } + + /** + * Data provider for testGetEditorForm3 + * + * @return array + */ + public function providerGetEditorForm3() + { + $data = array( + 'item_name' => 'foo', + 'item_original_name' => 'bar', + 'item_returnlength' => '', + 'item_returnopts_num' => 'UNSIGNED', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT 1', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => 'FUNCTION', + 'item_type_toggle' => 'PROCEDURE', + 'item_original_type' => 'FUNCTION', + 'item_num_params' => 1, + 'item_param_dir' => array(0 => ''), + 'item_param_name' => array(0 => 'baz'), + 'item_param_type' => array(0 => 'INT'), + 'item_param_length' => array(0 => '20'), + 'item_param_opts_num' => array(0 => 'UNSIGNED'), + 'item_param_opts_text' => array(0 => ''), + 'item_returntype' => 'INT', + 'item_isdeterministic' => '', + 'item_securitytype_definer' => '', + 'item_securitytype_invoker' => '', + 'item_sqldataaccess' => 'NO SQL' + ); + + return array( + array( + $data, + "name='edit_item'" + ), + array( + $data, + "name='item_name'" + ), + array( + $data, + "assertContains( + $matcher, + Routines::getExecuteForm($data) + ); + } + + /** + * Data provider for testGetExecuteForm1 + * + * @return array + */ + public function providerGetExecuteForm1() + { + $data = array( + 'item_name' => 'foo', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT 1;', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => 'PROCEDURE', + 'item_num_params' => 6, + 'item_param_dir' => array( + 0 => 'IN', + 1 => 'OUT', + 2 => 'IN', + 3 => 'IN', + 4 => 'IN', + 5 => 'IN' + ), + 'item_param_name' => array( + 0 => 'foo', + 1 => 'foa', + 2 => 'fob', + 3 => 'foc', + 4 => 'fod', + 5 => 'foe' + ), + 'item_param_type' => array( + 0 => 'DATE', + 1 => 'VARCHAR', + 2 => 'DATETIME', + 3 => 'GEOMETRY', + 4 => 'ENUM', + 5 => 'SET' + ), + 'item_param_length' => array( + 0 => '', + 1 => '22', + 2 => '', + 3 => '', + 4 => "'a','b'", + 5 => "'a','b'" + ), + 'item_param_length_arr' => array( + 0 => array(), + 1 => array('22'), + 2 => array(), + 3 => array(), + 4 => array("'a'", "'b'"), + 5 => array("'a'", "'b'") + ), + 'item_param_opts_num' => array( + 0 => '', + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '' + ), + 'item_param_opts_text' => array( + 0 => '', + 1 => 'utf8', + 2 => '', + 3 => '', + 4 => '', + 5 => '' + ), + 'item_returntype' => '', + 'item_isdeterministic' => '', + 'item_securitytype_definer' => '', + 'item_securitytype_invoker' => '', + 'item_sqldataaccess' => '' + ); + + return array( + array( + $data, + "name='item_name'" + ), + array( + $data, + "name='funcs[foo]'" + ), + array( + $data, + "" + ), + array( + $data, + "name='funcs[fob]'" + ), + array( + $data, + "setAjax(true); + Routines::setGlobals(); + $this->assertContains( + $matcher, + Routines::getExecuteForm($data) + ); + Response::getInstance()->setAjax(false); + } + + /** + * Data provider for testGetExecuteForm2 + * + * @return array + */ + public function providerGetExecuteForm2() + { + $data = array( + 'item_name' => 'foo', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT 1;', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => 'PROCEDURE', + 'item_num_params' => 6, + 'item_param_dir' => array( + 0 => 'IN', + 1 => 'OUT', + 2 => 'IN', + 3 => 'IN', + 4 => 'IN', + 5 => 'IN' + ), + 'item_param_name' => array( + 0 => 'foo', + 1 => 'foa', + 2 => 'fob', + 3 => 'foc', + 4 => 'fod', + 5 => 'foe' + ), + 'item_param_type' => array( + 0 => 'DATE', + 1 => 'VARCHAR', + 2 => 'DATETIME', + 3 => 'GEOMETRY', + 4 => 'ENUM', + 5 => 'SET' + ), + 'item_param_length' => array( + 0 => '', + 1 => '22', + 2 => '', + 3 => '', + 4 => "'a','b'", + 5 => "'a','b'" + ), + 'item_param_length_arr' => array( + 0 => array(), + 1 => array('22'), + 2 => array(), + 3 => array(), + 4 => array("'a'", "'b'"), + 5 => array("'a'", "'b'") + ), + 'item_param_opts_num' => array( + 0 => '', + 1 => '', + 2 => '', + 3 => '', + 4 => '', + 5 => '' + ), + 'item_param_opts_text' => array( + 0 => '', + 1 => 'utf8', + 2 => '', + 3 => '', + 4 => '', + 5 => '' + ), + 'item_returntype' => '', + 'item_isdeterministic' => '', + 'item_securitytype_definer' => '', + 'item_securitytype_invoker' => '', + 'item_sqldataaccess' => '' + ); + + return array( + array( + $data, + "name='execute_routine'" + ), + array( + $data, + "name='ajax_request'" + ), + ); + } + + /** + * Test for Routines::getQueryFromRequest + * + * @param array $request Request + * @param string $query Query + * @param int $num_err Error number + * + * @return void + * + * @dataProvider providerGetQueryFromRequest + */ + public function testGetQueryFromRequest($request, $query, $num_err) + { + global $_REQUEST, $errors, $cfg; + + $cfg['ShowFunctionFields'] = false; + + $GLOBALS['PMA_Types'] = new TypesMySQL(); + + $errors = array(); + Routines::setGlobals(); + + $old_dbi = isset($GLOBALS['dbi']) ? $GLOBALS['dbi'] : null; + $dbi = $this->getMockBuilder('PhpMyAdmin\DatabaseInterface') + ->disableOriginalConstructor() + ->getMock(); + $dbi->expects($this->any()) + ->method('escapeString') + ->will( + $this->returnValueMap( + array( + array('foo', null, 'foo'), + array("foo's bar", null, "foo\'s bar"), + array('', null, '') + ) + ) + ); + $GLOBALS['dbi'] = $dbi; + + unset($_REQUEST); + $_REQUEST = $request; + $this->assertEquals($query, Routines::getQueryFromRequest()); + $this->assertEquals($num_err, count($errors)); + + // reset + $GLOBALS['dbi'] = $old_dbi; + } + + /** + * Data provider for testGetQueryFromRequest + * + * @return array + */ + public function providerGetQueryFromRequest() + { + return array( + // Testing success + array( + array( + 'item_name' => 'p r o c', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT 0;', + 'item_comment' => 'foo', + 'item_definer' => 'me@home', + 'item_type' => 'PROCEDURE', + 'item_num_params' => '0', + 'item_param_dir' => '', + 'item_param_name' => '', + 'item_param_type' => '', + 'item_param_length' => '', + 'item_param_opts_num' => '', + 'item_param_opts_text' => '', + 'item_returntype' => '', + 'item_isdeterministic' => '', + 'item_securitytype' => 'INVOKER', + 'item_sqldataaccess' => 'NO SQL' + ), + 'CREATE DEFINER=`me`@`home` PROCEDURE `p r o c`() COMMENT \'foo\' ' + . 'DETERMINISTIC NO SQL SQL SECURITY INVOKER SELECT 0;', + 0 + ), + array( + array( + 'item_name' => 'pr``oc', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT \'foobar\';', + 'item_comment' => '', + 'item_definer' => 'someuser@somehost', + 'item_type' => 'PROCEDURE', + 'item_num_params' => '2', + 'item_param_dir' => array('IN', 'INOUT'), + 'item_param_name' => array('pa`ram', 'par 2'), + 'item_param_type' => array('INT', 'ENUM'), + 'item_param_length' => array('10', '\'a\', \'b\''), + 'item_param_opts_num' => array('ZEROFILL', ''), + 'item_param_opts_text' => array('utf8', 'latin1'), + 'item_returntype' => '', + 'item_securitytype' => 'DEFINER', + 'item_sqldataaccess' => 'foobar' + ), + 'CREATE DEFINER=`someuser`@`somehost` PROCEDURE `pr````oc`' + . '(IN `pa``ram` INT(10) ZEROFILL, INOUT `par 2` ENUM(\'a\', \'b\')' + . ' CHARSET latin1) NOT DETERMINISTIC SQL SECURITY DEFINER SELECT ' + . '\'foobar\';', + 0 + ), + array( + array( + 'item_name' => 'func\\', + 'item_returnlength' => '5,5', + 'item_returnopts_num' => 'UNSIGNED ZEROFILL', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT \'foobar\';', + 'item_comment' => 'foo\'s bar', + 'item_definer' => '', + 'item_type' => 'FUNCTION', + 'item_num_params' => '1', + 'item_param_dir' => '', + 'item_param_name' => array('pa`ram'), + 'item_param_type' => array('VARCHAR'), + 'item_param_length' => array('45'), + 'item_param_opts_num' => array(''), + 'item_param_opts_text' => array('latin1'), + 'item_returntype' => 'DECIMAL', + 'item_isdeterministic' => 'ON', + 'item_securitytype' => 'DEFINER', + 'item_sqldataaccess' => 'READ SQL DATA' + ), + 'CREATE FUNCTION `func\\`(`pa``ram` VARCHAR(45) CHARSET latin1) ' + . 'RETURNS DECIMAL(5,5) UNSIGNED ZEROFILL COMMENT \'foo\\\'s bar\' ' + . 'DETERMINISTIC SQL SECURITY DEFINER SELECT \'foobar\';', + 0 + ), + array( + array( + 'item_name' => 'func', + 'item_returnlength' => '20', + 'item_returnopts_num' => '', + 'item_returnopts_text' => 'utf8', + 'item_definition' => 'SELECT 0;', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => 'FUNCTION', + 'item_num_params' => '1', + 'item_returntype' => 'VARCHAR', + 'item_securitytype' => 'DEFINER', + 'item_sqldataaccess' => 'READ SQL DATA' + ), + 'CREATE FUNCTION `func`() RETURNS VARCHAR(20) CHARSET utf8 NOT ' + . 'DETERMINISTIC SQL SECURITY DEFINER SELECT 0;', + 0 + ), + // Testing failures + array( + array( + ), + 'CREATE () NOT DETERMINISTIC ', // invalid query + 3 + ), + array( + array( + 'item_name' => 'proc', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT 0;', + 'item_comment' => 'foo', + 'item_definer' => 'mehome', // invalid definer format + 'item_type' => 'PROCEDURE', + 'item_num_params' => '0', + 'item_param_dir' => '', + 'item_param_name' => '', + 'item_param_type' => '', + 'item_param_length' => '', + 'item_param_opts_num' => '', + 'item_param_opts_text' => '', + 'item_returntype' => '', + 'item_isdeterministic' => '', + 'item_securitytype' => 'INVOKER', + 'item_sqldataaccess' => 'NO SQL' + ), + 'CREATE PROCEDURE `proc`() COMMENT \'foo\' DETERMINISTIC ' + . 'NO SQL SQL SECURITY INVOKER SELECT 0;', // valid query + 1 + ), + array( + array( + 'item_name' => 'proc', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT 0;', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => 'PROCEDURE', + 'item_num_params' => '2', + 'item_param_dir' => array('FAIL', 'INOUT'), // invalid direction + 'item_param_name' => array('pa`ram', 'goo'), + 'item_param_type' => array('INT', 'ENUM'), + 'item_param_length' => array('10', ''), // missing ENUM values + 'item_param_opts_num' => array('ZEROFILL', ''), + 'item_param_opts_text' => array('utf8', 'latin1'), + 'item_returntype' => '', + 'item_securitytype' => 'DEFINER', + 'item_sqldataaccess' => 'foobar' // invalid, will just be ignored without throwing errors + ), + 'CREATE PROCEDURE `proc`((10) ZEROFILL, ' + . 'INOUT `goo` ENUM CHARSET latin1) NOT DETERMINISTIC ' + . 'SQL SECURITY DEFINER SELECT 0;', // invalid query + 2 + ), + array( + array( + 'item_name' => 'func', + 'item_returnlength' => '', // missing length for VARCHAR + 'item_returnopts_num' => '', + 'item_returnopts_text' => 'utf8', + 'item_definition' => 'SELECT 0;', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => 'FUNCTION', + 'item_num_params' => '2', + 'item_param_dir' => array('IN'), + 'item_param_name' => array(''), // missing name + 'item_param_type' => array('INT'), + 'item_param_length' => array('10'), + 'item_param_opts_num' => array('ZEROFILL'), + 'item_param_opts_text' => array('latin1'), + 'item_returntype' => 'VARCHAR', + 'item_securitytype' => 'DEFINER', + 'item_sqldataaccess' => '' + ), + 'CREATE FUNCTION `func`() RETURNS VARCHAR CHARSET utf8 NOT ' + . 'DETERMINISTIC SQL SECURITY DEFINER SELECT 0;', // invalid query + 2 + ), + array( + array( + 'item_name' => 'func', + 'item_returnlength' => '', + 'item_returnopts_num' => '', + 'item_returnopts_text' => '', + 'item_definition' => 'SELECT 0;', + 'item_comment' => '', + 'item_definer' => '', + 'item_type' => 'FUNCTION', + 'item_num_params' => '0', + 'item_returntype' => 'FAIL', // invalid return type + 'item_securitytype' => 'DEFINER', + 'item_sqldataaccess' => '' + ), + 'CREATE FUNCTION `func`() NOT DETERMINISTIC SQL ' + . 'SECURITY DEFINER SELECT 0;', // invalid query + 1 + ), + ); + } +} diff --git a/test/libraries/rte/PMA_RTN_getDataFromRequest_test.php b/test/libraries/rte/PMA_RTN_getDataFromRequest_test.php deleted file mode 100644 index f940c1ccd6..0000000000 --- a/test/libraries/rte/PMA_RTN_getDataFromRequest_test.php +++ /dev/null @@ -1,226 +0,0 @@ - $value) { - if ($value !== '') { - $_REQUEST[$key] = $value; - } - } - PMA_RTN_setGlobals(); - $this->assertEquals($out, PMA_RTN_getDataFromRequest()); - } - - /** - * Data provider for testgetDataFromRequest - * - * @return array - */ - public function provider() - { - return array( - array( - array( - 'item_name' => '', - 'item_original_name' => '', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => '', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => '', - 'item_type_toggle' => '', - 'item_original_type' => '', - 'item_param_dir' => '', - 'item_param_name' => '', - 'item_param_type' => '', - 'item_param_length' => '', - 'item_param_opts_num' => '', - 'item_param_opts_text' => '', - 'item_returntype' => '', - 'item_isdeterministic' => '', - 'item_securitytype' => '', - 'item_sqldataaccess' => '' - ), - array( - 'item_name' => '', - 'item_original_name' => '', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => '', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => 'PROCEDURE', - 'item_type_toggle' => 'FUNCTION', - 'item_original_type' => 'PROCEDURE', - 'item_num_params' => 0, - 'item_param_dir' => array(), - 'item_param_name' => array(), - 'item_param_type' => array(), - 'item_param_length' => array(), - 'item_param_opts_num' => array(), - 'item_param_opts_text' => array(), - 'item_returntype' => '', - 'item_isdeterministic' => '', - 'item_securitytype_definer' => '', - 'item_securitytype_invoker' => '', - 'item_sqldataaccess' => '' - ) - ), - array( - array( - 'item_name' => 'proc2', - 'item_original_name' => 'proc', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT NULL', - 'item_comment' => 'some text', - 'item_definer' => 'root@localhost', - 'item_type' => 'PROCEDURE', - 'item_type_toggle' => 'FUNCTION', - 'item_original_type' => 'PROCEDURE', - 'item_param_dir' => array(0 => 'IN', 1 => 'FAIL'), - 'item_param_name' => array(0 => 'bar', 1 => 'baz'), - 'item_param_type' => array(0 => 'INT', 1 => 'FAIL'), - 'item_param_length' => array(0 => '20', 1 => ''), - 'item_param_opts_num' => array(0 => 'UNSIGNED', 1 => ''), - 'item_param_opts_text' => array(0 => '', 1 => 'latin1'), - 'item_returntype' => '', - 'item_isdeterministic' => 'ON', - 'item_securitytype' => 'INVOKER', - 'item_sqldataaccess' => 'NO SQL' - ), - array( - 'item_name' => 'proc2', - 'item_original_name' => 'proc', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT NULL', - 'item_comment' => 'some text', - 'item_definer' => 'root@localhost', - 'item_type' => 'PROCEDURE', - 'item_type_toggle' => 'FUNCTION', - 'item_original_type' => 'PROCEDURE', - 'item_num_params' => 2, - 'item_param_dir' => array(0 => 'IN', 1 => ''), - 'item_param_name' => array(0 => 'bar', 1 => 'baz'), - 'item_param_type' => array(0 => 'INT', 1 => ''), - 'item_param_length' => array(0 => '20', 1 => ''), - 'item_param_opts_num' => array(0 => 'UNSIGNED', 1 => ''), - 'item_param_opts_text' => array(0 => '', 1 => 'latin1'), - 'item_returntype' => '', - 'item_isdeterministic' => ' checked=\'checked\'', - 'item_securitytype_definer' => '', - 'item_securitytype_invoker' => ' selected=\'selected\'', - 'item_sqldataaccess' => 'NO SQL' - ) - ), - array( - array( - 'item_name' => 'func2', - 'item_original_name' => 'func', - 'item_returnlength' => '20', - 'item_returnopts_num' => '', - 'item_returnopts_text' => 'CHARSET utf8', - 'item_definition' => 'SELECT NULL', - 'item_comment' => 'some text', - 'item_definer' => 'root@localhost', - 'item_type' => 'FUNCTION', - 'item_type_toggle' => 'PROCEDURE', - 'item_original_type' => 'FUNCTION', - 'item_param_dir' => array(0 => '', 1 => ''), - 'item_param_name' => array(0 => 'bar', 1 => 'baz'), - 'item_param_type' => array( - 0 => 'XSS', - 1 => 'TEXT' - ), - 'item_param_length' => array(0 => '10,10', 1 => ''), - 'item_param_opts_num' => array(0 => 'UNSIGNED', 1 => ''), - 'item_param_opts_text' => array(0 => '', 1 => 'utf8'), - 'item_returntype' => 'VARCHAR', - 'item_isdeterministic' => '', - 'item_securitytype' => 'DEFINER', - 'item_sqldataaccess' => '' - ), - array( - 'item_name' => 'func2', - 'item_original_name' => 'func', - 'item_returnlength' => '20', - 'item_returnopts_num' => '', - 'item_returnopts_text' => 'CHARSET utf8', - 'item_definition' => 'SELECT NULL', - 'item_comment' => 'some text', - 'item_definer' => 'root@localhost', - 'item_type' => 'FUNCTION', - 'item_type_toggle' => 'PROCEDURE', - 'item_original_type' => 'FUNCTION', - 'item_num_params' => '2', - 'item_param_dir' => array(), - 'item_param_name' => array(0 => 'bar', 1 => 'baz'), - 'item_param_type' => array(0 => '', 1 => 'TEXT'), - 'item_param_length' => array(0 => '10,10', 1 => ''), - 'item_param_opts_num' => array(0 => 'UNSIGNED', 1 => ''), - 'item_param_opts_text' => array(0 => '', 1 => 'utf8'), - 'item_returntype' => 'VARCHAR', - 'item_isdeterministic' => '', - 'item_securitytype_definer' => ' selected=\'selected\'', - 'item_securitytype_invoker' => '', - 'item_sqldataaccess' => '' - ) - ), - ); - } -} diff --git a/test/libraries/rte/PMA_RTN_getEditorForm_test.php b/test/libraries/rte/PMA_RTN_getEditorForm_test.php deleted file mode 100644 index ce62177b02..0000000000 --- a/test/libraries/rte/PMA_RTN_getEditorForm_test.php +++ /dev/null @@ -1,644 +0,0 @@ -getPath(); - - } - - /** - * Test for PMA_RTN_getParameterRow - * - * @return void - */ - public function testgetParameterRowEmpty() - { - PMA_RTN_setGlobals(); - $this->assertEquals('', PMA_RTN_getParameterRow(array(), 0)); - } - - /** - * Test for PMA_RTN_getParameterRow - * - * @param array $data Data for routine - * @param mixed $index Index - * @param array $matcher Matcher - * - * @return void - * - * @depends testgetParameterRowEmpty - * @dataProvider providerRow - */ - public function testgetParameterRow($data, $index, $matcher) - { - PMA_RTN_setGlobals(); - $this->assertContains( - $matcher, - PMA_RTN_getParameterRow($data, $index) - ); - } - - /** - * Data provider for testgetParameterRow - * - * @return array - */ - public function providerRow() - { - $data = array( - 'item_name' => '', - 'item_original_name' => '', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => '', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => 'PROCEDURE', - 'item_type_toggle' => 'FUNCTION', - 'item_original_type' => 'PROCEDURE', - 'item_num_params' => 1, - 'item_param_dir' => array(0 => 'IN'), - 'item_param_name' => array(0 => 'foo'), - 'item_param_type' => array(0 => 'INT'), - 'item_param_length' => array(0 => ''), - 'item_param_opts_num' => array(0 => 'UNSIGNED'), - 'item_param_opts_text' => array(0 => ''), - 'item_returntype' => '', - 'item_isdeterministic' => '', - 'item_securitytype_definer' => '', - 'item_securitytype_invoker' => '', - 'item_sqldataaccess' => '' - ); - - return array( - array( - $data, - 0, - "assertContains( - $matcher, - PMA_RTN_getEditorForm('add', '', $data) - ); - } - - /** - * Data provider for testgetEditorForm1 - * - * @return array - */ - public function providerEditor1() - { - $data = array( - 'item_name' => '', - 'item_original_name' => '', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => '', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => 'PROCEDURE', - 'item_type_toggle' => 'FUNCTION', - 'item_original_type' => 'PROCEDURE', - 'item_num_params' => 0, - 'item_param_dir' => array(), - 'item_param_name' => array(), - 'item_param_type' => array(), - 'item_param_length' => array(), - 'item_param_opts_num' => array(), - 'item_param_opts_text' => array(), - 'item_returntype' => '', - 'item_isdeterministic' => '', - 'item_securitytype_definer' => '', - 'item_securitytype_invoker' => '', - 'item_sqldataaccess' => '' - ); - - return array( - array( - $data, - "assertContains( - $matcher, - PMA_RTN_getEditorForm('edit', 'change', $data) - ); - } - - /** - * Data provider for testgetEditorForm2 - * - * @return array - */ - public function providerEditor2() - { - $data = array( - 'item_name' => 'foo', - 'item_original_name' => 'bar', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT 1', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => 'PROCEDURE', - 'item_type_toggle' => 'FUNCTION', - 'item_original_type' => 'PROCEDURE', - 'item_num_params' => 1, - 'item_param_dir' => array(0 => 'IN'), - 'item_param_name' => array(0 => 'baz'), - 'item_param_type' => array(0 => 'INT'), - 'item_param_length' => array(0 => '20'), - 'item_param_opts_num' => array(0 => 'UNSIGNED'), - 'item_param_opts_text' => array(0 => ''), - 'item_returntype' => '', - 'item_isdeterministic' => '', - 'item_securitytype_definer' => '', - 'item_securitytype_invoker' => '', - 'item_sqldataaccess' => 'NO SQL' - ); - - return array( - array( - $data, - "name='edit_item'" - ), - array( - $data, - "name='item_name'" - ), - array( - $data, - "setAjax(true); - PMA_RTN_setGlobals(); - $this->assertContains( - $matcher, - PMA_RTN_getEditorForm('edit', 'remove', $data) - ); - Response::getInstance()->setAjax(false); - } - - /** - * Data provider for testgetEditorForm3 - * - * @return array - */ - public function providerEditor3() - { - $data = array( - 'item_name' => 'foo', - 'item_original_name' => 'bar', - 'item_returnlength' => '', - 'item_returnopts_num' => 'UNSIGNED', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT 1', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => 'FUNCTION', - 'item_type_toggle' => 'PROCEDURE', - 'item_original_type' => 'FUNCTION', - 'item_num_params' => 1, - 'item_param_dir' => array(0 => ''), - 'item_param_name' => array(0 => 'baz'), - 'item_param_type' => array(0 => 'INT'), - 'item_param_length' => array(0 => '20'), - 'item_param_opts_num' => array(0 => 'UNSIGNED'), - 'item_param_opts_text' => array(0 => ''), - 'item_returntype' => 'INT', - 'item_isdeterministic' => '', - 'item_securitytype_definer' => '', - 'item_securitytype_invoker' => '', - 'item_sqldataaccess' => 'NO SQL' - ); - - return array( - array( - $data, - "name='edit_item'" - ), - array( - $data, - "name='item_name'" - ), - array( - $data, - "assertContains( - $matcher, - PMA_RTN_getExecuteForm($data) - ); - } - - /** - * Data provider for testgetExecuteForm1 - * - * @return array - */ - public function provider1() - { - $data = array( - 'item_name' => 'foo', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT 1;', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => 'PROCEDURE', - 'item_num_params' => 6, - 'item_param_dir' => array( - 0 => 'IN', - 1 => 'OUT', - 2 => 'IN', - 3 => 'IN', - 4 => 'IN', - 5 => 'IN' - ), - 'item_param_name' => array( - 0 => 'foo', - 1 => 'foa', - 2 => 'fob', - 3 => 'foc', - 4 => 'fod', - 5 => 'foe' - ), - 'item_param_type' => array( - 0 => 'DATE', - 1 => 'VARCHAR', - 2 => 'DATETIME', - 3 => 'GEOMETRY', - 4 => 'ENUM', - 5 => 'SET' - ), - 'item_param_length' => array( - 0 => '', - 1 => '22', - 2 => '', - 3 => '', - 4 => "'a','b'", - 5 => "'a','b'" - ), - 'item_param_length_arr' => array( - 0 => array(), - 1 => array('22'), - 2 => array(), - 3 => array(), - 4 => array("'a'", "'b'"), - 5 => array("'a'", "'b'") - ), - 'item_param_opts_num' => array( - 0 => '', - 1 => '', - 2 => '', - 3 => '', - 4 => '', - 5 => '' - ), - 'item_param_opts_text' => array( - 0 => '', - 1 => 'utf8', - 2 => '', - 3 => '', - 4 => '', - 5 => '' - ), - 'item_returntype' => '', - 'item_isdeterministic' => '', - 'item_securitytype_definer' => '', - 'item_securitytype_invoker' => '', - 'item_sqldataaccess' => '' - ); - - return array( - array( - $data, - "name='item_name'" - ), - array( - $data, - "name='funcs[foo]'" - ), - array( - $data, - "" - ), - array( - $data, - "name='funcs[fob]'" - ), - array( - $data, - "setAjax(true); - PMA_RTN_setGlobals(); - $this->assertContains( - $matcher, - PMA_RTN_getExecuteForm($data) - ); - Response::getInstance()->setAjax(false); - } - - /** - * Data provider for testgetExecuteForm2 - * - * @return array - */ - public function provider2() - { - $data = array( - 'item_name' => 'foo', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT 1;', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => 'PROCEDURE', - 'item_num_params' => 6, - 'item_param_dir' => array( - 0 => 'IN', - 1 => 'OUT', - 2 => 'IN', - 3 => 'IN', - 4 => 'IN', - 5 => 'IN' - ), - 'item_param_name' => array( - 0 => 'foo', - 1 => 'foa', - 2 => 'fob', - 3 => 'foc', - 4 => 'fod', - 5 => 'foe' - ), - 'item_param_type' => array( - 0 => 'DATE', - 1 => 'VARCHAR', - 2 => 'DATETIME', - 3 => 'GEOMETRY', - 4 => 'ENUM', - 5 => 'SET' - ), - 'item_param_length' => array( - 0 => '', - 1 => '22', - 2 => '', - 3 => '', - 4 => "'a','b'", - 5 => "'a','b'" - ), - 'item_param_length_arr' => array( - 0 => array(), - 1 => array('22'), - 2 => array(), - 3 => array(), - 4 => array("'a'", "'b'"), - 5 => array("'a'", "'b'") - ), - 'item_param_opts_num' => array( - 0 => '', - 1 => '', - 2 => '', - 3 => '', - 4 => '', - 5 => '' - ), - 'item_param_opts_text' => array( - 0 => '', - 1 => 'utf8', - 2 => '', - 3 => '', - 4 => '', - 5 => '' - ), - 'item_returntype' => '', - 'item_isdeterministic' => '', - 'item_securitytype_definer' => '', - 'item_securitytype_invoker' => '', - 'item_sqldataaccess' => '' - ); - - return array( - array( - $data, - "name='execute_routine'" - ), - array( - $data, - "name='ajax_request'" - ), - ); - } -} diff --git a/test/libraries/rte/PMA_RTN_getQueryFromRequest_test.php b/test/libraries/rte/PMA_RTN_getQueryFromRequest_test.php deleted file mode 100644 index 684a8024e9..0000000000 --- a/test/libraries/rte/PMA_RTN_getQueryFromRequest_test.php +++ /dev/null @@ -1,290 +0,0 @@ -getMockBuilder('PhpMyAdmin\DatabaseInterface') - ->disableOriginalConstructor() - ->getMock(); - $dbi->expects($this->any()) - ->method('escapeString') - ->will( - $this->returnValueMap( - array( - array('foo', null, 'foo'), - array("foo's bar", null, "foo\'s bar"), - array('', null, '') - ) - ) - ); - $GLOBALS['dbi'] = $dbi; - - unset($_REQUEST); - $_REQUEST = $request; - $this->assertEquals($query, PMA_RTN_getQueryFromRequest()); - $this->assertEquals($num_err, count($errors)); - - // reset - $GLOBALS['dbi'] = $old_dbi; - } - - /** - * Data provider for testgetQueryFromRequest - * - * @return array - */ - public function provider() - { - return array( - // Testing success - array( - array( - 'item_name' => 'p r o c', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT 0;', - 'item_comment' => 'foo', - 'item_definer' => 'me@home', - 'item_type' => 'PROCEDURE', - 'item_num_params' => '0', - 'item_param_dir' => '', - 'item_param_name' => '', - 'item_param_type' => '', - 'item_param_length' => '', - 'item_param_opts_num' => '', - 'item_param_opts_text' => '', - 'item_returntype' => '', - 'item_isdeterministic' => '', - 'item_securitytype' => 'INVOKER', - 'item_sqldataaccess' => 'NO SQL' - ), - 'CREATE DEFINER=`me`@`home` PROCEDURE `p r o c`() COMMENT \'foo\' ' - . 'DETERMINISTIC NO SQL SQL SECURITY INVOKER SELECT 0;', - 0 - ), - array( - array( - 'item_name' => 'pr``oc', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT \'foobar\';', - 'item_comment' => '', - 'item_definer' => 'someuser@somehost', - 'item_type' => 'PROCEDURE', - 'item_num_params' => '2', - 'item_param_dir' => array('IN', 'INOUT'), - 'item_param_name' => array('pa`ram', 'par 2'), - 'item_param_type' => array('INT', 'ENUM'), - 'item_param_length' => array('10', '\'a\', \'b\''), - 'item_param_opts_num' => array('ZEROFILL', ''), - 'item_param_opts_text' => array('utf8', 'latin1'), - 'item_returntype' => '', - 'item_securitytype' => 'DEFINER', - 'item_sqldataaccess' => 'foobar' - ), - 'CREATE DEFINER=`someuser`@`somehost` PROCEDURE `pr````oc`' - . '(IN `pa``ram` INT(10) ZEROFILL, INOUT `par 2` ENUM(\'a\', \'b\')' - . ' CHARSET latin1) NOT DETERMINISTIC SQL SECURITY DEFINER SELECT ' - . '\'foobar\';', - 0 - ), - array( - array( - 'item_name' => 'func\\', - 'item_returnlength' => '5,5', - 'item_returnopts_num' => 'UNSIGNED ZEROFILL', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT \'foobar\';', - 'item_comment' => 'foo\'s bar', - 'item_definer' => '', - 'item_type' => 'FUNCTION', - 'item_num_params' => '1', - 'item_param_dir' => '', - 'item_param_name' => array('pa`ram'), - 'item_param_type' => array('VARCHAR'), - 'item_param_length' => array('45'), - 'item_param_opts_num' => array(''), - 'item_param_opts_text' => array('latin1'), - 'item_returntype' => 'DECIMAL', - 'item_isdeterministic' => 'ON', - 'item_securitytype' => 'DEFINER', - 'item_sqldataaccess' => 'READ SQL DATA' - ), - 'CREATE FUNCTION `func\\`(`pa``ram` VARCHAR(45) CHARSET latin1) ' - . 'RETURNS DECIMAL(5,5) UNSIGNED ZEROFILL COMMENT \'foo\\\'s bar\' ' - . 'DETERMINISTIC SQL SECURITY DEFINER SELECT \'foobar\';', - 0 - ), - array( - array( - 'item_name' => 'func', - 'item_returnlength' => '20', - 'item_returnopts_num' => '', - 'item_returnopts_text' => 'utf8', - 'item_definition' => 'SELECT 0;', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => 'FUNCTION', - 'item_num_params' => '1', - 'item_returntype' => 'VARCHAR', - 'item_securitytype' => 'DEFINER', - 'item_sqldataaccess' => 'READ SQL DATA' - ), - 'CREATE FUNCTION `func`() RETURNS VARCHAR(20) CHARSET utf8 NOT ' - . 'DETERMINISTIC SQL SECURITY DEFINER SELECT 0;', - 0 - ), - // Testing failures - array( - array( - ), - 'CREATE () NOT DETERMINISTIC ', // invalid query - 3 - ), - array( - array( - 'item_name' => 'proc', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT 0;', - 'item_comment' => 'foo', - 'item_definer' => 'mehome', // invalid definer format - 'item_type' => 'PROCEDURE', - 'item_num_params' => '0', - 'item_param_dir' => '', - 'item_param_name' => '', - 'item_param_type' => '', - 'item_param_length' => '', - 'item_param_opts_num' => '', - 'item_param_opts_text' => '', - 'item_returntype' => '', - 'item_isdeterministic' => '', - 'item_securitytype' => 'INVOKER', - 'item_sqldataaccess' => 'NO SQL' - ), - 'CREATE PROCEDURE `proc`() COMMENT \'foo\' DETERMINISTIC ' - . 'NO SQL SQL SECURITY INVOKER SELECT 0;', // valid query - 1 - ), - array( - array( - 'item_name' => 'proc', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT 0;', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => 'PROCEDURE', - 'item_num_params' => '2', - 'item_param_dir' => array('FAIL', 'INOUT'), // invalid direction - 'item_param_name' => array('pa`ram', 'goo'), - 'item_param_type' => array('INT', 'ENUM'), - 'item_param_length' => array('10', ''), // missing ENUM values - 'item_param_opts_num' => array('ZEROFILL', ''), - 'item_param_opts_text' => array('utf8', 'latin1'), - 'item_returntype' => '', - 'item_securitytype' => 'DEFINER', - 'item_sqldataaccess' => 'foobar' // invalid, will just be ignored without throwing errors - ), - 'CREATE PROCEDURE `proc`((10) ZEROFILL, ' - . 'INOUT `goo` ENUM CHARSET latin1) NOT DETERMINISTIC ' - . 'SQL SECURITY DEFINER SELECT 0;', // invalid query - 2 - ), - array( - array( - 'item_name' => 'func', - 'item_returnlength' => '', // missing length for VARCHAR - 'item_returnopts_num' => '', - 'item_returnopts_text' => 'utf8', - 'item_definition' => 'SELECT 0;', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => 'FUNCTION', - 'item_num_params' => '2', - 'item_param_dir' => array('IN'), - 'item_param_name' => array(''), // missing name - 'item_param_type' => array('INT'), - 'item_param_length' => array('10'), - 'item_param_opts_num' => array('ZEROFILL'), - 'item_param_opts_text' => array('latin1'), - 'item_returntype' => 'VARCHAR', - 'item_securitytype' => 'DEFINER', - 'item_sqldataaccess' => '' - ), - 'CREATE FUNCTION `func`() RETURNS VARCHAR CHARSET utf8 NOT ' - . 'DETERMINISTIC SQL SECURITY DEFINER SELECT 0;', // invalid query - 2 - ), - array( - array( - 'item_name' => 'func', - 'item_returnlength' => '', - 'item_returnopts_num' => '', - 'item_returnopts_text' => '', - 'item_definition' => 'SELECT 0;', - 'item_comment' => '', - 'item_definer' => '', - 'item_type' => 'FUNCTION', - 'item_num_params' => '0', - 'item_returntype' => 'FAIL', // invalid return type - 'item_securitytype' => 'DEFINER', - 'item_sqldataaccess' => '' - ), - 'CREATE FUNCTION `func`() NOT DETERMINISTIC SQL ' - . 'SECURITY DEFINER SELECT 0;', // invalid query - 1 - ), - ); - } -} From bd81fa1543fbac23cceee0748d1983fca16acbd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 8 Sep 2017 23:19:30 -0300 Subject: [PATCH 8/8] Refactor rte_triggers 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_triggers.php | 5 - libraries/classes/Rte/General.php | 3 +- libraries/classes/Rte/Triggers.php | 478 ++++++++++++++++++ libraries/rte/rte_main.inc.php | 3 +- libraries/rte/rte_triggers.lib.php | 470 ----------------- test/classes/Rte/TriggersTest.php | 390 ++++++++++++++ .../rte/PMA_TRI_getDataFromRequest_test.php | 94 ---- .../rte/PMA_TRI_getEditorForm_test.php | 234 --------- .../rte/PMA_TRI_getQueryFromRequest_test.php | 127 ----- 9 files changed, 872 insertions(+), 932 deletions(-) create mode 100644 libraries/classes/Rte/Triggers.php delete mode 100644 libraries/rte/rte_triggers.lib.php create mode 100644 test/classes/Rte/TriggersTest.php delete mode 100644 test/libraries/rte/PMA_TRI_getDataFromRequest_test.php delete mode 100644 test/libraries/rte/PMA_TRI_getEditorForm_test.php delete mode 100644 test/libraries/rte/PMA_TRI_getQueryFromRequest_test.php diff --git a/db_triggers.php b/db_triggers.php index a415fb43d0..cdd0ebe81c 100644 --- a/db_triggers.php +++ b/db_triggers.php @@ -11,11 +11,6 @@ */ require_once 'libraries/common.inc.php'; -/** - * Include all other files - */ -require_once 'libraries/rte/rte_triggers.lib.php'; - /** * Do the magic */ diff --git a/libraries/classes/Rte/General.php b/libraries/classes/Rte/General.php index 028c3618ba..c4170715bf 100644 --- a/libraries/classes/Rte/General.php +++ b/libraries/classes/Rte/General.php @@ -10,6 +10,7 @@ namespace PhpMyAdmin\Rte; use PhpMyAdmin\Message; use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Events; +use PhpMyAdmin\Rte\Triggers; use PhpMyAdmin\Rte\Words; use PhpMyAdmin\Util; @@ -67,7 +68,7 @@ class General if ($item !== false) { // Show form if ($type == 'TRI') { - $editor = PMA_TRI_getEditorForm($mode, $item); + $editor = Triggers::getEditorForm($mode, $item); } else { // EVN $editor = Events::getEditorForm($mode, $operation, $item); } diff --git a/libraries/classes/Rte/Triggers.php b/libraries/classes/Rte/Triggers.php new file mode 100644 index 0000000000..234802e2cd --- /dev/null +++ b/libraries/classes/Rte/Triggers.php @@ -0,0 +1,478 @@ +getTriggers($db, $table); + echo RteList::get('trigger', $items); + /** + * Display a link for adding a new trigger, + * if the user has the necessary privileges + */ + echo Footer::triggers(); + } // end self::main() + + /** + * Handles editor requests for adding or editing an item + * + * @return void + */ + public static function handleEditor() + { + global $_REQUEST, $_POST, $errors, $db, $table; + + if (! empty($_REQUEST['editor_process_add']) + || ! empty($_REQUEST['editor_process_edit']) + ) { + $sql_query = ''; + + $item_query = self::getQueryFromRequest(); + + if (! count($errors)) { // set by PhpMyAdmin\Rte\Routines::getQueryFromRequest() + // Execute the created query + if (! empty($_REQUEST['editor_process_edit'])) { + // Backup the old trigger, in case something goes wrong + $trigger = self::getDataFromName($_REQUEST['item_original_name']); + $create_item = $trigger['create']; + $drop_item = $trigger['drop'] . ';'; + $result = $GLOBALS['dbi']->tryQuery($drop_item); + if (! $result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($drop_item) + ) + . '
' + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + } else { + $result = $GLOBALS['dbi']->tryQuery($item_query); + if (! $result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($item_query) + ) + . '
' + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + // We dropped the old item, but were unable to create the + // new one. Try to restore the backup query. + $result = $GLOBALS['dbi']->tryQuery($create_item); + + $errors = General::checkResult( + $result, + __( + 'Sorry, we failed to restore the dropped trigger.' + ), + $create_item, + $errors + ); + } else { + $message = Message::success( + __('Trigger %1$s has been modified.') + ); + $message->addParam( + Util::backquote($_REQUEST['item_name']) + ); + $sql_query = $drop_item . $item_query; + } + } + } else { + // 'Add a new item' mode + $result = $GLOBALS['dbi']->tryQuery($item_query); + if (! $result) { + $errors[] = sprintf( + __('The following query has failed: "%s"'), + htmlspecialchars($item_query) + ) + . '

' + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + } else { + $message = Message::success( + __('Trigger %1$s has been created.') + ); + $message->addParam( + Util::backquote($_REQUEST['item_name']) + ); + $sql_query = $item_query; + } + } + } + + if (count($errors)) { + $message = Message::error( + '' + . __( + 'One or more errors have occurred while processing your request:' + ) + . '' + ); + $message->addHtml('
    '); + foreach ($errors as $string) { + $message->addHtml('
  • ' . $string . '
  • '); + } + $message->addHtml('
'); + } + + $output = Util::getMessage($message, $sql_query); + $response = Response::getInstance(); + if ($response->isAjax()) { + if ($message->isSuccess()) { + $items = $GLOBALS['dbi']->getTriggers($db, $table, ''); + $trigger = false; + foreach ($items as $value) { + if ($value['name'] == $_REQUEST['item_name']) { + $trigger = $value; + } + } + $insert = false; + if (empty($table) + || ($trigger !== false && $table == $trigger['table']) + ) { + $insert = true; + $response->addJSON('new_row', RteList::getTriggerRow($trigger)); + $response->addJSON( + 'name', + htmlspecialchars( + mb_strtoupper( + $_REQUEST['item_name'] + ) + ) + ); + } + $response->addJSON('insert', $insert); + $response->addJSON('message', $output); + } else { + $response->addJSON('message', $message); + $response->setRequestStatus(false); + } + exit; + } + } + + /** + * Display a form used to add/edit a trigger, if necessary + */ + if (count($errors) + || (empty($_REQUEST['editor_process_add']) + && empty($_REQUEST['editor_process_edit']) + && (! empty($_REQUEST['add_item']) + || ! empty($_REQUEST['edit_item']))) // FIXME: this must be simpler than that + ) { + // Get the data for the form (if any) + if (! empty($_REQUEST['add_item'])) { + $title = Words::get('add'); + $item = self::getDataFromRequest(); + $mode = 'add'; + } else if (! empty($_REQUEST['edit_item'])) { + $title = __("Edit trigger"); + if (! empty($_REQUEST['item_name']) + && empty($_REQUEST['editor_process_edit']) + ) { + $item = self::getDataFromName($_REQUEST['item_name']); + if ($item !== false) { + $item['item_original_name'] = $item['item_name']; + } + } else { + $item = self::getDataFromRequest(); + } + $mode = 'edit'; + } + General::sendEditor('TRI', $mode, $item, $title, $db); + } + } // end self::handleEditor() + + /** + * This function will generate the values that are required to for the editor + * + * @return array Data necessary to create the editor. + */ + public static function getDataFromRequest() + { + $retval = array(); + $indices = array('item_name', + 'item_table', + 'item_original_name', + 'item_action_timing', + 'item_event_manipulation', + 'item_definition', + 'item_definer'); + foreach ($indices as $index) { + $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : ''; + } + return $retval; + } // end self::getDataFromRequest() + + /** + * This function will generate the values that are required to complete + * the "Edit trigger" form given the name of a trigger. + * + * @param string $name The name of the trigger. + * + * @return array Data necessary to create the editor. + */ + public static function getDataFromName($name) + { + global $db, $table, $_REQUEST; + + $temp = array(); + $items = $GLOBALS['dbi']->getTriggers($db, $table, ''); + foreach ($items as $value) { + if ($value['name'] == $name) { + $temp = $value; + } + } + if (empty($temp)) { + return false; + } else { + $retval = array(); + $retval['create'] = $temp['create']; + $retval['drop'] = $temp['drop']; + $retval['item_name'] = $temp['name']; + $retval['item_table'] = $temp['table']; + $retval['item_action_timing'] = $temp['action_timing']; + $retval['item_event_manipulation'] = $temp['event_manipulation']; + $retval['item_definition'] = $temp['definition']; + $retval['item_definer'] = $temp['definer']; + return $retval; + } + } // end self::getDataFromName() + + /** + * Displays a form used to add/edit a trigger + * + * @param string $mode If the editor will be used to edit a trigger + * or add a new one: 'edit' or 'add'. + * @param array $item Data for the trigger returned by self::getDataFromRequest() + * or self::getDataFromName() + * + * @return string HTML code for the editor. + */ + public static function getEditorForm($mode, $item) + { + global $db, $table, $event_manipulations, $action_timings; + + $modeToUpper = mb_strtoupper($mode); + $response = Response::getInstance(); + + // Escape special characters + $need_escape = array( + 'item_original_name', + 'item_name', + 'item_definition', + 'item_definer' + ); + foreach ($need_escape as $key => $index) { + $item[$index] = htmlentities($item[$index], ENT_QUOTES, 'UTF-8'); + } + $original_data = ''; + if ($mode == 'edit') { + $original_data = "\n"; + } + $query = "SELECT `TABLE_NAME` FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='" . $GLOBALS['dbi']->escapeString($db) . "' "; + $query .= "AND `TABLE_TYPE`='BASE TABLE'"; + $tables = $GLOBALS['dbi']->fetchResult($query); + + // Create the output + $retval = ""; + $retval .= "\n\n"; + $retval .= "
\n"; + $retval .= "\n"; + $retval .= $original_data; + $retval .= Url::getHiddenInputs($db, $table) . "\n"; + $retval .= "
\n"; + $retval .= "" . __('Details') . "\n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "\n"; + $retval .= "\n"; + $retval .= " \n"; + $retval .= "
" . __('Trigger name') . "\n"; + $retval .= " \n"; + $retval .= " \n"; + $retval .= "
" . _pgettext('Trigger action time', 'Time') . "
" . __('Event') . "
" . __('Definition') . "
" . __('Definer') . "isAjax()) { + $retval .= "\n"; + $retval .= "\n"; + } + $retval .= "\n\n"; + $retval .= "\n\n"; + + return $retval; + } // end self::getEditorForm() + + /** + * Composes the query necessary to create a trigger from an HTTP request. + * + * @return string The CREATE TRIGGER query. + */ + public static function getQueryFromRequest() + { + global $_REQUEST, $db, $errors, $action_timings, $event_manipulations; + + $query = 'CREATE '; + if (! empty($_REQUEST['item_definer'])) { + if (mb_strpos($_REQUEST['item_definer'], '@') !== false + ) { + $arr = explode('@', $_REQUEST['item_definer']); + $query .= 'DEFINER=' . Util::backquote($arr[0]); + $query .= '@' . Util::backquote($arr[1]) . ' '; + } else { + $errors[] = __('The definer must be in the "username@hostname" format!'); + } + } + $query .= 'TRIGGER '; + if (! empty($_REQUEST['item_name'])) { + $query .= Util::backquote($_REQUEST['item_name']) . ' '; + } else { + $errors[] = __('You must provide a trigger name!'); + } + if (! empty($_REQUEST['item_timing']) + && in_array($_REQUEST['item_timing'], $action_timings) + ) { + $query .= $_REQUEST['item_timing'] . ' '; + } else { + $errors[] = __('You must provide a valid timing for the trigger!'); + } + if (! empty($_REQUEST['item_event']) + && in_array($_REQUEST['item_event'], $event_manipulations) + ) { + $query .= $_REQUEST['item_event'] . ' '; + } else { + $errors[] = __('You must provide a valid event for the trigger!'); + } + $query .= 'ON '; + if (! empty($_REQUEST['item_table']) + && in_array($_REQUEST['item_table'], $GLOBALS['dbi']->getTables($db)) + ) { + $query .= Util::backquote($_REQUEST['item_table']); + } else { + $errors[] = __('You must provide a valid table name!'); + } + $query .= ' FOR EACH ROW '; + if (! empty($_REQUEST['item_definition'])) { + $query .= $_REQUEST['item_definition']; + } else { + $errors[] = __('You must provide a trigger definition.'); + } + + return $query; + } // end self::getQueryFromRequest() +} diff --git a/libraries/rte/rte_main.inc.php b/libraries/rte/rte_main.inc.php index 626f0ffcdd..179d63d473 100644 --- a/libraries/rte/rte_main.inc.php +++ b/libraries/rte/rte_main.inc.php @@ -8,6 +8,7 @@ use PhpMyAdmin\Response; use PhpMyAdmin\Rte\Events; use PhpMyAdmin\Rte\Routines; +use PhpMyAdmin\Rte\Triggers; use PhpMyAdmin\Url; if (! defined('PHPMYADMIN')) { @@ -92,7 +93,7 @@ case 'RTN': Routines::main($type); break; case 'TRI': - PMA_TRI_main(); + Triggers::main(); break; case 'EVN': Events::main(); diff --git a/libraries/rte/rte_triggers.lib.php b/libraries/rte/rte_triggers.lib.php deleted file mode 100644 index 644691cd2c..0000000000 --- a/libraries/rte/rte_triggers.lib.php +++ /dev/null @@ -1,470 +0,0 @@ -getTriggers($db, $table); - echo RteList::get('trigger', $items); - /** - * Display a link for adding a new trigger, - * if the user has the necessary privileges - */ - echo Footer::triggers(); -} // end PMA_TRI_main() - -/** - * Handles editor requests for adding or editing an item - * - * @return void - */ -function PMA_TRI_handleEditor() -{ - global $_REQUEST, $_POST, $errors, $db, $table; - - if (! empty($_REQUEST['editor_process_add']) - || ! empty($_REQUEST['editor_process_edit']) - ) { - $sql_query = ''; - - $item_query = PMA_TRI_getQueryFromRequest(); - - if (! count($errors)) { // set by PhpMyAdmin\Rte\Routines::getQueryFromRequest() - // Execute the created query - if (! empty($_REQUEST['editor_process_edit'])) { - // Backup the old trigger, in case something goes wrong - $trigger = PMA_TRI_getDataFromName($_REQUEST['item_original_name']); - $create_item = $trigger['create']; - $drop_item = $trigger['drop'] . ';'; - $result = $GLOBALS['dbi']->tryQuery($drop_item); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($drop_item) - ) - . '
' - . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); - } else { - $result = $GLOBALS['dbi']->tryQuery($item_query); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($item_query) - ) - . '
' - . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); - // We dropped the old item, but were unable to create the - // new one. Try to restore the backup query. - $result = $GLOBALS['dbi']->tryQuery($create_item); - - $errors = General::checkResult( - $result, - __( - 'Sorry, we failed to restore the dropped trigger.' - ), - $create_item, - $errors - ); - } else { - $message = PhpMyAdmin\Message::success( - __('Trigger %1$s has been modified.') - ); - $message->addParam( - PhpMyAdmin\Util::backquote($_REQUEST['item_name']) - ); - $sql_query = $drop_item . $item_query; - } - } - } else { - // 'Add a new item' mode - $result = $GLOBALS['dbi']->tryQuery($item_query); - if (! $result) { - $errors[] = sprintf( - __('The following query has failed: "%s"'), - htmlspecialchars($item_query) - ) - . '

' - . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); - } else { - $message = PhpMyAdmin\Message::success( - __('Trigger %1$s has been created.') - ); - $message->addParam( - PhpMyAdmin\Util::backquote($_REQUEST['item_name']) - ); - $sql_query = $item_query; - } - } - } - - if (count($errors)) { - $message = PhpMyAdmin\Message::error( - '' - . __( - 'One or more errors have occurred while processing your request:' - ) - . '' - ); - $message->addHtml('
    '); - foreach ($errors as $string) { - $message->addHtml('
  • ' . $string . '
  • '); - } - $message->addHtml('
'); - } - - $output = PhpMyAdmin\Util::getMessage($message, $sql_query); - $response = Response::getInstance(); - if ($response->isAjax()) { - if ($message->isSuccess()) { - $items = $GLOBALS['dbi']->getTriggers($db, $table, ''); - $trigger = false; - foreach ($items as $value) { - if ($value['name'] == $_REQUEST['item_name']) { - $trigger = $value; - } - } - $insert = false; - if (empty($table) - || ($trigger !== false && $table == $trigger['table']) - ) { - $insert = true; - $response->addJSON('new_row', RteList::getTriggerRow($trigger)); - $response->addJSON( - 'name', - htmlspecialchars( - mb_strtoupper( - $_REQUEST['item_name'] - ) - ) - ); - } - $response->addJSON('insert', $insert); - $response->addJSON('message', $output); - } else { - $response->addJSON('message', $message); - $response->setRequestStatus(false); - } - exit; - } - } - - /** - * Display a form used to add/edit a trigger, if necessary - */ - if (count($errors) - || (empty($_REQUEST['editor_process_add']) - && empty($_REQUEST['editor_process_edit']) - && (! empty($_REQUEST['add_item']) - || ! empty($_REQUEST['edit_item']))) // FIXME: this must be simpler than that - ) { - // Get the data for the form (if any) - if (! empty($_REQUEST['add_item'])) { - $title = Words::get('add'); - $item = PMA_TRI_getDataFromRequest(); - $mode = 'add'; - } else if (! empty($_REQUEST['edit_item'])) { - $title = __("Edit trigger"); - if (! empty($_REQUEST['item_name']) - && empty($_REQUEST['editor_process_edit']) - ) { - $item = PMA_TRI_getDataFromName($_REQUEST['item_name']); - if ($item !== false) { - $item['item_original_name'] = $item['item_name']; - } - } else { - $item = PMA_TRI_getDataFromRequest(); - } - $mode = 'edit'; - } - General::sendEditor('TRI', $mode, $item, $title, $db); - } -} // end PMA_TRI_handleEditor() - -/** - * This function will generate the values that are required to for the editor - * - * @return array Data necessary to create the editor. - */ -function PMA_TRI_getDataFromRequest() -{ - $retval = array(); - $indices = array('item_name', - 'item_table', - 'item_original_name', - 'item_action_timing', - 'item_event_manipulation', - 'item_definition', - 'item_definer'); - foreach ($indices as $index) { - $retval[$index] = isset($_REQUEST[$index]) ? $_REQUEST[$index] : ''; - } - return $retval; -} // end PMA_TRI_getDataFromRequest() - -/** - * This function will generate the values that are required to complete - * the "Edit trigger" form given the name of a trigger. - * - * @param string $name The name of the trigger. - * - * @return array Data necessary to create the editor. - */ -function PMA_TRI_getDataFromName($name) -{ - global $db, $table, $_REQUEST; - - $temp = array(); - $items = $GLOBALS['dbi']->getTriggers($db, $table, ''); - foreach ($items as $value) { - if ($value['name'] == $name) { - $temp = $value; - } - } - if (empty($temp)) { - return false; - } else { - $retval = array(); - $retval['create'] = $temp['create']; - $retval['drop'] = $temp['drop']; - $retval['item_name'] = $temp['name']; - $retval['item_table'] = $temp['table']; - $retval['item_action_timing'] = $temp['action_timing']; - $retval['item_event_manipulation'] = $temp['event_manipulation']; - $retval['item_definition'] = $temp['definition']; - $retval['item_definer'] = $temp['definer']; - return $retval; - } -} // end PMA_TRI_getDataFromName() - -/** - * Displays a form used to add/edit a trigger - * - * @param string $mode If the editor will be used to edit a trigger - * or add a new one: 'edit' or 'add'. - * @param array $item Data for the trigger returned by PMA_TRI_getDataFromRequest() - * or PMA_TRI_getDataFromName() - * - * @return string HTML code for the editor. - */ -function PMA_TRI_getEditorForm($mode, $item) -{ - global $db, $table, $event_manipulations, $action_timings; - - $modeToUpper = mb_strtoupper($mode); - $response = Response::getInstance(); - - // Escape special characters - $need_escape = array( - 'item_original_name', - 'item_name', - 'item_definition', - 'item_definer' - ); - foreach ($need_escape as $key => $index) { - $item[$index] = htmlentities($item[$index], ENT_QUOTES, 'UTF-8'); - } - $original_data = ''; - if ($mode == 'edit') { - $original_data = "\n"; - } - $query = "SELECT `TABLE_NAME` FROM `INFORMATION_SCHEMA`.`TABLES` "; - $query .= "WHERE `TABLE_SCHEMA`='" . $GLOBALS['dbi']->escapeString($db) . "' "; - $query .= "AND `TABLE_TYPE`='BASE TABLE'"; - $tables = $GLOBALS['dbi']->fetchResult($query); - - // Create the output - $retval = ""; - $retval .= "\n\n"; - $retval .= "
\n"; - $retval .= "\n"; - $retval .= $original_data; - $retval .= Url::getHiddenInputs($db, $table) . "\n"; - $retval .= "
\n"; - $retval .= "" . __('Details') . "\n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "\n"; - $retval .= "\n"; - $retval .= " \n"; - $retval .= "
" . __('Trigger name') . "\n"; - $retval .= " \n"; - $retval .= " \n"; - $retval .= "
" . _pgettext('Trigger action time', 'Time') . "
" . __('Event') . "
" . __('Definition') . "
" . __('Definer') . "isAjax()) { - $retval .= "\n"; - $retval .= "\n"; - } - $retval .= "\n\n"; - $retval .= "\n\n"; - - return $retval; -} // end PMA_TRI_getEditorForm() - -/** - * Composes the query necessary to create a trigger from an HTTP request. - * - * @return string The CREATE TRIGGER query. - */ -function PMA_TRI_getQueryFromRequest() -{ - global $_REQUEST, $db, $errors, $action_timings, $event_manipulations; - - $query = 'CREATE '; - if (! empty($_REQUEST['item_definer'])) { - if (mb_strpos($_REQUEST['item_definer'], '@') !== false - ) { - $arr = explode('@', $_REQUEST['item_definer']); - $query .= 'DEFINER=' . PhpMyAdmin\Util::backquote($arr[0]); - $query .= '@' . PhpMyAdmin\Util::backquote($arr[1]) . ' '; - } else { - $errors[] = __('The definer must be in the "username@hostname" format!'); - } - } - $query .= 'TRIGGER '; - if (! empty($_REQUEST['item_name'])) { - $query .= PhpMyAdmin\Util::backquote($_REQUEST['item_name']) . ' '; - } else { - $errors[] = __('You must provide a trigger name!'); - } - if (! empty($_REQUEST['item_timing']) - && in_array($_REQUEST['item_timing'], $action_timings) - ) { - $query .= $_REQUEST['item_timing'] . ' '; - } else { - $errors[] = __('You must provide a valid timing for the trigger!'); - } - if (! empty($_REQUEST['item_event']) - && in_array($_REQUEST['item_event'], $event_manipulations) - ) { - $query .= $_REQUEST['item_event'] . ' '; - } else { - $errors[] = __('You must provide a valid event for the trigger!'); - } - $query .= 'ON '; - if (! empty($_REQUEST['item_table']) - && in_array($_REQUEST['item_table'], $GLOBALS['dbi']->getTables($db)) - ) { - $query .= PhpMyAdmin\Util::backquote($_REQUEST['item_table']); - } else { - $errors[] = __('You must provide a valid table name!'); - } - $query .= ' FOR EACH ROW '; - if (! empty($_REQUEST['item_definition'])) { - $query .= $_REQUEST['item_definition']; - } else { - $errors[] = __('You must provide a trigger definition.'); - } - - return $query; -} // end PMA_TRI_getQueryFromRequest() diff --git a/test/classes/Rte/TriggersTest.php b/test/classes/Rte/TriggersTest.php new file mode 100644 index 0000000000..45db01d1ab --- /dev/null +++ b/test/classes/Rte/TriggersTest.php @@ -0,0 +1,390 @@ + $value) { + if ($value !== '') { + $_REQUEST[$key] = $value; + } + } + $this->assertEquals($out, Triggers::getDataFromRequest()); + } + + /** + * Data provider for testGetDataFromRequestEmpty + * + * @return array + */ + public function providerGetDataFromRequestEmpty() + { + return array( + array( + array( + 'item_name' => '', + 'item_table' => '', + 'item_original_name' => '', + 'item_action_timing' => '', + 'item_event_manipulation' => '', + 'item_definition' => '', + 'item_definer' => '' + ), + array( + 'item_name' => '', + 'item_table' => '', + 'item_original_name' => '', + 'item_action_timing' => '', + 'item_event_manipulation' => '', + 'item_definition' => '', + 'item_definer' => '' + ) + ), + array( + array( + 'item_name' => 'foo', + 'item_table' => 'foo', + 'item_original_name' => 'foo', + 'item_action_timing' => 'foo', + 'item_event_manipulation' => 'foo', + 'item_definition' => 'foo', + 'item_definer' => 'foo' + ), + array( + 'item_name' => 'foo', + 'item_table' => 'foo', + 'item_original_name' => 'foo', + 'item_action_timing' => 'foo', + 'item_event_manipulation' => 'foo', + 'item_definition' => 'foo', + 'item_definer' => 'foo' + ) + ) + ); + } + + /** + * Test for Triggers::getEditorForm + * + * @param array $data Data for trigger + * @param array $matcher Matcher + * + * @return void + * + * @dataProvider providerGetEditorFormAdd + * @group medium + */ + public function testGetEditorFormAdd($data, $matcher) + { + $GLOBALS['server'] = 1; + Triggers::setGlobals(); + $this->assertContains( + $matcher, + Triggers::getEditorForm('add', $data) + ); + } + + /** + * Provider for testGetEditorFormAdd + * + * @return array + */ + public function providerGetEditorFormAdd() + { + $data = array( + 'item_name' => '', + 'item_table' => 'table1', + 'item_original_name' => '', + 'item_action_timing' => '', + 'item_event_manipulation' => '', + 'item_definition' => '', + 'item_definer' => '' + ); + + return array( + array( + $data, + "name='add_item'" + ), + array( + $data, + "name='item_name'" + ), + array( + $data, + "name='item_table'" + ), + array( + $data, + "name='item_timing'" + ), + array( + $data, + "name='item_event'" + ), + array( + $data, + "name='item_definition'" + ), + array( + $data, + "name='item_definer'" + ), + array( + $data, + "name='editor_process_add'" + ) + ); + } + + /** + * Test for Triggers::getEditorForm + * + * @param array $data Data for trigger + * @param array $matcher Matcher + * + * @return void + * + * @dataProvider providerGetEditorFormEdit + * @group medium + */ + public function testGetEditorFormEdit($data, $matcher) + { + $GLOBALS['server'] = 1; + Triggers::setGlobals(); + $this->assertContains( + $matcher, + Triggers::getEditorForm('edit', $data) + ); + } + + /** + * Provider for testGetEditorFormEdit + * + * @return array + */ + public function providerGetEditorFormEdit() + { + $data = array( + 'item_name' => 'foo', + 'item_table' => 'table1', + 'item_original_name' => 'bar', + 'item_action_timing' => 'BEFORE', + 'item_event_manipulation' => 'INSERT', + 'item_definition' => 'SET @A=1;', + 'item_definer' => '' + ); + + return array( + array( + $data, + "name='edit_item'" + ), + array( + $data, + "name='item_name'" + ), + array( + $data, + "name='item_table'" + ), + array( + $data, + "name='item_timing'" + ), + array( + $data, + "name='item_event'" + ), + array( + $data, + "name='item_definition'" + ), + array( + $data, + "name='item_definer'" + ), + array( + $data, + "name='editor_process_edit'" + ) + ); + } + + /** + * Test for Triggers::getEditorForm + * + * @param array $data Data for trigger + * @param array $matcher Matcher + * + * @return void + * + * @dataProvider providerGetEditorFormAjax + */ + public function testGetEditorFormAjax($data, $matcher) + { + $GLOBALS['server'] = 1; + Response::getInstance()->setAjax(true); + Triggers::setGlobals(); + $this->assertContains( + $matcher, + Triggers::getEditorForm('edit', $data) + ); + Response::getInstance()->setAjax(false); + } + + /** + * Provider for testGetEditorFormAjax + * + * @return array + */ + public function providerGetEditorFormAjax() + { + $data = array( + 'item_name' => 'foo', + 'item_table' => 'table1', + 'item_original_name' => 'bar', + 'item_action_timing' => 'BEFORE', + 'item_event_manipulation' => 'INSERT', + 'item_definition' => 'SET @A=1;', + 'item_definer' => '' + ); + + return array( + array( + $data, + "name='editor_process_edit'" + ), + array( + $data, + "name='ajax_request'" + ) + ); + } + + /** + * Test for Triggers::getQueryFromRequest + * + * @param string $definer Definer + * @param string $name Name + * @param string $timing Timing + * @param string $event Event + * @param string $table Table + * @param string $definition Definition + * @param string $query Query + * @param string $num_err Error number + * + * @return void + * + * @dataProvider providerGetQueryFromRequest + */ + public function testGetQueryFromRequest( + $definer, $name, $timing, $event, $table, $definition, $query, $num_err + ) { + global $_REQUEST, $errors; + + $errors = array(); + Triggers::setGlobals(); + + $_REQUEST['item_definer'] = $definer; + $_REQUEST['item_name'] = $name; + $_REQUEST['item_timing'] = $timing; + $_REQUEST['item_event'] = $event; + $_REQUEST['item_table'] = $table; + $_REQUEST['item_definition'] = $definition; + $GLOBALS['server'] = 1; + + $this->assertEquals($query, Triggers::getQueryFromRequest()); + $this->assertEquals($num_err, count($errors)); + } + + /** + * Data provider for testGetQueryFromRequest + * + * @return array + */ + public function providerGetQueryFromRequest() + { + return array( + array('', + '', + '', + '', + '', + '', + 'CREATE TRIGGER ON FOR EACH ROW ', + 5 + ), + array( + 'root', + 'trigger', + 'BEFORE', + 'INSERT', + 'table`2', + 'SET @A=NULL', + 'CREATE TRIGGER `trigger` BEFORE INSERT ON FOR EACH ROW SET @A=NULL', + 2 + ), + array( + 'foo`s@host', + 'trigger`s test', + 'AFTER', + 'foo', + 'table3', + 'BEGIN SET @A=1; SET @B=2; END', + 'CREATE DEFINER=`foo``s`@`host` TRIGGER `trigger``s test` AFTER ON FOR EACH ROW BEGIN SET @A=1; SET @B=2; END', + 2 + ), + array( + 'root@localhost', + 'trigger', + 'BEFORE', + 'INSERT', + 'table1', + 'SET @A=NULL', + 'CREATE DEFINER=`root`@`localhost` TRIGGER `trigger` BEFORE INSERT ON `table1` FOR EACH ROW SET @A=NULL', + 0 + ), + ); + } +} diff --git a/test/libraries/rte/PMA_TRI_getDataFromRequest_test.php b/test/libraries/rte/PMA_TRI_getDataFromRequest_test.php deleted file mode 100644 index d0c320e335..0000000000 --- a/test/libraries/rte/PMA_TRI_getDataFromRequest_test.php +++ /dev/null @@ -1,94 +0,0 @@ - $value) { - if ($value !== '') { - $_REQUEST[$key] = $value; - } - } - $this->assertEquals($out, PMA_TRI_getDataFromRequest()); - } - - /** - * Data provider for testgetDataFromRequestEmpty - * - * @return array - */ - public function provider() - { - return array( - array( - array( - 'item_name' => '', - 'item_table' => '', - 'item_original_name' => '', - 'item_action_timing' => '', - 'item_event_manipulation' => '', - 'item_definition' => '', - 'item_definer' => '' - ), - array( - 'item_name' => '', - 'item_table' => '', - 'item_original_name' => '', - 'item_action_timing' => '', - 'item_event_manipulation' => '', - 'item_definition' => '', - 'item_definer' => '' - ) - ), - array( - array( - 'item_name' => 'foo', - 'item_table' => 'foo', - 'item_original_name' => 'foo', - 'item_action_timing' => 'foo', - 'item_event_manipulation' => 'foo', - 'item_definition' => 'foo', - 'item_definer' => 'foo' - ), - array( - 'item_name' => 'foo', - 'item_table' => 'foo', - 'item_original_name' => 'foo', - 'item_action_timing' => 'foo', - 'item_event_manipulation' => 'foo', - 'item_definition' => 'foo', - 'item_definer' => 'foo' - ) - ) - ); - } -} diff --git a/test/libraries/rte/PMA_TRI_getEditorForm_test.php b/test/libraries/rte/PMA_TRI_getEditorForm_test.php deleted file mode 100644 index fdbd79fb27..0000000000 --- a/test/libraries/rte/PMA_TRI_getEditorForm_test.php +++ /dev/null @@ -1,234 +0,0 @@ -assertContains( - $matcher, - PMA_TRI_getEditorForm('add', $data) - ); - } - - /** - * Provider for testGetEditorFormAdd - * - * @return array - */ - public function providerAdd() - { - $data = array( - 'item_name' => '', - 'item_table' => 'table1', - 'item_original_name' => '', - 'item_action_timing' => '', - 'item_event_manipulation' => '', - 'item_definition' => '', - 'item_definer' => '' - ); - - return array( - array( - $data, - "name='add_item'" - ), - array( - $data, - "name='item_name'" - ), - array( - $data, - "name='item_table'" - ), - array( - $data, - "name='item_timing'" - ), - array( - $data, - "name='item_event'" - ), - array( - $data, - "name='item_definition'" - ), - array( - $data, - "name='item_definer'" - ), - array( - $data, - "name='editor_process_add'" - ) - ); - } - - /** - * Test for PMA_TRI_getEditorForm - * - * @param array $data Data for trigger - * @param array $matcher Matcher - * - * @return void - * - * @dataProvider providerEdit - * @group medium - */ - public function testGetEditorFormEdit($data, $matcher) - { - $GLOBALS['server'] = 1; - PMA_TRI_setGlobals(); - $this->assertContains( - $matcher, - PMA_TRI_getEditorForm('edit', $data) - ); - } - - /** - * Provider for testGetEditorFormEdit - * - * @return array - */ - public function providerEdit() - { - $data = array( - 'item_name' => 'foo', - 'item_table' => 'table1', - 'item_original_name' => 'bar', - 'item_action_timing' => 'BEFORE', - 'item_event_manipulation' => 'INSERT', - 'item_definition' => 'SET @A=1;', - 'item_definer' => '' - ); - - return array( - array( - $data, - "name='edit_item'" - ), - array( - $data, - "name='item_name'" - ), - array( - $data, - "name='item_table'" - ), - array( - $data, - "name='item_timing'" - ), - array( - $data, - "name='item_event'" - ), - array( - $data, - "name='item_definition'" - ), - array( - $data, - "name='item_definer'" - ), - array( - $data, - "name='editor_process_edit'" - ) - ); - } - - /** - * Test for PMA_TRI_getEditorForm - * - * @param array $data Data for trigger - * @param array $matcher Matcher - * - * @return void - * - * @dataProvider providerAjax - */ - public function testGetEditorFormAjax($data, $matcher) - { - $GLOBALS['server'] = 1; - Response::getInstance()->setAjax(true); - PMA_TRI_setGlobals(); - $this->assertContains( - $matcher, - PMA_TRI_getEditorForm('edit', $data) - ); - Response::getInstance()->setAjax(false); - } - - /** - * Provider for testGetEditorFormAjax - * - * @return array - */ - public function providerAjax() - { - $data = array( - 'item_name' => 'foo', - 'item_table' => 'table1', - 'item_original_name' => 'bar', - 'item_action_timing' => 'BEFORE', - 'item_event_manipulation' => 'INSERT', - 'item_definition' => 'SET @A=1;', - 'item_definer' => '' - ); - - return array( - array( - $data, - "name='editor_process_edit'" - ), - array( - $data, - "name='ajax_request'" - ) - ); - } -} diff --git a/test/libraries/rte/PMA_TRI_getQueryFromRequest_test.php b/test/libraries/rte/PMA_TRI_getQueryFromRequest_test.php deleted file mode 100644 index c0169c1c80..0000000000 --- a/test/libraries/rte/PMA_TRI_getQueryFromRequest_test.php +++ /dev/null @@ -1,127 +0,0 @@ -assertEquals($query, PMA_TRI_getQueryFromRequest()); - $this->assertEquals($num_err, count($errors)); - } - - /** - * Data provider for testgetQueryFromRequest - * - * @return array - */ - public function provider() - { - return array( - array('', - '', - '', - '', - '', - '', - 'CREATE TRIGGER ON FOR EACH ROW ', - 5 - ), - array( - 'root', - 'trigger', - 'BEFORE', - 'INSERT', - 'table`2', - 'SET @A=NULL', - 'CREATE TRIGGER `trigger` BEFORE INSERT ON FOR EACH ROW SET @A=NULL', - 2 - ), - array( - 'foo`s@host', - 'trigger`s test', - 'AFTER', - 'foo', - 'table3', - 'BEGIN SET @A=1; SET @B=2; END', - 'CREATE DEFINER=`foo``s`@`host` TRIGGER `trigger``s test` AFTER ON FOR EACH ROW BEGIN SET @A=1; SET @B=2; END', - 2 - ), - array( - 'root@localhost', - 'trigger', - 'BEFORE', - 'INSERT', - 'table1', - 'SET @A=NULL', - 'CREATE DEFINER=`root`@`localhost` TRIGGER `trigger` BEFORE INSERT ON `table1` FOR EACH ROW SET @A=NULL', - 0 - ), - ); - } -}