function KUserDefinedField($row, &$page, &$siblings) { global $FUNCS; // udf params $custom_params = $row['custom_params']; if (strlen($custom_params)) { $arr_params = $FUNCS->unserialize($custom_params); if (is_array($arr_params) && count($arr_params)) { foreach ($arr_params as $k => $v) { $this->{$k} = $v; } } } // call parent parent::KField($row, $page, $siblings); if (!$FUNCS->is_core_type($this->k_type)) { $this->udf = 1; } }
function _render($input_name, $input_id, $extra = '') { $this->k_type = 'password'; return KField::_render($input_name, $input_id, $extra); // Calling grandparent statically! Not a bug: https://bugs.php.net/bug.php?id=42016 return $html; }
function editable($params, $node, $called_from_repeatable = 0) { global $CTX, $FUNCS, $PAGE, $DB, $AUTH; $is_udf = 0; $core_params = array('name' => '', 'label' => '', 'desc' => '', 'type' => 'textarea', 'hidden' => '0', 'search_type' => '', 'searchable' => '1', 'order' => '0', 'required' => '0', 'validator' => '', 'validator_msg' => '', 'separator' => '', 'val_separator' => '', 'opt_values' => '', 'opt_selected' => '', 'toolbar' => '', 'custom_toolbar' => '', 'css' => '', 'custom_styles' => '', 'maxlength' => '', 'height' => '', 'width' => '', 'group' => '', 'collapsed' => '', 'assoc_field' => '', 'crop' => '', 'enforce_max' => '', 'quality' => '80', 'show_preview' => '', 'preview_width' => '', 'preview_height' => '', 'no_xss_check' => '0', 'rtl' => '', 'body_id' => '', 'body_class' => '', 'disable_uploader' => '0', 'dynamic' => '', 'col_width' => '', 'input_width' => ''); $attr = $FUNCS->get_named_vars($core_params, $params); // HOOK: alter_editable_start $FUNCS->dispatch_event('alter_editable_start', array(&$attr, $params, $node, &$called_from_repeatable)); $attr['name'] = trim($attr['name']); $attr['type'] = strtolower(trim($attr['type'])); if (!$attr['type']) { $attr['type'] = 'textarea'; } $is_udf = 0; $attr_udf = array(); if (!$FUNCS->is_core_type($attr['type'])) { // is it a udf? if (array_key_exists($attr['type'], $FUNCS->udfs)) { $is_udf = 1; $classname = $FUNCS->udfs[$attr['type']]['handler']; $attr_udf = call_user_func(array($classname, 'handle_params'), $params); if (!is_array($attr_udf)) { $attr_udf = array(); } // remove core parameters if any set as custom params $core_params = array_merge(array('id' => '', 'deleted' => '', 'template_id' => '', 'custom_params' => '', 'k_desc' => '', 'k_type' => '', 'k_order' => '', 'k_group' => '', 'k_separator' => '', 'page' => '', 'siblings' => '', 'processed' => '', 'system' => '', 'err_msg' => '', 'modified' => '', 'udf' => '', 'cached' => '', 'refresh_form' => '', 'err_msg_refresh' => '', 'requires_multipart' => '', 'trust_mode' => '', 'no_js' => '', 'available_validators' => '', 'available_buttons' => ''), $core_params); foreach ($attr_udf as $k => $v) { if (array_key_exists($k, $core_params)) { unset($attr_udf[$k]); } } } else { die("ERROR: Tag \"" . $node->name . "\" has unknown type \"" . $attr['type'] . "\""); } } $attr['hidden'] = abs((int) $attr['hidden']); $attr['search_type'] = strtolower(trim($attr['search_type'])); if (!$attr['search_type']) { $attr['search_type'] = 'text'; } elseif (!in_array($attr['search_type'], array('text', 'integer', 'decimal'))) { die("ERROR: Tag \"" . $node->name . "\" has unknown search_type \"" . $attr['search_type'] . "\""); } // only text, radio and dropdown can have numeric search types if ($attr['search_type'] != 'text' && !in_array($attr['type'], array('text', 'radio', 'dropdown')) && $is_udf == 0) { die("ERROR: Tag \"" . $node->name . "\" cannot have \"" . $attr['search_type'] . "\" as search_type with \"" . $attr['type'] . "\" as field type"); } $attr['order'] = (int) $attr['order']; $attr['required'] = abs((int) $attr['required']); $attr['validator'] = strtolower(trim($attr['validator'])); $attr['separator'] = trim($attr['separator']); $attr['val_separator'] = trim($attr['val_separator']); $attr['opt_values'] = trim($attr['opt_values']); $attr['opt_selected'] = trim($attr['opt_selected']); $attr['toolbar'] = strtolower(trim($attr['toolbar'])); $attr['custom_toolbar'] = trim($attr['custom_toolbar']); $attr['css'] = trim($attr['css']); $attr['custom_styles'] = trim($attr['custom_styles']); $attr['maxlength'] = abs((int) $attr['maxlength']); $attr['height'] = abs((int) $attr['height']); $attr['width'] = abs((int) $attr['width']); $attr['group'] = trim($attr['group']); $attr['collapsed'] = abs((int) $attr['collapsed']); $attr['assoc_field'] = trim($attr['assoc_field']); $attr['crop'] = abs((int) $attr['crop']); $attr['enforce_max'] = trim($attr['enforce_max']); if ($attr['type'] == 'image' && ($attr['enforce_max'] != '1' && $attr['enforce_max'] != '0')) { $attr['enforce_max'] = 1; } if ($attr['type'] == 'thumbnail' && ($attr['enforce_max'] != '1' && $attr['enforce_max'] != '0')) { $attr['enforce_max'] = 0; } $attr['enforce_max'] = abs((int) $attr['enforce_max']); $attr['quality'] = (int) $attr['quality']; if ($attr['quality'] <= 0) { $attr['quality'] = '80'; } elseif ($attr['quality'] > 100) { $attr['quality'] = '100'; } $attr['show_preview'] = abs((int) $attr['show_preview']); $attr['preview_width'] = abs((int) $attr['preview_width']); $attr['preview_height'] = abs((int) $attr['preview_height']); $attr['no_xss_check'] = abs((int) $attr['no_xss_check']); $attr['rtl'] = abs((int) $attr['rtl']); $attr['body_id'] = trim($attr['body_id']); $attr['body_class'] = trim($attr['body_class']); $attr['disable_uploader'] = abs((int) $attr['disable_uploader']); $attr['dynamic'] = trim($attr['dynamic']); $attr['searchable'] = abs((int) $attr['searchable']); // Save a backup of all the parameters used to create this field. $tag = '<cms:editable'; foreach ($params as $p) { $tag .= "\r\n" . $p['lhs'] . $p['op'] . '\'' . str_replace("'", "\\'", $p['rhs']) . '\''; } $tag .= '/>'; if ($called_from_repeatable) { $attr['k_desc'] = $attr['desc']; unset($attr['desc']); $attr['k_type'] = $attr['type']; unset($attr['type']); $attr['k_order'] = $attr['order']; unset($attr['order']); $attr['k_separator'] = $attr['separator']; unset($attr['separator']); $attr['k_group'] = $attr['type'] == 'group' ? '' : $attr['group']; unset($attr['group']); $attr['_html'] = $tag; $attr['col_width'] = abs((int) $attr['col_width']); $attr['input_width'] = abs((int) $attr['input_width']); $attr['custom_params'] = $is_udf ? $FUNCS->serialize($attr_udf) : ''; return $attr; } // HOOK: alter_editable $skip = $FUNCS->dispatch_event('alter_editable', array(&$attr, &$attr_udf, $params, $node, $called_from_repeatable)); if ($skip) { return; } extract($attr); if (!$name) { die("ERROR: Tag \"" . $node->name . "\" needs a 'name' attribute"); } $found = 0; for ($x = 0; $x < count($PAGE->fields); $x++) { $field =& $PAGE->fields[$x]; if (strtoupper($field->name) == strtoupper($name)) { $found = 1; break; } } foreach ($node->children as $child) { $html .= $child->get_HTML(); } if ($found) { if (!$field->system) { if ($AUTH->user->access_level >= K_ACCESS_LEVEL_SUPER_ADMIN) { // Note the existing type of the field. This could get modified by the code that follows. $orig_field_type = $field->k_type; // Check if any core attribute has been modified $modified = array(); foreach ($attr as $k => $v) { if ($k == 'desc' || $k == 'type' || $k == 'order' || $k == 'group' || $k == 'separator') { $k = 'k_' . $k; } //MySQL has problems with these names if ($field->{$k} != trim($v)) { if ($attr['type'] == 'group' && $k == 'k_group') { //group of type 'group' will always be blank $v = ''; if ($field->{$k} == $v) { continue; } } $prev_value[$k] = $field->{$k}; $modified[$k] = $field->{$k} = trim($v); } } // Check if any udf attribute has been modified if ($is_udf) { $prev_udf_values = array(); foreach ($attr_udf as $k => $v) { $v = trim($v); if ($field->{$k} != $v) { $prev_udf_values[$k] = $field->{$k}; $field->{$k} = $v; } } if (count($prev_udf_values)) { $modified['custom_params'] = $FUNCS->serialize($attr_udf); } } // Check if the default text (if any) has changed if ($field->default_data != $html) { $modified['default_data'] = $field->default_data = $html; } // Check if deleted field has been recreated if ($field->deleted) { $modified['deleted'] = $field->deleted = "0"; } // HOOK: alter_editable_modifications $FUNCS->dispatch_event('alter_editable_modifications', array(&$modified, $field, $params, $node)); if (count($modified)) { $DB->begin(); // HOOK: alter_field_update $FUNCS->dispatch_event('alter_field_update', array(&$modified, $field, $params, $node)); if (array_key_exists('custom_params', $modified)) { // Call udf to do something for 'update_schema' event if ($field->k_type == $orig_field_type) { $field->_update_schema($prev_udf_values); } } // Check if search_type of custom field changed if (array_key_exists('search_type', $modified)) { $new_type = $modified['search_type']; $old_type = $prev_value['search_type']; if ($old_type && $old_type != $new_type) { if ($new_type == 'decimal') { if ($old_type == 'integer') { // If converting from integer to decimal, nothing is required } elseif ($old_type == 'text') { // Converting from text to decimal $FUNCS->change_field_type($old_type, $new_type, $field->id); } } elseif ($new_type == 'integer') { if ($old_type == 'decimal') { // Converting from decimal to integer will require stripping off all fractional parts $sql = 'UPDATE ' . K_TBL_DATA_NUMERIC . ' SET value = TRUNCATE(value,0) WHERE field_id=' . $DB->sanitize($field->id); $DB->_query($sql); $rs = $DB->rows_affected = mysql_affected_rows($DB->conn); if ($rs == -1) { die("ERROR: Unable to save modified decimal to integer values"); } } elseif ($old_type == 'text') { // Converting from text to integer $FUNCS->change_field_type($old_type, $new_type, $field->id); } } elseif ($new_type == 'text') { // Converting from numeric to text $FUNCS->change_field_type($old_type, $new_type, $field->id); } } } // Persist changes $modified['_html'] = $tag; $rs = $DB->update(K_TBL_FIELDS, $modified, "id='" . $DB->sanitize($field->id) . "'"); if ($rs == -1) { die("ERROR: Unable to save modified editable field"); } // HOOK: field_updated $FUNCS->dispatch_event('field_updated', array(&$modified, $field, $params, $node)); $DB->commit(); } $field->processed = 1; } if (!$hidden && !($PAGE->is_master && $PAGE->tpl_is_clonable)) { if (!($field->k_type == 'hidden' || $field->k_type == 'message' || $field->k_type == 'group')) { return $field->get_data(); } } } } else { if ($AUTH->user->access_level >= K_ACCESS_LEVEL_SUPER_ADMIN) { if (!$FUNCS->is_variable_clean($attr['name'])) { die("ERROR: Tag \"" . $node->name . "\": 'name' contains invalid characters. (Only lowercase[a-z], numerals[0-9] and underscore permitted. The first character cannot be a numeral)"); } if (substr($attr['name'], 0, 2) == 'k_') { die("ERROR: Tag \"" . $node->name . "\": 'name' cannot begin with 'k_'. Reserved for system fields."); } $DB->begin(); // Create a new record for this field in K_TBL_FIELDS. This stores only the meta. $fields = array('template_id' => $PAGE->tpl_id, 'name' => $attr['name'], 'label' => $attr['label'], 'k_desc' => $attr['desc'], 'k_type' => $attr['type'], 'hidden' => $attr['hidden'], 'search_type' => $attr['search_type'], 'k_order' => $attr['order'], 'default_data' => $html, 'required' => $attr['required'], 'deleted' => '0', 'validator' => $attr['validator'], 'validator_msg' => $attr['validator_msg'], 'k_separator' => $attr['separator'], 'val_separator' => $attr['val_separator'], 'opt_values' => $attr['opt_values'], 'opt_selected' => $attr['opt_selected'], 'toolbar' => $attr['toolbar'], 'custom_toolbar' => $attr['custom_toolbar'], 'css' => $attr['css'], 'custom_styles' => $attr['custom_styles'], 'maxlength' => $attr['maxlength'], 'height' => $attr['height'], 'width' => $attr['width'], 'k_group' => $attr['type'] == 'group' ? '' : $attr['group'], 'collapsed' => $attr['collapsed'], 'assoc_field' => $attr['assoc_field'], 'crop' => $attr['crop'], 'enforce_max' => $attr['enforce_max'], 'quality' => $attr['quality'], 'show_preview' => $attr['show_preview'], 'preview_width' => $attr['preview_width'], 'preview_height' => $attr['preview_height'], 'no_xss_check' => $attr['no_xss_check'], 'rtl' => $attr['rtl'], 'body_id' => $attr['body_id'], 'body_class' => $attr['body_class'], 'disable_uploader' => $attr['disable_uploader'], '_html' => $tag, 'dynamic' => $attr['dynamic']); if ($is_udf && count($attr_udf)) { $fields['custom_params'] = $FUNCS->serialize($attr_udf); } // HOOK: alter_field_insert $FUNCS->dispatch_event('alter_field_insert', array(&$fields, $attr, $is_udf, $params, $node)); $rs = $DB->insert(K_TBL_FIELDS, $fields); if ($rs == -1) { die("ERROR: Unable to insert record in K_TBL_FIELDS"); } $field_id = $DB->last_insert_id; $rs = $DB->select(K_TBL_FIELDS, array('*'), "id='" . $DB->sanitize($field_id) . "'"); if (!count($rs)) { die("ERROR: Failed to insert record in K_TBL_FIELDS"); } if ($is_udf) { $classname = $FUNCS->udfs[$attr['type']]['handler']; $f = new $classname($rs[0], $PAGE, $PAGE->fields); } else { $f = new KField($rs[0], $PAGE, $PAGE->fields); } $f->processed = 1; $PAGE->fields[] = $f; // Create a field record for each existing page. This is for storage. $rs = $DB->select(K_TBL_PAGES, array('*'), "template_id='" . $DB->sanitize($PAGE->tpl_id) . "'"); if (count($rs)) { $to_table = $f->search_type == 'text' ? K_TBL_DATA_TEXT : K_TBL_DATA_NUMERIC; foreach ($rs as $rec) { $arr_to_fields = array('page_id' => $rec['id'], 'field_id' => $field_id, 'value' => ''); if ($f->search_type == 'text') { $arr_to_fields['search_value'] = ''; } // HOOK: alter_datafield_insert_for_existingpage $FUNCS->dispatch_event('alter_datafield_insert_for_existingpage', array($rec, &$arr_to_fields, &$to_table, &$f, &$PAGE, $params, $node)); $rs2 = $DB->insert($to_table, $arr_to_fields); if ($rs2 == -1) { die("ERROR: Failed to insert record for K_TBL_FIELDS in" . $to_table); } if ($is_udf) { // Call udf to do something for 'create' event $f->_create($rec['id'], 1); } } } // HOOK: field_inserted $FUNCS->dispatch_event('field_inserted', array(&$f, $is_udf, &$PAGE, $params, $node)); $DB->commit(); if (!$hidden && !($PAGE->is_master && $PAGE->tpl_is_clonable)) { if (!($field->k_type == 'hidden' || $field->k_type == 'message' || $field->k_type == 'group')) { return $f->default_data; } } } } }