2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Functions for event management.
8 if (! defined('PHPMYADMIN')) {
13 * Sets required globals
15 function PMA_EVN_setGlobals()
17 global $event_status, $event_type, $event_interval;
19 $event_status = array(
20 'query' => array('ENABLE',
23 'display' => array('ENABLED',
27 $event_type = array('RECURRING',
29 $event_interval = array('YEAR',
47 * Main function for the events functionality
49 function PMA_EVN_main()
55 * Process all requests
57 PMA_EVN_handleEditor();
58 PMA_EVN_handleExport();
60 * Display a list of available events
62 $columns = "`EVENT_NAME`, `EVENT_TYPE`, `STATUS`";
63 $where = "EVENT_SCHEMA='" . PMA_sqlAddSlashes($db) . "'";
64 $query = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` "
65 . "WHERE $where ORDER BY `EVENT_NAME` ASC;";
66 $items = PMA_DBI_fetch_result($query);
67 echo PMA_RTE_getList('event', $items);
69 * Display a link for adding a new event, if
70 * the user has the privileges and a link to
71 * toggle the state of the event scheduler.
73 echo PMA_EVN_getFooterLinks();
74 } // end PMA_EVN_main()
77 * Handles editor requests for adding or editing an item
79 function PMA_EVN_handleEditor()
81 global $_REQUEST, $_POST, $errors, $db, $table;
83 if (! empty($_REQUEST['editor_process_add'])
84 ||
! empty($_REQUEST['editor_process_edit'])
88 $item_query = PMA_EVN_getQueryFromRequest();
90 if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest()
91 // Execute the created query
92 if (! empty($_REQUEST['editor_process_edit'])) {
93 // Backup the old trigger, in case something goes wrong
94 $create_item = PMA_DBI_get_definition(
97 $_REQUEST['item_original_name']
99 $drop_item = "DROP EVENT " . PMA_backquote($_REQUEST['item_original_name']) . ";\n";
100 $result = PMA_DBI_try_query($drop_item);
102 $errors[] = sprintf(__('The following query has failed: "%s"'), $drop_item) . '<br />'
103 . __('MySQL said: ') . PMA_DBI_getError(null);
105 $result = PMA_DBI_try_query($item_query);
107 $errors[] = sprintf(__('The following query has failed: "%s"'), $item_query) . '<br />'
108 . __('MySQL said: ') . PMA_DBI_getError(null);
109 // We dropped the old item, but were unable to create the new one
110 // Try to restore the backup query
111 $result = PMA_DBI_try_query($create_item);
113 // OMG, this is really bad! We dropped the query, failed to create a new one
114 // and now even the backup query does not execute!
115 // This should not happen, but we better handle this just in case.
116 $errors[] = __('Sorry, we failed to restore the dropped event.') . '<br />'
117 . __('The backed up query was:') . "\"$create_item\"" . '<br />'
118 . __('MySQL said: ') . PMA_DBI_getError(null);
121 $message = PMA_Message
::success(__('Event %1$s has been modified.'));
122 $message->addParam(PMA_backquote($_REQUEST['item_name']));
123 $sql_query = $drop_item . $item_query;
127 // 'Add a new item' mode
128 $result = PMA_DBI_try_query($item_query);
130 $errors[] = sprintf(__('The following query has failed: "%s"'), $item_query) . '<br /><br />'
131 . __('MySQL said: ') . PMA_DBI_getError(null);
133 $message = PMA_Message
::success(__('Event %1$s has been created.'));
134 $message->addParam(PMA_backquote($_REQUEST['item_name']));
135 $sql_query = $item_query;
140 if (count($errors)) {
141 $message = PMA_Message
::error(__('<b>One or more errors have occured while processing your request:</b>'));
142 $message->addString('<ul>');
143 foreach ($errors as $num => $string) {
144 $message->addString('<li>' . $string . '</li>');
146 $message->addString('</ul>');
149 $output = PMA_showMessage($message, $sql_query);
150 if ($GLOBALS['is_ajax_request']) {
151 $extra_data = array();
152 if ($message->isSuccess()) {
153 $columns = "`EVENT_NAME`, `EVENT_TYPE`, `STATUS`";
154 $where = "EVENT_SCHEMA='" . PMA_sqlAddSlashes($db) . "' "
155 . "AND EVENT_NAME='" . PMA_sqlAddSlashes($_REQUEST['item_name']) . "'";
156 $query = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE $where;";
157 $event = PMA_DBI_fetch_single_row($query);
158 $extra_data['name'] = htmlspecialchars(strtoupper($_REQUEST['item_name']));
159 $extra_data['new_row'] = PMA_EVN_getRowForList($event);
160 $extra_data['insert'] = ! empty($event);
163 $response = $message;
165 PMA_ajaxResponse($response, $message->isSuccess(), $extra_data);
169 * Display a form used to add/edit a trigger, if necessary
171 if (count($errors) ||
( empty($_REQUEST['editor_process_add']) && empty($_REQUEST['editor_process_edit'])
172 && (! empty($_REQUEST['add_item']) ||
! empty($_REQUEST['edit_item'])
173 ||
! empty($_REQUEST['item_changetype'])))
174 ) { // FIXME: this must be simpler than that
176 if (! empty($_REQUEST['item_changetype'])) {
177 $operation = 'change';
179 // Get the data for the form (if any)
180 if (! empty($_REQUEST['add_item'])) {
181 $title = PMA_RTE_getWord('add');
182 $item = PMA_EVN_getDataFromRequest();
184 } else if (! empty($_REQUEST['edit_item'])) {
185 $title = __("Edit event");
186 if (! empty($_REQUEST['item_name'])
187 && empty($_REQUEST['editor_process_edit'])
188 && empty($_REQUEST['item_changetype'])
190 $item = PMA_EVN_getDataFromName($_REQUEST['item_name']);
191 if ($item !== false) {
192 $item['item_original_name'] = $item['item_name'];
195 $item = PMA_EVN_getDataFromRequest();
199 if ($item !== false) {
201 $editor = PMA_EVN_getEditorForm($mode, $operation, $item);
202 if ($GLOBALS['is_ajax_request']) {
203 $extra_data = array('title' => $title);
204 PMA_ajaxResponse($editor, true, $extra_data);
206 echo "\n\n<h2>$title</h2>\n\n$editor";
208 require './libraries/footer.inc.php';
212 $message = __('Error in processing request') . ' : ';
214 PMA_RTE_getWord('not_found'),
215 htmlspecialchars(PMA_backquote($_REQUEST['item_name'])),
216 htmlspecialchars(PMA_backquote($db))
218 $message = PMA_message
::error($message);
219 if ($GLOBALS['is_ajax_request']) {
220 PMA_ajaxResponse($message, false);
226 } // end PMA_EVN_handleEditor()
229 * This function will generate the values that are required to for the editor
231 * @return array Data necessary to create the editor.
233 function PMA_EVN_getDataFromRequest()
236 $indices = array('item_name',
237 'item_original_name',
240 'item_interval_value',
241 'item_interval_field',
248 foreach ($indices as $key => $index) {
249 $retval[$index] = isset($_REQUEST[$index]) ?
$_REQUEST[$index] : '';
251 $retval['item_type'] = 'ONE TIME';
252 $retval['item_type_toggle'] = 'RECURRING';
253 if (isset($_REQUEST['item_type']) && $_REQUEST['item_type'] == 'RECURRING') {
254 $retval['item_type'] = 'RECURRING';
255 $retval['item_type_toggle'] = 'ONE TIME';
258 } // end PMA_EVN_getDataFromRequest()
261 * This function will generate the values that are required to complete
262 * the "Edit event" form given the name of a event.
264 * @param string $name The name of the event.
266 * @return array Data necessary to create the editor.
268 function PMA_EVN_getDataFromName($name)
273 $columns = "`EVENT_NAME`, `STATUS`, `EVENT_TYPE`, `EXECUTE_AT`, "
274 . "`INTERVAL_VALUE`, `INTERVAL_FIELD`, `STARTS`, `ENDS`, "
275 . "`EVENT_DEFINITION`, `ON_COMPLETION`, `DEFINER`, `EVENT_COMMENT`";
276 $where = "EVENT_SCHEMA='" . PMA_sqlAddSlashes($db) . "' "
277 . "AND EVENT_NAME='" . PMA_sqlAddSlashes($name) . "'";
278 $query = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE $where;";
279 $item = PMA_DBI_fetch_single_row($query);
283 $retval['item_name'] = $item['EVENT_NAME'];
284 $retval['item_status'] = $item['STATUS'];
285 $retval['item_type'] = $item['EVENT_TYPE'];
286 if ($retval['item_type'] == 'RECURRING') {
287 $retval['item_type_toggle'] = 'ONE TIME';
289 $retval['item_type_toggle'] = 'RECURRING';
291 $retval['item_execute_at'] = $item['EXECUTE_AT'];
292 $retval['item_interval_value'] = $item['INTERVAL_VALUE'];
293 $retval['item_interval_field'] = $item['INTERVAL_FIELD'];
294 $retval['item_starts'] = $item['STARTS'];
295 $retval['item_ends'] = $item['ENDS'];
296 $retval['item_preserve'] = '';
297 if ($item['ON_COMPLETION'] == 'PRESERVE') {
298 $retval['item_preserve'] = " checked='checked'";
300 $retval['item_definition'] = $item['EVENT_DEFINITION'];
301 $retval['item_definer'] = $item['DEFINER'];
302 $retval['item_comment'] = $item['EVENT_COMMENT'];
305 } // end PMA_EVN_getDataFromName()
308 * Displays a form used to add/edit an event
310 * @param string $mode If the editor will be used edit an event
311 * or add a new one: 'edit' or 'add'.
312 * @param string $operation If the editor was previously invoked with
313 * JS turned off, this will hold the name of
314 * the current operation
315 * @param array $item Data for the event returned by
316 * PMA_EVN_getDataFromRequest() or
317 * PMA_EVN_getDataFromName()
319 * @return string HTML code for the editor.
321 function PMA_EVN_getEditorForm($mode, $operation, $item)
323 global $db, $table, $titles, $event_status, $event_type, $event_interval;
325 // Escape special characters
326 $need_escape = array(
327 'item_original_name',
331 'item_interval_value',
338 foreach ($need_escape as $key => $index) {
339 $item[$index] = htmlentities($item[$index], ENT_QUOTES
);
342 if ($mode == 'edit') {
343 $original_data = "<input name='item_original_name' "
344 . "type='hidden' value='{$item['item_original_name']}'/>\n";
346 // Handle some logic first
347 if ($operation == 'change') {
348 if ($item['item_type'] == 'RECURRING') {
349 $item['item_type'] = 'ONE TIME';
350 $item['item_type_toggle'] = 'RECURRING';
352 $item['item_type'] = 'RECURRING';
353 $item['item_type_toggle'] = 'ONE TIME';
356 if ($item['item_type'] == 'ONE TIME') {
357 $isrecurring_class = ' hide';
358 $isonetime_class = '';
360 $isrecurring_class = '';
361 $isonetime_class = ' hide';
365 $retval .= "<!-- START " . strtoupper($mode) . " EVENT FORM -->\n\n";
366 $retval .= "<form class='rte_form' action='db_events.php' method='post'>\n";
367 $retval .= "<input name='{$mode}_item' type='hidden' value='1' />\n";
368 $retval .= $original_data;
369 $retval .= PMA_generate_common_hidden_inputs($db, $table) . "\n";
370 $retval .= "<fieldset>\n";
371 $retval .= "<legend>" . __('Details') . "</legend>\n";
372 $retval .= "<table class='rte_table' style='width: 100%'>\n";
374 $retval .= " <td style='width: 20%;'>" . __('Event name') . "</td>\n";
375 $retval .= " <td><input type='text' name='item_name' \n";
376 $retval .= " value='{$item['item_name']}'\n";
377 $retval .= " maxlength='64' /></td>\n";
378 $retval .= "</tr>\n";
380 $retval .= " <td>" . __('Status') . "</td>\n";
381 $retval .= " <td>\n";
382 $retval .= " <select name='item_status'>\n";
383 foreach ($event_status['display'] as $key => $value) {
385 if (! empty($item['item_status']) && $item['item_status'] == $value) {
386 $selected = " selected='selected'";
388 $retval .= "<option$selected>$value</option>";
390 $retval .= " </select>\n";
391 $retval .= " </td>\n";
392 $retval .= "</tr>\n";
395 $retval .= " <td>" . __('Event type') . "</td>\n";
396 $retval .= " <td>\n";
397 if ($GLOBALS['is_ajax_request']) {
398 $retval .= " <select name='item_type'>";
399 foreach ($event_type as $key => $value) {
401 if (! empty($item['item_type']) && $item['item_type'] == $value) {
402 $selected = " selected='selected'";
404 $retval .= "<option$selected>$value</option>";
406 $retval .= " </select>\n";
408 $retval .= " <input name='item_type' type='hidden' \n";
409 $retval .= " value='{$item['item_type']}' />\n";
410 $retval .= " <div style='width: 49%; float: left; text-align: center; font-weight: bold;'>\n";
411 $retval .= " {$item['item_type']}\n";
412 $retval .= " </div>\n";
413 $retval .= " <input style='width: 49%;' type='submit'\n";
414 $retval .= " name='item_changetype'\n";
415 $retval .= " value='";
416 $retval .= sprintf(__('Change to %s'), $item['item_type_toggle']);
419 $retval .= " </td>\n";
420 $retval .= "</tr>\n";
421 $retval .= "<tr class='onetime_event_row $isonetime_class'>\n";
422 $retval .= " <td>" . __('Execute at') . "</td>\n";
423 $retval .= " <td class='nowrap'>\n";
424 $retval .= " <input type='text' name='item_execute_at'\n";
425 $retval .= " value='{$item['item_execute_at']}'\n";
426 $retval .= " class='datetimefield' />\n";
427 $retval .= " </td>\n";
428 $retval .= "</tr>\n";
429 $retval .= "<tr class='recurring_event_row $isrecurring_class'>\n";
430 $retval .= " <td>" . __('Execute every') . "</td>\n";
431 $retval .= " <td>\n";
432 $retval .= " <input style='width: 49%;' type='text'\n";
433 $retval .= " name='item_interval_value'\n";
434 $retval .= " value='{$item['item_interval_value']}' />\n";
435 $retval .= " <select style='width: 49%;' name='item_interval_field'>";
436 foreach ($event_interval as $key => $value) {
438 if (! empty($item['item_interval_field'])
439 && $item['item_interval_field'] == $value
441 $selected = " selected='selected'";
443 $retval .= "<option$selected>$value</option>";
445 $retval .= " </select>\n";
446 $retval .= " </td>\n";
447 $retval .= "</tr>\n";
448 $retval .= "<tr class='recurring_event_row$isrecurring_class'>\n";
449 $retval .= " <td>" . _pgettext('Start of recurring event', 'Start') . "</td>\n";
450 $retval .= " <td class='nowrap'>\n";
451 $retval .= " <input type='text'\n name='item_starts'\n";
452 $retval .= " value='{$item['item_starts']}'\n";
453 $retval .= " class='datetimefield' />\n";
454 $retval .= " </td>\n";
455 $retval .= "</tr>\n";
456 $retval .= "<tr class='recurring_event_row$isrecurring_class'>\n";
457 $retval .= " <td>" . _pgettext('End of recurring event', 'End') . "</td>\n";
458 $retval .= " <td class='nowrap'>\n";
459 $retval .= " <input type='text' name='item_ends'\n";
460 $retval .= " value='{$item['item_ends']}'\n";
461 $retval .= " class='datetimefield' />\n";
462 $retval .= " </td>\n";
463 $retval .= "</tr>\n";
465 $retval .= " <td>" . __('Definition') . "</td>\n";
466 $retval .= " <td><textarea name='item_definition' rows='15' cols='40'>";
467 $retval .= $item['item_definition'];
468 $retval .= "</textarea></td>\n";
469 $retval .= "</tr>\n";
471 $retval .= " <td>" . __('On completion preserve') . "</td>\n";
472 $retval .= " <td><input type='checkbox' name='item_preserve'{$item['item_preserve']} /></td>\n";
473 $retval .= "</tr>\n";
475 $retval .= " <td>" . __('Definer') . "</td>\n";
476 $retval .= " <td><input type='text' name='item_definer'\n";
477 $retval .= " value='{$item['item_definer']}' /></td>\n";
478 $retval .= "</tr>\n";
480 $retval .= " <td>" . __('Comment') . "</td>\n";
481 $retval .= " <td><input type='text' name='item_comment' maxlength='64'\n";
482 $retval .= " value='{$item['item_comment']}' /></td>\n";
483 $retval .= "</tr>\n";
484 $retval .= "</table>\n";
485 $retval .= "</fieldset>\n";
486 if ($GLOBALS['is_ajax_request']) {
487 $retval .= "<input type='hidden' name='editor_process_{$mode}'\n";
488 $retval .= " value='true' />\n";
489 $retval .= "<input type='hidden' name='ajax_request' value='true' />\n";
491 $retval .= "<fieldset class='tblFooters'>\n";
492 $retval .= " <input type='submit' name='editor_process_{$mode}'\n";
493 $retval .= " value='" . __('Go') . "' />\n";
494 $retval .= "</fieldset>\n";
496 $retval .= "</form>\n\n";
497 $retval .= "<!-- END " . strtoupper($mode) . " EVENT FORM -->\n\n";
500 } // end PMA_EVN_getEditorForm()
503 * Composes the query necessary to create an event from an HTTP request.
505 * @return string The CREATE EVENT query.
507 function PMA_EVN_getQueryFromRequest()
509 global $_REQUEST, $db, $errors, $event_status, $event_type, $event_interval;
512 if (! empty($_REQUEST['item_definer'])) {
513 if (strpos($_REQUEST['item_definer'], '@') !== false) {
514 $arr = explode('@', $_REQUEST['item_definer']);
515 $query .= 'DEFINER=' . PMA_backquote($arr[0]);
516 $query .= '@' . PMA_backquote($arr[1]) . ' ';
518 $errors[] = __('The definer must be in the "username@hostname" format');
522 if (! empty($_REQUEST['item_name'])) {
523 $query .= PMA_backquote($_REQUEST['item_name']) . ' ';
525 $errors[] = __('You must provide an event name');
527 $query .= 'ON SCHEDULE ';
528 if (! empty($_REQUEST['item_type']) && in_array($_REQUEST['item_type'], $event_type)) {
529 if ($_REQUEST['item_type'] == 'RECURRING') {
530 if (! empty($_REQUEST['item_interval_value'])
531 && !empty($_REQUEST['item_interval_field'])
532 && in_array($_REQUEST['item_interval_field'], $event_interval)
534 $query .= 'EVERY ' . intval($_REQUEST['item_interval_value']) . ' ';
535 $query .= $_REQUEST['item_interval_field'] . ' ';
537 $errors[] = __('You must provide a valid interval value for the event.');
539 if (! empty($_REQUEST['item_starts'])) {
540 $query .= "STARTS '" . PMA_sqlAddSlashes($_REQUEST['item_starts']) . "' ";
542 if (! empty($_REQUEST['item_ends'])) {
543 $query .= "ENDS '" . PMA_sqlAddSlashes($_REQUEST['item_ends']) . "' ";
546 if (! empty($_REQUEST['item_execute_at'])) {
547 $query .= "AT '" . PMA_sqlAddSlashes($_REQUEST['item_execute_at']) . "' ";
549 $errors[] = __('You must provide a valid execution time for the event.');
553 $errors[] = __('You must provide a valid type for the event.');
555 $query .= 'ON COMPLETION ';
556 if (empty($_REQUEST['item_preserve'])) {
559 $query .= 'PRESERVE ';
560 if (! empty($_REQUEST['item_status'])) {
561 foreach ($event_status['display'] as $key => $value) {
562 if ($value == $_REQUEST['item_status']) {
563 $query .= $event_status['query'][$key] . ' ';
569 if (! empty($_REQUEST['item_definition'])) {
570 $query .= $_REQUEST['item_definition'];
572 $errors[] = __('You must provide an event definition.');
576 } // end PMA_EVN_getQueryFromRequest()