$top_children) { if ($top_branch == 'config') { $config_array = $top_children; } elseif ($top_branch == 'fields') { $fields_array = $top_children; } } } if (cacti_sizeof($fields_array)) { if (!isset($config_array['no_form_tag'])) { print "
'; } $i = 0; $row_class = 'odd'; foreach ($fields_array as $field_name => $field_array) { if ($field_array['method'] == 'hidden') { if (!isset($field_array['value'])) { cacti_log("WARNING: Cacti Form field '$field_name' does not include a 'value' Column. Using default.", false); cacti_debug_backtrace('form_edit'); if (isset($field_array['default'])) { $field_array['value'] = $field_array['default']; } else { cacti_log("WARNING: Cacti Form field '$field_name' does not include a 'default' Column. Using empty string.", false); $field_array['value'] = ''; } } print ''; } elseif ($field_array['method'] == 'hidden_zero') { if (!isset($field_array['value'])) { cacti_log("WARNING: Cacti Form field '$field_name' does not include a 'value' Column. Using default.", false); cacti_debug_backtrace('form_edit'); if (isset($field_array['default'])) { $field_array['value'] = $field_array['default']; } else { cacti_log("WARNING: Cacti Form field '$field_name' does not include a 'default' Column. Using '0'.", false); $field_array['value'] = '0'; } } print ''; } elseif ($field_array['method'] == 'spacer') { $collapsible = (isset($field_array['collapsible']) && $field_array['collapsible'] == 'true'); print "
" . htmle($field_array['friendly_name']); print '
' . (isset($field_array['description']) ? display_tooltip($field_array['description']) : '') . '
'; print ($collapsible ? "
" : '') . '
'; } else { // Make a row using a div if (isset($config_array['force_row_color'])) { print "
"; } else { print "
"; if ($row_class == 'even') { $row_class = 'odd'; } else { $row_class = 'even'; } } // Make a form cell print "
"; print "
"; if (isset($field_array['sub_checkbox'])) { if (!isset($field_array['sub_checkbox']['value'])) { cacti_log("WARNING: Cacti Form field '$field_name' does not include a sub_checkbox 'value' Column. Using default", false); cacti_debug_backtrace('form_edit'); if (isset($field_array['sub_checkbox']['default'])) { $field_array['sub_checkbox']['value'] = $field_array['default']; } else { cacti_log("WARNING: Cacti Form field '$field_name' does not include a 'default' Column. Using ''.", false); $field_array['sub_checkbox']['value'] = ''; } } form_checkbox( $field_array['sub_checkbox']['name'], $field_array['sub_checkbox']['value'], '', ($field_array['sub_checkbox']['default'] ?? ''), ($field_array['sub_checkbox']['form_id'] ?? ''), ($field_array['sub_checkbox']['class'] ?? ''), ($field_array['sub_checkbox']['on_change'] ?? ''), ($field_array['sub_checkbox']['friendly_name'] ?? '') ); } print htmle($field_array['friendly_name']); if (read_config_option('hide_form_description') == 'on') { print '
' . ($field_array['description'] ?? '') . ''; } else { print '
'; print display_tooltip($field_array['description'] ?? ''); print '
'; } print '
'; // End form cell print '
'; // New form column for content print '
'; draw_edit_control($field_name, $field_array); // End content column print '
'; // End form row print '
'; } $i++; } if (isset($_SESSION[SESS_ERROR_FIELDS]) && !cacti_sizeof($_SESSION[SESS_ERROR_FIELDS])) { kill_session_var(SESS_ERROR_FIELDS); } } } /** * Draws an edit control based on the specified method and field array. * * @param string $field_name - The name of the control. * @param array $field_array - An array containing data for this * control. see include/global_form.php * for more specific syntax. * * @return void */ function draw_edit_control(string $field_name, array &$field_array) : void { switch ($field_array['method']) { case 'textbox': form_text_box( $field_name, $field_array['value'], ($field_array['default'] ?? ''), $field_array['max_length'], ($field_array['size'] ?? '40'), ($field_array['type'] ?? 'text'), ($field_array['form_id'] ?? ''), ($field_array['placeholder'] ?? '') ); break; case 'filepath': form_filepath_box( $field_name, $field_array['value'], ($field_array['default'] ?? ''), $field_array['max_length'], ($field_array['size'] ?? '40'), 'text', ($field_array['form_id'] ?? '') ); break; case 'dirpath': form_dirpath_box( $field_name, $field_array['value'], ($field_array['default'] ?? ''), $field_array['max_length'], ($field_array['size'] ?? '40'), 'text', ($field_array['form_id'] ?? '') ); break; case 'textbox_password': form_text_box( $field_name, $field_array['value'], ($field_array['default'] ?? ''), $field_array['max_length'], ($field_array['size'] ?? '40'), 'password', ($field_array['form_id'] ?? ''), '********' ); if (!isset($field_array['noconfirm'])) { print '
'; form_text_box( $field_name . '_confirm', $field_array['value'], ($field_array['default'] ?? ''), $field_array['max_length'], ($field_array['size'] ?? '40'), 'password', ($field_array['form_id'] ?? ''), '********' ); } break; case 'textarea': form_text_area( $field_name, $field_array['value'], $field_array['textarea_rows'], $field_array['textarea_cols'], ($field_array['default'] ?? ''), ($field_array['class'] ?? ''), ($field_array['on_change'] ?? ''), ($field_array['placeholder'] ?? '') ); break; case 'textcert': form_cert_box( $field_name, $field_array['value'], ($field_array['default'] ?? ''), $field_array['textarea_rows'], $field_array['textarea_cols'] ); break; case 'privkey': form_privkey_box( $field_name, $field_array['value'], $field_array['textarea_rows'], $field_array['textarea_cols'] ); break; case 'drop_array': form_dropdown( $field_name, $field_array['array'], '', '', $field_array['value'], ($field_array['none_value'] ?? ''), ($field_array['default'] ?? ''), ($field_array['class'] ?? ''), ($field_array['on_change'] ?? ''), ($field_array['friendly_name'] ?? '') ); break; case 'drop_icon': form_dropicon( $field_name, $field_array['array'], '', '', $field_array['value'], ($field_array['none_value'] ?? ''), ($field_array['default'] ?? ''), ($field_array['class'] ?? ''), ($field_array['on_change'] ?? '') ); break; case 'drop_language': form_droplanguage( $field_name, '', '', $field_array['value'], ($field_array['none_value'] ?? ''), ($field_array['default'] ?? ''), ($field_array['class'] ?? ''), ($field_array['on_change'] ?? '') ); break; case 'drop_files': $array_files = []; $files = []; if (isset($field_array['directory'])) { $dir = $field_array['directory']; if (is_dir($dir) && is_readable($dir)) { if (function_exists('scandir')) { $files = scandir($dir); } elseif ($dh = opendir($dir)) { while (($file = readdir($dh)) !== false) { $files[] = $file; } closedir($dh); } if (cacti_sizeof($files)) { foreach ($files as $file) { if (is_readable($dir . '/' . $file) && $file != '.' && $file != '..') { if (!in_array($file, $field_array['exclusions'], true)) { $array_files[basename($file)] = basename($file); } } } } } } form_dropdown( $field_name, $array_files, '', '', $field_array['value'], ($field_array['none_value'] ?? ''), ($field_array['default'] ?? ''), ($field_array['class'] ?? ''), ($field_array['on_change'] ?? ''), ($field_array['friendly_name'] ?? '') ); break; case 'drop_sql': form_dropdown( $field_name, db_fetch_assoc($field_array['sql']), 'name', 'id', $field_array['value'], ($field_array['none_value'] ?? ''), ($field_array['default'] ?? ''), ($field_array['class'] ?? ''), ($field_array['on_change'] ?? ''), ($field_array['friendly_name'] ?? '') ); break; case 'drop_callback': form_callback( $field_name, $field_array['sql'], 'name', 'id', $field_array['action'], $field_array['id'], $field_array['value'], ($field_array['none_value'] ?? ''), ($field_array['default'] ?? ''), ($field_array['class'] ?? ''), ($field_array['on_change'] ?? ''), ($field_array['friendly_name'] ?? ''), ($field_array['request_vars'] ?? '') ); break; case 'drop_multi': form_multi_dropdown( $field_name, $field_array['array'], (isset($field_array['sql']) ? db_fetch_assoc($field_array['sql']) : $field_array['value']), 'id', ($field_array['class'] ?? ''), ($field_array['on_change'] ?? ''), ($field_array['select_all_text'] ?? ''), ($field_array['select_count_text'] ?? ''), ($field_array['select_all_value'] ?? '') ); break; case 'drop_tree': grow_dropdown_tree( $field_array['tree_id'], '0', $field_name, $field_array['value'] ); break; case 'drop_color': form_color_dropdown( $field_name, $field_array['value'], __('None'), ($field_array['default'] ?? ''), ($field_array['class'] ?? ''), ($field_array['on_change'] ?? '') ); break; case 'checkbox': form_checkbox( $field_name, $field_array['value'], $field_array['friendly_name'], ($field_array['default'] ?? ''), ($field_array['form_id'] ?? ''), ($field_array['class'] ?? ''), ($field_array['on_change'] ?? ''), $field_array['friendly_name'] ); break; case 'checkbox_group': if (isset($field_array['type']) && $field_array['type'] == 'flex') { print "
" . PHP_EOL; } else { print "
" . PHP_EOL; } foreach ($field_array['items'] as $check_name => $check_array) { if (isset($field_array['type']) && $field_array['type'] == 'flex') { print '
'; } form_checkbox( $check_name, $check_array['value'], $check_array['friendly_name'], ($check_array['default'] ?? ''), ($check_array['form_id'] ?? ''), ($field_array['class'] ?? ''), ($check_array['on_change'] ?? $field_array['on_change'] ?? ''), $field_array['friendly_name'], true ); if (isset($field_array['type']) && $field_array['type'] == 'flex') { print '
'; } else { print '
'; } } if (isset($field_array['type']) && $field_array['type'] == 'flex') { print '
' . PHP_EOL; } else { print '
' . PHP_EOL; } break; case 'radio': print "
" . PHP_EOL; foreach ($field_array['items'] as $radio_array) { form_radio_button( $field_name, $field_array['value'], $radio_array['radio_value'], $radio_array['radio_caption'], ($field_array['default'] ?? ''), ($field_array['class'] ?? ''), ($field_array['on_change'] ?? '') ); print '
'; } print '
' . PHP_EOL; break; case 'custom': print $field_array['value']; break; case 'template_checkbox': print '' . html_boolean_friendly($field_array['value']) . ''; form_hidden_box($field_name, $field_array['value'], '', true); break; case 'template_drop_array': print '' . $field_array['array'][$field_array['value']] . ''; form_hidden_box($field_name, $field_array['value'], '', true); break; case 'font': form_font_box( $field_name, $field_array['value'], ($field_array['default'] ?? ''), $field_array['max_length'], ($field_array['size'] ?? '40'), 'text', ($field_array['form_id'] ?? ''), ($field_array['placeholder'] ?? '') ); break; case 'file': form_file( $field_name, ($field_array['size'] ?? '40'), ($field_array['accept'] ?? '') ); break; case 'button': form_button( $field_name, ($field_array['value'] ?? ''), ($field_array['title'] ?? ''), ($field_array['on_click'] ?? '') ); break; case 'submit': form_submit( $field_name, ($field_array['value'] ?? ''), ($field_array['title'] ?? ''), ($field_array['on_click'] ?? '') ); break; default: if (isset($field_array['value'])) { print '' . htmle($field_array['value']) . ''; form_hidden_box($field_name, $field_array['value'], '', true); } else { cacti_log('ERROR: Field Name: ' . $field_name . ' includes Method: ' . $field_array['method'] . ' does not include a value \'value\' element.', false); } break; } } /** * form_button - draws a standard button form element * * @param string $form_name - The name of this form element * @param string $value - The display value for the button * @param string $title - The hover title for the button * @param mixed $action - The onClick action for the button * * @return void */ function form_button(string $form_name, string $value, string $title = '', mixed $action = '') : void { print "'; } /** * Generates an HTML submit button with optional JavaScript action and title. * * @param string $form_name - The name and ID of the form element. * @param string $value - The display text of the submit button. * @param string $title - The title attribute for the submit button. * @param mixed $action - JavaScript code to execute on button click. * * @return void */ function form_submit(string $form_name, string $value, string $title = '', mixed $action = '') : void { print "'; } /** * Draws a standard html file input element * * @param string $form_name - The name and ID of the file input element. * @param int $form_size - The size attribute of the file input element. Default is 30. * @param string $form_accept - The accept attribute of the file input element, specifying the types of files that the server accepts. Default is an empty string. * * @return void */ function form_file(string $form_name, int $form_size = 30, string $form_accept = '') : void { print '
'; print "'; print "'; print ""; print '
'; } /** * Draws a standard html textbox and provides status of a files existence * * @param string $form_name The name of this form element * @param mixed $prev_val The current value of this form element * @param mixed $default_val The value of this form element to use if there is no current value available * @param mixed $max_length The maximum number of characters that can be entered into this textbox * @param mixed $form_size The size (width) of the textbox * @param string $type The type of textbox, either 'text' or 'password' * @param mixed $current_id Used to determine if a current value for this form element * exists or not. a $current_id of '0' indicates that no * current value exists, a non-zero value indicates that * a current value does exist * @param mixed $data Array containing 'text' element for display and if * 'error' element present, shows failure * * @return void */ function form_filepath_box(string $form_name, mixed $prev_val, mixed $default_val, mixed $max_length, mixed $form_size = 30, string $type = 'text', mixed $current_id = 0, mixed $data = false) : void { if (($prev_val == '') && (empty($current_id))) { $prev_val = $default_val; } print "" . $extra_data; } /** * Draws a standard html textbox and provides status of a directories existence * * @param string $form_name The name of this form element * @param mixed $prev_val The current value of this form element * @param mixed $default_val The value of this form element to use if there is no current value available * @param mixed $max_length The maximum number of characters that can be entered into this textbox * @param mixed $form_size The size (width) of the textbox * @param string $type The type of textbox, either 'text' or 'password' * @param mixed $current_id Used to determine if a current value for this form element * exists or not. a $current_id of '0' indicates that no current value exists, * a non-zero value indicates that a current value does exist * * @return void */ function form_dirpath_box(string $form_name, mixed $prev_val, mixed $default_val, mixed $max_length, mixed $form_size = 30, string $type = 'text', mixed $current_id = 0) : void { if (($prev_val == '') && (empty($current_id))) { $prev_val = $default_val; } print ""; } elseif (is_file($prev_val)) { $extra_data = "'; } elseif ($prev_val == '') { $extra_data = ''; } else { $extra_data = ""; } print " id='$form_name' name='$form_name' placeholder='" . __esc('Enter a valid directory path') . "' size='$form_size'" . (!empty($max_length) ? " maxlength='$max_length'" : '') . " value='" . htmle($prev_val) . "'>" . $extra_data; } /** * Draws a textarea for pasting a PEM certificate that, like * form_privkey_box(), never redisplays the stored value - the textarea is * always left blank, and leaving it blank on save means "keep the existing * certificate" rather than clearing it. Like form_filepath_box()/ * form_dirpath_box(), a status indicator next to it shows the certificate's * expiration date (YYYY-MM-DD) rather than a found/not-found file check. * * @param string $form_name The name of this form element * @param mixed $stored_val The current (PEM) stored value; only used to * compute the expiration status, never displayed * @param mixed $default_val The value to check for a stored certificate when there is no current value * @param int $form_rows The number of rows for the textarea * @param int $form_columns The number of columns for the textarea * * @return void */ function form_cert_box(string $form_name, mixed $stored_val, mixed $default_val, int $form_rows, int $form_columns) : void { if ($stored_val == '') { $stored_val = $default_val; } $error_class = ''; if (isset($_SESSION[SESS_ERROR_FIELDS])) { if (!empty($_SESSION[SESS_ERROR_FIELDS][$form_name])) { $error_class = ' txtErrorTextBox'; unset($_SESSION[SESS_ERROR_FIELDS][$form_name]); } } // Unconditionally blank: form_input_validate() writes SESS_FIELD_VALUES // on every submission (even a successful save), and that save's redirect // runs before bottom_footer() clears it - repopulating from it here would // echo the just-submitted certificate back on the very next page load. $textarea_val = ''; if (trim((string) $stored_val) == '') { $extra_data = ''; } else { // @ - openssl_x509_parse() emits a warning for non-PEM input; the // false return value already tells us the certificate is invalid. $parsed = @openssl_x509_parse((string) $stored_val); if ($parsed === false || empty($parsed['validTo_time_t'])) { $extra_data = ""; } else { $expires = date('Y-m-d', $parsed['validTo_time_t']); if ($parsed['validTo_time_t'] < time()) { $extra_data = "" . __esc('Expired: %s', $expires) . ''; } else { $extra_data = "" . __esc('Good Till: %s', $expires) . ''; } } } print "' . $extra_data; } /** * Draws a textarea for pasting a private key that, unlike every other * field, never redisplays its stored value - the textarea is always left * blank, and leaving it blank on save means "keep the existing key" * rather than "clear it". The status area (styled like form_cert_box()'s * expiration date) instead shows whether a key is currently stored. * * @param string $form_name The name of this form element * @param mixed $stored_val The current (still-encrypted) stored value; only its * presence is used, its content is never displayed * @param int $form_rows The number of rows for the textarea * @param int $form_columns The number of columns for the textarea * * @return void */ function form_privkey_box(string $form_name, mixed $stored_val, int $form_rows, int $form_columns) : void { $error_class = ''; if (isset($_SESSION[SESS_ERROR_FIELDS])) { if (!empty($_SESSION[SESS_ERROR_FIELDS][$form_name])) { $error_class = ' txtErrorTextBox'; unset($_SESSION[SESS_ERROR_FIELDS][$form_name]); } } // Unconditionally blank: form_input_validate() writes SESS_FIELD_VALUES // on every submission (even a successful save), and that save's redirect // runs before bottom_footer() clears it - repopulating from it here would // echo the just-submitted plaintext private key back on the very next // page load. Never restore this field's value from session. $textarea_val = ''; if (trim((string) $stored_val) == '') { $extra_data = "" . __esc('[not set]') . ''; } else { $extra_data = "" . __esc('[stored]') . ''; } print "' . $extra_data; } /** * Draws a standard html textbox * * @param string $form_name The name of this form element * @param mixed $prev_val The current value of this form element * @param mixed $default_val The value of this form element to use if there is no current value available * @param mixed $max_length The maximum number of characters that can be entered into this textbox * @param mixed $form_size The size (width) of the textbox * @param string $type The type of textbox, either 'text' or 'password' * @param mixed $current_id Used to determine if a current value for this form element * exists or not. a $current_id of '0' indicates that no current value exists, * a non-zero value indicates that a current value does exist * @param string $placeholder Place a placeholder over an empty field * @param string $title Use a title attribute when hovering over the textbox * * @return void */ function form_text_box(string $form_name, mixed $prev_val, mixed $default_val, mixed $max_length, mixed $form_size = 30, string $type = 'text', mixed $current_id = 0, string $placeholder = '', string $title = '') : void { if (($prev_val == '') && (empty($current_id))) { $prev_val = $default_val; } print ""; } /** * Draws a standard html hidden element * * @param string $form_name The name of this form element * @param mixed $prev_val The current value of this form element * @param mixed $default_val The value of this form element to use if there is no current value available * @param mixed $in_form * * @return void */ function form_hidden_box(string $form_name, mixed $prev_val, mixed $default_val, mixed $in_form = false) : void { if ($prev_val == '') { $prev_val = $default_val; } print "
"; } /** * Draws a standard html dropdown box * * @param string $form_name The name of this form element * @param array $form_data An array containing data for this dropdown. it can be formatted * in one of two ways: * $array["id"] = "value"; * -- or -- * $array[0]["id"] = 43; * $array[0]["name"] = "Red"; * @param string $column_display Used to identify the key to be used for display data. this * is only applicable if the array is formatted using * the second method above * @param mixed $column_id Used to identify the key to be used for id data. this * is only applicable if the array is formatted using * the second method above * @param mixed $prev_val The current value of this form element * @param string $none_entry The name to use for a default 'none' element in the dropdown * @param mixed $default_val The value of this form element to use if there is * no current value available * @param string $class any css that needs to be applied to this form element * @param string $on_change The onChange modifier * @param string $display_name The display name for this form object * * @return void */ function form_dropdown(string $form_name, array $form_data, string $column_display, mixed $column_id, mixed $prev_val, string $none_entry, mixed $default_val, string $class = '', string $on_change = '', string $display_name = '') : void { global $form_id; if ($prev_val == '') { $prev_val = $default_val; } if (isset($_SESSION[SESS_ERROR_FIELDS])) { if (!empty($_SESSION[SESS_ERROR_FIELDS][$form_name])) { $class .= ($class != '' ? ' ' : '') . 'txtErrorTextBox'; unset($_SESSION[SESS_ERROR_FIELDS][$form_name]); } } if (isset($_SESSION[SESS_FIELD_VALUES])) { if (!empty($_SESSION[SESS_FIELD_VALUES][$form_name])) { $prev_val = $_SESSION[SESS_FIELD_VALUES][$form_name]; } } if ($display_name != '') { $display = " data-defaultLabel='" . htmle($display_name) . "'"; } else { $display = ''; } if ($class != '') { $class = " class='$class' "; } if ($on_change != '') { $on_change = " onChange='$on_change' "; } print "'; } /** * Draws a standard html dropdown box using icon definitions in the form array. * * @param string $form_name The name of this form element * @param array $form_data An array containing data for this dropdown. It must contain * the following structure. * * $dropdown_array = array( * 'server' => array( * 'display' => __('Some Value'), * 'class' => 'ti ti-server', * 'style' => 'width:30px;...' * ), * ... * ); * * @param string $column_display Used to identify the key to be used for display data. this * is only applicable if the array is formatted using the * second method above * @param string $column_id Used to identify the key to be used for id data. this * is only applicable if the array is formatted using the * second method above. * @param mixed $prev_val The current value of this form element * @param string $none_entry The name to use for a default 'none' element in the dropdown * @param mixed $default_val The value of this form element to use if there is no current value available * @param string $class Any css that needs to be applied to this form element * @param string $on_change The onChange modifier * @param string $class The CSS Class for the object * * @return void */ function form_dropicon(string $form_name, array $form_data, string $column_display, string $column_id, mixed $prev_val, string $none_entry, mixed $default_val, string $class = '', string $on_change = '') : void { if ($prev_val == '') { $prev_val = $default_val; } if (isset($_SESSION[SESS_ERROR_FIELDS])) { if (!empty($_SESSION[SESS_ERROR_FIELDS][$form_name])) { $class .= ($class != '' ? ' ' : '') . 'txtErrorTextBox'; unset($_SESSION[SESS_ERROR_FIELDS][$form_name]); } } if (isset($_SESSION[SESS_FIELD_VALUES])) { if (!empty($_SESSION[SESS_FIELD_VALUES][$form_name])) { $prev_val = $_SESSION[SESS_FIELD_VALUES][$form_name]; } } if ($class != '') { $class = " class='drop-icon $class' "; } else { $class = " class='drop-icon' "; } if ($on_change != '') { $on_change = " onChange='$on_change' "; } print "'; } /** * Generates a dropdown selection form element for languages. * * @param string $form_name The name attribute for the select element. * @param string $column_display Not used in the function. * @param string $column_id Not used in the function. * @param mixed $prev_val The previously selected value. * @param string $none_entry Not used in the function. * @param mixed $default_val The default value if no previous value is set. * @param string $class Optional. Additional CSS classes for the select element. * @param string $on_change Optional. JavaScript code to execute on change event. * * @return void */ function form_droplanguage(string $form_name, string $column_display, string $column_id, mixed $prev_val, string $none_entry, mixed $default_val, string $class = '', string $on_change = '') : void { if ($prev_val == '') { $prev_val = $default_val; } if (isset($_SESSION[SESS_ERROR_FIELDS])) { if (!empty($_SESSION[SESS_ERROR_FIELDS][$form_name])) { $class .= ($class != '' ? ' ' : '') . 'txtErrorTextBox'; unset($_SESSION[SESS_ERROR_FIELDS][$form_name]); } } if (isset($_SESSION[SESS_FIELD_VALUES])) { if (!empty($_SESSION[SESS_FIELD_VALUES][$form_name])) { $prev_val = $_SESSION[SESS_FIELD_VALUES][$form_name]; } } if ($class != '') { $class = " class='$class' "; } if ($on_change != '') { $on_change = " onChange='$on_change' "; } $languages = get_installed_locales(); print "'; } /** * Generates a form element based on the provided parameters and configuration. * * @param string $form_name The name of the form element. * @param string $classic_sql The SQL query to fetch data for the form element. * @param string $column_display The column name to be displayed in the form element. * @param string $column_id The column name to be used as the value in the form element. * @param mixed $action The action to be performed on form element change. * @param string $previous_id The previous ID value of the form element. * @param mixed $prev_val The previous value of the form element. * @param string $none_entry The text to display for a "none" entry. * @param mixed $default_val The default value for the form element. * @param string $class Optional. Additional CSS classes for the form element. * @param string $on_change Optional. JavaScript function to call on form element change. * @param string $display_name Optional. The display name for the column. * @param string $request_vars Optional. The the request variables to include in the action * * @return void */ function form_callback(string $form_name, string $classic_sql, string $column_display, string $column_id, mixed $action, string $previous_id, mixed $prev_val, string $none_entry, mixed $default_val, string $class = '', string $on_change = '', string $display_name = '', string $request_vars = '') : void { if ($prev_val == '') { $prev_val = $default_val; } if (isset($_SESSION[SESS_ERROR_FIELDS])) { if (!empty($_SESSION[SESS_ERROR_FIELDS][$form_name])) { $class .= ($class != '' ? ' ' : '') . 'txtErrorTextBox'; unset($_SESSION[SESS_ERROR_FIELDS][$form_name]); } } /* A non-zero 'autocomplete' config renders the full option list inline as a * plain '; if (!empty($none_entry)) { print ""; } $form_data = db_fetch_assoc($classic_sql); html_create_list($form_data, $column_display, $column_id, $previous_id); print ''; return; } if (!preg_match('/(^|\s)select2-callback(\s|$)/', $class)) { $class .= ($class != '' ? ' ' : '') . 'select2-callback'; } if (empty($previous_id) && $prev_val == '') { $prev_val = $none_entry; } print "'; } /** * Draws a standard html checkbox * * @param string $form_name The name of this form element * @param mixed $prev_val The current value of this form element * @param string $form_caption The text to display to the right of the checkbox * @param mixed $default_val The value of this form element to use if there is * no current value available * @param mixed $current_id Used to determine if a current value for this form element * exists or not. a $current_id of '0' indicates * that no current value exists, a non-zero value indicates * that a current value does exist. * @param string $class Specify a css class * @param string $on_change Specify a javascript onchange action * @param string $title Specify a title for the checkbox on hover * @param bool $show_label Show the form caption in the checkbox * * @return void */ function form_checkbox(string $form_name, mixed $prev_val, string $form_caption, mixed $default_val, mixed $current_id = 0, string $class = '', string $on_change = '', string $title = '', bool $show_label = false) : void { if (($prev_val === null) && (empty($current_id))) { $prev_val = $default_val; } if (isset($_SESSION[SESS_FIELD_VALUES])) { if (!empty($_SESSION[SESS_FIELD_VALUES][$form_name])) { $prev_val = $_SESSION[SESS_FIELD_VALUES][$form_name]; } } if ($class != '') { $class = ' ' . trim($class); } if ($on_change != '') { $on_change = " onChange='$on_change'"; } if ($prev_val == 'on') { $checked = " checked aria-checked='true'"; } else { $checked = " aria-checked='false'"; } $labelClass = ''; if ($show_label) { $labelClass = ' checkboxLabelWanted'; } print ""; print ""; print "'; print ''; } /** * Draws a standard html radio button * * @param string $form_name The name of this form element * @param mixed $prev_val The current value of this form element (selected or not) * @param mixed $current_val The current value of this form element (element id) * @param string $form_caption The text to display to the right of the checkbox * @param mixed $default_val The value of this form element to use if there is * @param string $class The object class for customization * @param string $on_change An onChange event to attach to the form object no current value available * * @return void */ function form_radio_button(string $form_name, mixed $prev_val, mixed $current_val, string $form_caption, mixed $default_val, string $class = '', string $on_change = '') : void { if ($prev_val == '') { $prev_val = $default_val; } if (isset($_SESSION[SESS_FIELD_VALUES])) { if (!empty($_SESSION[SESS_FIELD_VALUES][$form_name])) { $prev_val = $_SESSION[SESS_FIELD_VALUES][$form_name]; } } if ($class != '') { $class = " $class"; } if ($on_change != '') { $on_change = " onChange='$on_change' "; } if ($prev_val == $current_val) { $checked = " checked aria-checked='true'"; } else { $checked = " aria-checked='false'"; } $css_id = $form_name . '_' . $current_val; print ""; print ""; print "'; print ''; } /** * Draws a standard html text area box * * @param string $form_name The name of this form element * @param mixed $prev_val The current value of this form element (selected or not) * @param int $form_rows The number of rows in the text area box * @param int $form_columns The number of columns in the text area box * @param mixed $default_val The value of this form element to use if there is no current value available * @param string $class Additional CSS classes to apply to the textarea element. Default is an empty string. * @param string $on_change JavaScript code to execute when the textarea value changes. Default is an empty string. * @param string $placeholder Placeholder text for the textarea element. Default is an empty string. * * @return void */ function form_text_area(string $form_name, mixed $prev_val, int $form_rows, int $form_columns, mixed $default_val, string $class = '', string $on_change = '', string $placeholder = '') : void { if ($prev_val == '') { $prev_val = $default_val; } if (isset($_SESSION[SESS_ERROR_FIELDS])) { if (!empty($_SESSION[SESS_ERROR_FIELDS][$form_name])) { $class .= ($class != '' ? ' ' : '') . 'txtErrorTextBox'; unset($_SESSION[SESS_ERROR_FIELDS][$form_name]); } } if (isset($_SESSION[SESS_FIELD_VALUES])) { if (!empty($_SESSION[SESS_FIELD_VALUES][$form_name])) { $prev_val = $_SESSION[SESS_FIELD_VALUES][$form_name]; } } if ($on_change != '') { $on_change = " onChange='$on_change' "; } if ($placeholder != '') { $placeholder = " placeholder='" . htmle($placeholder) . "'"; } print "'; } /** * Draws a standard html multiple select dropdown * * @param string $form_name - the name of this form element * @param array $array_display - an array containing display values for this dropdown. it must * be formatted like: * $array[id] = display; * @param mixed $prev_vals - an array containing keys that should be marked as selected. * it must be formatted like: * $array[0][$column_id] = key * @param string $column_id - the name of the key used to reference the keys above * @param string $class - Optional. Additional CSS classes to apply to the select element. * @param string $on_change - Optional. JavaScript code to execute when the selection changes. * @param string $select_all_text - Optional. For class 'select2-multi-count', the summary text shown * when $select_all_value is selected (or nothing is selected). * @param string $select_count_text - Optional. For class 'select2-multi-count', the suffix appended * after the selected count (e.g. '3 '). * @param string $select_all_value - Optional. For class 'select2-multi-count', the option value that * represents "all" and takes priority over showing a count. * * @return void */ function form_multi_dropdown(string $form_name, array $array_display, mixed $prev_vals, string $column_id, string $class = '', string $on_change = '', string $select_all_text = '', string $select_count_text = '', string $select_all_value = '') : void { if (!is_array($prev_vals) && $prev_vals != '') { $values = explode(',', $prev_vals); $prev_vals = []; foreach ($values as $value) { $prev_vals[][$column_id] = $value; } } elseif ($prev_vals == '') { $values = db_fetch_cell_prepared('SELECT value FROM settings WHERE name = ?', [$form_name]); if ($values != '') { $values = explode(',', $values); foreach ($values as $value) { $prev_vals[][$column_id] = $value; } } } if (isset($_SESSION[SESS_ERROR_FIELDS])) { if (!empty($_SESSION[SESS_ERROR_FIELDS][$form_name])) { $class .= ($class != '' ? ' ' : '') . 'txtErrorTextBox'; unset($_SESSION[SESS_ERROR_FIELDS][$form_name]); } } /* The drop_multi form method renders a select2 'N Selected' multi dropdown by default. * A caller keeps the legacy jquery-multiselect widget (e.g. the Scheduler used by * Automation Networks, and the Data Source Profiles Consolidation Functions) by * including 'multiselect' in $class; those pages supply their own .multiselect() init * and must not also be decorated by select2. */ $class = trim($class); if (preg_match('/(^|\s)multiselect(\s|$)/', $class)) { /* legacy opt-in wins: strip any select2-multi-count so applySkin() does not * also decorate the field and collide with the page's own .multiselect() init */ $class = preg_replace('/(^|\s)select2-multi-count(?=\s|$)/', '', $class) ?? $class; $class = trim(preg_replace('/\s+/', ' ', $class) ?? $class); } elseif (!preg_match('/(^|\s)select2-multi-count(\s|$)/', $class)) { $class = trim('select2-multi-count ' . $class); } if ($on_change != '') { $on_change = " onChange='$on_change' "; } $select2Attrs = ''; if ($select_all_text != '') { $select2Attrs .= " data-select-all-text='" . html_escape_attr($select_all_text) . "'"; } if ($select_count_text != '') { $select2Attrs .= " data-select-count-text='" . html_escape_attr($select_count_text) . "'"; } if ($select_all_value != '') { $select2Attrs .= " data-select-all-value='" . html_escape_attr($select_all_value) . "'"; } print "'; } /** * Draws a dropdown containing a list of colors that uses a bit * of css magic to make the dropdown item background color represent each color in * the list * * @param string $form_name The name of this form element * @param mixed $prev_val The current value of this form element * @param string $none_entry The name to use for a default 'none' element in the dropdown * @param mixed $default_val The value of this form element to use if there is no current value available * @param string $class Additional CSS classes for the dropdown. * @param string $on_change JavaScript code to execute on change event. * * @return void */ function form_color_dropdown(string $form_name, mixed $prev_val, string $none_entry, mixed $default_val, string $class = '', string $on_change = '') : void { if ($prev_val == '') { $prev_val = $default_val; } if ($class != '') { $class = " class='colordropdown $class' "; } else { $class = " class='colordropdown'"; } $current_color = db_fetch_cell_prepared('SELECT hex FROM colors WHERE id = ?', [$prev_val] ); if ($on_change != '') { $on_change = ' ' . $on_change . ';'; } $on_change = " onChange='this.style.backgroundColor=this.options[this.selectedIndex].style.backgroundColor;$on_change'"; $colors_sql = 'SELECT * FROM colors ORDER BY SUBSTRING(hex,0,2) ASC, SUBSTRING(hex,2,2) ASC, SUBSTRING(hex,4,2) ASC'; $colors_list = db_fetch_assoc($colors_sql); print "'; } /** * Draws a standard html textbox and provides status of a fonts existence * * @param string $form_name The name of this form element * @param mixed $prev_val The current value of this form element * @param mixed $default_val The value of this form element to use if there is * no current value available * @param mixed $max_length The maximum number of characters that can be entered * into this textbox * @param mixed $form_size The size (width) of the textbox * @param string $type The type of textbox, either 'text' or 'password' * @param mixed $current_id Used to determine if a current value for this * form element exists or not. a $current_id of '0' * indicates that no current value exists, * a non-zero value indicates that a current * value does exist. * @param string $placeholder The placeholder text for the input element. Default is an empty string. * * @return void */ function form_font_box(string $form_name, mixed $prev_val, mixed $default_val, mixed $max_length, mixed $form_size = 30, string $type = 'text', mixed $current_id = 0, string $placeholder = '') : void { if (($prev_val == '') && (empty($current_id))) { $prev_val = $default_val; } print "'; } print " id='$form_name' " . ($placeholder != '' ? "placeholder='" . htmle($placeholder) . "'" : '') . " name='$form_name' size='$form_size'" . (!empty($max_length) ? " maxlength='$max_length'" : '') . " value='" . htmle($prev_val) . "'>" . $extra_data; } /** * Given as set of form options in the form of an array * generate a continuation form confirm dialog for the user. * * @param array $form_data Options to present to the users depending on the drop action * * The options array has two sections 'general' and 'options'. The 'general' option * must includes the following 4 variables: * - page: The page that is being rendered or returnedd to in case of a cancel * - actions: An array of legal actions that we can construct a title for * - eaction: An action to add to the form save when there are more than one on a page * - optvar: A request variable to pull the selected option from. Normally 'drp_action' * - item_array: An array of selected items that have been pre-processed * - item_list: An string of list items "
  • Title
  • " that have been pre-processed * - header: A paragraph that is placed before the options and after the message text * - footer: A paragraph that is placed after the options and just before the Continue button * * The 'options' array should have a matching value array for each of the approved * actions. For each action, you need one of the following formats variables: * - scont - Singular continuation string * - pcont - Plural continuation string * - cont - Generic continuation string * - smessage - Singular confirmation message to the user. * - pmessage - Plural confirmation message to the user. * - message - Generic confirmation message to the user. * - extra - An array of general form input. The supported methods include: * textbox, other, drop_array, checkbox, radio_button * additional options include: title, default, width, options for radio_button, and array for drop_array * * An example might look like the following: * * $form_data = array( * 'general' => array( * 'page' => 'login_providers.php', * 'actions' => $actions, * 'eaction' => 'action_variable', // Extra Action * 'optvar' => 'drp_action' * 'header' => 'some header text', * 'item_array' => $d_array, * 'item_list' => $d_list, * 'footer' => 'some footer text' * ), * 'options' => array( * 1 => array( * 'header' => 'some header text', * 'smessage' => __('Click \'Continue\' to Delete the following User Domain.'), * 'pmessage' => __('Click \'Continue\' to Delete following User Domains.'), * 'scont' => __('Delete User Domain'), * 'pcont' => __('Delete User Domains') * 'footer' => 'some footer text' * ), * 2 => array( * 'header' => 'some header text', * 'smessage' => __('Click \'Continue\' to Disable the following User Domain.'), * 'pmessage' => __('Click \'Continue\' to Disable following User Domains.'), * 'scont' => __('Disable User Domain'), * 'pcont' => __('Disable User Domains'), * 'extra' => array( * 'group_prefix' => array( * 'method' => 'textbox', * 'title' => __('Group Prefix:'), * 'default' => __('New Group'), * 'width' => 25, * 'size' => 25 * ) * ), * 'footer' => 'some footer text' * ) * ); * * @param string $plugin_hook The plugin hook to call for the continuation * @param array $save An array of data to save for the continuation * * @return void Data is streamed through stdout */ function form_continue_confirmation(array $form_data, string $plugin_hook = '', array $save = []) : void { $page = $form_data['general']['page']; $actions = $form_data['general']['actions']; $drpvar = $form_data['general']['optvar']; $iarray = $form_data['general']['item_array']; $ilist = $form_data['general']['item_list']; $drpval = gnrv($drpvar); $poutput = ''; $form_name = 'form'; $title = ''; $message = ''; if (!isset($form_data['options'][$drpval]) && $plugin_hook != '' && cacti_sizeof($iarray)) { $title = __('Proceed with action'); if (!cacti_sizeof($save)) { // Legacy plugin form confirmation logic $save['drp_action'] = $drpval; if ($ilist != '') { $save['ds_list'] = $ilist; } if (cacti_sizeof($iarray)) { $save['ds_array'] = $iarray; } } // Trap the output ob_start(); api_plugin_hook_function($plugin_hook, $save); $poutput = ob_get_clean(); } elseif (cacti_sizeof($iarray)) { $data = $form_data['options'][$drpval]; if (isset($data['return']) && $data['return'] == true) { raise_message('form_return', $data['rmessage'], MESSAGE_LEVEL_ERROR); header('Location: ' . $page); exit; } if (cacti_sizeof($iarray) > 1) { if (isset($data['pmessage'])) { $message = $data['pmessage']; } elseif (isset($data['message'])) { $message = $data['message']; } if (isset($data['pcont'])) { $title = $data['pcont']; } elseif (isset($data['cont'])) { $title = $data['cont']; } } else { if (isset($data['smessage'])) { $message = $data['smessage']; } elseif (isset($data['message'])) { $message = $data['message']; } if (isset($data['scont'])) { $title = $data['scont']; } elseif (isset($data['cont'])) { $title = $data['cont']; } } } else { raise_message(40); header('Location: ' . $page); exit; } top_header(); form_start($page, 'action_confirm'); html_start_box($actions[$drpval], '60%', true, 3, 'center', ''); if ($message != '') { print "

    $message

    "; } if (isset($form_data['general']['header'])) { print "

    "; print $form_data['general']['header']; print '

    '; } if (isset($data['header'])) { print "

    "; print $data['header']; print '

    '; } if ($ilist != '' && $poutput == '') { print "
    "; print "
      $ilist
    "; print '
    '; } if (isset($data['flist'])) { if (cacti_sizeof($iarray) > 1) { if (isset($data['pfmessage'])) { $message = $data['pfmessage']; } elseif (isset($data['fmessage'])) { $message = $data['fmessage']; } } else { if (isset($data['sfmessage'])) { $message = $data['sfmessage']; } elseif (isset($data['fmessage'])) { $message = $data['fmessage']; } } print "
    "; print "

    $message

    "; print '
    '; print "
    "; print "
      {$data['flist']}
    "; print '
    '; } if (isset($data['extra'])) { // prepend checkboxes for this form $form_array = []; foreach ($data['extra'] as $field_name => $field_array) { $form_array += [$field_name => $field_array]; $form_array[$field_name]['value'] = ''; // two form overrides if (isset($field_array['title'])) { $form_array[$field_name]['friendly_name'] = $field_array['title']; } elseif (!isset($form_array[$field_name]['friendly_name'])) { $form_array[$field_name]['friendly_name'] = ''; } if (isset($field_array['width'])) { $form_array[$field_name]['max_length'] = $field_array['width']; } if (read_config_option('hide_form_description') == 'on') { $form_array[$field_name]['description'] = ''; } $form_array[$field_name]['form_id'] = 0; if (isset($field_array['confirm'])) { $form_array[$field_name]['sub_checkbox'] = [ 'name' => 't_' . $field_name, 'friendly_name' => __('Update this Field'), 'class' => 'ui-state-disabled', 'value' => '' ]; } } print "
    "; draw_edit_form( [ 'config' => ['no_form_tag' => true], 'fields' => $form_array ] ); print '
    '; } if (isset($data['footer'])) { print "

    "; print $data['footer']; print '

    '; } if (isset($form_data['general']['footer'])) { print "

    "; print $form_data['general']['footer']; print '

    '; } if ($poutput != '') { print $poutput; } print "
    "; print ""; if (isset($form_data['general']['eaction'])) { if (!isset($form_data['general']['eactionid'])) { $form_data['eactionid'] = 1; } print ""; } if (isset($data['eaction'])) { if (!isset($data['eactionid'])) { $data['eactionid'] = 1; } print ""; } print ""; print ""; print "'; print "'; print '
    '; html_end_box(false, true); form_end(); bottom_footer(); } /** * Draws a table presenting the user with some choice and allowing * them to either proceed (delete) or cancel * * @param string $body_text The text to prompt the user with on this form * @param mixed $cancel_url The url to go to when the user clicks 'cancel' * @param mixed $action_url The url to go to when the user clicks 'delete' * * @return void */ function form_confirm(string $title_text, string $body_text, mixed $cancel_url, $action_url) : void { ?>
    " . $calt . ''; } else { $cancel_action = ''; } ?>
    " . $calt . ''; } else { $cancel_action = ''; } ?>
    ' . htmle($b['value']) . '' . PHP_EOL; } ?>
    '; } /** * Draws post form end. To be combined with form_start() * * This function prints the closing tag and, if the $ajax parameter is true, * includes JavaScript to handle unsaved form data warnings and form validation. * * @param bool $ajax Whether to include AJAX handling JavaScript. Default true. * * @return void */ function form_end(bool $ajax = true) : void { global $form_id, $form_action; print '' . PHP_EOL; if ($ajax) { if ($form_id == null) { cacti_log('WARNING: Function: form_end() called without a form_start() called first', false); cacti_debug_backtrace('FORM', false, true); $form_id = 'empty'; } ?>