Translated using Weblate (Slovenian)
[phpmyadmin.git] / libraries / insert_edit.lib.php
blob10f6d9bdceaf5b32556a33ae9311e03ad09fc34a
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * set of functions with the insert/edit features in pma
6 * @package PhpMyAdmin
7 */
8 use PMA\libraries\Message;
9 use PMA\libraries\plugins\TransformationsPlugin;
10 use PMA\libraries\Response;
11 use PMA\libraries\URL;
12 use PMA\libraries\Sanitize;
14 /**
15 * Retrieve form parameters for insert/edit form
17 * @param string $db name of the database
18 * @param string $table name of the table
19 * @param array|null $where_clauses where clauses
20 * @param array $where_clause_array array of where clauses
21 * @param string $err_url error url
23 * @return array $form_params array of insert/edit form parameters
25 function PMA_getFormParametersForInsertForm($db, $table, $where_clauses,
26 $where_clause_array, $err_url
27 ) {
28 $_form_params = array(
29 'db' => $db,
30 'table' => $table,
31 'goto' => $GLOBALS['goto'],
32 'err_url' => $err_url,
33 'sql_query' => $_REQUEST['sql_query'],
35 if (isset($where_clauses)) {
36 foreach ($where_clause_array as $key_id => $where_clause) {
37 $_form_params['where_clause[' . $key_id . ']'] = trim($where_clause);
40 if (isset($_REQUEST['clause_is_unique'])) {
41 $_form_params['clause_is_unique'] = $_REQUEST['clause_is_unique'];
43 return $_form_params;
46 /**
47 * Creates array of where clauses
49 * @param array|string|null $where_clause where clause
51 * @return array whereClauseArray array of where clauses
53 function PMA_getWhereClauseArray($where_clause)
55 if (!isset($where_clause)) {
56 return array();
59 if (is_array($where_clause)) {
60 return $where_clause;
63 return array(0 => $where_clause);
66 /**
67 * Analysing where clauses array
69 * @param array $where_clause_array array of where clauses
70 * @param string $table name of the table
71 * @param string $db name of the database
73 * @return array $where_clauses, $result, $rows
75 function PMA_analyzeWhereClauses(
76 $where_clause_array, $table, $db
77 ) {
78 $rows = array();
79 $result = array();
80 $where_clauses = array();
81 $found_unique_key = false;
82 foreach ($where_clause_array as $key_id => $where_clause) {
84 $local_query = 'SELECT * FROM '
85 . PMA\libraries\Util::backquote($db) . '.'
86 . PMA\libraries\Util::backquote($table)
87 . ' WHERE ' . $where_clause . ';';
88 $result[$key_id] = $GLOBALS['dbi']->query(
89 $local_query, null, PMA\libraries\DatabaseInterface::QUERY_STORE
91 $rows[$key_id] = $GLOBALS['dbi']->fetchAssoc($result[$key_id]);
93 $where_clauses[$key_id] = str_replace('\\', '\\\\', $where_clause);
94 $has_unique_condition = PMA_showEmptyResultMessageOrSetUniqueCondition(
95 $rows, $key_id, $where_clause_array, $local_query, $result
97 if ($has_unique_condition) {
98 $found_unique_key = true;
101 return array($where_clauses, $result, $rows, $found_unique_key);
105 * Show message for empty result or set the unique_condition
107 * @param array $rows MySQL returned rows
108 * @param string $key_id ID in current key
109 * @param array $where_clause_array array of where clauses
110 * @param string $local_query query performed
111 * @param array $result MySQL result handle
113 * @return boolean $has_unique_condition
115 function PMA_showEmptyResultMessageOrSetUniqueCondition($rows, $key_id,
116 $where_clause_array, $local_query, $result
118 $has_unique_condition = false;
120 // No row returned
121 if (! $rows[$key_id]) {
122 unset($rows[$key_id], $where_clause_array[$key_id]);
123 Response::getInstance()->addHtml(
124 PMA\libraries\Util::getMessage(
125 __('MySQL returned an empty result set (i.e. zero rows).'),
126 $local_query
130 * @todo not sure what should be done at this point, but we must not
131 * exit if we want the message to be displayed
133 } else {// end if (no row returned)
134 $meta = $GLOBALS['dbi']->getFieldsMeta($result[$key_id]);
136 list($unique_condition, $tmp_clause_is_unique)
137 = PMA\libraries\Util::getUniqueCondition(
138 $result[$key_id], // handle
139 count($meta), // fields_cnt
140 $meta, // fields_meta
141 $rows[$key_id], // row
142 true, // force_unique
143 false, // restrict_to_table
144 null // analyzed_sql_results
147 if (! empty($unique_condition)) {
148 $has_unique_condition = true;
150 unset($unique_condition, $tmp_clause_is_unique);
152 return $has_unique_condition;
156 * No primary key given, just load first row
158 * @param string $table name of the table
159 * @param string $db name of the database
161 * @return array containing $result and $rows arrays
163 function PMA_loadFirstRow($table, $db)
165 $result = $GLOBALS['dbi']->query(
166 'SELECT * FROM ' . PMA\libraries\Util::backquote($db)
167 . '.' . PMA\libraries\Util::backquote($table) . ' LIMIT 1;',
168 null,
169 PMA\libraries\DatabaseInterface::QUERY_STORE
171 $rows = array_fill(0, $GLOBALS['cfg']['InsertRows'], false);
172 return array($result, $rows);
176 * Add some url parameters
178 * @param array $url_params containing $db and $table as url parameters
179 * @param array $where_clause_array where clauses array
180 * @param string $where_clause where clause
182 * @return array Add some url parameters to $url_params array and return it
184 function PMA_urlParamsInEditMode($url_params, $where_clause_array, $where_clause)
186 if (isset($where_clause)) {
187 foreach ($where_clause_array as $where_clause) {
188 $url_params['where_clause'] = trim($where_clause);
191 if (! empty($_REQUEST['sql_query'])) {
192 $url_params['sql_query'] = $_REQUEST['sql_query'];
194 return $url_params;
198 * Show type information or function selectors in Insert/Edit
200 * @param string $which function|type
201 * @param array $url_params containing url parameters
202 * @param boolean $is_show whether to show the element in $which
204 * @return string an HTML snippet
206 function PMA_showTypeOrFunction($which, $url_params, $is_show)
208 $params = array();
210 switch($which) {
211 case 'function':
212 $params['ShowFunctionFields'] = ($is_show ? 0 : 1);
213 $params['ShowFieldTypesInDataEditView']
214 = $GLOBALS['cfg']['ShowFieldTypesInDataEditView'];
215 break;
216 case 'type':
217 $params['ShowFieldTypesInDataEditView'] = ($is_show ? 0 : 1);
218 $params['ShowFunctionFields']
219 = $GLOBALS['cfg']['ShowFunctionFields'];
220 break;
223 $params['goto'] = 'sql.php';
224 $this_url_params = array_merge($url_params, $params);
226 if (! $is_show) {
227 return ' : <a href="tbl_change.php'
228 . URL::getCommon($this_url_params) . '">'
229 . PMA_showTypeOrFunctionLabel($which)
230 . '</a>';
232 return '<th><a href="tbl_change.php'
233 . URL::getCommon($this_url_params)
234 . '" title="' . __('Hide') . '">'
235 . PMA_showTypeOrFunctionLabel($which)
236 . '</a></th>';
240 * Show type information or function selectors labels in Insert/Edit
242 * @param string $which function|type
244 * @return string an HTML snippet
246 function PMA_showTypeOrFunctionLabel($which)
248 switch($which) {
249 case 'function':
250 return __('Function');
251 case 'type':
252 return __('Type');
255 return null;
259 * Analyze the table column array
261 * @param array $column description of column in given table
262 * @param array $comments_map comments for every column that has a comment
263 * @param boolean $timestamp_seen whether a timestamp has been seen
265 * @return array description of column in given table
267 function PMA_analyzeTableColumnsArray($column, $comments_map, $timestamp_seen)
269 $column['Field_html'] = htmlspecialchars($column['Field']);
270 $column['Field_md5'] = md5($column['Field']);
271 // True_Type contains only the type (stops at first bracket)
272 $column['True_Type'] = preg_replace('@\(.*@s', '', $column['Type']);
273 $column['len'] = preg_match('@float|double@', $column['Type']) ? 100 : -1;
274 $column['Field_title'] = PMA_getColumnTitle($column, $comments_map);
275 $column['is_binary'] = PMA_isColumn(
276 $column,
277 array('binary', 'varbinary')
279 $column['is_blob'] = PMA_isColumn(
280 $column,
281 array('blob', 'tinyblob', 'mediumblob', 'longblob')
283 $column['is_char'] = PMA_isColumn(
284 $column,
285 array('char', 'varchar')
288 list($column['pma_type'], $column['wrap'], $column['first_timestamp'])
289 = PMA_getEnumSetAndTimestampColumns($column, $timestamp_seen);
291 return $column;
295 * Retrieve the column title
297 * @param array $column description of column in given table
298 * @param array $comments_map comments for every column that has a comment
300 * @return string column title
302 function PMA_getColumnTitle($column, $comments_map)
304 if (isset($comments_map[$column['Field']])) {
305 return '<span style="border-bottom: 1px dashed black;" title="'
306 . htmlspecialchars($comments_map[$column['Field']]) . '">'
307 . $column['Field_html'] . '</span>';
308 } else {
309 return $column['Field_html'];
314 * check whether the column is of a certain type
315 * the goal is to ensure that types such as "enum('one','two','binary',..)"
316 * or "enum('one','two','varbinary',..)" are not categorized as binary
318 * @param array $column description of column in given table
319 * @param array $types the types to verify
321 * @return boolean whether the column's type if one of the $types
323 function PMA_isColumn($column, $types)
325 foreach ($types as $one_type) {
326 if (mb_stripos($column['Type'], $one_type) === 0) {
327 return true;
330 return false;
334 * Retrieve set, enum, timestamp table columns
336 * @param array $column description of column in given table
337 * @param boolean $timestamp_seen whether a timestamp has been seen
339 * @return array $column['pma_type'], $column['wrap'], $column['first_timestamp']
341 function PMA_getEnumSetAndTimestampColumns($column, $timestamp_seen)
343 $column['first_timestamp'] = false;
344 switch ($column['True_Type']) {
345 case 'set':
346 $column['pma_type'] = 'set';
347 $column['wrap'] = '';
348 break;
349 case 'enum':
350 $column['pma_type'] = 'enum';
351 $column['wrap'] = '';
352 break;
353 case 'timestamp':
354 if (! $timestamp_seen) { // can only occur once per table
355 $column['first_timestamp'] = true;
357 $column['pma_type'] = $column['Type'];
358 $column['wrap'] = ' nowrap';
359 break;
361 default:
362 $column['pma_type'] = $column['Type'];
363 $column['wrap'] = ' nowrap';
364 break;
366 return array($column['pma_type'], $column['wrap'], $column['first_timestamp']);
370 * The function column
371 * We don't want binary data to be destroyed
372 * Note: from the MySQL manual: "BINARY doesn't affect how the column is
373 * stored or retrieved" so it does not mean that the contents is binary
375 * @param array $column description of column in given table
376 * @param boolean $is_upload upload or no
377 * @param string $column_name_appendix the name attribute
378 * @param string $onChangeClause onchange clause for fields
379 * @param array $no_support_types list of datatypes that are not (yet)
380 * handled by PMA
381 * @param integer $tabindex_for_function +3000
382 * @param integer $tabindex tab index
383 * @param integer $idindex id index
384 * @param boolean $insert_mode insert mode or edit mode
385 * @param boolean $readOnly is column read only or not
386 * @param array $foreignData foreign key data
388 * @return string an html snippet
390 function PMA_getFunctionColumn($column, $is_upload, $column_name_appendix,
391 $onChangeClause, $no_support_types, $tabindex_for_function,
392 $tabindex, $idindex, $insert_mode, $readOnly, $foreignData
394 $html_output = '';
395 if (($GLOBALS['cfg']['ProtectBinary'] === 'blob'
396 && $column['is_blob'] && !$is_upload)
397 || ($GLOBALS['cfg']['ProtectBinary'] === 'all'
398 && $column['is_binary'])
399 || ($GLOBALS['cfg']['ProtectBinary'] === 'noblob'
400 && $column['is_binary'])
402 $html_output .= '<td class="center">' . __('Binary') . '</td>' . "\n";
403 } elseif ($readOnly
404 || mb_strstr($column['True_Type'], 'enum')
405 || mb_strstr($column['True_Type'], 'set')
406 || in_array($column['pma_type'], $no_support_types)
408 $html_output .= '<td class="center">--</td>' . "\n";
409 } else {
410 $html_output .= '<td>' . "\n";
412 $html_output .= '<select name="funcs' . $column_name_appendix . '"'
413 . ' ' . $onChangeClause
414 . ' tabindex="' . ($tabindex + $tabindex_for_function) . '"'
415 . ' id="field_' . $idindex . '_1">';
416 $html_output .= PMA\libraries\Util::getFunctionsForField(
417 $column,
418 $insert_mode,
419 $foreignData
420 ) . "\n";
422 $html_output .= '</select>' . "\n";
423 $html_output .= '</td>' . "\n";
425 return $html_output;
429 * The null column
431 * @param array $column description of column in given table
432 * @param string $column_name_appendix the name attribute
433 * @param boolean $real_null_value is column value null or not null
434 * @param integer $tabindex tab index
435 * @param integer $tabindex_for_null +6000
436 * @param integer $idindex id index
437 * @param string $vkey [multi_edit]['row_id']
438 * @param array $foreigners keys into foreign fields
439 * @param array $foreignData data about the foreign keys
440 * @param boolean $readOnly is column read only or not
442 * @return string an html snippet
444 function PMA_getNullColumn($column, $column_name_appendix, $real_null_value,
445 $tabindex, $tabindex_for_null, $idindex, $vkey, $foreigners, $foreignData,
446 $readOnly
448 if ($column['Null'] != 'YES' || $readOnly) {
449 return "<td></td>\n";
451 $html_output = '';
452 $html_output .= '<td>' . "\n";
453 $html_output .= '<input type="hidden" name="fields_null_prev'
454 . $column_name_appendix . '"';
455 if ($real_null_value && !$column['first_timestamp']) {
456 $html_output .= ' value="on"';
458 $html_output .= ' />' . "\n";
460 $html_output .= '<input type="checkbox" class="checkbox_null" tabindex="'
461 . ($tabindex + $tabindex_for_null) . '"'
462 . ' name="fields_null' . $column_name_appendix . '"';
463 if ($real_null_value) {
464 $html_output .= ' checked="checked"';
466 $html_output .= ' id="field_' . ($idindex) . '_2" />';
468 // nullify_code is needed by the js nullify() function
469 $nullify_code = PMA_getNullifyCodeForNullColumn(
470 $column, $foreigners, $foreignData
472 // to be able to generate calls to nullify() in jQuery
473 $html_output .= '<input type="hidden" class="nullify_code" name="nullify_code'
474 . $column_name_appendix . '" value="' . $nullify_code . '" />';
475 $html_output .= '<input type="hidden" class="hashed_field" name="hashed_field'
476 . $column_name_appendix . '" value="' . $column['Field_md5'] . '" />';
477 $html_output .= '<input type="hidden" class="multi_edit" name="multi_edit'
478 . $column_name_appendix . '" value="' . Sanitize::escapeJsString($vkey) . '" />';
479 $html_output .= '</td>' . "\n";
481 return $html_output;
485 * Retrieve the nullify code for the null column
487 * @param array $column description of column in given table
488 * @param array $foreigners keys into foreign fields
489 * @param array $foreignData data about the foreign keys
491 * @return integer $nullify_code
493 function PMA_getNullifyCodeForNullColumn($column, $foreigners, $foreignData)
495 $foreigner = PMA_searchColumnInForeigners($foreigners, $column['Field']);
496 if (mb_strstr($column['True_Type'], 'enum')) {
497 if (mb_strlen($column['Type']) > 20) {
498 $nullify_code = '1';
499 } else {
500 $nullify_code = '2';
502 } elseif (mb_strstr($column['True_Type'], 'set')) {
503 $nullify_code = '3';
504 } elseif (!empty($foreigners)
505 && !empty($foreigner)
506 && $foreignData['foreign_link'] == false
508 // foreign key in a drop-down
509 $nullify_code = '4';
510 } elseif (!empty($foreigners)
511 && !empty($foreigner)
512 && $foreignData['foreign_link'] == true
514 // foreign key with a browsing icon
515 $nullify_code = '6';
516 } else {
517 $nullify_code = '5';
519 return $nullify_code;
523 * Get the HTML elements for value column in insert form
524 * (here, "column" is used in the sense of HTML column in HTML table)
526 * @param array $column description of column in given table
527 * @param string $backup_field hidden input field
528 * @param string $column_name_appendix the name attribute
529 * @param string $onChangeClause onchange clause for fields
530 * @param integer $tabindex tab index
531 * @param integer $tabindex_for_value offset for the values tabindex
532 * @param integer $idindex id index
533 * @param string $data description of the column field
534 * @param string $special_chars special characters
535 * @param array $foreignData data about the foreign keys
536 * @param array $paramTableDbArray array containing $table and $db
537 * @param integer $rownumber the row number
538 * @param array $titles An HTML IMG tag for a particular icon from
539 * a theme, which may be an actual file or
540 * an icon from a sprite
541 * @param string $text_dir text direction
542 * @param string $special_chars_encoded replaced char if the string starts
543 * with a \r\n pair (0x0d0a) add an extra \n
544 * @param string $vkey [multi_edit]['row_id']
545 * @param boolean $is_upload is upload or not
546 * @param integer $biggest_max_file_size 0 integer
547 * @param string $default_char_editing default char editing mode which is stored
548 * in the config.inc.php script
549 * @param array $no_support_types list of datatypes that are not (yet)
550 * handled by PMA
551 * @param array $gis_data_types list of GIS data types
552 * @param array $extracted_columnspec associative array containing type,
553 * spec_in_brackets and possibly
554 * enum_set_values (another array)
555 * @param boolean $readOnly is column read only or not
557 * @return string an html snippet
559 function PMA_getValueColumn($column, $backup_field, $column_name_appendix,
560 $onChangeClause, $tabindex, $tabindex_for_value, $idindex, $data,
561 $special_chars, $foreignData, $paramTableDbArray, $rownumber,
562 $titles, $text_dir, $special_chars_encoded, $vkey,
563 $is_upload, $biggest_max_file_size,
564 $default_char_editing, $no_support_types, $gis_data_types, $extracted_columnspec,
565 $readOnly
567 // HTML5 data-* attribute data-type
568 $data_type = $GLOBALS['PMA_Types']->getTypeClass($column['True_Type']);
569 $html_output = '';
571 if ($foreignData['foreign_link'] == true) {
572 $html_output .= PMA_getForeignLink(
573 $column, $backup_field, $column_name_appendix,
574 $onChangeClause, $tabindex, $tabindex_for_value, $idindex, $data,
575 $paramTableDbArray, $rownumber, $titles, $readOnly
578 } elseif (is_array($foreignData['disp_row'])) {
579 $html_output .= PMA_dispRowForeignData(
580 $backup_field, $column_name_appendix,
581 $onChangeClause, $tabindex, $tabindex_for_value,
582 $idindex, $data, $foreignData, $readOnly
585 } elseif ($GLOBALS['cfg']['LongtextDoubleTextarea']
586 && mb_strstr($column['pma_type'], 'longtext')
588 $html_output .= PMA_getTextarea(
589 $column, $backup_field, $column_name_appendix, $onChangeClause,
590 $tabindex, $tabindex_for_value, $idindex, $text_dir,
591 $special_chars_encoded, $data_type, $readOnly
594 } elseif (mb_strstr($column['pma_type'], 'text')) {
596 $html_output .= PMA_getTextarea(
597 $column, $backup_field, $column_name_appendix, $onChangeClause,
598 $tabindex, $tabindex_for_value, $idindex, $text_dir,
599 $special_chars_encoded, $data_type, $readOnly
601 $html_output .= "\n";
602 if (mb_strlen($special_chars) > 32000) {
603 $html_output .= "</td>\n";
604 $html_output .= '<td>' . __(
605 'Because of its length,<br /> this column might not be editable.'
609 } elseif ($column['pma_type'] == 'enum') {
610 $html_output .= PMA_getPmaTypeEnum(
611 $column, $backup_field, $column_name_appendix, $extracted_columnspec,
612 $onChangeClause, $tabindex, $tabindex_for_value, $idindex, $data,
613 $readOnly
616 } elseif ($column['pma_type'] == 'set') {
617 $html_output .= PMA_getPmaTypeSet(
618 $column, $extracted_columnspec, $backup_field,
619 $column_name_appendix, $onChangeClause, $tabindex,
620 $tabindex_for_value, $idindex, $data, $readOnly
623 } elseif ($column['is_binary'] || $column['is_blob']) {
624 $html_output .= PMA_getBinaryAndBlobColumn(
625 $column, $data, $special_chars, $biggest_max_file_size,
626 $backup_field, $column_name_appendix, $onChangeClause, $tabindex,
627 $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded,
628 $vkey, $is_upload, $readOnly
631 } elseif (! in_array($column['pma_type'], $no_support_types)) {
632 $html_output .= PMA_getValueColumnForOtherDatatypes(
633 $column, $default_char_editing, $backup_field,
634 $column_name_appendix, $onChangeClause, $tabindex, $special_chars,
635 $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded,
636 $data, $extracted_columnspec, $readOnly
640 if (in_array($column['pma_type'], $gis_data_types)) {
641 $html_output .= PMA_getHTMLforGisDataTypes();
644 return $html_output;
648 * Get HTML for foreign link in insert form
650 * @param array $column description of column in given table
651 * @param string $backup_field hidden input field
652 * @param string $column_name_appendix the name attribute
653 * @param string $onChangeClause onchange clause for fields
654 * @param integer $tabindex tab index
655 * @param integer $tabindex_for_value offset for the values tabindex
656 * @param integer $idindex id index
657 * @param string $data data to edit
658 * @param array $paramTableDbArray array containing $table and $db
659 * @param integer $rownumber the row number
660 * @param array $titles An HTML IMG tag for a particular icon from
661 * a theme, which may be an actual file or
662 * an icon from a sprite
663 * @param boolean $readOnly is column read only or not
665 * @return string an html snippet
667 function PMA_getForeignLink($column, $backup_field, $column_name_appendix,
668 $onChangeClause, $tabindex, $tabindex_for_value, $idindex, $data,
669 $paramTableDbArray, $rownumber, $titles, $readOnly
671 list($table, $db) = $paramTableDbArray;
672 $html_output = '';
673 $html_output .= $backup_field . "\n";
675 $html_output .= '<input type="hidden" name="fields_type'
676 . $column_name_appendix . '" value="foreign" />';
678 $html_output .= '<input type="text" name="fields' . $column_name_appendix . '" '
679 . 'class="textfield" '
680 . $onChangeClause . ' '
681 . ($readOnly ? 'readonly="readonly" ' : '')
682 . 'tabindex="' . ($tabindex + $tabindex_for_value) . '" '
683 . 'id="field_' . ($idindex) . '_3" '
684 . 'value="' . htmlspecialchars($data) . '" />';
686 $html_output .= '<a class="ajax browse_foreign" href="browse_foreigners.php'
687 . URL::getCommon(
688 array(
689 'db' => $db,
690 'table' => $table,
691 'field' => $column['Field'],
692 'rownumber' => $rownumber,
693 'data' => $data
695 ) . '">'
696 . str_replace("'", "\'", $titles['Browse']) . '</a>';
697 return $html_output;
701 * Get HTML to display foreign data
703 * @param string $backup_field hidden input field
704 * @param string $column_name_appendix the name attribute
705 * @param string $onChangeClause onchange clause for fields
706 * @param integer $tabindex tab index
707 * @param integer $tabindex_for_value offset for the values tabindex
708 * @param integer $idindex id index
709 * @param string $data data to edit
710 * @param array $foreignData data about the foreign keys
711 * @param boolean $readOnly is display read only or not
713 * @return string an html snippet
715 function PMA_dispRowForeignData($backup_field, $column_name_appendix,
716 $onChangeClause, $tabindex, $tabindex_for_value, $idindex, $data,
717 $foreignData, $readOnly
719 $html_output = '';
720 $html_output .= $backup_field . "\n";
721 $html_output .= '<input type="hidden"'
722 . ' name="fields_type' . $column_name_appendix . '"'
723 . ' value="foreign" />';
725 $html_output .= '<select name="fields' . $column_name_appendix . '"'
726 . ' ' . $onChangeClause
727 . ' class="textfield"'
728 . ($readOnly ? ' disabled' : '')
729 . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"'
730 . ' id="field_' . $idindex . '_3">';
731 $html_output .= PMA_foreignDropdown(
732 $foreignData['disp_row'], $foreignData['foreign_field'],
733 $foreignData['foreign_display'], $data,
734 $GLOBALS['cfg']['ForeignKeyMaxLimit']
736 $html_output .= '</select>';
738 //Add hidden input, as disabled <select> input does not included in POST.
739 if ($readOnly) {
740 $html_output .= '<input name="fields' . $column_name_appendix . '"'
741 . ' type="hidden" value="' . htmlspecialchars($data) . '">';
744 return $html_output;
748 * Get HTML textarea for insert form
750 * @param array $column column information
751 * @param string $backup_field hidden input field
752 * @param string $column_name_appendix the name attribute
753 * @param string $onChangeClause onchange clause for fields
754 * @param integer $tabindex tab index
755 * @param integer $tabindex_for_value offset for the values tabindex
756 * @param integer $idindex id index
757 * @param string $text_dir text direction
758 * @param string $special_chars_encoded replaced char if the string starts
759 * with a \r\n pair (0x0d0a) add an extra \n
760 * @param string $data_type the html5 data-* attribute type
761 * @param boolean $readOnly is column read only or not
763 * @return string an html snippet
765 function PMA_getTextarea($column, $backup_field, $column_name_appendix,
766 $onChangeClause, $tabindex, $tabindex_for_value, $idindex,
767 $text_dir, $special_chars_encoded, $data_type, $readOnly
769 $the_class = '';
770 $textAreaRows = $GLOBALS['cfg']['TextareaRows'];
771 $textareaCols = $GLOBALS['cfg']['TextareaCols'];
773 if ($column['is_char']) {
775 * @todo clarify the meaning of the "textfield" class and explain
776 * why character columns have the "char" class instead
778 $the_class = 'char';
779 $textAreaRows = $GLOBALS['cfg']['CharTextareaRows'];
780 $textareaCols = $GLOBALS['cfg']['CharTextareaCols'];
781 $extracted_columnspec = PMA\libraries\Util::extractColumnSpec(
782 $column['Type']
784 $maxlength = $extracted_columnspec['spec_in_brackets'];
785 } elseif ($GLOBALS['cfg']['LongtextDoubleTextarea']
786 && mb_strstr($column['pma_type'], 'longtext')
788 $textAreaRows = $GLOBALS['cfg']['TextareaRows'] * 2;
789 $textareaCols = $GLOBALS['cfg']['TextareaCols'] * 2;
791 $html_output = $backup_field . "\n"
792 . '<textarea name="fields' . $column_name_appendix . '"'
793 . ' class="' . $the_class . '"'
794 . ($readOnly ? ' readonly="readonly"' : '')
795 . (isset($maxlength) ? ' data-maxlength="' . $maxlength . '"' : '')
796 . ' rows="' . $textAreaRows . '"'
797 . ' cols="' . $textareaCols . '"'
798 . ' dir="' . $text_dir . '"'
799 . ' id="field_' . ($idindex) . '_3"'
800 . (! empty($onChangeClause) ? ' ' . $onChangeClause : '')
801 . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"'
802 . ' data-type="' . $data_type . '">'
803 . $special_chars_encoded
804 . '</textarea>';
806 return $html_output;
810 * Get HTML for enum type
812 * @param array $column description of column in given table
813 * @param string $backup_field hidden input field
814 * @param string $column_name_appendix the name attribute
815 * @param array $extracted_columnspec associative array containing type,
816 * spec_in_brackets and possibly
817 * enum_set_values (another array)
818 * @param string $onChangeClause onchange clause for fields
819 * @param integer $tabindex tab index
820 * @param integer $tabindex_for_value offset for the values tabindex
821 * @param integer $idindex id index
822 * @param mixed $data data to edit
823 * @param boolean $readOnly is column read only or not
825 * @return string an html snippet
827 function PMA_getPmaTypeEnum($column, $backup_field, $column_name_appendix,
828 $extracted_columnspec, $onChangeClause, $tabindex, $tabindex_for_value,
829 $idindex, $data, $readOnly
831 $html_output = '';
832 if (! isset($column['values'])) {
833 $column['values'] = PMA_getColumnEnumValues(
834 $column, $extracted_columnspec
837 $column_enum_values = $column['values'];
838 $html_output .= '<input type="hidden" name="fields_type'
839 . $column_name_appendix . '" value="enum" />';
840 $html_output .= "\n" . ' ' . $backup_field . "\n";
841 if (mb_strlen($column['Type']) > 20) {
842 $html_output .= PMA_getDropDownDependingOnLength(
843 $column, $column_name_appendix, $onChangeClause,
844 $tabindex, $tabindex_for_value,
845 $idindex, $data, $column_enum_values, $readOnly
847 } else {
848 $html_output .= PMA_getRadioButtonDependingOnLength(
849 $column_name_appendix, $onChangeClause,
850 $tabindex, $column, $tabindex_for_value,
851 $idindex, $data, $column_enum_values, $readOnly
854 return $html_output;
858 * Get column values
860 * @param array $column description of column in given table
861 * @param array $extracted_columnspec associative array containing type,
862 * spec_in_brackets and possibly enum_set_values
863 * (another array)
865 * @return array column values as an associative array
867 function PMA_getColumnEnumValues($column, $extracted_columnspec)
869 $column['values'] = array();
870 foreach ($extracted_columnspec['enum_set_values'] as $val) {
871 $column['values'][] = array(
872 'plain' => $val,
873 'html' => htmlspecialchars($val),
876 return $column['values'];
880 * Get HTML drop down for more than 20 string length
882 * @param array $column description of column in given table
883 * @param string $column_name_appendix the name attribute
884 * @param string $onChangeClause onchange clause for fields
885 * @param integer $tabindex tab index
886 * @param integer $tabindex_for_value offset for the values tabindex
887 * @param integer $idindex id index
888 * @param string $data data to edit
889 * @param array $column_enum_values $column['values']
890 * @param boolean $readOnly is column read only or not
892 * @return string an html snippet
894 function PMA_getDropDownDependingOnLength(
895 $column, $column_name_appendix, $onChangeClause,
896 $tabindex, $tabindex_for_value, $idindex, $data, $column_enum_values,
897 $readOnly
899 $html_output = '<select name="fields' . $column_name_appendix . '"'
900 . ' ' . $onChangeClause
901 . ' class="textfield"'
902 . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"'
903 . ($readOnly ? ' disabled' : '')
904 . ' id="field_' . ($idindex) . '_3">';
905 $html_output .= '<option value="">&nbsp;</option>' . "\n";
907 $selected_html = '';
908 foreach ($column_enum_values as $enum_value) {
909 $html_output .= '<option value="' . $enum_value['html'] . '"';
910 if ($data == $enum_value['plain']
911 || ($data == ''
912 && (! isset($_REQUEST['where_clause']) || $column['Null'] != 'YES')
913 && isset($column['Default'])
914 && $enum_value['plain'] == $column['Default'])
916 $html_output .= ' selected="selected"';
917 $selected_html = $enum_value['html'];
919 $html_output .= '>' . $enum_value['html'] . '</option>' . "\n";
921 $html_output .= '</select>';
923 //Add hidden input, as disabled <select> input does not included in POST.
924 if ($readOnly) {
925 $html_output .= '<input name="fields' . $column_name_appendix . '"'
926 . ' type="hidden" value="' . $selected_html . '">';
928 return $html_output;
932 * Get HTML radio button for less than 20 string length
934 * @param string $column_name_appendix the name attribute
935 * @param string $onChangeClause onchange clause for fields
936 * @param integer $tabindex tab index
937 * @param array $column description of column in given table
938 * @param integer $tabindex_for_value offset for the values tabindex
939 * @param integer $idindex id index
940 * @param string $data data to edit
941 * @param array $column_enum_values $column['values']
942 * @param boolean $readOnly is column read only or not
944 * @return string an html snippet
946 function PMA_getRadioButtonDependingOnLength(
947 $column_name_appendix, $onChangeClause,
948 $tabindex, $column, $tabindex_for_value, $idindex, $data,
949 $column_enum_values, $readOnly
951 $j = 0;
952 $html_output = '';
953 foreach ($column_enum_values as $enum_value) {
954 $html_output .= ' '
955 . '<input type="radio" name="fields' . $column_name_appendix . '"'
956 . ' class="textfield"'
957 . ' value="' . $enum_value['html'] . '"'
958 . ' id="field_' . ($idindex) . '_3_' . $j . '"'
959 . ' ' . $onChangeClause;
960 if ($data == $enum_value['plain']
961 || ($data == ''
962 && (! isset($_REQUEST['where_clause']) || $column['Null'] != 'YES')
963 && isset($column['Default'])
964 && $enum_value['plain'] == $column['Default'])
966 $html_output .= ' checked="checked"';
968 elseif ($readOnly) {
969 $html_output .= ' disabled';
971 $html_output .= ' tabindex="' . ($tabindex + $tabindex_for_value) . '" />';
972 $html_output .= '<label for="field_' . $idindex . '_3_' . $j . '">'
973 . $enum_value['html'] . '</label>' . "\n";
974 $j++;
976 return $html_output;
980 * Get the HTML for 'set' pma type
982 * @param array $column description of column in given table
983 * @param array $extracted_columnspec associative array containing type,
984 * spec_in_brackets and possibly
985 * enum_set_values (another array)
986 * @param string $backup_field hidden input field
987 * @param string $column_name_appendix the name attribute
988 * @param string $onChangeClause onchange clause for fields
989 * @param integer $tabindex tab index
990 * @param integer $tabindex_for_value offset for the values tabindex
991 * @param integer $idindex id index
992 * @param string $data description of the column field
993 * @param boolean $readOnly is column read only or not
995 * @return string an html snippet
997 function PMA_getPmaTypeSet(
998 $column, $extracted_columnspec, $backup_field,
999 $column_name_appendix, $onChangeClause, $tabindex,
1000 $tabindex_for_value, $idindex, $data, $readOnly
1002 list($column_set_values, $select_size) = PMA_getColumnSetValueAndSelectSize(
1003 $column, $extracted_columnspec
1005 $vset = array_flip(explode(',', $data));
1006 $html_output = $backup_field . "\n";
1007 $html_output .= '<input type="hidden" name="fields_type'
1008 . $column_name_appendix . '" value="set" />';
1009 $html_output .= '<select name="fields' . $column_name_appendix . '[]' . '"'
1010 . ' class="textfield"'
1011 . ($readOnly ? ' disabled' : '')
1012 . ' size="' . $select_size . '"'
1013 . ' multiple="multiple"'
1014 . ' ' . $onChangeClause
1015 . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"'
1016 . ' id="field_' . ($idindex) . '_3">';
1018 $selected_html = '';
1019 foreach ($column_set_values as $column_set_value) {
1020 $html_output .= '<option value="' . $column_set_value['html'] . '"';
1021 if (isset($vset[$column_set_value['plain']])) {
1022 $html_output .= ' selected="selected"';
1023 $selected_html = $column_set_value['html'];
1025 $html_output .= '>' . $column_set_value['html'] . '</option>' . "\n";
1027 $html_output .= '</select>';
1029 //Add hidden input, as disabled <select> input does not included in POST.
1030 if ($readOnly) {
1031 $html_output .= '<input name="fields' . $column_name_appendix . '[]' . '"'
1032 . ' type="hidden" value="' . $selected_html . '">';
1034 return $html_output;
1038 * Retrieve column 'set' value and select size
1040 * @param array $column description of column in given table
1041 * @param array $extracted_columnspec associative array containing type,
1042 * spec_in_brackets and possibly enum_set_values
1043 * (another array)
1045 * @return array $column['values'], $column['select_size']
1047 function PMA_getColumnSetValueAndSelectSize($column, $extracted_columnspec)
1049 if (! isset($column['values'])) {
1050 $column['values'] = array();
1051 foreach ($extracted_columnspec['enum_set_values'] as $val) {
1052 $column['values'][] = array(
1053 'plain' => $val,
1054 'html' => htmlspecialchars($val),
1057 $column['select_size'] = min(4, count($column['values']));
1059 return array($column['values'], $column['select_size']);
1063 * Get HTML for binary and blob column
1065 * @param array $column description of column in given table
1066 * @param string $data data to edit
1067 * @param string $special_chars special characters
1068 * @param integer $biggest_max_file_size biggest max file size for uploading
1069 * @param string $backup_field hidden input field
1070 * @param string $column_name_appendix the name attribute
1071 * @param string $onChangeClause onchange clause for fields
1072 * @param integer $tabindex tab index
1073 * @param integer $tabindex_for_value offset for the values tabindex
1074 * @param integer $idindex id index
1075 * @param string $text_dir text direction
1076 * @param string $special_chars_encoded replaced char if the string starts
1077 * with a \r\n pair (0x0d0a) add an extra \n
1078 * @param string $vkey [multi_edit]['row_id']
1079 * @param boolean $is_upload is upload or not
1080 * @param boolean $readOnly is column read only or not
1082 * @return string an html snippet
1084 function PMA_getBinaryAndBlobColumn(
1085 $column, $data, $special_chars, $biggest_max_file_size,
1086 $backup_field, $column_name_appendix, $onChangeClause, $tabindex,
1087 $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded,
1088 $vkey, $is_upload, $readOnly
1090 $html_output = '';
1091 // Add field type : Protected or Hexadecimal
1092 $fields_type_html = '<input type="hidden" name="fields_type'
1093 . $column_name_appendix . '" value="%s" />';
1094 // Default value : hex
1095 $fields_type_val = 'hex';
1096 if (($GLOBALS['cfg']['ProtectBinary'] === 'blob' && $column['is_blob'])
1097 || ($GLOBALS['cfg']['ProtectBinary'] === 'all')
1098 || ($GLOBALS['cfg']['ProtectBinary'] === 'noblob' && !$column['is_blob'])
1100 $html_output .= __('Binary - do not edit');
1101 if (isset($data)) {
1102 $data_size = PMA\libraries\Util::formatByteDown(
1103 mb_strlen(stripslashes($data)), 3, 1
1105 $html_output .= ' (' . $data_size[0] . ' ' . $data_size[1] . ')';
1106 unset($data_size);
1108 $fields_type_val = 'protected';
1109 $html_output .= '<input type="hidden" name="fields'
1110 . $column_name_appendix . '" value="" />';
1111 } elseif ($column['is_blob']
1112 || ($column['len'] > $GLOBALS['cfg']['LimitChars'])
1114 $html_output .= "\n" . PMA_getTextarea(
1115 $column, $backup_field, $column_name_appendix, $onChangeClause,
1116 $tabindex, $tabindex_for_value, $idindex, $text_dir,
1117 $special_chars_encoded, 'HEX', $readOnly
1119 } else {
1120 // field size should be at least 4 and max $GLOBALS['cfg']['LimitChars']
1121 $fieldsize = min(max($column['len'], 4), $GLOBALS['cfg']['LimitChars']);
1122 $html_output .= "\n" . $backup_field . "\n" . PMA_getHTMLinput(
1123 $column, $column_name_appendix, $special_chars, $fieldsize,
1124 $onChangeClause, $tabindex, $tabindex_for_value, $idindex, 'HEX',
1125 $readOnly
1128 $html_output .= sprintf($fields_type_html, $fields_type_val);
1130 if ($is_upload && $column['is_blob'] && !$readOnly) {
1131 // We don't want to prevent users from using
1132 // browser's default drag-drop feature on some page(s),
1133 // so we add noDragDrop class to the input
1134 $html_output .= '<br />'
1135 . '<input type="file"'
1136 . ' name="fields_upload' . $vkey . '[' . $column['Field_md5'] . ']"'
1137 . ' class="textfield noDragDrop" id="field_' . $idindex . '_3" size="10"'
1138 . ' ' . $onChangeClause . '/>&nbsp;';
1139 list($html_out,) = PMA_getMaxUploadSize(
1140 $column, $biggest_max_file_size
1142 $html_output .= $html_out;
1145 if (!empty($GLOBALS['cfg']['UploadDir']) && !$readOnly) {
1146 $html_output .= PMA_getSelectOptionForUpload($vkey, $column);
1149 return $html_output;
1153 * Get HTML input type
1155 * @param array $column description of column in given table
1156 * @param string $column_name_appendix the name attribute
1157 * @param string $special_chars special characters
1158 * @param integer $fieldsize html field size
1159 * @param string $onChangeClause onchange clause for fields
1160 * @param integer $tabindex tab index
1161 * @param integer $tabindex_for_value offset for the values tabindex
1162 * @param integer $idindex id index
1163 * @param string $data_type the html5 data-* attribute type
1164 * @param boolean $readOnly is column read only or not
1166 * @return string an html snippet
1168 function PMA_getHTMLinput(
1169 $column, $column_name_appendix, $special_chars, $fieldsize, $onChangeClause,
1170 $tabindex, $tabindex_for_value, $idindex, $data_type, $readOnly
1172 $input_type = 'text';
1173 // do not use the 'date' or 'time' types here; they have no effect on some
1174 // browsers and create side effects (see bug #4218)
1176 $the_class = 'textfield';
1177 // verify True_Type which does not contain the parentheses and length
1178 if ($readOnly) {
1179 //NOOP. Disable date/timepicker
1180 } else if ($column['True_Type'] === 'date') {
1181 $the_class .= ' datefield';
1182 } else if ($column['True_Type'] === 'time') {
1183 $the_class .= ' timefield';
1184 } else if ($column['True_Type'] === 'datetime'
1185 || $column['True_Type'] === 'timestamp'
1187 $the_class .= ' datetimefield';
1189 $input_min_max = false;
1190 if (in_array($column['True_Type'], $GLOBALS['PMA_Types']->getIntegerTypes())) {
1191 $extracted_columnspec = PMA\libraries\Util::extractColumnSpec(
1192 $column['Type']
1194 $is_unsigned = $extracted_columnspec['unsigned'];
1195 $min_max_values = $GLOBALS['PMA_Types']->getIntegerRange(
1196 $column['True_Type'], ! $is_unsigned
1198 $input_min_max = 'min="' . $min_max_values[0] . '" '
1199 . 'max="' . $min_max_values[1] . '"';
1200 $data_type = 'INT';
1202 return '<input type="' . $input_type . '"'
1203 . ' name="fields' . $column_name_appendix . '"'
1204 . ' value="' . $special_chars . '" size="' . $fieldsize . '"'
1205 . ((isset($column['is_char']) && $column['is_char'])
1206 ? ' data-maxlength="' . $fieldsize . '"'
1207 : '')
1208 . ($readOnly ? ' readonly="readonly"' : '')
1209 . ($input_min_max !== false ? ' ' . $input_min_max : '')
1210 . ' data-type="' . $data_type . '"'
1211 . ($input_type === 'time' ? ' step="1"' : '')
1212 . ' class="' . $the_class . '" ' . $onChangeClause
1213 . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"'
1214 . ' id="field_' . ($idindex) . '_3" />';
1218 * Get HTML select option for upload
1220 * @param string $vkey [multi_edit]['row_id']
1221 * @param array $column description of column in given table
1223 * @return string|void an html snippet
1225 function PMA_getSelectOptionForUpload($vkey, $column)
1227 $files = PMA_getFileSelectOptions(
1228 PMA\libraries\Util::userDir($GLOBALS['cfg']['UploadDir'])
1231 if ($files === false) {
1232 return '<span style="color:red">' . __('Error') . '</span><br />' . "\n"
1233 . __('The directory you set for upload work cannot be reached.') . "\n";
1234 } elseif (!empty($files)) {
1235 return "<br />\n"
1236 . '<i>' . __('Or') . '</i>' . ' '
1237 . __('web server upload directory:') . '<br />' . "\n"
1238 . '<select size="1" name="fields_uploadlocal'
1239 . $vkey . '[' . $column['Field_md5'] . ']">' . "\n"
1240 . '<option value="" selected="selected"></option>' . "\n"
1241 . $files
1242 . '</select>' . "\n";
1245 return null;
1249 * Retrieve the maximum upload file size
1251 * @param array $column description of column in given table
1252 * @param integer $biggest_max_file_size biggest max file size for uploading
1254 * @return array an html snippet and $biggest_max_file_size
1256 function PMA_getMaxUploadSize($column, $biggest_max_file_size)
1258 // find maximum upload size, based on field type
1260 * @todo with functions this is not so easy, as you can basically
1261 * process any data with function like MD5
1263 global $max_upload_size;
1264 $max_field_sizes = array(
1265 'tinyblob' => '256',
1266 'blob' => '65536',
1267 'mediumblob' => '16777216',
1268 'longblob' => '4294967296' // yeah, really
1271 $this_field_max_size = $max_upload_size; // from PHP max
1272 if ($this_field_max_size > $max_field_sizes[$column['pma_type']]) {
1273 $this_field_max_size = $max_field_sizes[$column['pma_type']];
1275 $html_output
1276 = PMA\libraries\Util::getFormattedMaximumUploadSize(
1277 $this_field_max_size
1278 ) . "\n";
1279 // do not generate here the MAX_FILE_SIZE, because we should
1280 // put only one in the form to accommodate the biggest field
1281 if ($this_field_max_size > $biggest_max_file_size) {
1282 $biggest_max_file_size = $this_field_max_size;
1284 return array($html_output, $biggest_max_file_size);
1288 * Get HTML for the Value column of other datatypes
1289 * (here, "column" is used in the sense of HTML column in HTML table)
1291 * @param array $column description of column in given table
1292 * @param string $default_char_editing default char editing mode which is stored
1293 * in the config.inc.php script
1294 * @param string $backup_field hidden input field
1295 * @param string $column_name_appendix the name attribute
1296 * @param string $onChangeClause onchange clause for fields
1297 * @param integer $tabindex tab index
1298 * @param string $special_chars special characters
1299 * @param integer $tabindex_for_value offset for the values tabindex
1300 * @param integer $idindex id index
1301 * @param string $text_dir text direction
1302 * @param string $special_chars_encoded replaced char if the string starts
1303 * with a \r\n pair (0x0d0a) add an extra \n
1304 * @param string $data data to edit
1305 * @param array $extracted_columnspec associative array containing type,
1306 * spec_in_brackets and possibly
1307 * enum_set_values (another array)
1308 * @param boolean $readOnly is column read only or not
1310 * @return string an html snippet
1312 function PMA_getValueColumnForOtherDatatypes($column, $default_char_editing,
1313 $backup_field,
1314 $column_name_appendix, $onChangeClause, $tabindex, $special_chars,
1315 $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded, $data,
1316 $extracted_columnspec, $readOnly
1318 // HTML5 data-* attribute data-type
1319 $data_type = $GLOBALS['PMA_Types']->getTypeClass($column['True_Type']);
1320 $fieldsize = PMA_getColumnSize($column, $extracted_columnspec);
1321 $html_output = $backup_field . "\n";
1322 if ($column['is_char']
1323 && ($GLOBALS['cfg']['CharEditing'] == 'textarea'
1324 || mb_strpos($data, "\n") !== false)
1326 $html_output .= "\n";
1327 $GLOBALS['cfg']['CharEditing'] = $default_char_editing;
1328 $html_output .= PMA_getTextarea(
1329 $column, $backup_field, $column_name_appendix, $onChangeClause,
1330 $tabindex, $tabindex_for_value, $idindex, $text_dir,
1331 $special_chars_encoded, $data_type, $readOnly
1333 } else {
1334 $html_output .= PMA_getHTMLinput(
1335 $column, $column_name_appendix, $special_chars, $fieldsize,
1336 $onChangeClause, $tabindex, $tabindex_for_value, $idindex,
1337 $data_type, $readOnly
1340 $virtual = array(
1341 'VIRTUAL', 'PERSISTENT', 'VIRTUAL GENERATED', 'STORED GENERATED'
1343 if (in_array($column['Extra'], $virtual)) {
1344 $html_output .= '<input type="hidden" name="virtual'
1345 . $column_name_appendix . '" value="1" />';
1347 if ($column['Extra'] == 'auto_increment') {
1348 $html_output .= '<input type="hidden" name="auto_increment'
1349 . $column_name_appendix . '" value="1" />';
1351 if (substr($column['pma_type'], 0, 9) == 'timestamp') {
1352 $html_output .= '<input type="hidden" name="fields_type'
1353 . $column_name_appendix . '" value="timestamp" />';
1355 if (substr($column['pma_type'], 0, 8) == 'datetime') {
1356 $html_output .= '<input type="hidden" name="fields_type'
1357 . $column_name_appendix . '" value="datetime" />';
1359 if ($column['True_Type'] == 'bit') {
1360 $html_output .= '<input type="hidden" name="fields_type'
1361 . $column_name_appendix . '" value="bit" />';
1363 if ($column['pma_type'] == 'date'
1364 || $column['pma_type'] == 'datetime'
1365 || substr($column['pma_type'], 0, 9) == 'timestamp'
1367 // the _3 suffix points to the date field
1368 // the _2 suffix points to the corresponding NULL checkbox
1369 // in dateFormat, 'yy' means the year with 4 digits
1372 return $html_output;
1376 * Get the field size
1378 * @param array $column description of column in given table
1379 * @param array $extracted_columnspec associative array containing type,
1380 * spec_in_brackets and possibly enum_set_values
1381 * (another array)
1383 * @return integer field size
1385 function PMA_getColumnSize($column, $extracted_columnspec)
1387 if ($column['is_char']) {
1388 $fieldsize = $extracted_columnspec['spec_in_brackets'];
1389 if ($fieldsize > $GLOBALS['cfg']['MaxSizeForInputField']) {
1391 * This case happens for CHAR or VARCHAR columns which have
1392 * a size larger than the maximum size for input field.
1394 $GLOBALS['cfg']['CharEditing'] = 'textarea';
1396 } else {
1398 * This case happens for example for INT or DATE columns;
1399 * in these situations, the value returned in $column['len']
1400 * seems appropriate.
1402 $fieldsize = $column['len'];
1404 return min(
1405 max($fieldsize, $GLOBALS['cfg']['MinSizeForInputField']),
1406 $GLOBALS['cfg']['MaxSizeForInputField']
1411 * Get HTML for gis data types
1413 * @return string an html snippet
1415 function PMA_getHTMLforGisDataTypes()
1417 $edit_str = PMA\libraries\Util::getIcon('b_edit.png', __('Edit/Insert'));
1418 return '<span class="open_gis_editor">'
1419 . PMA\libraries\Util::linkOrButton(
1420 '#', $edit_str, array(), false, false, '_blank'
1422 . '</span>';
1426 * get html for continue insertion form
1428 * @param string $table name of the table
1429 * @param string $db name of the database
1430 * @param array $where_clause_array array of where clauses
1431 * @param string $err_url error url
1433 * @return string an html snippet
1435 function PMA_getContinueInsertionForm($table, $db, $where_clause_array, $err_url)
1437 $html_output = '<form id="continueForm" method="post"'
1438 . ' action="tbl_replace.php" name="continueForm">'
1439 . URL::getHiddenInputs($db, $table)
1440 . '<input type="hidden" name="goto"'
1441 . ' value="' . htmlspecialchars($GLOBALS['goto']) . '" />'
1442 . '<input type="hidden" name="err_url"'
1443 . ' value="' . htmlspecialchars($err_url) . '" />'
1444 . '<input type="hidden" name="sql_query"'
1445 . ' value="' . htmlspecialchars($_REQUEST['sql_query']) . '" />';
1447 if (isset($_REQUEST['where_clause'])) {
1448 foreach ($where_clause_array as $key_id => $where_clause) {
1450 $html_output .= '<input type="hidden"'
1451 . ' name="where_clause[' . $key_id . ']"'
1452 . ' value="' . htmlspecialchars(trim($where_clause)) . '" />' . "\n";
1455 $tmp = '<select name="insert_rows" id="insert_rows">' . "\n";
1456 $option_values = array(1, 2, 5, 10, 15, 20, 30, 40);
1458 foreach ($option_values as $value) {
1459 $tmp .= '<option value="' . $value . '"';
1460 if ($value == $GLOBALS['cfg']['InsertRows']) {
1461 $tmp .= ' selected="selected"';
1463 $tmp .= '>' . $value . '</option>' . "\n";
1466 $tmp .= '</select>' . "\n";
1467 $html_output .= "\n" . sprintf(__('Continue insertion with %s rows'), $tmp);
1468 unset($tmp);
1469 $html_output .= '</form>' . "\n";
1470 return $html_output;
1474 * Get action panel
1476 * @param array $where_clause where clause
1477 * @param string $after_insert insert mode, e.g. new_insert, same_insert
1478 * @param integer $tabindex tab index
1479 * @param integer $tabindex_for_value offset for the values tabindex
1480 * @param boolean $found_unique_key boolean variable for unique key
1482 * @return string an html snippet
1484 function PMA_getActionsPanel($where_clause, $after_insert, $tabindex,
1485 $tabindex_for_value, $found_unique_key
1487 $html_output = '<fieldset id="actions_panel">'
1488 . '<table cellpadding="5" cellspacing="0">'
1489 . '<tr>'
1490 . '<td class="nowrap vmiddle">'
1491 . PMA_getSubmitTypeDropDown($where_clause, $tabindex, $tabindex_for_value)
1492 . "\n";
1494 $html_output .= '</td>'
1495 . '<td class="vmiddle">'
1496 . '&nbsp;&nbsp;&nbsp;<strong>'
1497 . __('and then') . '</strong>&nbsp;&nbsp;&nbsp;'
1498 . '</td>'
1499 . '<td class="nowrap vmiddle">'
1500 . PMA_getAfterInsertDropDown(
1501 $where_clause, $after_insert, $found_unique_key
1503 . '</td>'
1504 . '</tr>';
1505 $html_output .='<tr>'
1506 . PMA_getSubmitAndResetButtonForActionsPanel($tabindex, $tabindex_for_value)
1507 . '</tr>'
1508 . '</table>'
1509 . '</fieldset>';
1510 return $html_output;
1514 * Get a HTML drop down for submit types
1516 * @param array $where_clause where clause
1517 * @param integer $tabindex tab index
1518 * @param integer $tabindex_for_value offset for the values tabindex
1520 * @return string an html snippet
1522 function PMA_getSubmitTypeDropDown($where_clause, $tabindex, $tabindex_for_value)
1524 $html_output = '<select name="submit_type" class="control_at_footer" tabindex="'
1525 . ($tabindex + $tabindex_for_value + 1) . '">';
1526 if (isset($where_clause)) {
1527 $html_output .= '<option value="save">' . __('Save') . '</option>';
1529 $html_output .= '<option value="insert">'
1530 . __('Insert as new row')
1531 . '</option>'
1532 . '<option value="insertignore">'
1533 . __('Insert as new row and ignore errors')
1534 . '</option>'
1535 . '<option value="showinsert">'
1536 . __('Show insert query')
1537 . '</option>'
1538 . '</select>';
1539 return $html_output;
1543 * Get HTML drop down for after insert
1545 * @param array $where_clause where clause
1546 * @param string $after_insert insert mode, e.g. new_insert, same_insert
1547 * @param boolean $found_unique_key boolean variable for unique key
1549 * @return string an html snippet
1551 function PMA_getAfterInsertDropDown($where_clause, $after_insert, $found_unique_key)
1553 $html_output = '<select name="after_insert" class="control_at_footer">'
1554 . '<option value="back" '
1555 . ($after_insert == 'back' ? 'selected="selected"' : '') . '>'
1556 . __('Go back to previous page') . '</option>'
1557 . '<option value="new_insert" '
1558 . ($after_insert == 'new_insert' ? 'selected="selected"' : '') . '>'
1559 . __('Insert another new row') . '</option>';
1561 if (isset($where_clause)) {
1562 $html_output .= '<option value="same_insert" '
1563 . ($after_insert == 'same_insert' ? 'selected="selected"' : '') . '>'
1564 . __('Go back to this page') . '</option>';
1566 // If we have just numeric primary key, we can also edit next
1567 // in 2.8.2, we were looking for `field_name` = numeric_value
1568 //if (preg_match('@^[\s]*`[^`]*` = [0-9]+@', $where_clause)) {
1569 // in 2.9.0, we are looking for `table_name`.`field_name` = numeric_value
1570 $is_numeric = false;
1571 if (! is_array($where_clause)) {
1572 $where_clause = array($where_clause);
1574 for ($i = 0, $nb = count($where_clause); $i < $nb; $i++) {
1575 // preg_match() returns 1 if there is a match
1576 $is_numeric = (preg_match(
1577 '@^[\s]*`[^`]*`[\.]`[^`]*` = [0-9]+@',
1578 $where_clause[$i]
1579 ) == 1);
1580 if ($is_numeric === true) {
1581 break;
1584 if ($found_unique_key && $is_numeric) {
1585 $html_output .= '<option value="edit_next" '
1586 . ($after_insert == 'edit_next' ? 'selected="selected"' : '') . '>'
1587 . __('Edit next row') . '</option>';
1591 $html_output .= '</select>';
1592 return $html_output;
1597 * get Submit button and Reset button for action panel
1599 * @param integer $tabindex tab index
1600 * @param integer $tabindex_for_value offset for the values tabindex
1602 * @return string an html snippet
1604 function PMA_getSubmitAndResetButtonForActionsPanel($tabindex, $tabindex_for_value)
1606 return '<td>'
1607 . PMA\libraries\Util::showHint(
1609 'Use TAB key to move from value to value,'
1610 . ' or CTRL+arrows to move anywhere.'
1613 . '</td>'
1614 . '<td colspan="3" class="right vmiddle">'
1615 . '<input type="submit" class="control_at_footer" value="' . __('Go') . '"'
1616 . ' tabindex="' . ($tabindex + $tabindex_for_value + 6) . '" id="buttonYes" />'
1617 . '<input type="button" class="preview_sql" value="' . __('Preview SQL') . '"'
1618 . ' tabindex="' . ($tabindex + $tabindex_for_value + 7) . '" />'
1619 . '<input type="reset" class="control_at_footer" value="' . __('Reset') . '"'
1620 . ' tabindex="' . ($tabindex + $tabindex_for_value + 8) . '" />'
1621 . '</td>';
1625 * Get table head and table foot for insert row table
1627 * @param array $url_params url parameters
1629 * @return string an html snippet
1631 function PMA_getHeadAndFootOfInsertRowTable($url_params)
1633 $html_output = '<table class="insertRowTable topmargin">'
1634 . '<thead>'
1635 . '<tr>'
1636 . '<th>' . __('Column') . '</th>';
1638 if ($GLOBALS['cfg']['ShowFieldTypesInDataEditView']) {
1639 $html_output .= PMA_showTypeOrFunction('type', $url_params, true);
1641 if ($GLOBALS['cfg']['ShowFunctionFields']) {
1642 $html_output .= PMA_showTypeOrFunction('function', $url_params, true);
1645 $html_output .= '<th>' . __('Null') . '</th>'
1646 . '<th>' . __('Value') . '</th>'
1647 . '</tr>'
1648 . '</thead>'
1649 . ' <tfoot>'
1650 . '<tr>'
1651 . '<th colspan="5" class="tblFooters right">'
1652 . '<input type="submit" value="' . __('Go') . '" />'
1653 . '</th>'
1654 . '</tr>'
1655 . '</tfoot>';
1656 return $html_output;
1660 * Prepares the field value and retrieve special chars, backup field and data array
1662 * @param array $current_row a row of the table
1663 * @param array $column description of column in given table
1664 * @param array $extracted_columnspec associative array containing type,
1665 * spec_in_brackets and possibly
1666 * enum_set_values (another array)
1667 * @param boolean $real_null_value whether column value null or not null
1668 * @param array $gis_data_types list of GIS data types
1669 * @param string $column_name_appendix string to append to column name in input
1670 * @param bool $as_is use the data as is, used in repopulating
1672 * @return array $real_null_value, $data, $special_chars, $backup_field,
1673 * $special_chars_encoded
1675 function PMA_getSpecialCharsAndBackupFieldForExistingRow(
1676 $current_row, $column, $extracted_columnspec,
1677 $real_null_value, $gis_data_types, $column_name_appendix, $as_is
1679 $special_chars_encoded = '';
1680 $data = null;
1681 // (we are editing)
1682 if (!isset($current_row[$column['Field']])) {
1683 $real_null_value = true;
1684 $current_row[$column['Field']] = '';
1685 $special_chars = '';
1686 $data = $current_row[$column['Field']];
1687 } elseif ($column['True_Type'] == 'bit') {
1688 $special_chars = $as_is
1689 ? $current_row[$column['Field']]
1690 : PMA\libraries\Util::printableBitValue(
1691 $current_row[$column['Field']],
1692 $extracted_columnspec['spec_in_brackets']
1694 } elseif ((substr($column['True_Type'], 0, 9) == 'timestamp'
1695 || $column['True_Type'] == 'datetime'
1696 || $column['True_Type'] == 'time')
1697 && (mb_strpos($current_row[$column['Field']], ".") !== false)
1699 $current_row[$column['Field']] = $as_is
1700 ? $current_row[$column['Field']]
1701 : PMA\libraries\Util::addMicroseconds(
1702 $current_row[$column['Field']]
1704 $special_chars = htmlspecialchars($current_row[$column['Field']]);
1705 } elseif (in_array($column['True_Type'], $gis_data_types)) {
1706 // Convert gis data to Well Know Text format
1707 $current_row[$column['Field']] = $as_is
1708 ? $current_row[$column['Field']]
1709 : PMA\libraries\Util::asWKT(
1710 $current_row[$column['Field']], true
1712 $special_chars = htmlspecialchars($current_row[$column['Field']]);
1713 } else {
1714 // special binary "characters"
1715 if ($column['is_binary']
1716 || ($column['is_blob'] && $GLOBALS['cfg']['ProtectBinary'] !== 'all')
1718 $current_row[$column['Field']] = $as_is
1719 ? $current_row[$column['Field']]
1720 : bin2hex(
1721 $current_row[$column['Field']]
1723 } // end if
1724 $special_chars = htmlspecialchars($current_row[$column['Field']]);
1726 //We need to duplicate the first \n or otherwise we will lose
1727 //the first newline entered in a VARCHAR or TEXT column
1728 $special_chars_encoded
1729 = PMA\libraries\Util::duplicateFirstNewline($special_chars);
1731 $data = $current_row[$column['Field']];
1732 } // end if... else...
1734 //when copying row, it is useful to empty auto-increment column
1735 // to prevent duplicate key error
1736 if (isset($_REQUEST['default_action'])
1737 && $_REQUEST['default_action'] === 'insert'
1739 if ($column['Key'] === 'PRI'
1740 && mb_strpos($column['Extra'], 'auto_increment') !== false
1742 $data = $special_chars_encoded = $special_chars = null;
1745 // If a timestamp field value is not included in an update
1746 // statement MySQL auto-update it to the current timestamp;
1747 // however, things have changed since MySQL 4.1, so
1748 // it's better to set a fields_prev in this situation
1749 $backup_field = '<input type="hidden" name="fields_prev'
1750 . $column_name_appendix . '" value="'
1751 . htmlspecialchars($current_row[$column['Field']]) . '" />';
1753 return array(
1754 $real_null_value,
1755 $special_chars_encoded,
1756 $special_chars,
1757 $data,
1758 $backup_field
1763 * display default values
1765 * @param array $column description of column in given table
1766 * @param boolean $real_null_value whether column value null or not null
1768 * @return array $real_null_value, $data, $special_chars,
1769 * $backup_field, $special_chars_encoded
1771 function PMA_getSpecialCharsAndBackupFieldForInsertingMode(
1772 $column, $real_null_value
1774 if (! isset($column['Default'])) {
1775 $column['Default'] = '';
1776 $real_null_value = true;
1777 $data = '';
1778 } else {
1779 $data = $column['Default'];
1782 $trueType = $column['True_Type'];
1784 if ($trueType == 'bit') {
1785 $special_chars = PMA\libraries\Util::convertBitDefaultValue(
1786 $column['Default']
1788 } elseif (substr($trueType, 0, 9) == 'timestamp'
1789 || $trueType == 'datetime'
1790 || $trueType == 'time'
1792 $special_chars = PMA\libraries\Util::addMicroseconds($column['Default']);
1793 } elseif ($trueType == 'binary' || $trueType == 'varbinary') {
1794 $special_chars = bin2hex($column['Default']);
1795 } else {
1796 $special_chars = htmlspecialchars($column['Default']);
1798 $backup_field = '';
1799 $special_chars_encoded = PMA\libraries\Util::duplicateFirstNewline(
1800 $special_chars
1802 return array(
1803 $real_null_value, $data, $special_chars,
1804 $backup_field, $special_chars_encoded
1809 * Prepares the update/insert of a row
1811 * @return array $loop_array, $using_key, $is_insert, $is_insertignore
1813 function PMA_getParamsForUpdateOrInsert()
1815 if (isset($_REQUEST['where_clause'])) {
1816 // we were editing something => use the WHERE clause
1817 $loop_array = is_array($_REQUEST['where_clause'])
1818 ? $_REQUEST['where_clause']
1819 : array($_REQUEST['where_clause']);
1820 $using_key = true;
1821 $is_insert = isset($_REQUEST['submit_type'])
1822 && ($_REQUEST['submit_type'] == 'insert'
1823 || $_REQUEST['submit_type'] == 'showinsert'
1824 || $_REQUEST['submit_type'] == 'insertignore');
1825 } else {
1826 // new row => use indexes
1827 $loop_array = array();
1828 if (! empty($_REQUEST['fields'])) {
1829 foreach ($_REQUEST['fields']['multi_edit'] as $key => $dummy) {
1830 $loop_array[] = $key;
1833 $using_key = false;
1834 $is_insert = true;
1836 $is_insertignore = isset($_REQUEST['submit_type'])
1837 && $_REQUEST['submit_type'] == 'insertignore';
1838 return array($loop_array, $using_key, $is_insert, $is_insertignore);
1842 * Check wether insert row mode and if so include tbl_changen script and set
1843 * global variables.
1845 * @return void
1847 function PMA_isInsertRow()
1849 if (isset($_REQUEST['insert_rows'])
1850 && is_numeric($_REQUEST['insert_rows'])
1851 && $_REQUEST['insert_rows'] != $GLOBALS['cfg']['InsertRows']
1853 $GLOBALS['cfg']['InsertRows'] = $_REQUEST['insert_rows'];
1854 $response = Response::getInstance();
1855 $header = $response->getHeader();
1856 $scripts = $header->getScripts();
1857 $scripts->addFile('tbl_change.js');
1858 if (!defined('TESTSUITE')) {
1859 include 'tbl_change.php';
1860 exit;
1866 * set $_SESSION for edit_next
1868 * @param string $one_where_clause one where clause from where clauses array
1870 * @return void
1872 function PMA_setSessionForEditNext($one_where_clause)
1874 $local_query = 'SELECT * FROM ' . PMA\libraries\Util::backquote($GLOBALS['db'])
1875 . '.' . PMA\libraries\Util::backquote($GLOBALS['table']) . ' WHERE '
1876 . str_replace('` =', '` >', $one_where_clause) . ' LIMIT 1;';
1878 $res = $GLOBALS['dbi']->query($local_query);
1879 $row = $GLOBALS['dbi']->fetchRow($res);
1880 $meta = $GLOBALS['dbi']->getFieldsMeta($res);
1881 // must find a unique condition based on unique key,
1882 // not a combination of all fields
1883 list($unique_condition, $clause_is_unique)
1884 = PMA\libraries\Util::getUniqueCondition(
1885 $res, // handle
1886 count($meta), // fields_cnt
1887 $meta, // fields_meta
1888 $row, // row
1889 true, // force_unique
1890 false, // restrict_to_table
1891 null // analyzed_sql_results
1893 if (! empty($unique_condition)) {
1894 $_SESSION['edit_next'] = $unique_condition;
1896 unset($unique_condition, $clause_is_unique);
1900 * set $goto_include variable for different cases and retrieve like,
1901 * if $GLOBALS['goto'] empty, if $goto_include previously not defined
1902 * and new_insert, same_insert, edit_next
1904 * @param string $goto_include store some script for include, otherwise it is
1905 * boolean false
1907 * @return string $goto_include
1909 function PMA_getGotoInclude($goto_include)
1911 $valid_options = array('new_insert', 'same_insert', 'edit_next');
1912 if (isset($_REQUEST['after_insert'])
1913 && in_array($_REQUEST['after_insert'], $valid_options)
1915 $goto_include = 'tbl_change.php';
1916 } elseif (! empty($GLOBALS['goto'])) {
1917 if (! preg_match('@^[a-z_]+\.php$@', $GLOBALS['goto'])) {
1918 // this should NOT happen
1919 //$GLOBALS['goto'] = false;
1920 $goto_include = false;
1921 } else {
1922 $goto_include = $GLOBALS['goto'];
1924 if ($GLOBALS['goto'] == 'db_sql.php' && strlen($GLOBALS['table']) > 0) {
1925 $GLOBALS['table'] = '';
1928 if (! $goto_include) {
1929 if (strlen($GLOBALS['table']) === 0) {
1930 $goto_include = 'db_sql.php';
1931 } else {
1932 $goto_include = 'tbl_sql.php';
1935 return $goto_include;
1939 * Defines the url to return in case of failure of the query
1941 * @param array $url_params url parameters
1943 * @return string error url for query failure
1945 function PMA_getErrorUrl($url_params)
1947 if (isset($_REQUEST['err_url'])) {
1948 return $_REQUEST['err_url'];
1949 } else {
1950 return 'tbl_change.php' . URL::getCommon($url_params);
1955 * Builds the sql query
1957 * @param boolean $is_insertignore $_REQUEST['submit_type'] == 'insertignore'
1958 * @param array $query_fields column names array
1959 * @param array $value_sets array of query values
1961 * @return array of query
1963 function PMA_buildSqlQuery($is_insertignore, $query_fields, $value_sets)
1965 if ($is_insertignore) {
1966 $insert_command = 'INSERT IGNORE ';
1967 } else {
1968 $insert_command = 'INSERT ';
1970 $query = array(
1971 $insert_command . 'INTO '
1972 . PMA\libraries\Util::backquote($GLOBALS['table'])
1973 . ' (' . implode(', ', $query_fields) . ') VALUES ('
1974 . implode('), (', $value_sets) . ')'
1976 unset($insert_command, $query_fields);
1977 return $query;
1981 * Executes the sql query and get the result, then move back to the calling page
1983 * @param array $url_params url parameters array
1984 * @param array $query built query from PMA_buildSqlQuery()
1986 * @return array $url_params, $total_affected_rows, $last_messages
1987 * $warning_messages, $error_messages, $return_to_sql_query
1989 function PMA_executeSqlQuery($url_params, $query)
1991 $return_to_sql_query = '';
1992 if (! empty($GLOBALS['sql_query'])) {
1993 $url_params['sql_query'] = $GLOBALS['sql_query'];
1994 $return_to_sql_query = $GLOBALS['sql_query'];
1996 $GLOBALS['sql_query'] = implode('; ', $query) . ';';
1997 // to ensure that the query is displayed in case of
1998 // "insert as new row" and then "insert another new row"
1999 $GLOBALS['display_query'] = $GLOBALS['sql_query'];
2001 $total_affected_rows = 0;
2002 $last_messages = array();
2003 $warning_messages = array();
2004 $error_messages = array();
2006 foreach ($query as $single_query) {
2007 if ($_REQUEST['submit_type'] == 'showinsert') {
2008 $last_messages[] = Message::notice(__('Showing SQL query'));
2009 continue;
2011 if ($GLOBALS['cfg']['IgnoreMultiSubmitErrors']) {
2012 $result = $GLOBALS['dbi']->tryQuery($single_query);
2013 } else {
2014 $result = $GLOBALS['dbi']->query($single_query);
2016 if (! $result) {
2017 $error_messages[] = $GLOBALS['dbi']->getError();
2018 } else {
2019 // The next line contains a real assignment, it's not a typo
2020 if ($tmp = @$GLOBALS['dbi']->affectedRows()) {
2021 $total_affected_rows += $tmp;
2023 unset($tmp);
2025 $insert_id = $GLOBALS['dbi']->insertId();
2026 if ($insert_id != 0) {
2027 // insert_id is id of FIRST record inserted in one insert, so if we
2028 // inserted multiple rows, we had to increment this
2030 if ($total_affected_rows > 0) {
2031 $insert_id = $insert_id + $total_affected_rows - 1;
2033 $last_message = Message::notice(__('Inserted row id: %1$d'));
2034 $last_message->addParam($insert_id);
2035 $last_messages[] = $last_message;
2037 $GLOBALS['dbi']->freeResult($result);
2039 $warning_messages = PMA_getWarningMessages();
2041 return array(
2042 $url_params,
2043 $total_affected_rows,
2044 $last_messages,
2045 $warning_messages,
2046 $error_messages,
2047 $return_to_sql_query
2052 * get the warning messages array
2054 * @return array $warning_essages
2056 function PMA_getWarningMessages()
2058 $warning_essages = array();
2059 foreach ($GLOBALS['dbi']->getWarnings() as $warning) {
2060 $warning_essages[] = Message::sanitize(
2061 $warning['Level'] . ': #' . $warning['Code'] . ' ' . $warning['Message']
2064 return $warning_essages;
2068 * Column to display from the foreign table?
2070 * @param string $where_comparison string that contain relation field value
2071 * @param array $map all Relations to foreign tables for a given
2072 * table or optionally a given column in a table
2073 * @param string $relation_field relation field
2075 * @return string $dispval display value from the foreign table
2077 function PMA_getDisplayValueForForeignTableColumn($where_comparison,
2078 $map, $relation_field
2080 $foreigner = PMA_searchColumnInForeigners($map, $relation_field);
2081 $display_field = PMA_getDisplayField(
2082 $foreigner['foreign_db'],
2083 $foreigner['foreign_table']
2085 // Field to display from the foreign table?
2086 if (isset($display_field) && strlen($display_field) > 0) {
2087 $dispsql = 'SELECT ' . PMA\libraries\Util::backquote($display_field)
2088 . ' FROM ' . PMA\libraries\Util::backquote($foreigner['foreign_db'])
2089 . '.' . PMA\libraries\Util::backquote($foreigner['foreign_table'])
2090 . ' WHERE ' . PMA\libraries\Util::backquote($foreigner['foreign_field'])
2091 . $where_comparison;
2092 $dispresult = $GLOBALS['dbi']->tryQuery(
2093 $dispsql, null, PMA\libraries\DatabaseInterface::QUERY_STORE
2095 if ($dispresult && $GLOBALS['dbi']->numRows($dispresult) > 0) {
2096 list($dispval) = $GLOBALS['dbi']->fetchRow($dispresult, 0);
2097 } else {
2098 $dispval = '';
2100 if ($dispresult) {
2101 $GLOBALS['dbi']->freeResult($dispresult);
2103 return $dispval;
2105 return '';
2109 * Display option in the cell according to user choices
2111 * @param array $map all Relations to foreign tables for a given
2112 * table or optionally a given column in a table
2113 * @param string $relation_field relation field
2114 * @param string $where_comparison string that contain relation field value
2115 * @param string $dispval display value from the foreign table
2116 * @param string $relation_field_value relation field value
2118 * @return string $output HTML <a> tag
2120 function PMA_getLinkForRelationalDisplayField($map, $relation_field,
2121 $where_comparison, $dispval, $relation_field_value
2123 $foreigner = PMA_searchColumnInForeigners($map, $relation_field);
2124 if ('K' == $_SESSION['tmpval']['relational_display']) {
2125 // user chose "relational key" in the display options, so
2126 // the title contains the display field
2127 $title = (! empty($dispval))
2128 ? ' title="' . htmlspecialchars($dispval) . '"'
2129 : '';
2130 } else {
2131 $title = ' title="' . htmlspecialchars($relation_field_value) . '"';
2133 $_url_params = array(
2134 'db' => $foreigner['foreign_db'],
2135 'table' => $foreigner['foreign_table'],
2136 'pos' => '0',
2137 'sql_query' => 'SELECT * FROM '
2138 . PMA\libraries\Util::backquote($foreigner['foreign_db'])
2139 . '.' . PMA\libraries\Util::backquote($foreigner['foreign_table'])
2140 . ' WHERE ' . PMA\libraries\Util::backquote($foreigner['foreign_field'])
2141 . $where_comparison
2143 $output = '<a href="sql.php'
2144 . URL::getCommon($_url_params) . '"' . $title . '>';
2146 if ('D' == $_SESSION['tmpval']['relational_display']) {
2147 // user chose "relational display field" in the
2148 // display options, so show display field in the cell
2149 $output .= (!empty($dispval)) ? htmlspecialchars($dispval) : '';
2150 } else {
2151 // otherwise display data in the cell
2152 $output .= htmlspecialchars($relation_field_value);
2154 $output .= '</a>';
2155 return $output;
2159 * Transform edited values
2161 * @param string $db db name
2162 * @param string $table table name
2163 * @param array $transformation mimetypes for all columns of a table
2164 * [field_name][field_key]
2165 * @param array &$edited_values transform columns list and new values
2166 * @param string $file file containing the transformation plugin
2167 * @param string $column_name column name
2168 * @param array $extra_data extra data array
2169 * @param string $type the type of transformation
2171 * @return array $extra_data
2173 function PMA_transformEditedValues($db, $table,
2174 $transformation, &$edited_values, $file, $column_name, $extra_data, $type
2176 $include_file = 'libraries/plugins/transformations/' . $file;
2177 if (is_file($include_file)) {
2178 include_once $include_file;
2179 $_url_params = array(
2180 'db' => $db,
2181 'table' => $table,
2182 'where_clause' => $_REQUEST['where_clause'],
2183 'transform_key' => $column_name
2185 $transform_options = PMA_Transformation_getOptions(
2186 isset($transformation[$type . '_options'])
2187 ? $transformation[$type . '_options']
2188 : ''
2190 $transform_options['wrapper_link']
2191 = URL::getCommon($_url_params);
2192 $class_name = PMA_getTransformationClassName($include_file);
2193 /** @var TransformationsPlugin $transformation_plugin */
2194 $transformation_plugin = new $class_name();
2196 foreach ($edited_values as $cell_index => $curr_cell_edited_values) {
2197 if (isset($curr_cell_edited_values[$column_name])) {
2198 $edited_values[$cell_index][$column_name]
2199 = $extra_data['transformations'][$cell_index]
2200 = $transformation_plugin->applyTransformation(
2201 $curr_cell_edited_values[$column_name],
2202 $transform_options,
2206 } // end of loop for each transformation cell
2208 return $extra_data;
2212 * Get current value in multi edit mode
2214 * @param array $multi_edit_funcs multiple edit functions array
2215 * @param array $multi_edit_salt multiple edit array with encryption salt
2216 * @param array $gis_from_text_functions array that contains gis from text functions
2217 * @param string $current_value current value in the column
2218 * @param array $gis_from_wkb_functions initially $val is $multi_edit_columns[$key]
2219 * @param array $func_optional_param array('RAND','UNIX_TIMESTAMP')
2220 * @param array $func_no_param array of set of string
2221 * @param string $key an md5 of the column name
2223 * @return array $cur_value
2225 function PMA_getCurrentValueAsAnArrayForMultipleEdit( $multi_edit_funcs,
2226 $multi_edit_salt,
2227 $gis_from_text_functions, $current_value, $gis_from_wkb_functions,
2228 $func_optional_param, $func_no_param, $key
2230 if (empty($multi_edit_funcs[$key])) {
2231 return $current_value;
2232 } elseif ('UUID' === $multi_edit_funcs[$key]) {
2233 /* This way user will know what UUID new row has */
2234 $uuid = $GLOBALS['dbi']->fetchValue('SELECT UUID()');
2235 return "'" . $uuid . "'";
2236 } elseif ((in_array($multi_edit_funcs[$key], $gis_from_text_functions)
2237 && substr($current_value, 0, 3) == "'''")
2238 || in_array($multi_edit_funcs[$key], $gis_from_wkb_functions)
2240 // Remove enclosing apostrophes
2241 $current_value = mb_substr($current_value, 1, -1);
2242 // Remove escaping apostrophes
2243 $current_value = str_replace("''", "'", $current_value);
2244 return $multi_edit_funcs[$key] . '(' . $current_value . ')';
2245 } elseif (! in_array($multi_edit_funcs[$key], $func_no_param)
2246 || ($current_value != "''"
2247 && in_array($multi_edit_funcs[$key], $func_optional_param))
2249 if ((isset($multi_edit_salt[$key])
2250 && ($multi_edit_funcs[$key] == "AES_ENCRYPT"
2251 || $multi_edit_funcs[$key] == "AES_DECRYPT"))
2252 || (! empty($multi_edit_salt[$key])
2253 && ($multi_edit_funcs[$key] == "DES_ENCRYPT"
2254 || $multi_edit_funcs[$key] == "DES_DECRYPT"
2255 || $multi_edit_funcs[$key] == "ENCRYPT"))
2257 return $multi_edit_funcs[$key] . '(' . $current_value . ",'"
2258 . $GLOBALS['dbi']->escapeString($multi_edit_salt[$key]) . "')";
2259 } else {
2260 return $multi_edit_funcs[$key] . '(' . $current_value . ')';
2262 } else {
2263 return $multi_edit_funcs[$key] . '()';
2268 * Get query values array and query fields array for insert and update in multi edit
2270 * @param array $multi_edit_columns_name multiple edit columns name array
2271 * @param array $multi_edit_columns_null multiple edit columns null array
2272 * @param string $current_value current value in the column in loop
2273 * @param array $multi_edit_columns_prev multiple edit previous columns array
2274 * @param array $multi_edit_funcs multiple edit functions array
2275 * @param boolean $is_insert boolean value whether insert or not
2276 * @param array $query_values SET part of the sql query
2277 * @param array $query_fields array of query fields
2278 * @param string $current_value_as_an_array current value in the column
2279 * as an array
2280 * @param array $value_sets array of valu sets
2281 * @param string $key an md5 of the column name
2282 * @param array $multi_edit_columns_null_prev array of multiple edit columns
2283 * null previous
2285 * @return array ($query_values, $query_fields)
2287 function PMA_getQueryValuesForInsertAndUpdateInMultipleEdit($multi_edit_columns_name,
2288 $multi_edit_columns_null, $current_value, $multi_edit_columns_prev,
2289 $multi_edit_funcs,$is_insert, $query_values, $query_fields,
2290 $current_value_as_an_array, $value_sets, $key, $multi_edit_columns_null_prev
2292 // i n s e r t
2293 if ($is_insert) {
2294 // no need to add column into the valuelist
2295 if (strlen($current_value_as_an_array) > 0) {
2296 $query_values[] = $current_value_as_an_array;
2297 // first inserted row so prepare the list of fields
2298 if (empty($value_sets)) {
2299 $query_fields[] = PMA\libraries\Util::backquote(
2300 $multi_edit_columns_name[$key]
2305 } elseif (! empty($multi_edit_columns_null_prev[$key])
2306 && ! isset($multi_edit_columns_null[$key])
2308 // u p d a t e
2310 // field had the null checkbox before the update
2311 // field no longer has the null checkbox
2312 $query_values[]
2313 = PMA\libraries\Util::backquote($multi_edit_columns_name[$key])
2314 . ' = ' . $current_value_as_an_array;
2315 } elseif (empty($multi_edit_funcs[$key])
2316 && isset($multi_edit_columns_prev[$key])
2317 && (("'" . $GLOBALS['dbi']->escapeString($multi_edit_columns_prev[$key]) . "'" === $current_value)
2318 || ('0x' . $multi_edit_columns_prev[$key] === $current_value))
2320 // No change for this column and no MySQL function is used -> next column
2321 } elseif (! empty($current_value)) {
2322 // avoid setting a field to NULL when it's already NULL
2323 // (field had the null checkbox before the update
2324 // field still has the null checkbox)
2325 if (empty($multi_edit_columns_null_prev[$key])
2326 || empty($multi_edit_columns_null[$key])
2328 $query_values[]
2329 = PMA\libraries\Util::backquote($multi_edit_columns_name[$key])
2330 . ' = ' . $current_value_as_an_array;
2333 return array($query_values, $query_fields);
2337 * Get the current column value in the form for different data types
2339 * @param string|false $possibly_uploaded_val uploaded file content
2340 * @param string $key an md5 of the column name
2341 * @param array $multi_edit_columns_type array of multi edit column types
2342 * @param string $current_value current column value in the form
2343 * @param array $multi_edit_auto_increment multi edit auto increment
2344 * @param integer $rownumber index of where clause array
2345 * @param array $multi_edit_columns_name multi edit column names array
2346 * @param array $multi_edit_columns_null multi edit columns null array
2347 * @param array $multi_edit_columns_null_prev multi edit columns previous null
2348 * @param boolean $is_insert whether insert or not
2349 * @param boolean $using_key whether editing or new row
2350 * @param string $where_clause where clause
2351 * @param string $table table name
2352 * @param array $multi_edit_funcs multiple edit functions array
2354 * @return string $current_value current column value in the form
2356 function PMA_getCurrentValueForDifferentTypes($possibly_uploaded_val, $key,
2357 $multi_edit_columns_type, $current_value, $multi_edit_auto_increment,
2358 $rownumber, $multi_edit_columns_name, $multi_edit_columns_null,
2359 $multi_edit_columns_null_prev, $is_insert, $using_key, $where_clause, $table,
2360 $multi_edit_funcs
2362 // Fetch the current values of a row to use in case we have a protected field
2363 if ($is_insert
2364 && $using_key && isset($multi_edit_columns_type)
2365 && is_array($multi_edit_columns_type) && !empty($where_clause)
2367 $protected_row = $GLOBALS['dbi']->fetchSingleRow(
2368 'SELECT * FROM ' . PMA\libraries\Util::backquote($table)
2369 . ' WHERE ' . $where_clause . ';'
2373 if (false !== $possibly_uploaded_val) {
2374 $current_value = $possibly_uploaded_val;
2375 } else if (! empty($multi_edit_funcs[$key])) {
2376 $current_value = "'" . $GLOBALS['dbi']->escapeString($current_value)
2377 . "'";
2378 } else {
2379 // c o l u m n v a l u e i n t h e f o r m
2380 if (isset($multi_edit_columns_type[$key])) {
2381 $type = $multi_edit_columns_type[$key];
2382 } else {
2383 $type = '';
2386 if ($type != 'protected' && $type != 'set' && strlen($current_value) === 0) {
2387 // best way to avoid problems in strict mode
2388 // (works also in non-strict mode)
2389 if (isset($multi_edit_auto_increment)
2390 && isset($multi_edit_auto_increment[$key])
2392 $current_value = 'NULL';
2393 } else {
2394 $current_value = "''";
2396 } elseif ($type == 'set') {
2397 if (! empty($_REQUEST['fields']['multi_edit'][$rownumber][$key])) {
2398 $current_value = implode(
2399 ',', $_REQUEST['fields']['multi_edit'][$rownumber][$key]
2401 $current_value = "'"
2402 . $GLOBALS['dbi']->escapeString($current_value) . "'";
2403 } else {
2404 $current_value = "''";
2406 } elseif ($type == 'protected') {
2407 // here we are in protected mode (asked in the config)
2408 // so tbl_change has put this special value in the
2409 // columns array, so we do not change the column value
2410 // but we can still handle column upload
2412 // when in UPDATE mode, do not alter field's contents. When in INSERT
2413 // mode, insert empty field because no values were submitted.
2414 // If protected blobs where set, insert original fields content.
2415 if (! empty($protected_row[$multi_edit_columns_name[$key]])) {
2416 $current_value = '0x'
2417 . bin2hex($protected_row[$multi_edit_columns_name[$key]]);
2418 } else {
2419 $current_value = '';
2421 } elseif ($type === 'hex') {
2422 $current_value = '0x' . $current_value;
2423 } elseif ($type == 'bit') {
2424 $current_value = preg_replace('/[^01]/', '0', $current_value);
2425 $current_value = "b'" . $GLOBALS['dbi']->escapeString($current_value)
2426 . "'";
2427 } elseif (! ($type == 'datetime' || $type == 'timestamp')
2428 || $current_value != 'CURRENT_TIMESTAMP'
2430 $current_value = "'" . $GLOBALS['dbi']->escapeString($current_value)
2431 . "'";
2434 // Was the Null checkbox checked for this field?
2435 // (if there is a value, we ignore the Null checkbox: this could
2436 // be possible if Javascript is disabled in the browser)
2437 if (! empty($multi_edit_columns_null[$key])
2438 && ($current_value == "''" || $current_value == '')
2440 $current_value = 'NULL';
2443 // The Null checkbox was unchecked for this field
2444 if (empty($current_value)
2445 && ! empty($multi_edit_columns_null_prev[$key])
2446 && ! isset($multi_edit_columns_null[$key])
2448 $current_value = "''";
2450 } // end else (column value in the form)
2451 return $current_value;
2456 * Check whether inline edited value can be truncated or not,
2457 * and add additional parameters for extra_data array if needed
2459 * @param string $db Database name
2460 * @param string $table Table name
2461 * @param string $column_name Column name
2462 * @param array &$extra_data Extra data for ajax response
2464 * @return void
2466 function PMA_verifyWhetherValueCanBeTruncatedAndAppendExtraData(
2467 $db, $table, $column_name, &$extra_data
2470 $extra_data['isNeedToRecheck'] = false;
2472 $sql_for_real_value = 'SELECT ' . PMA\libraries\Util::backquote($table) . '.'
2473 . PMA\libraries\Util::backquote($column_name)
2474 . ' FROM ' . PMA\libraries\Util::backquote($db) . '.'
2475 . PMA\libraries\Util::backquote($table)
2476 . ' WHERE ' . $_REQUEST['where_clause'][0];
2478 $result = $GLOBALS['dbi']->tryQuery($sql_for_real_value);
2479 $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
2480 $meta = $fields_meta[0];
2481 if ($row = $GLOBALS['dbi']->fetchRow($result)) {
2482 $new_value = $row[0];
2483 if ((substr($meta->type, 0, 9) == 'timestamp')
2484 || ($meta->type == 'datetime')
2485 || ($meta->type == 'time')
2487 $new_value = PMA\libraries\Util::addMicroseconds($new_value);
2489 $extra_data['isNeedToRecheck'] = true;
2490 $extra_data['truncatableFieldValue'] = $new_value;
2492 $GLOBALS['dbi']->freeResult($result);
2496 * Function to get the columns of a table
2498 * @param string $db current db
2499 * @param string $table current table
2501 * @return array
2503 function PMA_getTableColumns($db, $table)
2505 $GLOBALS['dbi']->selectDb($db);
2506 return array_values($GLOBALS['dbi']->getColumns($db, $table, null, true));
2511 * Function to determine Insert/Edit rows
2513 * @param string $where_clause where clause
2514 * @param string $db current database
2515 * @param string $table current table
2517 * @return mixed
2519 function PMA_determineInsertOrEdit($where_clause, $db, $table)
2521 if (isset($_REQUEST['where_clause'])) {
2522 $where_clause = $_REQUEST['where_clause'];
2524 if (isset($_SESSION['edit_next'])) {
2525 $where_clause = $_SESSION['edit_next'];
2526 unset($_SESSION['edit_next']);
2527 $after_insert = 'edit_next';
2529 if (isset($_REQUEST['ShowFunctionFields'])) {
2530 $GLOBALS['cfg']['ShowFunctionFields'] = $_REQUEST['ShowFunctionFields'];
2532 if (isset($_REQUEST['ShowFieldTypesInDataEditView'])) {
2533 $GLOBALS['cfg']['ShowFieldTypesInDataEditView']
2534 = $_REQUEST['ShowFieldTypesInDataEditView'];
2536 if (isset($_REQUEST['after_insert'])) {
2537 $after_insert = $_REQUEST['after_insert'];
2540 if (isset($where_clause)) {
2541 // we are editing
2542 $insert_mode = false;
2543 $where_clause_array = PMA_getWhereClauseArray($where_clause);
2544 list($where_clauses, $result, $rows, $found_unique_key)
2545 = PMA_analyzeWhereClauses(
2546 $where_clause_array, $table, $db
2548 } else {
2549 // we are inserting
2550 $insert_mode = true;
2551 $where_clause = null;
2552 list($result, $rows) = PMA_loadFirstRow($table, $db);
2553 $where_clauses = null;
2554 $where_clause_array = array();
2555 $found_unique_key = false;
2558 // Copying a row - fetched data will be inserted as a new row,
2559 // therefore the where clause is needless.
2560 if (isset($_REQUEST['default_action'])
2561 && $_REQUEST['default_action'] === 'insert'
2563 $where_clause = $where_clauses = null;
2566 return array(
2567 $insert_mode, $where_clause, $where_clause_array, $where_clauses,
2568 $result, $rows, $found_unique_key,
2569 isset($after_insert) ? $after_insert : null
2574 * Function to get comments for the table columns
2576 * @param string $db current database
2577 * @param string $table current table
2579 * @return array $comments_map comments for columns
2581 function PMA_getCommentsMap($db, $table)
2583 $comments_map = array();
2585 if ($GLOBALS['cfg']['ShowPropertyComments']) {
2586 $comments_map = PMA_getComments($db, $table);
2589 return $comments_map;
2593 * Function to get URL parameters
2595 * @param string $db current database
2596 * @param string $table current table
2598 * @return array $url_params url parameters
2600 function PMA_getUrlParameters($db, $table)
2603 * @todo check if we could replace by "db_|tbl_" - please clarify!?
2605 $url_params = array(
2606 'db' => $db,
2607 'sql_query' => $_REQUEST['sql_query']
2610 if (preg_match('@^tbl_@', $GLOBALS['goto'])) {
2611 $url_params['table'] = $table;
2614 return $url_params;
2618 * Function to get html for the gis editor div
2620 * @return string
2622 function PMA_getHtmlForGisEditor()
2624 return '<div id="gis_editor"></div>'
2625 . '<div id="popup_background"></div>'
2626 . '<br />';
2630 * Function to get html for the ignore option in insert mode
2632 * @param int $row_id row id
2633 * @param bool $checked ignore option is checked or not
2635 * @return string
2637 function PMA_getHtmlForIgnoreOption($row_id, $checked = true)
2639 return '<input type="checkbox"'
2640 . ($checked ? ' checked="checked"' : '')
2641 . ' name="insert_ignore_' . $row_id . '"'
2642 . ' id="insert_ignore_' . $row_id . '" />'
2643 . '<label for="insert_ignore_' . $row_id . '">'
2644 . __('Ignore')
2645 . '</label><br />' . "\n";
2649 * Function to get html for the function option
2651 * @param array $column column
2652 * @param string $column_name_appendix column name appendix
2654 * @return String
2656 function PMA_getHtmlForFunctionOption($column, $column_name_appendix)
2658 return '<tr class="noclick">'
2659 . '<td '
2660 . 'class="center">'
2661 . $column['Field_title']
2662 . '<input type="hidden" name="fields_name' . $column_name_appendix
2663 . '" value="' . $column['Field_html'] . '"/>'
2664 . '</td>';
2669 * Function to get html for the column type
2671 * @param array $column column
2673 * @return string
2675 function PMA_getHtmlForInsertEditColumnType($column)
2677 return '<td class="center' . $column['wrap'] . '">'
2678 . '<span class="column_type" dir="ltr">' . $column['pma_type'] . '</span>'
2679 . '</td>';
2684 * Function to get html for the insert edit form header
2686 * @param bool $has_blob_field whether has blob field
2687 * @param bool $is_upload whether is upload
2689 * @return string
2691 function PMA_getHtmlForInsertEditFormHeader($has_blob_field, $is_upload)
2693 $html_output ='<form id="insertForm" class="lock-page ';
2694 if ($has_blob_field && $is_upload) {
2695 $html_output .='disableAjax';
2697 $html_output .='" method="post" action="tbl_replace.php" name="insertForm" ';
2698 if ($is_upload) {
2699 $html_output .= ' enctype="multipart/form-data"';
2701 $html_output .= '>';
2703 return $html_output;
2707 * Function to get html for each insert/edit column
2709 * @param array $table_columns table columns
2710 * @param int $column_number column index in table_columns
2711 * @param array $comments_map comments map
2712 * @param bool $timestamp_seen whether timestamp seen
2713 * @param array $current_result current result
2714 * @param string $chg_evt_handler javascript change event handler
2715 * @param string $jsvkey javascript validation key
2716 * @param string $vkey validation key
2717 * @param bool $insert_mode whether insert mode
2718 * @param array $current_row current row
2719 * @param int &$o_rows row offset
2720 * @param int &$tabindex tab index
2721 * @param int $columns_cnt columns count
2722 * @param bool $is_upload whether upload
2723 * @param int $tabindex_for_function tab index offset for function
2724 * @param array $foreigners foreigners
2725 * @param int $tabindex_for_null tab index offset for null
2726 * @param int $tabindex_for_value tab index offset for value
2727 * @param string $table table
2728 * @param string $db database
2729 * @param int $row_id row id
2730 * @param array $titles titles
2731 * @param int $biggest_max_file_size biggest max file size
2732 * @param string $default_char_editing default char editing mode which is stored
2733 * in the config.inc.php script
2734 * @param string $text_dir text direction
2735 * @param array $repopulate the data to be repopulated
2736 * @param array $column_mime the mime information of column
2737 * @param string $where_clause the where clause
2739 * @return string
2741 function PMA_getHtmlForInsertEditFormColumn($table_columns, $column_number,
2742 $comments_map, $timestamp_seen, $current_result, $chg_evt_handler,
2743 $jsvkey, $vkey, $insert_mode, $current_row, &$o_rows,
2744 &$tabindex, $columns_cnt, $is_upload, $tabindex_for_function,
2745 $foreigners, $tabindex_for_null, $tabindex_for_value, $table, $db,
2746 $row_id, $titles, $biggest_max_file_size, $default_char_editing,
2747 $text_dir, $repopulate, $column_mime, $where_clause
2749 $column = $table_columns[$column_number];
2750 $readOnly = false;
2751 if (! PMA_userHasColumnPrivileges($column, $insert_mode)) {
2752 $readOnly = true;
2755 if (! isset($column['processed'])) {
2756 $column = PMA_analyzeTableColumnsArray(
2757 $column, $comments_map, $timestamp_seen
2760 $as_is = false;
2761 if (!empty($repopulate) && !empty($current_row)) {
2762 $current_row[$column['Field']] = $repopulate[$column['Field_md5']];
2763 $as_is = true;
2766 $extracted_columnspec
2767 = PMA\libraries\Util::extractColumnSpec($column['Type']);
2769 if (-1 === $column['len']) {
2770 $column['len'] = $GLOBALS['dbi']->fieldLen(
2771 $current_result, $column_number
2773 // length is unknown for geometry fields,
2774 // make enough space to edit very simple WKTs
2775 if (-1 === $column['len']) {
2776 $column['len'] = 30;
2779 //Call validation when the form submitted...
2780 $onChangeClause = $chg_evt_handler
2781 . "=\"return verificationsAfterFieldChange('"
2782 . Sanitize::escapeJsString($column['Field_md5']) . "', '"
2783 . Sanitize::escapeJsString($jsvkey) . "','" . $column['pma_type'] . "')\"";
2785 // Use an MD5 as an array index to avoid having special characters
2786 // in the name attribute (see bug #1746964 )
2787 $column_name_appendix = $vkey . '[' . $column['Field_md5'] . ']';
2789 if ($column['Type'] === 'datetime'
2790 && ! isset($column['Default'])
2791 && ! is_null($column['Default'])
2792 && $insert_mode
2794 $column['Default'] = date('Y-m-d H:i:s', time());
2797 $html_output = PMA_getHtmlForFunctionOption(
2798 $column, $column_name_appendix
2801 if ($GLOBALS['cfg']['ShowFieldTypesInDataEditView']) {
2802 $html_output .= PMA_getHtmlForInsertEditColumnType($column);
2803 } //End if
2805 // Get a list of GIS data types.
2806 $gis_data_types = PMA\libraries\Util::getGISDatatypes();
2808 // Prepares the field value
2809 $real_null_value = false;
2810 $special_chars_encoded = '';
2811 if (!empty($current_row)) {
2812 // (we are editing)
2813 list(
2814 $real_null_value, $special_chars_encoded, $special_chars,
2815 $data, $backup_field
2817 = PMA_getSpecialCharsAndBackupFieldForExistingRow(
2818 $current_row, $column, $extracted_columnspec,
2819 $real_null_value, $gis_data_types, $column_name_appendix, $as_is
2821 } else {
2822 // (we are inserting)
2823 // display default values
2824 $tmp = $column;
2825 if (isset($repopulate[$column['Field_md5']])) {
2826 $tmp['Default'] = $repopulate[$column['Field_md5']];
2828 list($real_null_value, $data, $special_chars, $backup_field,
2829 $special_chars_encoded
2831 = PMA_getSpecialCharsAndBackupFieldForInsertingMode(
2832 $tmp, $real_null_value
2834 unset($tmp);
2837 $idindex = ($o_rows * $columns_cnt) + $column_number + 1;
2838 $tabindex = $idindex;
2840 // Get a list of data types that are not yet supported.
2841 $no_support_types = PMA\libraries\Util::unsupportedDatatypes();
2843 // The function column
2844 // -------------------
2845 $foreignData = PMA_getForeignData(
2846 $foreigners, $column['Field'], false, '', ''
2848 if ($GLOBALS['cfg']['ShowFunctionFields']) {
2849 $html_output .= PMA_getFunctionColumn(
2850 $column, $is_upload, $column_name_appendix,
2851 $onChangeClause, $no_support_types, $tabindex_for_function,
2852 $tabindex, $idindex, $insert_mode, $readOnly, $foreignData
2856 // The null column
2857 // ---------------
2858 $html_output .= PMA_getNullColumn(
2859 $column, $column_name_appendix, $real_null_value,
2860 $tabindex, $tabindex_for_null, $idindex, $vkey, $foreigners,
2861 $foreignData, $readOnly
2864 // The value column (depends on type)
2865 // ----------------
2866 // See bug #1667887 for the reason why we don't use the maxlength
2867 // HTML attribute
2869 //add data attributes "no of decimals" and "data type"
2870 $no_decimals = 0;
2871 $type = current(explode("(", $column['pma_type']));
2872 if (preg_match('/\(([^()]+)\)/', $column['pma_type'], $match)) {
2873 $match[0] = trim($match[0], '()');
2874 $no_decimals = $match[0];
2876 $html_output .= '<td' . ' data-type="' . $type . '"' . ' data-decimals="'
2877 . $no_decimals . '">' . "\n";
2878 // Will be used by js/tbl_change.js to set the default value
2879 // for the "Continue insertion" feature
2880 $html_output .= '<span class="default_value hide">'
2881 . $special_chars . '</span>';
2883 // Check input transformation of column
2884 $transformed_html = '';
2885 if (!empty($column_mime['input_transformation'])) {
2886 $file = $column_mime['input_transformation'];
2887 $include_file = 'libraries/plugins/transformations/' . $file;
2888 if (is_file($include_file)) {
2889 include_once $include_file;
2890 $class_name = PMA_getTransformationClassName($include_file);
2891 $transformation_plugin = new $class_name();
2892 $transformation_options = PMA_Transformation_getOptions(
2893 $column_mime['input_transformation_options']
2895 $_url_params = array(
2896 'db' => $db,
2897 'table' => $table,
2898 'transform_key' => $column['Field'],
2899 'where_clause' => $where_clause
2901 $transformation_options['wrapper_link']
2902 = URL::getCommon($_url_params);
2903 $current_value = '';
2904 if (isset($current_row[$column['Field']])) {
2905 $current_value = $current_row[$column['Field']];
2907 if (method_exists($transformation_plugin, 'getInputHtml')) {
2908 $transformed_html = $transformation_plugin->getInputHtml(
2909 $column, $row_id, $column_name_appendix,
2910 $transformation_options, $current_value, $text_dir,
2911 $tabindex, $tabindex_for_value, $idindex
2914 if (method_exists($transformation_plugin, 'getScripts')) {
2915 $GLOBALS['plugin_scripts'] = array_merge(
2916 $GLOBALS['plugin_scripts'], $transformation_plugin->getScripts()
2921 if (!empty($transformed_html)) {
2922 $html_output .= $transformed_html;
2923 } else {
2924 $html_output .= PMA_getValueColumn(
2925 $column, $backup_field, $column_name_appendix, $onChangeClause,
2926 $tabindex, $tabindex_for_value, $idindex, $data, $special_chars,
2927 $foreignData, array($table, $db), $row_id, $titles,
2928 $text_dir, $special_chars_encoded, $vkey, $is_upload,
2929 $biggest_max_file_size, $default_char_editing,
2930 $no_support_types, $gis_data_types, $extracted_columnspec, $readOnly
2933 return $html_output;
2937 * Function to get html for each insert/edit row
2939 * @param array $url_params url parameters
2940 * @param array $table_columns table columns
2941 * @param array $comments_map comments map
2942 * @param bool $timestamp_seen whether timestamp seen
2943 * @param array $current_result current result
2944 * @param string $chg_evt_handler javascript change event handler
2945 * @param string $jsvkey javascript validation key
2946 * @param string $vkey validation key
2947 * @param bool $insert_mode whether insert mode
2948 * @param array $current_row current row
2949 * @param int &$o_rows row offset
2950 * @param int &$tabindex tab index
2951 * @param int $columns_cnt columns count
2952 * @param bool $is_upload whether upload
2953 * @param int $tabindex_for_function tab index offset for function
2954 * @param array $foreigners foreigners
2955 * @param int $tabindex_for_null tab index offset for null
2956 * @param int $tabindex_for_value tab index offset for value
2957 * @param string $table table
2958 * @param string $db database
2959 * @param int $row_id row id
2960 * @param array $titles titles
2961 * @param int $biggest_max_file_size biggest max file size
2962 * @param string $text_dir text direction
2963 * @param array $repopulate the data to be repopulated
2964 * @param array $where_clause_array the array of where clauses
2966 * @return string
2968 function PMA_getHtmlForInsertEditRow($url_params, $table_columns,
2969 $comments_map, $timestamp_seen, $current_result, $chg_evt_handler,
2970 $jsvkey, $vkey, $insert_mode, $current_row, &$o_rows, &$tabindex, $columns_cnt,
2971 $is_upload, $tabindex_for_function, $foreigners, $tabindex_for_null,
2972 $tabindex_for_value, $table, $db, $row_id, $titles,
2973 $biggest_max_file_size, $text_dir, $repopulate, $where_clause_array
2975 $html_output = PMA_getHeadAndFootOfInsertRowTable($url_params)
2976 . '<tbody>';
2978 //store the default value for CharEditing
2979 $default_char_editing = $GLOBALS['cfg']['CharEditing'];
2980 $mime_map = PMA_getMIME($db, $table);
2981 $where_clause = '';
2982 if (isset($where_clause_array[$row_id])) {
2983 $where_clause = $where_clause_array[$row_id];
2985 for ($column_number = 0; $column_number < $columns_cnt; $column_number++) {
2986 $table_column = $table_columns[$column_number];
2987 $column_mime = array();
2988 if (isset($mime_map[$table_column['Field']])) {
2989 $column_mime = $mime_map[$table_column['Field']];
2991 $html_output .= PMA_getHtmlForInsertEditFormColumn(
2992 $table_columns, $column_number, $comments_map, $timestamp_seen,
2993 $current_result, $chg_evt_handler, $jsvkey, $vkey, $insert_mode,
2994 $current_row, $o_rows, $tabindex, $columns_cnt, $is_upload,
2995 $tabindex_for_function, $foreigners, $tabindex_for_null,
2996 $tabindex_for_value, $table, $db, $row_id, $titles,
2997 $biggest_max_file_size, $default_char_editing, $text_dir, $repopulate,
2998 $column_mime, $where_clause
3000 } // end for
3001 $o_rows++;
3002 $html_output .= ' </tbody>'
3003 . '</table><br />'
3004 . '<div class="clearfloat"></div>';
3006 return $html_output;
3010 * Returns whether the user has necessary insert/update privileges for the column
3012 * @param array $table_column array of column details
3013 * @param bool $insert_mode whether on insert mode
3015 * @return boolean whether user has necessary privileges
3017 function PMA_userHasColumnPrivileges($table_column, $insert_mode)
3019 $privileges = $table_column['Privileges'];
3020 return ($insert_mode && strstr($privileges, 'insert') !== false)
3021 || (! $insert_mode && strstr($privileges, 'update') !== false);