2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Functions for event management.
8 if (! defined('PHPMYADMIN')) {
13 * Sets required globals
17 function PMA_EVN_setGlobals()
19 global $event_status, $event_type, $event_interval;
21 $event_status = array(
22 'query' => array('ENABLE',
25 'display' => array('ENABLED',
29 $event_type = array('RECURRING',
31 $event_interval = array('YEAR',
49 * Main function for the events functionality
53 function PMA_EVN_main()
59 * Process all requests
61 PMA_EVN_handleEditor();
62 PMA_EVN_handleExport();
64 * Display a list of available events
66 $columns = "`EVENT_NAME`, `EVENT_TYPE`, `STATUS`";
67 $where = "EVENT_SCHEMA='" . PMA_Util
::sqlAddSlashes($db) . "'";
68 $query = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` "
69 . "WHERE $where ORDER BY `EVENT_NAME` ASC;";
70 $items = PMA_DBI_fetch_result($query);
71 echo PMA_RTE_getList('event', $items);
73 * Display a link for adding a new event, if
74 * the user has the privileges and a link to
75 * toggle the state of the event scheduler.
77 echo PMA_EVN_getFooterLinks();
78 } // end PMA_EVN_main()
81 * Handles editor requests for adding or editing an item
85 function PMA_EVN_handleEditor()
87 global $_REQUEST, $_POST, $errors, $db;
89 if (! empty($_REQUEST['editor_process_add'])
90 ||
! empty($_REQUEST['editor_process_edit'])
94 $item_query = PMA_EVN_getQueryFromRequest();
96 if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest()
97 // Execute the created query
98 if (! empty($_REQUEST['editor_process_edit'])) {
99 // Backup the old trigger, in case something goes wrong
100 $create_item = PMA_DBI_get_definition(
103 $_REQUEST['item_original_name']
105 $drop_item = "DROP EVENT "
106 . PMA_Util
::backquote($_REQUEST['item_original_name']) . ";\n";
107 $result = PMA_DBI_try_query($drop_item);
110 __('The following query has failed: "%s"'),
111 htmlspecialchars($drop_item)
114 . __('MySQL said: ') . PMA_DBI_getError(null);
116 $result = PMA_DBI_try_query($item_query);
119 __('The following query has failed: "%s"'),
120 htmlspecialchars($item_query)
123 . __('MySQL said: ') . PMA_DBI_getError(null);
124 // We dropped the old item, but were unable to create
125 // the new one. Try to restore the backup query
126 $result = PMA_DBI_try_query($create_item);
128 // OMG, this is really bad! We dropped the query,
129 // failed to create a new one
130 // and now even the backup query does not execute!
131 // This should not happen, but we better handle
132 // this just in case.
134 'Sorry, we failed to restore the dropped event.'
137 . __('The backed up query was:')
138 . "\"" . htmlspecialchars($create_item) . "\""
140 . __('MySQL said: ') . PMA_DBI_getError(null);
143 $message = PMA_Message
::success(
144 __('Event %1$s has been modified.')
147 PMA_Util
::backquote($_REQUEST['item_name'])
149 $sql_query = $drop_item . $item_query;
153 // 'Add a new item' mode
154 $result = PMA_DBI_try_query($item_query);
157 __('The following query has failed: "%s"'),
158 htmlspecialchars($item_query)
161 . __('MySQL said: ') . PMA_DBI_getError(null);
163 $message = PMA_Message
::success(
164 __('Event %1$s has been created.')
167 PMA_Util
::backquote($_REQUEST['item_name'])
169 $sql_query = $item_query;
174 if (count($errors)) {
175 $message = PMA_Message
::error(__('<b>One or more errors have occured while processing your request:</b>'));
176 $message->addString('<ul>');
177 foreach ($errors as $string) {
178 $message->addString('<li>' . $string . '</li>');
180 $message->addString('</ul>');
183 $output = PMA_Util
::getMessage($message, $sql_query);
184 if ($GLOBALS['is_ajax_request']) {
185 $response = PMA_Response
::getInstance();
186 if ($message->isSuccess()) {
187 $columns = "`EVENT_NAME`, `EVENT_TYPE`, `STATUS`";
188 $where = "EVENT_SCHEMA='" . PMA_Util
::sqlAddSlashes($db) . "' "
190 . PMA_Util
::sqlAddSlashes($_REQUEST['item_name']) . "'";
191 $query = "SELECT " . $columns
192 . " FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE " . $where. ";";
193 $event = PMA_DBI_fetch_single_row($query);
196 htmlspecialchars(strtoupper($_REQUEST['item_name']))
198 $response->addJSON('new_row', PMA_EVN_getRowForList($event));
199 $response->addJSON('insert', ! empty($event));
200 $response->addJSON('message', $output);
202 $response->isSuccess(false);
203 $response->addJSON('message', $message);
209 * Display a form used to add/edit a trigger, if necessary
212 ||
(empty($_REQUEST['editor_process_add'])
213 && empty($_REQUEST['editor_process_edit'])
214 && (! empty($_REQUEST['add_item'])
215 ||
! empty($_REQUEST['edit_item'])
216 ||
! empty($_REQUEST['item_changetype'])))
217 ) { // FIXME: this must be simpler than that
219 if (! empty($_REQUEST['item_changetype'])) {
220 $operation = 'change';
222 // Get the data for the form (if any)
223 if (! empty($_REQUEST['add_item'])) {
224 $title = PMA_RTE_getWord('add');
225 $item = PMA_EVN_getDataFromRequest();
227 } else if (! empty($_REQUEST['edit_item'])) {
228 $title = __("Edit event");
229 if (! empty($_REQUEST['item_name'])
230 && empty($_REQUEST['editor_process_edit'])
231 && empty($_REQUEST['item_changetype'])
233 $item = PMA_EVN_getDataFromName($_REQUEST['item_name']);
234 if ($item !== false) {
235 $item['item_original_name'] = $item['item_name'];
238 $item = PMA_EVN_getDataFromRequest();
242 if ($item !== false) {
244 $editor = PMA_EVN_getEditorForm($mode, $operation, $item);
245 if ($GLOBALS['is_ajax_request']) {
246 $response = PMA_Response
::getInstance();
247 $response->addJSON('message', $editor);
248 $response->addJSON('title', $title);
250 echo "\n\n<h2>$title</h2>\n\n$editor";
255 $message = __('Error in processing request') . ' : ';
257 PMA_RTE_getWord('not_found'),
258 htmlspecialchars(PMA_Util
::backquote($_REQUEST['item_name'])),
259 htmlspecialchars(PMA_Util
::backquote($db))
261 $message = PMA_message
::error($message);
262 if ($GLOBALS['is_ajax_request']) {
263 $response = PMA_Response
::getInstance();
264 $response->isSuccess(false);
265 $response->addJSON('message', $message);
272 } // end PMA_EVN_handleEditor()
275 * This function will generate the values that are required to for the editor
277 * @return array Data necessary to create the editor.
279 function PMA_EVN_getDataFromRequest()
282 $indices = array('item_name',
283 'item_original_name',
286 'item_interval_value',
287 'item_interval_field',
294 foreach ($indices as $index) {
295 $retval[$index] = isset($_REQUEST[$index]) ?
$_REQUEST[$index] : '';
297 $retval['item_type'] = 'ONE TIME';
298 $retval['item_type_toggle'] = 'RECURRING';
299 if (isset($_REQUEST['item_type']) && $_REQUEST['item_type'] == 'RECURRING') {
300 $retval['item_type'] = 'RECURRING';
301 $retval['item_type_toggle'] = 'ONE TIME';
304 } // end PMA_EVN_getDataFromRequest()
307 * This function will generate the values that are required to complete
308 * the "Edit event" form given the name of a event.
310 * @param string $name The name of the event.
312 * @return array Data necessary to create the editor.
314 function PMA_EVN_getDataFromName($name)
319 $columns = "`EVENT_NAME`, `STATUS`, `EVENT_TYPE`, `EXECUTE_AT`, "
320 . "`INTERVAL_VALUE`, `INTERVAL_FIELD`, `STARTS`, `ENDS`, "
321 . "`EVENT_DEFINITION`, `ON_COMPLETION`, `DEFINER`, `EVENT_COMMENT`";
322 $where = "EVENT_SCHEMA='" . PMA_Util
::sqlAddSlashes($db) . "' "
323 . "AND EVENT_NAME='" . PMA_Util
::sqlAddSlashes($name) . "'";
324 $query = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE $where;";
325 $item = PMA_DBI_fetch_single_row($query);
329 $retval['item_name'] = $item['EVENT_NAME'];
330 $retval['item_status'] = $item['STATUS'];
331 $retval['item_type'] = $item['EVENT_TYPE'];
332 if ($retval['item_type'] == 'RECURRING') {
333 $retval['item_type_toggle'] = 'ONE TIME';
335 $retval['item_type_toggle'] = 'RECURRING';
337 $retval['item_execute_at'] = $item['EXECUTE_AT'];
338 $retval['item_interval_value'] = $item['INTERVAL_VALUE'];
339 $retval['item_interval_field'] = $item['INTERVAL_FIELD'];
340 $retval['item_starts'] = $item['STARTS'];
341 $retval['item_ends'] = $item['ENDS'];
342 $retval['item_preserve'] = '';
343 if ($item['ON_COMPLETION'] == 'PRESERVE') {
344 $retval['item_preserve'] = " checked='checked'";
346 $retval['item_definition'] = $item['EVENT_DEFINITION'];
347 $retval['item_definer'] = $item['DEFINER'];
348 $retval['item_comment'] = $item['EVENT_COMMENT'];
351 } // end PMA_EVN_getDataFromName()
354 * Displays a form used to add/edit an event
356 * @param string $mode If the editor will be used edit an event
357 * or add a new one: 'edit' or 'add'.
358 * @param string $operation If the editor was previously invoked with
359 * JS turned off, this will hold the name of
360 * the current operation
361 * @param array $item Data for the event returned by
362 * PMA_EVN_getDataFromRequest() or
363 * PMA_EVN_getDataFromName()
365 * @return string HTML code for the editor.
367 function PMA_EVN_getEditorForm($mode, $operation, $item)
369 global $db, $table, $event_status, $event_type, $event_interval;
371 // Escape special characters
372 $need_escape = array(
373 'item_original_name',
377 'item_interval_value',
384 foreach ($need_escape as $index) {
385 $item[$index] = htmlentities($item[$index], ENT_QUOTES
);
388 if ($mode == 'edit') {
389 $original_data = "<input name='item_original_name' "
390 . "type='hidden' value='{$item['item_original_name']}'/>\n";
392 // Handle some logic first
393 if ($operation == 'change') {
394 if ($item['item_type'] == 'RECURRING') {
395 $item['item_type'] = 'ONE TIME';
396 $item['item_type_toggle'] = 'RECURRING';
398 $item['item_type'] = 'RECURRING';
399 $item['item_type_toggle'] = 'ONE TIME';
402 if ($item['item_type'] == 'ONE TIME') {
403 $isrecurring_class = ' hide';
404 $isonetime_class = '';
406 $isrecurring_class = '';
407 $isonetime_class = ' hide';
411 $retval .= "<!-- START " . strtoupper($mode) . " EVENT FORM -->\n\n";
412 $retval .= "<form class='rte_form' action='db_events.php' method='post'>\n";
413 $retval .= "<input name='{$mode}_item' type='hidden' value='1' />\n";
414 $retval .= $original_data;
415 $retval .= PMA_generate_common_hidden_inputs($db, $table) . "\n";
416 $retval .= "<fieldset>\n";
417 $retval .= "<legend>" . __('Details') . "</legend>\n";
418 $retval .= "<table class='rte_table' style='width: 100%'>\n";
420 $retval .= " <td style='width: 20%;'>" . __('Event name') . "</td>\n";
421 $retval .= " <td><input type='text' name='item_name' \n";
422 $retval .= " value='{$item['item_name']}'\n";
423 $retval .= " maxlength='64' /></td>\n";
424 $retval .= "</tr>\n";
426 $retval .= " <td>" . __('Status') . "</td>\n";
427 $retval .= " <td>\n";
428 $retval .= " <select name='item_status'>\n";
429 foreach ($event_status['display'] as $key => $value) {
431 if (! empty($item['item_status']) && $item['item_status'] == $value) {
432 $selected = " selected='selected'";
434 $retval .= "<option$selected>$value</option>";
436 $retval .= " </select>\n";
437 $retval .= " </td>\n";
438 $retval .= "</tr>\n";
441 $retval .= " <td>" . __('Event type') . "</td>\n";
442 $retval .= " <td>\n";
443 if ($GLOBALS['is_ajax_request']) {
444 $retval .= " <select name='item_type'>";
445 foreach ($event_type as $key => $value) {
447 if (! empty($item['item_type']) && $item['item_type'] == $value) {
448 $selected = " selected='selected'";
450 $retval .= "<option$selected>$value</option>";
452 $retval .= " </select>\n";
454 $retval .= " <input name='item_type' type='hidden' \n";
455 $retval .= " value='{$item['item_type']}' />\n";
456 $retval .= " <div style='width: 49%; float: left; text-align: center;"
457 . " font-weight: bold;'>\n";
458 $retval .= " {$item['item_type']}\n";
459 $retval .= " </div>\n";
460 $retval .= " <input style='width: 49%;' type='submit'\n";
461 $retval .= " name='item_changetype'\n";
462 $retval .= " value='";
463 $retval .= sprintf(__('Change to %s'), $item['item_type_toggle']);
466 $retval .= " </td>\n";
467 $retval .= "</tr>\n";
468 $retval .= "<tr class='onetime_event_row $isonetime_class'>\n";
469 $retval .= " <td>" . __('Execute at') . "</td>\n";
470 $retval .= " <td class='nowrap'>\n";
471 $retval .= " <input type='text' name='item_execute_at'\n";
472 $retval .= " value='{$item['item_execute_at']}'\n";
473 $retval .= " class='datetimefield' />\n";
474 $retval .= " </td>\n";
475 $retval .= "</tr>\n";
476 $retval .= "<tr class='recurring_event_row $isrecurring_class'>\n";
477 $retval .= " <td>" . __('Execute every') . "</td>\n";
478 $retval .= " <td>\n";
479 $retval .= " <input style='width: 49%;' type='text'\n";
480 $retval .= " name='item_interval_value'\n";
481 $retval .= " value='{$item['item_interval_value']}' />\n";
482 $retval .= " <select style='width: 49%;' name='item_interval_field'>";
483 foreach ($event_interval as $key => $value) {
485 if (! empty($item['item_interval_field'])
486 && $item['item_interval_field'] == $value
488 $selected = " selected='selected'";
490 $retval .= "<option$selected>$value</option>";
492 $retval .= " </select>\n";
493 $retval .= " </td>\n";
494 $retval .= "</tr>\n";
495 $retval .= "<tr class='recurring_event_row$isrecurring_class'>\n";
496 $retval .= " <td>" . _pgettext('Start of recurring event', 'Start');
497 $retval .= " </td>\n";
498 $retval .= " <td class='nowrap'>\n";
499 $retval .= " <input type='text'\n name='item_starts'\n";
500 $retval .= " value='{$item['item_starts']}'\n";
501 $retval .= " class='datetimefield' />\n";
502 $retval .= " </td>\n";
503 $retval .= "</tr>\n";
504 $retval .= "<tr class='recurring_event_row$isrecurring_class'>\n";
505 $retval .= " <td>" . _pgettext('End of recurring event', 'End') . "</td>\n";
506 $retval .= " <td class='nowrap'>\n";
507 $retval .= " <input type='text' name='item_ends'\n";
508 $retval .= " value='{$item['item_ends']}'\n";
509 $retval .= " class='datetimefield' />\n";
510 $retval .= " </td>\n";
511 $retval .= "</tr>\n";
513 $retval .= " <td>" . __('Definition') . "</td>\n";
514 $retval .= " <td><textarea name='item_definition' rows='15' cols='40'>";
515 $retval .= $item['item_definition'];
516 $retval .= "</textarea></td>\n";
517 $retval .= "</tr>\n";
519 $retval .= " <td>" . __('On completion preserve') . "</td>\n";
520 $retval .= " <td><input type='checkbox'\n";
521 $retval .= " name='item_preserve'{$item['item_preserve']} /></td>\n";
522 $retval .= "</tr>\n";
524 $retval .= " <td>" . __('Definer') . "</td>\n";
525 $retval .= " <td><input type='text' name='item_definer'\n";
526 $retval .= " value='{$item['item_definer']}' /></td>\n";
527 $retval .= "</tr>\n";
529 $retval .= " <td>" . __('Comment') . "</td>\n";
530 $retval .= " <td><input type='text' name='item_comment' maxlength='64'\n";
531 $retval .= " value='{$item['item_comment']}' /></td>\n";
532 $retval .= "</tr>\n";
533 $retval .= "</table>\n";
534 $retval .= "</fieldset>\n";
535 if ($GLOBALS['is_ajax_request']) {
536 $retval .= "<input type='hidden' name='editor_process_{$mode}'\n";
537 $retval .= " value='true' />\n";
538 $retval .= "<input type='hidden' name='ajax_request' value='true' />\n";
540 $retval .= "<fieldset class='tblFooters'>\n";
541 $retval .= " <input type='submit' name='editor_process_{$mode}'\n";
542 $retval .= " value='" . __('Go') . "' />\n";
543 $retval .= "</fieldset>\n";
545 $retval .= "</form>\n\n";
546 $retval .= "<!-- END " . strtoupper($mode) . " EVENT FORM -->\n\n";
549 } // end PMA_EVN_getEditorForm()
552 * Composes the query necessary to create an event from an HTTP request.
554 * @return string The CREATE EVENT query.
556 function PMA_EVN_getQueryFromRequest()
558 global $_REQUEST, $errors, $event_status, $event_type, $event_interval;
561 if (! empty($_REQUEST['item_definer'])) {
562 if (strpos($_REQUEST['item_definer'], '@') !== false) {
563 $arr = explode('@', $_REQUEST['item_definer']);
564 $query .= 'DEFINER=' . PMA_Util
::backquote($arr[0]);
565 $query .= '@' . PMA_Util
::backquote($arr[1]) . ' ';
567 $errors[] = __('The definer must be in the "username@hostname" format');
571 if (! empty($_REQUEST['item_name'])) {
572 $query .= PMA_Util
::backquote($_REQUEST['item_name']) . ' ';
574 $errors[] = __('You must provide an event name');
576 $query .= 'ON SCHEDULE ';
577 if (! empty($_REQUEST['item_type'])
578 && in_array($_REQUEST['item_type'], $event_type)
580 if ($_REQUEST['item_type'] == 'RECURRING') {
581 if (! empty($_REQUEST['item_interval_value'])
582 && !empty($_REQUEST['item_interval_field'])
583 && in_array($_REQUEST['item_interval_field'], $event_interval)
585 $query .= 'EVERY ' . intval($_REQUEST['item_interval_value']) . ' ';
586 $query .= $_REQUEST['item_interval_field'] . ' ';
588 $errors[] = __('You must provide a valid interval value for the event.');
590 if (! empty($_REQUEST['item_starts'])) {
592 . PMA_Util
::sqlAddSlashes($_REQUEST['item_starts']) . "' ";
594 if (! empty($_REQUEST['item_ends'])) {
596 . PMA_Util
::sqlAddSlashes($_REQUEST['item_ends']) . "' ";
599 if (! empty($_REQUEST['item_execute_at'])) {
601 . PMA_Util
::sqlAddSlashes($_REQUEST['item_execute_at']) . "' ";
603 $errors[] = __('You must provide a valid execution time for the event.');
607 $errors[] = __('You must provide a valid type for the event.');
609 $query .= 'ON COMPLETION ';
610 if (empty($_REQUEST['item_preserve'])) {
613 $query .= 'PRESERVE ';
614 if (! empty($_REQUEST['item_status'])) {
615 foreach ($event_status['display'] as $key => $value) {
616 if ($value == $_REQUEST['item_status']) {
617 $query .= $event_status['query'][$key] . ' ';
622 if (! empty($_REQUEST['item_comment'])) {
623 $query .= "COMMENT '" . PMA_Util
::sqlAddslashes(
624 $_REQUEST['item_comment']
628 if (! empty($_REQUEST['item_definition'])) {
629 $query .= $_REQUEST['item_definition'];
631 $errors[] = __('You must provide an event definition.');
635 } // end PMA_EVN_getQueryFromRequest()