Translated using Weblate (Slovenian)
[phpmyadmin.git] / libraries / insert_edit.lib.php
blob2eb7d3183070156b7c01750d0c19d307f95f0ef2
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 = '&nbsp;</td>';
589 $html_output .= '</tr>';
590 $html_output .= '<tr>' . '<td colspan="5" class="right">';
591 $html_output .= PMA_getTextarea(
592 $column, $backup_field, $column_name_appendix, $onChangeClause,
593 $tabindex, $tabindex_for_value, $idindex, $text_dir,
594 $special_chars_encoded, $data_type, $readOnly
597 } elseif (mb_strstr($column['pma_type'], 'text')) {
599 $html_output .= PMA_getTextarea(
600 $column, $backup_field, $column_name_appendix, $onChangeClause,
601 $tabindex, $tabindex_for_value, $idindex, $text_dir,
602 $special_chars_encoded, $data_type, $readOnly
604 $html_output .= "\n";
605 if (mb_strlen($special_chars) > 32000) {
606 $html_output .= "</td>\n";
607 $html_output .= '<td>' . __(
608 'Because of its length,<br /> this column might not be editable.'
612 } elseif ($column['pma_type'] == 'enum') {
613 $html_output .= PMA_getPmaTypeEnum(
614 $column, $backup_field, $column_name_appendix, $extracted_columnspec,
615 $onChangeClause, $tabindex, $tabindex_for_value, $idindex, $data,
616 $readOnly
619 } elseif ($column['pma_type'] == 'set') {
620 $html_output .= PMA_getPmaTypeSet(
621 $column, $extracted_columnspec, $backup_field,
622 $column_name_appendix, $onChangeClause, $tabindex,
623 $tabindex_for_value, $idindex, $data, $readOnly
626 } elseif ($column['is_binary'] || $column['is_blob']) {
627 $html_output .= PMA_getBinaryAndBlobColumn(
628 $column, $data, $special_chars, $biggest_max_file_size,
629 $backup_field, $column_name_appendix, $onChangeClause, $tabindex,
630 $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded,
631 $vkey, $is_upload, $readOnly
634 } elseif (! in_array($column['pma_type'], $no_support_types)) {
635 $html_output .= PMA_getValueColumnForOtherDatatypes(
636 $column, $default_char_editing, $backup_field,
637 $column_name_appendix, $onChangeClause, $tabindex, $special_chars,
638 $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded,
639 $data, $extracted_columnspec, $readOnly
643 if (in_array($column['pma_type'], $gis_data_types)) {
644 $html_output .= PMA_getHTMLforGisDataTypes();
647 return $html_output;
651 * Get HTML for foreign link in insert form
653 * @param array $column description of column in given table
654 * @param string $backup_field hidden input field
655 * @param string $column_name_appendix the name attribute
656 * @param string $onChangeClause onchange clause for fields
657 * @param integer $tabindex tab index
658 * @param integer $tabindex_for_value offset for the values tabindex
659 * @param integer $idindex id index
660 * @param string $data data to edit
661 * @param array $paramTableDbArray array containing $table and $db
662 * @param integer $rownumber the row number
663 * @param array $titles An HTML IMG tag for a particular icon from
664 * a theme, which may be an actual file or
665 * an icon from a sprite
666 * @param boolean $readOnly is column read only or not
668 * @return string an html snippet
670 function PMA_getForeignLink($column, $backup_field, $column_name_appendix,
671 $onChangeClause, $tabindex, $tabindex_for_value, $idindex, $data,
672 $paramTableDbArray, $rownumber, $titles, $readOnly
674 list($table, $db) = $paramTableDbArray;
675 $html_output = '';
676 $html_output .= $backup_field . "\n";
678 $html_output .= '<input type="hidden" name="fields_type'
679 . $column_name_appendix . '" value="foreign" />';
681 $html_output .= '<input type="text" name="fields' . $column_name_appendix . '" '
682 . 'class="textfield" '
683 . $onChangeClause . ' '
684 . ($readOnly ? 'readonly="readonly" ' : '')
685 . 'tabindex="' . ($tabindex + $tabindex_for_value) . '" '
686 . 'id="field_' . ($idindex) . '_3" '
687 . 'value="' . htmlspecialchars($data) . '" />';
689 $html_output .= '<a class="ajax browse_foreign" href="browse_foreigners.php'
690 . URL::getCommon(
691 array(
692 'db' => $db,
693 'table' => $table,
694 'field' => $column['Field'],
695 'rownumber' => $rownumber,
696 'data' => $data
698 ) . '">'
699 . str_replace("'", "\'", $titles['Browse']) . '</a>';
700 return $html_output;
704 * Get HTML to display foreign data
706 * @param string $backup_field hidden input field
707 * @param string $column_name_appendix the name attribute
708 * @param string $onChangeClause onchange clause for fields
709 * @param integer $tabindex tab index
710 * @param integer $tabindex_for_value offset for the values tabindex
711 * @param integer $idindex id index
712 * @param string $data data to edit
713 * @param array $foreignData data about the foreign keys
714 * @param boolean $readOnly is display read only or not
716 * @return string an html snippet
718 function PMA_dispRowForeignData($backup_field, $column_name_appendix,
719 $onChangeClause, $tabindex, $tabindex_for_value, $idindex, $data,
720 $foreignData, $readOnly
722 $html_output = '';
723 $html_output .= $backup_field . "\n";
724 $html_output .= '<input type="hidden"'
725 . ' name="fields_type' . $column_name_appendix . '"'
726 . ' value="foreign" />';
728 $html_output .= '<select name="fields' . $column_name_appendix . '"'
729 . ' ' . $onChangeClause
730 . ' class="textfield"'
731 . ($readOnly ? ' disabled' : '')
732 . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"'
733 . ' id="field_' . $idindex . '_3">';
734 $html_output .= PMA_foreignDropdown(
735 $foreignData['disp_row'], $foreignData['foreign_field'],
736 $foreignData['foreign_display'], $data,
737 $GLOBALS['cfg']['ForeignKeyMaxLimit']
739 $html_output .= '</select>';
741 //Add hidden input, as disabled <select> input does not included in POST.
742 if ($readOnly) {
743 $html_output .= '<input name="fields' . $column_name_appendix . '"'
744 . ' type="hidden" value="' . htmlspecialchars($data) . '">';
747 return $html_output;
751 * Get HTML textarea for insert form
753 * @param array $column column information
754 * @param string $backup_field hidden input field
755 * @param string $column_name_appendix the name attribute
756 * @param string $onChangeClause onchange clause for fields
757 * @param integer $tabindex tab index
758 * @param integer $tabindex_for_value offset for the values tabindex
759 * @param integer $idindex id index
760 * @param string $text_dir text direction
761 * @param string $special_chars_encoded replaced char if the string starts
762 * with a \r\n pair (0x0d0a) add an extra \n
763 * @param string $data_type the html5 data-* attribute type
764 * @param boolean $readOnly is column read only or not
766 * @return string an html snippet
768 function PMA_getTextarea($column, $backup_field, $column_name_appendix,
769 $onChangeClause, $tabindex, $tabindex_for_value, $idindex,
770 $text_dir, $special_chars_encoded, $data_type, $readOnly
772 $the_class = '';
773 $textAreaRows = $GLOBALS['cfg']['TextareaRows'];
774 $textareaCols = $GLOBALS['cfg']['TextareaCols'];
776 if ($column['is_char']) {
778 * @todo clarify the meaning of the "textfield" class and explain
779 * why character columns have the "char" class instead
781 $the_class = 'char';
782 $textAreaRows = $GLOBALS['cfg']['CharTextareaRows'];
783 $textareaCols = $GLOBALS['cfg']['CharTextareaCols'];
784 $extracted_columnspec = PMA\libraries\Util::extractColumnSpec(
785 $column['Type']
787 $maxlength = $extracted_columnspec['spec_in_brackets'];
788 } elseif ($GLOBALS['cfg']['LongtextDoubleTextarea']
789 && mb_strstr($column['pma_type'], 'longtext')
791 $textAreaRows = $GLOBALS['cfg']['TextareaRows'] * 2;
792 $textareaCols = $GLOBALS['cfg']['TextareaCols'] * 2;
794 $html_output = $backup_field . "\n"
795 . '<textarea name="fields' . $column_name_appendix . '"'
796 . ' class="' . $the_class . '"'
797 . ($readOnly ? ' readonly="readonly"' : '')
798 . (isset($maxlength) ? ' data-maxlength="' . $maxlength . '"' : '')
799 . ' rows="' . $textAreaRows . '"'
800 . ' cols="' . $textareaCols . '"'
801 . ' dir="' . $text_dir . '"'
802 . ' id="field_' . ($idindex) . '_3"'
803 . (! empty($onChangeClause) ? ' ' . $onChangeClause : '')
804 . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"'
805 . ' data-type="' . $data_type . '">'
806 . $special_chars_encoded
807 . '</textarea>';
809 return $html_output;
813 * Get HTML for enum type
815 * @param array $column description of column in given table
816 * @param string $backup_field hidden input field
817 * @param string $column_name_appendix the name attribute
818 * @param array $extracted_columnspec associative array containing type,
819 * spec_in_brackets and possibly
820 * enum_set_values (another array)
821 * @param string $onChangeClause onchange clause for fields
822 * @param integer $tabindex tab index
823 * @param integer $tabindex_for_value offset for the values tabindex
824 * @param integer $idindex id index
825 * @param mixed $data data to edit
826 * @param boolean $readOnly is column read only or not
828 * @return string an html snippet
830 function PMA_getPmaTypeEnum($column, $backup_field, $column_name_appendix,
831 $extracted_columnspec, $onChangeClause, $tabindex, $tabindex_for_value,
832 $idindex, $data, $readOnly
834 $html_output = '';
835 if (! isset($column['values'])) {
836 $column['values'] = PMA_getColumnEnumValues(
837 $column, $extracted_columnspec
840 $column_enum_values = $column['values'];
841 $html_output .= '<input type="hidden" name="fields_type'
842 . $column_name_appendix . '" value="enum" />';
843 $html_output .= "\n" . ' ' . $backup_field . "\n";
844 if (mb_strlen($column['Type']) > 20) {
845 $html_output .= PMA_getDropDownDependingOnLength(
846 $column, $column_name_appendix, $onChangeClause,
847 $tabindex, $tabindex_for_value,
848 $idindex, $data, $column_enum_values, $readOnly
850 } else {
851 $html_output .= PMA_getRadioButtonDependingOnLength(
852 $column_name_appendix, $onChangeClause,
853 $tabindex, $column, $tabindex_for_value,
854 $idindex, $data, $column_enum_values, $readOnly
857 return $html_output;
861 * Get column values
863 * @param array $column description of column in given table
864 * @param array $extracted_columnspec associative array containing type,
865 * spec_in_brackets and possibly enum_set_values
866 * (another array)
868 * @return array column values as an associative array
870 function PMA_getColumnEnumValues($column, $extracted_columnspec)
872 $column['values'] = array();
873 foreach ($extracted_columnspec['enum_set_values'] as $val) {
874 $column['values'][] = array(
875 'plain' => $val,
876 'html' => htmlspecialchars($val),
879 return $column['values'];
883 * Get HTML drop down for more than 20 string length
885 * @param array $column description of column in given table
886 * @param string $column_name_appendix the name attribute
887 * @param string $onChangeClause onchange clause for fields
888 * @param integer $tabindex tab index
889 * @param integer $tabindex_for_value offset for the values tabindex
890 * @param integer $idindex id index
891 * @param string $data data to edit
892 * @param array $column_enum_values $column['values']
893 * @param boolean $readOnly is column read only or not
895 * @return string an html snippet
897 function PMA_getDropDownDependingOnLength(
898 $column, $column_name_appendix, $onChangeClause,
899 $tabindex, $tabindex_for_value, $idindex, $data, $column_enum_values,
900 $readOnly
902 $html_output = '<select name="fields' . $column_name_appendix . '"'
903 . ' ' . $onChangeClause
904 . ' class="textfield"'
905 . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"'
906 . ($readOnly ? ' disabled' : '')
907 . ' id="field_' . ($idindex) . '_3">';
908 $html_output .= '<option value="">&nbsp;</option>' . "\n";
910 $selected_html = '';
911 foreach ($column_enum_values as $enum_value) {
912 $html_output .= '<option value="' . $enum_value['html'] . '"';
913 if ($data == $enum_value['plain']
914 || ($data == ''
915 && (! isset($_REQUEST['where_clause']) || $column['Null'] != 'YES')
916 && isset($column['Default'])
917 && $enum_value['plain'] == $column['Default'])
919 $html_output .= ' selected="selected"';
920 $selected_html = $enum_value['html'];
922 $html_output .= '>' . $enum_value['html'] . '</option>' . "\n";
924 $html_output .= '</select>';
926 //Add hidden input, as disabled <select> input does not included in POST.
927 if ($readOnly) {
928 $html_output .= '<input name="fields' . $column_name_appendix . '"'
929 . ' type="hidden" value="' . $selected_html . '">';
931 return $html_output;
935 * Get HTML radio button for less than 20 string length
937 * @param string $column_name_appendix the name attribute
938 * @param string $onChangeClause onchange clause for fields
939 * @param integer $tabindex tab index
940 * @param array $column description of column in given table
941 * @param integer $tabindex_for_value offset for the values tabindex
942 * @param integer $idindex id index
943 * @param string $data data to edit
944 * @param array $column_enum_values $column['values']
945 * @param boolean $readOnly is column read only or not
947 * @return string an html snippet
949 function PMA_getRadioButtonDependingOnLength(
950 $column_name_appendix, $onChangeClause,
951 $tabindex, $column, $tabindex_for_value, $idindex, $data,
952 $column_enum_values, $readOnly
954 $j = 0;
955 $html_output = '';
956 foreach ($column_enum_values as $enum_value) {
957 $html_output .= ' '
958 . '<input type="radio" name="fields' . $column_name_appendix . '"'
959 . ' class="textfield"'
960 . ' value="' . $enum_value['html'] . '"'
961 . ' id="field_' . ($idindex) . '_3_' . $j . '"'
962 . ' ' . $onChangeClause;
963 if ($data == $enum_value['plain']
964 || ($data == ''
965 && (! isset($_REQUEST['where_clause']) || $column['Null'] != 'YES')
966 && isset($column['Default'])
967 && $enum_value['plain'] == $column['Default'])
969 $html_output .= ' checked="checked"';
971 elseif ($readOnly) {
972 $html_output .= ' disabled';
974 $html_output .= ' tabindex="' . ($tabindex + $tabindex_for_value) . '" />';
975 $html_output .= '<label for="field_' . $idindex . '_3_' . $j . '">'
976 . $enum_value['html'] . '</label>' . "\n";
977 $j++;
979 return $html_output;
983 * Get the HTML for 'set' pma type
985 * @param array $column description of column in given table
986 * @param array $extracted_columnspec associative array containing type,
987 * spec_in_brackets and possibly
988 * enum_set_values (another array)
989 * @param string $backup_field hidden input field
990 * @param string $column_name_appendix the name attribute
991 * @param string $onChangeClause onchange clause for fields
992 * @param integer $tabindex tab index
993 * @param integer $tabindex_for_value offset for the values tabindex
994 * @param integer $idindex id index
995 * @param string $data description of the column field
996 * @param boolean $readOnly is column read only or not
998 * @return string an html snippet
1000 function PMA_getPmaTypeSet(
1001 $column, $extracted_columnspec, $backup_field,
1002 $column_name_appendix, $onChangeClause, $tabindex,
1003 $tabindex_for_value, $idindex, $data, $readOnly
1005 list($column_set_values, $select_size) = PMA_getColumnSetValueAndSelectSize(
1006 $column, $extracted_columnspec
1008 $vset = array_flip(explode(',', $data));
1009 $html_output = $backup_field . "\n";
1010 $html_output .= '<input type="hidden" name="fields_type'
1011 . $column_name_appendix . '" value="set" />';
1012 $html_output .= '<select name="fields' . $column_name_appendix . '[]' . '"'
1013 . ' class="textfield"'
1014 . ($readOnly ? ' disabled' : '')
1015 . ' size="' . $select_size . '"'
1016 . ' multiple="multiple"'
1017 . ' ' . $onChangeClause
1018 . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"'
1019 . ' id="field_' . ($idindex) . '_3">';
1021 $selected_html = '';
1022 foreach ($column_set_values as $column_set_value) {
1023 $html_output .= '<option value="' . $column_set_value['html'] . '"';
1024 if (isset($vset[$column_set_value['plain']])) {
1025 $html_output .= ' selected="selected"';
1026 $selected_html = $column_set_value['html'];
1028 $html_output .= '>' . $column_set_value['html'] . '</option>' . "\n";
1030 $html_output .= '</select>';
1032 //Add hidden input, as disabled <select> input does not included in POST.
1033 if ($readOnly) {
1034 $html_output .= '<input name="fields' . $column_name_appendix . '[]' . '"'
1035 . ' type="hidden" value="' . $selected_html . '">';
1037 return $html_output;
1041 * Retrieve column 'set' value and select size
1043 * @param array $column description of column in given table
1044 * @param array $extracted_columnspec associative array containing type,
1045 * spec_in_brackets and possibly enum_set_values
1046 * (another array)
1048 * @return array $column['values'], $column['select_size']
1050 function PMA_getColumnSetValueAndSelectSize($column, $extracted_columnspec)
1052 if (! isset($column['values'])) {
1053 $column['values'] = array();
1054 foreach ($extracted_columnspec['enum_set_values'] as $val) {
1055 $column['values'][] = array(
1056 'plain' => $val,
1057 'html' => htmlspecialchars($val),
1060 $column['select_size'] = min(4, count($column['values']));
1062 return array($column['values'], $column['select_size']);
1066 * Get HTML for binary and blob column
1068 * @param array $column description of column in given table
1069 * @param string $data data to edit
1070 * @param string $special_chars special characters
1071 * @param integer $biggest_max_file_size biggest max file size for uploading
1072 * @param string $backup_field hidden input field
1073 * @param string $column_name_appendix the name attribute
1074 * @param string $onChangeClause onchange clause for fields
1075 * @param integer $tabindex tab index
1076 * @param integer $tabindex_for_value offset for the values tabindex
1077 * @param integer $idindex id index
1078 * @param string $text_dir text direction
1079 * @param string $special_chars_encoded replaced char if the string starts
1080 * with a \r\n pair (0x0d0a) add an extra \n
1081 * @param string $vkey [multi_edit]['row_id']
1082 * @param boolean $is_upload is upload or not
1083 * @param boolean $readOnly is column read only or not
1085 * @return string an html snippet
1087 function PMA_getBinaryAndBlobColumn(
1088 $column, $data, $special_chars, $biggest_max_file_size,
1089 $backup_field, $column_name_appendix, $onChangeClause, $tabindex,
1090 $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded,
1091 $vkey, $is_upload, $readOnly
1093 $html_output = '';
1094 // Add field type : Protected or Hexadecimal
1095 $fields_type_html = '<input type="hidden" name="fields_type'
1096 . $column_name_appendix . '" value="%s" />';
1097 // Default value : hex
1098 $fields_type_val = 'hex';
1099 if (($GLOBALS['cfg']['ProtectBinary'] === 'blob' && $column['is_blob'])
1100 || ($GLOBALS['cfg']['ProtectBinary'] === 'all')
1101 || ($GLOBALS['cfg']['ProtectBinary'] === 'noblob' && !$column['is_blob'])
1103 $html_output .= __('Binary - do not edit');
1104 if (isset($data)) {
1105 $data_size = PMA\libraries\Util::formatByteDown(
1106 mb_strlen(stripslashes($data)), 3, 1
1108 $html_output .= ' (' . $data_size[0] . ' ' . $data_size[1] . ')';
1109 unset($data_size);
1111 $fields_type_val = 'protected';
1112 $html_output .= '<input type="hidden" name="fields'
1113 . $column_name_appendix . '" value="" />';
1114 } elseif ($column['is_blob']
1115 || ($column['len'] > $GLOBALS['cfg']['LimitChars'])
1117 $html_output .= "\n" . PMA_getTextarea(
1118 $column, $backup_field, $column_name_appendix, $onChangeClause,
1119 $tabindex, $tabindex_for_value, $idindex, $text_dir,
1120 $special_chars_encoded, 'HEX', $readOnly
1122 } else {
1123 // field size should be at least 4 and max $GLOBALS['cfg']['LimitChars']
1124 $fieldsize = min(max($column['len'], 4), $GLOBALS['cfg']['LimitChars']);
1125 $html_output .= "\n" . $backup_field . "\n" . PMA_getHTMLinput(
1126 $column, $column_name_appendix, $special_chars, $fieldsize,
1127 $onChangeClause, $tabindex, $tabindex_for_value, $idindex, 'HEX',
1128 $readOnly
1131 $html_output .= sprintf($fields_type_html, $fields_type_val);
1133 if ($is_upload && $column['is_blob'] && !$readOnly) {
1134 // We don't want to prevent users from using
1135 // browser's default drag-drop feature on some page(s),
1136 // so we add noDragDrop class to the input
1137 $html_output .= '<br />'
1138 . '<input type="file"'
1139 . ' name="fields_upload' . $vkey . '[' . $column['Field_md5'] . ']"'
1140 . ' class="textfield noDragDrop" id="field_' . $idindex . '_3" size="10"'
1141 . ' ' . $onChangeClause . '/>&nbsp;';
1142 list($html_out,) = PMA_getMaxUploadSize(
1143 $column, $biggest_max_file_size
1145 $html_output .= $html_out;
1148 if (!empty($GLOBALS['cfg']['UploadDir']) && !$readOnly) {
1149 $html_output .= PMA_getSelectOptionForUpload($vkey, $column);
1152 return $html_output;
1156 * Get HTML input type
1158 * @param array $column description of column in given table
1159 * @param string $column_name_appendix the name attribute
1160 * @param string $special_chars special characters
1161 * @param integer $fieldsize html field size
1162 * @param string $onChangeClause onchange clause for fields
1163 * @param integer $tabindex tab index
1164 * @param integer $tabindex_for_value offset for the values tabindex
1165 * @param integer $idindex id index
1166 * @param string $data_type the html5 data-* attribute type
1167 * @param boolean $readOnly is column read only or not
1169 * @return string an html snippet
1171 function PMA_getHTMLinput(
1172 $column, $column_name_appendix, $special_chars, $fieldsize, $onChangeClause,
1173 $tabindex, $tabindex_for_value, $idindex, $data_type, $readOnly
1175 $input_type = 'text';
1176 // do not use the 'date' or 'time' types here; they have no effect on some
1177 // browsers and create side effects (see bug #4218)
1179 $the_class = 'textfield';
1180 // verify True_Type which does not contain the parentheses and length
1181 if ($readOnly) {
1182 //NOOP. Disable date/timepicker
1183 } else if ($column['True_Type'] === 'date') {
1184 $the_class .= ' datefield';
1185 } else if ($column['True_Type'] === 'time') {
1186 $the_class .= ' timefield';
1187 } else if ($column['True_Type'] === 'datetime'
1188 || $column['True_Type'] === 'timestamp'
1190 $the_class .= ' datetimefield';
1192 $input_min_max = false;
1193 if (in_array($column['True_Type'], $GLOBALS['PMA_Types']->getIntegerTypes())) {
1194 $extracted_columnspec = PMA\libraries\Util::extractColumnSpec(
1195 $column['Type']
1197 $is_unsigned = $extracted_columnspec['unsigned'];
1198 $min_max_values = $GLOBALS['PMA_Types']->getIntegerRange(
1199 $column['True_Type'], ! $is_unsigned
1201 $input_min_max = 'min="' . $min_max_values[0] . '" '
1202 . 'max="' . $min_max_values[1] . '"';
1203 $data_type = 'INT';
1205 return '<input type="' . $input_type . '"'
1206 . ' name="fields' . $column_name_appendix . '"'
1207 . ' value="' . $special_chars . '" size="' . $fieldsize . '"'
1208 . ((isset($column['is_char']) && $column['is_char'])
1209 ? ' data-maxlength="' . $fieldsize . '"'
1210 : '')
1211 . ($readOnly ? ' readonly="readonly"' : '')
1212 . ($input_min_max !== false ? ' ' . $input_min_max : '')
1213 . ' data-type="' . $data_type . '"'
1214 . ($input_type === 'time' ? ' step="1"' : '')
1215 . ' class="' . $the_class . '" ' . $onChangeClause
1216 . ' tabindex="' . ($tabindex + $tabindex_for_value) . '"'
1217 . ' id="field_' . ($idindex) . '_3" />';
1221 * Get HTML select option for upload
1223 * @param string $vkey [multi_edit]['row_id']
1224 * @param array $column description of column in given table
1226 * @return string|void an html snippet
1228 function PMA_getSelectOptionForUpload($vkey, $column)
1230 $files = PMA_getFileSelectOptions(
1231 PMA\libraries\Util::userDir($GLOBALS['cfg']['UploadDir'])
1234 if ($files === false) {
1235 return '<span style="color:red">' . __('Error') . '</span><br />' . "\n"
1236 . __('The directory you set for upload work cannot be reached.') . "\n";
1237 } elseif (!empty($files)) {
1238 return "<br />\n"
1239 . '<i>' . __('Or') . '</i>' . ' '
1240 . __('web server upload directory:') . '<br />' . "\n"
1241 . '<select size="1" name="fields_uploadlocal'
1242 . $vkey . '[' . $column['Field_md5'] . ']">' . "\n"
1243 . '<option value="" selected="selected"></option>' . "\n"
1244 . $files
1245 . '</select>' . "\n";
1248 return null;
1252 * Retrieve the maximum upload file size
1254 * @param array $column description of column in given table
1255 * @param integer $biggest_max_file_size biggest max file size for uploading
1257 * @return array an html snippet and $biggest_max_file_size
1259 function PMA_getMaxUploadSize($column, $biggest_max_file_size)
1261 // find maximum upload size, based on field type
1263 * @todo with functions this is not so easy, as you can basically
1264 * process any data with function like MD5
1266 global $max_upload_size;
1267 $max_field_sizes = array(
1268 'tinyblob' => '256',
1269 'blob' => '65536',
1270 'mediumblob' => '16777216',
1271 'longblob' => '4294967296' // yeah, really
1274 $this_field_max_size = $max_upload_size; // from PHP max
1275 if ($this_field_max_size > $max_field_sizes[$column['pma_type']]) {
1276 $this_field_max_size = $max_field_sizes[$column['pma_type']];
1278 $html_output
1279 = PMA\libraries\Util::getFormattedMaximumUploadSize(
1280 $this_field_max_size
1281 ) . "\n";
1282 // do not generate here the MAX_FILE_SIZE, because we should
1283 // put only one in the form to accommodate the biggest field
1284 if ($this_field_max_size > $biggest_max_file_size) {
1285 $biggest_max_file_size = $this_field_max_size;
1287 return array($html_output, $biggest_max_file_size);
1291 * Get HTML for the Value column of other datatypes
1292 * (here, "column" is used in the sense of HTML column in HTML table)
1294 * @param array $column description of column in given table
1295 * @param string $default_char_editing default char editing mode which is stored
1296 * in the config.inc.php script
1297 * @param string $backup_field hidden input field
1298 * @param string $column_name_appendix the name attribute
1299 * @param string $onChangeClause onchange clause for fields
1300 * @param integer $tabindex tab index
1301 * @param string $special_chars special characters
1302 * @param integer $tabindex_for_value offset for the values tabindex
1303 * @param integer $idindex id index
1304 * @param string $text_dir text direction
1305 * @param string $special_chars_encoded replaced char if the string starts
1306 * with a \r\n pair (0x0d0a) add an extra \n
1307 * @param string $data data to edit
1308 * @param array $extracted_columnspec associative array containing type,
1309 * spec_in_brackets and possibly
1310 * enum_set_values (another array)
1311 * @param boolean $readOnly is column read only or not
1313 * @return string an html snippet
1315 function PMA_getValueColumnForOtherDatatypes($column, $default_char_editing,
1316 $backup_field,
1317 $column_name_appendix, $onChangeClause, $tabindex, $special_chars,
1318 $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded, $data,
1319 $extracted_columnspec, $readOnly
1321 // HTML5 data-* attribute data-type
1322 $data_type = $GLOBALS['PMA_Types']->getTypeClass($column['True_Type']);
1323 $fieldsize = PMA_getColumnSize($column, $extracted_columnspec);
1324 $html_output = $backup_field . "\n";
1325 if ($column['is_char']
1326 && ($GLOBALS['cfg']['CharEditing'] == 'textarea'
1327 || mb_strpos($data, "\n") !== false)
1329 $html_output .= "\n";
1330 $GLOBALS['cfg']['CharEditing'] = $default_char_editing;
1331 $html_output .= PMA_getTextarea(
1332 $column, $backup_field, $column_name_appendix, $onChangeClause,
1333 $tabindex, $tabindex_for_value, $idindex, $text_dir,
1334 $special_chars_encoded, $data_type, $readOnly
1336 } else {
1337 $html_output .= PMA_getHTMLinput(
1338 $column, $column_name_appendix, $special_chars, $fieldsize,
1339 $onChangeClause, $tabindex, $tabindex_for_value, $idindex,
1340 $data_type, $readOnly
1343 $virtual = array(
1344 'VIRTUAL', 'PERSISTENT', 'VIRTUAL GENERATED', 'STORED GENERATED'
1346 if (in_array($column['Extra'], $virtual)) {
1347 $html_output .= '<input type="hidden" name="virtual'
1348 . $column_name_appendix . '" value="1" />';
1350 if ($column['Extra'] == 'auto_increment') {
1351 $html_output .= '<input type="hidden" name="auto_increment'
1352 . $column_name_appendix . '" value="1" />';
1354 if (substr($column['pma_type'], 0, 9) == 'timestamp') {
1355 $html_output .= '<input type="hidden" name="fields_type'
1356 . $column_name_appendix . '" value="timestamp" />';
1358 if (substr($column['pma_type'], 0, 8) == 'datetime') {
1359 $html_output .= '<input type="hidden" name="fields_type'
1360 . $column_name_appendix . '" value="datetime" />';
1362 if ($column['True_Type'] == 'bit') {
1363 $html_output .= '<input type="hidden" name="fields_type'
1364 . $column_name_appendix . '" value="bit" />';
1366 if ($column['pma_type'] == 'date'
1367 || $column['pma_type'] == 'datetime'
1368 || substr($column['pma_type'], 0, 9) == 'timestamp'
1370 // the _3 suffix points to the date field
1371 // the _2 suffix points to the corresponding NULL checkbox
1372 // in dateFormat, 'yy' means the year with 4 digits
1375 return $html_output;
1379 * Get the field size
1381 * @param array $column description of column in given table
1382 * @param array $extracted_columnspec associative array containing type,
1383 * spec_in_brackets and possibly enum_set_values
1384 * (another array)
1386 * @return integer field size
1388 function PMA_getColumnSize($column, $extracted_columnspec)
1390 if ($column['is_char']) {
1391 $fieldsize = $extracted_columnspec['spec_in_brackets'];
1392 if ($fieldsize > $GLOBALS['cfg']['MaxSizeForInputField']) {
1394 * This case happens for CHAR or VARCHAR columns which have
1395 * a size larger than the maximum size for input field.
1397 $GLOBALS['cfg']['CharEditing'] = 'textarea';
1399 } else {
1401 * This case happens for example for INT or DATE columns;
1402 * in these situations, the value returned in $column['len']
1403 * seems appropriate.
1405 $fieldsize = $column['len'];
1407 return min(
1408 max($fieldsize, $GLOBALS['cfg']['MinSizeForInputField']),
1409 $GLOBALS['cfg']['MaxSizeForInputField']
1414 * Get HTML for gis data types
1416 * @return string an html snippet
1418 function PMA_getHTMLforGisDataTypes()
1420 $edit_str = PMA\libraries\Util::getIcon('b_edit.png', __('Edit/Insert'));
1421 return '<span class="open_gis_editor">'
1422 . PMA\libraries\Util::linkOrButton(
1423 '#', $edit_str, array(), false, false, '_blank'
1425 . '</span>';
1429 * get html for continue insertion form
1431 * @param string $table name of the table
1432 * @param string $db name of the database
1433 * @param array $where_clause_array array of where clauses
1434 * @param string $err_url error url
1436 * @return string an html snippet
1438 function PMA_getContinueInsertionForm($table, $db, $where_clause_array, $err_url)
1440 $html_output = '<form id="continueForm" method="post"'
1441 . ' action="tbl_replace.php" name="continueForm">'
1442 . URL::getHiddenInputs($db, $table)
1443 . '<input type="hidden" name="goto"'
1444 . ' value="' . htmlspecialchars($GLOBALS['goto']) . '" />'
1445 . '<input type="hidden" name="err_url"'
1446 . ' value="' . htmlspecialchars($err_url) . '" />'
1447 . '<input type="hidden" name="sql_query"'
1448 . ' value="' . htmlspecialchars($_REQUEST['sql_query']) . '" />';
1450 if (isset($_REQUEST['where_clause'])) {
1451 foreach ($where_clause_array as $key_id => $where_clause) {
1453 $html_output .= '<input type="hidden"'
1454 . ' name="where_clause[' . $key_id . ']"'
1455 . ' value="' . htmlspecialchars(trim($where_clause)) . '" />' . "\n";
1458 $tmp = '<select name="insert_rows" id="insert_rows">' . "\n";
1459 $option_values = array(1, 2, 5, 10, 15, 20, 30, 40);
1461 foreach ($option_values as $value) {
1462 $tmp .= '<option value="' . $value . '"';
1463 if ($value == $GLOBALS['cfg']['InsertRows']) {
1464 $tmp .= ' selected="selected"';
1466 $tmp .= '>' . $value . '</option>' . "\n";
1469 $tmp .= '</select>' . "\n";
1470 $html_output .= "\n" . sprintf(__('Continue insertion with %s rows'), $tmp);
1471 unset($tmp);
1472 $html_output .= '</form>' . "\n";
1473 return $html_output;
1477 * Get action panel
1479 * @param array $where_clause where clause
1480 * @param string $after_insert insert mode, e.g. new_insert, same_insert
1481 * @param integer $tabindex tab index
1482 * @param integer $tabindex_for_value offset for the values tabindex
1483 * @param boolean $found_unique_key boolean variable for unique key
1485 * @return string an html snippet
1487 function PMA_getActionsPanel($where_clause, $after_insert, $tabindex,
1488 $tabindex_for_value, $found_unique_key
1490 $html_output = '<fieldset id="actions_panel">'
1491 . '<table cellpadding="5" cellspacing="0">'
1492 . '<tr>'
1493 . '<td class="nowrap vmiddle">'
1494 . PMA_getSubmitTypeDropDown($where_clause, $tabindex, $tabindex_for_value)
1495 . "\n";
1497 $html_output .= '</td>'
1498 . '<td class="vmiddle">'
1499 . '&nbsp;&nbsp;&nbsp;<strong>'
1500 . __('and then') . '</strong>&nbsp;&nbsp;&nbsp;'
1501 . '</td>'
1502 . '<td class="nowrap vmiddle">'
1503 . PMA_getAfterInsertDropDown(
1504 $where_clause, $after_insert, $found_unique_key
1506 . '</td>'
1507 . '</tr>';
1508 $html_output .='<tr>'
1509 . PMA_getSubmitAndResetButtonForActionsPanel($tabindex, $tabindex_for_value)
1510 . '</tr>'
1511 . '</table>'
1512 . '</fieldset>';
1513 return $html_output;
1517 * Get a HTML drop down for submit types
1519 * @param array $where_clause where clause
1520 * @param integer $tabindex tab index
1521 * @param integer $tabindex_for_value offset for the values tabindex
1523 * @return string an html snippet
1525 function PMA_getSubmitTypeDropDown($where_clause, $tabindex, $tabindex_for_value)
1527 $html_output = '<select name="submit_type" class="control_at_footer" tabindex="'
1528 . ($tabindex + $tabindex_for_value + 1) . '">';
1529 if (isset($where_clause)) {
1530 $html_output .= '<option value="save">' . __('Save') . '</option>';
1532 $html_output .= '<option value="insert">'
1533 . __('Insert as new row')
1534 . '</option>'
1535 . '<option value="insertignore">'
1536 . __('Insert as new row and ignore errors')
1537 . '</option>'
1538 . '<option value="showinsert">'
1539 . __('Show insert query')
1540 . '</option>'
1541 . '</select>';
1542 return $html_output;
1546 * Get HTML drop down for after insert
1548 * @param array $where_clause where clause
1549 * @param string $after_insert insert mode, e.g. new_insert, same_insert
1550 * @param boolean $found_unique_key boolean variable for unique key
1552 * @return string an html snippet
1554 function PMA_getAfterInsertDropDown($where_clause, $after_insert, $found_unique_key)
1556 $html_output = '<select name="after_insert" class="control_at_footer">'
1557 . '<option value="back" '
1558 . ($after_insert == 'back' ? 'selected="selected"' : '') . '>'
1559 . __('Go back to previous page') . '</option>'
1560 . '<option value="new_insert" '
1561 . ($after_insert == 'new_insert' ? 'selected="selected"' : '') . '>'
1562 . __('Insert another new row') . '</option>';
1564 if (isset($where_clause)) {
1565 $html_output .= '<option value="same_insert" '
1566 . ($after_insert == 'same_insert' ? 'selected="selected"' : '') . '>'
1567 . __('Go back to this page') . '</option>';
1569 // If we have just numeric primary key, we can also edit next
1570 // in 2.8.2, we were looking for `field_name` = numeric_value
1571 //if (preg_match('@^[\s]*`[^`]*` = [0-9]+@', $where_clause)) {
1572 // in 2.9.0, we are looking for `table_name`.`field_name` = numeric_value
1573 $is_numeric = false;
1574 if (! is_array($where_clause)) {
1575 $where_clause = array($where_clause);
1577 for ($i = 0, $nb = count($where_clause); $i < $nb; $i++) {
1578 // preg_match() returns 1 if there is a match
1579 $is_numeric = (preg_match(
1580 '@^[\s]*`[^`]*`[\.]`[^`]*` = [0-9]+@',
1581 $where_clause[$i]
1582 ) == 1);
1583 if ($is_numeric === true) {
1584 break;
1587 if ($found_unique_key && $is_numeric) {
1588 $html_output .= '<option value="edit_next" '
1589 . ($after_insert == 'edit_next' ? 'selected="selected"' : '') . '>'
1590 . __('Edit next row') . '</option>';
1594 $html_output .= '</select>';
1595 return $html_output;
1600 * get Submit button and Reset button for action panel
1602 * @param integer $tabindex tab index
1603 * @param integer $tabindex_for_value offset for the values tabindex
1605 * @return string an html snippet
1607 function PMA_getSubmitAndResetButtonForActionsPanel($tabindex, $tabindex_for_value)
1609 return '<td>'
1610 . PMA\libraries\Util::showHint(
1612 'Use TAB key to move from value to value,'
1613 . ' or CTRL+arrows to move anywhere.'
1616 . '</td>'
1617 . '<td colspan="3" class="right vmiddle">'
1618 . '<input type="submit" class="control_at_footer" value="' . __('Go') . '"'
1619 . ' tabindex="' . ($tabindex + $tabindex_for_value + 6) . '" id="buttonYes" />'
1620 . '<input type="button" class="preview_sql" value="' . __('Preview SQL') . '"'
1621 . ' tabindex="' . ($tabindex + $tabindex_for_value + 7) . '" />'
1622 . '<input type="reset" class="control_at_footer" value="' . __('Reset') . '"'
1623 . ' tabindex="' . ($tabindex + $tabindex_for_value + 8) . '" />'
1624 . '</td>';
1628 * Get table head and table foot for insert row table
1630 * @param array $url_params url parameters
1632 * @return string an html snippet
1634 function PMA_getHeadAndFootOfInsertRowTable($url_params)
1636 $html_output = '<table class="insertRowTable topmargin">'
1637 . '<thead>'
1638 . '<tr>'
1639 . '<th>' . __('Column') . '</th>';
1641 if ($GLOBALS['cfg']['ShowFieldTypesInDataEditView']) {
1642 $html_output .= PMA_showTypeOrFunction('type', $url_params, true);
1644 if ($GLOBALS['cfg']['ShowFunctionFields']) {
1645 $html_output .= PMA_showTypeOrFunction('function', $url_params, true);
1648 $html_output .= '<th>' . __('Null') . '</th>'
1649 . '<th>' . __('Value') . '</th>'
1650 . '</tr>'
1651 . '</thead>'
1652 . ' <tfoot>'
1653 . '<tr>'
1654 . '<th colspan="5" class="tblFooters right">'
1655 . '<input type="submit" value="' . __('Go') . '" />'
1656 . '</th>'
1657 . '</tr>'
1658 . '</tfoot>';
1659 return $html_output;
1663 * Prepares the field value and retrieve special chars, backup field and data array
1665 * @param array $current_row a row of the table
1666 * @param array $column description of column in given table
1667 * @param array $extracted_columnspec associative array containing type,
1668 * spec_in_brackets and possibly
1669 * enum_set_values (another array)
1670 * @param boolean $real_null_value whether column value null or not null
1671 * @param array $gis_data_types list of GIS data types
1672 * @param string $column_name_appendix string to append to column name in input
1673 * @param bool $as_is use the data as is, used in repopulating
1675 * @return array $real_null_value, $data, $special_chars, $backup_field,
1676 * $special_chars_encoded
1678 function PMA_getSpecialCharsAndBackupFieldForExistingRow(
1679 $current_row, $column, $extracted_columnspec,
1680 $real_null_value, $gis_data_types, $column_name_appendix, $as_is
1682 $special_chars_encoded = '';
1683 $data = null;
1684 // (we are editing)
1685 if (!isset($current_row[$column['Field']])) {
1686 $real_null_value = true;
1687 $current_row[$column['Field']] = '';
1688 $special_chars = '';
1689 $data = $current_row[$column['Field']];
1690 } elseif ($column['True_Type'] == 'bit') {
1691 $special_chars = $as_is
1692 ? $current_row[$column['Field']]
1693 : PMA\libraries\Util::printableBitValue(
1694 $current_row[$column['Field']],
1695 $extracted_columnspec['spec_in_brackets']
1697 } elseif ((substr($column['True_Type'], 0, 9) == 'timestamp'
1698 || $column['True_Type'] == 'datetime'
1699 || $column['True_Type'] == 'time')
1700 && (mb_strpos($current_row[$column['Field']], ".") !== false)
1702 $current_row[$column['Field']] = $as_is
1703 ? $current_row[$column['Field']]
1704 : PMA\libraries\Util::addMicroseconds(
1705 $current_row[$column['Field']]
1707 $special_chars = htmlspecialchars($current_row[$column['Field']]);
1708 } elseif (in_array($column['True_Type'], $gis_data_types)) {
1709 // Convert gis data to Well Know Text format
1710 $current_row[$column['Field']] = $as_is
1711 ? $current_row[$column['Field']]
1712 : PMA\libraries\Util::asWKT(
1713 $current_row[$column['Field']], true
1715 $special_chars = htmlspecialchars($current_row[$column['Field']]);
1716 } else {
1717 // special binary "characters"
1718 if ($column['is_binary']
1719 || ($column['is_blob'] && $GLOBALS['cfg']['ProtectBinary'] !== 'all')
1721 $current_row[$column['Field']] = $as_is
1722 ? $current_row[$column['Field']]
1723 : bin2hex(
1724 $current_row[$column['Field']]
1726 } // end if
1727 $special_chars = htmlspecialchars($current_row[$column['Field']]);
1729 //We need to duplicate the first \n or otherwise we will lose
1730 //the first newline entered in a VARCHAR or TEXT column
1731 $special_chars_encoded
1732 = PMA\libraries\Util::duplicateFirstNewline($special_chars);
1734 $data = $current_row[$column['Field']];
1735 } // end if... else...
1737 //when copying row, it is useful to empty auto-increment column
1738 // to prevent duplicate key error
1739 if (isset($_REQUEST['default_action'])
1740 && $_REQUEST['default_action'] === 'insert'
1742 if ($column['Key'] === 'PRI'
1743 && mb_strpos($column['Extra'], 'auto_increment') !== false
1745 $data = $special_chars_encoded = $special_chars = null;
1748 // If a timestamp field value is not included in an update
1749 // statement MySQL auto-update it to the current timestamp;
1750 // however, things have changed since MySQL 4.1, so
1751 // it's better to set a fields_prev in this situation
1752 $backup_field = '<input type="hidden" name="fields_prev'
1753 . $column_name_appendix . '" value="'
1754 . htmlspecialchars($current_row[$column['Field']]) . '" />';
1756 return array(
1757 $real_null_value,
1758 $special_chars_encoded,
1759 $special_chars,
1760 $data,
1761 $backup_field
1766 * display default values
1768 * @param array $column description of column in given table
1769 * @param boolean $real_null_value whether column value null or not null
1771 * @return array $real_null_value, $data, $special_chars,
1772 * $backup_field, $special_chars_encoded
1774 function PMA_getSpecialCharsAndBackupFieldForInsertingMode(
1775 $column, $real_null_value
1777 if (! isset($column['Default'])) {
1778 $column['Default'] = '';
1779 $real_null_value = true;
1780 $data = '';
1781 } else {
1782 $data = $column['Default'];
1785 $trueType = $column['True_Type'];
1787 if ($trueType == 'bit') {
1788 $special_chars = PMA\libraries\Util::convertBitDefaultValue(
1789 $column['Default']
1791 } elseif (substr($trueType, 0, 9) == 'timestamp'
1792 || $trueType == 'datetime'
1793 || $trueType == 'time'
1795 $special_chars = PMA\libraries\Util::addMicroseconds($column['Default']);
1796 } elseif ($trueType == 'binary' || $trueType == 'varbinary') {
1797 $special_chars = bin2hex($column['Default']);
1798 } else {
1799 $special_chars = htmlspecialchars($column['Default']);
1801 $backup_field = '';
1802 $special_chars_encoded = PMA\libraries\Util::duplicateFirstNewline(
1803 $special_chars
1805 return array(
1806 $real_null_value, $data, $special_chars,
1807 $backup_field, $special_chars_encoded
1812 * Prepares the update/insert of a row
1814 * @return array $loop_array, $using_key, $is_insert, $is_insertignore
1816 function PMA_getParamsForUpdateOrInsert()
1818 if (isset($_REQUEST['where_clause'])) {
1819 // we were editing something => use the WHERE clause
1820 $loop_array = is_array($_REQUEST['where_clause'])
1821 ? $_REQUEST['where_clause']
1822 : array($_REQUEST['where_clause']);
1823 $using_key = true;
1824 $is_insert = isset($_REQUEST['submit_type'])
1825 && ($_REQUEST['submit_type'] == 'insert'
1826 || $_REQUEST['submit_type'] == 'showinsert'
1827 || $_REQUEST['submit_type'] == 'insertignore');
1828 } else {
1829 // new row => use indexes
1830 $loop_array = array();
1831 if (! empty($_REQUEST['fields'])) {
1832 foreach ($_REQUEST['fields']['multi_edit'] as $key => $dummy) {
1833 $loop_array[] = $key;
1836 $using_key = false;
1837 $is_insert = true;
1839 $is_insertignore = isset($_REQUEST['submit_type'])
1840 && $_REQUEST['submit_type'] == 'insertignore';
1841 return array($loop_array, $using_key, $is_insert, $is_insertignore);
1845 * Check wether insert row mode and if so include tbl_changen script and set
1846 * global variables.
1848 * @return void
1850 function PMA_isInsertRow()
1852 if (isset($_REQUEST['insert_rows'])
1853 && is_numeric($_REQUEST['insert_rows'])
1854 && $_REQUEST['insert_rows'] != $GLOBALS['cfg']['InsertRows']
1856 $GLOBALS['cfg']['InsertRows'] = $_REQUEST['insert_rows'];
1857 $response = Response::getInstance();
1858 $header = $response->getHeader();
1859 $scripts = $header->getScripts();
1860 $scripts->addFile('tbl_change.js');
1861 if (!defined('TESTSUITE')) {
1862 include 'tbl_change.php';
1863 exit;
1869 * set $_SESSION for edit_next
1871 * @param string $one_where_clause one where clause from where clauses array
1873 * @return void
1875 function PMA_setSessionForEditNext($one_where_clause)
1877 $local_query = 'SELECT * FROM ' . PMA\libraries\Util::backquote($GLOBALS['db'])
1878 . '.' . PMA\libraries\Util::backquote($GLOBALS['table']) . ' WHERE '
1879 . str_replace('` =', '` >', $one_where_clause) . ' LIMIT 1;';
1881 $res = $GLOBALS['dbi']->query($local_query);
1882 $row = $GLOBALS['dbi']->fetchRow($res);
1883 $meta = $GLOBALS['dbi']->getFieldsMeta($res);
1884 // must find a unique condition based on unique key,
1885 // not a combination of all fields
1886 list($unique_condition, $clause_is_unique)
1887 = PMA\libraries\Util::getUniqueCondition(
1888 $res, // handle
1889 count($meta), // fields_cnt
1890 $meta, // fields_meta
1891 $row, // row
1892 true, // force_unique
1893 false, // restrict_to_table
1894 null // analyzed_sql_results
1896 if (! empty($unique_condition)) {
1897 $_SESSION['edit_next'] = $unique_condition;
1899 unset($unique_condition, $clause_is_unique);
1903 * set $goto_include variable for different cases and retrieve like,
1904 * if $GLOBALS['goto'] empty, if $goto_include previously not defined
1905 * and new_insert, same_insert, edit_next
1907 * @param string $goto_include store some script for include, otherwise it is
1908 * boolean false
1910 * @return string $goto_include
1912 function PMA_getGotoInclude($goto_include)
1914 $valid_options = array('new_insert', 'same_insert', 'edit_next');
1915 if (isset($_REQUEST['after_insert'])
1916 && in_array($_REQUEST['after_insert'], $valid_options)
1918 $goto_include = 'tbl_change.php';
1919 } elseif (! empty($GLOBALS['goto'])) {
1920 if (! preg_match('@^[a-z_]+\.php$@', $GLOBALS['goto'])) {
1921 // this should NOT happen
1922 //$GLOBALS['goto'] = false;
1923 $goto_include = false;
1924 } else {
1925 $goto_include = $GLOBALS['goto'];
1927 if ($GLOBALS['goto'] == 'db_sql.php' && strlen($GLOBALS['table']) > 0) {
1928 $GLOBALS['table'] = '';
1931 if (! $goto_include) {
1932 if (strlen($GLOBALS['table']) === 0) {
1933 $goto_include = 'db_sql.php';
1934 } else {
1935 $goto_include = 'tbl_sql.php';
1938 return $goto_include;
1942 * Defines the url to return in case of failure of the query
1944 * @param array $url_params url parameters
1946 * @return string error url for query failure
1948 function PMA_getErrorUrl($url_params)
1950 if (isset($_REQUEST['err_url'])) {
1951 return $_REQUEST['err_url'];
1952 } else {
1953 return 'tbl_change.php' . URL::getCommon($url_params);
1958 * Builds the sql query
1960 * @param boolean $is_insertignore $_REQUEST['submit_type'] == 'insertignore'
1961 * @param array $query_fields column names array
1962 * @param array $value_sets array of query values
1964 * @return array of query
1966 function PMA_buildSqlQuery($is_insertignore, $query_fields, $value_sets)
1968 if ($is_insertignore) {
1969 $insert_command = 'INSERT IGNORE ';
1970 } else {
1971 $insert_command = 'INSERT ';
1973 $query = array(
1974 $insert_command . 'INTO '
1975 . PMA\libraries\Util::backquote($GLOBALS['table'])
1976 . ' (' . implode(', ', $query_fields) . ') VALUES ('
1977 . implode('), (', $value_sets) . ')'
1979 unset($insert_command, $query_fields);
1980 return $query;
1984 * Executes the sql query and get the result, then move back to the calling page
1986 * @param array $url_params url parameters array
1987 * @param array $query built query from PMA_buildSqlQuery()
1989 * @return array $url_params, $total_affected_rows, $last_messages
1990 * $warning_messages, $error_messages, $return_to_sql_query
1992 function PMA_executeSqlQuery($url_params, $query)
1994 $return_to_sql_query = '';
1995 if (! empty($GLOBALS['sql_query'])) {
1996 $url_params['sql_query'] = $GLOBALS['sql_query'];
1997 $return_to_sql_query = $GLOBALS['sql_query'];
1999 $GLOBALS['sql_query'] = implode('; ', $query) . ';';
2000 // to ensure that the query is displayed in case of
2001 // "insert as new row" and then "insert another new row"
2002 $GLOBALS['display_query'] = $GLOBALS['sql_query'];
2004 $total_affected_rows = 0;
2005 $last_messages = array();
2006 $warning_messages = array();
2007 $error_messages = array();
2009 foreach ($query as $single_query) {
2010 if ($_REQUEST['submit_type'] == 'showinsert') {
2011 $last_messages[] = Message::notice(__('Showing SQL query'));
2012 continue;
2014 if ($GLOBALS['cfg']['IgnoreMultiSubmitErrors']) {
2015 $result = $GLOBALS['dbi']->tryQuery($single_query);
2016 } else {
2017 $result = $GLOBALS['dbi']->query($single_query);
2019 if (! $result) {
2020 $error_messages[] = $GLOBALS['dbi']->getError();
2021 } else {
2022 // The next line contains a real assignment, it's not a typo
2023 if ($tmp = @$GLOBALS['dbi']->affectedRows()) {
2024 $total_affected_rows += $tmp;
2026 unset($tmp);
2028 $insert_id = $GLOBALS['dbi']->insertId();
2029 if ($insert_id != 0) {
2030 // insert_id is id of FIRST record inserted in one insert, so if we
2031 // inserted multiple rows, we had to increment this
2033 if ($total_affected_rows > 0) {
2034 $insert_id = $insert_id + $total_affected_rows - 1;
2036 $last_message = Message::notice(__('Inserted row id: %1$d'));
2037 $last_message->addParam($insert_id);
2038 $last_messages[] = $last_message;
2040 $GLOBALS['dbi']->freeResult($result);
2042 $warning_messages = PMA_getWarningMessages();
2044 return array(
2045 $url_params,
2046 $total_affected_rows,
2047 $last_messages,
2048 $warning_messages,
2049 $error_messages,
2050 $return_to_sql_query
2055 * get the warning messages array
2057 * @return array $warning_essages
2059 function PMA_getWarningMessages()
2061 $warning_essages = array();
2062 foreach ($GLOBALS['dbi']->getWarnings() as $warning) {
2063 $warning_essages[] = Message::sanitize(
2064 $warning['Level'] . ': #' . $warning['Code'] . ' ' . $warning['Message']
2067 return $warning_essages;
2071 * Column to display from the foreign table?
2073 * @param string $where_comparison string that contain relation field value
2074 * @param array $map all Relations to foreign tables for a given
2075 * table or optionally a given column in a table
2076 * @param string $relation_field relation field
2078 * @return string $dispval display value from the foreign table
2080 function PMA_getDisplayValueForForeignTableColumn($where_comparison,
2081 $map, $relation_field
2083 $foreigner = PMA_searchColumnInForeigners($map, $relation_field);
2084 $display_field = PMA_getDisplayField(
2085 $foreigner['foreign_db'],
2086 $foreigner['foreign_table']
2088 // Field to display from the foreign table?
2089 if (isset($display_field) && strlen($display_field) > 0) {
2090 $dispsql = 'SELECT ' . PMA\libraries\Util::backquote($display_field)
2091 . ' FROM ' . PMA\libraries\Util::backquote($foreigner['foreign_db'])
2092 . '.' . PMA\libraries\Util::backquote($foreigner['foreign_table'])
2093 . ' WHERE ' . PMA\libraries\Util::backquote($foreigner['foreign_field'])
2094 . $where_comparison;
2095 $dispresult = $GLOBALS['dbi']->tryQuery(
2096 $dispsql, null, PMA\libraries\DatabaseInterface::QUERY_STORE
2098 if ($dispresult && $GLOBALS['dbi']->numRows($dispresult) > 0) {
2099 list($dispval) = $GLOBALS['dbi']->fetchRow($dispresult, 0);
2100 } else {
2101 $dispval = '';
2103 if ($dispresult) {
2104 $GLOBALS['dbi']->freeResult($dispresult);
2106 return $dispval;
2108 return '';
2112 * Display option in the cell according to user choices
2114 * @param array $map all Relations to foreign tables for a given
2115 * table or optionally a given column in a table
2116 * @param string $relation_field relation field
2117 * @param string $where_comparison string that contain relation field value
2118 * @param string $dispval display value from the foreign table
2119 * @param string $relation_field_value relation field value
2121 * @return string $output HTML <a> tag
2123 function PMA_getLinkForRelationalDisplayField($map, $relation_field,
2124 $where_comparison, $dispval, $relation_field_value
2126 $foreigner = PMA_searchColumnInForeigners($map, $relation_field);
2127 if ('K' == $_SESSION['tmpval']['relational_display']) {
2128 // user chose "relational key" in the display options, so
2129 // the title contains the display field
2130 $title = (! empty($dispval))
2131 ? ' title="' . htmlspecialchars($dispval) . '"'
2132 : '';
2133 } else {
2134 $title = ' title="' . htmlspecialchars($relation_field_value) . '"';
2136 $_url_params = array(
2137 'db' => $foreigner['foreign_db'],
2138 'table' => $foreigner['foreign_table'],
2139 'pos' => '0',
2140 'sql_query' => 'SELECT * FROM '
2141 . PMA\libraries\Util::backquote($foreigner['foreign_db'])
2142 . '.' . PMA\libraries\Util::backquote($foreigner['foreign_table'])
2143 . ' WHERE ' . PMA\libraries\Util::backquote($foreigner['foreign_field'])
2144 . $where_comparison
2146 $output = '<a href="sql.php'
2147 . URL::getCommon($_url_params) . '"' . $title . '>';
2149 if ('D' == $_SESSION['tmpval']['relational_display']) {
2150 // user chose "relational display field" in the
2151 // display options, so show display field in the cell
2152 $output .= (!empty($dispval)) ? htmlspecialchars($dispval) : '';
2153 } else {
2154 // otherwise display data in the cell
2155 $output .= htmlspecialchars($relation_field_value);
2157 $output .= '</a>';
2158 return $output;
2162 * Transform edited values
2164 * @param string $db db name
2165 * @param string $table table name
2166 * @param array $transformation mimetypes for all columns of a table
2167 * [field_name][field_key]
2168 * @param array &$edited_values transform columns list and new values
2169 * @param string $file file containing the transformation plugin
2170 * @param string $column_name column name
2171 * @param array $extra_data extra data array
2172 * @param string $type the type of transformation
2174 * @return array $extra_data
2176 function PMA_transformEditedValues($db, $table,
2177 $transformation, &$edited_values, $file, $column_name, $extra_data, $type
2179 $include_file = 'libraries/plugins/transformations/' . $file;
2180 if (is_file($include_file)) {
2181 include_once $include_file;
2182 $_url_params = array(
2183 'db' => $db,
2184 'table' => $table,
2185 'where_clause' => $_REQUEST['where_clause'],
2186 'transform_key' => $column_name
2188 $transform_options = PMA_Transformation_getOptions(
2189 isset($transformation[$type . '_options'])
2190 ? $transformation[$type . '_options']
2191 : ''
2193 $transform_options['wrapper_link']
2194 = URL::getCommon($_url_params);
2195 $class_name = PMA_getTransformationClassName($include_file);
2196 /** @var TransformationsPlugin $transformation_plugin */
2197 $transformation_plugin = new $class_name();
2199 foreach ($edited_values as $cell_index => $curr_cell_edited_values) {
2200 if (isset($curr_cell_edited_values[$column_name])) {
2201 $edited_values[$cell_index][$column_name]
2202 = $extra_data['transformations'][$cell_index]
2203 = $transformation_plugin->applyTransformation(
2204 $curr_cell_edited_values[$column_name],
2205 $transform_options,
2209 } // end of loop for each transformation cell
2211 return $extra_data;
2215 * Get current value in multi edit mode
2217 * @param array $multi_edit_funcs multiple edit functions array
2218 * @param array $multi_edit_salt multiple edit array with encryption salt
2219 * @param array $gis_from_text_functions array that contains gis from text functions
2220 * @param string $current_value current value in the column
2221 * @param array $gis_from_wkb_functions initially $val is $multi_edit_columns[$key]
2222 * @param array $func_optional_param array('RAND','UNIX_TIMESTAMP')
2223 * @param array $func_no_param array of set of string
2224 * @param string $key an md5 of the column name
2226 * @return array $cur_value
2228 function PMA_getCurrentValueAsAnArrayForMultipleEdit( $multi_edit_funcs,
2229 $multi_edit_salt,
2230 $gis_from_text_functions, $current_value, $gis_from_wkb_functions,
2231 $func_optional_param, $func_no_param, $key
2233 if (empty($multi_edit_funcs[$key])) {
2234 return $current_value;
2235 } elseif ('UUID' === $multi_edit_funcs[$key]) {
2236 /* This way user will know what UUID new row has */
2237 $uuid = $GLOBALS['dbi']->fetchValue('SELECT UUID()');
2238 return "'" . $uuid . "'";
2239 } elseif ((in_array($multi_edit_funcs[$key], $gis_from_text_functions)
2240 && substr($current_value, 0, 3) == "'''")
2241 || in_array($multi_edit_funcs[$key], $gis_from_wkb_functions)
2243 // Remove enclosing apostrophes
2244 $current_value = mb_substr($current_value, 1, -1);
2245 // Remove escaping apostrophes
2246 $current_value = str_replace("''", "'", $current_value);
2247 return $multi_edit_funcs[$key] . '(' . $current_value . ')';
2248 } elseif (! in_array($multi_edit_funcs[$key], $func_no_param)
2249 || ($current_value != "''"
2250 && in_array($multi_edit_funcs[$key], $func_optional_param))
2252 if ((isset($multi_edit_salt[$key])
2253 && ($multi_edit_funcs[$key] == "AES_ENCRYPT"
2254 || $multi_edit_funcs[$key] == "AES_DECRYPT"))
2255 || (! empty($multi_edit_salt[$key])
2256 && ($multi_edit_funcs[$key] == "DES_ENCRYPT"
2257 || $multi_edit_funcs[$key] == "DES_DECRYPT"
2258 || $multi_edit_funcs[$key] == "ENCRYPT"))
2260 return $multi_edit_funcs[$key] . '(' . $current_value . ",'"
2261 . $GLOBALS['dbi']->escapeString($multi_edit_salt[$key]) . "')";
2262 } else {
2263 return $multi_edit_funcs[$key] . '(' . $current_value . ')';
2265 } else {
2266 return $multi_edit_funcs[$key] . '()';
2271 * Get query values array and query fields array for insert and update in multi edit
2273 * @param array $multi_edit_columns_name multiple edit columns name array
2274 * @param array $multi_edit_columns_null multiple edit columns null array
2275 * @param string $current_value current value in the column in loop
2276 * @param array $multi_edit_columns_prev multiple edit previous columns array
2277 * @param array $multi_edit_funcs multiple edit functions array
2278 * @param boolean $is_insert boolean value whether insert or not
2279 * @param array $query_values SET part of the sql query
2280 * @param array $query_fields array of query fields
2281 * @param string $current_value_as_an_array current value in the column
2282 * as an array
2283 * @param array $value_sets array of valu sets
2284 * @param string $key an md5 of the column name
2285 * @param array $multi_edit_columns_null_prev array of multiple edit columns
2286 * null previous
2288 * @return array ($query_values, $query_fields)
2290 function PMA_getQueryValuesForInsertAndUpdateInMultipleEdit($multi_edit_columns_name,
2291 $multi_edit_columns_null, $current_value, $multi_edit_columns_prev,
2292 $multi_edit_funcs,$is_insert, $query_values, $query_fields,
2293 $current_value_as_an_array, $value_sets, $key, $multi_edit_columns_null_prev
2295 // i n s e r t
2296 if ($is_insert) {
2297 // no need to add column into the valuelist
2298 if (strlen($current_value_as_an_array) > 0) {
2299 $query_values[] = $current_value_as_an_array;
2300 // first inserted row so prepare the list of fields
2301 if (empty($value_sets)) {
2302 $query_fields[] = PMA\libraries\Util::backquote(
2303 $multi_edit_columns_name[$key]
2308 } elseif (! empty($multi_edit_columns_null_prev[$key])
2309 && ! isset($multi_edit_columns_null[$key])
2311 // u p d a t e
2313 // field had the null checkbox before the update
2314 // field no longer has the null checkbox
2315 $query_values[]
2316 = PMA\libraries\Util::backquote($multi_edit_columns_name[$key])
2317 . ' = ' . $current_value_as_an_array;
2318 } elseif (empty($multi_edit_funcs[$key])
2319 && isset($multi_edit_columns_prev[$key])
2320 && (("'" . $GLOBALS['dbi']->escapeString($multi_edit_columns_prev[$key]) . "'" === $current_value)
2321 || ('0x' . $multi_edit_columns_prev[$key] === $current_value))
2323 // No change for this column and no MySQL function is used -> next column
2324 } elseif (! empty($current_value)) {
2325 // avoid setting a field to NULL when it's already NULL
2326 // (field had the null checkbox before the update
2327 // field still has the null checkbox)
2328 if (empty($multi_edit_columns_null_prev[$key])
2329 || empty($multi_edit_columns_null[$key])
2331 $query_values[]
2332 = PMA\libraries\Util::backquote($multi_edit_columns_name[$key])
2333 . ' = ' . $current_value_as_an_array;
2336 return array($query_values, $query_fields);
2340 * Get the current column value in the form for different data types
2342 * @param string|false $possibly_uploaded_val uploaded file content
2343 * @param string $key an md5 of the column name
2344 * @param array $multi_edit_columns_type array of multi edit column types
2345 * @param string $current_value current column value in the form
2346 * @param array $multi_edit_auto_increment multi edit auto increment
2347 * @param integer $rownumber index of where clause array
2348 * @param array $multi_edit_columns_name multi edit column names array
2349 * @param array $multi_edit_columns_null multi edit columns null array
2350 * @param array $multi_edit_columns_null_prev multi edit columns previous null
2351 * @param boolean $is_insert whether insert or not
2352 * @param boolean $using_key whether editing or new row
2353 * @param string $where_clause where clause
2354 * @param string $table table name
2355 * @param array $multi_edit_funcs multiple edit functions array
2357 * @return string $current_value current column value in the form
2359 function PMA_getCurrentValueForDifferentTypes($possibly_uploaded_val, $key,
2360 $multi_edit_columns_type, $current_value, $multi_edit_auto_increment,
2361 $rownumber, $multi_edit_columns_name, $multi_edit_columns_null,
2362 $multi_edit_columns_null_prev, $is_insert, $using_key, $where_clause, $table,
2363 $multi_edit_funcs
2365 // Fetch the current values of a row to use in case we have a protected field
2366 if ($is_insert
2367 && $using_key && isset($multi_edit_columns_type)
2368 && is_array($multi_edit_columns_type) && !empty($where_clause)
2370 $protected_row = $GLOBALS['dbi']->fetchSingleRow(
2371 'SELECT * FROM ' . PMA\libraries\Util::backquote($table)
2372 . ' WHERE ' . $where_clause . ';'
2376 if (false !== $possibly_uploaded_val) {
2377 $current_value = $possibly_uploaded_val;
2378 } else if (! empty($multi_edit_funcs[$key])) {
2379 $current_value = "'" . $GLOBALS['dbi']->escapeString($current_value)
2380 . "'";
2381 } else {
2382 // c o l u m n v a l u e i n t h e f o r m
2383 if (isset($multi_edit_columns_type[$key])) {
2384 $type = $multi_edit_columns_type[$key];
2385 } else {
2386 $type = '';
2389 if ($type != 'protected' && $type != 'set' && strlen($current_value) === 0) {
2390 // best way to avoid problems in strict mode
2391 // (works also in non-strict mode)
2392 if (isset($multi_edit_auto_increment)
2393 && isset($multi_edit_auto_increment[$key])
2395 $current_value = 'NULL';
2396 } else {
2397 $current_value = "''";
2399 } elseif ($type == 'set') {
2400 if (! empty($_REQUEST['fields']['multi_edit'][$rownumber][$key])) {
2401 $current_value = implode(
2402 ',', $_REQUEST['fields']['multi_edit'][$rownumber][$key]
2404 $current_value = "'"
2405 . $GLOBALS['dbi']->escapeString($current_value) . "'";
2406 } else {
2407 $current_value = "''";
2409 } elseif ($type == 'protected') {
2410 // here we are in protected mode (asked in the config)
2411 // so tbl_change has put this special value in the
2412 // columns array, so we do not change the column value
2413 // but we can still handle column upload
2415 // when in UPDATE mode, do not alter field's contents. When in INSERT
2416 // mode, insert empty field because no values were submitted.
2417 // If protected blobs where set, insert original fields content.
2418 if (! empty($protected_row[$multi_edit_columns_name[$key]])) {
2419 $current_value = '0x'
2420 . bin2hex($protected_row[$multi_edit_columns_name[$key]]);
2421 } else {
2422 $current_value = '';
2424 } elseif ($type === 'hex') {
2425 $current_value = '0x' . $current_value;
2426 } elseif ($type == 'bit') {
2427 $current_value = preg_replace('/[^01]/', '0', $current_value);
2428 $current_value = "b'" . $GLOBALS['dbi']->escapeString($current_value)
2429 . "'";
2430 } elseif (! ($type == 'datetime' || $type == 'timestamp')
2431 || $current_value != 'CURRENT_TIMESTAMP'
2433 $current_value = "'" . $GLOBALS['dbi']->escapeString($current_value)
2434 . "'";
2437 // Was the Null checkbox checked for this field?
2438 // (if there is a value, we ignore the Null checkbox: this could
2439 // be possible if Javascript is disabled in the browser)
2440 if (! empty($multi_edit_columns_null[$key])
2441 && ($current_value == "''" || $current_value == '')
2443 $current_value = 'NULL';
2446 // The Null checkbox was unchecked for this field
2447 if (empty($current_value)
2448 && ! empty($multi_edit_columns_null_prev[$key])
2449 && ! isset($multi_edit_columns_null[$key])
2451 $current_value = "''";
2453 } // end else (column value in the form)
2454 return $current_value;
2459 * Check whether inline edited value can be truncated or not,
2460 * and add additional parameters for extra_data array if needed
2462 * @param string $db Database name
2463 * @param string $table Table name
2464 * @param string $column_name Column name
2465 * @param array &$extra_data Extra data for ajax response
2467 * @return void
2469 function PMA_verifyWhetherValueCanBeTruncatedAndAppendExtraData(
2470 $db, $table, $column_name, &$extra_data
2473 $extra_data['isNeedToRecheck'] = false;
2475 $sql_for_real_value = 'SELECT ' . PMA\libraries\Util::backquote($table) . '.'
2476 . PMA\libraries\Util::backquote($column_name)
2477 . ' FROM ' . PMA\libraries\Util::backquote($db) . '.'
2478 . PMA\libraries\Util::backquote($table)
2479 . ' WHERE ' . $_REQUEST['where_clause'][0];
2481 $result = $GLOBALS['dbi']->tryQuery($sql_for_real_value);
2482 $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
2483 $meta = $fields_meta[0];
2484 if ($row = $GLOBALS['dbi']->fetchRow($result)) {
2485 $new_value = $row[0];
2486 if ((substr($meta->type, 0, 9) == 'timestamp')
2487 || ($meta->type == 'datetime')
2488 || ($meta->type == 'time')
2490 $new_value = PMA\libraries\Util::addMicroseconds($new_value);
2492 $extra_data['isNeedToRecheck'] = true;
2493 $extra_data['truncatableFieldValue'] = $new_value;
2495 $GLOBALS['dbi']->freeResult($result);
2499 * Function to get the columns of a table
2501 * @param string $db current db
2502 * @param string $table current table
2504 * @return array
2506 function PMA_getTableColumns($db, $table)
2508 $GLOBALS['dbi']->selectDb($db);
2509 return array_values($GLOBALS['dbi']->getColumns($db, $table, null, true));
2514 * Function to determine Insert/Edit rows
2516 * @param string $where_clause where clause
2517 * @param string $db current database
2518 * @param string $table current table
2520 * @return mixed
2522 function PMA_determineInsertOrEdit($where_clause, $db, $table)
2524 if (isset($_REQUEST['where_clause'])) {
2525 $where_clause = $_REQUEST['where_clause'];
2527 if (isset($_SESSION['edit_next'])) {
2528 $where_clause = $_SESSION['edit_next'];
2529 unset($_SESSION['edit_next']);
2530 $after_insert = 'edit_next';
2532 if (isset($_REQUEST['ShowFunctionFields'])) {
2533 $GLOBALS['cfg']['ShowFunctionFields'] = $_REQUEST['ShowFunctionFields'];
2535 if (isset($_REQUEST['ShowFieldTypesInDataEditView'])) {
2536 $GLOBALS['cfg']['ShowFieldTypesInDataEditView']
2537 = $_REQUEST['ShowFieldTypesInDataEditView'];
2539 if (isset($_REQUEST['after_insert'])) {
2540 $after_insert = $_REQUEST['after_insert'];
2543 if (isset($where_clause)) {
2544 // we are editing
2545 $insert_mode = false;
2546 $where_clause_array = PMA_getWhereClauseArray($where_clause);
2547 list($where_clauses, $result, $rows, $found_unique_key)
2548 = PMA_analyzeWhereClauses(
2549 $where_clause_array, $table, $db
2551 } else {
2552 // we are inserting
2553 $insert_mode = true;
2554 $where_clause = null;
2555 list($result, $rows) = PMA_loadFirstRow($table, $db);
2556 $where_clauses = null;
2557 $where_clause_array = array();
2558 $found_unique_key = false;
2561 // Copying a row - fetched data will be inserted as a new row,
2562 // therefore the where clause is needless.
2563 if (isset($_REQUEST['default_action'])
2564 && $_REQUEST['default_action'] === 'insert'
2566 $where_clause = $where_clauses = null;
2569 return array(
2570 $insert_mode, $where_clause, $where_clause_array, $where_clauses,
2571 $result, $rows, $found_unique_key,
2572 isset($after_insert) ? $after_insert : null
2577 * Function to get comments for the table columns
2579 * @param string $db current database
2580 * @param string $table current table
2582 * @return array $comments_map comments for columns
2584 function PMA_getCommentsMap($db, $table)
2586 $comments_map = array();
2588 if ($GLOBALS['cfg']['ShowPropertyComments']) {
2589 $comments_map = PMA_getComments($db, $table);
2592 return $comments_map;
2596 * Function to get URL parameters
2598 * @param string $db current database
2599 * @param string $table current table
2601 * @return array $url_params url parameters
2603 function PMA_getUrlParameters($db, $table)
2606 * @todo check if we could replace by "db_|tbl_" - please clarify!?
2608 $url_params = array(
2609 'db' => $db,
2610 'sql_query' => $_REQUEST['sql_query']
2613 if (preg_match('@^tbl_@', $GLOBALS['goto'])) {
2614 $url_params['table'] = $table;
2617 return $url_params;
2621 * Function to get html for the gis editor div
2623 * @return string
2625 function PMA_getHtmlForGisEditor()
2627 return '<div id="gis_editor"></div>'
2628 . '<div id="popup_background"></div>'
2629 . '<br />';
2633 * Function to get html for the ignore option in insert mode
2635 * @param int $row_id row id
2636 * @param bool $checked ignore option is checked or not
2638 * @return string
2640 function PMA_getHtmlForIgnoreOption($row_id, $checked = true)
2642 return '<input type="checkbox"'
2643 . ($checked ? ' checked="checked"' : '')
2644 . ' name="insert_ignore_' . $row_id . '"'
2645 . ' id="insert_ignore_' . $row_id . '" />'
2646 . '<label for="insert_ignore_' . $row_id . '">'
2647 . __('Ignore')
2648 . '</label><br />' . "\n";
2652 * Function to get html for the function option
2654 * @param array $column column
2655 * @param string $column_name_appendix column name appendix
2657 * @return String
2659 function PMA_getHtmlForFunctionOption($column, $column_name_appendix)
2661 $longDoubleTextArea = $GLOBALS['cfg']['LongtextDoubleTextarea'];
2662 return '<tr class="noclick">'
2663 . '<td '
2664 . ($longDoubleTextArea
2665 && mb_strstr($column['True_Type'], 'longtext')
2666 ? 'rowspan="2"'
2667 : ''
2669 . 'class="center">'
2670 . $column['Field_title']
2671 . '<input type="hidden" name="fields_name' . $column_name_appendix
2672 . '" value="' . $column['Field_html'] . '"/>'
2673 . '</td>';
2678 * Function to get html for the column type
2680 * @param array $column column
2682 * @return string
2684 function PMA_getHtmlForInsertEditColumnType($column)
2686 return '<td class="center' . $column['wrap'] . '">'
2687 . '<span class="column_type" dir="ltr">' . $column['pma_type'] . '</span>'
2688 . '</td>';
2693 * Function to get html for the insert edit form header
2695 * @param bool $has_blob_field whether has blob field
2696 * @param bool $is_upload whether is upload
2698 * @return string
2700 function PMA_getHtmlForInsertEditFormHeader($has_blob_field, $is_upload)
2702 $html_output ='<form id="insertForm" class="lock-page ';
2703 if ($has_blob_field && $is_upload) {
2704 $html_output .='disableAjax';
2706 $html_output .='" method="post" action="tbl_replace.php" name="insertForm" ';
2707 if ($is_upload) {
2708 $html_output .= ' enctype="multipart/form-data"';
2710 $html_output .= '>';
2712 return $html_output;
2716 * Function to get html for each insert/edit column
2718 * @param array $table_columns table columns
2719 * @param int $column_number column index in table_columns
2720 * @param array $comments_map comments map
2721 * @param bool $timestamp_seen whether timestamp seen
2722 * @param array $current_result current result
2723 * @param string $chg_evt_handler javascript change event handler
2724 * @param string $jsvkey javascript validation key
2725 * @param string $vkey validation key
2726 * @param bool $insert_mode whether insert mode
2727 * @param array $current_row current row
2728 * @param int &$o_rows row offset
2729 * @param int &$tabindex tab index
2730 * @param int $columns_cnt columns count
2731 * @param bool $is_upload whether upload
2732 * @param int $tabindex_for_function tab index offset for function
2733 * @param array $foreigners foreigners
2734 * @param int $tabindex_for_null tab index offset for null
2735 * @param int $tabindex_for_value tab index offset for value
2736 * @param string $table table
2737 * @param string $db database
2738 * @param int $row_id row id
2739 * @param array $titles titles
2740 * @param int $biggest_max_file_size biggest max file size
2741 * @param string $default_char_editing default char editing mode which is stored
2742 * in the config.inc.php script
2743 * @param string $text_dir text direction
2744 * @param array $repopulate the data to be repopulated
2745 * @param array $column_mime the mime information of column
2746 * @param string $where_clause the where clause
2748 * @return string
2750 function PMA_getHtmlForInsertEditFormColumn($table_columns, $column_number,
2751 $comments_map, $timestamp_seen, $current_result, $chg_evt_handler,
2752 $jsvkey, $vkey, $insert_mode, $current_row, &$o_rows,
2753 &$tabindex, $columns_cnt, $is_upload, $tabindex_for_function,
2754 $foreigners, $tabindex_for_null, $tabindex_for_value, $table, $db,
2755 $row_id, $titles, $biggest_max_file_size, $default_char_editing,
2756 $text_dir, $repopulate, $column_mime, $where_clause
2758 $column = $table_columns[$column_number];
2759 $readOnly = false;
2760 if (! PMA_userHasColumnPrivileges($column, $insert_mode)) {
2761 $readOnly = true;
2764 if (! isset($column['processed'])) {
2765 $column = PMA_analyzeTableColumnsArray(
2766 $column, $comments_map, $timestamp_seen
2769 $as_is = false;
2770 if (!empty($repopulate) && !empty($current_row)) {
2771 $current_row[$column['Field']] = $repopulate[$column['Field_md5']];
2772 $as_is = true;
2775 $extracted_columnspec
2776 = PMA\libraries\Util::extractColumnSpec($column['Type']);
2778 if (-1 === $column['len']) {
2779 $column['len'] = $GLOBALS['dbi']->fieldLen(
2780 $current_result, $column_number
2782 // length is unknown for geometry fields,
2783 // make enough space to edit very simple WKTs
2784 if (-1 === $column['len']) {
2785 $column['len'] = 30;
2788 //Call validation when the form submitted...
2789 $onChangeClause = $chg_evt_handler
2790 . "=\"return verificationsAfterFieldChange('"
2791 . Sanitize::escapeJsString($column['Field_md5']) . "', '"
2792 . Sanitize::escapeJsString($jsvkey) . "','" . $column['pma_type'] . "')\"";
2794 // Use an MD5 as an array index to avoid having special characters
2795 // in the name attribute (see bug #1746964 )
2796 $column_name_appendix = $vkey . '[' . $column['Field_md5'] . ']';
2798 if ($column['Type'] === 'datetime'
2799 && ! isset($column['Default'])
2800 && ! is_null($column['Default'])
2801 && $insert_mode
2803 $column['Default'] = date('Y-m-d H:i:s', time());
2806 $html_output = PMA_getHtmlForFunctionOption(
2807 $column, $column_name_appendix
2810 if ($GLOBALS['cfg']['ShowFieldTypesInDataEditView']) {
2811 $html_output .= PMA_getHtmlForInsertEditColumnType($column);
2812 } //End if
2814 // Get a list of GIS data types.
2815 $gis_data_types = PMA\libraries\Util::getGISDatatypes();
2817 // Prepares the field value
2818 $real_null_value = false;
2819 $special_chars_encoded = '';
2820 if (!empty($current_row)) {
2821 // (we are editing)
2822 list(
2823 $real_null_value, $special_chars_encoded, $special_chars,
2824 $data, $backup_field
2826 = PMA_getSpecialCharsAndBackupFieldForExistingRow(
2827 $current_row, $column, $extracted_columnspec,
2828 $real_null_value, $gis_data_types, $column_name_appendix, $as_is
2830 } else {
2831 // (we are inserting)
2832 // display default values
2833 $tmp = $column;
2834 if (isset($repopulate[$column['Field_md5']])) {
2835 $tmp['Default'] = $repopulate[$column['Field_md5']];
2837 list($real_null_value, $data, $special_chars, $backup_field,
2838 $special_chars_encoded
2840 = PMA_getSpecialCharsAndBackupFieldForInsertingMode(
2841 $tmp, $real_null_value
2843 unset($tmp);
2846 $idindex = ($o_rows * $columns_cnt) + $column_number + 1;
2847 $tabindex = $idindex;
2849 // Get a list of data types that are not yet supported.
2850 $no_support_types = PMA\libraries\Util::unsupportedDatatypes();
2852 // The function column
2853 // -------------------
2854 $foreignData = PMA_getForeignData(
2855 $foreigners, $column['Field'], false, '', ''
2857 if ($GLOBALS['cfg']['ShowFunctionFields']) {
2858 $html_output .= PMA_getFunctionColumn(
2859 $column, $is_upload, $column_name_appendix,
2860 $onChangeClause, $no_support_types, $tabindex_for_function,
2861 $tabindex, $idindex, $insert_mode, $readOnly, $foreignData
2865 // The null column
2866 // ---------------
2867 $html_output .= PMA_getNullColumn(
2868 $column, $column_name_appendix, $real_null_value,
2869 $tabindex, $tabindex_for_null, $idindex, $vkey, $foreigners,
2870 $foreignData, $readOnly
2873 // The value column (depends on type)
2874 // ----------------
2875 // See bug #1667887 for the reason why we don't use the maxlength
2876 // HTML attribute
2878 //add data attributes "no of decimals" and "data type"
2879 $no_decimals = 0;
2880 $type = current(explode("(", $column['pma_type']));
2881 if (preg_match('/\(([^()]+)\)/', $column['pma_type'], $match)) {
2882 $match[0] = trim($match[0], '()');
2883 $no_decimals = $match[0];
2885 $html_output .= '<td' . ' data-type="' . $type . '"' . ' data-decimals="'
2886 . $no_decimals . '">' . "\n";
2887 // Will be used by js/tbl_change.js to set the default value
2888 // for the "Continue insertion" feature
2889 $html_output .= '<span class="default_value hide">'
2890 . $special_chars . '</span>';
2892 // Check input transformation of column
2893 $transformed_html = '';
2894 if (!empty($column_mime['input_transformation'])) {
2895 $file = $column_mime['input_transformation'];
2896 $include_file = 'libraries/plugins/transformations/' . $file;
2897 if (is_file($include_file)) {
2898 include_once $include_file;
2899 $class_name = PMA_getTransformationClassName($include_file);
2900 $transformation_plugin = new $class_name();
2901 $transformation_options = PMA_Transformation_getOptions(
2902 $column_mime['input_transformation_options']
2904 $_url_params = array(
2905 'db' => $db,
2906 'table' => $table,
2907 'transform_key' => $column['Field'],
2908 'where_clause' => $where_clause
2910 $transformation_options['wrapper_link']
2911 = URL::getCommon($_url_params);
2912 $current_value = '';
2913 if (isset($current_row[$column['Field']])) {
2914 $current_value = $current_row[$column['Field']];
2916 if (method_exists($transformation_plugin, 'getInputHtml')) {
2917 $transformed_html = $transformation_plugin->getInputHtml(
2918 $column, $row_id, $column_name_appendix,
2919 $transformation_options, $current_value, $text_dir,
2920 $tabindex, $tabindex_for_value, $idindex
2923 if (method_exists($transformation_plugin, 'getScripts')) {
2924 $GLOBALS['plugin_scripts'] = array_merge(
2925 $GLOBALS['plugin_scripts'], $transformation_plugin->getScripts()
2930 if (!empty($transformed_html)) {
2931 $html_output .= $transformed_html;
2932 } else {
2933 $html_output .= PMA_getValueColumn(
2934 $column, $backup_field, $column_name_appendix, $onChangeClause,
2935 $tabindex, $tabindex_for_value, $idindex, $data, $special_chars,
2936 $foreignData, array($table, $db), $row_id, $titles,
2937 $text_dir, $special_chars_encoded, $vkey, $is_upload,
2938 $biggest_max_file_size, $default_char_editing,
2939 $no_support_types, $gis_data_types, $extracted_columnspec, $readOnly
2942 $html_output .= '</td>'
2943 . '</tr>';
2945 return $html_output;
2949 * Function to get html for each insert/edit row
2951 * @param array $url_params url parameters
2952 * @param array $table_columns table columns
2953 * @param array $comments_map comments map
2954 * @param bool $timestamp_seen whether timestamp seen
2955 * @param array $current_result current result
2956 * @param string $chg_evt_handler javascript change event handler
2957 * @param string $jsvkey javascript validation key
2958 * @param string $vkey validation key
2959 * @param bool $insert_mode whether insert mode
2960 * @param array $current_row current row
2961 * @param int &$o_rows row offset
2962 * @param int &$tabindex tab index
2963 * @param int $columns_cnt columns count
2964 * @param bool $is_upload whether upload
2965 * @param int $tabindex_for_function tab index offset for function
2966 * @param array $foreigners foreigners
2967 * @param int $tabindex_for_null tab index offset for null
2968 * @param int $tabindex_for_value tab index offset for value
2969 * @param string $table table
2970 * @param string $db database
2971 * @param int $row_id row id
2972 * @param array $titles titles
2973 * @param int $biggest_max_file_size biggest max file size
2974 * @param string $text_dir text direction
2975 * @param array $repopulate the data to be repopulated
2976 * @param array $where_clause_array the array of where clauses
2978 * @return string
2980 function PMA_getHtmlForInsertEditRow($url_params, $table_columns,
2981 $comments_map, $timestamp_seen, $current_result, $chg_evt_handler,
2982 $jsvkey, $vkey, $insert_mode, $current_row, &$o_rows, &$tabindex, $columns_cnt,
2983 $is_upload, $tabindex_for_function, $foreigners, $tabindex_for_null,
2984 $tabindex_for_value, $table, $db, $row_id, $titles,
2985 $biggest_max_file_size, $text_dir, $repopulate, $where_clause_array
2987 $html_output = PMA_getHeadAndFootOfInsertRowTable($url_params)
2988 . '<tbody>';
2990 //store the default value for CharEditing
2991 $default_char_editing = $GLOBALS['cfg']['CharEditing'];
2992 $mime_map = PMA_getMIME($db, $table);
2993 $where_clause = '';
2994 if (isset($where_clause_array[$row_id])) {
2995 $where_clause = $where_clause_array[$row_id];
2997 for ($column_number = 0; $column_number < $columns_cnt; $column_number++) {
2998 $table_column = $table_columns[$column_number];
2999 $column_mime = array();
3000 if (isset($mime_map[$table_column['Field']])) {
3001 $column_mime = $mime_map[$table_column['Field']];
3003 $html_output .= PMA_getHtmlForInsertEditFormColumn(
3004 $table_columns, $column_number, $comments_map, $timestamp_seen,
3005 $current_result, $chg_evt_handler, $jsvkey, $vkey, $insert_mode,
3006 $current_row, $o_rows, $tabindex, $columns_cnt, $is_upload,
3007 $tabindex_for_function, $foreigners, $tabindex_for_null,
3008 $tabindex_for_value, $table, $db, $row_id, $titles,
3009 $biggest_max_file_size, $default_char_editing, $text_dir, $repopulate,
3010 $column_mime, $where_clause
3012 } // end for
3013 $o_rows++;
3014 $html_output .= ' </tbody>'
3015 . '</table><br />'
3016 . '<div class="clearfloat"></div>';
3018 return $html_output;
3022 * Returns whether the user has necessary insert/update privileges for the column
3024 * @param array $table_column array of column details
3025 * @param bool $insert_mode whether on insert mode
3027 * @return boolean whether user has necessary privileges
3029 function PMA_userHasColumnPrivileges($table_column, $insert_mode)
3031 $privileges = $table_column['Privileges'];
3032 return ($insert_mode && strstr($privileges, 'insert') !== false)
3033 || (! $insert_mode && strstr($privileges, 'update') !== false);