[ * 'name_of_col_in_table' => [ * 'value' => $name_of_col_in_table', * 'pk' => 1/0 - sets the primary key (only one) * 'fk' => 1/0 - sets the foreign key (do not use at the moment ... buggy ;) * 'mandatory' => 1/0 - triggers * in output, but nor error check * 'output_name' => 'text' - text put as label for the element * 'type' => 'view/text/textarea/date/drop_down_db/drop_down_array/drop_down_db_input/drop_down_db_same_db/radio_array/binary/hidden/file/password' * View is special, it just prints out the data as is, will not be saved * 1) more will come * 2) keep in mind that binary will not be checked, as it is always set to a value (default is 'no') * ---- the next four fields are only NECESSARY (!!!) for drop_down_db_input * 'table_name' => the name of the table for the drop down * 'pk_name' => the pk_name of the table for the drop down * 'input_name' => the text field name in the table for the drop down * 'input_value' => the $name of input_name (must be same) * 'order_by' => 'order bY' string for drop_down_db(_input) if no query given but fields set * 'query' => for drop_down_db/array if no outer query given * 'preset' => value to preset when array is unset (available for all types) * 'element_list' => ['true', 'false'] - MUST (!) be set for binary * 'length' => 'nr' - only available for 'text' (maxlength) * 'size' => 'nr' - only available for 'text' (size of input field) * 'rows' => 'nr' - only available for 'textarea' * 'cols' => 'nr' - only available for 'textarea' * 'error_check' => 'custom/email/date/number/unique' - 1) more will come * 'error_regex' => 'regex' - if error_check is custom regex here * 'error_example' => 'text' - example input text for error_check (only custom right now) * 'empty' => 'value/text' - ONLY for view. If no data found, set this value * --- file: * 'save_dir' => 'directory where it should be saved to * 'accept_type' => 'mime types accepted (mime/text,mime/jpeg ... etc)' * ], * ... * ], * # all reference tables (n<->n) * 'reference_array' => [ * 'name_u_choose' => [ * 'table_name' => 'table_u_choose_for_n_to_n_table', * 'other_table_pk' => 'primary_key_name_of_reference_table', * 'output_name' => 'Printed out next to multiple select field', * 'mandatory' => 1/0 for must be selected, * 'select_size' => size of multiple select field, * 'query' => 'the query to load the multiple select field * (select id, concat_ws(' ',name_a, name_b) from reference_table)', * 'selected' => $var_name for name='xx' in multiple select * ], * ... * ], * # fields that should be shown from the load_query and with what aditions * 'show_fields' => [ * [ * 'name' => 'name_of_col_in_query' - col from the query that should be shown * 'before_value' => 'text' - if set this text will be put in FRONT of the value from the col * 'binary' => ['true','false'] - for 1/0 fields in DB changes it int human readable format * ], * ... * ], * # the laod query * 'load_query' => 'query', - query for generting the list in 'load' function * # the name of the main table * 'table_name' => 'table_name' - the exakt name of the table ... * # security levels for load ... usefull is delete with a low number and load with a high * 'security_level' => * 'load' => ... for load to appear * 'new' => 1... - security level minimum required for new part to appear (goes in hadn with save) * 'save' => ... - should be same level as new [or its a bit useless] * 'delete' => ... - for delete * * example for a page: * * $form->form_procedure_load(${$form->archive_pk_name}); * $form->form_procedure_new(); * $form->form_procedure_save(); * $form->form_procedure_delete(); * * $form->form_create_load(); * $form->form_create_new(); * if ($form->yes) * { * $from->form_create_element('element_name'); * $from->form_create_hidden_fields(); * $form->form_creae_save_delete(); * } * $form->_form(); * * * list_of_functions: * form_get_col_name_from_key($want_key) * returns the value for the key (out of table_array) * form_get_col_name_array_from_key($want_key) * returns array of values for the searched key ... * form_print_msg () [form_error_msg()] * returns the HTML formated part with the error msg, if one exists * form_procedure_load($id) * starts the loading procedure * form_procedure_new() * starts the new procedure * form_procedure_save() * starts the save procedure * form_procedure_delete() * starts the delete procedure * form_create_load () [form_load()] * returns the HTML part for loading a table row, load_query & field_array have to be set for this!!!!!! * form_create_new () [form_new()] * returns the HTML part for creating a new table_row * form_create_save_delete () [form_delete_save()] * returns the HTML part for saveing and deleteing one table_row * form_create_element ($element_name, $query='') * creates and HTML element based on the description in the table_array array, * second parameter is for drop_down fields, either a query for _db or an array for _array * form_error_check() * checks on errors after submit based on the settings in the table_array array * form_set_order() * if it finds the order flag set in the table_array sets the order for the current element to MAX+1 from the DB * form_unset_table_array() * unsets the table_array value fields for new entries * form_create_hidden_fields($hidden_array) * outputs a string with the HTML hidden fields (array must be $name['hidden_name']=$hidden_value) * form_create_element_reference_table($table_name) [form_show_reference_table()] * creates and table tr part for the reference table name given * form_load_table_array($pk_id=0) * loads the table_array and the reference tables for the pk_id set in the class or given via parameter * form_save_table_array($addslashes=0) * save table array & reference tables * form_delete_table_array() * deletes table array & reference tables * * // debug methods * form_dump_table_array() * returns a formatted string with alle table_array vars * * HISTORY: * 2005/07/14 (cs) fixed the insert for reference tables, prepared drop down text insert to be correct [untested] * 2005/07/08 (cs) added int set for integer insert values * 2005/07/07 (cs) bug with protected data, error got triggered even if no delete was pressed * 2005/06/30 (cs) changed color settings, they get set from CSS file now * 2005/06/29 (cs) finished full support for element_lists * 2005/06/24 (cs) added full support for a list in a form, a list is written * to an other table and the other table has this forms PK as a FK * 2005/06/23 (cs) changed all HTML to Smarty Template Type * 2005/06/22 (cs) you can put more than one error check into the error field; * alphanumeric check and unique in same table are new * 2005/06/21 (cs) changed the error_msg writings to debug * 2005/03/31 (cs) fixed the class call with all debug vars * 2004/11/10 (cs) fix bug with preset: don't check if set, check if variable is set at all * 2004/09/30 (cs) layout change * 2003-06-13: error with 'protected' flag, fixed and added error msg, * if protected flag is detected during delete * 2003-06-12: adapted class to register_global_vars off * 2003-06-10: in procedure_delete function I added 'protected' variable clause, * so if this field exists in the DB and is set, you are not able to delete * [at the moment used for admin edit user in DB] * 2003-05-30: _temp for drop_down_db was added always and not only for same_db * 2003-05-28: added drop_down_db_same_db for drop down/input combinations going into the same DB. * WARNING!!! please be careful that input_value var name MUST have the ending _temp * This might get change in future * added a 'where' field to the field list, this is only used for the drop_down for selecting * only a certain field list. If where is filled out and used in combination with insert (not same_db) * then this key will be SET when inserted into the DB !!! * 2003-04-09: added open_dir for download of file (URL), save_dir is only for upload (absolute path) * added require once for class_db_array_io.php * 2003-03-31: added a file upload module (type==file) * 2003-03-20: added form_procedure_new, etc functions so for default calls it is easier to write * also added security levels to all functions where it is needed * 2003-03-14: changed the static error msgs to dynamic ones * 2003-03-13: very bad bug with getting key function. fixed it (set first array value always) * reason was that in second if I forgot to check if the second method field was really * set, so I compared to empty which was always right. * 2003-03-11: started renaming some functions: * form_load, form_new, form_delete_save -> form_create_... (and _save_delete) * .._show_reference_table -> create_element_reference_table * added language array * - kept old var names/function names for backward compatbile * 2003-03-10: added flag for form_delete_save, first flag hides delete part, second flag * hides checkbox for delete, both are set 0 default * added drop_down_db_input element type. * next to a drop down with elements froma db, there is an input field, * if something is input there and not yet in the DB it will be inserted into * the db first and then selected in the drop down, if already in db, the element * in the drop down will be selected * 2003-03-07: form_create_hidden_fields() has to be called mandatory * 2003-03-06: if nothing selected for reference table, do not write * a wrong return in form_delete_table_array quit the function to early * 2003-03-04: drop_down_array value for option was left from array and * not right * 2003-02-27: added another check in unset if reference array exists * 2003-02-26: change form to extend db_array_io and created load, save, * delete functions removed all reference table functions, * except show function rewrite config array * re-wrote the class info vars into array * 2003-02-25: added reference table functions * 2002-10-22: create this class so creating basic and medium form pages * can be handled easy. * with a given config file the class handles error checks, * save data, loads data, etc *********************************************************************/ declare(strict_types=1); namespace CoreLibs\Output\Form; use CoreLibs\Get\System; use CoreLibs\Debug\Support; class Generate { // for the load statetment describes which elements from // the load query should be shown and i which format /** @var array */ public array $field_array = []; /** @var string */ public string $load_query; // the query needed for loading a data set (one row in the table) /** @var string */ public string $col_name; // the name of the columen (before _) [used for order button] /** @var int */ public int $yes = 0; // the yes flag that triggers the template to show ALL and not only new/load /** @var string */ public string $msg = ''; // the error msg /** @var int */ public int $error = 0; // the error flag set for printing red error msg /** @var int */ public int $warning = 0; // warning flag, for information (saved, loaded, etc) /** @var string */ public string $archive_pk_name; // the pk name for the load select form /** @var string */ private string $int_pk_name; // primary key, only internal usage /** @var array */ public array $reference_array = []; // reference arrays -> stored in $this->reference_array[$table_name] => []; // NOTE: should be changed to this @var mixed[] /** @var array */ public array $element_list = []; // element list for elements next to each other as a special sub group /** @var array */ public array $table_array = []; /** @var string */ public string $my_page_name; // the name of the page without .php extension /** @var bool */ public bool $mobile_phone = false; /** @var string */ public string $email_regex; // buttons and checkboxes /** @var string */ public string $archive; /** @var string */ public string $new; /** @var string */ public string $really_new; /** @var string */ public string $delete; /** @var string */ public string $really_delete; /** @var string */ public string $save; /** @var string */ public string $remove_button; // security values /** @var int base acl for current page */ private int $base_acl_level = 0; /** @var int admin master flag (1/0) */ private int $acl_admin = 0; /** @var array */ public array $security_level; /** @var array Login ACL */ public array $login_acl = []; // layout publics /** @var int */ public int $table_width = 0; // internal lang & encoding vars /** @var string */ public string $lang_dir = ''; /** @var string */ public string $lang; /** @var string */ public string $lang_short; /** @var string */ public string $domain; /** @var string */ public string $encoding; // language /** @var \CoreLibs\Language\L10n */ public \CoreLibs\Language\L10n $l; // log /** @var \CoreLibs\Logging\Logging */ public \CoreLibs\Logging\Logging $log; /** @var \CoreLibs\DB\Extended\ArrayIO */ public \CoreLibs\DB\Extended\ArrayIO $dba; // now some default error msgs (english) /** @var array */ public array $language_array = []; /** * construct form generator * * phpcs:ignore * @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[],db_convert_placeholder?:bool,db_convert_placeholder_target?:string,db_debug_replace_placeholder?:bool} $db_config db config array, mandatory * @param \CoreLibs\Logging\Logging $log Logging class * @param \CoreLibs\Language\L10n $l10n l10n language class * @param array $login_acl Login ACL array, * at least base/admin should be set * @param array|null $table_arrays Override table array data * instead of try to load from * include file * @throws \Exception 1: No table_arrays set/no class found for my page name */ public function __construct( array $db_config, \CoreLibs\Logging\Logging $log, \CoreLibs\Language\L10n $l10n, array $login_acl, ?array $table_arrays = null, ) { // init logger if not set $this->log = $log; // don't log per class $this->log->unsetLogFlag(\CoreLibs\Logging\Logger\Flag::per_class); // init the language class $this->l = $l10n; // parse and read, legacy stuff $locale = $this->l->getLocaleAsArray(); $this->encoding = $locale['encoding']; $this->lang = $locale['lang']; $this->lang_short = $locale['lang_short']; $this->domain = $locale['domain']; $this->lang_dir = $locale['path']; // load config array // get table array definitions for current page name $this->login_acl = $login_acl; // security settings $this->base_acl_level = $this->login_acl['base'] ?? 0; $this->acl_admin = $this->login_acl['admin'] ?? 0; // replace any non valid variable names and set my page name $this->my_page_name = str_replace( ['.'], '_', System::getPageName(System::NO_EXTENSION) ); // first check if we have a in page override as $table_arrays[page name] if ( isset($table_arrays[System::getPageName(System::NO_EXTENSION)]) && is_array($table_arrays[System::getPageName(System::NO_EXTENSION)]) ) { // $config_array = $GLOBALS['table_arrays'][System::getPageName(1)]; $config_array = $table_arrays[System::getPageName(1)]; } else { // primary try to load the class /** @var TableArrays\Interface\TableArraysInterface|false $content_class */ $content_class = $this->loadTableArray(); if (is_object($content_class)) { $config_array = $content_class->setTableArray(); } else { // throw an error here as we cannot load the class at all throw new \Exception("Cannot load " . $this->my_page_name, 1); } } // $log->debug('CONFIG ARRAY', $log->prAr($config_array)); // start the array_io class which will start db_io ... $this->dba = new \CoreLibs\DB\Extended\ArrayIO( $db_config, $config_array['table_array'], $config_array['table_name'], $this->log, // set the ACL $this->base_acl_level, $this->acl_admin ); // here should be a check if the config_array is correct ... if (isset($config_array['show_fields']) && is_array($config_array['show_fields'])) { $this->field_array = $config_array['show_fields']; } if (isset($config_array['load_query']) && $config_array['load_query']) { $this->load_query = $config_array['load_query']; } if (empty($this->load_query)) { $this->log->error('Missing Load Query for: ' . $this->my_page_name); } $this->archive_pk_name = 'a_' . $this->dba->getPkName(); $this->col_name = str_replace('_id', '', $this->dba->getPkName()); $this->int_pk_name = $this->dba->getPkName(); // check if reference_arrays are given and proceed them if (isset($config_array['reference_arrays']) && is_array($config_array['reference_arrays'])) { foreach ($config_array['reference_arrays'] as $key => $value) { $this->reference_array[$key] = $value; } } if (isset($config_array['element_list']) && is_array($config_array['element_list'])) { foreach ($config_array['element_list'] as $key => $value) { $this->element_list[$key] = $value; } } // set button vars $this->archive = $_POST['archive'] ?? ''; $this->new = $_POST['new'] ?? ''; $this->really_new = $_POST['really_new'] ?? ''; $this->delete = $_POST['delete'] ?? ''; $this->really_delete = $_POST['really_delete'] ?? ''; $this->save = $_POST['save'] ?? ''; $this->remove_button = $_POST['remove_button'] ?? ''; // security levels for buttons/actions // if array does not exists create basic if ( !isset($config_array['security_level']) || (isset($config_array['security_level']) && (!is_array($config_array['security_level']) || (is_array($config_array['security_level']) && count($config_array['security_level']) < 4)) ) ) { $this->security_level = [ 'load' => 20, 'new' => 100, 'save' => 40, 'delete' => 100 ]; } else { // write array to class var $this->security_level = isset($config_array['security_level']) ? $config_array['security_level'] : [ 'load' => 20, 'new' => 100, 'save' => 40, 'delete' => 100 ]; } // set email regex $this->email_regex = \CoreLibs\Check\Email::getEmailRegex(); } // PRIVATE METHODS |=================================================> /** * load table array class based on my page name converted to camel case * class files are in \TableArrays folder in \Output\Form * @return TableArrays\Interface\TableArraysInterface|false Return class object or false on failure */ private function loadTableArray(): TableArrays\Interface\TableArraysInterface|false { // note: it schould be Schemas but an original type made it to this // this file is kept for the old usage, new one should be EditSchemas $table_array_shim = [ 'EditSchemes' => 'EditSchemas' ]; // camel case $this->my_page_name from foo_bar_note to FooBarNote $page_name_camel_case = ''; foreach (explode('_', $this->my_page_name) as $part) { $page_name_camel_case .= ucfirst($part); } $class_string = __NAMESPACE__ . "\\TableArrays\\" . ( // shim lookup $table_array_shim[$page_name_camel_case] ?? $page_name_camel_case ); try { /** @var TableArrays\Interface\TableArraysInterface|false $class */ $class = new $class_string($this); } catch (\Throwable $t) { $this->log->critical('CLASS LOADING: Failed loading: ' . $class_string . ' => ' . $t->getMessage()); return false; } if (is_object($class)) { return $class; } return false; } // PUBLIC METHODS |=================================================> /** * return current acl admin flag (1/0) * * @return int Admin flag 1 for on or 0 for off */ public function getAclAdmin(): int { return $this->acl_admin; } /** * check if current acl level is match to requested on * * @param int $level Requested ACL level * @return bool if current level equal or larger return tru, else false */ public function checkBaseACL(int $level): bool { return $this->base_acl_level >= $level ? true : false; } /** * dumps all values into output (for error msg) * * @return string full table array data output as string html formatted */ public function formDumpTableArray() { $string = 'TABLE ARRAY DUMP: ' . $this->dba->getTableName() . '
'; foreach ($this->dba->getTableArray() as $key => $value) { $string .= '' . $key . ': ' . $value['value'] . '
'; } return $string; } /** * the value of the $want_key array field * works only with fields that appear only ONCE * if multiple gets only FIRST * * @param string $want_key key to search for * @param string|null $key_value value to match to (optional) * @return string|null returns key found or empty string */ public function formGetColNameFromKey( string $want_key, ?string $key_value = null ): ?string { foreach ($this->dba->getTableArray() as $key => $value) { if (isset($value[$want_key]) && !$key_value) { return $key; } elseif (isset($value[$want_key]) && $value[$want_key] == $key_value && $key_value) { return $key; } } // return nothing on nothing return null; } /** * array of fields * * @param string $want_key the key where you want the data from * @param string|null $key_value if set searches for special right value * @return array found key fields */ public function formGetColNameArrayFromKey( string $want_key, ?string $key_value = null ): array { $key_array = []; foreach ($this->dba->getTableArray(true) as $key => $value) { if ($value[$want_key] && !$key_value) { array_push($key_array, $key); } if ($value[$want_key] == $key_value) { array_push($key_array, $key); } } return $key_array; } /** * formated output for the error && warning msg * * @return array error message with msg, width, clas */ public function formPrintMsg(): array { $class = ''; if ($this->error) { $class = 'error'; } if ($this->warning) { $class = 'warning'; } return [ 'msg' => $this->msg, 'width' => $this->table_width, 'class' => $class ]; } // next for functions are pre_test fkts for easier default new,load, etc handling /** * default load procedure * * @param string $archive_id archive id to load * @return void has no return */ public function formProcedureLoad(string $archive_id): void { if ( isset($this->security_level['load']) && $this->archive && $archive_id && $this->base_acl_level >= $this->security_level['load'] ) { $this->formLoadTableArray($archive_id); $this->yes = 1; } } /** * default new procedure * * @return void has no return */ public function formProcedureNew(): void { if ( isset($this->security_level['new']) && $this->new && $this->base_acl_level >= $this->security_level['new'] ) { if ($this->really_new == 'yes') { $this->formUnsetTableArray(); } else { $this->msg .= $this->l->__('You have to select the Checkbox for New!
'); $this->error = 2; } $this->yes = 1; } } /** * default save procedure * * @return void has no return */ public function formProcedureSave(): void { if ( isset($this->security_level['save']) && $this->save && $this->base_acl_level >= $this->security_level['save'] ) { $this->formErrorCheck(); if (!$this->error) { $this->formSaveTableArray(); } $this->yes = 1; } } /** * default delete procedure * * @return void has no return */ public function formProcedureDelete(): void { // delete is also by 'protected' if ( isset($this->security_level['delete']) && $this->delete && $this->base_acl_level >= $this->security_level['delete'] ) { if ( !empty($this->dba->getTableArray()['protected']['value']) ) { $this->msg .= $this->l->__('Cannot delete this Dataset, because it is internaly protected!'); $this->error = 2; } if ($this->really_delete == 'yes') { $this->formDeleteTableArray(); } else { $this->msg .= $this->l->__('You have to select the Checkbox for Delete!
'); $this->error = 2; $this->yes = 1; } } } /** * default delete procedure * * @param array $element_list element array that should be removed * @param array $remove_name key names that should be removed * @return void has no return */ public function formProcedureDeleteFromElementList( array $element_list, array $remove_name ): void { /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ $this->log->debug('REMOVE ELEMENT', 'Remove REF ELEMENT: ' . $this->base_acl_level . ' >= ' . $this->security_level['delete']); $this->log->debug('REMOVE ELEMENT', 'Protected Value set: ' . (string)isset($this->dba->getTableArray()['protected']['value'])); $this->log->debug('REMOVE ELEMENT', 'Error: ' . $this->error); // only do if the user is allowed to delete if ( isset($this->security_level['delete']) && $this->base_acl_level >= $this->security_level['delete'] && empty($this->dba->getTableArray()['protected']['value']) && !$this->error ) { for ($i = 0, $i_max = count($element_list); $i < $i_max; $i++) { // $this->log->debug('form_error', 'Array: ' // . is_array($this->element_list[$element_list[$i]]['read_data']) . ' | ' // . $this->element_list[$element_list[$i]]['delete']); // if prefix, set it $prfx = !empty($this->element_list[$element_list[$i]]['prefix']) ? $this->element_list[$element_list[$i]]['prefix'] . '_' : ''; // get the primary key $pk_name = ''; foreach ($this->element_list[$element_list[$i]]['elements'] as $el_name => $data) { if (isset($data['pk_id'])) { $pk_name = $el_name; break; } } // which key should be deleted $id = $remove_name[$i]; if ( (!empty($this->element_list[$element_list[$i]]['delete_name']) || !empty($this->element_list[$element_list[$i]]['delete'])) && empty($this->element_list[$element_list[$i]]['enable_name']) ) { // flag var name $flag = $remove_name[$i] . '_flag'; if ($_POST[$flag] == 'true') { $q = 'DELETE FROM ' . $element_list[$i] . ' WHERE ' . $pk_name . ' = ' . $_POST[$id]; $this->dba->dbExec($q); $this->msg .= $this->l->__('Removed entry from list
'); $this->warning = 1; } // post okay true -> delete } elseif ( isset($this->element_list[$element_list[$i]]['read_data']) && !$this->element_list[$element_list[$i]]['delete'] ) { if (!isset($_POST[$id])) { $_POST[$id] = []; } for ($j = 0, $j_max = count($_POST[$id]); $j < $j_max; $j++) { // if it is not activated if (!$_POST[$remove_name[$i]][$j]) { $q = 'UPDATE ' . $element_list[$i] . ' WHERE ' . $pk_name . ' = ' . $_POST[$prfx . $pk_name][$j]; // $this->log->debug('edit_db', 'UP: $q'); // $this->dbExec($q); $this->msg .= $this->l->__('Disabled deselected entries from list
'); $this->warning = 1; } } } elseif ( isset($this->element_list[$element_list[$i]]['read_data']) && $this->element_list[$element_list[$i]]['delete'] ) { // $this->log->debug('form_clean', 'ID [$id] [$prfx . $pk_name]'); // $this->log->debug('form_clean', 'ID arr: ' . $this->log->prAr($_POST[$id])); // $this->log->debug('form_clean', 'PK arr: ' . $this->log->prAr($_POST[$prfx.$pk_name])); for ($j = 0, $j_max = count($_POST[$prfx . $pk_name]); $j < $j_max; $j++) { if (!$_POST[$remove_name[$i]][$j] && $_POST[$prfx . $pk_name][$j]) { $q = 'DELETE FROM ' . $element_list[$i] . ' WHERE ' . $pk_name . ' = ' . $_POST[$prfx . $pk_name][$j]; // $this->log->debug('edit_db', 'DEL: $q'); $this->dba->dbExec($q); $this->msg .= $this->l->__('Deleted deselected entries from list
'); $this->warning = 1; } } } } // for each element group } if ($this->remove_button) { $this->yes = 1; } } /** * create the load list and return it as an array * * * @return array load list array with primary key, name and selected entry */ public function formCreateLoad(): array { $pk_selected = ''; $t_pk_name = ''; $pk_names = []; $pk_ids = []; $seclevel_okay = false; // for error abort only $return_array = [ 't_pk_name' => $t_pk_name, 'pk_ids' => $pk_ids, 'pk_names' => $pk_names, 'pk_selected' => $pk_selected, 'seclevel_okay' => $seclevel_okay, ]; // when security level is okay ... if ( empty($this->security_level['load']) || $this->base_acl_level < $this->security_level['load'] ) { return $return_array; } if (empty($this->load_query)) { $this->log->error('Missing load list query'); return $return_array; } $t_pk_name = $this->archive_pk_name; // load list data $this->dba->dbExec($this->load_query); while (is_array($res = $this->dba->dbFetchArray())) { $pk_ids[] = $res[$this->int_pk_name]; if ( isset($this->dba->getTableArray()[$this->int_pk_name]['value']) && $res[$this->int_pk_name] == $this->dba->getTableArray()[$this->int_pk_name]['value'] ) { $pk_selected = $res[$this->int_pk_name]; } $t_string = ''; foreach ($this->field_array as $field_array) { if ($t_string) { $t_string .= ', '; } if (!empty($field_array['before_value'])) { $t_string .= $this->l->__($field_array['before_value']); } // must have res element set if ( !empty($field_array['name']) && isset($res[$field_array['name']]) ) { $_t_value = ''; // if we have a binary set, where 0 = YES and 1 = NO if (!empty($field_array['binary'])) { $_t_value = !empty($res[$field_array['name']]) ? ($field_array['binary'][0] ?? 'Yes') : ($field_array['binary'][1] ?? 'No'); } else { $_t_value = $res[$field_array['name']]; } $t_string .= $this->l->__($_t_value); } } $pk_names[] = $t_string; } $seclevel_okay = true; return [ 't_pk_name' => $t_pk_name, 'pk_ids' => $pk_ids, 'pk_names' => $pk_names, 'pk_selected' => $pk_selected, 'seclevel_okay' => $seclevel_okay, ]; } /** * Create new entry element for HTML output * * @param bool $hide_new_checkbox show or hide the new checkbox, default is false * @return array return the new create array with name & checkbox show flag */ public function formCreateNew(bool $hide_new_checkbox = false): array { $show_checkbox = false; $new_name = ''; $seclevel_okay = false; // when security level is okay if ( empty($this->security_level['new']) || $this->base_acl_level < $this->security_level['new'] ) { return [ 'new_name' => $new_name, 'show_checkbox' => $show_checkbox, 'seclevel_okay' => $seclevel_okay, ]; } if ($this->yes && !$hide_new_checkbox) { $show_checkbox = false; } // set type of new name if ($this->yes) { $new_name = $this->l->__('Clear all and create new'); } else { $new_name = $this->l->__('New'); } $seclevel_okay = true; return [ 'new_name' => $new_name, 'show_checkbox' => $show_checkbox, 'seclevel_okay' => $seclevel_okay, ]; } /** * create the save and delete element html group data * @param bool $hide_delete hide the delete button (default false) * @param bool $hide_delete_checkbox hide the delete checkbox (default false) * @return array return the hide/show delete framework * for html creation */ public function formCreateSaveDelete( bool $hide_delete = false, bool $hide_delete_checkbox = false, bool $old_school_hidden = false ): array { $seclevel_okay = false; $save = ''; $pk_name = ''; $pk_value = ''; $show_delete = false; if ( (empty($this->security_level['save']) || $this->base_acl_level < $this->security_level['save']) && (empty($this->security_level['delete']) || $this->base_acl_level < $this->security_level['delete']) ) { return [ 'seclevel_okay' => $seclevel_okay, 'save' => $save, 'pk_name' => $pk_name, 'pk_value' => $pk_value, 'show_delete' => $show_delete, 'old_school_hidden' => $old_school_hidden, 'hide_delete_checkbox' => $hide_delete_checkbox ]; } if ( !empty($this->security_level['save']) && $this->base_acl_level >= $this->security_level['save'] ) { $seclevel_okay = true; if (empty($this->dba->getTableArray()[$this->int_pk_name]['value'])) { $save = $this->l->__('Save'); } else { $save = $this->l->__('Update'); } // print the old_school hidden if requestet if ($old_school_hidden === true) { $pk_name = $this->int_pk_name; $pk_value = $this->dba->getTableArray()[$this->int_pk_name]['value']; } } // show save part // show delete part only if pk is set && we want to see the delete if ( !empty($this->dba->getTableArray()[$this->int_pk_name]['value']) && !$hide_delete && !empty($this->security_level['delete']) && $this->base_acl_level >= $this->security_level['delete'] ) { $show_delete = true; } return [ 'seclevel_okay' => $seclevel_okay, 'save' => $save, 'pk_name' => $pk_name, 'pk_value' => $pk_value, 'show_delete' => $show_delete, 'old_school_hidden' => $old_school_hidden, 'hide_delete_checkbox' => $hide_delete_checkbox ]; // end of function } /** * create a form element based on the settings in the element array entry * * @param string $element_name the name from the array, you want to have build * @param string|null $query can overrule internal query data, * for drop down, as data comes from a reference table * for drop_down_text it has to be an * array with $key->$value * @return array html settings array */ public function formCreateElement(string $element_name, ?string $query = null): array { $data = []; // special 2nd color for 'binary' attribut if ( $this->dba->getTableArray()[$element_name]['type'] == 'binary' && !isset($this->dba->getTableArray()[$element_name]['value']) ) { $EDIT_FGCOLOR_T = 'edit_fgcolor_no'; } else { $EDIT_FGCOLOR_T = 'edit_fgcolor'; } $output_name = $this->dba->getTableArray()[$element_name]['output_name']; if ( isset($this->dba->getTableArray()[$element_name]['mandatory']) && $this->dba->getTableArray()[$element_name]['mandatory'] ) { $output_name .= ' *'; } // create right side depending on 'definiton' in table_array $type = $this->dba->getTableArray()[$element_name]['type']; // set default min edit/read to 100 (admin) $min_edit_acl = $this->dba->getTableArray()[$element_name]['min_edit_acl'] ?? 100; $min_show_acl = $this->dba->getTableArray()[$element_name]['min_show_acl'] ?? 100; $show_value = '-'; // view only output if ($this->dba->getTableArray()[$element_name]['type'] == 'view') { $data['value'] = empty($this->dba->getTableArray()[$element_name]['value']) ? $this->dba->getTableArray()[$element_name]['empty'] : $this->dba->getTableArray()[$element_name]['value']; $show_value = $data['value']; } // binary true/false element if ($this->dba->getTableArray()[$element_name]['type'] == 'binary') { $data['checked'] = 0; for ($i = (count($this->dba->getTableArray()[$element_name]['element_list']) - 1); $i >= 0; $i--) { $data['value'][] = $i; $data['output'][] = $this->dba->getTableArray()[$element_name]['element_list'][$i] ?? null; $data['name'] = $element_name; if ( isset($this->dba->getTableArray()[$element_name]['value']) && (($i && $this->dba->getTableArray()[$element_name]['value']) || (!$i && !$this->dba->getTableArray()[$element_name]['value'])) ) { $data['checked'] = $this->dba->getTableArray()[$element_name]['value']; $show_value = $this->dba->getTableArray()[$element_name]['element_list'][$i] ?? $data['checked']; } if ($i) { $data['separator'] = ''; } } } // checkbox element if ($this->dba->getTableArray()[$element_name]['type'] == 'checkbox') { $data['name'] = $element_name; $data['value'][] = $this->dba->getTableArray()[$element_name]['element_list']; $data['checked'] = $this->dba->getTableArray()[$element_name]['value']; // array map element list + value // foreach ($data['checked'] as $checked) $show_value = join(', ', $data['checked']); } // normal text element if ($this->dba->getTableArray()[$element_name]['type'] == 'text') { $data['name'] = $element_name; $data['value'] = $this->dba->getTableArray()[$element_name]['value'] ?? ''; $data['size'] = $this->dba->getTableArray()[$element_name]['size'] ?? ''; $data['length'] = $this->dba->getTableArray()[$element_name]['length'] ?? ''; $show_value = $data['value']; } // password element, does not write back the value if ($this->dba->getTableArray()[$element_name]['type'] == 'password') { $data['name'] = $element_name; $data['HIDDEN_value'] = $this->dba->getTableArray()[$element_name]['HIDDEN_value']; $data['size'] = $this->dba->getTableArray()[$element_name]['size'] ?? ''; $data['length'] = $this->dba->getTableArray()[$element_name]['length'] ?? ''; } // date (YYYY-MM-DD) if ($this->dba->getTableArray()[$element_name]['type'] == 'date') { $data['name'] = $element_name; $data['value'] = $this->dba->getTableArray()[$element_name]['value'] ?? ''; $show_value = $data['value']; } // date time (no sec) (YYYY-MM-DD HH:mm) if ($this->dba->getTableArray()[$element_name]['type'] == 'datetime') { $data['name'] = $element_name; $data['value'] = $this->dba->getTableArray()[$element_name]['value'] ?? ''; $show_value = $data['value']; } // textarea if ($this->dba->getTableArray()[$element_name]['type'] == 'textarea') { $data['name'] = $element_name; $data['value'] = $this->dba->getTableArray()[$element_name]['value'] ?? ''; $data['rows'] = $this->dba->getTableArray()[$element_name]['rows'] ?? ''; $data['cols'] = $this->dba->getTableArray()[$element_name]['cols'] ?? ''; $show_value = $data['value']; } // for drop_down_* if (preg_match("/^drop_down_/", $this->dba->getTableArray()[$element_name]['type'])) { $type = 'drop_down'; // outer query overrules inner if (empty($query) && !empty($this->dba->getTableArray()[$element_name]['query'])) { $query = $this->dba->getTableArray()[$element_name]['query']; } } // for drop_down_db* $data['drop_down_input'] = 0; if (preg_match("/^drop_down_db/", $this->dba->getTableArray()[$element_name]['type'])) { // if still NO query if (empty($query)) { // select pk_name, input_name from table_name (order by order_by) $query = "SELECT " . ( ( isset($this->dba->getTableArray()[$element_name]['select_distinct']) && $this->dba->getTableArray()[$element_name]['select_distinct'] ) ? "DISTINCT" : '' ) . " " . $this->dba->getTableArray()[$element_name]['pk_name'] . ", " . $this->dba->getTableArray()[$element_name]['input_name'] . " "; if (!empty($this->dba->getTableArray()[$element_name]['order_by'])) { $query .= ", " . $this->dba->getTableArray()[$element_name]['order_by'] . " "; } $query .= "FROM " . $this->dba->getTableArray()[$element_name]['table_name']; // possible where statements if (!empty($this->dba->getTableArray()[$element_name]['where'])) { $query .= " WHERE " . $this->dba->getTableArray()[$element_name]['where']; } // not self where if ( !empty($this->dba->getTableArray()[$element_name]['where_not_self']) && !empty($this->dba->getTableArray()[$this->int_pk_name]['value']) ) { // check if query has where already if (strstr($query, 'WHERE') === false) { $query .= " WHERE "; } else { $query .= " AND "; } $query .= " " . $this->int_pk_name . " <> " . $this->dba->getTableArray()[$this->int_pk_name]['value']; } // possible order statements if (!empty($this->dba->getTableArray()[$element_name]['order_by'])) { $query .= " ORDER BY " . $this->dba->getTableArray()[$element_name]['order_by']; } } // set output data $data['selected'] = ''; $data['name'] = $element_name; $data['value'][] = ''; $data['output'][] = $this->l->__('Please choose ... '); // $this->log->debug('DROP DOWN DB', 'TABLE ARRAY [' . $element_name . ']: ' // . $this->log->prAr($this->dba->getTableArray())); while (is_array($res = $this->dba->dbReturn($query))) { // $this->log->debug('DROP DOWN DB', 'Hightlight: [' . $element_name . '] ' // . ($this->dba->getTableArray()[$element_name]['value'] ?? '-') // . ' RES[0]: ' . $res[0] . ', Sel: ' . $res[1]); $data['value'][] = $res[0]; $data['output'][] = $res[1]; if ( isset($this->dba->getTableArray()[$element_name]['value']) && $this->dba->getTableArray()[$element_name]['value'] == $res[0] ) { $data['selected'] = $this->dba->getTableArray()[$element_name]['value']; $show_value = $res[1]; // $this->log->debug('DROP DOWN DB', 'Selectd [' . $element_name . ']: ' // . $data['selected'] . '/' . $show_value); // break; // continue; } } // $this->dbCacheReset($query); // for _input put additional field next to drop down if (preg_match("/^drop_down_db_input/", $this->dba->getTableArray()[$element_name]['type'])) { $data['drop_down_input'] = 1; // pre fill the temp if empty and other side is selected, only for same_db if ( $this->dba->getTableArray()[$element_name]['type'] == 'drop_down_db_input_same_db' && !$this->dba->getTableArray()[$element_name]['input_value'] && $this->dba->getTableArray()[$element_name]['value'] ) { $this->dba->getTableArray()[$element_name]['input_value'] = $this->dba->getTableArray()[$element_name]['value']; } $data['input_value'] = $this->dba->getTableArray()[$element_name]['input_value']; $data['input_name'] = $this->dba->getTableArray()[$element_name]['input_name'] . (($this->dba->getTableArray()[$element_name]['type'] == 'drop_down_db_input_same_db') ? '_temp' : '' ); $data['input_size'] = $this->dba->getTableArray()[$element_name]['size']; $data['input_length'] = $this->dba->getTableArray()[$element_name]['length']; } } // drop down array if ($this->dba->getTableArray()[$element_name]['type'] == 'drop_down_array') { $data['selected'] = ''; $data['name'] = $element_name; $data['value'][] = ''; $data['output'][] = $this->l->__('Please choose ... '); // outer query overrules inner foreach ($query as $key => $value) { $data['value'][] = $key; $data['output'][] = $value; if ($this->dba->getTableArray()[$element_name]['value'] == $key) { $data['selected'] = $this->dba->getTableArray()[$element_name]['value']; $show_value = $value; } } } // radio array if ($this->dba->getTableArray()[$element_name]['type'] == 'radio_array') { if (!$query) { $query = $this->dba->getTableArray()[$element_name]['query']; } $data['name'] = $element_name; foreach ($query as $key => $value) { $data['value'][] = $key; $data['output'][] = $value; if ($this->dba->getTableArray()[$element_name]['value'] == $key) { $data['checked'] = $this->dba->getTableArray()[$element_name]['value']; $show_value = $value; } $data['separator'] = ''; } } // for media / not yet implemented if ($this->dba->getTableArray()[$element_name]['type'] == 'media') { //media::insert_file($element_name,$this->dba->getTableArray()[$element_name]['value'],$query); } // order button if ($this->dba->getTableArray()[$element_name]['type'] == 'order') { $data['output_name'] = $this->dba->getTableArray()[$element_name]['output_name']; $data['name'] = $element_name; $data['value'] = $this->dba->getTableArray()[$element_name]['value'] ?? 0; $data['col_name'] = $this->col_name; $data['table_name'] = $this->dba->getTableName(); $data['query'] = $query !== null ? urlencode($query) : ''; } // file upload if ($this->dba->getTableArray()[$element_name]['type'] == 'file') { $data['name'] = $element_name; // if file for this exsists, print 'delete, view stuff' if ($this->dba->getTableArray()[$element_name]['value']) { $data['content'] = 1; $data['url'] = $this->dba->getTableArray()[$element_name]['open_dir'] . $this->dba->getTableArray()[$element_name]['value']; $data['output'] = $this->dba->getTableArray()[$element_name]['value']; $data['value'] = $this->dba->getTableArray()[$element_name]['value']; } } // $this->log->debug('ELEMENT CREATE', 'Data: [' . $output_name . '] ' . $this->log->prAr($data)); return [ 'output_name' => $output_name, 'color' => $EDIT_FGCOLOR_T, 'type' => $type, 'data' => $data, 'show_value' => $show_value, 'allow_edit' => $this->base_acl_level >= $min_edit_acl ? 1 : 0, 'allow_show' => $this->base_acl_level >= $min_show_acl ? 1 : 0, ]; } /** * full error message string for output * checks each filled entry to the table array defined error checks * should be cought like this ... * if ($msg = $form->form_error_check()) * $error=1; * * @return void has no return */ public function formErrorCheck(): void { foreach ($this->dba->getTableArray() as $key => $value) { // skip if we are not allowe to write this anyway // $this->log->debug('ERROR CHECK', 'ACL K: ' . $key . ', ' // . ($value['min_edit_acl'] ?? 100) . ' < ' . $this->base_acl_level); if ($this->base_acl_level < ($value['min_edit_acl'] ?? 100)) { continue; } //if ($value['mandatory'] && $value['error_check']) // if error value set && somethign input, check if input okay if ( isset($value['error_check']) && !empty($this->dba->getTableArray()[$key]['value']) ) { $this->log->debug('ERROR CHECK', 'Key: ' . $key . ' => ' . $value['error_check']); // each error check can be a piped seperated value, lets split it // $this->log->debug('edit', $value['error_check']); foreach (explode('|', $value['error_check']) as $error_check) { switch ($error_check) { case 'number': if (!is_numeric($this->dba->getTableArray()[$key]['value'])) { $this->msg .= sprintf( $this->l->__('Please enter a vailid Number for the %s Field!
'), $this->dba->getTableArray()[$key]['output_name'] ); } break; case 'date': // YYYY-MM-DD if (!\CoreLibs\Combined\DateTime::checkDate($this->dba->getTableArray()[$key]['value'])) { $this->msg .= sprintf( $this->l->__( 'Please enter a valid date (YYYY-MM-DD) for the %s Field!
' ), $this->dba->getTableArray()[$key]['output_name'] ); } break; case 'time': // HH:MM[:SS] if ( !\CoreLibs\Combined\DateTime::checkDateTime($this->dba->getTableArray()[$key]['value']) ) { $this->msg .= sprintf( $this->l->__( 'Please enter a valid time (HH:mm[:SS]) for the %s Field!
' ), $this->dba->getTableArray()[$key]['output_name'] ); } break; case 'datetime': // YYYY-MM-DD HH:MM[:SS] if ( !\CoreLibs\Combined\DateTime::checkDateTime($this->dba->getTableArray()[$key]['value']) ) { $this->msg .= sprintf( $this->l->__( 'Please enter a valid date time (YYYY-MM-DD HH:mm) ' . 'for the %s Field!
' ), $this->dba->getTableArray()[$key]['output_name'] ); } break; case 'intervalshort': // ony interval n [Y/M/D] only if ( !preg_match( "/^\d{1,3}\ ?([ymd]{1}|day(s)?|year(s)?|month(s)?)$/i", $this->dba->getTableArray()[$key]['value'] ) ) { $this->msg .= sprintf( $this->l->__( 'Please enter a valid time interval in the format ' . ' Y|M|D for the %s Field!
' ), $this->dba->getTableArray()[$key]['output_name'] ); } break; case 'email': if (!preg_match("/$this->email_regex/", $this->dba->getTableArray()[$key]['value'])) { $this->msg .= sprintf( $this->l->__( 'Please enter a valid E-Mail Address for the %s Field!
' ), $this->dba->getTableArray()[$key]['output_name'] ); } break; // check unique, check if field in table is not yet exist case 'unique': $q = 'SELECT ' . $key . ' AS unique_row ' . 'FROM ' . $this->dba->getTableName() . ' ' . 'WHERE ' . $key . ' = ' . "'" . $this->dba->dbEscapeString($this->dba->getTableArray()[$key]['value']) . "'"; if ($this->dba->getTableArray()[$this->int_pk_name]['value']) { $q .= ' AND ' . $this->int_pk_name . ' <> ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; } if ( is_array($s_res = $this->dba->dbReturnRow($q)) && !empty($s_res['unique_row']) ) { $this->msg .= sprintf( $this->l->__('The field %s can be used only once!
'), $this->dba->getTableArray()[$key]['output_name'] ); } break; case 'custom': if ( !preg_match( $this->dba->getTableArray()[$key]['error_regex'], $this->dba->getTableArray()[$key]['value'] ) ) { $this->msg .= sprintf( $this->l->__('Please enter a valid (%s) input for the %s Field!
'), $this->dba->getTableArray()[$key]['error_example'], $this->dba->getTableArray()[$key]['output_name'] ); } break; case 'alphanumericspace': // $this->log->debug('edit', 'IN Alphanumericspace'); if (!preg_match("/^[0-9A-Za-z_\-\ ]+$/", $this->dba->getTableArray()[$key]['value'])) { $this->msg .= sprintf( $this->l->__('Please enter a valid alphanumeric (Numbers and Letters, -, _ ' . 'and spaces allowed) value for the %s Field!
'), $this->dba->getTableArray()[$key]['output_name'] ); } break; case 'alphanumeric': // $this->log->debug('edit', 'IN Alphanumeric'); if (!preg_match("/^[0-9A-Za-z_\-]+$/", $this->dba->getTableArray()[$key]['value'])) { $this->msg .= sprintf( $this->l->__('Please enter a valid alphanumeric (Numbers and Letters only ' . 'also - and _, no spaces) value for the %s Field!
'), $this->dba->getTableArray()[$key]['output_name'] ); } break; // this one also allows @ and . case 'alphanumericextended': // $this->log->debug('edit', 'IN Alphanumericextended'); if (!preg_match("/^[0-9A-Za-z_\-@\.]+$/", $this->dba->getTableArray()[$key]['value'])) { $this->msg .= sprintf( $this->l->__('Please enter a valid alphanumeric extended (Numbers, Letters, -, ' . '_, @ and . only, no spaces) value for the %s Field!
'), $this->dba->getTableArray()[$key]['output_name'] ); } break; case 'password': // password can only be alphanumeric + special chars // password and CONFIRM_password need to be the same if ( $this->dba->getTableArray()[$key]['value'] != $this->dba->getTableArray()[$key]['CONFIRM_value'] ) { // error } break; case 'json': // check if valid json $json_out = json_decode($this->dba->getTableArray()[$key]['value'], true); $this->log->debug('JSON ENCODE', 'LAST ERROR: ' . json_last_error() . ' WITH: ' . $this->dba->getTableArray()[$key]['value']); if (json_last_error()) { $this->msg .= sprintf( $this->l->__('Please enter a valid JSON string for the field %s: %s'), $this->dba->getTableArray()[$key]['output_name'], json_last_error_msg() ); } break; } // switch } // for each error to check } elseif ( isset($value['mandatory']) && $value['mandatory'] && ( // for all 'normal' fields ( $this->dba->getTableArray()[$key]['type'] != 'password' && $this->dba->getTableArray()[$key]['type'] != 'drop_down_db_input' && !$this->dba->getTableArray()[$key]['value'] ) || // for drop_down_db_input check if one of both fields filled ( $this->dba->getTableArray()[$key]['type'] == 'drop_down_db_input' && !$this->dba->getTableArray()[$key]['input_value'] && !$this->dba->getTableArray()[$key]['value'] ) || // for password ( $this->dba->getTableArray()[$key]['type'] == 'password' && !$this->dba->getTableArray()[$key]['value'] && !$this->dba->getTableArray()[$key]['HIDDEN_value'] ) ) // main if end ) { // if mandatory && no input // $this->log->debug('form', 'A: ' . $this->dba->getTableArray()[$key]['type'] . ' -- ' // . $this->dba->getTableArray()[$key]['input_value'] . ' -- ' // . $this->dba->getTableArray()[$key]['value']); if ( empty($this->dba->getTableArray()[$key]['value']) && $this->dba->getTableArray()[$key]['type'] != 'binary' ) { $this->msg .= sprintf( $this->l->__('Please enter something into the %s field!
'), $this->dba->getTableArray()[$key]['output_name'] ); } } // mandatory // check file upload if ( isset($this->dba->getTableArray()[$key]['type']) && $this->dba->getTableArray()[$key]['type'] == 'file' && $GLOBALS['_FILES'][$key . '_file']['name'] && is_array($this->dba->getTableArray()[$key]['accept_type']) ) { // check against allowed types $mime_okay = 0; foreach ($this->dba->getTableArray()[$key]['accept_type'] as $mime_type) { if ($GLOBALS['_FILES'][$key . '_file']['type'] == $mime_type) { $mime_okay = 1; } } if (!$mime_okay) { $this->msg .= sprintf( $this->l->__('Uploaded File %s has MIME Type %s which is not in ' . 'theallowed MIME List for Upload Field %s!
'), $GLOBALS['_FILES'][$key . '_file']['name'], $GLOBALS['_FILES'][$key . '_file']['type'], $this->dba->getTableArray()[$key]['output_name'] ); } } } // while // do check for reference tables reset($this->reference_array); foreach ($this->reference_array as $key => $value) { // skip if not allowed to write if ( $this->base_acl_level < ($this->reference_array[$key]['min_edit_acl'] ?? 100) ) { continue; } if ( !empty($this->reference_array[$key]['mandatory']) && empty($this->reference_array[$key]['selected'][0]) ) { $this->msg .= sprintf( $this->l->__('Please select at least one Element from field %s!
'), $this->reference_array[$key]['output_name'] ); } } // $this->log->debug('edit_error', 'QS:
' . print_r($_POST, true) . '
'); if (!empty($this->element_list)) { // check the mandatory stuff // if mandatory, check that at least on pk exists or // if at least the mandatory field is filled foreach ($this->element_list as $table_name => $reference_array) { if (!is_array($reference_array)) { $reference_array = []; } // skip if not allowed to write if ( $this->base_acl_level < ($this->reference_array['min_edit_acl'] ?? 100) ) { continue; } // set pk/fk id for this $_pk_name = ''; $_fk_name = ''; foreach ($reference_array['elements'] as $_name => $_data) { if (isset($_data['pk_id'])) { $_pk_name = $_name; } if (isset($_data['fk_id'])) { $_fk_name = $_name; } } // get the leasy of keys from the elements array $keys = array_keys($reference_array['elements']); // prefix $prfx = $reference_array['prefix'] ? $reference_array['prefix'] . '_' : ''; // get max elements $max = 0; foreach ($keys as $key) { if ( isset($_POST[$prfx . $key]) && is_array($_POST[$prfx . $key]) && count($_POST[$prfx . $key]) > $max ) { $max = count($_POST[$prfx . $key]); } // $this->log->debug('edit_error_chk', 'KEY: ' . $prfx . $key . ' | count: ' // . count($_POST[$prfx.$key]) . ' | M: $max'); // $this->log->debug('edit_error_chk', 'K: ' . $_POST[$prfx.$key] . ' | ' . $_POST[$prfx.$key][0]); } // $this->log->debug('POST ARRAY', $this->log->prAr($_POST)); // init variables before inner loop run $mand_okay = 0; $mand_name = ''; $row_okay = []; $default_wrong = []; $error = []; $element_set = []; # check each row for ($i = 0; $i < $max; $i++) { // either one of the post pks is set, or the mandatory foreach ($reference_array['elements'] as $el_name => $data_array) { if ( /** @phan-suppress-next-line PhanTypeMismatchDimAssignment This error makes no sense */ !empty($data_array['mandatory']) ) { $mand_name = $data_array['output_name']; } // check if there is a primary ket inside, so it is okay if ( isset($data_array['pk_id']) && count($_POST[$prfx . $el_name]) && !empty($reference_array['mandatory']) ) { $mand_okay = 1; } // we found a mandatory field. check now if one is set to satisfy the main mandatory // also check, if this field is mandatory and its not set, but any other, throw an error // $this->log->debug('edit_error_chk', 'RG error - Data[' . $prfx . $el_name // . ': ' . $_POST[$prfx . $el_name][$i] . ' | ' // . $_POST[$prfx . $el_name] . ' - ' . $reference_array['enable_name'] . ' - ' // . $_POST[$reference_array['enable_name']][$_POST[$prfx . $el_name][$i]]); if ( !empty($data_array['mandatory']) && !empty($_POST[$prfx . $el_name][$i]) ) { $mand_okay = 1; $row_okay[$i] = 1; } elseif ( !empty($data_array['type']) && $data_array['type'] == 'radio_group' && !isset($_POST[$prfx . $el_name]) ) { // radio group and set where one not active // $this->log->debug('edit_error_chk', 'RADIO GROUP'); $row_okay[$_POST[$prfx . $el_name][$i] ?? 0] = 0; $default_wrong[$_POST[$prfx . $el_name][$i] ?? 0] = 1; $error[$_POST[$prfx . $el_name][$i] ?? 0] = 1; } elseif ( isset($_POST[$prfx . $el_name][$i]) && !isset($error[$i]) ) { // $this->log->debug('edit_error_chk', '[$i]'); $element_set[$i] = 1; $row_okay[$i] = 1; } elseif ( !empty($data_array['mandatory']) && !$_POST[$prfx . $el_name][$i] ) { $row_okay[$i] = 0; } // do optional error checks like for normal fields // currently active: unique/alphanumeric if (!empty($data_array['error_check'])) { foreach (explode('|', $data_array['error_check']) as $error_check) { switch ($error_check) { // check unique, check if field is filled and not same in _POST set case 'unique': // must be set for double check if ( $_POST[$prfx . $el_name][$i] && count(array_keys( $_POST[$prfx . $el_name], $_POST[$prfx . $el_name][$i] )) >= 2 ) { $this->msg .= sprintf( $this->l->__('The field %s in row %s ' . 'can be used only once!
'), $reference_array['output_name'], $i ); $_POST['ERROR'][$prfx][$i] = 1; } break; case 'alphanumericspace': // only check if set if ( $_POST[$prfx . $el_name][$i] && !preg_match("/^[0-9A-Za-z\ ]+$/", $_POST[$prfx . $el_name][$i]) ) { $this->msg .= sprintf( $this->l->__('Please enter a valid alphanumeric (Numbers and Letters, ' . 'spaces allowed) value for the ' . '%s Field and row %s!
'), $reference_array['output_name'], $i ); $_POST['ERROR'][$prfx][$i] = 1; } break; } } } } // if main mandatory } // main mandatory is met -> error msg if ( !$mand_okay && !empty($reference_array['mandatory']) ) { $this->msg .= sprintf( $this->l->__('You need to enter at least one data set for field %s!
'), $reference_array['output_name'] ); } for ($i = 0; $i < $max; $i++) { if (!isset($row_okay[$i]) && isset($element_set[$i])) { $this->msg .= sprintf( $this->l->__('The row %s has %s set as mandatory, ' . 'please fill at least this field out
'), $i, $mand_name ); } if (!isset($row_okay[$i]) && isset($default_wrong[$i])) { $this->msg .= sprintf( $this->l->__('The row %s would have a default setting, but it would be disabled. ' . 'Please change the default setting and save again
'), $i ); } } } // each element list } if ($this->msg) { $this->error = 1; } } /** * sets the order to the maximum, if order flag is set in array * * @return array table array with set order number */ public function formSetOrder(): array { // get order name $order_name = $this->formGetColNameFromKey('order'); if (empty($order_name)) { return $this->dba->getTableArray(); } // first check out of order ... if (empty($this->dba->getTableArray()[$order_name]['value'])) { // set order (read max) $q = 'SELECT MAX(' . $order_name . ') + 1 AS max_page_order ' . 'FROM ' . $this->dba->getTableName(); if ( is_array($res = $this->dba->dbReturnRow($q)) && !empty($res['max_page_order']) ) { $this->dba->setTableArrayEntry($res['max_page_order'], $order_name, 'value'); } // frist element is 0 because NULL gets returned, set to 1 if (!$this->dba->getTableArray()[$order_name]['value']) { $this->dba->setTableArrayEntry(1, $order_name, 'value'); } } elseif (!empty($this->dba->getTableArray()[$this->int_pk_name]['value'])) { $q = 'SELECT ' . $order_name . ' AS order_name ' . 'FROM ' . $this->dba->getTableName() . ' ' . 'WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; if ( is_array($res = $this->dba->dbReturnRow($q)) && !empty($res['order_name']) ) { $this->dba->setTableArrayEntry($res['order_name'], $order_name, 'value'); } } return $this->dba->getTableArray(); } /** * resets all values in table_array and in the reference tables * * @return void has no return */ public function formUnsetTableArray(): void { $this->dba->setPkId(null); foreach ($this->dba->getTableArray() as $key => $value) { $this->dba->unsetTableArrayEntry($key, 'value'); $this->dba->unsetTableArrayEntry($key, 'input_value'); // if preset var present preset if (isset($this->dba->getTableArray()[$key]['preset'])) { $this->dba->setTableArrayEntry($this->dba->getTableArray()[$key]['preset'], $key, 'value'); } } if (is_array($this->reference_array)) { if (!is_array($this->reference_array)) { $this->reference_array = []; } reset($this->reference_array); foreach ($this->reference_array as $key => $value) { unset($this->reference_array[$key]['selected']); } } $this->warning = 1; $this->msg = $this->l->__('Cleared for new Dataset!'); } /** * load a table & reference * * @param string|null $pk_id overrule pk_id * @return void has no return */ public function formLoadTableArray(?string $pk_id = null): void { if ($pk_id) { $this->dba->setPkId($pk_id); } $this->dba->setTableArray($this->dba->dbRead(true)); foreach ($this->dba->getTableArray() as $key => $value) { $this->dba->unsetTableArrayEntry($key, 'input_value'); } if (is_array($this->reference_array)) { // load each reference_table if (!is_array($this->reference_array)) { $this->reference_array = []; } reset($this->reference_array); foreach ($this->reference_array as $key => $value) { unset($this->reference_array[$key]['selected']); $q = 'SELECT ' . $this->reference_array[$key]['other_table_pk'] . ' FROM ' . $this->reference_array[$key]['table_name'] . ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; while (is_array($res = $this->dba->dbReturn($q))) { $this->reference_array[$key]['selected'][] = $res[$this->reference_array[$key]['other_table_pk']]; } } } $this->warning = 1; $this->msg = $this->l->__('Dataset has been loaded!
'); } /** * save a table, reference and all input fields * note that the addslashes flag here is passed on to the dbWrite method * it only does html conversion, add slashes for DB is done automatically * * @param bool $addslashes override internal addslasahes flag (default false) * @return void has no return */ public function formSaveTableArray(bool $addslashes = false) { // for drop_down_db_input check if text field is filled and if, if not yet in db ... // and upload files foreach ($this->dba->getTableArray() as $key => $value) { // drop_down_db with input + reference table // $this->log->debug('form', 'A: ' . $this->dba->getTableArray()[$key]['type'] // . ' --- ' . $this->dba->getTableArray()[$key]['input_value']); if ( isset($this->dba->getTableArray()[$key]['type']) && $this->dba->getTableArray()[$key]['type'] == 'drop_down_db_input' && $this->dba->getTableArray()[$key]['input_value'] ) { // $this->log->debug('form', 'HERE'); // check if this text name already exists (lowercase compare) $q = 'SELECT ' . $this->dba->getTableArray()[$key]['pk_name'] . ' AS pk_name ' . ' FROM ' . $this->dba->getTableArray()[$key]['table_name'] . ' WHERE LCASE(' . $this->dba->getTableArray()[$key]['input_name'] . ') = ' . "'" . $this->dba->dbEscapeString( strtolower($this->dba->getTableArray()[$key]['input_value']) ) . "'"; // if a where was given, add here if ($this->dba->getTableArray()[$key]['where']) { $q .= ' AND ' . $this->dba->getTableArray()[$key]['where']; } if ( is_array($s_res = $this->dba->dbReturnRow($q)) && !empty($s_res['pk_name']) ) { $this->dba->setTableArrayEntry($s_res['pk_name'], $key, 'value'); } else { // if a where was given, set this key also [dangerous!] // postgreSQL compatible insert $q = 'INSERT INTO ' . $this->dba->getTableArray()[$key]['table_name'] . ' (' . $this->dba->getTableArray()[$key]['input_name'] . ') VALUES (' . "'" . $this->dba->dbEscapeString($this->dba->getTableArray()[$key]['input_value']) . "')"; $this->dba->dbExec($q); if (!empty($this->dba->getTableArray()[$key]['where']) && is_numeric($this->dba->dbGetInsertPK())) { // make an update on the just inseted data with the where data als update values $q = 'UPDATE ' . $this->dba->getTableArray()[$key]['table_name'] . ' SET '; $q .= $this->dba->getTableArray()[$key]['where'] . ' '; $q .= 'WHERE ' . $this->dba->getTableArray()[$key]['pk_name'] . ' = ' . $this->dba->dbGetInsertPK(); $this->dba->dbExec($q); } $this->dba->setTableArrayEntry($this->dba->dbGetInsertPK(), $key, 'value'); } // set value from DB through select or insert $this->dba->unsetTableArrayEntry($key, 'input_value'); } // if it is certain field type && if there is something in the temp field // drop_down_db with input and in same table if ( isset($this->dba->getTableArray()[$key]['type']) && $this->dba->getTableArray()[$key]['type'] == 'drop_down_db_input_same_db' && $this->dba->getTableArray()[$key]['input_value'] ) { // if drop down & input are different if ($this->dba->getTableArray()[$key]['input_value'] != $this->dba->getTableArray()[$key]['value']) { // check if 'right input' is in DB $q = 'SELECT ' . $this->dba->getTableArray()[$key]['input_name'] . ' AS temp ' . ' FROM ' . $this->dba->getTableArray()[$key]['table_name'] . ' WHERE LCASE(' . $this->dba->getTableArray()[$key]['input_name'] . ') = ' . "'" . strtolower($this->dba->dbEscapeString( $this->dba->getTableArray()[$key]['input_value'] )) . "'"; // if a where was given, add here if ($this->dba->getTableArray()[$key]['where']) { $q .= ' AND ' . $this->dba->getTableArray()[$key]['where']; } if ( is_array($s_res = $this->dba->dbReturnRow($q)) && empty($s_res['temp']) ) { $this->dba->setTableArrayEntry($this->dba->getTableArray()[$key]['input_value'], $key, 'value'); } else { // found in DB $this->dba->setTableArrayEntry($this->dba->getTableArray()[$key]['value'], $key, 'input_value'); } } // key difference ? } // for same_db drop down // upload & save files to locations if ( isset($this->dba->getTableArray()[$key]['type']) && $this->dba->getTableArray()[$key]['type'] == 'file' ) { // if smth in $$key_file -> save or overwrite // if smth in $key && $$key_delete && !$$key_file-> delte // if smth in $key, keep as is // $_file=$key . '_file'; // $_delete=$key . '_delete'; // $this->log->debug('form', 'UF: ' . $GLOBALS['_FILES'][$key . '_file']['name']); // $this->log->debug('form', 'delete: ' . $key . '_delete => ' . $GLOBALS[$key . '_delete']); if ($GLOBALS['_FILES'][$key . '_file']['name']) { // check if dir exists if (is_dir($this->dba->getTableArray()[$key]['save_dir'])) { //if a slash at the end (if not add slash) if (!preg_match("|/$|", $this->dba->getTableArray()[$key]['save_dir'])) { $this->dba->getTableArray()[$key]['save_dir'] .= '/'; } if ( move_uploaded_file( $GLOBALS['_FILES'][$key . '_file']['tmp_name'], $this->dba->getTableArray()[$key]['save_dir'] . $GLOBALS['_FILES'][$key . '_file']['name'] ) ) { // make it unique with a unique number at the beginning $this->dba->setTableArrayEntry( uniqid((string)rand(), true) . '_' . $GLOBALS['_FILES'][$key . '_file']['name'], $key, 'value' ); } else { $this->msg .= $this->l->__('File could not be copied to target directory! ' . 'Perhaps wrong directory permissions . '); $this->error = 1; } // could not move file (dir permissions?) } else { $this->msg .= sprintf( $this->l->__('Target Directory \'%s\' is not a vaild directory!'), $this->dba->getTableArray()[$key]['save_dir'] ); $this->error = 1; } // could not dir check (dir wrong??) } if ( !empty($GLOBALS[$key . '_delete']) && $this->dba->getTableArray()[$key]['value'] && !$GLOBALS['_FILES'][$key . '_file']['name'] ) { unlink($this->dba->getTableArray()[$key]['save_dir'] . $this->dba->getTableArray()[$key]['value']); $this->dba->unsetTableArrayEntry($key, 'value'); } } // for password crypt it as blowfish, or if not available MD5 if ( isset($this->dba->getTableArray()[$key]['type']) && $this->dba->getTableArray()[$key]['type'] == 'password' ) { if ($this->dba->getTableArray()[$key]['value']) { // use the better new passwordSet instead of crypt based $this->dba->getTableArray()[$key]['value'] = \CoreLibs\Security\Password::passwordSet($this->dba->getTableArray()[$key]['value']); $this->dba->setTableArrayEntry( $this->dba->getTableArray()[$key]['value'], $key, 'HIDDEN_value' ); } else { // $this->dba->getTableArray()[$key]['HIDDEN_value'] = } } } // go through each field // set object order (if necessary) $this->formSetOrder(); // $this->log->debug('PK NAME SET', "PK NAME: " . $this->dba->getPkName() . "/" . $this->int_pk_name . ": " // . $this->dba->getTableArray()[$this->dba->getPkName()]['value'] . "/" // . $this->dba->getTableArray()[$this->int_pk_name]['value']); // write the object $this->dba->dbWrite($addslashes, [], true); // write reference array (s) if necessary if (is_array($this->reference_array)) { if (!is_array($this->reference_array)) { $this->reference_array = []; } reset($this->reference_array); foreach ($this->reference_array as $reference_array) { $q = 'DELETE FROM ' . $reference_array['table_name'] . ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; $this->dba->dbExec($q); $q = 'INSERT INTO ' . $reference_array['table_name'] . ' (' . $reference_array['other_table_pk'] . ', ' . $this->int_pk_name . ') VALUES '; for ($i = 0, $i_max = count($reference_array['selected']); $i < $i_max; $i++) { $t_q = '(' . $reference_array['selected'][$i] . ', ' . $this->dba->getTableArray()[$this->int_pk_name]['value'] . ')'; $this->dba->dbExec($q . $t_q); } } // foreach reference arrays } // if reference arrays // write element list if (!empty($this->element_list)) { $type = []; reset($this->element_list); foreach ($this->element_list as $table_name => $reference_array) { // early skip if not enought ACL if ($this->base_acl_level < ($reference_array['min_edit_acl'] ?? 100)) { continue; } // init arrays $q_begin = []; $q_middle = []; $q_end = []; $q_names = []; $q_data = []; $q_values = []; $no_write = []; $block_write = []; // get the number of keys from the elements array $keys = array_keys($reference_array['elements']); // element prefix name $prfx = $reference_array['prefix'] ? $reference_array['prefix'] . '_' : ''; // get max elements $max = 0; foreach ($keys as $key) { if ( isset($_POST[$prfx . $key]) && is_array($_POST[$prfx . $key]) && count($_POST[$prfx . $key]) > $max ) { $max = count($_POST[$prfx . $key]); } } $this->log->debug('REF ELEMENT', 'RUN FOR TABLE: ' . $table_name); // $this->log->debug('edit_error', 'MAX: $max'); // check if there is a hidden key, update, else insert foreach ($reference_array['elements'] as $el_name => $data_array) { // $this->log->debug('edit_error_query', 'QUERY: ' . $this->log->prAr($_POST)); // go through all submitted data // for ($i = 0; $i < count($_POST[$el_name]); $i++) for ($i = 0; $i < $max; $i++) { if (!isset($no_write[$i])) { $no_write[$i] = 0; // $this->log->debug('REF ELEMENT', 'Init no write for pos: ' . $i); } if (!isset($block_write[$i])) { $block_write[$i] = 0; // $this->log->debug('REF ELEMENT', 'Init block write for pos: ' . $i); } // if we have enable name & delete set, // then only insert/update those which are flagged as active // check if mandatory field is set, if not set 'do not write flag' if ( isset($data_array['mandatory']) && $data_array['mandatory'] && ( !isset($_POST[$prfx . $el_name][$i]) || (isset($_POST[$prfx . $el_name][$i]) && empty($_POST[$prfx . $el_name][$i])) ) ) { $no_write[$i] = 1; } // $this->log->debug('REF ELEMENT', "[$i] [" . $prfx . $el_name . "]: ' // . "MANDATORY: " . isset($data_array['mandatory']) // . " SET: " . isset($_POST[$prfx . $el_name][$i]) // . ", EMPTY: " . empty($_POST[$prfx . $el_name][$i]) // . " | DO ACTION " . ((!isset($_POST[$prfx . $el_name][$i]) || // (isset($_POST[$prfx . $el_name][$i]) && // empty($_POST[$prfx . $el_name][$i]))) ? 'YES' : 'NO' // ) . " => NO WRITE: " . $no_write[$i]); if ( !empty($reference_array['enable_name']) && isset($reference_array['delete']) && $reference_array['delete'] && (!isset($_POST[$reference_array['enable_name']][$i]) || empty($_POST[$reference_array['enable_name']][$i])) ) { $no_write[$i] = 1; } // $this->log->debug('REF ELEMENT', "[$i] [" . $prfx . $el_name . "]: ENABLED NAME: " // . isset($reference_array['enable_name']) // . ", DELETE: " . isset($reference_array['delete']) . ", NOT ENABLED FOR POS: " // . (isset($reference_array['enable_name']) ? // isset($_POST[$reference_array['enable_name']][$i]) : '-')); $this->log->debug('REF ELEMENT', "[$i] [" . $prfx . $el_name . "]: WRITE: " . $no_write[$i]); // flag if data is in the text field and we are in a reference data set if (isset($reference_array['type']) && $reference_array['type'] == 'reference_data') { if ( !empty($data_array['type']) && $data_array['type'] == 'text' && isset($_POST[$prfx . $el_name][$i]) ) { $block_write[$i] = 1; } } else { $block_write[$i] = 1; } // $this->log->debug('REF ELEMENT', "[$i] [" . $prfx . $el_name . "]: " // . "REFERENCE TYPE: " . isset($reference_array['type']) // . ", SET REFERENCE TYPE: " // . (isset($reference_array['type']) ? $reference_array['type'] : '-') // . ", DATA TYPE: " . $data_array['type'] . ", SET: " . isset($_POST[$prfx . $el_name][$i]) // . ", => BLOCK WIRTE: " . $block_write[$i]); // set type and boundaries for insert/update if ( isset($data_array['pk_id']) && !empty($data_array['pk_id']) && !empty($_POST[$prfx . $el_name][$i]) ) { $q_begin[$i] = 'UPDATE ' . $table_name . ' SET '; $q_end[$i] = ' WHERE ' . $el_name . ' = ' . $_POST[$prfx . $el_name][$i]; $type[$i] = 'update'; $this->log->debug('REF ELEMENT', 'SET UPDATE'); } elseif ( isset($data_array['pk_id']) && !empty($data_array['pk_id']) && empty($_POST[$prfx . $el_name][$i]) ) { $q_begin[$i] = 'INSERT INTO ' . $table_name . ' ('; $q_middle[$i] = ') VALUES ('; $q_end[$i] = ')'; $type[$i] = 'insert'; $this->log->debug('REF ELEMENT', 'SET INSERT'); } // $this->log->debug('REF ELEMENT', "[$i] [" . $prfx . $el_name . "] " // . "PK SET: " . isset($data_array['pk_id']) . '/' . empty($data_array['pk_id']) // . ', KEY SET: ' . empty($_POST[$prfx . $el_name][$i]) // . " -> TYPE: " . (isset($type[$i]) ? $type[$i] : '-')); // write all data (insert/update) because I don't know until // all are processed if it is insert or update // don't write primary key backup for update // for reference_data type, only write if at least one text type field is set // $this->log->debug('edit_error', 'I: $i | EL Name: ' . $prfx . $el_name // . ' | Data: ' . $_POST[$prfx . $el_name][$i] . ' | Type: ' . $type[$i] // . ' | PK: ' . $data_array['pk_id'] . ', Block write: ' . $block_write[$i]); // only add elements that are not PK or FK flaged if (!isset($data_array['pk_id']) && !isset($data_array['fk_id'])) { // update data list if (isset($q_data[$i])) { $q_data[$i] .= ', '; } else { $q_data[$i] = ''; } // insert name part list if (isset($q_names[$i])) { $q_names[$i] .= ', '; } else { $q_names[$i] = ''; } // insert value part list if (isset($q_values[$i])) { $q_values[$i] .= ', '; } else { $q_values[$i] = ''; } // insert column name add $q_names[$i] .= $el_name; // data part, read from where [POST] // radio group selections (only one can be active) if (isset($data_array['type']) && $data_array['type'] == 'radio_group') { if (isset($_POST[$prfx . $el_name]) && $i == $_POST[$prfx . $el_name]) { $_value = $i + 1; } else { $_value = 'NULL'; } } else { $_value = $_POST[$prfx . $el_name][$i] ?? ''; } // pre write data set. if int value, unset flagged // need to be set null or 0 depending on settings if (isset($data_array['int']) || isset($data_array['int_null'])) { if (!$_value && isset($data_array['int_null'])) { $_value = 'NULL'; } elseif (!$_value) { $_value = 0; } $q_data[$i] .= $el_name . ' = ' . $_value; $q_values[$i] .= $_value; } else { // normal data gets escaped $q_data[$i] .= $el_name . ' = ' . "'" . $this->dba->dbEscapeString($_value) . "'"; $q_values[$i] .= "'" . $this->dba->dbEscapeString($_value) . "'"; } } } } // eche table elements // finalize the queries, add FK key reference for inserts and run the query for ($i = 0, $i_max = count($type); $i < $i_max; $i++) { $q = ''; // skip empty or not fully filled rows if (isset($no_write[$i]) && !$no_write[$i]) { if (!isset($q_begin[$i])) { $q_begin[$i] = ''; } if (!isset($q_end[$i])) { $q_end[$i] = ''; } // if tpye is update if (isset($type[$i]) && $type[$i] == 'update') { $q = $q_begin[$i] . ($q_data[$i] ?? '') . $q_end[$i]; // or if we have block write, then it is insert (new) } elseif (isset($block_write[$i]) && $block_write[$i]) { $q = $q_begin[$i] . ($q_names[$i] ?? '') . ', ' . $this->int_pk_name . ($q_middle[$i] ?? '') . ($q_values[$i] ?? '') . ', ' . $this->dba->getTableArray()[$this->int_pk_name]['value'] . $q_end[$i]; } /** @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset */ $this->log->debug('edit', 'Pos[' . $i . '] => ' . $type[$i] . ' Q: ' . $q . '
'); // write the dataset if ($q) { $this->dba->dbExec($q); } } } // for each created query } // each element list } $this->warning = 1; $this->msg = $this->l->__('Dataset has been saved!
'); } /** * delete a table and reference fields * * @return void */ public function formDeleteTableArray() { // remove any reference arrays if (is_array($this->reference_array)) { if (!is_array($this->reference_array)) { $this->reference_array = []; } reset($this->reference_array); foreach ($this->reference_array as $reference_array) { $q = 'DELETE FROM ' . $reference_array['table_name'] . ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; $this->dba->dbExec($q); } } // remove any element list references if (!empty($this->element_list)) { reset($this->element_list); foreach ($this->element_list as $table_name => $data_array) { $q = 'DELETE FROM ' . $table_name . ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; $this->dba->dbExec($q); } } // unlink ALL files foreach ($this->dba->getTableArray() as $key => $value) { if ( isset($this->dba->getTableArray()[$key]['type']) && $this->dba->getTableArray()[$key]['type'] == 'file' ) { unlink($this->dba->getTableArray()[$key]['save_dir'] . $this->dba->getTableArray()[$key]['value']); } } $this->dba->dbDelete(); $this->warning = 1; $this->msg = $this->l->__('Dataset has been deleted!'); } /** * creates HTML hidden input fields out of an hash array * * @param array $hidden_array The list of fields to be added as hidden * @return array key -> value list of hidden fileds data */ public function formCreateHiddenFields(array $hidden_array = []): array { $hidden = []; foreach ($this->dba->getTableArray() as $key => $value) { if ( isset($this->dba->getTableArray()[$key]['type']) && $this->dba->getTableArray()[$key]['type'] == 'hidden' ) { if (array_key_exists($key, $this->dba->getTableArray())) { $hidden_array[$key] = $this->dba->getTableArray()[$key]['value'] ?? ''; } else { $hidden_array[$key] = ''; } } } reset($hidden_array); foreach ($hidden_array as $key => $value) { $hidden[] = ['key' => $key, 'value' => $value]; } return $hidden; } /** * creates the multiple select part for a reference_table * * @param string $table_name Table name for reference array lookup * @return array Reference table output array */ public function formCreateElementReferenceTable(string $table_name): array { $data = []; // $show_value = ''; // set default min edit/read to 100 (admin) $min_edit_acl = $this->reference_array[$table_name]['min_edit_acl'] ?? 100; $min_show_acl = $this->reference_array[$table_name]['min_show_acl'] ?? 100; // output name $output_name = $this->reference_array[$table_name]['output_name']; // mandatory flag if ( isset($this->reference_array[$table_name]['mandatory']) && $this->reference_array[$table_name]['mandatory'] ) { $output_name .= ' *'; } $data['name'] = $this->reference_array[$table_name]['other_table_pk']; $data['size'] = $this->reference_array[$table_name]['select_size']; while (is_array($res = $this->dba->dbReturn($this->reference_array[$table_name]['query']))) { $data['value'][] = $res[0]; $data['output'][] = $res[1]; $selected = (\CoreLibs\Convert\Html::checked( $this->reference_array[$table_name]['selected'] ?? '', $res[0] )) ? $res[0] : ''; $data['selected'][] = $selected; if (!empty($selected)) { if (!empty($show_value)) { $show_value .= ", "; } $show_value .= $res[1]; } } $type = 'reference_table'; return [ 'output_name' => $output_name, 'type' => $type, 'color' => 'edit_fgcolor', 'data' => $data, 'show_value' => empty($show_value) ? '-' : $show_value, 'allow_edit' => $this->base_acl_level >= $min_edit_acl ? 1 : 0, 'allow_show' => $this->base_acl_level >= $min_show_acl ? 1 : 0, ]; } /** * create list of elements next to each other for a group of data in an input field * this currently only works for a list that is filled from a sub table and creates * only a connection to this one new version will allow a sub list with free input * fields to directly fill a sub table to a master table * * @param string $table_name Which element entry to create * @return array Element for html creation */ public function formCreateElementListTable(string $table_name): array { // init data rray $data = [ 'delete_name' => '', 'delete' => 0, 'enable_name' => '', 'prefix' => '', 'pk_name' => '', 'fk_name' => '', 'type' => [], 'output_name' => [], 'preset' => [], 'element_list' => [], 'output_data' => [], 'content' => [], 'pos' => [], 'table_name' => $table_name // sub table name ]; $show_value = '-'; // set default min edit/read to 100 (admin) $min_edit_acl = $this->element_list[$table_name]['min_edit_acl'] ?? 100; $min_show_acl = $this->element_list[$table_name]['min_show_acl'] ?? 100; // output name for the viewable left table td box, prefixed with * if mandatory $output_name = $this->element_list[$table_name]['output_name']; // mandatory flag if ( isset($this->element_list[$table_name]['mandatory']) && $this->element_list[$table_name]['mandatory'] ) { $output_name .= ' *'; } // delete button name, if there is one set if (isset($this->element_list[$table_name]['delete_name'])) { $data['delete_name'] = $this->element_list[$table_name]['delete_name']; } // set the enable checkbox for delete, if the delete flag is given if there is one if (isset($this->element_list[$table_name]['enable_name'])) { $data['enable_name'] = $this->element_list[$table_name]['enable_name']; if (isset($this->element_list[$table_name]['delete'])) { $data['delete'] = 1; } } // prefix for the elements, to not collide with names in the master set if (isset($this->element_list[$table_name]['prefix'])) { $data['prefix'] = $this->element_list[$table_name]['prefix'] . '_'; } // build the select part if ( !isset($this->element_list[$table_name]['elements']) || !is_array($this->element_list[$table_name]['elements']) ) { $this->element_list[$table_name]['elements'] = []; } reset($this->element_list[$table_name]['elements']); // generic data read in (counts for all rows) // visible list data output $q_select = []; $proto = []; foreach ($this->element_list[$table_name]['elements'] as $el_name => $data_array) { // $this->log->debug('CFG', 'El: ' . $el_name . ' -> ' . $this->log->prAr($data_array)); // if the element name matches the read array, then set the table as a name prefix // this is for reading the data $q_select[] = $el_name; // prefix the name for any further data parts $el_name = $data['prefix'] . $el_name; // this are the output names (if given) $data['output_name'][$el_name] = $data_array['output_name'] ?? ''; // this is the type of the field $data['type'][$el_name] = $data_array['type'] ?? ''; // set the primary key name if (isset($data_array['pk_id'])) { $data['pk_name'] = $el_name; } if (isset($data_array['fk_id'])) { $data['fk_name'] = $el_name; } // if drop down db read data for element list from the given sub table as from the query // only two elements are allowed: pos 0 is key, pso 1 is visible output name if (!empty($data_array['type']) && $data_array['type'] == 'drop_down_db') { while (is_array($res = $this->dba->dbReturn($data_array['query']))) { /** @phan-suppress-next-line PhanTypeInvalidDimOffset */ // $this->log->debug('ELEMENT LIST', 'Q[' . $this->dba->dbGetQueryHash($data_array['query']) . '] ' // . 'pos: ' . $this->dba->dbGetCursorPos($data_array['query']) // . ' | want: ' . ($data_array['preset'] ?? '-') // . ' | set: ' . ($data['preset'][$el_name] ?? '-')); // first is default for this element if ( isset($data_array['preset']) && (!isset($data['preset'][$el_name]) || empty($data['preset'][$el_name])) && ($this->dba->dbGetCursorPos($data_array['query']) == $data_array['preset']) ) { $data['preset'][$el_name] = $res[0]; } // split up data, 0 is id, 1 name $data['element_list'][$el_name][] = $res[0]; $data['output_data'][$el_name][] = $res[1]; } } elseif (isset($data_array['element_list'])) { $data['element_list'][$el_name] = $data_array['element_list']; // this is for the checkboxes } // $this->log->debug('ELEMENT LIST', 'Data: ' // . (count($data['element_list'][$el_name] ?? []) ? 'YES' : '*NO*') // . ', B: ' . (is_bool($res ?? null) ? 'Y' : 'N')); // $this->log->debug('POST CREATE ELEMENT LIST TABLE', 'Table: ' . $table_name // . ', Post: ' . $el_name . ' => ' // . ((isset($_POST[$el_name]) && is_array($_POST[$el_name])) ? // 'AS ARRAY'/*.$this->log->prAr($_POST[$el_name])*/ : // 'NOT SET/OR NOT ARRAY') // . ((isset($_POST[$el_name]) && !is_array($_POST[$el_name])) ? $_POST[$el_name] : '')); // if error, check new line addition so we don't lose it if ($this->error) { if (isset($_POST[$el_name]) && is_array($_POST[$el_name])) { // this is for the new line $proto[$el_name] = $_POST[$el_name][(count($_POST[$el_name]) - 1)] ?? 0; } else { $proto[$el_name] = 0; } } else { $proto[$el_name] = ''; } // $proto[$el_name] = $this->error ? $_POST[$el_name][(count($_POST[$el_name]) - 1)] : ''; } // $this->log->debug('CFG DATA', 'Data: ' . $this->log->prAr($data)); // $this->log->debug('CFG PROTO', 'Proto: ' . $this->log->prAr($proto)); // $this->log->debug('CFG SELECT', 'Proto: ' . $this->log->prAr($q_select)); // query for reading in the data $this->log->debug('edit_error', 'ERR: ' . $this->error); // if we got a read data, build the read select for the read, and read out the 'selected' /** @phan-assert array $this->element_list[$table_name]['read_data'] */ if (isset($this->element_list[$table_name]['read_data'])) { // we need a second one for the query build only // prefix all elements with the $table name $_q_select = []; foreach ($q_select as $_pos => $element) { $_q_select[$_pos] = $table_name . '.' . $element; } // set if missing if (!isset($this->element_list[$table_name]['read_data']['pk_id'])) { $this->element_list[$table_name]['read_data']['pk_id'] = ''; } if (!isset($this->element_list[$table_name]['read_data']['name'])) { $this->element_list[$table_name]['read_data']['name'] = ''; } if (!isset($this->element_list[$table_name]['read_data']['table_name'])) { $this->element_list[$table_name]['read_data']['table_name'] = ''; } // add the read names in here, prefix them with the table name // earch to read part is split by | if (!empty($this->element_list[$table_name]['read_data']['name'])) { /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ foreach (explode('|', $this->element_list[$table_name]['read_data']['name']) as $read_name) { array_unshift( $_q_select, /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ $this->element_list[$table_name]['read_data']['table_name'] . '.' . $read_name ); array_unshift($q_select, $read_name); } } // @phan HACK $data['prefix'] = $data['prefix']; // set the rest of the data so we can print something out /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ $data['type'][$data['prefix'] . $this->element_list[$table_name]['read_data']['name']] = 'string'; // build the read query $q = 'SELECT '; // if (!$this->dba->getTableArray()[$this->int_pk_name]['value']) // $q .= 'DISTINCT '; // prefix join key with table name, and implode the query select part $q .= str_replace( $table_name . '.' /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ . $this->element_list[$table_name]['read_data']['pk_id'], /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ $this->element_list[$table_name]['read_data']['table_name'] /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ . '.' . $this->element_list[$table_name]['read_data']['pk_id'], implode(', ', $_q_select) ) . ' '; // if ( // !$this->dba->getTableArray()[$this->int_pk_name]['value'] && // $this->element_list[$table_name]['read_data']['order'] // ) { // $q .= ', ' . $this->element_list[$table_name]['read_data']['order'] . ' '; // read from the read table as main, and left join to the sub table to read the actual data // } /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ $q .= 'FROM ' . $this->element_list[$table_name]['read_data']['table_name'] . ' '; $q .= 'LEFT JOIN ' . $table_name . ' '; $q .= 'ON ('; /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ $q .= $this->element_list[$table_name]['read_data']['table_name'] . '.' /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ . $this->element_list[$table_name]['read_data']['pk_id'] . ' = ' /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ . $table_name . '.' . $this->element_list[$table_name]['read_data']['pk_id'] . ' '; // if ($this->dba->getTableArray()[$this->int_pk_name]['value']) $q .= 'AND ' . $table_name . '.' . $this->int_pk_name . ' = ' . (!empty($this->dba->getTableArray()[$this->int_pk_name]['value']) ? $this->dba->getTableArray()[$this->int_pk_name]['value'] : 'NULL') . ' '; $q .= ') '; if (isset($this->element_list[$table_name]['read_data']['order'])) { $q .= ' ORDER BY ' /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ . $this->element_list[$table_name]['read_data']['table_name'] /** @phan-suppress-next-line PhanTypeArraySuspiciousNullable */ . '.' . $this->element_list[$table_name]['read_data']['order']; } } else { // only create query if we have a primary key // reads directly from the reference table if ( isset($this->dba->getTableArray()[$this->int_pk_name]['value']) && $this->dba->getTableArray()[$this->int_pk_name]['value'] ) { $q = 'SELECT ' . implode(', ', $q_select) . ' FROM ' . $table_name . ' WHERE ' . $this->int_pk_name . ' = ' . $this->dba->getTableArray()[$this->int_pk_name]['value']; } } // $this->log->debug('CFG QUERY', 'Q: ' . $q); // only run if we have query strnig $written_pos = []; if (isset($q)) { $prfx = $data['prefix']; // short $pos = 0; // position in while for overwrite if needed // read out the list and add the selected data if needed while (is_array($res = $this->dba->dbReturn($q))) { $_data = []; // go through each res for ($i = 0, $i_max = count($q_select); $i < $i_max; $i++) { // query select part, set to the element name $el_name = $q_select[$i]; // $this->log->debug('edit_error', '[$i] ELNAME: $el_name | POS[$prfx$el_name]: ' // . $_POST[$prfx . $el_name][$pos] . ' | RES: ' . $res[$el_name]); // if we have an error, we take what we have in the vars, if not we take the data from the db if ($this->error) { // if we have a radio group, set a bit different if ( isset($data['element_list'][$prfx . $el_name]) && $data['element_list'][$prfx . $el_name] == 'radio_group' ) { $_data[$prfx . $el_name] = ($res[$el_name]) ? ($res[$el_name] - 1) : 0; } elseif (isset($_POST[$prfx . $el_name][$pos])) { $_data[$prfx . $el_name] = $_POST[$prfx . $el_name][$pos]; } else { $_data[$prfx . $el_name] = ''; } } else { if (isset($data['preset'][$prfx . $el_name]) && !isset($res[$el_name])) { $_data[$prfx . $el_name] = $data['preset'][$prfx . $el_name]; } else { $_data[$prfx . $el_name] = $res[$el_name]; } } } $data['content'][] = $_data; $data['pos'][] = [0 => $pos]; // this is for the checkboxes $written_pos[] = $pos; $pos++; // move up one // reset and unset before next run unset($_data); } } // add lost error ones $this->log->error('P: ' . $data['prefix'] . ', ' . Support::prAr($_POST['ERROR'][$data['prefix']] ?? [])); if ($this->error && !empty($_POST['ERROR'][$data['prefix']])) { $prfx = $data['prefix']; // short $_post_data = []; // MAX entries defined via $data['pk_name'] entry (must exist) $_max_pos = count($_POST[$data['pk_name']] ?? []); // write all excte previous loaded @ $pos foreach ($q_select as $_el_name) { for ($_pos = 0; $_pos <= $_max_pos; $_pos++) { // if not in data pos if (!in_array($_pos, $written_pos)) { $_post_data[$_pos][$prfx . $_el_name] = $_POST[$prfx . $_el_name][$_pos] ?? ''; } } } // only add if all fields in data are filled, else skip // pk_name field is excluded of check foreach ($_post_data as $_pos => $_data) { $filled = false; foreach ($_data as $_name => $_value) { if ($_name != $data['pk_name'] && !empty($_value)) { $filled = true; } } if ($filled == true) { $data['content'][] = $_data; $data['pos'][] = [0 => $_pos]; } } } // if this is normal single reference data check the content on the element count // if there is a max_empty is set, then fill up new elements (unfilled) // until we reach max empty if ( /*isset($this->element_list[$table_name]['type']) && $this->element_list[$table_name]['type'] == 'reference_data' &&*/ isset($this->element_list[$table_name]['max_empty']) && is_numeric($this->element_list[$table_name]['max_empty']) && $this->element_list[$table_name]['max_empty'] > 0 ) { // if the max empty is bigger than 10, just cut it to ten at the moment if ($this->element_list[$table_name]['max_empty'] > 10) { $this->element_list[$table_name]['max_empty'] = 10; } // check if we need to fill fields $element_count = count($data['content']); $missing_empty_count = $this->element_list[$table_name]['max_empty'] - $element_count; $this->log->debug('CFG MAX', 'Max empty: ' . $this->element_list[$table_name]['max_empty'] . ', Missing: ' . $missing_empty_count . ', Has: ' . $element_count); // set if we need more open entries or if we do not have any entries yet if ( ($missing_empty_count < $this->element_list[$table_name]['max_empty']) || $element_count == 0 ) { for ( $pos = $element_count, $pos_max = $this->element_list[$table_name]['max_empty'] + $element_count; $pos <= $pos_max; $pos++ ) { $_data = []; // the fields that need to be filled are in data->type array: // pk fields are unfilled // fk fields are filled with the fk_id 'int_pk_name' value foreach ($data['type'] as $el_name => $type) { $_data[$el_name] = ''; if ( !empty($data['pk_name']) && $el_name == $data['pk_name'] ) { // do nothing for pk name } elseif ( !empty($data['fk_name']) && $el_name == $data['fk_name'] && isset($this->dba->getTableArray()[$this->int_pk_name]['value']) ) { $_data[$el_name] = $this->dba->getTableArray()[$this->int_pk_name]['value']; } } $data['content'][] = $_data; // this is for the checkboxes $data['pos'][] = [ 0 => $pos ]; $this->log->debug('CFG ELEMENT LIST FILL', 'Pos: ' . $pos . '/' . $pos_max . ', Content: ' . count($data['content']) . ', Pos: ' . count($data['pos'])); } } } // push in an empty line of this type, but only if we have a delete key that is also filled if (!empty($data['delete_name'])) { $data['content'][] = $proto; // we also need the pos add or we through an error in smarty $data['pos'][] = [ 0 => count($data['pos']) ]; } // $this->log->debug('CFG ELEMENT LIST FILL', 'Data array: ' . $this->log->prAr($data)); $type = 'element_list'; return [ 'output_name' => $output_name, 'type' => $type, 'color' => 'edit_fgcolor', 'data' => $data, 'show_value' => $show_value, 'allow_edit' => $this->base_acl_level >= $min_edit_acl ? 1 : 0, 'allow_show' => $this->base_acl_level >= $min_show_acl ? 1 : 0, ]; } // end of class } // __END__